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.
@@ -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>;
@@ -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;
@@ -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';
@@ -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.12.0",
4
- "description": "Core module for gerdur.",
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": {