From b94bb20cc1cea5c7cb922919454492e7c426c746 Mon Sep 17 00:00:00 2001 From: GitHub Actions <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 17 Jun 2022 18:07:23 +0000 Subject: [PATCH] =?UTF-8?q?=F0=9F=A4=96=20mb=5Fqol=5Fseed=5Frecording=5Fdi?= =?UTF-8?q?sambiguation=202022.6.17?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit refactor: more TypeScript migration (#499) --- ...seed_recording_disambiguation.changelog.md | 1 + mb_qol_seed_recording_disambiguation.meta.js | 17 + ...eed_recording_disambiguation.metadata.json | 1 + mb_qol_seed_recording_disambiguation.user.js | 299 ++++++++++++++++++ 4 files changed, 318 insertions(+) create mode 100644 mb_qol_seed_recording_disambiguation.changelog.md create mode 100644 mb_qol_seed_recording_disambiguation.meta.js create mode 100644 mb_qol_seed_recording_disambiguation.metadata.json create mode 100644 mb_qol_seed_recording_disambiguation.user.js diff --git a/mb_qol_seed_recording_disambiguation.changelog.md b/mb_qol_seed_recording_disambiguation.changelog.md new file mode 100644 index 000000000..b5dd497f2 --- /dev/null +++ b/mb_qol_seed_recording_disambiguation.changelog.md @@ -0,0 +1 @@ +- **2022.6.17**: Internal changes: more TypeScript migration ([#499](https://github.com/ROpdebee/mb-userscripts/pull/499)) diff --git a/mb_qol_seed_recording_disambiguation.meta.js b/mb_qol_seed_recording_disambiguation.meta.js new file mode 100644 index 000000000..f91fa420e --- /dev/null +++ b/mb_qol_seed_recording_disambiguation.meta.js @@ -0,0 +1,17 @@ +// ==UserScript== +// @name MB: QoL: Seed the batch recording comments script +// @description Seed the recording comments for the batch recording comments userscripts with live and DJ-mix data. +// @version 2022.6.17 +// @author ROpdebee +// @license MIT; https://opensource.org/licenses/MIT +// @namespace https://github.com/ROpdebee/mb-userscripts +// @homepageURL https://github.com/ROpdebee/mb-userscripts +// @supportURL https://github.com/ROpdebee/mb-userscripts/issues +// @downloadURL https://raw.github.com/ROpdebee/mb-userscripts/dist/mb_qol_seed_recording_disambiguation.user.js +// @updateURL https://raw.github.com/ROpdebee/mb-userscripts/dist/mb_qol_seed_recording_disambiguation.meta.js +// @match *://*.musicbrainz.org/release/* +// @exclude *://*.musicbrainz.org/release/add +// @exclude *://*.musicbrainz.org/release/*/edit* +// @run-at document-end +// @grant none +// ==/UserScript== \ No newline at end of file diff --git a/mb_qol_seed_recording_disambiguation.metadata.json b/mb_qol_seed_recording_disambiguation.metadata.json new file mode 100644 index 000000000..2eadd9df4 --- /dev/null +++ b/mb_qol_seed_recording_disambiguation.metadata.json @@ -0,0 +1 @@ +{"version":"2022.6.17"} \ No newline at end of file diff --git a/mb_qol_seed_recording_disambiguation.user.js b/mb_qol_seed_recording_disambiguation.user.js new file mode 100644 index 000000000..a5368090e --- /dev/null +++ b/mb_qol_seed_recording_disambiguation.user.js @@ -0,0 +1,299 @@ +// ==UserScript== +// @name MB: QoL: Seed the batch recording comments script +// @description Seed the recording comments for the batch recording comments userscripts with live and DJ-mix data. +// @version 2022.6.17 +// @author ROpdebee +// @license MIT; https://opensource.org/licenses/MIT +// @namespace https://github.com/ROpdebee/mb-userscripts +// @homepageURL https://github.com/ROpdebee/mb-userscripts +// @supportURL https://github.com/ROpdebee/mb-userscripts/issues +// @downloadURL https://raw.github.com/ROpdebee/mb-userscripts/dist/mb_qol_seed_recording_disambiguation.user.js +// @updateURL https://raw.github.com/ROpdebee/mb-userscripts/dist/mb_qol_seed_recording_disambiguation.meta.js +// @match *://*.musicbrainz.org/release/* +// @exclude *://*.musicbrainz.org/release/add +// @exclude *://*.musicbrainz.org/release/*/edit* +// @run-at document-end +// @grant none +// ==/UserScript== + +// For original source code, see https://github.com/ROpdebee/mb-userscripts/tree/main/src/mb_qol_seed_recording_disambiguation +(function () { + 'use strict'; + + /* minified: babel helpers, nativejsx, babel-plugin-transform-async-to-promises */ + var appendChildren=function(t,e){(e=Array.isArray(e)?e:[e]).forEach((function(e){e instanceof HTMLElement?t.appendChild(e):(e||"string"==typeof e)&&t.appendChild(document.createTextNode(e.toString()));}));},setStyles=function(t,e){for(const r in e)t.style[r]=e[r];};function ownKeys(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter((function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}))),r.push.apply(r,n);}return r}function _objectSpread2(t){for(var e=1;et.length)&&(e=t.length);for(var r=0,n=new Array(e);r!(null==e)))}let LogLevel;!function(e){e[e.DEBUG=0]="DEBUG",e[e.LOG=1]="LOG",e[e.INFO=2]="INFO",e[e.SUCCESS=3]="SUCCESS",e[e.WARNING=4]="WARNING",e[e.ERROR=5]="ERROR";}(LogLevel||(LogLevel={}));const HANDLER_NAMES={[LogLevel.DEBUG]:"onDebug",[LogLevel.LOG]:"onLog",[LogLevel.INFO]:"onInfo",[LogLevel.SUCCESS]:"onSuccess",[LogLevel.WARNING]:"onWarn",[LogLevel.ERROR]:"onError"},DEFAULT_OPTIONS={logLevel:LogLevel.INFO,sinks:[]};class Logger{constructor(e){_defineProperty(this,"_configuration",void 0),this._configuration=_objectSpread2(_objectSpread2({},DEFAULT_OPTIONS),e);}fireHandlers(e,t,n){e{const o=r[HANDLER_NAMES[e]];o&&(n?o.call(r,t,n):o.call(r,t));}));}debug(e){this.fireHandlers(LogLevel.DEBUG,e);}log(e){this.fireHandlers(LogLevel.LOG,e);}info(e){this.fireHandlers(LogLevel.INFO,e);}success(e){this.fireHandlers(LogLevel.SUCCESS,e);}warn(e,t){this.fireHandlers(LogLevel.WARNING,e,t);}error(e,t){this.fireHandlers(LogLevel.ERROR,e,t);}configure(e){Object.assign(this._configuration,e);}get configuration(){return this._configuration}addSink(e){this._configuration.sinks.push(e);}}const LOGGER=new Logger;function logFailure(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"An error occurred";e.catch((e=>{LOGGER.error(t,e);}));}class AssertionError extends Error{}function assert(e,t){if(!e)throw new AssertionError(null!=t?t:"Assertion failed")}function assertNonNull(e,t){assert(null!==e,null!=t?t:"Assertion failed: Expected value to be non-null");}function qs(e,t){const n=qsMaybe(e,t);return assertNonNull(n,"Could not find required element"),n}function qsMaybe(e,t){return (null!=t?t:document).querySelector(e)}function onDocumentLoaded(e){"loading"!==document.readyState?e():document.addEventListener("DOMContentLoaded",e);}var USERSCRIPT_ID="mb_qol_seed_recording_disambiguation";function insertStylesheet(e,t){if(void 0===t&&(t="ROpdebee_".concat(USERSCRIPT_ID,"_css")),null!==qsMaybe("style#".concat(t)))return;const n=function(){var n=document.createElement("style");return n.setAttribute("id",t),appendChildren(n,e),n}.call(this);document.head.insertAdjacentElement("beforeend",n);}function parseVersion(e){return e.split(".").map((e=>parseInt(e)))}function versionLessThan(e,t){let n=0;for(;nt[n])return !1;n++;}return e.lengthversionLessThan(n,parseVersion(e.versionAdded))));0!==r.length&&showFeatureNotification(t.name,t.version,r.map((e=>e.description)));}function showFeatureNotification(e,t,n){insertStylesheet(css_248z,"ROpdebee_Update_Banner");const r=function(){var o=document.createElement("div");o.setAttribute("class","banner warning-header");var i=document.createElement("p");o.appendChild(i),appendChildren(i,"".concat(e," was updated to v").concat(t,"! "));var s=document.createElement("a");s.setAttribute("href",CHANGELOG_URL),i.appendChild(s);var a=document.createTextNode("See full changelog here");s.appendChild(a),appendChildren(i,". New features since last update:");var l=document.createElement("div");l.setAttribute("class","ROpdebee_feature_list"),o.appendChild(l);var c=document.createElement("ul");l.appendChild(c),appendChildren(c,n.map((e=>function(){var t=document.createElement("li");return appendChildren(t,e),t}.call(this))));var d=document.createElement("button");return d.setAttribute("class","dismiss-banner remove-item icon"),d.setAttribute("data-banner-name","alert"),d.setAttribute("type","button"),d.addEventListener("click",(()=>{r.remove(),localStorage.setItem(LAST_DISPLAYED_KEY,GM.info.script.version);})),o.appendChild(d),o}.call(this);qs("#page").insertAdjacentElement("beforebegin",r);} + + if (document.location.hostname === 'musicbrainz.org' || document.location.hostname.endsWith('.musicbrainz.org')) { + onDocumentLoaded(maybeDisplayNewFeatures); + } + + const seedLive = _async(function () { + return _await(getRecordingRels(document.location.pathname.split('/')[2]), function (relInfo) { + const recComments = relInfo.mediums.flatMap(medium => medium.tracks.map(track => createTrackLiveComment(track, medium, relInfo))); + const uniqueComments = [...new Set(recComments.map(_ref => { + let _ref2 = _slicedToArray(_ref, 2), comment = _ref2[1]; + return comment; + }))]; + if (uniqueComments.length === 1) { + fillInput(qs('input#all-recording-comments'), uniqueComments[0]); + } else { + recComments.forEach(_ref3 => { + let _ref4 = _slicedToArray(_ref3, 2), trackGid = _ref4[0], comment = _ref4[1]; + fillInput(qs('tr#'.concat(trackGid, ' input.recording-comment')), comment); + }); + } + fillInput(qs('textarea#recording-comments-edit-note'), ''.concat(GMinfo.script.name, ' v').concat(GMinfo.script.version, ': Seed live comments')); + }); + }); + const getRecordingRels = _async(function (relGid) { + return _await(fetch(''.concat(document.location.origin, '/ws/js/release/').concat(relGid, '?inc=rels recordings')), function (resp) { + return resp.json(); + }); + }); + class ConflictError extends Error { + } + function unicodeToAscii(s) { + return s.replace(/[“”″]/g, '"').replace(/[‘’′]/g, '\'').replace(/[‐‒–]/g, '-'); + } + function getReleaseTitle() { + return document.querySelector('.releaseheader > h1 bdi').textContent; + } + function getDJMixComment() { + return 'part of \u201C'.concat(getReleaseTitle(), '\u201D DJ\u2010mix'); + } + function stringifyDate(date) { + const year = date.year ? date.year.toString().padStart(4, '0') : '????'; + const month = date.month ? date.month.toString().padStart(2, '0') : '??'; + const day = date.day ? date.day.toString().padStart(2, '0') : '??'; + return [ + year, + month, + day + ].join('\u2010').replace(/(?:‐\?{2}){1,2}$/, ''); + } + function getDateStr(rel) { + if (!rel.begin_date || !rel.end_date) + return null; + const _map = [ + rel.begin_date, + rel.end_date + ].map(date => stringifyDate(date)), _map2 = _slicedToArray(_map, 2), beginStr = _map2[0], endStr = _map2[1]; + if (beginStr === '????' || endStr === '????') + return null; + return beginStr === endStr ? beginStr : ''.concat(beginStr, '\u2013').concat(endStr); + } + function selectCommentPart(candidates, partName) { + if (candidates.size === 0) + return null; + if (candidates.size > 1) { + throw new ConflictError('Conflicting '.concat(partName, ': ').concat([...candidates].join(' vs. '))); + } + return candidates.values().next().value; + } + function filterRels(rels, linkTypeID) { + return rels.filter(rel => rel.linkTypeID === linkTypeID); + } + function getRecordingVenue(rels) { + const venuesFormatted = new Set(filterRels(rels, 693).map(placeRel => formatRecordingVenue(placeRel))); + return selectCommentPart(venuesFormatted, '\u201Crecorded at\u201D ARs'); + } + function getRecordingArea(rels) { + const areasFormatted = new Set(filterRels(rels, 698).map(areaRel => formatRecordingArea(areaRel))); + return selectCommentPart(areasFormatted, '\u201Crecorded in\u201D ARs'); + } + function formatRecordingVenue(placeRel) { + return (placeRel.entity0_credit || placeRel.target.name) + ', ' + formatRecordingBareArea(placeRel.target.area); + } + function formatRecordingArea(areaRel) { + return formatRecordingBareArea(areaRel.target); + } + function formatRecordingBareArea(area) { + var _state, _state2, _state2$primary_code, _city; + const areaList = [ + area, + ...area.containment + ]; + let city = null; + let country = null; + let state = null; + for (let i = areaList.length - 1; i >= 0; i--) { + const areaPart = areaList[i]; + switch (areaPart.typeID) { + case 1: + country = areaPart; + break; + case 2: + state = (_state = state) !== null && _state !== void 0 ? _state : areaPart; + break; + case 3: + case 4: + city = areaPart; + break; + } + } + if (!country || ![ + 'US', + 'CA' + ].includes(country.country_code)) { + state = null; + } + let countryName; + if (!country) + countryName = null; + else if (country.primary_code === 'US') + countryName = 'USA'; + else if (country.primary_code === 'GB') + countryName = 'UK'; + else + countryName = country.name; + const stateName = (_state2 = state) === null || _state2 === void 0 ? void 0 : (_state2$primary_code = _state2.primary_code) === null || _state2$primary_code === void 0 ? void 0 : _state2$primary_code.split('-')[1]; + const cityName = ((_city = city) === null || _city === void 0 ? void 0 : _city.name) || stateName === 'DC' && 'Washington'; + const parts = [ + cityName, + stateName, + countryName + ].filter(Boolean); + return parts.join(', '); + } + function getRecordingDate(rels) { + const dateStrs = new Set(filterNonNull(rels.filter(rel => [ + 698, + 693, + 278 + ].includes(rel.linkTypeID)).map(rel => getDateStr(rel)))); + return selectCommentPart(dateStrs, 'recording dates'); + } + function getRecordingLiveComment(rec) { + var _getRecordingVenue; + const rels = rec.relationships; + const place = (_getRecordingVenue = getRecordingVenue(rels)) !== null && _getRecordingVenue !== void 0 ? _getRecordingVenue : getRecordingArea(rels); + const date = getRecordingDate(rels); + let comment = 'live'; + if (date) + comment += ', ' + date; + if (place) + comment += ': ' + place; + return comment; + } + function isLiveRecording(rec, releaseGroup) { + const recordingRelationships = filterRels(rec.relationships, 278); + if (recordingRelationships.length > 0) { + return recordingRelationships.some(recRel => { + var _recRel$attributes; + return ((_recRel$attributes = recRel.attributes) !== null && _recRel$attributes !== void 0 ? _recRel$attributes : []).find(attr => attr.typeID === 578); + }); + } else { + var _releaseGroup$seconda; + return ((_releaseGroup$seconda = releaseGroup.secondaryTypeIDs) !== null && _releaseGroup$seconda !== void 0 ? _releaseGroup$seconda : []).includes(6); + } + } + function fillInput(input, value) { + input.value = value; + input.dispatchEvent(new Event('input')); + input.dispatchEvent(new Event('input.rc')); + } + function seedDJMix() { + fillInput(qs('input#all-recording-comments'), getDJMixComment()); + fillInput(qs('textarea#recording-comments-edit-note'), ''.concat(GMinfo.script.name, ' v').concat(GMinfo.script.version, ': Seed DJ\u2010mix comments')); + } + function displayWarning(msg) { + const warnList = qs('#ROpdebee_seed_comments_warnings'); + warnList.append(function () { + var $$a = document.createElement('li'); + appendChildren($$a, msg); + return $$a; + }.call(this)); + warnList.closest('tr').style.display = ''; + } + function createTrackLiveComment(track, medium, releaseInfo) { + const rec = track.recording; + if (!isLiveRecording(rec, releaseInfo.releaseGroup)) { + displayWarning('Skipping track #'.concat(medium.position, '.').concat(track.number, ': Not a live recording')); + return [ + track.gid, + rec.comment + ]; + } + const existing = unicodeToAscii(rec.comment.trim()); + try { + const newComment = getRecordingLiveComment(rec); + if (existing && existing !== 'live' && existing !== unicodeToAscii(newComment)) { + throw new ConflictError('Significant differences between old and new comments: '.concat(existing, ' vs ').concat(newComment)); + } + return [ + track.gid, + newComment + ]; + } catch (err) { + if (!(err instanceof ConflictError)) + throw err; + displayWarning('Track #'.concat(medium.position, '.').concat(track.number, ': Refusing to update comment: ').concat(err.message)); + return [ + track.gid, + rec.comment + ]; + } + } + function insertButtons() { + const tr = qsMaybe('table#set-recording-comments tr'); + if (tr === null) { + setTimeout(insertButtons, 500); + return; + } + const liveButton = function () { + var $$c = document.createElement('button'); + $$c.setAttribute('id', 'ROpdebee_seed_comments_live'); + $$c.setAttribute('class', 'btn-link'); + $$c.setAttribute('type', 'button'); + $$c.addEventListener('click', () => { + logFailure(seedLive()); + }); + var $$d = document.createTextNode('Live'); + $$c.appendChild($$d); + return $$c; + }.call(this); + const djButton = function () { + var $$e = document.createElement('button'); + $$e.setAttribute('id', 'ROpdebee_seed_comments_djmix'); + $$e.setAttribute('class', 'btn-link'); + $$e.setAttribute('type', 'button'); + $$e.addEventListener('click', seedDJMix); + var $$f = document.createTextNode('DJ\u2010mix'); + $$e.appendChild($$f); + return $$e; + }.call(this); + tr.after(function () { + var $$g = document.createElement('tr'); + var $$h = document.createElement('td'); + $$g.appendChild($$h); + var $$i = document.createTextNode('Seed recording comments:'); + $$h.appendChild($$i); + var $$j = document.createElement('td'); + $$g.appendChild($$j); + appendChildren($$j, liveButton); + var $$l = document.createTextNode(' | '); + $$j.appendChild($$l); + appendChildren($$j, djButton); + return $$g; + }.call(this), function () { + var $$n = document.createElement('tr'); + setStyles($$n, { display: 'none' }); + var $$o = document.createElement('td'); + $$n.appendChild($$o); + var $$p = document.createTextNode('Warnings'); + $$o.appendChild($$p); + var $$q = document.createElement('td'); + $$n.appendChild($$q); + var $$r = document.createElement('ul'); + $$r.setAttribute('id', 'ROpdebee_seed_comments_warnings'); + setStyles($$r, { color: 'red' }); + $$q.appendChild($$r); + return $$n; + }.call(this)); + } + insertButtons(); + +})();