NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript== // @name ymail-basic. DIRECT LINKS TO MUSICBRAINZ // @version 2022.9.26.1 // @description BASIC Yahoo! Mail only (/neo/b/). Adds links to MusicBrainz edits directly in mail.yahoo.com folders view (including "no votes" and "subscription" emails). No need to open all those e-mails any more. Only one link per edit ID, duplicate ID are coloured and e-mail(s) marked for deletion. Once clicked, the link is faded, to keep trace of already browsed edits. Limitations : only Opera(maybe) and y!mail BASIC I guess. // @namespace https://github.com/jesus2099/konami-command // @supportURL https://github.com/jesus2099/konami-command/labels/ymail-basic_DIRECT-LINKS-TO-MUSICBRAINZ // @downloadURL https://github.com/jesus2099/konami-command/raw/master/ymail-basic_DIRECT-LINKS-TO-MUSICBRAINZ.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 2010-06-28; https://web.archive.org/web/20131103163402/userscripts.org/scripts/show/80308 / https://web.archive.org/web/20141011084013/userscripts-mirror.org/scripts/show/80308 // @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 none // @include /^https?://mail.yahoo.com/b/.*/ // @run-at document-end // ==/UserScript== "use strict"; /* - --- - --- - --- - START OF CONFIGURATION - --- - --- - --- - */ var colour = "yellow"; var colourclicked = "pink"; var colourdupe = "mistyrose"; var colourno = "yellow"; var colournobg = "red"; var colourloading = "gold"; var loadingtxt = "⌛ loading…"; var edittypes = {deleted: "×", merged: "+"}; var markReadEditsForDeletion = true; /* - --- - --- - --- - END OF CONFIGURATION - --- - --- - --- - */ var userjs = "jesus2099userjs80308"; var edits = []; var emailSubjects = document.querySelectorAll("table#messageListContainer > tbody td[data-test-id='subject'] > a"); if (emailSubjects) { for (var i = 0; i < emailSubjects.length; i++) { var emailSubject = emailSubjects[i]; var emailtxt = emailSubject.getAttribute("title"); var emailHref = self.location.protocol + "//" + self.location.host + emailSubject.getAttribute("href"); var editid = emailtxt.match(/^(?:Note added to|Someone has voted against)( your)? edit #([0-9]+)$/); var jiraIdTitle = emailtxt.match(/^\[MeB JIRA\] \(([A-Z][A-Z\d]*-\d+)\) (.+)$/); emailSubject.parentNode.style.setProperty("line-height", "13px"); var emailSender = getParent(emailSubject, "tr").querySelector("td[data-test-id='sender'] > a"); if (jiraIdTitle) { // An email about a JIRA ticket var jiraURL = "//tickets.musicbrainz.org/browse/" + jiraIdTitle[1]; editlink(emailSubject, jiraURL, edits[jiraURL], jiraIdTitle[1]); if (!edits[jiraURL]) { edits[jiraURL] = emailSubject; } emailSubject.replaceChild(document.createTextNode(jiraIdTitle[2]), emailSubject.lastChild); } else if (editid) { // An email about an edit (edit note or no vote) editid = editid[editid.length - 1]; emailSubject.replaceChild(document.createTextNode(emailtxt.substring(0, emailtxt.length - editid.length - 2)), emailSubject.firstChild); emailSender.setAttribute("href", "//musicbrainz.org/user/" + encodeURIComponent(emailSender.textContent.trim())); emailSender.setAttribute("target", "_blank"); emailSender.style.setProperty("background-color", colour); editlink(emailSubject, editid, edits[editid]); if (!edits[editid]) { edits[editid] = emailSubject; } let xhr = new XMLHttpRequest(); xhr.emailSubject = emailSubject; xhr.emailRow = getParent(emailSubject, "tr"); xhr.addEventListener("load", function(event) { if (this.status > 199 && this.status < 400) { this.emailRow.classList.remove("u_b"); // mark as read var editNote = this.responseText.match(/'[^']+' has added the following note to(?: your)? edit #\d+:<BR><\/div><div dir='ltr'>-{72}<BR><\/div><div dir='ltr'>(.+)<BR><\/div><div dir='ltr'>-{72}<BR><\/div><div dir='ltr'>If you would like to reply to this note, please add your note at:<BR>/); if (editNote) { editNote = editNote[1]; var div = document.createElement("div"); div.innerHTML = editNote.replace(/<a/g, '<a style="color: blue; text-decoration: underline;"'); div.style.setProperty("background-color", "#eee"); div.style.setProperty("padding", "4px"); this.emailSubject.parentNode.insertBefore(div, this.emailSubject); } } }); xhr.open("get", emailHref, true); xhr.send(null); } else if (emailSubject.getAttribute("title").match(/^Edits for your subscriptions$/)) { // A subscription email getParent(emailSubject, "tr").style.setProperty("background-color", colourloading); emailSubject.insertBefore(loading(), emailSubject.firstChild); let xhr = new XMLHttpRequest(); xhr.emailSubject = emailSubject; xhr.emailRow = getParent(emailSubject, "tr"); xhr.addEventListener("load", function(event) { if (this.status > 199 && this.status < 400) { this.emailRow.classList.remove("u_b"); // mark as read this.emailRow.style.setProperty("background-color", ""); var res = this.responseText; var deletedOrMergedEntities = res.match(/(deleted|merged) by edit #([0-9]+)/g); this.emailSubject.removeChild(this.emailSubject.firstChild); if (deletedOrMergedEntities) { for (var i = 0; i < deletedOrMergedEntities.length; i++) { var modid = deletedOrMergedEntities[i].match(/by edit #([0-9]+)/)[1]; let type = deletedOrMergedEntities[i].match(/(deleted|merged) by edit #([0-9]+)/)[1]; editlink(this.emailSubject, modid, edits[modid], edittypes[type] + modid).setAttribute("title", type); if (!edits[modid]) { edits[modid] = this.emailSubject; } } } else { this.emailSubject.style.setProperty("background-color", colourclicked); } var entitiesEditorsExtractorz = "<BR>(?:</div><div dir='ltr'>)?([^>]+) \\((\\d+ open), (\\d+ applied)\\)<BR>(?:</div><div dir='ltr'>)?(?:Open edits: )?<a href=\"(https?://musicbrainz\\.org/(?:artist|collection|label|series|user)/[^/]+/edits)(?:/open)?\" target=_blank"; var alledits = res.match(new RegExp(entitiesEditorsExtractorz, "g")); for (var ee = 0; ee < alledits.length; ee++) { var allparts = alledits[ee].match(new RegExp(entitiesEditorsExtractorz)); var lnk = editlink(this.emailSubject, allparts[4], false, allparts[3]); var a = document.createElement("a"); a.setAttribute("href", allparts[4].replace(/\/edits$/, "")); a.setAttribute("target", "_blank"); a.style.setProperty("background-color", colourclicked); var im = a.appendChild(document.createElement("img")); var openedits = "/open_edits"; let type = allparts[4].match(/artist|collection|label|series/); if (type) { im.setAttribute("src", "//musicbrainz.org/static/images/entity/%type%.svg".replace(/%type%/, type).replace(/collection/, "release_group")); im.setAttribute("height", "16px"); im.setAttribute("width", "16px"); } else if (allparts[4].match(/user/)) { im.setAttribute("src", "//gravatar.com/avatar/placeholder?d=mm&s=12"); openedits = "/edits/open"; } im.style.setProperty("margin-right", "4px"); im.style.setProperty("vertical-align", "-.3em"); a.appendChild(document.createTextNode(allparts[1])); lnk.parentNode.insertBefore(a, lnk); a = a.cloneNode(true); a.removeChild(a.firstChild); a.replaceChild(document.createTextNode(allparts[2]), a.firstChild); a.setAttribute("href", a.getAttribute("href") + openedits); lnk.parentNode.insertBefore(document.createTextNode(" ("), lnk); lnk.parentNode.insertBefore(a, lnk); lnk.parentNode.insertBefore(document.createTextNode(", "), lnk); lnk.parentNode.insertBefore(document.createTextNode(")"), lnk.nextSibling); } } }); xhr.open("get", emailHref, true); xhr.send(null); } if (emailSubject.getAttribute("title").match(/^Someone has voted against your edit(?: #[0-9]+)?$/)) { // An own no‐voted edit emailSender.style.setProperty("background-color", colourloading); emailSender.replaceChild(loading(), emailSender.firstChild); let xhr = new XMLHttpRequest(); xhr.emailSubject = emailSubject; xhr.emailSender = emailSender; xhr.emailRow = getParent(emailSubject, "tr"); xhr.addEventListener("load", function(event) { if (this.status > 199 && this.status < 400) { this.emailRow.classList.remove("u_b"); // mark as read var nono = this.responseText.match(/'([^']+)' has voted against your edit #([0-9]+)/); if (nono) { this.emailSender.replaceChild(document.createTextNode(nono[1]), this.emailSender.firstChild); // from: xxx this.emailSender.style.setProperty("background-color", colournobg); this.emailSender.style.setProperty("color", colourno); this.emailSender.setAttribute("href", this.emailSender.getAttribute("href").replace(/[^/]+$/, encodeURIComponent(nono[1]))); } else { this.emailSender.replaceChild(document.createTextNode("(._.?)"), this.emailSender.firstChild); } } }); xhr.open("get", emailHref, true); xhr.send(null); } } } function editlink(emailSubject, urlOrEditId, dupe, txt) { var fragment = document.createDocumentFragment(); var a = document.createElement("a"); a.addEventListener("click", function(event) { var sameEditLinks = document.querySelectorAll("table#messageListContainer > tbody a." + userjs + "new[href$='" + this.getAttribute("href").replace(/^(https?:)?\/\/(beta\.)?/g, "") + "']"); // in case of on the fly change by mb-PREFERRED-MBS for (var e = 0; e < sameEditLinks.length; e++) { sameEditLinks[e].className = sameEditLinks[e].classList.replace(userjs + "new", userjs + "read"); sameEditLinks[e].style.setProperty("background-color", colourclicked); sameEditLinks[e].style.setProperty("text-decoration", "line-through"); if (markReadEditsForDeletion) { var cb = getParent(sameEditLinks[e], "tr"); if ( cb && cb.getElementsByClassName(userjs + "new").length == 0 && (cb = cb.querySelector("input[name='mids[]'][type='checkbox']")) ) { cb.checked = true; } } } }, true); a.setAttribute("href", urlOrEditId.match(/^\d+$/) ? "//musicbrainz.org/edit/" + urlOrEditId : urlOrEditId); a.classList.add(userjs + "new"); a.setAttribute("target", "_blank"); a.style.setProperty("background-color", dupe ? colourdupe : colour); if (dupe) { edits[urlOrEditId].style.setProperty("background-color", colourdupe); emailSubject.style.setProperty("background-color", colourdupe); } a.appendChild(document.createTextNode(txt ? txt : "Edit #" + urlOrEditId)); fragment.appendChild(a); fragment.appendChild(document.createElement("br")); emailSubject.parentNode.insertBefore(fragment, emailSubject); return a; } function loading() { var frag = document.createDocumentFragment(); var span = document.createElement("span"); span.style.setProperty("background-color", colour); span.appendChild(document.createTextNode(loadingtxt)); frag.appendChild(span); frag.appendChild(document.createTextNode(" ")); return frag; }