gerdur-core 0.0.0-probe → 1.0.0

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 +10 -0
  2. package/LICENSE +1 -0
  3. package/README.md +188 -1
  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 +67 -5
  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,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;
@@ -0,0 +1,121 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ /**
4
+ * Fast LRU & TTL cache
5
+ * @param {Integer} options.max - Max entries in the cache. @default Infinity
6
+ * @param {Integer} options.ttl - Timeout before removing entries. @default Infinity
7
+ */
8
+ class FastLRU {
9
+ constructor({ maxSize = Infinity, ttl = 0 }) {
10
+ // Default options
11
+ this._max = maxSize;
12
+ this._ttl = ttl;
13
+ this._cache = new Map();
14
+ // Metadata for entries
15
+ this._meta = {};
16
+ }
17
+ /**
18
+ * Add new entry
19
+ */
20
+ set(key, value, ttl = this._ttl) {
21
+ // Execution time
22
+ const time = Date.now();
23
+ // Remvove least recently used elements if exceeds max bytes
24
+ if (this._cache.size >= this._max) {
25
+ const items = Object.values(this._meta);
26
+ if (this._ttl > 0) {
27
+ for (const item of items) {
28
+ if (item.expire < time) {
29
+ this.delete(item.key);
30
+ }
31
+ }
32
+ }
33
+ if (this._cache.size >= this._max) {
34
+ const least = items.sort((a, b) => a.hits - b.hits)[0];
35
+ this.delete(least.key);
36
+ }
37
+ }
38
+ // Override if key already set
39
+ this._cache.set(key, value);
40
+ this._meta[key] = {
41
+ key,
42
+ hits: 0,
43
+ expire: time + ttl,
44
+ };
45
+ }
46
+ /**
47
+ * Get entry
48
+ */
49
+ get(key) {
50
+ if (this._cache.has(key)) {
51
+ const item = this._cache.get(key);
52
+ if (this._ttl > 0) {
53
+ const time = Date.now();
54
+ if (this._meta[key].expire < time) {
55
+ this.delete(key);
56
+ return undefined;
57
+ }
58
+ }
59
+ this._meta[key].hits++;
60
+ return item;
61
+ }
62
+ }
63
+ /**
64
+ * Get without hitting hits
65
+ */
66
+ peek(key) {
67
+ return this._cache.get(key);
68
+ }
69
+ /**
70
+ * Remove entry
71
+ */
72
+ delete(key) {
73
+ delete this._meta[key];
74
+ this._cache.delete(key);
75
+ }
76
+ /**
77
+ * Remove all entries
78
+ */
79
+ clear() {
80
+ this._cache.clear();
81
+ this._meta = {};
82
+ }
83
+ /**
84
+ * Check has entry
85
+ */
86
+ has(key) {
87
+ return this._cache.has(key);
88
+ }
89
+ /**
90
+ * Get all kies
91
+ * @returns {Iterator} Iterator on all kies
92
+ */
93
+ keys() {
94
+ return this._cache.keys();
95
+ }
96
+ /**
97
+ * Iterate over values
98
+ */
99
+ values() {
100
+ return this._cache.values();
101
+ }
102
+ /**
103
+ * Iterate over entries
104
+ */
105
+ entries() {
106
+ return this._cache.entries();
107
+ }
108
+ /**
109
+ * For each
110
+ */
111
+ forEach(cb) {
112
+ return this._cache.forEach(cb);
113
+ }
114
+ /**
115
+ * Entries total size
116
+ */
117
+ get size() {
118
+ return this._cache.size;
119
+ }
120
+ }
121
+ exports.default = FastLRU;
@@ -0,0 +1,16 @@
1
+ import type { trackType } from '../types';
2
+ export declare class WrongLicense extends Error {
3
+ constructor(format: string);
4
+ }
5
+ export declare class GeoBlocked extends Error {
6
+ constructor(country: string);
7
+ }
8
+ /**
9
+ * @param track Track info json returned from `getTrackInfo`
10
+ * @param quality 1 = 128kbps, 3 = 320kbps and 9 = flac (around 1411kbps)
11
+ */
12
+ export declare const getTrackDownloadUrl: (track: trackType, quality: number) => Promise<{
13
+ trackUrl: string;
14
+ isEncrypted: boolean;
15
+ fileSize: number;
16
+ } | null>;