2015-06-05 09:13:42 +00:00
|
|
|
|
// Class MBLinks : query MusicBrainz for urls and display links for matching urls
|
|
|
|
|
// The main method is searchAndDisplayMbLink()
|
|
|
|
|
|
|
|
|
|
// Example:
|
|
|
|
|
// $(document).ready(function () {
|
|
|
|
|
//
|
|
|
|
|
// var mblinks = new MBLinks('EXAMPLE_MBLINKS_CACHE', 7*24*60); // force refresh of cached links once a week
|
|
|
|
|
//
|
|
|
|
|
// var artist_link = 'http://' + window.location.href.match( /^https?:\/\/(.*)\/album\/.+$/i)[1];
|
|
|
|
|
// mblinks.searchAndDisplayMbLink(artist_link, 'artist', function (link) { $('div#there').before(link); } );
|
|
|
|
|
//
|
|
|
|
|
// var album_link = 'http://' + window.location.href.match( /^https?:\/\/(.*\/album\/.+)$/i)[1];
|
|
|
|
|
// mblinks.searchAndDisplayMbLink(album_link, 'release', function (link) { $('div#there').after(link); } );
|
|
|
|
|
// }
|
|
|
|
|
|
2015-06-11 12:25:58 +00:00
|
|
|
|
// user_cache_key = textual key used to store cached data in local storage
|
2015-06-05 09:13:42 +00:00
|
|
|
|
// expiration = time in minutes before an entry is refreshed, value <= 0 disables cache reads
|
2015-06-12 14:17:22 +00:00
|
|
|
|
// version = optionnal version, to force creation of a cache (ie. when format of keys changes)
|
|
|
|
|
var MBLinks = function (user_cache_key, expiration, version) {
|
2015-06-05 09:13:42 +00:00
|
|
|
|
this.supports_local_storage = function () {
|
|
|
|
|
try {
|
|
|
|
|
return !!localStorage.getItem;
|
|
|
|
|
} catch (e) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}();
|
|
|
|
|
|
2015-06-08 20:44:39 +00:00
|
|
|
|
this.ajax_requests = {
|
2015-06-08 22:16:41 +00:00
|
|
|
|
// properties: "key": {handler: function, next: property, context: {}}
|
2015-06-08 20:44:39 +00:00
|
|
|
|
first: "",
|
|
|
|
|
last: "",
|
|
|
|
|
empty: function() {return this.first == "";},
|
2015-06-08 22:16:41 +00:00
|
|
|
|
push: function(key, handler, context) {
|
2015-06-08 20:44:39 +00:00
|
|
|
|
if (key in this) {
|
2015-06-08 22:16:41 +00:00
|
|
|
|
this[key].handler = handler;
|
|
|
|
|
this[key].context = context;
|
2015-06-08 20:44:39 +00:00
|
|
|
|
}
|
|
|
|
|
else {
|
2015-06-08 22:16:41 +00:00
|
|
|
|
this[key] = {handler: handler, next: "", context: context};
|
2015-06-08 20:44:39 +00:00
|
|
|
|
if (this.first == "") {
|
|
|
|
|
this.first = this.last = key;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
this[this.last].next = key;
|
|
|
|
|
this.last = key;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
shift: function() {
|
2015-06-08 22:16:41 +00:00
|
|
|
|
if (this.empty()) { return; }
|
2015-06-08 20:44:39 +00:00
|
|
|
|
var key = this.first;
|
2015-06-08 22:16:41 +00:00
|
|
|
|
var handler = this[key].handler;
|
|
|
|
|
var context = this[key].context;
|
2015-06-08 20:44:39 +00:00
|
|
|
|
this.first = this[key].next;
|
|
|
|
|
delete this[key]; // delete this property
|
2015-06-08 22:16:41 +00:00
|
|
|
|
return $.proxy(handler, context);
|
2015-06-08 20:44:39 +00:00
|
|
|
|
}
|
|
|
|
|
};
|
2015-06-05 09:13:42 +00:00
|
|
|
|
this.cache = {};
|
2015-06-10 22:21:39 +00:00
|
|
|
|
this.expirationMinutes = parseInt(expiration, 10);
|
2015-06-11 11:52:59 +00:00
|
|
|
|
var cache_version = 2;
|
2015-06-11 12:25:58 +00:00
|
|
|
|
this.user_cache_key = user_cache_key;
|
2015-06-12 14:17:22 +00:00
|
|
|
|
this.cache_key = this.user_cache_key + '-v' + cache_version + (typeof version != 'undefined' ? '.' + version : '');
|
2015-06-05 15:01:19 +00:00
|
|
|
|
this.mb_server = '//musicbrainz.org';
|
2015-06-05 19:57:03 +00:00
|
|
|
|
// overrides link title and img src url (per type), see createMusicBrainzLink()
|
|
|
|
|
this.type_link_info = {
|
|
|
|
|
release_group: {
|
|
|
|
|
title: 'See this release group on MusicBrainz',
|
|
|
|
|
},
|
2015-06-11 13:30:39 +00:00
|
|
|
|
place: {
|
|
|
|
|
img_src: '<img src="'+ this.mb_server + '/static/images/entity/place_lg.png" height=16 width=16 />'
|
|
|
|
|
}
|
2015-06-05 19:57:03 +00:00
|
|
|
|
}
|
2015-06-05 09:13:42 +00:00
|
|
|
|
|
|
|
|
|
this.initAjaxEngine = function () {
|
|
|
|
|
var ajax_requests = this.ajax_requests;
|
|
|
|
|
setInterval(function () {
|
2015-06-08 22:16:41 +00:00
|
|
|
|
if (!ajax_requests.empty()) {
|
2015-06-05 09:13:42 +00:00
|
|
|
|
var request = ajax_requests.shift();
|
|
|
|
|
if (typeof request === "function") {
|
|
|
|
|
request();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}, 1000);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
this.initCache = function () {
|
|
|
|
|
if (!this.supports_local_storage) return;
|
|
|
|
|
// Check if we already added links for this content
|
2015-06-05 15:15:04 +00:00
|
|
|
|
this.cache = JSON.parse(localStorage.getItem(this.cache_key) || '{}');
|
2015-06-11 12:00:12 +00:00
|
|
|
|
// remove old entries
|
|
|
|
|
this.clearCacheExpired();
|
2015-06-11 12:25:58 +00:00
|
|
|
|
// remove old cache versions
|
|
|
|
|
this.removeOldCacheVersions();
|
2015-06-05 09:13:42 +00:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
this.saveCache = function () {
|
|
|
|
|
if (!this.supports_local_storage) return;
|
|
|
|
|
try {
|
|
|
|
|
localStorage.setItem(this.cache_key, JSON.stringify(this.cache));
|
|
|
|
|
} catch (e) {
|
|
|
|
|
alert(e);
|
|
|
|
|
}
|
2015-06-11 11:53:38 +00:00
|
|
|
|
};
|
2015-06-05 09:13:42 +00:00
|
|
|
|
|
2015-06-11 12:25:58 +00:00
|
|
|
|
this.removeOldCacheVersions = function () {
|
|
|
|
|
var to_remove = [];
|
|
|
|
|
for (var i = 0, len = localStorage.length; i < len; ++i) {
|
|
|
|
|
var key = localStorage.key(i);
|
|
|
|
|
if (key.indexOf(this.user_cache_key) === 0) {
|
|
|
|
|
if (key != this.cache_key) { // we don't want to remove current cache
|
|
|
|
|
to_remove.push(key);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// remove old cache keys
|
|
|
|
|
for (var i = 0; i < to_remove.length; i++) {
|
|
|
|
|
localStorage.removeItem(to_remove[i]);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2015-06-11 12:00:12 +00:00
|
|
|
|
this.clearCacheExpired = function() {
|
|
|
|
|
//var old_cache_entries = Object.keys(this.cache).length;
|
|
|
|
|
//console.log("clearCacheExpired " + old_cache_entries);
|
|
|
|
|
var now = new Date().getTime();
|
|
|
|
|
var new_cache = {};
|
|
|
|
|
var that = this;
|
|
|
|
|
$.each(this.cache, function (key, value) {
|
|
|
|
|
if (that.is_cached(key)) {
|
|
|
|
|
new_cache[key] = that.cache[key];
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
//var new_cache_entries = Object.keys(new_cache).length;
|
|
|
|
|
//console.log("Cleared cache entries: " + old_cache_entries + ' -> ' + new_cache_entries);
|
|
|
|
|
this.cache = new_cache;
|
|
|
|
|
};
|
|
|
|
|
|
2015-06-12 09:18:08 +00:00
|
|
|
|
this.is_cached = function (key) {
|
|
|
|
|
return (this.cache[key] && this.expirationMinutes > 0 && new Date().getTime() < this.cache[key].timestamp + this.expirationMinutes*60*1000);
|
2015-06-11 11:52:59 +00:00
|
|
|
|
};
|
|
|
|
|
|
2015-06-07 19:49:51 +00:00
|
|
|
|
// Search for ressource 'url' in local cache, and return the matching MBID if there's only matching MB entity.
|
|
|
|
|
// 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.
|
2015-06-12 09:18:08 +00:00
|
|
|
|
this.resolveMBID = function (key) {
|
|
|
|
|
if (this.is_cached(key) && this.cache[key].urls.length == 1) {
|
|
|
|
|
return this.cache[key].urls[0].slice(-36);
|
2015-06-07 19:49:51 +00:00
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2015-06-05 19:50:52 +00:00
|
|
|
|
this.createMusicBrainzLink = function (mb_url, _type) {
|
2015-06-05 19:57:03 +00:00
|
|
|
|
var title = 'See this ' + _type + ' on MusicBrainz';
|
2015-06-05 19:50:52 +00:00
|
|
|
|
var img_url = this.mb_server + '/static/images/entity/' + _type + '.png';
|
2015-06-11 13:30:39 +00:00
|
|
|
|
var img_src = '<img src="' + img_url + '" height=16 width=16 />';
|
2015-06-05 19:57:03 +00:00
|
|
|
|
// handle overrides
|
|
|
|
|
var ti = this.type_link_info[_type];
|
|
|
|
|
if (ti) {
|
|
|
|
|
if (ti.title) title = ti.title;
|
|
|
|
|
if (ti.img_url) img_url = ti.img_url;
|
2015-06-11 13:30:39 +00:00
|
|
|
|
if (ti.img_src) img_src = ti.img_src;
|
2015-06-05 19:57:03 +00:00
|
|
|
|
}
|
2015-06-11 13:30:39 +00:00
|
|
|
|
return '<a href="' + mb_url + '" title="' + title + '">' + img_src + '</a> ';
|
2015-06-05 09:13:42 +00:00
|
|
|
|
};
|
|
|
|
|
|
2015-06-05 15:26:53 +00:00
|
|
|
|
// Search for ressource 'url' on MB, for relation of type 'mb_type' (artist, release, label, release-group, ...)
|
2015-06-05 09:13:42 +00:00
|
|
|
|
// and call 'insert_func' function with matching MB links (a tag built in createMusicBrainzLink) for each
|
|
|
|
|
// entry found
|
2015-06-12 09:18:08 +00:00
|
|
|
|
this.searchAndDisplayMbLink = function (url, mb_type, insert_func, key) {
|
2015-06-05 09:13:42 +00:00
|
|
|
|
var mblinks = this;
|
2015-06-05 19:50:52 +00:00
|
|
|
|
var _type = mb_type.replace('-', '_'); // underscored type
|
2015-06-05 09:13:42 +00:00
|
|
|
|
|
2015-06-12 09:18:08 +00:00
|
|
|
|
if (!key) key = url;
|
|
|
|
|
if (this.is_cached(key)) {
|
|
|
|
|
$.each(mblinks.cache[key].urls, function (idx, mb_url) {
|
2015-06-05 19:50:52 +00:00
|
|
|
|
insert_func(mblinks.createMusicBrainzLink(mb_url, _type));
|
2015-06-05 09:13:42 +00:00
|
|
|
|
});
|
|
|
|
|
} else {
|
2015-06-10 21:52:36 +00:00
|
|
|
|
|
|
|
|
|
// webservice query url
|
|
|
|
|
var query = mblinks.mb_server + '/ws/2/url?resource=' + encodeURIComponent(url) + '&inc=' + mb_type + '-rels';
|
|
|
|
|
|
2015-06-08 22:16:41 +00:00
|
|
|
|
// Merge with previous context if there's already a pending ajax request
|
|
|
|
|
var handlers = [];
|
2015-06-10 21:52:36 +00:00
|
|
|
|
if (query in mblinks.ajax_requests) {
|
|
|
|
|
handlers = mblinks.ajax_requests[query].context.handlers;
|
2015-06-08 22:16:41 +00:00
|
|
|
|
}
|
|
|
|
|
handlers.push(insert_func);
|
2015-06-10 21:52:36 +00:00
|
|
|
|
|
|
|
|
|
mblinks.ajax_requests.push(
|
|
|
|
|
// key
|
|
|
|
|
query,
|
|
|
|
|
|
|
|
|
|
// handler
|
|
|
|
|
function () {
|
|
|
|
|
var ctx = this; // context from $.proxy()
|
|
|
|
|
var mbl = ctx.mblinks;
|
|
|
|
|
$.getJSON(ctx.query,
|
|
|
|
|
function (data) {
|
|
|
|
|
if ('relations' in data) {
|
2015-06-12 09:18:08 +00:00
|
|
|
|
mbl.cache[ctx.key] = {
|
2015-06-11 11:52:59 +00:00
|
|
|
|
timestamp: new Date().getTime(),
|
2015-06-10 21:52:36 +00:00
|
|
|
|
urls: []
|
|
|
|
|
};
|
|
|
|
|
$.each(data['relations'], function (idx, relation) {
|
|
|
|
|
if (ctx._type in relation) {
|
|
|
|
|
var mb_url = mbl.mb_server + '/' + ctx.mb_type + '/' + relation[ctx._type]['id'];
|
2015-06-12 09:18:08 +00:00
|
|
|
|
if ($.inArray(mb_url, mbl.cache[ctx.key].urls) == -1) { // prevent dupes
|
|
|
|
|
mbl.cache[ctx.key].urls.push(mb_url);
|
2015-06-10 21:52:36 +00:00
|
|
|
|
$.each(ctx.handlers, function(i, handler) {
|
|
|
|
|
handler(mbl.createMusicBrainzLink(mb_url, ctx._type))
|
|
|
|
|
})
|
|
|
|
|
}
|
2015-06-05 09:13:42 +00:00
|
|
|
|
}
|
2015-06-10 21:52:36 +00:00
|
|
|
|
});
|
|
|
|
|
mbl.saveCache();
|
|
|
|
|
}
|
2015-06-05 09:13:42 +00:00
|
|
|
|
}
|
2015-06-10 21:52:36 +00:00
|
|
|
|
);
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
// context
|
|
|
|
|
{
|
2015-06-12 09:18:08 +00:00
|
|
|
|
'key': key, // cache key
|
2015-06-10 21:52:36 +00:00
|
|
|
|
'handlers': handlers, // list of handlers
|
|
|
|
|
'mb_type': mb_type, // musicbrainz type ie. release-group
|
|
|
|
|
'_type': _type, // musicbrainz type '-' replaced, ie. release_group
|
|
|
|
|
'query': query, // json request url
|
|
|
|
|
'mblinks': mblinks // MBLinks object
|
|
|
|
|
}
|
|
|
|
|
);
|
2015-06-05 09:13:42 +00:00
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
this.initCache();
|
|
|
|
|
this.initAjaxEngine();
|
|
|
|
|
|
|
|
|
|
return this;
|
|
|
|
|
};
|