Compare commits
1 Commits
main
...
a486e58e3e
Author | SHA1 | Date | |
---|---|---|---|
a486e58e3e |
18
animebytes_display_anime_names/display_anime_names.js
Normal file
18
animebytes_display_anime_names/display_anime_names.js
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
// ==UserScript==
|
||||||
|
// @name Display anime names in collages
|
||||||
|
// @namespace Violentmonkey Scripts
|
||||||
|
// @match https://animebytes.tv/collage.php
|
||||||
|
// @grant none
|
||||||
|
// @version 1.1
|
||||||
|
// @author Lukáš Kucharczyk
|
||||||
|
// @description Displays anime titles underneath posters on the collage page.
|
||||||
|
// @downloadURL https://git.kucharczyk.xyz/lukas/userscripts/raw/branch/main/animebytes_display_anime_names/display_anime_names.js
|
||||||
|
// ==/UserScript==
|
||||||
|
let r = document.querySelectorAll('#collage_table tbody tr td')
|
||||||
|
r.forEach((element) => {
|
||||||
|
let anime_title = element.querySelector('a img').attributes['alt'].value
|
||||||
|
let anime_title_div = document.createElement('div')
|
||||||
|
anime_title_div.style = 'width: 125px; height: 50px;'
|
||||||
|
element.appendChild(anime_title_div)
|
||||||
|
anime_title_div.innerText = anime_title
|
||||||
|
})
|
@ -1,30 +0,0 @@
|
|||||||
// ==UserScript==
|
|
||||||
// @name Display anime names under pictures
|
|
||||||
// @namespace Violentmonkey Scripts
|
|
||||||
// @match https://animebytes.tv/collage.php
|
|
||||||
// @match https://animebytes.tv/company.php
|
|
||||||
// @match https://animebytes.tv/
|
|
||||||
// @grant none
|
|
||||||
// @version 1.4
|
|
||||||
// @author Lukáš Kucharczyk
|
|
||||||
// @description Displays anime titles underneath posters on the collage page.
|
|
||||||
// @downloadURL https://git.kucharczyk.xyz/lukas/userscripts/raw/branch/main/animebytes_display_anime_names/display_anime_names.user.js
|
|
||||||
// @supportURL https://git.kucharczyk.xyz/lukas/userscripts
|
|
||||||
// ==/UserScript==
|
|
||||||
let url_selectors = {
|
|
||||||
"^(https?://)?animebytes.tv/?$": ".aot_inner",
|
|
||||||
"^(https?://)?animebytes.tv/(collage|company).php": "#collage_table tbody tr td"
|
|
||||||
}
|
|
||||||
let selectors_as_array = Object.entries(url_selectors)
|
|
||||||
let selector = selectors_as_array.filter(([key, value]) => {
|
|
||||||
let regex = new RegExp(key)
|
|
||||||
return regex.test(window.location)
|
|
||||||
})
|
|
||||||
let elements = document.querySelectorAll(selector[0][1])
|
|
||||||
elements.forEach((element) => {
|
|
||||||
let anime_title = element.querySelector('a img').attributes['alt'].value
|
|
||||||
let anime_title_div = document.createElement('div')
|
|
||||||
anime_title_div.style = 'width: 125px; height: 50px;'
|
|
||||||
element.appendChild(anime_title_div)
|
|
||||||
anime_title_div.innerText = anime_title
|
|
||||||
})
|
|
@ -1,144 +0,0 @@
|
|||||||
// ==UserScript==
|
|
||||||
// @name Import Deezer releases into MusicBrainz
|
|
||||||
// @namespace https://github.com/murdos/musicbrainz-userscripts/
|
|
||||||
// @description One-click importing of releases from deezer.com into MusicBrainz
|
|
||||||
// @version 2022.12.6.1
|
|
||||||
// @downloadURL https://git.kucharczyk.xyz/lukas/userscripts/raw/branch/main/deezer_importer/deezer_importer.user.js
|
|
||||||
// @match http*://www.deezer.com/*/album/*
|
|
||||||
// @require https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js
|
|
||||||
// @require mbimport.js
|
|
||||||
// @require logger.js
|
|
||||||
// @require mbimportstyle.js
|
|
||||||
// @icon https://raw.githubusercontent.com/murdos/musicbrainz-userscripts/master/assets/images/Musicbrainz_import_logo.png
|
|
||||||
// @grant GM_xmlhttpRequest
|
|
||||||
// @grant GM.xmlHttpRequest
|
|
||||||
// ==/UserScript==
|
|
||||||
|
|
||||||
// prevent JQuery conflicts, see http://wiki.greasespot.net/@grant
|
|
||||||
this.$ = this.jQuery = jQuery.noConflict(true);
|
|
||||||
|
|
||||||
$(document).ready(function () {
|
|
||||||
let gmXHR;
|
|
||||||
|
|
||||||
if (typeof GM_xmlhttpRequest != 'undefined') {
|
|
||||||
gmXHR = GM_xmlhttpRequest;
|
|
||||||
} else if (GM.xmlHttpRequest != 'undefined') {
|
|
||||||
gmXHR = GM.xmlHttpRequest;
|
|
||||||
} else {
|
|
||||||
LOGGER.error('Userscript requires GM_xmlHttpRequest or GM.xmlHttpRequest');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// allow 1 second for Deezer SPA to initialize
|
|
||||||
window.setTimeout(function () {
|
|
||||||
MBImportStyle();
|
|
||||||
let releaseUrl = window.location.href.replace(/\?.*$/, '').replace(/#.*$/, '');
|
|
||||||
let releaseId = releaseUrl.replace(/^https?:\/\/www\.deezer\.com\/[^/]+\/album\//i, '');
|
|
||||||
let deezerApiUrl = `https://api.deezer.com/album/${releaseId}`;
|
|
||||||
|
|
||||||
gmXHR({
|
|
||||||
method: 'GET',
|
|
||||||
url: deezerApiUrl,
|
|
||||||
onload: function (resp) {
|
|
||||||
try {
|
|
||||||
let release = parseDeezerRelease(releaseUrl, JSON.parse(resp.responseText));
|
|
||||||
insertLink(release, releaseUrl);
|
|
||||||
} catch (e) {
|
|
||||||
LOGGER.error('Failed to parse release: ', e);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onerror: function (resp) {
|
|
||||||
LOGGER.error('AJAX status:', resp.status);
|
|
||||||
LOGGER.error('AJAX response:', resp.responseText);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}, 1000);
|
|
||||||
});
|
|
||||||
|
|
||||||
function parseDeezerRelease(releaseUrl, data) {
|
|
||||||
let releaseDate = data.release_date.split('-');
|
|
||||||
|
|
||||||
let release = {
|
|
||||||
artist_credit: [],
|
|
||||||
title: data.title,
|
|
||||||
year: releaseDate[0],
|
|
||||||
month: releaseDate[1],
|
|
||||||
day: releaseDate[2],
|
|
||||||
packaging: 'None',
|
|
||||||
country: 'XW',
|
|
||||||
status: 'official',
|
|
||||||
language: 'eng',
|
|
||||||
script: 'Latn',
|
|
||||||
type: '',
|
|
||||||
urls: [],
|
|
||||||
labels: [],
|
|
||||||
discs: [],
|
|
||||||
};
|
|
||||||
|
|
||||||
$.each(data.contributors, function (index, artist) {
|
|
||||||
if (artist.role != 'Main') return true;
|
|
||||||
|
|
||||||
let ac = {
|
|
||||||
artist_name: artist.name,
|
|
||||||
joinphrase: index == data.contributors.length - 1 ? '' : ', ',
|
|
||||||
};
|
|
||||||
|
|
||||||
if (artist.name == 'Various Artists') {
|
|
||||||
ac = MBImport.specialArtist('various_artists', ac);
|
|
||||||
}
|
|
||||||
|
|
||||||
release.artist_credit.push(ac);
|
|
||||||
});
|
|
||||||
|
|
||||||
let disc = {
|
|
||||||
format: 'Digital Media',
|
|
||||||
title: '',
|
|
||||||
tracks: [],
|
|
||||||
};
|
|
||||||
|
|
||||||
$.each(data.tracks.data, function (index, track) {
|
|
||||||
let t = {
|
|
||||||
number: index + 1,
|
|
||||||
title: track.title_short,
|
|
||||||
duration: track.duration * 1000,
|
|
||||||
artist_credit: [],
|
|
||||||
};
|
|
||||||
|
|
||||||
// ignore pointless "(Original Mix)" in title version
|
|
||||||
if (track.title_version && !track.title_version.match(/^\s*\(Original Mix\)\s*$/i)) {
|
|
||||||
t.title += ` ${track.title_version}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
t.artist_credit.push({ artist_name: track.artist.name });
|
|
||||||
|
|
||||||
disc.tracks.push(t);
|
|
||||||
});
|
|
||||||
|
|
||||||
release.discs.push(disc);
|
|
||||||
|
|
||||||
release.urls.push({
|
|
||||||
link_type: MBImport.URL_TYPES.stream_for_free,
|
|
||||||
url: releaseUrl,
|
|
||||||
});
|
|
||||||
release.labels.push({ name: data.label });
|
|
||||||
release.type = data.record_type;
|
|
||||||
release.barcode = data.upc;
|
|
||||||
|
|
||||||
return release;
|
|
||||||
}
|
|
||||||
|
|
||||||
function insertLink(release, release_url) {
|
|
||||||
let editNote = MBImport.makeEditNote(release_url, 'Deezer');
|
|
||||||
let parameters = MBImport.buildFormParameters(release, editNote);
|
|
||||||
|
|
||||||
let mbUI = $(
|
|
||||||
`<div class="toolbar-item">
|
|
||||||
${MBImport.buildFormHTML(parameters)}
|
|
||||||
</div><div class="toolbar-item">
|
|
||||||
${MBImport.buildSearchButton(release)}
|
|
||||||
</div>`
|
|
||||||
).hide();
|
|
||||||
|
|
||||||
$('.page-topbar').append(mbUI);
|
|
||||||
mbUI.show();
|
|
||||||
}
|
|
@ -1,49 +0,0 @@
|
|||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Logger
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
var LOGGER = (function () {
|
|
||||||
let LOG_LEVEL = 'info';
|
|
||||||
|
|
||||||
function fnDebug() {
|
|
||||||
if (LOG_LEVEL == 'debug') {
|
|
||||||
_log('DEBUG', arguments);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function fnInfo() {
|
|
||||||
if (LOG_LEVEL == 'debug' || LOG_LEVEL === 'info') {
|
|
||||||
_log('INFO', arguments);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function fnError() {
|
|
||||||
_log('ERROR', arguments);
|
|
||||||
}
|
|
||||||
|
|
||||||
function fnSetLevel(level) {
|
|
||||||
LOG_LEVEL = level;
|
|
||||||
}
|
|
||||||
|
|
||||||
// --------------------------------------- privates ----------------------------------------- //
|
|
||||||
|
|
||||||
function _log(level, args) {
|
|
||||||
// Prepends log level to things that will be logged
|
|
||||||
args = Array.prototype.slice.call(args);
|
|
||||||
args.unshift(`[${level}]`);
|
|
||||||
try {
|
|
||||||
console.log.apply(this, args);
|
|
||||||
} catch (e) {
|
|
||||||
// do nothing
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---------------------------------- expose publics here ------------------------------------ //
|
|
||||||
|
|
||||||
return {
|
|
||||||
debug: fnDebug,
|
|
||||||
info: fnInfo,
|
|
||||||
error: fnError,
|
|
||||||
setLevel: fnSetLevel,
|
|
||||||
};
|
|
||||||
})();
|
|
@ -1,425 +0,0 @@
|
|||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// MusicBrainz Import helper functions
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
/*
|
|
||||||
* How to use this module?
|
|
||||||
*
|
|
||||||
* - First build a release object (see expected format below) that you'll fill in from source of data
|
|
||||||
* - Call as follows, e.g.:
|
|
||||||
* var parameters = MBImport.buildFormParameters(parsedRelease, optionalEditNote);
|
|
||||||
* - Then build the HTML that you'll inject into source site page:
|
|
||||||
* var formHtml = MBImport.buildFormHTML(parameters);
|
|
||||||
* - Addinionally, you can inject a search link to verify that the release is not already known by MusicBrainz:
|
|
||||||
* var linkHtml = MBImport.buildSearchLink(parsedRelease);
|
|
||||||
*
|
|
||||||
* Expected format of release object:
|
|
||||||
*
|
|
||||||
* release = {
|
|
||||||
* title,
|
|
||||||
* artist_credit,
|
|
||||||
* type,
|
|
||||||
* status,
|
|
||||||
* secondary_types,
|
|
||||||
* language,
|
|
||||||
* script,
|
|
||||||
* packaging,
|
|
||||||
* country,
|
|
||||||
* year,
|
|
||||||
* month,
|
|
||||||
* day,
|
|
||||||
* labels = [ { name, mbid, catno }, ... ],
|
|
||||||
* barcode,
|
|
||||||
* comment,
|
|
||||||
* annotation,
|
|
||||||
* urls = [ {url, link_type }, ... ],
|
|
||||||
* discs = [
|
|
||||||
* {
|
|
||||||
* title,
|
|
||||||
* format,
|
|
||||||
* tracks = [
|
|
||||||
* { number, title, duration, artist_credit },
|
|
||||||
* ...
|
|
||||||
* ]
|
|
||||||
* },
|
|
||||||
* ...
|
|
||||||
* ],
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* where 'artist_credit' has the following format:
|
|
||||||
*
|
|
||||||
* artist_credit = [
|
|
||||||
* {
|
|
||||||
* credited_name,
|
|
||||||
* artist_name,
|
|
||||||
* mbid,
|
|
||||||
* joinphrase
|
|
||||||
* },
|
|
||||||
* ...
|
|
||||||
* ]
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
var MBImport = (function () {
|
|
||||||
// --------------------------------------- publics ----------------------------------------- //
|
|
||||||
|
|
||||||
let special_artists = {
|
|
||||||
various_artists: {
|
|
||||||
name: 'Various Artists',
|
|
||||||
mbid: '89ad4ac3-39f7-470e-963a-56509c546377',
|
|
||||||
},
|
|
||||||
unknown: {
|
|
||||||
name: '[unknown]',
|
|
||||||
mbid: '125ec42a-7229-4250-afc5-e057484327fe',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
let url_types = {
|
|
||||||
purchase_for_download: 74,
|
|
||||||
download_for_free: 75,
|
|
||||||
discogs: 76,
|
|
||||||
purchase_for_mail_order: 79,
|
|
||||||
other_databases: 82,
|
|
||||||
stream_for_free: 85,
|
|
||||||
license: 301,
|
|
||||||
};
|
|
||||||
|
|
||||||
function fnSpecialArtist(key, ac) {
|
|
||||||
let credited_name = '';
|
|
||||||
let joinphrase = '';
|
|
||||||
if (typeof ac !== 'undefined') {
|
|
||||||
joinphrase = ac.joinphrase;
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
artist_name: special_artists[key].name,
|
|
||||||
credited_name: credited_name,
|
|
||||||
joinphrase: joinphrase,
|
|
||||||
mbid: special_artists[key].mbid,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// compute HTML of search link
|
|
||||||
function fnBuildSearchLink(release) {
|
|
||||||
let parameters = searchParams(release);
|
|
||||||
let url_params = [];
|
|
||||||
parameters.forEach(function (parameter) {
|
|
||||||
let value = `${parameter.value}`;
|
|
||||||
url_params.push(encodeURI(`${parameter.name}=${value}`));
|
|
||||||
});
|
|
||||||
return `<a class="musicbrainz_import" href="//musicbrainz.org/search?${url_params.join('&')}">Search in MusicBrainz</a>`;
|
|
||||||
}
|
|
||||||
|
|
||||||
// compute HTML of search button
|
|
||||||
function fnBuildSearchButton(release) {
|
|
||||||
let parameters = searchParams(release);
|
|
||||||
let html = `<form class="musicbrainz_import musicbrainz_import_search" action="//musicbrainz.org/search" method="get" target="_blank" accept-charset="UTF-8" charset="${document.characterSet}">`;
|
|
||||||
parameters.forEach(function (parameter) {
|
|
||||||
let value = `${parameter.value}`;
|
|
||||||
html += `<input type='hidden' value='${value.replace(/'/g, ''')}' name='${parameter.name}'/>`;
|
|
||||||
});
|
|
||||||
html += '<button type="submit" title="Search for this release in MusicBrainz (open a new tab)"><span>Search in MB</span></button>';
|
|
||||||
html += '</form>';
|
|
||||||
return html;
|
|
||||||
}
|
|
||||||
|
|
||||||
function fnSearchUrlFor(type, what) {
|
|
||||||
type = type.replace('-', '_');
|
|
||||||
|
|
||||||
let params = [`query=${luceneEscape(what)}`, `type=${type}`, 'indexed=1'];
|
|
||||||
return `//musicbrainz.org/search?${params.join('&')}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
// compute HTML of import form
|
|
||||||
function fnBuildFormHTML(parameters) {
|
|
||||||
// Build form
|
|
||||||
let innerHTML = `<form class="musicbrainz_import musicbrainz_import_add" action="//musicbrainz.org/release/add" method="post" target="_blank" accept-charset="UTF-8" charset="${document.characterSet}">`;
|
|
||||||
parameters.forEach(function (parameter) {
|
|
||||||
let value = `${parameter.value}`;
|
|
||||||
innerHTML += `<input type='hidden' value='${value.replace(/'/g, ''')}' name='${parameter.name}'/>`;
|
|
||||||
});
|
|
||||||
|
|
||||||
innerHTML +=
|
|
||||||
'<button type="submit" title="Import this release into MusicBrainz (open a new tab)"><img src="//musicbrainz.org/favicon.ico" /><span>Import into MB</span></button>';
|
|
||||||
innerHTML += '</form>';
|
|
||||||
|
|
||||||
return innerHTML;
|
|
||||||
}
|
|
||||||
|
|
||||||
// build form POST parameters that MB is waiting
|
|
||||||
function fnBuildFormParameters(release, edit_note) {
|
|
||||||
// Form parameters
|
|
||||||
let parameters = new Array();
|
|
||||||
appendParameter(parameters, 'name', release.title);
|
|
||||||
|
|
||||||
// Release Artist credits
|
|
||||||
buildArtistCreditsFormParameters(parameters, '', release.artist_credit);
|
|
||||||
|
|
||||||
if (release['secondary_types']) {
|
|
||||||
for (let i = 0; i < release.secondary_types.length; i++) {
|
|
||||||
appendParameter(parameters, 'type', release.secondary_types[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
appendParameter(parameters, 'status', release.status);
|
|
||||||
appendParameter(parameters, 'language', release.language);
|
|
||||||
appendParameter(parameters, 'script', release.script);
|
|
||||||
appendParameter(parameters, 'packaging', release.packaging);
|
|
||||||
|
|
||||||
// ReleaseGroup
|
|
||||||
appendParameter(parameters, 'release_group', release.release_group_mbid);
|
|
||||||
|
|
||||||
// Date + country
|
|
||||||
appendParameter(parameters, 'country', release.country);
|
|
||||||
if (!isNaN(release.year) && release.year != 0) {
|
|
||||||
appendParameter(parameters, 'date.year', release.year);
|
|
||||||
}
|
|
||||||
if (!isNaN(release.month) && release.month != 0) {
|
|
||||||
appendParameter(parameters, 'date.month', release.month);
|
|
||||||
}
|
|
||||||
if (!isNaN(release.day) && release.day != 0) {
|
|
||||||
appendParameter(parameters, 'date.day', release.day);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Barcode
|
|
||||||
appendParameter(parameters, 'barcode', release.barcode);
|
|
||||||
|
|
||||||
// Disambiguation comment
|
|
||||||
appendParameter(parameters, 'comment', release.comment);
|
|
||||||
|
|
||||||
// Annotation
|
|
||||||
appendParameter(parameters, 'annotation', release.annotation);
|
|
||||||
|
|
||||||
// Label + catnos
|
|
||||||
if (Array.isArray(release.labels)) {
|
|
||||||
for (let i = 0; i < release.labels.length; i++) {
|
|
||||||
let label = release.labels[i];
|
|
||||||
appendParameter(parameters, `labels.${i}.name`, label.name);
|
|
||||||
appendParameter(parameters, `labels.${i}.mbid`, label.mbid);
|
|
||||||
if (label.catno != 'none') {
|
|
||||||
appendParameter(parameters, `labels.${i}.catalog_number`, label.catno);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// URLs
|
|
||||||
if (Array.isArray(release.urls)) {
|
|
||||||
for (let i = 0; i < release.urls.length; i++) {
|
|
||||||
let url = release.urls[i];
|
|
||||||
appendParameter(parameters, `urls.${i}.url`, url.url);
|
|
||||||
appendParameter(parameters, `urls.${i}.link_type`, url.link_type);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Mediums
|
|
||||||
let total_tracks = 0;
|
|
||||||
let total_tracks_with_duration = 0;
|
|
||||||
let total_duration = 0;
|
|
||||||
for (let i = 0; i < release.discs.length; i++) {
|
|
||||||
let disc = release.discs[i];
|
|
||||||
appendParameter(parameters, `mediums.${i}.format`, disc.format);
|
|
||||||
appendParameter(parameters, `mediums.${i}.name`, disc.title);
|
|
||||||
|
|
||||||
// Tracks
|
|
||||||
for (let j = 0; j < disc.tracks.length; j++) {
|
|
||||||
let track = disc.tracks[j];
|
|
||||||
total_tracks++;
|
|
||||||
appendParameter(parameters, `mediums.${i}.track.${j}.number`, track.number);
|
|
||||||
appendParameter(parameters, `mediums.${i}.track.${j}.name`, track.title);
|
|
||||||
let tracklength = '?:??';
|
|
||||||
let duration_ms = hmsToMilliSeconds(track.duration);
|
|
||||||
if (!isNaN(duration_ms)) {
|
|
||||||
tracklength = duration_ms;
|
|
||||||
total_tracks_with_duration++;
|
|
||||||
total_duration += duration_ms;
|
|
||||||
}
|
|
||||||
appendParameter(parameters, `mediums.${i}.track.${j}.length`, tracklength);
|
|
||||||
appendParameter(parameters, `mediums.${i}.track.${j}.recording`, track.recording);
|
|
||||||
buildArtistCreditsFormParameters(parameters, `mediums.${i}.track.${j}.`, track.artist_credit);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Guess release type if not given
|
|
||||||
if (!release.type && release.title && total_tracks == total_tracks_with_duration) {
|
|
||||||
release.type = fnGuessReleaseType(release.title, total_tracks, total_duration);
|
|
||||||
}
|
|
||||||
appendParameter(parameters, 'type', release.type);
|
|
||||||
|
|
||||||
// Add Edit note parameter
|
|
||||||
appendParameter(parameters, 'edit_note', edit_note);
|
|
||||||
|
|
||||||
return parameters;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert a list of artists to a list of artist credits with joinphrases
|
|
||||||
function fnArtistCredits(artists_list) {
|
|
||||||
let artists = artists_list.map(function (item) {
|
|
||||||
return { artist_name: item };
|
|
||||||
});
|
|
||||||
if (artists.length > 2) {
|
|
||||||
let last = artists.pop();
|
|
||||||
last.joinphrase = '';
|
|
||||||
let prev = artists.pop();
|
|
||||||
prev.joinphrase = ' & ';
|
|
||||||
for (let i = 0; i < artists.length; i++) {
|
|
||||||
artists[i].joinphrase = ', ';
|
|
||||||
}
|
|
||||||
artists.push(prev);
|
|
||||||
artists.push(last);
|
|
||||||
} else if (artists.length == 2) {
|
|
||||||
artists[0].joinphrase = ' & ';
|
|
||||||
}
|
|
||||||
let credits = [];
|
|
||||||
// re-split artists if featuring or vs
|
|
||||||
artists.map(function (item) {
|
|
||||||
let c = item.artist_name.replace(/\s*\b(?:feat\.?|ft\.?|featuring)\s+/gi, ' feat. ');
|
|
||||||
c = c.replace(/\s*\(( feat. )([^\)]+)\)/g, '$1$2');
|
|
||||||
c = c.replace(/\s*\b(?:versus|vs\.?)\s+/gi, ' vs. ');
|
|
||||||
c = c.replace(/\s+/g, ' ');
|
|
||||||
let splitted = c.split(/( feat\. | vs\. )/);
|
|
||||||
if (splitted.length == 1) {
|
|
||||||
credits.push(item); // nothing to split
|
|
||||||
} else {
|
|
||||||
let new_items = [];
|
|
||||||
let n = 0;
|
|
||||||
for (let i = 0; i < splitted.length; i++) {
|
|
||||||
if (n && (splitted[i] == ' feat. ' || splitted[i] == ' vs. ')) {
|
|
||||||
new_items[n - 1].joinphrase = splitted[i];
|
|
||||||
} else {
|
|
||||||
new_items[n++] = {
|
|
||||||
artist_name: splitted[i].trim(),
|
|
||||||
joinphrase: '',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
new_items[n - 1].joinphrase = item.joinphrase;
|
|
||||||
new_items.map(function (newit) {
|
|
||||||
credits.push(newit);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return credits;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Try to guess release type using number of tracks, title and total duration (in millisecs)
|
|
||||||
function fnGuessReleaseType(title, num_tracks, duration_ms) {
|
|
||||||
if (num_tracks < 1) return '';
|
|
||||||
let has_single = !!title.match(/\bsingle\b/i);
|
|
||||||
let has_EP = !!title.match(/\bEP\b/i);
|
|
||||||
if (has_single && has_EP) {
|
|
||||||
has_single = false;
|
|
||||||
has_EP = false;
|
|
||||||
}
|
|
||||||
let perhaps_single = (has_single && num_tracks <= 4) || num_tracks <= 2;
|
|
||||||
let perhaps_EP = has_EP || (num_tracks > 2 && num_tracks <= 6);
|
|
||||||
let perhaps_album = num_tracks > 8;
|
|
||||||
if (isNaN(duration_ms)) {
|
|
||||||
// no duration, try to guess with title and number of tracks
|
|
||||||
if (perhaps_single && !perhaps_EP && !perhaps_album) return 'single';
|
|
||||||
if (!perhaps_single && perhaps_EP && !perhaps_album) return 'EP';
|
|
||||||
if (!perhaps_single && !perhaps_EP && perhaps_album) return 'album';
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
let duration_mn = duration_ms / (60 * 1000);
|
|
||||||
if (perhaps_single && duration_mn >= 1 && duration_mn < 7) return 'single';
|
|
||||||
if (perhaps_EP && duration_mn > 7 && duration_mn <= 30) return 'EP';
|
|
||||||
if (perhaps_album && duration_mn > 30) return 'album';
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
|
|
||||||
// convert HH:MM:SS or MM:SS to milliseconds
|
|
||||||
function hmsToMilliSeconds(str) {
|
|
||||||
/* eslint-disable-next-line use-isnan */
|
|
||||||
if (typeof str == 'undefined' || str === null || str === NaN || str === '') return NaN;
|
|
||||||
if (typeof str == 'number') return str;
|
|
||||||
let t = str.split(':');
|
|
||||||
let s = 0;
|
|
||||||
let m = 1;
|
|
||||||
while (t.length > 0) {
|
|
||||||
s += m * parseInt(t.pop(), 10);
|
|
||||||
m *= 60;
|
|
||||||
}
|
|
||||||
return s * 1000;
|
|
||||||
}
|
|
||||||
|
|
||||||
// convert ISO8601 duration (limited to hours/minutes/seconds) to milliseconds
|
|
||||||
// format looks like PT1H45M5.789S (note: floats can be used)
|
|
||||||
// https://en.wikipedia.org/wiki/ISO_8601#Durations
|
|
||||||
function fnISO8601toMilliSeconds(str) {
|
|
||||||
let regex = /^PT(?:(\d*\.?\d*)H)?(?:(\d*\.?\d*)M)?(?:(\d*\.?\d*)S)?$/,
|
|
||||||
m = str.replace(',', '.').match(regex);
|
|
||||||
if (!m) return NaN;
|
|
||||||
return (3600 * parseFloat(m[1] || 0) + 60 * parseFloat(m[2] || 0) + parseFloat(m[3] || 0)) * 1000;
|
|
||||||
}
|
|
||||||
|
|
||||||
function fnMakeEditNote(release_url, importer_name, format, home = 'https://github.com/murdos/musicbrainz-userscripts') {
|
|
||||||
return `Imported from ${release_url}${format ? ` (${format})` : ''} using ${importer_name} import script from ${home}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
// --------------------------------------- privates ----------------------------------------- //
|
|
||||||
|
|
||||||
function appendParameter(parameters, paramName, paramValue) {
|
|
||||||
if (!paramValue) return;
|
|
||||||
parameters.push({ name: paramName, value: paramValue });
|
|
||||||
}
|
|
||||||
|
|
||||||
function luceneEscape(text) {
|
|
||||||
let newtext = text.replace(/[-[\]{}()*+?~:\\^!"\/]/g, '\\$&');
|
|
||||||
return newtext.replace('&&', '&&').replace('||', '||');
|
|
||||||
}
|
|
||||||
|
|
||||||
function buildArtistCreditsFormParameters(parameters, paramPrefix, artist_credit) {
|
|
||||||
if (!artist_credit) return;
|
|
||||||
for (let i = 0; i < artist_credit.length; i++) {
|
|
||||||
let ac = artist_credit[i];
|
|
||||||
appendParameter(parameters, `${paramPrefix}artist_credit.names.${i}.name`, ac.credited_name);
|
|
||||||
appendParameter(parameters, `${paramPrefix}artist_credit.names.${i}.artist.name`, ac.artist_name);
|
|
||||||
appendParameter(parameters, `${paramPrefix}artist_credit.names.${i}.mbid`, ac.mbid);
|
|
||||||
if (typeof ac.joinphrase != 'undefined' && ac.joinphrase != '') {
|
|
||||||
appendParameter(parameters, `${paramPrefix}artist_credit.names.${i}.join_phrase`, ac.joinphrase);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function searchParams(release) {
|
|
||||||
let params = [];
|
|
||||||
|
|
||||||
const totaltracks = release.discs.reduce((acc, { tracks }) => acc + tracks.length, 0);
|
|
||||||
let release_artist = '';
|
|
||||||
for (let i = 0; i < release.artist_credit.length; i++) {
|
|
||||||
let ac = release.artist_credit[i];
|
|
||||||
release_artist += ac.artist_name;
|
|
||||||
if (typeof ac.joinphrase != 'undefined' && ac.joinphrase != '') {
|
|
||||||
release_artist += ac.joinphrase;
|
|
||||||
} else {
|
|
||||||
if (i != release.artist_credit.length - 1) release_artist += ', ';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let query =
|
|
||||||
`artist:(${luceneEscape(release_artist)})` +
|
|
||||||
` release:(${luceneEscape(release.title)})` +
|
|
||||||
` tracks:(${totaltracks})${release.country ? ` country:${release.country}` : ''}`;
|
|
||||||
|
|
||||||
appendParameter(params, 'query', query);
|
|
||||||
appendParameter(params, 'type', 'release');
|
|
||||||
appendParameter(params, 'advanced', '1');
|
|
||||||
return params;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---------------------------------- expose publics here ------------------------------------ //
|
|
||||||
|
|
||||||
return {
|
|
||||||
buildSearchLink: fnBuildSearchLink,
|
|
||||||
buildSearchButton: fnBuildSearchButton,
|
|
||||||
buildFormHTML: fnBuildFormHTML,
|
|
||||||
buildFormParameters: fnBuildFormParameters,
|
|
||||||
makeArtistCredits: fnArtistCredits,
|
|
||||||
guessReleaseType: fnGuessReleaseType,
|
|
||||||
hmsToMilliSeconds: hmsToMilliSeconds,
|
|
||||||
ISO8601toMilliSeconds: fnISO8601toMilliSeconds,
|
|
||||||
makeEditNote: fnMakeEditNote,
|
|
||||||
searchUrlFor: fnSearchUrlFor,
|
|
||||||
URL_TYPES: url_types,
|
|
||||||
SPECIAL_ARTISTS: special_artists,
|
|
||||||
specialArtist: fnSpecialArtist,
|
|
||||||
};
|
|
||||||
})();
|
|
@ -1,74 +0,0 @@
|
|||||||
function _add_css(css) {
|
|
||||||
document.head.insertAdjacentHTML('beforeend', `<style>${css.replace(/\s+/g, ' ')}</style>`);
|
|
||||||
}
|
|
||||||
|
|
||||||
function MBImportStyle() {
|
|
||||||
let css_import_button = `
|
|
||||||
.musicbrainz_import button {
|
|
||||||
border-radius:5px;
|
|
||||||
display:inline-block;
|
|
||||||
cursor:pointer;
|
|
||||||
font-family:Arial;
|
|
||||||
font-size:12px !important;
|
|
||||||
padding:3px 6px;
|
|
||||||
text-decoration:none;
|
|
||||||
border: 1px solid rgba(180,180,180,0.8) !important;
|
|
||||||
background-color: rgba(240,240,240,0.8) !important;
|
|
||||||
color: #334 !important;
|
|
||||||
height: 26px ;
|
|
||||||
}
|
|
||||||
.musicbrainz_import button:hover {
|
|
||||||
background-color: rgba(250,250,250,0.9) !important;
|
|
||||||
}
|
|
||||||
.musicbrainz_import button:active {
|
|
||||||
background-color: rgba(170,170,170,0.8) !important;
|
|
||||||
}
|
|
||||||
.musicbrainz_import button img {
|
|
||||||
vertical-align: middle !important;
|
|
||||||
margin-right: 4px !important;
|
|
||||||
height: 16px;
|
|
||||||
}
|
|
||||||
.musicbrainz_import button span {
|
|
||||||
min-height: 16px;
|
|
||||||
display: inline-block;
|
|
||||||
}
|
|
||||||
img[src*="musicbrainz.org"] {
|
|
||||||
display: inline-block;
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
_add_css(css_import_button);
|
|
||||||
}
|
|
||||||
|
|
||||||
function MBSearchItStyle() {
|
|
||||||
let css_search_it = `
|
|
||||||
.mb_valign {
|
|
||||||
display: inline-block;
|
|
||||||
vertical-align: top;
|
|
||||||
}
|
|
||||||
.mb_searchit {
|
|
||||||
width: 16px;
|
|
||||||
height: 16px;
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
background-color: #FFF7BE;
|
|
||||||
border: 0px;
|
|
||||||
vertical-align: top;
|
|
||||||
font-size: 11px;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
a.mb_search_link {
|
|
||||||
color: #888;
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
a.mb_search_link small {
|
|
||||||
font-size: 8px;
|
|
||||||
}
|
|
||||||
.mb_searchit a.mb_search_link:hover {
|
|
||||||
color: darkblue;
|
|
||||||
}
|
|
||||||
.mb_wrapper {
|
|
||||||
display: inline-block;
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
_add_css(css_search_it);
|
|
||||||
}
|
|
@ -1,242 +0,0 @@
|
|||||||
// Class MBLinks : query MusicBrainz for urls and display links for matching urls
|
|
||||||
// The main method is searchAndDisplayMbLink()
|
|
||||||
|
|
||||||
// Example:
|
|
||||||
// $(document).ready(function () {
|
|
||||||
//
|
|
||||||
// var mblinks = new MBLinks('EXAMPLE_MBLINKS_CACHE', 7*24*60); // force refresh of cached links once a week
|
|
||||||
//
|
|
||||||
// var artist_link = 'http://' + window.location.href.match( /^https?:\/\/(.*)\/album\/.+$/i)[1];
|
|
||||||
// mblinks.searchAndDisplayMbLink(artist_link, 'artist', function (link) { $('div#there').before(link); } );
|
|
||||||
//
|
|
||||||
// var album_link = 'http://' + window.location.href.match( /^https?:\/\/(.*\/album\/.+)$/i)[1];
|
|
||||||
// mblinks.searchAndDisplayMbLink(album_link, 'release', function (link) { $('div#there').after(link); } );
|
|
||||||
// }
|
|
||||||
|
|
||||||
// user_cache_key = textual key used to store cached data in local storage
|
|
||||||
// version = optionnal version, to force creation of a cache (ie. when format of keys changes)
|
|
||||||
// expiration = time in minutes before an entry is refreshed, value <= 0 disables cache reads, if undefined or false, use defaults
|
|
||||||
var MBLinks = function (user_cache_key, version, expiration) {
|
|
||||||
this.supports_local_storage = (function () {
|
|
||||||
try {
|
|
||||||
return !!localStorage.getItem;
|
|
||||||
} catch (e) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
|
|
||||||
this.ajax_requests = {
|
|
||||||
// properties: "key": {handler: function, next: property, context: {}}
|
|
||||||
first: '',
|
|
||||||
last: '',
|
|
||||||
empty: function () {
|
|
||||||
return this.first == '';
|
|
||||||
},
|
|
||||||
push: function (key, handler, context) {
|
|
||||||
if (key in this) {
|
|
||||||
this[key].handler = handler;
|
|
||||||
this[key].context = context;
|
|
||||||
} else {
|
|
||||||
this[key] = { handler: handler, next: '', context: context };
|
|
||||||
if (this.first == '') {
|
|
||||||
this.first = this.last = key;
|
|
||||||
} else {
|
|
||||||
this[this.last].next = key;
|
|
||||||
this.last = key;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
shift: function () {
|
|
||||||
if (this.empty()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let key = this.first;
|
|
||||||
let handler = this[key].handler;
|
|
||||||
let context = this[key].context;
|
|
||||||
this.first = this[key].next;
|
|
||||||
delete this[key]; // delete this property
|
|
||||||
return $.proxy(handler, context);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
this.cache = {};
|
|
||||||
this.expirationMinutes = typeof expiration != 'undefined' && expiration !== false ? parseInt(expiration, 10) : 90 * 24 * 60; // default to 90 days
|
|
||||||
let cache_version = 2;
|
|
||||||
this.user_cache_key = user_cache_key;
|
|
||||||
this.cache_key = `${this.user_cache_key}-v${cache_version}${typeof version != 'undefined' ? `.${version}` : ''}`;
|
|
||||||
this.mb_server = '//musicbrainz.org';
|
|
||||||
// overrides link title and img src url (per type), see createMusicBrainzLink()
|
|
||||||
this.type_link_info = {
|
|
||||||
release_group: {
|
|
||||||
title: 'See this release group on MusicBrainz',
|
|
||||||
},
|
|
||||||
place: {
|
|
||||||
img_src: `<img src="${this.mb_server}/static/images/entity/place.svg" height=16 width=16 />`,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
this.initAjaxEngine = function () {
|
|
||||||
let ajax_requests = this.ajax_requests;
|
|
||||||
setInterval(function () {
|
|
||||||
if (!ajax_requests.empty()) {
|
|
||||||
let request = ajax_requests.shift();
|
|
||||||
if (typeof request === 'function') {
|
|
||||||
request();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, 1000);
|
|
||||||
};
|
|
||||||
|
|
||||||
this.initCache = function () {
|
|
||||||
if (!this.supports_local_storage) return;
|
|
||||||
// Check if we already added links for this content
|
|
||||||
this.cache = JSON.parse(localStorage.getItem(this.cache_key) || '{}');
|
|
||||||
// remove old entries
|
|
||||||
this.clearCacheExpired();
|
|
||||||
// remove old cache versions
|
|
||||||
this.removeOldCacheVersions();
|
|
||||||
};
|
|
||||||
|
|
||||||
this.saveCache = function () {
|
|
||||||
if (!this.supports_local_storage) return;
|
|
||||||
try {
|
|
||||||
localStorage.setItem(this.cache_key, JSON.stringify(this.cache));
|
|
||||||
} catch (e) {
|
|
||||||
alert(e);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
this.removeOldCacheVersions = function () {
|
|
||||||
let to_remove = [];
|
|
||||||
for (var i = 0, len = localStorage.length; i < len; ++i) {
|
|
||||||
let key = localStorage.key(i);
|
|
||||||
if (key.indexOf(this.user_cache_key) === 0) {
|
|
||||||
if (key != this.cache_key) {
|
|
||||||
// we don't want to remove current cache
|
|
||||||
to_remove.push(key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// remove old cache keys
|
|
||||||
for (var i = 0; i < to_remove.length; i++) {
|
|
||||||
localStorage.removeItem(to_remove[i]);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
this.clearCacheExpired = function () {
|
|
||||||
//var old_cache_entries = Object.keys(this.cache).length;
|
|
||||||
//console.log("clearCacheExpired " + old_cache_entries);
|
|
||||||
let now = new Date().getTime();
|
|
||||||
let new_cache = {};
|
|
||||||
let that = this;
|
|
||||||
$.each(this.cache, function (key, value) {
|
|
||||||
if (that.is_cached(key)) {
|
|
||||||
new_cache[key] = that.cache[key];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
//var new_cache_entries = Object.keys(new_cache).length;
|
|
||||||
//console.log("Cleared cache entries: " + old_cache_entries + ' -> ' + new_cache_entries);
|
|
||||||
this.cache = new_cache;
|
|
||||||
};
|
|
||||||
|
|
||||||
this.is_cached = function (key) {
|
|
||||||
return (
|
|
||||||
this.cache[key] &&
|
|
||||||
this.expirationMinutes > 0 &&
|
|
||||||
new Date().getTime() < this.cache[key].timestamp + this.expirationMinutes * 60 * 1000
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Search for ressource 'url' in local cache, and return the matching MBID if there's only matching MB entity.
|
|
||||||
// If the url is not known by the cache, no attempt will be made to request the MusicBrainz webservice, in order to keep this method synchronous.
|
|
||||||
this.resolveMBID = function (key) {
|
|
||||||
if (this.is_cached(key) && this.cache[key].urls.length == 1) {
|
|
||||||
return this.cache[key].urls[0].slice(-36);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
this.createMusicBrainzLink = function (mb_url, _type) {
|
|
||||||
let title = `See this ${_type} on MusicBrainz`;
|
|
||||||
let img_url = `${this.mb_server}/static/images/entity/${_type}.svg`;
|
|
||||||
let img_src = `<img src="${img_url}" height=16 width=16 />`;
|
|
||||||
// handle overrides
|
|
||||||
let ti = this.type_link_info[_type];
|
|
||||||
if (ti) {
|
|
||||||
if (ti.title) title = ti.title;
|
|
||||||
if (ti.img_url) img_url = ti.img_url;
|
|
||||||
if (ti.img_src) img_src = ti.img_src;
|
|
||||||
}
|
|
||||||
return `<a href="${mb_url}" title="${title}">${img_src}</a> `;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Search for ressource 'url' on MB, for relation of type 'mb_type' (artist, release, label, release-group, ...)
|
|
||||||
// and call 'insert_func' function with matching MB links (a tag built in createMusicBrainzLink) for each
|
|
||||||
// entry found
|
|
||||||
this.searchAndDisplayMbLink = function (url, mb_type, insert_func, key) {
|
|
||||||
let mblinks = this;
|
|
||||||
let _type = mb_type.replace('-', '_'); // underscored type
|
|
||||||
|
|
||||||
if (!key) key = url;
|
|
||||||
if (this.is_cached(key)) {
|
|
||||||
$.each(mblinks.cache[key].urls, function (idx, mb_url) {
|
|
||||||
insert_func(mblinks.createMusicBrainzLink(mb_url, _type));
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
// webservice query url
|
|
||||||
let query = `${mblinks.mb_server}/ws/2/url?resource=${encodeURIComponent(url)}&inc=${mb_type}-rels`;
|
|
||||||
|
|
||||||
// Merge with previous context if there's already a pending ajax request
|
|
||||||
let handlers = [];
|
|
||||||
if (query in mblinks.ajax_requests) {
|
|
||||||
handlers = mblinks.ajax_requests[query].context.handlers;
|
|
||||||
}
|
|
||||||
handlers.push(insert_func);
|
|
||||||
|
|
||||||
mblinks.ajax_requests.push(
|
|
||||||
// key
|
|
||||||
query,
|
|
||||||
|
|
||||||
// handler
|
|
||||||
function () {
|
|
||||||
let ctx = this; // context from $.proxy()
|
|
||||||
let mbl = ctx.mblinks;
|
|
||||||
$.getJSON(ctx.query, function (data) {
|
|
||||||
if ('relations' in data) {
|
|
||||||
mbl.cache[ctx.key] = {
|
|
||||||
timestamp: new Date().getTime(),
|
|
||||||
urls: [],
|
|
||||||
};
|
|
||||||
$.each(data['relations'], function (idx, relation) {
|
|
||||||
if (ctx._type in relation) {
|
|
||||||
let mb_url = `${mbl.mb_server}/${ctx.mb_type}/${relation[ctx._type]['id']}`;
|
|
||||||
if ($.inArray(mb_url, mbl.cache[ctx.key].urls) == -1) {
|
|
||||||
// prevent dupes
|
|
||||||
mbl.cache[ctx.key].urls.push(mb_url);
|
|
||||||
$.each(ctx.handlers, function (i, handler) {
|
|
||||||
handler(mbl.createMusicBrainzLink(mb_url, ctx._type));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
mbl.saveCache();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
// context
|
|
||||||
{
|
|
||||||
key: key, // cache key
|
|
||||||
handlers: handlers, // list of handlers
|
|
||||||
mb_type: mb_type, // musicbrainz type ie. release-group
|
|
||||||
_type: _type, // musicbrainz type '-' replaced, ie. release_group
|
|
||||||
query: query, // json request url
|
|
||||||
mblinks: mblinks, // MBLinks object
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
this.initCache();
|
|
||||||
this.initAjaxEngine();
|
|
||||||
|
|
||||||
return this;
|
|
||||||
};
|
|
@ -1,13 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
set -euo pipefail
|
|
||||||
[[ "${DEBUG:-}" -eq 1 ]] && set -x
|
|
||||||
|
|
||||||
declare -a urls
|
|
||||||
urls=(\
|
|
||||||
https://raw.githubusercontent.com/murdos/musicbrainz-userscripts/master/lib/mbimport.js \
|
|
||||||
https://raw.githubusercontent.com/murdos/musicbrainz-userscripts/master/lib/logger.js \
|
|
||||||
https://raw.githubusercontent.com/murdos/musicbrainz-userscripts/master/lib/mbimportstyle.js
|
|
||||||
https://raw.githubusercontent.com/murdos/musicbrainz-userscripts/master/lib/mblinks.js
|
|
||||||
)
|
|
||||||
|
|
||||||
wget "${urls[@]}"
|
|
@ -6,7 +6,6 @@
|
|||||||
// @version 1.0
|
// @version 1.0
|
||||||
// @author Lukas Kucharczyk (lukas@kucharczyk.xyz)
|
// @author Lukas Kucharczyk (lukas@kucharczyk.xyz)
|
||||||
// @description Automatically redirects Hacker News links to a more modern interface at hn.premii.com.
|
// @description Automatically redirects Hacker News links to a more modern interface at hn.premii.com.
|
||||||
// @downloadURL https://git.kucharczyk.xyz/lukas/userscripts/raw/branch/main/hacker_news_redirect/hn_premii_com_redirect.user.js
|
|
||||||
// ==/UserScript==
|
// ==/UserScript==
|
||||||
(function()
|
(function()
|
||||||
{
|
{
|
@ -1,81 +0,0 @@
|
|||||||
// ==UserScript==
|
|
||||||
// @name JavDB - Copy all magnets
|
|
||||||
// @namespace Violentmonkey Scripts
|
|
||||||
// @match https://javdb.com/v/*
|
|
||||||
// @grant none
|
|
||||||
// @version 1.0
|
|
||||||
// @author Lukáš Kucharczyk
|
|
||||||
// @description Adds a button to copy all magnet links at once.
|
|
||||||
// @downloadURL https://git.kucharczyk.xyz/lukas/userscripts/raw/branch/main/javdb_copy_all_magnets.user.js
|
|
||||||
// @supportURL https://git.kucharczyk.xyz/lukas/userscripts
|
|
||||||
// ==/UserScript==
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {string} type
|
|
||||||
* @param {object} props
|
|
||||||
* @param {...(string|HTMLElement)} children
|
|
||||||
* @return {HTMLElement}
|
|
||||||
*/
|
|
||||||
function elt(type, props, ...children) {
|
|
||||||
let dom = document.createElement(type);
|
|
||||||
if (props) {
|
|
||||||
Object.keys(props).forEach((key) => {
|
|
||||||
if (key === "style") {
|
|
||||||
Object.assign(dom.style, props[key]);
|
|
||||||
} else if (key === "dataset") {
|
|
||||||
Object.keys(props[key]).forEach((dataKey) => {
|
|
||||||
dom.dataset[dataKey] = props[key][dataKey];
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
dom[key] = props[key];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
for (let child of children) {
|
|
||||||
if (typeof child !== "string") dom.appendChild(child);
|
|
||||||
else dom.appendChild(document.createTextNode(child));
|
|
||||||
}
|
|
||||||
return dom;
|
|
||||||
}
|
|
||||||
|
|
||||||
function findElementsWithText(text, tagName = "*") {
|
|
||||||
const elements = document.querySelectorAll(tagName);
|
|
||||||
return Array.from(elements).filter((element) =>
|
|
||||||
element.textContent.includes(text)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const allMagnetButtons = findElementsWithText("Copy", "button");
|
|
||||||
let allMagnetLinks = allMagnetButtons.reduce((prevValue, currentButton) => {
|
|
||||||
return prevValue + "\n" + currentButton.dataset.clipboardText;
|
|
||||||
}, "");
|
|
||||||
|
|
||||||
let copyAllButton = elt(
|
|
||||||
"div",
|
|
||||||
{
|
|
||||||
className: "item columns is-desktop",
|
|
||||||
},
|
|
||||||
elt("div", {
|
|
||||||
className: "magnet-name column is-four-fifths",
|
|
||||||
}),
|
|
||||||
elt(
|
|
||||||
"div",
|
|
||||||
{
|
|
||||||
className: "buttons column",
|
|
||||||
},
|
|
||||||
elt(
|
|
||||||
"button",
|
|
||||||
{
|
|
||||||
type: "button",
|
|
||||||
className: "button is-info copy-to-clipboard",
|
|
||||||
dataset: {
|
|
||||||
clipboardText: allMagnetLinks,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"Copy all magnets"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
const magnetContainer = document.getElementById("magnets-content");
|
|
||||||
magnetContainer.prepend(copyAllButton);
|
|
@ -1,12 +1,12 @@
|
|||||||
// ==UserScript==
|
// ==UserScript==
|
||||||
// @name Last.fm: remove title attributes
|
// @name Remove title attributes
|
||||||
// @namespace Violentmonkey Scripts
|
// @namespace Violentmonkey Scripts
|
||||||
// @match https://www.last.fm/music/*
|
// @match https://www.last.fm/music/*
|
||||||
// @grant none
|
// @grant none
|
||||||
// @version 1.2
|
// @version 1.0
|
||||||
// @author Lukáš Kucharczyk
|
// @author Lukáš Kucharczyk
|
||||||
// @description Removes all title attributes of all <a> tags.
|
// @description Removes all title attributes of all <a> tags.
|
||||||
// @downloadURL https://git.kucharczyk.xyz/lukas/userscripts/raw/branch/main/last_fm_remove_titles/last_fm_remove_titles.user.js
|
// @downloadURL https://git.kucharczyk.xyz/lukas/userscripts/raw/branch/main/last_fm_remove_titles/last_fm_remove_titles.js
|
||||||
// ==/UserScript==
|
// ==/UserScript==
|
||||||
document.querySelectorAll('a[title]').forEach((el) => {
|
document.querySelectorAll('a[title]').forEach((el) => {
|
||||||
el.removeAttribute('title')
|
el.removeAttribute('title')
|
@ -1,68 +0,0 @@
|
|||||||
// ==UserScript==
|
|
||||||
// @name New script - spalena53.cz
|
|
||||||
// @namespace Violentmonkey Scripts
|
|
||||||
// @match https://www.spalena53.cz/hledat/dostojevskij
|
|
||||||
// @grant none
|
|
||||||
// @version 1.0
|
|
||||||
// @author -
|
|
||||||
// @description 04/03/2023, 07:42:56
|
|
||||||
// ==/UserScript==
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {string} type
|
|
||||||
* @param {object} props
|
|
||||||
* @param {...(string|HTMLElement)} children
|
|
||||||
* @return {HTMLElement}
|
|
||||||
*/
|
|
||||||
function elt(type, props, ...children) {
|
|
||||||
let dom = document.createElement(type);
|
|
||||||
if (props) Object.assign(dom, props);
|
|
||||||
for (let child of children) {
|
|
||||||
if (typeof child != "string") dom.appendChild(child);
|
|
||||||
else dom.appendChild(document.createTextNode(child));
|
|
||||||
}
|
|
||||||
return dom;
|
|
||||||
}
|
|
||||||
|
|
||||||
let bookElements = document.querySelectorAll(".product.book");
|
|
||||||
let outOfStockElements = Array.from(bookElements).filter(
|
|
||||||
(node) => node.querySelector(".availability_info.black") != null
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param {HTMLElement} element
|
|
||||||
*/
|
|
||||||
function toggleDisplay(element) {
|
|
||||||
if (element.style.display != "none") element.style.display = "none";
|
|
||||||
else element.style.display = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
let toggleOutOfStockLabel = elt(
|
|
||||||
"label",
|
|
||||||
{
|
|
||||||
for: "out-of-stock",
|
|
||||||
className: "change_number",
|
|
||||||
},
|
|
||||||
"Toggle out of stock"
|
|
||||||
);
|
|
||||||
toggleOutOfStockLabel.cssText = `
|
|
||||||
height: 38px;
|
|
||||||
margin-right: 1rem;
|
|
||||||
`;
|
|
||||||
|
|
||||||
let toggleOutOfStockCheckbox = elt("input", {
|
|
||||||
onclick: (event) => {
|
|
||||||
outOfStockElements.forEach((element) => toggleDisplay(element));
|
|
||||||
},
|
|
||||||
id: "out-of-stock",
|
|
||||||
type: "checkbox",
|
|
||||||
className: "change_number",
|
|
||||||
});
|
|
||||||
|
|
||||||
toggleOutOfStockCheckbox.style.cssText = `
|
|
||||||
height: 33px;
|
|
||||||
`;
|
|
||||||
|
|
||||||
let pageHead = document.querySelector(".page_head");
|
|
||||||
pageHead.append(toggleOutOfStockLabel, toggleOutOfStockCheckbox);
|
|
Reference in New Issue
Block a user