Consolidate MangaCircus app, scraper, and Compose baseline

This commit is contained in:
Maashkinoozhe committed 2026-10-07 23:28:20 +02:00
1 parent cfb2d79103
commit eef4ffa07c
103 files changed
+9316 -172

No files matched your search

+37
View File
@@ -0,0 +1,37 @@
#!/usr/bin/env node
'use strict';
// Run on the host. Authentication stays inside the reader container; no token
// appears in command arguments, terminal output or a published daemon port.
const { spawnSync } = require('node:child_process');
const path = require('node:path');
const action = process.argv[2] || 'check';
const id = process.argv[3];
if (!['check', 'state', 'pause', 'resume', 'retry'].includes(action) ||
(action === 'retry' && !id) || (id && !/^[a-zA-Z0-9-]{1,80}$/.test(id))) {
console.error('Usage: node tools/compose-control.js check|state|pause|resume|retry <job-id>');
process.exit(2);
}
const script = action === 'check' ? "require('./tools/check.js')" : `
const {secret}=require('./runtime/config');
(async()=>{
const action=${JSON.stringify(action)},id=${JSON.stringify(id || null)};
const response=await fetch(process.env.SCRAPER_URL+(action==='state'?'/api/state':'/api/control'),{
method:action==='state'?'GET':'POST',signal:AbortSignal.timeout(20000),
headers:{authorization:'Bearer '+secret('SCRAPER_TOKEN'),'content-type':'application/json'},
...(action==='state'?{}:{body:JSON.stringify({action,id})})
});
if(!response.ok)throw new Error('Scraper returned HTTP '+response.status);
const s=await response.json();
const job=j=>j?{updated:j.updated,completed:j.completed,total:j.total,current:j.current,lastChapter:j.lastChapter}:null;
console.log(JSON.stringify({version:s.version,status:s.status,paused:s.paused,settings:s.settings,
sourcePaused:s.sourcePaused,publishedRevision:s.publishedRevision,
active:s.active?.map(a=>({source:a.source,id:a.current?.id,title:a.current?.title,job:job(a.job)})),
queue:s.queue?.map(q=>({id:q.id,title:q.title,source:q.source,status:q.status,failure:q.failure, nextAttemptAt:q.nextAttemptAt})),
openIncidents:s.incidents?.filter(i=>i.state==='open').map(i=>({kind:i.kind,title:i.title,message:i.message})),
runtimeHeartbeat:s.runtimeHeartbeat,nextDiscoveryAt:s.nextDiscoveryAt,libraryStatus:s.libraryStatus},null,2));
})().catch(e=>{console.error(e.message);process.exitCode=1;});`;
const result = spawnSync('docker', ['compose', 'exec', '-T', 'reader', 'node', '-e', script], {
cwd: path.resolve(__dirname, '..'), encoding: 'utf8', stdio: 'inherit', windowsHide: true,
});
if (result.error) console.error(result.error.message);
process.exit(result.status ?? 1);