fluncle 0.136.0 → 0.138.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 +160 -5
- package/package.json +1 -1
package/bin/fluncle.mjs
CHANGED
|
@@ -561,7 +561,7 @@ function parseVersion(version) {
|
|
|
561
561
|
var currentVersion;
|
|
562
562
|
var init_version = __esm(() => {
|
|
563
563
|
init_output();
|
|
564
|
-
currentVersion = "0.
|
|
564
|
+
currentVersion = "0.138.0".trim() ? "0.138.0".trim() : "0.1.0";
|
|
565
565
|
});
|
|
566
566
|
|
|
567
567
|
// src/update-notifier.ts
|
|
@@ -2189,7 +2189,7 @@ function parseVersion2(version) {
|
|
|
2189
2189
|
var currentVersion2, latestReleaseUrl = "https://api.github.com/repos/mauricekleine/fluncle/releases/latest";
|
|
2190
2190
|
var init_version2 = __esm(() => {
|
|
2191
2191
|
init_output();
|
|
2192
|
-
currentVersion2 = "0.
|
|
2192
|
+
currentVersion2 = "0.138.0".trim() ? "0.138.0".trim() : "0.1.0";
|
|
2193
2193
|
});
|
|
2194
2194
|
|
|
2195
2195
|
// ../../packages/registry/src/index.ts
|
|
@@ -2247,11 +2247,11 @@ var init_src = __esm(() => {
|
|
|
2247
2247
|
},
|
|
2248
2248
|
{
|
|
2249
2249
|
exposedContent: [
|
|
2250
|
-
"the
|
|
2250
|
+
"the free mixing tool — name artists you like, and Fluncle ranks what mixes in clean next from the whole archive; chain a set and share it as a link"
|
|
2251
2251
|
],
|
|
2252
2252
|
kind: "web_route",
|
|
2253
2253
|
name: "web.mix",
|
|
2254
|
-
operatorNotes: "
|
|
2254
|
+
operatorNotes: "PUBLIC-CAPABLE, gated by a SELF-LIFTING DEPTH MEASUREMENT (not admin auth). The old ~250-finding / admin gate is gone: `/mix` now measures the live archive on every load (`getMixChainDepth` — can the median track reach a full set + rail by a named harmonic move?) and opens to the world on its own the day the catalogue lands enough keyed depth. Until then a stranger is redirected home and the operator still gets in to dogfood. This entry stays `pending` (dark to the dev-row, llms.txt, the sitemap, /status) ONLY so we do not advertise a URL that still redirects — the flip is: confirm the depth gate has opened in prod, remove `pending`, announce. The web weight is pre-set, so the flip needs no other change. No probeConfig — a closed gate 302s a bare GET, which would read as a false 'down'.",
|
|
2255
2255
|
pending: true,
|
|
2256
2256
|
route: "/mix",
|
|
2257
2257
|
url: `${SITE}/mix`,
|
|
@@ -3654,7 +3654,8 @@ __export(exports_admin_tracks, {
|
|
|
3654
3654
|
contextQueueCommand: () => contextQueueCommand,
|
|
3655
3655
|
captureQueueCommand: () => captureQueueCommand,
|
|
3656
3656
|
backfillLastfmCommand: () => backfillLastfmCommand,
|
|
3657
|
-
backfillDiscogsCommand: () => backfillDiscogsCommand
|
|
3657
|
+
backfillDiscogsCommand: () => backfillDiscogsCommand,
|
|
3658
|
+
backfillAppleMusicCommand: () => backfillAppleMusicCommand
|
|
3658
3659
|
});
|
|
3659
3660
|
async function fetchAdminTracks(options) {
|
|
3660
3661
|
const {
|
|
@@ -3827,6 +3828,13 @@ async function backfillDiscogsCommand(limit, dryRun, cursor) {
|
|
|
3827
3828
|
}
|
|
3828
3829
|
return adminApiPost(`/api/admin/backfill/discogs?${params.toString()}`);
|
|
3829
3830
|
}
|
|
3831
|
+
async function backfillAppleMusicCommand(limit, dryRun, cursor) {
|
|
3832
|
+
const params = new URLSearchParams({ dryRun: String(dryRun), limit: String(limit) });
|
|
3833
|
+
if (cursor) {
|
|
3834
|
+
params.set("cursor", cursor);
|
|
3835
|
+
}
|
|
3836
|
+
return adminApiPost(`/api/admin/backfill/apple-music?${params.toString()}`);
|
|
3837
|
+
}
|
|
3830
3838
|
async function vehiclesCommand(limit) {
|
|
3831
3839
|
const tracks = await fetchAdminTracks({ hasVideo: true, max: limit, order: "desc" });
|
|
3832
3840
|
return tracks.map((track) => ({
|
|
@@ -5746,6 +5754,22 @@ var init_admin_artists = __esm(() => {
|
|
|
5746
5754
|
init_api();
|
|
5747
5755
|
});
|
|
5748
5756
|
|
|
5757
|
+
// src/commands/admin-labels.ts
|
|
5758
|
+
var exports_admin_labels = {};
|
|
5759
|
+
__export(exports_admin_labels, {
|
|
5760
|
+
backfillLabelImagesCommand: () => backfillLabelImagesCommand
|
|
5761
|
+
});
|
|
5762
|
+
async function backfillLabelImagesCommand(limit, dryRun, cursor) {
|
|
5763
|
+
const params = new URLSearchParams({ dryRun: String(dryRun), limit: String(limit) });
|
|
5764
|
+
if (cursor) {
|
|
5765
|
+
params.set("cursor", cursor);
|
|
5766
|
+
}
|
|
5767
|
+
return adminApiPost(`/api/admin/backfill/label-images?${params.toString()}`);
|
|
5768
|
+
}
|
|
5769
|
+
var init_admin_labels = __esm(() => {
|
|
5770
|
+
init_api();
|
|
5771
|
+
});
|
|
5772
|
+
|
|
5749
5773
|
// src/commands/preview-migration.ts
|
|
5750
5774
|
var exports_preview_migration = {};
|
|
5751
5775
|
__export(exports_preview_migration, {
|
|
@@ -8754,6 +8778,10 @@ function addAdminCommands(program2) {
|
|
|
8754
8778
|
const { backfillDiscogsCommand: backfillDiscogsCommand2 } = await Promise.resolve().then(() => (init_admin_tracks(), exports_admin_tracks));
|
|
8755
8779
|
await runBackfillDiscogs(options, backfillDiscogsCommand2);
|
|
8756
8780
|
});
|
|
8781
|
+
backfill.command("apple-music").description("Resolve missing Apple Music URLs for published findings (exact ISRC match)").option("--dry-run", "Report the eligible set without resolving or writing", false).option("--limit <limit>", "Max findings to resolve", "50").option("--json", "Print JSON", false).action(async (options) => {
|
|
8782
|
+
const { backfillAppleMusicCommand: backfillAppleMusicCommand2 } = await Promise.resolve().then(() => (init_admin_tracks(), exports_admin_tracks));
|
|
8783
|
+
await runBackfillAppleMusic(options, backfillAppleMusicCommand2);
|
|
8784
|
+
});
|
|
8757
8785
|
backfill.command("artists").description("Back-fill the artist entity (artists + track_artists) for existing findings").option("--dry-run", "Report which findings would be upserted without touching the DB", false).option("--limit <limit>", "Max findings to process", "50").option("--json", "Print JSON", false).action(async (options) => {
|
|
8758
8786
|
const { backfillArtistsCommand: backfillArtistsCommand2 } = await Promise.resolve().then(() => (init_admin_artists(), exports_admin_artists));
|
|
8759
8787
|
await runBackfillArtists(options, backfillArtistsCommand2);
|
|
@@ -8762,6 +8790,10 @@ function addAdminCommands(program2) {
|
|
|
8762
8790
|
const { backfillArtistImagesCommand: backfillArtistImagesCommand2 } = await Promise.resolve().then(() => (init_admin_artists(), exports_admin_artists));
|
|
8763
8791
|
await runBackfillArtistImages(options, backfillArtistImagesCommand2);
|
|
8764
8792
|
});
|
|
8793
|
+
backfill.command("label-images").description("Resolve label logos (Discogs \u2192 Wikidata) into R2 for existing labels").option("--dry-run", "Report the eligible worklist without any vendor call or write", false).option("--limit <limit>", "Max labels to process", "50").option("--json", "Print JSON", false).action(async (options) => {
|
|
8794
|
+
const { backfillLabelImagesCommand: backfillLabelImagesCommand2 } = await Promise.resolve().then(() => (init_admin_labels(), exports_admin_labels));
|
|
8795
|
+
await runBackfillLabelImages(options, backfillLabelImagesCommand2);
|
|
8796
|
+
});
|
|
8765
8797
|
artists.command("resolve").description("Resolve an artist's social identity (MB url-rels + Firecrawl gap-fill)").argument("[artistId]").option("--queue", "Show the resolve worklist (artists awaiting resolution), oldest first", false).option("--limit <limit>", "Number of artists to show with --queue", "50").option("--json", "Print JSON", false).allowExcessArguments().action(async (artistId, options) => {
|
|
8766
8798
|
if (options.queue) {
|
|
8767
8799
|
const { listArtistsCommand: listArtistsCommand2 } = await Promise.resolve().then(() => (init_admin_artists(), exports_admin_artists));
|
|
@@ -9161,6 +9193,72 @@ async function runBackfillDiscogs(options, backfillDiscogsCommand2) {
|
|
|
9161
9193
|
console.log(` ${item.logId}: release ${item.releaseId}${master}`);
|
|
9162
9194
|
}
|
|
9163
9195
|
}
|
|
9196
|
+
async function runBackfillAppleMusic(options, backfillAppleMusicCommand2) {
|
|
9197
|
+
const limit = parseListLimit(options.limit);
|
|
9198
|
+
const resolved = [];
|
|
9199
|
+
const unresolved = [];
|
|
9200
|
+
const failed = [];
|
|
9201
|
+
const skipped = [];
|
|
9202
|
+
let cursor;
|
|
9203
|
+
let dryRun = options.dryRun;
|
|
9204
|
+
let throttled = false;
|
|
9205
|
+
let configured = true;
|
|
9206
|
+
while (resolved.length + unresolved.length + failed.length < limit) {
|
|
9207
|
+
const remaining = limit - (resolved.length + unresolved.length + failed.length);
|
|
9208
|
+
const result = await backfillAppleMusicCommand2(remaining, options.dryRun, cursor);
|
|
9209
|
+
dryRun = result.dryRun;
|
|
9210
|
+
configured = result.configured;
|
|
9211
|
+
resolved.push(...result.resolved);
|
|
9212
|
+
unresolved.push(...result.unresolved);
|
|
9213
|
+
failed.push(...result.failed);
|
|
9214
|
+
skipped.push(...result.skipped);
|
|
9215
|
+
if (!options.json) {
|
|
9216
|
+
const verb2 = result.dryRun ? "would resolve" : "resolved";
|
|
9217
|
+
console.log(` \u2026${verb2} ${result.resolvedCount}; ${result.unresolvedCount} unresolved; ${result.failedCount} failed; ${result.skippedCount} skipped`);
|
|
9218
|
+
}
|
|
9219
|
+
if (!result.configured) {
|
|
9220
|
+
break;
|
|
9221
|
+
}
|
|
9222
|
+
if (result.rateLimited) {
|
|
9223
|
+
throttled = true;
|
|
9224
|
+
break;
|
|
9225
|
+
}
|
|
9226
|
+
if (result.nextCursor === null) {
|
|
9227
|
+
break;
|
|
9228
|
+
}
|
|
9229
|
+
cursor = result.nextCursor;
|
|
9230
|
+
}
|
|
9231
|
+
if (options.json) {
|
|
9232
|
+
printSweepJson({
|
|
9233
|
+
configured,
|
|
9234
|
+
dryRun,
|
|
9235
|
+
failed,
|
|
9236
|
+
rateLimited: throttled,
|
|
9237
|
+
resolved,
|
|
9238
|
+
resolvedCount: resolved.length,
|
|
9239
|
+
skipped,
|
|
9240
|
+
skippedCount: skipped.length,
|
|
9241
|
+
unresolved,
|
|
9242
|
+
unresolvedCount: unresolved.length
|
|
9243
|
+
}, failed.length);
|
|
9244
|
+
return;
|
|
9245
|
+
}
|
|
9246
|
+
if (!configured) {
|
|
9247
|
+
console.log("Apple Music backfill is not configured (the Worker's MusicKit secrets are unset) \u2014 nothing resolved.");
|
|
9248
|
+
return;
|
|
9249
|
+
}
|
|
9250
|
+
const verb = dryRun ? "Would resolve" : "Resolved";
|
|
9251
|
+
console.log(`${verb} ${resolved.length} Apple Music URL(s); ${unresolved.length} unresolved; ${failed.length} failed; ${skipped.length} skipped.`);
|
|
9252
|
+
for (const item of resolved) {
|
|
9253
|
+
console.log(` ${item.logId}: ${item.url}`);
|
|
9254
|
+
}
|
|
9255
|
+
for (const item of failed) {
|
|
9256
|
+
console.log(` ${item.logId}: ${item.error}`);
|
|
9257
|
+
}
|
|
9258
|
+
if (failed.length > 0) {
|
|
9259
|
+
process.exitCode = 1;
|
|
9260
|
+
}
|
|
9261
|
+
}
|
|
9164
9262
|
async function runBackfillArtists(options, backfillArtistsCommand2) {
|
|
9165
9263
|
const limit = parseListLimit(options.limit);
|
|
9166
9264
|
const upserted = [];
|
|
@@ -9253,6 +9351,63 @@ async function runBackfillArtistImages(options, backfillArtistImagesCommand2) {
|
|
|
9253
9351
|
process.exitCode = 1;
|
|
9254
9352
|
}
|
|
9255
9353
|
}
|
|
9354
|
+
async function runBackfillLabelImages(options, backfillLabelImagesCommand2) {
|
|
9355
|
+
const limit = parseListLimit(options.limit);
|
|
9356
|
+
const resolved = [];
|
|
9357
|
+
const none = [];
|
|
9358
|
+
const failed = [];
|
|
9359
|
+
let cursor;
|
|
9360
|
+
let dryRun = options.dryRun;
|
|
9361
|
+
let throttled = false;
|
|
9362
|
+
while (resolved.length + none.length + failed.length < limit) {
|
|
9363
|
+
const remaining = limit - (resolved.length + none.length + failed.length);
|
|
9364
|
+
const result = await backfillLabelImagesCommand2(remaining, options.dryRun, cursor);
|
|
9365
|
+
dryRun = result.dryRun;
|
|
9366
|
+
resolved.push(...result.resolved);
|
|
9367
|
+
none.push(...result.none);
|
|
9368
|
+
failed.push(...result.failed);
|
|
9369
|
+
if (!options.json) {
|
|
9370
|
+
const verb2 = result.dryRun ? "would resolve" : "resolved";
|
|
9371
|
+
console.log(` \u2026${verb2} ${result.resolvedCount}; ${result.noneCount} without an image; ${result.failedCount} failed`);
|
|
9372
|
+
}
|
|
9373
|
+
if (result.rateLimited) {
|
|
9374
|
+
throttled = true;
|
|
9375
|
+
break;
|
|
9376
|
+
}
|
|
9377
|
+
if (result.nextCursor === null) {
|
|
9378
|
+
break;
|
|
9379
|
+
}
|
|
9380
|
+
cursor = result.nextCursor;
|
|
9381
|
+
}
|
|
9382
|
+
if (options.json) {
|
|
9383
|
+
printJson({
|
|
9384
|
+
dryRun,
|
|
9385
|
+
failed,
|
|
9386
|
+
failedCount: failed.length,
|
|
9387
|
+
none,
|
|
9388
|
+
noneCount: none.length,
|
|
9389
|
+
ok: true,
|
|
9390
|
+
rateLimited: throttled,
|
|
9391
|
+
resolved,
|
|
9392
|
+
resolvedCount: resolved.length
|
|
9393
|
+
});
|
|
9394
|
+
if (failed.length > 0) {
|
|
9395
|
+
process.exitCode = 1;
|
|
9396
|
+
}
|
|
9397
|
+
return;
|
|
9398
|
+
}
|
|
9399
|
+
const verb = dryRun ? "Would resolve" : "Resolved";
|
|
9400
|
+
console.log(`${verb} ${resolved.length} label logo(s); ${none.length} without an image; ${failed.length} failed.`);
|
|
9401
|
+
for (const slug of resolved) {
|
|
9402
|
+
console.log(` ${slug}`);
|
|
9403
|
+
}
|
|
9404
|
+
for (const item of failed) {
|
|
9405
|
+
console.log(` ${item.slug}: ${item.error}`);
|
|
9406
|
+
}
|
|
9407
|
+
if (failed.length > 0) {
|
|
9408
|
+
process.exitCode = 1;
|
|
9409
|
+
}
|
|
9410
|
+
}
|
|
9256
9411
|
async function runArtistResolveQueue(options, listArtistsCommand2) {
|
|
9257
9412
|
const limit = parseListLimit(options.limit);
|
|
9258
9413
|
const result = await listArtistsCommand2(limit ?? 50);
|
package/package.json
CHANGED