UNPKG

rsshub

Version:
193 lines (191 loc) 7.63 kB
import { t as config } from "./config-C37vj7VH.mjs"; import { t as logger_default } from "./logger-Czu8UMNd.mjs"; import { t as ofetch_default } from "./ofetch-BIyrKU3Y.mjs"; import { t as parseDate } from "./parse-date-BrP7mxXf.mjs"; import { t as cache_default } from "./cache-Bo__VnGm.mjs"; import { n as puppeteer_default, t as getPuppeteerPage } from "./puppeteer-DGmvuGvT.mjs"; import { t as captcha_default } from "./captcha-CMCNYwwK.mjs"; import { load } from "cheerio"; //#region lib/routes/xiaohongshu/util.ts const getHeaders = (cookie) => ({ Accept: "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding": "gzip, deflate, br", "Accept-Language": "en-US,en;q=0.9", "Cache-Control": "no-cache", Connection: "keep-alive", Host: "www.xiaohongshu.com", Pragma: "no-cache", "Sec-Ch-Ua": "\"Chromium\";v=\"122\", \"Not(A:Brand\";v=\"24\", \"Google Chrome\";v=\"122\"", "Sec-Ch-Ua-Mobile": "?0", "Sec-Ch-Ua-Platform": "\"Windows\"", "Sec-Fetch-Dest": "document", "Sec-Fetch-Mode": "navigate", "Sec-Fetch-Site": "none", "Sec-Fetch-User": "?1", "Upgrade-Insecure-Requests": "1", "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36", ...cookie ? { Cookie: cookie } : {} }); const getUser = (url, cache) => cache.tryGet(url, async () => { const { page, destory } = await getPuppeteerPage(url, { onBeforeLoad: async (page$1) => { await page$1.setRequestInterception(true); page$1.on("request", (request) => { request.resourceType() === "document" || request.resourceType() === "script" || request.resourceType() === "xhr" || request.resourceType() === "other" ? request.continue() : request.abort(); }); } }); try { let collect = ""; logger_default.http(`Requesting ${url}`); await page.goto(url, { waitUntil: "domcontentloaded" }); await page.waitForSelector("div.reds-tab-item:nth-child(2), #red-captcha"); if (await page.$("#red-captcha")) throw new captcha_default("小红书风控校验,请稍后再试"); const initialState = await page.evaluate(() => window.__INITIAL_STATE__); if (!await page.$(".lock-icon")) { await page.click("div.reds-tab-item:nth-child(2)"); try { collect = await (await page.waitForResponse((res) => { const req = res.request(); return req.url().includes("/api/sns/web/v2/note/collect/page") && req.method() === "GET" && req.resourceType() === "xhr"; }, { timeout: 5e3 })).json(); } catch {} } let { userPageData, notes } = initialState.user; userPageData = userPageData._rawValue || userPageData; notes = notes._rawValue || notes; return { userPageData, notes, collect }; } finally { await destory(); } }, config.cache.routeExpire, false); const getBoard = (url, cache) => cache.tryGet(url, async () => { const browser = await puppeteer_default(); try { const page = await browser.newPage(); await page.setRequestInterception(true); page.on("request", (request) => { request.resourceType() === "document" || request.resourceType() === "script" || request.resourceType() === "xhr" ? request.continue() : request.abort(); }); logger_default.http(`Requesting ${url}`); await page.goto(url); await page.waitForSelector(".pc-container"); return (await page.evaluate(() => window.__INITIAL_SSR_STATE__)).Main; } finally { await browser.close(); } }, config.cache.routeExpire, false); async function renderNotesFulltext(notes, urlPrex, displayLivePhoto) { const data = []; const promises = notes.flatMap((note) => note.map(async ({ noteCard, id }) => { const link = `${urlPrex}/${id}`; const guid = `${urlPrex}/${noteCard.noteId}`; const { title, description, pubDate, updated } = await getFullNote(link, displayLivePhoto); return { title, link, description, author: noteCard.user.nickName, guid, pubDate, updated }; })); data.push(...await Promise.all(promises)); return data; } async function getFullNote(link, displayLivePhoto) { return await cache_default.tryGet(link, async () => { const script = extractInitialState(load(await ofetch_default(link, { headers: getHeaders(config.xiaohongshu.cookie) }))); const state = JSON.parse(script); const note = state.note.noteDetailMap[state.note.firstNoteId].note; const title = note.title; let desc = note.desc; desc = desc.replaceAll(/\[.*?\]/g, ""); desc = desc.replaceAll(/#(.*?)#/g, "#$1"); desc = desc.replaceAll("\n", "<br>"); const pubDate = parseDate(note.time, "x"); const updated = parseDate(note.lastUpdateTime, "x"); let mediaContent = ""; if (note.type === "video") { const originVideoKey = note.video?.consumer?.originVideoKey; const videoUrls = []; if (originVideoKey) videoUrls.push(`http://sns-video-al.xhscdn.com/${originVideoKey}`); for (const type of [ "av1", "h264", "h265", "h266" ]) { const streams = note.video?.media?.stream?.[type]; if (streams?.length > 0) { const stream = streams[0]; if (stream.masterUrl) videoUrls.push(stream.masterUrl); if (stream.backupUrls?.length) videoUrls.push(...stream.backupUrls); } } const posterUrl = note.imageList?.[0]?.urlDefault; if (videoUrls.length > 0) mediaContent = `<video controls ${posterUrl ? `poster="${posterUrl}"` : ""}> ${videoUrls.map((url) => `<source src="${url}" type="video/mp4">`).join("\n")} </video><br>`; } else mediaContent = note.imageList.map((image) => { if (image.livePhoto && displayLivePhoto) { const videoUrls = []; for (const type of [ "av1", "h264", "h265", "h266" ]) { const streams = image.stream?.[type]; if (streams?.length > 0) { if (streams[0].masterUrl) videoUrls.push(streams[0].masterUrl); if (streams[0].backupUrls?.length) videoUrls.push(...streams[0].backupUrls); } } if (videoUrls.length > 0) return `<video controls poster="${image.urlDefault}"> ${videoUrls.map((url) => `<source src="${url}" type="video/mp4">`).join("\n")} </video>`; } return `<img src="${image.urlDefault}">`; }).join("<br>"); const description = `${mediaContent}<br>${desc}`; return { title: title || note.desc, description, pubDate, updated }; }); } async function getUserWithCookie(url) { const cookie = config.xiaohongshu.cookie; const $ = load(await ofetch_default(url, { headers: getHeaders(cookie) })); const paths = $("#userPostedFeeds > section > div > a.cover.ld.mask").map((i, item) => item.attributes[3].value); const script = extractInitialState($); const state = JSON.parse(script); let index = 0; for (const item of state.user.notes.flat()) { const path = paths[index]; if (path && path.includes("?")) item.id = item.id + path?.slice(path.indexOf("?")); index = index + 1; } return state.user; } function extractInitialState($) { let script = $("script").filter((i, script$1) => { return (script$1.children[0]?.data)?.startsWith("window.__INITIAL_STATE__="); }).text(); script = script.slice(25); script = script.replaceAll("undefined", "null"); return script; } async function checkCookie() { const cookie = config.xiaohongshu.cookie; const res = await ofetch_default("https://edith.xiaohongshu.com/api/sns/web/v2/user/me", { headers: getHeaders(cookie) }); return res.code === 0 && !!res.data.user_id; } //#endregion export { renderNotesFulltext as a, getUserWithCookie as i, getBoard as n, getUser as r, checkCookie as t };