2014-12-21 22:25:10 +00:00
// ==UserScript==
// @name Musicbrainz UI enhancements
// @description Various UI enhancements for Musicbrainz
2015-09-15 11:00:36 +00:00
// @version 2015.09.15.1
2014-12-21 22:25:10 +00:00
// @downloadURL https://raw.githubusercontent.com/murdos/musicbrainz-userscripts/master/mb_ui_enhancements.user.js
// @updateURL https://raw.githubusercontent.com/murdos/musicbrainz-userscripts/master/mb_ui_enhancements.user.js
// @icon http://wiki.musicbrainz.org/-/images/3/3d/Musicbrainz_logo.png
// @namespace http://userscripts.org/users/22504
// @include http*://*musicbrainz.org/*
2015-09-15 11:00:36 +00:00
// @require http://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.js
2014-12-21 22:25:10 +00:00
// @require https://raw.github.com/murdos/mbediting.js/master/mbediting.js
// ==/UserScript==
2015-09-15 11:00:36 +00:00
// prevent JQuery conflicts, see http://wiki.greasespot.net/@grant
this . $ = this . jQuery = jQuery . noConflict ( true ) ;
2014-12-21 22:25:10 +00:00
2015-09-15 11:00:36 +00:00
$ ( document ) . ready ( function ( ) {
2014-12-21 22:25:10 +00:00
LASTFM _APIKEY = null ;
// Highlight table rows
$ ( 'table.tbl tbody tr' ) . hover (
function ( ) {
$ ( this ) . children ( 'td' ) . each ( function ( ) {
var backgroundColor = $ ( this ) . css ( "backgroundColor" ) ;
if ( backgroundColor != 'rgb(255, 255, 0)' )
$ ( this ) . css ( "backgroundColor" , "#ffeea8" ) ;
} ) ;
} ,
function ( ) {
$ ( this ) . children ( 'td' ) . each ( function ( ) {
var backgroundColor = $ ( this ) . css ( "backgroundColor" ) ;
if ( backgroundColor != 'rgb(255, 255, 0)' )
$ ( this ) . css ( "backgroundColor" , "" ) ;
} ) ;
}
) ;
2014-12-21 23:03:22 +00:00
var re ;
2014-12-21 22:25:10 +00:00
// Top tracks from Lastfm
re = new RegExp ( "musicbrainz\.org\/artist\/([a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12})$" , "i" ) ;
if ( LASTFM _APIKEY && window . location . href . match ( re ) ) {
$ ( 'h2.discography' ) . before ( '<h2 class="toptracks">Top Last.fm recordings</h2><ul class="toptracks" />' ) ;
var mbid = window . location . href . match ( re ) [ 1 ] ;
var toptracks = $ . getJSON ( 'http://ws.audioscrobbler.com/2.0/?method=artist.gettoptracks&mbid=' + mbid + '&api_key=' + LASTFM _APIKEY + '&format=json' , function ( data ) {
$ . each ( data . toptracks . track , function ( index , track ) {
if ( index >= 5 ) return true ;
var url = track . mbid ? '/recording/' + track . mbid : track . url ;
$ ( 'ul.toptracks' ) . append ( '<li><a href="' + url + '">' + track . name + '</a></li>' ) ;
} ) ;
} ) ;
}
2015-02-14 11:29:36 +00:00
// Fix for http://tickets.musicbrainz.org/browse/MBS-750
2014-12-21 22:25:10 +00:00
re = new RegExp ( "musicbrainz\.org\/release\/([a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12})" , "i" ) ;
if ( window . location . href . match ( re ) ) {
2015-02-14 11:29:36 +00:00
if ( $ ( "table.medium thead" ) . length == 1 ) {
var text = $ . trim ( $ ( "table.medium thead" ) . text ( ) ) ;
2014-12-21 22:25:10 +00:00
if ( text . match ( / 1$/ ) ) {
2015-02-14 11:29:36 +00:00
$ ( "table.medium thead a" ) . text ( text . replace ( / 1$/ , '' ) ) ;
2014-12-21 22:25:10 +00:00
}
}
}
2015-02-14 11:29:36 +00:00
// Better fix for http://tickets.musicbrainz.org/browse/MBS-1943
2014-12-21 22:25:10 +00:00
re = new RegExp ( "musicbrainz\.org\/(artist|release-group|release|recording|work|label)\/([a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12})" , "i" ) ;
if ( window . location . href . match ( re ) ) {
$ ( "#sidebar h2:contains('Rating')" ) . before ( $ ( "#sidebar h2:contains('External links')" ) ) ;
var pageHasRGLinks = $ ( "#sidebar h2:contains('Release group external links')" ) . length > 0 ;
$ ( "#sidebar h2:contains('Rating')" ) . before (
$ ( "#sidebar h2:contains('External links')" ) . nextAll ( "ul.external_links" ) . filter ( function ( ) {
return ! pageHasRGLinks || $ ( this ) . nextAll ( "h2:contains('Release group external links')" ) . length > 0 ;
} ) ) ;
$ ( "#sidebar h2:contains('Rating')" ) . before ( $ ( "#sidebar h2:contains('Release group external links')" ) ) ;
$ ( "#sidebar h2:contains('Rating')" ) . before ( $ ( "#sidebar h2:contains('Release group external links')" ) . nextAll ( "ul.external_links" ) ) ;
}
// Remove the affiliate section
re = new RegExp ( "musicbrainz\.org\/(artist|release-group|release|recording|work|label)\/([a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12})" , "i" ) ;
if ( window . location . href . match ( re ) ) {
$ ( '#sidebar-affiliates' ) . remove ( ) ;
}
// Batch merge -> open in a new tab/windows
2014-12-21 23:03:22 +00:00
re = new RegExp ( "musicbrainz\.org\/artist\/([a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12})/(recordings|releases|works)" , "i" ) ;
2014-12-21 22:25:10 +00:00
if ( window . location . href . match ( re ) ) {
$ ( "form" ) . filter ( function ( ) {
return $ ( this ) . prop ( "action" ) . match ( "merge_queue" ) ;
} ) . attr ( "target" , "_blank" ) ;
}
// Modify link to edits: remove " - <Edit type>" from the link "Edit XXXX - <Edit type>"
2014-12-21 23:03:22 +00:00
re = new RegExp ( "musicbrainz\.org/.*/(open_)?edits" , "i" ) ;
2014-12-21 22:25:10 +00:00
if ( window . location . href . match ( re ) ) {
$ ( "div.edit-description ~ h2" ) . each ( function ( ) {
var parts = $ ( this ) . find ( "a" ) . text ( ) . split ( " - " ) ;
$ ( this ) . find ( "a" ) . text ( parts [ 0 ] ) ;
$ ( this ) . append ( " - " + parts [ 1 ] ) ;
} ) ;
}
// Add direct link to cover art tab for Add cover art edits
2014-12-21 23:03:22 +00:00
re = new RegExp ( "musicbrainz\.org/(.*/(open_)?edits|edit\/\d+)" , "i" ) ;
2014-12-21 22:25:10 +00:00
if ( window . location . href . match ( re ) ) {
$ ( "div.edit-description ~ h2:contains('cover art')" ) . each ( function ( ) {
$editdetails = $ ( this ) . parents ( '.edit-header' ) . siblings ( '.edit-details' ) ;
mbid = $editdetails . find ( "a[href*='musicbrainz.org/release/']" ) . attr ( 'href' ) . match ( /\/release\/(.{36})/ ) [ 1 ] ;
$editdetails . find ( 'tbody td.edit-cover-art' ) . after ( "<tr><th span='2'><a href='/release/" + mbid + "/cover-art'>See all artworks for this release</a></th></tr>" ) ;
} ) ;
}
// Embed Youtube videos
re = new RegExp ( "musicbrainz\.org\/recording\/[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$" , "i" ) ;
if ( window . location . href . match ( re ) ) {
var $youtube _link = $ ( '#sidebar li.youtube-favicon a' ) ;
if ( $youtube _link . length > 0 ) {
var youtube _id = $youtube _link . prop ( "href" ) . match ( /http:\/\/www\.youtube\.com\/watch\?v=(.*)/ ) [ 1 ] ;
$ ( "table.details" ) . width ( "60%" ) ;
$ ( "h2:contains('Relationships')" ) . after ( '<iframe width="360" height="275" frameborder="0" style="float: right;" src="https://www.youtube.com/embed/' + youtube _id + '?rel=0" allowfullscreen=""></iframe>' ) ;
}
}
2015-02-14 11:29:36 +00:00
// When attaching CDTOC, autoselect artist when there's only one result
2014-12-21 22:25:10 +00:00
re = new RegExp ( "musicbrainz\.org\/cdtoc\/attach.*&filter-artist.query=.*" , "i" ) ;
if ( window . location . href . match ( re ) ) {
$artists = $ ( 'ul.radio-list li' ) ;
if ( $artists . length == 1 ) {
$artists . find ( 'input:radio' ) . attr ( 'checked' , true ) ;
}
}
// Highlight Year in ISRCs codes
re = new RegExp ( "musicbrainz\.org\/artist\/([a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12})/recordings" , "i" ) ;
if ( window . location . href . match ( re ) ) {
var isrcColNo ; // = ($("#content table.tbl thead th:eq(2)").text() == "Artist") ? 3 : 2;
$ ( "#content table.tbl thead th" ) . each ( function ( index , th ) {
2014-12-25 20:28:46 +00:00
if ( $ ( th ) . text ( ) == "ISRCs" ) {
isrcColNo = index ;
return false ;
}
2014-12-21 22:25:10 +00:00
} ) ;
2014-12-25 20:28:46 +00:00
var reg = new RegExp ( "([A-Z]{2}[A-Z0-9]{3}[0-9]{7})" ) ;
2014-12-21 22:25:10 +00:00
$ ( "#content table.tbl tbody tr" ) . each ( function ( ) {
var $td = $ ( this ) . find ( "td:eq(" + isrcColNo + ")" ) ;
var isrcs = $td . text ( ) . trim ( ) . split ( "\n<br>\n" ) ;
var newHTML = "" ;
$ . each ( isrcs , function ( index , isrc ) {
isrc = isrc . trim ( ) ;
2014-12-25 20:28:46 +00:00
newHTML += "<a href='/isrc/" + isrc + "'><code>" ;
2014-12-21 22:25:10 +00:00
newHTML += isrc . substring ( 0 , 5 ) + "<b>" + isrc . substring ( 5 , 7 ) + "</b>" + isrc . substring ( 7 ) ;
2014-12-25 20:28:46 +00:00
newHTML += "</code></a>" ;
2014-12-21 22:25:10 +00:00
if ( index != isrcs . length - 1 ) { newHTML += "<br>" } ;
} ) ;
$td . html ( newHTML ) ;
} ) ;
}
2014-12-25 20:14:06 +00:00
// Display ISRCs and recording comment on release tracklisting
2015-06-10 20:46:17 +00:00
re = new RegExp ( "musicbrainz\.org\/release\/([a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12})#?$" , "i" ) ;
2014-12-21 23:03:22 +00:00
if ( window . location . href . match ( re ) ) {
2014-12-25 20:14:06 +00:00
var ISRC _COLUMN _POSITION = 2 ;
2014-12-21 23:03:22 +00:00
var mbid = window . location . href . match ( re ) [ 1 ] ;
2015-02-14 12:56:20 +00:00
// Get tracks data from webservice
2014-12-21 23:03:22 +00:00
var wsurl = "/ws/2/release/" + mbid + "?inc=isrcs+recordings" ;
$ . getJSON ( wsurl , function ( data ) {
2015-02-14 12:56:20 +00:00
// Store tracks data from webservice in a hash table
var tracks = { } ;
$ . each ( data . media , function ( index , medium ) {
$ . each ( medium . tracks , function ( i , track ) {
tracks [ track . id ] = track ;
} ) ;
} ) ;
// Different behavior depending on the number of mediums
2015-06-10 20:46:17 +00:00
if ( $ ( 'table.medium' ) . length <= 10 ) {
2015-02-14 12:56:20 +00:00
// All mediums are already displayed: handle them now
$ ( "table.medium" ) . each ( function ( ) {
handleMedium ( $ ( this ) , tracks )
} ) ;
} else {
// Each medium will be handled when it's loaded
var HANDLED _ATTRIBUTE = 'ui_enh_isrcs_handled' ;
$ ( 'table.medium' ) . attr ( HANDLED _ATTRIBUTE , 'no' ) ;
$ ( 'table.medium' ) . bind ( "DOMNodeInserted" , function ( event ) {
$target = $ ( event . target ) ;
if ( $target . prop ( 'nodeName' ) == 'TBODY' && $target . parent ( ) . attr ( HANDLED _ATTRIBUTE ) == 'no' && $target . find ( 'tr.subh' ) . length > 0 ) {
$medium = $target . parent ( ) ;
$medium . attr ( HANDLED _ATTRIBUTE , 'pending' ) ;
handleMedium ( $medium , tracks ) ;
$medium . attr ( HANDLED _ATTRIBUTE , 'done' ) ;
}
} ) ;
}
} ) ;
function handleMedium ( $medium , ws _tracks ) {
2015-02-14 11:29:36 +00:00
// Extend colspan for medium table header
2015-02-14 12:56:20 +00:00
$medium . find ( "thead tr" ) . each ( function ( ) {
2015-06-10 20:46:17 +00:00
$ ( this ) . find ( "th:eq(0)" ) . attr ( "colspan" , $ ( this ) . find ( "th:eq(0)" ) . attr ( "colspan" ) * 1 + 1 ) ;
2014-12-21 23:03:22 +00:00
} ) ;
2015-02-14 11:29:36 +00:00
// Table sub-header
2015-06-10 20:46:17 +00:00
$medium . find ( "tbody tr.subh th:nth-last-child(" + ISRC _COLUMN _POSITION + ")" ) . before ( "<th style='width: 150px;' class='isrc c'> ISRC </th>" ) ;
2015-02-14 12:56:20 +00:00
// Handle each track
$medium . find ( "tbody tr[id]" ) . each ( function ( index , medium _track ) {
track _mbid = $ ( medium _track ) . attr ( 'id' ) ;
var isrcsLinks = "" ;
if ( ws _tracks . hasOwnProperty ( track _mbid ) ) {
track = ws _tracks [ track _mbid ] ;
2014-12-25 20:14:06 +00:00
var recording = track . recording ;
// Recording comment
if ( recording . disambiguation != "" ) {
2015-06-10 20:46:17 +00:00
var td _title _index = $ ( "#" + track _mbid ) . find ( "td:eq(1)" ) . hasClass ( "video" ) ? 2 : 1 ;
$ ( "#" + track _mbid ) . find ( "td:eq(" + td _title _index + ") a:eq(0)" ) . after ( ' <span class="comment">(' + recording . disambiguation + ')</span>' ) ;
2014-12-25 20:14:06 +00:00
}
// ISRCS
if ( recording . isrcs . length != 0 ) {
var links = jQuery . map ( recording . isrcs , function ( isrc , i ) {
2014-12-21 23:03:22 +00:00
return ( "<a href='/isrc/" + isrc + "'>" + isrc + "</a>" ) ;
} ) ;
2014-12-25 20:14:06 +00:00
isrcsLinks = links . join ( ", " ) ;
2014-12-21 23:03:22 +00:00
}
2015-02-14 12:56:20 +00:00
}
$ ( '#' + track _mbid ) . find ( "td:nth-last-child(" + ISRC _COLUMN _POSITION + ")" ) . before ( "<td class='isrc c'><small>" + isrcsLinks + "</small></td>" ) ;
2014-12-21 23:03:22 +00:00
} ) ;
2015-02-14 12:56:20 +00:00
}
2014-12-21 23:03:22 +00:00
}
2015-09-09 15:49:29 +00:00
// Display "Edit relationships" link for release besides "Edit" link
re = new RegExp ( "musicbrainz\.org\/release\/([a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12})" , "i" ) ;
if ( window . location . href . match ( re ) ) {
var mbid = window . location . href . match ( re ) [ 1 ] ;
$ ( 'ul.tabs' ) . append ( '<li><a href="/release/' + mbid + '/edit-relationships">Edit relationships</a></li>' ) ;
}
2015-02-14 11:29:36 +00:00
// Discogs link rollover
2014-12-21 22:25:10 +00:00
// TODO...
// -------------- End of script ------------------------
2015-09-15 11:00:36 +00:00
} ) ;
2014-12-21 22:25:10 +00:00