2015-01-18 01:01:36 +00:00
// ==UserScript==
2012-06-08 23:58:47 +00:00
// @name Import Discogs releases to MusicBrainz
2015-06-10 13:00:03 +00:00
// @description Add a button to import Discogs releases to MusicBrainz and add links to matching MusicBrainz entities for various Discogs entities (artist,release,master,label)
2016-02-14 09:59:47 +00:00
// @version 2016.02.14.0
2012-06-08 23:58:47 +00:00
// @namespace http://userscripts.org/users/22504
2012-12-08 21:30:19 +00:00
// @downloadURL https://raw.github.com/murdos/musicbrainz-userscripts/master/discogs_importer.user.js
// @updateURL https://raw.github.com/murdos/musicbrainz-userscripts/master/discogs_importer.user.js
2016-02-13 22:39:06 +00:00
// @include http*://www.discogs.com/*
// @include http*://*.discogs.com/*release/*
// @exclude http*://*.discogs.com/*release/*?f=xml*
// @exclude http*://www.discogs.com/release/add
2015-06-06 11:12:47 +00:00
// @require https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js
2015-06-17 22:29:08 +00:00
// @require lib/mbimport.js
2015-06-05 18:49:23 +00:00
// @require lib/logger.js
2015-06-05 20:17:24 +00:00
// @require lib/mblinks.js
2015-06-15 07:52:59 +00:00
// @require lib/mbimportstyle.js
2015-07-10 12:28:43 +00:00
// @icon https://raw.githubusercontent.com/murdos/musicbrainz-userscripts/master/assets/images/Musicbrainz_import_logo.png
2012-06-08 23:58:47 +00:00
// ==/UserScript==
2015-06-06 11:12:47 +00:00
// prevent JQuery conflicts, see http://wiki.greasespot.net/@grant
this . $ = this . jQuery = jQuery . noConflict ( true ) ;
if ( ! unsafeWindow ) unsafeWindow = window ;
2015-06-11 09:57:52 +00:00
var DEBUG = false ;
//DEBUG = true;
if ( DEBUG ) {
LOGGER . setLevel ( 'debug' ) ;
}
2015-06-06 11:12:47 +00:00
2012-06-08 23:58:47 +00:00
////////////////////////////////////////////////////////////////////////////////////////////////////////
2015-01-18 01:01:36 +00:00
/ *
* Test cases :
* - http : //www.discogs.com/release/1566223 : Artist credit of tracks contains an ending ',' join phrase
* /
2012-06-08 23:58:47 +00:00
2015-06-16 07:15:13 +00:00
var mblinks = new MBLinks ( 'DISCOGS_MBLINKS_CACHE' , '1' ) ;
2012-06-08 23:58:47 +00:00
2015-06-05 20:17:24 +00:00
$ ( document ) . ready ( function ( ) {
2012-06-08 23:58:47 +00:00
2015-06-15 07:52:59 +00:00
MBImportStyle ( ) ;
2015-06-14 19:58:43 +00:00
MBSearchItStyle ( ) ;
2015-06-15 07:52:59 +00:00
2015-06-14 12:08:55 +00:00
var current _page _key = getDiscogsLinkKey ( window . location . href . replace ( /\?.*$/ , '' ) . replace ( /#.*$/ , '' ) . replace ( '/master/view/' , '/master/' ) ) ;
2015-06-12 13:55:00 +00:00
if ( ! current _page _key ) return ;
2015-06-12 13:07:21 +00:00
// disable evil pjax (used for artist page navigation)
// it causes various annoying issues with our code;
// it should be possible to react to pjax events
$ ( "div#pjax_container" ) . attr ( 'id' , 'pjax_disabled' ) ;
2012-06-08 23:58:47 +00:00
2015-06-18 21:02:01 +00:00
// Display links of equivalent MusicBrainz entities
2015-06-18 21:00:31 +00:00
insertMBLinks ( current _page _key ) ;
2012-06-08 23:58:47 +00:00
2015-06-18 21:02:01 +00:00
// Add an import button in a new section in sidebar, if we're on a release page
2015-06-12 13:55:00 +00:00
var current _page _info = link _infos [ current _page _key ] ;
if ( current _page _info . type == 'release' ) {
2013-12-31 18:21:47 +00:00
// Discogs Webservice URL
2016-02-14 09:59:47 +00:00
var discogsWsUrl = 'https://api.discogs.com/releases/' + current _page _info . id ;
2013-12-31 18:21:47 +00:00
$ . ajax ( {
2014-02-21 18:25:49 +00:00
url : discogsWsUrl ,
2014-12-30 16:35:11 +00:00
dataType : 'json' ,
2014-02-21 18:25:49 +00:00
crossDomain : true ,
success : function ( data , textStatus , jqXHR ) {
2015-01-18 13:00:58 +00:00
LOGGER . debug ( "Discogs JSON Data from API:" , data ) ;
2015-06-16 21:24:24 +00:00
try {
var release = parseDiscogsRelease ( data ) ;
2015-06-18 21:05:18 +00:00
insertMBSection ( release , current _page _key ) ;
2015-06-16 21:24:24 +00:00
} catch ( e ) {
$ ( 'div.musicbrainz' ) . remove ( ) ;
var mbUI = $ ( '<div class="section musicbrainz"><h3>MusicBrainz</h3></div>' ) . hide ( ) ;
var mbContentBlock = $ ( '<div class="section_content"></div>' ) ;
mbUI . append ( mbContentBlock ) ;
var mbError = $ ( '<p><small>' + e + '<br /><b>Please <a href="https://github.com/murdos/musicbrainz-userscripts/issues">report</a> this error, along the current page URL.</b></small></p>' ) ;
mbContentBlock . prepend ( mbError ) ;
2015-06-17 08:50:52 +00:00
insertMbUI ( mbUI ) ;
2015-06-16 21:24:24 +00:00
mbError . css ( { 'background-color' : '#fbb' , 'margin-top' : '4px' , 'margin-bottom' : '4px' } ) ;
mbUI . slideDown ( ) ;
throw e ;
}
2014-02-21 18:25:49 +00:00
} ,
error : function ( jqXHR , textStatus , errorThrown ) {
2015-01-18 13:00:58 +00:00
LOGGER . error ( "AJAX Status: " , textStatus ) ;
LOGGER . error ( "AJAX error thrown: " , errorThrown ) ;
2014-02-21 18:25:49 +00:00
}
2013-08-04 08:33:02 +00:00
} ) ;
2012-06-08 23:58:47 +00:00
}
} ) ;
2013-12-31 18:21:47 +00:00
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2015-06-18 21:02:01 +00:00
// Display links of equivalent MusicBrainz entities //
2013-12-31 18:21:47 +00:00
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2013-08-04 08:33:02 +00:00
2013-12-31 18:21:47 +00:00
// Insert MusicBrainz links in a section of the page
2015-06-18 21:00:31 +00:00
function insertMBLinks ( current _page _key ) {
2013-12-04 07:36:53 +00:00
2015-06-14 19:58:43 +00:00
function searchAndDisplayMbLinkInSection ( $tr , discogs _type , mb _type , nosearch ) {
2015-06-12 09:21:43 +00:00
if ( ! mb _type ) mb _type = defaultMBtype ( discogs _type ) ;
2015-06-11 09:22:23 +00:00
$tr . find ( 'a[mlink^="' + discogs _type + '/"]' ) . each ( function ( ) {
2013-08-04 08:33:02 +00:00
var $link = $ ( this ) ;
2015-06-12 09:27:19 +00:00
if ( $link . attr ( 'mlink_stop' ) ) return ; // for places
2015-06-11 09:22:23 +00:00
var mlink = $link . attr ( 'mlink' ) ;
2015-06-06 08:42:28 +00:00
// ensure we do it only once per link
2015-06-11 13:33:11 +00:00
var done = ( $link . attr ( 'mlink_done' ) || "" ) . split ( "," ) ;
for ( var i = 0 ; i < done . length ; i ++ ) {
if ( mb _type == done [ i ] ) return ;
}
done . push ( mb _type ) ;
$link . attr ( 'mlink_done' , done . filter ( function ( e ) { return ( e != "" ) ; } ) . join ( ',' ) ) ;
2015-06-11 09:22:23 +00:00
if ( link _infos [ mlink ] && link _infos [ mlink ] . type == discogs _type ) {
var discogs _url = link _infos [ mlink ] . clean _url ;
2015-06-12 09:27:19 +00:00
var cachekey = getCacheKeyFromInfo ( mlink , mb _type ) ;
2015-06-14 19:58:43 +00:00
var has _wrapper = $link . closest ( 'span.mb_wrapper' ) . length ;
if ( ! has _wrapper ) {
$link . wrap ( '<span class="mb_wrapper"><span class="mb_valign"></span></span>' ) ;
}
if ( ! nosearch ) {
// add search link for the current link text
var entities = {
'artist' : { mark : 'A' } ,
'release' : { mark : 'R' } ,
'release-group' : { mark : 'G' } ,
'place' : { mark : 'P' } ,
'label' : { mark : 'L' }
}
var mark = '' ;
var entity _name = 'entity' ;
if ( mb _type in entities ) {
mark = entities [ mb _type ] . mark ;
entity _name = mb _type . replace ( /[_-]/g , ' ' ) ;
}
2015-06-17 22:29:08 +00:00
$link . closest ( 'span.mb_wrapper' ) . prepend ( '<span class="mb_valign mb_searchit"><a class="mb_search_link" target="_blank" title="Search this ' + entity _name + ' on MusicBrainz (open in a new tab)" href="' + MBImport . searchUrlFor ( mb _type , $link . text ( ) ) + '"><small>' + mark + '</small>?</a></span>' ) ;
2015-06-14 19:58:43 +00:00
}
var insert _normal = function ( link ) {
$link . closest ( 'span.mb_valign' ) . before ( '<span class="mb_valign">' + link + '</span>' ) ;
$link . closest ( 'span.mb_wrapper' ) . find ( '.mb_searchit' ) . remove ( ) ;
} ;
var insert _stop = function ( link ) {
insert _normal ( link ) ;
$link . attr ( 'mlink_stop' , true ) ;
} ;
var insert _func = insert _normal ;
2015-06-12 09:27:19 +00:00
if ( mb _type == 'place' ) {
// if a place link was added we stop, we don't want further queries for this 'label'
2015-06-14 19:58:43 +00:00
insert _func = insert _stop ;
2015-06-12 09:27:19 +00:00
}
mblinks . searchAndDisplayMbLink ( discogs _url , mb _type , insert _func , cachekey ) ;
2015-06-11 09:22:23 +00:00
}
2013-08-04 08:33:02 +00:00
} ) ;
}
2015-06-12 13:08:12 +00:00
function debug _color ( what , n , id ) {
2015-06-11 09:57:52 +00:00
var colors = [
'#B3C6FF' ,
'#C6B3FF' ,
'#ECB3FF' ,
'#FFB3EC' ,
'#FFB3C6' ,
'#FFC6B3' ,
'#FFECB3' ,
'#ECFFB3' ,
'#C6FFB3' ,
'#B3FFC6' ,
'#B3FFEC' ,
'#B3ECFF' ,
'#7598FF' ,
] ;
if ( DEBUG ) {
$ ( what ) . css ( 'border' , '2px dotted ' + colors [ n % colors . length ] ) ;
var debug _attr = $ ( what ) . attr ( 'debug_discogs' ) ;
2015-06-12 13:08:12 +00:00
if ( ! id ) id = '' ;
2015-06-11 09:57:52 +00:00
if ( debug _attr ) {
2015-06-12 13:08:12 +00:00
$ ( what ) . attr ( 'debug_discogs' , debug _attr + ' || ' + id + '(' + n + ')' ) ;
2015-06-11 09:57:52 +00:00
} else {
2015-06-12 13:08:12 +00:00
$ ( what ) . attr ( 'debug_discogs' , id + '(' + n + ')' ) ;
2015-06-11 09:57:52 +00:00
}
}
}
2015-06-05 21:28:45 +00:00
2015-06-12 13:12:09 +00:00
var add _mblinks _counter = 0 ;
2015-06-14 19:58:43 +00:00
function add _mblinks ( _root , selector , types , nosearch ) {
2015-06-12 13:12:09 +00:00
// types can be:
// 'discogs type 1'
// ['discogs_type 1', 'discogs_type 2']
// [['discogs_type 1', 'mb type 1'], 'discogs_type 2']
// etc.
if ( ! $ . isArray ( types ) ) {
// just one string
types = [ types ] ;
}
$ . each ( types ,
function ( idx , val ) {
if ( ! $ . isArray ( val ) ) {
types [ idx ] = [ val , undefined ] ;
}
}
) ;
LOGGER . debug ( 'add_mblinks: ' + selector + ' / ' + JSON . stringify ( types ) ) ;
_root . find ( selector ) . each ( function ( ) {
var node = $ ( this ) . get ( 0 ) ;
magnifyLinks ( node ) ;
debug _color ( this , ++ add _mblinks _counter , selector ) ;
var that = this ;
$ . each ( types , function ( idx , val ) {
var discogs _type = val [ 0 ] ;
var mb _type = val [ 1 ] ;
2015-06-14 19:58:43 +00:00
searchAndDisplayMbLinkInSection ( $ ( that ) , discogs _type , mb _type , nosearch ) ;
2015-06-12 13:12:09 +00:00
} ) ;
} ) ;
}
2013-08-04 08:33:02 +00:00
2015-06-18 21:00:31 +00:00
// Find MB link for the current page and display it next to page title
var mbLinkInsert = function ( link ) {
var $h1 = $ ( 'h1' ) ;
var $titleSpan = $h1 . children ( 'span[itemprop="name"]' ) ;
if ( $titleSpan . length > 0 ) {
$titleSpan . before ( link ) ;
} else {
$h1 . prepend ( link ) ;
}
}
var current _page _info = link _infos [ current _page _key ] ;
var mb _type = defaultMBtype ( current _page _info . type ) ;
var cachekey = getCacheKeyFromInfo ( current _page _key , mb _type ) ;
mblinks . searchAndDisplayMbLink ( current _page _info . clean _url , mb _type , mbLinkInsert , cachekey ) ;
var $root = $ ( 'body' ) ;
2015-06-12 13:15:07 +00:00
add _mblinks ( $root , 'div.profile' , [ 'artist' , 'label' ] ) ;
add _mblinks ( $root , 'tr[data-object-type="release"] td.artist,td.title' , 'artist' ) ;
add _mblinks ( $root , 'tr[data-object-type="release"] td.title' , 'release' ) ;
add _mblinks ( $root , 'tr[data-object-type="release"]' , 'label' ) ;
add _mblinks ( $root , 'tr[data-object-type~="master"]' , [ 'master' , 'artist' , 'label' ] ) ;
add _mblinks ( $root , 'div#tracklist' , 'artist' ) ;
add _mblinks ( $root , 'div#companies' , [ [ 'label' , 'place' ] , 'label' ] ) ;
add _mblinks ( $root , 'div#credits' , [ 'label' , 'artist' ] ) ;
2015-06-14 19:58:43 +00:00
add _mblinks ( $root , 'div#page_aside div.section_content:first' , 'master' , true ) ;
2015-06-18 21:00:31 +00:00
2013-08-04 08:33:02 +00:00
}
2013-12-04 07:36:53 +00:00
2013-12-31 18:21:47 +00:00
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Normalize Discogs URLs in a DOM tree //
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2015-06-12 13:09:53 +00:00
var mlink _processed = 0 ;
2013-12-31 18:21:47 +00:00
// Normalize Discogs URLs in a DOM tree
2015-06-12 13:09:53 +00:00
function magnifyLinks ( rootNode ) {
2013-08-04 08:33:02 +00:00
if ( ! rootNode ) {
rootNode = document . body ;
}
2012-06-08 23:58:47 +00:00
// Check if we already added links for this content
2015-06-12 13:09:53 +00:00
if ( rootNode . hasAttribute ( 'mlink_processed' ) )
2012-06-08 23:58:47 +00:00
return ;
2015-06-12 13:09:53 +00:00
rootNode . setAttribute ( 'mlink_processed' , ++ mlink _processed ) ;
2012-06-08 23:58:47 +00:00
2013-08-04 08:33:02 +00:00
var elems = rootNode . getElementsByTagName ( 'a' ) ;
2012-06-08 23:58:47 +00:00
for ( var i = 0 ; i < elems . length ; i ++ ) {
var elem = elems [ i ] ;
// Ignore empty links
2013-12-31 18:21:47 +00:00
if ( ! elem . href || $ . trim ( elem . textContent ) == '' || elem . textContent . substring ( 4 , 0 ) == 'http' )
2012-06-08 23:58:47 +00:00
continue ;
2015-06-11 09:22:23 +00:00
if ( ! elem . hasAttribute ( 'mlink' ) ) {
elem . setAttribute ( 'mlink' , getDiscogsLinkKey ( elem . href ) ) ;
}
2013-12-31 18:21:47 +00:00
}
}
2015-06-11 09:22:23 +00:00
// contains infos for each link key
var link _infos = { } ;
// Parse discogs url to extract info, returns a key and set link_infos for this key
// the key is in the form discogs_type/discogs_id
function getDiscogsLinkKey ( url ) {
2016-02-13 22:39:06 +00:00
var re = /^https?:\/\/(?:www|api)\.discogs\.com\/(?:(?:(?!sell).+|sell.+)\/)?(master|release|artist|label)s?\/(\d+)(?:[^\?#]*)(?:\?noanv=1|\?anv=[^=]+)?$/i ;
2013-12-31 18:21:47 +00:00
if ( m = re . exec ( url ) ) {
2015-06-11 09:22:23 +00:00
var key = m [ 1 ] + '/' + m [ 2 ] ;
if ( ! link _infos [ key ] ) {
link _infos [ key ] = {
type : m [ 1 ] ,
id : m [ 2 ] ,
2016-02-14 09:59:47 +00:00
clean _url : 'https://www.discogs.com/' + m [ 1 ] + '/' + m [ 2 ]
2015-06-11 09:22:23 +00:00
}
LOGGER . debug ( 'getDiscogsLinkKey:' + url + ' --> ' + key ) ;
} else {
LOGGER . debug ( 'getDiscogsLinkKey:' + url + ' --> ' + key + ' (key exists)' ) ;
}
return key ;
2012-06-08 23:58:47 +00:00
}
2015-06-11 09:22:23 +00:00
LOGGER . debug ( 'getDiscogsLinkKey:' + url + ' ?' ) ;
return false ;
2012-06-08 23:58:47 +00:00
}
2015-06-11 09:22:23 +00:00
function getCleanUrl ( url , discogs _type ) {
try {
var key = getDiscogsLinkKey ( url ) ;
if ( key ) {
if ( ! discogs _type || link _infos [ key ] . type == discogs _type ) {
LOGGER . debug ( 'getCleanUrl: ' + key + ', ' + url + ' --> ' + link _infos [ key ] . clean _url ) ;
return link _infos [ key ] . clean _url ;
} else {
LOGGER . debug ( 'getCleanUrl: ' + key + ', ' + url + ' --> unmatched type: ' + discogs _type ) ;
}
}
}
catch ( err ) {
LOGGER . error ( err ) ;
}
LOGGER . debug ( 'getCleanUrl: ' + url + ' (' + discogs _type + ') failed' ) ;
return false ;
}
2015-06-12 09:21:43 +00:00
function defaultMBtype ( discogs _type ) {
if ( discogs _type == 'master' ) return 'release-group' ;
return discogs _type ;
}
2015-06-12 09:23:38 +00:00
function getCacheKeyFromInfo ( info _key , mb _type ) {
var inf = link _infos [ info _key ] ;
if ( inf ) {
if ( ! mb _type ) mb _type = defaultMBtype ( inf . type ) ;
return inf . type + '/' + inf . id + '/' + mb _type ;
}
return '' ;
}
function getCacheKeyFromUrl ( url , discogs _type , mb _type ) {
try {
var key = getDiscogsLinkKey ( url ) ;
if ( key ) {
if ( ! discogs _type || link _infos [ key ] . type == discogs _type ) {
var cachekey = getCacheKeyFromInfo ( key , mb _type ) ;
LOGGER . debug ( 'getCacheKeyFromUrl: ' + key + ', ' + url + ' --> ' + cachekey ) ;
return cachekey ;
} else {
LOGGER . debug ( 'getCacheKeyFromUrl: ' + key + ', ' + url + ' --> unmatched type: ' + discogs _type ) ;
}
}
}
catch ( err ) {
LOGGER . error ( err ) ;
}
LOGGER . debug ( 'getCacheKeyFromUrl: ' + url + ' (' + discogs _type + ') failed' ) ;
return false ;
}
2015-06-12 09:24:55 +00:00
function MBIDfromUrl ( url , discogs _type , mb _type ) {
var cachekey = getCacheKeyFromUrl ( url , discogs _type , mb _type ) ;
if ( ! cachekey ) return '' ;
return mblinks . resolveMBID ( cachekey ) ;
2015-06-11 09:22:23 +00:00
}
2013-12-31 18:21:47 +00:00
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Insert MusicBrainz section into Discogs page //
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2015-06-17 08:50:52 +00:00
function insertMbUI ( mbUI ) {
var e ;
if ( ( e = $ ( "div.section.social" ) ) && e . length ) {
e . before ( mbUI ) ;
} else if ( ( e = $ ( '#statistics' ) ) && e . length ) {
e . before ( mbUI ) ;
} else if ( ( e = $ ( "div.marketplace_box_links" ) ) && e . length ) {
e . after ( mbUI ) ;
}
}
2013-12-31 18:21:47 +00:00
// Insert links in Discogs page
2015-06-18 21:05:18 +00:00
function insertMBSection ( release , current _page _key ) {
2015-06-12 13:55:00 +00:00
var current _page _info = link _infos [ current _page _key ] ;
2013-12-31 18:21:47 +00:00
2015-06-14 12:17:49 +00:00
var mbUI = $ ( '<div class="section musicbrainz"><h3>MusicBrainz</h3></div>' ) . hide ( ) ;
2013-12-31 18:21:47 +00:00
2015-06-14 12:25:10 +00:00
if ( DEBUG ) mbUI . css ( { 'border' : '1px dotted red' } ) ;
2013-12-31 18:21:47 +00:00
var mbContentBlock = $ ( '<div class="section_content"></div>' ) ;
mbUI . append ( mbContentBlock ) ;
2015-06-17 07:43:57 +00:00
if ( release . maybe _buggy ) {
var warning _buggy = $ ( '<p><small><b>Warning</b>: this release has perhaps a buggy tracklist, please check twice the data you import.</small><p' ) . css ( { 'color' : 'red' , 'margin-top' : '4px' , 'margin-bottom' : '4px' } ) ;
mbContentBlock . prepend ( warning _buggy ) ;
}
2013-12-31 18:21:47 +00:00
// Form parameters
2015-06-17 22:29:08 +00:00
var edit _note = MBImport . makeEditNote ( current _page _info . clean _url , 'Discogs' ) ;
var parameters = MBImport . buildFormParameters ( release , edit _note ) ;
2013-12-31 18:21:47 +00:00
2015-06-16 13:34:02 +00:00
// Build form + search button
var innerHTML = '<div id="mb_buttons">'
2015-06-17 22:29:08 +00:00
+ MBImport . buildFormHTML ( parameters )
+ MBImport . buildSearchButton ( release )
2015-06-16 13:34:02 +00:00
+ '</div>' ;
2015-06-14 12:21:18 +00:00
mbContentBlock . append ( innerHTML ) ;
2015-06-16 13:34:02 +00:00
2015-06-17 08:50:52 +00:00
insertMbUI ( mbUI ) ;
2013-12-31 18:21:47 +00:00
2015-06-16 13:34:02 +00:00
$ ( '#mb_buttons' ) . css ( {
display : 'inline-block' ,
width : '100%'
} ) ;
2015-06-17 12:44:06 +00:00
$ ( 'form.musicbrainz_import' ) . css ( { width : '49%' , display : 'inline-block' } ) ;
$ ( 'form.musicbrainz_import_search' ) . css ( { 'float' : 'right' } )
$ ( 'form.musicbrainz_import > button' ) . css ( { width : '100%' , 'box-sizing' : 'border-box' } ) ;
2015-06-16 13:34:02 +00:00
2015-06-14 12:17:49 +00:00
mbUI . slideDown ( ) ;
2012-06-08 23:58:47 +00:00
}
2013-12-31 18:21:47 +00:00
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Parsing of Discogs data //
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2015-06-21 13:45:21 +00:00
function cleanup _discogs _artist _credit ( obj ) {
// Fix some odd Discogs release (e.g. http://api.discogs.com/releases/1566223) that have a ',' join phrase after the last artist
// Discogs set a join phrase even there's only one artist or when extraartists is set (ie. remix)
var last = obj . artist _credit . length - 1 ;
if ( last == 0 || obj . artist _credit [ last ] . joinphrase == ", " ) {
obj . artist _credit [ last ] . joinphrase = "" ;
}
}
2015-06-04 08:08:03 +00:00
2015-06-23 06:35:20 +00:00
// Returns the name without the numerical suffic Discogs adds as disambiguation
// ie. "ABC (123)" -> "ABC"
function artistNoNum ( artist _name ) {
return artist _name . replace ( / \(\d+\)$/ , "" ) ;
}
2015-06-23 07:40:39 +00:00
// Parse a US date string and set object properties year, month, day
function parse _YYYY _MM _DD ( date , obj ) {
if ( ! date ) return ;
var m = date . split ( /\D+/ , 3 ) . map ( function ( e ) {
return parseInt ( e , 10 ) ;
} ) ;
if ( m [ 0 ] !== undefined ) {
obj . year = m [ 0 ] ;
if ( m [ 1 ] !== undefined ) {
obj . month = m [ 1 ] ;
if ( m [ 2 ] !== undefined ) {
obj . day = m [ 2 ] ;
}
}
}
}
2012-06-08 23:58:47 +00:00
// Analyze Discogs data and return a release object
function parseDiscogsRelease ( data ) {
2014-12-30 16:35:11 +00:00
var discogsRelease = data ;
2012-06-08 23:58:47 +00:00
2015-06-17 22:18:22 +00:00
var release = { } ;
2012-06-08 23:58:47 +00:00
release . discs = [ ] ;
2015-06-17 07:43:57 +00:00
//buggy tracklist indicator, used to warn user
release . maybe _buggy = false ;
2012-06-08 23:58:47 +00:00
// Release artist credit
2015-06-17 22:18:22 +00:00
release . artist _credit = [ ] ;
2012-06-08 23:58:47 +00:00
$ . each ( discogsRelease . artists , function ( index , artist ) {
var ac = {
2015-06-23 06:35:20 +00:00
'artist_name' : artistNoNum ( artist . name ) ,
'credited_name' : ( artist . anv != "" ? artist . anv : artistNoNum ( artist . name ) ) ,
2015-06-07 19:49:51 +00:00
'joinphrase' : decodeDiscogsJoinphrase ( artist . join ) ,
2015-06-11 09:22:23 +00:00
'mbid' : MBIDfromUrl ( artist . resource _url , 'artist' )
2012-06-08 23:58:47 +00:00
} ;
2015-06-21 14:26:45 +00:00
if ( artist . id == 194 ) { // discogs place holder for various
ac = MBImport . specialArtist ( 'various_artists' , ac ) ;
}
2012-06-08 23:58:47 +00:00
release . artist _credit . push ( ac ) ;
} ) ;
2015-06-21 13:45:21 +00:00
cleanup _discogs _artist _credit ( release ) ;
2012-06-08 23:58:47 +00:00
2015-06-07 19:49:51 +00:00
// ReleaseGroup
2015-06-11 13:57:15 +00:00
if ( discogsRelease . master _url ) {
release . release _group _mbid = MBIDfromUrl ( discogsRelease . master _url , 'master' ) ;
}
2015-06-07 19:49:51 +00:00
2012-06-08 23:58:47 +00:00
// Release title
release . title = discogsRelease . title ;
// Release date
if ( discogsRelease . released ) {
2015-06-23 07:40:39 +00:00
parse _YYYY _MM _DD ( discogsRelease . released , release ) ;
2012-06-08 23:58:47 +00:00
}
// Release country
if ( discogsRelease . country ) {
2015-06-17 22:18:22 +00:00
release . country = Countries [ discogsRelease . country ] ;
2012-06-08 23:58:47 +00:00
}
// Release labels
2015-06-17 22:18:22 +00:00
release . labels = [ ] ;
2012-06-08 23:58:47 +00:00
if ( discogsRelease . labels ) {
$ . each ( discogsRelease . labels , function ( index , label ) {
2015-06-11 09:22:23 +00:00
var labelinfo = {
name : label . name ,
catno : ( label . catno == "none" ? "[none]" : label . catno ) ,
mbid : MBIDfromUrl ( label . resource _url , 'label' )
} ;
release . labels . push ( labelinfo ) ;
2012-06-08 23:58:47 +00:00
} ) ;
}
2014-02-21 19:05:25 +00:00
// Release URL
2015-06-23 07:49:48 +00:00
release . urls = [ { url : getCleanUrl ( discogsRelease . uri , 'release' ) , link _type : MBImport . URL _TYPES . discogs } ] ;
2014-02-21 19:05:25 +00:00
2012-06-08 23:58:47 +00:00
// Release format
2015-06-17 22:18:22 +00:00
var release _formats = [ ] ;
release . secondary _types = [ ] ;
2012-06-08 23:58:47 +00:00
if ( discogsRelease . formats . length > 0 ) {
2015-06-17 22:18:22 +00:00
for ( var i = 0 ; i < discogsRelease . formats . length ; i ++ ) {
2015-06-22 20:35:37 +00:00
// Release format
var discogs _format = discogsRelease . formats [ i ] . name ;
var mb _format = undefined ;
if ( discogs _format in MediaTypes ) {
mb _format = MediaTypes [ discogs _format ] ;
2015-06-17 21:50:22 +00:00
}
2012-12-08 21:23:04 +00:00
if ( discogsRelease . formats [ i ] . descriptions ) {
$ . each ( discogsRelease . formats [ i ] . descriptions , function ( index , desc ) {
2015-06-22 20:35:37 +00:00
if ( ! ( discogs _format in [ 'Box Set' ] ) ) {
// Release format: special handling of vinyl 7", 10" and 12" and other more specific CD/DVD formats
if ( desc . match ( /7"|10"|12"|^VCD|SVCD|CD\+G|HDCD|DVD-Audio|DVD-Video/ ) && ( desc in MediaTypes ) ) mb _format = MediaTypes [ desc ] ;
}
2012-12-08 21:23:04 +00:00
// Release format: special handling of Vinyl, LP == 12" (http://www.discogs.com/help/submission-guidelines-release-format.html#LP)
2015-06-22 20:35:37 +00:00
if ( discogs _format == "Vinyl" && desc == "LP" ) mb _format = '12" Vinyl' ;
2014-08-15 00:23:51 +00:00
// Release format: special handling of CD, Mini == 8cm CD
2015-06-22 20:35:37 +00:00
if ( discogs _format == "CD" && desc == "Mini" ) mb _format = '8cm CD' ;
2012-12-08 21:23:04 +00:00
// Release status
if ( desc . match ( /Promo|Smplr/ ) ) release . status = "promotion" ;
2014-08-14 22:51:44 +00:00
if ( desc . match ( /Unofficial Release/ ) ) release . status = "bootleg" ;
2012-12-08 21:23:04 +00:00
// Release type
2014-08-14 23:55:30 +00:00
if ( desc . match ( /Compilation/ ) ) release . secondary _types . push ( "compilation" ) ;
if ( desc . match ( /^Album/ ) ) release . type = "album" ;
2015-06-27 07:32:19 +00:00
if ( desc . match ( /Single(?! Sided)/ ) ) release . type = "single" ;
2014-08-14 23:55:30 +00:00
if ( desc . match ( /EP|Mini-Album/ ) ) release . type = "ep" ;
2012-12-08 21:23:04 +00:00
} ) ;
}
2012-06-08 23:58:47 +00:00
2015-06-22 20:35:37 +00:00
if ( mb _format ) {
for ( var j = 0 ; j < discogsRelease . formats [ i ] . qty ; j ++ ) {
release _formats . push ( mb _format ) ;
}
}
2012-12-08 21:23:04 +00:00
// Release packaging
2012-12-08 21:30:19 +00:00
if ( discogsRelease . formats [ i ] . text ) {
2015-06-23 08:19:16 +00:00
var freetext = discogsRelease . formats [ i ] . text . toLowerCase ( ) . replace ( /[\s-]/g , '' ) ;
2012-12-08 21:30:19 +00:00
if ( freetext . match ( /cardboard|paper/ ) ) release . packaging = "cardboard/paper sleeve" ;
2015-06-23 08:19:54 +00:00
else if ( freetext . match ( /digipak/ ) ) release . packaging = "digipak" ;
else if ( freetext . match ( /keepcase/ ) ) release . packaging = "keep case" ;
else if ( freetext . match ( /jewel/ ) ) {
2012-12-08 21:30:19 +00:00
release . packaging = freetext . match ( /slim/ ) ? "slim jewel case" : "jewel case" ;
}
2015-06-23 08:20:24 +00:00
else if ( freetext . match ( /gatefold|digisleeve/ ) ) release . packaging = "gatefold cover" ;
2012-12-08 21:30:19 +00:00
}
2012-06-08 23:58:47 +00:00
}
}
// Barcode
if ( discogsRelease . identifiers ) {
$ . each ( discogsRelease . identifiers , function ( index , identifier ) {
if ( identifier . type == "Barcode" ) {
release . barcode = identifier . value . replace ( / /g , '' ) ;
return false ;
}
} ) ;
}
// Inspect tracks
var tracks = [ ] ;
2015-06-03 15:09:38 +00:00
var heading = "" ;
2012-12-08 21:23:04 +00:00
var releaseNumber = 1 ;
var lastPosition = 0 ;
2012-06-08 23:58:47 +00:00
$ . each ( discogsRelease . tracklist , function ( index , discogsTrack ) {
2015-06-03 15:09:38 +00:00
if ( discogsTrack . type _ == 'heading' ) {
heading = discogsTrack . title ;
return ;
2015-06-23 07:43:20 +00:00
}
if ( discogsTrack . type _ != 'track' && discogsTrack . type _ != 'index' ) {
2015-06-03 15:09:38 +00:00
return ;
}
2012-06-08 23:58:47 +00:00
var track = new Object ( ) ;
track . title = discogsTrack . title ;
2015-06-17 22:29:08 +00:00
track . duration = MBImport . hmsToMilliSeconds ( discogsTrack . duration ) ; // MB in milliseconds
2012-06-08 23:58:47 +00:00
// Track artist credit
2015-06-17 22:18:22 +00:00
track . artist _credit = [ ] ;
2012-06-08 23:58:47 +00:00
if ( discogsTrack . artists ) {
$ . each ( discogsTrack . artists , function ( index , artist ) {
var ac = {
2015-06-23 06:35:20 +00:00
'artist_name' : artistNoNum ( artist . name ) ,
'credited_name' : ( artist . anv != "" ? artist . anv : artistNoNum ( artist . name ) ) ,
2015-06-07 19:49:51 +00:00
'joinphrase' : decodeDiscogsJoinphrase ( artist . join ) ,
2015-06-11 09:22:23 +00:00
'mbid' : MBIDfromUrl ( artist . resource _url , 'artist' )
2012-06-08 23:58:47 +00:00
} ;
track . artist _credit . push ( ac ) ;
} ) ;
2015-06-21 13:45:21 +00:00
cleanup _discogs _artist _credit ( track ) ;
2012-06-08 23:58:47 +00:00
}
// Track position and release number
var trackPosition = discogsTrack . position ;
2015-06-03 22:37:15 +00:00
// Handle sub-tracks
2015-01-16 12:56:36 +00:00
if ( trackPosition == "" && discogsTrack . sub _tracks ) {
trackPosition = discogsTrack . sub _tracks [ 0 ] . position ;
2015-06-03 22:37:15 +00:00
// Append titles of sub-tracks to main track title
var subtrack _titles = [ ] ;
2015-06-04 08:08:03 +00:00
var subtrack _total _duration = 0 ;
2015-06-03 22:37:15 +00:00
$ . each ( discogsTrack . sub _tracks , function ( subtrack _index , subtrack ) {
if ( subtrack . type _ != 'track' ) {
return ;
}
2015-06-04 08:08:03 +00:00
if ( subtrack . duration ) {
2015-06-17 22:29:08 +00:00
subtrack _total _duration += MBImport . hmsToMilliSeconds ( subtrack . duration ) ;
2015-06-04 08:08:03 +00:00
}
2015-06-03 22:37:15 +00:00
if ( subtrack . title ) {
subtrack _titles . push ( subtrack . title ) ;
} else {
subtrack _titles . push ( '[unknown]' ) ;
}
} ) ;
if ( subtrack _titles . length ) {
if ( track . title ) {
track . title += ': ' ;
}
track . title += subtrack _titles . join ( ' / ' ) ;
}
2015-06-13 02:25:31 +00:00
if ( isNaN ( track . duration ) && ! isNaN ( subtrack _total _duration ) ) {
2015-06-12 22:24:41 +00:00
track . duration = subtrack _total _duration ;
2015-06-04 08:08:03 +00:00
}
2015-01-16 12:56:36 +00:00
}
2012-06-08 23:58:47 +00:00
// Skip special tracks
2015-06-22 23:50:11 +00:00
if ( trackPosition . match ( /^(?:video|mp3)/i ) ) {
2012-06-08 23:58:47 +00:00
trackPosition = "" ;
}
2015-06-22 21:24:49 +00:00
// Possible track position:
// A1 or A => Vinyl or Cassette : guess releaseNumber from vinyl side
// 1-1 or 1.1 => releaseNumber.trackNumber
// 1 => trackNumber
2016-01-07 14:20:02 +00:00
var tmp = trackPosition . match ( /(\d+|[A-Z])(?:[\.-]+(\d+))?/i ) ;
2015-06-17 22:18:22 +00:00
if ( tmp ) {
2012-12-08 21:23:04 +00:00
tmp [ 1 ] = parseInt ( tmp [ 1 ] , 10 ) ;
2015-06-16 22:31:22 +00:00
var buggyTrackNumber = false ;
var prevReleaseNumber = releaseNumber ;
2015-06-22 21:24:49 +00:00
if ( Number . isInteger ( tmp [ 1 ] ) ) {
if ( tmp [ 2 ] ) { // 1-1, 1-2, 2-1, ... - we can get release number and track number from this
releaseNumber = tmp [ 1 ] ;
2015-06-22 21:27:48 +00:00
lastPosition = parseInt ( tmp [ 2 ] , 10 ) ;
2015-06-22 21:24:49 +00:00
} else if ( tmp [ 1 ] <= lastPosition ) { // 1, 2, 3, ... - We've moved onto a new medium
releaseNumber ++ ;
2015-06-22 21:27:48 +00:00
lastPosition = tmp [ 1 ] ;
2015-06-22 21:24:49 +00:00
} else {
2015-06-22 21:27:48 +00:00
lastPosition = tmp [ 1 ] ;
2015-06-22 21:24:49 +00:00
}
2015-06-17 22:18:22 +00:00
} else {
2015-06-22 23:50:11 +00:00
if ( trackPosition . match ( /^[A-Z]\d*$/i ) ) { // Vinyl or cassette, handle it specially
2015-06-22 23:54:37 +00:00
// A,B -> 1; C,D -> 2; E,F -> 3, etc...
releaseNumber = ( ( 32 | trackPosition . charCodeAt ( 0 ) ) - 97 >> 1 ) + 1 ;
2015-06-22 21:24:49 +00:00
lastPosition ++ ;
2015-06-22 23:50:11 +00:00
} else if ( trackPosition . match ( /^[A-Z]+\d*$/i ) ) { // Vinyl or cassette, handle it specially
2015-06-22 21:24:49 +00:00
// something like AA1, exemple : http://www.discogs.com/release/73531
// TODO: find a better fix
buggyTrackNumber = true ;
}
2012-12-08 21:23:04 +00:00
}
2015-06-16 22:31:22 +00:00
if ( releaseNumber > release _formats . length ) {
// something went wrong in track position parsing
buggyTrackNumber = true ;
releaseNumber = prevReleaseNumber ;
}
if ( buggyTrackNumber ) {
// well, it went wrong so ...
lastPosition ++ ;
}
2012-06-08 23:58:47 +00:00
}
// Create release if needed
2015-06-22 23:55:55 +00:00
var discindex = releaseNumber - 1 ;
if ( ! release . discs [ discindex ] ) {
2015-06-23 06:23:50 +00:00
var newdisc = {
tracks : [ ] ,
format : release _formats [ discindex ] ,
} ;
2015-06-03 15:09:38 +00:00
if ( heading ) {
2015-06-23 06:23:50 +00:00
newdisc . title = heading ;
2015-06-03 15:09:38 +00:00
heading = "" ;
}
2015-06-23 06:23:50 +00:00
release . discs . push ( newdisc ) ;
2012-06-08 23:58:47 +00:00
}
// Track number (only for Vinyl and Cassette)
2015-06-22 23:55:55 +00:00
if ( buggyTrackNumber || ( release . discs [ discindex ] . format . match ( /(Vinyl|Cassette)/ )
2015-06-22 23:50:11 +00:00
&& discogsTrack . position . match ( /^[A-Z]+[\.-]?\d*/i ) ) ) {
2012-06-08 23:58:47 +00:00
track . number = discogsTrack . position ;
}
// Trackposition is empty e.g. for release title
2015-06-12 22:24:41 +00:00
if ( trackPosition != "" && trackPosition != null ) {
2015-06-22 23:55:55 +00:00
release . discs [ discindex ] . tracks . push ( track ) ;
2015-06-12 22:24:41 +00:00
}
2015-06-17 07:43:57 +00:00
if ( buggyTrackNumber && ! release . maybe _buggy ) {
release . maybe _buggy = true ;
}
2012-06-08 23:58:47 +00:00
} ) ;
2015-07-02 07:52:24 +00:00
if ( release . discs . length == 1 && release . discs [ 0 ] . title ) {
// remove title if there is only one disc
// https://github.com/murdos/musicbrainz-userscripts/issues/69
release . discs [ 0 ] . title = '' ;
}
2015-01-18 13:00:58 +00:00
LOGGER . info ( "Parsed release: " , release ) ;
2012-06-08 23:58:47 +00:00
return release ;
}
function decodeDiscogsJoinphrase ( join ) {
var joinphrase = "" ;
var trimedjoin = join . replace ( /^\s*/ , "" ) . replace ( /\s*$/ , "" ) ;
if ( trimedjoin == "" ) return trimedjoin ;
if ( trimedjoin != "," ) joinphrase += " " ;
joinphrase += trimedjoin ;
joinphrase += " " ;
return joinphrase ;
}
2013-12-31 18:21:47 +00:00
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Discogs -> MusicBrainz mapping //
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2012-06-08 23:58:47 +00:00
2015-06-17 22:18:22 +00:00
var MediaTypes = {
"8-Track Cartridge" : "Cartridge" ,
"Acetate" : "Vinyl" ,
"Betamax" : "Betamax" ,
"Blu-ray" : "Blu-ray" ,
"Blu-ray-R" : "Blu-ray" ,
"Cassette" : "Cassette" ,
"CD" : "CD" ,
"CDr" : "CD-R" ,
"CDV" : "CDV" ,
"CD+G" : "CD+G" ,
"Cylinder" : "Wax Cylinder" ,
"DAT" : "DAT" ,
"Datassette" : "Other" ,
"DCC" : "DCC" ,
"DVD" : "DVD" ,
"DVDr" : "DVD" ,
"DVD-Audio" : "DVD-Audio" ,
"DVD-Video" : "DVD-Video" ,
"Edison Disc" : "Vinyl" ,
"File" : "Digital Media" ,
"Flexi-disc" : "Vinyl" ,
"Floppy Disk" : "Other" ,
"HDCD" : "HDCD" ,
"HD DVD" : "HD-DVD" ,
"HD DVD-R" : "HD-DVD" ,
"Hybrid" : "Other" ,
"Laserdisc" : "LaserDisc" ,
"Memory Stick" : "Other" ,
"Microcassette" : "Other" ,
"Minidisc" : "MiniDisc" ,
"MVD" : "Other" ,
"Reel-To-Reel" : "Reel-to-reel" ,
"SelectaVision" : "Other" ,
"Shellac" : "Vinyl" ,
"SVCD" : "SVCD" ,
"UMD" : "UMD" ,
"VCD" : "VCD" ,
"VHS" : "VHS" ,
"Video 2000" : "Other" ,
"Vinyl" : "Vinyl" ,
'7"' : '7" Vinyl' ,
'10"' : '10" Vinyl' ,
'12"' : '12" Vinyl'
} ;
var Countries = {
"Afghanistan" : "AF" ,
"Albania" : "AL" ,
"Algeria" : "DZ" ,
"American Samoa" : "AS" ,
"Andorra" : "AD" ,
"Angola" : "AO" ,
"Anguilla" : "AI" ,
"Antarctica" : "AQ" ,
"Antigua and Barbuda" : "AG" ,
"Argentina" : "AR" ,
"Armenia" : "AM" ,
"Aruba" : "AW" ,
"Australia" : "AU" ,
"Austria" : "AT" ,
"Azerbaijan" : "AZ" ,
"Bahamas" : "BS" ,
"Bahrain" : "BH" ,
"Bangladesh" : "BD" ,
"Barbados" : "BB" ,
"Belarus" : "BY" ,
"Belgium" : "BE" ,
"Belize" : "BZ" ,
"Benin" : "BJ" ,
"Bermuda" : "BM" ,
"Bhutan" : "BT" ,
"Bolivia" : "BO" ,
"Croatia" : "HR" ,
"Botswana" : "BW" ,
"Bouvet Island" : "BV" ,
"Brazil" : "BR" ,
"British Indian Ocean Territory" : "IO" ,
"Brunei Darussalam" : "BN" ,
"Bulgaria" : "BG" ,
"Burkina Faso" : "BF" ,
"Burundi" : "BI" ,
"Cambodia" : "KH" ,
"Cameroon" : "CM" ,
"Canada" : "CA" ,
"Cape Verde" : "CV" ,
"Cayman Islands" : "KY" ,
"Central African Republic" : "CF" ,
"Chad" : "TD" ,
"Chile" : "CL" ,
"China" : "CN" ,
"Christmas Island" : "CX" ,
"Cocos (Keeling) Islands" : "CC" ,
"Colombia" : "CO" ,
"Comoros" : "KM" ,
"Congo" : "CG" ,
"Cook Islands" : "CK" ,
"Costa Rica" : "CR" ,
"Virgin Islands, British" : "VG" ,
"Cuba" : "CU" ,
"Cyprus" : "CY" ,
"Czech Republic" : "CZ" ,
"Denmark" : "DK" ,
"Djibouti" : "DJ" ,
"Dominica" : "DM" ,
"Dominican Republic" : "DO" ,
"Ecuador" : "EC" ,
"Egypt" : "EG" ,
"El Salvador" : "SV" ,
"Equatorial Guinea" : "GQ" ,
"Eritrea" : "ER" ,
"Estonia" : "EE" ,
"Ethiopia" : "ET" ,
"Falkland Islands (Malvinas)" : "FK" ,
"Faroe Islands" : "FO" ,
"Fiji" : "FJ" ,
"Finland" : "FI" ,
"France" : "FR" ,
"French Guiana" : "GF" ,
"French Polynesia" : "PF" ,
"French Southern Territories" : "TF" ,
"Gabon" : "GA" ,
"Gambia" : "GM" ,
"Georgia" : "GE" ,
"Germany" : "DE" ,
"Ghana" : "GH" ,
"Gibraltar" : "GI" ,
"Greece" : "GR" ,
"Greenland" : "GL" ,
"Grenada" : "GD" ,
"Guadeloupe" : "GP" ,
"Guam" : "GU" ,
"Guatemala" : "GT" ,
"Guinea" : "GN" ,
"Guinea-Bissau" : "GW" ,
"Guyana" : "GY" ,
"Haiti" : "HT" ,
"Virgin Islands, U.S." : "VI" ,
"Honduras" : "HN" ,
"Hong Kong" : "HK" ,
"Hungary" : "HU" ,
"Iceland" : "IS" ,
"India" : "IN" ,
"Indonesia" : "ID" ,
"Wallis and Futuna" : "WF" ,
"Iraq" : "IQ" ,
"Ireland" : "IE" ,
"Israel" : "IL" ,
"Italy" : "IT" ,
"Jamaica" : "JM" ,
"Japan" : "JP" ,
"Jordan" : "JO" ,
"Kazakhstan" : "KZ" ,
"Kenya" : "KE" ,
"Kiribati" : "KI" ,
"Kuwait" : "KW" ,
"Kyrgyzstan" : "KG" ,
"Lao People's Democratic Republic" : "LA" ,
"Latvia" : "LV" ,
"Lebanon" : "LB" ,
"Lesotho" : "LS" ,
"Liberia" : "LR" ,
"Libyan Arab Jamahiriya" : "LY" ,
"Liechtenstein" : "LI" ,
"Lithuania" : "LT" ,
"Luxembourg" : "LU" ,
"Montserrat" : "MS" ,
"Macedonia, The Former Yugoslav Republic of" : "MK" ,
"Madagascar" : "MG" ,
"Malawi" : "MW" ,
"Malaysia" : "MY" ,
"Maldives" : "MV" ,
"Mali" : "ML" ,
"Malta" : "MT" ,
"Marshall Islands" : "MH" ,
"Martinique" : "MQ" ,
"Mauritania" : "MR" ,
"Mauritius" : "MU" ,
"Mayotte" : "YT" ,
"Mexico" : "MX" ,
"Micronesia, Federated States of" : "FM" ,
"Morocco" : "MA" ,
"Monaco" : "MC" ,
"Mongolia" : "MN" ,
"Mozambique" : "MZ" ,
"Myanmar" : "MM" ,
"Namibia" : "NA" ,
"Nauru" : "NR" ,
"Nepal" : "NP" ,
"Netherlands" : "NL" ,
"Netherlands Antilles" : "AN" ,
"New Caledonia" : "NC" ,
"New Zealand" : "NZ" ,
"Nicaragua" : "NI" ,
"Niger" : "NE" ,
"Nigeria" : "NG" ,
"Niue" : "NU" ,
"Norfolk Island" : "NF" ,
"Northern Mariana Islands" : "MP" ,
"Norway" : "NO" ,
"Oman" : "OM" ,
"Pakistan" : "PK" ,
"Palau" : "PW" ,
"Panama" : "PA" ,
"Papua New Guinea" : "PG" ,
"Paraguay" : "PY" ,
"Peru" : "PE" ,
"Philippines" : "PH" ,
"Pitcairn" : "PN" ,
"Poland" : "PL" ,
"Portugal" : "PT" ,
"Puerto Rico" : "PR" ,
"Qatar" : "QA" ,
"Reunion" : "RE" ,
"Romania" : "RO" ,
"Russian Federation" : "RU" ,
"Russia" : "RU" ,
"Rwanda" : "RW" ,
"Saint Kitts and Nevis" : "KN" ,
"Saint Lucia" : "LC" ,
"Saint Vincent and The Grenadines" : "VC" ,
"Samoa" : "WS" ,
"San Marino" : "SM" ,
"Sao Tome and Principe" : "ST" ,
"Saudi Arabia" : "SA" ,
"Senegal" : "SN" ,
"Seychelles" : "SC" ,
"Sierra Leone" : "SL" ,
"Singapore" : "SG" ,
"Slovenia" : "SI" ,
"Solomon Islands" : "SB" ,
"Somalia" : "SO" ,
"South Africa" : "ZA" ,
"Spain" : "ES" ,
"Sri Lanka" : "LK" ,
"Sudan" : "SD" ,
"Suriname" : "SR" ,
"Swaziland" : "SZ" ,
"Sweden" : "SE" ,
"Switzerland" : "CH" ,
"Syrian Arab Republic" : "SY" ,
"Tajikistan" : "TJ" ,
"Tanzania, United Republic of" : "TZ" ,
"Thailand" : "TH" ,
"Togo" : "TG" ,
"Tokelau" : "TK" ,
"Tonga" : "TO" ,
"Trinidad and Tobago" : "TT" ,
"Tunisia" : "TN" ,
"Turkey" : "TR" ,
"Turkmenistan" : "TM" ,
"Turks and Caicos Islands" : "TC" ,
"Tuvalu" : "TV" ,
"Uganda" : "UG" ,
"Ukraine" : "UA" ,
"United Arab Emirates" : "AE" ,
"UK" : "GB" ,
"US" : "US" ,
"United States Minor Outlying Islands" : "UM" ,
"Uruguay" : "UY" ,
"Uzbekistan" : "UZ" ,
"Vanuatu" : "VU" ,
"Vatican City State (Holy See)" : "VA" ,
"Venezuela" : "VE" ,
"Viet Nam" : "VN" ,
"Western Sahara" : "EH" ,
"Yemen" : "YE" ,
"Zambia" : "ZM" ,
"Zimbabwe" : "ZW" ,
"Taiwan" : "TW" ,
"[Worldwide]" : "XW" ,
"Europe" : "XE" ,
"Soviet Union (historical, 1922-1991)" : "SU" ,
"East Germany (historical, 1949-1990)" : "XG" ,
"Czechoslovakia (historical, 1918-1992)" : "XC" ,
"Congo, The Democratic Republic of the" : "CD" ,
"Slovakia" : "SK" ,
"Bosnia and Herzegovina" : "BA" ,
"Korea (North), Democratic People's Republic of" : "KP" ,
"North Korea" : "KP" ,
"Korea (South), Republic of" : "KR" ,
"South Korea" : "KR" ,
"Montenegro" : "ME" ,
"South Georgia and the South Sandwich Islands" : "GS" ,
"Palestinian Territory" : "PS" ,
"Macao" : "MO" ,
"Timor-Leste" : "TL" ,
"<85>land Islands" : "AX" ,
"Guernsey" : "GG" ,
"Isle of Man" : "IM" ,
"Jersey" : "JE" ,
"Serbia" : "RS" ,
"Saint Barthélemy" : "BL" ,
"Saint Martin" : "MF" ,
"Moldova" : "MD" ,
"Yugoslavia (historical, 1918-2003)" : "YU" ,
"Serbia and Montenegro (historical, 2003-2006)" : "CS" ,
"Côte d'Ivoire" : "CI" ,
"Heard Island and McDonald Islands" : "HM" ,
"Iran, Islamic Republic of" : "IR" ,
"Saint Pierre and Miquelon" : "PM" ,
"Saint Helena" : "SH" ,
"Svalbard and Jan Mayen" : "SJ"
} ;