Checkpoint peering identity and opt-in discovery

This commit is contained in:
Codex committed 2026-10-13 22:00:54 +02:00
1 parent eba9b50e30
commit 47de081721
44 files changed
+1557 -55

No files matched your search

+23 -2
View File
@@ -224,16 +224,24 @@
const jobRow = (item, movable = false) => {
const running = activeEntries.some(entry => entry.current.id === item.id);
const availability = item.availability;
const expected = availability?.expectedLastChapter;
const sparse = /^\d+$/.test(String(expected || '')) && Number(availability?.numberedChapters) < Number(expected);
const partialCoverage = availability?.coverage === 'partial' || sparse;
const outcome = item.status === 'complete'
? `${item.publishedCount ?? 0} chapter${item.publishedCount === 1 ? '' : 's'} published · finished ${when(item.completed)}`
: item.status === 'ready' ? 'Awaiting edition confirmation' : item.status.replaceAll('_', ' ');
return h('div', { class: 'scraper-item' + (running ? ' active' : ''), 'data-source': item.source },
h('div', { class: 'grow' }, h('b', {}, item.title),
item.status === 'complete' || availability ? h('div', { class: 'coverage-indicators' },
item.status === 'complete' ? h('span', { class: 'coverage-badge coverage-complete' }, 'Hosted selection complete') : null,
availability ? h('span', { class: 'coverage-badge ' + (partialCoverage ? 'coverage-partial' : 'coverage-unknown') },
partialCoverage ? 'Series coverage partial' : 'Series coverage unverified') : null,
item.status === 'complete' && !availability ? h('span', { class: 'coverage-badge coverage-unknown' }, 'Series coverage unverified') : null) : null,
h('div', { class: 'muted small' }, `${item.source} · ${item.kind === 'discovery' ? 'Checking for updates' : item.scopeLabel || 'all missing chapters'} · ${outcome}`
+ (item.existingPolicy === 'add-source' ? ' · alternate source' : '')),
item.error ? h('div', { class: 'small error' }, item.error) : null,
item.sourceTitle ? h('div', { class: 'small' }, `Source edition: ${item.sourceTitle}`) : null,
availability ? h('div', { class: 'muted small' }, `${availability.selectedChapters} hosted selections${availability.specialReleases ? ` · ${availability.specialReleases} unnumbered releases` : ''}${availability.expectedLastChapter ? ` · metadata last chapter: ${availability.expectedLastChapter}` : ''} · ${availability.coverage === 'partial' ? 'Partial source coverage' : 'Whole-series completeness not verified'}`) : null),
availability ? h('div', { class: 'muted small' }, `${availability.selectedChapters} hosted selections${availability.specialReleases ? ` · ${availability.specialReleases} unnumbered releases` : ''}${availability.expectedLastChapter ? ` · metadata last chapter: ${availability.expectedLastChapter}` : ''}`) : null),
movable ? h('button', { class: 'btn small', disabled: running || pending[0]?.id === item.id, title: 'Move up', onclick: () => move(item, -1) }, '↑') : null,
movable ? h('button', { class: 'btn small', disabled: running || pending.at(-1)?.id === item.id, title: 'Move down', onclick: () => move(item, 1) }, '↓') : null,
item.status === 'error' ? h('button', { class: 'btn small primary', onclick: () => command({ command: 'control', action: 'retry', id: item.id }) }, 'Retry') : null,
@@ -354,7 +362,20 @@
return h('section', { class: 'scraper-source-card' }, h('h3', {}, adapter.label),
h('p', { class: 'muted small' }, `${running ? 'Active' : state.sourcePaused?.[adapter.id] ? 'Paused by source protection' : 'Idle'} · ${waiting} waiting · ${problems} need attention`),
sourceRateEditors.find(editor => editor.querySelector('b')?.textContent === adapter.label));
}), h('p', { class: 'muted small' }, 'Each source runs sequentially with its own limits. New limits apply when that source starts or resumes a manga.'));
}), h('p', { class: 'muted small' }, 'Each source runs sequentially with its own limits. New limits apply when that source starts or resumes a manga.'),
h('h2', {}, 'Available-source log'),
h('p', { class: 'muted small' }, 'A queued URL is only a lead. Catalog found, adapter compatibility and download rights are separate facts. This log does not approve or start a download.'),
h('div', { class: 'scraper-queue' }, (state.sourceLedger || []).filter(entry => !sourceFilter || entry.source === sourceFilter).map(entry =>
h('div', { class: 'scraper-item' }, h('div', { class: 'grow' },
h('b', {}, entry.title || entry.sourceTitle || entry.seriesId || 'Unknown title'),
h('div', { class: 'muted small' }, `${entry.source} · catalog ${entry.catalog} · adapter ${entry.adapter} · rights ${entry.rights}`),
h('div', { class: 'muted small' }, `${entry.hostedCount == null ? 'Chapter count unknown' : `${entry.hostedCount} selected chapters`} · series coverage ${entry.coverage || 'unknown'} · checked ${when(entry.lastObservedAt)}`),
entry.sourceTitle && entry.sourceTitle !== entry.title ? h('div', { class: 'small' }, `Source edition: ${entry.sourceTitle}`) : null,
entry.reason ? h('div', { class: 'small' }, `Availability: ${entry.reason}`) : null,
entry.lastFailure ? h('div', { class: 'small error' }, `${entry.lastFailure.kind}: ${entry.lastFailure.message}`) : null),
entry.url && /^https?:\/\//.test(entry.url) ? h('a', { class: 'btn small', href: entry.url, target: '_blank', rel: 'noopener noreferrer' }, 'Source ↗') : null))),
!(state.sourceLedger || []).some(entry => !sourceFilter || entry.source === sourceFilter)
? h('p', { class: 'muted small' }, 'No source observations yet for this filter.') : null);
card.append(activityPanel, queuePanel, updatesPanel, sourcesPanel);
};