Files
Claude fe8e08d8cf fix(tts): follow Anomalous_TTS interface 13, no local paths
Anomalous_TTS no longer takes a folder or file path on this computer from
a request (ComfyUI-Manager review of the node): the storage place, other
character folders and pretrained sources are set only in its settings
file, and imported files are always uploaded.

- GPT-SoVITS settings shows the storage place, other places and package
  sources without change, move or remove buttons, and names the node's
  settings file (status.settings_file) with a copy button and how to edit it.
- The import window drops "from this computer": no server path picker
  (ui_tts_path_picker.js is gone), no local folder scan or local clip
  preview; a very large upload is confirmed instead.
- tts_setup_api.js loses the removed routes; formatSize moves there.
- The storage-change activity entry, unused locale keys and picker CSS go.

Verified: tools/check_structure.mjs; tts_setup_api in Node with fetch
stubbed; the settings card, batch hero, add menu, file sources and player
rendered with jsdom and stubbed ComfyUI scripts. Not run in ComfyUI.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018P2T2R7TFbJsc3C9maCD8B
2026-10-08 20:21:50 +00:00

58 lines
1.9 KiB
JavaScript

import { t } from './interface_settings.js';
/**
* Listening to clips in the import window, while they upload or wait unassigned:
* one clip at a time, its row marked and its button turned into "stop"; clicking
* another clip switches to it, so clips can be compared one after another. Files play
* from memory (`row.url`, an object URL the window revokes with the row).
*/
export function createImportPlayer() {
let audio = null;
let current = null;
const mark = (row, playing, error = '') => {
const button = row?.els?.play;
if (!button) return;
button.textContent = playing ? '■' : '▶';
button.title = error ? t('ttsPreviewFailed', { error }) : t(playing ? 'ttsPreviewStop' : 'audioPlay');
button.setAttribute('aria-label', button.title);
button.classList.toggle('is-failed', Boolean(error));
row.els.root.classList.toggle('is-playing', playing);
};
function stop() {
audio?.pause();
audio = null;
mark(current, false);
current = null;
}
/** Play `row`, or stop it when it is the one playing. */
function toggle(row) {
if (current === row) { stop(); return; }
stop();
if (!row.file) return;
row.url = row.url || URL.createObjectURL(row.file);
const mine = new Audio(row.url);
audio = mine;
current = row;
mark(row, true);
const fail = (error) => {
if (audio !== mine) return;
audio = null;
current = null;
mark(row, false, error);
};
mine.onended = () => { if (audio === mine) stop(); };
mine.onerror = () => fail(mine.error?.message || t('ttsPreviewUnreadable'));
mine.play().catch(e => fail(e.message || String(e)));
}
return {
toggle,
stop,
/** A row leaves the window: stop it if it is playing. */
forget: (row) => { if (current === row) stop(); },
};
}