mirror of
https://github.com/DIYgod/RSSHub.git
synced 2026-08-29 01:53:47 +08:00
fix(route/picnob): support img not in slide
This commit is contained in:
@@ -3,47 +3,11 @@ import { Route, ViewType } from '@/types';
|
||||
import cache from '@/utils/cache';
|
||||
import { parseRelativeDate } from '@/utils/parse-date';
|
||||
import { load } from 'cheerio';
|
||||
import { connect, Options } from 'puppeteer-real-browser';
|
||||
|
||||
const realBrowserOption: Options = {
|
||||
args: ['--start-maximized'],
|
||||
turnstile: true,
|
||||
headless: false,
|
||||
// disableXvfb: true,
|
||||
// ignoreAllFlags:true,
|
||||
customConfig: {
|
||||
chromePath: config.chromiumExecutablePath,
|
||||
},
|
||||
connectOption: {
|
||||
defaultViewport: null,
|
||||
},
|
||||
plugins: [],
|
||||
};
|
||||
|
||||
async function getPageWithPuppeteer(url: string, selector: string): Promise<string> {
|
||||
if (config.puppeteerRealBrowserService) {
|
||||
const res = await fetch(`${config.puppeteerRealBrowserService}?url=${encodeURIComponent(url)}&selector=${encodeURIComponent(selector)}`);
|
||||
const json = await res.json();
|
||||
return (json.data.at(0) || '') as string;
|
||||
} else {
|
||||
const { page, browser } = await connect(realBrowserOption);
|
||||
await page.goto(url, { timeout: 50000 });
|
||||
let verify: boolean | null = null;
|
||||
const startDate = Date.now();
|
||||
while (!verify && Date.now() - startDate < 50000) {
|
||||
// eslint-disable-next-line no-await-in-loop, no-restricted-syntax
|
||||
verify = await page.evaluate((sel) => (document.querySelector(sel) ? true : null), selector).catch(() => null);
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
await new Promise((r) => setTimeout(r, 1000));
|
||||
}
|
||||
const html = await page.content();
|
||||
await browser.close();
|
||||
return html;
|
||||
}
|
||||
}
|
||||
|
||||
function getProfilePage(profileUrl: string): Promise<string> {
|
||||
return getPageWithPuppeteer(profileUrl, '.post_box');
|
||||
async function getPageWithRealBrowser(url: string, selector: string): Promise<string> {
|
||||
const res = await fetch(`${config.puppeteerRealBrowserService}?url=${encodeURIComponent(url)}&selector=${encodeURIComponent(selector)}`);
|
||||
const json = await res.json();
|
||||
return (json.data?.at(0) || '') as string;
|
||||
}
|
||||
|
||||
export const route: Route = {
|
||||
@@ -79,7 +43,7 @@ export const route: Route = {
|
||||
};
|
||||
|
||||
async function handler(ctx) {
|
||||
if (!config.puppeteerRealBrowserService && !config.chromiumExecutablePath) {
|
||||
if (!config.puppeteerRealBrowserService) {
|
||||
throw new Error('PUPPETEER_REAL_BROWSER_SERVICE or CHROMIUM_EXECUTABLE_PATH is required to use this route.');
|
||||
}
|
||||
|
||||
@@ -89,7 +53,7 @@ async function handler(ctx) {
|
||||
const type = ctx.req.param('type') ?? 'profile';
|
||||
const profileUrl = `${baseUrl}/profile/${id}/${type === 'tagged' ? 'tagged/' : ''}`;
|
||||
|
||||
const html = await getProfilePage(profileUrl);
|
||||
const html = await getPageWithRealBrowser(profileUrl, '.post_box');
|
||||
|
||||
const $ = load(html);
|
||||
|
||||
@@ -111,54 +75,8 @@ async function handler(ctx) {
|
||||
};
|
||||
});
|
||||
|
||||
// Fetch all post details concurrently
|
||||
// First, get HTML for all posts
|
||||
let htmlList: string[];
|
||||
if (config.puppeteerRealBrowserService) {
|
||||
// Use puppeteer service for multiple URLs
|
||||
htmlList = (await Promise.all(
|
||||
list.map((item) =>
|
||||
cache.tryGet(`picnob:user:${id}:${item.guid}:html`, async () => {
|
||||
const selector = '.video_img, .swiper-slide';
|
||||
const res = await fetch(`${config.puppeteerRealBrowserService}?url=${encodeURIComponent(item.link)}&selector=${encodeURIComponent(selector)}`);
|
||||
const json = await res.json();
|
||||
return (json.data?.at(0) || '') as string;
|
||||
})
|
||||
)
|
||||
)) as string[];
|
||||
} else {
|
||||
// Use local puppeteer browser
|
||||
const { browser } = await connect(realBrowserOption);
|
||||
try {
|
||||
htmlList = (await Promise.all(
|
||||
list.map((item) =>
|
||||
cache.tryGet(`picnob:user:${id}:${item.guid}:html`, async () => {
|
||||
const page = await browser.newPage();
|
||||
try {
|
||||
await page.goto(item.link, { timeout: 50000 });
|
||||
let verify: boolean | null = null;
|
||||
const startDate = Date.now();
|
||||
while (!verify && Date.now() - startDate < 50000) {
|
||||
// eslint-disable-next-line no-await-in-loop, no-restricted-syntax
|
||||
verify = await page.evaluate(() => (document.querySelector('.video_img') || document.querySelector('.swiper-slide') ? true : null)).catch(() => null);
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
await new Promise((r) => setTimeout(r, 1000));
|
||||
}
|
||||
return await page.content();
|
||||
} catch {
|
||||
return '';
|
||||
} finally {
|
||||
await page.close();
|
||||
}
|
||||
})
|
||||
)
|
||||
)) as string[];
|
||||
} finally {
|
||||
await browser.close();
|
||||
}
|
||||
}
|
||||
const htmlList = (await Promise.all(list.map((item) => cache.tryGet(`picnob:user:${id}:${item.guid}:html`, async () => await getPageWithRealBrowser(item.link, '.view'))))) as string[];
|
||||
|
||||
// Process HTML to generate descriptions
|
||||
const newDescription = htmlList.map((html) => {
|
||||
if (!html) {
|
||||
return '';
|
||||
@@ -168,9 +86,8 @@ async function handler(ctx) {
|
||||
return `<video src="${$('.video_img a').attr('href')}" poster="${$('.video_img img').attr('data-src')}"></video><br />${$('.sum_full').text()}`;
|
||||
} else {
|
||||
let description = '';
|
||||
for (const slide of $('.swiper-slide').toArray()) {
|
||||
const $slide = $(slide);
|
||||
description += `<img src="${$slide.find('.pic img').attr('data-src')}" /><br />`;
|
||||
for (const pic of $('.pic img').toArray()) {
|
||||
description += `<img src="${$(pic).attr('data-src')}" /><br />`;
|
||||
}
|
||||
description += $('.sum_full').text();
|
||||
return description;
|
||||
|
||||
Reference in New Issue
Block a user