@@ -45,19 +45,27 @@ const MBLinks = function (user_cache_key, version, expiration) {
4545
4646 if ( ! relations ) return ;
4747
48- const insertedMbUrls = { } ;
48+ // Build map of mb_url -> ended (true if any relation has ended). Only relevant for release.
49+ const urlData = { } ;
4950 relations . forEach ( relation => {
5051 if ( _type in relation ) {
5152 const mb_url = `${ mblinks . mb_server } /${ reference . mb_type } /${ relation [ _type ] . id } ` ;
52- if ( insertedMbUrls [ mb_url ] ) return ;
53- insertedMbUrls [ mb_url ] = true ;
54- if ( $ . inArray ( mb_url , mblinks . cache [ key ] . urls ) === - 1 ) {
55- mblinks . cache [ key ] . urls . push ( mb_url ) ;
56- }
57- const link = mblinks . createMusicBrainzLink ( mb_url , _type ) ;
58- matching_urls_data . forEach ( m => m . insert_func ( link ) ) ;
53+ if ( ! ( mb_url in urlData ) ) urlData [ mb_url ] = { ended : false } ;
54+ if ( relation . ended ) urlData [ mb_url ] . ended = true ;
5955 }
6056 } ) ;
57+
58+ const cacheUrls = mblinks . cache [ key ] . urls ;
59+ const getUrl = entry => ( typeof entry === 'string' ? entry : entry . url ) ;
60+ Object . keys ( urlData ) . forEach ( mb_url => {
61+ const ended = urlData [ mb_url ] . ended ;
62+ const alreadyCached = cacheUrls . some ( e => getUrl ( e ) === mb_url ) ;
63+ if ( ! alreadyCached ) {
64+ cacheUrls . push ( { url : mb_url , ended : _type === 'release' ? ended : false } ) ;
65+ }
66+ const link = mblinks . createMusicBrainzLink ( mb_url , _type , _type === 'release' ? { ended } : { } ) ;
67+ matching_urls_data . forEach ( m => m . insert_func ( link ) ) ;
68+ } ) ;
6169 }
6270
6371 this . supports_local_storage = ( function ( ) {
@@ -103,7 +111,7 @@ const MBLinks = function (user_cache_key, version, expiration) {
103111 } ;
104112 this . cache = { } ;
105113 this . expirationMinutes = typeof expiration != 'undefined' && expiration !== false ? parseInt ( expiration , 10 ) : 90 * 24 * 60 ; // default to 90 days
106- let cache_version = 2 ;
114+ let cache_version = 3 ;
107115 this . user_cache_key = user_cache_key ;
108116 this . cache_key = `${ this . user_cache_key } -v${ cache_version } ${ typeof version != 'undefined' ? `.${ version } ` : '' } ` ;
109117 this . mb_server = 'https://musicbrainz.org' ;
@@ -227,17 +235,21 @@ const MBLinks = function (user_cache_key, version, expiration) {
227235 // If the url is not known by the cache, no attempt will be made to request the MusicBrainz webservice, in order to keep this method synchronous.
228236 this . resolveMBID = function ( key ) {
229237 if ( this . is_cached ( key ) && this . cache [ key ] . urls . length == 1 ) {
230- return this . cache [ key ] . urls [ 0 ] . slice ( - 36 ) ;
238+ const entry = this . cache [ key ] . urls [ 0 ] ;
239+ const mb_url = typeof entry === 'string' ? entry : entry . url ;
240+ return mb_url . slice ( - 36 ) ;
231241 }
232242 } ;
233243
234244 /**
235245 * Create an HTML element for a MusicBrainz link with the given type and URL.
236246 * @param {string } mb_url - The URL of the MusicBrainz entity.
237247 * @param {string } _type - The type of the MusicBrainz entity.
248+ * @param {Object } [options] - Optional options.
249+ * @param {boolean } [options.ended] - When true and type is release, applies grayscale to the icon.
238250 * @returns {string } The HTML for the MusicBrainz link.
239251 */
240- this . createMusicBrainzLink = function ( mb_url , _type ) {
252+ this . createMusicBrainzLink = function ( mb_url , _type , options ) {
241253 let title = `See this ${ _type } on MusicBrainz` ;
242254 let img_url = `${ this . mb_server } /static/images/entity/${ _type } .svg` ;
243255 let img_src = `<img src="${ img_url } " height=16 width=16 />` ;
@@ -248,6 +260,9 @@ const MBLinks = function (user_cache_key, version, expiration) {
248260 if ( ti . img_url ) img_url = ti . img_url ;
249261 if ( ti . img_src ) img_src = ti . img_src ;
250262 }
263+ if ( _type === 'release' && options && options . ended ) {
264+ img_src = img_src . replace ( '/>' , ' style="filter: grayscale(1)" />' ) ;
265+ }
251266 return `<a href="${ mb_url } " title="${ title } ">${ img_src } </a> ` ;
252267 } ;
253268
@@ -265,7 +280,8 @@ const MBLinks = function (user_cache_key, version, expiration) {
265280
266281 if ( ! key ) key = url ;
267282 if ( this . is_cached ( key ) ) {
268- $ . each ( mblinks . cache [ key ] . urls , function ( idx , mb_url ) {
283+ $ . each ( mblinks . cache [ key ] . urls , function ( idx , cacheEntry ) {
284+ const mb_url = typeof cacheEntry === 'string' ? cacheEntry : cacheEntry . url ;
269285 insert_func ( mblinks . createMusicBrainzLink ( mb_url , _type ) ) ;
270286 } ) ;
271287 if ( typeof onComplete === 'function' ) {
@@ -353,8 +369,12 @@ const MBLinks = function (user_cache_key, version, expiration) {
353369 const key = data . key || data . url ;
354370 if ( this . is_cached ( key ) ) {
355371 // Handle cached results immediately
356- $ . each ( mblinks . cache [ key ] . urls , function ( idx , mb_url ) {
357- data . insert_func ( mblinks . createMusicBrainzLink ( mb_url , data . mb_type . replace ( '-' , '_' ) ) ) ;
372+ const data_type = data . mb_type . replace ( '-' , '_' ) ;
373+ $ . each ( mblinks . cache [ key ] . urls , function ( idx , cacheEntry ) {
374+ const mb_url = typeof cacheEntry === 'string' ? cacheEntry : cacheEntry . url ;
375+ const ended = typeof cacheEntry === 'string' ? false : cacheEntry . ended ;
376+ const options = data_type === 'release' ? { ended } : { } ;
377+ data . insert_func ( mblinks . createMusicBrainzLink ( mb_url , data_type , options ) ) ;
358378 } ) ;
359379 } else {
360380 uncached_urls . push ( data ) ;
0 commit comments