您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Accurate filling the upload and group edit forms based on foobar2000's playlist selection via pasted output of copy command, release consistency check, two tracklist layouts, basic colours customization, featured artists extraction, image URl fetching from store and more. As alternative to copied playlist, URL to product in supported webstore can be used -- see below for the list.
当前为
// ==UserScript== // @name RED (+ NWCD, Orpheus) Upload Assistant // @namespace https://greatest.deepsurf.us/cs/users/321857-anakunda // @version 1.106 // @description Accurate filling the upload and group edit forms based on foobar2000's playlist selection via pasted output of copy command, release consistency check, two tracklist layouts, basic colours customization, featured artists extraction, image URl fetching from store and more. As alternative to copied playlist, URL to product in supported webstore can be used -- see below for the list. // @author Anakunda // @iconURL https://redacted.ch/favicon.ico // @match https://redacted.ch/upload.php* // @match https://redacted.ch/torrents.php?action=editgroup* // @match https://redacted.ch/requests.php?action=new* // @match https://notwhat.cd/upload.php* // @match https://notwhat.cd/torrents.php?action=editgroup* // @match https://notwhat.cd/requests.php?action=new* // @match https://orpheus.network/upload.php* // @match https://orpheus.network/torrents.php?action=editgroup* // @match https://orpheus.network/requests.php?action=new* // @connect file://* // @connect * // @grant GM_xmlhttpRequest // @grant GM_getValue // @grant GM_setValue // @grant GM_deleteValue // @grant GM_log // ==/UserScript== // The pattern for built-in copy command or custom Text Tools quick copy command, which is handled by this helper is: // $fix_eol(%album artist%,)$char(30)$fix_eol(%album%,)$char(30)[$if3(%date%,%ORIGINAL RELEASE DATE%,%year%)]$char(30)[$if3(%releasedate%,%retail date%,%date%,%year%)]$char(30)[$fix_eol($if2(%label%,%publisher%),)]$char(30)[$fix_eol($if3(%catalog%,%CATALOGNUMBER%,%catalog #%,%barcode%,%UPC%,%EAN%),)]$char(30)%__encoding%$char(30)%__codec%$char(30)[%__codec_profile%]$char(30)[%__bitrate%]$char(30)[%__bitspersample%]$char(30)[%__samplerate%]$char(30)[%__channels%]$char(30)[$if3(%media%,%discogs_format%,%source%)]$char(30)[$fix_eol(%genre%,)]['; '$fix_eol(%style%,)]$char(30)[$num(%discnumber%,0)]$char(30)[$num(%totaldiscs%,0)]$char(30)[$fix_eol(%discsubtitle%,)]$char(30)[%track number%]$char(30)[$num(%totaltracks%,0)]$char(30)$fix_eol(%title%,)$char(30)[$fix_eol(%track artist%,)]$char(30)[$if($strcmp($fix_eol(%performer%,),$fix_eol(%artist%,)),,$fix_eol(%performer%,))]$char(30)[$fix_eol(%composer%,)]$char(30)[$fix_eol(%conductor%,)]$char(30)[$fix_eol(%remixer%,)]$char(30)[$fix_eol(%compiler%,)]$char(30)[$fix_eol($if2(%producer%,%producedby%),)]$char(30)%length_seconds_fp%$char(30)%length_samples%$char(30)[%replaygain_album_gain%]$char(30)[%album dynamic range%]$char(30)[%__tool%][ | %ENCODER%][ | %ENCODER_OPTIONS%]$char(30)[$fix_eol($if2(%url%,'https://www.discogs.com/release/'%discogs_release_id%),)]$char(30)$directory_path(%path%)$char(30)[$replace($replace($if2(%comment%,%description%),$char(13),$char(29)),$char(10),$char(28))] // // Fetch release description from webstore URL, supported // // Supported sites for music: // - qobuz.com // - highresaudio.com // - bandcamp.com // - prestomusic.com // // Supported sites for ebooks: // - martinus.cz, martinus.sk // - goodreads.com // - databazeknih.cz // // Supported sites for applications: // - sanet.st 'use strict'; var prefs = { set: function(prop, def) { this[prop] = GM_getValue(prop, def) }, save: function() { for (var iter in this) { if (typeof this[iter] != 'function') GM_setValue(iter, this[iter]) } }, }; prefs.set('remap_texttools_newlines', 0); // convert underscores to linebreaks (ambiguous) prefs.set('clean_on_apply', 0); // clean the input box on successfull fill prefs.set('keep_meaningles_composers', 0); // keep composers from file tags also for non-composer emphasis works prefs.set('always_hide_dnu_list', 0); // risky! prefs.set('single_threshold', 8 * 60); // Max length of single in s prefs.set('EP_threshold', 28 * 60); // Max time of EP in s prefs.set('auto_preview_cover', 1); prefs.set('auto_rehost_cover', 1); prefs.set('always_request_perfect_flac', 0); prefs.set('request_default_bounty', 0); // tracklist specific prefs.set('tracklist_style', 1); // 1: classical, 2: propertional right aligned prefs.set('max_tracklist_width', 80); // right margin of the right aligned tracklist. should not exceed the group description width on any device prefs.set('title_separator', '. '); // divisor of track# and title prefs.set('pad_leader', ' '); prefs.set('tracklist_head_color', '#4682B4'); prefs.set('tracklist_single_color', '#708080'); // classical tracklist only components colouring prefs.set('tracklist_discsubtitle_color', '#008B8B'); prefs.set('tracklist_classicalblock_color', 'Olive'); prefs.set('tracklist_tracknumber_color', '#8899AA'); prefs.set('tracklist_artist_color', '#889B2F'); prefs.set('tracklist_composer_color', '#556B2F'); prefs.set('tracklist_duration_color', '#4682B4'); document.head.appendChild(document.createElement('style')).innerHTML = ` .ua-messages { text-indent: -2em; margin-left: 2em; } .ua-critical { color: red; font-weight: bold; } .ua-warning { color: #C00000; font-weight: 500; } .ua-info { color: #0012ff; } .ua-button { vertical-align: middle; background-color: transparent; } .ua-input { width: 610px; height: 3em; margin-top: 8px; margin-bottom: 8px; background-color: antiquewhite; font-size: small; } `; const isUpload = document.URL.toLowerCase().indexOf('/upload\.php') >= 0; const isRequest = document.URL.toLowerCase().indexOf('/requests.php?action=new') >= 0; const isEdit = document.URL.toLowerCase().indexOf('/torrents.php?action=editgroup') >= 0; var iter, ref, tbl, elem, child, tb, messages = null, domparser = new DOMParser(), dom; if (isUpload) { ref = document.querySelector('form#upload_table > div#dynamic_form'); if (ref == null) return; common1(); let x = []; x.push(document.createElement('tr')); x[0].classList.add('ua-button'); child = document.createElement('input'); child.id = 'fill-from-text'; child.value = 'Fill from text (overwrite)'; child.type = 'button'; child.style.width = '13em'; child.onclick = fill_from_text; x[0].append(child); elem.append(x[0]); x.push(document.createElement('tr')); x[1].classList.add('ua-button'); child = document.createElement('input'); child.id = 'fill-from-text-weak'; child.value = 'Fill from text (keep values)'; child.type = 'button'; child.style.width = '13em'; child.onclick = fill_from_text; x[1].append(child); elem.append(x[1]); common2(); ref.parentNode.insertBefore(tbl, ref); } else if (isEdit) { ref = document.querySelector('form.edit_form > div > div > input[type="submit"]'); if (ref == null) return; ref = ref.parentNode; ref.parentNode.insertBefore(document.createElement('br'), ref); common1(); child = document.createElement('input'); child.id = 'append-from-text'; child.value = 'Fill from text (append)'; child.type = 'button'; child.onclick = fill_from_text; elem.append(child); common2(); tbl.style.marginBottom = '10px'; ref.parentNode.insertBefore(tbl, ref); } else if (isRequest) { ref = document.getElementById('categories'); if (ref == null) return; ref = ref.parentNode.parentNode.nextElementSibling; ref.parentNode.insertBefore(document.createElement('br'), ref); common1(); child = document.createElement('input'); child.id = 'fill-from-text-weak'; child.value = 'Fill from URL'; child.type = 'button'; child.onclick = fill_from_text; elem.append(child); common2(); child = document.createElement('td'); child.colSpan = 2; child.append(tbl); elem = document.createElement('tr'); elem.append(child); ref.parentNode.insertBefore(elem, ref); } if ((ref = document.getElementById('image') || document.querySelector('input[name="image"]')) != null) { ref.ondblclick = clear0; ref.onmousedown = clear1; ref.ondrop = clear0; } function clear0() { this.value = null } function clear1(e) { if (e.button == 1) this.value = null } function common1() { tbl = document.createElement('tr'); tbl.style.backgroundColor = 'darkgoldenrod'; tbl.style.verticalAlign = 'middle'; elem = document.createElement('td'); elem.style.textAlign = 'center'; child = document.createElement('textarea'); child.id = 'import_data'; child.name = 'import_data'; child.classList.add('ua-input'); child.spellcheck = false; //child.ondblclick = clear0; child.onmousedown = clear1; child.ondrop = clear0; //child.onpaste = fill_from_text; elem.append(child); tbl.append(elem); elem = document.createElement('td'); elem.style.textAlign = 'center'; } function common2() { tbl.append(elem); tb = document.createElement('tbody'); tb.append(tbl); tbl = document.createElement('table'); tbl.id = 'upload assistant'; tbl.append(tb); } // if (prefs.always_hide_dnu_list && (ref = document.querySelector('div#content > div:first-of-type')) != null) { // ref.style.display = 'none'; // Hide DNU list (warning - risky!) // } if ((ref = document.getElementById('yadg_input')) != null) ref.ondrop = clear0; class TagManager extends Array { constructor() { super(); this.presubstitutions = [ [/\b(?:Singer\/Songwriter)\b/i, 'singer.songwriter'], [/\b(?:Pop\/Rock)\b/i, 'pop.rock'], [/\b(?:Folk\/Rock)\b/i, 'folk.rock'], ]; this.substitutions = [ [/^Alternative(?:\s+and\s+|\s*[&+]\s*)Indie$/i, 'alternative', 'indie'], [/^Pop(?:\s+and\s+|\s*[&+]\s*)Rock$/i, 'pop', 'rock'], [/^Pop\s*(?:[\-\−\—\–]\s*)?Rock$/i, 'pop.rock'], [/^Rock(?:\s+and\s+|\s*[&+]\s*)Pop$/i, 'pop', 'rock'], [/^Rock\s*(?:[\-\−\—\–]\s*)?Pop$/i, 'pop.rock'], [/^Alt\.Rock$/i, 'alternative.rock'], [/^AOR$/, 'album.oriented.rock'], [/^Synth[\s\-\−\—\–]+Pop$/i, 'synthpop'], [/^Soul(?:\s+and\s+|\s*[&+]\s*)Funk$/i, 'soul', 'funk'], [/^Funk(?:\s+and\s+|\s*[&+]\s*)Soul$/i, 'soul', 'funk'], [/^World(?:\s+and\s+|\s*[&+]\s*)Country$/i, 'world.music', 'country'], [/^Jazz Fusion\s*&\s*Jazz Rock$/i, 'jazz.fusion', 'jazz.rock'], [/^(?:Singer(?:\s+and\s+|\s*[&+]\s*))?Songwriter$/i, 'singer.songwriter'], [/^(?:R\s*(?:[\'\’\`][Nn](?:\s+|[\'\’\`]\s*)|&\s*)B|RnB)$/i, 'rhytm.and.blues'], [/\b(?:Soundtracks?)$/i, 'score'], [/^(?:Electro)$/i, 'electronic'], [/^(?:Metal)$/i, 'heavy.metal'], [/^(?:NonFiction)$/i, 'non.fiction'], [/^(?:Rap)$/i, 'hip.hop'], [/^NeoSoul$/i, 'neo.soul'], [/^(?:NuJazz)$/i, 'nu.jazz'], [/^(?:Hardcore)$/i, 'hard.core'], [/^(?:Ambiente)$/i, 'ambient'], [/^(?:Neo[\s\-\−\—\–]+Classical)$/i, 'neoclassical'], [/^(?:Bluesy[\s\-\−\—\–]+Rock)$/i, 'blues.rock'], [/^(?:Be[\s\-\−\—\–]+Bop)$/i, 'bebop'], [/^(?:Chill)[\s\-\−\—\–]+(?:Out)$/i, 'chillout'], [/^(?:Atmospheric)[\s\-\−\—\–]+(?:Black)$/, 'atmospheric.black.metal'], [/^GoaTrance$/i, 'goa.trance'], ]; this.additions = [ [/^(?:(?:(?:Be|Post|Neo)[\s\-\−\—\–]*)?Bop|Modal|Fusion|Free[\s\-\−\—\–]+Improvisation|Jazz[\s\-\−\—\–]+Fusion|Big[\s\-\−\—\–]*Band)$/i, 'jazz'], [/^(?:(?:Free|Cool|Avant[\s\-\−\—\–]*Garde|Contemporary|Vocal|Instrumental|Modal|Soul|Smooth|Piano|Latin|Afro[\s\-\−\—\–]*Cuban)[\s\-\−\—\–]+Jazz)$/i, 'jazz'], [/^(?:Opera)$/i, 'classical'], [/\b(?:Chamber[\s\-\−\—\–]+Music)\b/i, 'classical'], ]; this.removals = [ ]; } add(...tags) { var added = 0; for (var tag of tags) { if (typeof tag != 'string') continue; this.presubstitutions.forEach(k => { if (k[0].test(tag)) tag = tag.replace(k[0], k[1]) }); tag.split(/\s*[\,\/\;\>\|]+\s*/).forEach(function(tag) { tag = tag.normalize("NFD"). replace(/[\u0300-\u036f]/g, ''). replace(/\(.*?\)|\[.*?\]|\{.*?\}/g, ''). trim(); if (tag.length <= 0 || tag == '?') return null; function test(obj) { return obj instanceof RegExp && obj.test(tag) || typeof obj == 'string' && tag.toLowerCase() == obj.toLowerCase(); } if (this.removals.some(k => test(k))) { addMessage('Warning: bad tag \'' + tag + '\' found', 'ua-warning'); return; } for (var k of this.additions) { if (test(k[0])) added += this.add(...k.slice(1)); } for (k of this.substitutions) { if (test(k[0])) { added += this.add(...k.slice(1)); return; } } tag = tag. replace(/\bAlt\.(?=\s+)/i, 'Alternative'). replace(/^[3-9]0s$/i, '19$0'). replace(/^[0-2]0s$/i, '20$0'). replace(/\b(Psy)[\s\-\−\—\–]+(Trance|Core|Chill)\b/i, '$1$2'). replace(/\s*(?:[\'\’\`][Nn](?:\s+|[\'\’\`]\s*)|[\&\+]\s*)/, ' and '). replace(/[\s\-\−\—\–\_\.\,\'\`\~]+/g, '.'). replace(/[^\w\.]+/g, ''). toLowerCase(); if (tag.length >= 2 && !this.includes(tag)) { this.push(tag); ++added; } }.bind(this)); } return added; } toString() { return this.length > 0 ? this.sort().join(', ') : null; } }; function fill_from_text(e) { var overwrite = this.id == 'fill-from-text'; var clipBoard = document.getElementById('import_data'); if (clipBoard == null) return false; //let promise = clientInformation.clipboard.readText().then(text => clipBoard = text); //if (typeof clipBoard != 'string') return false; var category = document.getElementById('categories'); var i, matches, rx; if ((messages = document.getElementById('UA messages')) != null) messages.parentNode.removeChild(messages); if (category == null && document.getElementById('releasetype') != null || category != null && (category.value == 0 || category.value == 'Music')) return fill_from_text_music(); if (category != null && (category.value == 1 || category.value == 'Applications')) return fill_from_text_apps(); if (category != null && (category.value == 2 || category.value == 3 || category.value == 'E-Books' || category.value == 'Audiobooks')) return fill_from_text_books(); return category == null ? fill_from_text_apps() || fill_from_text_books() : false; function fill_from_text_music() { const div = ['—', '⸺', '⸻']; const doubleParsParsers = [ /\(+(\([^\(\)]*\))\)+/, /\[+(\[[^\[\]]*\])\]+/, /\{+(\{[^\{\}]*\})\}+/, ]; var track, tracks = []; var lines = clipBoard.value.split(/[\r\n]+/); if (lines.length == 1 && /^https?:\/\//i.test(lines[0])) { init_from_url_music(lines[0]); return; } else for (iter of lines) { if (!iter.trim()) continue; // skip empty lines let metaData = iter.split('\x1E'); track = { artist: metaData.shift().trim() || undefined, album: metaData.shift().trim() || undefined, album_year: safeParseYear(metaData.shift().trim()), release_date: metaData.shift().trim() || undefined, label: metaData.shift().trim() || undefined, catalog: metaData.shift().trim() || undefined, encoding: metaData.shift().trim() || undefined, codec: metaData.shift().trim() || undefined, codec_profile: metaData.shift().trim() || undefined, bitrate: safeParseInt(metaData.shift()), bd: safeParseInt(metaData.shift()), sr: safeParseInt(metaData.shift()), channels: safeParseInt(metaData.shift()), media: metaData.shift().trim() || undefined, genre: metaData.shift().trim() || undefined, discnumber: safeParseInt(metaData.shift()), totaldiscs: safeParseInt(metaData.shift()), discsubtitle: metaData.shift().trim() || undefined, tracknumber: metaData.shift().trim() || undefined, totaltracks: safeParseInt(metaData.shift()), title: metaData.shift().trim() || undefined, track_artist: metaData.shift().trim() || undefined, performer: metaData.shift().trim() || undefined, composer: metaData.shift().trim() || undefined, conductor: metaData.shift().trim() || undefined, remixer: metaData.shift().trim() || undefined, compiler: metaData.shift().trim() || undefined, producer: metaData.shift().trim() || undefined, duration: safeParseFloat(metaData.shift()), samples: safeParseInt(metaData.shift()), rg: metaData.shift().trim() || undefined, dr: metaData.shift().trim() || undefined, vendor: metaData.shift().trim() || undefined, url: metaData.shift().trim() || undefined, dirpath: metaData.shift() || undefined, comment: metaData.shift().trim() || undefined, }; if (track.comment == '.') track.comment = undefined; if (track.comment) { track.comment = track.comment.replace(/\x1D/g, '\r').replace(/\x1C/g, '\n'); if (prefs.remap_texttools_newlines) track.comment = track.comment.replace(/__/g, '\r\n').replace(/_/g, '\n') // ambiguous } if (track.dr != null) track.dr = parseInt(track.dr); // DR0 tracks.push(track); } function safeParseInt(x) { return typeof x != 'string' ? null : x.length <= 0 ? undefined : parseInt(x) } function safeParseFloat(x) { return typeof x != 'string' ? null : x.length <= 0 ? undefined : parseFloat(x) } function safeParseYear(x) { return typeof x != 'string' ? null : x.length <= 0 ? undefined : extract_year(x) || NaN } var album_artists = [], albums = [], album_years = [], release_dates = [], labels = [], catalogs = []; var codecs = [], bds = [], medias = [], genres = [], srs = {}, urls = [], comments = [], track_artists = []; var encodings = [], bitrates = [], codec_profiles = [], drs = [], channels = [], rgs = [], dirpaths = []; var vendors = []; let isVA = false, composer_emphasis = false, is_from_dsd = false, is_classical = false; var total_time = 0, release_type, album_bitrate = 0; var totaldiscs = 1, artist_counter = 0, edition_title, media, yadg_prefil = ''; for (iter of tracks) { push_unique(album_artists, 'artist'); push_unique(track_artists, 'track_artist'); push_unique(albums, 'album'); push_unique(album_years, 'album_year'); push_unique(release_dates, 'release_date'); push_unique(labels, 'label'); push_unique(catalogs, 'catalog'); push_unique(encodings, 'encoding'); push_unique(codecs, 'codec'); push_unique(codec_profiles, 'codec_profile'); push_unique(bitrates, 'bitrate'); push_unique(bds, 'bd'); push_unique(channels, 'channels'); push_unique(medias, 'media'); if (iter.sr) { if (typeof srs[iter.sr] != 'number') { srs[iter.sr] = iter.duration; } else { srs[iter.sr] += iter.duration; } } push_unique(genres, 'genre'); push_unique(urls, 'url'); push_unique(comments, 'comment'); push_unique(rgs, 'rg'); push_unique(drs, 'dr'); push_unique(vendors, 'vendor'); push_unique(dirpaths, 'dirpath'); if (iter.discnumber > totaldiscs) totaldiscs = iter.discnumber; total_time += iter.duration || NaN; album_bitrate += (iter.duration || NaN) * iter.bitrate; } function push_unique(array, prop) { if (iter[prop] !== undefined && iter[prop] !== null && (typeof iter[prop] != 'string' || iter[prop].length > 0) && !array.includes(iter[prop])) array.push(iter[prop]); } // inconsistent releases not allowed - die const requisites = [ [album_artists, 'album artists'], [albums, 'album'], [encodings, 'encoding'], [codecs, 'codec'], [codec_profiles, 'codec profile'], [vendors, 'vendor'], [medias, 'media'], [channels, 'channel'], ]; for (iter of requisites) { if (iter[0].length > 1) { addMessage('FATAL: fuzzy releases aren\'t allowed (' + iter[1] + '): ' + iter[0], 'ua-critical'); clipBoard.value = null; return false; } } function validatorFunc(arr, validator, str) { if (arr.length <= 0 || !arr.some(validator)) return true; addMessage('FATAL: disallowed ' + str + ' present (' + arr.filter(validator) + ')', 'ua-critical'); clipBoard.value = null; return false; } if (!validatorFunc(codecs, (codec) => !['FLAC', 'MP3', 'AAC', 'DTS', 'AC3'].includes(codec), 'codecs') || !validatorFunc(bds, (bd) => ![16, 24].includes(bd), 'bit depths') || !validatorFunc(Object.keys(srs), (sr) => sr < 44100 || sr > 192000 || sr % 44100 != 0 && sr % 48000 != 0, 'sample rates')) return false; for (iter of tracks) { if (iter.duration == undefined) continue; if (!isRequest && (isNaN(iter.duration) || iter.duration <= 0)) { addMessage('FATAL: invalid track ' + iter.tracknumber + ' length: ' + iter.duration, 'ua-critical'); return false; } } var tags = new TagManager(); album_bitrate /= total_time; if (total_time > 0 && total_time <= prefs.single_threshold && tracks.length < 8) { release_type = getReleaseIndex('Single'); } else if (total_time > 0 && total_time <= prefs.EP_threshold && tracks.length < 16) { release_type = getReleaseIndex('EP'); } // Processing artists: recognition, splitting and feeding to categores if (album_artists.length == 1) { matches = album_artists[0]; let artists = []; for (iter = 0; iter < 7; ++iter) artists.push([]); const multiArtistParser = /\s*(?:[;\/\|]|,(?:\s*and\s+)?)\s*/; const featParsers = [ /\s+(?:featuring|with|meets)\s+(.*?)\s*$/, /\s+feat\.\s+(.*?)\s*$/, /\s+\[(?:feat(?:\.|uring)|with)\s+([^\[\]]+?)\s*\]/, /\s+\((?:feat(?:\.|uring)|with)\s+([^\(\)]+?)\s*\)/, ]; const remixParsers = [ /\(remix(?:ed)? by ([^\(\)]+)\)/i, /\(([^\(\)]+?)(?:[\'\’\`]s)? remix\)/i, /\[remix(?:ed)? by ([^\[\]]+)\]/i, /\[([^\[\]]+?)(?:[\'\’\`]s)? remix\]/i, ]; const other_artists_parsers = [ [/^(.*?)\s+(?:under|(?:conducted) by)\s+(.*)$/, artists[4]], [/^()(.*?)\s+\(conductor\)$/i, artists[4]], //[/^()(.*?)\s+\(.*\)$/i, guests], ]; const invalidArtist = /^#?N\/?A$/i; const noAkas = /\s+(?:aka|AKA)\s+(.*)/; const ampersandParser = /\s+(?:&|and)(?!\s*(?:The|his|her|Friends)\b)\s+/i; let j; if (/^(?:Various(?:\s+Artists?)?)$/i.test(matches) || matches == 'VA') { isVA = true; } else { spliceGuests(); j = matches.split(multiArtistParser); (j.every(twoOrMore) ? j : [ matches ]).forEach(function(i) { i = guessOtherArtists(i); if (i.length > 0 && !invalidArtist.test(i) && !artists[0].includesCaseless(i)) artists[0].push(i); }); yadg_prefil = matches; } if (albums.length == 1) { remixParsers.forEach(rx => { if (rx.test(albums[0])) addArtists(2, RegExp.$1) }); featParsers.slice(2).forEach(function(rx) { if (rx.test(albums[0])) { addMessage('Warning: featured artist(s) in album title (' + albums[0] + ')', 'ua-warning'); addGuests(RegExp.$1); albums[0] = albums[0].replace(rx, ''); } }); } for (iter of tracks) { addPerformers('track_artist'); addPerformers('performer'); addArtists(2, iter.remixer); addArtists(3, iter.composer); addArtists(4, iter.conductor); addArtists(5, iter.compiler); addArtists(6, iter.producer); if (iter.title) { remixParsers.forEach(rx => { if (rx.test(iter.title)) addArtists(2, RegExp.$1) }); featParsers.slice(2).forEach(function(rx) { if (rx.test(iter.title)) { addMessage('Warning: featured artist(s) in track title (#' + iter.tracknumber + ': ' + iter.title + ')', 'ua-warning'); addGuests(RegExp.$1); iter.track_artist = (!isVA && (!iter.track_artist || iter.track_artist.includes(RegExp.$1)) ? iter.artist : iter.track_artist) + ' feat. ' + RegExp.$1; iter.title = iter.title.replace(rx, ''); } }); } } // iterate tracks for (iter = 0; iter < Math.round(tracks.length / 2); ++iter) { splitAmpersands(0); splitAmpersands(1); } function notInGuestsMain(k) { return !artists[0].includesCaseless(k) && !artists[1].includesCaseless(k) } function twoOrMore(artist) { return artist.length >= 2 && !invalidArtist.test(artist) }; function looksLikeTrueName(artist) { return artist.split(/\s+/).length >= 2 && !/^(?:The|his|Friends)\s+/i.test(artist); } function addPerformers(prop) { if (iter[prop]) { // && (matches = iter[prop].match(guestParser)) matches = iter.prop; spliceGuests(); j = matches.split(multiArtistParser); (j.every(twoOrMore) ? j : [ matches ]).forEach(function(i) { i = guessOtherArtists(i); if (i.length > 0 && !invalidArtist.test(i) && !artists[0].includesCaseless(i) && (isVA || !artists[1].includesCaseless(i))) (isVA ? artists[0] : artists[1]).push(i); }); } } function spliceGuests() { featParsers.forEach(function(k) { if (k.test(matches)) { addGuests(RegExp.$1); matches = matches.replace(k, ''); } }); } function addArtists(index, str) { if (!str) return; j = str.split(multiArtistParser); (j.every(twoOrMore) ? j : [ str ]).forEach(function(i) { i = i.replace(noAkas, ''); if (i.length > 0 && !invalidArtist.test(i) && !artists[index].includesCaseless(i)) artists[index].push(i); }); } function addGuests(str) { if (!str) return; j = str.split(multiArtistParser); (j.every(twoOrMore) ? j : [ str ]).forEach(function(i) { i = i.replace(noAkas, ''); if (i.length > 0 && !invalidArtist.test(i) && notInGuestsMain(i)) artists[1].push(i); }); } function guessOtherArtists(name) { other_artists_parsers.forEach(function(it) { if (it[0].exec(name) == null) return; name = RegExp.$2.replace(noAkas, ''); if (name.length > 0 && !invalidArtist.test(name) && !it[1].includesCaseless(name)) it[1].push(RegExp.$2); name = RegExp.$1; }); return name.replace(noAkas, ''); } function splitAmpersands(n) { for (i = artists[n].length; i > 0; --i) { j = artists[n][i - 1].split(ampersandParser); if (j.length >= 2 && j.every(twoOrMore) && (!j.every(notInGuestsMain) || j.every(looksLikeTrueName))) { artists[n].splice(i - 1, 1, ...j.filter(function(k) { return (n == 0 || !artists[n].includesCaseless(k)) && !artists[n].includesCaseless(k); })); } } } if (element_writable(document.getElementById('artist'))) { const artistSel = 'input[name="artists[]"]'; let artist_index = 0; feedArtistCategory(artists[0].filter(k => !artists[4].includesCaseless(k)), 1); feedArtistCategory(artists[1].filter(k => !artists[0].includesCaseless(k) && !artists[4].includesCaseless(k)), 2); for (iter = 2; iter < 7; ++iter) feedArtistCategory(artists[iter], iter + 1); if (overwrite) while (document.getElementById('artist_' + artist_index) != null) { exec(function() { RemoveArtistField() }); } function feedArtistCategory(list, type) { for (iter of list.sort()) { if (isUpload) { var id = 'artist'; if (artist_index > 0) id += '_' + artist_index; while ((ref = document.getElementById(id)) == null) add_artist(); } else { ref = document.querySelectorAll(artistSel); if (ref.length < artist_index + 1) { for (i = ref.length; i < artist_index + 1; ++i) add_artist(); ref = document.querySelectorAll(artistSel); } ref = ref[artist_index]; } if (ref == null) continue; ref.value = iter; ref.nextElementSibling.value = type; ++artist_index; } } } } else if ((ref = element_writable(document.getElementById('artist'))) != null) { while (document.getElementById('artist_1') != null) exec(function() { RemoveArtistField() }); ref.value = null; } if (isVA && !release_type) release_type = getReleaseIndex('Compilation'); if (albums.length == 1) { let album = albums[0]; rx = /\s+(?:-\s+Single|\[Single\]|\(Single\))$/i; if (rx.test(album)) { release_type = getReleaseIndex('Single'); album = album.replace(rx, ''); } rx = /\s+(?:(?:-\s+)?EP|\[EP\]|\(EP\))$/; if (rx.test(album)) { release_type = getReleaseIndex('EP'); album = album.replace(rx, ''); } rx = /\s+\((?:Live|En\s+directo?|Ao\s+Vivo)\b[^\(\)]*\)$/i; if (rx.test(album) && (!release_type || release_type == getReleaseIndex('Compilation'))) { release_type = getReleaseIndex('Live album'); album = album.replace(rx, ''); } rx = /\s+\[(?:Live|En\s+directo?|Ao\s+Vivo)\b[^\[\]]*\]$/i; if (rx.test(album) && (!release_type || release_type == getReleaseIndex('Compilation'))) { release_type = getReleaseIndex('Live album'); album = album.replace(rx, ''); } if (/(?:^Live\s+(?:[aA]t|[Ii]n)\b|^Directo?\s+[Ee]n\b|\bUnplugged\b|\bAcoustic\s+Stage\b|\s+Live$)/.test(album) && (!release_type || release_type == getReleaseIndex('Compilation'))) { release_type = getReleaseIndex('Live album'); } rx = /\b(?:Best [Oo]f|Greatest Hits|Complete\s+(.+?\s+)(?:Albums|Recordings))\b/; if (rx.test(album) && !release_type) release_type = getReleaseIndex('Anthology') rx = '\\b(?:Soundtrack|Score|Motion\\s+Picture|Series|Television|Original(?:\\s+\\w+)?\\s+Cast|Music\\s+from|(?:Musique|Bande)\\s+originale)\\b'; if (reInParenthesis(rx).test(album) || reInBrackets(rx).test(album)) { if (!release_type) release_type = getReleaseIndex('Soundtrack'); //album = album.replace(rx, ''); tags.add('score'); composer_emphasis = true; } rx = /\s+(?:\([^\(\)]*\bRemix(?:e[ds])?\b[^\(\)]*\)|Remix(?:e[ds])?)$/i; if (rx.test(album)) { if (!release_type) release_type = getReleaseIndex('Remix'); //album = album.replace(rx, ''); } rx = /\s+\[[^\[\]]*\bRemix(?:e[ds])?\b[^\[\]]*\]$/i; if (rx.test(album)) { if (!release_type) release_type = getReleaseIndex('Remix'); //album = album.replace(rx, ''); } rx = /\s+\(([^\(\)]*\b(?:Remaster(?:ed)?\b[^\(\)]*|Reissue|Edition|Version))\)$/i; if (matches = rx.exec(album)) { album = album.replace(rx, ''); edition_title = matches[1]; } rx = /\s+\[([^\[\]]*\b(?:Remaster(?:ed)?\b[^\[\]]*|Reissue|Edition|Version))\]$/i; if (matches = rx.exec(album)) { album = album.replace(rx, ''); edition_title = matches[1]; } rx = /\s+-\s+([^\[\]\(\)\-\−\—\–]*\b(?:(?:Remaster(?:ed)?|Bonus\s+Track)\b[^\[\]\(\)\-\−\—\–]*|Reissue|Edition|Version))$/i; if (matches = rx.exec(album)) { album = album.replace(rx, ''); edition_title = matches[1]; } rx = /\s+(?:\[(?:LP|Vinyl|12"|7")\]|\((?:LP|Vinyl|12"|7")\))$/; if (rx.test(album)) { album = album.replace(rx, ''); media = 'Vinyl'; } rx = /\s+(?:\[SA-?CD\]|\(SA-?CD\))$/; if (rx.test(album)) { album = album.replace(rx, ''); media = 'SACD'; } rx = /\s+(?:\[(?:Blu[\s\-\−\—\–]?Ray|B[DR])\]|\((?:Blu[\s\-\−\—\–]?Ray|B[DR])\))$/; if (rx.test(album)) { album = album.replace(rx, ''); media = 'Blu-Ray'; } rx = /\s+(?:\[DVD(?:-?A)?\]|\(DVD(?:-?A)?\))$/; if (rx.test(album)) { album = album.replace(rx, ''); media = 'DVD'; } if (element_writable(ref = document.getElementById('title') || document.querySelector('input[name="title"]'))) { ref.value = album; } if (yadg_prefil) yadg_prefil += ' '; yadg_prefil += album; } else if (element_writable(ref = document.getElementById('title'))) ref.value = null; if (element_writable(ref = document.getElementById('yadg_input'))) { ref.value = yadg_prefil || null; if (yadg_prefil && (ref = document.getElementById('yadg_submit')) != null && !ref.disabled) ref.click(); } if (element_writable(ref = document.getElementById('year'))) { ref.value = album_years.length == 1 ? album_years[0] : null; } if (album_years.length > 1) { addMessage('Warning: inconsistent album year accross album: ' + album_years, 'ua-warning'); } i = release_dates.length == 1 && extract_year(release_dates[0]); if (element_writable(ref = document.getElementById('remaster_year')) || !isUpload && i > 0 && (ref = document.querySelector('input[name="year"]')) != null && !ref.disabled) { ref.value = i || null; } if (release_dates.length > 1) { addMessage('Warning: inconsistent release date accross album: ' + release_dates, 'ua-warning'); } if (element_writable(ref = document.getElementById('remaster_title'))) { ref.value = edition_title || null; } rx = /\s*[\,\;]\s*/g; if (element_writable(ref = document.getElementById('remaster_record_label') || document.querySelector('input[name="recordlabel"]'))) { ref.value = labels.length == 1 ? labels[0].replace(rx, ' / ') : null; } if (labels.length > 1) addMessage('Warning: inconsistent label accross album: ' + labels, 'ua-warning'); if (element_writable(ref = document.getElementById('remaster_catalogue_number') || document.querySelector('input[name="cataloguenumber"]'))) { ref.value = catalogs.length >= 1 ? catalogs.map(k => k.replace(rx, ' / ')).join(' / ') : null; } var br_isSet = (ref = document.getElementById('bitrate')) != null && ref.value; if (element_writable(ref = document.getElementById('format'))) { ref.value = codecs.length == 1 ? codecs[0] : null; ref.onchange(); //exec(function() { Format() }); } if (codecs.length == 1 && isRequest) reqSelectFormats(prefs.always_request_perfect_flac ? 'FLAC' : codecs[0]); var sel; if (encodings[0] == 'lossless') { sel = bds.includes(24) ? '24bit Lossless' : 'Lossless'; } else if (bitrates.length >= 1) { let lame_version = codecs[0] == 'MP3' && vendors.length > 0 && /^LAME(\d+)\.(\d+)/i.test(vendors[0]) ? parseInt(RegExp.$1) * 1000 + parseInt(RegExp.$2) : undefined; if (codecs[0] == 'MP3' && codec_profiles.length == 1 && codec_profiles[0] == 'VBR V0') { sel = lame_version >= 3094 ? 'V0 (VBR)' : 'APX (VBR)' } else if (codecs[0] == 'MP3' && codec_profiles.length == 1 && codec_profiles[0] == 'VBR V1') { sel = 'V1 (VBR)' } else if (codecs[0] == 'MP3' && codec_profiles.length == 1 && codec_profiles[0] == 'VBR V2') { sel = lame_version >= 3094 ? sel = 'V2 (VBR)' : 'APS (VBR)' } else if (bitrates.length == 1 && [192, 256, 320].includes(Math.round(bitrates[0]))) { sel = Math.round(bitrates[0]); } else { sel = 'Other'; } } if ((ref = document.getElementById('bitrate')) != null && !ref.disabled && (overwrite || !br_isSet)) { ref.value = sel || null; ref.onchange(); //exec(function() { Bitrate() }); if (sel == 'Other' && (ref = document.getElementById('other_bitrate')) != null) { ref.value = Math.round(bitrates.length == 1 ? bitrates[0] : album_bitrate); if ((ref = document.getElementById('vbr')) != null) ref.checked = bitrates.length > 1; } } if (sel && isRequest) { if (prefs.always_request_perfect_flac) { reqSelectBitrates('Lossless', '24bit Lossless'); } else reqSelectBitrates(sel); } if (medias.length >= 1) { sel = undefined; [ [/\b(?:WEB|File|Download|digital\s+media)\b/i, 'WEB'], [/\bCD\b/, 'CD'], [/\b(?:SA-?CD|[Hh]ybrid)\b/, 'SACD'], [/\b(?:[Bb]lu[\-\−\—\–\s]?[Rr]ay|BR|BD)\b/, 'Blu-Ray'], [/\bDVD(?:-?A)?\b/, 'DVD'], [/\b(?:[Vv]inyl\b|LP\b|12"|7")/, 'Vinyl'], ].forEach(k => { if (k[0].test(medias[0])) sel = k[1] }); media = sel || media; } if (element_writable(ref = document.getElementById('media'))) ref.value = media || null; if (media && isRequest) { if (prefs.always_request_perfect_flac) { reqSelectMedias('WEB', 'CD', 'Blu-Ray', 'DVD', 'SACD'); } else reqSelectMedias(media); } function isRedBook(t) { return t.bd == 16 && t.sr == 44100 && t.channels == 2 && t.samples > 0 && t.samples % 588 == 0; } if (!media) { if (tracks.every(isRedBook)) { addMessage('Info: media not determined - CD estimated', 'ua-info'); } else if (tracks.some(t => t.bd > 16 || (t.sr > 0 && t.sr != 44100) || t.samples > 0 && t.samples % 588 != 0)) { addMessage('Info: media not determined - NOT CD', 'ua-info'); } } else if (media != 'CD' && tracks.every(isRedBook)) { addMessage('Info: media is ' + media + ', but CD is possible', 'ua-info'); } if (media == 'WEB') for (iter of tracks) { if (iter.duration > 29.5 && iter.duration < 30.5) addMessage('Warning: track ' + iter.tracknumber + ' possible preview', 'ua-warning'); } if (genres.length >= 1) { genres.forEach(function(genre) { if (/\b(?:Classical|Symphony|Symphonic(?:al)?$|Chamber|Choral|Etude|Opera|Duets|Klassik)\b/i.test(genre) && !/\b(?:metal|rock|pop)\b/i.test(genre)) { composer_emphasis = true; is_classical = true } if (/\b(?:Jazz|Vocal)\b/i.test(genre) && !/\b(?:Nu|Future|Acid)[\s\-\−\—\–]*Jazz\b/i.test(genre) && !/\bElectr(?:o|ic)[\s\-\−\—\–]?Swing\b/i.test(genre)) { composer_emphasis = true; } if (/\b(?:Soundtracks?|Score|Films?|Games?|Video|Series?|Theatre|Musical)\b/i.test(genre)) { composer_emphasis = true; if (!release_type) release_type = getReleaseIndex('Soundtrack'); } tags.add(genre); }); if (genres.length > 1) addMessage('Warning: inconsistent genre accross album: ' + genres, 'ua-warning'); } if (element_writable(ref = document.getElementById('tags'))) ref.value = tags.length >= 1 ? tags.toString() : null; if ((ref = document.getElementById('releasetype')) != null && !ref.disabled && (overwrite || !ref.value || ref.value == 0)) ref.value = release_type || getReleaseIndex('Album'); if (!composer_emphasis && !prefs.keep_meaningles_composers) { document.querySelectorAll('input[name="artists[]"]').forEach(function(i) { if (['4', '5'].includes(i.nextElementSibling.value)) i.value = null }); } for (iter of tracks) { doubleParsParsers.forEach(function(rx) { if (rx.test(iter.title)) { addMessage('Warning: doubled parentheses in track #' + iter.tracknumber + ' title ("' + iter.title + '")', 'ua-warning'); //iter.title.replace(rx, RegExp.$1); } }); } if (tracks.length > 1 && array_homogenous(tracks.map(k => k.title))) { addMessage('Warning: all tracks having same title: ' + tracks[0].title, 'ua-warning'); } var description; if (isUpload) { var ripinfo, dur; const vinyl_test = /^((?:Vinyl|LP) rip by\s+)(.*)$/im; // ============================================= The Playlist ============================================= if (tracks.length > 1) { gen_full_tracklist(); } else { // single description = '[align=center]'; description += isRED() ? '[pad=20|20|20|20]' : ''; description += '[size=4][b][color=' + prefs.tracklist_artist_color + ']' + album_artists[0] + '[/color][hr]'; //description += '[color=' + prefs.tracklist_single_color + ']'; description += tracks[0].title; //description += '[/color]' description += '[/b]'; if (tracks[0].composer) { description += '\n[i][color=' + prefs.tracklist_composer_color + '](' + tracks[0].composer + ')[/color][/i]'; } description += '\n\n[color=' + prefs.tracklist_duration_color +'][' + makeTimeString(tracks[0].duration) + '][/color][/size]'; if (isRED()) description += '[/pad]'; description += '[/align]'; } if (comments.length == 1 && comments[0]) { if (matches = comments[0].match(vinyl_test)) { ripinfo = comments[0].slice(matches.index).trim().split(/[\r\n]+/); description = description.concat('\n\n', comments[0].slice(0, matches.index).trim()); } else { description += '\n\n' + comments[0]; } } if (element_writable(ref = document.getElementById('album_desc'))) { ref.value = description; preview(0); } if ((ref = document.getElementById('body')) != null && !ref.disabled) { let editioninfo; if (edition_title) { editioninfo = '[size=5][b]' + edition_title; if (release_dates.length == 1 && (i = extract_year(release_dates[0]))) editioninfo += ' (' + i + ')'; editioninfo = editioninfo.concat('[/b][/size]\n\n'); } else { editioninfo = '' } if (ref.textLength > 0) { ref.value = ref.value.concat('\n\n', editioninfo, description); } else { ref.value = editioninfo + description; } preview(0); } var lineage = '', comment = '', drinfo, srcinfo; if (element_writable(ref = document.getElementById('release_samplerate'))) { ref.value = Object.keys(srs).length == 1 ? Math.floor(Object.keys(srs)[0] / 1000) : Object.keys(srs).length > 1 ? '999' : null; } if (Object.keys(srs).length > 0) { let kHz = Object.keys(srs).sort((a, b) => srs[b] - srs[a]).map(f => f / 1000).join('/').concat('kHz'); if (bds.some(bd => bd > 16)) { if (drs.length >= 1) drinfo = '[hide=DR' + (drs.length == 1 ? drs[0] : '') + '][pre][/pre]'; if (media == 'Vinyl') { let hassr = ref == null || Object.keys(srs).length > 1; lineage = hassr ? kHz + ' ' : ''; if (ripinfo) { ripinfo[0] = ripinfo[0].replace(vinyl_test, '$1[color=blue]$2[/color]'); if (hassr) { ripinfo[0] = ripinfo[0].replace(/^Vinyl\b/, 'vinyl') } lineage += ripinfo[0] + '\n\n[u]Lineage:[/u]' + ripinfo.slice(1).map(k => '\n' + k).join(''); } else { lineage += (hassr ? 'Vinyl' : ' vinyl') + ' rip by [color=blue][/color]\n\n[u]Lineage:[/u]'; } if (drs.length >= 1) drinfo += '\n\n[img][/img]\n[img][/img]\n[img][/img][/hide]'; } else if (['Blu-Ray', 'DVD', 'SACD'].includes(media)) { lineage = ref ? '' : kHz; if (channels.length == 1) add_channel_info(); if (media == 'SACD' || is_from_dsd) { lineage += ' from DSD64 using foobar2000\'s SACD decoder (direct-fp64)'; lineage += '\nOutput gain +0dB'; } drinfo += '[/hide]'; //add_rg_info(); } else { // WEB Hi-Res if (ref == null || Object.keys(srs).length > 1) lineage = kHz; if (channels.length == 1 && channels[0] != 2) add_channel_info(); add_dr_info(); //if (lineage.length > 0) add_rg_info(); if (bds.length > 1) bds.filter(bd => bd != 24).forEach(function(bd) { let hybrid_tracks = tracks.filter(k => k.bd == bd).map(k => k.tracknumber); if (hybrid_tracks.length < 1) return; if (lineage) lineage += '\n'; lineage += 'Note: track'; if (hybrid_tracks.length > 1) lineage += 's'; lineage += ' #' + hybrid_tracks.sort().join(', ') + (hybrid_tracks.length > 1 ? ' are' : ' is') + ' ' + bd + 'bit lossless'; }); drinfo = Object.keys(srs).length == 1 && Object.keys(srs)[0] == 88200 ? drinfo.concat('[/hide]') : null; } } else { // 16bit or lossy if (Object.keys(srs).some(f => f != 44100)) lineage = kHz; if (channels.length == 1 && channels[0] != 2) add_channel_info(); //add_dr_info(); //if (lineage.length > 0) add_rg_info(); if (['AAC', 'Opus', 'Vorbis'].includes(codecs[0]) && vendors[0]) { let _encoder_settings = vendors[0]; if (codecs[0] == 'AAC' && /^qaac\s+[\d\.]+/i.test(vendors[0])) { let enc = []; if (matches = vendors[0].match(/\bqaac\s+([\d\.]+)\b/i)) enc[0] = matches[1]; if (matches = vendors[0].match(/\bCoreAudioToolbox\s+([\d\.]+)\b/i)) enc[1] = matches[1]; if (matches = vendors[0].match(/\b(AAC-\S+)\s+Encoder\b/i)) enc[2] = matches[1]; if (matches = vendors[0].match(/\b([TC]VBR|ABR|CBR)\s+(\S+)\b/)) { enc[3] = matches[1]; enc[4] = matches[2]; } if (matches = vendors[0].match(/\bQuality\s+(\d+)\b/i)) enc[5] = matches[1]; _encoder_settings = 'Converted by Apple\'s ' + enc[2] + ' encoder (' + enc[3] + '-' + enc[4] + ')'; } if (lineage) lineage += '\n\n'; lineage += _encoder_settings; } } } function add_dr_info() { if (drs.length != 1 || document.getElementById('release_dynamicrange') != null) return false; if (lineage.length > 0) lineage += ' | '; if (drs[0] < 4) lineage += '[color=red]'; lineage += 'DR' + drs[0]; if (drs[0] < 4) lineage += '[/color]'; return true; } function add_rg_info() { if (rgs.length != 1) return false; if (lineage.length > 0) lineage += ' | '; lineage += 'RG'; //lineage += 'RG ' + rgs[0]; return true; } function add_channel_info() { if (channels.length != 1) return false; let chi = getChanString(channels[0]); if (lineage.length > 0 && chi.length > 0) lineage += ', '; lineage += chi; return chi.length > 0; } if (urls.length == 1 && urls[0]) srcinfo = '[url]' + urls[0] + '[/url]'; if ((ref = document.getElementById('release_lineage')) != null) { if (element_writable(ref)) { if (drinfo) comment = drinfo; if (lineage && srcinfo) lineage += '\n\n'; if (srcinfo) lineage += srcinfo; ref.value = lineage; preview(1); } } else { comment = lineage; if (comment && drinfo) comment += '\n\n'; if (drinfo) comment += drinfo; if (comment && srcinfo) comment += '\n\n'; if (srcinfo) comment += srcinfo; } if (element_writable(ref = document.getElementById('release_desc'))) { ref.value = comment; if (comment.length > 0) preview(isNWCD() ? 2 : 1); } if (encodings[0] == 'lossless' && codecs[0] == 'FLAC' && bds.includes(24) && dirpaths.length == 1) { var uri = new URL(dirpaths[0] + '\\foo_dr.txt'); GM_xmlhttpRequest({ method: 'GET', url: uri.href, responseType: 'blob', onload: function(response) { if (response.readyState != 4 || !response.responseText) return; var rlsDesc = document.getElementById('release_lineage') || document.getElementById('release_desc'); if (rlsDesc == null) return; var value = rlsDesc.value; matches = value.match(/(^\[hide=DR\d*\]\[pre\])\[\/pre\]/im); if (matches == null) return; var index = matches.index + matches[1].length; rlsDesc.value = value.slice(0, index).concat(response.responseText, value.slice(index)); } }); } } else if (isRequest) { description = [] if (release_dates.length == 1) { i = new Date(release_dates[0]); description.push('Releasing ' + (isNaN(i) ? release_dates[0] : i.toString().replace(/\s+\d+:.*/, ''))); } if (urls.length == 1) description.push('[url]' + urls[0] + '[/url]'); if (catalogs.length == 1 && /^\d{10,}$/.test(catalogs[0])) { description.push('[url=https://www.google.com/search?q=' + catalogs[0] + ']Find more stores...[/url]'); } if (comments.length == 1) description.push(comments[0]); description = description.join('\n\n'); if (description.length > 0 && element_writable(ref = document.getElementById('description'))) ref.value = description; } if (element_writable(document.getElementById('image') || document.querySelector('input[name="image"]'))) { let u = urls[0]; if (/^https?:\/\/(\w+\.)?discogs\.com\/release\/[\w\-]+\/?$/i.test(u)) u += '/images'; GM_xmlhttpRequest({ method: 'GET', url: u, onload: fetch_image_from_store }); } // } else if (element_writable(document.getElementById('image') || document.querySelector('input[name="image"]')) // && ((ref = document.getElementById('album_desc')) != null || (ref = document.getElementById('body')) != null) // && ref.textLength > 0 && (matches = ref.value.matchAll(/\b(https?\/\/[\w\-\&\_\?\=]+)/i)) != null) { if (element_writable(ref = document.getElementById('release_dynamicrange'))) { ref.value = drs.length == 1 ? drs[0] : null; } if (isRequest && prefs.request_default_bounty > 0) { let amount = prefs.request_default_bounty < 1024 ? prefs.request_default_bounty : prefs.request_default_bounty / 1024; if ((ref = document.getElementById('amount_box')) != null && !ref.disabled) ref.value = amount; if ((ref = document.getElementById('unit')) != null && !ref.disabled) { ref.value = prefs.request_default_bounty < 1024 ? 'mb' : 'gb'; } exec(function() { Calculate() }); } if (prefs.clean_on_apply) clipBoard.value = null; prefs.save(); return true; function gen_full_tracklist() { // ========================= TACKLIST ========================= description = isRED() ? '[pad=5|0|0|0]' : ''; description += '[size=4][color=' + prefs.tracklist_head_color + '][b]Tracklisting[/b][/color][/size]'; if (isRED()) '[/pad]'; let classical_units = new Set(); if (is_classical && !tracks.some(k => k.discsubtitle)) { for (track of tracks) { if (matches = track.title.match(/^(.+?)\s*:\s+(.*)$/)) { classical_units.add(track.classical_unit_title = matches[1]); track.classical_title = matches[2]; } else { track.classical_unit_title = null; } } for (let unit of classical_units.keys()) { let group_performer = array_homogenous(tracks.filter(k => k.classical_unit_title === unit).map(k => k.track_artist)); let group_composer = array_homogenous(tracks.filter(k => k.classical_unit_title === unit).map(k => k.composer)); for (track of tracks) { if (track.classical_unit_title !== unit) continue; if (group_composer) track.classical_unit_composer = track.composer; if (group_performer) track.classical_unit_performer = track.track_artist; } } } let block = 1, lastdisc, lastsubtitle, lastside, vinyl_trackwidth; let lastwork = classical_units.size > 0 ? null : undefined; description += '\n'; let volumes = new Map(tracks.map(k => [k.discnumber, undefined])); volumes.forEach(function(val, key) { volumes.set(key, array_homogenous(tracks.filter(k => k.discnumber == key).map(k => k.discsubtitle))); }); if (media == 'Vinyl') { let max_side_track = undefined; rx = /^([A-Z])(\d+)?(\.(\d+))?/i; for (iter of tracks) { if (matches = iter.tracknumber.match(rx)) { max_side_track = Math.max(parseInt(matches[2]) || 1, max_side_track || 0); } } if (typeof max_side_track == 'number') { max_side_track = max_side_track.toString().length; vinyl_trackwidth = 1 + max_side_track; for (iter of tracks) { if (matches = iter.tracknumber.match(rx)) { iter.tracknumber = matches[1].toUpperCase(); if (matches[2]) iter.tracknumber += matches[2].padStart(max_side_track, '0'); } } } } function prologue(prefix, postfix) { function block1() { if (block == 3) description += postfix; description += '\n'; block = 1; } function block2() { if (block == 3) description += postfix; description += '\n'; block = 2; } function block3() { if (block == 2) { description += '[hr]' } else { description += '\n' } if (block != 3) description += prefix; block = 3; } if (totaldiscs > 1 && iter.discnumber != lastdisc) { block1(); description += '[size=3][color=' + prefs.tracklist_discsubtitle_color + '][b]Disc ' + iter.discnumber; if (iter.discsubtitle && (!volumes.has(iter.discnumber) || volumes.get(iter.discnumber))) { description += ' - ' + iter.discsubtitle; lastsubtitle = iter.discsubtitle; } description += '[/b][/color][/size]'; lastdisc = iter.discnumber; } if (iter.discsubtitle != lastsubtitle) { block1(); if (iter.discsubtitle) { description += '[size=2][color=' + prefs.tracklist_discsubtitle_color + '][b]' + iter.discsubtitle + '[/b][/color][/size]'; } lastsubtitle = iter.discsubtitle; } if (iter.classical_unit_title !== lastwork) { if (iter.classical_unit_composer || iter.classical_unit_title || iter.classical_unit_performer) { block2(); description += '[size=2][color=' + prefs.tracklist_classicalblock_color + '][b]'; if (iter.classical_unit_composer) description += iter.classical_unit_composer + ': '; if (iter.classical_unit_title) description += iter.classical_unit_title; description += '[/b]'; if (iter.classical_unit_performer) description += ' (' + iter.classical_unit_performer + ')'; description += '[/color][/size]'; } else { if (block != 2) block1(); } lastwork = iter.classical_unit_title; } block3(); if (media == 'Vinyl') { let c = iter.tracknumber[0].toUpperCase(); if (lastside != undefined && c != lastside) description += '\n'; lastside = c; } } var varying_composer = !array_homogenous(tracks.map(k => k.composer)); for (iter of tracks.sort(function(a, b) { var d = a.discnumber - b.discnumber; var t = a.tracknumber - b.tracknumber; return isNaN(d) || d == 0 ? isNaN(t) ? a.tracknumber.localeCompare(b.tracknumber) : t : d; })) { let title = ''; let ttwidth = vinyl_trackwidth || Math.max((iter.totaltracks || tracks.length).toString().length, 2); if (prefs.tracklist_style == 1) { // STYLE 1 ---------------------------------------- prologue('[size=2]', '[/size]\n'); track = '[b][color=' + prefs.tracklist_tracknumber_color + ']'; track += isNaN(parseInt(iter.tracknumber)) ? iter.tracknumber : iter.tracknumber.padStart(ttwidth, '0'); track += '[/color][/b]' + prefs.title_separator; if (iter.track_artist && !iter.classical_unit_performer) { title = '[color=' + prefs.tracklist_artist_color + ']' + iter.track_artist + '[/color] - '; } title += iter.classical_title || iter.title; if (iter.composer && composer_emphasis && varying_composer && !iter.classical_unit_composer) { title = title.concat(' [color=', prefs.tracklist_composer_color, '](', iter.composer, ')[/color]'); } description += track + title; if (iter.duration) description += ' [i][color=' + prefs.tracklist_duration_color +'][' + makeTimeString(iter.duration) + '][/color][/i]'; } else if (prefs.tracklist_style == 2) { // STYLE 2 ---------------------------------------- prologue('[size=2][pre]', '[/pre][/size]'); track = isNaN(parseInt(iter.tracknumber)) ? iter.tracknumber : iter.tracknumber.padStart(ttwidth, '0'); track += prefs.title_separator; if (iter.track_artist && !iter.classical_unit_performer) title = iter.track_artist + ' - '; title += iter.classical_title || iter.title; if (iter.composer && composer_emphasis && varying_composer && !iter.classical_unit_composer) { title = title.concat(' (', iter.composer, ')'); } dur = iter.duration ? '[' + makeTimeString(iter.duration) + ']' : null; let l = 0, j, left, padding, spc; let width = prefs.max_tracklist_width - track.length; if (dur) width -= dur.length + 1; while (title.length > 0) { j = width; if (title.length > width) { while (j > 0 && title[j] != ' ') { --j } if (j <= 0) j = width; } left = title.slice(0, j).trim(); if (++l <= 1) { description += track + left; if (dur) { spc = width - left.length; padding = (spc < 2 ? ' '.repeat(spc) : ' ' + prefs.pad_leader.repeat(spc - 1)) + ' '; description += padding + dur; } width = prefs.max_tracklist_width - track.length - 2; } else { description += '\n' + ' '.repeat(track.length) + left; } title = title.slice(j).trim(); } } } if (prefs.tracklist_style == 1 && total_time > 0) { description += '\n\n' + div[0].repeat(10) + '\n[color=' + prefs.tracklist_duration_color + ']Total time: [i]' + makeTimeString(total_time) + '[/i][/color][/size]'; } else if (prefs.tracklist_style == 2) { if (total_time > 0) { dur = '[' + makeTimeString(total_time) + ']'; description = description.concat('\n\n', div[0].repeat(32).padStart(prefs.max_tracklist_width)); description = description.concat('\n', 'Total time:'.padEnd(prefs.max_tracklist_width - dur.length), dur); } description = description.concat('[/pre][/size]'); } } function getChanString(n) { if (!n) return null; const chanmap = [ 'mono', 'stereo', '2.1', '4.0 surround sound', '5.0 surround sound', '5.1 surround sound', '7.0 surround sound', '7.1 surround sound', ]; return n >= 1 && n <= 8 ? chanmap[n - 1] : n + 'chn surround sound'; } function init_from_url_music(url) { if (typeof url != 'string') return false; var artist, album, albumYear, remasterYear, channels, label, composer, bd, sr = 44.1, description, compiler, producer, totaltracks, totaldiscs, discsubtitle, discnumber, tracknumber, title, track_artist, duration, catalogue, encoding, format, bitrate; if (url.toLowerCase().indexOf('qobuz.com') >= 0) { GM_xmlhttpRequest({ method: 'GET', url: url, onload: function(response) { if (response.readyState != 4 || response.status != 200) return; dom = domparser.parseFromString(response.responseText, "text/html"); if (dom == null) return; if ((ref = dom.querySelector('h2.album-meta__artist')) != null) artist = ref.textContent.trim(); if ((ref = dom.querySelector('h1.album-meta__title')) != null) album = ref.textContent.trim(); ref = dom.querySelector('div.album-meta > ul > li:first-of-type'); if (ref != null) remasterYear = normalizeDate(ref.textContent); ref = dom.querySelector('p.album-about__copyright'); albumYear = ref != null && extract_year(ref.textContent) || extract_year(remasterYear); let genres = []; dom.querySelectorAll('section#about > ul > li').forEach(function(k) { if (/\b(\d+)\s*(?:dis[ck]|disco|disque)(?:s?\b|\(s\))/i.test(k.textContent)) { totaldiscs = parseInt(RegExp.$1); } if (/\b(\d+)\s*(?:track|pist[ae]|tracce)(?:s?\b|\(s\))/i.test(k.textContent)) { totaltracks = parseInt(RegExp.$1); } if (k.textContent.includes('Label')) label = k.children[0].textContent.trim() else if (k.textContent.includes('Composer')) { composer = k.children[0].textContent.trim(); if (/\bVarious\b/i.test(composer)) composer = null; } else if (k.textContent.includes('Genre') && k.children.length > 0) { k.querySelectorAll('a').forEach(k => { genres.push(k.textContent.trim()) }); if (genres.length > 0 && ['Pop/Rock'].includes(genres[0])) genres.shift(); if (genres.length > 0 && ['Metal', 'Heavy Metal'].some(genre => genres.includes(genre))) { while (genres.length > 1) genres.shift(); } } }); bd = 16; channels = 2; dom.querySelectorAll('span.album-quality__info').forEach(function(k) { if (/\b([\d\.\,]+)\s*kHz\b/i.test(k.textContent) != null) sr = parseFloat(RegExp.$1.replace(/,/g, '.')); if (/\b(\d+)[\-\s]*Bits?\b/i.test(k.textContent) != null) bd = parseInt(RegExp.$1); if (/\b(?:Stereo)\b/i.test(k.textContent)) channels = 2; if (/\b(\d)\.(\d)\b/.test(k.textContent)) channels = parseInt(RegExp.$1) + parseInt(RegExp.$2); }); get_desc_from_node('section#description > p', response.finalUrl, true); if ((ref = dom.querySelector('a[title="Qobuzissime"]')) != null) { description += '\x1C[align=center][url=https://www.qobuz.com' + ref.pathname + '][img]https://ptpimg.me/4z35uj.png[/img][/url][/align]'; } ref = dom.querySelectorAll('div.player__tracks > div.track > div.track__items'); let works = dom.querySelectorAll('div.player__tracks > p.player__work'); if (!totaltracks) totaltracks = ref.length; ref.forEach(function(k) { discsubtitle = null; works.forEach(function(j) { if (j.compareDocumentPosition(k) == Node.DOCUMENT_POSITION_FOLLOWING) discsubtitle = j }); discsubtitle = discsubtitle != null ? discsubtitle.textContent.trim() : undefined; if (/^\s*(?:dis[ck]|disco|disque)\s+(\d+)\s*$/i.test(discsubtitle)) { discnumber = parseInt(RegExp.$1); discsubtitle = undefined; } else discnumber = undefined; if (discnumber > totaldiscs) totaldiscs = discnumber; tracknumber = parseInt(k.querySelector('span[itemprop="position"]').textContent.trim()); title = k.querySelector('span.track__item--name').textContent.trim().replace(/\s+/g, ' '); duration = timestrToTime(k.querySelector('span.track__item--duration').textContent); track_artist = undefined; track = [ artist, album, albumYear, remasterYear, label, undefined, 'lossless', 'FLAC', undefined, undefined, bd, sr * 1000, channels, 'WEB', genres.join(', '), discnumber, totaldiscs, discsubtitle, tracknumber, totaltracks, title, track_artist, undefined, composer, undefined, undefined, compiler, producer, duration, undefined, undefined, undefined, undefined, response.finalUrl, undefined, description, ]; tracks.push(track.join('\x1E')); }); clipBoard.value = tracks.join('\n'); fill_from_text_music(); } }); } else if (url.toLowerCase().indexOf('highresaudio.com') >= 0) { GM_xmlhttpRequest({ method: 'GET', url: url, onload: function(response) { if (response.readyState != 4 || response.status != 200) return; dom = domparser.parseFromString(response.responseText, "text/html"); if (dom == null) return; ref = dom.querySelector('h1 > span.artist'); if (ref != null) artist = ref.textContent.trim(); ref = dom.getElementById('h1-album-title'); if (ref != null) album = ref.firstChild.textContent.trim(); let genres = [], format; dom.querySelectorAll('div.album-col-info-data > div > p').forEach(function(k) { if (/\b(?:Genre|Subgenre)\b/i.test(k.firstChild.textContent)) genres.push(k.lastChild.textContent.trim()); if (/\b(?:Label)\b/i.test(k.firstChild.textContent)) label = k.lastChild.textContent.trim(); if (/\b(?:Album[\s\-]Release)\b/i.test(k.firstChild.textContent)) { albumYear = normalizeDate(k.lastChild.textContent); } if (/\b(?:HRA[\s\-]Release)\b/i.test(k.firstChild.textContent)) { remasterYear = normalizeDate(k.lastChild.textContent); } }); i = 0; dom.querySelectorAll('tbody > tr > td.col-format').forEach(function(k) { if (/^(FLAC)\s*([\d\.\,]+)\b/.exec(k.textContent) != null) { format = RegExp.$1; sr = parseFloat(RegExp.$2.replace(/,/g, '.')); ++i; } }); if (i > 1) sr = undefined; // ambiguous get_desc_from_node('div#albumtab-info > p', response.finalUrl); ref = dom.querySelectorAll('ul.playlist > li.pltrack'); totaltracks = ref.length; ref.forEach(function(k) { discsubtitle = k; while ((discsubtitle = discsubtitle.previousElementSibling) != null) { if (discsubtitle.nodeName == 'LI' && discsubtitle.className == 'plinfo') { discsubtitle = discsubtitle.textContent.replace(/\s*:$/, '').trim(); if (/\b(?:DIS[CK]|Volume|CD)\s*(\d+)\b/i.exec(discsubtitle)) discnumber = parseInt(RegExp.$1); break; } } //if (discnumber > totaldiscs) totaldiscs = discnumber; tracknumber = parseInt(k.querySelector('span.track').textContent.trim()); title = k.querySelector('span.title').textContent.trim().replace(/\s+/g, ' '); duration = timestrToTime(k.querySelector('span.time').textContent); track_artist = undefined; track = [ artist, album, albumYear, remasterYear, label, undefined, 'lossless', 'FLAC', //format, undefined, undefined, 24, sr * 1000, 2, 'WEB', genres.join(', '), discnumber, totaldiscs, discsubtitle, tracknumber, totaltracks, title, track_artist, undefined, composer, undefined, undefined, compiler, producer, duration, undefined, undefined, undefined, undefined, response.finalUrl, undefined, description, ]; tracks.push(track.join('\x1E')); }); clipBoard.value = tracks.join('\n'); fill_from_text_music(); } }); } else if (url.toLowerCase().indexOf('bandcamp.com') >= 0) { GM_xmlhttpRequest({ method: 'GET', url: url, onload: function(response) { if (response.readyState != 4 || response.status != 200) return; dom = domparser.parseFromString(response.responseText, "text/html"); if (dom == null) return; ref = dom.querySelector('span[itemprop="byArtist"] > a'); if (ref != null) artist = ref.textContent.trim(); ref = dom.querySelector('h2[itemprop="name"]'); if (ref != null) album = ref.textContent.trim(); ref = dom.querySelector('div.tralbum-credits'); if (ref != null && /\breleased\s+(.*?\b\d{4})\b/i.test(ref.textContent)) { remasterYear = RegExp.$1; albumYear = remasterYear; } ref = dom.querySelector('p#band-name-location > span.title'); if (ref != null) label = ref.textContent.trim(); let tags = new TagManager; dom.querySelectorAll('div.tralbum-tags > a.tag').forEach(k => { tags.add(k.textContent.trim()) }); description = []; dom.querySelectorAll('div.tralbumData').forEach(function(k) { if (!k.classList.contains('tralbum-tags')) description.push(html2php(k, response.finalUrl)) }); description = description.join('\n\n').replace(/\n/g, '\x1C').replace(/\r/g, '\x1D'); ref = dom.querySelectorAll('table.track_list > tbody > tr[itemprop="tracks"]'); totaltracks = ref.length; ref.forEach(function(k) { tracknumber = parseInt(k.querySelector('div.track_number').textContent); title = k.querySelector('span.track-title').textContent.trim().replace(/\s+/g, ' '); duration = timestrToTime(k.querySelector('span.time').textContent); track_artist = undefined; track = [ artist, album, albumYear, remasterYear, label, undefined, 'lossless', 'FLAC', undefined, undefined, undefined, undefined, 2, 'WEB', tags.toString(), discnumber, totaldiscs, undefined, tracknumber, totaltracks, title, track_artist, undefined, composer, undefined, undefined, compiler, producer, duration, undefined, undefined, undefined, undefined, response.finalUrl, undefined, description, ]; tracks.push(track.join('\x1E')); }); clipBoard.value = tracks.join('\n'); fill_from_text_music(); } }); } else if (url.toLowerCase().indexOf('prestomusic.com') >= 0) { GM_xmlhttpRequest({ method: 'GET', url: url, onload: function(response) { if (response.readyState != 4 || response.status != 200) return; dom = domparser.parseFromString(response.responseText, "text/html"); if (dom == null) return; artist = getArtists(dom.querySelectorAll('div.c-product-block__contributors > p')); ref = dom.querySelector('h1.c-product-block__title'); if (ref != null) album = ref.lastChild.textContent.trim(); dom.querySelectorAll('div.c-product-block__metadata > ul > li').forEach(function(k) { if (k.firstChild.textContent.indexOf('Release Date') >= 0) { remasterYear = extract_year(k.lastChild.textContent); } else if (k.firstChild.textContent.indexOf('Label') >= 0) { label = k.lastChild.textContent.trim(); } else if (k.firstChild.textContent.indexOf('Catalogue No') >= 0) { catalogue = k.lastChild.textContent.trim(); } }); albumYear = remasterYear; let genre; if (/\/jazz\//i.test(response.finalUrl)) genre = 'Jazz'; if (/\/classical\//i.test(response.finalUrl)) genre = 'Classical'; get_desc_from_node('div#about > div > p', response.finalUrl, true); ref = dom.querySelectorAll('div#related > div > ul > li'); composer = []; ref.forEach(function(k) { if (k.parentNode.previousElementSibling.textContent.indexOf('Composers') >= 0) { composer.push(k.firstChild.textContent.trim().replace(/^(.*?)\s*,\s+(.*)$/, '$2 $1')); } }); composer = composer.join(', ') || undefined; ref = dom.querySelectorAll('div.has--sample'); totaltracks = ref.length; let tracknumber = 0; ref.forEach(function(k) { tracknumber = ++tracknumber; title = k.querySelector('p.c-track__title').textContent.trim().replace(/\s+/g, ' '); duration = timestrToTime(k.querySelector('div.c-track__duration').textContent); if (k.classList.contains('c-track')) { track_artist = getArtists(k.parentNode.parentNode.querySelectorAll(':scope > div.c-track__details > ul > li')); discsubtitle = k.parentNode.parentNode.querySelector(':scope > div > div > div > p.c-track__title'); discsubtitle = discsubtitle != null ? discsubtitle.textContent.trim() : undefined; } else { track_artist = getArtists(k.querySelectorAll(':scope > div.c-track__details > ul > li')); discsubtitle = undefined; } if (track_artist == artist) track_artist = undefined; track = [ artist, album, albumYear, remasterYear, label, catalogue, undefined, //encoding, undefined, //format, undefined, undefined, //bitrate, undefined, //bd, undefined, //sr * 1000, 2, 'WEB', genre, discnumber, totaldiscs, discsubtitle, tracknumber, totaltracks, title, track_artist, undefined, composer, undefined, undefined, compiler, producer, duration, undefined, undefined, undefined, undefined, response.finalUrl, undefined, description, ]; tracks.push(track.join('\x1E')); }); clipBoard.value = tracks.join('\n'); fill_from_text_music(); function getArtists(elems) { if (elems == null) return undefined; var artists = []; elems.forEach(k => { artists.push(k.textContent.trim()) }); return artists.join(artists.length > 3 ? ', ' : ' & '); } } }); } function get_desc_from_node(selector, url, quote = false) { description = []; dom.querySelectorAll(selector).forEach(k => { description.push(html2php(k, url).trim()) }); description = description.join('\n\n').trim().replace(/\n/g, '\x1C').replace(/\r/g, '\x1D'); if (quote && description.length > 0) description = '[quote]' + description + '[/quote]'; } } // init_from_url_music function normalizeDate(str) { if (typeof str != 'string') return null; return /\b(d{4}-\d+-\d+|\d{1,2}\/\d{1,2}\/\d{2})\b/.test(str) ? RegExp.$1 : /\b(\d{1,2})\/(\d{1,2})\/(\d{4})\b/.test(str) ? RegExp.$2 + '/' + RegExp.$1 + '/' + RegExp.$3 : /\b(\d{1,2})\.\s?(\d{1,2})\.\s?(\d{2}|\d{4})\b/.test(str) ? RegExp.$2 + '/' + RegExp.$1 + '/' + RegExp.$3 : extract_year(str); } function fetch_image_from_store(response) { if (response.readyState != 4 || !response.responseText) return; dom = domparser.parseFromString(response.responseText, "text/html"); if (dom == null) return; function testDomain(str) { return typeof str == 'string' && response.finalUrl.toLowerCase().includes(str.toLowerCase()); } if (testDomain('qobuz.com') && (ref = dom.querySelector('div.album-cover > img')) != null) { setImage(ref.src); } else if (testDomain('highresaudio.com') && (ref = dom.querySelector('div.albumbody > img.cover[data-pin-media]')) != null) { setImage(ref.dataset.pinMedia); } else if (testDomain('bandcamp.com') && (ref = dom.querySelector('div#tralbumArt > a.popupImage')) != null) { setImage(ref.href); } else if (testDomain('7digital.com') && (ref = dom.querySelector('span.release-packshot-image > img[itemprop="image"]')) != null) { setImage(ref.src); } else if (testDomain('hdtracks.com') && (ref = dom.querySelector('p.product-image > img')) != null) { setImage(ref.src); } else if (testDomain('discogs.com') && (ref = dom.querySelector('div#view_images > p:first-of-type > span > img')) != null) { setImage(ref.src); } else if (testDomain('junodownload.com') && (ref = dom.querySelector('a.productimage')) != null) { setImage(ref.href); } else if (testDomain('supraphonline.cz') && (ref = dom.querySelector('div.sexycover > img')) != null) { setImage(ref.src.replace(/\?\d+$/, '')); } else if (testDomain('prestomusic.com') && (ref = dom.querySelector('div.c-product-block__aside > a')) != null) { setImage(ref.href.replace(/\?\d+$/, '')); } } function reqSelectFormats(...vals) { vals.forEach(function(val) { [ ['MP3', 0], ['FLAC', 1], ['AAC', 2], ['AC3', 3], ['DTS', 4], ].forEach(function(fmt) { if (val == fmt[0] && (ref = document.getElementById('format_' + fmt[1])) != null) { ref.checked = true; ref.onchange(); } }); }); } function reqSelectBitrates(...vals) { vals.forEach(function(val) { var ndx = 10; [ [192, 0], ['APS (VBR)', 1], ['V2 (VBR)', 2], ['V1 (VBR)', 3], [256, 4], ['APX (VBR)', 5], ['V0 (VBR)', 6], [320, 7], ['Lossless', 8], ['24bit Lossless', 9], ['Other', 10], ].forEach(k => { if (val == k[0]) ndx = k[1] }); if ((ref = document.getElementById('bitrate_' + ndx)) != null) { ref.checked = true; ref.onchange(); } }); } function reqSelectMedias(...vals) { vals.forEach(function(val) { [ ['CD', 0], ['DVD', 1], ['Vinyl', 2], ['Soundboard', 3], ['SACD', 4], ['DAT', 5], ['Cassette', 6], ['WEB', 7], ['Blu-Ray', 8], ].forEach(function(med) { if (val == med[0] && (ref = document.getElementById('media_' + med[1])) != null) { ref.checked = true; ref.onchange(); } }); if (val == 'CD') { if ((ref = document.getElementById('needlog')) != null) { ref.checked = true; ref.onchange(); if ((ref = document.getElementById('minlogscore')) != null) ref.value = 100; } if ((ref = document.getElementById('needcue')) != null) ref.checked = true; //if ((ref = document.getElementById('needchecksum')) != null) ref.checked = true; } }); } function getReleaseIndex(str) { var ndx; [ ['Album', 1], ['Soundtrack', 3], ['EP', 5], ['Anthology', 6], ['Compilation', 7], ['Single', 9], ['Live album', 11], ['Remix', 13], ['Bootleg', 14], ['Interview', 15], ['Mixtape', 16], ['Demo', 17], ['Concert Recording', 18], ['DJ Mix', 19], ['Unknown', 21], ].forEach(k => { if (str == k[0]) ndx = k[1] }); return ndx || 21; } } function fill_from_text_apps() { if (!/^https?:\/\//i.test(clipBoard.value)) return false; var description, tags = new TagManager(); if (clipBoard.value.toLowerCase().indexOf('//sanet') >= 0) { GM_xmlhttpRequest({ method: 'GET', url: clipBoard.value, onload: function(response) { if (response.readyState != 4 || response.status != 200) return; dom = domparser.parseFromString(response.responseText, "text/html"); i = dom.querySelector('h1.item_title > span'); if (element_writable(ref = document.getElementById('title'))) { ref.value = i != null ? i.textContent. replace(/\(x64\)$/i, '(64-bit)'). replace(/\b(?:Build)\s+(\d+)/, 'build $1'). replace(/\b(?:Multilingual|Multilanguage)\b/, 'multilingual') : null; } description = html2php(dom.querySelector('section.descr'), response.finalUrl); if (/\s*^(?:\[i\]\[\/i\])?Homepage$.*/m.test(description)) description = RegExp.leftContext; description = description.trim().split(/\n/).slice(5).map(k => k.trimRight()).join('\n').trim(); ref = dom.querySelector('section.descr > div.release-info'); var releaseInfo = ref != null && ref.textContent.trim(); if (/\b(?:Languages?)\s*:\s*(.*?)\s*(?:$|\|)/i.exec(releaseInfo) != null) { description += '\n\n[b]Languages:[/b]\n' + RegExp.$1; } ref = dom.querySelector('div.txtleft > a'); if (ref != null) description += '\n\n[b]Product page:[/b]\n[url]' + de_anonymize(ref.href) + '[/url]'; write_description(description); if ((ref = dom.querySelector('section.descr > div.center > a.mfp-image')) != null) { setImage(ref.href); } else { ref = dom.querySelector('section.descr > div.center > img[data-src]'); if (ref != null) setImage(ref.dataset.src); } var cat = dom.querySelector('a.cat:last-of-type > span'); if (cat != null) { if (cat.textContent.toLowerCase() == 'windows') { tags.add('apps.windows'); if (/\b(?:x64)\b/i.test(releaseInfo)) tags.add('win64'); if (/\b(?:x86)\b/i.test(releaseInfo)) tags.add('win32'); } if (cat.textContent.toLowerCase() == 'macos') tags.add('apps.mac'); if (cat.textContent.toLowerCase() == 'linux' || cat.textContent.toLowerCase() == 'unix') tags.add('apps.linux'); if (cat.textContent.toLowerCase() == 'android') tags.add('apps.android'); if (cat.textContent.toLowerCase() == 'ios') tags.add('apps.ios'); } if (tags.length > 0 && element_writable(ref = document.getElementById('tags'))) { ref.value = tags.toString(); } }, }); return true; } return false; } function fill_from_text_books() { if (!/^https?:\/\//i.test(clipBoard.value)) return false; var description, tags = new TagManager(); if (clipBoard.value.toLowerCase().indexOf('martinus.cz') >= 0 || clipBoard.value.toLowerCase().indexOf('martinus.sk') >= 0) { GM_xmlhttpRequest({ method: 'GET', url: clipBoard.value, onload: function(response) { if (response.readyState != 4 || response.status != 200) return; dom = domparser.parseFromString(response.responseText, "text/html"); function get_detail(x, y) { var ref = dom.querySelector('section#details > div > div > div:first-of-type > div:nth-child(' + x + ') > dl:nth-child(' + y + ') > dd'); return ref != null ? ref.textContent.trim() : null; } i = dom.querySelectorAll('article > ul > li > a'); if (i.length > 0 && element_writable(ref = document.getElementById('title'))) { description = join_authors(i); if ((i = dom.querySelector('article > h1')) != null) description += ' - ' + i.textContent.trim(); i = dom.querySelector('div.bar.mb-medium > div:nth-child(1) > dl > dd > span'); if (i != null && (i = extract_year(i.textContent))) description += ' (' + i + ')'; ref.value = description; } description = '[quote]' + html2php(dom.querySelector('section#description > div')). replace(/^\s*\[img\].*?\[\/img\]\s*/i, '') + '[/quote]'; const translation_map = [ [/\b(?:originál)/i, 'Original title'], [/\b(?:datum|dátum|rok)\b/i, 'Release date'], [/\b(?:katalog|katalóg)/i, 'Catalogue #'], [/\b(?:stran|strán)\b/i, 'Page count'], [/\bjazyk/i, 'Language'], [/\b(?:nakladatel|vydavatel)/i, 'Publisher'], [/\b(?:doporuč|ODPORÚČ)/i, 'Age rating'], ]; dom.querySelectorAll('section#details > div > div > div:first-of-type > div > dl').forEach(function(detail) { var lbl = detail.children[0].textContent.trim(); var val = detail.children[1].textContent.trim(); if (/\b(?:rozm)/i.test(lbl) || /\b(?:vazba|vázba)\b/i.test(lbl)) return; translation_map.forEach(k => { if (k[0].test(lbl)) lbl = k[1] }); if (/\b(?:ISBN)\b/i.test(lbl)) { val = '[url=https://www.worldcat.org/isbn/' + detail.children[1].textContent.trim() + ']' + detail.children[1].textContent.trim() + '[/url]'; // } else if (/\b(?:ISBN)\b/i.test(lbl)) { // val = '[url=https://www.goodreads.com/search/search?q=' + detail.children[1].textContent.trim() + // '&search_type=books]' + detail.children[1].textContent.trim() + '[/url]'; } description += '\n[b]' + lbl + ':[/b] ' + val; }); description += '\n[b]More info:[/b] ' + response.finalUrl; write_description(description); if ((i = dom.querySelector('a.mj-product-preview > img')) != null) { setImage(i.src.replace(/\?.*/, '')); } else if ((i = dom.querySelector('head > meta[property="og:image"]')) != null) { setImage(i.content.replace(/\?.*/, '')); } dom.querySelectorAll('dd > ul > li > a').forEach(x => { tags.add(x.textContent) }); if (tags.length > 0 && element_writable(ref = document.getElementById('tags'))) { ref.value = tags.toString(); } }, }); return true; } else if (clipBoard.value.toLowerCase().indexOf('goodreads.com') >= 0) { GM_xmlhttpRequest({ method: 'GET', url: clipBoard.value, onload: function(response) { if (response.readyState != 4 || response.status != 200) return; dom = domparser.parseFromString(response.responseText, "text/html"); i = dom.querySelectorAll('a.authorName > span'); if (i.length > 0 && element_writable(ref = document.getElementById('title'))) { description = join_authors(i); if ((i = dom.querySelector('h1#bookTitle')) != null) description += ' - ' + i.textContent.trim(); if ((i = dom.querySelector('div#details > div.row:nth-of-type(2)')) != null && (i = extract_year(i.textContent))) description += ' (' + i + ')'; ref.value = description; } description = '[quote]' + html2php(dom.querySelector('div#description > span:last-of-type'), response.finalUrl) + '[/quote]'; function strip(str) { return typeof str == 'string' ? str.replace(/\s{2,}/g, ' ').replace(/[\n\r]+/, '').replace(/\s*\.{3}(?:less|more)\b/g, '').trim() : null; } dom.querySelectorAll('div#details > div.row').forEach(k => { description += '\n' + strip(k.innerText) }); description += '\n'; dom.querySelectorAll('div#bookDataBox > div.clearFloats').forEach(function(detail) { var lbl = detail.children[0].textContent.trim(); var val = strip(detail.children[1].textContent); if (/\b(?:ISBN)\b/i.test(lbl) && ((matches = val.match(/\b(\d{13})\b/)) != null || (matches = val.match(/\b(\d{10})\b/)) != null)) { val = '[url=https://www.worldcat.org/isbn/' + matches[1] + ']' + strip(detail.children[1].textContent) + '[/url]'; } description += '\n[b]' + lbl + ':[/b] ' + val; }); description += '\n[b]More info:[/b] ' + response.finalUrl; write_description(description); if ((i = dom.querySelector('div.editionCover > img')) != null) { setImage(i.src.replace(/\?.*/, '')); } dom.querySelectorAll('div.elementList > div.left').forEach(x => { tags.add(x.textContent.trim()) }); if (tags.length > 0 && element_writable(ref = document.getElementById('tags'))) { ref.value = tags.toString(); } }, }); return true; } else if (clipBoard.value.toLowerCase().indexOf('databazeknih.cz') >= 0) { let url = clipBoard.value; if (url.toLowerCase().indexOf('show=alldesc') < 0) { if (!url.includes('?')) { url += '?show=alldesc' } else { url += '&show=alldesc' } } GM_xmlhttpRequest({ method: 'GET', url: url, onload: function(response) { if (response.readyState != 4 || response.status != 200) return; dom = domparser.parseFromString(response.responseText, "text/html"); i = dom.querySelectorAll('span[itemprop="author"] > a'); if (i != null && element_writable(ref = document.getElementById('title'))) { description = join_authors(i); if ((i = dom.querySelector('h1[itemprop="name"]')) != null) description += ' - ' + i.textContent.trim(); i = dom.querySelector('span[itemprop="datePublished"]'); if (i != null && (i = extract_year(i.textContent))) description += ' (' + i + ')'; ref.value = description; } description = '[quote]' + html2php(dom.querySelector('p[itemprop="description"]'), response.finalUrl) + '[/quote]'; const translation_map = [ [/\b(?:orig)/i, 'Original title'], [/\b(?:série)\b/i, 'Series'], [/\b(?:vydáno)\b/i, 'Released'], [/\b(?:stran)\b/i, 'Page count'], [/\b(?:jazyk)\b/i, 'Language'], [/\b(?:překlad)/i, 'Translation'], [/\b(?:autor obálky)\b/i, 'Cover author'], ]; dom.querySelectorAll('table.bdetail tr').forEach(function(detail) { var lbl = detail.children[0].textContent.trim(); var val = detail.children[1].textContent.trim(); if (/(?:žánr|\bvazba)\b/i.test(lbl)) return; translation_map.forEach(k => { if (k[0].test(lbl)) lbl = k[1] }); if (/\b(?:ISBN)\b/i.test(lbl) && /\b(\d+(?:-\d+)*)\b/.exec(val) != null) { val = '[url=https://www.worldcat.org/isbn/' + RegExp.$1.replace(/-/g, '') + ']' + detail.children[1].textContent.trim() + '[/url]'; } description += '\n[b]' + lbl + '[/b] ' + val; }); description += '\n[b]More info:[/b] ' + response.finalUrl.replace(/\?.*/, ''); write_description(description); if ((i = dom.querySelector('div#icover_mid > a')) != null) setImage(i.href.replace(/\?.*/, '')); if ((i = dom.querySelector('div#lbImage')) != null && (matches = i.style.backgroundImage.match(/\burl\("(.*)"\)/i)) != null) { setImage(matches[1].replace(/\?.*/, '')); } dom.querySelectorAll('h5[itemprop="genre"] > a').forEach(x => { tags.add(x.textContent.trim()) }); dom.querySelectorAll('a.tag').forEach(x => { tags.add(x.textContent.trim()) }); if (tags.length > 0 && element_writable(ref = document.getElementById('tags'))) { ref.value = tags.toString(); } }, }); return true; } return false; function join_authors(nodeList) { if (typeof nodeList != 'object') return null; var authors = []; nodeList.forEach(k => { authors.push(k.textContent.trim()) }); return authors.join(' & '); } } function preview(n) { if (!prefs.auto_preview) return; var btn = document.querySelector('input.button_preview_' + n + '[type="button"][value="Preview"]'); if (btn != null) btn.click(); } function html2php(node, url) { var text = ''; if (node instanceof HTMLElement) node.childNodes.forEach(function(ch) { if (ch.nodeType == 3) { text += ch.data.replace(/\s+/g, ' '); } else if (ch.nodeName == 'P') { text += '\n' + html2php(ch, url); } else if (ch.nodeName == 'DIV') { text += '\n' + html2php(ch, url) + '\n\n'; } else if (ch.nodeName == 'LABEL') { text += '\n\n[b]' + html2php(ch, url) + '[/b]'; } else if (ch.nodeName == 'SPAN') { text += html2php(ch, url); } else if (ch.nodeName == 'BR' || ch.nodeName == 'HR') { text += '\n'; } else if (ch.nodeName == 'B' || ch.nodeName == 'STRONG') { text += '[b]' + html2php(ch, url) + '[/b]'; } else if (ch.nodeName == 'I' || ch.nodeName == 'EM') { text += '[i]' + html2php(ch, url) + '[/i]'; } else if (ch.nodeName == 'U') { text += '[u]' + html2php(ch, url) + '[/u]'; } else if (ch.nodeName == 'CODE') { text += '[pre]' + ch.textContent + '[/pre]'; } else if (ch.nodeName == 'A') { text += ch.textContent.trim() ? '[url=' + de_anonymize(ch.href) + ']' + ch.textContent.replace(/\s+/g, ' ') + '[/url]' : '[url]' + de_anonymize(ch.href) + '[/url]'; } else if (ch.nodeName == 'IMG') { text += '[img]' + (ch.dataset.src || ch.src) + '[/img]'; } }); return text; //.replace(/\n{3,}/, '\n\n'); } function de_anonymize(uri) { return typeof uri == 'string' ? uri.replace(/^https?:\/\/(?:www\.)?anonymz\.com\/\?/i, '') : null; } function write_description(desc) { if (typeof desc != 'string') return; if (element_writable(ref = document.getElementById('desc'))) ref.value = desc; if ((ref = document.getElementById('body')) != null && !ref.disabled) { if (ref.textLength > 0) ref.value += '\n\n'; ref.value += desc; } } function setImage(url) { var image = document.getElementById('image') || document.querySelector('input[name="image"]'); if (!element_writable(image)) return false; image.value = url; if (prefs.auto_preview_cover) { if ((child = document.getElementById('cover preview')) == null) { elem = document.createElement('div'); elem.style.paddingTop = '10px'; child = document.createElement('img'); child.id = 'cover preview'; child.style.width = '90%'; elem.append(child); image.parentNode.previousElementSibling.append(elem); } child.src = url; } // Re-Host to PTPIMG if (prefs.auto_rehost_cover) { var rehost_btn = document.querySelector('input.rehost_it_cover[type="button"]'); if (rehost_btn != null) { rehost_btn.click(); } else { var pr = rehostImgs([url]); if (pr != null) pr.then(new_urls => { image.value = new_urls[0] }); } } } // PTPIMG rehoster taken from `PTH PTPImg It` function rehostImgs(urls) { if (!Array.isArray(urls)) return null; var config = JSON.parse(window.localStorage.ptpimg_it); return config.api_key ? new Promise(ptpimg_upload_urls).catch(m => { alert(m) }) : null; function ptpimg_upload_urls(resolve, reject) { const boundary = 'NN-GGn-PTPIMG'; var data = '--' + boundary + "\n"; data += 'Content-Disposition: form-data; name="link-upload"\n\n'; data += urls.map(function(url) { return url.toLowerCase().indexOf('://reho.st/') < 0 && url.toLowerCase().indexOf('discogs.com') >= 0 ? 'https://reho.st/' + url : url; }).join('\n') + '\n'; data += '--' + boundary + '\n'; data += 'Content-Disposition: form-data; name="api_key"\n\n'; data += config.api_key + '\n'; data += '--' + boundary + '--'; GM_xmlhttpRequest({ method: 'POST', url: 'https://ptpimg.me/upload.php', responseType: 'json', headers: { 'Content-type': 'multipart/form-data; boundary=' + boundary, }, data: data, onload: response => { if (response.status != 200) reject('Response error ' + response.status); resolve(response.response.map(item => 'https://ptpimg.me/' + item.code + '.' + item.ext)); }, }); } } function element_writable(elem) { return elem != null && !elem.disabled && (overwrite || !elem.value) } } function add_artist() { exec(function() { AddArtistField() }) } function array_homogenous(arr) { return arr.every(k => k === arr[0]) } 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 makeTimeString(duration) { let t = Math.abs(Math.round(duration)); let H = Math.floor(t / 60 ** 2); let M = Math.floor(t / 60 % 60); let S = t % 60; return (duration < 0 ? '-' : '') + (H > 0 ? H + ':' + M.toString().padStart(2, '0') : M.toString()) + ':' + S.toString().padStart(2, '0'); } function timestrToTime(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 != '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()); } function isRED() { return document.domain.toLowerCase().endsWith('redacted.ch') } function isNWCD() { return document.domain.toLowerCase().endsWith('notwhat.cd') } function isOrpheus() { return document.domain.toLowerCase().endsWith('orpheus.network') } function reInParenthesis(expr) { return new RegExp('\\s+\\([^\\(\\)]*'.concat(expr, '[^\\(\\)]*\\)$'), 'i') } function reInBrackets(expr) { return new RegExp('\\s+\\[[^\\[\\]]*'.concat(expr, '[^\\[\\]]*\\]$'), 'i') } function matchCaseless(str) { return str.toLowerCase() == this.toLowerCase() } Array.prototype.includesCaseless = function(str) { return this.find(matchCaseless, str) != undefined }; function addMessage(text, cls) { messages = document.getElementById('UA messages'); if (messages == null) { var ua = document.getElementById('upload assistant'); if (ua == null) return null; messages = document.createElement('TR'); if (messages == null) return null; messages.id = 'UA messages'; ua.children[0].append(messages); elem = document.createElement('TD'); if (elem == null) return null; elem.colSpan = 2; elem.style.padding = '15px'; elem.style.textAlign = 'left'; messages.append(elem); } else { elem = messages.children[0]; // tbody if (elem == null) return null; } var div = document.createElement('DIV'); div.classList.add('ua-messages', cls); div.textContent = text; return elem.appendChild(div); }