tts-voice-creator-clone-and.../static/js/rehearser-library.js

63 lines
3.0 KiB
JavaScript

// ── Rehearser library persistence ────────────────────────────────────────────
// SQLite-backed rehearsal records and the one-time IndexedDB migration are
// isolated from parsing, casting, and stage playback. Functions stay global
// during the compatibility migration because audiobook.js/library.js call them.
async function rehDbGetAll() {
const r = await fetch('/api/rehearsals');
if (!r.ok) throw new Error('rehDbGetAll failed: ' + r.status);
const d = await r.json();
return d.rehearsals || [];
}
async function rehDbGetById(id) {
const r = await fetch('/api/rehearsals/' + id);
if (r.status === 404) return undefined;
if (!r.ok) throw new Error('rehDbGetById failed: ' + r.status);
return r.json();
}
async function rehDbAdd(record) {
const r = await fetch('/api/rehearsals', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(_rehSanitize(record)) });
if (!r.ok) throw new Error('rehDbAdd failed: ' + r.status);
return (await r.json()).id;
}
async function rehDbPut(record) {
if (!record.id) return rehDbAdd(record);
const r = await fetch('/api/rehearsals/' + record.id, { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(_rehSanitize(record)) });
if (!r.ok) throw new Error('rehDbPut failed: ' + r.status);
}
async function rehDbDelete(id) {
const r = await fetch('/api/rehearsals/' + id, { method: 'DELETE' });
if (!r.ok) throw new Error('rehDbDelete failed: ' + r.status);
}
function _rehSanitize(rec) {
const out = { ...rec };
if (out.clips) out.clips = (out.clips || []).map(c => ({ lineIndex: c.lineIndex, speaker: c.speaker, type: c.type }));
return out;
}
function _rehIdbGetAll() {
return new Promise(resolve => {
const req = indexedDB.open('reh-library', 1);
req.onerror = () => resolve([]);
req.onsuccess = e => {
const db = e.target.result;
if (!db.objectStoreNames.contains('rehearsals')) { db.close(); resolve([]); return; }
const all = db.transaction('rehearsals', 'readonly').objectStore('rehearsals').getAll();
all.onsuccess = ev => { db.close(); resolve(ev.target.result || []); };
all.onerror = () => { db.close(); resolve([]); };
};
});
}
(async function _rehMigrateIfNeeded() {
try {
if ((await rehDbGetAll()).length) return;
const old = await _rehIdbGetAll();
if (!old.length) return;
const r = await fetch('/api/rehearsals/migrate', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(old.map(_rehSanitize)) });
if (r.ok) console.log(`[rehearser] migrated ${(await r.json()).imported} records from IndexedDB → SQLite`);
} catch (e) { console.warn('[rehearser] migration skipped:', e); }
})();
window.rehDbGetById = rehDbGetById;
window.TTVC = window.TTVC || {};
window.TTVC.rehearser = window.TTVC.rehearser || {};
window.TTVC.rehearser.library = { rehDbGetAll, rehDbGetById, rehDbPut, rehDbDelete };