mirror of
https://github.com/murdos/musicbrainz-userscripts
synced 2024-12-13 20:02:27 +00:00
Merge pull request #142 from Freso/merge-in-bitmaps-userscripts
Merge in bitmap’s userscripts
This commit is contained in:
commit
e25284bcd2
6 changed files with 2053 additions and 0 deletions
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
.DS_Store
|
||||
*.bak
|
32
README.md
32
README.md
|
@ -17,6 +17,10 @@
|
|||
* [Import Metal Archives releases into MusicBrainz](#metalarchives_importer)
|
||||
* [Import Qobuz releases to MusicBrainz](#qobuz_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 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)
|
||||
[![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
|
||||
|
||||
Generate MusicBrainz DiscIds from online EAC logs, and check existence in MusicBrainz database.
|
||||
|
|
1340
batch-add-recording-relationships.user.js
Normal file
1340
batch-add-recording-relationships.user.js
Normal file
File diff suppressed because it is too large
Load diff
303
expand-collapse-release-groups.user.js
Normal file
303
expand-collapse-release-groups.user.js
Normal 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 = "▶";
|
||||
button.style.cursor = "pointer";
|
||||
button.style.marginRight = "4px";
|
||||
button.style.color = "#777";
|
||||
|
||||
button.addEventListener("mousedown", function() {
|
||||
toggled = !toggled;
|
||||
if (toggled)
|
||||
button.innerHTML = "▼";
|
||||
else button.innerHTML = "▶";
|
||||
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() + "×" + 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
173
fast-cancel-edits.user.js
Normal 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);
|
||||
}
|
||||
}
|
||||
};
|
||||
}());
|
||||
}
|
203
set-recording-comments.user.js
Normal file
203
set-recording-comments.user.js
Normal 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();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
Loading…
Reference in a new issue