您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Musicbrainz function library.
当前为
此脚本不应直接安装。它是供其他脚本使用的外部库,要使用该库请加入元指令 // @require https://update.gf.qytechs.cn/scripts/5140/18914/MusicBrainz%20function%20library.js
// ==UserScript== // @name MusicBrainz function library // @namespace http://www.jens-bertram.net/userscripts/mbz-lib // @description Musicbrainz function library. // @require https://code.jquery.com/jquery-2.1.1.min.js // @version 0.2.0beta // @grant none // @supportURL https://github.com/JensBee/userscripts // @license MIT // ==/UserScript== window.MBZ = {}; MBZ.baseUrl = 'https://musicbrainz.org/'; MBZ.iconUrl = MBZ.baseUrl + 'favicon.ico', MBZ.Html = { /** * Add CSS entry to pages <head/>. * @param style definition to add */ _addGlobalStyle: function(css) { if ($('head').length == 0) { $('body').append($('<head>')); } var style = $('head>style'); if (style.length == 0) { style = $('<style>'); style.attr('type', 'text/css'); $('head').append(style); } style.append(css); }, _init: function() { this._addGlobalStyle( 'button.mbzButton {cursor:pointer;' + 'text-decoration:none; text-shadow:-1px -1px 0 rgba(255,201,97,0.3); font-weight:bold; color:#000;' + 'padding:5px 5px 5px 25px; border-radius:5px;' + 'border-top:1px solid #736CAE; border-left:1px solid #736CAE;' + 'border-bottom:1px solid #FFC961; border-right:1px solid #FFC961;' + 'background:#FFE3B0 url("' + MBZ.iconUrl + '") no-repeat 5px center;}' + 'button.mbzButton:hover {' + 'border:1px solid #454074; background-color:#FFD88C;}' + 'button.mbzButton:disabled {cursor:default;' + 'border:1px solid #ccc; background-color:#ccc; color:#5a5a5a;}' ); }, /** * Create a MusicBrainz link. * @params[type] type to link to (e.g. release) * @params[id] mbid to link to (optional) * @params[more] stuff to add after mbid + '/' (optional) * @return plain link text */ getLink: function (params) { return MBZ.baseUrl + params.type + '/' + (params.id ? params.id + '/' : '') + (params.more || ''); }, /** * Create a MusicBrainz link. * @params[type] type to link to (e.g. release) * @params[id] mbid to link to (optional) * @params[more] stuff to add after mbid + '/' (optional) * @params[title] link title attribute (optional) * @params[text] link text (optional) * @params[before] stuff to put before link (optional) * @params[after] stuff to put after link (optional) * @params[icon] true/false: include MusicBrainz icon (optional, default: true) * @return link jQuery object */ getLinkElement: function (params) { params.icon = (typeof params.icon !== 'undefined' && params.icon == false ? false : true); var retEl = $('<div style="display:inline-block;">'); if (params.before) { retEl.append(params.before); } var linkEl = $('<a>' + (params.icon ? this.mbzIcon : '') + (params.text || '') + '</a>'); linkEl.attr('href', this.getLink({ type: params.type, id: params.id, more: params.more })).attr('target', '_blank'); if (params.title) { linkEl.attr('title', params.title); } retEl.append(linkEl); if (params.after) { retEl.append(params.after); } return retEl; }, getMbzButton: function(caption, title) { var btn = $('<button type="button" class="mbzButton">' + caption + '</button>'); if (title) { btn.attr('title', title); } return btn; }, mbzIcon: '<img src="' + MBZ.iconUrl + '" />' }; MBZ.Html._init(); MBZ.Util = { /** * Convert anything to string. * @data object */ asString: function (data) { if (data == null) { return ''; } switch (typeof data) { case 'string': return data.trim(); case 'object': return data.toString().trim(); case 'function': return 'function'; case 'undefined': return ''; default: data = data + ''; return data.trim(); } }, /** * Creates http + https url from a given https? url. * @url http/https url * @return array with given url prefixed with http + https or single url, if not https? protocol */ expandProtocol: function(url) { var urls; if (url.toLowerCase().startsWith('http')) { var urlPath = url.replace(/^https?:\/\//,''); urls = ['http://' + urlPath, 'https://' + urlPath]; } else { urls = [url]; } return urls; }, /** * Creates http + https urls from a given array of https? urls. * @urls array of http/https urls * @return array with given urls prefixed with http + https */ expandProtocols: function(urls) { var newUrls = []; var self = this; $.each(urls, function(idx, val){ newUrls = newUrls.concat(self.expandProtocol(val)); }); return newUrls; }, /** * Convert HH:MM:SS, MM:SS, SS to seconds. * http://stackoverflow.com/a/9640417 * @str string * @return seconds extracted from initial string */ hmsToSeconds: function (str) { str = MBZ.Util.asString(str); if (str.indexOf(':') > -1) { var p = str.split(':'), s = 0, m = 1; while (p.length > 0) { s += m * parseInt(p.pop(), 10); m *= 60; } return s; } else { return str; } }, /** * Remove a trailing slash from a string * @str string * @return intial string with trailing slash removed */ rmTrSlash: function (str) { if(str.substr(-1) == '/') { return str.substr(0, str.length - 1); } return str; } }; MBZ.CA = { baseUrl: 'https://coverartarchive.org/', // no https here (bad_cert notice) originBaseUrl: 'https://cors-anywhere.herokuapp.com/coverartarchive.org:443/', /** * Create a CoverArtArchive link. * @params[type] type to link to (e.g. release) * @params[id] mbid to link to (optional) * @params[more] stuff to add after mbid (optional) */ getLink: function (params) { return this.originBaseUrl + params.type + '/' + (params.id ? params.id + '/' : '') + (params.more || ''); }, }; /** * MusicBrainz web service v2 interface. */ MBZ.WS = { _baseUrl: MBZ.baseUrl + 'ws/2/', _queue: [], _pollFreq: 1100, _pollInterval: null, /** * Add to request queue. * @params[cb] callback * @params[url] request url * @params[args] callback function parameters object * @params[scope] scope for calling callback function */ _qAdd: function(params) { this._queue.push(params); if (!this._pollInterval) { if (this._queue.length == 1) { this._qPoll(); } this._pollInterval = setInterval(this._qPoll, this._pollFreq); } }, /** * Execute queued requests. */ _qPoll: function() { if (MBZ.WS._queue.length > 0) { var item = MBZ.WS._queue.pop(); $.getJSON(item.url, function(data) { if (item.args) { if (item.scope) { item.cb.call(item.scope, data, item.args); } else { item.cb(data, item.args); } } else { if (item.scope) { item.cb.call(item.scope, data); } else { item.cb(data); } } }).fail(function(jqxhr, textStatus, error) { var err = textStatus + ', ' + error; console.error("Request (" + item.url + ") failed: " + err); if (item.scope) { item.cb.call(item.scope); } else { item.cb(); } }); } else if (MBZ.WS._queue.length == 0 && MBZ.WS._pollInterval) { clearInterval(MBZ.WS._pollInterval); } }, /** * Lookup a musicbrainz url relation * @params[cb] callback function * @params[res] url to lookup * @params[rel] relation type * @params[scope] scope for callback function */ getUrlRelation: function (params) { this._qAdd({ cb: params.cb, url: this._baseUrl + 'url?resource=' + encodeURIComponent(params.res) + '&inc=' + params.rel + '-rels', scope: params.scope }); }, /** * Lookup musicbrainz url relations * @params[urls] array of urls to lookup * @params[rel] relation type * @params[cb] callback function for each response * @params[cbInc] callback for each item looked up * @params[cbDone] callback to call if all items have been looked up * @params[scope] scope for callback functions */ getUrlRelations: function(params) { var self = this; var count = params.urls.length; var current = 0; function localCb(data) { if (params.scope) { params.cb.call(params.scope, data); } else { params.cb(data); } if (typeof params.cbInc === 'function') { if (params.scope) { params.cbInc.call(params.scope); } else { params.cbInc(); } } if (++current == count && typeof params.cbDone === 'function') { if (params.scope) { params.cbDone.call(params.scope); } else { params.cbDone(); } } } $.each(params.urls, function(idx, val) { self.getUrlRelation({ cb: localCb, res: val, rel: params.rel }); }); } }; /** * Release related functions. */ MBZ.Release = function() { var form = $('<form method="post" id="' + MBZ.Release._form.baseName + '-' + (MBZ.Release._form.count++) + '" target="_blank" action="' + MBZ.Release._form.target + '" acceptCharset="UTF-8"></form>'); this.data = { annotation: '', // content artists: [], labels: [], mediums: [], note: '', // content packaging: '', // type releases: [], title: '', // content tracks: [], urls: [] // [target, type] }; function addField(name, value) { name = MBZ.Util.asString(name); value = MBZ.Util.asString(value); if (name.length > 0 && value.length > 0) { form.append($('<input type="hidden" name="' + name + '" value="' + value .replace(/&/g, '&') .replace(/"/g, '"') .replace(/'/g, ''') .replace(/</g, '<') .replace(/>/g, '>') + '"/>')); } } function buildForm(dataSet) { if (dataSet.annotation != '') { addField('annotation', dataSet.annotation); } if (dataSet.artists.length > 0) { $.each(dataSet.artists, function(idx, val) { var prefix = 'artist_credit.names.' + (val.idx || idx); addField(prefix + '.name', val.cred); addField(prefix + '.mbid', val.id); addField(prefix + '.artist.name', val.name); addField(prefix + '.join_phrase', val.join); }); } if (dataSet.labels.length > 0) { $.each(dataSet.labels, function(idx, val) { var prefix = 'labels.' + (val.idx || idx); addField(prefix + '.mbid', val.id); addField(prefix + '.name', val.name); addField(prefix + '.catalog_number', val.catNo); }); } if (dataSet.note != '') { addField('edit_note', dataSet.note); } if (dataSet.releases.length > 0) { $.each(dataSet.releases, function(idx, val) { var prefix = 'events.' + (val.idx || idx); addField(prefix + '.date.year', val.y); addField(prefix + '.date.month', val.m); addField(prefix + '.date.day', val.d); addField(prefix + '.country', val.cc); }); } $.each(dataSet.mediums, function(idx, val) { var prefix = 'mediums.' + (val.idx || idx); addField(prefix + '.format', val.fmt); addField(prefix + '.name', val.name); }); if (dataSet.packaging != '') { addField('packaging', dataSet.packaging); } if (dataSet.title != '') { addField('name', dataSet.title); } $.each(dataSet.tracks, function(idx, val) { var prefix = 'mediums.' + val.med + '.track.' + (val.idx || idx); addField(prefix + '.name', val.tit); addField(prefix + '.number', val.num); addField(prefix + '.recording', val.recId); addField(prefix + '.length', val.dur); if (val.artists) { $.each(val.artists, function(aIdx, aVal) { var aPrefix = prefix + '.artist_credit.names.' + (aVal.idx || aIdx); addField(aPrefix + '.name', aVal.cred); addField(aPrefix + '.mbid', aVal.id); addField(aPrefix + '.artist.name', aVal.name); addField(aPrefix + '.join_phrase', aVal.join); }); } }); if (dataSet.urls.length > 0) { $.each(dataSet.urls, function(idx, val) { addField('urls.' + idx + '.url', val[0]); addField('urls.' + idx + '.link_type', val[1]); }); } } /** * Submit data to musicbrainz. */ this.submitRelease = function() { buildForm(this.data); $('body').append(form); form.submit(); }; }; MBZ.Release._relationCb = function(data) { if (!data) { return {}; } if (data.relations) { var rels = {_res: data.resource}; $.each(data.relations, function(idx, val) { var id = val.release.id; var type = val.type; if (!rels[id]) { rels[id] = []; } if (rels[id].indexOf(type) == -1) { rels[id].push(type); } }); return rels; } }; MBZ.Release._form = { baseName: 'mbAddReleaseForm', count: 0, target: MBZ.baseUrl + 'release/add' }; /** * Lookup a musicbrainz url relation for 'release' type. * @params[cb] callback function * @params[res] url to lookup * @params[scope] scope for callback function */ MBZ.Release.getUrlRelation = function(params) { function innerCb(cbData) { if (params.scope) { params.cb.call(params.scope, MBZ.Release._relationCb(cbData)); } else { params.cb(MBZ.Release._relationCb(cbData)); } } MBZ.WS.getUrlRelation({ cb: innerCb, res: params.res, rel: 'release', scope: params.scope }); }; /** * Lookup musicbrainz url relations for 'release' type. * @params[urls] array of urls to lookup * @params[cb] callback function for each response * @params[cbInc] callback for each item looked up * @params[cbDone] callback to call if all items have been looked up * @params[scope] scope for callback functions */ MBZ.Release.getUrlRelations = function(params) { function innerCb(cbData) { if (params.scope) { params.cb.call(params.scope, MBZ.Release._relationCb(cbData)); } else { params.cb(MBZ.Release._relationCb(cbData)); } } MBZ.WS.getUrlRelations({ urls: params.urls, rel: 'release', cb: innerCb, cbInc: params.cbInc, cbDone: params.cbDone, scope: params.scope }); }; MBZ.Release.prototype = { /** * Add an artist entry. * @params plain artist name as string or object: * params[cred] artist name as credited * params[id] artists mbid * params[idx] position * params[join] phrase to join with next artist * params[name] artist name */ addArtist: function(params) { if (typeof params === 'string') { this.data.artists.push({name: params}); } else { this.data.artists.push(params); } }, /** * Add a label entry. * @params plain label name as string or object. * params[catNo] catalog number * params[id] mbid * params[idx] position * params[name] label name */ addLabel: function(params) { if (typeof params === 'string') { this.data.labels.push({name: params}); } else { this.data.labels.push(params); } }, /** * Set format of a medium. * @params[idx] position * @params[fmt] format type name * @params[name] name */ addMedium: function(params) { this.data.mediums.push(params) }, /** * Add a release event. * @params[y] YYYY * @params[m] MM * @params[d] DD * @params[cc] country code * @params[idx] position */ addRelease: function(params) { this.data.releases.push(params); }, /** * Add a track. * @params[med] medium number * @params[tit] track name * @params[idx] track number * @params[num] track number (free-form) * @params[dur] length in MM:SS or milliseconds * @params[recId] mbid of existing recording to associate * @params[artists] array of objects: * obj[cred] artist name as credited * obj[id] artists mbid * obj[idx] position * obj[join] phrase to join with next artist * obj[name] artist name */ addTrack: function(params) { this.data.tracks.push(params); }, /** * @url target url * @type musicbrainz url type * @return true if value was added */ addUrl: function(url, type) { url = MBZ.Util.asString(url); type = MBZ.Util.asString(type); this.data.urls.push([url, type]); return true; }, /** * Dump current data (best viewed in FireBug). */ dump: function() { console.log(this.data); }, /** * @content annotation content * @return old value */ setAnnotation: function(content) { var old = this.data.annotation; this.data.annotation = MBZ.Util.asString(content); return old; }, /** * @content edeting note content * @return old value */ setNote: function(content) { var old = this.data.note; this.data.note = MBZ.Util.asString(content); return old; }, /** * @content packaging type * @return old value */ setPackaging: function(type) { var old = this.data.packaging; this.data.packaging = MBZ.Util.asString(type); return old; }, /** * @name release title * @return old value */ setTitle: function(name) { var old = this.data.title; this.data.title = MBZ.Util.asString(name); return old; }, };
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址