gerdur-core 2.12.0 → 2.13.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 +11 -0
- package/README.md +2 -0
- 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 +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 2.13.0 - 2026-08-31
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- **`getCoverArtByISRC(isrc, {minSize?, maxTries?})`** and
|
|
8
|
+
**`getRecordingCoverArt(recording, …)`** — the full ISRC → cover chain with a
|
|
9
|
+
proper release ranking: `getBestCoverArtUrl` on the *first* release a recording
|
|
10
|
+
lists often hits a promo comp / bootleg with no art. These walk the
|
|
11
|
+
release-groups **canonical-first** (Official > Album > earliest date) and
|
|
12
|
+
return the first real front cover, bounded to `maxTries` (default 4) lookups.
|
|
13
|
+
|
|
3
14
|
## 2.12.0 - 2026-08-31
|
|
4
15
|
|
|
5
16
|
Phase 4 — an optional, read-only **enrichment** layer against open databases.
|
package/README.md
CHANGED
|
@@ -449,6 +449,8 @@ call `configureMusicBrainz({userAgent})` once at startup.
|
|
|
449
449
|
| `getMusicBrainzRecording(mbid)` / `getMusicBrainzRelease(mbid, inc?)` | direct MBID lookups — the release adds label, catalogue number, barcode. |
|
|
450
450
|
| `getCoverArt(mbid, entity = 'release-group')` | Cover Art Archive images (`front` / `approved` / `thumbnails`). `null` when there's no art. |
|
|
451
451
|
| `getBestCoverArtUrl(mbid, {entity?, minSize = 1200})` | one URL — the approved front cover at ≥ `minSize` px, else full-res. Deezer caps its own art at 1800 px; this goes bigger. |
|
|
452
|
+
| `getCoverArtByISRC(isrc, {minSize?, maxTries?})` | the whole chain — ISRC → recording → **canonical-first** release walk → first real front cover. Use this, not `getBestCoverArtUrl` on `releases[0]` (often a promo comp with no art). |
|
|
453
|
+
| `getRecordingCoverArt(recording, …)` | same, from an already-fetched `MBRecording`. |
|
|
452
454
|
|
|
453
455
|
```js
|
|
454
456
|
configureMusicBrainz({userAgent: 'myapp/1.0 ( me@example.com )'});
|
|
@@ -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; } });
|