您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Tries to recognize and add featured artists from selected text in group description
当前为
- // ==UserScript==
- // @name Gazelle extract featured artists from description
- // @namespace https://greasyfork.org/cs/users/321857-anakunda
- // @version 1.40
- // @description Tries to recognize and add featured artists from selected text in group description
- // @author Anakunda
- // @copyright 2020, Anakunda (https://greasyfork.org/cs/users/321857-anakunda)
- // @license GPL-3.0-or-later
- // @match https://redacted.ch/torrents.php?*id=*
- // @match https://orpheus.network/torrents.php?*id=*
- // @match https://notwhat.cd/torrents.php?*id=*
- // @grant GM_getValue
- // @grant GM_setValue
- // @grant GM_deleteValue
- // ==/UserScript==
- const multiArtistParsers = [
- /\s*[,;\u3001](?!\s*(?:[JjSs]r)\b)(?:\s*[Aa]nd\s+)?\s*/,
- /\s+[\/\|\×]\s+/,
- ];
- const ampersandParsers = [
- /\s+(?:vs\.?|X)\s+(?!\s*(?:[\&\/\+\,\;]|and))/i,
- /\s*[;\/\|\×]\s*(?!\s*(?:\s*[\&\/\+\,\;]|and))/i,
- /\s+(?:[\&\+]|and)\s+(?!his\b|her\b|Friends$|Strings$)/i, // /\s+(?:[\&\+]|and)\s+(?!(?:The|his|her|Friends)\b)/i,
- /\s*\+\s*(?!(?:his\b|her\b|Friends$|Strings$))/i,
- ];
- const featArtistParsers = [
- ///\s+(?:meets)\s+(.+?)\s*$/i,
- /* 0 */ /\s+(?:[Ww](?:ith|\.?\/)|[Aa]vec)\s+(?!his\b|her\b|Friends$|Strings$)(.+?)\s*$/,
- /* 1 */ /(?:\s+[\-\−\—\–\_])?\s+(?:[Ff]eaturing\s+|(?:[Ff]eat|[Ff]t|FT)\.\s*|[Ff]\.?\/\s+)([^\(\)\[\]\{\}]+?)(?=\s*(?:[\(\[\{].*)?$)/,
- /* 2 */ /\s+\[\s*f(?:eat(?:\.|uring)|t\.|\.?\/)\s+([^\[\]]+?)\s*\]/i,
- /* 3 */ /\s+\(\s*f(?:eat(?:\.|uring)|t\.|\.?\/)\s+([^\(\)]+?)\s*\)/i,
- /* 4 */ /\s+\[\s*(?:(?:en\s+)?duo\s+)?avec\s+([^\[\]]+?)\s*\]/i,
- /* 5 */ /\s+\(\s*(?:(?:en\s+)?duo\s+)?avec\s+([^\(\)]+?)\s*\)/i,
- /* 6 */ /\s+\[\s*(?:with|[Ww]\.?\/)\s+(?![Hh]is\b|[Hh]er\b|Friends$|Strings$)([^\[\]]+?)\s*\]/,
- /* 7 */ /\s+\(\s*(?:with|[Ww]\.?\/)\s+(?![Hh]is\b|[Hh]er\b|Friends$|Strings$)([^\(\)]+?)\s*\)/,
- ];
- const remixParsers = [
- /\s+\(([^\(\)]+?)[\'\’\`]s[^\(\)]*\s(?:(?:Re)?Mix|Reworx)\)/i,
- /\s+\[([^\[\]]+?)[\'\’\`]s[^\[\]]*\s(?:(?:Re)?Mix|Reworx)\]/i,
- /\s+\(([^\(\)]+?)\s+(?:(?:Extended|Enhanced)\s+)?(?:Remix|Reworx)\)/i,
- /\s+\[([^\[\]]+?)\s+(?:(?:Extended|Enhanced)\s+)?(?:Remix|Reworx)\]/i,
- /\s+\(Remix(?:ed)?\s+by\s+([^\(\)]+)\)/i,
- /\s+\[Remix(?:ed)?\s+by\s+([^\[\]]+)\]/i,
- ];
- const otherArtistsParsers = [
- [/^(.*?)\s+(?:under|(?:conducted)\s+by)\s+(.*)$/, 4],
- [/^()(.*?)\s+\(conductor\)$/i, 4],
- //[/^()(.*?)\s+\(.*\)$/i, 1],
- ];
- const pseudoArtistParsers = [
- /* 0 */ /^(?:Various(?:\s+Artists)?|VA|\<various\s+artists\>|Různí(?:\s+interpreti)?)$/i,
- /* 1 */ /^(?:#??N[\/\-]?A|[JS]r\.?)$/i,
- /* 2 */ /^(?:auditorium|[Oo]becenstvo|[Pp]ublikum)$/,
- /* 3 */ /^(?:(Special\s+)??Guests?|Friends|(?:Studio\s+)?Orchestra)$/i,
- /* 4 */ /^(?:Various\s+Composers)$/i,
- /* 5 */ /^(?:[Aa]nonym)/,
- /* 6 */ /^(?:traditional|trad\.|lidová)$/i,
- /* 7 */ /\b(?:traditional|trad\.|lidová)$/,
- /* 8 */ /^(?:tradiční|lidová)\s+/,
- /* 9 */ /^(?:[Ll]iturgical\b|[Ll]iturgick[áý])/,
- ];
- const siteApiTimeframeStorageKey = document.location.hostname + ' API time frame';
- const gazelleApiFrame = 10500;
- var artistIndex, siteArtistsCache = {}, notSiteArtistsCache = [], xhr = new XMLHttpRequest;
- var modal = null, btnAdd = null, btnCustom = null, customCtrls = [], sel = null, ajaxRejects = 0;
- var prefs = {
- set: function(prop, def) { this[prop] = GM_getValue(prop, def) }
- };
- Array.prototype.includesCaseless = function(str) {
- if (typeof str != 'string') return false;
- str = str.toLowerCase();
- return this.find(elem => typeof elem == 'string' && elem.toLowerCase() == str) != undefined;
- };
- Array.prototype.pushUnique = function(...items) {
- if (Array.isArray(items) && items.length > 0) items.forEach(it => { if (!this.includes(it)) this.push(it) });
- return this.length;
- };
- Array.prototype.pushUniqueCaseless = function(...items) {
- if (Array.isArray(items) && items.length > 0) items.forEach(it => { if (!this.includesCaseless(it)) this.push(it) });
- return this.length;
- };
- (function() {
- 'use strict';
- const styleSheet = `
- .modal {
- position: fixed;
- left: 0;
- top: 0;
- width: 100%;
- height: 100%;
- background-color: rgba(0, 0, 0, 0.5);
- opacity: 0;
- visibility: hidden;
- transform: scale(1.1);
- transition: visibility 0s linear 0.25s, opacity 0.25s 0s, transform 0.25s;
- }
- .modal-content {
- position: absolute;
- top: 50%;
- left: 50%;
- font-size: 17px;
- transform: translate(-50%, -50%);
- background-color: FloralWhite;
- color: black;
- width: 31rem;
- border-radius: 0.5rem;
- padding: 2rem 2rem 2rem 2rem;
- font-family: monospace;
- }
- .show-modal {
- opacity: 1;
- visibility: visible;
- transform: scale(1.0);
- transition: visibility 0s linear 0s, opacity 0.25s 0s, transform 0.25s;
- }
- input[type="text"] { cursor: text; }
- input[type="radio"] { cursor: pointer; }
- .lbl { cursor: pointer; }
- .tooltip {
- position: relative;
- }
- .tooltip .tooltiptext {
- visibility: hidden;
- width: 120px;
- background-color: #555;
- color: #fff;
- text-align: center;
- border-radius: 6px;
- padding: 5px 0;
- position: absolute;
- z-index: 1;
- bottom: 125%;
- left: 50%;
- margin-left: -60px;
- opacity: 0;
- transition: opacity 0.3s;
- }
- .tooltip .tooltiptext::after {
- position: absolute;
- top: 100%;
- left: 50%;
- margin-left: -5px;
- border-width: 5px;
- border-style: solid;
- border-color: #555 transparent transparent transparent;
- }
- .tooltip:hover .tooltiptext {
- visibility: visible;
- opacity: 1;
- }
- `;
- var addBox = document.querySelector('form.add_form[name="artists"]');
- if (addBox == null) return;
- btnAdd = document.createElement('input');
- btnAdd.id = 'add-artists-from-selection';
- btnAdd.value = 'Extract from selection';
- btnAdd.onclick = add_from_selection;
- btnAdd.type = 'button';
- btnAdd.style.marginLeft = '5px';
- btnAdd.style.visibility = 'hidden';
- addBox.appendChild(btnAdd);
- var style = document.createElement('style');
- document.head.appendChild(style);
- style.id = 'artist-parser-form';
- style.type = 'text/css';
- style.innerHTML = styleSheet;
- var el, elem = [];
- elem.push(document.createElement('div'));
- elem[elem.length - 1].className = 'modal';
- elem[elem.length - 1].id = 'add-from-selection-form';
- modal = elem[0];
- elem.push(document.createElement('div'));
- elem[elem.length - 1].className = 'modal-content';
- elem.push(document.createElement('input'));
- elem[elem.length - 1].id = 'btnFill';
- elem[elem.length - 1].type = 'submit';
- elem[elem.length - 1].value = 'Capture';
- elem[elem.length - 1].style = "position: fixed; right: 30px; width: 80px; top: 30px;";
- elem[elem.length - 1].onclick = doParse;
- elem.push(document.createElement('input'));
- elem[elem.length - 1].id = 'btnCancel';
- elem[elem.length - 1].type = 'button';
- elem[elem.length - 1].value = 'Cancel';
- elem[elem.length - 1].style = "position: fixed; right: 30px; width: 80px; top: 65px;";
- elem[elem.length - 1].onclick = closeModal;
- var presetIndex = 0;
- function addPreset(val, label = 'Custom', rx = null, order = [1, 2]) {
- elem.push(document.createElement('div'));
- el = document.createElement('input');
- elem[elem.length - 1].style.paddingBottom = '10px';
- el.id = 'parse-preset-' + val;
- el.name = 'parse-preset';
- el.value = val;
- if (val == 1) el.checked = true;
- el.type = 'radio';
- el.onchange = update_custom_ctrls;
- if (rx) {
- el.rx = rx;
- el.order = order;
- }
- if (val == 999) btnCustom = el;
- elem[elem.length - 1].appendChild(el);
- el = document.createElement('label');
- el.style.marginLeft = '10px';
- el.style.marginRight = '10px';
- el.htmlFor = 'parse-preset-' + val;
- el.className = 'lbl';
- el.innerHTML = label;
- elem[elem.length - 1].appendChild(el);
- if (val != 999) return;
- el = document.createElement('input');
- el.type = 'text';
- el.id = 'custom-pattern';
- el.style.width = '20rem';
- el.style.fontFamily = 'monospace';
- el.autoComplete = "on";
- addTooltip(el, 'RegExp to parse lines, first two captured groups are used');
- customCtrls.push(elem[elem.length - 1].appendChild(el));
- el = document.createElement('input');
- el.type = 'radio';
- el.name = 'parse-order';
- el.id = 'parse-order-1';
- el.value = 1;
- el.checked = true;
- el.style.marginLeft = '1rem';
- addTooltip(el, 'Captured regex groups assigned in order $1: artist(s), $2: assignment');
- customCtrls.push(elem[elem.length - 1].appendChild(el));
- el = document.createElement('label');
- el.htmlFor = 'parse-order-1';
- el.textContent = '→';
- el.style.marginLeft = '5px';
- elem[elem.length - 1].appendChild(el);
- el = document.createElement('input');
- el.type = 'radio';
- el.name = 'parse-order';
- el.id = 'parse-order-2';
- el.value = 2;
- el.style.marginLeft = '10px';
- addTooltip(el, 'Captured regex groups assigned in order $1: assignment, $2: artist(s)');
- customCtrls.push(elem[elem.length - 1].appendChild(el));
- el = document.createElement('label');
- el.htmlFor = 'parse-order-2';
- el.textContent = '←';
- el.style.marginLeft = '5px';
- elem[elem.length - 1].appendChild(el);
- }
- addPreset(++presetIndex, escapeHTML('<artist(s)> - <assignment>]'), /^\s*(.+?)(?:\:|\s+[\-\−\—\~\–]+\s+(.*?))?\s*$/);
- addPreset(++presetIndex, escapeHTML('<artist>[, <assignment>]') +
- '<span style="font-family: initial;"> <i>(HRA style)</i></span>', /^\s*(.+?)(?:\:|\s*,\s*(.*?))?\s*$/);
- addPreset(++presetIndex, escapeHTML('<artist(s)>[: <assignment>]'), /^\s*(.+?)(?:\:|\s*:+\s*(.*?))?(?:\s*,)?\s*$/);
- addPreset(++presetIndex, escapeHTML('<artist(s)>[ (<assignment>)]'), /^\s*(.+?)(?:\:|\s+(?:\([^\(\)]+\)|\[[^\[\]]+\]|\{[^\{\}]+\}))?(?:\s*,)?\s*$/);
- addPreset(++presetIndex, escapeHTML('[<assignment> - ]<artist(s)>'), /^\s*(?:(.*?)\s+[\-\−\—\~\–]+\s+)?(.+?)\:?(?:\s*,)?\s*$/, [2, 1]);
- addPreset(++presetIndex, escapeHTML('[<assignment>: ]<artist(s)>'), /^\s*(?:(.*?)\s*:+\s*)?(.+?)\:?(?:\s*,)?\s*$/, [2, 1]);
- addPreset(++presetIndex, escapeHTML('<artist>[ / <assignment>]'), /^\s*(.+?)(?:\:|\s*\/+\s*(.*?))?(?:\s*,)?\s*$/);
- addPreset(++presetIndex, escapeHTML('<artist>[; <assignment>]'), /^\s*(.+?)(?:\:|\s*;\s*(.*?))?(?:\s*,)?\s*$/);
- addPreset(++presetIndex, escapeHTML('[<assignment> / ]<artist(s)>'), /^\s*(?:(.*?)\s*\/+\s*)?(.+?)\:?(?:\s*,)?\s*$/, [2, 1]);
- addPreset(++presetIndex, '<span style="font-family: initial;">From tracklist</span>',
- /^\s*((?:\d+|[A-Z](?:\d+)?)(?:[\-\.](?:\d+|[A-Za-z])|[A-Za-z])?)(?:\s*[\-\−\—\~\–\.\:]\s*|\s+)(.+?)(?:\s+(\((?:\d+:)?\d+:\d+\)|\[(?:\d+:)?\d+:\d+\]))?\s*$/, []);
- addPreset(999);
- elem.slice(2).forEach(k => { elem[1].appendChild(k) });
- elem[0].appendChild(elem[1]);
- document.body.appendChild(elem[0]);
- window.addEventListener("click", windowOnClick);
- document.addEventListener('selectionchange', () => {
- var cs = window.getComputedStyle(modal);
- if (!btnAdd || window.getComputedStyle(modal).visibility != 'hidden') return;
- var sel = document.getSelection();
- ShowHideAddbutton();
- });
- })();
- /^([A-Z])(?:[\-\.\s]?((\d+)(\.?\S+)?))?$/i
- function add_from_selection() {
- sel = document.getSelection();
- if (sel.isCollapsed || modal == null) return;
- prefs.set('preset', 1);
- prefs.set('custom_pattern', '^\\s*(.+?)(?:\\s*:+\\s*(.*?)|\\:)?\\s*$');
- prefs.set('custom_pattern_order', 1);
- setRadiosValue('parse-preset', prefs.preset);
- customCtrls[0].value = prefs.custom_pattern;
- setRadiosValue('parse-order', prefs.custom_pattern_order);
- sel = sel.toString();
- update_custom_ctrls();
- modal.classList.add("show-modal");
- }
- function doParse(expr, flags = '') {
- closeModal();
- if (!sel) return;
- let preset = getSelectedRadio('parse-preset');
- if (preset == null) return;
- prefs.preset = preset.value;
- let order = preset.order;
- let custom_parse_order = getSelectedRadio('parse-order');
- let rx = preset.rx;
- if (!rx && preset.value == 999 && custom_parse_order != null) {
- rx = new RegExp(customCtrls[0].value);
- order = custom_parse_order != null ?
- custom_parse_order.value == 1 ? [1, 2] : custom_parse_order.value == 2 ? [2, 1] : null : [1, 2];
- }
- let artists = [
- 'artist_main', 'artist_guest', 'artists_remix', 'artists_composers',
- 'artists_conductors', 'artists_dj', 'artists_producer',
- ].map(category => Array.from(document.querySelectorAll(`ul#artist_list > li.${category} > a`)).map(a => a.textContent.trim()));
- //artists = artists.map(a => []);
- cleanupArtistsForm();
- artistIndex = 0;
- sel.split(/(?:\r?\n)+/).forEach(function(line) {
- if (!line || !line.trim()) return;
- if (/^\s*(?:Recorded|Mastered)\b/i.test(line)) return;
- line = line.replace(/\s+\(tracks?\b[^\(\)]+\)/, '').replace(/\s+\[tracks?\b[^\[\]]+\]/, '')
- let matches = /^\s*(?:Produced)[ \-\−\—\~\–]by (.+?)\s*$/.exec(line);
- if (matches != null) splitAmpersands(matches[1]).forEach(producer => { addArtist(producer, 7) });
- else if (rx instanceof RegExp && (matches = rx.exec(line)) != null) {
- if (!Array.isArray(order) || order.length < 2) {
- let title = matches[2];
- if (/^(.+?) [\-\−\—\–] /.test(title)) {
- let artist = RegExp.$1;
- if ((matches = featArtistParsers.slice(0, 2).reduce((m, rx) => m || rx.exec(artist), null)) != null) {
- splitAmpersands(artist.slice(0, matches.index)).forEach(artist => { addArtist(artist, 1) });
- splitAmpersands(matches[1]).forEach(artist => { addArtist(artist, 2) });
- } else splitAmpersands(artist).forEach(artist => { addArtist(artist, 1) });
- }
- if ((matches = featArtistParsers.reduce((m, rx) => m || rx.exec(title), null)) != null)
- splitAmpersands(matches[1]).forEach(artist => { addArtist(artist, 2) });
- if ((matches = remixParsers.reduce((m, rx) => m || rx.exec(title), null)) != null)
- splitAmpersands(matches[1]).forEach(remixer => { addArtist(remixer, 3) });
- } else if (matches[order[0]]) {
- let role = deduceArtist(matches[order[1]]);
- splitAmpersands(matches[order[0]]).forEach(artist => { addArtist(artist, role) });
- } else splitAmpersands(matches[order[1]]).forEach(artist => { addArtist(artist, 2) });
- }
- });
- prefs.custom_pattern = customCtrls[0].value;
- prefs.custom_pattern_order = custom_parse_order != null ? custom_parse_order.value : 1;
- for (let i in prefs) { if (typeof prefs[i] != 'function') GM_setValue(i, prefs[i]) }
- return;
- function deduceArtist(str) {
- if (/\b(?:remix)/i.test(str)) return 3; // remixer
- if (/\b(?:composer|libretto|lyric\w*|written[ \-\−\—\~\–]by)\b/i.test(str)) return 4; // composer
- if (/\b(?:conduct|director\b|direction\b)/i.test(str)) return 5; // conductor
- if (/\b(?:compiler\b)/i.test(str)) return 6; // compiler
- if (/\b(?:producer\b|produced[ \-\−\—\~\–]by\b)/i.test(str)) return 7; // producer
- return 2;
- }
- function addArtist(name, type = 1) {
- if (!name || !(type > 0)) return false;
- if (pseudoArtistParsers.some(rx => rx.test(name))) return false;
- // avoid dupes
- if (artists[type - 1].includesCaseless(name)) return false;
- if (type == 1 && [4, 5].some(cat => artists[cat].includesCaseless(name))) return false;
- if (type == 2 && [0, 4, 5].some(cat => artists[cat].includesCaseless(name))) return false;
- let input = getArtistField(artistIndex);
- if (input == null) {
- AddArtistField();
- if ((input = getArtistField(artistIndex)) == null) return false;
- }
- input.value = name;
- input.nextElementSibling.value = type;
- artists[type - 1].pushUniqueCaseless(name);
- ++artistIndex;
- return true;
- }
- }
- function getArtistField(index) {
- if (!(index >= 0)) return null;
- let inputs = document.querySelectorAll('input[name="aliasname[]"]');
- return index < inputs.length ? inputs[index] : null;
- }
- function closeModal() {
- if (modal == null) return;
- ShowHideAddbutton();
- modal.classList.remove("show-modal");
- }
- function windowOnClick(event) {
- if (modal != null && event.target === modal) closeModal();
- }
- function update_custom_ctrls() {
- function en(elem) {
- if (elem == null || btnCustom == null) return;
- elem.disabled = !btnCustom.checked;
- elem.style.opacity = btnCustom.checked ? 1 : 0.5;
- }
- customCtrls.forEach(k => { en(k) });
- }
- function getSelectedRadio(name) {
- for (var i of document.getElementsByName(name)) { if (i.checked) return i }
- return null;
- }
- function setRadiosValue(name, val) {
- for (var i of document.getElementsByName(name)) { if (i.value == val) i.checked = true }
- }
- function ShowHideAddbutton() {
- //btnAdd.style.visibility = document.getSelection().type == 'Range' ? 'visible' : 'hidden';
- btnAdd.style.visibility = document.getSelection().isCollapsed ? 'hidden' : 'visible';
- }
- function escapeHTML(string) {
- var pre = document.createElement('pre');
- var text = document.createTextNode(string);
- pre.appendChild(text);
- return pre.innerHTML;
- }
- function cleanupArtistsForm() {
- document.querySelectorAll('input[name="aliasname[]"]').forEach(function(input) {
- input.value = '';
- input.nextElementSibling.value = 1;
- });
- }
- function addTooltip(elem, text) {
- if (elem == null) return;
- elem.classList.add('tooltip');
- var tt = document.createElement('span');
- tt.className = 'tooltiptext';
- tt.textContent = text;
- elem.appendChild(tt);
- }
- function twoOrMore(artist) { return artist.length >= 2 && !pseudoArtistParsers.some(rx => rx.test(artist)) };
- function looksLikeTrueName(artist, index = 0) {
- return twoOrMore(artist)
- && (index == 0 || !/^(?:his\b|her\b|Friends$|Strings$)/i.test(artist))
- && artist.split(/\s+/).length >= 2
- && !pseudoArtistParsers.some(rx => rx.test(artist)) || getSiteArtist(artist);
- }
- function strip(art, level = 0) {
- return typeof art == 'string' ? [
- /\s+(?:aka|AKA)\.?\s+(.*)$/g,
- /\s*\([^\(\)]+\)/g,
- /\s*\[[^\[\]]+\]/g,
- /\s*\{[^\{\}]+\}/g,
- ].slice(level).reduce((acc, rx) => acc.replace(rx, ''), art) : undefined;
- }
- function getSiteArtist(artist) {
- //if (isOPS) return undefined;
- if (!artist || notSiteArtistsCache.includesCaseless(artist)) return null;
- var key = Object.keys(siteArtistsCache).find(it => it.toLowerCase() == artist.toLowerCase());
- if (key) return siteArtistsCache[key];
- var now = Date.now();
- try { var apiTimeFrame = JSON.parse(window.localStorage[siteApiTimeframeStorageKey]) } catch(e) { apiTimeFrame = {} }
- if (!apiTimeFrame.timeStamp || now > apiTimeFrame.timeStamp + gazelleApiFrame) {
- apiTimeFrame.timeStamp = now;
- apiTimeFrame.requestCounter = 1;
- } else ++apiTimeFrame.requestCounter;
- window.localStorage[siteApiTimeframeStorageKey] = JSON.stringify(apiTimeFrame);
- if (apiTimeFrame.requestCounter > 5) {
- console.debug('getSiteArtist() request exceeding AJAX API time frame: /ajax.php?action=artist&artistname="' +
- artist + '" (' + apiTimeFrame.requestCounter + ')');
- ++ajaxRejects;
- return undefined;
- }
- try {
- var requestUrl = '/ajax.php?action=artist&artistname=' + encodeURIComponent(artist);
- xhr.open('GET', requestUrl, false);
- //if (isRED && prefs.redacted_api_key) xhr.setRequestHeader('Authorization', prefs.redacted_api_key);
- xhr.send();
- if (xhr.status == 404) {
- notSiteArtistsCache.pushUniqueCaseless(artist);
- return null;
- }
- if (xhr.readyState != XMLHttpRequest.DONE || xhr.status < 200 || xhr.status >= 400) {
- console.warn('getSiteArtist("' + artist + '") error:', xhr, 'url:', document.location.origin + requestUrl);
- return undefined; // error
- }
- let response = JSON.parse(xhr.responseText);
- if (response.status != 'success') {
- notSiteArtistsCache.pushUniqueCaseless(artist);
- return null;
- }
- siteArtistsCache[artist] = response.response;
- if (prefs.diag_mode) console.log('getSiteArtist("' + artist + '") success:', siteArtistsCache[artist]);
- return (siteArtistsCache[artist]);
- } catch(e) {
- console.error('UA::getSiteArtist("' + artist + '"):', e, xhr);
- return undefined;
- }
- }
- function splitArtists(str, parsers = multiArtistParsers) {
- var result = [str];
- parsers.forEach(function(parser) {
- for (var i = result.length; i > 0; --i) {
- var j = result[i - 1].split(parser).map(strip);
- if (j.length > 1 && j.every(twoOrMore) && !j.some(artist => pseudoArtistParsers.some(rx => rx.test(artist)))
- && !getSiteArtist(result[i - 1])) result.splice(i - 1, 1, ...j);
- }
- });
- return result;
- }
- function splitAmpersands(artists) {
- if (typeof artists == 'string') var result = splitArtists(strip(artists, 1));
- else if (Array.isArray(artists)) result = Array.from(artists); else return [];
- ampersandParsers.forEach(function(ampersandParser) {
- for (let i = result.length; i > 0; --i) {
- let j = result[i - 1].split(ampersandParser).map(strip);
- if (j.length <= 1 || !j.every(looksLikeTrueName) || getSiteArtist(result[i - 1])) continue;
- result.splice(i - 1, 1, ...j.filter(function(artist) {
- return !result.includesCaseless(artist) && !pseudoArtistParsers.some(rx => rx.test(artist));
- }));
- }
- });
- return result;
- }