Merge pull request #142 from Freso/merge-in-bitmaps-userscripts

Merge in bitmap’s userscripts
This commit is contained in:
Aurélien Mino 2017-03-11 09:14:16 +01:00 committed by GitHub
commit e25284bcd2
6 changed files with 2053 additions and 0 deletions

2
.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
.DS_Store
*.bak

View file

@ -17,6 +17,10 @@
* [Import Metal Archives releases into MusicBrainz](#metalarchives_importer) * [Import Metal Archives releases into MusicBrainz](#metalarchives_importer)
* [Import Qobuz releases to MusicBrainz](#qobuz_importer) * [Import Qobuz releases to MusicBrainz](#qobuz_importer)
* [Import Takealot releases to MusicBrainz](#takealot_importer) * [Import Takealot releases to MusicBrainz](#takealot_importer)
* [MusicBrainz: Batch-add "performance of" relationships](#batch-add-recording-relationships)
* [MusicBrainz: Expand/collapse release groups](#expand-collapse-release-groups)
* [MusicBrainz: Fast cancel edits](#fast-cancel-edits)
* [MusicBrainz: Set recording comments for a release](#set-recording-comments)
* [Musicbrainz DiscIds Detector](#mb_discids_detector) * [Musicbrainz DiscIds Detector](#mb_discids_detector)
* [Musicbrainz UI enhancements](#mb_ui_enhancements) * [Musicbrainz UI enhancements](#mb_ui_enhancements)
@ -139,6 +143,34 @@ Add a button to import Takealot releases to MusicBrainz
[![Source](https://github.com/jerone/UserScripts/blob/master/_resources/Source-button.png)](https://github.com/murdos/musicbrainz-userscripts/blob/master/takealot_importer.user.js) [![Source](https://github.com/jerone/UserScripts/blob/master/_resources/Source-button.png)](https://github.com/murdos/musicbrainz-userscripts/blob/master/takealot_importer.user.js)
[![Install](https://raw.github.com/jerone/UserScripts/master/_resources/Install-button.png)](https://raw.github.com/murdos/musicbrainz-userscripts/master/takealot_importer.user.js) [![Install](https://raw.github.com/jerone/UserScripts/master/_resources/Install-button.png)](https://raw.github.com/murdos/musicbrainz-userscripts/master/takealot_importer.user.js)
## <a name="batch-add-recording-relationships"></a> MusicBrainz: Batch-add "performance of" relationships
Batch link recordings to works from artist Recordings page.
[![Source](https://github.com/jerone/UserScripts/blob/master/_resources/Source-button.png)](https://github.com/murdos/musicbrainz-userscripts/blob/master/batch-add-recording-relationships.user.js)
[![Install](https://raw.github.com/jerone/UserScripts/master/_resources/Install-button.png)](https://raw.githubusercontent.com/murdos/musicbrainz-userscripts/master/batch-add-recording-relationships.user.js)
## <a name="expand-collapse-release-groups"></a> MusicBrainz: Expand/collapse release groups
See what's inside a release group without having to follow its URL. Also adds convenient edit links for it.
[![Source](https://github.com/jerone/UserScripts/blob/master/_resources/Source-button.png)](https://github.com/murdos/musicbrainz-userscripts/blob/master/expand-collapse-release-groups.user.js)
[![Install](https://raw.github.com/jerone/UserScripts/master/_resources/Install-button.png)](https://raw.githubusercontent.com/murdos/musicbrainz-userscripts/master/expand-collapse-release-groups.user.js)
## <a name="fast-cancel-edits"></a> MusicBrainz: Fast cancel edits
Mass cancel open edits with optional edit notes.
[![Source](https://github.com/jerone/UserScripts/blob/master/_resources/Source-button.png)](https://github.com/murdos/musicbrainz-userscripts/blob/master/fast-cancel-edits.user.js)
[![Install](https://raw.github.com/jerone/UserScripts/master/_resources/Install-button.png)](https://raw.githubusercontent.com/murdos/musicbrainz-userscripts/master/fast-cancel-edits.user.js)
## <a name="set-recording-comments"></a> MusicBrainz: Set recording comments for a release
Batch set recording comments from a Release page.
[![Source](https://github.com/jerone/UserScripts/blob/master/_resources/Source-button.png)](https://github.com/murdos/musicbrainz-userscripts/blob/master/set-recording-comments.user.js)
[![Install](https://raw.github.com/jerone/UserScripts/master/_resources/Install-button.png)](https://raw.githubusercontent.com/murdos/musicbrainz-userscripts/master/set-recording-comments.user.js)
## <a name="mb_discids_detector"></a> Musicbrainz DiscIds Detector ## <a name="mb_discids_detector"></a> Musicbrainz DiscIds Detector
Generate MusicBrainz DiscIds from online EAC logs, and check existence in MusicBrainz database. Generate MusicBrainz DiscIds from online EAC logs, and check existence in MusicBrainz database.

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,303 @@
// ==UserScript==
// @name MusicBrainz: Expand/collapse release groups
// @description See what's inside a release group without having to follow its URL. Also adds convenient edit links for it.
// @namespace http://userscripts.org/users/266906
// @author Michael Wiencek <mwtuea@gmail.com>
// @version 6.4
// @license GPL
// @downloadURL https://raw.githubusercontent.com/murdos/musicbrainz-userscripts/master/expand-collapse-release-groups.user.js
// @updateURL https://raw.githubusercontent.com/murdos/musicbrainz-userscripts/master/expand-collapse-release-groups.user.js
// @grant none
// @include *://musicbrainz.org/artist/*
// @include *://musicbrainz.org/label/*
// @include *://musicbrainz.org/release-group/*
// @include *://musicbrainz.org/series/*
// @include *://beta.musicbrainz.org/artist/*
// @include *://beta.musicbrainz.org/label/*
// @include *://beta.musicbrainz.org/release-group/*
// @include *://beta.musicbrainz.org/series/*
// @include *://test.musicbrainz.org/artist/*
// @include *://test.musicbrainz.org/label/*
// @include *://test.musicbrainz.org/release-group/*
// @include *://test.musicbrainz.org/series/*
// @match *://musicbrainz.org/artist/*
// @match *://musicbrainz.org/label/*
// @match *://musicbrainz.org/release-group/*
// @match *://musicbrainz.org/series/*
// @match *://beta.musicbrainz.org/artist/*
// @match *://beta.musicbrainz.org/label/*
// @match *://beta.musicbrainz.org/release-group/*
// @match *://beta.musicbrainz.org/series/*
// @match *://test.musicbrainz.org/artist/*
// @match *://test.musicbrainz.org/label/*
// @match *://test.musicbrainz.org/release-group/*
// @match *://test.musicbrainz.org/series/*
// @exclude *musicbrainz.org/label/*/*
// @exclude *musicbrainz.org/release-group/*/*
// @exclude *musicbrainz.org/series/*/*
// ==/UserScript==
var MBID_REGEX = /[0-9a-z]{8}\-[0-9a-z]{4}\-[0-9a-z]{4}\-[0-9a-z]{4}\-[0-9a-z]{12}/;
var releasesOrReleaseGroups = document.querySelectorAll("#content table.tbl > tbody > tr > td a[href^='/release']");
for (var r = 0; r < releasesOrReleaseGroups.length; r++) {
if (releasesOrReleaseGroups[r].getAttribute("href").match(/\/release-group\//)) {
inject_release_group_button(releasesOrReleaseGroups[r].parentNode);
} else {
inject_release_button(releasesOrReleaseGroups[r].parentNode);
}
}
function inject_release_group_button(parent) {
var mbid = parent.querySelector("a").href.match(MBID_REGEX),
table = document.createElement("table");
table.style.marginTop = "1em";
table.style.marginLeft = "1em";
table.style.paddingLeft = "1em";
var button = create_button(
"/ws/2/release?release-group=" + mbid + "&limit=100&inc=media&fmt=json",
function(toggled) {
if (toggled) parent.appendChild(table); else parent.removeChild(table);
},
function(json) {
parse_release_group(json, mbid, parent, table);
},
function(status) {
table.innerHTML = '<tr><td style="color: #f00;">Error loading release group (HTTP status ' + status + ')</td></tr>';
}
);
parent.insertBefore(button, parent.firstChild);
}
function inject_release_button(parent, _table_parent, _table, _mbid) {
var mbid = _mbid || parent.querySelector("a").href.match(MBID_REGEX),
table = _table || document.createElement("table");
table.style.marginTop = "1em";
table.style.marginLeft = "1em";
table.style.paddingLeft = "1em";
var button = create_button(
"/ws/2/release/" + mbid + "?inc=media+recordings+artist-credits&fmt=json",
function(toggled) {
if (toggled) parent.appendChild(table); else parent.removeChild(table);
},
function(json) {
parse_release(json, table);
},
function(status) {
table.innerHTML = '<tr><td style="color: #f00;">Error loading release (HTTP status ' + status + ')</td></tr>';
}
);
parent.insertBefore(button, parent.childNodes[0]);
}
function create_button(url, dom_callback, success_callback, error_callback) {
var button = document.createElement("span"), toggled = false;
button.innerHTML = "&#9654;";
button.style.cursor = "pointer";
button.style.marginRight = "4px";
button.style.color = "#777";
button.addEventListener("mousedown", function() {
toggled = !toggled;
if (toggled)
button.innerHTML = "&#9660;";
else button.innerHTML = "&#9654;";
dom_callback(toggled);
}, false);
button.addEventListener("mousedown", function() {
var this_event = arguments.callee;
button.removeEventListener("mousedown", this_event, false);
var req = new XMLHttpRequest();
req.onreadystatechange = function() {
if (req.readyState != 4) return;
if (req.status == 200 && req.responseText) {
success_callback(JSON.parse(req.responseText));
} else {
button.addEventListener("mousedown", function() {
button.removeEventListener("mousedown", arguments.callee, false);
button.addEventListener("mousedown", this_event, false);
}, false);
error_callback(req.status);
}
};
req.open("GET", url, true);
req.send(null);
}, false);
return button;
}
function format_time(ms) {
var ts = ms / 1000, s = Math.round(ts % 60);
return (Math.floor(ts / 60) + ":" + (s >= 10 ? s : "0" + s));
}
function parse_release_group(json, mbid, parent, table) {
var releases = json.releases;
table.innerHTML = "";
for (var i = 0; i < releases.length; i++) {
var release = releases[i], media = {}, tracks = [], formats = [];
for (var j = 0; j < release.media.length; j++) {
var medium = release.media[j], format = medium.format, count = medium["track-count"];
if (format)
format in media ? (media[format] += 1) : (media[format] = 1);
tracks.push(count);
}
for (format in media) {
var count = media[format], txt;
if (count > 1)
formats.push(count.toString() + "&#215;" + format);
else formats.push(format);
}
release.tracks = tracks.join(" + ");
release.formats = formats.join(" + ");
}
releases.sort(function(a, b) {
if (a.date < b.date) return -1;
if (a.date > b.date) return 1;
return 0;
});
for (var i = 0; i < releases.length; i++) {(function(release) {
var track_tr = document.createElement("tr"),
track_td = document.createElement("td"),
track_table = document.createElement("table"),
format_td = document.createElement("td"),
tr = document.createElement("tr"),
td = document.createElement("td"),
a = createLink("/release/" + release.id, release.title);
track_td.colSpan = 6;
track_table.style.width = "100%";
track_table.style.marginLeft = "1em";
track_tr.appendChild(track_td);
inject_release_button(td, track_td, track_table, release.id);
td.appendChild(a);
if (release.disambiguation) {
td.appendChild(document.createTextNode(" (" + release.disambiguation + ")"));
}
tr.appendChild(td);
format_td.innerHTML = release.formats;
tr.appendChild(format_td);
var columns = [
release.tracks,
release.date || "",
release.country || "",
release.status || ""
];
for (var i = 0; i < columns.length; i++)
tr.appendChild(createElement("td", columns[i]));
table.appendChild(tr);
table.appendChild(track_tr);
})(releases[i]);}
var bottom_tr = document.createElement("tr"),
bottom_td = document.createElement("td");
bottom_td.colSpan = 6;
bottom_td.style.padding = "1em";
bottom_td.appendChild(createLink("/release-group/" + mbid + "/edit", "edit"));
bottom_td.appendChild(document.createTextNode(" | "));
bottom_td.appendChild(createLink("/release/add?release-group=" + mbid, "add release"));
bottom_td.appendChild(document.createTextNode(" | "));
bottom_td.appendChild(createLink("/release-group/" + mbid + "/edits", "editing history"));
bottom_tr.appendChild(bottom_td);
table.appendChild(bottom_tr);
}
function parse_release(json, table) {
var media = json.media;
table.innerHTML = "";
for (var i = 0; i < media.length; i++) {
var medium = media[i],
format = medium.format ? medium.format + " " + (i + 1) : "Medium " + (i + 1);
table.innerHTML += '<tr class="subh"><td colspan="4">' + format + "</td></tr>";
for (var j = 0; j < medium.tracks.length; j++) {
var track = medium.tracks[j], recording = track.recording,
disambiguation = recording.disambiguation ? " (" + recording.disambiguation + ")" : "",
length = track.length ? format_time(track.length) : "?:??"
artist_credit = track["artist-credit"] || track.recording["artist-credit"],
tr = document.createElement("tr");
tr.appendChild(createElement("td", j + 1));
var title_td = createElement("td", disambiguation);
title_td.insertBefore(createLink("/recording/" + recording.id, recording.title), title_td.firstChild);
tr.appendChild(title_td);
tr.appendChild(createElement("td", length));
var ac_td = document.createElement("td");
ac_td.appendChild(createAC(artist_credit));
tr.appendChild(ac_td);
table.appendChild(tr);
}
}
var bottom_tr = document.createElement("tr"),
bottom_td = document.createElement("td");
bottom_td.colSpan = 4;
bottom_td.style.padding = "1em";
bottom_td.appendChild(createLink("/release/" + json.id + "/edit", "edit"));
bottom_td.appendChild(document.createTextNode(" | "));
bottom_td.appendChild(createLink("/release/" + json.id + "/edit-relationships", "edit relationships"));
bottom_td.appendChild(document.createTextNode(" | "));
bottom_td.appendChild(createLink("/release/" + json.id + "/edits", "editing history"));
bottom_tr.appendChild(bottom_td);
table.appendChild(bottom_tr);
}
function createAC(obj) {
var span = document.createElement("span");
for (var i = 0; i < obj.length; i++) {
var credit = obj[i], artist = credit.artist,
link = createLink("/artist/" + artist.id, credit.name || artist.name);
link.setAttribute("title", artist["sort-name"]);
span.appendChild(link);
if (credit.joinphrase)
span.appendChild(document.createTextNode(credit.joinphrase));
}
return span;
}
function createElement(name, text) {
var element = document.createElement(name);
element.textContent = text;
return element;
}
function createLink(href, text) {
var element = createElement("a", text);
element.href = href;
return element;
}

173
fast-cancel-edits.user.js Normal file
View file

@ -0,0 +1,173 @@
// ==UserScript==
// @name MusicBrainz: Fast cancel edits
// @description Mass cancel open edits with optional edit notes.
// @version 2015.6.7
// @author Michael Wiencek
// @license X11
// @downloadURL https://raw.githubusercontent.com/murdos/musicbrainz-userscripts/master/fast-cancel-edits.user.js
// @updateURL https://raw.githubusercontent.com/murdos/musicbrainz-userscripts/master/fast-cancel-edits.user.js
// @include *://musicbrainz.org/user/*/edits/open*
// @include *://musicbrainz.org/*/*/open_edits*
// @include *://musicbrainz.org/*/*/edits*
// @include *://musicbrainz.org/search/edits*
// @include *://*.musicbrainz.org/user/*/edits/open*
// @include *://*.musicbrainz.org/*/*/open_edits*
// @include *://*.musicbrainz.org/*/*/edits*
// @include *://*.musicbrainz.org/search/edits*
// @include *://*.mbsandbox.org/user/*/edits/open*
// @include *://*.mbsandbox.org/*/*/open_edits*
// @include *://*.mbsandbox.org/*/*/edits*
// @include *://*.mbsandbox.org/search/edits*
// @match *://musicbrainz.org/user/*/edits/open*
// @match *://musicbrainz.org/*/*/open_edits*
// @match *://musicbrainz.org/*/*/edits*
// @match *://musicbrainz.org/search/edits*
// @match *://*.musicbrainz.org/user/*/edits/open*
// @match *://*.musicbrainz.org/*/*/open_edits*
// @match *://*.musicbrainz.org/*/*/edits*
// @match *://*.musicbrainz.org/search/edits*
// @match *://*.mbsandbox.org/user/*/edits/open*
// @match *://*.mbsandbox.org/*/*/open_edits*
// @match *://*.mbsandbox.org/*/*/edits*
// @match *://*.mbsandbox.org/search/edits*
// @grant none
// ==/UserScript==
// ==License==
// Copyright (C) 2014 Michael Wiencek
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
// Except as contained in this notice, the name(s) of the above copyright
// holders shall not be used in advertising or otherwise to promote the sale,
// use or other dealings in this Software without prior written
// authorization.
// ==/License==
//**************************************************************************//
var scr = document.createElement("script");
scr.textContent = "(" + fastCancelScript + ")();";
document.body.appendChild(scr);
function fastCancelScript() {
var totalCancels = 0;
var $status = $("<div></div>")
.css({
"position": "fixed",
"right": "0",
"bottom": "0",
"background": "#FFBA58",
"border-top": "1px #000 solid",
"border-left": "1px #000 solid",
"padding": "0.5em"
})
.appendTo("body")
.hide();
function updateStatus() {
if (totalCancels === 0) {
$status.hide();
} else {
$status.text("Canceling " + totalCancels + " edit" +
(totalCancels > 1 ? "s" : "") + "...").show();
}
}
document.body.addEventListener("click", function (event) {
if (event.target && event.target.tagName && event.target.tagName == "A" && event.target.classList.contains("negative")) {
event.stopPropagation();
event.preventDefault();
totalCancels += 1;
updateStatus();
var $self = $(event.target),
$edit = $self.parents("div.edit-list:eq(0)");
pushRequest(function () {
var editNote = $edit.find("div.add-edit-note textarea").val();
var data = { "confirm.edit_note": editNote };
$.ajax({
type: "POST",
url: $self.attr("href"),
data: data,
error: function (request, status, error) {
$self
.css({
"background": "red",
"color": "yellow",
"cursor": "help"
})
.attr("title", "Error cancelling this edit: “" + error + "”");
$edit
.css({border: "6px solid red"})
.show();
},
complete: function () {
$edit.remove();
totalCancels -= 1;
updateStatus();
}
});
});
$edit.hide();
}
});
$("div#edits > form[action$='/edit/enter_votes']").on("submit", function(event) {
if (totalCancels > 0) {
event.preventDefault();
alert("Please wait, " + (totalCancels > 1 ? totalCancels + " edits are" : "an edit is") + " being cancelled in the background.");
}
});
var pushRequest = (function () {
var queue = [],
last = 0,
active = false,
rate = 2000;
function next() {
if (queue.length === 0) {
active = false;
} else {
queue.shift()();
last = new Date().getTime();
setTimeout(next, rate);
}
}
return function (req) {
queue.push(req);
if (!active) {
active = true;
var now = new Date().getTime();
if (now - last >= rate) {
next();
} else {
var timeout = rate - now + last;
setTimeout(next, timeout);
}
}
};
}());
}

View file

@ -0,0 +1,203 @@
// ==UserScript==
// @name MusicBrainz: Set recording comments for a release
// @description Batch set recording comments from a Release page.
// @version 2016.5.30
// @author Michael Wiencek
// @license X11
// @namespace 790382e7-8714-47a7-bfbd-528d0caa2333
// @downloadURL https://raw.githubusercontent.com/murdos/musicbrainz-userscripts/master/set-recording-comments.user.js
// @updateURL https://raw.githubusercontent.com/murdos/musicbrainz-userscripts/master/set-recording-comments.user.js
// @include *://musicbrainz.org/release/*
// @include *://beta.musicbrainz.org/release/*
// @include *://*.mbsandbox.org/release/*
// @match *://musicbrainz.org/release/*
// @match *://beta.musicbrainz.org/release/*
// @match *://*.mbsandbox.org/release/*
// @exclude *://musicbrainz.org/release/*/*
// @exclude *://beta.musicbrainz.org/release/*/*
// @exclude *://*.mbsandbox.org/release/*/*
// @grant none
// ==/UserScript==
// ==License==
// Copyright (C) 2014 Michael Wiencek
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
// Except as contained in this notice, the name(s) of the above copyright
// holders shall not be used in advertising or otherwise to promote the sale,
// use or other dealings in this Software without prior written
// authorization.
// ==/License==
var scr = document.createElement("script");
scr.textContent = "$(" + setRecordingComments + ");";
document.body.appendChild(scr);
function setRecordingComments() {
var $tracks;
var $inputs = $();
var EDIT_RECORDING_EDIT = 72;
$("head").append($("<style></style>").text("input.recording-comment { background: inherit; border: 1px #999 solid; width: 32em; margin-left: 0.5em; }"));
var delay = setInterval(function () {
$tracks = $(".medium tbody tr[id]");
if ($tracks.length) {
clearInterval(delay);
} else {
return;
}
$tracks.each(function () {
var $td = $(this).children("td:not(.pos):not(.video):not(.rating):not(.treleases)").has("a[href^=\\/recording\\/]"),
node = $td.children("td > .mp, td > .name-variation, td > a[href^=\\/recording\\/]").filter(":first"),
$input = $("<input />").addClass("recording-comment").insertAfter(node);
if (!editing) {
$input.hide();
}
$inputs = $inputs.add($input);
});
var release = location.pathname.match(MBID_REGEX)[0];
$.get("/ws/2/release/" + release + "?inc=recordings&fmt=json", function (data) {
var comments = _.pluck(_.pluck(_.flatten(_.pluck(data.media, "tracks")), "recording"), "disambiguation");
for (var i = 0, len = comments.length; i < len; i++) {
var comment = comments[i];
$inputs.eq(i).val(comment).data("old", comment);
}
});
}, 1000);
if (!location.pathname.match(/^\/release\/[a-f\d]{8}-[a-f\d]{4}-[a-f\d]{4}-[a-f\d]{4}-[a-f\d]{12}$/)) {
return;
}
var MBID_REGEX = /[a-f\d]{8}-[a-f\d]{4}-[a-f\d]{4}-[a-f\d]{4}-[a-f\d]{12}/,
editing = false,
activeRequest = null;
$("body").on("input.rc", ".recording-comment", function () {
$(this).css("border-color", this.value === $(this).data("old") ? "#999" : "red");
});
var $container = $("<div></div>").insertAfter("h2.tracklist");
$("<button>Edit recording comments</button>")
.addClass("styled-button")
.on("click", function () {
editing = !editing;
$("#set-recording-comments").add($inputs).toggle(editing);
$(this).text((editing ? "Hide" : "Edit") + " recording comments");
if (editing) {
$("#all-recording-comments").focus();
}
})
.appendTo($container);
$container.append('\
<table id="set-recording-comments">\
<tr>\
<td><label for="all-recording-comments">Set all visible comments to:</label></td>\
<td><input type="text" id="all-recording-comments" style="width: 32em;"></td>\
</tr>\
<tr>\
<td><label for="recording-comments-edit-note">Edit note:</label></td>\
<td><textarea id="recording-comments-edit-note" style="width: 32em;" rows="5"></textarea></td>\
</tr>\
<tr>\
<td colspan="2">\
<button id="submit-recording-comments" class="styled-button">Submit changes (visible and marked red)</button>\
</td>\
</tr>\
</table>');
$("#set-recording-comments").hide();
$("#all-recording-comments").on("input", function () {
$inputs.filter(":visible").val(this.value).trigger("input.rc");
});
var $submitButton = $("#submit-recording-comments").on("click", function () {
if (activeRequest) {
activeRequest.abort();
activeRequest = null;
$submitButton.text("Submit changes (marked red)");
$inputs.prop("disabled", false).trigger("input.rc");
return;
}
$submitButton.text("Submitting...click to cancel!");
$inputs.prop("disabled", true);
var editData = [], deferred = $.Deferred();
$.each($tracks, function (i, track) {
if ($(track).filter(":visible").length > 0) {
var $input = $inputs.eq(i), comment = $input.val();
if (comment === $input.data("old")) {
$input.prop("disabled", false);
return;
}
deferred
.done(function () {
$input.data("old", comment).trigger("input.rc").prop("disabled", false);
})
.fail(function () {
$input.css("border-color", "red").prop("disabled", false);
});
var link = track.querySelector("td a[href^='/recording/']"),
mbid = link.href.match(MBID_REGEX)[0];
editData.push({edit_type: EDIT_RECORDING_EDIT, to_edit: mbid, comment: comment});
}
});
if (editData.length === 0) {
$inputs.prop("disabled", false);
$submitButton.prop("disabled", false).text("Submit changes (marked red)");
} else {
var editNote = $("#recording-comments-edit-note").val();
activeRequest = $.ajax({
type: 'POST',
url: '/ws/js/edit/create',
dataType: 'json',
data: JSON.stringify({edits: editData, editNote: editNote}),
contentType: 'application/json; charset=utf-8',
})
.always(function () {
$submitButton.prop("disabled", false).text("Submit changes (marked red)");
})
.done(function () {
deferred.resolve();
})
.fail(function () {
deferred.reject();
});
}
});
}