fluncle 0.40.0 → 0.42.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 +82 -19
  2. package/package.json +1 -1
package/bin/fluncle.mjs CHANGED
@@ -2539,7 +2539,7 @@ function parseVersion(version) {
2539
2539
  var currentVersion;
2540
2540
  var init_version = __esm(() => {
2541
2541
  init_output();
2542
- currentVersion = "0.40.0".trim() ? "0.40.0".trim() : "0.1.0";
2542
+ currentVersion = "0.42.0".trim() ? "0.42.0".trim() : "0.1.0";
2543
2543
  });
2544
2544
 
2545
2545
  // src/update-notifier.ts
@@ -4001,7 +4001,7 @@ function parseVersion2(version) {
4001
4001
  var currentVersion2, latestReleaseUrl = "https://api.github.com/repos/mauricekleine/fluncle/releases/latest";
4002
4002
  var init_version2 = __esm(() => {
4003
4003
  init_output();
4004
- currentVersion2 = "0.40.0".trim() ? "0.40.0".trim() : "0.1.0";
4004
+ currentVersion2 = "0.42.0".trim() ? "0.42.0".trim() : "0.1.0";
4005
4005
  });
4006
4006
 
4007
4007
  // src/commands/track.ts
@@ -4046,9 +4046,11 @@ async function trackVideoCommand(idOrLogId, files, onProgress) {
4046
4046
  const manifest = files.render ? await readManifestFields(files.render) : {};
4047
4047
  const videoModel = files.model?.trim().slice(0, 120) || manifest.model || DEFAULT_VIDEO_MODEL;
4048
4048
  const videoModelReasoning = files.reasoning?.trim().slice(0, 120) || manifest.reasoning || DEFAULT_VIDEO_REASONING;
4049
+ const squared = Boolean(urls["footage"] && urls["footage-social"]);
4049
4050
  const finalize = await adminApiPost(`/api/admin/tracks/${encodeURIComponent(idOrLogId)}/video/finalize`, {
4050
4051
  videoModel,
4051
4052
  videoModelReasoning,
4053
+ ...squared ? { squared: true } : {},
4052
4054
  ...manifest.vehicle ? { videoVehicle: manifest.vehicle } : {}
4053
4055
  });
4054
4056
  return { logId: finalize.logId, ok: true, trackId: finalize.trackId, urls };
@@ -4130,6 +4132,7 @@ var init_track = __esm(() => {
4130
4132
  init_output();
4131
4133
  VIDEO_FIELDS = [
4132
4134
  { field: "footage", option: "footage" },
4135
+ { field: "footage-social", option: "footageSocial" },
4133
4136
  { field: "footage-silent", option: "footageSilent" },
4134
4137
  { field: "poster", option: "poster" },
4135
4138
  { field: "cover", option: "cover" },
@@ -4215,11 +4218,19 @@ async function enrichQueueCommand(limit) {
4215
4218
  async function enrichSweepCommand(limit) {
4216
4219
  return adminApiPost(`/api/admin/enrich-sweep?limit=${limit}`);
4217
4220
  }
4218
- async function backfillLastfmCommand(limit, dryRun) {
4219
- return adminApiPost(`/api/admin/backfill/lastfm?limit=${limit}&dryRun=${dryRun}`);
4221
+ async function backfillLastfmCommand(limit, dryRun, cursor) {
4222
+ const params = new URLSearchParams({ dryRun: String(dryRun), limit: String(limit) });
4223
+ if (cursor) {
4224
+ params.set("cursor", cursor);
4225
+ }
4226
+ return adminApiPost(`/api/admin/backfill/lastfm?${params.toString()}`);
4220
4227
  }
4221
- async function backfillDiscogsCommand(limit, dryRun) {
4222
- return adminApiPost(`/api/admin/backfill/discogs?limit=${limit}&dryRun=${dryRun}`);
4228
+ async function backfillDiscogsCommand(limit, dryRun, cursor) {
4229
+ const params = new URLSearchParams({ dryRun: String(dryRun), limit: String(limit) });
4230
+ if (cursor) {
4231
+ params.set("cursor", cursor);
4232
+ }
4233
+ return adminApiPost(`/api/admin/backfill/discogs?${params.toString()}`);
4223
4234
  }
4224
4235
  async function vehiclesCommand(limit) {
4225
4236
  const tracks = await fetchAdminTracks({ hasVideo: true, max: limit, order: "desc" });
@@ -5400,7 +5411,7 @@ function addAdminCommands(program2) {
5400
5411
  const { trackUpdateCommand: trackUpdateCommand2 } = await Promise.resolve().then(() => (init_track(), exports_track));
5401
5412
  await runTrackUpdate(trackId, options, trackUpdateCommand2);
5402
5413
  });
5403
- adminTrack.command("video").description("Upload a track's video bundle to R2 and link it").argument("[idOrLogId]").option("--composition <file>", "Composition source file").option("--cover <file>", "Cover image").option("--dir <dir>", "Bundle directory").option("--footage <file>", "Video footage").option("--footage-silent <file>", "Silent video footage").option("--json", "Print JSON", false).option("--model <model>", "Authoring AI model (<provider>/<model>)").option("--note <file>", "Note file").option("--poster <file>", "Poster image").option("--props <file>", "Render props JSON").option("--reasoning <level>", "Authoring model reasoning effort (e.g. high)").option("--render <file>", "Render metadata JSON").allowExcessArguments().action(async (idOrLogId, options) => {
5414
+ adminTrack.command("video").description("Upload a track's video bundle to R2 and link it").argument("[idOrLogId]").option("--composition <file>", "Composition source file").option("--cover <file>", "Cover image").option("--dir <dir>", "Bundle directory").option("--footage <file>", "Video footage (square crop source)").option("--footage-silent <file>", "Silent video footage (retiring)").option("--footage-social <file>", "Portrait social cut (baked text)").option("--json", "Print JSON", false).option("--model <model>", "Authoring AI model (<provider>/<model>)").option("--note <file>", "Note file").option("--poster <file>", "Poster image").option("--props <file>", "Render props JSON").option("--reasoning <level>", "Authoring model reasoning effort (e.g. high)").option("--render <file>", "Render metadata JSON").allowExcessArguments().action(async (idOrLogId, options) => {
5404
5415
  const { trackVideoCommand: trackVideoCommand2 } = await Promise.resolve().then(() => (init_track(), exports_track));
5405
5416
  await runTrackVideo(idOrLogId, options, trackVideoCommand2);
5406
5417
  });
@@ -5590,37 +5601,87 @@ async function runPreviewArchiveBackfill(options, previewArchiveBackfillCommand2
5590
5601
  }
5591
5602
  async function runBackfillLastfm(options, backfillLastfmCommand2) {
5592
5603
  const limit = parseListLimit(options.limit);
5593
- const result = await backfillLastfmCommand2(limit, options.dryRun);
5604
+ const loved = [];
5605
+ const failed = [];
5606
+ let cursor;
5607
+ let dryRun = options.dryRun;
5608
+ while (loved.length + failed.length < limit) {
5609
+ const remaining = limit - (loved.length + failed.length);
5610
+ const result = await backfillLastfmCommand2(remaining, options.dryRun, cursor);
5611
+ dryRun = result.dryRun;
5612
+ loved.push(...result.loved);
5613
+ failed.push(...result.failed);
5614
+ if (!options.json) {
5615
+ const verb2 = result.dryRun ? "Would love" : "Loved";
5616
+ console.log(` \u2026${verb2.toLowerCase()} ${result.lovedCount}; ${result.failedCount} failed`);
5617
+ }
5618
+ if (result.nextCursor === null) {
5619
+ break;
5620
+ }
5621
+ cursor = result.nextCursor;
5622
+ }
5594
5623
  if (options.json) {
5595
- printJson(result);
5624
+ printJson({
5625
+ dryRun,
5626
+ failed,
5627
+ failedCount: failed.length,
5628
+ loved,
5629
+ lovedCount: loved.length,
5630
+ ok: true
5631
+ });
5596
5632
  return;
5597
5633
  }
5598
- const verb = result.dryRun ? "Would love" : "Loved";
5599
- console.log(`${verb} ${result.lovedCount} finding(s) on Last.fm; ${result.failedCount} failed.`);
5600
- for (const logId of result.loved) {
5634
+ const verb = dryRun ? "Would love" : "Loved";
5635
+ console.log(`${verb} ${loved.length} finding(s) on Last.fm; ${failed.length} failed.`);
5636
+ for (const logId of loved) {
5601
5637
  console.log(` ${logId}`);
5602
5638
  }
5603
- for (const item of result.failed) {
5639
+ for (const item of failed) {
5604
5640
  console.log(` ${item.logId}: ${item.error}`);
5605
5641
  }
5606
5642
  }
5607
5643
  async function runBackfillDiscogs(options, backfillDiscogsCommand2) {
5608
5644
  const limit = parseListLimit(options.limit);
5609
- const result = await backfillDiscogsCommand2(limit, options.dryRun);
5645
+ const resolved = [];
5646
+ const unresolved = [];
5647
+ let cursor;
5648
+ let dryRun = options.dryRun;
5649
+ while (resolved.length + unresolved.length < limit) {
5650
+ const remaining = limit - (resolved.length + unresolved.length);
5651
+ const result = await backfillDiscogsCommand2(remaining, options.dryRun, cursor);
5652
+ dryRun = result.dryRun;
5653
+ resolved.push(...result.resolved);
5654
+ unresolved.push(...result.unresolved);
5655
+ if (!options.json) {
5656
+ const verb2 = result.dryRun ? "would resolve" : "resolved";
5657
+ console.log(` \u2026${verb2} ${result.resolvedCount}; ${result.unresolvedCount} unresolved`);
5658
+ }
5659
+ if (result.nextCursor === null) {
5660
+ break;
5661
+ }
5662
+ cursor = result.nextCursor;
5663
+ }
5610
5664
  if (options.json) {
5611
- printJson(result);
5665
+ printJson({
5666
+ dryRun,
5667
+ ok: true,
5668
+ resolved,
5669
+ resolvedCount: resolved.length,
5670
+ unresolved,
5671
+ unresolvedCount: unresolved.length
5672
+ });
5612
5673
  return;
5613
5674
  }
5614
- const verb = result.dryRun ? "Would resolve" : "Resolved";
5615
- console.log(`${verb} ${result.resolvedCount} Discogs release id(s); ${result.unresolvedCount} unresolved.`);
5616
- for (const item of result.resolved) {
5675
+ const verb = dryRun ? "Would resolve" : "Resolved";
5676
+ console.log(`${verb} ${resolved.length} Discogs release id(s); ${unresolved.length} unresolved.`);
5677
+ for (const item of resolved) {
5617
5678
  const master = item.masterId ? ` (master ${item.masterId})` : "";
5618
5679
  console.log(` ${item.logId}: release ${item.releaseId}${master}`);
5619
5680
  }
5620
5681
  }
5621
5682
  async function runTrackVideo(idOrLogId, options, trackVideoCommand2) {
5622
5683
  if (!idOrLogId) {
5623
- throw new Error("Missing id. Usage: fluncle admin track video <track_id|log_id> (--dir <dir> | --footage <file> [--footage-silent <file>] [--poster <file>] [--cover <file>] [--note <file>] [--composition <file>] [--props <file>] [--render <file>])");
5684
+ throw new Error("Missing id. Usage: fluncle admin track video <track_id|log_id> (--dir <dir> | --footage <file> [--footage-social <file>] [--footage-silent <file>] [--poster <file>] [--cover <file>] [--note <file>] [--composition <file>] [--props <file>] [--render <file>])");
5624
5685
  }
5625
5686
  const dir = options.dir ? path.resolve(process.cwd(), options.dir) : undefined;
5626
5687
  const fromDir = (name) => {
@@ -5641,6 +5702,7 @@ async function runTrackVideo(idOrLogId, options, trackVideoCommand2) {
5641
5702
  cover: resolveFile(options.cover, "cover.jpg"),
5642
5703
  footage: resolveFile(options.footage, "footage.mp4"),
5643
5704
  footageSilent: resolveFile(options.footageSilent, "footage-silent.mp4"),
5705
+ footageSocial: resolveFile(options.footageSocial, "footage.social.mp4"),
5644
5706
  model: options.model,
5645
5707
  note: resolveFile(options.note, "note.txt"),
5646
5708
  poster: resolveFile(options.poster, "poster.jpg"),
@@ -6229,6 +6291,7 @@ var stringOptions = new Set([
6229
6291
  "--file",
6230
6292
  "--footage",
6231
6293
  "--footage-silent",
6294
+ "--footage-social",
6232
6295
  "--from",
6233
6296
  "--key",
6234
6297
  "--limit",
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.40.0"
34
+ "version": "0.42.0"
35
35
  }