q-fi-core 2.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (79) hide show
  1. package/CHANGELOG.md +109 -0
  2. package/LICENSE +1 -0
  3. package/README.md +186 -0
  4. package/dist/api/api.d.ts +78 -0
  5. package/dist/api/api.js +182 -0
  6. package/dist/api/cache.d.ts +3 -0
  7. package/dist/api/cache.js +12 -0
  8. package/dist/api/index.d.ts +2 -0
  9. package/dist/api/index.js +18 -0
  10. package/dist/api/request.d.ts +23 -0
  11. package/dist/api/request.js +88 -0
  12. package/dist/converter/deezer.d.ts +3 -0
  13. package/dist/converter/deezer.js +45 -0
  14. package/dist/converter/index.d.ts +5 -0
  15. package/dist/converter/index.js +34 -0
  16. package/dist/converter/parse.d.ts +18 -0
  17. package/dist/converter/parse.js +176 -0
  18. package/dist/converter/spotify.d.ts +40 -0
  19. package/dist/converter/spotify.js +154 -0
  20. package/dist/converter/tidal.d.ts +146 -0
  21. package/dist/converter/tidal.js +199 -0
  22. package/dist/converter/youtube.d.ts +6 -0
  23. package/dist/converter/youtube.js +102 -0
  24. package/dist/index.d.ts +6 -0
  25. package/dist/index.js +24 -0
  26. package/dist/lib/decrypt.d.ts +9 -0
  27. package/dist/lib/decrypt.js +63 -0
  28. package/dist/lib/fast-lru.d.ts +63 -0
  29. package/dist/lib/fast-lru.js +121 -0
  30. package/dist/lib/get-url.d.ts +16 -0
  31. package/dist/lib/get-url.js +154 -0
  32. package/dist/lib/http.d.ts +66 -0
  33. package/dist/lib/http.js +235 -0
  34. package/dist/lib/metaflac-js.d.ts +124 -0
  35. package/dist/lib/metaflac-js.js +343 -0
  36. package/dist/lib/request.d.ts +18 -0
  37. package/dist/lib/request.js +86 -0
  38. package/dist/metadata-writer/abumCover.d.ts +10 -0
  39. package/dist/metadata-writer/abumCover.js +37 -0
  40. package/dist/metadata-writer/flacmetata.d.ts +3 -0
  41. package/dist/metadata-writer/flacmetata.js +80 -0
  42. package/dist/metadata-writer/getTrackLyrics.d.ts +2 -0
  43. package/dist/metadata-writer/getTrackLyrics.js +26 -0
  44. package/dist/metadata-writer/id3.d.ts +3 -0
  45. package/dist/metadata-writer/id3.js +119 -0
  46. package/dist/metadata-writer/index.d.ts +9 -0
  47. package/dist/metadata-writer/index.js +44 -0
  48. package/dist/metadata-writer/musixmatchLyrics.d.ts +1 -0
  49. package/dist/metadata-writer/musixmatchLyrics.js +39 -0
  50. package/dist/metadata-writer/useragents.d.ts +1 -0
  51. package/dist/metadata-writer/useragents.js +86 -0
  52. package/dist/types/album.d.ts +123 -0
  53. package/dist/types/album.js +2 -0
  54. package/dist/types/artist.d.ts +36 -0
  55. package/dist/types/artist.js +2 -0
  56. package/dist/types/channel.d.ts +33 -0
  57. package/dist/types/channel.js +2 -0
  58. package/dist/types/index.d.ts +10 -0
  59. package/dist/types/index.js +26 -0
  60. package/dist/types/playlist-channel.d.ts +81 -0
  61. package/dist/types/playlist-channel.js +2 -0
  62. package/dist/types/playlist.d.ts +49 -0
  63. package/dist/types/playlist.js +2 -0
  64. package/dist/types/profile.d.ts +29 -0
  65. package/dist/types/profile.js +2 -0
  66. package/dist/types/radio.d.ts +7 -0
  67. package/dist/types/radio.js +2 -0
  68. package/dist/types/search.d.ts +79 -0
  69. package/dist/types/search.js +2 -0
  70. package/dist/types/show.d.ts +61 -0
  71. package/dist/types/show.js +2 -0
  72. package/dist/types/tracks.d.ts +144 -0
  73. package/dist/types/tracks.js +2 -0
  74. package/dist/types/user.d.ts +16 -0
  75. package/dist/types/user.js +2 -0
  76. package/package.json +69 -0
  77. package/types/index.d.ts +1 -0
  78. package/types/index.js +3 -0
  79. package/types/package.json +4 -0
