// تعامل با سرور FastAPI async function startUpload() { console.log("Upload started..."); // دیباگ const f = document.getElementById('fileIn').files[0]; if(!f) return; // اطمینان از اینکه دیتابیس آماده است if (!db) { try { console.log("Waiting for DB..."); await initDB(); } catch(e) { alert("خطا در بارگذاری دیتابیس. لطفا صفحه را رفرش کنید."); return; } } document.getElementById('homeScreen').style.display = 'none'; document.getElementById('loader').style.display = 'flex'; document.getElementById('queueStatusMsg').innerText = "در حال آپلود و پردازش اولیه..."; const txCheck = db.transaction("projects", "readwrite"); const storeCheck = txCheck.objectStore("projects"); const reqAll = storeCheck.getAll(); reqAll.onsuccess = async (e) => { let projects = e.target.result; projects.sort((a, b) => a.id - b.id); if (projects.length >= 4) { const toDelete = projects[0]; storeCheck.delete(toDelete.id); } const defaultName = `پروژه ${projects.length >= 4 ? 4 : projects.length + 1}`; const fd = new FormData(); fd.append('file', f); try { const r = await fetch('/api/upload', {method:'POST', body:fd}); if (!r.ok) throw new Error("Server Error: " + r.status); const d = await r.json(); state.id = d.file_id; state.w = d.width; state.h = d.height; state.st = { f: 'vazir', fz: 65, col: '#A020F0', bg: '#000000', type: 'solid', y: 150, x: 0, name: 'karaoke_static' }; let rawSegs = d.segments.map(s => ({...s, isHidden: false})); rawSegs.sort((a, b) => a.start - b.start); for(let i = 0; i < rawSegs.length - 1; i++) { const curr = rawSegs[i]; const next = rawSegs[i+1]; if (curr.end > next.start) { curr.end = next.start; if (curr.words) { curr.words = curr.words.filter(w => w.start < curr.end); if(curr.words.length > 0) { let lastW = curr.words[curr.words.length - 1]; if(lastW.end > curr.end) lastW.end = curr.end; } } } } state.segs = rawSegs; const durSec = rawSegs.length > 0 ? rawSegs[rawSegs.length-1].end : 0; let mm = Math.floor(durSec / 60); let ss = Math.floor(durSec % 60); const durStr = `${mm < 10 ? '0'+mm : mm}:${ss < 10 ? '0'+ss : ss}`; const txSave = db.transaction("projects", "readwrite"); const newProject = { id: Date.now(), name: defaultName, dateStr: getPersianDate(), lastModified: Date.now(), videoBlob: f, state: JSON.parse(JSON.stringify(state)), duration: durStr, thumbnail: null }; txSave.objectStore("projects").add(newProject); txSave.oncomplete = () => { openProject(newProject.id); }; } catch(e) { console.error(e); alert("خطا در آپلود یا پردازش: " + e); loadHome(); } finally { document.getElementById('loader').style.display='none'; document.getElementById('fileIn').value = ''; document.getElementById('queueStatusMsg').innerText = ""; } }; } async function generateAIStyle() { const desc = document.getElementById('magicPrompt').value; if(!desc) return; const btn = document.querySelector('.btn-magic-action'); const originalText = btn.innerHTML; btn.innerHTML = '
در حال طراحی...'; btn.disabled = true; try { const r = await fetch('/api/generate-style', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({description: desc}) }); const styleData = await r.json(); state.st.col = styleData.primaryColor; state.st.bg = styleData.outlineColor; state.st.f = styleData.font; state.st.fz = styleData.fontSize; document.getElementById('col').value = state.st.col; document.getElementById('bgCol').value = state.st.bg; document.getElementById('fz').value = state.st.fz; activateCustomStyle(); setMode(styleData.backType); upd(); toolsContainer.classList.remove('open'); alert('طراحی اعمال شد!'); } catch(e) { alert('خطا در هوش مصنوعی'); } finally { btn.innerHTML = originalText; btn.disabled = false; } } async function render() { v.pause(); togglePlayIcon(false); document.getElementById('loader').style.display='flex'; const statusMsg = document.getElementById('queueStatusMsg'); statusMsg.innerText = "در حال ارسال به صف..."; const activeSegments = state.segs.filter(s => !s.isHidden); const pl = { file_id: state.id, segments: activeSegments, video_width: state.w, video_height: state.h, style: { font: state.st.f, fontSize: state.st.fz, primaryColor: state.st.col, outlineColor: state.st.bg, backType: state.st.type, marginV: state.st.y, x: state.st.x, name: state.st.name } }; try { let r = await fetch('/api/enqueue-render', {method:'POST', headers:{'Content-Type':'application/json'}, body:JSON.stringify(pl)}); let d = await r.json(); if (d.error_code && d.error_code === 'VIDEO_NOT_FOUND') { statusMsg.innerText = "ویدیو در سرور یافت نشد، در حال بارگذاری مجدد..."; const videoBlob = await getVideoBlobFromDB(currentProjectId); const fd = new FormData(); fd.append('file', videoBlob); fd.append('file_id', state.id); const reuploadResponse = await fetch('/api/reupload', { method: 'POST', body: fd }); if (!reuploadResponse.ok) throw new Error('خطا در بارگذاری مجدد ویدیو.'); statusMsg.innerText = "بارگذاری مجدد موفق بود، ارسال دوباره به صف..."; r = await fetch('/api/enqueue-render', {method:'POST', headers:{'Content-Type':'application/json'}, body:JSON.stringify(pl)}); d = await r.json(); } if (d.job_id) { pollStatus(d.job_id); } else { throw new Error(d.error || "خطا لطفاً این پروژه را حذف و ویدیو را مجدداً آپلود کنید."); } } catch(e) { alert('خطا: ' + e.message); document.getElementById('loader').style.display='none'; } } function pollStatus(jobId) { const statusMsg = document.getElementById('queueStatusMsg'); const interval = setInterval(async () => { try { const r = await fetch(`/api/job-status/${jobId}`); const d = await r.json(); if (d.status === 'queued') statusMsg.innerHTML = `شما نفر ${d.queue_position} در صف ساخت هستید...`; else if (d.status === 'processing') statusMsg.innerText = "نوبت شماست! در حال ساخت ویدیو..."; else if (d.status === 'completed') { clearInterval(interval); showFinalResult(d.url); } else if (d.status === 'failed') { clearInterval(interval); alert("خطا در ساخت ویدیو: " + d.error); document.getElementById('loader').style.display='none'; } } catch (e) { console.error("خطا در چک کردن وضعیت", e); } }, 2500); } function showFinalResult(url) { document.getElementById('loader').style.display='none'; const resVid = document.getElementById('resultVideo'); resVid.src = url + "?t=" + new Date().getTime(); resVid.load(); const fullUrl = new URL(url, window.location.origin).href; const dlBtn = document.getElementById('downloadBtn'); dlBtn.href = fullUrl; dlBtn.onclick = function(e) { e.preventDefault(); window.parent.postMessage({ type: 'DOWNLOAD_REQUEST', url: fullUrl }, '*'); }; document.getElementById('resultScreen').style.display='flex'; resVid.play(); } function closeResult() { document.getElementById('resultScreen').style.display='none'; const rv = document.getElementById('resultVideo'); rv.pause(); rv.src = ""; }