// ---------- Хранилище (IndexedDB + localStorage) ---------- function openRecDB() { return new Promise((resolve, reject) => { const req = indexedDB.open('lyngvo_recs', 1); req.onupgradeneeded = () => { req.result.createObjectStore('recs', { keyPath: 'id', autoIncrement: true }); }; req.onsuccess = () => resolve(req.result); req.onerror = () => reject(req.error); }); } async function saveTranscription(id, text) { try { const db = await openRecDB(); const tx = db.transaction('recs', 'readwrite'); const store = tx.objectStore('recs'); const rec = await new Promise(r => { const req = store.get(id); req.onsuccess = () => r(req.result); }); if (rec) { rec.transcription = text; store.put(rec); } await new Promise(r => { tx.oncomplete = r; }); renderRecHistory(); } catch(e) { /* тихо */ } } async function saveRecording(blob, word, duration) { try { const db = await openRecDB(); const tx = db.transaction('recs', 'readwrite'); const store = tx.objectStore('recs'); store.add({ word, duration, blob, ts: Date.now() }); const all = await new Promise(r => { const req = store.getAll(); req.onsuccess = () => r(req.result); }); if (all.length > 10) { const toDelete = all.sort((a,b) => a.ts - b.ts).slice(0, all.length - 10); for (const rec of toDelete) store.delete(rec.id); } await new Promise(r => { tx.oncomplete = r; }); renderRecHistory(); } catch(e) { /* тихо */ } } async function loadRecordings() { try { const db = await openRecDB(); const tx = db.transaction('recs', 'readonly'); const store = tx.objectStore('recs'); const all = await new Promise(r => { const req = store.getAll(); req.onsuccess = () => r(req.result); }); return all.sort((a,b) => b.ts - a.ts); } catch(e) { return []; } } async function renderRecHistory() { const recs = await loadRecordings(); const div = document.getElementById('recHistory'); if (!recs.length) { div.innerHTML = ''; return; } div.innerHTML = '
📼 История записей (выберите для стерео):
' + recs.map(r => { const d = new Date(r.ts); const time = d.toLocaleTimeString('ru-RU', {hour:'2-digit',minute:'2-digit'}); let trHTML = ''; if (r.transcription) { trHTML = '' + r.transcription.split(/\s+/).map(w => { const sy = syllabifyIT(w); if (sy.includes('-')) { return sy.split('-').map((s,si) => '' + s + '' ).join('-'); } return w; }).join(' ') + ''; } return '
' + '' + r.word + '' + '' + time + ' · ' + r.duration.toFixed(1) + 'с' + '' + '' + '' + trHTML + '' + '
'; }).join(''); } async function deleteRec(id) { try { const db = await openRecDB(); const tx = db.transaction('recs', 'readwrite'); tx.objectStore('recs').delete(id); await new Promise(r => { tx.oncomplete = r; }); renderRecHistory(); } catch(e) { /* тихо */ } } // ---------- История фраз (localStorage) ---------- const HIST_KEY = 'lyngvo_phrases'; function loadHistory() { try { return JSON.parse(localStorage.getItem(HIST_KEY)) || []; } catch { return []; } } function saveToHistory(text) { let hist = loadHistory().filter(t => t !== text); hist.unshift(text); hist = hist.slice(0, 5); localStorage.setItem(HIST_KEY, JSON.stringify(hist)); renderHistory(); } function renderHistory() { const hist = loadHistory(); const div = document.getElementById('history'); if (!hist.length) { div.innerHTML = ''; return; } div.innerHTML = hist.map(t => '' + t + '' ).join(''); }