Edit emotions: list every clip, and let the line follow the clip

The audio boxes are a native datalist, which lists only files whose names contain
the box's text, so a filled box showed one or two clips. Pressing a box now empties
it to list all of them (the file shows as the placeholder) and puts the file back
when nothing is picked; Backspace or Delete really clears it.

Picking another clip kept the old clip's line next to it. The line box now follows:
the line it had for the first clip, the line the node already reads for a clip in
use, or blank, which makes the node read the clip's own .txt / .lab / list line.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
DemonGatanjieu
2026-10-10 11:39:15 +08:00
co-authored by Claude Opus 5.5
parent bd9afedb68
commit a3ee55dfd2
2 changed files with 36 additions and 0 deletions
+3
View File
@@ -24,6 +24,9 @@
- The settings page is split into tabs: **Look, Models, Workflows, Prompts, Backup, Help**. "Change where downloads go" opens Models directly.
- **Where downloads (and now imports) go is a choice**: by base model (the new default), in Downloads then by base model, all in a Downloads folder, straight in the type's folder, or your own folder typed by hand; an example path shows the result. Without a saved setting, downloads now go by base model instead of into a Downloads folder.
### Fixes
- **Edit emotions: every clip in the list, and the line follows the clip (编辑情绪:下拉列出全部音频,换音频台词跟着换)**: a box that already held a file listed only the files whose names contain it (the browser filters by the box's text), so a character's other clips seemed missing. Pressing the box now lists all of them, with the current file shown greyed; leaving without a pick keeps it. Picking another clip no longer keeps the old clip's line beside it: the line the node already reads for that clip is filled in, otherwise the box is left blank and the node reads the clip's own line (its .txt / .lab or the annotation list) when it speaks; going back to the first clip brings its line back.
## v1.59.0 Beta (Model Downloads, Backup, Share Codes, Node Combos, MCP, Light Theme) — unreleased
### ⬇️ Download missing models from Model Check (模型检查一键下载缺失模型)
+33
View File
@@ -39,6 +39,24 @@ function audioInput(listId, value) {
input.setAttribute('list', listId);
input.placeholder = t('ttsEditorAudioPlaceholder');
input.value = value || '';
// The browser lists only the files matching the box's text, so a filled box offered one or
// two. Pressing it empties the box to list them all (the file shows greyed meanwhile);
// leaving without a pick puts the file back, unless it was deleted with a key.
let kept = '';
input.addEventListener('mousedown', () => {
if (!input.value) return;
kept = input.value;
input.placeholder = kept;
input.value = '';
});
input.addEventListener('keydown', (e) => {
if (e.key === 'Backspace' || e.key === 'Delete') kept = '';
});
input.addEventListener('blur', () => {
if (!input.value) input.value = kept;
kept = '';
input.placeholder = t('ttsEditorAudioPlaceholder');
});
return input;
}
@@ -82,6 +100,19 @@ export function openGptSovitsEditor(group, { onSaved } = {}) {
close();
}, true);
// A picked file gets its own line: the one it had in this dialog, the line the node read for it
// when it is in use already, or blank, which the node fills from the file's .txt / .lab / list.
const knownText = new Map([raw.reference, ...Object.values(raw.emotions || {})]
.filter(ref => ref?.audio && ref.text).map(ref => [ref.audio, ref.text]));
const linkText = (audio, text) => {
const start = { audio: audio.value.trim(), text: text.value };
audio.addEventListener('input', () => {
const path = audio.value.trim();
if (!audioList.includes(path)) return;
text.value = path === start.audio ? start.text : knownText.get(path) || '';
});
};
const play = (input) => {
player?.pause();
const path = input.value.trim();
@@ -107,6 +138,7 @@ export function openGptSovitsEditor(group, { onSaved } = {}) {
const mainRow = el('div', 'anomalous-tts-row is-main');
const mainAudio = audioInput(listId, settings.reference?.audio);
const mainText = textInput(settings.reference?.text);
linkText(mainAudio, mainText);
mainRow.append(
el('span', 'anomalous-tts-row-name', '{main}'),
mainAudio,
@@ -127,6 +159,7 @@ export function openGptSovitsEditor(group, { onSaved } = {}) {
nameInput.value = row.name || '';
const audio = audioInput(listId, row.audio);
const text = textInput(row.text);
linkText(audio, text);
line.append(
nameInput,
audio,