fluncle 0.185.0 → 0.187.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 +260 -169
- 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.187.0".trim() ? "0.187.0".trim() : "0.1.0";
|
|
565
565
|
});
|
|
566
566
|
|
|
567
567
|
// src/update-notifier.ts
|
|
@@ -965,7 +965,7 @@ async function fetchRecentPage(cursor, limit = 10) {
|
|
|
965
965
|
if (cursor) {
|
|
966
966
|
params.set("cursor", cursor);
|
|
967
967
|
}
|
|
968
|
-
const response = await publicApiGet(`/api/
|
|
968
|
+
const response = await publicApiGet(`/api/v1/findings?${params.toString()}`);
|
|
969
969
|
return {
|
|
970
970
|
nextCursor: response.nextCursor,
|
|
971
971
|
totalCount: response.totalCount,
|
|
@@ -980,7 +980,7 @@ async function recentCommand(limit) {
|
|
|
980
980
|
if (cursor) {
|
|
981
981
|
params.set("cursor", cursor);
|
|
982
982
|
}
|
|
983
|
-
const response = await publicApiGet(`/api/
|
|
983
|
+
const response = await publicApiGet(`/api/v1/findings?${params.toString()}`);
|
|
984
984
|
for (const apiTrack of response.tracks) {
|
|
985
985
|
results.push(mapTrack(apiTrack));
|
|
986
986
|
if (results.length >= limit) {
|
|
@@ -1287,7 +1287,7 @@ async function galaxyGetCommand(slug) {
|
|
|
1287
1287
|
return { findings: response.findings, galaxy: response.galaxy };
|
|
1288
1288
|
}
|
|
1289
1289
|
async function galaxyMapReadCommand() {
|
|
1290
|
-
const response = await adminApiGet("/api/admin/galaxies");
|
|
1290
|
+
const response = await adminApiGet("/api/v1/admin/galaxies");
|
|
1291
1291
|
return response.galaxies;
|
|
1292
1292
|
}
|
|
1293
1293
|
async function galaxyEmbeddingsCommand(options) {
|
|
@@ -1299,10 +1299,10 @@ async function galaxyEmbeddingsCommand(options) {
|
|
|
1299
1299
|
params.set("limit", options.limit);
|
|
1300
1300
|
}
|
|
1301
1301
|
const query = params.toString();
|
|
1302
|
-
return adminApiGet(`/api/admin/tracks/embeddings${query ? `?${query}` : ""}`);
|
|
1302
|
+
return adminApiGet(`/api/v1/admin/tracks/embeddings${query ? `?${query}` : ""}`);
|
|
1303
1303
|
}
|
|
1304
1304
|
async function galaxyMapWriteCommand(clusters) {
|
|
1305
|
-
const response = await adminApiPut("/api/admin/galaxies/map", {
|
|
1305
|
+
const response = await adminApiPut("/api/v1/admin/galaxies/map", {
|
|
1306
1306
|
clusters
|
|
1307
1307
|
});
|
|
1308
1308
|
return response.galaxies;
|
|
@@ -1313,7 +1313,7 @@ var init_galaxies = __esm(() => {
|
|
|
1313
1313
|
|
|
1314
1314
|
// src/commands/mixtape-api.ts
|
|
1315
1315
|
async function mixtapeListCommand() {
|
|
1316
|
-
const response = await adminApiGet("/api/admin/mixtapes");
|
|
1316
|
+
const response = await adminApiGet("/api/v1/admin/mixtapes");
|
|
1317
1317
|
return response.mixtapes;
|
|
1318
1318
|
}
|
|
1319
1319
|
async function mixtapeGetCommand(idOrLogId) {
|
|
@@ -1380,20 +1380,20 @@ async function distributeYoutube(mixtapeId, videoPath, onProgress) {
|
|
|
1380
1380
|
offset = 0;
|
|
1381
1381
|
}
|
|
1382
1382
|
onProgress?.("Recording the YouTube link");
|
|
1383
|
-
await adminApiPost(`/api/admin/mixtapes/${encodeURIComponent(mixtapeId)}/youtube/finalize`, { videoId });
|
|
1383
|
+
await adminApiPost(`/api/v1/admin/mixtapes/${encodeURIComponent(mixtapeId)}/youtube/finalize`, { videoId });
|
|
1384
1384
|
return { url: `https://youtu.be/${videoId}`, videoId };
|
|
1385
1385
|
}
|
|
1386
1386
|
async function publishYoutubeCommand(idOrLogId) {
|
|
1387
1387
|
const mixtapeId = await resolveMixtapeId(idOrLogId);
|
|
1388
|
-
const response = await adminApiPost(`/api/admin/mixtapes/${encodeURIComponent(mixtapeId)}/youtube/publish`);
|
|
1388
|
+
const response = await adminApiPost(`/api/v1/admin/mixtapes/${encodeURIComponent(mixtapeId)}/youtube/publish`);
|
|
1389
1389
|
return { url: response.url };
|
|
1390
1390
|
}
|
|
1391
1391
|
async function resyncYoutube(mixtapeId) {
|
|
1392
|
-
const response = await adminApiPost(`/api/admin/mixtapes/${encodeURIComponent(mixtapeId)}/youtube/resync`);
|
|
1392
|
+
const response = await adminApiPost(`/api/v1/admin/mixtapes/${encodeURIComponent(mixtapeId)}/youtube/resync`);
|
|
1393
1393
|
return { url: response.url, videoId: response.videoId };
|
|
1394
1394
|
}
|
|
1395
1395
|
async function authYoutubeCommand() {
|
|
1396
|
-
const response = await adminApiGet("/api/admin/youtube/auth/start");
|
|
1396
|
+
const response = await adminApiGet("/api/v1/admin/youtube/auth/start");
|
|
1397
1397
|
console.log(`Open this YouTube authorization URL:
|
|
1398
1398
|
|
|
1399
1399
|
${response.authUrl}
|
|
@@ -1401,11 +1401,11 @@ ${response.authUrl}
|
|
|
1401
1401
|
After approving access, Google returns to the Fluncle admin callback and stores the refresh token server-side.`);
|
|
1402
1402
|
}
|
|
1403
1403
|
async function initiate(mixtapeId, contentLength, contentType) {
|
|
1404
|
-
const response = await adminApiPost(`/api/admin/mixtapes/${encodeURIComponent(mixtapeId)}/youtube/initiate`, { contentLength, contentType });
|
|
1404
|
+
const response = await adminApiPost(`/api/v1/admin/mixtapes/${encodeURIComponent(mixtapeId)}/youtube/initiate`, { contentLength, contentType });
|
|
1405
1405
|
return { accessToken: response.accessToken, sessionUri: response.sessionUri };
|
|
1406
1406
|
}
|
|
1407
1407
|
async function mintToken() {
|
|
1408
|
-
const response = await adminApiPost("/api/admin/youtube/token");
|
|
1408
|
+
const response = await adminApiPost("/api/v1/admin/youtube/token");
|
|
1409
1409
|
return response.accessToken;
|
|
1410
1410
|
}
|
|
1411
1411
|
async function putChunk(args) {
|
|
@@ -1465,7 +1465,7 @@ function nextOffset(rangeHeader, fallback) {
|
|
|
1465
1465
|
return Number(match[1]) + 1;
|
|
1466
1466
|
}
|
|
1467
1467
|
async function resolveMixtapeId(idOrLogId) {
|
|
1468
|
-
const response = await adminApiGet("/api/admin/mixtapes");
|
|
1468
|
+
const response = await adminApiGet("/api/v1/admin/mixtapes");
|
|
1469
1469
|
const match = response.mixtapes.find((mixtape) => mixtape.id === idOrLogId || mixtape.logId === idOrLogId);
|
|
1470
1470
|
if (!match?.id) {
|
|
1471
1471
|
throw new CliError2("mixtape_not_found", `No mixtape with id or Log ID ${idOrLogId}`);
|
|
@@ -1553,18 +1553,18 @@ async function distributeMixcloud(mixtapeId, audioPath, onProgress, unlisted = f
|
|
|
1553
1553
|
const externalId = result.key;
|
|
1554
1554
|
const url = `https://www.mixcloud.com${result.key}`;
|
|
1555
1555
|
onProgress?.("Mixcloud: recording the link…");
|
|
1556
|
-
await adminApiPost(`/api/admin/mixtapes/${encodeURIComponent(mixtapeId)}/mixcloud/finalize`, {
|
|
1556
|
+
await adminApiPost(`/api/v1/admin/mixtapes/${encodeURIComponent(mixtapeId)}/mixcloud/finalize`, {
|
|
1557
1557
|
externalId,
|
|
1558
1558
|
url
|
|
1559
1559
|
});
|
|
1560
1560
|
return { url };
|
|
1561
1561
|
}
|
|
1562
1562
|
async function resyncMixcloud(mixtapeId) {
|
|
1563
|
-
const response = await adminApiPost(`/api/admin/mixtapes/${encodeURIComponent(mixtapeId)}/mixcloud/resync`);
|
|
1563
|
+
const response = await adminApiPost(`/api/v1/admin/mixtapes/${encodeURIComponent(mixtapeId)}/mixcloud/resync`);
|
|
1564
1564
|
return { url: response.url };
|
|
1565
1565
|
}
|
|
1566
1566
|
async function authMixcloudCommand() {
|
|
1567
|
-
const response = await adminApiGet("/api/admin/mixcloud/auth/start");
|
|
1567
|
+
const response = await adminApiGet("/api/v1/admin/mixcloud/auth/start");
|
|
1568
1568
|
console.log(`Open this Mixcloud authorization URL:
|
|
1569
1569
|
|
|
1570
1570
|
${response.authUrl}
|
|
@@ -1591,7 +1591,7 @@ function mixtapeTags(_mixtape) {
|
|
|
1591
1591
|
}
|
|
1592
1592
|
async function fetchMixcloudToken() {
|
|
1593
1593
|
try {
|
|
1594
|
-
const response = await adminApiPost("/api/admin/mixcloud/token");
|
|
1594
|
+
const response = await adminApiPost("/api/v1/admin/mixcloud/token");
|
|
1595
1595
|
return response.accessToken;
|
|
1596
1596
|
} catch {
|
|
1597
1597
|
throw new CliError2("mixcloud_not_connected", "Mixcloud is not connected. Run `fluncle admin auth mixcloud` to authorize it.");
|
|
@@ -1648,11 +1648,11 @@ __export(exports_mixtapes, {
|
|
|
1648
1648
|
mixtapeDistributeCommand: () => mixtapeDistributeCommand
|
|
1649
1649
|
});
|
|
1650
1650
|
async function mixtapesCommand() {
|
|
1651
|
-
const response = await publicApiGet("/api/mixtapes");
|
|
1651
|
+
const response = await publicApiGet("/api/v1/mixtapes");
|
|
1652
1652
|
return response.mixtapes;
|
|
1653
1653
|
}
|
|
1654
1654
|
async function mixtapeUpdateCommand(id, options) {
|
|
1655
|
-
return adminApiPatch(`/api/admin/mixtapes/${encodeURIComponent(id)}`, buildBody(options));
|
|
1655
|
+
return adminApiPatch(`/api/v1/admin/mixtapes/${encodeURIComponent(id)}`, buildBody(options));
|
|
1656
1656
|
}
|
|
1657
1657
|
async function mixtapeDistributeCommand(idOrLogId, options, onProgress = () => {}) {
|
|
1658
1658
|
const mixtape = await mixtapeGetCommand(idOrLogId);
|
|
@@ -1723,7 +1723,7 @@ async function mixtapeResyncCommand(idOrLogId, options, onProgress = () => {}) {
|
|
|
1723
1723
|
let doYoutube = Boolean(options.youtube);
|
|
1724
1724
|
let doMixcloud = Boolean(options.mixcloud);
|
|
1725
1725
|
if (!explicit) {
|
|
1726
|
-
const social = await adminApiGet(`/api/admin/mixtapes/${encodeURIComponent(mixtapeId)}/social`);
|
|
1726
|
+
const social = await adminApiGet(`/api/v1/admin/mixtapes/${encodeURIComponent(mixtapeId)}/social`);
|
|
1727
1727
|
const platforms = new Set(social.posts.map((post) => post.platform));
|
|
1728
1728
|
doYoutube = platforms.has("youtube");
|
|
1729
1729
|
doMixcloud = platforms.has("mixcloud");
|
|
@@ -1942,7 +1942,7 @@ async function recentCommand2(limit) {
|
|
|
1942
1942
|
if (cursor) {
|
|
1943
1943
|
params.set("cursor", cursor);
|
|
1944
1944
|
}
|
|
1945
|
-
const response = await publicApiGet(`/api/
|
|
1945
|
+
const response = await publicApiGet(`/api/v1/findings?${params.toString()}`);
|
|
1946
1946
|
for (const apiTrack of response.tracks) {
|
|
1947
1947
|
results.push(mapTrack2(apiTrack));
|
|
1948
1948
|
if (results.length >= limit) {
|
|
@@ -2031,7 +2031,7 @@ __export(exports_random, {
|
|
|
2031
2031
|
randomCommand: () => randomCommand
|
|
2032
2032
|
});
|
|
2033
2033
|
async function randomCommand() {
|
|
2034
|
-
const response = await publicApiGet("/api/tracks/random");
|
|
2034
|
+
const response = await publicApiGet("/api/v1/tracks/random");
|
|
2035
2035
|
return response.track;
|
|
2036
2036
|
}
|
|
2037
2037
|
var init_random = __esm(() => {
|
|
@@ -2048,7 +2048,7 @@ async function subscribeCommand(email, json) {
|
|
|
2048
2048
|
if (!address) {
|
|
2049
2049
|
throw new CliError2("invalid_email", "Enter a valid email address.");
|
|
2050
2050
|
}
|
|
2051
|
-
await publicApiPost("/api/newsletter", {
|
|
2051
|
+
await publicApiPost("/api/v1/newsletter", {
|
|
2052
2052
|
email: address
|
|
2053
2053
|
});
|
|
2054
2054
|
if (json) {
|
|
@@ -2076,7 +2076,7 @@ async function submitCommand(input) {
|
|
|
2076
2076
|
if (!query) {
|
|
2077
2077
|
throw new CliError2("missing_query", "Missing search input");
|
|
2078
2078
|
}
|
|
2079
|
-
const response = await publicApiGet(`/api/search?q=${encodeURIComponent(query)}`);
|
|
2079
|
+
const response = await publicApiGet(`/api/v1/search?q=${encodeURIComponent(query)}`);
|
|
2080
2080
|
if (response.results.length === 0) {
|
|
2081
2081
|
throw new CliError2("no_results", "No Spotify tracks found.");
|
|
2082
2082
|
}
|
|
@@ -2086,7 +2086,7 @@ async function submitCommand(input) {
|
|
|
2086
2086
|
}
|
|
2087
2087
|
const note = await promptLine("Note (optional): ", PROMPT_NON_INTERACTIVE_MESSAGE2);
|
|
2088
2088
|
const contact = await promptLine("Contact (optional): ", PROMPT_NON_INTERACTIVE_MESSAGE2);
|
|
2089
|
-
await publicApiPost("/api/submissions", {
|
|
2089
|
+
await publicApiPost("/api/v1/submissions", {
|
|
2090
2090
|
album: selected.album,
|
|
2091
2091
|
artists: selected.artists,
|
|
2092
2092
|
artworkUrl: selected.artworkUrl,
|
|
@@ -2229,7 +2229,7 @@ async function pollForToken(baseUrl, device) {
|
|
|
2229
2229
|
throw new CliError2("expired_token", "The login request timed out. Run `fluncle login` again.");
|
|
2230
2230
|
}
|
|
2231
2231
|
async function fetchSessionUser(baseUrl, token) {
|
|
2232
|
-
const response = await fetch(`${baseUrl}/api/me`, {
|
|
2232
|
+
const response = await fetch(`${baseUrl}/api/v1/me`, {
|
|
2233
2233
|
headers: { Authorization: `Bearer ${token}` }
|
|
2234
2234
|
});
|
|
2235
2235
|
if (!response.ok) {
|
|
@@ -2264,8 +2264,8 @@ __export(exports_me, {
|
|
|
2264
2264
|
});
|
|
2265
2265
|
async function meCommand() {
|
|
2266
2266
|
const [me, progress] = await Promise.all([
|
|
2267
|
-
userApiGet("/api/me"),
|
|
2268
|
-
userApiGet("/api/me/galaxy-progress")
|
|
2267
|
+
userApiGet("/api/v1/me"),
|
|
2268
|
+
userApiGet("/api/v1/me/galaxy-progress")
|
|
2269
2269
|
]);
|
|
2270
2270
|
if (!me.user) {
|
|
2271
2271
|
throw new Error("Your sign-in expired. Run `fluncle login` to link this device again.");
|
|
@@ -2442,7 +2442,7 @@ function parseVersion2(version) {
|
|
|
2442
2442
|
var currentVersion2, latestReleaseUrl = "https://api.github.com/repos/mauricekleine/fluncle/releases/latest";
|
|
2443
2443
|
var init_version2 = __esm(() => {
|
|
2444
2444
|
init_output();
|
|
2445
|
-
currentVersion2 = "0.
|
|
2445
|
+
currentVersion2 = "0.187.0".trim() ? "0.187.0".trim() : "0.1.0";
|
|
2446
2446
|
});
|
|
2447
2447
|
|
|
2448
2448
|
// ../../packages/registry/src/index.ts
|
|
@@ -2761,7 +2761,22 @@ var init_src = __esm(() => {
|
|
|
2761
2761
|
{
|
|
2762
2762
|
apiFormat: "application/json",
|
|
2763
2763
|
discoveryUrl: `${SITE}/api/v1/openapi.json`,
|
|
2764
|
-
exposedContent: [
|
|
2764
|
+
exposedContent: [
|
|
2765
|
+
"the feed as JSON — findings and published mixtapes, newest found first, cursor-paginated (limit max 48, cursor)"
|
|
2766
|
+
],
|
|
2767
|
+
kind: "api",
|
|
2768
|
+
name: "api.findings",
|
|
2769
|
+
probeConfig: { cadenceMs: PROBE_CADENCE_MS, kind: "http", timeoutMs: PROBE_TIMEOUT_MS },
|
|
2770
|
+
route: "/api/v1/findings",
|
|
2771
|
+
url: `${SITE}/api/v1/findings`,
|
|
2772
|
+
weights: { status: "secondary", web: "primary" }
|
|
2773
|
+
},
|
|
2774
|
+
{
|
|
2775
|
+
apiFormat: "application/json",
|
|
2776
|
+
discoveryUrl: `${SITE}/api/v1/openapi.json`,
|
|
2777
|
+
exposedContent: [
|
|
2778
|
+
"every track Fluncle holds as JSON, newest release first, numbered pages (page); certified=true narrows to findings, certified=false to the rest, omitted returns both"
|
|
2779
|
+
],
|
|
2765
2780
|
kind: "api",
|
|
2766
2781
|
name: "api.tracks",
|
|
2767
2782
|
probeConfig: { cadenceMs: PROBE_CADENCE_MS, kind: "http", timeoutMs: PROBE_TIMEOUT_MS },
|
|
@@ -2940,8 +2955,8 @@ var init_src = __esm(() => {
|
|
|
2940
2955
|
name: "api.health",
|
|
2941
2956
|
operatorNotes: "Linked as the `status` relation from /.well-known/api-catalog. Service `web` on /status.",
|
|
2942
2957
|
probeConfig: { cadenceMs: PROBE_CADENCE_MS, kind: "http", timeoutMs: PROBE_TIMEOUT_MS },
|
|
2943
|
-
route: "/api/health",
|
|
2944
|
-
url: `${SITE}/api/health`,
|
|
2958
|
+
route: "/api/v1/health",
|
|
2959
|
+
url: `${SITE}/api/v1/health`,
|
|
2945
2960
|
weights: { status: "tertiary", web: "tertiary" }
|
|
2946
2961
|
},
|
|
2947
2962
|
{
|
|
@@ -3144,7 +3159,7 @@ var init_src = __esm(() => {
|
|
|
3144
3159
|
apiFormat: "application/json",
|
|
3145
3160
|
discoveryUrl: `${SITE}/.well-known/mcp/server-card.json`,
|
|
3146
3161
|
exposedContent: [
|
|
3147
|
-
"the archive as MCP tools (Streamable HTTP, no auth): list_tracks, list_fresh, get_track, get_random_track, get_status, search_archive, get_artist, get_label, build_set,
|
|
3162
|
+
"the archive as MCP tools (Streamable HTTP, no auth): list_findings, list_tracks, list_fresh, get_track, get_random_track, get_status, search_archive, get_artist, get_label, build_set, list_similar_artists, list_album_catalogue, list_artist_catalogue, list_label_catalogue, search_tracks, submit_track, subscribe_newsletter",
|
|
3148
3163
|
"the archive as MCP resources: each finding/mixtape at fluncle://finding/<logId> or fluncle://mixtape/<logId> (its public record)",
|
|
3149
3164
|
"Fluncle-voiced MCP prompts: recommend_finding, walk_recent_night, decode_coordinate"
|
|
3150
3165
|
],
|
|
@@ -3457,6 +3472,19 @@ var init_src = __esm(() => {
|
|
|
3457
3472
|
title: "Artist edges",
|
|
3458
3473
|
weights: { status: "hidden" }
|
|
3459
3474
|
},
|
|
3475
|
+
{
|
|
3476
|
+
command: "fluncle admin backfills artist-credits",
|
|
3477
|
+
exposedContent: [
|
|
3478
|
+
"mint identity-true artists from MusicBrainz credits for slice 0's zero-matched residual → track_artists edges"
|
|
3479
|
+
],
|
|
3480
|
+
kind: "cron",
|
|
3481
|
+
name: "cron.artist-credits",
|
|
3482
|
+
operatorNotes: "every 5m, run by a rave-02 HOST systemd timer (docs/agents/hermes/artist-credits-timer/). The MB CREDIT SWEEP (RFC artist-primary-capture, slice 1b): the sibling that completes what `backfill_artist_edges` (slice 0) could not. Slice 0's name-fold left a ~14.3k ZERO-MATCHED residual (a track it stamped but wrote no edge — no credited name folded to an existing identity), and those are exactly the tracks capture-authorization (slice 1) cannot reason about, since it matches BY IDENTITY through the `track_artists` graph. This sweep picks up that residual: for each zero-matched track carrying a MusicBrainz recording identity (`mb_recording_id`, or the `mb_<recording-mbid>` PK a crawler-born row carries), ONE paced `/recording/<mbid>?inc=artist-credits` lookup through the shared MusicBrainz client names its credited artists WITH their MB artist ids, and each resolves down a three-rung ladder: an EXACT `mbid` match, else an ADOPT (the credit name folds unambiguously onto an existing artist with no mbid — the common case, since the residual is dominated by compound credit strings like 'Sub Focus & Dimension' whose members Fluncle already holds as Spotify-keyed rows; adopting `coalesce`s the mbid onto that row instead of minting a duplicate, the split-identity guard), else a MINT of a fresh identity-true row (`mintArtistByMbid` — a real MBID is identity, the licence slice 0 lacked). Fail-closed on any ambiguity (a shared fold, or a fold whose row carries a different mbid) → mint, never a wrong merge. Then the `track_artists` edges are written. A zero-matched track with NO MB identity is TERMINALLY SKIPPED (stamped, never retried). METADATA / GRAPH IDENTITY ONLY — it certifies nothing and publishes nothing (agent tier, the `backfill_recording_mbids` precedent). Worker-paced (the box holds no MusicBrainz budget): a SMALL bounded batch per tick (each row is one ~1.1s MB call), 1 req/s, circuit-broken on a throttle, with a 60s response budget that pauses mid-page and resumes on the next request. The `tracks` row carries the durable per-row reliability state — its OWN `artist_credits_backfilled_at` stamp, DISTINCT from slice 0's `artist_edges_backfilled_at` (never disturbed). The ~14.3k residual drains at ~40/tick over ~a day and a half. Zero LLM tokens. Source: docs/agents/hermes/scripts/artist-credits-sweep.*. See docs/artist-relationship.md.",
|
|
3483
|
+
probeConfig: { cadenceMs: 5 * MINUTE_MS, cronName: "fluncle-artist-credits", kind: "cron" },
|
|
3484
|
+
statusDescription: "mints artists from MusicBrainz credits for the residual",
|
|
3485
|
+
title: "Artist credits",
|
|
3486
|
+
weights: { status: "hidden" }
|
|
3487
|
+
},
|
|
3460
3488
|
{
|
|
3461
3489
|
command: "fluncle admin backfills label-lineage",
|
|
3462
3490
|
exposedContent: [
|
|
@@ -3883,7 +3911,7 @@ __export(exports_status, {
|
|
|
3883
3911
|
statusCommand: () => statusCommand
|
|
3884
3912
|
});
|
|
3885
3913
|
async function statusCommand() {
|
|
3886
|
-
return publicApiGet("/api/status");
|
|
3914
|
+
return publicApiGet("/api/v1/status");
|
|
3887
3915
|
}
|
|
3888
3916
|
function ago(seconds) {
|
|
3889
3917
|
if (seconds < 60) {
|
|
@@ -3967,14 +3995,14 @@ __export(exports_track, {
|
|
|
3967
3995
|
checkBundleCompleteness: () => checkBundleCompleteness
|
|
3968
3996
|
});
|
|
3969
3997
|
async function trackGetCommand(idOrLogId) {
|
|
3970
|
-
return publicApiGet(`/api/tracks/${encodeURIComponent(idOrLogId)}`);
|
|
3998
|
+
return publicApiGet(`/api/v1/tracks/${encodeURIComponent(idOrLogId)}`);
|
|
3971
3999
|
}
|
|
3972
4000
|
async function trackSimilarCommand(idOrLogId, limit) {
|
|
3973
4001
|
const query = limit === undefined ? "" : `?limit=${encodeURIComponent(String(limit))}`;
|
|
3974
|
-
return publicApiGet(`/api/tracks/${encodeURIComponent(idOrLogId)}/similar${query}`);
|
|
4002
|
+
return publicApiGet(`/api/v1/tracks/${encodeURIComponent(idOrLogId)}/similar${query}`);
|
|
3975
4003
|
}
|
|
3976
4004
|
async function trackGetAdminCommand(idOrLogId) {
|
|
3977
|
-
return adminApiGet(`/api/admin/tracks/${encodeURIComponent(idOrLogId)}`);
|
|
4005
|
+
return adminApiGet(`/api/v1/admin/tracks/${encodeURIComponent(idOrLogId)}`);
|
|
3978
4006
|
}
|
|
3979
4007
|
function isPlatesOnlyUpload(files) {
|
|
3980
4008
|
const hasPlate = PLATE_FIELDS.some((option) => Boolean(files[option]));
|
|
@@ -4021,7 +4049,7 @@ async function trackVideoCommand(idOrLogId, files, onProgress, options = {}) {
|
|
|
4021
4049
|
throw new CliError2("nothing_to_upload", "No bundle files resolved to upload (pass --dir <bundle> or explicit file flags).");
|
|
4022
4050
|
}
|
|
4023
4051
|
const platesOnly = isPlatesOnlyUpload(files);
|
|
4024
|
-
const presign = await adminApiPost(`/api/admin/tracks/${encodeURIComponent(idOrLogId)}/video/uploads`, { fields: present.map((spec) => spec.field) });
|
|
4052
|
+
const presign = await adminApiPost(`/api/v1/admin/tracks/${encodeURIComponent(idOrLogId)}/video/uploads`, { fields: present.map((spec) => spec.field) });
|
|
4025
4053
|
const byField = new Map(presign.uploads.map((upload) => [upload.field, upload]));
|
|
4026
4054
|
const urls = {};
|
|
4027
4055
|
const STREAM_THRESHOLD_BYTES = 8 * 1024 * 1024;
|
|
@@ -4052,7 +4080,7 @@ async function trackVideoCommand(idOrLogId, files, onProgress, options = {}) {
|
|
|
4052
4080
|
const videoModel = files.model?.trim().slice(0, 120) || manifest.model || DEFAULT_VIDEO_MODEL;
|
|
4053
4081
|
const videoModelReasoning = files.reasoning?.trim().slice(0, 120) || manifest.reasoning || DEFAULT_VIDEO_REASONING;
|
|
4054
4082
|
const squared = Boolean(urls["footage"] && urls["footage-social"]);
|
|
4055
|
-
const finalize = await adminApiPost(`/api/admin/tracks/${encodeURIComponent(idOrLogId)}/video/finalize`, {
|
|
4083
|
+
const finalize = await adminApiPost(`/api/v1/admin/tracks/${encodeURIComponent(idOrLogId)}/video/finalize`, {
|
|
4056
4084
|
videoModel,
|
|
4057
4085
|
videoModelReasoning,
|
|
4058
4086
|
...squared ? { squared: true } : {},
|
|
@@ -4083,7 +4111,7 @@ async function readManifestFields(renderPath) {
|
|
|
4083
4111
|
return result;
|
|
4084
4112
|
}
|
|
4085
4113
|
async function trackDraftCommand(idOrLogId, platform2) {
|
|
4086
|
-
return adminApiPost(`/api/admin/tracks/${encodeURIComponent(idOrLogId)}/social/${platform2}/draft`);
|
|
4114
|
+
return adminApiPost(`/api/v1/admin/tracks/${encodeURIComponent(idOrLogId)}/social/${platform2}/draft`);
|
|
4087
4115
|
}
|
|
4088
4116
|
async function trackSocialUpdateCommand(idOrLogId, platform2, options) {
|
|
4089
4117
|
const body = { status: options.status };
|
|
@@ -4093,14 +4121,14 @@ async function trackSocialUpdateCommand(idOrLogId, platform2, options) {
|
|
|
4093
4121
|
if (options.scheduledFor !== undefined) {
|
|
4094
4122
|
body.scheduledFor = options.scheduledFor;
|
|
4095
4123
|
}
|
|
4096
|
-
return adminApiPatch(`/api/admin/tracks/${encodeURIComponent(idOrLogId)}/social/${platform2}`, body);
|
|
4124
|
+
return adminApiPatch(`/api/v1/admin/tracks/${encodeURIComponent(idOrLogId)}/social/${platform2}`, body);
|
|
4097
4125
|
}
|
|
4098
4126
|
async function trackSocialShowCommand(idOrLogId) {
|
|
4099
|
-
return adminApiGet(`/api/admin/tracks/${encodeURIComponent(idOrLogId)}/social`);
|
|
4127
|
+
return adminApiGet(`/api/v1/admin/tracks/${encodeURIComponent(idOrLogId)}/social`);
|
|
4100
4128
|
}
|
|
4101
4129
|
async function trackSocialCaptureCommand(limit) {
|
|
4102
4130
|
const body = limit === undefined ? {} : { limit: String(limit) };
|
|
4103
|
-
return adminApiPost(`/api/admin/social/posts/capture`, body);
|
|
4131
|
+
return adminApiPost(`/api/v1/admin/social/posts/capture`, body);
|
|
4104
4132
|
}
|
|
4105
4133
|
async function trackUpdateCommand(trackId, options) {
|
|
4106
4134
|
const body = {};
|
|
@@ -4146,13 +4174,13 @@ async function trackUpdateCommand(trackId, options) {
|
|
|
4146
4174
|
if (options.analyzedAt !== undefined) {
|
|
4147
4175
|
body.analyzedAt = options.analyzedAt;
|
|
4148
4176
|
}
|
|
4149
|
-
return adminApiPatch(`/api/admin/tracks/${encodeURIComponent(trackId)}`, body);
|
|
4177
|
+
return adminApiPatch(`/api/v1/admin/tracks/${encodeURIComponent(trackId)}`, body);
|
|
4150
4178
|
}
|
|
4151
4179
|
async function trackRequeueVideoCommand(idOrLogId) {
|
|
4152
|
-
return adminApiPost(`/api/admin/tracks/${encodeURIComponent(idOrLogId)}/video/requeue`);
|
|
4180
|
+
return adminApiPost(`/api/v1/admin/tracks/${encodeURIComponent(idOrLogId)}/video/requeue`);
|
|
4153
4181
|
}
|
|
4154
4182
|
async function trackPurgeVideoCommand(idOrLogId) {
|
|
4155
|
-
return adminApiPost(`/api/admin/tracks/${encodeURIComponent(idOrLogId)}/video/purge`);
|
|
4183
|
+
return adminApiPost(`/api/v1/admin/tracks/${encodeURIComponent(idOrLogId)}/video/purge`);
|
|
4156
4184
|
}
|
|
4157
4185
|
async function trackObserveCommand(idOrLogId, options) {
|
|
4158
4186
|
const body = { script: options.script };
|
|
@@ -4174,7 +4202,7 @@ async function trackObserveCommand(idOrLogId, options) {
|
|
|
4174
4202
|
if (options.force) {
|
|
4175
4203
|
body.force = true;
|
|
4176
4204
|
}
|
|
4177
|
-
return adminApiPost(`/api/admin/tracks/${encodeURIComponent(idOrLogId)}/observe`, body);
|
|
4205
|
+
return adminApiPost(`/api/v1/admin/tracks/${encodeURIComponent(idOrLogId)}/observe`, body);
|
|
4178
4206
|
}
|
|
4179
4207
|
async function trackContextCommand(idOrLogId, options = {}) {
|
|
4180
4208
|
const body = {};
|
|
@@ -4184,7 +4212,7 @@ async function trackContextCommand(idOrLogId, options = {}) {
|
|
|
4184
4212
|
if (options.refresh) {
|
|
4185
4213
|
body.refresh = true;
|
|
4186
4214
|
}
|
|
4187
|
-
return adminApiPost(`/api/admin/tracks/${encodeURIComponent(idOrLogId)}/context`, body);
|
|
4215
|
+
return adminApiPost(`/api/v1/admin/tracks/${encodeURIComponent(idOrLogId)}/context`, body);
|
|
4188
4216
|
}
|
|
4189
4217
|
async function trackNoteCommand(idOrLogId, options) {
|
|
4190
4218
|
const body = { note: options.note };
|
|
@@ -4194,7 +4222,7 @@ async function trackNoteCommand(idOrLogId, options) {
|
|
|
4194
4222
|
if (typeof options.promptVersion === "number") {
|
|
4195
4223
|
body.promptVersion = options.promptVersion;
|
|
4196
4224
|
}
|
|
4197
|
-
return adminApiPost(`/api/admin/tracks/${encodeURIComponent(idOrLogId)}/note`, body);
|
|
4225
|
+
return adminApiPost(`/api/v1/admin/tracks/${encodeURIComponent(idOrLogId)}/note`, body);
|
|
4198
4226
|
}
|
|
4199
4227
|
var DEFAULT_VIDEO_MODEL = "anthropic/claude-opus-4-8", DEFAULT_VIDEO_REASONING = "high", FOUND_BASE = "https://found.fluncle.com", VIDEO_FIELDS, RERENDER_CONTRACT_FIELDS, RERENDER_ADVISORY_FIELDS, FOOTAGE_FIELDS, PLATE_FIELDS, NON_FILE_OPTIONS, DIVERSITY_LEDGER_FIELDS;
|
|
4200
4228
|
var init_track = __esm(() => {
|
|
@@ -4247,7 +4275,7 @@ __export(exports_admin_attention, {
|
|
|
4247
4275
|
attentionQueueCommand: () => attentionQueueCommand
|
|
4248
4276
|
});
|
|
4249
4277
|
async function attentionQueueCommand() {
|
|
4250
|
-
const response = await adminApiGet("/api/admin/attention");
|
|
4278
|
+
const response = await adminApiGet("/api/v1/admin/attention");
|
|
4251
4279
|
return response.attention;
|
|
4252
4280
|
}
|
|
4253
4281
|
function attentionQueueLines(queue) {
|
|
@@ -4291,7 +4319,7 @@ __export(exports_add, {
|
|
|
4291
4319
|
addCommand: () => addCommand
|
|
4292
4320
|
});
|
|
4293
4321
|
async function addCommand(spotifyUrl, options) {
|
|
4294
|
-
const result = await adminApiPost("/api/admin/tracks", {
|
|
4322
|
+
const result = await adminApiPost("/api/v1/admin/tracks", {
|
|
4295
4323
|
dryRun: options.dryRun,
|
|
4296
4324
|
note: options.note,
|
|
4297
4325
|
spotifyUrl
|
|
@@ -4356,7 +4384,7 @@ async function trackUpdateCommand2(trackId, options) {
|
|
|
4356
4384
|
if (options.analyzedAt !== undefined) {
|
|
4357
4385
|
body.analyzedAt = options.analyzedAt;
|
|
4358
4386
|
}
|
|
4359
|
-
return adminApiPatch(`/api/admin/tracks/${encodeURIComponent(trackId)}`, body);
|
|
4387
|
+
return adminApiPatch(`/api/v1/admin/tracks/${encodeURIComponent(trackId)}`, body);
|
|
4360
4388
|
}
|
|
4361
4389
|
var init_track2 = __esm(() => {
|
|
4362
4390
|
init_api();
|
|
@@ -4382,6 +4410,7 @@ __export(exports_admin_tracks, {
|
|
|
4382
4410
|
backfillLastfmCommand: () => backfillLastfmCommand,
|
|
4383
4411
|
backfillDiscogsCommand: () => backfillDiscogsCommand,
|
|
4384
4412
|
backfillArtistEdgesCommand: () => backfillArtistEdgesCommand,
|
|
4413
|
+
backfillArtistCreditsCommand: () => backfillArtistCreditsCommand,
|
|
4385
4414
|
backfillAppleMusicCommand: () => backfillAppleMusicCommand,
|
|
4386
4415
|
backfillAppleCatalogueCommand: () => backfillAppleCatalogueCommand
|
|
4387
4416
|
});
|
|
@@ -4433,7 +4462,7 @@ async function fetchAdminTracks(options) {
|
|
|
4433
4462
|
if (cursor) {
|
|
4434
4463
|
params.set("cursor", cursor);
|
|
4435
4464
|
}
|
|
4436
|
-
const response = await adminApiGet(`/api/admin/tracks?${params.toString()}`);
|
|
4465
|
+
const response = await adminApiGet(`/api/v1/admin/tracks?${params.toString()}`);
|
|
4437
4466
|
for (const apiTrack of response.tracks) {
|
|
4438
4467
|
const track = mapTrack2(apiTrack);
|
|
4439
4468
|
if (track.type === "mixtape") {
|
|
@@ -4482,7 +4511,7 @@ async function trackWorkCommand(options) {
|
|
|
4482
4511
|
if (options.count) {
|
|
4483
4512
|
params.set("count", "true");
|
|
4484
4513
|
}
|
|
4485
|
-
const response = await adminApiGet(`/api/admin/tracks/work?${params.toString()}`);
|
|
4514
|
+
const response = await adminApiGet(`/api/v1/admin/tracks/work?${params.toString()}`);
|
|
4486
4515
|
return { queued: response.queued, tracks: response.tracks ?? [] };
|
|
4487
4516
|
}
|
|
4488
4517
|
async function requeueAnalysisCommand(options) {
|
|
@@ -4547,39 +4576,46 @@ async function backfillLastfmCommand(limit, dryRun, cursor) {
|
|
|
4547
4576
|
if (cursor) {
|
|
4548
4577
|
params.set("cursor", cursor);
|
|
4549
4578
|
}
|
|
4550
|
-
return adminApiPost(`/api/admin/backfill/lastfm?${params.toString()}`);
|
|
4579
|
+
return adminApiPost(`/api/v1/admin/backfill/lastfm?${params.toString()}`);
|
|
4551
4580
|
}
|
|
4552
4581
|
async function backfillDiscogsCommand(limit, dryRun, cursor) {
|
|
4553
4582
|
const params = new URLSearchParams({ dryRun: String(dryRun), limit: String(limit) });
|
|
4554
4583
|
if (cursor) {
|
|
4555
4584
|
params.set("cursor", cursor);
|
|
4556
4585
|
}
|
|
4557
|
-
return adminApiPost(`/api/admin/backfill/discogs?${params.toString()}`);
|
|
4586
|
+
return adminApiPost(`/api/v1/admin/backfill/discogs?${params.toString()}`);
|
|
4558
4587
|
}
|
|
4559
4588
|
async function backfillAppleMusicCommand(limit, dryRun, cursor) {
|
|
4560
4589
|
const params = new URLSearchParams({ dryRun: String(dryRun), limit: String(limit) });
|
|
4561
4590
|
if (cursor) {
|
|
4562
4591
|
params.set("cursor", cursor);
|
|
4563
4592
|
}
|
|
4564
|
-
return adminApiPost(`/api/admin/backfill/apple-music?${params.toString()}`);
|
|
4593
|
+
return adminApiPost(`/api/v1/admin/backfill/apple-music?${params.toString()}`);
|
|
4565
4594
|
}
|
|
4566
4595
|
async function backfillAppleCatalogueCommand(limit, dryRun) {
|
|
4567
4596
|
const params = new URLSearchParams({ dryRun: String(dryRun), limit: String(limit) });
|
|
4568
|
-
return adminApiPost(`/api/admin/backfill/apple-catalogue?${params.toString()}`);
|
|
4597
|
+
return adminApiPost(`/api/v1/admin/backfill/apple-catalogue?${params.toString()}`);
|
|
4569
4598
|
}
|
|
4570
4599
|
async function backfillRecordingMbidsCommand(limit, dryRun, cursor) {
|
|
4571
4600
|
const params = new URLSearchParams({ dryRun: String(dryRun), limit: String(limit) });
|
|
4572
4601
|
if (cursor) {
|
|
4573
4602
|
params.set("cursor", cursor);
|
|
4574
4603
|
}
|
|
4575
|
-
return adminApiPost(`/api/admin/backfill/recording-mbids?${params.toString()}`);
|
|
4604
|
+
return adminApiPost(`/api/v1/admin/backfill/recording-mbids?${params.toString()}`);
|
|
4576
4605
|
}
|
|
4577
4606
|
async function backfillArtistEdgesCommand(limit, dryRun, cursor) {
|
|
4578
4607
|
const params = new URLSearchParams({ dryRun: String(dryRun), limit: String(limit) });
|
|
4579
4608
|
if (cursor) {
|
|
4580
4609
|
params.set("cursor", cursor);
|
|
4581
4610
|
}
|
|
4582
|
-
return adminApiPost(`/api/admin/backfill/artist-edges?${params.toString()}`);
|
|
4611
|
+
return adminApiPost(`/api/v1/admin/backfill/artist-edges?${params.toString()}`);
|
|
4612
|
+
}
|
|
4613
|
+
async function backfillArtistCreditsCommand(limit, dryRun, cursor) {
|
|
4614
|
+
const params = new URLSearchParams({ dryRun: String(dryRun), limit: String(limit) });
|
|
4615
|
+
if (cursor) {
|
|
4616
|
+
params.set("cursor", cursor);
|
|
4617
|
+
}
|
|
4618
|
+
return adminApiPost(`/api/v1/admin/backfill/artist-credits?${params.toString()}`);
|
|
4583
4619
|
}
|
|
4584
4620
|
async function vehiclesCommand(limit) {
|
|
4585
4621
|
const tracks = await fetchAdminTracks({ hasVideo: true, max: limit, order: "desc" });
|
|
@@ -4599,7 +4635,7 @@ async function mixableOrderCommand(logIds, seed) {
|
|
|
4599
4635
|
if (seed) {
|
|
4600
4636
|
params.set("seed", seed);
|
|
4601
4637
|
}
|
|
4602
|
-
return adminApiGet(`/api/admin/tracks/mixable-order?${params.toString()}`);
|
|
4638
|
+
return adminApiGet(`/api/v1/admin/tracks/mixable-order?${params.toString()}`);
|
|
4603
4639
|
}
|
|
4604
4640
|
var pageSize3 = 48;
|
|
4605
4641
|
var init_admin_tracks = __esm(() => {
|
|
@@ -4620,7 +4656,7 @@ async function previewArchiveUploadCommand(idOrLogId, options) {
|
|
|
4620
4656
|
form.append("preview", Bun.file(options.file), basename(options.file));
|
|
4621
4657
|
form.append("source", options.source);
|
|
4622
4658
|
form.append("mime", options.mime);
|
|
4623
|
-
return adminApiPostForm(`/api/admin/tracks/${encodeURIComponent(idOrLogId)}/preview`, form);
|
|
4659
|
+
return adminApiPostForm(`/api/v1/admin/tracks/${encodeURIComponent(idOrLogId)}/preview`, form);
|
|
4624
4660
|
}
|
|
4625
4661
|
async function previewArchiveBackfillCommand(options) {
|
|
4626
4662
|
const result = {
|
|
@@ -4631,7 +4667,7 @@ async function previewArchiveBackfillCommand(options) {
|
|
|
4631
4667
|
};
|
|
4632
4668
|
let cursor;
|
|
4633
4669
|
while (result.archived.length < (options.limit ?? Number.POSITIVE_INFINITY)) {
|
|
4634
|
-
const page = await publicApiGet(`/api/
|
|
4670
|
+
const page = await publicApiGet(`/api/v1/findings?limit=48${cursor ? `&cursor=${encodeURIComponent(cursor)}` : ""}`);
|
|
4635
4671
|
for (const track of page.tracks) {
|
|
4636
4672
|
if (result.archived.length >= (options.limit ?? Number.POSITIVE_INFINITY)) {
|
|
4637
4673
|
break;
|
|
@@ -4643,7 +4679,7 @@ async function previewArchiveBackfillCommand(options) {
|
|
|
4643
4679
|
result.skipped.push({ reason: "no_log_id", trackId: track.trackId });
|
|
4644
4680
|
continue;
|
|
4645
4681
|
}
|
|
4646
|
-
const status = await adminApiGet(`/api/admin/tracks/${encodeURIComponent(track.trackId)}/preview`);
|
|
4682
|
+
const status = await adminApiGet(`/api/v1/admin/tracks/${encodeURIComponent(track.trackId)}/preview`);
|
|
4647
4683
|
if (status.archived) {
|
|
4648
4684
|
result.skipped.push({ reason: "already_archived", trackId: track.trackId });
|
|
4649
4685
|
continue;
|
|
@@ -4682,7 +4718,7 @@ async function uploadResolvedPreview(trackId, preview) {
|
|
|
4682
4718
|
form.append("preview", new Blob([preview.bytes], { type: preview.mime }), `preview.${extension}`);
|
|
4683
4719
|
form.append("source", preview.source);
|
|
4684
4720
|
form.append("mime", preview.mime);
|
|
4685
|
-
await adminApiPostForm(`/api/admin/tracks/${encodeURIComponent(trackId)}/preview`, form);
|
|
4721
|
+
await adminApiPostForm(`/api/v1/admin/tracks/${encodeURIComponent(trackId)}/preview`, form);
|
|
4686
4722
|
}
|
|
4687
4723
|
async function resolvePreview(track) {
|
|
4688
4724
|
const stored = await downloadPreview(track.previewUrl, "deezer:stored");
|
|
@@ -4862,20 +4898,20 @@ async function distributeYoutube2(mixtapeId, videoPath, onProgress) {
|
|
|
4862
4898
|
offset = 0;
|
|
4863
4899
|
}
|
|
4864
4900
|
onProgress?.("Recording the YouTube link");
|
|
4865
|
-
await adminApiPost(`/api/admin/mixtapes/${encodeURIComponent(mixtapeId)}/youtube/finalize`, { videoId });
|
|
4901
|
+
await adminApiPost(`/api/v1/admin/mixtapes/${encodeURIComponent(mixtapeId)}/youtube/finalize`, { videoId });
|
|
4866
4902
|
return { url: `https://youtu.be/${videoId}`, videoId };
|
|
4867
4903
|
}
|
|
4868
4904
|
async function publishYoutubeCommand2(idOrLogId) {
|
|
4869
4905
|
const mixtapeId = await resolveMixtapeId2(idOrLogId);
|
|
4870
|
-
const response = await adminApiPost(`/api/admin/mixtapes/${encodeURIComponent(mixtapeId)}/youtube/publish`);
|
|
4906
|
+
const response = await adminApiPost(`/api/v1/admin/mixtapes/${encodeURIComponent(mixtapeId)}/youtube/publish`);
|
|
4871
4907
|
return { url: response.url };
|
|
4872
4908
|
}
|
|
4873
4909
|
async function resyncYoutube2(mixtapeId) {
|
|
4874
|
-
const response = await adminApiPost(`/api/admin/mixtapes/${encodeURIComponent(mixtapeId)}/youtube/resync`);
|
|
4910
|
+
const response = await adminApiPost(`/api/v1/admin/mixtapes/${encodeURIComponent(mixtapeId)}/youtube/resync`);
|
|
4875
4911
|
return { url: response.url, videoId: response.videoId };
|
|
4876
4912
|
}
|
|
4877
4913
|
async function authYoutubeCommand2() {
|
|
4878
|
-
const response = await adminApiGet("/api/admin/youtube/auth/start");
|
|
4914
|
+
const response = await adminApiGet("/api/v1/admin/youtube/auth/start");
|
|
4879
4915
|
console.log(`Open this YouTube authorization URL:
|
|
4880
4916
|
|
|
4881
4917
|
${response.authUrl}
|
|
@@ -4883,11 +4919,11 @@ ${response.authUrl}
|
|
|
4883
4919
|
After approving access, Google returns to the Fluncle admin callback and stores the refresh token server-side.`);
|
|
4884
4920
|
}
|
|
4885
4921
|
async function initiate2(mixtapeId, contentLength, contentType) {
|
|
4886
|
-
const response = await adminApiPost(`/api/admin/mixtapes/${encodeURIComponent(mixtapeId)}/youtube/initiate`, { contentLength, contentType });
|
|
4922
|
+
const response = await adminApiPost(`/api/v1/admin/mixtapes/${encodeURIComponent(mixtapeId)}/youtube/initiate`, { contentLength, contentType });
|
|
4887
4923
|
return { accessToken: response.accessToken, sessionUri: response.sessionUri };
|
|
4888
4924
|
}
|
|
4889
4925
|
async function mintToken2() {
|
|
4890
|
-
const response = await adminApiPost("/api/admin/youtube/token");
|
|
4926
|
+
const response = await adminApiPost("/api/v1/admin/youtube/token");
|
|
4891
4927
|
return response.accessToken;
|
|
4892
4928
|
}
|
|
4893
4929
|
async function putChunk2(args) {
|
|
@@ -4947,7 +4983,7 @@ function nextOffset2(rangeHeader, fallback) {
|
|
|
4947
4983
|
return Number(match[1]) + 1;
|
|
4948
4984
|
}
|
|
4949
4985
|
async function resolveMixtapeId2(idOrLogId) {
|
|
4950
|
-
const response = await adminApiGet("/api/admin/mixtapes");
|
|
4986
|
+
const response = await adminApiGet("/api/v1/admin/mixtapes");
|
|
4951
4987
|
const match = response.mixtapes.find((mixtape) => mixtape.id === idOrLogId || mixtape.logId === idOrLogId);
|
|
4952
4988
|
if (!match?.id) {
|
|
4953
4989
|
throw new CliError2("mixtape_not_found", `No mixtape with id or Log ID ${idOrLogId}`);
|
|
@@ -4983,10 +5019,10 @@ __export(exports_publish, {
|
|
|
4983
5019
|
publishAdvanceCommand: () => publishAdvanceCommand
|
|
4984
5020
|
});
|
|
4985
5021
|
async function publishAdvanceCommand() {
|
|
4986
|
-
return adminApiPost("/api/admin/social/publish/advance", {});
|
|
5022
|
+
return adminApiPost("/api/v1/admin/social/publish/advance", {});
|
|
4987
5023
|
}
|
|
4988
5024
|
async function publishAdvancePauseCommand(paused) {
|
|
4989
|
-
const response = await adminApiPut("/api/admin/social/publish/advance/state", { paused });
|
|
5025
|
+
const response = await adminApiPut("/api/v1/admin/social/publish/advance/state", { paused });
|
|
4990
5026
|
return response.paused;
|
|
4991
5027
|
}
|
|
4992
5028
|
var init_publish = __esm(() => {
|
|
@@ -5000,10 +5036,10 @@ __export(exports_capture, {
|
|
|
5000
5036
|
captureBudgetCommand: () => captureBudgetCommand
|
|
5001
5037
|
});
|
|
5002
5038
|
async function captureBudgetCommand() {
|
|
5003
|
-
return adminApiGet("/api/admin/catalogue/capture-budget");
|
|
5039
|
+
return adminApiGet("/api/v1/admin/catalogue/capture-budget");
|
|
5004
5040
|
}
|
|
5005
5041
|
async function setCaptureBudgetCommand(input) {
|
|
5006
|
-
return adminApiPut("/api/admin/catalogue/capture-budget", input);
|
|
5042
|
+
return adminApiPut("/api/v1/admin/catalogue/capture-budget", input);
|
|
5007
5043
|
}
|
|
5008
5044
|
var init_capture = __esm(() => {
|
|
5009
5045
|
init_api();
|
|
@@ -5207,7 +5243,7 @@ __export(exports_recordings, {
|
|
|
5207
5243
|
});
|
|
5208
5244
|
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "node:fs";
|
|
5209
5245
|
async function recordingGet(id) {
|
|
5210
|
-
const response = await adminApiGet(`/api/admin/recordings/${encodeURIComponent(id)}`);
|
|
5246
|
+
const response = await adminApiGet(`/api/v1/admin/recordings/${encodeURIComponent(id)}`);
|
|
5211
5247
|
return response.recording;
|
|
5212
5248
|
}
|
|
5213
5249
|
function formatRecordingSummary(recording) {
|
|
@@ -5225,7 +5261,7 @@ async function recordingsListCommand(options = {}) {
|
|
|
5225
5261
|
query.set("parentId", options.parentId);
|
|
5226
5262
|
}
|
|
5227
5263
|
const suffix = query.toString() ? `?${query.toString()}` : "";
|
|
5228
|
-
const response = await adminApiGet(`/api/admin/recordings${suffix}`);
|
|
5264
|
+
const response = await adminApiGet(`/api/v1/admin/recordings${suffix}`);
|
|
5229
5265
|
if (options.json) {
|
|
5230
5266
|
printJson2({ ok: true, recordings: response.recordings });
|
|
5231
5267
|
return;
|
|
@@ -5255,7 +5291,7 @@ async function recordingGetCommand(id, options = {}) {
|
|
|
5255
5291
|
}
|
|
5256
5292
|
async function recordingCreateCommand(options = {}) {
|
|
5257
5293
|
if (options.plan) {
|
|
5258
|
-
const created2 = await adminApiPost("/api/admin/recordings", {
|
|
5294
|
+
const created2 = await adminApiPost("/api/v1/admin/recordings", {
|
|
5259
5295
|
kind: "plan",
|
|
5260
5296
|
recordedAt: options.recordedAt
|
|
5261
5297
|
});
|
|
@@ -5277,7 +5313,7 @@ async function recordingCreateCommand(options = {}) {
|
|
|
5277
5313
|
if (!existsSync2(options.video)) {
|
|
5278
5314
|
throw new CliError2("file_not_found", `Set-video master not found: ${options.video}`);
|
|
5279
5315
|
}
|
|
5280
|
-
const created = await adminApiPost("/api/admin/recordings", {
|
|
5316
|
+
const created = await adminApiPost("/api/v1/admin/recordings", {
|
|
5281
5317
|
recordedAt: options.recordedAt,
|
|
5282
5318
|
title
|
|
5283
5319
|
});
|
|
@@ -5288,7 +5324,7 @@ async function recordingCreateCommand(options = {}) {
|
|
|
5288
5324
|
}
|
|
5289
5325
|
};
|
|
5290
5326
|
log(`Recording ${recording.id} created, staging the set video…`);
|
|
5291
|
-
const upload = await uploadRenditionMultipart(options.video, `/api/admin/recordings/${encodeURIComponent(recording.id)}/set-video/presign`, log);
|
|
5327
|
+
const upload = await uploadRenditionMultipart(options.video, `/api/v1/admin/recordings/${encodeURIComponent(recording.id)}/set-video/presign`, log);
|
|
5292
5328
|
if (options.json) {
|
|
5293
5329
|
printJson2({ key: upload.key, ok: true, recording, url: upload.url });
|
|
5294
5330
|
return;
|
|
@@ -5322,7 +5358,7 @@ async function recordingUpdateCommand(id, options = {}) {
|
|
|
5322
5358
|
if (Object.keys(body).length === 0) {
|
|
5323
5359
|
throw new CliError2("no_fields", "Nothing to update. Pass --title, --recorded-at, --parent-id, or --tracklist-file");
|
|
5324
5360
|
}
|
|
5325
|
-
const response = await adminApiPatch(`/api/admin/recordings/${encodeURIComponent(id)}`, body);
|
|
5361
|
+
const response = await adminApiPatch(`/api/v1/admin/recordings/${encodeURIComponent(id)}`, body);
|
|
5326
5362
|
if (options.json) {
|
|
5327
5363
|
printJson2({ ok: true, recording: response.recording });
|
|
5328
5364
|
return;
|
|
@@ -5333,7 +5369,7 @@ async function recordingDeleteCommand(id, options = {}) {
|
|
|
5333
5369
|
if (!id) {
|
|
5334
5370
|
throw new CliError2("missing_id", "Missing recording id for: delete");
|
|
5335
5371
|
}
|
|
5336
|
-
await adminApiDelete(`/api/admin/recordings/${encodeURIComponent(id)}`);
|
|
5372
|
+
await adminApiDelete(`/api/v1/admin/recordings/${encodeURIComponent(id)}`);
|
|
5337
5373
|
if (options.json) {
|
|
5338
5374
|
printJson2({ ok: true });
|
|
5339
5375
|
return;
|
|
@@ -5344,7 +5380,7 @@ async function recordingPromoteCommand(id, options = {}) {
|
|
|
5344
5380
|
if (!id) {
|
|
5345
5381
|
throw new CliError2("missing_id", "Missing recording id for: promote");
|
|
5346
5382
|
}
|
|
5347
|
-
const response = await adminApiPost(`/api/admin/recordings/${encodeURIComponent(id)}/promote`);
|
|
5383
|
+
const response = await adminApiPost(`/api/v1/admin/recordings/${encodeURIComponent(id)}/promote`);
|
|
5348
5384
|
const recording = response.recording;
|
|
5349
5385
|
if (options.json) {
|
|
5350
5386
|
printJson2({ ok: true, recording });
|
|
@@ -5368,7 +5404,7 @@ async function recordingReplaceCuesCommand(id, options = {}) {
|
|
|
5368
5404
|
} catch {
|
|
5369
5405
|
throw new CliError2("invalid_cues", `Cues file is not valid JSON: ${options.cuesFile}`);
|
|
5370
5406
|
}
|
|
5371
|
-
const response = await adminApiPut(`/api/admin/recordings/${encodeURIComponent(id)}/cues`, { cues });
|
|
5407
|
+
const response = await adminApiPut(`/api/v1/admin/recordings/${encodeURIComponent(id)}/cues`, { cues });
|
|
5372
5408
|
if (options.json) {
|
|
5373
5409
|
printJson2({ ok: true, recording: response.recording });
|
|
5374
5410
|
return;
|
|
@@ -5463,19 +5499,19 @@ async function clipsListCommand(filter = {}) {
|
|
|
5463
5499
|
params.set("status", filter.status);
|
|
5464
5500
|
}
|
|
5465
5501
|
const query = params.toString();
|
|
5466
|
-
const response = await adminApiGet(`/api/admin/clips${query ? `?${query}` : ""}`);
|
|
5502
|
+
const response = await adminApiGet(`/api/v1/admin/clips${query ? `?${query}` : ""}`);
|
|
5467
5503
|
return response.clips;
|
|
5468
5504
|
}
|
|
5469
5505
|
async function clipPostsListCommand() {
|
|
5470
|
-
const response = await adminApiGet("/api/admin/clips/social");
|
|
5506
|
+
const response = await adminApiGet("/api/v1/admin/clips/social");
|
|
5471
5507
|
return response.posts;
|
|
5472
5508
|
}
|
|
5473
5509
|
async function clipScheduleCommand(clipId, scheduledFor) {
|
|
5474
|
-
const response = await adminApiPatch(`/api/admin/clips/${encodeURIComponent(clipId)}/schedule`, { scheduledFor });
|
|
5510
|
+
const response = await adminApiPatch(`/api/v1/admin/clips/${encodeURIComponent(clipId)}/schedule`, { scheduledFor });
|
|
5475
5511
|
return response.post;
|
|
5476
5512
|
}
|
|
5477
5513
|
async function clipDripPauseCommand(paused) {
|
|
5478
|
-
const response = await adminApiPut("/api/admin/clips/drip/state", {
|
|
5514
|
+
const response = await adminApiPut("/api/v1/admin/clips/drip/state", {
|
|
5479
5515
|
paused
|
|
5480
5516
|
});
|
|
5481
5517
|
return response.paused;
|
|
@@ -5516,9 +5552,9 @@ async function clipCutCommand(clipId, onProgress = () => {}) {
|
|
|
5516
5552
|
throw new CliError2("clip_too_large", `The cut is ${(sizeBytes / 1e6).toFixed(1)} MB (> 100 MB Cloudflare MT ceiling). Shorten the window or lower the bitrate cap`);
|
|
5517
5553
|
}
|
|
5518
5554
|
onProgress(`Clip ${clipId}: uploading ${(sizeBytes / 1e6).toFixed(1)} MB…`);
|
|
5519
|
-
const presign = await adminApiPost(`/api/admin/clips/${encodeURIComponent(clipId)}/cut/presign`, { contentType: "video/mp4" });
|
|
5555
|
+
const presign = await adminApiPost(`/api/v1/admin/clips/${encodeURIComponent(clipId)}/cut/presign`, { contentType: "video/mp4" });
|
|
5520
5556
|
await putClip(presign.url, presign.contentType, outputPath);
|
|
5521
|
-
await adminApiPost(`/api/admin/clips/${encodeURIComponent(clipId)}/cut/finalize`);
|
|
5557
|
+
await adminApiPost(`/api/v1/admin/clips/${encodeURIComponent(clipId)}/cut/finalize`);
|
|
5522
5558
|
onProgress(`Clip ${clipId}: done → ${FOUND_BASE3}/${presign.key}`);
|
|
5523
5559
|
return {
|
|
5524
5560
|
clipId,
|
|
@@ -5588,7 +5624,7 @@ __export(exports_recordings2, {
|
|
|
5588
5624
|
});
|
|
5589
5625
|
import { existsSync as existsSync3, readFileSync as readFileSync3 } from "node:fs";
|
|
5590
5626
|
async function recordingGet2(id) {
|
|
5591
|
-
const response = await adminApiGet(`/api/admin/recordings/${encodeURIComponent(id)}`);
|
|
5627
|
+
const response = await adminApiGet(`/api/v1/admin/recordings/${encodeURIComponent(id)}`);
|
|
5592
5628
|
return response.recording;
|
|
5593
5629
|
}
|
|
5594
5630
|
function formatRecordingSummary2(recording) {
|
|
@@ -5606,7 +5642,7 @@ async function recordingsListCommand2(options = {}) {
|
|
|
5606
5642
|
query.set("parentId", options.parentId);
|
|
5607
5643
|
}
|
|
5608
5644
|
const suffix = query.toString() ? `?${query.toString()}` : "";
|
|
5609
|
-
const response = await adminApiGet(`/api/admin/recordings${suffix}`);
|
|
5645
|
+
const response = await adminApiGet(`/api/v1/admin/recordings${suffix}`);
|
|
5610
5646
|
if (options.json) {
|
|
5611
5647
|
printJson2({ ok: true, recordings: response.recordings });
|
|
5612
5648
|
return;
|
|
@@ -5636,7 +5672,7 @@ async function recordingGetCommand2(id, options = {}) {
|
|
|
5636
5672
|
}
|
|
5637
5673
|
async function recordingCreateCommand2(options = {}) {
|
|
5638
5674
|
if (options.plan) {
|
|
5639
|
-
const created2 = await adminApiPost("/api/admin/recordings", {
|
|
5675
|
+
const created2 = await adminApiPost("/api/v1/admin/recordings", {
|
|
5640
5676
|
kind: "plan",
|
|
5641
5677
|
recordedAt: options.recordedAt
|
|
5642
5678
|
});
|
|
@@ -5658,7 +5694,7 @@ async function recordingCreateCommand2(options = {}) {
|
|
|
5658
5694
|
if (!existsSync3(options.video)) {
|
|
5659
5695
|
throw new CliError2("file_not_found", `Set-video master not found: ${options.video}`);
|
|
5660
5696
|
}
|
|
5661
|
-
const created = await adminApiPost("/api/admin/recordings", {
|
|
5697
|
+
const created = await adminApiPost("/api/v1/admin/recordings", {
|
|
5662
5698
|
recordedAt: options.recordedAt,
|
|
5663
5699
|
title
|
|
5664
5700
|
});
|
|
@@ -5669,7 +5705,7 @@ async function recordingCreateCommand2(options = {}) {
|
|
|
5669
5705
|
}
|
|
5670
5706
|
};
|
|
5671
5707
|
log(`Recording ${recording.id} created, staging the set video…`);
|
|
5672
|
-
const upload = await uploadRenditionMultipart(options.video, `/api/admin/recordings/${encodeURIComponent(recording.id)}/set-video/presign`, log);
|
|
5708
|
+
const upload = await uploadRenditionMultipart(options.video, `/api/v1/admin/recordings/${encodeURIComponent(recording.id)}/set-video/presign`, log);
|
|
5673
5709
|
if (options.json) {
|
|
5674
5710
|
printJson2({ key: upload.key, ok: true, recording, url: upload.url });
|
|
5675
5711
|
return;
|
|
@@ -5703,7 +5739,7 @@ async function recordingUpdateCommand2(id, options = {}) {
|
|
|
5703
5739
|
if (Object.keys(body).length === 0) {
|
|
5704
5740
|
throw new CliError2("no_fields", "Nothing to update. Pass --title, --recorded-at, --parent-id, or --tracklist-file");
|
|
5705
5741
|
}
|
|
5706
|
-
const response = await adminApiPatch(`/api/admin/recordings/${encodeURIComponent(id)}`, body);
|
|
5742
|
+
const response = await adminApiPatch(`/api/v1/admin/recordings/${encodeURIComponent(id)}`, body);
|
|
5707
5743
|
if (options.json) {
|
|
5708
5744
|
printJson2({ ok: true, recording: response.recording });
|
|
5709
5745
|
return;
|
|
@@ -5714,7 +5750,7 @@ async function recordingDeleteCommand2(id, options = {}) {
|
|
|
5714
5750
|
if (!id) {
|
|
5715
5751
|
throw new CliError2("missing_id", "Missing recording id for: delete");
|
|
5716
5752
|
}
|
|
5717
|
-
await adminApiDelete(`/api/admin/recordings/${encodeURIComponent(id)}`);
|
|
5753
|
+
await adminApiDelete(`/api/v1/admin/recordings/${encodeURIComponent(id)}`);
|
|
5718
5754
|
if (options.json) {
|
|
5719
5755
|
printJson2({ ok: true });
|
|
5720
5756
|
return;
|
|
@@ -5725,7 +5761,7 @@ async function recordingPromoteCommand2(id, options = {}) {
|
|
|
5725
5761
|
if (!id) {
|
|
5726
5762
|
throw new CliError2("missing_id", "Missing recording id for: promote");
|
|
5727
5763
|
}
|
|
5728
|
-
const response = await adminApiPost(`/api/admin/recordings/${encodeURIComponent(id)}/promote`);
|
|
5764
|
+
const response = await adminApiPost(`/api/v1/admin/recordings/${encodeURIComponent(id)}/promote`);
|
|
5729
5765
|
const recording = response.recording;
|
|
5730
5766
|
if (options.json) {
|
|
5731
5767
|
printJson2({ ok: true, recording });
|
|
@@ -5749,7 +5785,7 @@ async function recordingReplaceCuesCommand2(id, options = {}) {
|
|
|
5749
5785
|
} catch {
|
|
5750
5786
|
throw new CliError2("invalid_cues", `Cues file is not valid JSON: ${options.cuesFile}`);
|
|
5751
5787
|
}
|
|
5752
|
-
const response = await adminApiPut(`/api/admin/recordings/${encodeURIComponent(id)}/cues`, { cues });
|
|
5788
|
+
const response = await adminApiPut(`/api/v1/admin/recordings/${encodeURIComponent(id)}/cues`, { cues });
|
|
5753
5789
|
if (options.json) {
|
|
5754
5790
|
printJson2({ ok: true, recording: response.recording });
|
|
5755
5791
|
return;
|
|
@@ -5805,20 +5841,20 @@ function readContentFile(filePath) {
|
|
|
5805
5841
|
}
|
|
5806
5842
|
}
|
|
5807
5843
|
async function newsletterDraftCommand(options) {
|
|
5808
|
-
return adminApiPost("/api/admin/newsletter/editions", buildBody2(options, { requireContent: true }));
|
|
5844
|
+
return adminApiPost("/api/v1/admin/newsletter/editions", buildBody2(options, { requireContent: true }));
|
|
5809
5845
|
}
|
|
5810
5846
|
async function newsletterUpdateCommand(id, options) {
|
|
5811
|
-
return adminApiPatch(`/api/admin/newsletter/editions/${encodeURIComponent(id)}`, buildBody2(options, { requireContent: false }));
|
|
5847
|
+
return adminApiPatch(`/api/v1/admin/newsletter/editions/${encodeURIComponent(id)}`, buildBody2(options, { requireContent: false }));
|
|
5812
5848
|
}
|
|
5813
5849
|
async function newsletterSendCommand(id) {
|
|
5814
|
-
return adminApiPost(`/api/admin/newsletter/editions/${encodeURIComponent(id)}/send`);
|
|
5850
|
+
return adminApiPost(`/api/v1/admin/newsletter/editions/${encodeURIComponent(id)}/send`);
|
|
5815
5851
|
}
|
|
5816
5852
|
async function newsletterListCommand() {
|
|
5817
|
-
const response = await adminApiGet("/api/admin/newsletter/editions");
|
|
5853
|
+
const response = await adminApiGet("/api/v1/admin/newsletter/editions");
|
|
5818
5854
|
return response.editions;
|
|
5819
5855
|
}
|
|
5820
5856
|
async function newsletterDeleteCommand(id) {
|
|
5821
|
-
return adminApiDelete(`/api/admin/newsletter/editions/${encodeURIComponent(id)}`);
|
|
5857
|
+
return adminApiDelete(`/api/v1/admin/newsletter/editions/${encodeURIComponent(id)}`);
|
|
5822
5858
|
}
|
|
5823
5859
|
var init_newsletter = __esm(() => {
|
|
5824
5860
|
init_api();
|
|
@@ -5835,7 +5871,7 @@ __export(exports_admin_logbook, {
|
|
|
5835
5871
|
import { existsSync as existsSync5, readFileSync as readFileSync5 } from "node:fs";
|
|
5836
5872
|
async function logbookGapsCommand(limit) {
|
|
5837
5873
|
const query = typeof limit === "number" ? `?limit=${encodeURIComponent(String(limit))}` : "";
|
|
5838
|
-
const response = await adminApiGet(`/api/admin/logbook/gaps${query}`);
|
|
5874
|
+
const response = await adminApiGet(`/api/v1/admin/logbook/gaps${query}`);
|
|
5839
5875
|
return { gaps: response.gaps, spent: response.spent };
|
|
5840
5876
|
}
|
|
5841
5877
|
function resolveBody(options) {
|
|
@@ -5857,14 +5893,14 @@ function requireTitle(options) {
|
|
|
5857
5893
|
return options.title;
|
|
5858
5894
|
}
|
|
5859
5895
|
async function logbookCreateCommand(sector, options) {
|
|
5860
|
-
return adminApiPost(`/api/admin/logbook/${encodeURIComponent(sector)}`, {
|
|
5896
|
+
return adminApiPost(`/api/v1/admin/logbook/${encodeURIComponent(sector)}`, {
|
|
5861
5897
|
body: resolveBody(options),
|
|
5862
5898
|
...typeof options.promptVersion === "number" ? { promptVersion: options.promptVersion } : {},
|
|
5863
5899
|
title: requireTitle(options)
|
|
5864
5900
|
});
|
|
5865
5901
|
}
|
|
5866
5902
|
async function logbookUpdateCommand(sector, options) {
|
|
5867
|
-
return adminApiPatch(`/api/admin/logbook/${encodeURIComponent(sector)}`, {
|
|
5903
|
+
return adminApiPatch(`/api/v1/admin/logbook/${encodeURIComponent(sector)}`, {
|
|
5868
5904
|
body: resolveBody(options),
|
|
5869
5905
|
title: requireTitle(options)
|
|
5870
5906
|
});
|
|
@@ -5894,11 +5930,11 @@ __export(exports_admin_prompts, {
|
|
|
5894
5930
|
});
|
|
5895
5931
|
import { existsSync as existsSync6, readFileSync as readFileSync6 } from "node:fs";
|
|
5896
5932
|
async function promptsListCommand() {
|
|
5897
|
-
const response = await adminApiGet("/api/admin/prompts");
|
|
5933
|
+
const response = await adminApiGet("/api/v1/admin/prompts");
|
|
5898
5934
|
return response.prompts;
|
|
5899
5935
|
}
|
|
5900
5936
|
async function promptGetCommand(slug) {
|
|
5901
|
-
return adminApiGet(`/api/admin/prompts/${encodeURIComponent(slug)}`);
|
|
5937
|
+
return adminApiGet(`/api/v1/admin/prompts/${encodeURIComponent(slug)}`);
|
|
5902
5938
|
}
|
|
5903
5939
|
async function promptDetailCommand(slug) {
|
|
5904
5940
|
const prompts = await promptsListCommand();
|
|
@@ -5924,7 +5960,7 @@ function resolveBody2(options) {
|
|
|
5924
5960
|
async function promptUpdateCommand(slug, options) {
|
|
5925
5961
|
const body = resolveBody2(options);
|
|
5926
5962
|
const note = options.note?.trim();
|
|
5927
|
-
const response = await adminApiPost(`/api/admin/prompts/${encodeURIComponent(slug)}`, note ? { body, note } : { body });
|
|
5963
|
+
const response = await adminApiPost(`/api/v1/admin/prompts/${encodeURIComponent(slug)}`, note ? { body, note } : { body });
|
|
5928
5964
|
return { slug, version: response.version };
|
|
5929
5965
|
}
|
|
5930
5966
|
async function promptRollbackCommand(slug, version) {
|
|
@@ -5948,7 +5984,7 @@ async function restore(detail, input) {
|
|
|
5948
5984
|
if (input.body.trim() === detail.activeBody.trim()) {
|
|
5949
5985
|
return { from: input.from, skipped: true, slug: detail.slug, version: detail.activeVersion };
|
|
5950
5986
|
}
|
|
5951
|
-
const response = await adminApiPost(`/api/admin/prompts/${encodeURIComponent(detail.slug)}`, { body: input.body, note: input.note });
|
|
5987
|
+
const response = await adminApiPost(`/api/v1/admin/prompts/${encodeURIComponent(detail.slug)}`, { body: input.body, note: input.note });
|
|
5952
5988
|
return { from: input.from, skipped: false, slug: detail.slug, version: response.version };
|
|
5953
5989
|
}
|
|
5954
5990
|
function parseAgainst(value) {
|
|
@@ -6063,7 +6099,7 @@ var init_admin_prompts = __esm(() => {
|
|
|
6063
6099
|
|
|
6064
6100
|
// src/commands/add.ts
|
|
6065
6101
|
async function addCommand2(spotifyUrl, options) {
|
|
6066
|
-
const result = await adminApiPost("/api/admin/tracks", {
|
|
6102
|
+
const result = await adminApiPost("/api/v1/admin/tracks", {
|
|
6067
6103
|
dryRun: options.dryRun,
|
|
6068
6104
|
note: options.note,
|
|
6069
6105
|
spotifyUrl
|
|
@@ -6094,7 +6130,7 @@ __export(exports_submissions, {
|
|
|
6094
6130
|
});
|
|
6095
6131
|
import { createInterface as createInterface2 } from "node:readline/promises";
|
|
6096
6132
|
async function listSubmissionsCommand(options = {}) {
|
|
6097
|
-
const response = await adminApiGet("/api/admin/submissions");
|
|
6133
|
+
const response = await adminApiGet("/api/v1/admin/submissions");
|
|
6098
6134
|
if (options.json) {
|
|
6099
6135
|
printJson2({ ok: true, submissions: response.submissions });
|
|
6100
6136
|
return;
|
|
@@ -6116,7 +6152,7 @@ async function reviewSubmissionCommand(submissionId, options = {}) {
|
|
|
6116
6152
|
console.log(formatSubmissionDetail(submission));
|
|
6117
6153
|
}
|
|
6118
6154
|
async function rejectSubmissionCommand(submissionId, options = {}) {
|
|
6119
|
-
const response = await adminApiPost(`/api/admin/submissions/${encodeURIComponent(submissionId)}/reject`);
|
|
6155
|
+
const response = await adminApiPost(`/api/v1/admin/submissions/${encodeURIComponent(submissionId)}/reject`);
|
|
6120
6156
|
if (options.json) {
|
|
6121
6157
|
printJson2({ ok: true, submission: response.submission });
|
|
6122
6158
|
return;
|
|
@@ -6141,7 +6177,7 @@ async function approveSubmissionCommand(submissionId, options = {}) {
|
|
|
6141
6177
|
json: options.json,
|
|
6142
6178
|
note: submission.note
|
|
6143
6179
|
});
|
|
6144
|
-
const response = await adminApiPost(`/api/admin/submissions/${encodeURIComponent(submission.id)}/approve`);
|
|
6180
|
+
const response = await adminApiPost(`/api/v1/admin/submissions/${encodeURIComponent(submission.id)}/approve`);
|
|
6145
6181
|
if (options.json) {
|
|
6146
6182
|
printJson2({ ok: true, submission: response.submission });
|
|
6147
6183
|
return;
|
|
@@ -6149,7 +6185,7 @@ async function approveSubmissionCommand(submissionId, options = {}) {
|
|
|
6149
6185
|
console.log(`Approved ${formatTrackLine(submission)}.`);
|
|
6150
6186
|
}
|
|
6151
6187
|
async function triageSubmissionCommand(submissionId, verdict, options = {}) {
|
|
6152
|
-
const response = await adminApiPost(`/api/admin/submissions/${encodeURIComponent(submissionId)}/triage`, {
|
|
6188
|
+
const response = await adminApiPost(`/api/v1/admin/submissions/${encodeURIComponent(submissionId)}/triage`, {
|
|
6153
6189
|
...typeof options.promptVersion === "number" ? { promptVersion: options.promptVersion } : {},
|
|
6154
6190
|
verdict
|
|
6155
6191
|
});
|
|
@@ -6160,7 +6196,7 @@ async function triageSubmissionCommand(submissionId, verdict, options = {}) {
|
|
|
6160
6196
|
console.log(`Triaged ${formatTrackLine(response.submission)}: ${response.submission.triageVerdict ?? ""}`);
|
|
6161
6197
|
}
|
|
6162
6198
|
async function fetchSubmission(submissionId) {
|
|
6163
|
-
const response = await adminApiGet(`/api/admin/submissions/${encodeURIComponent(submissionId)}`);
|
|
6199
|
+
const response = await adminApiGet(`/api/v1/admin/submissions/${encodeURIComponent(submissionId)}`);
|
|
6164
6200
|
return response.submission;
|
|
6165
6201
|
}
|
|
6166
6202
|
async function confirm(label) {
|
|
@@ -6215,7 +6251,7 @@ __export(exports_auth, {
|
|
|
6215
6251
|
authSpotifyCommand: () => authSpotifyCommand
|
|
6216
6252
|
});
|
|
6217
6253
|
async function authSpotifyCommand() {
|
|
6218
|
-
const response = await adminApiGet("/api/admin/spotify/auth/start");
|
|
6254
|
+
const response = await adminApiGet("/api/v1/admin/spotify/auth/start");
|
|
6219
6255
|
console.log(`Open this Spotify authorization URL:
|
|
6220
6256
|
|
|
6221
6257
|
${response.authUrl}
|
|
@@ -6285,18 +6321,18 @@ async function distributeMixcloud2(mixtapeId, audioPath, onProgress, unlisted =
|
|
|
6285
6321
|
const externalId = result.key;
|
|
6286
6322
|
const url = `https://www.mixcloud.com${result.key}`;
|
|
6287
6323
|
onProgress?.("Mixcloud: recording the link…");
|
|
6288
|
-
await adminApiPost(`/api/admin/mixtapes/${encodeURIComponent(mixtapeId)}/mixcloud/finalize`, {
|
|
6324
|
+
await adminApiPost(`/api/v1/admin/mixtapes/${encodeURIComponent(mixtapeId)}/mixcloud/finalize`, {
|
|
6289
6325
|
externalId,
|
|
6290
6326
|
url
|
|
6291
6327
|
});
|
|
6292
6328
|
return { url };
|
|
6293
6329
|
}
|
|
6294
6330
|
async function resyncMixcloud2(mixtapeId) {
|
|
6295
|
-
const response = await adminApiPost(`/api/admin/mixtapes/${encodeURIComponent(mixtapeId)}/mixcloud/resync`);
|
|
6331
|
+
const response = await adminApiPost(`/api/v1/admin/mixtapes/${encodeURIComponent(mixtapeId)}/mixcloud/resync`);
|
|
6296
6332
|
return { url: response.url };
|
|
6297
6333
|
}
|
|
6298
6334
|
async function authMixcloudCommand2() {
|
|
6299
|
-
const response = await adminApiGet("/api/admin/mixcloud/auth/start");
|
|
6335
|
+
const response = await adminApiGet("/api/v1/admin/mixcloud/auth/start");
|
|
6300
6336
|
console.log(`Open this Mixcloud authorization URL:
|
|
6301
6337
|
|
|
6302
6338
|
${response.authUrl}
|
|
@@ -6323,7 +6359,7 @@ function mixtapeTags2(_mixtape) {
|
|
|
6323
6359
|
}
|
|
6324
6360
|
async function fetchMixcloudToken2() {
|
|
6325
6361
|
try {
|
|
6326
|
-
const response = await adminApiPost("/api/admin/mixcloud/token");
|
|
6362
|
+
const response = await adminApiPost("/api/v1/admin/mixcloud/token");
|
|
6327
6363
|
return response.accessToken;
|
|
6328
6364
|
} catch {
|
|
6329
6365
|
throw new CliError2("mixcloud_not_connected", "Mixcloud is not connected. Run `fluncle admin auth mixcloud` to authorize it.");
|
|
@@ -6375,7 +6411,7 @@ __export(exports_auth_tiktok, {
|
|
|
6375
6411
|
authTikTokCommand: () => authTikTokCommand
|
|
6376
6412
|
});
|
|
6377
6413
|
async function authTikTokCommand() {
|
|
6378
|
-
const response = await adminApiGet("/api/admin/tiktok/auth/start");
|
|
6414
|
+
const response = await adminApiGet("/api/v1/admin/tiktok/auth/start");
|
|
6379
6415
|
console.log(`Open this TikTok authorization URL:
|
|
6380
6416
|
|
|
6381
6417
|
${response.authUrl}
|
|
@@ -6393,7 +6429,7 @@ __export(exports_auth_lastfm, {
|
|
|
6393
6429
|
});
|
|
6394
6430
|
async function authLastfmCommand(options) {
|
|
6395
6431
|
if (options.token?.trim()) {
|
|
6396
|
-
const response2 = await adminApiPost("/api/admin/lastfm/auth/session", { token: options.token.trim() });
|
|
6432
|
+
const response2 = await adminApiPost("/api/v1/admin/lastfm/auth/session", { token: options.token.trim() });
|
|
6397
6433
|
console.log(`Last.fm connected as ${response2.name || "fluncle"}.
|
|
6398
6434
|
|
|
6399
6435
|
Set this as the Worker secret LASTFM_SESSION_KEY (it does not expire):
|
|
@@ -6405,7 +6441,7 @@ ${response2.sessionKey}
|
|
|
6405
6441
|
Also store it in 1Password (Fluncle vault) alongside the API key + shared secret.`);
|
|
6406
6442
|
return;
|
|
6407
6443
|
}
|
|
6408
|
-
const response = await adminApiGet("/api/admin/lastfm/auth/start");
|
|
6444
|
+
const response = await adminApiGet("/api/v1/admin/lastfm/auth/start");
|
|
6409
6445
|
console.log(`Open this Last.fm authorization URL (logged in as fluncle) and click "Yes, allow access":
|
|
6410
6446
|
|
|
6411
6447
|
${response.authUrl}
|
|
@@ -6426,7 +6462,7 @@ __export(exports_admin_notes, {
|
|
|
6426
6462
|
});
|
|
6427
6463
|
async function noteHeldCommand(options) {
|
|
6428
6464
|
const query = options.settled ? "?open=false" : "";
|
|
6429
|
-
return adminApiGet(`/api/admin/note-rejections${query}`);
|
|
6465
|
+
return adminApiGet(`/api/v1/admin/note-rejections${query}`);
|
|
6430
6466
|
}
|
|
6431
6467
|
async function noteGateCommand(options) {
|
|
6432
6468
|
const patch = {};
|
|
@@ -6437,10 +6473,10 @@ async function noteGateCommand(options) {
|
|
|
6437
6473
|
patch.maxOverlap = options.maxOverlap;
|
|
6438
6474
|
}
|
|
6439
6475
|
if (Object.keys(patch).length === 0) {
|
|
6440
|
-
const response2 = await adminApiGet("/api/admin/note-rejections");
|
|
6476
|
+
const response2 = await adminApiGet("/api/v1/admin/note-rejections");
|
|
6441
6477
|
return response2.gate;
|
|
6442
6478
|
}
|
|
6443
|
-
const response = await adminApiPatch("/api/admin/note-gate", patch);
|
|
6479
|
+
const response = await adminApiPatch("/api/v1/admin/note-gate", patch);
|
|
6444
6480
|
return response.gate;
|
|
6445
6481
|
}
|
|
6446
6482
|
var init_admin_notes = __esm(() => {
|
|
@@ -6455,7 +6491,7 @@ __export(exports_admin_observations, {
|
|
|
6455
6491
|
});
|
|
6456
6492
|
async function observationHeldCommand(options) {
|
|
6457
6493
|
const query = options.settled ? "?open=false" : "";
|
|
6458
|
-
return adminApiGet(`/api/admin/observation-rejections${query}`);
|
|
6494
|
+
return adminApiGet(`/api/v1/admin/observation-rejections${query}`);
|
|
6459
6495
|
}
|
|
6460
6496
|
async function observationGateCommand(options) {
|
|
6461
6497
|
const patch = {};
|
|
@@ -6466,10 +6502,10 @@ async function observationGateCommand(options) {
|
|
|
6466
6502
|
patch.maxOverlap = options.maxOverlap;
|
|
6467
6503
|
}
|
|
6468
6504
|
if (Object.keys(patch).length === 0) {
|
|
6469
|
-
const response2 = await adminApiGet("/api/admin/observation-rejections");
|
|
6505
|
+
const response2 = await adminApiGet("/api/v1/admin/observation-rejections");
|
|
6470
6506
|
return response2.gate;
|
|
6471
6507
|
}
|
|
6472
|
-
const response = await adminApiPatch("/api/admin/observation-gate", patch);
|
|
6508
|
+
const response = await adminApiPatch("/api/v1/admin/observation-gate", patch);
|
|
6473
6509
|
return response.gate;
|
|
6474
6510
|
}
|
|
6475
6511
|
var init_admin_observations = __esm(() => {
|
|
@@ -6485,13 +6521,13 @@ __export(exports_admin_frontier, {
|
|
|
6485
6521
|
});
|
|
6486
6522
|
async function frontierRefreshCommand(options) {
|
|
6487
6523
|
const limit = options.limit ? Number.parseInt(options.limit, 10) : undefined;
|
|
6488
|
-
return adminApiPost("/api/admin/frontier-playlists/refresh", limit ? { limit } : {});
|
|
6524
|
+
return adminApiPost("/api/v1/admin/frontier-playlists/refresh", limit ? { limit } : {});
|
|
6489
6525
|
}
|
|
6490
6526
|
async function frontierStatusCommand() {
|
|
6491
|
-
return adminApiGet("/api/admin/frontier/minting");
|
|
6527
|
+
return adminApiGet("/api/v1/admin/frontier/minting");
|
|
6492
6528
|
}
|
|
6493
6529
|
async function frontierSetMintingCommand(open) {
|
|
6494
|
-
return adminApiPut("/api/admin/frontier/minting", { open });
|
|
6530
|
+
return adminApiPut("/api/v1/admin/frontier/minting", { open });
|
|
6495
6531
|
}
|
|
6496
6532
|
var init_admin_frontier = __esm(() => {
|
|
6497
6533
|
init_api();
|
|
@@ -6516,11 +6552,11 @@ __export(exports_admin_catalogue, {
|
|
|
6516
6552
|
});
|
|
6517
6553
|
async function catalogueRankCommand(options) {
|
|
6518
6554
|
const limit = options.limit ? Number.parseInt(options.limit, 10) : undefined;
|
|
6519
|
-
const response = await adminApiPost("/api/admin/catalogue/rank", limit ? { limit } : {});
|
|
6555
|
+
const response = await adminApiPost("/api/v1/admin/catalogue/rank", limit ? { limit } : {});
|
|
6520
6556
|
return { summary: response.summary, telescope: response.telescope };
|
|
6521
6557
|
}
|
|
6522
6558
|
async function catalogueDemandCommand() {
|
|
6523
|
-
const response = await adminApiPost("/api/admin/catalogue/demand", {});
|
|
6559
|
+
const response = await adminApiPost("/api/v1/admin/catalogue/demand", {});
|
|
6524
6560
|
return response.summary;
|
|
6525
6561
|
}
|
|
6526
6562
|
async function catalogueListCommand(options) {
|
|
@@ -6529,34 +6565,34 @@ async function catalogueListCommand(options) {
|
|
|
6529
6565
|
if (options.limit) {
|
|
6530
6566
|
params.set("limit", options.limit);
|
|
6531
6567
|
}
|
|
6532
|
-
return adminApiGet(`/api/admin/catalogue?${params.toString()}`);
|
|
6568
|
+
return adminApiGet(`/api/v1/admin/catalogue?${params.toString()}`);
|
|
6533
6569
|
}
|
|
6534
6570
|
async function clearWrongAudioCommand(trackId) {
|
|
6535
|
-
return adminApiPost("/api/admin/catalogue/wrong-audio/clear", {
|
|
6571
|
+
return adminApiPost("/api/v1/admin/catalogue/wrong-audio/clear", {
|
|
6536
6572
|
trackId
|
|
6537
6573
|
});
|
|
6538
6574
|
}
|
|
6539
6575
|
async function requeueUnmatchedCommand() {
|
|
6540
|
-
return adminApiPost("/api/admin/catalogue/captures/requeue-unmatched", {});
|
|
6576
|
+
return adminApiPost("/api/v1/admin/catalogue/captures/requeue-unmatched", {});
|
|
6541
6577
|
}
|
|
6542
6578
|
async function forceCaptureCommand(trackId) {
|
|
6543
|
-
return adminApiPost("/api/admin/catalogue/force-capture", {
|
|
6579
|
+
return adminApiPost("/api/v1/admin/catalogue/force-capture", {
|
|
6544
6580
|
trackId
|
|
6545
6581
|
});
|
|
6546
6582
|
}
|
|
6547
6583
|
async function flagWrongAudioCommand(trackId) {
|
|
6548
|
-
return adminApiPost("/api/admin/catalogue/wrong-audio/flag", {
|
|
6584
|
+
return adminApiPost("/api/v1/admin/catalogue/wrong-audio/flag", {
|
|
6549
6585
|
trackId
|
|
6550
6586
|
});
|
|
6551
6587
|
}
|
|
6552
6588
|
async function certifyTrackCommand(trackId, note) {
|
|
6553
|
-
return adminApiPost("/api/admin/catalogue/certify", {
|
|
6589
|
+
return adminApiPost("/api/v1/admin/catalogue/certify", {
|
|
6554
6590
|
...note ? { note } : {},
|
|
6555
6591
|
trackId
|
|
6556
6592
|
});
|
|
6557
6593
|
}
|
|
6558
6594
|
async function setTrackDismissedCommand(trackId, dismissed) {
|
|
6559
|
-
return adminApiPut("/api/admin/catalogue/dismissed", {
|
|
6595
|
+
return adminApiPut("/api/v1/admin/catalogue/dismissed", {
|
|
6560
6596
|
dismissed,
|
|
6561
6597
|
trackId
|
|
6562
6598
|
});
|
|
@@ -6566,10 +6602,10 @@ async function listUnverifiedCapturesCommand(options) {
|
|
|
6566
6602
|
if (options.limit) {
|
|
6567
6603
|
params.set("limit", options.limit);
|
|
6568
6604
|
}
|
|
6569
|
-
return adminApiGet(`/api/admin/catalogue/captures/unverified?${params.toString()}`);
|
|
6605
|
+
return adminApiGet(`/api/v1/admin/catalogue/captures/unverified?${params.toString()}`);
|
|
6570
6606
|
}
|
|
6571
6607
|
async function verifyCaptureCommand(trackId, verdict) {
|
|
6572
|
-
return adminApiPost("/api/admin/catalogue/captures/verify", {
|
|
6608
|
+
return adminApiPost("/api/v1/admin/catalogue/captures/verify", {
|
|
6573
6609
|
trackId,
|
|
6574
6610
|
verdict
|
|
6575
6611
|
});
|
|
@@ -6579,10 +6615,10 @@ async function crawlCatalogueCommand(limit, maxHop, dryRun) {
|
|
|
6579
6615
|
if (dryRun) {
|
|
6580
6616
|
params.set("dryRun", "true");
|
|
6581
6617
|
}
|
|
6582
|
-
return adminApiPost(`/api/admin/catalogue/crawl?${params.toString()}`);
|
|
6618
|
+
return adminApiPost(`/api/v1/admin/catalogue/crawl?${params.toString()}`);
|
|
6583
6619
|
}
|
|
6584
6620
|
async function crawlStatusCommand() {
|
|
6585
|
-
return adminApiGet("/api/admin/catalogue/crawl");
|
|
6621
|
+
return adminApiGet("/api/v1/admin/catalogue/crawl");
|
|
6586
6622
|
}
|
|
6587
6623
|
var CATALOGUE_LENSES;
|
|
6588
6624
|
var init_admin_catalogue = __esm(() => {
|
|
@@ -6596,7 +6632,7 @@ __export(exports_admin_reach, {
|
|
|
6596
6632
|
reachCollectCommand: () => reachCollectCommand
|
|
6597
6633
|
});
|
|
6598
6634
|
async function reachCollectCommand() {
|
|
6599
|
-
return adminApiPost("/api/admin/reach/collect", {});
|
|
6635
|
+
return adminApiPost("/api/v1/admin/reach/collect", {});
|
|
6600
6636
|
}
|
|
6601
6637
|
var init_admin_reach = __esm(() => {
|
|
6602
6638
|
init_api();
|
|
@@ -6626,13 +6662,13 @@ function buildBioBody(options) {
|
|
|
6626
6662
|
return body;
|
|
6627
6663
|
}
|
|
6628
6664
|
async function describeArtistCommand(slug, options) {
|
|
6629
|
-
return adminApiPost(`/api/admin/artists/${encodeURIComponent(slug)}/bio`, buildBioBody(options));
|
|
6665
|
+
return adminApiPost(`/api/v1/admin/artists/${encodeURIComponent(slug)}/bio`, buildBioBody(options));
|
|
6630
6666
|
}
|
|
6631
6667
|
async function draftArtistBioCommand(slug) {
|
|
6632
|
-
return adminApiGet(`/api/admin/artists/${encodeURIComponent(slug)}/bio-draft`);
|
|
6668
|
+
return adminApiGet(`/api/v1/admin/artists/${encodeURIComponent(slug)}/bio-draft`);
|
|
6633
6669
|
}
|
|
6634
6670
|
async function artistsBioQueueCommand(limit) {
|
|
6635
|
-
const response = await adminApiGet(`/api/admin/artists/bio-queue?limit=${limit}`);
|
|
6671
|
+
const response = await adminApiGet(`/api/v1/admin/artists/bio-queue?limit=${limit}`);
|
|
6636
6672
|
return response.artists;
|
|
6637
6673
|
}
|
|
6638
6674
|
async function listArtistsCommand(limit, cursor) {
|
|
@@ -6640,14 +6676,14 @@ async function listArtistsCommand(limit, cursor) {
|
|
|
6640
6676
|
if (cursor) {
|
|
6641
6677
|
params.set("cursor", cursor);
|
|
6642
6678
|
}
|
|
6643
|
-
return adminApiGet(`/api/admin/artists?${params.toString()}`);
|
|
6679
|
+
return adminApiGet(`/api/v1/admin/artists?${params.toString()}`);
|
|
6644
6680
|
}
|
|
6645
6681
|
async function resolveArtistCommand(artistId) {
|
|
6646
|
-
return adminApiPost(`/api/admin/artists/${encodeURIComponent(artistId)}/resolve`);
|
|
6682
|
+
return adminApiPost(`/api/v1/admin/artists/${encodeURIComponent(artistId)}/resolve`);
|
|
6647
6683
|
}
|
|
6648
6684
|
async function rankArtistsCommand(options) {
|
|
6649
6685
|
const limit = options.limit ? Number.parseInt(options.limit, 10) : undefined;
|
|
6650
|
-
const response = await adminApiPost("/api/admin/artists/rank", limit ? { limit } : {});
|
|
6686
|
+
const response = await adminApiPost("/api/v1/admin/artists/rank", limit ? { limit } : {});
|
|
6651
6687
|
return { summary: response.summary };
|
|
6652
6688
|
}
|
|
6653
6689
|
async function backfillArtistImagesCommand(limit, dryRun, cursor) {
|
|
@@ -6655,14 +6691,14 @@ async function backfillArtistImagesCommand(limit, dryRun, cursor) {
|
|
|
6655
6691
|
if (cursor) {
|
|
6656
6692
|
params.set("cursor", cursor);
|
|
6657
6693
|
}
|
|
6658
|
-
return adminApiPost(`/api/admin/backfill/artist-images?${params.toString()}`);
|
|
6694
|
+
return adminApiPost(`/api/v1/admin/backfill/artist-images?${params.toString()}`);
|
|
6659
6695
|
}
|
|
6660
6696
|
async function backfillArtistsCommand(limit, dryRun, cursor) {
|
|
6661
6697
|
const params = new URLSearchParams({ dryRun: String(dryRun), limit: String(limit) });
|
|
6662
6698
|
if (cursor) {
|
|
6663
6699
|
params.set("cursor", cursor);
|
|
6664
6700
|
}
|
|
6665
|
-
return adminApiPost(`/api/admin/backfill/artists?${params.toString()}`);
|
|
6701
|
+
return adminApiPost(`/api/v1/admin/backfill/artists?${params.toString()}`);
|
|
6666
6702
|
}
|
|
6667
6703
|
var init_admin_artists = __esm(() => {
|
|
6668
6704
|
init_api();
|
|
@@ -6694,17 +6730,17 @@ __export(exports_admin_labels, {
|
|
|
6694
6730
|
backfillLabelImagesCommand: () => backfillLabelImagesCommand
|
|
6695
6731
|
});
|
|
6696
6732
|
async function mergeLabelCommand(losingSlug, canonicalSlug) {
|
|
6697
|
-
const response = await adminApiPost(`/api/admin/labels/${encodeURIComponent(losingSlug)}/merge`, { canonicalSlug });
|
|
6733
|
+
const response = await adminApiPost(`/api/v1/admin/labels/${encodeURIComponent(losingSlug)}/merge`, { canonicalSlug });
|
|
6698
6734
|
return response.result;
|
|
6699
6735
|
}
|
|
6700
6736
|
async function describeLabelCommand(slug, options) {
|
|
6701
|
-
return adminApiPost(`/api/admin/labels/${encodeURIComponent(slug)}/bio`, buildBioBody2(options));
|
|
6737
|
+
return adminApiPost(`/api/v1/admin/labels/${encodeURIComponent(slug)}/bio`, buildBioBody2(options));
|
|
6702
6738
|
}
|
|
6703
6739
|
async function draftLabelBioCommand(slug) {
|
|
6704
|
-
return adminApiGet(`/api/admin/labels/${encodeURIComponent(slug)}/bio-draft`);
|
|
6740
|
+
return adminApiGet(`/api/v1/admin/labels/${encodeURIComponent(slug)}/bio-draft`);
|
|
6705
6741
|
}
|
|
6706
6742
|
async function labelsBioQueueCommand(limit) {
|
|
6707
|
-
const response = await adminApiGet(`/api/admin/labels/bio-queue?limit=${limit}`);
|
|
6743
|
+
const response = await adminApiGet(`/api/v1/admin/labels/bio-queue?limit=${limit}`);
|
|
6708
6744
|
return response.labels;
|
|
6709
6745
|
}
|
|
6710
6746
|
async function backfillLabelImagesCommand(limit, dryRun, cursor) {
|
|
@@ -6712,14 +6748,14 @@ async function backfillLabelImagesCommand(limit, dryRun, cursor) {
|
|
|
6712
6748
|
if (cursor) {
|
|
6713
6749
|
params.set("cursor", cursor);
|
|
6714
6750
|
}
|
|
6715
|
-
return adminApiPost(`/api/admin/backfill/label-images?${params.toString()}`);
|
|
6751
|
+
return adminApiPost(`/api/v1/admin/backfill/label-images?${params.toString()}`);
|
|
6716
6752
|
}
|
|
6717
6753
|
async function backfillLabelLineageCommand(limit, dryRun, cursor) {
|
|
6718
6754
|
const params = new URLSearchParams({ dryRun: String(dryRun), limit: String(limit) });
|
|
6719
6755
|
if (cursor) {
|
|
6720
6756
|
params.set("cursor", cursor);
|
|
6721
6757
|
}
|
|
6722
|
-
return adminApiPost(`/api/admin/backfill/label-lineage?${params.toString()}`);
|
|
6758
|
+
return adminApiPost(`/api/v1/admin/backfill/label-lineage?${params.toString()}`);
|
|
6723
6759
|
}
|
|
6724
6760
|
var init_admin_labels = __esm(() => {
|
|
6725
6761
|
init_api();
|
|
@@ -6739,7 +6775,7 @@ async function backfillCoverMastersCommand(kind, limit, dryRun, cursor, retryNon
|
|
|
6739
6775
|
if (retryNone) {
|
|
6740
6776
|
params.set("retry", "none");
|
|
6741
6777
|
}
|
|
6742
|
-
return adminApiPost(`/api/admin/backfill/cover-masters?${params.toString()}`);
|
|
6778
|
+
return adminApiPost(`/api/v1/admin/backfill/cover-masters?${params.toString()}`);
|
|
6743
6779
|
}
|
|
6744
6780
|
var init_admin_covers = __esm(() => {
|
|
6745
6781
|
init_api();
|
|
@@ -6753,13 +6789,13 @@ __export(exports_admin_albums, {
|
|
|
6753
6789
|
albumsBioQueueCommand: () => albumsBioQueueCommand
|
|
6754
6790
|
});
|
|
6755
6791
|
async function describeAlbumCommand(slug, options) {
|
|
6756
|
-
return adminApiPost(`/api/admin/albums/${encodeURIComponent(slug)}/bio`, buildBioBody2(options));
|
|
6792
|
+
return adminApiPost(`/api/v1/admin/albums/${encodeURIComponent(slug)}/bio`, buildBioBody2(options));
|
|
6757
6793
|
}
|
|
6758
6794
|
async function draftAlbumBioCommand(slug) {
|
|
6759
|
-
return adminApiGet(`/api/admin/albums/${encodeURIComponent(slug)}/bio-draft`);
|
|
6795
|
+
return adminApiGet(`/api/v1/admin/albums/${encodeURIComponent(slug)}/bio-draft`);
|
|
6760
6796
|
}
|
|
6761
6797
|
async function albumsBioQueueCommand(limit) {
|
|
6762
|
-
const response = await adminApiGet(`/api/admin/albums/bio-queue?limit=${limit}`);
|
|
6798
|
+
const response = await adminApiGet(`/api/v1/admin/albums/bio-queue?limit=${limit}`);
|
|
6763
6799
|
return response.albums;
|
|
6764
6800
|
}
|
|
6765
6801
|
var init_admin_albums = __esm(() => {
|
|
@@ -6781,7 +6817,7 @@ async function migratePreviewArchiveCommand(args) {
|
|
|
6781
6817
|
if (args.cursor) {
|
|
6782
6818
|
params.set("cursor", args.cursor);
|
|
6783
6819
|
}
|
|
6784
|
-
return adminApiPost(`/api/admin/migrations/preview-archive?${params.toString()}`);
|
|
6820
|
+
return adminApiPost(`/api/v1/admin/migrations/preview-archive?${params.toString()}`);
|
|
6785
6821
|
}
|
|
6786
6822
|
var init_preview_migration = __esm(() => {
|
|
6787
6823
|
init_api();
|
|
@@ -10014,6 +10050,10 @@ function addAdminCommands(program2) {
|
|
|
10014
10050
|
const { backfillArtistEdgesCommand: backfillArtistEdgesCommand2 } = await Promise.resolve().then(() => (init_admin_tracks(), exports_admin_tracks));
|
|
10015
10051
|
await runBackfillArtistEdges(options, backfillArtistEdgesCommand2);
|
|
10016
10052
|
});
|
|
10053
|
+
backfill.command("artist-credits").description("Mint identity-true artists from MusicBrainz credits for the zero-matched residual").option("--dry-run", "Report the eligible worklist without any vendor call or write", false).option("--limit <limit>", "Max worklist rows to visit", "40").option("--json", "Print JSON", false).action(async (options) => {
|
|
10054
|
+
const { backfillArtistCreditsCommand: backfillArtistCreditsCommand2 } = await Promise.resolve().then(() => (init_admin_tracks(), exports_admin_tracks));
|
|
10055
|
+
await runBackfillArtistCredits(options, backfillArtistCreditsCommand2);
|
|
10056
|
+
});
|
|
10017
10057
|
backfill.command("cover-masters").description("Resolve owned \u22641200\xB2 cover masters (album/artist) into R2").option("--kind <kind>", "Which entity to drain: album | artist", "album").option("--dry-run", "Report the eligible worklist without any fetch or write", false).option("--retry-none", "First re-queue a bounded batch of terminal none rows to pending, then run the pass", false).option("--limit <limit>", "Max entities to process", "50").option("--json", "Print JSON", false).action(async (options) => {
|
|
10018
10058
|
const { backfillCoverMastersCommand: backfillCoverMastersCommand2 } = await Promise.resolve().then(() => (init_admin_covers(), exports_admin_covers));
|
|
10019
10059
|
await runBackfillCoverMasters(options, backfillCoverMastersCommand2);
|
|
@@ -11061,6 +11101,57 @@ async function runBackfillArtistEdges(options, backfillArtistEdgesCommand2) {
|
|
|
11061
11101
|
const verb = dryRun ? "Would write" : "Wrote";
|
|
11062
11102
|
console.log(`${verb} ${edgesWritten} track_artists edge(s) over ${scanned} track(s): ${fullyMatched.length} fully matched, ${partiallyMatched.length} partially, ${zeroMatched.length} with none; ${unmatchedNames} credited name(s) left unmatched.`);
|
|
11063
11103
|
}
|
|
11104
|
+
async function runBackfillArtistCredits(options, backfillArtistCreditsCommand2) {
|
|
11105
|
+
const limit = parseListLimit(options.limit) ?? 40;
|
|
11106
|
+
let cursor;
|
|
11107
|
+
let dryRun = options.dryRun;
|
|
11108
|
+
let scanned = 0;
|
|
11109
|
+
let mintedArtists = 0;
|
|
11110
|
+
let matchedArtists = 0;
|
|
11111
|
+
let adoptedArtists = 0;
|
|
11112
|
+
let edgesWritten = 0;
|
|
11113
|
+
let skippedNoIdentity = 0;
|
|
11114
|
+
let throttled = false;
|
|
11115
|
+
while (scanned < limit) {
|
|
11116
|
+
const remaining = limit - scanned;
|
|
11117
|
+
const result = await backfillArtistCreditsCommand2(remaining, options.dryRun, cursor);
|
|
11118
|
+
dryRun = result.dryRun;
|
|
11119
|
+
scanned += result.scanned;
|
|
11120
|
+
mintedArtists += result.mintedArtists;
|
|
11121
|
+
matchedArtists += result.matchedArtists;
|
|
11122
|
+
adoptedArtists += result.adoptedArtists;
|
|
11123
|
+
edgesWritten += result.edgesWritten;
|
|
11124
|
+
skippedNoIdentity += result.skippedNoIdentity;
|
|
11125
|
+
if (!options.json) {
|
|
11126
|
+
const verb2 = result.dryRun ? "would visit" : "visited";
|
|
11127
|
+
console.log(` \u2026${verb2} ${result.scanned}; minted ${result.mintedArtists}, adopted ${result.adoptedArtists}, matched ${result.matchedArtists} artist(s); wrote ${result.edgesWritten} edge(s); ${result.skippedNoIdentity} without a MusicBrainz identity`);
|
|
11128
|
+
}
|
|
11129
|
+
if (result.rateLimited) {
|
|
11130
|
+
throttled = true;
|
|
11131
|
+
break;
|
|
11132
|
+
}
|
|
11133
|
+
if (result.nextCursor === null) {
|
|
11134
|
+
break;
|
|
11135
|
+
}
|
|
11136
|
+
cursor = result.nextCursor;
|
|
11137
|
+
}
|
|
11138
|
+
if (options.json) {
|
|
11139
|
+
printJson({
|
|
11140
|
+
adoptedArtists,
|
|
11141
|
+
dryRun,
|
|
11142
|
+
edgesWritten,
|
|
11143
|
+
matchedArtists,
|
|
11144
|
+
mintedArtists,
|
|
11145
|
+
ok: true,
|
|
11146
|
+
rateLimited: throttled,
|
|
11147
|
+
scanned,
|
|
11148
|
+
skippedNoIdentity
|
|
11149
|
+
});
|
|
11150
|
+
return;
|
|
11151
|
+
}
|
|
11152
|
+
const verb = dryRun ? "Would visit" : "Visited";
|
|
11153
|
+
console.log(`${verb} ${scanned} track(s): minted ${mintedArtists}, adopted ${adoptedArtists}, matched ${matchedArtists} artist(s); wrote ${edgesWritten} track_artists edge(s); ${skippedNoIdentity} carried no MusicBrainz identity.`);
|
|
11154
|
+
}
|
|
11064
11155
|
async function runArtistResolveQueue(options, listArtistsCommand2) {
|
|
11065
11156
|
const limit = parseListLimit(options.limit);
|
|
11066
11157
|
const result = await listArtistsCommand2(limit ?? 50);
|