fluncle 0.87.0 → 0.88.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 +32 -178
- 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.88.0".trim() ? "0.88.0".trim() : "0.1.0";
|
|
542
542
|
});
|
|
543
543
|
|
|
544
544
|
// src/update-notifier.ts
|
|
@@ -1335,47 +1335,22 @@ __export(exports_mixtapes, {
|
|
|
1335
1335
|
mixtapesCommand: () => mixtapesCommand,
|
|
1336
1336
|
mixtapeUpdateCommand: () => mixtapeUpdateCommand,
|
|
1337
1337
|
mixtapeResyncCommand: () => mixtapeResyncCommand,
|
|
1338
|
-
mixtapePublishCommand: () => mixtapePublishCommand,
|
|
1339
|
-
mixtapeMembersCommand: () => mixtapeMembersCommand,
|
|
1340
1338
|
mixtapeListCommand: () => mixtapeListCommand,
|
|
1341
1339
|
mixtapeGetCommand: () => mixtapeGetCommand,
|
|
1342
|
-
mixtapeDistributeCommand: () => mixtapeDistributeCommand
|
|
1343
|
-
mixtapeDeleteCommand: () => mixtapeDeleteCommand,
|
|
1344
|
-
mixtapeCreateCommand: () => mixtapeCreateCommand
|
|
1340
|
+
mixtapeDistributeCommand: () => mixtapeDistributeCommand
|
|
1345
1341
|
});
|
|
1346
|
-
import { existsSync, readFileSync as readFileSync2 } from "node:fs";
|
|
1347
1342
|
async function mixtapesCommand() {
|
|
1348
1343
|
const response = await publicApiGet("/api/mixtapes");
|
|
1349
1344
|
return response.mixtapes;
|
|
1350
1345
|
}
|
|
1351
|
-
async function mixtapeCreateCommand(options) {
|
|
1352
|
-
return adminApiPost("/api/admin/mixtapes", buildBody(options));
|
|
1353
|
-
}
|
|
1354
1346
|
async function mixtapeUpdateCommand(id, options) {
|
|
1355
1347
|
return adminApiPatch(`/api/admin/mixtapes/${encodeURIComponent(id)}`, buildBody(options));
|
|
1356
1348
|
}
|
|
1357
|
-
async function mixtapeMembersCommand(id, refs, options) {
|
|
1358
|
-
const members = refs.map((ref) => ({ ref }));
|
|
1359
|
-
if (options.from) {
|
|
1360
|
-
members.push(...parseCueFile(options.from));
|
|
1361
|
-
}
|
|
1362
|
-
return adminApiPut(`/api/admin/mixtapes/${encodeURIComponent(id)}/members`, { members });
|
|
1363
|
-
}
|
|
1364
|
-
async function mixtapePublishCommand(id) {
|
|
1365
|
-
return adminApiPost(`/api/admin/mixtapes/${encodeURIComponent(id)}/publish`);
|
|
1366
|
-
}
|
|
1367
|
-
async function mixtapeDeleteCommand(id) {
|
|
1368
|
-
return adminApiDelete(`/api/admin/mixtapes/${encodeURIComponent(id)}`);
|
|
1369
|
-
}
|
|
1370
1349
|
async function mixtapeDistributeCommand(idOrLogId, options, onProgress = () => {}) {
|
|
1371
1350
|
const mixtape = await mixtapeGetCommand(idOrLogId);
|
|
1372
1351
|
if (!mixtape.id) {
|
|
1373
1352
|
throw new CliError2("mixtape_not_found", `No mixtape with id or log id ${idOrLogId}`);
|
|
1374
1353
|
}
|
|
1375
|
-
if (mixtape.status === "draft") {
|
|
1376
|
-
throw new CliError2("mixtape_not_promoted", `${mixtape.id} is still a draft — promote its recording first:
|
|
1377
|
-
` + " fluncle admin recordings promote <recordingId>");
|
|
1378
|
-
}
|
|
1379
1354
|
const both = !options.youtube && !options.mixcloud;
|
|
1380
1355
|
const doYoutube = both || Boolean(options.youtube);
|
|
1381
1356
|
const doMixcloud = both || Boolean(options.mixcloud);
|
|
@@ -1388,7 +1363,8 @@ async function mixtapeDistributeCommand(idOrLogId, options, onProgress = () => {
|
|
|
1388
1363
|
const mixtapeId = mixtape.id;
|
|
1389
1364
|
const logId = mixtape.logId;
|
|
1390
1365
|
if (!logId) {
|
|
1391
|
-
throw new CliError2("
|
|
1366
|
+
throw new CliError2("mixtape_not_promoted", `${mixtapeId} has no coordinate yet — promote its recording first:
|
|
1367
|
+
` + " fluncle admin recordings promote <recordingId>");
|
|
1392
1368
|
}
|
|
1393
1369
|
if (!mixtape.durationMs) {
|
|
1394
1370
|
const source = options.audio ?? options.video;
|
|
@@ -1495,65 +1471,6 @@ function buildBody(options) {
|
|
|
1495
1471
|
}
|
|
1496
1472
|
return body;
|
|
1497
1473
|
}
|
|
1498
|
-
function parseCueFile(filePath) {
|
|
1499
|
-
if (!existsSync(filePath)) {
|
|
1500
|
-
throw new CliError2("file_not_found", `Cue file not found: ${filePath}`);
|
|
1501
|
-
}
|
|
1502
|
-
const text = readFileSync2(filePath, "utf-8");
|
|
1503
|
-
const trimmed = text.trim();
|
|
1504
|
-
if (trimmed.startsWith("[") || trimmed.startsWith("{")) {
|
|
1505
|
-
try {
|
|
1506
|
-
const parsed = JSON.parse(trimmed);
|
|
1507
|
-
if (!Array.isArray(parsed)) {
|
|
1508
|
-
throw new Error("not an array");
|
|
1509
|
-
}
|
|
1510
|
-
return parsed.map((entry, index) => {
|
|
1511
|
-
if (typeof entry === "string") {
|
|
1512
|
-
return { ref: entry.trim() };
|
|
1513
|
-
}
|
|
1514
|
-
const obj = entry;
|
|
1515
|
-
if (typeof obj?.ref !== "string") {
|
|
1516
|
-
throw new CliError2("invalid_cue_json", `Entry ${index + 1} missing "ref" string`);
|
|
1517
|
-
}
|
|
1518
|
-
const cue = { ref: obj.ref.trim() };
|
|
1519
|
-
if (typeof obj.startMs === "number" && Number.isInteger(obj.startMs) && obj.startMs >= 0) {
|
|
1520
|
-
cue.startMs = obj.startMs;
|
|
1521
|
-
}
|
|
1522
|
-
return cue;
|
|
1523
|
-
});
|
|
1524
|
-
} catch (error) {
|
|
1525
|
-
if (error instanceof CliError2) {
|
|
1526
|
-
throw error;
|
|
1527
|
-
}
|
|
1528
|
-
throw new CliError2("invalid_cue_json", `Cue JSON parse failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
1529
|
-
}
|
|
1530
|
-
}
|
|
1531
|
-
return parseCueSheet(text);
|
|
1532
|
-
}
|
|
1533
|
-
function parseCueSheet(text) {
|
|
1534
|
-
const entries = [];
|
|
1535
|
-
for (const line of text.split(/\r?\n/)) {
|
|
1536
|
-
const trimmed = line.trim();
|
|
1537
|
-
if (!trimmed || trimmed.startsWith("#")) {
|
|
1538
|
-
continue;
|
|
1539
|
-
}
|
|
1540
|
-
const match = trimmed.match(/^(\d{1,2}:\d{2}(?::\d{2})?)\s+(.+)$/);
|
|
1541
|
-
if (match) {
|
|
1542
|
-
const [, time, ref] = match;
|
|
1543
|
-
if (time === undefined || ref === undefined) {
|
|
1544
|
-
continue;
|
|
1545
|
-
}
|
|
1546
|
-
const startMs = parseDuration(time);
|
|
1547
|
-
if (startMs === null) {
|
|
1548
|
-
continue;
|
|
1549
|
-
}
|
|
1550
|
-
entries.push({ ref: ref.trim(), startMs });
|
|
1551
|
-
} else {
|
|
1552
|
-
entries.push({ ref: trimmed });
|
|
1553
|
-
}
|
|
1554
|
-
}
|
|
1555
|
-
return entries;
|
|
1556
|
-
}
|
|
1557
1474
|
var init_mixtapes = __esm(() => {
|
|
1558
1475
|
init_util();
|
|
1559
1476
|
init_api();
|
|
@@ -2251,7 +2168,7 @@ function parseVersion2(version) {
|
|
|
2251
2168
|
var currentVersion2, latestReleaseUrl = "https://api.github.com/repos/mauricekleine/fluncle/releases/latest";
|
|
2252
2169
|
var init_version2 = __esm(() => {
|
|
2253
2170
|
init_output();
|
|
2254
|
-
currentVersion2 = "0.
|
|
2171
|
+
currentVersion2 = "0.88.0".trim() ? "0.88.0".trim() : "0.1.0";
|
|
2255
2172
|
});
|
|
2256
2173
|
|
|
2257
2174
|
// ../../packages/registry/src/index.ts
|
|
@@ -2773,7 +2690,7 @@ var init_src = __esm(() => {
|
|
|
2773
2690
|
{
|
|
2774
2691
|
command: "fluncle admin",
|
|
2775
2692
|
exposedContent: [
|
|
2776
|
-
"the operator/agent command group (hidden): tracks publish|update|enrich|video|draft|social|preview|observe|context|note,
|
|
2693
|
+
"the operator/agent command group (hidden): tracks publish|update|enrich|video|draft|social|preview|observe|context|note, recordings create|promote, mixtapes update|distribute|resync, newsletter draft|update|send|list, backfills, auth"
|
|
2777
2694
|
],
|
|
2778
2695
|
kind: "cli",
|
|
2779
2696
|
name: "cli.admin",
|
|
@@ -3668,7 +3585,7 @@ var init_mixtape_youtube2 = __esm(() => {
|
|
|
3668
3585
|
|
|
3669
3586
|
// src/commands/mixtape-set-video.ts
|
|
3670
3587
|
import { randomUUID } from "node:crypto";
|
|
3671
|
-
import { existsSync
|
|
3588
|
+
import { existsSync, rmSync as rmSync2, statSync as statSync3 } from "node:fs";
|
|
3672
3589
|
import { tmpdir } from "node:os";
|
|
3673
3590
|
import { join as join4 } from "node:path";
|
|
3674
3591
|
function planMultipart(contentLength, partSize = DEFAULT_PART_SIZE) {
|
|
@@ -3725,7 +3642,7 @@ function renditionFfmpegArgs(inputPath, outputPath) {
|
|
|
3725
3642
|
];
|
|
3726
3643
|
}
|
|
3727
3644
|
async function uploadRenditionMultipart(masterPath, presignPath, onProgress = () => {}) {
|
|
3728
|
-
if (!
|
|
3645
|
+
if (!existsSync(masterPath)) {
|
|
3729
3646
|
throw new CliError2("file_not_found", `Set-video master not found: ${masterPath}`);
|
|
3730
3647
|
}
|
|
3731
3648
|
await assertFfmpeg();
|
|
@@ -3838,7 +3755,7 @@ __export(exports_recordings, {
|
|
|
3838
3755
|
recordingDeleteCommand: () => recordingDeleteCommand,
|
|
3839
3756
|
recordingCreateCommand: () => recordingCreateCommand
|
|
3840
3757
|
});
|
|
3841
|
-
import { existsSync as
|
|
3758
|
+
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "node:fs";
|
|
3842
3759
|
async function recordingGet(id) {
|
|
3843
3760
|
const response = await adminApiGet(`/api/admin/recordings/${encodeURIComponent(id)}`);
|
|
3844
3761
|
return response.recording;
|
|
@@ -3907,7 +3824,7 @@ async function recordingCreateCommand(options = {}) {
|
|
|
3907
3824
|
if (!options.video) {
|
|
3908
3825
|
throw new CliError2("missing_video", "A recording needs a --video <file> to stage");
|
|
3909
3826
|
}
|
|
3910
|
-
if (!
|
|
3827
|
+
if (!existsSync2(options.video)) {
|
|
3911
3828
|
throw new CliError2("file_not_found", `Set-video master not found: ${options.video}`);
|
|
3912
3829
|
}
|
|
3913
3830
|
const created = await adminApiPost("/api/admin/recordings", {
|
|
@@ -3943,11 +3860,11 @@ async function recordingUpdateCommand(id, options = {}) {
|
|
|
3943
3860
|
body.parentId = options.parentId;
|
|
3944
3861
|
}
|
|
3945
3862
|
if (options.tracklistFile !== undefined) {
|
|
3946
|
-
if (!
|
|
3863
|
+
if (!existsSync2(options.tracklistFile)) {
|
|
3947
3864
|
throw new CliError2("file_not_found", `Tracklist file not found: ${options.tracklistFile}`);
|
|
3948
3865
|
}
|
|
3949
3866
|
try {
|
|
3950
|
-
body.tracklistJson = JSON.parse(
|
|
3867
|
+
body.tracklistJson = JSON.parse(readFileSync2(options.tracklistFile, "utf8"));
|
|
3951
3868
|
} catch {
|
|
3952
3869
|
throw new CliError2("invalid_tracklist", `Tracklist file is not valid JSON: ${options.tracklistFile}`);
|
|
3953
3870
|
}
|
|
@@ -3992,12 +3909,12 @@ async function recordingReplaceCuesCommand(id, options = {}) {
|
|
|
3992
3909
|
if (!options.cuesFile) {
|
|
3993
3910
|
throw new CliError2("missing_cues_file", "replace-cues needs a --cues-file <file> (the ordered cue array)");
|
|
3994
3911
|
}
|
|
3995
|
-
if (!
|
|
3912
|
+
if (!existsSync2(options.cuesFile)) {
|
|
3996
3913
|
throw new CliError2("file_not_found", `Cues file not found: ${options.cuesFile}`);
|
|
3997
3914
|
}
|
|
3998
3915
|
let cues;
|
|
3999
3916
|
try {
|
|
4000
|
-
cues = JSON.parse(
|
|
3917
|
+
cues = JSON.parse(readFileSync2(options.cuesFile, "utf8"));
|
|
4001
3918
|
} catch {
|
|
4002
3919
|
throw new CliError2("invalid_cues", `Cues file is not valid JSON: ${options.cuesFile}`);
|
|
4003
3920
|
}
|
|
@@ -4201,7 +4118,7 @@ __export(exports_recordings2, {
|
|
|
4201
4118
|
recordingDeleteCommand: () => recordingDeleteCommand2,
|
|
4202
4119
|
recordingCreateCommand: () => recordingCreateCommand2
|
|
4203
4120
|
});
|
|
4204
|
-
import { existsSync as
|
|
4121
|
+
import { existsSync as existsSync3, readFileSync as readFileSync3 } from "node:fs";
|
|
4205
4122
|
async function recordingGet2(id) {
|
|
4206
4123
|
const response = await adminApiGet(`/api/admin/recordings/${encodeURIComponent(id)}`);
|
|
4207
4124
|
return response.recording;
|
|
@@ -4270,7 +4187,7 @@ async function recordingCreateCommand2(options = {}) {
|
|
|
4270
4187
|
if (!options.video) {
|
|
4271
4188
|
throw new CliError2("missing_video", "A recording needs a --video <file> to stage");
|
|
4272
4189
|
}
|
|
4273
|
-
if (!
|
|
4190
|
+
if (!existsSync3(options.video)) {
|
|
4274
4191
|
throw new CliError2("file_not_found", `Set-video master not found: ${options.video}`);
|
|
4275
4192
|
}
|
|
4276
4193
|
const created = await adminApiPost("/api/admin/recordings", {
|
|
@@ -4306,11 +4223,11 @@ async function recordingUpdateCommand2(id, options = {}) {
|
|
|
4306
4223
|
body.parentId = options.parentId;
|
|
4307
4224
|
}
|
|
4308
4225
|
if (options.tracklistFile !== undefined) {
|
|
4309
|
-
if (!
|
|
4226
|
+
if (!existsSync3(options.tracklistFile)) {
|
|
4310
4227
|
throw new CliError2("file_not_found", `Tracklist file not found: ${options.tracklistFile}`);
|
|
4311
4228
|
}
|
|
4312
4229
|
try {
|
|
4313
|
-
body.tracklistJson = JSON.parse(
|
|
4230
|
+
body.tracklistJson = JSON.parse(readFileSync3(options.tracklistFile, "utf8"));
|
|
4314
4231
|
} catch {
|
|
4315
4232
|
throw new CliError2("invalid_tracklist", `Tracklist file is not valid JSON: ${options.tracklistFile}`);
|
|
4316
4233
|
}
|
|
@@ -4355,12 +4272,12 @@ async function recordingReplaceCuesCommand2(id, options = {}) {
|
|
|
4355
4272
|
if (!options.cuesFile) {
|
|
4356
4273
|
throw new CliError2("missing_cues_file", "replace-cues needs a --cues-file <file> (the ordered cue array)");
|
|
4357
4274
|
}
|
|
4358
|
-
if (!
|
|
4275
|
+
if (!existsSync3(options.cuesFile)) {
|
|
4359
4276
|
throw new CliError2("file_not_found", `Cues file not found: ${options.cuesFile}`);
|
|
4360
4277
|
}
|
|
4361
4278
|
let cues;
|
|
4362
4279
|
try {
|
|
4363
|
-
cues = JSON.parse(
|
|
4280
|
+
cues = JSON.parse(readFileSync3(options.cuesFile, "utf8"));
|
|
4364
4281
|
} catch {
|
|
4365
4282
|
throw new CliError2("invalid_cues", `Cues file is not valid JSON: ${options.cuesFile}`);
|
|
4366
4283
|
}
|
|
@@ -4386,7 +4303,7 @@ __export(exports_newsletter, {
|
|
|
4386
4303
|
newsletterDraftCommand: () => newsletterDraftCommand,
|
|
4387
4304
|
newsletterDeleteCommand: () => newsletterDeleteCommand
|
|
4388
4305
|
});
|
|
4389
|
-
import { existsSync as
|
|
4306
|
+
import { existsSync as existsSync4, readFileSync as readFileSync4 } from "node:fs";
|
|
4390
4307
|
function buildBody2(options, { requireContent }) {
|
|
4391
4308
|
const body = {};
|
|
4392
4309
|
if (options.contentFile !== undefined) {
|
|
@@ -4406,10 +4323,10 @@ function buildBody2(options, { requireContent }) {
|
|
|
4406
4323
|
return body;
|
|
4407
4324
|
}
|
|
4408
4325
|
function readContentFile(filePath) {
|
|
4409
|
-
if (!
|
|
4326
|
+
if (!existsSync4(filePath)) {
|
|
4410
4327
|
throw new CliError2("file_not_found", `Content file not found: ${filePath}`);
|
|
4411
4328
|
}
|
|
4412
|
-
const text =
|
|
4329
|
+
const text = readFileSync4(filePath, "utf-8");
|
|
4413
4330
|
try {
|
|
4414
4331
|
return JSON.parse(text);
|
|
4415
4332
|
} catch (error) {
|
|
@@ -5044,7 +4961,7 @@ var init_format2 = __esm(() => {
|
|
|
5044
4961
|
});
|
|
5045
4962
|
|
|
5046
4963
|
// src/cli.ts
|
|
5047
|
-
import { existsSync as
|
|
4964
|
+
import { existsSync as existsSync5, readFileSync as readFileSync5 } from "fs";
|
|
5048
4965
|
import path2 from "path";
|
|
5049
4966
|
|
|
5050
4967
|
// ../../node_modules/commander/lib/error.js
|
|
@@ -7372,27 +7289,11 @@ function addAdminCommands(program2) {
|
|
|
7372
7289
|
adminMixtapes.action(() => {
|
|
7373
7290
|
adminMixtapes.outputHelp();
|
|
7374
7291
|
});
|
|
7375
|
-
adminMixtapes.command("create").description("Log a new mixtape draft").option("--duration-ms <duration>", "Duration (mm:ss, h:mm:ss, or ms)").option("--json", "Print JSON", false).option("--note <text>", "Operator note").option("--recorded-at <date>", "Recorded date (ISO)").option("--soundcloud-url <url>", "SoundCloud URL (manual; YouTube + Mixcloud come from distribute)").allowExcessArguments().action(async (options) => {
|
|
7376
|
-
const { mixtapeCreateCommand: mixtapeCreateCommand2 } = await Promise.resolve().then(() => (init_mixtapes(), exports_mixtapes));
|
|
7377
|
-
await runMixtapeCreate(options, mixtapeCreateCommand2);
|
|
7378
|
-
});
|
|
7379
7292
|
adminMixtapes.command("update").description("Update a mixtape's fields").argument("[id]").option("--duration-ms <duration>", "Duration (mm:ss, h:mm:ss, or ms)").option("--json", "Print JSON", false).option("--note <text>", "Operator note").option("--recorded-at <date>", "Recorded date (ISO)").option("--soundcloud-url <url>", "SoundCloud URL (manual; YouTube + Mixcloud come from distribute)").allowExcessArguments().action(async (id, options) => {
|
|
7380
7293
|
const { mixtapeUpdateCommand: mixtapeUpdateCommand2 } = await Promise.resolve().then(() => (init_mixtapes(), exports_mixtapes));
|
|
7381
7294
|
await runMixtapeUpdate(id, options, mixtapeUpdateCommand2);
|
|
7382
7295
|
});
|
|
7383
|
-
adminMixtapes.command("
|
|
7384
|
-
const { mixtapeMembersCommand: mixtapeMembersCommand2 } = await Promise.resolve().then(() => (init_mixtapes(), exports_mixtapes));
|
|
7385
|
-
await runMixtapeMembers(id, refs, options, mixtapeMembersCommand2);
|
|
7386
|
-
});
|
|
7387
|
-
adminMixtapes.command("publish").description("Publish a mixtape draft").argument("[id]").option("--json", "Print JSON", false).allowExcessArguments().action(async (id, options) => {
|
|
7388
|
-
const { mixtapePublishCommand: mixtapePublishCommand2 } = await Promise.resolve().then(() => (init_mixtapes(), exports_mixtapes));
|
|
7389
|
-
await runMixtapePublish(id, options, mixtapePublishCommand2);
|
|
7390
|
-
});
|
|
7391
|
-
adminMixtapes.command("delete").description("Discard a mixtape draft (published mixtapes can't be deleted)").argument("[id]").option("--json", "Print JSON", false).option("--yes", "Skip confirmation", false).allowExcessArguments().action(async (id, options) => {
|
|
7392
|
-
const { mixtapeDeleteCommand: mixtapeDeleteCommand2 } = await Promise.resolve().then(() => (init_mixtapes(), exports_mixtapes));
|
|
7393
|
-
await runMixtapeDelete(id, options, mixtapeDeleteCommand2);
|
|
7394
|
-
});
|
|
7395
|
-
adminMixtapes.command("list").description("List all mixtapes (including drafts)").option("--json", "Print JSON", false).allowExcessArguments().action(async (options) => {
|
|
7296
|
+
adminMixtapes.command("list").description("List all mixtapes (including distributing)").option("--json", "Print JSON", false).allowExcessArguments().action(async (options) => {
|
|
7396
7297
|
const { mixtapeListCommand: mixtapeListCommand2 } = await Promise.resolve().then(() => (init_mixtapes(), exports_mixtapes));
|
|
7397
7298
|
await runMixtapeList(options, mixtapeListCommand2);
|
|
7398
7299
|
});
|
|
@@ -7559,7 +7460,7 @@ async function runTrackPreviewArchive(idOrLogId, options, previewArchiveUploadCo
|
|
|
7559
7460
|
console.log(` mime: ${result.mime}`);
|
|
7560
7461
|
}
|
|
7561
7462
|
async function runTrackObserve(idOrLogId, options, trackObserveCommand2) {
|
|
7562
|
-
const script = options.scriptFile ?
|
|
7463
|
+
const script = options.scriptFile ? readFileSync5(options.scriptFile, "utf8") : options.script;
|
|
7563
7464
|
if (!idOrLogId || !script || !script.trim()) {
|
|
7564
7465
|
throw new Error("Usage: fluncle admin tracks observe <track_id|log_id> (--script <text> | --script-file <file>) [--voice-id <id>] [--duration-ms <ms>] [--context-note <text>] [--json]");
|
|
7565
7466
|
}
|
|
@@ -7615,7 +7516,7 @@ async function runTrackContext(idOrLogId, options, trackContextCommand2) {
|
|
|
7615
7516
|
}
|
|
7616
7517
|
}
|
|
7617
7518
|
async function runTrackNote(idOrLogId, options, trackNoteCommand2) {
|
|
7618
|
-
const note = options.scriptFile ?
|
|
7519
|
+
const note = options.scriptFile ? readFileSync5(options.scriptFile, "utf8") : options.script;
|
|
7619
7520
|
if (!idOrLogId || !note || !note.trim()) {
|
|
7620
7521
|
throw new Error("Usage: fluncle admin tracks note <track_id|log_id> (--script <text> | --script-file <file>) [--json]");
|
|
7621
7522
|
}
|
|
@@ -7761,7 +7662,7 @@ async function runTrackVideo(idOrLogId, options, trackVideoCommand2) {
|
|
|
7761
7662
|
return;
|
|
7762
7663
|
}
|
|
7763
7664
|
const candidate = path2.join(dir, name);
|
|
7764
|
-
return
|
|
7665
|
+
return existsSync5(candidate) ? candidate : undefined;
|
|
7765
7666
|
};
|
|
7766
7667
|
const resolveFile = (explicit, name) => {
|
|
7767
7668
|
if (explicit) {
|
|
@@ -7938,14 +7839,6 @@ async function runTrackPurgeVideo(idOrLogId, options, trackPurgeVideoCommand2) {
|
|
|
7938
7839
|
}
|
|
7939
7840
|
console.log(result.noVideo ? `${result.logId} has no video \u2014 nothing to purge.` : `Purging the stale renditions for ${result.logId} from the edge. The next play picks up the fresh render.`);
|
|
7940
7841
|
}
|
|
7941
|
-
async function runMixtapeCreate(options, mixtapeCreateCommand2) {
|
|
7942
|
-
const result = await mixtapeCreateCommand2(options);
|
|
7943
|
-
if (options.json) {
|
|
7944
|
-
printJson(result);
|
|
7945
|
-
return;
|
|
7946
|
-
}
|
|
7947
|
-
console.log(`Logged draft ${result.mixtape.id}. It stays a draft until you publish it.`);
|
|
7948
|
-
}
|
|
7949
7842
|
async function runMixtapeUpdate(id, options, mixtapeUpdateCommand2) {
|
|
7950
7843
|
if (!id) {
|
|
7951
7844
|
throw new Error("Missing mixtape id. Usage: fluncle admin mixtapes update <id>");
|
|
@@ -7957,31 +7850,6 @@ async function runMixtapeUpdate(id, options, mixtapeUpdateCommand2) {
|
|
|
7957
7850
|
}
|
|
7958
7851
|
console.log(`Saved ${result.mixtape.id}.`);
|
|
7959
7852
|
}
|
|
7960
|
-
async function runMixtapeMembers(id, refs, options, mixtapeMembersCommand2) {
|
|
7961
|
-
if (!id) {
|
|
7962
|
-
throw new Error("Missing mixtape id. Usage: fluncle admin mixtapes members <id> [refs...]");
|
|
7963
|
-
}
|
|
7964
|
-
if (refs.length === 0 && !options.from) {
|
|
7965
|
-
throw new Error("Provide refs as arguments or a cue-sheet file with --from");
|
|
7966
|
-
}
|
|
7967
|
-
const result = await mixtapeMembersCommand2(id, refs, options);
|
|
7968
|
-
if (options.json) {
|
|
7969
|
-
printJson(result);
|
|
7970
|
-
return;
|
|
7971
|
-
}
|
|
7972
|
-
console.log(`Saved the tracklist: ${result.mixtape.memberCount} bangers on ${result.mixtape.id}.`);
|
|
7973
|
-
}
|
|
7974
|
-
async function runMixtapePublish(id, options, mixtapePublishCommand2) {
|
|
7975
|
-
if (!id) {
|
|
7976
|
-
throw new Error("Missing mixtape id. Usage: fluncle admin mixtapes publish <id>");
|
|
7977
|
-
}
|
|
7978
|
-
const result = await mixtapePublishCommand2(id);
|
|
7979
|
-
if (options.json) {
|
|
7980
|
-
printJson(result);
|
|
7981
|
-
return;
|
|
7982
|
-
}
|
|
7983
|
-
console.log(`Minted ${result.mixtape.logId} (fluncle://${result.mixtape.logId}) \u2014 distributing. ` + "Run `distribute` to push it to the platforms.");
|
|
7984
|
-
}
|
|
7985
7853
|
async function runMixtapeDistribute(idOrLogId, options, mixtapeDistributeCommand2) {
|
|
7986
7854
|
if (!idOrLogId) {
|
|
7987
7855
|
throw new Error("Missing mixtape id. Usage: fluncle admin mixtapes distribute <idOrLogId> --video <mp4> --audio <file>");
|
|
@@ -8023,20 +7891,6 @@ async function runMixtapeResync(idOrLogId, options, mixtapeResyncCommand2) {
|
|
|
8023
7891
|
console.log(`Re-synced ${result.logId} (fluncle://${result.logId}).
|
|
8024
7892
|
${links}`);
|
|
8025
7893
|
}
|
|
8026
|
-
async function runMixtapeDelete(id, options, mixtapeDeleteCommand2) {
|
|
8027
|
-
if (!id) {
|
|
8028
|
-
throw new Error("Missing mixtape id. Usage: fluncle admin mixtapes delete <id> --yes");
|
|
8029
|
-
}
|
|
8030
|
-
if (!options.yes) {
|
|
8031
|
-
throw new Error("Pass --yes to confirm the discard. Published mixtapes can't be deleted.");
|
|
8032
|
-
}
|
|
8033
|
-
await mixtapeDeleteCommand2(id);
|
|
8034
|
-
if (options.json) {
|
|
8035
|
-
printJson({ id, ok: true });
|
|
8036
|
-
return;
|
|
8037
|
-
}
|
|
8038
|
-
console.log(`Discarded draft ${id}.`);
|
|
8039
|
-
}
|
|
8040
7894
|
async function runMixtapeList(options, mixtapeListCommand2) {
|
|
8041
7895
|
const mixtapes = await mixtapeListCommand2();
|
|
8042
7896
|
if (options.json) {
|
|
@@ -8048,8 +7902,8 @@ async function runMixtapeList(options, mixtapeListCommand2) {
|
|
|
8048
7902
|
return;
|
|
8049
7903
|
}
|
|
8050
7904
|
for (const mixtape of mixtapes) {
|
|
8051
|
-
const status = mixtape.status ?? "
|
|
8052
|
-
const coordinate3 = mixtape.logId ?? "
|
|
7905
|
+
const status = mixtape.status ?? "distributing";
|
|
7906
|
+
const coordinate3 = mixtape.logId ?? "unminted";
|
|
8053
7907
|
console.log(`${coordinate3} ${status} ${mixtape.memberCount} bangers ${mixtape.title}`);
|
|
8054
7908
|
}
|
|
8055
7909
|
}
|
|
@@ -8092,8 +7946,8 @@ async function runMixtapeGet(idOrLogId, options, mixtapeGetCommand2) {
|
|
|
8092
7946
|
printJson(mixtape);
|
|
8093
7947
|
return;
|
|
8094
7948
|
}
|
|
8095
|
-
const coordinate3 = mixtape.logId ?? "
|
|
8096
|
-
const status = mixtape.status ?? "
|
|
7949
|
+
const coordinate3 = mixtape.logId ?? "unminted";
|
|
7950
|
+
const status = mixtape.status ?? "distributing";
|
|
8097
7951
|
console.log(`${mixtape.title}`);
|
|
8098
7952
|
console.log(` ${coordinate3} \xB7 ${status} \xB7 ${mixtape.memberCount} bangers`);
|
|
8099
7953
|
if (mixtape.note) {
|
package/package.json
CHANGED