feat: add standalone AM downloader with WebDAV sync
This commit is contained in:
+11
@@ -0,0 +1,11 @@
|
||||
<!doctype html><html lang="zh-CN"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>AM Downloader</title><style>
|
||||
*{box-sizing:border-box}body{margin:0;background:#0b1220;color:#e5edf7;font:14px system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif}button,input,select{font:inherit}.wrap{max-width:1080px;margin:auto;padding:28px 18px 60px}.top{display:flex;justify-content:space-between;align-items:center;margin-bottom:22px}.brand{font-size:25px;font-weight:800}.brand b{color:#10b981}.sub{color:#7f8da3;margin-top:5px}.card{background:#111b2c;border:1px solid #22304a;border-radius:18px;padding:18px;margin-bottom:16px}.row{display:flex;gap:8px}.row>*{flex:1}.input{width:100%;padding:11px 12px;border-radius:11px;border:1px solid #2a3852;background:#0c1525;color:#fff;outline:none}.btn{border:0;border-radius:11px;padding:11px 15px;background:#10b981;color:#06251b;font-weight:700;cursor:pointer}.btn.alt{background:#1d2a40;color:#d9e3ef}.title{font-size:16px;font-weight:750;margin-bottom:12px}.muted{color:#7f8da3;font-size:12px}.task{display:grid;grid-template-columns:46px 1fr auto;gap:12px;align-items:center;padding:12px 0;border-bottom:1px solid #1f2b40}.task:last-child{border-bottom:0}.cover{width:46px;height:46px;border-radius:9px;object-fit:cover;background:#1b2638}.name{font-weight:650}.meta{font-size:12px;color:#7f8da3;margin-top:4px}.status{font-size:12px;padding:5px 8px;border-radius:8px;background:#1c2a40}.done{color:#34d399}.error{color:#fb7185}.settings{display:none}.settings.open{display:block}label{display:block;color:#9aa8bb;font-size:12px;margin:10px 0 6px}@media(max-width:720px){.row{flex-wrap:wrap}.row>*{flex-basis:100%}.top{align-items:flex-start}.task{grid-template-columns:40px 1fr}.task .actions{grid-column:2}.cover{width:40px;height:40px}}
|
||||
</style></head><body><div class="wrap"><div class="top"><div><div class="brand">AM <b>Downloader</b></div><div class="sub">独立下载队列 · WebDAV NAS 同步</div></div><button class="btn alt" onclick="toggleSettings()">设置</button></div>
|
||||
<div class="card"><div class="title">添加下载任务</div><div class="row"><input id="json" class="input" placeholder="粘贴 AM 歌曲 JSON"><select id="quality" class="input"><option value="standard">标准</option><option value="exhigh">高品质</option><option value="lossless">无损</option><option value="hires">Hi-Res</option><option value="sky">Sky</option><option value="atmos">Atmos</option><option value="master">Master</option></select><button class="btn" onclick="add()">加入队列</button></div><div class="muted" style="margin-top:9px">后续 AM 的下载按钮将直接把歌曲加入此队列,浏览器不再承担大文件下载。</div></div>
|
||||
<div id="settings" class="card settings"><div class="title">下载与 WebDAV</div><label>AM API</label><input id="amApi" class="input"><label>本地下载目录</label><input id="downloadDir" class="input"><label>WebDAV 地址</label><input id="davUrl" class="input" placeholder="https://nas.example.com/dav/music"><div class="row"><div><label>用户名</label><input id="davUser" class="input"></div><div><label>密码</label><input id="davPass" type="password" class="input"></div></div><label>远程音乐目录</label><input id="davPath" class="input" placeholder="Music"><label>默认下载品质</label><select id="defaultQuality" class="input"><option value="standard">标准</option><option value="exhigh">高品质</option><option value="lossless">无损</option><option value="hires">Hi-Res</option><option value="sky">Sky</option><option value="jyeffect">高清音效</option><option value="jymaster">母带</option><option value="atmos">Atmos</option><option value="atmos_plus">Atmos+</option><option value="master">Master</option></select><div class="row" style="margin-top:14px"><button class="btn" onclick="saveSettings()">保存设置</button><button class="btn alt" onclick="testDav()">测试 WebDAV</button></div></div>
|
||||
<div class="card"><div class="title">下载队列 <span id="count" class="muted"></span></div><div id="tasks" class="muted">加载中…</div></div></div><script>
|
||||
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()}
|
||||
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="task"><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><div class="actions"><span class="status ${t.status==='done'?'done':t.status==='error'?'error':''}">${esc(t.status)}</span>${t.status==='error'?` <button class="btn alt" onclick="retry(${t.id})">重试</button>`:''}</div></div>`).join(''):'暂无任务'}catch(e){$('tasks').textContent=e.message}}function esc(s){return String(s||'').replace(/[&<>"']/g,m=>({'&':'&','<':'<','>':'>','"':'"',"'":'''}[m]))}
|
||||
async function add(){try{let s=JSON.parse($('json').value);s.quality=$('quality').value;await api('/tasks',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify(s)});$('json').value='';load()}catch(e){alert('任务格式错误或提交失败:'+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);
|
||||
</script></body></html>
|
||||
Reference in New Issue
Block a user