fluncle 0.83.0 → 0.85.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 +117 -15
- package/package.json +1 -1
package/bin/fluncle.mjs
CHANGED
|
@@ -538,7 +538,7 @@ function parseVersion(version) {
|
|
|
538
538
|
var currentVersion;
|
|
539
539
|
var init_version = __esm(() => {
|
|
540
540
|
init_output();
|
|
541
|
-
currentVersion = "0.
|
|
541
|
+
currentVersion = "0.85.0".trim() ? "0.85.0".trim() : "0.1.0";
|
|
542
542
|
});
|
|
543
543
|
|
|
544
544
|
// src/update-notifier.ts
|
|
@@ -2446,7 +2446,7 @@ function parseVersion2(version) {
|
|
|
2446
2446
|
var currentVersion2, latestReleaseUrl = "https://api.github.com/repos/mauricekleine/fluncle/releases/latest";
|
|
2447
2447
|
var init_version2 = __esm(() => {
|
|
2448
2448
|
init_output();
|
|
2449
|
-
currentVersion2 = "0.
|
|
2449
|
+
currentVersion2 = "0.85.0".trim() ? "0.85.0".trim() : "0.1.0";
|
|
2450
2450
|
});
|
|
2451
2451
|
|
|
2452
2452
|
// ../../packages/registry/src/index.ts
|
|
@@ -3866,6 +3866,7 @@ var exports_recordings = {};
|
|
|
3866
3866
|
__export(exports_recordings, {
|
|
3867
3867
|
recordingsListCommand: () => recordingsListCommand,
|
|
3868
3868
|
recordingUpdateCommand: () => recordingUpdateCommand,
|
|
3869
|
+
recordingReplaceCuesCommand: () => recordingReplaceCuesCommand,
|
|
3869
3870
|
recordingPromoteCommand: () => recordingPromoteCommand,
|
|
3870
3871
|
recordingGetCommand: () => recordingGetCommand,
|
|
3871
3872
|
recordingGet: () => recordingGet,
|
|
@@ -3878,12 +3879,21 @@ async function recordingGet(id) {
|
|
|
3878
3879
|
return response.recording;
|
|
3879
3880
|
}
|
|
3880
3881
|
function formatRecordingSummary(recording) {
|
|
3882
|
+
const kind = recording.hasVideo ? `take v${recording.version}` : "plan";
|
|
3881
3883
|
const promoted = recording.logId ? ` → fluncle://${recording.logId}` : " (un-promoted)";
|
|
3882
3884
|
const cues = recording.tracklist.length;
|
|
3883
|
-
return `${recording.id} ${recording.title}${promoted} [${cues} cue${cues === 1 ? "" : "s"}]`;
|
|
3885
|
+
return `${recording.id} [${kind}] ${recording.title}${promoted} [${cues} cue${cues === 1 ? "" : "s"}]`;
|
|
3884
3886
|
}
|
|
3885
3887
|
async function recordingsListCommand(options = {}) {
|
|
3886
|
-
const
|
|
3888
|
+
const query = new URLSearchParams;
|
|
3889
|
+
if (options.kind) {
|
|
3890
|
+
query.set("kind", options.kind);
|
|
3891
|
+
}
|
|
3892
|
+
if (options.parentId) {
|
|
3893
|
+
query.set("parentId", options.parentId);
|
|
3894
|
+
}
|
|
3895
|
+
const suffix = query.toString() ? `?${query.toString()}` : "";
|
|
3896
|
+
const response = await adminApiGet(`/api/admin/recordings${suffix}`);
|
|
3887
3897
|
if (options.json) {
|
|
3888
3898
|
printJson2({ ok: true, recordings: response.recordings });
|
|
3889
3899
|
return;
|
|
@@ -3905,16 +3915,29 @@ async function recordingGetCommand(id, options = {}) {
|
|
|
3905
3915
|
return;
|
|
3906
3916
|
}
|
|
3907
3917
|
console.log(formatRecordingSummary(recording));
|
|
3908
|
-
console.log(` r2Key: ${recording.r2Key}`);
|
|
3918
|
+
console.log(` r2Key: ${recording.r2Key ?? "— (no set video)"}`);
|
|
3909
3919
|
for (const cue of recording.tracklist) {
|
|
3910
3920
|
const at = cue.startMs === undefined ? "—" : `${(cue.startMs / 1000).toFixed(1)}s`;
|
|
3911
3921
|
console.log(` ${at} ${cue.artists.join(", ")} — ${cue.title}`);
|
|
3912
3922
|
}
|
|
3913
3923
|
}
|
|
3914
3924
|
async function recordingCreateCommand(options = {}) {
|
|
3925
|
+
if (options.plan) {
|
|
3926
|
+
const created2 = await adminApiPost("/api/admin/recordings", {
|
|
3927
|
+
kind: "plan",
|
|
3928
|
+
recordedAt: options.recordedAt
|
|
3929
|
+
});
|
|
3930
|
+
const recording2 = created2.recording;
|
|
3931
|
+
if (options.json) {
|
|
3932
|
+
printJson2({ ok: true, recording: recording2 });
|
|
3933
|
+
return;
|
|
3934
|
+
}
|
|
3935
|
+
console.log(`Plan ${recording2.id} created — handle "${recording2.title}"`);
|
|
3936
|
+
return;
|
|
3937
|
+
}
|
|
3915
3938
|
const title = options.title?.trim();
|
|
3916
3939
|
if (!title) {
|
|
3917
|
-
throw new CliError2("missing_title", "A recording needs a --title");
|
|
3940
|
+
throw new CliError2("missing_title", "A recording needs a --title (or --plan for a videoless plan)");
|
|
3918
3941
|
}
|
|
3919
3942
|
if (!options.video) {
|
|
3920
3943
|
throw new CliError2("missing_video", "A recording needs a --video <file> to stage");
|
|
@@ -3951,6 +3974,9 @@ async function recordingUpdateCommand(id, options = {}) {
|
|
|
3951
3974
|
if (options.recordedAt !== undefined) {
|
|
3952
3975
|
body.recordedAt = options.recordedAt;
|
|
3953
3976
|
}
|
|
3977
|
+
if (options.parentId !== undefined) {
|
|
3978
|
+
body.parentId = options.parentId;
|
|
3979
|
+
}
|
|
3954
3980
|
if (options.tracklistFile !== undefined) {
|
|
3955
3981
|
if (!existsSync3(options.tracklistFile)) {
|
|
3956
3982
|
throw new CliError2("file_not_found", `Tracklist file not found: ${options.tracklistFile}`);
|
|
@@ -3962,7 +3988,7 @@ async function recordingUpdateCommand(id, options = {}) {
|
|
|
3962
3988
|
}
|
|
3963
3989
|
}
|
|
3964
3990
|
if (Object.keys(body).length === 0) {
|
|
3965
|
-
throw new CliError2("no_fields", "Nothing to update — pass --title, --recorded-at, or --tracklist-file");
|
|
3991
|
+
throw new CliError2("no_fields", "Nothing to update — pass --title, --recorded-at, --parent-id, or --tracklist-file");
|
|
3966
3992
|
}
|
|
3967
3993
|
const response = await adminApiPatch(`/api/admin/recordings/${encodeURIComponent(id)}`, body);
|
|
3968
3994
|
if (options.json) {
|
|
@@ -3994,6 +4020,29 @@ async function recordingPromoteCommand(id, options = {}) {
|
|
|
3994
4020
|
}
|
|
3995
4021
|
console.log(recording.logId ? `Promoted recording ${id} → mixtape fluncle://${recording.logId}` : `Promoted recording ${id}`);
|
|
3996
4022
|
}
|
|
4023
|
+
async function recordingReplaceCuesCommand(id, options = {}) {
|
|
4024
|
+
if (!id) {
|
|
4025
|
+
throw new CliError2("missing_id", "Missing recording id for: replace-cues");
|
|
4026
|
+
}
|
|
4027
|
+
if (!options.cuesFile) {
|
|
4028
|
+
throw new CliError2("missing_cues_file", "replace-cues needs a --cues-file <file> (the ordered cue array)");
|
|
4029
|
+
}
|
|
4030
|
+
if (!existsSync3(options.cuesFile)) {
|
|
4031
|
+
throw new CliError2("file_not_found", `Cues file not found: ${options.cuesFile}`);
|
|
4032
|
+
}
|
|
4033
|
+
let cues;
|
|
4034
|
+
try {
|
|
4035
|
+
cues = JSON.parse(readFileSync3(options.cuesFile, "utf8"));
|
|
4036
|
+
} catch {
|
|
4037
|
+
throw new CliError2("invalid_cues", `Cues file is not valid JSON: ${options.cuesFile}`);
|
|
4038
|
+
}
|
|
4039
|
+
const response = await adminApiPut(`/api/admin/recordings/${encodeURIComponent(id)}/cues`, { cues });
|
|
4040
|
+
if (options.json) {
|
|
4041
|
+
printJson2({ ok: true, recording: response.recording });
|
|
4042
|
+
return;
|
|
4043
|
+
}
|
|
4044
|
+
console.log(`Replaced cues for ${formatRecordingSummary(response.recording)}`);
|
|
4045
|
+
}
|
|
3997
4046
|
var init_recordings = __esm(() => {
|
|
3998
4047
|
init_api();
|
|
3999
4048
|
init_output();
|
|
@@ -4441,6 +4490,7 @@ var exports_recordings2 = {};
|
|
|
4441
4490
|
__export(exports_recordings2, {
|
|
4442
4491
|
recordingsListCommand: () => recordingsListCommand2,
|
|
4443
4492
|
recordingUpdateCommand: () => recordingUpdateCommand2,
|
|
4493
|
+
recordingReplaceCuesCommand: () => recordingReplaceCuesCommand2,
|
|
4444
4494
|
recordingPromoteCommand: () => recordingPromoteCommand2,
|
|
4445
4495
|
recordingGetCommand: () => recordingGetCommand2,
|
|
4446
4496
|
recordingGet: () => recordingGet2,
|
|
@@ -4453,12 +4503,21 @@ async function recordingGet2(id) {
|
|
|
4453
4503
|
return response.recording;
|
|
4454
4504
|
}
|
|
4455
4505
|
function formatRecordingSummary2(recording) {
|
|
4506
|
+
const kind = recording.hasVideo ? `take v${recording.version}` : "plan";
|
|
4456
4507
|
const promoted = recording.logId ? ` → fluncle://${recording.logId}` : " (un-promoted)";
|
|
4457
4508
|
const cues = recording.tracklist.length;
|
|
4458
|
-
return `${recording.id} ${recording.title}${promoted} [${cues} cue${cues === 1 ? "" : "s"}]`;
|
|
4509
|
+
return `${recording.id} [${kind}] ${recording.title}${promoted} [${cues} cue${cues === 1 ? "" : "s"}]`;
|
|
4459
4510
|
}
|
|
4460
4511
|
async function recordingsListCommand2(options = {}) {
|
|
4461
|
-
const
|
|
4512
|
+
const query = new URLSearchParams;
|
|
4513
|
+
if (options.kind) {
|
|
4514
|
+
query.set("kind", options.kind);
|
|
4515
|
+
}
|
|
4516
|
+
if (options.parentId) {
|
|
4517
|
+
query.set("parentId", options.parentId);
|
|
4518
|
+
}
|
|
4519
|
+
const suffix = query.toString() ? `?${query.toString()}` : "";
|
|
4520
|
+
const response = await adminApiGet(`/api/admin/recordings${suffix}`);
|
|
4462
4521
|
if (options.json) {
|
|
4463
4522
|
printJson2({ ok: true, recordings: response.recordings });
|
|
4464
4523
|
return;
|
|
@@ -4480,16 +4539,29 @@ async function recordingGetCommand2(id, options = {}) {
|
|
|
4480
4539
|
return;
|
|
4481
4540
|
}
|
|
4482
4541
|
console.log(formatRecordingSummary2(recording));
|
|
4483
|
-
console.log(` r2Key: ${recording.r2Key}`);
|
|
4542
|
+
console.log(` r2Key: ${recording.r2Key ?? "— (no set video)"}`);
|
|
4484
4543
|
for (const cue of recording.tracklist) {
|
|
4485
4544
|
const at = cue.startMs === undefined ? "—" : `${(cue.startMs / 1000).toFixed(1)}s`;
|
|
4486
4545
|
console.log(` ${at} ${cue.artists.join(", ")} — ${cue.title}`);
|
|
4487
4546
|
}
|
|
4488
4547
|
}
|
|
4489
4548
|
async function recordingCreateCommand2(options = {}) {
|
|
4549
|
+
if (options.plan) {
|
|
4550
|
+
const created2 = await adminApiPost("/api/admin/recordings", {
|
|
4551
|
+
kind: "plan",
|
|
4552
|
+
recordedAt: options.recordedAt
|
|
4553
|
+
});
|
|
4554
|
+
const recording2 = created2.recording;
|
|
4555
|
+
if (options.json) {
|
|
4556
|
+
printJson2({ ok: true, recording: recording2 });
|
|
4557
|
+
return;
|
|
4558
|
+
}
|
|
4559
|
+
console.log(`Plan ${recording2.id} created — handle "${recording2.title}"`);
|
|
4560
|
+
return;
|
|
4561
|
+
}
|
|
4490
4562
|
const title = options.title?.trim();
|
|
4491
4563
|
if (!title) {
|
|
4492
|
-
throw new CliError2("missing_title", "A recording needs a --title");
|
|
4564
|
+
throw new CliError2("missing_title", "A recording needs a --title (or --plan for a videoless plan)");
|
|
4493
4565
|
}
|
|
4494
4566
|
if (!options.video) {
|
|
4495
4567
|
throw new CliError2("missing_video", "A recording needs a --video <file> to stage");
|
|
@@ -4526,6 +4598,9 @@ async function recordingUpdateCommand2(id, options = {}) {
|
|
|
4526
4598
|
if (options.recordedAt !== undefined) {
|
|
4527
4599
|
body.recordedAt = options.recordedAt;
|
|
4528
4600
|
}
|
|
4601
|
+
if (options.parentId !== undefined) {
|
|
4602
|
+
body.parentId = options.parentId;
|
|
4603
|
+
}
|
|
4529
4604
|
if (options.tracklistFile !== undefined) {
|
|
4530
4605
|
if (!existsSync5(options.tracklistFile)) {
|
|
4531
4606
|
throw new CliError2("file_not_found", `Tracklist file not found: ${options.tracklistFile}`);
|
|
@@ -4537,7 +4612,7 @@ async function recordingUpdateCommand2(id, options = {}) {
|
|
|
4537
4612
|
}
|
|
4538
4613
|
}
|
|
4539
4614
|
if (Object.keys(body).length === 0) {
|
|
4540
|
-
throw new CliError2("no_fields", "Nothing to update — pass --title, --recorded-at, or --tracklist-file");
|
|
4615
|
+
throw new CliError2("no_fields", "Nothing to update — pass --title, --recorded-at, --parent-id, or --tracklist-file");
|
|
4541
4616
|
}
|
|
4542
4617
|
const response = await adminApiPatch(`/api/admin/recordings/${encodeURIComponent(id)}`, body);
|
|
4543
4618
|
if (options.json) {
|
|
@@ -4569,6 +4644,29 @@ async function recordingPromoteCommand2(id, options = {}) {
|
|
|
4569
4644
|
}
|
|
4570
4645
|
console.log(recording.logId ? `Promoted recording ${id} → mixtape fluncle://${recording.logId}` : `Promoted recording ${id}`);
|
|
4571
4646
|
}
|
|
4647
|
+
async function recordingReplaceCuesCommand2(id, options = {}) {
|
|
4648
|
+
if (!id) {
|
|
4649
|
+
throw new CliError2("missing_id", "Missing recording id for: replace-cues");
|
|
4650
|
+
}
|
|
4651
|
+
if (!options.cuesFile) {
|
|
4652
|
+
throw new CliError2("missing_cues_file", "replace-cues needs a --cues-file <file> (the ordered cue array)");
|
|
4653
|
+
}
|
|
4654
|
+
if (!existsSync5(options.cuesFile)) {
|
|
4655
|
+
throw new CliError2("file_not_found", `Cues file not found: ${options.cuesFile}`);
|
|
4656
|
+
}
|
|
4657
|
+
let cues;
|
|
4658
|
+
try {
|
|
4659
|
+
cues = JSON.parse(readFileSync5(options.cuesFile, "utf8"));
|
|
4660
|
+
} catch {
|
|
4661
|
+
throw new CliError2("invalid_cues", `Cues file is not valid JSON: ${options.cuesFile}`);
|
|
4662
|
+
}
|
|
4663
|
+
const response = await adminApiPut(`/api/admin/recordings/${encodeURIComponent(id)}/cues`, { cues });
|
|
4664
|
+
if (options.json) {
|
|
4665
|
+
printJson2({ ok: true, recording: response.recording });
|
|
4666
|
+
return;
|
|
4667
|
+
}
|
|
4668
|
+
console.log(`Replaced cues for ${formatRecordingSummary2(response.recording)}`);
|
|
4669
|
+
}
|
|
4572
4670
|
var init_recordings2 = __esm(() => {
|
|
4573
4671
|
init_api();
|
|
4574
4672
|
init_output();
|
|
@@ -7626,11 +7724,11 @@ function addAdminCommands(program2) {
|
|
|
7626
7724
|
adminRecordings.action(() => {
|
|
7627
7725
|
adminRecordings.outputHelp();
|
|
7628
7726
|
});
|
|
7629
|
-
adminRecordings.command("create").description("Create a recording
|
|
7727
|
+
adminRecordings.command("create").description("Create a recording (--video to stage a take, or --plan for a videoless plan)").option("--plan", "Create a videoless PLAN (server mints a Galaxy-vocab handle)", false).option("--title <text>", "Recording title (a take)").option("--video <file>", "Set-video master to stage (a 1080p rendition is derived)").option("--recorded-at <date>", "Recorded date (ISO)").option("--json", "Print JSON", false).allowExcessArguments().action(async (options) => {
|
|
7630
7728
|
const { recordingCreateCommand: recordingCreateCommand3 } = await Promise.resolve().then(() => (init_recordings2(), exports_recordings2));
|
|
7631
7729
|
await recordingCreateCommand3(options);
|
|
7632
7730
|
});
|
|
7633
|
-
adminRecordings.command("list").description("List
|
|
7731
|
+
adminRecordings.command("list").description("List recordings (--kind plan|take, --parent-id <plan> for a plan's takes)").option("--kind <kind>", "Filter by kind: plan | take").option("--parent-id <id>", "List the takes attached to this plan").option("--json", "Print JSON", false).allowExcessArguments().action(async (options) => {
|
|
7634
7732
|
const { recordingsListCommand: recordingsListCommand3 } = await Promise.resolve().then(() => (init_recordings2(), exports_recordings2));
|
|
7635
7733
|
await recordingsListCommand3(options);
|
|
7636
7734
|
});
|
|
@@ -7638,10 +7736,14 @@ function addAdminCommands(program2) {
|
|
|
7638
7736
|
const { recordingGetCommand: recordingGetCommand3 } = await Promise.resolve().then(() => (init_recordings2(), exports_recordings2));
|
|
7639
7737
|
await recordingGetCommand3(id, options);
|
|
7640
7738
|
});
|
|
7641
|
-
adminRecordings.command("update").description("Update a recording's title
|
|
7739
|
+
adminRecordings.command("update").description("Update a recording's title/recorded date/tracklist, or attach it to a plan").argument("[id]").option("--title <text>", "Recording title").option("--recorded-at <date>", "Recorded date (ISO)").option("--parent-id <id>", "Attach this take to its plan (assigns the take's version)").option("--tracklist-file <file>", "JSON file with the whole cue tracklist array").option("--json", "Print JSON", false).allowExcessArguments().action(async (id, options) => {
|
|
7642
7740
|
const { recordingUpdateCommand: recordingUpdateCommand3 } = await Promise.resolve().then(() => (init_recordings2(), exports_recordings2));
|
|
7643
7741
|
await recordingUpdateCommand3(id, options);
|
|
7644
7742
|
});
|
|
7743
|
+
adminRecordings.command("replace-cues").description("Replace a recording's whole cue tracklist from a JSON file (--cues-file)").argument("[id]").option("--cues-file <file>", "JSON file with the ordered cue array").option("--json", "Print JSON", false).allowExcessArguments().action(async (id, options) => {
|
|
7744
|
+
const { recordingReplaceCuesCommand: recordingReplaceCuesCommand3 } = await Promise.resolve().then(() => (init_recordings2(), exports_recordings2));
|
|
7745
|
+
await recordingReplaceCuesCommand3(id, options);
|
|
7746
|
+
});
|
|
7645
7747
|
adminRecordings.command("delete").description("Delete a recording (cascade its clips)").argument("[id]").option("--json", "Print JSON", false).allowExcessArguments().action(async (id, options) => {
|
|
7646
7748
|
const { recordingDeleteCommand: recordingDeleteCommand3 } = await Promise.resolve().then(() => (init_recordings2(), exports_recordings2));
|
|
7647
7749
|
await recordingDeleteCommand3(id, options);
|
package/package.json
CHANGED