Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ Add a button on CD1D.com release pages allowing to open MusicBrainz release edit

## <a name="deezer_importer"></a> Import Deezer releases into MusicBrainz

One-click importing of releases from deezer.com into MusicBrainz
One-click importing of releases from deezer.com into MusicBrainz. Also allows to submit their ISRCs to MusicBrainz releases.

[![Source](https://github.com/jerone/UserScripts/blob/master/_resources/Source-button.png)](https://github.com/murdos/musicbrainz-userscripts/blob/master/deezer_importer.user.js)
[![Install](https://raw.github.com/jerone/UserScripts/master/_resources/Install-button.png)](https://raw.githubusercontent.com/murdos/musicbrainz-userscripts/master/deezer_importer.user.js)
Expand Down
77 changes: 58 additions & 19 deletions deezer_importer.user.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// ==UserScript==
// @name Import Deezer releases into MusicBrainz
// @namespace https://github.com/murdos/musicbrainz-userscripts/
// @description One-click importing of releases from deezer.com into MusicBrainz
// @version 2025.6.2
// @description One-click importing of releases from deezer.com into MusicBrainz. Also allows to submit their ISRCs to MusicBrainz releases.
// @version 2025.6.24
// @downloadURL https://raw.githubusercontent.com/murdos/musicbrainz-userscripts/master/deezer_importer.user.js
// @updateURL https://raw.githubusercontent.com/murdos/musicbrainz-userscripts/master/deezer_importer.user.js
// @include http*://www.deezer.com/*/album/*
Expand Down Expand Up @@ -35,15 +35,37 @@ $(document).ready(function () {
MBImportStyle();
let releaseUrl = window.location.href.replace(/\?.*$/, '').replace(/#.*$/, '');
let releaseId = releaseUrl.replace(/^https?:\/\/www\.deezer\.com\/[^/]+\/album\//i, '');
let deezerApiUrl = `https://api.deezer.com/album/${releaseId}`;
let deezerApiUrl = `https://api.deezer.com/album/${releaseId}?limit=1`; // limit track result to 1, we will request tracks in a separate API call (that returns more complete data)
let deezerTrackUrl = `https://api.deezer.com/album/${releaseId}/tracks?limit=100`;

gmXHR({
method: 'GET',
url: deezerApiUrl,
onload: function (resp) {
try {
let release = parseDeezerRelease(releaseUrl, JSON.parse(resp.responseText));
insertLink(release, releaseUrl);
let releaseRaw = JSON.parse(resp.responseText);
releaseRaw.tracks.data = [];
// request album tracks from separate endpoint (includes track ISRCs and disk numbers)
let loadTracks = function (next) {
gmXHR({
method: 'GET',
url: next,
onload: function (res) {
let tracksRaw = JSON.parse(res.responseText);
releaseRaw.tracks.data.push(...tracksRaw.data);
if (tracksRaw.next) loadTracks(tracksRaw.next);
else {
let [release, isrcs] = parseDeezerRelease(releaseUrl, releaseRaw);
insertLink(release, releaseUrl, isrcs);
}
},
onerror: function (res) {
LOGGER.error('AJAX status:', res.status);
LOGGER.error('AJAX response:', res.responseText);
},
});
};
loadTracks(deezerTrackUrl);
} catch (e) {
LOGGER.error('Failed to parse release: ', e);
}
Expand Down Expand Up @@ -76,6 +98,8 @@ function parseDeezerRelease(releaseUrl, data) {
discs: [],
};

let isrcs = [];

$.each(data.contributors, function (index, artist) {
if (artist.role != 'Main') return true;

Expand All @@ -91,31 +115,34 @@ function parseDeezerRelease(releaseUrl, data) {
release.artist_credit.push(ac);
});

let disc = {
format: 'Digital Media',
title: '',
tracks: [],
};

$.each(data.tracks.data, function (index, track) {
for (const track of data.tracks.data) {
let t = {
number: index + 1,
number: track.track_position,
title: track.title_short,
duration: track.duration * 1000,
artist_credit: [],
};

if (track.isrc) isrcs.push(track.isrc);
else isrcs.push(null);

// ignore pointless "(Original Mix)" in title version
if (track.title_version && !track.title_version.match(/^\s*\(Original Mix\)\s*$/i)) {
t.title += ` ${track.title_version}`;
}

t.artist_credit.push({ artist_name: track.artist.name });

disc.tracks.push(t);
});
// add new disk object(s) if not added yet
while (release.discs.length < track.disk_number)
release.discs.push({
format: 'Digital Media',
title: '',
tracks: [],
});

release.discs.push(disc);
release.discs[track.disk_number - 1].tracks.push(t);
}

release.urls.push({
link_type: MBImport.URL_TYPES.stream_for_free,
Expand All @@ -125,7 +152,7 @@ function parseDeezerRelease(releaseUrl, data) {
release.type = data.record_type;
release.barcode = data.upc;

return release;
return [release, isrcs];
}

function waitForEl(selector, callback) {
Expand All @@ -138,7 +165,7 @@ function waitForEl(selector, callback) {
}
}

function insertLink(release, release_url) {
function insertLink(release, release_url, isrcs) {
let editNote = MBImport.makeEditNote(release_url, 'Deezer');
let parameters = MBImport.buildFormParameters(release, editNote);

Expand All @@ -147,8 +174,20 @@ function insertLink(release, release_url) {
${MBImport.buildFormHTML(parameters)}
</div><div class="toolbar-item">
${MBImport.buildSearchButton(release)}
</div>`,
</div><div class="toolbar-item"></div>`,
).hide();
$(
`<form class="musicbrainz_import"><button type="submit" title="Submit ISRCs to MusicBrainz with kepstin’s MagicISRC"><span>Submit ISRCs</span></button></form>`,
)
.on('click', event => {
const query = [
`edit-note=${encodeURIComponent(editNote)}`,
...isrcs.map((isrc, index) => (isrc == null ? `isrc${index + 1}=` : `isrc${index + 1}=${isrc}`)),
].join('&');
event.preventDefault();
window.open(`https://magicisrc.kepstin.ca?${query}`);
})
.appendTo(mbUI.last());
waitForEl('[data-testid="toolbar"]', function () {
$('[data-testid="toolbar"]').css({
'align-items': 'center',
Expand Down
Loading