feat: add download progress and deduplication

This commit is contained in:
OpenClaw Agent
2026-09-16 02:20:43 +08:00
parent 1de4f9d85d
commit 0da24cb183
2 changed files with 82 additions and 21 deletions
+2 -2
View File
@@ -8,6 +8,6 @@
const $=id=>document.getElementById(id);async function api(u,o){let r=await fetch('/api'+u,o);if(!r.ok)throw new Error(await r.text());return r.status===204?null:r.json()};function esc(s){return String(s||'').replace(/[&<>"']/g,m=>({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;'}[m]))}
async function search(){let k=$('keyword').value.trim();if(!k)return;try{let x=await api('/search?keyword='+encodeURIComponent(k)+'&source='+$('source').value);let songs=x.data?.songs||[];$('resultsCard').style.display='block';$('results').innerHTML=songs.length?songs.map((s,i)=>`<div class="result"><img class="cover" src="${esc(s.pic||'')}" onerror="this.style.display='none'"><div><div class="name">${esc(s.title)}</div><div class="meta">${esc(s.artist||'')} · ${esc(s.album||'')}</div></div><button class="btn" onclick='queueSong(${JSON.stringify(s)})'>下载</button></div>`).join(''):'没有结果'}catch(e){alert('搜索失败:'+e.message)}}
async function queueSong(s){s.quality=$('defaultQuality').value||'standard';try{await api('/tasks',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify(s)});load()}catch(e){alert('加入失败:'+e.message)}}
async function load(){try{let x=await api('/tasks');$('count').textContent='· '+x.data.length+' 个任务';$('tasks').innerHTML=x.data.length?x.data.map(t=>`<div class="result"><img class="cover" src="${esc(t.pic||'')}" onerror="this.style.display='none'"><div><div class="name">${esc(t.title)} <span class="muted">${esc(t.artist||'')}</span></div><div class="meta">${esc(t.source)} · ${esc(t.quality)} · ${t.status==='done'?'已完成':t.status==='error'?esc(t.error):esc(t.status)}</div></div><span class="status ${t.status==='done'?'done':t.status==='error'?'error':''}">${esc(t.status)}</span></div>`).join(''):'暂无任务'}catch(e){$('tasks').textContent=e.message}}async function retry(id){await api('/tasks/'+id+'/retry',{method:'POST'});load()}function toggleSettings(){$('settings').classList.toggle('open');if($('settings').classList.contains('open'))loadSettings()}
async function loadSettings(){let s=await api('/settings');$('amApi').value=s.amApi;$('downloadDir').value=s.downloadDir;$('davUrl').value=s.webdavUrl;$('davUser').value=s.webdavUser;$('davPass').value=s.webdavPass;$('davPath').value=s.webdavPath;$('defaultQuality').value=s.quality;$('quality').value=s.quality}async function saveSettings(){let b={amApi:$('amApi').value,downloadDir:$('downloadDir').value,webdavUrl:$('davUrl').value,webdavUser:$('davUser').value,webdavPass:$('davPass').value,webdavPath:$('davPath').value,quality:$('defaultQuality').value};await api('/settings',{method:'PUT',headers:{'Content-Type':'application/json'},body:JSON.stringify(b)});alert('已保存')}async function testDav(){try{let b={url:$('davUrl').value,user:$('davUser').value,pass:$('davPass').value,path:$('davPath').value};await api('/webdav/test',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify(b)});alert('WebDAV 连接成功')}catch(e){alert('WebDAV 连接失败:'+e.message)}}load();setInterval(load,3000);
async function load(){try{let x=await api('/tasks');$('count').textContent='· '+x.data.length+' 个任务';$('tasks').innerHTML=x.data.length?x.data.map(t=>{let p=t.progress>0?` · ${t.progress.toFixed(0)}%`:'';let action=t.status==='error'?`<button class="btn alt" onclick="retry(${t.id})">重试</button>`:'';return `<div class="result"><img class="cover" src="${esc(t.pic||'')}" onerror="this.style.display='none'"><div><div class="name">${esc(t.title)} <span class="muted">${esc(t.artist||'')}</span></div><div class="meta">${esc(t.source)} · ${esc(t.quality)} · ${t.status==='done'?'已完成':t.status==='error'?esc(t.error):esc(t.status)}${p}</div></div>${action||`<span class="status ${t.status==='done'?'done':t.status==='error'?'error':''}">${esc(t.status)}</span>`}</div>`}).join(''):'暂无任务'}catch(e){$('tasks').textContent=e.message}}async function retry(id){await api('/tasks/'+id+'/retry',{method:'POST'});load()}function toggleSettings(){$('settings').classList.toggle('open');if($('settings').classList.contains('open'))loadSettings()}
async function loadSettings(){let s=await api('/settings');$('amApi').value=s.amApi;$('downloadDir').value=s.downloadDir;$('davUrl').value=s.webdavUrl;$('davUser').value=s.webdavUser;$('davPass').value=s.webdavPass;$('davPath').value=s.webdavPath;$('defaultQuality').value=s.quality}async function saveSettings(){let b={amApi:$('amApi').value,downloadDir:$('downloadDir').value,webdavUrl:$('davUrl').value,webdavUser:$('davUser').value,webdavPass:$('davPass').value,webdavPath:$('davPath').value,quality:$('defaultQuality').value};await api('/settings',{method:'PUT',headers:{'Content-Type':'application/json'},body:JSON.stringify(b)});alert('已保存')}async function testDav(){try{let b={url:$('davUrl').value,user:$('davUser').value,pass:$('davPass').value,path:$('davPath').value};await api('/webdav/test',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify(b)});alert('WebDAV 连接成功')}catch(e){alert('WebDAV 连接失败:'+e.message)}}load();setInterval(load,3000);
</script></body></html>