gerdur 1.0.2 → 2.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.
- package/CHANGELOG.md +24 -0
- package/dist/package.json +2 -2
- package/dist/src/gerdur.js +2 -0
- package/dist/src/index.d.ts +3 -2
- package/dist/src/index.js +7 -1
- package/dist/src/lib/api-download.d.ts +19 -2
- package/dist/src/lib/api-download.js +39 -19
- package/dist/src/lib/config.d.ts +1 -1
- package/dist/src/lib/config.js +6 -0
- package/dist/src/lib/download-track.d.ts +3 -1
- package/dist/src/lib/download-track.js +7 -2
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,29 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 2.0.0 - 2026-08-31
|
|
4
|
+
|
|
5
|
+
### Changed
|
|
6
|
+
|
|
7
|
+
- **Metadata is now much richer** (`gerdur-core@^2.0.0`). Every downloaded file
|
|
8
|
+
gets ReplayGain (`REPLAYGAIN_TRACK_GAIN`), BPM, real `©`/`℗` lines, the true
|
|
9
|
+
original release date (distinct from a reissue date), full studio credits
|
|
10
|
+
(featured artists, mastering / mixing / recording engineers, producers),
|
|
11
|
+
compilation/live flags, iTunes advisory, Deezer ids, and the artist photo as a
|
|
12
|
+
second embedded image. Album/playlist tracks are hydrated with one coalesced
|
|
13
|
+
`song.getData` so the credits are complete.
|
|
14
|
+
- **`.lrc` sidecar files** are written next to the audio for tracks with
|
|
15
|
+
time-synced lyrics. Toggle with `"lyrics": {"lrcFile": false}` in
|
|
16
|
+
`gerdur.config.json`.
|
|
17
|
+
- Cover-art requests are capped at Deezer's real ceiling of 1800 px.
|
|
18
|
+
|
|
19
|
+
### Breaking (programmatic API)
|
|
20
|
+
|
|
21
|
+
- `gerdur-core.addTrackTags` changed signature/return — see its 2.0.0 changelog.
|
|
22
|
+
`getTrackBuffer` is unaffected (still resolves to `Buffer | null`); new
|
|
23
|
+
`getTaggedTrack(track, quality, options)` returns `{buffer, model}` with the
|
|
24
|
+
structured metadata and LRC. `downloadTrackToFile` now also returns `lrcPath`
|
|
25
|
+
when a sidecar was written.
|
|
26
|
+
|
|
3
27
|
## 1.0.1 - 2026-08-30
|
|
4
28
|
|
|
5
29
|
### Changed
|
package/dist/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gerdur",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "The crucial streaming module for dabox systems.",
|
|
5
5
|
"author": "Christian",
|
|
6
6
|
"license": "SEE LICENSE IN LICENSE",
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
"adm-zip": "^0.5.16",
|
|
49
49
|
"chalk": "^4.1.2",
|
|
50
50
|
"commander": "^9.5.0",
|
|
51
|
-
"gerdur-core": "^
|
|
51
|
+
"gerdur-core": "^2.0.0",
|
|
52
52
|
"dot-prop": "^6.0.1",
|
|
53
53
|
"got": "^11.8.6",
|
|
54
54
|
"gradient-string": "^2.0.2",
|
package/dist/src/gerdur.js
CHANGED
|
@@ -215,6 +215,7 @@ const startDownload = async (saveLayout, url, skipPrompt) => {
|
|
|
215
215
|
const trackNumber = conf.get('trackNumber', true);
|
|
216
216
|
const fallbackTrack = conf.get('fallbackTrack', true);
|
|
217
217
|
const fallbackQuality = conf.get('fallbackQuality', true);
|
|
218
|
+
const lrc = conf.get('lyrics.lrcFile', true);
|
|
218
219
|
const overwrite = options.overwrite ?? conf.get('overwrite', false);
|
|
219
220
|
const resolveFullPath = options.resolveFullPath ?? conf.get('playlist.resolveFullPath');
|
|
220
221
|
const savedFiles = [];
|
|
@@ -259,6 +260,7 @@ const startDownload = async (saveLayout, url, skipPrompt) => {
|
|
|
259
260
|
fallbackQuality,
|
|
260
261
|
overwrite,
|
|
261
262
|
message: `(${index}/${data.tracks.length})`,
|
|
263
|
+
lrc,
|
|
262
264
|
prefetched: prefetchedUrls.get(track.SNG_ID) ?? null,
|
|
263
265
|
});
|
|
264
266
|
// Add to saved list
|
package/dist/src/index.d.ts
CHANGED
|
@@ -56,7 +56,8 @@ export declare class LoginError extends Error {
|
|
|
56
56
|
export declare const getArl: (email: string, password: string) => Promise<string>;
|
|
57
57
|
export { createSession, Session } from './lib/session';
|
|
58
58
|
export type { SessionOptions, DownloadTracksOptions, SearchType } from './lib/session';
|
|
59
|
-
export { getTrackBuffer, downloadTrackToFile } from './lib/api-download';
|
|
59
|
+
export { getTrackBuffer, getTaggedTrack, downloadTrackToFile } from './lib/api-download';
|
|
60
60
|
export type { Quality, GetTrackBufferOptions, DownloadTrackOptions, DownloadResult } from './lib/api-download';
|
|
61
61
|
export { default as Config, globalConfigPath, resolveConfigFile } from './lib/config';
|
|
62
|
-
export { initDeezerApi, parseInfo, searchMusic, getUser, getTrackInfo, getAlbumInfo, getAlbumTracks, getPlaylistInfo, getPlaylistTracks, getArtistInfo, getDiscography, getLyrics, getTrackDownloadUrl, GeoBlocked, } from 'gerdur-core';
|
|
62
|
+
export { initDeezerApi, parseInfo, searchMusic, getUser, getTrackInfo, getAlbumInfo, getAlbumTracks, getPlaylistInfo, getPlaylistTracks, getArtistInfo, getDiscography, getLyrics, getTrackDownloadUrl, resolveDownloadUrls, addTrackTags, getRichAlbum, normalizeContributors, toLrc, GeoBlocked, } from 'gerdur-core';
|
|
63
|
+
export type { AddTrackTagsOptions, TaggedTrack, TrackTagModel, RichAlbum, ResolvedUrl, NormalizedContributors, } from 'gerdur-core';
|
package/dist/src/index.js
CHANGED
|
@@ -33,7 +33,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
33
33
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
34
34
|
};
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
exports.GeoBlocked = exports.getTrackDownloadUrl = exports.getLyrics = exports.getDiscography = exports.getArtistInfo = exports.getPlaylistTracks = exports.getPlaylistInfo = exports.getAlbumTracks = exports.getAlbumInfo = exports.getTrackInfo = exports.getUser = exports.searchMusic = exports.parseInfo = exports.initDeezerApi = exports.resolveConfigFile = exports.globalConfigPath = exports.Config = exports.downloadTrackToFile = exports.getTrackBuffer = exports.Session = exports.createSession = exports.getArl = exports.LoginError = exports.loginWithEmail = void 0;
|
|
36
|
+
exports.GeoBlocked = exports.toLrc = exports.normalizeContributors = exports.getRichAlbum = exports.addTrackTags = exports.resolveDownloadUrls = exports.getTrackDownloadUrl = exports.getLyrics = exports.getDiscography = exports.getArtistInfo = exports.getPlaylistTracks = exports.getPlaylistInfo = exports.getAlbumTracks = exports.getAlbumInfo = exports.getTrackInfo = exports.getUser = exports.searchMusic = exports.parseInfo = exports.initDeezerApi = exports.resolveConfigFile = exports.globalConfigPath = exports.Config = exports.downloadTrackToFile = exports.getTaggedTrack = exports.getTrackBuffer = exports.Session = exports.createSession = exports.getArl = exports.LoginError = exports.loginWithEmail = void 0;
|
|
37
37
|
// ─── Authentication ────────────────────────────────────────────────────────
|
|
38
38
|
const email_login_1 = require("./lib/email-login");
|
|
39
39
|
Object.defineProperty(exports, "loginWithEmail", { enumerable: true, get: function () { return email_login_1.loginWithEmail; } });
|
|
@@ -74,6 +74,7 @@ Object.defineProperty(exports, "Session", { enumerable: true, get: function () {
|
|
|
74
74
|
// ─── Download primitives ─────────────────────────────────────────────────────
|
|
75
75
|
var api_download_1 = require("./lib/api-download");
|
|
76
76
|
Object.defineProperty(exports, "getTrackBuffer", { enumerable: true, get: function () { return api_download_1.getTrackBuffer; } });
|
|
77
|
+
Object.defineProperty(exports, "getTaggedTrack", { enumerable: true, get: function () { return api_download_1.getTaggedTrack; } });
|
|
77
78
|
Object.defineProperty(exports, "downloadTrackToFile", { enumerable: true, get: function () { return api_download_1.downloadTrackToFile; } });
|
|
78
79
|
// ─── Config ──────────────────────────────────────────────────────────────────
|
|
79
80
|
// The same config the CLI uses (env var, global path resolution, arl storage).
|
|
@@ -98,4 +99,9 @@ Object.defineProperty(exports, "getArtistInfo", { enumerable: true, get: functio
|
|
|
98
99
|
Object.defineProperty(exports, "getDiscography", { enumerable: true, get: function () { return gerdur_core_1.getDiscography; } });
|
|
99
100
|
Object.defineProperty(exports, "getLyrics", { enumerable: true, get: function () { return gerdur_core_1.getLyrics; } });
|
|
100
101
|
Object.defineProperty(exports, "getTrackDownloadUrl", { enumerable: true, get: function () { return gerdur_core_1.getTrackDownloadUrl; } });
|
|
102
|
+
Object.defineProperty(exports, "resolveDownloadUrls", { enumerable: true, get: function () { return gerdur_core_1.resolveDownloadUrls; } });
|
|
103
|
+
Object.defineProperty(exports, "addTrackTags", { enumerable: true, get: function () { return gerdur_core_1.addTrackTags; } });
|
|
104
|
+
Object.defineProperty(exports, "getRichAlbum", { enumerable: true, get: function () { return gerdur_core_1.getRichAlbum; } });
|
|
105
|
+
Object.defineProperty(exports, "normalizeContributors", { enumerable: true, get: function () { return gerdur_core_1.normalizeContributors; } });
|
|
106
|
+
Object.defineProperty(exports, "toLrc", { enumerable: true, get: function () { return gerdur_core_1.toLrc; } });
|
|
101
107
|
Object.defineProperty(exports, "GeoBlocked", { enumerable: true, get: function () { return gerdur_core_1.GeoBlocked; } });
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
|
+
import type { AddTrackTagsOptions } from 'gerdur-core';
|
|
2
3
|
import type { trackType } from 'gerdur-core/types';
|
|
3
4
|
/** Music quality accepted by the API. */
|
|
4
5
|
export type Quality = '128' | '320' | 'flac' | 1 | 3 | 9;
|
|
@@ -10,18 +11,30 @@ export interface GetTrackBufferOptions {
|
|
|
10
11
|
* before giving up. Default true.
|
|
11
12
|
*/
|
|
12
13
|
fallbackQuality?: boolean;
|
|
14
|
+
/**
|
|
15
|
+
* Extra metadata-writer options passed straight to `gerdur-core.addTrackTags`
|
|
16
|
+
* (e.g. `{embedArtistImage: false, richCredits: false}`). `coverSize` above
|
|
17
|
+
* wins over `metadata.coverSize`.
|
|
18
|
+
*/
|
|
19
|
+
metadata?: AddTrackTagsOptions;
|
|
13
20
|
}
|
|
14
21
|
/**
|
|
15
22
|
* Download, decrypt, and tag a single track entirely in memory.
|
|
16
23
|
*
|
|
17
24
|
* Returns the ready-to-write audio Buffer (MP3 or FLAC), or `null` if the track
|
|
18
25
|
* is not available for download. Nothing is written to disk and nothing is
|
|
19
|
-
* logged.
|
|
26
|
+
* logged. Use `getTaggedTrack` if you also want the structured metadata / LRC.
|
|
20
27
|
*
|
|
21
28
|
* @param track Track info (e.g. from `getTrackInfo` or `parseUrl`).
|
|
22
29
|
* @param quality '128' | '320' | 'flac' (or numeric 1 | 3 | 9).
|
|
23
30
|
*/
|
|
24
|
-
export declare const getTrackBuffer: (track: trackType, quality?: Quality,
|
|
31
|
+
export declare const getTrackBuffer: (track: trackType, quality?: Quality, options?: GetTrackBufferOptions) => Promise<Buffer | null>;
|
|
32
|
+
/**
|
|
33
|
+
* Like `getTrackBuffer`, but returns `{buffer, model}` — `model` carries every
|
|
34
|
+
* field gerdur pulled from Deezer, including `model.lyricsSynced` (an LRC
|
|
35
|
+
* document) when the track has time-synced lyrics.
|
|
36
|
+
*/
|
|
37
|
+
export declare const getTaggedTrack: (track: trackType, quality?: Quality, options?: GetTrackBufferOptions) => Promise<import("gerdur-core").TaggedTrack | null>;
|
|
25
38
|
export interface DownloadTrackOptions extends GetTrackBufferOptions {
|
|
26
39
|
/**
|
|
27
40
|
* Output file path or a `saveLayout` template (e.g. `{ART_NAME} - {SNG_TITLE}`).
|
|
@@ -37,12 +50,16 @@ export interface DownloadTrackOptions extends GetTrackBufferOptions {
|
|
|
37
50
|
trackNumber?: boolean;
|
|
38
51
|
/** Re-download even if the destination file already exists. Default false. */
|
|
39
52
|
overwrite?: boolean;
|
|
53
|
+
/** Write a `.lrc` sidecar next to the audio when the track has synced lyrics. Default true. */
|
|
54
|
+
lrc?: boolean;
|
|
40
55
|
}
|
|
41
56
|
export interface DownloadResult {
|
|
42
57
|
/** The path the file was written to (or would have been, if skipped). */
|
|
43
58
|
path: string;
|
|
44
59
|
/** True if the file was written; false if skipped because it already existed. */
|
|
45
60
|
written: boolean;
|
|
61
|
+
/** Path of the `.lrc` sidecar, if one was written. */
|
|
62
|
+
lrcPath?: string;
|
|
46
63
|
}
|
|
47
64
|
/**
|
|
48
65
|
* Download a single track to disk (silent). Resolves the destination path from
|
|
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.downloadTrackToFile = exports.getTrackBuffer = void 0;
|
|
6
|
+
exports.downloadTrackToFile = exports.getTaggedTrack = exports.getTrackBuffer = void 0;
|
|
7
7
|
const fs_1 = require("fs");
|
|
8
8
|
const path_1 = require("path");
|
|
9
9
|
const got_1 = __importDefault(require("got"));
|
|
@@ -22,18 +22,12 @@ const resolveQuality = (quality) => {
|
|
|
22
22
|
const key = String(quality).toLowerCase();
|
|
23
23
|
return QUALITY_MAP[key] ?? QUALITY_MAP['320'];
|
|
24
24
|
};
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
*
|
|
32
|
-
* @param track Track info (e.g. from `getTrackInfo` or `parseUrl`).
|
|
33
|
-
* @param quality '128' | '320' | 'flac' (or numeric 1 | 3 | 9).
|
|
34
|
-
*/
|
|
35
|
-
const getTrackBuffer = async (track, quality = '320', { coverSize = 500, fallbackQuality = true } = {}) => {
|
|
36
|
-
const order = fallbackQuality ? [quality, '320', '128'] : [quality];
|
|
25
|
+
const tagOptions = (o) => ({
|
|
26
|
+
...o.metadata,
|
|
27
|
+
coverSize: o.coverSize ?? o.metadata?.coverSize ?? 500,
|
|
28
|
+
});
|
|
29
|
+
const fetchDecryptTag = async (track, quality, options) => {
|
|
30
|
+
const order = options.fallbackQuality === false ? [quality] : [quality, '320', '128'];
|
|
37
31
|
const tried = new Set();
|
|
38
32
|
for (const q of order) {
|
|
39
33
|
const { q: qNum } = resolveQuality(q);
|
|
@@ -54,13 +48,34 @@ const getTrackBuffer = async (track, quality = '320', { coverSize = 500, fallbac
|
|
|
54
48
|
if (!trackData) {
|
|
55
49
|
continue;
|
|
56
50
|
}
|
|
57
|
-
const { body } = await (0, got_1.default)(trackData.trackUrl, { responseType: 'buffer' });
|
|
51
|
+
const { body } = await (0, got_1.default)(trackData.trackUrl, { responseType: 'buffer', agent: { http: gerdur_core_1.httpAgent, https: gerdur_core_1.httpsAgent } });
|
|
58
52
|
const decrypted = trackData.isEncrypted ? (0, decrypt_1.decryptDownload)(body, track.SNG_ID) : body;
|
|
59
|
-
return (0, gerdur_core_1.addTrackTags)(decrypted, track,
|
|
53
|
+
return (0, gerdur_core_1.addTrackTags)(decrypted, track, tagOptions(options));
|
|
60
54
|
}
|
|
61
55
|
return null;
|
|
62
56
|
};
|
|
57
|
+
/**
|
|
58
|
+
* Download, decrypt, and tag a single track entirely in memory.
|
|
59
|
+
*
|
|
60
|
+
* Returns the ready-to-write audio Buffer (MP3 or FLAC), or `null` if the track
|
|
61
|
+
* is not available for download. Nothing is written to disk and nothing is
|
|
62
|
+
* logged. Use `getTaggedTrack` if you also want the structured metadata / LRC.
|
|
63
|
+
*
|
|
64
|
+
* @param track Track info (e.g. from `getTrackInfo` or `parseUrl`).
|
|
65
|
+
* @param quality '128' | '320' | 'flac' (or numeric 1 | 3 | 9).
|
|
66
|
+
*/
|
|
67
|
+
const getTrackBuffer = async (track, quality = '320', options = {}) => {
|
|
68
|
+
const tagged = await fetchDecryptTag(track, quality, options);
|
|
69
|
+
return tagged ? tagged.buffer : null;
|
|
70
|
+
};
|
|
63
71
|
exports.getTrackBuffer = getTrackBuffer;
|
|
72
|
+
/**
|
|
73
|
+
* Like `getTrackBuffer`, but returns `{buffer, model}` — `model` carries every
|
|
74
|
+
* field gerdur pulled from Deezer, including `model.lyricsSynced` (an LRC
|
|
75
|
+
* document) when the track has time-synced lyrics.
|
|
76
|
+
*/
|
|
77
|
+
const getTaggedTrack = (track, quality = '320', options = {}) => fetchDecryptTag(track, quality, options);
|
|
78
|
+
exports.getTaggedTrack = getTaggedTrack;
|
|
64
79
|
/**
|
|
65
80
|
* Download a single track to disk (silent). Resolves the destination path from
|
|
66
81
|
* the `output` template, skips existing files unless `overwrite` is set, and
|
|
@@ -75,15 +90,20 @@ const downloadTrackToFile = async (track, quality = '320', options = {}) => {
|
|
|
75
90
|
if ((0, fs_1.existsSync)(savePath) && !overwrite) {
|
|
76
91
|
return { path: savePath, written: false };
|
|
77
92
|
}
|
|
78
|
-
const
|
|
79
|
-
if (!
|
|
93
|
+
const tagged = await (0, exports.getTaggedTrack)(track, quality, options);
|
|
94
|
+
if (!tagged) {
|
|
80
95
|
return null;
|
|
81
96
|
}
|
|
82
97
|
const dir = (0, path_1.dirname)(savePath);
|
|
83
98
|
if (dir && !(0, fs_1.existsSync)(dir)) {
|
|
84
99
|
(0, fs_1.mkdirSync)(dir, { recursive: true });
|
|
85
100
|
}
|
|
86
|
-
(0, fs_1.writeFileSync)(savePath, buffer);
|
|
87
|
-
|
|
101
|
+
(0, fs_1.writeFileSync)(savePath, tagged.buffer);
|
|
102
|
+
let lrcPath;
|
|
103
|
+
if (options.lrc !== false && tagged.model.lyricsSynced) {
|
|
104
|
+
lrcPath = savePath.replace(/\.(mp3|flac)$/i, '.lrc');
|
|
105
|
+
(0, fs_1.writeFileSync)(lrcPath, tagged.model.lyricsSynced);
|
|
106
|
+
}
|
|
107
|
+
return { path: savePath, written: true, lrcPath };
|
|
88
108
|
};
|
|
89
109
|
exports.downloadTrackToFile = downloadTrackToFile;
|
package/dist/src/lib/config.d.ts
CHANGED
|
@@ -12,7 +12,7 @@ export declare const globalConfigPath: () => string;
|
|
|
12
12
|
* 3. the global config path (created on first write)
|
|
13
13
|
*/
|
|
14
14
|
export declare const resolveConfigFile: (configFile: string) => string;
|
|
15
|
-
type keysType = 'concurrency' | 'saveLayout' | 'saveLayout.track' | 'saveLayout.album' | 'saveLayout.artist' | 'saveLayout.playlist' | 'playlist.resolveFullPath' | 'trackNumber' | 'fallbackTrack' | 'fallbackQuality' | 'overwrite' | 'coverSize' | 'coverSize.128' | 'coverSize.320' | 'coverSize.flac' | 'cookies.arl' | 'cookies.email' | 'cookies.password';
|
|
15
|
+
type keysType = 'concurrency' | 'saveLayout' | 'saveLayout.track' | 'saveLayout.album' | 'saveLayout.artist' | 'saveLayout.playlist' | 'playlist.resolveFullPath' | 'trackNumber' | 'fallbackTrack' | 'fallbackQuality' | 'overwrite' | 'coverSize' | 'coverSize.128' | 'coverSize.320' | 'coverSize.flac' | 'lyrics.lrcFile' | 'cookies.arl' | 'cookies.email' | 'cookies.password';
|
|
16
16
|
declare class Config {
|
|
17
17
|
userConfigLocation: string | null;
|
|
18
18
|
private configFile;
|
package/dist/src/lib/config.js
CHANGED
|
@@ -62,6 +62,9 @@ const defaultConfig = {
|
|
|
62
62
|
'320': 500,
|
|
63
63
|
flac: 1000,
|
|
64
64
|
},
|
|
65
|
+
lyrics: {
|
|
66
|
+
lrcFile: true,
|
|
67
|
+
},
|
|
65
68
|
cookies: {
|
|
66
69
|
arl: 'c973964816688562722418b5200c1515dffaad15a42643ebf87cc72824a54612ec51c2ad42d566743f9e424c774e98ccae7737770acff59251328e6cd598c7bcac38ca269adf78bfb88ec5bbad6cd800db3c0b88b2af645bb22b99e71de26416',
|
|
67
70
|
},
|
|
@@ -94,6 +97,9 @@ class Config {
|
|
|
94
97
|
if (userConfig.coverSize) {
|
|
95
98
|
userConfig.coverSize = { ...defaultConfig.coverSize, ...userConfig.coverSize };
|
|
96
99
|
}
|
|
100
|
+
if (userConfig.lyrics) {
|
|
101
|
+
userConfig.lyrics = { ...defaultConfig.lyrics, ...userConfig.lyrics };
|
|
102
|
+
}
|
|
97
103
|
if (userConfig.cookies) {
|
|
98
104
|
userConfig.cookies = { ...defaultConfig.cookies, ...userConfig.cookies };
|
|
99
105
|
}
|
|
@@ -19,6 +19,8 @@ interface downloadTrackProps {
|
|
|
19
19
|
isQualityFallback?: boolean;
|
|
20
20
|
overwrite?: boolean;
|
|
21
21
|
message?: string;
|
|
22
|
+
/** Write a `.lrc` sidecar for tracks with time-synced lyrics. Default true. */
|
|
23
|
+
lrc?: boolean;
|
|
22
24
|
/**
|
|
23
25
|
* A download URL already resolved for this track by a batch `resolveDownloadUrls`
|
|
24
26
|
* pass. When set, the per-track `get_url` request and quality-fallback round-trips
|
|
@@ -32,5 +34,5 @@ interface downloadTrackProps {
|
|
|
32
34
|
format: string;
|
|
33
35
|
} | null;
|
|
34
36
|
}
|
|
35
|
-
declare const downloadTrack: ({ track, quality, info, coverSizes, path, totalTracks, trackNumber, fallbackTrack, fallbackQuality, isFallback, isQualityFallback, overwrite, message, prefetched, }: downloadTrackProps) => Promise<string | undefined>;
|
|
37
|
+
declare const downloadTrack: ({ track, quality, info, coverSizes, path, totalTracks, trackNumber, fallbackTrack, fallbackQuality, isFallback, isQualityFallback, overwrite, message, lrc, prefetched, }: downloadTrackProps) => Promise<string | undefined>;
|
|
36
38
|
export default downloadTrack;
|
|
@@ -18,7 +18,7 @@ const pipeline = (0, util_1.promisify)(stream_1.default.pipeline);
|
|
|
18
18
|
const simulate = process.env.SIMULATE;
|
|
19
19
|
/** media-API format string -> gerdur's numeric quality */
|
|
20
20
|
const FORMAT_TO_QUALITY = { FLAC: 9, MP3_320: 3, MP3_256: 3, MP3_128: 1, MP3_64: 1 };
|
|
21
|
-
const downloadTrack = async ({ track, quality, info, coverSizes, path, totalTracks, trackNumber = true, fallbackTrack = true, fallbackQuality = true, isFallback = false, isQualityFallback = false, overwrite = false, message = '', prefetched = null, }) => {
|
|
21
|
+
const downloadTrack = async ({ track, quality, info, coverSizes, path, totalTracks, trackNumber = true, fallbackTrack = true, fallbackQuality = true, isFallback = false, isQualityFallback = false, overwrite = false, message = '', lrc = true, prefetched = null, }) => {
|
|
22
22
|
(0, log_update_1.default)(signale_1.default.pending(track.SNG_TITLE + ' by ' + track.ART_NAME + ' from ' + track.ALB_TITLE));
|
|
23
23
|
try {
|
|
24
24
|
let ext = '.mp3', fileSize = 0, downloaded = 0, coverSize = 500;
|
|
@@ -89,6 +89,7 @@ const downloadTrack = async ({ track, quality, info, coverSizes, path, totalTrac
|
|
|
89
89
|
isFallback: true,
|
|
90
90
|
overwrite,
|
|
91
91
|
message,
|
|
92
|
+
lrc,
|
|
92
93
|
});
|
|
93
94
|
}
|
|
94
95
|
else if (fallbackQuality && quality !== 1) {
|
|
@@ -105,6 +106,7 @@ const downloadTrack = async ({ track, quality, info, coverSizes, path, totalTrac
|
|
|
105
106
|
isQualityFallback: true,
|
|
106
107
|
overwrite,
|
|
107
108
|
message,
|
|
109
|
+
lrc,
|
|
108
110
|
});
|
|
109
111
|
}
|
|
110
112
|
(0, log_update_1.default)(signale_1.default.warn(`Skipped "${track.SNG_TITLE}", track not available.`));
|
|
@@ -149,7 +151,7 @@ const downloadTrack = async ({ track, quality, info, coverSizes, path, totalTrac
|
|
|
149
151
|
outFile = (0, fs_1.readFileSync)(tmpfile);
|
|
150
152
|
}
|
|
151
153
|
(0, log_update_1.default)(signale_1.default.pending('Tagging ' + track.SNG_TITLE + ' by ' + track.ART_NAME));
|
|
152
|
-
const trackWithMetadata = await (0, gerdur_core_1.addTrackTags)(outFile, track, coverSize);
|
|
154
|
+
const { buffer: trackWithMetadata, model } = await (0, gerdur_core_1.addTrackTags)(outFile, track, { coverSize });
|
|
153
155
|
// Delete temporary file now
|
|
154
156
|
(0, fs_1.unlinkSync)(tmpfile);
|
|
155
157
|
(0, log_update_1.default)(signale_1.default.pending('Saving ' + track.SNG_TITLE + ' by ' + track.ART_NAME));
|
|
@@ -161,6 +163,9 @@ const downloadTrack = async ({ track, quality, info, coverSizes, path, totalTrac
|
|
|
161
163
|
}
|
|
162
164
|
// Save file to disk
|
|
163
165
|
(0, fs_1.writeFileSync)(savePath, trackWithMetadata);
|
|
166
|
+
if (lrc !== false && model.lyricsSynced) {
|
|
167
|
+
(0, fs_1.writeFileSync)(savePath.replace(/\.(mp3|flac)$/i, '.lrc'), model.lyricsSynced);
|
|
168
|
+
}
|
|
164
169
|
}
|
|
165
170
|
// Print sucess info
|
|
166
171
|
(0, log_update_1.default)(signale_1.default.success(`${isFallback ? chalk_1.default.yellow('[Fallback] ') : ''}${track.SNG_TITLE} by ${track.ART_NAME}`));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gerdur",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "The crucial streaming module for dabox systems.",
|
|
5
5
|
"author": "Christian",
|
|
6
6
|
"license": "SEE LICENSE IN LICENSE",
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
"adm-zip": "^0.5.16",
|
|
49
49
|
"chalk": "^4.1.2",
|
|
50
50
|
"commander": "^9.5.0",
|
|
51
|
-
"gerdur-core": "^
|
|
51
|
+
"gerdur-core": "^2.0.0",
|
|
52
52
|
"dot-prop": "^6.0.1",
|
|
53
53
|
"got": "^11.8.6",
|
|
54
54
|
"gradient-string": "^2.0.2",
|