2019-04-11 12:41:12 +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)
2019-04-11 12:41:12 +00:00
// @version 2019.4.11.1
2012-06-08 23:58:47 +00:00
// @namespace http://userscripts.org/users/22504
2016-02-17 11:01:03 +00:00
// @downloadURL https://raw.githubusercontent.com/murdos/musicbrainz-userscripts/master/discogs_importer.user.js
// @updateURL https://raw.githubusercontent.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 ) ;
2015-06-11 09:57:52 +00:00
var DEBUG = false ;
//DEBUG = true;
if ( DEBUG ) {
2019-04-11 12:45:52 +00:00
LOGGER . setLevel ( 'debug' ) ;
2015-06-11 09:57:52 +00:00
}
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
2019-04-11 12:45:52 +00:00
$ ( document ) . ready ( function ( ) {
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
2019-04-11 12:45:52 +00:00
let 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
2019-04-11 12:45:52 +00:00
$ ( '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
2019-04-11 12:45:52 +00:00
let current _page _info = link _infos [ current _page _key ] ;
2015-06-12 13:55:00 +00:00
if ( current _page _info . type == 'release' ) {
2013-12-31 18:21:47 +00:00
// Discogs Webservice URL
2019-04-11 12:45:52 +00:00
let 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 ,
2019-04-11 12:45:52 +00:00
success : function ( data , textStatus , jqXHR ) {
LOGGER . debug ( 'Discogs JSON Data from API:' , data ) ;
2015-06-16 21:24:24 +00:00
try {
2019-04-11 12:45:52 +00:00
let release = parseDiscogsRelease ( data ) ;
insertMBSection ( release , current _page _key ) ;
2018-11-20 22:18:49 +00:00
} catch ( e ) {
2019-04-11 12:45:52 +00:00
$ ( 'div.musicbrainz' ) . remove ( ) ;
let mbUI = $ ( '<div class="section musicbrainz"><h3>MusicBrainz</h3></div>' ) . hide ( ) ;
let mbContentBlock = $ ( '<div class="section_content"></div>' ) ;
mbUI . append ( mbContentBlock ) ;
let 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 ) ;
insertMbUI ( mbUI ) ;
mbError . css ( { 'background-color' : '#fbb' , 'margin-top' : '4px' , 'margin-bottom' : '4px' } ) ;
mbUI . slideDown ( ) ;
throw e ;
2015-06-16 21:24:24 +00:00
}
2014-02-21 18:25:49 +00:00
} ,
error : function ( jqXHR , textStatus , errorThrown ) {
2019-04-11 12:45:52 +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 ) {
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 ) ;
2019-04-11 12:45:52 +00:00
$tr . find ( ` a[mlink^=" ${ discogs _type } /"] ` ) . each ( function ( ) {
let $link = $ ( this ) ;
2015-06-12 09:27:19 +00:00
if ( $link . attr ( 'mlink_stop' ) ) return ; // for places
2019-04-11 12:45:52 +00:00
let mlink = $link . attr ( 'mlink' ) ;
2015-06-06 08:42:28 +00:00
// ensure we do it only once per link
2019-04-11 12:45:52 +00:00
let done = ( $link . attr ( 'mlink_done' ) || '' ) . split ( ',' ) ;
for ( let i = 0 ; i < done . length ; i ++ ) {
if ( mb _type == done [ i ] ) return ;
2015-06-11 13:33:11 +00:00
}
done . push ( mb _type ) ;
2019-04-11 12:45:52 +00:00
$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 ) {
2019-04-11 12:45:52 +00:00
let discogs _url = link _infos [ mlink ] . clean _url ;
let cachekey = getCacheKeyFromInfo ( mlink , mb _type ) ;
let 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
let entities = {
artist : { mark : 'A' } ,
release : { mark : 'R' } ,
'release-group' : { mark : 'G' } ,
place : { mark : 'P' } ,
label : { mark : 'L' }
} ;
let mark = '' ;
let entity _name = 'entity' ;
if ( mb _type in entities ) {
mark = entities [ mb _type ] . mark ;
entity _name = mb _type . replace ( /[_-]/g , ' ' ) ;
}
$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 } < / s m a l l > ? < / a > < / s p a n > `
) ;
2015-06-14 19:58:43 +00:00
}
2019-04-11 12:45:52 +00:00
let 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 ( ) ;
} ;
let insert _stop = function ( link ) {
insert _normal ( link ) ;
$link . attr ( 'mlink_stop' , true ) ;
} ;
let insert _func = insert _normal ;
if ( mb _type == 'place' ) {
// if a place link was added we stop, we don't want further queries for this 'label'
insert _func = insert _stop ;
2015-06-14 19:58:43 +00:00
}
2019-04-11 12:45:52 +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 ) {
2019-04-11 12:45:52 +00:00
let 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 ] } ` ) ;
let debug _attr = $ ( what ) . attr ( 'debug_discogs' ) ;
if ( ! id ) id = '' ;
if ( debug _attr ) {
$ ( what ) . attr ( 'debug_discogs' , ` ${ debug _attr } || ${ id } ( ${ n } ) ` ) ;
} else {
$ ( what ) . attr ( 'debug_discogs' , ` ${ id } ( ${ n } ) ` ) ;
}
2015-06-11 09:57:52 +00:00
}
}
2015-06-05 21:28:45 +00:00
2019-04-11 12:45:52 +00:00
let add _mblinks _counter = 0 ;
2015-06-14 19:58:43 +00:00
function add _mblinks ( _root , selector , types , nosearch ) {
2019-04-11 12:45:52 +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 ] ;
2015-06-12 13:12:09 +00:00
}
2019-04-11 12:45:52 +00:00
$ . 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 ( ) {
let node = $ ( this ) . get ( 0 ) ;
magnifyLinks ( node ) ;
debug _color ( this , ++ add _mblinks _counter , selector ) ;
let that = this ;
$ . each ( types , function ( idx , val ) {
let discogs _type = val [ 0 ] ;
let mb _type = val [ 1 ] ;
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
2019-04-11 12:45:52 +00:00
let mbLinkInsert = function ( link ) {
let $h1 = $ ( 'h1' ) ;
let $titleSpan = $h1 . children ( 'span[itemprop="name"]' ) ;
if ( $titleSpan . length > 0 ) {
$titleSpan . before ( link ) ;
} else {
$h1 . prepend ( link ) ;
}
} ;
let current _page _info = link _infos [ current _page _key ] ;
let mb _type = defaultMBtype ( current _page _info . type ) ;
let cachekey = getCacheKeyFromInfo ( current _page _key , mb _type ) ;
2015-06-18 21:00:31 +00:00
mblinks . searchAndDisplayMbLink ( current _page _info . clean _url , mb _type , mbLinkInsert , cachekey ) ;
2019-04-11 12:45:52 +00:00
let $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 ) ;
2013-08-04 08:33:02 +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
2019-04-11 12:45:52 +00:00
if ( rootNode . hasAttribute ( 'mlink_processed' ) ) return ;
2015-06-12 13:09:53 +00:00
rootNode . setAttribute ( 'mlink_processed' , ++ mlink _processed ) ;
2012-06-08 23:58:47 +00:00
2019-04-11 12:45:52 +00:00
let elems = rootNode . getElementsByTagName ( 'a' ) ;
for ( let i = 0 ; i < elems . length ; i ++ ) {
let elem = elems [ i ] ;
2012-06-08 23:58:47 +00:00
// Ignore empty links
2019-04-11 12:45:52 +00:00
if ( ! elem . href || $ . trim ( elem . textContent ) == '' || elem . textContent . substring ( 4 , 0 ) == 'http' ) continue ;
2015-06-11 09:22:23 +00:00
if ( ! elem . hasAttribute ( 'mlink' ) ) {
2019-04-11 12:45:52 +00:00
elem . setAttribute ( 'mlink' , getDiscogsLinkKey ( elem . href ) ) ;
2015-06-11 09:22:23 +00:00
}
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 ) {
2019-04-11 12:45:52 +00:00
let re = /^https?:\/\/(?:www|api)\.discogs\.com\/(?:(?:(?!sell).+|sell.+)\/)?(master|release|artist|label)s?\/(\d+)(?:[^\?#]*)(?:\?noanv=1|\?anv=[^=]+)?$/i ;
if ( ( m = re . exec ( url ) ) ) {
let key = ` ${ m [ 1 ] } / ${ m [ 2 ] } ` ;
if ( ! link _infos [ key ] ) {
link _infos [ key ] = {
type : m [ 1 ] ,
id : m [ 2 ] ,
clean _url : ` https://www.discogs.com/ ${ m [ 1 ] } / ${ m [ 2 ] } `
} ;
LOGGER . debug ( ` getDiscogsLinkKey: ${ url } --> ${ key } ` ) ;
} else {
LOGGER . debug ( ` getDiscogsLinkKey: ${ url } --> ${ key } (key exists) ` ) ;
2015-06-11 09:22:23 +00:00
}
2019-04-11 12:45:52 +00:00
return key ;
2012-06-08 23:58:47 +00:00
}
2019-04-11 12:45:52 +00:00
LOGGER . debug ( ` getDiscogsLinkKey: ${ url } ? ` ) ;
2015-06-11 09:22:23 +00:00
return false ;
2012-06-08 23:58:47 +00:00
}
2015-06-11 09:22:23 +00:00
function getCleanUrl ( url , discogs _type ) {
2019-04-11 12:45:52 +00:00
try {
let 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 ) ;
2015-06-11 09:22:23 +00:00
}
2019-04-11 12:45:52 +00:00
LOGGER . debug ( ` getCleanUrl: ${ url } ( ${ discogs _type } ) failed ` ) ;
return false ;
2015-06-11 09:22:23 +00:00
}
2015-06-12 09:21:43 +00:00
function defaultMBtype ( discogs _type ) {
2019-04-11 12:45:52 +00:00
if ( discogs _type == 'master' ) return 'release-group' ;
return discogs _type ;
2015-06-12 09:21:43 +00:00
}
2015-06-12 09:23:38 +00:00
function getCacheKeyFromInfo ( info _key , mb _type ) {
2019-04-11 12:45:52 +00:00
let inf = link _infos [ info _key ] ;
if ( inf ) {
if ( ! mb _type ) mb _type = defaultMBtype ( inf . type ) ;
return ` ${ inf . type } / ${ inf . id } / ${ mb _type } ` ;
}
return '' ;
2015-06-12 09:23:38 +00:00
}
function getCacheKeyFromUrl ( url , discogs _type , mb _type ) {
2019-04-11 12:45:52 +00:00
try {
let key = getDiscogsLinkKey ( url ) ;
if ( key ) {
if ( ! discogs _type || link _infos [ key ] . type == discogs _type ) {
let 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 ) ;
2015-06-12 09:23:38 +00:00
}
2019-04-11 12:45:52 +00:00
LOGGER . debug ( ` getCacheKeyFromUrl: ${ url } ( ${ discogs _type } ) failed ` ) ;
return false ;
2015-06-12 09:23:38 +00:00
}
2015-06-12 09:24:55 +00:00
function MBIDfromUrl ( url , discogs _type , mb _type ) {
2019-04-11 12:45:52 +00:00
let 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 ) {
2019-04-11 12:45:52 +00:00
let e ;
if ( ( e = $ ( 'div.section.collections' ) ) && e . length ) {
e . after ( mbUI ) ;
} else if ( ( e = $ ( '#statistics' ) ) && e . length ) {
e . before ( mbUI ) ;
} else if ( ( e = $ ( 'div.section.social' ) ) && e . length ) {
e . before ( mbUI ) ;
}
2015-06-17 08:50:52 +00:00
}
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 ) {
2019-04-11 12:45:52 +00:00
let current _page _info = link _infos [ current _page _key ] ;
2013-12-31 18:21:47 +00:00
2019-04-11 12:45:52 +00:00
let mbUI = $ ( '<div class="section musicbrainz"><h3>MusicBrainz</h3></div>' ) . hide ( ) ;
2013-12-31 18:21:47 +00:00
2019-04-11 12:45:52 +00:00
if ( DEBUG ) mbUI . css ( { border : '1px dotted red' } ) ;
2015-06-14 12:25:10 +00:00
2019-04-11 12:45:52 +00:00
let mbContentBlock = $ ( '<div class="section_content"></div>' ) ;
2013-12-31 18:21:47 +00:00
mbUI . append ( mbContentBlock ) ;
2015-06-17 07:43:57 +00:00
if ( release . maybe _buggy ) {
2019-04-11 12:45:52 +00:00
let 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 ) ;
2015-06-17 07:43:57 +00:00
}
2013-12-31 18:21:47 +00:00
// Form parameters
2019-04-11 12:45:52 +00:00
let edit _note = MBImport . makeEditNote ( current _page _info . clean _url , 'Discogs' ) ;
let 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
2019-04-11 12:45:52 +00:00
let innerHTML = ` <div id="mb_buttons"> ${ MBImport . buildFormHTML ( parameters ) } ${ MBImport . buildSearchButton ( release ) } </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 ( {
2019-04-11 12:45:52 +00:00
display : 'inline-block' ,
width : '100%'
2015-06-16 13:34:02 +00:00
} ) ;
2019-04-11 12:45:52 +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 ) {
2019-04-11 12:45:52 +00:00
// 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)
let last = obj . artist _credit . length - 1 ;
if ( last == 0 || obj . artist _credit [ last ] . joinphrase == ', ' ) {
obj . artist _credit [ last ] . joinphrase = '' ;
}
2015-06-21 13:45:21 +00:00
}
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 ) {
2019-04-11 12:45:52 +00:00
return artist _name . replace ( / \(\d+\)$/ , '' ) ;
2015-06-23 06:35:20 +00:00
}
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 ) {
2019-04-11 12:45:52 +00:00
if ( ! date ) return ;
let 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 ] ;
}
}
2015-06-23 07:40:39 +00:00
}
}
2012-06-08 23:58:47 +00:00
// Analyze Discogs data and return a release object
function parseDiscogsRelease ( data ) {
2019-04-11 12:45:52 +00:00
let discogsRelease = data ;
2012-06-08 23:58:47 +00:00
2019-04-11 12:45:52 +00:00
let 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 ) {
2019-04-11 12:45:52 +00:00
let ac = {
artist _name : artistNoNum ( artist . name ) ,
credited _name : artist . anv != '' ? artist . anv : artistNoNum ( artist . name ) ,
joinphrase : decodeDiscogsJoinphrase ( artist . join ) ,
mbid : MBIDfromUrl ( artist . resource _url , 'artist' )
2012-06-08 23:58:47 +00:00
} ;
2019-04-11 12:45:52 +00:00
if ( artist . id == 194 ) {
// discogs place holder for various
ac = MBImport . specialArtist ( 'various_artists' , ac ) ;
2015-06-21 14:26:45 +00:00
}
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 ) {
2019-04-11 12:45:52 +00:00
release . release _group _mbid = MBIDfromUrl ( discogsRelease . master _url , 'master' ) ;
2015-06-11 13:57:15 +00:00
}
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 ) {
2019-04-11 12:45:52 +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 ) {
2019-04-11 12:45:52 +00:00
let 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
2019-04-11 12:45:52 +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
2019-04-11 12:45:52 +00:00
let release _formats = [ ] ;
2015-06-17 22:18:22 +00:00
release . secondary _types = [ ] ;
2012-06-08 23:58:47 +00:00
if ( discogsRelease . formats . length > 0 ) {
2019-04-11 12:45:52 +00:00
for ( let 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' ] ) ) {
2016-12-17 09:13:32 +00:00
// Release format: special handling of Vinyl and Shellac 7", 10" and 12"
2019-04-11 12:45:52 +00:00
if ( desc . match ( /7"|10"|12"/ ) && discogs _format . concat ( desc ) in MediaTypes )
mb _format = MediaTypes [ discogs _format . concat ( desc ) ] ;
2016-12-17 09:13:32 +00:00
// Release format: special handling of specific CD/DVD formats
2019-04-11 12:45:52 +00:00
if ( desc . match ( /^VCD|SVCD|CD\+G|HDCD|DVD-Audio|DVD-Video/ ) && desc in MediaTypes ) mb _format = MediaTypes [ desc ] ;
2015-06-22 20:35:37 +00:00
}
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)
2019-04-11 12:45:52 +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
2019-04-11 12:45:52 +00:00
if ( discogs _format == 'CD' && desc == 'Mini' ) mb _format = '8cm CD' ;
2012-12-08 21:23:04 +00:00
// Release status
2019-04-11 12:45:52 +00:00
if ( desc . match ( /Promo|Smplr/ ) ) release . status = 'promotion' ;
if ( desc . match ( /Unofficial Release/ ) ) release . status = 'bootleg' ;
2012-12-08 21:23:04 +00:00
// Release type
2019-04-11 12:45:52 +00:00
if ( desc . match ( /Compilation/ ) ) release . secondary _types . push ( 'compilation' ) ;
if ( desc . match ( /^Album/ ) ) release . type = 'album' ;
if ( desc . match ( /Single(?! Sided)/ ) ) release . type = 'single' ;
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 ) {
2019-04-11 12:45:52 +00:00
for ( let j = 0 ; j < discogsRelease . formats [ i ] . qty ; j ++ ) {
2015-06-22 20:35:37 +00:00
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 ) {
2019-04-11 12:45:52 +00:00
let freetext = discogsRelease . formats [ i ] . text . toLowerCase ( ) . replace ( /[\s-]/g , '' ) ;
if ( freetext . match ( /cardboard|paper/ ) ) release . packaging = 'cardboard/paper sleeve' ;
else if ( freetext . match ( /digipak/ ) ) release . packaging = 'digipak' ;
else if ( freetext . match ( /keepcase/ ) ) release . packaging = 'keep case' ;
2015-06-23 08:19:54 +00:00
else if ( freetext . match ( /jewel/ ) ) {
2019-04-11 12:45:52 +00:00
release . packaging = freetext . match ( /slim/ ) ? 'slim jewel case' : 'jewel case' ;
} 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 ) {
2019-04-11 12:45:52 +00:00
if ( identifier . type == 'Barcode' ) {
2012-06-08 23:58:47 +00:00
release . barcode = identifier . value . replace ( / /g , '' ) ;
return false ;
}
} ) ;
}
// Inspect tracks
2019-04-11 12:45:52 +00:00
let tracks = [ ] ;
2012-06-08 23:58:47 +00:00
2019-04-11 12:45:52 +00:00
let heading = '' ;
let releaseNumber = 1 ;
let 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' ) {
2019-04-11 12:45:52 +00:00
heading = discogsTrack . title ;
return ;
2015-06-23 07:43:20 +00:00
}
if ( discogsTrack . type _ != 'track' && discogsTrack . type _ != 'index' ) {
2019-04-11 12:45:52 +00:00
return ;
2015-06-03 15:09:38 +00:00
}
2012-06-08 23:58:47 +00:00
2019-04-11 12:45:52 +00:00
let track = new Object ( ) ;
2012-06-08 23:58:47 +00:00
2018-02-28 10:48:30 +00:00
track . title = discogsTrack . title . replace ( /´ /g , '’ ' ) ;
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 ) {
2019-04-11 12:45:52 +00:00
let ac = {
artist _name : artistNoNum ( artist . name ) ,
credited _name : artist . anv != '' ? artist . anv : artistNoNum ( artist . name ) ,
joinphrase : decodeDiscogsJoinphrase ( artist . join ) ,
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
2019-04-11 12:45:52 +00:00
let trackPosition = discogsTrack . position ;
2012-06-08 23:58:47 +00:00
2015-06-03 22:37:15 +00:00
// Handle sub-tracks
2019-04-11 12:45:52 +00:00
if ( trackPosition == '' && discogsTrack . sub _tracks ) {
2015-01-16 12:56:36 +00:00
trackPosition = discogsTrack . sub _tracks [ 0 ] . position ;
2015-06-03 22:37:15 +00:00
// Append titles of sub-tracks to main track title
2019-04-11 12:45:52 +00:00
let subtrack _titles = [ ] ;
let subtrack _total _duration = 0 ;
2015-06-03 22:37:15 +00:00
$ . each ( discogsTrack . sub _tracks , function ( subtrack _index , subtrack ) {
2019-04-11 12:45:52 +00:00
if ( subtrack . type _ != 'track' ) {
return ;
}
if ( subtrack . duration ) {
subtrack _total _duration += MBImport . hmsToMilliSeconds ( subtrack . duration ) ;
}
if ( subtrack . title ) {
subtrack _titles . push ( subtrack . title ) ;
} else {
subtrack _titles . push ( '[unknown]' ) ;
}
2015-06-03 22:37:15 +00:00
} ) ;
if ( subtrack _titles . length ) {
2019-04-11 12:45:52 +00:00
if ( track . title ) {
track . title += ': ' ;
}
track . title += subtrack _titles . join ( ' / ' ) ;
2015-06-03 22:37:15 +00:00
}
2015-06-13 02:25:31 +00:00
if ( isNaN ( track . duration ) && ! isNaN ( subtrack _total _duration ) ) {
2019-04-11 12:45:52 +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 ) ) {
2019-04-11 12:45:52 +00:00
trackPosition = '' ;
2012-06-08 23:58:47 +00:00
}
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
2019-04-11 12:45:52 +00:00
let 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 ;
2019-04-11 12:45:52 +00:00
let prevReleaseNumber = releaseNumber ;
2015-06-16 22:31:22 +00:00
2015-06-22 21:24:49 +00:00
if ( Number . isInteger ( tmp [ 1 ] ) ) {
2019-04-11 12:45:52 +00:00
if ( tmp [ 2 ] ) {
// 1-1, 1-2, 2-1, ... - we can get release number and track number from this
releaseNumber = tmp [ 1 ] ;
lastPosition = parseInt ( tmp [ 2 ] , 10 ) ;
} else if ( tmp [ 1 ] <= lastPosition ) {
// 1, 2, 3, ... - We've moved onto a new medium
releaseNumber ++ ;
lastPosition = tmp [ 1 ] ;
} else {
lastPosition = tmp [ 1 ] ;
}
2015-06-17 22:18:22 +00:00
} else {
2019-04-11 12:45:52 +00:00
if ( trackPosition . match ( /^[A-Z]\d*$/i ) ) {
// Vinyl or cassette, handle it specially
// A,B -> 1; C,D -> 2; E,F -> 3, etc...
releaseNumber = ( ( ( 32 | trackPosition . charCodeAt ( 0 ) ) - 97 ) >> 1 ) + 1 ;
lastPosition ++ ;
} else if ( trackPosition . match ( /^[A-Z]+\d*$/i ) ) {
// Vinyl or cassette, handle it specially
// 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 ) {
2019-04-11 12:45:52 +00:00
// well, it went wrong so ...
lastPosition ++ ;
2015-06-16 22:31:22 +00:00
}
2012-06-08 23:58:47 +00:00
}
// Create release if needed
2019-04-11 12:45:52 +00:00
let discindex = releaseNumber - 1 ;
2015-06-22 23:55:55 +00:00
if ( ! release . discs [ discindex ] ) {
2019-04-11 12:45:52 +00:00
let newdisc = {
tracks : [ ] ,
format : release _formats [ discindex ]
2015-06-23 06:23:50 +00:00
} ;
2015-06-03 15:09:38 +00:00
if ( heading ) {
2019-04-11 12:45:52 +00:00
newdisc . title = heading ;
heading = '' ;
2015-06-03 15:09:38 +00:00
}
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)
2019-04-11 12:45:52 +00:00
if (
buggyTrackNumber ||
( release . discs [ discindex ] . format . match ( /(Vinyl|Cassette)/ ) && 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
2019-04-11 12:45:52 +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 ) {
2019-04-11 12:45:52 +00:00
release . maybe _buggy = true ;
2015-06-17 07:43:57 +00:00
}
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 ) {
2019-04-11 12:45:52 +00:00
// remove title if there is only one disc
// https://github.com/murdos/musicbrainz-userscripts/issues/69
release . discs [ 0 ] . title = '' ;
2015-07-02 07:52:24 +00:00
}
2019-04-11 12:45:52 +00:00
LOGGER . info ( 'Parsed release: ' , release ) ;
2012-06-08 23:58:47 +00:00
return release ;
}
function decodeDiscogsJoinphrase ( join ) {
2019-04-11 12:45:52 +00:00
let joinphrase = '' ;
let trimedjoin = join . replace ( /^\s*/ , '' ) . replace ( /\s*$/ , '' ) ;
if ( trimedjoin == '' ) return trimedjoin ;
if ( trimedjoin != ',' ) joinphrase += ' ' ;
2012-06-08 23:58:47 +00:00
joinphrase += trimedjoin ;
2019-04-11 12:45:52 +00:00
joinphrase += ' ' ;
2012-06-08 23:58:47 +00:00
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 = {
2019-04-11 12:45:52 +00:00
'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' : 'USB Flash Drive' ,
Microcassette : 'Other' ,
Minidisc : 'MiniDisc' ,
MVD : 'Other' ,
'Reel-To-Reel' : 'Reel-to-reel' ,
SACD : 'SACD' ,
SelectaVision : 'Other' ,
Shellac : 'Shellac' ,
2016-12-17 09:13:32 +00:00
'Shellac7"' : '7" Shellac' ,
'Shellac10"' : '10" Shellac' ,
'Shellac12"' : '12" Shellac' ,
2019-04-11 12:45:52 +00:00
SVCD : 'SVCD' ,
UMD : 'UMD' ,
VCD : 'VCD' ,
VHS : 'VHS' ,
'Video 2000' : 'Other' ,
Vinyl : 'Vinyl' ,
2016-12-17 09:13:32 +00:00
'Vinyl7"' : '7" Vinyl' ,
'Vinyl10"' : '10" Vinyl' ,
2019-04-11 12:45:52 +00:00
'Vinyl12"' : '12" Vinyl' ,
'Lathe Cut' : 'Phonograph record'
2015-06-17 22:18:22 +00:00
} ;
var Countries = {
2019-04-11 12:45:52 +00:00
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' ,
'Barbados, The' : '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 : '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 & 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' ,
USSR : 'SU' ,
'East Germany (historical, 1949-1990)' : 'XG' ,
Czechoslovakia : 'XC' ,
'Congo, Republic of the' : 'CD' ,
Slovakia : 'SK' ,
'Bosnia & 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 : 'YU' ,
'Serbia and Montenegro' : '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'
2015-06-17 22:18:22 +00:00
} ;