tts-voice-creator-clone-and.../static/js/voice-cache.js

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;
})();