first commit
This commit is contained in:
10 files changed
+829
No files matched your search
@@ -0,0 +1,79 @@
|
||||
'use strict';
|
||||
const $ = id => document.getElementById(id);
|
||||
let token = '', running = false, starting = false, loadingChannels = false, loadedKey = '', lastLog = -1;
|
||||
const labels = {idle:'等待开始',running:'下载中',completed:'已完成',partial:'未达到目标',cancelled:'已停止',error:'任务中断'};
|
||||
const key = () => $('key').value.trim();
|
||||
function controls() {
|
||||
const busy = running || starting;
|
||||
$('start').disabled = busy || !loadedKey || loadedKey !== key() || !$('channel').value;
|
||||
$('stop').disabled = !running;
|
||||
$('channels').disabled = busy || loadingChannels;
|
||||
for (const id of ['key','channel','target']) $(id).disabled = busy || (id === 'channel' && !loadedKey);
|
||||
}
|
||||
async function post(path, body) {
|
||||
const response = await fetch('/api/' + path, {method:'POST',headers:{'Content-Type':'application/json','X-Session-Token':token},body:JSON.stringify(body)});
|
||||
const data = await response.json();
|
||||
if (!response.ok) throw new Error(data.error || '请求失败');
|
||||
return data;
|
||||
}
|
||||
$('key').addEventListener('input', () => {loadedKey=''; $('channel').replaceChildren(new Option('请重新获取频道','')); controls();});
|
||||
$('channels').addEventListener('click', async () => {
|
||||
loadingChannels=true; controls(); $('notice').textContent='正在获取频道…';
|
||||
const submittedKey = key();
|
||||
try {
|
||||
const data = await post('channels',{key:submittedKey});
|
||||
if (key() !== submittedKey) return;
|
||||
$('channel').replaceChildren(...data.channels.map(c => new Option(c,c)));
|
||||
loadedKey=submittedKey; $('notice').textContent=`已获取 ${data.channels.length} 个频道。`;
|
||||
$('debug-channel').value=$('channel').value;
|
||||
} catch(error) {$('notice').textContent=error.message;}
|
||||
finally {loadingChannels=false; controls();}
|
||||
});
|
||||
$('channel').addEventListener('change', () => {$('debug-channel').value=$('channel').value; controls();});
|
||||
$('download-form').addEventListener('submit', async event => {
|
||||
event.preventDefault(); starting=true; controls(); $('notice').textContent='';
|
||||
try {await post('start',{key:key(),channel:$('channel').value,target:Number($('target').value)}); await refresh();}
|
||||
catch(error) {$('notice').textContent=error.message;}
|
||||
finally {starting=false; controls();}
|
||||
});
|
||||
$('stop').addEventListener('click', async () => {
|
||||
$('stop').disabled=true;
|
||||
try {await post('stop',{}); $('notice').textContent='正在停止,等待当前请求或文章保存结束…';}
|
||||
catch(error) {$('notice').textContent=error.message;}
|
||||
});
|
||||
$('debug-form').addEventListener('submit', async event => {
|
||||
event.preventDefault(); $('debug-submit').disabled=true; $('debug-output').textContent='正在请求…';
|
||||
try {
|
||||
const data=await post('debug',{key:key(),endpoint:$('endpoint').value,channel:$('debug-channel').value,num:Number($('debug-num').value),start:Number($('debug-start').value)});
|
||||
const output=JSON.stringify(data,null,2);
|
||||
$('debug-output').textContent=output.slice(0,100000)+(output.length>100000?'\n…输出超过 100000 字符,已截断。':'');
|
||||
} catch(error) {$('debug-output').textContent=error.message;}
|
||||
finally {$('debug-submit').disabled=false;}
|
||||
});
|
||||
async function refresh() {
|
||||
const response=await fetch('/api/state');
|
||||
if (!response.ok) throw new Error('无法读取下载状态');
|
||||
const data=await response.json();
|
||||
running=data.status==='running'; controls();
|
||||
const percent=data.target ? Math.floor(data.saved/data.target*100) : 0;
|
||||
$('status').textContent=labels[data.status] || data.status;
|
||||
$('progress-text').textContent=`下载新闻 ${data.saved}/${data.target} 条`;
|
||||
$('percent').textContent=`已完成 ${percent}%`; $('progress').value=percent;
|
||||
for (const id of ['saved','skipped','failed','requests','message','output']) $(id).textContent=data[id];
|
||||
const latest=data.logs.length ? data.logs[data.logs.length-1].id : 0;
|
||||
if (latest!==lastLog) {
|
||||
const logs=$('logs'); const bottom=logs.scrollHeight-logs.scrollTop-logs.clientHeight<40;
|
||||
logs.replaceChildren(...data.logs.map(log => {const row=document.createElement('div'); const stamp=document.createElement('time'); stamp.textContent=log.time; row.append(stamp,document.createTextNode(log.message)); return row;}));
|
||||
if (bottom) logs.scrollTop=logs.scrollHeight;
|
||||
lastLog=latest;
|
||||
}
|
||||
}
|
||||
async function poll() {
|
||||
try {await refresh();}
|
||||
catch(error) {$('notice').textContent='与本地服务连接中断,请检查启动窗口。';}
|
||||
setTimeout(poll,700);
|
||||
}
|
||||
(async () => {
|
||||
try {const response=await fetch('/api/session'); token=(await response.json()).token; await poll();}
|
||||
catch(error) {$('notice').textContent='初始化失败,请刷新页面。';}
|
||||
})();
|
||||
Reference in new issue
Block a user