@@ -0,0 +1,146 @@
1
+ import type { playlistInfo, trackType } from '../types';
2
+ interface commonType {
3
+ id: number;
4
+ title: string;
5
+ duration: number;
6
+ premiumStreamingOnly: boolean;
7
+ trackNumber: number;
8
+ copyright: string;
9
+ url: string;
10
+ explicit: boolean;
11
+ audioQuality: string;
12
+ artist: {
13
+ id: number;
14
+ name: string;
15
+ type: string;
16
+ };
17
+ album: {
18
+ id: number;
19
+ title: string;
20
+ cover: string;
21
+ };
22
+ }
23
+ interface tidalTrackType extends commonType {
24
+ isrc: string;
25
+ editable: boolean;
26
+ audioQuality: string;
27
+ album: {
28
+ id: number;
29
+ title: string;
30
+ cover: string;
31
+ };
32
+ }
33
+ interface tidalAlbumType extends commonType {
34
+ cover: string;
35
+ videoCover: null | string;
36
+ upc: string;
37
+ audioQuality: string;
38
+ }
39
+ interface tidalPlaylistType {
40
+ uuid: string;
41
+ title: string;
42
+ numberOfTracks: number;
43
+ numberOfVideos: number;
44
+ creator: {
45
+ id: number;
46
+ };
47
+ description: string;
48
+ duration: number;
49
+ lastUpdated: string;
50
+ created: string;
51
+ type: string;
52
+ publicPlaylist: boolean;
53
+ url: string;
54
+ image: string;
55
+ }
56
+ interface listType {
57
+ limit: number;
58
+ offset: number;
59
+ totalNumberOfItems: number;
60
+ }
61
+ interface tidalArtistTopTracksType extends listType {
62
+ items: tidalTrackType[];
63
+ }
64
+ interface tidalAlbumsTracksType extends listType {
65
+ items: tidalAlbumType[];
66
+ }
67
+ interface tidalPlaylistTracksType extends listType {
68
+ items: tidalTrackType[];
69
+ }
70
+ /**
71
+ * Get a track by its id
72
+ * @param string} id - track id
73
+ * @example tidal.getTrack('64975224')
74
+ */
75
+ export declare const getTrack: (id: string) => Promise<tidalTrackType>;
76
+ /**
77
+ * Convert a tidal track to deezer
78
+ * @param {string} id - track id
79
+ */
80
+ export declare const track2deezer: (id: string) => Promise<trackType>;
81
+ /**
82
+ * Get an album by its id
83
+ * @param {string} id - album id
84
+ * @example tidal.getAlbum('80216363')
85
+ */
86
+ export declare const getAlbum: (id: string) => Promise<tidalAlbumType>;
87
+ /**
88
+ * Convert a tidal albums to deezer
89
+ * @param {string} id - album id
90
+ */
91
+ export declare const album2deezer: (id: string) => Promise<[import("../types").albumType, trackType[]]>;
92
+ /**
93
+ * Get album tracks by album id
94
+ * @param {string} id - album id
95
+ * @example tidal.getAlbumTracks('80216363')
96
+ */
97
+ export declare const getAlbumTracks: (id: string) => Promise<tidalAlbumsTracksType>;
98
+ /**
99
+ * Get artist albums by artist id
100
+ * @param {string} id - artist id
101
+ * @example tidal.getArtistAlbums('3575680')
102
+ */
103
+ export declare const getArtistAlbums: (id: string) => Promise<tidalAlbumsTracksType>;
104
+ /**
105
+ * Get top tracks by artist
106
+ * @param {string} id - artist id
107
+ * @example tidal.getArtistTopTracks('3575680')
108
+ */
109
+ export declare const getArtistTopTracks: (id: string) => Promise<tidalArtistTopTracksType>;
110
+ /**
111
+ * Get a playlist by its uuid
112
+ * @param {string} uuid - playlist uuid
113
+ * @example tidal.getPlaylist('1c5d01ed-4f05-40c4-bd28-0f73099e9648')
114
+ */
115
+ export declare const getPlaylist: (uuid: string) => Promise<tidalPlaylistType>;
116
+ /**
117
+ * Get playlist tracks by playlist uuid
118
+ * @param {string} uuid - playlist uuid
119
+ * @example tidal.getPlaylistTracks('1c5d01ed-4f05-40c4-bd28-0f73099e9648')
120
+ */
121
+ export declare const getPlaylistTracks: (uuid: string) => Promise<tidalPlaylistTracksType>;
122
+ /**
123
+ * Get valid urls to album art
124
+ * @param {string} uuid - album art uuid (can be found as cover property in album object)
125
+ * @example tidal.albumArtToUrl('9a56f482-e9cf-46c3-bb21-82710e7854d4')
126
+ * @returns {Object}
127
+ */
128
+ export declare const albumArtToUrl: (uuid: string) => {
129
+ sm: string;
130
+ md: string;
131
+ lg: string;
132
+ xl: string;
133
+ };
134
+ /**
135
+ * Find tidal artists tracks on deezer
136
+ * @param {string} id - artist id
137
+ * @example tidal.artist2Deezer('3575680')
138
+ */
139
+ export declare const artist2Deezer: (id: string, onError?: ((item: tidalTrackType, index: number, err: Error) => void) | undefined) => Promise<trackType[]>;
140
+ /**
141
+ * Find same set of playlist tracks on deezer
142
+ * @param {string} uuid - playlist uuid
143
+ * @example tidal.playlist2Deezer('1c5d01ed-4f05-40c4-bd28-0f73099e9648')
144
+ */
145
+ export declare const playlist2Deezer: (uuid: string, onError?: ((item: tidalTrackType, index: number, err: Error) => void) | undefined) => Promise<[playlistInfo, trackType[]]>;
146
+ export {};
@@ -0,0 +1,199 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.playlist2Deezer = exports.artist2Deezer = exports.albumArtToUrl = exports.getPlaylistTracks = exports.getPlaylist = exports.getArtistTopTracks = exports.getArtistAlbums = exports.getAlbumTracks = exports.album2deezer = exports.getAlbum = exports.track2deezer = exports.getTrack = void 0;
7
+ const p_queue_1 = __importDefault(require("p-queue"));
8
+ const deezer_1 = require("./deezer");
9
+ const http_1 = require("../lib/http");
10
+ const client = new http_1.HttpClient({
11
+ baseURL: 'https://api.tidal.com/v1/',
12
+ timeout: 15000,
13
+ headers: {
14
+ 'user-agent': 'TIDAL/3704 CFNetwork/1220.1 Darwin/20.3.0',
15
+ 'x-tidal-token': 'i4ZDjcyhed7Mu47q',
16
+ },
17
+ params: { limit: 500, countryCode: 'US' },
18
+ });
19
+ const queue = new p_queue_1.default({ concurrency: 25 });
20
+ /**
21
+ * Get a track by its id
22
+ * @param string} id - track id
23
+ * @example tidal.getTrack('64975224')
24
+ */
25
+ const getTrack = async (id) => {
26
+ const { data } = await client.get(`tracks/${id}`);
27
+ return data;
28
+ };
29
+ exports.getTrack = getTrack;
30
+ /**
31
+ * Convert a tidal track to deezer
32
+ * @param {string} id - track id
33
+ */
34
+ const track2deezer = async (id) => {
35
+ const track = await (0, exports.getTrack)(id);
36
+ return await (0, deezer_1.isrc2deezer)(track.title, track.isrc);
37
+ };
38
+ exports.track2deezer = track2deezer;
39
+ /**
40
+ * Get an album by its id
41
+ * @param {string} id - album id
42
+ * @example tidal.getAlbum('80216363')
43
+ */
44
+ const getAlbum = async (id) => {
45
+ const { data } = await client.get(`albums/${id}`);
46
+ return data;
47
+ };
48
+ exports.getAlbum = getAlbum;
49
+ /**
50
+ * Convert a tidal albums to deezer
51
+ * @param {string} id - album id
52
+ */
53
+ const album2deezer = async (id) => {
54
+ const album = await (0, exports.getAlbum)(id);
55
+ return await (0, deezer_1.upc2deezer)(album.title, album.upc);
56
+ };
57
+ exports.album2deezer = album2deezer;
58
+ /**
59
+ * Get album tracks by album id
60
+ * @param {string} id - album id
61
+ * @example tidal.getAlbumTracks('80216363')
62
+ */
63
+ const getAlbumTracks = async (id) => {
64
+ const { data } = await client.get(`albums/${id}/tracks`);
65
+ return data;
66
+ };
67
+ exports.getAlbumTracks = getAlbumTracks;
68
+ /**
69
+ * Get artist albums by artist id
70
+ * @param {string} id - artist id
71
+ * @example tidal.getArtistAlbums('3575680')
72
+ */
73
+ const getArtistAlbums = async (id) => {
74
+ const { data } = await client.get(`artists/${id}/albums`);
75
+ data.items = data.items.filter((item) => item.artist.id.toString() === id);
76
+ return data;
77
+ };
78
+ exports.getArtistAlbums = getArtistAlbums;
79
+ /**
80
+ * Get top tracks by artist
81
+ * @param {string} id - artist id
82
+ * @example tidal.getArtistTopTracks('3575680')
83
+ */
84
+ const getArtistTopTracks = async (id) => {
85
+ const { data } = await client.get(`artists/${id}/toptracks`);
86
+ data.items = data.items.filter((item) => item.artist.id.toString() === id);
87
+ return data;
88
+ };
89
+ exports.getArtistTopTracks = getArtistTopTracks;
90
+ /**
91
+ * Get a playlist by its uuid
92
+ * @param {string} uuid - playlist uuid
93
+ * @example tidal.getPlaylist('1c5d01ed-4f05-40c4-bd28-0f73099e9648')
94
+ */
95
+ const getPlaylist = async (uuid) => {
96
+ const { data } = await client.get(`playlists/${uuid}`);
97
+ return data;
98
+ };
99
+ exports.getPlaylist = getPlaylist;
100
+ /**
101
+ * Get playlist tracks by playlist uuid
102
+ * @param {string} uuid - playlist uuid
103
+ * @example tidal.getPlaylistTracks('1c5d01ed-4f05-40c4-bd28-0f73099e9648')
104
+ */
105
+ const getPlaylistTracks = async (uuid) => {
106
+ const { data } = await client.get(`playlists/${uuid}/tracks`);
107
+ return data;
108
+ };
109
+ exports.getPlaylistTracks = getPlaylistTracks;
110
+ /**
111
+ * Get valid urls to album art
112
+ * @param {string} uuid - album art uuid (can be found as cover property in album object)
113
+ * @example tidal.albumArtToUrl('9a56f482-e9cf-46c3-bb21-82710e7854d4')
114
+ * @returns {Object}
115
+ */
116
+ const albumArtToUrl = (uuid) => {
117
+ const baseUrl = `https://resources.tidal.com/images/${uuid.replace(/-/g, '/')}`;
118
+ return {
119
+ sm: `${baseUrl}/160x160.jpg`,
120
+ md: `${baseUrl}/320x320.jpg`,
121
+ lg: `${baseUrl}/640x640.jpg`,
122
+ xl: `${baseUrl}/1280x1280.jpg`,
123
+ };
124
+ };
125
+ exports.albumArtToUrl = albumArtToUrl;
126
+ /**
127
+ * Find tidal artists tracks on deezer
128
+ * @param {string} id - artist id
129
+ * @example tidal.artist2Deezer('3575680')
130
+ */
131
+ const artist2Deezer = async (id, onError) => {
132
+ const { items } = await (0, exports.getArtistTopTracks)(id);
133
+ const tracks = [];
134
+ await queue.addAll(items.map((item, index) => {
135
+ return async () => {
136
+ try {
137
+ const track = await (0, deezer_1.isrc2deezer)(item.title, item.isrc);
138
+ // console.log(signale.success(`Track #${index}: ${item.name}`));
139
+ tracks.push(track);
140
+ }
141
+ catch (err) {
142
+ if (onError) {
143
+ onError(item, index, err);
144
+ }
145
+ }
146
+ };
147
+ }));
148
+ return tracks;
149
+ };
150
+ exports.artist2Deezer = artist2Deezer;
151
+ /**
152
+ * Find same set of playlist tracks on deezer
153
+ * @param {string} uuid - playlist uuid
154
+ * @example tidal.playlist2Deezer('1c5d01ed-4f05-40c4-bd28-0f73099e9648')
155
+ */
156
+ const playlist2Deezer = async (uuid, onError) => {
157
+ const body = await (0, exports.getPlaylist)(uuid);
158
+ const { items } = await (0, exports.getPlaylistTracks)(uuid);
159
+ const tracks = [];
160
+ await queue.addAll(items.map((item, index) => {
161
+ return async () => {
162
+ try {
163
+ const track = await (0, deezer_1.isrc2deezer)(item.title, item.isrc);
164
+ // console.log(signale.success(`Track #${index}: ${item.track.name}`));
165
+ track.TRACK_POSITION = index + 1;
166
+ tracks.push(track);
167
+ }
168
+ catch (err) {
169
+ if (onError) {
170
+ onError(item, index, err);
171
+ }
172
+ }
173
+ };
174
+ }));
175
+ const userId = body.creator.id.toString();
176
+ const playlistInfoData = {
177
+ PLAYLIST_ID: body.uuid,
178
+ PARENT_USERNAME: userId,
179
+ PARENT_USER_ID: userId,
180
+ PICTURE_TYPE: 'cover',
181
+ PLAYLIST_PICTURE: body.image,
182
+ TITLE: body.title,
183
+ TYPE: '0',
184
+ STATUS: '0',
185
+ USER_ID: userId,
186
+ DATE_ADD: body.created,
187
+ DATE_MOD: body.lastUpdated,
188
+ DATE_CREATE: body.created,
189
+ NB_SONG: body.numberOfTracks,
190
+ NB_FAN: 0,
191
+ CHECKSUM: body.created,
192
+ HAS_ARTIST_LINKED: false,
193
+ IS_SPONSORED: false,
194
+ IS_EDITO: false,
195
+ __TYPE__: 'playlist',
196
+ };
197
+ return [playlistInfoData, tracks];
198
+ };
199
+ exports.playlist2Deezer = playlist2Deezer;
@@ -0,0 +1,6 @@
1
+ import type { trackType } from '../types';
2
+ /**
3
+ * Convert a youtube video to track by video id
4
+ * @param {String} id - video id
5
+ */
6
+ export declare const track2deezer: (id: string) => Promise<trackType>;
@@ -0,0 +1,102 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.track2deezer = void 0;
4
+ const node_html_parser_1 = require("node-html-parser");
5
+ const api_1 = require("../api");
6
+ const http_1 = require("../lib/http");
7
+ const parseInlineObject = (document, variableName) => {
8
+ const prefix = `${variableName} = `;
9
+ const start = document.indexOf(prefix);
10
+ if (start === -1) {
11
+ return null;
12
+ }
13
+ const jsonStart = start + prefix.length;
14
+ let depth = 0;
15
+ let isInString = false;
16
+ let isEscaped = false;
17
+ for (let index = jsonStart; index < document.length; index++) {
18
+ const char = document[index];
19
+ if (isInString) {
20
+ if (isEscaped) {
21
+ isEscaped = false;
22
+ }
23
+ else if (char === '\\') {
24
+ isEscaped = true;
25
+ }
26
+ else if (char === '"') {
27
+ isInString = false;
28
+ }
29
+ continue;
30
+ }
31
+ if (char === '"') {
32
+ isInString = true;
33
+ continue;
34
+ }
35
+ if (char === '{') {
36
+ depth += 1;
37
+ }
38
+ else if (char === '}') {
39
+ depth -= 1;
40
+ if (depth === 0) {
41
+ return JSON.parse(document.slice(jsonStart, index + 1));
42
+ }
43
+ }
44
+ }
45
+ return null;
46
+ };
47
+ const searchTrackByTitle = async (title) => {
48
+ const normalizedTitle = title
49
+ .toLowerCase()
50
+ .replace(/\(off.*\)/i, '')
51
+ .replace(/official video/gi, '')
52
+ .replace(/lyrics?/gi, '')
53
+ .replace(/ft.*/i, '')
54
+ .replace(/[,-.]/g, ' ')
55
+ .replace(/ +/g, ' ')
56
+ .trim();
57
+ if (!normalizedTitle) {
58
+ return undefined;
59
+ }
60
+ const { TRACK } = await (0, api_1.searchMusic)(normalizedTitle, ['TRACK'], 20);
61
+ const filteredTracks = TRACK.data.filter((track) => normalizedTitle.includes(track.ART_NAME.toLowerCase()));
62
+ return filteredTracks[0] || TRACK.data[0];
63
+ };
64
+ const getTrack = async (id) => {
65
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t;
66
+ const response = await (0, http_1.getText)(`https://www.youtube.com/watch?v=${id}&hl=en`);
67
+ const scripts = (0, node_html_parser_1.parse)(response)
68
+ .querySelectorAll('script')
69
+ .map((script) => script.text)
70
+ .join('\n');
71
+ const playerResponse = parseInlineObject(scripts, 'var ytInitialPlayerResponse');
72
+ const initialData = parseInlineObject(scripts, 'var ytInitialData');
73
+ const rows = (_j = (_h = (_g = (_f = (_e = (_d = (_c = (_b = (_a = initialData === null || initialData === void 0 ? void 0 : initialData.contents) === null || _a === void 0 ? void 0 : _a.twoColumnWatchNextResults) === null || _b === void 0 ? void 0 : _b.results) === null || _c === void 0 ? void 0 : _c.results) === null || _d === void 0 ? void 0 : _d.contents) === null || _e === void 0 ? void 0 : _e.find((content) => Boolean(content.videoSecondaryInfoRenderer))) === null || _f === void 0 ? void 0 : _f.videoSecondaryInfoRenderer) === null || _g === void 0 ? void 0 : _g.metadataRowContainer) === null || _h === void 0 ? void 0 : _h.metadataRowContainerRenderer) === null || _j === void 0 ? void 0 : _j.rows;
74
+ if (rows && rows.length > 0) {
75
+ const song = rows.find((row) => { var _a, _b; return ((_b = (_a = row.metadataRowRenderer) === null || _a === void 0 ? void 0 : _a.title) === null || _b === void 0 ? void 0 : _b.simpleText) === 'Song'; });
76
+ const artist = rows.find((row) => { var _a, _b; return ((_b = (_a = row.metadataRowRenderer) === null || _a === void 0 ? void 0 : _a.title) === null || _b === void 0 ? void 0 : _b.simpleText) === 'Artist'; });
77
+ const songName = (_m = (_l = (_k = song === null || song === void 0 ? void 0 : song.metadataRowRenderer) === null || _k === void 0 ? void 0 : _k.contents) === null || _l === void 0 ? void 0 : _l[0]) === null || _m === void 0 ? void 0 : _m.simpleText;
78
+ const artistName = (_s = (_r = (_q = (_p = (_o = artist === null || artist === void 0 ? void 0 : artist.metadataRowRenderer) === null || _o === void 0 ? void 0 : _o.contents) === null || _p === void 0 ? void 0 : _p[0]) === null || _q === void 0 ? void 0 : _q.runs) === null || _r === void 0 ? void 0 : _r[0]) === null || _s === void 0 ? void 0 : _s.text;
79
+ if (songName && artistName) {
80
+ const { TRACK } = await (0, api_1.searchAlternative)(artistName, songName, 1);
81
+ if (TRACK.data[0]) {
82
+ return TRACK.data[0];
83
+ }
84
+ }
85
+ }
86
+ if ((_t = playerResponse === null || playerResponse === void 0 ? void 0 : playerResponse.videoDetails) === null || _t === void 0 ? void 0 : _t.title) {
87
+ return await searchTrackByTitle(playerResponse.videoDetails.title);
88
+ }
89
+ return undefined;
90
+ };
91
+ /**
92
+ * Convert a youtube video to track by video id
93
+ * @param {String} id - video id
94
+ */
95
+ const track2deezer = async (id) => {
96
+ const track = await getTrack(id);
97
+ if (track) {
98
+ return track;
99
+ }
100
+ throw new Error('No track found for youtube video ' + id);
101
+ };
102
+ exports.track2deezer = track2deezer;
@@ -0,0 +1,6 @@
1
+ export { initDeezerApi } from './lib/request';
2
+ export * from './api';
3
+ export * from './converter';
4
+ export * from './lib/decrypt';
5
+ export * from './lib/get-url';
6
+ export * from './metadata-writer';
package/dist/index.js ADDED
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ exports.initDeezerApi = void 0;
18
+ var request_1 = require("./lib/request");
19
+ Object.defineProperty(exports, "initDeezerApi", { enumerable: true, get: function () { return request_1.initDeezerApi; } });
20
+ __exportStar(require("./api"), exports);
21
+ __exportStar(require("./converter"), exports);
22
+ __exportStar(require("./lib/decrypt"), exports);
23
+ __exportStar(require("./lib/get-url"), exports);
24
+ __exportStar(require("./metadata-writer"), exports);
@@ -0,0 +1,9 @@
1
+ /// <reference types="node" />
2
+ import type { trackType } from '../types';
3
+ export declare const getSongFileName: ({ MD5_ORIGIN, SNG_ID, MEDIA_VERSION }: trackType, quality: number) => string;
4
+ /**
5
+ *
6
+ * @param source Downloaded song from `getTrackDownloadUrl`
7
+ * @param trackId Song ID as string
8
+ */
9
+ export declare const decryptDownload: (source: Buffer, trackId: string) => Buffer;
@@ -0,0 +1,63 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.decryptDownload = exports.getSongFileName = void 0;
7
+ const crypto_1 = __importDefault(require("crypto"));
8
+ const md5 = (data, type = 'ascii') => {
9
+ const md5sum = crypto_1.default.createHash('md5');
10
+ md5sum.update(data.toString(), type);
11
+ return md5sum.digest('hex');
12
+ };
13
+ const getSongFileName = ({ MD5_ORIGIN, SNG_ID, MEDIA_VERSION }, quality) => {
14
+ if (!MD5_ORIGIN) {
15
+ throw new Error(`Missing MD5_ORIGIN for track ${SNG_ID}`);
16
+ }
17
+ const step1 = [MD5_ORIGIN, quality, SNG_ID, MEDIA_VERSION].join('¤');
18
+ let step2 = md5(step1) + '¤' + step1 + '¤';
19
+ while (step2.length % 16 > 0)
20
+ step2 += ' ';
21
+ return crypto_1.default.createCipheriv('aes-128-ecb', 'jo6aey6haid2Teih', '').update(step2, 'ascii', 'hex');
22
+ };
23
+ exports.getSongFileName = getSongFileName;
24
+ const getBlowfishKey = (trackId) => {
25
+ const SECRET = 'g4el58wc' + '0zvf9na1';
26
+ const idMd5 = md5(trackId);
27
+ let bfKey = '';
28
+ for (let i = 0; i < 16; i++) {
29
+ bfKey += String.fromCharCode(idMd5.charCodeAt(i) ^ idMd5.charCodeAt(i + 16) ^ SECRET.charCodeAt(i));
30
+ }
31
+ return bfKey;
32
+ };
33
+ const decryptChunk = (chunk, blowFishKey) => {
34
+ const cipher = crypto_1.default.createDecipheriv('bf-cbc', blowFishKey, Buffer.from([0, 1, 2, 3, 4, 5, 6, 7]));
35
+ cipher.setAutoPadding(false);
36
+ return Buffer.concat([cipher.update(chunk), cipher.final()]);
37
+ };
38
+ /**
39
+ *
40
+ * @param source Downloaded song from `getTrackDownloadUrl`
41
+ * @param trackId Song ID as string
42
+ */
43
+ const decryptDownload = (source, trackId) => {
44
+ const chunkSize = 2048;
45
+ const blowFishKey = getBlowfishKey(trackId);
46
+ let chunkIndex = 0;
47
+ let position = 0;
48
+ const destBuffer = Buffer.alloc(source.length);
49
+ while (position < source.length) {
50
+ const currentChunkSize = Math.min(chunkSize, source.length - position);
51
+ const sourceChunk = source.subarray(position, position + currentChunkSize);
52
+ if (chunkIndex % 3 > 0 || currentChunkSize < chunkSize) {
53
+ sourceChunk.copy(destBuffer, position);
54
+ }
55
+ else {
56
+ decryptChunk(sourceChunk, blowFishKey).copy(destBuffer, position);
57
+ }
58
+ position += currentChunkSize;
59
+ chunkIndex++;
60
+ }
61
+ return destBuffer;
62
+ };
63
+ exports.decryptDownload = decryptDownload;
@@ -0,0 +1,63 @@
1
+ /**
2
+ * Fast LRU & TTL cache
3
+ * @param {Integer} options.max - Max entries in the cache. @default Infinity
4
+ * @param {Integer} options.ttl - Timeout before removing entries. @default Infinity
5
+ */
6
+ declare class FastLRU {
7
+ _max: number;
8
+ _ttl: number;
9
+ _cache: Map<any, any>;
10
+ _meta: {
11
+ [key: string]: any;
12
+ };
13
+ constructor({ maxSize, ttl }: {
14
+ maxSize?: number | undefined;
15
+ ttl?: number | undefined;
16
+ });
17
+ /**
18
+ * Add new entry
19
+ */
20
+ set(key: string, value: any, ttl?: number): void;
21
+ /**
22
+ * Get entry
23
+ */
24
+ get(key: string): any;
25
+ /**
26
+ * Get without hitting hits
27
+ */
28
+ peek(key: string): any;
29
+ /**
30
+ * Remove entry
31
+ */
32
+ delete(key: string): void;
33
+ /**
34
+ * Remove all entries
35
+ */
36
+ clear(): void;
37
+ /**
38
+ * Check has entry
39
+ */
40
+ has(key: string): boolean;
41
+ /**
42
+ * Get all kies
43
+ * @returns {Iterator} Iterator on all kies
44
+ */
45
+ keys(): IterableIterator<any>;
46
+ /**
47
+ * Iterate over values
48
+ */
49
+ values(): IterableIterator<any>;
50
+ /**
51
+ * Iterate over entries
52
+ */
53
+ entries(): IterableIterator<[any, any]>;
54
+ /**
55
+ * For each
56
+ */
57
+ forEach(cb: any): void;
58
+ /**
59
+ * Entries total size
60
+ */
61
+ get size(): number;
62
+ }
63
+ export default FastLRU;