Elias207's picture
Update static/js/api.js
e53076a verified
// تعامل با سرور 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 = '<div class="spinner" style="width:20px;height:20px;border-width:3px;"></div> در حال طراحی...';
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 = `شما نفر <span style="color:#00e676; font-size:1.3em;">${d.queue_position}</span> در صف ساخت هستید...`;
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 = ""; }