Wire the RSS and Search tabs to the new backend: - RSS: add/remove feeds, per-article "Add" (download), and a full auto-download rule editor (match/regex, must[-not]-contain, per-feed scope, category, save path, paused) with edit/delete. - Search: results now add via the server-side download endpoint (magnet/.torrent); add a Torznab indexer manager (list/add/remove). - api.js: feed/rule/indexer/download client methods. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
66 lines
2.7 KiB
JavaScript
66 lines
2.7 KiB
JavaScript
// Thin API client + SSE live stream.
|
|
|
|
async function jget(url) {
|
|
const r = await fetch(url);
|
|
if (!r.ok) throw new Error(`${url} → ${r.status}`);
|
|
return r.json();
|
|
}
|
|
async function jpost(url, body) {
|
|
const r = await fetch(url, {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify(body || {}),
|
|
});
|
|
if (!r.ok) throw new Error(`${url} → ${r.status}`);
|
|
return r.json();
|
|
}
|
|
|
|
export const api = {
|
|
authStatus: () => jget('/api/auth/status'),
|
|
login: (username, password) => jpost('/api/login', { username, password }),
|
|
logout: () => jpost('/api/logout', {}),
|
|
plugins: () => jget('/api/plugins'),
|
|
|
|
meta: () => jget('/api/meta'),
|
|
snapshot: () => jget('/api/snapshot'),
|
|
torrent: (hash) => jget(`/api/torrents/${hash}`),
|
|
trackers: (hash) => jget(`/api/torrents/${hash}/trackers`),
|
|
peers: (hash) => jget(`/api/torrents/${hash}/peers`),
|
|
files: (hash) => jget(`/api/torrents/${hash}/files`),
|
|
pieces: (hash) => jget(`/api/torrents/${hash}/pieces`),
|
|
|
|
action: (action, hashes, params) => jpost('/api/action', { action, hashes, params }),
|
|
remove: (hashes, deleteFiles) => jpost('/api/delete', { hashes, deleteFiles }),
|
|
add: (opts) => jpost('/api/add', opts),
|
|
toggleAltSpeed: () => jpost('/api/altspeed', {}),
|
|
|
|
createCategory: (name, savePath) => jpost('/api/categories', { name, savePath }),
|
|
deleteCategory: (name) => jpost('/api/categories/delete', { name }),
|
|
editCategory: (name, newName, savePath) =>
|
|
jpost('/api/categories/edit', { name, newName, savePath }),
|
|
createTag: (name) => jpost('/api/tags', { name }),
|
|
deleteTag: (name) => jpost('/api/tags/delete', { name }),
|
|
|
|
rss: () => jget('/api/rss'),
|
|
rssRules: () => jget('/api/rss/rules'),
|
|
addFeed: (name, url) => jpost('/api/rss', { name, url }),
|
|
deleteFeed: (name) => jpost('/api/rss/delete', { name }),
|
|
saveRssRule: (rule) => jpost('/api/rss/rules', rule),
|
|
deleteRssRule: (name) => jpost('/api/rss/rules/delete', { name }),
|
|
rssDownload: (item) => jpost('/api/rss/download', item),
|
|
saveIndexer: (ix) => jpost('/api/indexers', ix),
|
|
deleteIndexer: (name) => jpost('/api/indexers/delete', { name }),
|
|
script: () => jget('/api/script'),
|
|
saveScript: (source) => jpost('/api/script', { source }),
|
|
saveScriptSettings: (settings) => jpost('/api/script/settings', { settings }),
|
|
search: (q) => jget(`/api/search?q=${encodeURIComponent(q)}`),
|
|
|
|
// Live snapshot stream. onSnapshot(snapshot) called ~1/s.
|
|
stream(onSnapshot, onStatus) {
|
|
const es = new EventSource('/api/stream');
|
|
es.addEventListener('snapshot', (e) => onSnapshot(JSON.parse(e.data)));
|
|
es.onopen = () => onStatus && onStatus('connected');
|
|
es.onerror = () => onStatus && onStatus('reconnecting');
|
|
return es;
|
|
},
|
|
};
|