fluncle 0.219.0 → 0.221.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/bin/fluncle.mjs +202 -11
- package/package.json +1 -1
package/bin/fluncle.mjs
CHANGED
|
@@ -610,7 +610,7 @@ function parseVersion(version) {
|
|
|
610
610
|
var currentVersion;
|
|
611
611
|
var init_version = __esm(() => {
|
|
612
612
|
init_output();
|
|
613
|
-
currentVersion = "0.
|
|
613
|
+
currentVersion = "0.221.0".trim() ? "0.221.0".trim() : "0.1.0";
|
|
614
614
|
});
|
|
615
615
|
|
|
616
616
|
// src/update-notifier.ts
|
|
@@ -2452,7 +2452,7 @@ function parseVersion2(version) {
|
|
|
2452
2452
|
var currentVersion2, latestReleaseUrl = "https://api.github.com/repos/mauricekleine/fluncle/releases/latest";
|
|
2453
2453
|
var init_version2 = __esm(() => {
|
|
2454
2454
|
init_output();
|
|
2455
|
-
currentVersion2 = "0.
|
|
2455
|
+
currentVersion2 = "0.221.0".trim() ? "0.221.0".trim() : "0.1.0";
|
|
2456
2456
|
});
|
|
2457
2457
|
|
|
2458
2458
|
// ../../packages/registry/src/index.ts
|
|
@@ -4934,11 +4934,14 @@ async function backfillAppleCatalogueCommand(limit, dryRun) {
|
|
|
4934
4934
|
const params = new URLSearchParams({ dryRun: String(dryRun), limit: String(limit) });
|
|
4935
4935
|
return adminApiPost(`/api/v1/admin/backfill/apple-catalogue?${params.toString()}`);
|
|
4936
4936
|
}
|
|
4937
|
-
async function backfillRecordingMbidsCommand(limit, dryRun, cursor) {
|
|
4937
|
+
async function backfillRecordingMbidsCommand(limit, dryRun, cursor, isrcRefreshLimit) {
|
|
4938
4938
|
const params = new URLSearchParams({ dryRun: String(dryRun), limit: String(limit) });
|
|
4939
4939
|
if (cursor) {
|
|
4940
4940
|
params.set("cursor", cursor);
|
|
4941
4941
|
}
|
|
4942
|
+
if (isrcRefreshLimit !== undefined) {
|
|
4943
|
+
params.set("isrcRefreshLimit", String(isrcRefreshLimit));
|
|
4944
|
+
}
|
|
4942
4945
|
return adminApiPost(`/api/v1/admin/backfill/recording-mbids?${params.toString()}`);
|
|
4943
4946
|
}
|
|
4944
4947
|
async function backfillArtistEdgesCommand(limit, dryRun, cursor) {
|
|
@@ -7016,15 +7019,48 @@ var init_admin_reach = __esm(() => {
|
|
|
7016
7019
|
var exports_admin_artists = {};
|
|
7017
7020
|
__export(exports_admin_artists, {
|
|
7018
7021
|
resolveArtistCommand: () => resolveArtistCommand,
|
|
7022
|
+
removeArtistRuleCommand: () => removeArtistRuleCommand,
|
|
7019
7023
|
rankArtistsCommand: () => rankArtistsCommand,
|
|
7020
7024
|
listArtistsCommand: () => listArtistsCommand,
|
|
7025
|
+
listArtistRulesCommand: () => listArtistRulesCommand,
|
|
7021
7026
|
draftArtistBioCommand: () => draftArtistBioCommand,
|
|
7022
7027
|
describeArtistCommand: () => describeArtistCommand,
|
|
7023
7028
|
buildBioBody: () => buildBioBody,
|
|
7024
7029
|
backfillArtistsCommand: () => backfillArtistsCommand,
|
|
7025
7030
|
backfillArtistImagesCommand: () => backfillArtistImagesCommand,
|
|
7026
|
-
artistsBioQueueCommand: () => artistsBioQueueCommand
|
|
7031
|
+
artistsBioQueueCommand: () => artistsBioQueueCommand,
|
|
7032
|
+
artistRuleInput: () => artistRuleInput,
|
|
7033
|
+
addArtistRuleCommand: () => addArtistRuleCommand
|
|
7027
7034
|
});
|
|
7035
|
+
function artistRuleInput(artistMbid, verdict, artistName) {
|
|
7036
|
+
const cleanMbid = artistMbid.trim();
|
|
7037
|
+
if (!MBID_PATTERN.test(cleanMbid)) {
|
|
7038
|
+
throw new Error("Artist MBID must be a MusicBrainz artist MBID");
|
|
7039
|
+
}
|
|
7040
|
+
if (verdict !== "allow" && verdict !== "block") {
|
|
7041
|
+
throw new Error("Pass --verdict allow|block");
|
|
7042
|
+
}
|
|
7043
|
+
const cleanName = artistName?.trim();
|
|
7044
|
+
if (artistName !== undefined && !cleanName) {
|
|
7045
|
+
throw new Error("--name must be a non-empty artist name");
|
|
7046
|
+
}
|
|
7047
|
+
return {
|
|
7048
|
+
artistMbid: cleanMbid.toLowerCase(),
|
|
7049
|
+
...cleanName ? { artistName: cleanName } : {},
|
|
7050
|
+
verdict
|
|
7051
|
+
};
|
|
7052
|
+
}
|
|
7053
|
+
async function listArtistRulesCommand() {
|
|
7054
|
+
const response = await adminApiGet("/api/v1/admin/artist-rules");
|
|
7055
|
+
return response.rules;
|
|
7056
|
+
}
|
|
7057
|
+
async function addArtistRuleCommand(input) {
|
|
7058
|
+
const response = await adminApiPost("/api/v1/admin/artist-rules", input);
|
|
7059
|
+
return response.rule;
|
|
7060
|
+
}
|
|
7061
|
+
async function removeArtistRuleCommand(id) {
|
|
7062
|
+
return adminApiDelete(`/api/v1/admin/artist-rules/${encodeURIComponent(id)}`);
|
|
7063
|
+
}
|
|
7028
7064
|
function buildBioBody(options) {
|
|
7029
7065
|
const body = { bio: options.bio };
|
|
7030
7066
|
if (options.dryRun) {
|
|
@@ -7077,8 +7113,10 @@ async function backfillArtistsCommand(limit, dryRun, cursor) {
|
|
|
7077
7113
|
}
|
|
7078
7114
|
return adminApiPost(`/api/v1/admin/backfill/artists?${params.toString()}`);
|
|
7079
7115
|
}
|
|
7116
|
+
var MBID_PATTERN;
|
|
7080
7117
|
var init_admin_artists = __esm(() => {
|
|
7081
7118
|
init_api();
|
|
7119
|
+
MBID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
7082
7120
|
});
|
|
7083
7121
|
|
|
7084
7122
|
// src/commands/admin-artists.ts
|
|
@@ -7103,23 +7141,84 @@ var init_admin_artists2 = __esm(() => {
|
|
|
7103
7141
|
var exports_admin_labels = {};
|
|
7104
7142
|
__export(exports_admin_labels, {
|
|
7105
7143
|
updateLabelCommand: () => updateLabelCommand,
|
|
7144
|
+
replaceLabelArtistRulesCommand: () => replaceLabelArtistRulesCommand,
|
|
7145
|
+
parseLabelArtistRulesJson: () => parseLabelArtistRulesJson,
|
|
7106
7146
|
mergeLabelCommand: () => mergeLabelCommand,
|
|
7147
|
+
listLabelArtistRulesCommand: () => listLabelArtistRulesCommand,
|
|
7107
7148
|
labelsBioQueueCommand: () => labelsBioQueueCommand,
|
|
7108
7149
|
draftLabelBioCommand: () => draftLabelBioCommand,
|
|
7109
7150
|
describeLabelCommand: () => describeLabelCommand,
|
|
7110
7151
|
backfillLabelLineageCommand: () => backfillLabelLineageCommand,
|
|
7111
7152
|
backfillLabelImagesCommand: () => backfillLabelImagesCommand
|
|
7112
7153
|
});
|
|
7113
|
-
|
|
7114
|
-
|
|
7115
|
-
|
|
7154
|
+
function requireArtistMbid(value, at) {
|
|
7155
|
+
if (typeof value !== "string" || !MBID_PATTERN2.test(value.trim())) {
|
|
7156
|
+
throw new Error(`${at}.artistMbid must be a MusicBrainz artist MBID`);
|
|
7157
|
+
}
|
|
7158
|
+
return value.trim().toLowerCase();
|
|
7116
7159
|
}
|
|
7117
|
-
|
|
7160
|
+
function requireArtistName(value, at) {
|
|
7161
|
+
if (typeof value !== "string" || value.trim().length === 0) {
|
|
7162
|
+
throw new Error(`${at}.artistName must be a non-empty string`);
|
|
7163
|
+
}
|
|
7164
|
+
return value.trim();
|
|
7165
|
+
}
|
|
7166
|
+
function requireArtistVerdict(value, at) {
|
|
7167
|
+
if (value === "allow" || value === "block") {
|
|
7168
|
+
return value;
|
|
7169
|
+
}
|
|
7170
|
+
throw new Error(`${at}.verdict must be 'allow' or 'block'`);
|
|
7171
|
+
}
|
|
7172
|
+
function parseLabelArtistRulesJson(source) {
|
|
7173
|
+
let parsed;
|
|
7174
|
+
try {
|
|
7175
|
+
parsed = JSON.parse(source);
|
|
7176
|
+
} catch {
|
|
7177
|
+
throw new Error("Rules file must contain valid JSON");
|
|
7178
|
+
}
|
|
7179
|
+
if (!Array.isArray(parsed)) {
|
|
7180
|
+
throw new Error("Rules file must contain a JSON array");
|
|
7181
|
+
}
|
|
7182
|
+
if (parsed.length > 100) {
|
|
7183
|
+
throw new Error("Rules file may contain at most 100 artist rules");
|
|
7184
|
+
}
|
|
7185
|
+
return parsed.map((entry, index) => {
|
|
7186
|
+
const at = `Rules file entry ${index + 1}`;
|
|
7187
|
+
if (typeof entry !== "object" || entry === null || Array.isArray(entry)) {
|
|
7188
|
+
throw new Error(`${at} must be an object`);
|
|
7189
|
+
}
|
|
7190
|
+
const value = entry;
|
|
7191
|
+
return {
|
|
7192
|
+
artistMbid: requireArtistMbid(value.artistMbid, at),
|
|
7193
|
+
artistName: requireArtistName(value.artistName, at),
|
|
7194
|
+
verdict: requireArtistVerdict(value.verdict, at)
|
|
7195
|
+
};
|
|
7196
|
+
});
|
|
7197
|
+
}
|
|
7198
|
+
async function resolveLabel(slugOrId) {
|
|
7118
7199
|
const { labels } = await adminApiGet("/api/v1/admin/labels");
|
|
7119
7200
|
const match = labels.find((label) => label.slug === slugOrId || label.id === slugOrId);
|
|
7120
7201
|
if (!match) {
|
|
7121
7202
|
throw new Error(`No label with slug or id '${slugOrId}' — check \`fluncle labels\``);
|
|
7122
7203
|
}
|
|
7204
|
+
return match;
|
|
7205
|
+
}
|
|
7206
|
+
async function listLabelArtistRulesCommand(slugOrId) {
|
|
7207
|
+
const label = await resolveLabel(slugOrId);
|
|
7208
|
+
const response = await adminApiGet(`/api/v1/admin/labels/${encodeURIComponent(label.id)}/artists`);
|
|
7209
|
+
return { label, rules: response.rules };
|
|
7210
|
+
}
|
|
7211
|
+
async function replaceLabelArtistRulesCommand(slugOrId, rules) {
|
|
7212
|
+
const label = await resolveLabel(slugOrId);
|
|
7213
|
+
const response = await adminApiPut(`/api/v1/admin/labels/${encodeURIComponent(label.id)}/artists`, { rules });
|
|
7214
|
+
return { label, rules: response.rules };
|
|
7215
|
+
}
|
|
7216
|
+
async function mergeLabelCommand(losingSlug, canonicalSlug) {
|
|
7217
|
+
const response = await adminApiPost(`/api/v1/admin/labels/${encodeURIComponent(losingSlug)}/merge`, { canonicalSlug });
|
|
7218
|
+
return response.result;
|
|
7219
|
+
}
|
|
7220
|
+
async function updateLabelCommand(slugOrId, seedState, rewalk = false) {
|
|
7221
|
+
const match = await resolveLabel(slugOrId);
|
|
7123
7222
|
const response = await adminApiPatch(`/api/v1/admin/labels/${encodeURIComponent(match.id)}`, {
|
|
7124
7223
|
...rewalk ? { rewalk: true } : {},
|
|
7125
7224
|
...seedState === undefined ? {} : { seedState }
|
|
@@ -7150,9 +7249,11 @@ async function backfillLabelLineageCommand(limit, dryRun, cursor) {
|
|
|
7150
7249
|
}
|
|
7151
7250
|
return adminApiPost(`/api/v1/admin/backfill/label-lineage?${params.toString()}`);
|
|
7152
7251
|
}
|
|
7252
|
+
var MBID_PATTERN2;
|
|
7153
7253
|
var init_admin_labels = __esm(() => {
|
|
7154
7254
|
init_api();
|
|
7155
7255
|
init_admin_artists2();
|
|
7256
|
+
MBID_PATTERN2 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
7156
7257
|
});
|
|
7157
7258
|
|
|
7158
7259
|
// src/commands/admin-covers.ts
|
|
@@ -9693,6 +9794,26 @@ function labelUpdateLines(label, options) {
|
|
|
9693
9794
|
}
|
|
9694
9795
|
return lines;
|
|
9695
9796
|
}
|
|
9797
|
+
var ARTIST_RULE_BOUNDARY = "Rules change what the next crawl takes. Everything already here stays.";
|
|
9798
|
+
function artistRuleWriteLine(prefix) {
|
|
9799
|
+
return `${prefix} \u2014 ${ARTIST_RULE_BOUNDARY.replace(/^R/, "r")}`;
|
|
9800
|
+
}
|
|
9801
|
+
function artistRuleLines(rules) {
|
|
9802
|
+
if (rules.length === 0) {
|
|
9803
|
+
return ["No artist rules."];
|
|
9804
|
+
}
|
|
9805
|
+
const rows = rules.map((rule) => [
|
|
9806
|
+
rule.id,
|
|
9807
|
+
rule.verdict,
|
|
9808
|
+
rule.resolvedName ?? rule.artistName,
|
|
9809
|
+
rule.resolvedMbid ?? rule.artistMbid,
|
|
9810
|
+
rule.artistSpotifyId ?? "unresolved"
|
|
9811
|
+
]);
|
|
9812
|
+
const headings = ["ID", "VERDICT", "ARTIST", "MUSICBRAINZ", "SPOTIFY"];
|
|
9813
|
+
const widths = headings.map((heading, index) => Math.max(heading.length, ...rows.map((row) => row[index]?.length ?? 0)));
|
|
9814
|
+
const line = (row) => row.map((value, index) => value.padEnd(widths[index] ?? value.length)).join(" ").trimEnd();
|
|
9815
|
+
return [line(headings), line(widths.map((width) => "-".repeat(width))), ...rows.map(line)];
|
|
9816
|
+
}
|
|
9696
9817
|
function createProgram() {
|
|
9697
9818
|
const program2 = configureCommand(new Command);
|
|
9698
9819
|
program2.name("fluncle").description(fluncleTagline.toLowerCase()).option("--env <local|production>", "Config profile to load (default: production)").showSuggestionAfterError(false).addHelpCommand("help [command]", "display help for command").hook("preAction", (_thisCommand, actionCommand) => {
|
|
@@ -10548,7 +10669,7 @@ JSON field reference:
|
|
|
10548
10669
|
const { backfillLabelLineageCommand: backfillLabelLineageCommand2 } = await Promise.resolve().then(() => (init_admin_labels(), exports_admin_labels));
|
|
10549
10670
|
await runBackfillLabelLineage(options, backfillLabelLineageCommand2);
|
|
10550
10671
|
});
|
|
10551
|
-
backfill.command("recording-mbids").description("Fill MusicBrainz recording MBIDs (crawler PK strip + ISRC resolve) over tracks").option("--dry-run", "Report the eligible worklist without any vendor call or write", false).option("--limit <limit>", "Max ISRC lookups to process", "50").option("--json", "Print JSON", false).action(async (options) => {
|
|
10672
|
+
backfill.command("recording-mbids").description("Fill MusicBrainz recording MBIDs (crawler PK strip + ISRC resolve) over tracks").option("--dry-run", "Report the eligible worklist without any vendor call or write", false).option("--limit <limit>", "Max ISRC lookups to process", "50").option("--isrc-refresh-limit <limit>", "Max MusicBrainz ISRC re-reads to process", "25").option("--json", "Print JSON", false).action(async (options) => {
|
|
10552
10673
|
const { backfillRecordingMbidsCommand: backfillRecordingMbidsCommand2 } = await Promise.resolve().then(() => (init_admin_tracks(), exports_admin_tracks));
|
|
10553
10674
|
await runBackfillRecordingMbids(options, backfillRecordingMbidsCommand2);
|
|
10554
10675
|
});
|
|
@@ -10586,6 +10707,34 @@ JSON field reference:
|
|
|
10586
10707
|
const { rankArtistsCommand: rankArtistsCommand2 } = await Promise.resolve().then(() => (init_admin_artists(), exports_admin_artists));
|
|
10587
10708
|
await runArtistsRank(options, rankArtistsCommand2);
|
|
10588
10709
|
});
|
|
10710
|
+
artists.command("rule").description("Always or never take one MusicBrainz artist's records (operator)").argument("<artist-mbid>", "The MusicBrainz artist MBID").requiredOption("--verdict <verdict>", "The ruling: allow or block").option("--name <name>", "Artist name (optional; the server resolves it when omitted)").option("--json", "Print JSON", false).action(async (artistMbid, options) => {
|
|
10711
|
+
const { addArtistRuleCommand: addArtistRuleCommand2, artistRuleInput: artistRuleInput2 } = await Promise.resolve().then(() => (init_admin_artists(), exports_admin_artists));
|
|
10712
|
+
const rule = await addArtistRuleCommand2(artistRuleInput2(artistMbid, options.verdict, options.name));
|
|
10713
|
+
if (options.json) {
|
|
10714
|
+
printJson({ ok: true, rule });
|
|
10715
|
+
return;
|
|
10716
|
+
}
|
|
10717
|
+
console.log(artistRuleWriteLine(`Rule set for ${rule.resolvedName ?? rule.artistName}: ${rule.verdict.toUpperCase()}`));
|
|
10718
|
+
});
|
|
10719
|
+
artists.command("rules").description("List the global artist crawl rules").option("--json", "Print JSON", false).action(async (options) => {
|
|
10720
|
+
const { listArtistRulesCommand: listArtistRulesCommand2 } = await Promise.resolve().then(() => (init_admin_artists(), exports_admin_artists));
|
|
10721
|
+
const rules = await listArtistRulesCommand2();
|
|
10722
|
+
if (options.json) {
|
|
10723
|
+
printJson({ ok: true, rules });
|
|
10724
|
+
return;
|
|
10725
|
+
}
|
|
10726
|
+
console.log(artistRuleLines(rules).join(`
|
|
10727
|
+
`));
|
|
10728
|
+
});
|
|
10729
|
+
artists.command("unrule").description("Remove one global artist crawl rule (operator)").argument("<id>", "The artist rule id").option("--json", "Print JSON", false).action(async (id, options) => {
|
|
10730
|
+
const { removeArtistRuleCommand: removeArtistRuleCommand2 } = await Promise.resolve().then(() => (init_admin_artists(), exports_admin_artists));
|
|
10731
|
+
const result = await removeArtistRuleCommand2(id);
|
|
10732
|
+
if (options.json) {
|
|
10733
|
+
printJson(result);
|
|
10734
|
+
return;
|
|
10735
|
+
}
|
|
10736
|
+
console.log(artistRuleWriteLine(`Rule removed: ${id}`));
|
|
10737
|
+
});
|
|
10589
10738
|
artists.command("draft-bio").description("Assemble the Worker-grounded bio prompt for an artist (the sweep's trigger)").argument("<slug>").option("--json", "Print JSON", false).allowExcessArguments().action(async (slug, options) => {
|
|
10590
10739
|
const { draftArtistBioCommand: draftArtistBioCommand2 } = await Promise.resolve().then(() => (init_admin_artists(), exports_admin_artists));
|
|
10591
10740
|
await runEntityBioDraft("artist", slug, options, draftArtistBioCommand2);
|
|
@@ -10607,6 +10756,31 @@ JSON field reference:
|
|
|
10607
10756
|
const { draftLabelBioCommand: draftLabelBioCommand2 } = await Promise.resolve().then(() => (init_admin_labels(), exports_admin_labels));
|
|
10608
10757
|
await runEntityBioDraft("label", slug, options, draftLabelBioCommand2);
|
|
10609
10758
|
});
|
|
10759
|
+
labels.command("artists").description("List or replace one label's artist crawl rules").argument("<slug>", "The label's slug (an exact lbl_\u2026 id also works)").option("--replace", "Replace the complete rule set from --rules-file", false).option("--rules-file <file>", "JSON array of { artistMbid, artistName, verdict } rules").option("--json", "Print JSON", false).action(async (slug, options) => {
|
|
10760
|
+
const {
|
|
10761
|
+
listLabelArtistRulesCommand: listLabelArtistRulesCommand2,
|
|
10762
|
+
parseLabelArtistRulesJson: parseLabelArtistRulesJson2,
|
|
10763
|
+
replaceLabelArtistRulesCommand: replaceLabelArtistRulesCommand2
|
|
10764
|
+
} = await Promise.resolve().then(() => (init_admin_labels(), exports_admin_labels));
|
|
10765
|
+
if (!options.replace && options.rulesFile !== undefined) {
|
|
10766
|
+
throw new Error("Pass --replace with --rules-file");
|
|
10767
|
+
}
|
|
10768
|
+
if (options.replace && options.rulesFile === undefined) {
|
|
10769
|
+
throw new Error("Pass --rules-file <json> with --replace");
|
|
10770
|
+
}
|
|
10771
|
+
const result = options.replace ? await replaceLabelArtistRulesCommand2(slug, parseLabelArtistRulesJson2(readFileSync7(options.rulesFile ?? "", "utf8"))) : await listLabelArtistRulesCommand2(slug);
|
|
10772
|
+
if (options.json) {
|
|
10773
|
+
printJson({ ok: true, rules: result.rules });
|
|
10774
|
+
return;
|
|
10775
|
+
}
|
|
10776
|
+
if (options.replace) {
|
|
10777
|
+
const noun = result.rules.length === 1 ? "rule" : "rules";
|
|
10778
|
+
console.log(artistRuleWriteLine(`${result.rules.length} ${noun} set`));
|
|
10779
|
+
return;
|
|
10780
|
+
}
|
|
10781
|
+
console.log(artistRuleLines(result.rules).join(`
|
|
10782
|
+
`));
|
|
10783
|
+
});
|
|
10610
10784
|
labels.command("update").description("Rule on a label's crawl scope or arm a scoped re-walk (operator)").argument("<slug>", "The label's slug (an exact lbl_\u2026 id also works)").option("--seed-state <state>", "The ruling: enabled, disabled, or undecided").option("--rewalk", "Arm a scoped re-walk without changing the ruling", false).option("--json", "Print JSON", false).action(async (slug, options) => {
|
|
10611
10785
|
const seedState = options.seedState;
|
|
10612
10786
|
if (seedState !== undefined && seedState !== "enabled" && seedState !== "disabled" && seedState !== "undecided") {
|
|
@@ -10635,12 +10809,14 @@ JSON field reference:
|
|
|
10635
10809
|
const {
|
|
10636
10810
|
aliasWritten,
|
|
10637
10811
|
canonicalSlug: canon,
|
|
10812
|
+
droppedRules,
|
|
10638
10813
|
losingSlug: loser,
|
|
10639
10814
|
reconciled,
|
|
10640
10815
|
repointed
|
|
10641
10816
|
} = result;
|
|
10642
10817
|
console.log(`Merged ${loser} \u2192 ${canon}.`);
|
|
10643
10818
|
console.log(` Re-pointed: ${repointed.tracks} track(s), ${repointed.childLabels} sublabel(s), ${repointed.aliases} alias(es).`);
|
|
10819
|
+
console.log(` Dropped: ${droppedRules} loser-scoped artist rule(s).`);
|
|
10644
10820
|
console.log(reconciled.length > 0 ? ` Filled onto ${canon} (was empty): ${reconciled.join(", ")}.` : ` Nothing to fill \u2014 ${canon} already carried every fact.`);
|
|
10645
10821
|
console.log(` Seed state resolved to: ${result.seedState}.`);
|
|
10646
10822
|
console.log(` Alias written: "${aliasWritten.alias}" (${aliasWritten.aliasSlug}) \u2192 confirmed, so it can never re-mint.`);
|
|
@@ -11732,21 +11908,26 @@ async function runBackfillLabelImages(options, backfillLabelImagesCommand2) {
|
|
|
11732
11908
|
}
|
|
11733
11909
|
async function runBackfillRecordingMbids(options, backfillRecordingMbidsCommand2) {
|
|
11734
11910
|
const limit = parseListLimit(options.limit);
|
|
11911
|
+
const isrcRefreshLimit = parseListLimit(options.isrcRefreshLimit);
|
|
11735
11912
|
const resolved = [];
|
|
11736
11913
|
const missed = [];
|
|
11737
11914
|
const failed = [];
|
|
11915
|
+
const isrcRefreshed = [];
|
|
11916
|
+
const isrcRefreshMissed = [];
|
|
11738
11917
|
let cursor;
|
|
11739
11918
|
let dryRun = options.dryRun;
|
|
11740
11919
|
let prefixStripped = 0;
|
|
11741
11920
|
let throttled = false;
|
|
11742
11921
|
while (resolved.length + missed.length + failed.length < limit) {
|
|
11743
11922
|
const remaining = limit - (resolved.length + missed.length + failed.length);
|
|
11744
|
-
const result = await backfillRecordingMbidsCommand2(remaining, options.dryRun, cursor);
|
|
11923
|
+
const result = await backfillRecordingMbidsCommand2(remaining, options.dryRun, cursor, isrcRefreshLimit);
|
|
11745
11924
|
dryRun = result.dryRun;
|
|
11746
11925
|
prefixStripped += result.prefixStripped;
|
|
11747
11926
|
resolved.push(...result.resolved);
|
|
11748
11927
|
missed.push(...result.missed);
|
|
11749
11928
|
failed.push(...result.failed);
|
|
11929
|
+
isrcRefreshed.push(...result.isrcRefreshed ?? []);
|
|
11930
|
+
isrcRefreshMissed.push(...result.isrcRefreshMissed ?? []);
|
|
11750
11931
|
if (!options.json) {
|
|
11751
11932
|
const verb2 = result.dryRun ? "would resolve" : "resolved";
|
|
11752
11933
|
console.log(` \u2026stripped ${result.prefixStripped} from PK; ${verb2} ${result.resolvedCount} by ISRC; ${result.missedCount} not in MusicBrainz; ${result.failedCount} failed`);
|
|
@@ -11765,6 +11946,10 @@ async function runBackfillRecordingMbids(options, backfillRecordingMbidsCommand2
|
|
|
11765
11946
|
dryRun,
|
|
11766
11947
|
failed,
|
|
11767
11948
|
failedCount: failed.length,
|
|
11949
|
+
isrcRefreshMissed,
|
|
11950
|
+
isrcRefreshMissedCount: isrcRefreshMissed.length,
|
|
11951
|
+
isrcRefreshed,
|
|
11952
|
+
isrcRefreshedCount: isrcRefreshed.length,
|
|
11768
11953
|
missed,
|
|
11769
11954
|
missedCount: missed.length,
|
|
11770
11955
|
ok: true,
|
|
@@ -11780,6 +11965,7 @@ async function runBackfillRecordingMbids(options, backfillRecordingMbidsCommand2
|
|
|
11780
11965
|
}
|
|
11781
11966
|
const verb = dryRun ? "Would fill" : "Filled";
|
|
11782
11967
|
console.log(`${verb} ${prefixStripped} recording MBID(s) from crawler PKs; ${resolved.length} by ISRC; ${missed.length} not in MusicBrainz; ${failed.length} failed.`);
|
|
11968
|
+
console.log(`${dryRun ? "Would re-read" : "Re-read"} ${isrcRefreshed.length + isrcRefreshMissed.length} recording(s) for ISRCs \u2014 ${isrcRefreshed.length} filled, ${isrcRefreshMissed.length} still none.`);
|
|
11783
11969
|
for (const item of failed) {
|
|
11784
11970
|
console.log(` ${item.trackId}: ${item.error}`);
|
|
11785
11971
|
}
|
|
@@ -13504,6 +13690,7 @@ function normalizeCommanderError(error) {
|
|
|
13504
13690
|
return new Error(message);
|
|
13505
13691
|
}
|
|
13506
13692
|
var stringOptions = new Set([
|
|
13693
|
+
"--isrc-refresh-limit",
|
|
13507
13694
|
"--against",
|
|
13508
13695
|
"--analyzed-at",
|
|
13509
13696
|
"--analyzed-from",
|
|
@@ -13553,6 +13740,7 @@ var stringOptions = new Set([
|
|
|
13553
13740
|
"--mime",
|
|
13554
13741
|
"--min-phrase-words",
|
|
13555
13742
|
"--model",
|
|
13743
|
+
"--name",
|
|
13556
13744
|
"--note",
|
|
13557
13745
|
"--ok",
|
|
13558
13746
|
"--order",
|
|
@@ -13568,6 +13756,7 @@ var stringOptions = new Set([
|
|
|
13568
13756
|
"--reasoning",
|
|
13569
13757
|
"--recorded-at",
|
|
13570
13758
|
"--recording",
|
|
13759
|
+
"--rules-file",
|
|
13571
13760
|
"--render",
|
|
13572
13761
|
"--scene",
|
|
13573
13762
|
"--scheduled-for",
|
|
@@ -13635,5 +13824,7 @@ if (__require.main == __require.module) {
|
|
|
13635
13824
|
export {
|
|
13636
13825
|
parseTelemetryTimestamp,
|
|
13637
13826
|
labelUpdateLines,
|
|
13638
|
-
createProgram
|
|
13827
|
+
createProgram,
|
|
13828
|
+
artistRuleLines,
|
|
13829
|
+
ARTIST_RULE_BOUNDARY
|
|
13639
13830
|
};
|
package/package.json
CHANGED