119 lines
4.6 KiB
JavaScript
119 lines
4.6 KiB
JavaScript
// ---------- Хранилище (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 = '<div style="color:#999;margin-bottom:4px">📼 История записей (выберите для стерео):</div>' +
|
||
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 = '<span style="color:#aaa;font-size:0.82em;margin:0 4px">' +
|
||
r.transcription.split(/\s+/).map(w => {
|
||
const sy = syllabifyIT(w);
|
||
if (sy.includes('-')) {
|
||
return sy.split('-').map(s =>
|
||
'<span style="cursor:pointer;padding:0 2px;border-radius:3px"' +
|
||
' onmouseover="this.style.background=\'#ffeb3b\'"' +
|
||
' onmouseout="this.style.background=\'\'">' + s + '</span>'
|
||
).join('<span style="color:#ccc">·</span>');
|
||
}
|
||
return w;
|
||
}).join(' ') +
|
||
'</span>';
|
||
}
|
||
return '<div class="recItem">' +
|
||
'<span style="cursor:pointer" onclick="document.getElementById(\'inputText\').value=\'' +
|
||
r.word.replace(/'/g, "\\'") + '\';ttsText=\'' + r.word.replace(/'/g, "\\'") + '\'">' + r.word + '</span>' +
|
||
'<span style="color:#999">' + time + ' · ' + r.duration.toFixed(1) + 'с</span>' +
|
||
'<button onclick="playRec(' + r.id + ')">▶</button>' +
|
||
'<button onclick="stereoRec(' + r.id + ')">🎧</button>' +
|
||
'<button onclick="compareRec(' + r.id + ')">📊</button>' +
|
||
trHTML +
|
||
'<button onclick="deleteRec(' + r.id + ')" style="background:#e44;padding:4px 8px">🗑</button>' +
|
||
'</div>';
|
||
}).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 =>
|
||
'<span onclick="var v=\'' + t.replace(/'/g, "\\'") +
|
||
'\';document.getElementById(\'inputText\').value=v;ttsText=v;renderHistory()">' + t + '</span>'
|
||
).join('');
|
||
}
|