Spaces:
Sleeping
Sleeping
| // app.js โ HarmoSplit ใใญใณใใจใณใใญใธใใฏ๏ผStripe ่ช่จผๅฏพๅฟ๏ผ | |
| const dropZone = document.getElementById('dropZone'); | |
| const fileInput = document.getElementById('fileInput'); | |
| const startBtn = document.getElementById('startBtn'); | |
| const instVol = document.getElementById('instVol'); | |
| const instVolLabel= document.getElementById('instVolLabel'); | |
| const modelSelect = document.getElementById('modelSelect'); | |
| const useMdx = document.getElementById('useMdx'); | |
| const uploadSection = document.getElementById('uploadSection'); | |
| const progressSection= document.getElementById('progressSection'); | |
| const resultSection = document.getElementById('resultSection'); | |
| const errorSection = document.getElementById('errorSection'); | |
| const progressBar = document.getElementById('progressBar'); | |
| const progressPct = document.getElementById('progressPct'); | |
| const progressFile = document.getElementById('progressFile'); | |
| const logBox = document.getElementById('logBox'); | |
| const downloadBtn = document.getElementById('downloadBtn'); | |
| const errorMsg = document.getElementById('errorMsg'); | |
| let selectedFile = null; | |
| let verifiedToken = ''; | |
| // โโ ่ตทๅๆ: Stripe ๆๅนใใฉใใ็ขบ่ช โโโโโโโโโโโโโโโโโโโโโโโโ | |
| async function initAuth() { | |
| try { | |
| const res = await fetch('/auth-mode'); | |
| const data = await res.json(); | |
| if (!data.free_mode) { | |
| // ๆๆใขใผใ: ใใผใฏใณใจใชใขใ่กจ็คบ | |
| document.getElementById('tokenArea').style.display = 'block'; | |
| // ใญใผใซใซในใใฌใผใธใซไฟๅญๆธใฟใใผใฏใณใใใใฐๅพฉๅ | |
| const saved = localStorage.getItem('hmsplit_token'); | |
| if (saved) { | |
| document.getElementById('tokenInput').value = saved; | |
| await verifyToken(saved, false); | |
| } | |
| } else { | |
| // ็กๆใขใผใ: ใใผใฏใณไธ่ฆ | |
| verifiedToken = 'FREE'; | |
| } | |
| } catch (e) { | |
| verifiedToken = 'FREE'; // ใจใฉใผๆใฏ็กๆๆฑใ | |
| } | |
| } | |
| // โโ ใใผใฏใณๆค่จผ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| async function verifyToken(token, showAlert = true) { | |
| try { | |
| const res = await fetch('/verify-token', { | |
| method: 'POST', | |
| headers: { 'Content-Type': 'application/json' }, | |
| body: JSON.stringify({ token }), | |
| }); | |
| const data = await res.json(); | |
| if (data.valid) { | |
| verifiedToken = token; | |
| localStorage.setItem('hmsplit_token', token); | |
| document.getElementById('tokenOk').classList.remove('hidden'); | |
| document.getElementById('tokenInput').style.borderColor = 'var(--success)'; | |
| } else { | |
| verifiedToken = ''; | |
| localStorage.removeItem('hmsplit_token'); | |
| document.getElementById('tokenOk').classList.add('hidden'); | |
| document.getElementById('tokenInput').style.borderColor = 'var(--error)'; | |
| if (showAlert) alert('ใใผใฏใณใ็กๅนใงใใๆ้ใใผใธใใ็ป้ฒใใฆใใ ใใใ'); | |
| } | |
| return data.valid; | |
| } catch { | |
| return false; | |
| } | |
| } | |
| document.getElementById('verifyBtn')?.addEventListener('click', async () => { | |
| const token = document.getElementById('tokenInput').value.trim(); | |
| if (!token) { alert('ใใผใฏใณใๅ ฅๅใใฆใใ ใใ'); return; } | |
| await verifyToken(token, true); | |
| }); | |
| // โโ ใใกใคใซ้ธๆ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| function selectFile(file) { | |
| selectedFile = file; | |
| dropZone.classList.add('has-file'); | |
| dropZone.querySelector('.drop-icon').textContent = fileIsVideo(file.name) ? '๐ฌ' : '๐ต'; | |
| const sub = dropZone.querySelector('.drop-sub'); | |
| sub.textContent = file.name; | |
| sub.classList.add('drop-filename'); | |
| updateStartBtn(); | |
| } | |
| function fileIsVideo(name) { | |
| return /\.(mp4|mov|avi|mkv|m4v|flv|webm|ts)$/i.test(name); | |
| } | |
| function updateStartBtn() { | |
| const hasFile = !!selectedFile; | |
| const hasToken = !!verifiedToken; | |
| startBtn.disabled = !(hasFile && hasToken); | |
| } | |
| dropZone.addEventListener('dragover', e => { e.preventDefault(); dropZone.classList.add('dragover'); }); | |
| dropZone.addEventListener('dragleave', () => dropZone.classList.remove('dragover')); | |
| dropZone.addEventListener('drop', e => { | |
| e.preventDefault(); dropZone.classList.remove('dragover'); | |
| if (e.dataTransfer.files.length) selectFile(e.dataTransfer.files[0]); | |
| }); | |
| dropZone.addEventListener('click', () => fileInput.click()); | |
| fileInput.addEventListener('change', () => { if (fileInput.files.length) selectFile(fileInput.files[0]); }); | |
| instVol.addEventListener('input', () => { | |
| instVolLabel.textContent = Math.round(instVol.value * 100) + '%'; | |
| }); | |
| // โโ ๅฆ็้ๅง โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| startBtn.addEventListener('click', async () => { | |
| if (!selectedFile || !verifiedToken) return; | |
| uploadSection.classList.add('hidden'); | |
| progressSection.classList.remove('hidden'); | |
| logBox.innerHTML = ''; | |
| progressBar.style.width = '0%'; | |
| progressPct.textContent = '0%'; | |
| progressFile.textContent = selectedFile.name; | |
| const fd = new FormData(); | |
| fd.append('file', selectedFile); | |
| fd.append('inst_vol', instVol.value); | |
| fd.append('model', modelSelect.value); | |
| fd.append('use_mdx', useMdx.checked ? 'true' : 'false'); | |
| fd.append('token', verifiedToken === 'FREE' ? '' : verifiedToken); | |
| let jobId; | |
| try { | |
| const res = await fetch('/upload', { method: 'POST', body: fd }); | |
| const data = await res.json(); | |
| if (!res.ok || data.error) throw new Error(data.error || 'ใขใใใญใผใๅคฑๆ'); | |
| jobId = data.job_id; | |
| } catch (e) { | |
| showError(e.message); return; | |
| } | |
| const sse = new EventSource(`/progress/${jobId}`); | |
| sse.addEventListener('message', e => { | |
| let payload; | |
| try { payload = JSON.parse(e.data); } catch { return; } | |
| if (payload.status) { | |
| sse.close(); | |
| if (payload.status === 'done') showResult(jobId); | |
| else showError('ๅฆ็ไธญใซใจใฉใผใ็บ็ใใพใใใใญใฐใ็ขบ่ชใใฆใใ ใใใ'); | |
| return; | |
| } | |
| if (payload.msg) { | |
| const p = document.createElement('p'); | |
| p.textContent = payload.msg; | |
| if (payload.msg.includes('โ ') || payload.msg.includes('ๅฎไบ')) p.classList.add('ok'); | |
| if (payload.msg.includes('โ')) p.classList.add('err'); | |
| logBox.appendChild(p); | |
| logBox.scrollTop = logBox.scrollHeight; | |
| } | |
| if (payload.pct !== undefined) { | |
| progressBar.style.width = payload.pct + '%'; | |
| progressPct.textContent = payload.pct + '%'; | |
| } | |
| }); | |
| sse.onerror = () => { | |
| sse.close(); | |
| setTimeout(async () => { | |
| try { | |
| const res = await fetch(`/status/${jobId}`); | |
| const data = await res.json(); | |
| if (data.status === 'done') showResult(jobId); | |
| else showError(data.error || 'ๆฅ็ถใจใฉใผ'); | |
| } catch { showError('ใตใผใใผใจใฎๆฅ็ถใๅใใพใใ'); } | |
| }, 500); | |
| }; | |
| }); | |
| function showResult(jobId) { | |
| progressSection.classList.add('hidden'); | |
| resultSection.classList.remove('hidden'); | |
| downloadBtn.href = `/download/${jobId}`; | |
| } | |
| function showError(msg) { | |
| progressSection.classList.add('hidden'); | |
| errorSection.classList.remove('hidden'); | |
| errorMsg.textContent = msg; | |
| } | |
| function reset() { | |
| selectedFile = null; | |
| fileInput.value = ''; | |
| dropZone.classList.remove('has-file', 'dragover'); | |
| dropZone.querySelector('.drop-icon').textContent = '๐ต'; | |
| const sub = dropZone.querySelector('.drop-sub'); | |
| sub.textContent = 'ใพใใฏ'; sub.classList.remove('drop-filename'); | |
| progressBar.style.width = '0%'; progressPct.textContent = '0%'; | |
| logBox.innerHTML = ''; | |
| uploadSection.classList.remove('hidden'); | |
| progressSection.classList.add('hidden'); | |
| resultSection.classList.add('hidden'); | |
| errorSection.classList.add('hidden'); | |
| updateStartBtn(); | |
| } | |
| document.getElementById('resetBtn').addEventListener('click', reset); | |
| document.getElementById('resetBtnErr').addEventListener('click', reset); | |
| // ่ตทๅ | |
| initAuth().then(() => updateStartBtn()); | |