69 lines
3.2 KiB
JavaScript
69 lines
3.2 KiB
JavaScript
'use strict';
|
|
|
|
const DEFAULT_API_BASE = 'https://api.bgm.tv';
|
|
let apiBase = DEFAULT_API_BASE;
|
|
// Set by runSync from settings.bgmApiBase (sync is locked/serial, so a module-level value is safe).
|
|
function setApiBase(base) { apiBase = (typeof base === 'string' && base.trim()) ? base.trim().replace(/\/+$/, '') : DEFAULT_API_BASE; }
|
|
|
|
const sleep = (ms) => new Promise(r => setTimeout(r, ms));
|
|
|
|
async function bgmFetch(path, token) {
|
|
const res = await fetch(apiBase + path, {
|
|
headers: {
|
|
'Accept': 'application/json',
|
|
'User-Agent': 'BangumiVaultDocker/1.0',
|
|
...(token ? { 'Authorization': 'Bearer ' + String(token).trim() } : {})
|
|
}
|
|
});
|
|
if (!res.ok) {
|
|
const t = await res.text().catch(() => res.statusText);
|
|
throw new Error(`HTTP ${res.status}: ${String(t).slice(0, 200)}`);
|
|
}
|
|
return res.json();
|
|
}
|
|
|
|
async function fetchMe(token) {
|
|
return bgmFetch('/v0/me', token);
|
|
}
|
|
|
|
async function fetchCollectionAll(username, st, ct, token, onPage) {
|
|
const limit = 50; let offset = 0; let total = Infinity; let page = 0; const out = [];
|
|
while (offset < total) {
|
|
const path = `/v0/users/${encodeURIComponent(username)}/collections?subject_type=${st}&type=${ct}&limit=${limit}&offset=${offset}`;
|
|
const js = await bgmFetch(path, token); const data = Array.isArray(js) ? js : (js.data || []);
|
|
total = Number.isFinite(js.total) ? js.total : (offset + data.length + (data.length === limit ? limit : 0));
|
|
out.push(...data.map(x => ({ ...x, __fallback: { subject_type: st, collection_type: ct } }))); page++;
|
|
if (onPage) onPage(page, out.length);
|
|
if (!data.length || data.length < limit) break;
|
|
offset += limit; await sleep(110);
|
|
}
|
|
return out;
|
|
}
|
|
|
|
async function fetchCollectionRecent(username, st, ct, token, cutoff, onPage) {
|
|
const limit = 50; let offset = 0; let total = Infinity; let page = 0; const out = []; const cutoffMs = cutoff.getTime();
|
|
while (offset < total) {
|
|
const path = `/v0/users/${encodeURIComponent(username)}/collections?subject_type=${st}&type=${ct}&limit=${limit}&offset=${offset}`;
|
|
const js = await bgmFetch(path, token); const data = Array.isArray(js) ? js : (js.data || []);
|
|
total = Number.isFinite(js.total) ? js.total : (offset + data.length + (data.length === limit ? limit : 0));
|
|
const decorated = data.map(x => ({ ...x, __fallback: { subject_type: st, collection_type: ct } }));
|
|
const recent = decorated.filter(x => { const t = Date.parse(x.updated_at || x.updatedAt || ''); return !Number.isFinite(t) || t >= cutoffMs; });
|
|
out.push(...recent); page++;
|
|
const stopByTime = data.length > 0 && recent.length === 0 && data.every(x => { const t = Date.parse(x.updated_at || x.updatedAt || ''); return Number.isFinite(t) && t < cutoffMs; });
|
|
if (onPage) onPage(page, out.length, stopByTime);
|
|
if (!data.length || data.length < limit || stopByTime) break;
|
|
offset += limit; await sleep(80);
|
|
}
|
|
return out;
|
|
}
|
|
|
|
async function fetchSubjectDetail(subjectId, token) {
|
|
try {
|
|
return await bgmFetch(`/v0/subjects/${encodeURIComponent(subjectId)}`, token || '');
|
|
} catch {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
module.exports = { DEFAULT_API_BASE, setApiBase, sleep, bgmFetch, fetchMe, fetchCollectionAll, fetchCollectionRecent, fetchSubjectDetail };
|