fluncle 0.235.0 → 0.236.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.
Files changed (2) hide show
  1. package/bin/fluncle.mjs +36 -5
  2. package/package.json +1 -1
package/bin/fluncle.mjs CHANGED
@@ -622,7 +622,7 @@ function parseVersion(version) {
622
622
  var currentVersion;
623
623
  var init_version = __esm(() => {
624
624
  init_output();
625
- currentVersion = "0.235.0".trim() ? "0.235.0".trim() : "0.1.0";
625
+ currentVersion = "0.236.0".trim() ? "0.236.0".trim() : "0.1.0";
626
626
  });
627
627
 
628
628
  // src/update-notifier.ts
@@ -2335,7 +2335,7 @@ function parseVersion2(version) {
2335
2335
  var currentVersion2, latestReleaseUrl = "https://api.github.com/repos/mauricekleine/fluncle/releases/latest";
2336
2336
  var init_version2 = __esm(() => {
2337
2337
  init_output();
2338
- currentVersion2 = "0.235.0".trim() ? "0.235.0".trim() : "0.1.0";
2338
+ currentVersion2 = "0.236.0".trim() ? "0.236.0".trim() : "0.1.0";
2339
2339
  });
2340
2340
 
2341
2341
  // ../../packages/registry/src/index.ts
@@ -11433,7 +11433,7 @@ var init_admin_bios = __esm(() => {
11433
11433
  });
11434
11434
 
11435
11435
  // ../../packages/contracts/src/orpc/admin-catalogue.ts
11436
- var CatalogueLensSchema, CapturePriorityReasonSchema, CatalogueMatchSchema, CatalogueTrackItemSchema, CatalogueSummarySchema, listCatalogueTracks, rankCatalogue, recordDemand, clearWrongAudio, requeueUnmatchedCaptures, requeueAnchor, flagWrongAudio, forceCapture, certifyTrack, setTrackDismissed, CaptureVerifyItemSchema, listUnverifiedCaptures, verifyCapture, CrawlPassSchema, CrawlPhaseInitializationSchema, CrawlPhaseInputSchema, CrawlPhaseOutputSchema, CrawlStatusSchema, crawlCatalogue, getCrawlStatus, ANCHOR_CANDIDATE_LIMIT = 100, ANCHOR_ARTIST_LIMIT = 20, ANCHOR_TEXT_MAX = 300, ANCHOR_ISRC_MAX = 64, ANCHOR_ID_MAX = 64, ANCHOR_URL_MAX = 2048, AnchorCandidateSchema, anchorTrack, DEEZER_CANDIDATE_LIMIT = 5, DEEZER_TEXT_MAX = 300, DEEZER_ISRC_MAX = 64, DEEZER_TRACK_ID_MAX = 32, DeezerIsrcCandidateSchema, resolveAnchor, resolveAnchorReview, setAnchorSearch, setAnchorApify, CaptureBudgetStateSchema, getCaptureBudget, setCaptureBudget, SpotifyAnchorBreakerStateSchema, getSpotifyAnchorBreaker, resetSpotifyAnchorBreaker, AppleBreakerStateSchema, resetAppleBreaker, adminCatalogueContract;
11436
+ var CatalogueLensSchema, CapturePriorityReasonSchema, CatalogueMatchSchema, CatalogueTrackItemSchema, CatalogueSummarySchema, listCatalogueTracks, rankCatalogue, recordDemand, clearWrongAudio, requeueUnmatchedCaptures, requeueAnchor, requeueIsrcRecovery, flagWrongAudio, forceCapture, certifyTrack, setTrackDismissed, CaptureVerifyItemSchema, listUnverifiedCaptures, verifyCapture, CrawlPassSchema, CrawlPhaseInitializationSchema, CrawlPhaseInputSchema, CrawlPhaseOutputSchema, CrawlStatusSchema, crawlCatalogue, getCrawlStatus, ANCHOR_CANDIDATE_LIMIT = 100, ANCHOR_ARTIST_LIMIT = 20, ANCHOR_TEXT_MAX = 300, ANCHOR_ISRC_MAX = 64, ANCHOR_ID_MAX = 64, ANCHOR_URL_MAX = 2048, AnchorCandidateSchema, anchorTrack, DEEZER_CANDIDATE_LIMIT = 5, DEEZER_TEXT_MAX = 300, DEEZER_ISRC_MAX = 64, DEEZER_TRACK_ID_MAX = 32, DeezerIsrcCandidateSchema, resolveAnchor, resolveAnchorReview, setAnchorSearch, setAnchorApify, CaptureBudgetStateSchema, getCaptureBudget, setCaptureBudget, SpotifyAnchorBreakerStateSchema, getSpotifyAnchorBreaker, resetSpotifyAnchorBreaker, AppleBreakerStateSchema, resetAppleBreaker, adminCatalogueContract;
11437
11437
  var init_admin_catalogue = __esm(() => {
11438
11438
  init_dist3();
11439
11439
  init_zod();
@@ -11562,6 +11562,21 @@ var init_admin_catalogue = __esm(() => {
11562
11562
  summary: "Clear named rows' anchor re-ask backoff so the next tick retries them (operator)",
11563
11563
  tags: ["Admin"]
11564
11564
  }).input(object({ trackIds: array(string2().min(1)).min(1).max(250) })).output(object({ ok: literal(true), requeued: number2() }));
11565
+ requeueIsrcRecovery = oc.route({
11566
+ method: "POST",
11567
+ operationId: "requeueIsrcRecovery",
11568
+ path: "/admin/catalogue/isrc-recovery/requeue",
11569
+ summary: "Clear Deezer-empty ISRC-recovery stamps from a named window (operator)",
11570
+ tags: ["Admin"]
11571
+ }).input(object({
11572
+ dryRun: boolean2().default(true),
11573
+ since: string2().regex(/^\d{4}-\d{2}-\d{2}(T\d{2}:\d{2}:\d{2}(\.\d{1,3})?Z)?$/, "since must be an ISO date (2026-09-09) or instant (2026-09-09T00:00:00.000Z)")
11574
+ })).output(object({
11575
+ dryRun: boolean2(),
11576
+ matched: number2(),
11577
+ ok: literal(true),
11578
+ requeued: number2()
11579
+ }));
11565
11580
  flagWrongAudio = oc.route({
11566
11581
  method: "POST",
11567
11582
  operationId: "flagWrongAudio",
@@ -11934,6 +11949,7 @@ var init_admin_catalogue = __esm(() => {
11934
11949
  rank_catalogue: rankCatalogue,
11935
11950
  record_demand: recordDemand,
11936
11951
  requeue_anchor: requeueAnchor,
11952
+ requeue_isrc_recovery: requeueIsrcRecovery,
11937
11953
  requeue_unmatched_captures: requeueUnmatchedCaptures,
11938
11954
  reset_apple_breaker: resetAppleBreaker,
11939
11955
  reset_spotify_anchor_breaker: resetSpotifyAnchorBreaker,
@@ -17235,10 +17251,10 @@ async function resolveDeezerSearch(track) {
17235
17251
  return;
17236
17252
  }
17237
17253
  try {
17238
- const query = `artist:"${artist}" track:"${stripVersionSuffix(track.title.trim())}"`;
17254
+ const query = `${artist} ${stripVersionSuffix(track.title.trim())}`;
17239
17255
  const response = await fetch(`https://api.deezer.com/search?q=${encodeURIComponent(query)}`);
17240
17256
  const body = await response.json();
17241
- const hit = (body.data ?? []).find((item) => item.preview && versionMatches(track.title, item.title ?? "") && baseTitleMatches(track.title, item.title ?? "") && durationAgrees(track.durationMs, item.duration));
17257
+ const hit = (body.data ?? []).find((item) => item.preview && normalize(item.artist?.name ?? "").includes(normalize(artist)) && versionMatches(track.title, item.title ?? "") && baseTitleMatches(track.title, item.title ?? "") && durationAgrees(track.durationMs, item.duration));
17242
17258
  return downloadPreview(hit?.preview, "deezer:search");
17243
17259
  } catch {
17244
17260
  return;
@@ -18510,6 +18526,9 @@ async function requeueAnchorCommand(trackIds) {
18510
18526
  trackIds
18511
18527
  });
18512
18528
  }
18529
+ async function requeueIsrcRecoveryCommand(input) {
18530
+ return adminApiPost("/api/v1/admin/catalogue/isrc-recovery/requeue", input);
18531
+ }
18513
18532
  async function forceCaptureCommand(trackId) {
18514
18533
  return adminApiPost("/api/v1/admin/catalogue/force-capture", {
18515
18534
  trackId
@@ -22166,6 +22185,18 @@ JSON field reference:
22166
22185
  }
22167
22186
  console.log(`Re-queued ${requeued} of ${trackIds.length} row(s) \u2014 the next anchor tick picks them up at their real priority.`);
22168
22187
  });
22188
+ catalogue.command("requeue-isrc-recovery").description("Clear Deezer-empty ISRC-recovery stamps from a window (dry-run; --apply to take)").requiredOption("--since <iso>", "Inclusive lower bound on the stamp (2026-09-09)").option("--apply", "Actually clear the stamps (default is a dry-run count)", false).option("--json", "Print JSON", false).action(async (options) => {
22189
+ await Promise.resolve().then(() => init_admin_catalogue2());
22190
+ const result = await requeueIsrcRecoveryCommand({
22191
+ dryRun: options.apply !== true,
22192
+ since: options.since
22193
+ });
22194
+ if (options.json) {
22195
+ printJson({ ok: true, ...result });
22196
+ return;
22197
+ }
22198
+ console.log(result.dryRun ? `DRY RUN \u2014 ${result.matched} row(s) stamped Deezer-empty since ${options.since}. Re-run with --apply to clear them.` : `Cleared ${result.requeued} of ${result.matched} row(s) \u2014 the next isrc-recovery tick asks them again.`);
22199
+ });
22169
22200
  catalogue.command("requeue-unmatched").description("Re-queue terminal-unmatched captures after a matcher improvement (operator)").option("--json", "Print JSON", false).action(async (options) => {
22170
22201
  await Promise.resolve().then(() => init_admin_catalogue2());
22171
22202
  const { requeued, skippedVetoed } = await requeueUnmatchedCommand();
package/package.json CHANGED
@@ -31,5 +31,5 @@
31
31
  "url": "git+https://github.com/mauricekleine/fluncle.git"
32
32
  },
33
33
  "type": "module",
34
- "version": "0.235.0"
34
+ "version": "0.236.0"
35
35
  }