您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Tries to recognize and add featured artists from selected text in description
当前为
// ==UserScript== // @name Gazelle extract featured artists from description // @namespace https://greasyfork.org/cs/users/321857-anakunda // @version 1.31 // @description Tries to recognize and add featured artists from selected text in description // @author Anakunda // @match https://redacted.ch/torrents.php?*id=* // @match https://orpheus.network/torrents.php?*id=* // @match https://notwhat.cd/torrents.php?*id=* // @grant RegExp // @grant GM_xmlhttpRequest // @grant GM_getValue // @grant GM_setValue // @grant GM_deleteValue // @grant GM_log // @require https://greasyfork.org/scripts/388280-xpathlib/code/XPathLib.js // ==/UserScript== var artist_index; var modal = null, btnAdd = null, btnCustom = null, customCtrls = [], sel = null; var prefs = { set: function(prop, def) { this[prop] = GM_getValue(prop, def) } }; (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 = do_parse; 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*$/); addPreset(++presetIndex, escapeHTML('<artist(s)>[ (<assignment>)]'), /^\s*(.*?)(?:\s*(?:\([^\(\)]+\)|\[[^\[\]]+\]|\{[^\{\}]+\}))?\s*$/); addPreset(++presetIndex, escapeHTML('[<assignment> - ]<artist(s)>'), /^\s*(?:(.*?)\s+[\-\−\—\~\–]+\s+)?(.*?)\s*$/, [2, 1]); addPreset(++presetIndex, escapeHTML('[<assignment>: ]<artist(s)>'), /^\s*(?:(.*?)\s*:+\s*)?(.*?)\s*$/, [2, 1]); addPreset(++presetIndex, escapeHTML('<artist>[ / <assignment>]'), /^\s*(.*?)(?:\s*\/+\s*(.*?))?\s*$/); addPreset(++presetIndex, escapeHTML('<artist>[; <assignment>]'), /^\s*(.*?)(?:\s*;\s*(.*?))?\s*$/); addPreset(++presetIndex, escapeHTML('[<assignment> / ]<artist(s)>'), /^\s*(?:(.*?)\s*\/+\s*)?(.*?)\s*$/, [2, 1]); addPreset(++presetIndex, '<span style="font-family: initial;">From tracklist</span>', /^\s*\d+\s*[\-\−\—\~\–\.\:]\s*(.*?)\s+[\-\−\—\~\–\:]\s+|\s+\(feat(?:uring|\.)\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(); }); })(); 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 do_parse(expr, flags = '') { closeModal(); if (!sel) return; var preset = getSelectedRadio('parse-preset'); if (preset == null) return; prefs.preset = preset.value; var order = preset.order; var custom_parse_order = getSelectedRadio('parse-order'); var rx = preset.rx; if (!rx && preset.value == 999 && custom_parse_order != null) { rx = new RegExp(customCtrls[0].value); if (custom_parse_order != null) { order = custom_parse_order.value == 1 ? [1, 2] : custom_parse_order.value == 2 ? [2, 1] : null; } else { order = [1, 2]; } } const artist_parser = /\s*(?:[\,\;\/\|]|(?:&)\s+(?!(?:The|His|Friends)\b))\s*/i; const weak_artist_parser = /\s*[\,\;\/\|]\s*/; const guest_parser = /^(.*?)(?:\s+(?:feat(?:\.|uring)|with|meets)\s+(.*))?$/; function extr_artists(kind) { return document.querySelectorAll('ul#artist_list > li.' + kind + ' > a') } var artists = [ extr_artists('artist_main'), extr_artists('artist_guest'), extr_artists('artists_remix'), extr_artists('artists_composers'), extr_artists('artists_conductors'), extr_artists('artists_dj'), extr_artists('artists_producer'), ]; cleanupArtistsForm(); var addedartists = []; for (var i = 0; i < 7; ++i) addedartists.push([]); artist_index = 0; for (var line of sel.split(/[\r\n]+/)) { if (!line || !line.trim()) continue; if (line.search(/^\s*(?:Recorded|Mastered)\b/i) >= 0) continue; line = line.replace(/\s+\(tracks?\b[^\(\)]+\)/, '').replace(/\s+\[tracks?\b[^\[\]]+\]/, '') var matches = line.match(/^\s*Produced[ \-\−\—\~\–]by (.+?)\s*$/); if (matches) { add_artist(matches[1], 7); } else if (matches = rx.exec(line)) { var j; if (order.length < 2) { if (matches[2]) matches[2].split(weak_artist_parser).forEach(k => { add_artist(k, 2) }); if (matches[1]) { matches = matches[1].match(guest_parser); matches[1].split(artist_parser).forEach(k => { add_artist(k) }); if (matches[2]) matches[2].split(artist_parser).forEach(k => { add_artist(k, 2) }); } } else if (matches[order[0]]) { matches[order[0]].split(artist_parser).forEach(k => { add_artist(k, deduce_artist(matches[order[1]])) }); } else { matches[order[1]].split(artist_parser).forEach(k => { add_artist(k) }); } } } prefs.custom_pattern = customCtrls[0].value; prefs.custom_pattern_order = custom_parse_order != null ? custom_parse_order.value : 1; for (i in prefs) { if (typeof prefs[i] != 'function') GM_setValue(i, prefs[i]) } return; function deduce_artist(str) { var result = 2; // guest by default if (str) { if (str.search(/\b(?:remix)/i) >= 0) result = 3; // remixer if (str.search(/\b(?:composer|libretto|lyric\w*|written[ \-\−\—\~\–]by)\b/i) >= 0) result = 4; // composer if (str.search(/\b(?:conduct|rirector\b)/i) >= 0) result = 5; // conductor if (str.search(/\b(?:compiler\b)/i) >= 0) result = 5; // conductor if (str.search(/\b(?:producer\b|produced[ \-\−\—\~\–]by\b)/i) >= 0) result = 7; // producer } return result; } function add_artist(name, type = 1) { if (!name || !type) return false; // avoid dupes for (var i of artists[0]) { if (name == i.textContent) return false } if (type >= 2) for (i of artists[type - 1]) { if (name == i.textContent) return false } for (i of addedartists[0]) { if (name == i) return false } if (type >= 2) for (i of addedartists[type - 1]) { if (name == i) return false } var id = get_artist_field(artist_index); if (id == null) { add_artist_field(); id = get_artist_field(artist_index); if (id == null) return false; } id.value = name; id.nextElementSibling.value = type; addedartists[type - 1].push(name); ++artist_index; return true; } } function add_artist_field() { exec(function() { AddArtistField() }) } function exec(fn) { let script = document.createElement('script'); script.type = 'application/javascript'; script.textContent = '(' + fn + ')();'; document.body.appendChild(script); // run the script document.body.removeChild(script); // clean up } function get_artist_field(index) { var id = document.getElementById('artist'); if (index <= 0) return id; for (var i = 0; i < index; ++i) { do { id = id.nextElementSibling } while (id != null && (id.localName != 'input' || id.name != 'aliasname[]')); if (id == null) break; } return id; } 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() { var id = get_artist_field(0); do { id.value = null; id = id.nextElementSibling; if (id == null) break; id.value = 1; do { id = id.nextElementSibling } while (id != null && (id.localName != 'input' || id.name != 'aliasname[]')); } while (id != null); } 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); }