@audiofool/moondog 0.3.0-beta.2 → 0.3.0-beta.4
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/README.md +1 -1
- package/package.json +1 -1
- package/scripts/moondog.mjs +17 -3
- package/src/core/listening-now.mjs +75 -6
- package/src/core/moondog-application.mjs +66 -9
- package/src/i18n/messages/de.mjs +1 -1
- package/src/i18n/messages/en.mjs +1 -1
- package/src/i18n/messages/es.mjs +1 -1
- package/src/i18n/messages/fr.mjs +1 -1
- package/src/i18n/messages/it.mjs +1 -1
- package/src/i18n/messages/ja.mjs +1 -1
- package/src/i18n/messages/ko.mjs +1 -1
- package/src/i18n/messages/pt.mjs +1 -1
- package/src/i18n/messages/zh-Hant.mjs +1 -1
- package/src/i18n/messages/zh.mjs +1 -1
- package/src/i18n/screen/es.mjs +58 -0
- package/src/i18n/screen/ja.mjs +58 -0
- package/src/i18n/screen/pt.mjs +58 -0
- package/src/i18n/screen/zh.mjs +58 -0
- package/src/integrations/apple-music/terminal-preview-player.mjs +8 -0
- package/src/integrations/stable-audio/cover.mjs +324 -0
- package/src/integrations/stable-audio/local-generator.mjs +127 -37
- package/src/integrations/stable-audio/setup.mjs +653 -0
- package/src/integrations/stable-audio/sources.mjs +106 -0
- package/src/profile/taste-compiler.mjs +14 -5
- package/src/runtime/pi/agent-runtime.mjs +45 -11
- package/src/runtime/pi/record-name.mjs +80 -0
- package/src/surfaces/cli/command-completions.mjs +15 -1
- package/src/surfaces/cli/tui.mjs +229 -6
package/README.md
CHANGED
package/package.json
CHANGED
package/scripts/moondog.mjs
CHANGED
|
@@ -55,6 +55,7 @@ import { createAppleMusicCatalog } from "../src/integrations/apple-music/catalog
|
|
|
55
55
|
import { createTerminalPreviewPlayer } from "../src/integrations/apple-music/terminal-preview-player.mjs";
|
|
56
56
|
import { createNeteasePlayer } from "../src/integrations/netease/ncm-cli-player.mjs";
|
|
57
57
|
import { createAtmosphereStream, createLocalGenerator } from "../src/integrations/stable-audio/local-generator.mjs";
|
|
58
|
+
import { createStableAudioSetup } from "../src/integrations/stable-audio/setup.mjs";
|
|
58
59
|
import { createMusicAppPlayer } from "../src/integrations/apple-music/music-app.mjs";
|
|
59
60
|
import {
|
|
60
61
|
createOpenMusicSimilarity,
|
|
@@ -922,10 +923,14 @@ async function main() {
|
|
|
922
923
|
const neteasePlayer = createNeteasePlayer();
|
|
923
924
|
const playbackService = await resolvePlaybackService();
|
|
924
925
|
if (playbackService === "netease") await neteasePlayer.check();
|
|
925
|
-
// Moondog makes music on this Mac with
|
|
926
|
-
//
|
|
927
|
-
//
|
|
926
|
+
// Moondog makes music on this Mac with Stable Audio 3 once the listener turns it on, in a room
|
|
927
|
+
// that can play what it makes: Moondog's own install, downloaded when they ask, or their folder.
|
|
928
|
+
// The terminal and the window each keep one generator, so each makes one track at a time; a
|
|
929
|
+
// choice saved on one side is checked again on the other.
|
|
928
930
|
const localGenerator = previewPlayer ? createLocalGenerator() : null;
|
|
931
|
+
const generationSetup = localGenerator ? createStableAudioSetup() : null;
|
|
932
|
+
// A model set up or removed, here or on the other side, is checked again.
|
|
933
|
+
const unwatchGenerationSetup = generationSetup?.subscribe(() => { void localGenerator.check().catch(() => {}); }) ?? (() => {});
|
|
929
934
|
await localGenerator?.check();
|
|
930
935
|
void localGenerator?.sweep().catch(() => {});
|
|
931
936
|
const unwatchGeneration = localGenerator?.watch() ?? (() => {});
|
|
@@ -1158,7 +1163,12 @@ async function main() {
|
|
|
1158
1163
|
status: () => localGenerator.status(),
|
|
1159
1164
|
check: () => localGenerator.check(),
|
|
1160
1165
|
save: (settings) => localGenerator.save(settings),
|
|
1166
|
+
// Uses an installed model of Moondog's own install.
|
|
1167
|
+
use: async (model) => (generationSetup?.status()?.models?.[model]?.state === "ready"
|
|
1168
|
+
? localGenerator.save({ source: "managed", model }) : localGenerator.check()),
|
|
1161
1169
|
subscribe: (listener) => localGenerator.subscribe(listener),
|
|
1170
|
+
// Download, cancel and remove, shared by the window and the terminal.
|
|
1171
|
+
setup: generationSetup,
|
|
1162
1172
|
},
|
|
1163
1173
|
// The room asks whether a Last.fm key is set, and saves one the listener pastes.
|
|
1164
1174
|
lastfm: {
|
|
@@ -1270,6 +1280,10 @@ async function main() {
|
|
|
1270
1280
|
} finally {
|
|
1271
1281
|
unwatchPlayback();
|
|
1272
1282
|
unwatchGeneration();
|
|
1283
|
+
unwatchGenerationSetup();
|
|
1284
|
+
// A download or uv run this process owns would keep it alive after the room closes; it stops and
|
|
1285
|
+
// resumes next time. One owned by the other window or terminal runs on.
|
|
1286
|
+
await generationSetup?.close?.();
|
|
1273
1287
|
// A made track still playing is stopped while the generator listens, so its outcome is kept.
|
|
1274
1288
|
if (localGenerator) {
|
|
1275
1289
|
previewPlayer?.stop?.();
|
|
@@ -1,11 +1,13 @@
|
|
|
1
|
-
// What the listener plays right now, wherever it plays:
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
|
|
1
|
+
// What the listener plays right now, wherever it plays: Moondog's own player (the songs it played or
|
|
2
|
+
// queued, the tracks it made, its stream), the Music app on this Mac, Spotify on its active device,
|
|
3
|
+
// or NetEase through ncm-cli, with the playlist, album or queue it plays from.
|
|
4
|
+
// Two players rarely play at once. When they do, one that plays wins over a paused one, then
|
|
5
|
+
// Moondog's own player, which pauses the others when it starts, then the listener's chosen service,
|
|
6
|
+
// then this order.
|
|
7
|
+
export const LISTENING_ORDER = Object.freeze(["moondog", "apple_music", "spotify", "netease"]);
|
|
6
8
|
|
|
7
9
|
export function activeListening(sources, chosen) {
|
|
8
|
-
const order = [...new Set([chosen, ...LISTENING_ORDER])];
|
|
10
|
+
const order = [...new Set(["moondog", chosen, ...LISTENING_ORDER])];
|
|
9
11
|
const heard = sources.filter((source) => source.song && (source.state === "playing" || source.state === "paused"));
|
|
10
12
|
return heard.sort((a, b) => (a.state === "playing" ? 0 : 1) - (b.state === "playing" ? 0 : 1) ||
|
|
11
13
|
order.indexOf(a.service) - order.indexOf(b.service))[0] ?? null;
|
|
@@ -75,6 +77,21 @@ async function spotify(application, { signal }) {
|
|
|
75
77
|
};
|
|
76
78
|
}
|
|
77
79
|
|
|
80
|
+
// Moondog's own player: Apple Music songs in the window or the terminal, and the tracks Moondog made.
|
|
81
|
+
const madeBy = (track) => ({ title: track.title, artists: track.generated ? ["Moondog"] : track.artist_credit ? [track.artist_credit] : [] });
|
|
82
|
+
function moondogPlayer(application) {
|
|
83
|
+
const now = application.musicPreviewPlayer.nowPlaying();
|
|
84
|
+
if (!now?.song?.title) return { state: "stopped" };
|
|
85
|
+
const kind = !now.song.generated ? "moondog_queue" : application.streamView?.() ? "moondog_stream" : "moondog_made";
|
|
86
|
+
return {
|
|
87
|
+
state: now.state,
|
|
88
|
+
player: "Moondog's own player",
|
|
89
|
+
song: madeBy(now.song),
|
|
90
|
+
from: { kind, name: null, tracks_total: now.count, position: now.position },
|
|
91
|
+
next: now.next.map(madeBy),
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
|
|
78
95
|
async function netease(application) {
|
|
79
96
|
const now = await application.neteaseNowPlaying();
|
|
80
97
|
if (now.state === "stopped" || !now.song) return { state: "stopped" };
|
|
@@ -91,6 +108,7 @@ async function netease(application) {
|
|
|
91
108
|
/** Every player Moondog can read, the one the listener hears first: { active, sources }. */
|
|
92
109
|
export async function readListeningNow(application, { signal } = {}) {
|
|
93
110
|
const readers = [
|
|
111
|
+
typeof application.musicPreviewPlayer?.nowPlaying === "function" ? ["moondog", () => moondogPlayer(application)] : null,
|
|
94
112
|
application.musicApp?.available ? ["apple_music", () => musicApp(application)] : null,
|
|
95
113
|
application.spotifyReady() ? ["spotify", () => spotify(application, { signal })] : null,
|
|
96
114
|
application.neteaseReady() ? ["netease", () => netease(application)] : null,
|
|
@@ -106,3 +124,54 @@ export async function readListeningNow(application, { signal } = {}) {
|
|
|
106
124
|
const active = activeListening(sources, application.playbackService);
|
|
107
125
|
return { active: active?.service ?? null, sources: active ? [active, ...sources.filter((source) => source !== active)] : sources };
|
|
108
126
|
}
|
|
127
|
+
|
|
128
|
+
// What Moondog's own player plays: the queue it was sent last, and where in it the player's own
|
|
129
|
+
// events put it. The window and the terminal players keep one each, so the agent can read the songs
|
|
130
|
+
// it played or queued, and the tracks it made, as it reads the Music app or Spotify.
|
|
131
|
+
|
|
132
|
+
const entry = (track) => ({
|
|
133
|
+
title: String(track?.title ?? "").trim(),
|
|
134
|
+
artist_credit: String(track?.artist_credit ?? "").trim(),
|
|
135
|
+
...(track?.generated === true ? { generated: true } : {}),
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
export function createPlayerNow() {
|
|
139
|
+
// null, or { tracks, index, state } where state is "loading", "playing" or "paused".
|
|
140
|
+
let queue = null;
|
|
141
|
+
return {
|
|
142
|
+
/** A new queue replaces the last one and starts from its first song. */
|
|
143
|
+
queued(tracks) {
|
|
144
|
+
const list = (Array.isArray(tracks) ? tracks : []).map(entry).filter((track) => track.title);
|
|
145
|
+
queue = list.length ? { tracks: list, index: 0, state: "loading" } : null;
|
|
146
|
+
},
|
|
147
|
+
/** A made track queued behind the last one, as Moondog's stream does. */
|
|
148
|
+
appended(track) {
|
|
149
|
+
const added = entry(track);
|
|
150
|
+
if (queue && added.title) queue.tracks.push(added);
|
|
151
|
+
},
|
|
152
|
+
/** One of the player's events: { type, position } moves it along; stopped empties it. */
|
|
153
|
+
observe(event) {
|
|
154
|
+
// The terminal's player announces each new queue with its songs; the window's does not.
|
|
155
|
+
if (event?.type === "queue" && Array.isArray(event.tracks)) { this.queued(event.tracks); return; }
|
|
156
|
+
if (!queue) return;
|
|
157
|
+
if (event?.type === "stopped") { queue = null; return; }
|
|
158
|
+
if (Number.isInteger(event?.position) && event.position >= 1 && event.position <= queue.tracks.length) queue.index = event.position - 1;
|
|
159
|
+
if (event?.type === "playing" || event?.type === "paused" || event?.type === "loading") queue.state = event.type;
|
|
160
|
+
},
|
|
161
|
+
clear() {
|
|
162
|
+
queue = null;
|
|
163
|
+
},
|
|
164
|
+
/** null when nothing is queued, or { state, song, position, count, next } with up to ten songs after it. */
|
|
165
|
+
read() {
|
|
166
|
+
if (!queue) return null;
|
|
167
|
+
return {
|
|
168
|
+
// A song still loading is the one the listener is about to hear.
|
|
169
|
+
state: queue.state === "paused" ? "paused" : "playing",
|
|
170
|
+
song: { ...queue.tracks[queue.index] },
|
|
171
|
+
position: queue.index + 1,
|
|
172
|
+
count: queue.tracks.length,
|
|
173
|
+
next: queue.tracks.slice(queue.index + 1, queue.index + 11).map((track) => ({ ...track })),
|
|
174
|
+
};
|
|
175
|
+
},
|
|
176
|
+
};
|
|
177
|
+
}
|
|
@@ -5,7 +5,7 @@ import { compactListenerProfile, readListenerProfile } from "../profile/listener
|
|
|
5
5
|
import { mixCounts, songKeys } from "../profile/moondog-suggestions.mjs";
|
|
6
6
|
import { ARTIST_CREDIT_SEPARATORS } from "./listener-avoids.mjs";
|
|
7
7
|
import { textNamesSong } from "./track-title.mjs";
|
|
8
|
-
import { compileTaste, tasteSources } from "../profile/taste-compiler.mjs";
|
|
8
|
+
import { acceptableRecordTitle, compileTaste, tasteSources } from "../profile/taste-compiler.mjs";
|
|
9
9
|
import { stableAudioPrompt } from "../integrations/stable-audio/local-generator.mjs";
|
|
10
10
|
|
|
11
11
|
import {
|
|
@@ -21,7 +21,24 @@ import { webProviderName } from "../integrations/web/web-result.mjs";
|
|
|
21
21
|
import { musicAppSource, readListeningNow } from "./listening-now.mjs";
|
|
22
22
|
import { normalizeConversationFolder, normalizeConversationLabel, normalizeMemoryContent, shortConversationTitle } from "../memory/local-memory-store.mjs";
|
|
23
23
|
import { queueListeningIntent, queueCancellationRequested, unheardRequested } from "./spotify-listening-intent.mjs";
|
|
24
|
-
import { DEFAULT_LOCALE, normalizeLocale } from "../i18n/index.mjs";
|
|
24
|
+
import { DEFAULT_LOCALE, messageLocale, normalizeLocale } from "../i18n/index.mjs";
|
|
25
|
+
|
|
26
|
+
// How long a record's title in the wrong language waits to be named again before the agent's stays.
|
|
27
|
+
const TITLE_LANGUAGE_TIMEOUT_MS = 10_000;
|
|
28
|
+
|
|
29
|
+
// Whether a record's name is written in a language. A short name gives the word-based guess little to
|
|
30
|
+
// go on, and the guess then falls back to the setting, so the script decides first: Chinese, Japanese
|
|
31
|
+
// and Korean names are in their own script, and the other languages Moondog speaks in none of those.
|
|
32
|
+
const CJK = /[\p{Script=Han}\p{Script=Hiragana}\p{Script=Katakana}\p{Script=Hangul}]/u;
|
|
33
|
+
const SCRIPTS = { zh: /\p{Script=Han}/u, "zh-Hant": /\p{Script=Han}/u, ja: /[\p{Script=Han}\p{Script=Hiragana}\p{Script=Katakana}]/u, ko: /\p{Script=Hangul}/u };
|
|
34
|
+
export function nameFitsLanguage(name, locale) {
|
|
35
|
+
const text = String(name ?? "");
|
|
36
|
+
if (SCRIPTS[locale] ? !SCRIPTS[locale].test(text) : CJK.test(text)) return false;
|
|
37
|
+
const guess = messageLocale(text, locale);
|
|
38
|
+
// Kanji with no kana, such as 月夜 or 雨音, is Japanese as much as Chinese, so the Japanese setting decides.
|
|
39
|
+
if (locale === "ja" && (guess === "zh" || guess === "zh-Hant") && !/\p{Script=Hangul}/u.test(text)) return true;
|
|
40
|
+
return guess === locale;
|
|
41
|
+
}
|
|
25
42
|
import { createPlaybackSelection, DEFAULT_PLAYBACK_SERVICE, normalizePlaybackService } from "./playback-preferences.mjs";
|
|
26
43
|
|
|
27
44
|
const minimumNodeVersion = [22, 19, 0];
|
|
@@ -586,14 +603,15 @@ export class MoondogApplication {
|
|
|
586
603
|
// ones it can trace and none that names an artist or a song. The track and its receipt stay on
|
|
587
604
|
// this Mac, and its play goes in the ledger as Moondog's own, never as the listener's attention.
|
|
588
605
|
// moment and request come from the agent's host, not from the model.
|
|
589
|
-
async makeTrack({ descriptors, bpm, bpmSource, seconds, title } = {}, { moment = null, request = null, transient = false, signal, onProgress } = {}) {
|
|
606
|
+
async makeTrack({ descriptors, bpm, bpmSource, seconds, title } = {}, { moment = null, request = null, transient = false, signal, onProgress, nameRecord } = {}) {
|
|
590
607
|
const { compiled, receipt } = await this.#compileForGeneration({ descriptors, bpm, bpmSource, title }, { moment, request, transient });
|
|
591
608
|
if (!compiled.usable) {
|
|
592
609
|
return { state: "not_made", reason: compiled.descriptors.length ? "needs_a_sound" : "no_traceable_descriptors", dropped: compiled.dropped };
|
|
593
610
|
}
|
|
594
611
|
const prompt = stableAudioPrompt(compiled);
|
|
595
612
|
const endedStream = await this.#endStream("replaced");
|
|
596
|
-
const
|
|
613
|
+
const named = await this.#titleInSettingLanguage(compiled, nameRecord, signal);
|
|
614
|
+
const made = await this.localGenerator.generate({ prompt, seconds, title: named, receipt }, { signal, onProgress });
|
|
597
615
|
// A reply stopped as the track finished keeps the track, but plays nothing over what is on now.
|
|
598
616
|
await this.quietOtherPlayers("apple_music", { signal });
|
|
599
617
|
// The terminal plays the file itself; the window asks for it by id and never sees the path.
|
|
@@ -636,18 +654,21 @@ export class MoondogApplication {
|
|
|
636
654
|
|
|
637
655
|
// Starts Moondog's atmosphere stream from the listener's taste: its first track plays now, and
|
|
638
656
|
// each next one is made while the last plays. Every track goes in the ledger as Moondog's pick.
|
|
639
|
-
async startStream({ descriptors, bpm, bpmSource, seconds, minutes, title } = {}, { moment = null, request = null, transient = false, signal, onProgress } = {}) {
|
|
657
|
+
async startStream({ descriptors, bpm, bpmSource, seconds, minutes, title } = {}, { moment = null, request = null, transient = false, signal, onProgress, nameRecord } = {}) {
|
|
640
658
|
if (!this.streamReady()) throw Object.assign(new Error("A stream can't run here. Music making must be on, in the terminal room or the window."), { code: "stream_not_ready" });
|
|
641
659
|
const { compiled, receipt } = await this.#compileForGeneration({ descriptors, bpm, bpmSource, title }, { moment, request, transient });
|
|
642
660
|
if (!compiled.usable) {
|
|
643
661
|
return { state: "not_made", reason: compiled.descriptors.length ? "needs_a_sound" : "no_traceable_descriptors", dropped: compiled.dropped };
|
|
644
662
|
}
|
|
645
663
|
await this.#endStream("replaced");
|
|
664
|
+
// The stream's name, which its first track carries, in the language Moondog is set to.
|
|
665
|
+
const named = await this.#titleInSettingLanguage(compiled, nameRecord, signal);
|
|
646
666
|
// Other music pauses only once the first track exists, as for a single track.
|
|
647
667
|
let started;
|
|
648
668
|
try {
|
|
649
|
-
started = await this.atmosphereStream.start({ compiled, title:
|
|
650
|
-
{ signal, onProgress, onTrack: (track) => this.#noteGeneratedPlay(track), beforePlay: () => this.quietOtherPlayers("apple_music", { signal })
|
|
669
|
+
started = await this.atmosphereStream.start({ compiled, title: named, seconds, minutes, receipt },
|
|
670
|
+
{ signal, onProgress, onTrack: (track) => this.#noteGeneratedPlay(track), beforePlay: () => this.quietOtherPlayers("apple_music", { signal }),
|
|
671
|
+
nameTrack: typeof nameRecord === "function" ? this.#streamNamer(nameRecord, compiled) : undefined });
|
|
651
672
|
} catch (error) {
|
|
652
673
|
// The listener turned it off while its first track was made: their choice, not a failure to retry.
|
|
653
674
|
if (error?.code === "generation_stopped" && error.ended === "asked" && !signal?.aborted) return { state: "not_made", reason: "stopped_by_listener" };
|
|
@@ -659,6 +680,37 @@ export class MoondogApplication {
|
|
|
659
680
|
...(compiled.bpm ? { bpm: compiled.bpm } : {}), elapsed_ms: made.elapsed_ms };
|
|
660
681
|
}
|
|
661
682
|
|
|
683
|
+
// The agent writes a record's title itself, but can follow the conversation's language instead of
|
|
684
|
+
// the one Moondog is set to. A title in another language is named again in the setting's language,
|
|
685
|
+
// keeping its picture; if that cannot be done in time, the agent's title stays.
|
|
686
|
+
async #titleInSettingLanguage(compiled, nameRecord, signal) {
|
|
687
|
+
if (typeof nameRecord !== "function" || nameFitsLanguage(compiled.title, this.locale)) return compiled.title;
|
|
688
|
+
const terms = compiled.descriptors.map((descriptor) => descriptor.term);
|
|
689
|
+
const timeout = AbortSignal.timeout(TITLE_LANGUAGE_TIMEOUT_MS);
|
|
690
|
+
try {
|
|
691
|
+
const name = await Promise.race([
|
|
692
|
+
this.#streamNamer(nameRecord, compiled)({ draft: compiled.title, featured: terms.slice(0, 3), sound: terms.slice(3),
|
|
693
|
+
...(compiled.bpm ? { bpm: compiled.bpm } : {}), earlier: [] }, { signal: signal ? AbortSignal.any([signal, timeout]) : timeout }),
|
|
694
|
+
new Promise((resolve) => { timeout.addEventListener("abort", () => resolve(null), { once: true }); }),
|
|
695
|
+
]);
|
|
696
|
+
return name ?? compiled.title;
|
|
697
|
+
} catch {
|
|
698
|
+
return compiled.title;
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
// Names a stream's later tracks: the agent's namer asks the model, with the names of Moondog's recent
|
|
703
|
+
// tracks so it does not repeat them, and a name passes the same check as the agent's own titles and
|
|
704
|
+
// must be in the language Moondog is set to.
|
|
705
|
+
#streamNamer(nameRecord, compiled) {
|
|
706
|
+
return async (context, options) => {
|
|
707
|
+
const recent = (this.localGenerator?.recentTracks?.(8) ?? []).map((track) => track.title).filter(Boolean);
|
|
708
|
+
const name = acceptableRecordTitle(await nameRecord({ ...context, recent }, options), compiled.names);
|
|
709
|
+
// A name in another language than Moondog's setting is not kept.
|
|
710
|
+
return name && nameFitsLanguage(name, this.locale) ? name : null;
|
|
711
|
+
};
|
|
712
|
+
}
|
|
713
|
+
|
|
662
714
|
// A single track or a new stream takes over from a running stream, once its next track stops being made.
|
|
663
715
|
// The stream's track plays on until the new one starts, so nothing goes silent while that is made.
|
|
664
716
|
// Says whether a stream ended.
|
|
@@ -774,9 +826,10 @@ export class MoondogApplication {
|
|
|
774
826
|
return this.requireNetease().nowPlaying();
|
|
775
827
|
}
|
|
776
828
|
|
|
777
|
-
// Whether any player the listener uses can be read: the Music app, Spotify or NetEase.
|
|
829
|
+
// Whether any player the listener uses can be read: Moondog's own, the Music app, Spotify or NetEase.
|
|
778
830
|
listeningReadable() {
|
|
779
|
-
return this.
|
|
831
|
+
return typeof this.musicPreviewPlayer?.nowPlaying === "function" || this.musicApp?.available === true ||
|
|
832
|
+
this.spotifyReady() || this.neteaseReady();
|
|
780
833
|
}
|
|
781
834
|
|
|
782
835
|
// What the listener plays right now on any of them, and what it plays from (src/core/listening-now.mjs).
|
|
@@ -2183,6 +2236,10 @@ export class MoondogApplication {
|
|
|
2183
2236
|
const rest = new Set();
|
|
2184
2237
|
while (album && queue.at(-1)?.album_uri === album && !rest.has(queue.at(-1).uri)) rest.add(queue.pop().uri);
|
|
2185
2238
|
const seen = new Set([observed.currently_playing?.uri, ...queue.map(track => track.uri)].filter(Boolean));
|
|
2239
|
+
// With nothing playing and nothing queued, Spotify has dropped what Moondog queued (its device
|
|
2240
|
+
// went idle), so those songs were not heard: a new request may queue them again.
|
|
2241
|
+
// A player that could not be read says nothing, so the songs stay held back.
|
|
2242
|
+
if (!seen.size && player && player.is_playing !== true && !player.item) this.recentSimilarQueueUris.clear();
|
|
2186
2243
|
for (const [uri, acceptedAt] of this.recentSimilarQueueUris) {
|
|
2187
2244
|
if (Date.now() - acceptedAt > 15 * 60_000) this.recentSimilarQueueUris.delete(uri);
|
|
2188
2245
|
else seen.add(uri);
|
package/src/i18n/messages/de.mjs
CHANGED
|
@@ -132,7 +132,7 @@ export default {
|
|
|
132
132
|
"choice.retract": ({ title, artist }) => { const name = title ? `„${title}“ von ${artist}` : artist; return `\n\nZurückgenommen: deine frühere Wahl zu ${name}.`; },
|
|
133
133
|
"generate.made": ({ title, length, seed }) => `Auf diesem Mac mit Stable Audio 3 gemacht: „${title}“ (${length}, Seed ${seed}).`,
|
|
134
134
|
"generate.stream": ({ minutes }) => `Der Stream läuft auf diesem Mac weiter, jedes Mal mit einem neuen Stück, bis zu ${minutes} Minuten. Du kannst ihn jederzeit stoppen.`,
|
|
135
|
-
"onAir.request": "Geh auf Sendung:
|
|
135
|
+
"onAir.request": "Geh auf Sendung: Mach neue Musik für jetzt und lass sie weiterlaufen",
|
|
136
136
|
"turn.cancelled": "Weitere Schritte abgebrochen.",
|
|
137
137
|
"turn.interrupted": "Die Antwort wurde unterbrochen. Die erfassten Spotify-Ergebnisse stehen unten; keine Aktion wurde wiederholt.",
|
|
138
138
|
};
|
package/src/i18n/messages/en.mjs
CHANGED
|
@@ -134,7 +134,7 @@ export default {
|
|
|
134
134
|
"generate.made": ({ title, length, seed }) => `Made on this Mac with Stable Audio 3: "${title}" (${length}, seed ${seed}).`,
|
|
135
135
|
"generate.stream": ({ minutes }) => `The stream keeps going on this Mac, a new track each time, for up to ${minutes} minutes. Stop it any time.`,
|
|
136
136
|
// What the listener says to go on air, in the language the reply follows (/onair in the terminal).
|
|
137
|
-
"onAir.request": "Go on air:
|
|
137
|
+
"onAir.request": "Go on air: make new music for right now and keep it going",
|
|
138
138
|
"turn.cancelled": "Cancelled further work.",
|
|
139
139
|
"turn.interrupted": "The response was interrupted. The recorded Spotify outcomes are below; no action was replayed.",
|
|
140
140
|
};
|
package/src/i18n/messages/es.mjs
CHANGED
|
@@ -132,7 +132,7 @@ export default {
|
|
|
132
132
|
"choice.retract": ({ title, artist }) => { const name = title ? `"${title}" de ${artist}` : artist; return `\n\nDeshecho: tu elección anterior sobre ${name}.`; },
|
|
133
133
|
"generate.made": ({ title, length, seed }) => `Hecho en este Mac con Stable Audio 3: «${title}» (${length}, semilla ${seed}).`,
|
|
134
134
|
"generate.stream": ({ minutes }) => `El flujo sigue en este Mac, con una pista nueva cada vez, hasta ${minutes} minutos. Puedes pararlo cuando quieras.`,
|
|
135
|
-
"onAir.request": "Sal al aire:
|
|
135
|
+
"onAir.request": "Sal al aire: crea música nueva para este momento y que siga sonando",
|
|
136
136
|
"turn.cancelled": "Cancelé el resto.",
|
|
137
137
|
"turn.interrupted": "La respuesta se interrumpió. Abajo están los resultados registrados en Spotify; no se repitió ninguna acción.",
|
|
138
138
|
};
|
package/src/i18n/messages/fr.mjs
CHANGED
|
@@ -132,7 +132,7 @@ export default {
|
|
|
132
132
|
"choice.retract": ({ title, artist }) => { const name = title ? `« ${title} » de ${artist}` : artist; return `\n\nAnnulé : votre choix précédent sur ${name}.`; },
|
|
133
133
|
"generate.made": ({ title, length, seed }) => `Fait sur ce Mac avec Stable Audio 3 : « ${title} » (${length}, graine ${seed}).`,
|
|
134
134
|
"generate.stream": ({ minutes }) => `Le flux continue sur ce Mac, avec un nouveau morceau à chaque fois, jusqu'à ${minutes} minutes. Vous pouvez l'arrêter à tout moment.`,
|
|
135
|
-
"onAir.request": "Prends l'antenne :
|
|
135
|
+
"onAir.request": "Prends l'antenne : crée de la musique nouvelle pour ce moment et fais-la durer",
|
|
136
136
|
"turn.cancelled": "Suite annulée.",
|
|
137
137
|
"turn.interrupted": "La réponse a été interrompue. Les résultats Spotify enregistrés figurent ci-dessous ; aucune action n'a été relancée.",
|
|
138
138
|
};
|
package/src/i18n/messages/it.mjs
CHANGED
|
@@ -132,7 +132,7 @@ export default {
|
|
|
132
132
|
"choice.retract": ({ title, artist }) => { const name = title ? `"${title}" di ${artist}` : artist; return `\n\nAnnullato: la tua scelta precedente su ${name}.`; },
|
|
133
133
|
"generate.made": ({ title, length, seed }) => `Fatto su questo Mac con Stable Audio 3: «${title}» (${length}, seed ${seed}).`,
|
|
134
134
|
"generate.stream": ({ minutes }) => `Il flusso continua su questo Mac, con un brano nuovo ogni volta, fino a ${minutes} minuti. Puoi fermarlo quando vuoi.`,
|
|
135
|
-
"onAir.request": "Vai in onda:
|
|
135
|
+
"onAir.request": "Vai in onda: crea musica nuova per adesso e tienila accesa",
|
|
136
136
|
"turn.cancelled": "Ho annullato il resto.",
|
|
137
137
|
"turn.interrupted": "La risposta si è interrotta. Gli esiti di Spotify registrati sono qui sotto; nessuna azione è stata ripetuta.",
|
|
138
138
|
};
|
package/src/i18n/messages/ja.mjs
CHANGED
|
@@ -132,7 +132,7 @@ export default {
|
|
|
132
132
|
"choice.retract": ({ title, artist }) => { const name = title ? `${artist}の「${title}」` : artist; return `\n\n取り消しました: ${name}についての前の選択。`; },
|
|
133
133
|
"generate.made": ({ title, length, seed }) => `この Mac の Stable Audio 3 で作りました:「${title}」(${length}、シード ${seed})。`,
|
|
134
134
|
"generate.stream": ({ minutes }) => `この Mac で一曲ずつ新しい曲を作り続けます(最長 ${minutes} 分)。いつでも止められます。`,
|
|
135
|
-
"onAir.request": "
|
|
135
|
+
"onAir.request": "オンエアして。今の気分に合わせて新しい音楽を作って、流し続けて",
|
|
136
136
|
"turn.cancelled": "以降の処理をキャンセルしました。",
|
|
137
137
|
"turn.interrupted": "返事が中断されました。記録された Spotify の操作結果は下のとおりです。操作は繰り返していません。",
|
|
138
138
|
};
|
package/src/i18n/messages/ko.mjs
CHANGED
|
@@ -132,7 +132,7 @@ export default {
|
|
|
132
132
|
"choice.retract": ({ title, artist }) => { const name = title ? `${artist}의 "${title}"` : artist; return `\n\n취소했습니다: ${name}에 대한 이전 선택.`; },
|
|
133
133
|
"generate.made": ({ title, length, seed }) => `이 Mac의 Stable Audio 3로 만들었습니다: "${title}" (${length}, 시드 ${seed}).`,
|
|
134
134
|
"generate.stream": ({ minutes }) => `이 Mac에서 매번 새 곡을 만들며 최대 ${minutes}분 동안 이어집니다. 언제든 멈출 수 있습니다.`,
|
|
135
|
-
"onAir.request": "방송 시작해 줘. 지금 분위기에 맞춰 음악을 계속 틀어 줘",
|
|
135
|
+
"onAir.request": "방송 시작해 줘. 지금 분위기에 맞춰 새 음악을 만들어서 계속 틀어 줘",
|
|
136
136
|
"turn.cancelled": "남은 작업을 취소했습니다.",
|
|
137
137
|
"turn.interrupted": "답변이 중단되었습니다. 기록된 Spotify 결과는 아래와 같으며, 어떤 작업도 다시 실행하지 않았습니다.",
|
|
138
138
|
};
|
package/src/i18n/messages/pt.mjs
CHANGED
|
@@ -132,7 +132,7 @@ export default {
|
|
|
132
132
|
"choice.retract": ({ title, artist }) => { const name = title ? `"${title}" de ${artist}` : artist; return `\n\nDesfeito: sua escolha anterior sobre ${name}.`; },
|
|
133
133
|
"generate.made": ({ title, length, seed }) => `Feito neste Mac com o Stable Audio 3: "${title}" (${length}, semente ${seed}).`,
|
|
134
134
|
"generate.stream": ({ minutes }) => `O fluxo continua neste Mac, com uma faixa nova a cada vez, por até ${minutes} minutos. Pare quando quiser.`,
|
|
135
|
-
"onAir.request": "Entre no ar:
|
|
135
|
+
"onAir.request": "Entre no ar: crie música nova para agora e mantenha tocando",
|
|
136
136
|
"turn.cancelled": "Cancelei o resto.",
|
|
137
137
|
"turn.interrupted": "A resposta foi interrompida. Abaixo estão os resultados registrados no Spotify; nenhuma ação foi repetida.",
|
|
138
138
|
};
|
|
@@ -132,7 +132,7 @@ export default {
|
|
|
132
132
|
"choice.retract": ({ title, artist }) => { const name = title ? `${artist}的《${title}》` : artist; return `\n\n已撤銷:你之前對${name}的選擇。`; },
|
|
133
133
|
"generate.made": ({ title, length, seed }) => `用這台 Mac 上的 Stable Audio 3 做的:「${title}」(${length},種子 ${seed})。`,
|
|
134
134
|
"generate.stream": ({ minutes }) => `音樂流會在這台 Mac 上一首接一首地做下去,最多 ${minutes} 分鐘,隨時可以停。`,
|
|
135
|
-
"onAir.request": "
|
|
135
|
+
"onAir.request": "開播吧:照現在的感覺做新的音樂,一直放下去",
|
|
136
136
|
"turn.cancelled": "已取消後續操作。",
|
|
137
137
|
"turn.interrupted": "回覆中斷了。已記錄的 Spotify 結果如下;沒有重新執行任何操作。",
|
|
138
138
|
};
|
package/src/i18n/messages/zh.mjs
CHANGED
|
@@ -132,7 +132,7 @@ export default {
|
|
|
132
132
|
"choice.retract": ({ title, artist }) => { const name = title ? `${artist}的《${title}》` : artist; return `\n\n已撤销:你之前对${name}的选择。`; },
|
|
133
133
|
"generate.made": ({ title, length, seed }) => `用这台 Mac 上的 Stable Audio 3 做的:「${title}」(${length},种子 ${seed})。`,
|
|
134
134
|
"generate.stream": ({ minutes }) => `音乐流会在这台 Mac 上一首接一首地做下去,最多 ${minutes} 分钟,随时可以停。`,
|
|
135
|
-
"onAir.request": "
|
|
135
|
+
"onAir.request": "开播吧:按现在的感觉做新的音乐,一直放下去",
|
|
136
136
|
"turn.cancelled": "已取消后续操作。",
|
|
137
137
|
"turn.interrupted": "回复中断;已确认的 Spotify 操作结果如下。未重新执行任何操作。",
|
|
138
138
|
};
|
package/src/i18n/screen/es.mjs
CHANGED
|
@@ -1060,4 +1060,62 @@ export default {
|
|
|
1060
1060
|
"The next record is still being cut.": "El siguiente disco aún se está grabando.",
|
|
1061
1061
|
"Off air.": "Fuera del aire.",
|
|
1062
1062
|
"Turn on music making first: /generation on.": "Primero activa la creación de música: /generation on.",
|
|
1063
|
+
"Download a Stable Audio 3 model from Stability AI": "Descargar un modelo de Stable Audio 3 de Stability AI",
|
|
1064
|
+
"Make music with a downloaded model": "Hacer música con un modelo descargado",
|
|
1065
|
+
"Delete a downloaded model from this Mac": "Borrar de este Mac un modelo descargado",
|
|
1066
|
+
"Stop the download": "Detener la descarga",
|
|
1067
|
+
"Medium: best sound, about 5.2 GB": "Medium: el mejor sonido, unos 5,2 GB",
|
|
1068
|
+
"Small Music: faster, lighter, about 1.7 GB": "Small Music: más rápido y ligero, unos 1,7 GB",
|
|
1069
|
+
"getting ready": "preparando",
|
|
1070
|
+
"There isn't enough free space on this Mac for the download. Free some up, then use /generation download again.": "No hay espacio libre suficiente en este Mac para la descarga. Libera algo y vuelve a usar /generation download.",
|
|
1071
|
+
"A downloaded file didn't match the one Stability AI publishes, so Moondog deleted it. Use /generation download to try again.": "Un archivo descargado no coincidía con el que publica Stability AI, así que Moondog lo borró. Usa /generation download para intentarlo de nuevo.",
|
|
1072
|
+
"The download couldn't reach its source. Check your connection, then use /generation download to try again.": "La descarga no pudo llegar a su origen. Revisa tu conexión y usa /generation download para intentarlo de nuevo.",
|
|
1073
|
+
"Another Moondog window or terminal is already downloading. /generation shows how far it is.": "Otra ventana o terminal de Moondog ya está descargando. /generation muestra cuánto lleva.",
|
|
1074
|
+
"The download didn't finish: {error}. Use /generation download to try again.": "La descarga no terminó: {error}. Usa /generation download para intentarlo de nuevo.",
|
|
1075
|
+
"unknown error": "error desconocido",
|
|
1076
|
+
"Stable Audio 3 {model} is ready. Ask for a track.": "Stable Audio 3 {model} está listo. Pide una pista.",
|
|
1077
|
+
"Stable Audio 3 {model} is downloaded. Use it with /generation use {choice}.": "Stable Audio 3 {model} está descargado. Úsalo con /generation use {choice}.",
|
|
1078
|
+
"Download stopped. /generation download {choice} picks it up where it left off.": "Descarga detenida. /generation download {choice} sigue donde se quedó.",
|
|
1079
|
+
"download stopped on an error": "descarga detenida por un error",
|
|
1080
|
+
"downloading": "descargando",
|
|
1081
|
+
"downloading, {percent}%": "descargando, {percent}%",
|
|
1082
|
+
"installed, in use": "instalado, en uso",
|
|
1083
|
+
"installed": "instalado",
|
|
1084
|
+
"partly downloaded": "descargado en parte",
|
|
1085
|
+
"not downloaded": "sin descargar",
|
|
1086
|
+
"{size} GB": "{size} GB",
|
|
1087
|
+
"In use: your own install at {folder}.": "En uso: tu propia instalación en {folder}.",
|
|
1088
|
+
"Get a model with /generation download medium or small. /generation use, remove and cancel manage them.": "Consigue un modelo con /generation download medium o small. /generation use, remove y cancel los gestionan.",
|
|
1089
|
+
"Making music on this Mac is off. Get Stable Audio 3 with /generation download medium, or small for a lighter model; music making turns on when it's done.": "Hacer música en este Mac está desactivado. Consigue Stable Audio 3 con /generation download medium, o small para un modelo más ligero; la creación de música se activa al terminar.",
|
|
1090
|
+
"Stable Audio 3 {model} isn't downloaded yet. Get it with /generation download {choice}.": "Stable Audio 3 {model} aún no está descargado. Consíguelo con /generation download {choice}.",
|
|
1091
|
+
"Making music on this Mac is off. Stable Audio 3 {model} is ready; turn it on with /generation on.": "Hacer música en este Mac está desactivado. Stable Audio 3 {model} está listo; actívalo con /generation on.",
|
|
1092
|
+
"Use /generation download, use or remove with medium or small, or /generation cancel.": "Usa /generation download, use o remove con medium o small, o /generation cancel.",
|
|
1093
|
+
"No download is running.": "No hay ninguna descarga en curso.",
|
|
1094
|
+
"Stable Audio 3 {model} is already downloading.": "Stable Audio 3 {model} ya se está descargando.",
|
|
1095
|
+
"Another download is running. /generation cancel stops it.": "Hay otra descarga en curso. /generation cancel la detiene.",
|
|
1096
|
+
"Stable Audio 3 {model} is already on this Mac. Use it with /generation use {choice}.": "Stable Audio 3 {model} ya está en este Mac. Úsalo con /generation use {choice}.",
|
|
1097
|
+
"Already downloaded.": "Ya está descargado.",
|
|
1098
|
+
"Stable Audio 3 comes under the Stability AI Community License ({license}), and its text encoder, T5Gemma, under the Gemma Terms of Use ({gemma}). Moondog downloads it only from Stability AI's official sources and checks every file.\n\nTo agree and download {model} ({size} GB): /generation download {choice} --agree": "Stable Audio 3 se rige por la Stability AI Community License ({license}), y su codificador de texto, T5Gemma, por los Gemma Terms of Use ({gemma}). Moondog lo descarga solo de las fuentes oficiales de Stability AI y comprueba cada archivo.\n\nPara aceptar y descargar {model} ({size} GB): /generation download {choice} --agree",
|
|
1099
|
+
"Waiting for your agreement.": "Esperando tu aceptación.",
|
|
1100
|
+
"The download didn't finish.": "La descarga no terminó.",
|
|
1101
|
+
"Downloading Stable Audio 3 {model} ({size} GB) from Stability AI's official sources. It runs in the background; /generation cancel stops it, and a later download picks up where it left off.": "Descargando Stable Audio 3 {model} ({size} GB) de las fuentes oficiales de Stability AI. Sigue en segundo plano; /generation cancel la detiene, y una descarga posterior sigue donde se quedó.",
|
|
1102
|
+
"Downloading Stable Audio 3 {model}.": "Descargando Stable Audio 3 {model}.",
|
|
1103
|
+
"Wait for the download to finish, or stop it with /generation cancel, before removing a model.": "Espera a que termine la descarga, o detenla con /generation cancel, antes de quitar un modelo.",
|
|
1104
|
+
"A download is running.": "Hay una descarga en curso.",
|
|
1105
|
+
"Stable Audio 3 {model} isn't on this Mac.": "Stable Audio 3 {model} no está en este Mac.",
|
|
1106
|
+
"Removing Stable Audio 3 {model} deletes its {size} GB from this Mac. It's the last model, so the rest of Moondog's Stable Audio 3 setup goes too. To go ahead: /generation remove {choice} --yes": "Quitar Stable Audio 3 {model} borra sus {size} GB de este Mac. Es el último modelo, así que también se va el resto de la instalación de Stable Audio 3 de Moondog. Para seguir: /generation remove {choice} --yes",
|
|
1107
|
+
"Removing Stable Audio 3 {model} deletes its {size} GB from this Mac. To go ahead: /generation remove {choice} --yes": "Quitar Stable Audio 3 {model} borra sus {size} GB de este Mac. Para seguir: /generation remove {choice} --yes",
|
|
1108
|
+
"Nothing removed yet.": "Aún no se ha quitado nada.",
|
|
1109
|
+
"Removed Stable Audio 3 {model} from this Mac.": "Stable Audio 3 {model} quitado de este Mac.",
|
|
1110
|
+
"Removed.": "Quitado.",
|
|
1111
|
+
"Removed. Music making isn't ready.": "Quitado. La creación de música no está lista.",
|
|
1112
|
+
"Use /generation, /generation on [folder] or off, or /generation download, use or remove with medium or small.": "Usa /generation, /generation on [carpeta] u off, o /generation download, use o remove con medium o small.",
|
|
1113
|
+
"best sound": "el mejor sonido",
|
|
1114
|
+
"faster, lighter": "más rápido y ligero",
|
|
1115
|
+
"getting uv": "obteniendo uv",
|
|
1116
|
+
"getting Stable Audio 3's code": "obteniendo el código de Stable Audio 3",
|
|
1117
|
+
"setting up Python": "preparando Python",
|
|
1118
|
+
"downloading the model": "descargando el modelo",
|
|
1119
|
+
"checking the files": "comprobando los archivos",
|
|
1120
|
+
"Stable Audio 3's Python environment couldn't be set up. Check your connection, then use /generation download to try again.": "No se pudo preparar el entorno de Python de Stable Audio 3. Revisa tu conexión y usa /generation download para intentarlo de nuevo.",
|
|
1063
1121
|
};
|
package/src/i18n/screen/ja.mjs
CHANGED
|
@@ -1060,4 +1060,62 @@ export default {
|
|
|
1060
1060
|
"The next record is still being cut.": "次のレコードはまだカッティング中です。",
|
|
1061
1061
|
"Off air.": "オフエアにしました。",
|
|
1062
1062
|
"Turn on music making first: /generation on.": "先に音楽作りをオンにしてください:/generation on。",
|
|
1063
|
+
"Download a Stable Audio 3 model from Stability AI": "Stability AI から Stable Audio 3 のモデルをダウンロードする",
|
|
1064
|
+
"Make music with a downloaded model": "ダウンロードしたモデルで音楽を作る",
|
|
1065
|
+
"Delete a downloaded model from this Mac": "ダウンロードしたモデルをこの Mac から削除する",
|
|
1066
|
+
"Stop the download": "ダウンロードを止める",
|
|
1067
|
+
"Medium: best sound, about 5.2 GB": "Medium:いちばん良い音、約 5.2 GB",
|
|
1068
|
+
"Small Music: faster, lighter, about 1.7 GB": "Small Music:速くて軽い、約 1.7 GB",
|
|
1069
|
+
"getting ready": "準備中",
|
|
1070
|
+
"There isn't enough free space on this Mac for the download. Free some up, then use /generation download again.": "この Mac にはダウンロードに足りる空き容量がありません。空きを作ってから、もう一度 /generation download を使ってください。",
|
|
1071
|
+
"A downloaded file didn't match the one Stability AI publishes, so Moondog deleted it. Use /generation download to try again.": "ダウンロードしたファイルが Stability AI の公開しているものと一致しなかったため、Moondog が削除しました。/generation download でやり直してください。",
|
|
1072
|
+
"The download couldn't reach its source. Check your connection, then use /generation download to try again.": "ダウンロード元に接続できませんでした。接続を確かめてから、/generation download でやり直してください。",
|
|
1073
|
+
"Another Moondog window or terminal is already downloading. /generation shows how far it is.": "別の Moondog のウィンドウかターミナルがすでにダウンロードしています。/generation で進み具合がわかります。",
|
|
1074
|
+
"The download didn't finish: {error}. Use /generation download to try again.": "ダウンロードが終わりませんでした:{error}。/generation download でやり直してください。",
|
|
1075
|
+
"unknown error": "不明なエラー",
|
|
1076
|
+
"Stable Audio 3 {model} is ready. Ask for a track.": "Stable Audio 3 {model} の準備ができました。曲をリクエストしてください。",
|
|
1077
|
+
"Stable Audio 3 {model} is downloaded. Use it with /generation use {choice}.": "Stable Audio 3 {model} をダウンロードしました。/generation use {choice} で使えます。",
|
|
1078
|
+
"Download stopped. /generation download {choice} picks it up where it left off.": "ダウンロードを止めました。/generation download {choice} で続きから再開します。",
|
|
1079
|
+
"download stopped on an error": "エラーでダウンロードが止まりました",
|
|
1080
|
+
"downloading": "ダウンロード中",
|
|
1081
|
+
"downloading, {percent}%": "ダウンロード中、{percent}%",
|
|
1082
|
+
"installed, in use": "インストール済み、使用中",
|
|
1083
|
+
"installed": "インストール済み",
|
|
1084
|
+
"partly downloaded": "一部ダウンロード済み",
|
|
1085
|
+
"not downloaded": "未ダウンロード",
|
|
1086
|
+
"{size} GB": "{size} GB",
|
|
1087
|
+
"In use: your own install at {folder}.": "使用中:{folder} にある自分のインストール。",
|
|
1088
|
+
"Get a model with /generation download medium or small. /generation use, remove and cancel manage them.": "/generation download medium か small でモデルを入手します。/generation use、remove、cancel で管理します。",
|
|
1089
|
+
"Making music on this Mac is off. Get Stable Audio 3 with /generation download medium, or small for a lighter model; music making turns on when it's done.": "この Mac での音楽作りはオフです。/generation download medium で Stable Audio 3 を入手してください。軽いモデルなら small です。終わると音楽作りがオンになります。",
|
|
1090
|
+
"Stable Audio 3 {model} isn't downloaded yet. Get it with /generation download {choice}.": "Stable Audio 3 {model} はまだダウンロードされていません。/generation download {choice} で入手してください。",
|
|
1091
|
+
"Making music on this Mac is off. Stable Audio 3 {model} is ready; turn it on with /generation on.": "この Mac での音楽作りはオフです。Stable Audio 3 {model} は準備できています。/generation on でオンにしてください。",
|
|
1092
|
+
"Use /generation download, use or remove with medium or small, or /generation cancel.": "/generation download、use、remove に medium か small を付けるか、/generation cancel を使ってください。",
|
|
1093
|
+
"No download is running.": "実行中のダウンロードはありません。",
|
|
1094
|
+
"Stable Audio 3 {model} is already downloading.": "Stable Audio 3 {model} はすでにダウンロード中です。",
|
|
1095
|
+
"Another download is running. /generation cancel stops it.": "別のダウンロードが実行中です。/generation cancel で止まります。",
|
|
1096
|
+
"Stable Audio 3 {model} is already on this Mac. Use it with /generation use {choice}.": "Stable Audio 3 {model} はすでにこの Mac にあります。/generation use {choice} で使えます。",
|
|
1097
|
+
"Already downloaded.": "ダウンロード済みです。",
|
|
1098
|
+
"Stable Audio 3 comes under the Stability AI Community License ({license}), and its text encoder, T5Gemma, under the Gemma Terms of Use ({gemma}). Moondog downloads it only from Stability AI's official sources and checks every file.\n\nTo agree and download {model} ({size} GB): /generation download {choice} --agree": "Stable Audio 3 は Stability AI Community License({license})に、そのテキストエンコーダー T5Gemma は Gemma Terms of Use({gemma})に従います。Moondog は Stability AI の公式の配布元からのみダウンロードし、すべてのファイルを確かめます。\n\n同意して {model}({size} GB)をダウンロードするには:/generation download {choice} --agree",
|
|
1099
|
+
"Waiting for your agreement.": "同意を待っています。",
|
|
1100
|
+
"The download didn't finish.": "ダウンロードが終わりませんでした。",
|
|
1101
|
+
"Downloading Stable Audio 3 {model} ({size} GB) from Stability AI's official sources. It runs in the background; /generation cancel stops it, and a later download picks up where it left off.": "Stability AI の公式の配布元から Stable Audio 3 {model}({size} GB)をダウンロードしています。バックグラウンドで進みます。/generation cancel で止まり、後のダウンロードは続きから再開します。",
|
|
1102
|
+
"Downloading Stable Audio 3 {model}.": "Stable Audio 3 {model} をダウンロードしています。",
|
|
1103
|
+
"Wait for the download to finish, or stop it with /generation cancel, before removing a model.": "モデルを削除する前に、ダウンロードが終わるのを待つか、/generation cancel で止めてください。",
|
|
1104
|
+
"A download is running.": "ダウンロードが実行中です。",
|
|
1105
|
+
"Stable Audio 3 {model} isn't on this Mac.": "Stable Audio 3 {model} はこの Mac にありません。",
|
|
1106
|
+
"Removing Stable Audio 3 {model} deletes its {size} GB from this Mac. It's the last model, so the rest of Moondog's Stable Audio 3 setup goes too. To go ahead: /generation remove {choice} --yes": "Stable Audio 3 {model} を削除すると、この Mac からその {size} GB が消えます。最後のモデルなので、Moondog の Stable Audio 3 のほかの部分も消えます。進めるには:/generation remove {choice} --yes",
|
|
1107
|
+
"Removing Stable Audio 3 {model} deletes its {size} GB from this Mac. To go ahead: /generation remove {choice} --yes": "Stable Audio 3 {model} を削除すると、この Mac からその {size} GB が消えます。進めるには:/generation remove {choice} --yes",
|
|
1108
|
+
"Nothing removed yet.": "まだ何も削除していません。",
|
|
1109
|
+
"Removed Stable Audio 3 {model} from this Mac.": "Stable Audio 3 {model} をこの Mac から削除しました。",
|
|
1110
|
+
"Removed.": "削除しました。",
|
|
1111
|
+
"Removed. Music making isn't ready.": "削除しました。音楽作りの準備ができていません。",
|
|
1112
|
+
"Use /generation, /generation on [folder] or off, or /generation download, use or remove with medium or small.": "/generation、/generation on [フォルダ] か off、または /generation download、use、remove に medium か small を付けて使ってください。",
|
|
1113
|
+
"best sound": "いちばん良い音",
|
|
1114
|
+
"faster, lighter": "速くて軽い",
|
|
1115
|
+
"getting uv": "uv を取得中",
|
|
1116
|
+
"getting Stable Audio 3's code": "Stable Audio 3 のコードを取得中",
|
|
1117
|
+
"setting up Python": "Python を準備中",
|
|
1118
|
+
"downloading the model": "モデルをダウンロード中",
|
|
1119
|
+
"checking the files": "ファイルを確認中",
|
|
1120
|
+
"Stable Audio 3's Python environment couldn't be set up. Check your connection, then use /generation download to try again.": "Stable Audio 3 の Python 環境を準備できませんでした。接続を確かめてから、/generation download でやり直してください。",
|
|
1063
1121
|
};
|