UNPKG

rsshub

Version:
123 lines (122 loc) • 5.32 kB
import { t as rofetch } from "./ofetch-C3ts-Hud.mjs"; import { t as config } from "./config-CCmw1BNE.mjs"; import { t as parseDate } from "./parse-date-Cr0wQjV_.mjs"; import { t as got_default } from "./got-BTowW50G.mjs"; import { t as ConfigNotFoundError } from "./config-not-found-fQ5mxvDU.mjs"; import { t as getPlaywrightPage } from "./playwright-o20DiLNh.mjs"; import { Fragment, jsx, jsxs } from "hono/jsx/jsx-runtime"; import { load } from "cheerio"; import { renderToString } from "hono/jsx/dom/server"; //#region lib/routes/nhentai/util.tsx const baseUrl = "https://nhentai.net"; const getCookie = async (username, password, cache) => { const loginUrl = "https://nhentai.net/login/"; const cacheKey = "nhentai:cookie"; const cachedCookie = await cache.get(cacheKey); if (cachedCookie) { const { cookie, time } = JSON.parse(cachedCookie); if (Date.now() - time < 86400 * 3 * 1e3) return cookie; } const { data, headers } = await got_default(loginUrl); const csrfTokenMiddleware = data.match(/name="csrfmiddlewaretoken" value="(.*?)"/)[1]; const csrfTokenCookie = headers["set-cookie"].map((c) => c.split(";", 1)[0]).join("; "); const login = await got_default.post(loginUrl, { headers: { referer: loginUrl, cookie: csrfTokenCookie }, form: { csrfmiddlewaretoken: csrfTokenMiddleware, username_or_email: username, password, next: "" }, followRedirect: false }); if (login.statusCode !== 302) { cache.set(cacheKey, JSON.stringify({ cookie: "", time: Date.now() })); return ""; } const userTokenCookie = login.headers["set-cookie"].map((c) => c.split(";", 1)[0]).join("; "); cache.set(cacheKey, JSON.stringify({ cookie: userTokenCookie, time: Date.now() })); return userTokenCookie; }; const fetchPage = async (url) => { try { return await rofetch(url); } catch (error) { if ((error.status ?? error.statusCode) === 403) { const { page, destroy } = await getPlaywrightPage(url, { onBeforeLoad: async (page) => { const allowedTypes = /* @__PURE__ */ new Set([ "document", "script", "xhr", "fetch" ]); await page.route("**/*", (route) => { const request = route.request(); allowedTypes.has(request.resourceType()) ? route.continue() : route.abort(); }); } }); const content = await page.content(); await destroy(); return content; } throw error; } }; const getSimple = async (url) => { const $ = load(await fetchPage(url)); return $(".gallery a.cover").toArray().map((ele) => parseSimpleDetail($(ele))); }; const getDetails = (cache, simples, limit) => Promise.all(simples.slice(0, limit).map((simple) => cache.tryGet(simple.link, () => getDetail(simple)))); const getTorrents = async (cache, simples, limit) => { if (!config.nhentai || !config.nhentai.username || !config.nhentai.password) throw new ConfigNotFoundError("nhentai RSS with torrents is disabled due to the lack of <a href=\"https://docs.rsshub.app/deploy/config#route-specific-configurations\">relevant config</a>"); const cookie = await getCookie(config.nhentai.username, config.nhentai.password, cache); if (!cookie) throw new ConfigNotFoundError("Invalid username (or email) or password for nhentai torrent download"); return getTorrentWithCookie(cache, simples, cookie, limit); }; const getTorrentWithCookie = (cache, simples, cookie, limit) => Promise.all(simples.slice(0, limit).map((simple) => cache.tryGet(simple.link + "download", () => getTorrent(simple, cookie)))); const parseSimpleDetail = ($ele) => { const link = new URL($ele.attr("href"), baseUrl).href; const thumb = $ele.children("img"); const highResoThumbSrc = (thumb.attr("data-src") || thumb.attr("src")).replace("thumb", "1").replace(/t(\d+)\.nhentai\.net/, "i$1.nhentai.net").replace(".webp.webp", ".webp"); return { title: $ele.children(".caption").text(), link, description: `<img src="${highResoThumbSrc}">` }; }; const getTorrent = async (simple, cookie) => { const { link } = simple; const response = await rofetch(link + "download", { headers: { Cookie: cookie } }); return { ...simple, enclosure_url: response, enclosure_type: "application/x-bittorrent" }; }; const getDetail = async (simple) => { const { link } = simple; const $ = load(await fetchPage(link)); const galleryImgs = $(".gallerythumb img").toArray().map((ele) => new URL($(ele).attr("data-src"), baseUrl).href).map((src) => src.replace(/(.+)(\d)t\.(.+)/, (_, p1, p2, p3) => `${p1}${p2}.${p3}`)).map((src) => src.replace(/t(\d+)\.nhentai\.net/, "i$1.nhentai.net")).map((src) => src.replace(/\.(jpg|png|gif)\.webp$/, ".$1")).map((src) => src.replace(/\.webp\.webp$/, ".webp")); return { ...simple, title: $("div#info > h2").text() || $("div#info > h1").text(), pubDate: parseDate($("time").attr("datetime")), description: renderDescription(galleryImgs.length, galleryImgs) }; }; const renderDescription = (length, images) => renderToString(/* @__PURE__ */ jsxs(Fragment, { children: [ /* @__PURE__ */ jsxs("h1", { children: [length, " pages"] }), /* @__PURE__ */ jsx("br", {}), images.map((image, index) => /* @__PURE__ */ jsxs("span", { children: [/* @__PURE__ */ jsx("img", { src: image }), /* @__PURE__ */ jsx("br", {})] }, `${image}-${index}`)) ] })); //#endregion export { getSimple as n, getTorrents as r, getDetails as t };