const dropzone = document.getElementById('dropzone'); const fileInput = document.getElementById('fileInput'); const fileList = document.getElementById('fileList'); const setupBtn = document.getElementById('setupFfmpegBtn'); const TYPE_ICONS = { image: 'πΌοΈ', video: 'π¬', audio: 'π΅', archive: 'π¦', unknown: 'π', }; // drag & drop dropzone.addEventListener('dragover', e => { e.preventDefault(); dropzone.classList.add('drag-over'); }); dropzone.addEventListener('dragleave', e => { if (!dropzone.contains(e.relatedTarget)) { dropzone.classList.remove('drag-over'); } }); dropzone.addEventListener('drop', e => { e.preventDefault(); dropzone.classList.remove('drag-over'); handleFiles(Array.from(e.dataTransfer.files)); }); // ΠΊΠ»ΠΈΠΊ Π½Π° Π·ΠΎΠ½Ρ β ΠΎΡΠΊΡΡΠ²Π°Π΅ΠΌ ΡΠ°ΠΉΠ»ΠΎΠ²ΡΠΉ Π΄ΠΈΠ°Π»ΠΎΠ³ dropzone.addEventListener('click', e => { if (e.target.tagName === 'LABEL' || e.target.closest('label')) return; fileInput.click(); }); fileInput.addEventListener('change', () => { handleFiles(Array.from(fileInput.files)); fileInput.value = ''; }); // ctrl+v β Π²ΡΡΠ°Π²ΠΊΠ° ΠΊΠ°ΡΡΠΈΠ½ΠΊΠΈ ΠΈΠ· Π±ΡΡΠ΅ΡΠ° (ΡΠΊΡΠΈΠ½ΡΠΎΡΡ ΠΈ Ρ.Π΄.) document.addEventListener('paste', e => { const items = Array.from(e.clipboardData?.items || []); const files = items .filter(i => i.kind === 'file') .map(i => i.getAsFile()) .filter(Boolean); if (files.length > 0) handleFiles(files); }); function handleFiles(files) { if (files.length === 0) return; fileList.classList.remove('hidden'); files.forEach(f => uploadFile(f)); } async function uploadFile(file) { const card = makeCard(file.name, 'unknown'); fileList.prepend(card); const status = card.querySelector('.file-status'); const fd = new FormData(); fd.append('file', file); let data; try { const r = await fetch('/api/upload', { method: 'POST', body: fd }); data = await r.json(); if (!r.ok) throw new Error(data.error || r.statusText); } catch (err) { setStatus(status, 'ΠΎΡΠΈΠ±ΠΊΠ°: ' + err.message, 'error'); return; } // ΠΎΠ±Π½ΠΎΠ²Π»ΡΠ΅ΠΌ ΠΈΠΊΠΎΠ½ΠΊΡ ΠΈ ΠΌΠ΅ΡΠ°-ΠΈΠ½ΡΠΎ const icon = card.querySelector('.file-icon'); icon.textContent = TYPE_ICONS[data.type] || 'π'; icon.className = `file-icon ${data.type}`; card.querySelector('.file-meta').textContent = data.type + ' Β· ' + fmtSize(file.size); if (data.targets.length === 0) { setStatus(status, 'ΡΠΎΡΠΌΠ°Ρ Π½Π΅ ΠΏΠΎΠ΄Π΄Π΅ΡΠΆΠΈΠ²Π°Π΅ΡΡΡ', 'error'); return; } // ΡΡΡΠΎΠΈΠΌ select + ΠΊΠ½ΠΎΠΏΠΊΡ ΠΊΠΎΠ½Π²Π΅ΡΡΠ°ΡΠΈΠΈ const actions = card.querySelector('.file-actions'); actions.innerHTML = ''; const sel = document.createElement('select'); sel.className = 'format-select'; data.targets.forEach(t => { const opt = document.createElement('option'); opt.value = t; opt.textContent = t; sel.appendChild(opt); }); const btn = document.createElement('button'); btn.className = 'btn btn-primary'; btn.textContent = 'ΠΊΠΎΠ½Π²Π΅ΡΡΠΈΡΠΎΠ²Π°ΡΡ'; btn.onclick = () => doConvert(data, sel.value, card); setStatus(status, 'Π³ΠΎΡΠΎΠ²'); actions.appendChild(sel); actions.appendChild(btn); } async function doConvert(uploadData, target, card) { const btn = card.querySelector('.btn-primary'); const status = card.querySelector('.file-status'); btn.disabled = true; status.innerHTML = 'ΠΊΠΎΠ½Π²Π΅ΡΡΠΈΡΡΡ...'; status.className = 'file-status'; // Π±Π΅ΡΡΠΌ Π°ΠΊΡΡΠ°Π»ΡΠ½ΠΎΠ΅ Π·Π½Π°ΡΠ΅Π½ΠΈΠ΅ select Π½Π° ΠΌΠΎΠΌΠ΅Π½Ρ Π½Π°ΠΆΠ°ΡΠΈΡ const sel = card.querySelector('.format-select'); const actualTarget = sel ? sel.value : target; let result; try { const r = await fetch('/api/convert', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ id: uploadData.id, saved: uploadData.saved, target: actualTarget, filename: uploadData.filename, }), }); result = await r.json(); if (!r.ok) throw new Error(result.error || r.statusText); } catch (err) { const msg = err.message.slice(0, 220); setStatus(status, 'ΠΎΡΠΈΠ±ΠΊΠ°: ' + msg, 'error'); btn.disabled = false; return; } setStatus(status, 'Π³ΠΎΡΠΎΠ²ΠΎ', 'success'); btn.disabled = false; // ΠΊΠ½ΠΎΠΏΠΊΠ° ΡΠΊΠ°ΡΠ°ΡΡ β Π·Π°ΠΌΠ΅Π½ΡΠ΅ΠΌ Π΅ΡΠ»ΠΈ ΡΠΆΠ΅ Π΅ΡΡΡ const actions = card.querySelector('.file-actions'); actions.querySelector('.btn-download')?.remove(); const dl = document.createElement('a'); dl.href = '/api/download/' + encodeURIComponent(result.result); dl.download = result.filename; dl.className = 'btn btn-download'; dl.textContent = 'ΡΠΊΠ°ΡΠ°ΡΡ'; actions.appendChild(dl); } function makeCard(filename, type) { const card = document.createElement('div'); card.className = 'file-card'; card.innerHTML = `