gerdur-core 2.12.0 → 2.13.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.
- package/CHANGELOG.md +26 -0
- package/README.md +655 -344
- package/dist/enrich/coverart.d.ts +19 -0
- package/dist/enrich/coverart.js +45 -1
- package/dist/enrich/index.d.ts +1 -1
- package/dist/enrich/index.js +3 -1
- package/package.json +19 -2
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { MBRecording } from './musicbrainz';
|
|
1
2
|
export interface CoverArtImage {
|
|
2
3
|
id: string;
|
|
3
4
|
front: boolean;
|
|
@@ -29,3 +30,21 @@ export declare const getBestCoverArtUrl: (mbid: string, { entity, minSize }?: {
|
|
|
29
30
|
entity?: "release-group" | "release" | undefined;
|
|
30
31
|
minSize?: number | undefined;
|
|
31
32
|
}) => Promise<string | null>;
|
|
33
|
+
/**
|
|
34
|
+
* The best cover for a MusicBrainz recording — walks its release-groups
|
|
35
|
+
* canonical-first (Official Album, earliest) and returns the first Cover Art
|
|
36
|
+
* Archive front cover it finds. `null` when none of the top few have art.
|
|
37
|
+
* Bounded to `maxTries` release-groups (default 4) to keep the request count low.
|
|
38
|
+
*/
|
|
39
|
+
export declare const getRecordingCoverArt: (rec: MBRecording, { minSize, maxTries }?: {
|
|
40
|
+
minSize?: number | undefined;
|
|
41
|
+
maxTries?: number | undefined;
|
|
42
|
+
}) => Promise<string | null>;
|
|
43
|
+
/**
|
|
44
|
+
* One call: ISRC → MusicBrainz recording → best Cover Art Archive front cover
|
|
45
|
+
* (larger than Deezer's 1800 px cap). `null` when there's no match or no art.
|
|
46
|
+
*/
|
|
47
|
+
export declare const getCoverArtByISRC: (isrc: string, options?: {
|
|
48
|
+
minSize?: number;
|
|
49
|
+
maxTries?: number;
|
|
50
|
+
}) => Promise<string | null>;
|
package/dist/enrich/coverart.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getBestCoverArtUrl = exports.getCoverArt = void 0;
|
|
3
|
+
exports.getCoverArtByISRC = exports.getRecordingCoverArt = exports.getBestCoverArtUrl = exports.getCoverArt = void 0;
|
|
4
4
|
const client_1 = require("./client");
|
|
5
|
+
const musicbrainz_1 = require("./musicbrainz");
|
|
5
6
|
const client = new client_1.PoliteJsonClient({
|
|
6
7
|
userAgent: 'gerdur-core (+https://github.com/soulwax/gerdur-core)',
|
|
7
8
|
minIntervalMs: 200,
|
|
@@ -56,3 +57,46 @@ const getBestCoverArtUrl = async (mbid, { entity = 'release-group', minSize = 12
|
|
|
56
57
|
return sized ? sized[1] : front.image;
|
|
57
58
|
};
|
|
58
59
|
exports.getBestCoverArtUrl = getBestCoverArtUrl;
|
|
60
|
+
/** Rank a recording's releases so the canonical original album comes first. */
|
|
61
|
+
const rankReleases = (rec) => {
|
|
62
|
+
const seen = new Set();
|
|
63
|
+
return rec.releases
|
|
64
|
+
.filter((r) => r.releaseGroupMbid)
|
|
65
|
+
.map((r) => {
|
|
66
|
+
var _a;
|
|
67
|
+
return ({
|
|
68
|
+
rgid: r.releaseGroupMbid,
|
|
69
|
+
// Official beats Promotion/Bootleg/Pseudo-Release; Album beats Single/EP/Compilation;
|
|
70
|
+
// then earliest date wins.
|
|
71
|
+
score: (r.status === 'Official' ? 0 : r.status ? 10 : 5) + (r.primaryType === 'Album' ? 0 : r.primaryType ? 2 : 1),
|
|
72
|
+
date: (_a = r.date) !== null && _a !== void 0 ? _a : '9999',
|
|
73
|
+
});
|
|
74
|
+
})
|
|
75
|
+
.sort((a, b) => a.score - b.score || a.date.localeCompare(b.date))
|
|
76
|
+
.map((r) => r.rgid)
|
|
77
|
+
.filter((rgid) => (seen.has(rgid) ? false : seen.add(rgid)));
|
|
78
|
+
};
|
|
79
|
+
/**
|
|
80
|
+
* The best cover for a MusicBrainz recording — walks its release-groups
|
|
81
|
+
* canonical-first (Official Album, earliest) and returns the first Cover Art
|
|
82
|
+
* Archive front cover it finds. `null` when none of the top few have art.
|
|
83
|
+
* Bounded to `maxTries` release-groups (default 4) to keep the request count low.
|
|
84
|
+
*/
|
|
85
|
+
const getRecordingCoverArt = async (rec, { minSize = 1200, maxTries = 4 } = {}) => {
|
|
86
|
+
for (const rgid of rankReleases(rec).slice(0, maxTries)) {
|
|
87
|
+
const url = await (0, exports.getBestCoverArtUrl)(rgid, { entity: 'release-group', minSize });
|
|
88
|
+
if (url)
|
|
89
|
+
return url;
|
|
90
|
+
}
|
|
91
|
+
return null;
|
|
92
|
+
};
|
|
93
|
+
exports.getRecordingCoverArt = getRecordingCoverArt;
|
|
94
|
+
/**
|
|
95
|
+
* One call: ISRC → MusicBrainz recording → best Cover Art Archive front cover
|
|
96
|
+
* (larger than Deezer's 1800 px cap). `null` when there's no match or no art.
|
|
97
|
+
*/
|
|
98
|
+
const getCoverArtByISRC = async (isrc, options = {}) => {
|
|
99
|
+
const rec = await (0, musicbrainz_1.lookupRecordingByISRC)(isrc);
|
|
100
|
+
return rec ? (0, exports.getRecordingCoverArt)(rec, options) : null;
|
|
101
|
+
};
|
|
102
|
+
exports.getCoverArtByISRC = getCoverArtByISRC;
|
package/dist/enrich/index.d.ts
CHANGED
|
@@ -10,5 +10,5 @@
|
|
|
10
10
|
export { PoliteJsonClient } from './client';
|
|
11
11
|
export { configureMusicBrainz, lookupRecordingByISRC, getMusicBrainzRecording, getMusicBrainzRelease, } from './musicbrainz';
|
|
12
12
|
export type { MBRecording, MBRelease, MBArtistCredit } from './musicbrainz';
|
|
13
|
-
export { getCoverArt, getBestCoverArtUrl } from './coverart';
|
|
13
|
+
export { getCoverArt, getBestCoverArtUrl, getRecordingCoverArt, getCoverArtByISRC } from './coverart';
|
|
14
14
|
export type { CoverArt, CoverArtImage } from './coverart';
|
package/dist/enrich/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getBestCoverArtUrl = exports.getCoverArt = exports.getMusicBrainzRelease = exports.getMusicBrainzRecording = exports.lookupRecordingByISRC = exports.configureMusicBrainz = exports.PoliteJsonClient = void 0;
|
|
3
|
+
exports.getCoverArtByISRC = exports.getRecordingCoverArt = exports.getBestCoverArtUrl = exports.getCoverArt = exports.getMusicBrainzRelease = exports.getMusicBrainzRecording = exports.lookupRecordingByISRC = exports.configureMusicBrainz = exports.PoliteJsonClient = void 0;
|
|
4
4
|
/**
|
|
5
5
|
* Optional, pluggable **enrichment** against third-party open databases —
|
|
6
6
|
* strictly read-only, off by default, never wired into `addTrackTags`. Use it to
|
|
@@ -20,3 +20,5 @@ Object.defineProperty(exports, "getMusicBrainzRelease", { enumerable: true, get:
|
|
|
20
20
|
var coverart_1 = require("./coverart");
|
|
21
21
|
Object.defineProperty(exports, "getCoverArt", { enumerable: true, get: function () { return coverart_1.getCoverArt; } });
|
|
22
22
|
Object.defineProperty(exports, "getBestCoverArtUrl", { enumerable: true, get: function () { return coverart_1.getBestCoverArtUrl; } });
|
|
23
|
+
Object.defineProperty(exports, "getRecordingCoverArt", { enumerable: true, get: function () { return coverart_1.getRecordingCoverArt; } });
|
|
24
|
+
Object.defineProperty(exports, "getCoverArtByISRC", { enumerable: true, get: function () { return coverart_1.getCoverArtByISRC; } });
|
package/package.json
CHANGED
|
@@ -1,7 +1,24 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gerdur-core",
|
|
3
|
-
"version": "2.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "2.13.1",
|
|
4
|
+
"description": "Deezer API client, cross-service URL resolution, Blowfish track decryption and MP3/FLAC metadata tagging — the engine behind the gerdur CLI.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"deezer",
|
|
7
|
+
"deezer-api",
|
|
8
|
+
"spotify",
|
|
9
|
+
"tidal",
|
|
10
|
+
"isrc",
|
|
11
|
+
"music",
|
|
12
|
+
"metadata",
|
|
13
|
+
"id3",
|
|
14
|
+
"flac",
|
|
15
|
+
"lyrics",
|
|
16
|
+
"lrc",
|
|
17
|
+
"musicbrainz",
|
|
18
|
+
"cover-art",
|
|
19
|
+
"decrypt",
|
|
20
|
+
"blowfish"
|
|
21
|
+
],
|
|
5
22
|
"main": "dist/index.js",
|
|
6
23
|
"types": "dist/index.d.ts",
|
|
7
24
|
"scripts": {
|