42 lines
1.7 KiB
JavaScript
42 lines
1.7 KiB
JavaScript
// Shared voice-library cache. The backend index is authoritative; this layer
|
|
// prevents multiple frontend panels from starting duplicate scans in one tab.
|
|
(function installVoiceLibraryCache() {
|
|
const KEY = 'ttsvc_voice_library_cache_v2';
|
|
const MAX_AGE_MS = 30_000;
|
|
let inFlight = null;
|
|
|
|
function read() {
|
|
try {
|
|
const value = JSON.parse(sessionStorage.getItem(KEY) || 'null');
|
|
if (!value || !Array.isArray(value.voices) || !Number.isFinite(value.savedAt)) return null;
|
|
return Date.now() - value.savedAt <= MAX_AGE_MS ? value.voices : null;
|
|
} catch (_) { return null; }
|
|
}
|
|
function write(voices) {
|
|
try { sessionStorage.setItem(KEY, JSON.stringify({ savedAt: Date.now(), voices })); } catch (_) {}
|
|
}
|
|
function invalidate() {
|
|
try { sessionStorage.removeItem(KEY); } catch (_) {}
|
|
}
|
|
async function fetchVoices(options = {}) {
|
|
const refresh = options === true || options.refresh === true;
|
|
if (!refresh) {
|
|
const cached = read();
|
|
if (cached) return cached;
|
|
}
|
|
if (inFlight) return inFlight;
|
|
inFlight = fetch('/api/voices' + (refresh ? '?refresh=1' : ''), { cache: 'no-store' })
|
|
.then(async response => {
|
|
if (!response.ok) { const error = await response.json().catch(() => ({})); throw new Error(error.detail || response.statusText); }
|
|
const voices = await response.json();
|
|
if (!Array.isArray(voices)) throw new Error('Voice library response was not an array');
|
|
write(voices);
|
|
return voices;
|
|
})
|
|
.finally(() => { inFlight = null; });
|
|
return inFlight;
|
|
}
|
|
window.fetchVoiceLibrary = fetchVoices;
|
|
window.invalidateVoiceLibraryCache = invalidate;
|
|
})();
|