您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Greasy Fork is available in English.
Zkopíruje playlist do schránky tak aby jej bylo možno v hudebním přehrávači aplikovat na tagy
当前为
// ==UserScript== // @name Supraphon Online: Extract metadata to clipboard // @namespace https://greasyfork.runtimutd.eu.org/cs/users/321857-anakunda // @version 1.1 // @description Zkopíruje playlist do schránky tak aby jej bylo možno v hudebním přehrávači aplikovat na tagy // @author Já, Osobně // @iconURL https://www.supraphonline.cz/favicon.ico // @match http*://*.supraphonline.cz/album/* // @grant GM_getValue // @grant GM_getValue // @grant GM_setClipboard // @grant GM_deleteValue // @grant GM.xmlHttpRequest // ==/UserScript== // Výraz pro 'Automatically Fill Values' funkci ve foobaru2000: // %album artist%%album%%date%%releasedate%%genre%%label%%catalog%%discnumber%%totaldiscs%%discsubtitle%%tracknumber%%totaltracks%%artist%%title%%performer%%composer%%media%%comment%%url% 'use strict'; Array.prototype.pushUnique = function(...items) { items.forEach(it => { if (!this.includes(it)) this.push(it) }); return this.length; }; Array.prototype.pushUniqueCaseless = function(...items) { items.forEach(it => { if (!this.includesCaseless(it)) this.push(it) }); return this.length; }; var hTimer = setInterval(function() { var ref = document.querySelector('div.table-action'); if (ref == null) return; clearInterval(hTimer); var child = document.createElement('button'); child.id = 'copy-info-to-clipboard'; child.textContent = 'Kopírovat do schránky'; child.type = 'button'; child.name = 'copy-info-to-clipboard'; child.className = 'btn btn-danger topframe_login'; child.style.marginRight = '10px'; child.onclick = fetchAlbum; ref.prepend(child); }, 1000); function fetchAlbum(evt) { var original_text = evt.target.textContent; evt.target.disabled = true; evt.target.textContent = 'Pracuji...'; var isVA = false, ndx, artists = [], tracks = [], totalTime, discNumber, discSubtitle; var domParser = new DOMParser(); var release = { artists: [], composers: [], performers: [], totalDiscs: 1, }; document.querySelectorAll('h2.album-artist > a').forEach(it => { release.artists.pushUnique(it.title) }); if (release.artists.length == 0 && (ref = document.querySelector('h2.album-artist[title]')) != null) { if (/^(?:Různí(?:\s+interpreti)?|Various(?:\s+Artists)?|VA)$/i.test(ref.title)) isVA = true; if (isVA) release.artists = ['Various Artists']; //else albumArtist = [ref.title]; } var ref = document.querySelector('span[itemprop="byArtist"] > meta[itemprop="name"]'); if (ref != null && /^(?:Různí\s+interpreti)$/i.test(ref.content)) isVA = true; if ((ref = document.querySelector('h1[itemprop="name"]')) != null) release.album = ref.firstChild.data.trim(); if ((ref = document.querySelector('meta[itemprop="numTracks"]')) != null) release.totalTracks = parseInt(ref.content); if ((ref = document.querySelector('meta[itemprop="genre"]')) != null) release.genre = ref.content; if ((ref = document.querySelector('li.album-version > div.selected > div')) != null) { if (/\b(?:CD)\b/.test(ref.textContent)) release.media = 'CD'; if (/\b(?:LP)\b/.test(ref.textContent)) release.media = 'Vinyl'; if (/\b(?:MP3)\b/.test(ref.textContent)) release.media = 'WEB-DL'; if (/\b(?:FLAC)\b/.test(ref.textContent)) release.media = 'WEB-DL'; if (/\b(?:Hi[\s\-]*Res)\b/.test(ref.textContent)) release.media = 'WEB-DL'; } document.querySelectorAll('ul.summary > li').forEach(function(it) { if (it.children.length < 1) return; if (it.children[0].textContent.startsWith('Nosič')) release.media = it.lastChild.textContent.trim(); if (it.children[0].textContent.startsWith('Datum vydání')) release.releaseDate = normalizeDate(it.lastChild.textContent); //if (it.children[0].textContent.startsWith('Žánr')) release.genre = it.lastChild.textContent.trim(); if (it.children[0].textContent.startsWith('Vydavatel')) release.label = it.lastChild.textContent.trim(); if (it.children[0].textContent.startsWith('Katalogové číslo')) release.catalogue = it.lastChild.textContent.trim(); if (it.children[0].textContent.startsWith('Celková stopáž')) totalTime = timeStringToTime(it.lastChild.textContent.trim()); if (/^(?:\([PC]\)|℗|©)$/i.test(it.children[0].textContent)) release.albumYear = extract_year(it.lastChild.data); }); [ [/^(?:Orchestrální\s+hudba)$/i, 'Orchestral Music'], [/^(?:Komorní\s+hudba)$/i, 'Chamber Music'], [/^(?:Vokální)$/i, 'Classical, Vocal'], [/^(?:Klasická\s+hudba)$/i, 'Classical'], [/^(?:Melodram)$/i, 'Classical, Melodram'], [/^(?:Symfonie)$/i, 'Symphony'], [/^(?:Vánoční\s+hudba)$/i, 'Christmas Music'], [/^(?:Alternativní)$/i, 'Alternative'], [/^(?:Dechová\s+hudba)$/i, 'Brass Music'], [/^(?:Elektronika)$/i, 'Electronic'], [/^(?:Folklor)$/i, 'Folclore, World Music'], [/^(?:Instrumentální\s+hudba)$/i, 'Instrumental'], [/^(?:Latinské\s+rytmy)$/i, 'Latin'], [/^(?:Meditační\s+hudba)$/i, 'Meditative'], [/^(?:Pro\s+děti)$/i, 'Children'], ].forEach(it => { if (it[0].test(release.genre)) release.genre = it[1] }); const creators = [ 'autoři', 'interpreti', 'tělesa', 'digitalizace', ]; for (var i = 0; i < 4; ++i) artists[i] = {}; document.querySelectorAll('ul.sidebar-artist > li').forEach(function(it) { if ((ref = it.querySelector('h3')) != null) { ndx = undefined; creators.forEach((it, _ndx) => { if (ref.textContent.includes(it)) ndx = _ndx }); } else { if (typeof ndx != 'number') return; ref = it.querySelector('span'); let key = ref != null ? ref.textContent.replace(/\s*:.*$/, '').toLowerCase() : undefined; // [ // [/^(?:zpěv)$/, 'vocal'], // [/^(?:hudba)$/, 'music'], // [/^(?:původní\s+text)$/, 'original lyrics'], // [/^(?:text)$/, 'lyrics'], // [/^(?:autor)$/, 'author'], // [/^(?:účinkuje)$/, 'participating'], // [/^(?:nahrál)$/, 'recorded'], // [/^(?:sbormistr)$/, 'choirmaster'], // [/^(?:řídí|dirigent)$/, 'conductor'], // ].forEach(it => { if (it[0].test(key)) key = it[1] }); if (!(artists[ndx][key] instanceof Array)) artists[ndx][key] = []; artists[ndx][key].pushUnique(it.querySelector('a').textContent.trim()); } }); release.description = Array.from(document.querySelectorAll('div[itemprop="description"] p')) .map(it => it.textContent.trim()).join(' ').replace(/[\r\n]+/g, ' '); for (i = 1; i < 3; ++i) Object.keys(artists[i]).forEach(it => { release.performers.pushUnique(...artists[i][it]) }); Object.keys(artists[0]).forEach(it => { release.composers.pushUnique(...artists[0][it]) }); if (release.artists.length == 0 && !isVA) release.artists = release.performers; var promises = []; document.querySelectorAll('table.table-tracklist > tbody > tr').forEach(function(it) { if (it.classList.contains('cd-header')) { discNumber = /\b\d+\b/.test(it.querySelector(':scope h3').firstChild.data.trim()) ? parseInt(RegExp.lastMatch) : undefined; if (discNumber > release.totalDiscs) release.totalDiscs = discNumber; } if (it.classList.contains('song-header')) discSubtitle = it.children[0].title.trim() || undefined; if (it.classList.contains('track') && it.id) { let track = { id: parseInt(it.id.replace(/^track-/i, '')), artists: [], performers: [], composers: [], conductors: [], producers: [], discNumber: discNumber, discSubtitle: discSubtitle, }; if (/^\s*(\d+)\.?\s*$/.test(it.children[0].firstChild.textContent)) track.trackNumber = parseInt(RegExp.$1); ref = it.querySelectorAll('meta[itemprop="name"]'); if (ref.length > 0) track.title = ref[0].content; if (/^PT(\d+)H(\d+)M(\d+)S$/i.test(it.querySelector('meta[itemprop="duration"]').content)) { track.duration = parseInt(RegExp.$1 || 0) * 60**2 + parseInt(RegExp.$2 || 0) * 60 + parseInt(RegExp.$3 || 0); } tracks.push(track); ref = it.querySelector('td > a.trackdetail'); if (ref != null) promises.push(new Promise(function(resolve, reject) { GM_xmlhttpRequest({ method: 'GET', url: ref.href, responseType: 'text/html', context: track, onload: function(response) { if (response.readyState != 4 || response.status != 200) reject('Response error ' + response.status + ' (' + response.statusText + ')'); let dom = domParser.parseFromString(response.responseText, "text/html"); if (dom == null) reject('Parse error'); var track = response.context; var tr_det = dom.querySelector('div[data-swap="trackdetail-' + track.id + '"] > div > div.row'); if (tr_det == null) reject('No trackdetail for track-' + track.id); tr_det.querySelectorAll('div:nth-of-type(1) > ul > li > span').forEach(function(it) { if (it.textContent.startsWith('Nahrávka dokončena')) track.recordDate = it.nextSibling.data.trim(); if (it.textContent.startsWith('Místo nahrání')) track.recordPlace = it.nextSibling.data.trim(); if (it.textContent.startsWith('Rok prvního vydání')) track.albumYear = parseInt(it.nextSibling.data); if (it.textContent.startsWith('(P)')) track.copyright = it.nextSibling.data.trim(); if (it.textContent.startsWith('Žánr')) track.genre = it.nextSibling.data.trim(); }); tr_det.querySelectorAll('div:nth-of-type(2) > ul > li > span').forEach(function(it) { function oneOf(arr) { return arr.some(k => elem[0].startsWith(k)) } var elem = [it.textContent.trim().replace(/:.*/, ''), it.nextElementSibling.textContent.trim()]; if (oneOf(['hudba', 'text', 'hudba+text', 'původní text', 'český text', 'libreto'])) { track.composers.push(elem); } else if (oneOf(['nahrál'])) { } else if (oneOf(['dirigent', 'řídí'])) { track.conductors.push(elem); } else if (oneOf(['produkce'])) { track.producers.push(elem[1]); } else { track.performers.push(elem); } }); // TODO: vyfiltrovat track.artists z track.performers resolve(true); }, onerror: response => { reject('Response error ' + response.status + ' (' + response.statusText + ')') }, ontimeout: function() { reject('Timeout') }, }); })); } }); Promise.all(promises).then(function() { var clipBoard = ''; tracks.sort(function(a, b) { var k = a.discNumber - b.discNumber; return isNaN(k) || k == 0 ? a.trackNumber - b.trackNumber : k; }).forEach(function(track) { clipBoard += [ joinArtists(release.artists), release.album, release.albumYear || track.albumYear, release.releaseDate, track.genre || release.genre, release.label, release.catalogue, track.discNumber, release.totalDiscs > 1 ? release.totalDiscs : undefined, track.discSubtitle, track.trackNumber, release.totalTracks, joinArtists(track.artists.length > 0 ? track.artists : release.artists), track.title, track.performers.concat(track.conductors).map(desc).join(', ') || release.performers.join(', '), track.composers.map(desc).join(', ') || release.composers.join(', '), release.media, release.description, document.location.origin + document.location.pathname, ].join('\x1E') + '\n'; }); GM_setClipboard(clipBoard, 'text'); }).catch(e => { alert(e) }).then(function() { evt.target.disabled = false; evt.target.textContent = original_text; }); } function desc(el) { var res = el[1]; if (el[0] && el[0] != 'hudební tělesa') res += ' (' + el[0] + ')'; return res; } function joinArtists(list) { return list.length < 3 ? list.join(' a ') : list.slice(0, -1).join(', ') + ' a ' + list[list.length - 1]; } function normalizeDate(str) { if (typeof str != 'string') return null; if (/\b(d{4})-(\d+)-(\d+)\b/.test(str)) { var D = parseInt(RegExp.$3); var M = parseInt(RegExp.$2); var Y = parseInt(RegExp.$1); } else if (/\b(\d{1,2})\/(\d{1,2})\/(\d{2}|\d{4})\b/.test(str)) { D = parseInt(RegExp.$2); M = parseInt(RegExp.$1); Y = parseInt(RegExp.$3); } else if (/\b(\d{1,2})\.\s?(\d{1,2})\.\s?(\d{2}|\d{4})\b/.test(str)) { D = parseInt(RegExp.$1); M = parseInt(RegExp.$2); Y = parseInt(RegExp.$3); } if (Y < 100) Y += 2000; return D > 0 && M > 0 && Y > 0 ? Y.toString().padStart(4, '0') + '-' + M.toString().padStart(2, '0') + '-' + D.toString().padStart(2, '0') : extract_year(str); } function timeStringToTime(str) { if (!/(-\s*)?\b(\d+(?::\d{2})*(?:\.\d+)?)\b/.test(str)) return null; var t = 0, a = RegExp.$2.split(':'); while (a.length > 0) t = t * 60 + parseFloat(a.shift()); return RegExp.$1 ? -t : t; } function extract_year(expr) { if (typeof expr == 'number') return Math.round(expr); if (typeof expr != 'string') return null; if (/\b(\d{4})\b/.test(expr)) return parseInt(RegExp.$1); var d = new Date(expr); return parseInt(isNaN(d) ? expr : d.getFullYear()); }