NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript== // @name mb. FUNKEY ILLUSTRATED RECORDS // @version 2024.9.27 // @description musicbrainz.org: CAA front cover art archive pictures/images (release groups and releases) Big illustrated discography and/or inline everywhere possible without cluttering the pages // @namespace https://github.com/jesus2099/konami-command // @supportURL https://github.com/jesus2099/konami-command/labels/mb_FUNKEY-ILLUSTRATED-RECORDS // @downloadURL https://github.com/jesus2099/konami-command/raw/master/mb_FUNKEY-ILLUSTRATED-RECORDS.user.js // @author jesus2099 // @licence CC-BY-NC-SA-4.0; https://creativecommons.org/licenses/by-nc-sa/4.0/ // @licence GPL-3.0-or-later; http://www.gnu.org/licenses/gpl-3.0.txt // @since 2012-12-19; https://web.archive.org/web/20131103163409/userscripts.org/scripts/show/154481 / https://web.archive.org/web/20141011084022/userscripts-mirror.org/scripts/show/154481 // @icon data:image/gif;base64,R0lGODlhEAAQAKEDAP+/3/9/vwAAAP///yH/C05FVFNDQVBFMi4wAwEAAAAh/glqZXN1czIwOTkAIfkEAQACAwAsAAAAABAAEAAAAkCcL5nHlgFiWE3AiMFkNnvBed42CCJgmlsnplhyonIEZ8ElQY8U66X+oZF2ogkIYcFpKI6b4uls3pyKqfGJzRYAACH5BAEIAAMALAgABQAFAAMAAAIFhI8ioAUAIfkEAQgAAwAsCAAGAAUAAgAAAgSEDHgFADs= // @require https://github.com/jesus2099/konami-command/raw/de88f870c0e6c633e02f32695e32c4f50329fc3e/lib/SUPER.js?version=2022.3.24.224 // @grant GM_registerMenuCommand // @grant GM_getValue // @grant GM_setValue // @include /^https?:\/\/(\w+\.)?musicbrainz\.org\/[^/]+\/[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}\/(open_)?edits/ // @include /^https?:\/\/(\w+\.)?musicbrainz\.org\/(artist|cdtoc|collection|label|recording|series|tag)\// // @include /^https?:\/\/(\w+\.)?musicbrainz\.org\/edit\/\d+/ // @include /^https?:\/\/(\w+\.)?musicbrainz\.org\/release([-_]group)?\/.+$/ // @include /^https?:\/\/(\w+\.)?musicbrainz\.org\/release\/merge(\?.*)?$/ // @include /^https?:\/\/(\w+\.)?musicbrainz\.org\/search\/edits\?.+/ // @include /^https?:\/\/(\w+\.)?musicbrainz\.org\/search\?.*type=(annotation|release(_group)?).*$/ // @include /^https?:\/\/(\w+\.)?musicbrainz\.org\/user\/[^/]+\/edits/ // @include /^https?:\/\/(\w+\.)?musicbrainz\.org\/user\/[^/]+\/(ratings|tag\/)/ // @exclude *.org/*/*/edit // @exclude *.org/*/*/edit?* // @exclude *.org/cdtoc/remove* // @run-at document-idle // ==/UserScript== "use strict"; let userjs = "jesus2099userjs154481"; // linked in mb. MERGE HELPOR 2, mb_HIDE-DIGITAL-RELEASES and mb_PRINT-ALL-PAGES let types = ["release-group", "release"]; let GUID = "[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}"; var colour = "yellow"; var pics_settings = { big: GM_getValue("bigpics", true), small: GM_getValue("smallpics", true), setMenu: function(id) { GM_registerMenuCommand((pics_settings[id] ? "☑" : "☐") + " " + id.toUpperCase() + " PICS", function(event) { pics_settings[id] = !pics_settings[id]; GM_setValue(id + "pics", pics_settings[id]); pics_settings.setMenu(id); }, {autoClose: false, id: id}); }, }; pics_settings.setMenu("big"); pics_settings.setMenu("small"); // Exclusions if (pics_settings.big) { if (location.pathname.match(/^\/artist\/[^/]+\/(recordings|relationship)|^\/recording/)) { pics_settings.big = false; } } if (pics_settings.small) { if (location.pathname.match(/^\/search\/edits|(open_)?edits$/)) { pics_settings.small = false; } } // Hide MBS-11059 release group CAA icon, once my linked and thumbnailed CAA icon is loading var css = document.createElement("style"); css.setAttribute("type", "text/css"); document.head.appendChild(css); css = css.sheet; css.insertRule("table.tbl > tbody > tr > td > a[href$='/cover-art'][ref^='/release-group/'] ~ span.caa-icon { display: none; }", 0); // Add CAA icons in secondary release lists if (location.pathname.match(/^\/artist\/[^/]+\/relationships$|^\/cdtoc\/|^\/recording\/|^\/edit\/|edits$/)) { var releases = document.querySelectorAll("tbody > tr > td a[href^='/release/']"); for (var r = 0; r < releases.length; r++) { var release = include_span_mp(releases[r]); release.parentNode.insertBefore(createTag("a", {a: {href: releases[r].getAttribute("href") + "/cover-art"}}, createTag("span", {a: {class: "caa-icon " + userjs}})), release); } } // Add thumbnail in MBS release CAA icons var caaIcons = document.querySelectorAll("a[href$='/cover-art'] > span.caa-icon"); if (caaIcons.length > 0) { // TODO: commenting this out might bring regressions: pics_settings.small = false; for (var ci = 0; ci < caaIcons.length; ci++) { loadCaaIcon(caaIcons[ci]); } } // React hydrate imposes delay var reactHydratePage = location.pathname.match(/^\/release\//); setTimeout(function() { for (var t = 0; t < types.length; t++) { // TODO: rglink smallpic is often broken by React, though var as = document.querySelectorAll("tr > td a[href^='/" + types[t] + "/']:not([href$='/cover-art']), div#page.fullwidth ul:not(.tabs) > li a[href^='/" + types[t] + "/']:not([href$='/cover-art']), tr > td > span[class^='rglink'] + a[href^='/" + types[t] + "/']:not([href$='/cover-art'])"); var istable, istablechecked, artistcol; for (var a = 0; a < as.length; a++) { var imgurl = as[a].getAttribute("href").match(new RegExp("^/" + types[t] + "/(" + GUID + ")$")); if (imgurl) { imgurl = "//coverartarchive.org/" + types[t] + "/" + imgurl[1] + "/front"; if (!istablechecked) { istable = getParent(as[0], "table"); if (istable) { artistcol = document.evaluate(".//thead/tr/th[contains(./text(), 'Artist') or contains(./a/text(), 'Artist')]", istable, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null).snapshotLength == 1; } istablechecked = true; } // SMALL PICS // ---------- if (pics_settings.small) { if (types[t] == "release-group") { var CAALoader = new XMLHttpRequest(); CAALoader.addEventListener("load", function(event) { if (this.status == 200) { var RGCAA = JSON.parse(this.responseText); if (RGCAA.images.length > 0) { var releaseGroupOrSpanMp = include_span_mp(this.releaseGroup); // insert small pic after ratings var insertPoint = releaseGroupOrSpanMp; if ( releaseGroupOrSpanMp.previousSibling // is not first element && releaseGroupOrSpanMp.previousSibling.matches // is not text node && releaseGroupOrSpanMp.previousSibling.matches("span.caa-icon") // is CAA icon ) { // insert before CAA icon to enable its CSS hiding insertPoint = releaseGroupOrSpanMp.previousSibling; } loadCaaIcon(releaseGroupOrSpanMp.parentNode.insertBefore( createTag("a", {a: { href: RGCAA.release + "/cover-art", ref: this.releaseGroup.getAttribute("href"), title: RGCAA.images.length + " image" + (RGCAA.images.length != 1 ? "s" : "") + " found in this release" }}, createTag("span", {a: {class: "caa-icon " + userjs}}) ), insertPoint).firstChild ); } } else { console.log("Error " + this.status + " (" + this.statusText + ") for " + this.releaseGroup); } }); CAALoader.addEventListener("error", function(event) { console.log("Error " + this.status + " (" + this.statusText + ") for " + this.releaseGroup); }); CAALoader.releaseGroup = as[a]; CAALoader.open("GET", "https://coverartarchive.org" + as[a].getAttribute("href").match(new RegExp("/release-group/" + GUID)), true); CAALoader.send(null); } } // TODO: I think there is no longer any UL LI, now only TABLE TR, I guess but not sure... var box = getParent(as[a], "table") || getParent(as[a], "ul"); box.addEventListener("mouseover", updateBig); box.addEventListener("mouseout", updateBig); // BIG PICS // -------- if (pics_settings.big && (box = box.previousSibling && box.previousSibling.tagName == "DIV" && box.previousSibling.classList.contains(userjs + "bigbox") ? box.previousSibling : box.parentNode.insertBefore(createTag("div", {a: {class: userjs + "bigbox"}}), box))) { var artisttd = artistcol && getSibling(getParent(as[a], "td"), "td"); // textContent is faster but shows <script> content. artisttd contains React? <script> when pending AC edits. https://kellegous.com/j/2013/02/27/innertext-vs-textcontent/ box.appendChild(createTag("a", {a: {href: as[a].getAttribute("href"), title: as[a].textContent + (artisttd ? "\n" + artisttd.innerText.trim() : "")}, s: {display: "inline-block", height: "100%", margin: "8px 8px 4px 4px"}}, [ "⌛", createTag("img", { a: {src: imgurl + "-250", alt: as[a].textContent}, s: {verticalAlign: "middle", display: "none", maxHeight: "125px", boxShadow: "1px 1px 4px black"}, e: { load: function(event) { removeNode(this.parentNode.firstChild); this.style.setProperty("display", "inline"); }, error: function(event) { removeNode(this.parentNode); }, mouseover: updateA, mouseout: updateA } }) ])); } } } } }, reactHydratePage ? 1000 : 10); function updateA(event) { var ah = this.parentNode.getAttribute("href"); var rels = document.querySelectorAll("tr > td a[href='" + ah + "'], div#page.fullwidth ul > li a[href='" + ah + "']"); for (var r = 0; r < rels.length; r++) { if (event.type == "mouseover") { rels[r].style.setProperty("background-color", colour); } else { rels[r].style.removeProperty("background-color"); } } } function updateBig(event) { var tr = getParent(event.target, "tr") || getParent(event.target, "li"); if (tr) { var img = tr.querySelector("a[href^='/release']:not([href$='/cover-art'])"); if (img) { img = document.querySelector("div." + userjs + "bigbox > a > img[src='//coverartarchive.org" + img.getAttribute("href") + "/front-250']"); if (img) { if (event.type == "mouseover") { img.parentNode.style.setProperty("border", "4px solid " + colour); img.parentNode.style.setProperty("margin", img.parentNode.style.getPropertyValue("margin").replace(/\.\d*/g, "").replace(/-?\d+/g, function(number) { return +number - 4; })); } else { img.parentNode.style.removeProperty("border"); img.parentNode.style.setProperty("margin", img.parentNode.style.getPropertyValue("margin").replace(/\.\d*/g, "").replace(/-?\d+/g, function(number) { return +number + 4; })); } } } } } function loadCaaIcon(caaIcon) { // Adding thumbnails to release CAA icons var imgurl = caaIcon.parentNode.getAttribute("ref") || caaIcon.parentNode.getAttribute("href").replace(/\/cover-art/, ""); imgurl = "//coverartarchive.org" + imgurl + "/front-250"; createTag("img", { a: { src: imgurl }, e: { load: function (event) { caaIcon.style.setProperty("background-size", "contain"); caaIcon.style.setProperty("background-image", "url(" + this.getAttribute("src") + ")"); }, error: function (event) { if (caaIcon.classList.contains(userjs)) { removeNode(caaIcon.parentNode); } } } }); } function include_span_mp(element) { return element.parentNode.matches("span.mp") ? element.parentNode : element; }