Skip to content

Commit f8139b7

Browse files
authored
feat(Deezer): workaround for fetching copyright & total disk number (#639)
1 parent 437c505 commit f8139b7

File tree

2 files changed

+63
-26
lines changed

2 files changed

+63
-26
lines changed

README.md

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -50,22 +50,22 @@ Depending on the URLs you provide freyr, it will;
5050

5151
Here's a list of the metadata that freyr can extract from each streaming service:
5252

53-
| Meta | Spotify | Apple Music | Deezer |
54-
| :------------: | :-----: | :---------: | :---------------: |
55-
| `Title` ||| |
56-
| `Artist` ||| |
57-
| `Composer` ||| |
58-
| `Album` ||| |
59-
| `Genre` ||| |
60-
| `Track Number` ||| |
61-
| `Disk Number` |||(no total) |
62-
| `Release Date` ||| |
63-
| `Rating` ||| |
64-
| `Album Artist` ||| |
65-
| `ISRC` ||| |
66-
| `Label` ||| |
67-
| `Copyright` ||| |
68-
| `Cover Art` ||| |
53+
| Meta | Spotify | Apple Music | Deezer |
54+
| :------------: | :-----: | :---------: | :----: |
55+
| `Title` ||| |
56+
| `Artist` ||| |
57+
| `Composer` ||| |
58+
| `Album` ||| |
59+
| `Genre` ||| |
60+
| `Track Number` ||| |
61+
| `Disk Number` ||||
62+
| `Release Date` ||| |
63+
| `Rating` ||| |
64+
| `Album Artist` ||| |
65+
| `ISRC` ||| |
66+
| `Label` ||| |
67+
| `Copyright` ||| |
68+
| `Cover Art` ||| |
6969

7070
## Support the project
7171

src/services/deezer.js

Lines changed: 47 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ const sleep = ms => new Promise(res => setTimeout(res, ms));
2222

2323
export class DeezerCore {
2424
legacyApiUrl = 'https://api.deezer.com';
25+
altApiUrl = 'https://www.deezer.com/ajax/gw-light.php';
2526

2627
requestObject = got.extend({
2728
responseType: 'json',
@@ -32,8 +33,13 @@ export class DeezerCore {
3233

3334
#retrySymbol = Symbol('DeezerCoreTrialCount');
3435

35-
#getIfHasError = response =>
36-
response.body && typeof response.body === 'object' && 'error' in response.body && response.body.error;
36+
#getIfHasError = response => {
37+
if (!(response.body && typeof response.body === 'object' && 'error' in response.body)) return null;
38+
39+
if (Array.isArray(response.body.error)) return response.body.error.length > 0 ? response.body.error[0] : null;
40+
41+
return response.body.error;
42+
};
3743

3844
validatorQueue = new AsyncQueue('validatorQueue', 1, async now => {
3945
if (this.#validatorData.queries.length === 50)
@@ -63,8 +69,8 @@ export class DeezerCore {
6369

6470
totalTrials = 5;
6571

66-
async legacyApiCall(ref, opts) {
67-
const response = await this.#sendRequest(ref, opts, this.totalTrials || 5).catch(err => {
72+
async wrappedCall(called) {
73+
const response = await called.catch(err => {
6874
throw new WebapiError(
6975
`${err.syscall ? `${err.syscall} ` : ''}${err.code} ${err.hostname || err.host}`,
7076
err.response ? err.response.statusCode : null,
@@ -81,8 +87,31 @@ export class DeezerCore {
8187
return response.body;
8288
}
8389

90+
#altAuth = {token: null, sessionId: null};
91+
92+
async altApiCall(method, opts) {
93+
if (!this.#altAuth.token) {
94+
let result = await this._altApiCall('deezer.getUserData');
95+
this.#altAuth = {token: result.checkForm, sessionId: result.SESSION_ID};
96+
}
97+
98+
return this._altApiCall(method, opts);
99+
}
100+
101+
async _altApiCall(method, opts) {
102+
const response = await this.wrappedCall(
103+
this.requestObject.post(this.altApiUrl, {
104+
headers: {...(this.#altAuth?.sessionId && {cookie: `sid=${this.#altAuth.sessionId}`})},
105+
searchParams: {method, api_version: '1.0', api_token: this.#altAuth.token ?? ''},
106+
json: {lang: 'en', ...opts},
107+
}),
108+
);
109+
110+
return response.results;
111+
}
112+
84113
processID(gnFn) {
85-
return (id, opts) => this.legacyApiCall(gnFn(id), opts);
114+
return (id, opts) => this.wrappedCall(this.#sendRequest(gnFn(id), opts, this.totalTrials || 5));
86115
}
87116

88117
processList(gnFn) {
@@ -207,6 +236,7 @@ export default class Deezer {
207236
total_tracks: albumInfo.ntracks,
208237
release_date: new Date(trackInfo.release_date),
209238
disc_number: trackInfo.disk_number,
239+
total_discs: albumInfo.tracks.reduce((acc, track) => Math.max(acc, track.altData.DISK_NUMBER), 1),
210240
contentRating: !!trackInfo.explicit_lyrics,
211241
isrc: trackInfo.isrc,
212242
genres: albumInfo.genres,
@@ -218,8 +248,9 @@ export default class Deezer {
218248
};
219249
}
220250

221-
wrapAlbumData(albumObject) {
251+
wrapAlbumData(albumObject, altAlbumObject) {
222252
const artistObject = albumObject.artist || {};
253+
let altTracks = Object.fromEntries((altAlbumObject.SONGS?.data || []).map(track => [track.SNG_ID, track]));
223254
return {
224255
id: albumObject.id,
225256
uri: albumObject.link,
@@ -232,12 +263,12 @@ export default class Deezer {
232263
? 'single'
233264
: 'album',
234265
genres: ((albumObject.genres || {}).data || []).map(genre => genre.name),
235-
copyrights: [{type: 'P', text: albumObject.copyright}], // find workaround
266+
copyrights: [{type: 'P', text: altAlbumObject.DATA.PRODUCER_LINE}],
236267
images: [albumObject.cover_small, albumObject.cover_medium, albumObject.cover_big, albumObject.cover_xl],
237268
label: albumObject.label,
238269
release_date: new Date(albumObject.release_date),
239270
ntracks: albumObject.nb_tracks,
240-
tracks: albumObject.tracks,
271+
tracks: albumObject.tracks.data.map(track => ({...track, altData: altTracks[track.id]})),
241272
getImage(width, height) {
242273
const min = (val, max) => Math.min(max, val) || max;
243274
return this.images
@@ -298,7 +329,13 @@ export default class Deezer {
298329
albumQueue = new AsyncQueue(
299330
'deezer:albumQueue',
300331
4,
301-
this.createDataProcessor(async id => this.wrapAlbumData(await this.#store.core.getAlbum(id))),
332+
this.createDataProcessor(async id => {
333+
let [album, altAlbumData] = await Promise.all([
334+
this.#store.core.getAlbum(id),
335+
this.#store.core.altApiCall('deezer.pageAlbum', {alb_id: id}),
336+
]);
337+
return this.wrapAlbumData(album, altAlbumData);
338+
}),
302339
);
303340

304341
async getAlbum(uris) {
@@ -327,7 +364,7 @@ export default class Deezer {
327364

328365
async getAlbumTracks(uri) {
329366
const album = await this.getAlbum(uri);
330-
return this.trackQueue.push(album.tracks.data.map(track => track.link));
367+
return this.trackQueue.push(album.tracks.map(track => track.link));
331368
}
332369

333370
async getArtistAlbums(uris) {

0 commit comments

Comments
 (0)