utils.js
1 /** 2 * Pixiv shared helpers: authenticated Ajax fetch with standard error handling. 3 * 4 * All Pixiv Ajax APIs return `{ error: false, body: ... }` on success. 5 * On failure the HTTP status code is used to distinguish auth (401/403), 6 * not-found (404), and other errors. 7 */ 8 import { AuthRequiredError, CommandExecutionError } from '@jackwener/opencli/errors'; 9 const PIXIV_DOMAIN = 'www.pixiv.net'; 10 /** 11 * Navigate to Pixiv (to attach cookies) then fetch a Pixiv Ajax API endpoint. 12 * 13 * Handles the common navigate → evaluate(fetch) → error-check pattern used 14 * by every Pixiv TS adapter. 15 * 16 * @param page - Browser page instance 17 * @param path - API path, e.g. '/ajax/illust/12345' 18 * @param opts - Optional query params 19 * @returns - The parsed `body` from the JSON response 20 * @throws AuthRequiredError on 401/403 21 * @throws CommandExecutionError on 404 or other HTTP errors 22 */ 23 export async function pixivFetch(page, path, opts = {}) { 24 await page.goto(`https://${PIXIV_DOMAIN}`); 25 const qs = opts.params 26 ? '?' + Object.entries(opts.params).map(([k, v]) => `${k}=${encodeURIComponent(v)}`).join('&') 27 : ''; 28 const url = `https://${PIXIV_DOMAIN}${path}${qs}`; 29 const data = await page.evaluate(` 30 (async () => { 31 const res = await fetch(${JSON.stringify(url)}, { credentials: 'include' }); 32 if (!res.ok) return { __httpError: res.status }; 33 return await res.json(); 34 })() 35 `); 36 if (data?.__httpError) { 37 const status = data.__httpError; 38 if (status === 401 || status === 403) { 39 throw new AuthRequiredError(PIXIV_DOMAIN, 'Authentication required — please log in to Pixiv in Chrome'); 40 } 41 if (status === 404) { 42 throw new CommandExecutionError(opts.notFoundMsg || `Pixiv resource not found (HTTP 404)`); 43 } 44 throw new CommandExecutionError(`Pixiv request failed (HTTP ${status})`); 45 } 46 return data?.body; 47 } 48 /** Maximum number of illust IDs per batch detail request (Pixiv server limit). */ 49 export const BATCH_SIZE = 48;