diff --git a/.gitignore b/.gitignore
index c2658d7..9098881 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,3 @@
node_modules/
+package-lock.json
+git_modules/
diff --git a/install-deps.sh b/install-deps.sh
new file mode 100755
index 0000000..92e3e5f
--- /dev/null
+++ b/install-deps.sh
@@ -0,0 +1,5 @@
+npm install line-navigator --save
+
+mkdir git_modules
+cd git_modules
+git clone https://github.com/brillout/forge-sha256/
diff --git a/www/css/main.css b/www/css/main.css
index 50f7243..d113c43 100644
--- a/www/css/main.css
+++ b/www/css/main.css
@@ -116,4 +116,36 @@ blockquote {
right: 5px;
white-space: nowrap;
position: fixed;
+ overflow-y: auto;
+ z-index: 100;
+}
+
+.warning {
+ color: yellow !important;
+}
+
+.warning:before {
+ content: "!";
+ color: red;
+ margin-right: 5px;
+ font-weight: bolder;
+
+ transition: color 1s;
+}
+
+.warning:hover:before {
+ color: white;
+}
+
+.metadata {
+ color: white;
+}
+
+.metadata .overlap {
+ color: orange !important;
+ text-decoration: underline;
+}
+
+.meta-dupe {
+ color: orange !important;
}
diff --git a/www/i/close.svg b/www/i/close.svg
deleted file mode 100644
index 25ce681..0000000
--- a/www/i/close.svg
+++ /dev/null
@@ -1,43 +0,0 @@
-
-
-
-
diff --git a/www/index.html b/www/index.html
index 74ceb8a..01fb35d 100644
--- a/www/index.html
+++ b/www/index.html
@@ -3,6 +3,7 @@
+
@@ -21,10 +22,10 @@
@@ -56,7 +57,7 @@
Title:
- Title (Raomanised):
+ Title (Romanised):
Artist:
Artist (Romanised):
Mapper:
@@ -67,9 +68,32 @@
Set ID:
+
+
+
+ HP:
+ CS:
+ OD:
+ AR:
+ SV:
+ TR:
+
+
+
+
+
+ Background Image:
+
+
Viewing:
-
diff --git a/www/js/client.js b/www/js/client.js
index 3531a99..27cba5d 100644
--- a/www/js/client.js
+++ b/www/js/client.js
@@ -10,8 +10,9 @@ function _removeFile(id) {
if(file_id!==undefined && OSU_FILES[file_id])
{
- global.signal("FILE_REMOVE", {id: file_id, osu: OSU_FILES[file_id]});
+ const osu = OSU_FILES[file_id];
OSU_FILES[file_id] = null;
+ global.signal("FILE_REMOVE", {id: file_id, osu: osu});
}
}
@@ -28,7 +29,7 @@ function _readfile(event) {
osu.LoadString(reader.result).then(result => {
console.log("Read version "+osu.version);
if(osu.okay()) {
- //TODO: Push to read osu files
+ //Push to read osu files
OSU_FILES.push(osu);
global.signal("FILE_ADD", {id: OSU_FILES.length-1, osu: osu});
@@ -45,6 +46,98 @@ function _readfile(event) {
}
}
+var SIDEBAR_VIEWING = null;
+
+function get_aggregate()
+{
+ return OSU_FILES.where(x=> x)[0];
+}
+
+function clear_sidebar() {
+ for(const elem of document.getElementsByClassName("metadata")) {
+ elem.innerText="";
+ removeClass(elem, "meta-dupe");
+ }
+}
+
+function populate_sidebar(osu) {
+
+ const meta = (id, value_name, transform) => {
+ transform = transform || ((value) => value);
+
+ const elem = document.getElementById("meta-"+id);
+ const value = transform(path(osu, value_name));
+ elem.innerText = value;
+
+ if(OSU_FILES.where(x=> x && transform(path(x, value_name)) == value).length != OSU_FILES.where(x=> x).length)
+ {
+ //Is a not-dupe.
+ addClass(elem, "meta-dupe");
+ }
+ else removeClass(elem, "meta-dupe");
+ };
+
+ if(!osu) {
+ if(OSU_FILES.where(x=> x).length<1) clear_sidebar();
+ else {
+ //Is aggregate.
+
+ populate_sidebar(get_aggregate());
+
+ SIDEBAR_VIEWING = null;
+ }
+ } else {
+ //Is single
+
+ //General
+ meta("audio-filename", "data.General.AudioFilename");
+ meta("audio-lead-in", "data.General.AudioLeadIn");
+ meta("preview-time", "data.General.PreviewTime");
+ meta("countdown", "data.General.Countdown");
+ meta("sample-set", "data.General.SampleSet");
+ meta("stacking", "data.General.StackLeniency");
+ meta("mode", "data.General.Mode");
+ meta("letterbox", "data.General.LetterboxInBreaks");
+ meta("widescreen", "data.General.WidescreenStoryboard");
+
+ //Metadata
+ meta("title", "data.Metadata.TitleUnicode");
+ meta("title-ascii", "data.Metadata.Title");
+ meta("artist", "data.Metadata.ArtistUnicode");
+ meta("artist-ascii", "data.Metadata.Artist");
+ meta("mapper", "data.Metadata.Creator");
+ meta("difficulty", "data.Metadata.Version");
+ meta("source", "data.Metadata.Source");
+ meta("tags", "data.Metadata.Tags", tags=> tags.join(", "));
+ meta("beatmap-id", "data.Metadata.BeatmapID");
+ meta("beatmap-set-id", "data.Metadata.BeatmapSetID");
+
+ //Diff
+ meta("diff-hp", "data.Difficulty.HPDrainRate");
+ meta("diff-cs", "data.Difficulty.CircleSize");
+ meta("diff-od", "data.Difficulty.OverallDifficulty");
+ meta("diff-ar", "data.Difficulty.ApproachRate");
+ meta("diff-sv", "data.Difficulty.SliderMultiplier");
+ meta("diff-tr", "data.Difficulty.SliderTickRate");
+
+ //Background
+ meta("background", "spec.Background");
+
+ SIDEBAR_VIEWING = osu;
+ }
+}
+
+function repopulate_sidebar(get_sel) {
+ if(get_sel) {
+ const elem = document.getElementById("meta-selector");
+ if(elem.selectedIndex==0)
+ populate_sidebar();
+ else
+ populate_sidebar(OSU_FILES[elem.value]);
+ }
+ else
+ populate_sidebar(SIDEBAR_VIEWING);
+}
function _onload() {
@@ -69,4 +162,112 @@ function _onload() {
}, false);
}
// --- End collapsers --- //
+
+
+ // --- Selector change -- //
+ const metadataSelector = document.getElementById('meta-selector');
+ metadataSelector.addEventListener("change", function(event) {
+ if(this.selectedIndex==0) {
+ populate_sidebar();
+ } else {
+ const osu = OSU_FILES[this.value];
+ if(osu) {
+ populate_sidebar(osu);
+ }
+ }
+ });
+}
+
+const OSUFILE_DOM_PRE = "O_file";
+
+function setWarn(elem, on, str) {
+ if(!elem) return;
+
+ if(on) {
+ addClass(elem, "warning");
+ elem.setAttribute("title", "Warning"+ (str?": "+str:""));
+ } else if(hasClass(elem,"warning")) {
+ removeClass(elem, "warning");
+ elem.removeAttribute("title");
+ }
}
+
+/// --- HOOKS --- ///
+
+//Create DOM elem for file.
+global.hook("FILE_ADD", function(arg) {
+ const id = arg.id;
+ const osu = arg.osu;
+ //A new file has been added.
+ //test
+
+ var elem = document.createElement("div");
+ elem.setAttribute("id", OSUFILE_DOM_PRE+id);
+ elem.setAttribute("class", "osufile");
+ elem.innerText = osu.Fullname();
+ elem.addEventListener("click", function() {
+ _removeFile(OSUFILE_DOM_PRE+id);
+ });
+ elem.dataset.index = id;
+
+ console.log(OSU_FILES.where(x=> x && osu.equals(x)).length);
+ console.log(OSU_FILES.where(x=> x && x.equals(new OsuFile())||true));
+ console.log(OSU_FILES);
+ if(OSU_FILES.where(x=> x && x.equals(osu)).length > 1) {
+ setWarn(elem, true, "File already added!");
+ }
+
+ document.getElementById("selector").appendChild(elem);
+
+ repopulate_sidebar();
+});
+
+//Add to Metadata Selector
+global.hook("FILE_ADD", function(arg) {
+ const osu = arg.osu;
+ const id = arg.id;
+
+ var elem = document.createElement("option");
+ elem.setAttribute("value", id);
+ elem.setAttribute("id", "meta-sel-"+id);
+ elem.innerText = osu.Shortname();
+
+ var sel = document.getElementById("meta-selector");
+ sel.appendChild(elem);
+
+ if(!SIDEBAR_VIEWING) {
+ repopulate_sidebar();
+ }
+});
+
+//Remove Metadata selector
+global.hook("FILE_REMOVE", function(arg) {
+ const osu = arg.osu;
+ const id = arg.id;
+
+ document.getElementById("meta-sel-"+id).remove();
+
+ repopulate_sidebar(true);
+});
+
+//Recalc dupe warnings
+global.hook("FILE_REMOVE", function(arg) {
+ const osu = arg.osu;
+ const id = arg.id;
+
+ for(let i =OSU_FILES.length-1;i>=0;i--) {
+ if(!OSU_FILES[i]) continue;
+ let setwarn = false;
+ for(let j = 0;j {
var osu = new OsuFile();
osu.errors = [];
+ osu.spec = {};
osu.version = json.version;
osu.data = json.data;
+
+ osu.specialise();
+
+ return osu;
};
OSU.serialise = function() {
@@ -332,3 +356,15 @@ OSU.serialise = function() {
OSU.toString = function() {
return JSON.stringify(this.serialise());
};
+
+OSU.hash = function() {
+ if(this._hash) return this._hash;
+ else
+ return this._hash = forge_sha256(this.toString());
+};
+
+OSU.equals = function(...osu) {
+ const hash = this.hash();
+ console.log(hash);
+ return osu.where(x=> x && x.hash() === hash).length == osu.length;
+};
diff --git a/www/js/util.js b/www/js/util.js
index c1abefd..76cd126 100644
--- a/www/js/util.js
+++ b/www/js/util.js
@@ -13,7 +13,7 @@ function addGlobalStyle(text)
function hasClass(ele, cls)
{
- return !!ele.className.match(new RegExp('(\\s|^)'+cls+'(\\s|$)'));
+ return ele && !!ele.className.match(new RegExp('(\\s|^)'+cls+'(\\s|$)'));
}
function addClass(ele, cls)
@@ -22,9 +22,13 @@ function addClass(ele, cls)
}
Array.prototype.where = function(predicate) {
- output = [];
- for(const elem of this) {
- if(predicate(elem)) output.push(elem);
+ var output = [];
+ const ar = this;
+ for(let i=0;i