nixamp 0.48.1 → 0.49.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/dist/ai-keys.d.ts +1 -1
- package/dist/ai-keys.js +2 -0
- package/dist/ai-label.d.ts +210 -0
- package/dist/ai-label.js +725 -0
- package/dist/ai-radio.d.ts +11 -5
- package/dist/ai-radio.js +27 -11
- package/dist/ai-text.d.ts +2 -0
- package/dist/ai-text.js +4 -2
- package/dist/label-routes.d.ts +15 -0
- package/dist/label-routes.js +255 -0
- package/dist/server.d.ts +3 -0
- package/dist/server.js +28 -1
- package/dist/station-cli.js +109 -0
- package/dist/station-guide.d.ts +1 -1
- package/dist/station-guide.js +5 -1
- package/dist/station-mcp.d.ts +247 -20
- package/dist/station-mcp.js +36 -0
- package/dist/station-usage.d.ts +1 -1
- package/dist/station-usage.js +15 -1
- package/package.json +1 -1
- package/src/ai-keys.ts +2 -0
- package/src/ai-label.ts +826 -0
- package/src/ai-radio.ts +30 -13
- package/src/ai-text.ts +6 -2
- package/src/label-routes.ts +268 -0
- package/src/server.ts +30 -1
- package/src/station-cli.ts +102 -0
- package/src/station-guide.ts +5 -1
- package/src/station-mcp.ts +34 -0
- package/src/station-usage.ts +15 -1
- package/web/dist/assets/{ar-BvPTr_2x.js → ar-BEVjqkqM.js} +1 -1
- package/web/dist/assets/{cs-g4ii7Tkl.js → cs-DjazXQ15.js} +1 -1
- package/web/dist/assets/{da-D9vYCFH7.js → da-DnyF6SYK.js} +1 -1
- package/web/dist/assets/{de-lYElbebQ.js → de--q1ph9Ez.js} +1 -1
- package/web/dist/assets/{es-CiDbfxFy.js → es-Do3DkBwD.js} +1 -1
- package/web/dist/assets/{fi-BWlqMMWx.js → fi-B7sJTx1N.js} +1 -1
- package/web/dist/assets/{fr-D2n5nXQv.js → fr-Dy7f5rGi.js} +1 -1
- package/web/dist/assets/{hi-DM9Nh04K.js → hi-C9vSnTQ4.js} +1 -1
- package/web/dist/assets/{hu-Bzb0X4rk.js → hu-h-eueQE8.js} +1 -1
- package/web/dist/assets/{id-j0QazySW.js → id-D8Ffd-Pc.js} +1 -1
- package/web/dist/assets/{it-BVvva3a6.js → it-BKM_2rj1.js} +1 -1
- package/web/dist/assets/{main-DPfBhzsz.js → main-Dl_uRj22.js} +2 -2
- package/web/dist/assets/{nl-CrJQ6obW.js → nl-Cj3ETrcl.js} +1 -1
- package/web/dist/assets/radio-zPgyISLf.js +1 -0
- package/web/dist/assets/{ru-DFIjjKvG.js → ru-B5zmGSnG.js} +1 -1
- package/web/dist/assets/{sv-BO9QPL4K.js → sv-BMtjA1uI.js} +1 -1
- package/web/dist/assets/{uk-DwmG3Owv.js → uk-B2vuB6Un.js} +1 -1
- package/web/dist/assets/{vi-C-2EzgMe.js → vi-CXam3lDh.js} +1 -1
- package/web/dist/assets/{zh-BlnCenyZ.js → zh-DnYhyzqb.js} +1 -1
- package/web/dist/index.html +1 -1
- package/web/dist/radio.html +33 -1
- package/web/dist/sw.js +20 -20
- package/web/dist/assets/radio-DI0H8flN.js +0 -1
package/dist/station-cli.js
CHANGED
|
@@ -282,6 +282,8 @@ export async function station(argv) {
|
|
|
282
282
|
}
|
|
283
283
|
case "ai":
|
|
284
284
|
return await aiCommand(argv.slice(1), call, show, json);
|
|
285
|
+
case "label":
|
|
286
|
+
return await labelCommand(argv.slice(1), call, show);
|
|
285
287
|
case "shares":
|
|
286
288
|
return await sharesCommand(argv.slice(1), call, show);
|
|
287
289
|
case "lyrics":
|
|
@@ -438,6 +440,113 @@ async function aiCommand(argv, call, show, json) {
|
|
|
438
440
|
return 2;
|
|
439
441
|
}
|
|
440
442
|
}
|
|
443
|
+
/** `nixamp station label ...`: AI artists who put out an album a month (ai-label.ts). */
|
|
444
|
+
async function labelCommand(argv, call, show) {
|
|
445
|
+
const [sub, key] = argv;
|
|
446
|
+
const when = (at) => at === -1 ? "never (off)" : at === 0 ? "now" : new Date(at).toISOString().slice(0, 10);
|
|
447
|
+
const describe = (one) => {
|
|
448
|
+
const albums = one["albums"] ?? [];
|
|
449
|
+
return [
|
|
450
|
+
`${String(one["name"])} [${String(one["key"])}] ${String(one["genre"])}${one["enabled"] ? "" : " (off)"}`,
|
|
451
|
+
...albums.map((album) => ` ${String(album["year"])} ${String(album["title"])} ${String(album["composed"])}/${String(album["songs"])} songs${album["doneAt"] ? "" : " (recording)"}`),
|
|
452
|
+
` next album ${when(Number(one["nextAlbumAt"] ?? -1))}`,
|
|
453
|
+
...(one["lastError"] ? [` problem ${String(one["lastError"])}`] : []),
|
|
454
|
+
].join("\n");
|
|
455
|
+
};
|
|
456
|
+
switch (sub) {
|
|
457
|
+
case undefined:
|
|
458
|
+
case "status":
|
|
459
|
+
case "list":
|
|
460
|
+
return show(await call("GET", "/api/v1/stations/label"), (body) => {
|
|
461
|
+
const settings = (body["settings"] ?? {});
|
|
462
|
+
const artists = body["artists"] ?? [];
|
|
463
|
+
const roster = body["roster"] ?? [];
|
|
464
|
+
return [
|
|
465
|
+
`holder ${String(settings["holder"])}${settings["enabled"] ? "" : " (off)"}`,
|
|
466
|
+
`files ${String(body["root"])}/<genre>/<artist>/<year>-<album>/`,
|
|
467
|
+
`composer ${String(body["composer"] ?? "none")}; words by ${String(body["writer"] ?? "nobody (no model key)")}`,
|
|
468
|
+
`this month ${String(body["secondsThisMonth"])} of ${Number(settings["monthlySeconds"]) === 0 ? "unlimited" : String(settings["monthlySeconds"])} s${body["busy"] ? `; recording ${String(body["busy"])}` : ""}`,
|
|
469
|
+
`albums ${String(settings["songsPerAlbum"])} songs of ${String(settings["songSeconds"])} s; ${String(settings["seedAlbums"])} to start, then one every ${String(settings["everyDays"])} days`,
|
|
470
|
+
...(body["waiting"] ? [`waiting ${String(body["waiting"])}`] : []),
|
|
471
|
+
"",
|
|
472
|
+
...(artists.length ? artists.map(describe) : ["Nobody signed yet. nixamp station label sign --roster"]),
|
|
473
|
+
"",
|
|
474
|
+
`roster ${roster.map((one) => `${String(one["key"])}${one["signed"] ? " (signed)" : ""}`).join(", ")}`,
|
|
475
|
+
].join("\n");
|
|
476
|
+
});
|
|
477
|
+
case "sign": {
|
|
478
|
+
const body = has(argv, "--roster") ? { roster: true } : {
|
|
479
|
+
...(flag(argv, "--preset") ? { preset: flag(argv, "--preset") } : {}),
|
|
480
|
+
...(flag(argv, "--name") ? { name: flag(argv, "--name") } : {}),
|
|
481
|
+
...(flag(argv, "--genre") ? { genre: flag(argv, "--genre") } : {}),
|
|
482
|
+
...(flag(argv, "--sound") ? { sound: flag(argv, "--sound") } : {}),
|
|
483
|
+
...(flag(argv, "--voice") ? { voice: flag(argv, "--voice") } : {}),
|
|
484
|
+
...(flag(argv, "--bio") ? { bio: flag(argv, "--bio") } : {}),
|
|
485
|
+
...(flag(argv, "--themes") ? { themes: flag(argv, "--themes") } : {}),
|
|
486
|
+
};
|
|
487
|
+
return show(await call("POST", "/api/v1/stations/label/artists", body), (answer) => {
|
|
488
|
+
const signed = answer["artists"] ?? (answer["artist"] ? [answer["artist"]] : []);
|
|
489
|
+
return signed.length ? `Signed ${signed.map((one) => `${String(one["name"])} (${String(one["genre"])})`).join(", ")}. Their first albums are planned and recorded from here.` : "Everybody on the roster is already signed.";
|
|
490
|
+
});
|
|
491
|
+
}
|
|
492
|
+
case "album": {
|
|
493
|
+
if (!key) {
|
|
494
|
+
console.error("nixamp station label album needs the artist's key (nixamp station label)");
|
|
495
|
+
return 2;
|
|
496
|
+
}
|
|
497
|
+
return show(await call("POST", `/api/v1/stations/label/artists/${key}/album`, {}), (answer) => {
|
|
498
|
+
const album = answer["album"];
|
|
499
|
+
return `Planned "${String(album["title"])}" (${(album["songs"] ?? []).length} songs); recording now, a song at a time.`;
|
|
500
|
+
});
|
|
501
|
+
}
|
|
502
|
+
case "set": {
|
|
503
|
+
if (!key) {
|
|
504
|
+
console.error("nixamp station label set needs the artist's key");
|
|
505
|
+
return 2;
|
|
506
|
+
}
|
|
507
|
+
const body = {
|
|
508
|
+
...(flag(argv, "--sound") ? { sound: flag(argv, "--sound") } : {}),
|
|
509
|
+
...(flag(argv, "--voice") ? { voice: flag(argv, "--voice") } : {}),
|
|
510
|
+
...(flag(argv, "--bio") ? { bio: flag(argv, "--bio") } : {}),
|
|
511
|
+
...(flag(argv, "--themes") ? { themes: flag(argv, "--themes") } : {}),
|
|
512
|
+
...(has(argv, "--off") ? { enabled: false } : has(argv, "--on") ? { enabled: true } : {}),
|
|
513
|
+
};
|
|
514
|
+
return show(await call("PATCH", `/api/v1/stations/label/artists/${key}`, body), (answer) => `${String(answer["artist"]["name"])} updated.`);
|
|
515
|
+
}
|
|
516
|
+
case "drop": {
|
|
517
|
+
if (!key) {
|
|
518
|
+
console.error("nixamp station label drop needs the artist's key");
|
|
519
|
+
return 2;
|
|
520
|
+
}
|
|
521
|
+
const files = has(argv, "--files");
|
|
522
|
+
return show(await call("DELETE", `/api/v1/stations/label/artists/${key}${files ? "?files=1" : ""}`), () => files ? "Dropped, with their music." : "Dropped. Their albums stay on the air; nothing new will be recorded.");
|
|
523
|
+
}
|
|
524
|
+
case "config": {
|
|
525
|
+
const number = (name) => (flag(argv, name) === undefined ? undefined : Number(flag(argv, name)));
|
|
526
|
+
const body = Object.fromEntries(Object.entries({
|
|
527
|
+
holder: flag(argv, "--holder"),
|
|
528
|
+
monthlySeconds: number("--budget"),
|
|
529
|
+
everyDays: number("--every-days"),
|
|
530
|
+
seedAlbums: number("--seed-albums"),
|
|
531
|
+
songsPerAlbum: number("--songs"),
|
|
532
|
+
songSeconds: number("--seconds"),
|
|
533
|
+
enabled: has(argv, "--off") ? false : has(argv, "--on") ? true : undefined,
|
|
534
|
+
publish: has(argv, "--unlisted") ? false : has(argv, "--public") ? true : undefined,
|
|
535
|
+
}).filter(([, value]) => value !== undefined));
|
|
536
|
+
return show(await call("POST", "/api/v1/stations/label", body), (answer) => {
|
|
537
|
+
const settings = answer["settings"];
|
|
538
|
+
return `Label: ${String(settings["holder"])}, ${String(settings["songsPerAlbum"])} songs of ${String(settings["songSeconds"])} s an album, every ${String(settings["everyDays"])} days, at most ${Number(settings["monthlySeconds"]) === 0 ? "unlimited" : `${String(settings["monthlySeconds"])} s`} a month${settings["enabled"] ? "" : " (off)"}.`;
|
|
539
|
+
});
|
|
540
|
+
}
|
|
541
|
+
case "run":
|
|
542
|
+
return show(await call("POST", "/api/v1/stations/label/run", {}), (body) => body["waiting"] ? `Nothing to record now: ${String(body["waiting"])}.` : "Recording whatever is due.");
|
|
543
|
+
case "resume":
|
|
544
|
+
return show(await call("POST", "/api/v1/stations/label", { resume: true }), () => "Recording again.");
|
|
545
|
+
default:
|
|
546
|
+
console.error(`nixamp station label: no command "${sub}".\n\n${USAGE}`);
|
|
547
|
+
return 2;
|
|
548
|
+
}
|
|
549
|
+
}
|
|
441
550
|
/** `nixamp station lyrics ...`: our own songs' words, published back to nichedb.dev. */
|
|
442
551
|
async function lyricsCommand(argv, call, show, json) {
|
|
443
552
|
const [sub, id] = argv;
|
package/dist/station-guide.d.ts
CHANGED
|
@@ -27,7 +27,7 @@ export interface GuideEntry {
|
|
|
27
27
|
* gateway that cannot run its script against this server (the Moshpit's
|
|
28
28
|
* /n/<name>), and for a crawler. Everything from a station is escaped.
|
|
29
29
|
*/
|
|
30
|
-
export declare function renderGuide(entries: GuideEntry[], apiBase?: string, ads?: GuideAds): string;
|
|
30
|
+
export declare function renderGuide(entries: GuideEntry[], apiBase?: string, ads?: GuideAds, labelHref?: string): string;
|
|
31
31
|
export declare const GUIDE_HTML: string;
|
|
32
32
|
/**
|
|
33
33
|
* The guide's policy. With crawlproof configured (guideAds below) its tracker
|
package/dist/station-guide.js
CHANGED
|
@@ -150,7 +150,7 @@ const GROUPS = ["rooms", "vod", "ai", "shared", "radio", "tv"];
|
|
|
150
150
|
* gateway that cannot run its script against this server (the Moshpit's
|
|
151
151
|
* /n/<name>), and for a crawler. Everything from a station is escaped.
|
|
152
152
|
*/
|
|
153
|
-
export function renderGuide(entries, apiBase = "", ads = {}) {
|
|
153
|
+
export function renderGuide(entries, apiBase = "", ads = {}, labelHref = "") {
|
|
154
154
|
const groupOf = (one) => one.group ?? (one.kind === "video" ? "tv" : "radio");
|
|
155
155
|
const cards = (group) => entries
|
|
156
156
|
.filter((one) => groupOf(one) === group && /^https?:\/\//.test(one.page))
|
|
@@ -172,6 +172,10 @@ export function renderGuide(entries, apiBase = "", ads = {}) {
|
|
|
172
172
|
// The one ad goes at the top of the content, never against the footer.
|
|
173
173
|
page = page.replace('<p class="lead">Radio and TV, on the air now. Pick one and press play.</p>\n', (lead) => `${lead} <div class="ad-unit ad-${format}"><iframe src="${CRAWLPROOF}/api/ads/frame?slot=${encodeURIComponent(slot)}&format=${format}" title="Advertisement" loading="lazy" referrerpolicy="strict-origin-when-cross-origin" sandbox="allow-scripts allow-popups allow-popups-to-escape-sandbox allow-top-navigation-by-user-activation" scrolling="no"></iframe></div>\n`);
|
|
174
174
|
}
|
|
175
|
+
// The AI label's artists and albums, under the AI stations they play on.
|
|
176
|
+
if (/^\/[a-z]+$/.test(labelHref)) {
|
|
177
|
+
page = page.replace('<div id="ai" class="grid" aria-live="polite">', `<p class="lead"><a href="${labelHref}">The AI label: every artist, album and song, with the words →</a></p>\n <div id="ai" class="grid" aria-live="polite">`);
|
|
178
|
+
}
|
|
175
179
|
const api = /^https:\/\/[^\s"<>]+$/.test(apiBase) ? apiBase.replace(/\/+$/, "") : "";
|
|
176
180
|
return (page.replace('<p id="empty" class="empty">', entries.length ? '<p id="empty" class="empty" hidden>' : '<p id="empty" class="empty">')).replace("<body>", api ? `<body data-api="${escape(api)}">` : "<body>");
|
|
177
181
|
}
|
package/dist/station-mcp.d.ts
CHANGED
|
@@ -26,15 +26,26 @@ export declare const STATION_TOOLS: ({
|
|
|
26
26
|
breaksEvery?: undefined;
|
|
27
27
|
start?: undefined;
|
|
28
28
|
off?: undefined;
|
|
29
|
-
key?: undefined;
|
|
30
|
-
preset?: undefined;
|
|
31
29
|
style?: undefined;
|
|
32
30
|
description?: undefined;
|
|
33
31
|
vocals?: undefined;
|
|
34
32
|
trackSeconds?: undefined;
|
|
35
33
|
perDay?: undefined;
|
|
34
|
+
key?: undefined;
|
|
35
|
+
preset?: undefined;
|
|
36
|
+
roster?: undefined;
|
|
37
|
+
genre?: undefined;
|
|
38
|
+
sound?: undefined;
|
|
39
|
+
voice?: undefined;
|
|
40
|
+
bio?: undefined;
|
|
41
|
+
themes?: undefined;
|
|
36
42
|
enabled?: undefined;
|
|
43
|
+
holder?: undefined;
|
|
37
44
|
monthlySeconds?: undefined;
|
|
45
|
+
everyDays?: undefined;
|
|
46
|
+
seedAlbums?: undefined;
|
|
47
|
+
songsPerAlbum?: undefined;
|
|
48
|
+
songSeconds?: undefined;
|
|
38
49
|
state?: undefined;
|
|
39
50
|
reason?: undefined;
|
|
40
51
|
open?: undefined;
|
|
@@ -86,15 +97,26 @@ export declare const STATION_TOOLS: ({
|
|
|
86
97
|
breaksEvery?: undefined;
|
|
87
98
|
start?: undefined;
|
|
88
99
|
off?: undefined;
|
|
89
|
-
key?: undefined;
|
|
90
|
-
preset?: undefined;
|
|
91
100
|
style?: undefined;
|
|
92
101
|
description?: undefined;
|
|
93
102
|
vocals?: undefined;
|
|
94
103
|
trackSeconds?: undefined;
|
|
95
104
|
perDay?: undefined;
|
|
105
|
+
key?: undefined;
|
|
106
|
+
preset?: undefined;
|
|
107
|
+
roster?: undefined;
|
|
108
|
+
genre?: undefined;
|
|
109
|
+
sound?: undefined;
|
|
110
|
+
voice?: undefined;
|
|
111
|
+
bio?: undefined;
|
|
112
|
+
themes?: undefined;
|
|
96
113
|
enabled?: undefined;
|
|
114
|
+
holder?: undefined;
|
|
97
115
|
monthlySeconds?: undefined;
|
|
116
|
+
everyDays?: undefined;
|
|
117
|
+
seedAlbums?: undefined;
|
|
118
|
+
songsPerAlbum?: undefined;
|
|
119
|
+
songSeconds?: undefined;
|
|
98
120
|
state?: undefined;
|
|
99
121
|
reason?: undefined;
|
|
100
122
|
open?: undefined;
|
|
@@ -170,14 +192,25 @@ export declare const STATION_TOOLS: ({
|
|
|
170
192
|
breaksEvery?: undefined;
|
|
171
193
|
start?: undefined;
|
|
172
194
|
off?: undefined;
|
|
173
|
-
key?: undefined;
|
|
174
|
-
preset?: undefined;
|
|
175
195
|
style?: undefined;
|
|
176
196
|
vocals?: undefined;
|
|
177
197
|
trackSeconds?: undefined;
|
|
178
198
|
perDay?: undefined;
|
|
199
|
+
key?: undefined;
|
|
200
|
+
preset?: undefined;
|
|
201
|
+
roster?: undefined;
|
|
202
|
+
genre?: undefined;
|
|
203
|
+
sound?: undefined;
|
|
204
|
+
voice?: undefined;
|
|
205
|
+
bio?: undefined;
|
|
206
|
+
themes?: undefined;
|
|
179
207
|
enabled?: undefined;
|
|
208
|
+
holder?: undefined;
|
|
180
209
|
monthlySeconds?: undefined;
|
|
210
|
+
everyDays?: undefined;
|
|
211
|
+
seedAlbums?: undefined;
|
|
212
|
+
songsPerAlbum?: undefined;
|
|
213
|
+
songSeconds?: undefined;
|
|
181
214
|
state?: undefined;
|
|
182
215
|
reason?: undefined;
|
|
183
216
|
open?: undefined;
|
|
@@ -250,14 +283,25 @@ export declare const STATION_TOOLS: ({
|
|
|
250
283
|
breaksEvery?: undefined;
|
|
251
284
|
start?: undefined;
|
|
252
285
|
off?: undefined;
|
|
253
|
-
key?: undefined;
|
|
254
|
-
preset?: undefined;
|
|
255
286
|
style?: undefined;
|
|
256
287
|
vocals?: undefined;
|
|
257
288
|
trackSeconds?: undefined;
|
|
258
289
|
perDay?: undefined;
|
|
290
|
+
key?: undefined;
|
|
291
|
+
preset?: undefined;
|
|
292
|
+
roster?: undefined;
|
|
293
|
+
genre?: undefined;
|
|
294
|
+
sound?: undefined;
|
|
295
|
+
voice?: undefined;
|
|
296
|
+
bio?: undefined;
|
|
297
|
+
themes?: undefined;
|
|
259
298
|
enabled?: undefined;
|
|
299
|
+
holder?: undefined;
|
|
260
300
|
monthlySeconds?: undefined;
|
|
301
|
+
everyDays?: undefined;
|
|
302
|
+
seedAlbums?: undefined;
|
|
303
|
+
songsPerAlbum?: undefined;
|
|
304
|
+
songSeconds?: undefined;
|
|
261
305
|
state?: undefined;
|
|
262
306
|
reason?: undefined;
|
|
263
307
|
open?: undefined;
|
|
@@ -311,15 +355,26 @@ export declare const STATION_TOOLS: ({
|
|
|
311
355
|
breaksEvery?: undefined;
|
|
312
356
|
start?: undefined;
|
|
313
357
|
off?: undefined;
|
|
314
|
-
key?: undefined;
|
|
315
|
-
preset?: undefined;
|
|
316
358
|
style?: undefined;
|
|
317
359
|
description?: undefined;
|
|
318
360
|
vocals?: undefined;
|
|
319
361
|
trackSeconds?: undefined;
|
|
320
362
|
perDay?: undefined;
|
|
363
|
+
key?: undefined;
|
|
364
|
+
preset?: undefined;
|
|
365
|
+
roster?: undefined;
|
|
366
|
+
genre?: undefined;
|
|
367
|
+
sound?: undefined;
|
|
368
|
+
voice?: undefined;
|
|
369
|
+
bio?: undefined;
|
|
370
|
+
themes?: undefined;
|
|
321
371
|
enabled?: undefined;
|
|
372
|
+
holder?: undefined;
|
|
322
373
|
monthlySeconds?: undefined;
|
|
374
|
+
everyDays?: undefined;
|
|
375
|
+
seedAlbums?: undefined;
|
|
376
|
+
songsPerAlbum?: undefined;
|
|
377
|
+
songSeconds?: undefined;
|
|
323
378
|
state?: undefined;
|
|
324
379
|
reason?: undefined;
|
|
325
380
|
open?: undefined;
|
|
@@ -380,15 +435,26 @@ export declare const STATION_TOOLS: ({
|
|
|
380
435
|
breaksEvery?: undefined;
|
|
381
436
|
start?: undefined;
|
|
382
437
|
off?: undefined;
|
|
383
|
-
key?: undefined;
|
|
384
|
-
preset?: undefined;
|
|
385
438
|
style?: undefined;
|
|
386
439
|
description?: undefined;
|
|
387
440
|
vocals?: undefined;
|
|
388
441
|
trackSeconds?: undefined;
|
|
389
442
|
perDay?: undefined;
|
|
443
|
+
key?: undefined;
|
|
444
|
+
preset?: undefined;
|
|
445
|
+
roster?: undefined;
|
|
446
|
+
genre?: undefined;
|
|
447
|
+
sound?: undefined;
|
|
448
|
+
voice?: undefined;
|
|
449
|
+
bio?: undefined;
|
|
450
|
+
themes?: undefined;
|
|
390
451
|
enabled?: undefined;
|
|
452
|
+
holder?: undefined;
|
|
391
453
|
monthlySeconds?: undefined;
|
|
454
|
+
everyDays?: undefined;
|
|
455
|
+
seedAlbums?: undefined;
|
|
456
|
+
songsPerAlbum?: undefined;
|
|
457
|
+
songSeconds?: undefined;
|
|
392
458
|
state?: undefined;
|
|
393
459
|
reason?: undefined;
|
|
394
460
|
open?: undefined;
|
|
@@ -449,15 +515,26 @@ export declare const STATION_TOOLS: ({
|
|
|
449
515
|
off: {
|
|
450
516
|
type: string;
|
|
451
517
|
};
|
|
452
|
-
key?: undefined;
|
|
453
|
-
preset?: undefined;
|
|
454
518
|
style?: undefined;
|
|
455
519
|
description?: undefined;
|
|
456
520
|
vocals?: undefined;
|
|
457
521
|
trackSeconds?: undefined;
|
|
458
522
|
perDay?: undefined;
|
|
523
|
+
key?: undefined;
|
|
524
|
+
preset?: undefined;
|
|
525
|
+
roster?: undefined;
|
|
526
|
+
genre?: undefined;
|
|
527
|
+
sound?: undefined;
|
|
528
|
+
voice?: undefined;
|
|
529
|
+
bio?: undefined;
|
|
530
|
+
themes?: undefined;
|
|
459
531
|
enabled?: undefined;
|
|
532
|
+
holder?: undefined;
|
|
460
533
|
monthlySeconds?: undefined;
|
|
534
|
+
everyDays?: undefined;
|
|
535
|
+
seedAlbums?: undefined;
|
|
536
|
+
songsPerAlbum?: undefined;
|
|
537
|
+
songSeconds?: undefined;
|
|
461
538
|
state?: undefined;
|
|
462
539
|
reason?: undefined;
|
|
463
540
|
open?: undefined;
|
|
@@ -544,6 +621,17 @@ export declare const STATION_TOOLS: ({
|
|
|
544
621
|
monthlySeconds: {
|
|
545
622
|
type: string;
|
|
546
623
|
};
|
|
624
|
+
roster?: undefined;
|
|
625
|
+
genre?: undefined;
|
|
626
|
+
sound?: undefined;
|
|
627
|
+
voice?: undefined;
|
|
628
|
+
bio?: undefined;
|
|
629
|
+
themes?: undefined;
|
|
630
|
+
holder?: undefined;
|
|
631
|
+
everyDays?: undefined;
|
|
632
|
+
seedAlbums?: undefined;
|
|
633
|
+
songsPerAlbum?: undefined;
|
|
634
|
+
songSeconds?: undefined;
|
|
547
635
|
state?: undefined;
|
|
548
636
|
reason?: undefined;
|
|
549
637
|
open?: undefined;
|
|
@@ -584,15 +672,132 @@ export declare const STATION_TOOLS: ({
|
|
|
584
672
|
breaksEvery?: undefined;
|
|
585
673
|
start?: undefined;
|
|
586
674
|
off?: undefined;
|
|
587
|
-
key?: undefined;
|
|
588
|
-
preset?: undefined;
|
|
589
675
|
style?: undefined;
|
|
590
676
|
description?: undefined;
|
|
591
677
|
vocals?: undefined;
|
|
592
678
|
trackSeconds?: undefined;
|
|
593
679
|
perDay?: undefined;
|
|
680
|
+
server: {
|
|
681
|
+
type: "string";
|
|
682
|
+
description: string;
|
|
683
|
+
};
|
|
684
|
+
action: {
|
|
685
|
+
type: string;
|
|
686
|
+
enum: string[];
|
|
687
|
+
};
|
|
688
|
+
key: {
|
|
689
|
+
type: "string";
|
|
690
|
+
description: string;
|
|
691
|
+
};
|
|
692
|
+
preset: {
|
|
693
|
+
readonly type: "string";
|
|
694
|
+
};
|
|
695
|
+
roster: {
|
|
696
|
+
type: string;
|
|
697
|
+
};
|
|
698
|
+
name: {
|
|
699
|
+
readonly type: "string";
|
|
700
|
+
};
|
|
701
|
+
genre: {
|
|
702
|
+
readonly type: "string";
|
|
703
|
+
};
|
|
704
|
+
sound: {
|
|
705
|
+
type: "string";
|
|
706
|
+
description: string;
|
|
707
|
+
};
|
|
708
|
+
voice: {
|
|
709
|
+
readonly type: "string";
|
|
710
|
+
};
|
|
711
|
+
bio: {
|
|
712
|
+
readonly type: "string";
|
|
713
|
+
};
|
|
714
|
+
themes: {
|
|
715
|
+
readonly type: "string";
|
|
716
|
+
};
|
|
717
|
+
enabled: {
|
|
718
|
+
type: string;
|
|
719
|
+
};
|
|
720
|
+
publish: {
|
|
721
|
+
type: string;
|
|
722
|
+
};
|
|
723
|
+
holder: {
|
|
724
|
+
readonly type: "string";
|
|
725
|
+
};
|
|
726
|
+
monthlySeconds: {
|
|
727
|
+
type: string;
|
|
728
|
+
};
|
|
729
|
+
everyDays: {
|
|
730
|
+
type: string;
|
|
731
|
+
};
|
|
732
|
+
seedAlbums: {
|
|
733
|
+
type: string;
|
|
734
|
+
};
|
|
735
|
+
songsPerAlbum: {
|
|
736
|
+
type: string;
|
|
737
|
+
};
|
|
738
|
+
songSeconds: {
|
|
739
|
+
type: string;
|
|
740
|
+
};
|
|
741
|
+
state?: undefined;
|
|
742
|
+
reason?: undefined;
|
|
743
|
+
open?: undefined;
|
|
744
|
+
moderation?: undefined;
|
|
745
|
+
maxMb?: undefined;
|
|
746
|
+
perHour?: undefined;
|
|
747
|
+
artists?: undefined;
|
|
748
|
+
stations?: undefined;
|
|
749
|
+
support?: undefined;
|
|
750
|
+
label?: undefined;
|
|
751
|
+
license?: undefined;
|
|
752
|
+
id?: undefined;
|
|
753
|
+
private?: undefined;
|
|
754
|
+
};
|
|
755
|
+
required?: undefined;
|
|
756
|
+
};
|
|
757
|
+
} | {
|
|
758
|
+
name: string;
|
|
759
|
+
description: string;
|
|
760
|
+
inputSchema: {
|
|
761
|
+
type: string;
|
|
762
|
+
properties: {
|
|
763
|
+
playlist?: undefined;
|
|
764
|
+
idempotencyKey?: undefined;
|
|
765
|
+
folder?: undefined;
|
|
766
|
+
items?: undefined;
|
|
767
|
+
shuffle?: undefined;
|
|
768
|
+
repeat?: undefined;
|
|
769
|
+
bitrate?: undefined;
|
|
770
|
+
visibility?: undefined;
|
|
771
|
+
listed?: undefined;
|
|
772
|
+
basis?: undefined;
|
|
773
|
+
note?: undefined;
|
|
774
|
+
video?: undefined;
|
|
775
|
+
minItems?: undefined;
|
|
776
|
+
minFilms?: undefined;
|
|
777
|
+
maxVideoRunning?: undefined;
|
|
778
|
+
breaksEvery?: undefined;
|
|
779
|
+
start?: undefined;
|
|
780
|
+
off?: undefined;
|
|
781
|
+
style?: undefined;
|
|
782
|
+
description?: undefined;
|
|
783
|
+
vocals?: undefined;
|
|
784
|
+
trackSeconds?: undefined;
|
|
785
|
+
perDay?: undefined;
|
|
786
|
+
key?: undefined;
|
|
787
|
+
preset?: undefined;
|
|
788
|
+
roster?: undefined;
|
|
789
|
+
genre?: undefined;
|
|
790
|
+
sound?: undefined;
|
|
791
|
+
voice?: undefined;
|
|
792
|
+
bio?: undefined;
|
|
793
|
+
themes?: undefined;
|
|
594
794
|
enabled?: undefined;
|
|
795
|
+
holder?: undefined;
|
|
595
796
|
monthlySeconds?: undefined;
|
|
797
|
+
everyDays?: undefined;
|
|
798
|
+
seedAlbums?: undefined;
|
|
799
|
+
songsPerAlbum?: undefined;
|
|
800
|
+
songSeconds?: undefined;
|
|
596
801
|
server: {
|
|
597
802
|
type: "string";
|
|
598
803
|
description: string;
|
|
@@ -662,15 +867,26 @@ export declare const STATION_TOOLS: ({
|
|
|
662
867
|
breaksEvery?: undefined;
|
|
663
868
|
start?: undefined;
|
|
664
869
|
off?: undefined;
|
|
665
|
-
key?: undefined;
|
|
666
|
-
preset?: undefined;
|
|
667
870
|
style?: undefined;
|
|
668
871
|
description?: undefined;
|
|
669
872
|
vocals?: undefined;
|
|
670
873
|
trackSeconds?: undefined;
|
|
671
874
|
perDay?: undefined;
|
|
875
|
+
key?: undefined;
|
|
876
|
+
preset?: undefined;
|
|
877
|
+
roster?: undefined;
|
|
878
|
+
genre?: undefined;
|
|
879
|
+
sound?: undefined;
|
|
880
|
+
voice?: undefined;
|
|
881
|
+
bio?: undefined;
|
|
882
|
+
themes?: undefined;
|
|
672
883
|
enabled?: undefined;
|
|
884
|
+
holder?: undefined;
|
|
673
885
|
monthlySeconds?: undefined;
|
|
886
|
+
everyDays?: undefined;
|
|
887
|
+
seedAlbums?: undefined;
|
|
888
|
+
songsPerAlbum?: undefined;
|
|
889
|
+
songSeconds?: undefined;
|
|
674
890
|
state?: undefined;
|
|
675
891
|
reason?: undefined;
|
|
676
892
|
open?: undefined;
|
|
@@ -742,15 +958,26 @@ export declare const STATION_TOOLS: ({
|
|
|
742
958
|
breaksEvery?: undefined;
|
|
743
959
|
start?: undefined;
|
|
744
960
|
off?: undefined;
|
|
745
|
-
key?: undefined;
|
|
746
|
-
preset?: undefined;
|
|
747
961
|
style?: undefined;
|
|
748
962
|
description?: undefined;
|
|
749
963
|
vocals?: undefined;
|
|
750
964
|
trackSeconds?: undefined;
|
|
751
965
|
perDay?: undefined;
|
|
966
|
+
key?: undefined;
|
|
967
|
+
preset?: undefined;
|
|
968
|
+
roster?: undefined;
|
|
969
|
+
genre?: undefined;
|
|
970
|
+
sound?: undefined;
|
|
971
|
+
voice?: undefined;
|
|
972
|
+
bio?: undefined;
|
|
973
|
+
themes?: undefined;
|
|
752
974
|
enabled?: undefined;
|
|
975
|
+
holder?: undefined;
|
|
753
976
|
monthlySeconds?: undefined;
|
|
977
|
+
everyDays?: undefined;
|
|
978
|
+
seedAlbums?: undefined;
|
|
979
|
+
songsPerAlbum?: undefined;
|
|
980
|
+
songSeconds?: undefined;
|
|
754
981
|
state?: undefined;
|
|
755
982
|
reason?: undefined;
|
|
756
983
|
open?: undefined;
|
package/dist/station-mcp.js
CHANGED
|
@@ -105,6 +105,23 @@ export const STATION_TOOLS = [
|
|
|
105
105
|
},
|
|
106
106
|
},
|
|
107
107
|
},
|
|
108
|
+
{
|
|
109
|
+
name: "station_label",
|
|
110
|
+
description: "The AI label: AI artists (a name, genre, sound and voice) who release albums on their own, written and sung in English, filed as <library>/ai/<genre>/<artist>/<year>-<album>/001. <title>.mp3 with .lyrics.txt, a public station per genre, and the catalogue at /label. action status (default), sign (preset from the roster, roster: true for all of it, or name + genre + sound), album (plan the artist's next album now), update, drop, configure (holder, monthlySeconds, everyDays, seedAlbums, songsPerAlbum, songSeconds, enabled, publish), run, resume.",
|
|
111
|
+
inputSchema: {
|
|
112
|
+
type: "object",
|
|
113
|
+
properties: {
|
|
114
|
+
server: SERVER,
|
|
115
|
+
action: { type: "string", enum: ["status", "sign", "album", "update", "drop", "configure", "run", "resume"] },
|
|
116
|
+
key: { ...STRING, description: "The artist's key (10 hex characters), from status." },
|
|
117
|
+
preset: STRING, roster: { type: "boolean" }, name: STRING, genre: STRING,
|
|
118
|
+
sound: { ...STRING, description: "The music in words: instruments, tempo, mood. Name no real artist." },
|
|
119
|
+
voice: STRING, bio: STRING, themes: STRING, enabled: { type: "boolean" }, publish: { type: "boolean" }, holder: STRING,
|
|
120
|
+
monthlySeconds: { type: "integer" }, everyDays: { type: "integer" }, seedAlbums: { type: "integer" },
|
|
121
|
+
songsPerAlbum: { type: "integer" }, songSeconds: { type: "integer" },
|
|
122
|
+
},
|
|
123
|
+
},
|
|
124
|
+
},
|
|
108
125
|
{
|
|
109
126
|
name: "station_shares",
|
|
110
127
|
description: "Listener shares: anybody may share an MP3 link or file from the public guide; AI files it under a genre and holds anything that looks like a commercial release. action status (default; waiting shares), list (state), configure (open, moderation ai|owner, publish, maxMb, perHour), approve, reject, delete.",
|
|
@@ -215,6 +232,25 @@ export async function callStationTool(name, args, options = {}) {
|
|
|
215
232
|
return say("action is status, create, generate, update, remove, budget or resume", true);
|
|
216
233
|
return answer.ok ? say(JSON.stringify(answer.body, null, 2)) : refused(answer.body);
|
|
217
234
|
}
|
|
235
|
+
if (name === "station_label") {
|
|
236
|
+
const action = String(args["action"] ?? "status");
|
|
237
|
+
const key = typeof args["key"] === "string" && /^[a-f0-9]{10}$/.test(args["key"]) ? args["key"] : "";
|
|
238
|
+
const answer = action === "status" ? await call("GET", "/api/v1/stations/label")
|
|
239
|
+
: action === "sign" ? await call("POST", "/api/v1/stations/label/artists", pick(["preset", "roster", "name", "genre", "sound", "voice", "bio", "themes", "enabled"]))
|
|
240
|
+
: action === "configure" ? await call("POST", "/api/v1/stations/label", pick(["holder", "monthlySeconds", "everyDays", "seedAlbums", "songsPerAlbum", "songSeconds", "enabled", "publish"]))
|
|
241
|
+
: action === "run" ? await call("POST", "/api/v1/stations/label/run", {})
|
|
242
|
+
: action === "resume" ? await call("POST", "/api/v1/stations/label", { resume: true })
|
|
243
|
+
: !key ? null
|
|
244
|
+
: action === "album" ? await call("POST", `/api/v1/stations/label/artists/${key}/album`, {})
|
|
245
|
+
: action === "update" ? await call("PATCH", `/api/v1/stations/label/artists/${key}`, pick(["sound", "voice", "bio", "themes", "enabled"]))
|
|
246
|
+
: action === "drop" ? await call("DELETE", `/api/v1/stations/label/artists/${key}`)
|
|
247
|
+
: undefined;
|
|
248
|
+
if (answer === null)
|
|
249
|
+
return say("Which artist? Pass its key from action status.", true);
|
|
250
|
+
if (answer === undefined)
|
|
251
|
+
return say("action is status, sign, album, update, drop, configure, run or resume", true);
|
|
252
|
+
return answer.ok ? say(JSON.stringify(answer.body, null, 2)) : refused(answer.body);
|
|
253
|
+
}
|
|
218
254
|
if (name === "station_holders") {
|
|
219
255
|
const action = String(args["action"] ?? "list");
|
|
220
256
|
const answer = action === "list" ? await call("GET", "/api/v1/stations/holders")
|
package/dist/station-usage.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
/** `nixamp station` usage, apart so `nixamp help station` does not load the client. */
|
|
2
|
-
export declare const USAGE = "nixamp station \u2014 make a collection into a station\n\n nixamp station list\n nixamp station create --name NAME (--folder PATH | --playlist ID | --items 0,1,2) [--shuffle] [--no-repeat] [--bitrate 128] [--breaks 600 (the default; 0 for none)]\n nixamp station show ID\n nixamp station status ID\n nixamp station start ID\n nixamp station stop ID\n nixamp station skip ID\n nixamp station breaks ID SECONDS a spot between entries every SECONDS (120..86400; --off for none)\n nixamp station retry ID try every left-out file again\n nixamp station publish ID --basis owned|permission|licensed|public-domain [--note TEXT] [--unlisted] [--no-list]\n nixamp station unpublish ID [--private]\n nixamp station link ID [--rotate]\n nixamp station delete ID\n nixamp station guide-host NAME [--remove]\n NAME's front page is the public station guide (e.g. a Moshpit name)\n nixamp station guide-ads [--site ID] [--slot ID] [--format banner_300x250|text_link] [--off]\n crawlproof analytics (project ID) and an ad unit (slot ID) on the guide\n nixamp station guide-peer URL [--remove]\n the guide also lists the public, listed stations of the server at URL\n nixamp station auto [--no-video] [--min 10] [--films 3] [--tv 2] [--breaks 600] [--no-start]\n a station per genre, kept in step with the library (--off stops it)\n\n AI radio (music composed for a station, a few tracks a day):\n nixamp station ai what is composing, this month's seconds, the stations\n nixamp station ai create (--preset lofi|synthwave|ambient|chiptune|punk|jazz | --name NAME --style TEXT)\n [--vocals] [--seconds 120] [--per-day 2] [--unlisted] public on the guide unless --unlisted\n nixamp station ai generate KEY compose one now\n nixamp station ai set KEY [--style TEXT] [--per-day N] [--seconds N] [--off|--on]\n nixamp station ai remove KEY [--files]\n nixamp station ai budget SECONDS seconds of music a month across AI stations (0: no cap)\n nixamp station ai resume after the provider ran out of credit\n nixamp station ai key NAME ELEVENLABS_API_KEY | GEMINI_API_KEY | OPENAI_API_KEY | ANTHROPIC_API_KEY,\n NIXAMP_OPENAI_URL | NIXAMP_OPENAI_MODEL (an OpenAI-compatible stand-in), from stdin\n\n Listener shares (anybody shares an MP3 link or file from the guide; AI files and checks it):\n nixamp station shares the setting and what is waiting\n nixamp station shares on [--owner-moderation] [--unlisted] [--max-mb 60] [--per-hour 6]\n nixamp station shares off\n nixamp station shares list [--state held|approved|reported|rejected]\n nixamp station shares approve|reject|delete SHARE\n nixamp station shares trust ADDRESS [--remove] believe this proxy's X-Forwarded-For\n\n Lyrics (shown on the station page from each file's own tag, else nichedb.dev; ours published back):\n nixamp station lyrics the key, what was published, which stations may publish\n nixamp station lyrics publish ID publish a station's words now (public, listed, basis owned only)\n nixamp station lyrics key nichedb's key (NIXAMP_LYRICS_KEY), from stdin (--clear forgets it)\n\n Copyright holders (the now-playing card: who holds a track's copyright, and how to support them):\n nixamp station holder list\n nixamp station holder set NAME [--artist ARTIST]... [--station ID]... [--support https://...] [--label Subscribe] [--license TEXT]\n nixamp station holder remove ID\n\n --json machine-readable output\n --url, --key another server, as with `nixamp admin`\n\nA new station is private and stopped. Starting it does not publish it.";
|
|
2
|
+
export declare const USAGE = "nixamp station \u2014 make a collection into a station\n\n nixamp station list\n nixamp station create --name NAME (--folder PATH | --playlist ID | --items 0,1,2) [--shuffle] [--no-repeat] [--bitrate 128] [--breaks 600 (the default; 0 for none)]\n nixamp station show ID\n nixamp station status ID\n nixamp station start ID\n nixamp station stop ID\n nixamp station skip ID\n nixamp station breaks ID SECONDS a spot between entries every SECONDS (120..86400; --off for none)\n nixamp station retry ID try every left-out file again\n nixamp station publish ID --basis owned|permission|licensed|public-domain [--note TEXT] [--unlisted] [--no-list]\n nixamp station unpublish ID [--private]\n nixamp station link ID [--rotate]\n nixamp station delete ID\n nixamp station guide-host NAME [--remove]\n NAME's front page is the public station guide (e.g. a Moshpit name)\n nixamp station guide-ads [--site ID] [--slot ID] [--format banner_300x250|text_link] [--off]\n crawlproof analytics (project ID) and an ad unit (slot ID) on the guide\n nixamp station guide-peer URL [--remove]\n the guide also lists the public, listed stations of the server at URL\n nixamp station auto [--no-video] [--min 10] [--films 3] [--tv 2] [--breaks 600] [--no-start]\n a station per genre, kept in step with the library (--off stops it)\n\n AI radio (music composed for a station, a few tracks a day):\n nixamp station ai what is composing, this month's seconds, the stations\n nixamp station ai create (--preset lofi|synthwave|ambient|chiptune|punk|jazz | --name NAME --style TEXT)\n [--vocals] [--seconds 120] [--per-day 2] [--unlisted] public on the guide unless --unlisted\n nixamp station ai generate KEY compose one now\n nixamp station ai set KEY [--style TEXT] [--per-day N] [--seconds N] [--off|--on]\n nixamp station ai remove KEY [--files]\n nixamp station ai budget SECONDS seconds of music a month across AI stations (0: no cap)\n nixamp station ai resume after the provider ran out of credit\n nixamp station ai key NAME ELEVENLABS_API_KEY | GEMINI_API_KEY | OPENAI_API_KEY | ANTHROPIC_API_KEY,\n NIXAMP_OPENAI_URL | NIXAMP_OPENAI_MODEL (an OpenAI-compatible stand-in),\n NIXAMP_MUSIC_MODEL (music_v1|music_v2|music_v2_5), from stdin\n\n AI label (AI artists who release albums on their own; a station per genre; the catalogue at /label):\n nixamp station label artists, albums, this month's seconds, what it is waiting for\n nixamp station label sign --roster the first roster: velvet-ruckus, juno-kincaid, chrome-orchard, delta-wren,\n ashen-cartography, lumi-kestrel\n nixamp station label sign (--preset KEY | --name NAME --genre GENRE --sound TEXT [--voice TEXT] [--bio TEXT] [--themes TEXT])\n nixamp station label album KEY plan the artist's next album now and record it\n nixamp station label set KEY [--sound TEXT] [--voice TEXT] [--bio TEXT] [--themes TEXT] [--off|--on]\n nixamp station label drop KEY [--files]\n nixamp station label config [--holder \"Profullstack, Inc.\"] [--budget SECONDS] [--every-days 30] [--seed-albums 2]\n [--songs 8] [--seconds 150] [--on|--off] [--public|--unlisted]\n nixamp station label run record whatever is due now\n nixamp station label resume after the provider ran out of credit\n\n Listener shares (anybody shares an MP3 link or file from the guide; AI files and checks it):\n nixamp station shares the setting and what is waiting\n nixamp station shares on [--owner-moderation] [--unlisted] [--max-mb 60] [--per-hour 6]\n nixamp station shares off\n nixamp station shares list [--state held|approved|reported|rejected]\n nixamp station shares approve|reject|delete SHARE\n nixamp station shares trust ADDRESS [--remove] believe this proxy's X-Forwarded-For\n\n Lyrics (shown on the station page from each file's own tag, else nichedb.dev; ours published back):\n nixamp station lyrics the key, what was published, which stations may publish\n nixamp station lyrics publish ID publish a station's words now (public, listed, basis owned only)\n nixamp station lyrics key nichedb's key (NIXAMP_LYRICS_KEY), from stdin (--clear forgets it)\n\n Copyright holders (the now-playing card: who holds a track's copyright, and how to support them):\n nixamp station holder list\n nixamp station holder set NAME [--artist ARTIST]... [--station ID]... [--support https://...] [--label Subscribe] [--license TEXT]\n nixamp station holder remove ID\n\n --json machine-readable output\n --url, --key another server, as with `nixamp admin`\n\nA new station is private and stopped. Starting it does not publish it.";
|
package/dist/station-usage.js
CHANGED
|
@@ -33,7 +33,21 @@ export const USAGE = `nixamp station — make a collection into a station
|
|
|
33
33
|
nixamp station ai budget SECONDS seconds of music a month across AI stations (0: no cap)
|
|
34
34
|
nixamp station ai resume after the provider ran out of credit
|
|
35
35
|
nixamp station ai key NAME ELEVENLABS_API_KEY | GEMINI_API_KEY | OPENAI_API_KEY | ANTHROPIC_API_KEY,
|
|
36
|
-
NIXAMP_OPENAI_URL | NIXAMP_OPENAI_MODEL (an OpenAI-compatible stand-in),
|
|
36
|
+
NIXAMP_OPENAI_URL | NIXAMP_OPENAI_MODEL (an OpenAI-compatible stand-in),
|
|
37
|
+
NIXAMP_MUSIC_MODEL (music_v1|music_v2|music_v2_5), from stdin
|
|
38
|
+
|
|
39
|
+
AI label (AI artists who release albums on their own; a station per genre; the catalogue at /label):
|
|
40
|
+
nixamp station label artists, albums, this month's seconds, what it is waiting for
|
|
41
|
+
nixamp station label sign --roster the first roster: velvet-ruckus, juno-kincaid, chrome-orchard, delta-wren,
|
|
42
|
+
ashen-cartography, lumi-kestrel
|
|
43
|
+
nixamp station label sign (--preset KEY | --name NAME --genre GENRE --sound TEXT [--voice TEXT] [--bio TEXT] [--themes TEXT])
|
|
44
|
+
nixamp station label album KEY plan the artist's next album now and record it
|
|
45
|
+
nixamp station label set KEY [--sound TEXT] [--voice TEXT] [--bio TEXT] [--themes TEXT] [--off|--on]
|
|
46
|
+
nixamp station label drop KEY [--files]
|
|
47
|
+
nixamp station label config [--holder "Profullstack, Inc."] [--budget SECONDS] [--every-days 30] [--seed-albums 2]
|
|
48
|
+
[--songs 8] [--seconds 150] [--on|--off] [--public|--unlisted]
|
|
49
|
+
nixamp station label run record whatever is due now
|
|
50
|
+
nixamp station label resume after the provider ran out of credit
|
|
37
51
|
|
|
38
52
|
Listener shares (anybody shares an MP3 link or file from the guide; AI files and checks it):
|
|
39
53
|
nixamp station shares the setting and what is waiting
|