2017-11-11 01:28:11 +00:00
// ==UserScript==
2015-07-18 20:59:15 +00:00
// @name Display shortcut for relationships on MusicBrainz
// @description Display icon shortcut for relationships of release-group, release, recording and work: e.g. Amazon, Discogs, Wikipedia, ... links. This allows to access some relationships without opening the entity page.
2022-04-21 21:51:06 +00:00
// @version 2022.4.21.1
2015-07-18 20:59:15 +00:00
// @author Aurelien Mino <aurelien.mino@gmail.com>
// @licence GPL (http://www.gnu.org/copyleft/gpl.html)
// @downloadURL https://raw.github.com/murdos/musicbrainz-userscripts/master/mb_relationship_shortcuts.user.js
// @updateURL https://raw.github.com/murdos/musicbrainz-userscripts/master/mb_relationship_shortcuts.user.js
2022-04-21 21:51:06 +00:00
// @namespace https://github.com/murdos/musicbrainz-userscripts
2015-07-18 20:59:15 +00:00
// @include http*://*musicbrainz.org/artist/*
// @include http*://*musicbrainz.org/release-group/*
// @include http*://*musicbrainz.org/label/*
2022-01-27 11:38:19 +00:00
// @exclude */artist/*/recordings*
2022-04-21 21:51:06 +00:00
// @require https://code.jquery.com/jquery-3.6.0.min.js
2015-07-18 20:59:15 +00:00
// ==/UserScript==
// Definitions: relations-type and corresponding icons we are going to treat
2021-08-05 15:50:04 +00:00
const relationsIconsURLs = {
2015-07-18 20:59:15 +00:00
'release-group' : {
2021-08-05 16:25:01 +00:00
// http://www.amaesingtools.com/images/left_arrow_icon.gif
'single from' : ` data:image/gif;base64,R0lGODlhDwALAJEAAP2ZAZmZmf///wAAACH5BAAAAAAALAAAAAAPAAsAAAIflI+pq2ABY0DAiYmwqOyaCoaHxjHaZp0e9UhQB8dCAQA7 ` ,
2015-07-18 20:59:15 +00:00
} ,
2018-11-20 22:18:49 +00:00
release : {
2020-04-05 14:01:21 +00:00
remaster : 'http://web.archive.org/web/20060708200714/http://wiki.musicbrainz.org/-/musicbrainz/img/moin-www.png' ,
} ,
2015-07-18 20:59:15 +00:00
} ;
2021-11-13 22:59:37 +00:00
const urlRelationsIconClasses = {
allmusic : 'allmusic' ,
'amazon asin' : 'amazon' ,
2021-11-30 10:51:45 +00:00
'creative commons licensed download' : 'creativecommons' ,
2021-11-13 22:59:37 +00:00
discogs : 'discogs' ,
imdb : 'imdb' ,
2021-11-30 10:51:45 +00:00
lyrics : 'lyrics' ,
2021-11-13 22:59:37 +00:00
secondhandsongs : 'secondhandsongs' ,
vgmdb : 'vgmdb' ,
wikidata : 'wikidata' ,
2017-11-12 02:01:52 +00:00
} ;
2021-11-13 22:59:37 +00:00
const otherDatabasesIconClasses = {
'd-nb.info' : 'dnb' ,
'www.musik-sammler.de' : 'musiksammler' ,
'rateyourmusic.com' : 'rateyourmusic' ,
'www.worldcat.org' : 'worldcat' ,
2021-11-12 12:30:00 +00:00
} ;
2021-11-13 22:59:37 +00:00
const streamingIconClasses = {
'music.amazon.' : 'amazonmusic' ,
'music.apple.com' : 'applemusic' ,
'bandcamp.com' : 'bandcamp' ,
'www.deezer.com' : 'deezer' ,
2021-11-30 10:55:56 +00:00
'www.hdtracks.com' : 'hdtracks' ,
2021-11-13 22:59:37 +00:00
'itunes.apple.com' : 'itunes' ,
'qobuz.com' : 'qobuz' ,
'soundcloud.com' : 'soundcloud' ,
'open.spotify.com' : 'spotify' ,
'tidal.com' : 'tidal' ,
} ;
2022-04-21 21:51:06 +00:00
/ * *
* @ param { string } mbid
* @ param { string } targetUrl
* @ param { string } iconClass
* /
2021-11-13 22:59:37 +00:00
function injectShortcutIcon ( mbid , targetUrl , iconClass ) {
if ( ! iconClass ) return ;
$ ( ` # ${ mbid } td.relationships ` ) . append (
` <a href=' ${ targetUrl . replace ( /'/g , ''' ) } '><span class='favicon ${ iconClass } -favicon' /></a> `
) ;
}
2022-04-21 21:51:06 +00:00
/ * *
* @ param { string } url
* @ param { Object } iconClassMap
* /
2021-11-13 22:59:37 +00:00
function findIconClassOfUrl ( url , iconClassMap ) {
for ( let partialUrl in iconClassMap ) {
2022-04-21 21:51:06 +00:00
if ( url . includes ( partialUrl ) ) {
2021-11-13 22:59:37 +00:00
return iconClassMap [ partialUrl ] ;
}
}
}
2021-08-05 15:50:04 +00:00
const incOptions = {
2018-11-20 22:18:49 +00:00
'release-group' : [ 'release-group-rels' , 'url-rels' ] ,
release : [ 'release-rels' , 'url-rels' , 'discids' ] ,
recording : [ 'work-rels' ] ,
2020-04-05 14:01:21 +00:00
work : [ 'url-rels' ] ,
2015-07-18 20:59:15 +00:00
} ;
2021-11-13 22:59:37 +00:00
const userscriptCSS = `
td . relationships span . favicon {
display : inline - block ;
width : 16 px ;
height : 16 px ;
vertical - align : middle ;
2022-01-27 11:26:45 +00:00
margin : 2 px ;
2021-11-30 10:51:45 +00:00
}
2021-12-10 17:29:57 +00:00
td . relationships span . favicon . ended {
opacity : 25 % ; /* make ended rels less visible */
}
2021-11-30 10:51:45 +00:00
/* additional custom favicons which are not shipped by MBS */
2021-11-30 10:55:56 +00:00
. hdtracks - favicon {
background - image : url ( https : //www.hdtracks.com/favicon.ico);
background - size : 16 px ;
}
2021-11-30 10:51:45 +00:00
. creativecommons - favicon {
background - image : url ( https : //creativecommons.org/favicon.ico);
}
. lyrics - favicon {
/* archived version, originally from http://www.nomy.nu/img/lyrics-icon.gif */
background - image : url ( data : image / gif ; base64 , R0lGODlhEQARALMAAAAAAP ////z8/Onp6dzc3KmpqaGhoZGRkYyMjHx8fP///wAAAAAAAAAAAAAAAAAAACH5BAEAAAoALAAAAAARABEAAARNUBCUqr0JEVnI+GA4EJ0WnGiKTskQGEcsy0YwVK6q2/g7/7Vba6cTumA/Gm9ITBl9yViw10Q9kdEps7o8RqU8EzcwIXlEIrOEgsFoBBEAOw==);
2021-11-13 22:59:37 +00:00
} ` ;
2022-04-21 21:51:06 +00:00
// prevent JQuery conflicts, see https://wiki.greasespot.net/@grant
2015-07-18 20:59:15 +00:00
this . $ = this . jQuery = jQuery . noConflict ( true ) ;
if ( ! unsafeWindow ) unsafeWindow = window ;
2020-04-05 14:01:21 +00:00
$ ( document ) . ready ( function ( ) {
2015-07-18 20:59:15 +00:00
// Get pageType (label or artist)
2018-11-20 22:18:49 +00:00
let parent = { } ;
let child = { } ;
2021-08-05 15:50:04 +00:00
let m ;
2018-11-20 22:18:49 +00:00
if ( ( m = window . location . href . match ( '/artist/(.{36})[^/]*$' ) ) ) {
2015-07-18 20:59:15 +00:00
parent . type = 'artist' ;
parent . mbid = m [ 1 ] ;
child . type = 'release-group' ;
2018-11-20 22:18:49 +00:00
} else if ( ( m = window . location . href . match ( '/(release-group|label)/(.{36})[^/]*$' ) ) ) {
2015-07-18 20:59:15 +00:00
parent . type = m [ 1 ] ;
parent . mbid = m [ 2 ] ;
child . type = 'release' ;
2018-11-20 22:18:49 +00:00
} else if ( ( m = window . location . href . match ( '/artist/(.{36})/(releases|recordings|works)' ) ) ) {
2015-07-18 20:59:15 +00:00
parent . type = 'artist' ;
parent . mbid = m [ 1 ] ;
child . type = m [ 2 ] . replace ( /s$/ , '' ) ;
} else {
// Not supported
return ;
}
2022-04-21 21:51:06 +00:00
document . head . insertAdjacentHTML ( 'beforeend' , ` <style id='relationship-shortcuts-userscript-css'> ${ userscriptCSS } </style> ` ) ;
2021-11-13 22:59:37 +00:00
2022-04-21 21:51:06 +00:00
const mbidRE = /(release|release-group|work)\/([a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12})/ ;
2015-07-18 20:59:15 +00:00
// Determine target column
2018-11-20 22:18:49 +00:00
let columnindex = 0 ;
2020-04-05 14:01:21 +00:00
$ ( "table.tbl tbody tr[class!='subh']" ) . each ( function ( ) {
2018-11-20 22:18:49 +00:00
$ ( this )
. children ( 'td' )
2020-04-05 14:01:21 +00:00
. each ( function ( ) {
2022-04-21 21:51:06 +00:00
const href = $ ( this ) . find ( 'a' ) . attr ( 'href' ) ;
if ( href !== undefined && href . match ( mbidRE ) ) {
2018-11-20 22:18:49 +00:00
return false ;
}
columnindex ++ ;
} ) ;
2015-07-18 20:59:15 +00:00
return false ;
} ) ;
// Set MBID to row in tables to get easiest fastest access
2020-04-05 14:01:21 +00:00
$ ( "table.tbl tr[class!='subh']" ) . each ( function ( ) {
2018-11-20 22:18:49 +00:00
let $tr = $ ( this ) ;
2022-01-27 11:26:45 +00:00
$tr . children ( ` th:eq( ${ columnindex } ) ` ) . after ( '<th>Relationships</th>' ) ;
2018-11-20 22:18:49 +00:00
$tr . children ( ` td:eq( ${ columnindex } ) ` ) . after ( "<td class='relationships'></td>" ) ;
$ ( this )
. find ( 'a' )
2020-04-05 14:01:21 +00:00
. each ( function ( ) {
2018-11-20 22:18:49 +00:00
let href = $ ( this ) . attr ( 'href' ) ;
if ( ( m = href . match ( mbidRE ) ) ) {
$tr . attr ( 'id' , m [ 2 ] ) ;
return false ;
}
} ) ;
2015-07-18 20:59:15 +00:00
} ) ;
2020-03-31 09:56:56 +00:00
// Adapt width of subheader rows by incrementing the colspan of a cell
2020-04-05 19:56:29 +00:00
$ ( 'table.tbl tr.subh' ) . each ( function ( ) {
2020-03-31 10:28:52 +00:00
$ ( this )
. children ( 'th[colspan]' )
2020-04-05 19:56:29 +00:00
. attr ( 'colspan' , function ( index , oldValue ) {
2020-03-31 10:28:52 +00:00
if ( index === 0 ) {
return Number ( oldValue ) + 1 ;
} else {
return oldValue ;
}
} ) ;
2020-03-31 09:56:56 +00:00
} ) ;
2017-04-16 20:07:25 +00:00
// Calculate offset for multi-page lists
2018-11-20 22:18:49 +00:00
let page = 1 ;
if ( ( m = window . location . href . match ( '[?&]page=([0-9]*)' ) ) ) {
2017-11-11 01:28:11 +00:00
page = m [ 1 ] ;
2017-04-16 20:07:25 +00:00
}
2018-11-20 22:18:49 +00:00
let offset = ( page - 1 ) * 100 ;
2017-11-11 01:28:11 +00:00
2015-07-18 20:59:15 +00:00
// Call the MB webservice
2022-04-21 21:51:06 +00:00
const url = ` /ws/2/ ${ child . type } ? ${ parent . type } = ${ parent . mbid } &inc= ${ incOptions [ child . type ] . join ( '+' ) } &limit=100&offset= ${ offset } ` ;
2015-07-18 20:59:15 +00:00
2020-04-05 14:01:21 +00:00
$ . get ( url , function ( data , textStatus , jqXHR ) {
2015-07-18 20:59:15 +00:00
// Parse each child
2018-11-20 22:18:49 +00:00
$ ( data )
. find ( child . type )
2020-04-05 14:01:21 +00:00
. each ( function ( ) {
2018-11-20 22:18:49 +00:00
let mbid = $ ( this ) . attr ( 'id' ) ;
// URL relationships
2021-12-10 17:32:22 +00:00
let alreadyInjectedUrls = [ ] ;
2018-11-20 22:18:49 +00:00
$ ( this )
. find ( "relation-list[target-type='url'] relation" )
2020-04-05 14:01:21 +00:00
. each ( function ( ) {
2021-11-13 22:59:37 +00:00
let relType = $ ( this ) . attr ( 'type' ) ;
let targetUrl = $ ( this ) . children ( 'target' ) . text ( ) ;
2021-12-10 17:29:57 +00:00
let ended = $ ( this ) . children ( 'ended' ) . text ( ) === 'true' ;
2021-12-10 17:32:22 +00:00
// Dedupe rels by URL (e.g. for Bandcamp, which has purchase and stream rels)
if ( alreadyInjectedUrls . includes ( targetUrl ) ) return ;
alreadyInjectedUrls . push ( targetUrl ) ;
2021-12-10 17:29:57 +00:00
let iconClass ;
2021-11-13 22:59:37 +00:00
if ( relType in urlRelationsIconClasses ) {
2021-12-10 17:29:57 +00:00
iconClass = urlRelationsIconClasses [ relType ] ;
2021-12-11 01:47:24 +00:00
} else if ( [ 'free streaming' , 'streaming' , 'download for free' , 'purchase for download' ] . includes ( relType ) ) {
2021-12-10 17:29:57 +00:00
iconClass = findIconClassOfUrl ( targetUrl , streamingIconClasses ) ;
2021-11-13 22:59:37 +00:00
} else {
// Other database?
2021-12-10 17:29:57 +00:00
iconClass = findIconClassOfUrl ( targetUrl , otherDatabasesIconClasses ) ;
}
if ( iconClass ) {
if ( ended ) {
iconClass = [ 'ended' , iconClass ] . join ( ' ' ) ;
2018-11-20 22:18:49 +00:00
}
2021-12-10 17:29:57 +00:00
injectShortcutIcon ( mbid , targetUrl , iconClass ) ;
}
2018-11-20 22:18:49 +00:00
} ) ;
// Other relationships
$ ( this )
. find ( "relation-list[target-type!='url']" )
2020-04-05 14:01:21 +00:00
. each ( function ( ) {
let targettype = $ ( this ) . attr ( 'target-type' ) . replace ( 'release_group' , 'release-group' ) ;
2018-11-20 22:18:49 +00:00
let relations = { } ;
if ( relationsIconsURLs [ targettype ] === undefined ) {
return ;
}
$ ( this )
. children ( 'relation' )
2020-04-05 14:01:21 +00:00
. each ( function ( ) {
2022-04-21 21:51:06 +00:00
const reltype = $ ( this ) . attr ( 'type' ) ;
const target = $ ( this ) . children ( 'target' ) . text ( ) ;
const url = targettype == 'url' ? target : ` / ${ targettype } / ${ target } ` ;
2018-11-20 22:18:49 +00:00
2020-03-14 00:43:40 +00:00
if ( Object . prototype . hasOwnProperty . call ( relationsIconsURLs [ targettype ] , reltype ) ) {
if ( ! Object . prototype . hasOwnProperty . call ( relations , reltype ) ) relations [ reltype ] = [ url ] ;
2018-11-20 22:18:49 +00:00
else relations [ reltype ] . push ( url ) ;
}
} ) ;
2020-04-05 14:01:21 +00:00
$ . each ( relations , function ( reltype , urls ) {
2018-11-20 22:18:49 +00:00
let html = '' ;
if ( urls . length < - 1 ) {
html += ` <img src=' ${ relationsIconsURLs [ targettype ] [ reltype ] } ' />( ${ urls . length } ) ` ;
} else {
2020-04-05 14:01:21 +00:00
$ . each ( urls , function ( index , url ) {
2018-11-20 22:18:49 +00:00
html += ` <a href=' ${ url } '><img src=' ${ relationsIconsURLs [ targettype ] [ reltype ] } ' /></a> ` ;
} ) ;
}
$ ( ` # ${ mbid } td.relationships ` ) . append ( html ) ;
2015-07-18 20:59:15 +00:00
} ) ;
2018-11-20 22:18:49 +00:00
} ) ;
2015-07-18 20:59:15 +00:00
} ) ;
} ) ;
} ) ;