musicbrainz-userscripts/bandcamp_importer.user.js
Laurent Monin 507641ee33 Bandcamp importer: add links to matching MB artist and releases
Based on the discogs importer code, but with few improvements:
- localStorage entries can expire (set to 1 week)
- code has its own namespace, and is more generic (it will move to a lib later)
- prevent jquery libs conflicts (GM vs website), jquery upgraded to 2.1.4
2015-06-05 10:39:00 +02:00

331 lines
11 KiB
JavaScript

// ==UserScript==
// @name Import Bandcamp releases into MB
// @description Add a button on Bandcamp's album pages to open MusicBrainz release editor with pre-filled data for the selected release
// @version 2015.05.29.2
// @namespace http://userscripts.org/users/22504
// @downloadURL https://raw.github.com/murdos/musicbrainz-userscripts/master/bandcamp_importer.user.js
// @updateURL https://raw.github.com/murdos/musicbrainz-userscripts/master/bandcamp_importer.user.js
// @include http*://*.bandcamp.com/album/*
// @include http*://*.bandcamp.com/track/*
// @require https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js
// @require https://raw.github.com/murdos/musicbrainz-userscripts/master/lib/import_functions.js
// @require https://raw.github.com/murdos/musicbrainz-userscripts/master/lib/logger.js
// @grant None
// ==/UserScript==
// prevent JQuery conflicts, see http://wiki.greasespot.net/@grant
this.$ = this.jQuery = jQuery.noConflict(true);
if (!unsafeWindow) unsafeWindow = window;
var BandcampImport = {
// Analyze Bandcamp data and return a release object
retrieveReleaseInfo: function () {
var bandcampAlbumData = unsafeWindow.TralbumData;
var bandcampEmbedData = unsafeWindow.EmbedData;
var release = {
discs: [],
artist_credit: [],
title: '',
year: 0,
month: 0,
day: 0,
parent_album: '',
labels: [],
format: 'Digital Media',
country: 'XW',
type: '',
status: 'official',
packaging: 'None',
language: 'eng',
script: 'Latn',
urls: []
};
// Release artist credit
release.artist_credit = [{
artist_name: bandcampAlbumData.artist
}];
// Grab release title
release.title = bandcampAlbumData.current.title;
// Grab release event information
var date = this.convdate(bandcampAlbumData.current.release_date);
if (date) {
if (!(date.year > 2008 || (date.year == 2008 && date.month >= 9))) {
// use publish date if release date is before Bandcamp launch (2008-09)
var pdate = this.convdate(bandcampAlbumData.current.publish_date);
if (pdate) {
date = pdate;
}
}
release.year = date.year;
release.month = date.month;
release.day = date.day;
}
if (bandcampEmbedData.album_title) {
release.parent_album = bandcampEmbedData.album_title;
}
// FIXME: implement a mapping between bandcamp release types and MB ones
release.type = bandcampAlbumData.current.type;
// map Bandcamp single tracks to singles
if (release.type == "track") {
release.type = "single";
}
// Tracks
var disc = {
tracks: [],
format: release.format
};
release.discs.push(disc);
$.each(bandcampAlbumData.trackinfo, function (index, bctrack) {
var track = {
'title': bctrack.title,
'duration': Math.round(bctrack.duration * 1000),
'artist_credit': []
};
disc.tracks.push(track);
});
// Check for hidden tracks (more tracks in the download than shown for streaming ie.)
var showntracks = bandcampAlbumData.trackinfo.length;
var numtracks = -1;
var nostream = false;
// album description indicates number of tracks in the download
var match = /^\d+ track album$/.exec($("meta[property='og:description']").attr("content"));
if (match) {
numtracks = parseInt(match);
}
if (numtracks > 0 && numtracks > showntracks) {
// display a warning if tracks in download differs from tracks shown
$('h2.trackTitle').append(
'<p style="font-size:70%; font-style: italic; margin: 0.1em 0;">' +
'Warning: ' + numtracks + ' vs ' + showntracks + ' tracks' +
'</p>'
);
// append unknown tracks to the release
for (var i = 0; i < numtracks - showntracks; i++) {
var track = {
'title': '[unknown]',
'duration': null,
'artist_credit': []
};
disc.tracks.push(track);
}
// disable stream link as only part of the album can be streamed
nostream = true;
}
// URLs
var link_type = {
purchase_for_download: 74,
download_for_free: 75,
stream_for_free: 85,
license: 301
};
// Download for free vs. for purchase
if (bandcampAlbumData.current.download_pref !== null) {
if (bandcampAlbumData.freeDownloadPage !== null || bandcampAlbumData.current.download_pref === 1 || (
bandcampAlbumData.current.download_pref === 2 && bandcampAlbumData.current.minimum_price === 0)) {
release.urls.push({
'url': window.location.href,
'link_type': link_type.download_for_free
});
}
if (bandcampAlbumData.current.download_pref === 2) {
release.urls.push({
'url': window.location.href,
'link_type': link_type.purchase_for_download
});
}
}
// Check if the release is streamable
if (bandcampAlbumData.hasAudio && !nostream) {
release.urls.push({
'url': window.location.href,
'link_type': link_type.stream_for_free
});
}
// Check if release is Creative Commons licensed
if ($("div#license a.cc-icons").length > 0) {
release.urls.push({
'url': $("div#license a.cc-icons").attr("href"),
'link_type': link_type.license
});
}
// Check if album has a back link to a label
var label = $("a.back-to-label-link span.back-to-label-name").text();
if (label) {
release.labels.push({
'name': label,
'mbid': '',
'catno': 'none'
});
}
return release;
},
// Insert links in page
insertLink: function (release) {
if (release.type == "single" && typeof release.parent_album != "undefined") {
return false;
}
// Form parameters
var edit_note = 'Imported from ' + window.location.href;
var parameters = MBReleaseImportHelper.buildFormParameters(release, edit_note);
// Build form
var innerHTML = MBReleaseImportHelper.buildFormHTML(parameters);
// Append MB import link
$('h2.trackTitle').append(innerHTML);
},
// helper to convert bandcamp date to MB date
convdate: function (date) {
if (typeof date != "undefined" && date !== "") {
var d = new Date(date);
return {
"year": d.getUTCFullYear(),
"month": d.getUTCMonth() + 1,
"day": d.getUTCDate()
};
}
return false;
}
};
var MBLinks = function (cachekey, expiration) {
this.supports_local_storage = function () {
try {
return !!localStorage.getItem;
} catch (e) {
return false;
}
}();
this.ajax_requests = [];
this.cache = {};
this.expirationMinutes = parseInt(expiration);
this.cache_key = cachekey;
this.initAjaxEngine = function () {
var ajax_requests = this.ajax_requests;
setInterval(function () {
if (ajax_requests.length > 0) {
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
var cache_string = localStorage.getItem(this.cache_key);
if (!cache_string) {
cache_string = "{}";
}
this.cache = JSON.parse(cache_string);
};
this.saveCache = function () {
if (!this.supports_local_storage) return;
try {
localStorage.setItem(this.cache_key, JSON.stringify(this.cache));
} catch (e) {
alert(e);
}
},
this.createMusicBrainzLink = function (mb_url, mb_type) {
return '<a href="' + mb_url + '" title="Link to MB ' + mb_type +
'"><img src="//musicbrainz.org/static/images/entity/' + mb_type + '.png" /></a> ';
};
this.searchAndDisplayMbLink = function (url, mb_type, insert_func) {
var mblinks = this;
if (mb_type != 'artist' && mb_type != 'release' && mb_type != 'label' && mb_type != 'release-group') {
return;
}
if (mblinks.cache[url]
&& mblinks.expirationMinutes > 0
&& new Date().getTime() < mblinks.cache[url].timestamp) {
$.each(mblinks.cache[url].urls, function (idx, mb_url) {
insert_func(mblinks.createMusicBrainzLink(mb_url, mb_type));
});
} else {
mblinks.ajax_requests.push($.proxy(function () {
var context = this;
$.getJSON('//musicbrainz.org/ws/2/url?resource=' + context.url + '&inc=' + context.mb_type +
'-rels',
function (data) {
if ('relations' in data) {
var expires = new Date().getTime() + (mblinks.expirationMinutes * 60 * 1000);
mblinks.cache[context.url] = {
timestamp: expires,
urls: []
};
$.each(data['relations'], function (idx, relation) {
if (context.mb_type.replace('-', '_') in relation) {
var mb_url = '//musicbrainz.org/' + context.mb_type + '/' + relation[context.mb_type.replace('-', '_')]['id'];
if ($.inArray(mb_url, mblinks.cache[context.url].urls) == -1) { // prevent dupes
mblinks.cache[context.url].urls.push(mb_url);
mblinks.saveCache();
context.insert_func(mblinks.createMusicBrainzLink(mb_url, mb_type));
}
}
});
}
});
}, {
'url': url,
'insert_func': insert_func,
'mb_type': mb_type
}));
}
};
this.initCache();
this.initAjaxEngine();
return this;
};
$(document).ready(function () {
var mblinks = new MBLinks('BCI_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#name-section span[itemprop="byArtist"]').before(link); } );
var album_link = 'http://' + window.location.href.match( /^https?:\/\/(.*\/album\/.+)$/i)[1];
mblinks.searchAndDisplayMbLink(album_link, 'release', function (link) { $('div#name-section span[itemprop="byArtist"]').after(link); } );
var release = BandcampImport.retrieveReleaseInfo();
LOGGER.info("Parsed release: ", release);
BandcampImport.insertLink(release);
// append a comma after each tag to ease cut'n'paste to MB
$("div.tralbum-tags a:not(:last-child)").after(",");
// append a link to the full size image
var fullsizeimageurl = $("div#tralbumArt a").attr("href").replace('_10', '_0');
$("div#tralbumArt").after("<div id='bci_link'><a class='custom-color' href='" + fullsizeimageurl +
"' title='Open original image in a new tab (Bandcamp importer)' target='_blank'>Original image</a></div>");
$("div#bci_link").css({ 'padding-top': '0.5em', 'text-align': 'right' });
$("div#bci_link a").css({ 'font-weight': 'bold' });
});