diff --git a/docker-compose.yml b/docker-compose.yml
index 33f9172b1a..3f11873660 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -12,7 +12,6 @@ services:
CACHE_TYPE: redis
REDIS_URL: 'redis://redis:6379/'
PUPPETEER_WS_ENDPOINT: 'ws://browserless:3000' # marked
- PUPPETEER_REAL_BROWSER_SERVICE: 'http://real-browser:3000' # marked
healthcheck:
test: ['CMD', 'curl', '-f', 'http://localhost:1200/healthz']
interval: 30s
@@ -22,17 +21,6 @@ services:
- redis
- browserless # marked
- real-browser:
- image: ghcr.io/hyoban/puppeteer-real-browser-hono
- restart: always
- ports:
- - '3001:3000'
- healthcheck:
- test: ['CMD', 'curl', '-f', 'http://localhost:3000']
- interval: 30s
- timeout: 10s
- retries: 3
-
browserless: # marked
image: browserless/chrome # marked
restart: always # marked
diff --git a/lib/routes/comic-walker/manga.ts b/lib/routes/comic-walker/manga.ts
index 4ee72b67ab..77bdf53afc 100644
--- a/lib/routes/comic-walker/manga.ts
+++ b/lib/routes/comic-walker/manga.ts
@@ -25,7 +25,7 @@ export const route: Route = {
target: '/manga/:id',
},
],
- name: 'カドコミ(Kadocomi)漫画详情',
+ name: '漫画详情',
maintainers: ['xiaobailoves'],
handler: async (ctx) => {
diff --git a/lib/routes/picnob.info/user.ts b/lib/routes/picnob.info/user.ts
index 4160f53ca4..f8ac278722 100644
--- a/lib/routes/picnob.info/user.ts
+++ b/lib/routes/picnob.info/user.ts
@@ -6,6 +6,7 @@ import { ViewType } from '@/types';
import cache from '@/utils/cache';
import ofetch from '@/utils/ofetch';
import { parseDate } from '@/utils/parse-date';
+import wait from '@/utils/wait';
import type { Post, Profile, Pull, Status, Story } from './types';
@@ -105,7 +106,7 @@ async function handler(ctx) {
}
if (attempt < 9) {
// eslint-disable-next-line no-await-in-loop
- await new Promise((resolve) => setTimeout(resolve, 3000));
+ await wait(3000);
}
}
diff --git a/lib/routes/picnob/user.ts b/lib/routes/picnob/user.ts
index e76aa0ab1b..14a388a42f 100644
--- a/lib/routes/picnob/user.ts
+++ b/lib/routes/picnob/user.ts
@@ -1,51 +1,51 @@
-import { load } from 'cheerio';
-import type { ConnectResult, Options } from 'puppeteer-real-browser';
-import { connect } from 'puppeteer-real-browser';
+// import { load } from 'cheerio';
+// import type { ConnectResult, Options } from 'puppeteer-real-browser';
+// import { connect } from 'puppeteer-real-browser';
-import { config } from '@/config';
+// import { config } from '@/config';
import type { Route } from '@/types';
import { ViewType } from '@/types';
-import cache from '@/utils/cache';
-import { parseRelativeDate } from '@/utils/parse-date';
+// import cache from '@/utils/cache';
+// import { parseRelativeDate } from '@/utils/parse-date';
-const realBrowserOption: Options = {
- args: ['--start-maximized'],
- turnstile: true,
- headless: false,
- // disableXvfb: true,
- // ignoreAllFlags:true,
- customConfig: {
- chromePath: config.chromiumExecutablePath,
- },
- connectOption: {
- defaultViewport: null,
- },
- plugins: [],
-};
+// const realBrowserOption: Options = {
+// args: ['--start-maximized'],
+// turnstile: true,
+// headless: false,
+// // disableXvfb: true,
+// // ignoreAllFlags:true,
+// customConfig: {
+// chromePath: config.chromiumExecutablePath,
+// },
+// connectOption: {
+// defaultViewport: null,
+// },
+// plugins: [],
+// };
-async function getPageWithRealBrowser(url: string, selector: string, conn: ConnectResult | null) {
- try {
- if (conn) {
- const page = conn.page;
- await page.goto(url, { timeout: 30000 });
- let verify: boolean | null = null;
- const startDate = Date.now();
- while (!verify && Date.now() - startDate < 30000) {
- // 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));
- }
- return await page.content();
- } else {
- const res = await fetch(`${config.puppeteerRealBrowserService}?url=${encodeURIComponent(url)}&selector=${encodeURIComponent(selector)}`);
- const json = await res.json();
- return (json.data?.at(0) || '') as string;
- }
- } catch {
- return '';
- }
-}
+// async function getPageWithRealBrowser(url: string, selector: string, conn: ConnectResult | null) {
+// try {
+// if (conn) {
+// const page = conn.page;
+// await page.goto(url, { timeout: 30000 });
+// let verify: boolean | null = null;
+// const startDate = Date.now();
+// while (!verify && Date.now() - startDate < 30000) {
+// // 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));
+// }
+// return await page.content();
+// } else {
+// const res = await fetch(`${config.puppeteerRealBrowserService}?url=${encodeURIComponent(url)}&selector=${encodeURIComponent(selector)}`);
+// const json = await res.json();
+// return (json.data?.at(0) || '') as string;
+// }
+// } catch {
+// return '';
+// }
+// }
export const route: Route = {
path: '/user/:id/:type?',
@@ -57,8 +57,8 @@ export const route: Route = {
},
features: {
requireConfig: false,
- requirePuppeteer: true,
- antiCrawler: true,
+ requirePuppeteer: false,
+ antiCrawler: false,
supportBT: false,
supportPodcast: false,
supportScihub: false,
@@ -79,104 +79,108 @@ export const route: Route = {
view: ViewType.Pictures,
};
-async function handler(ctx) {
- if (!config.puppeteerRealBrowserService && !config.chromiumExecutablePath) {
- throw new Error('PUPPETEER_REAL_BROWSER_SERVICE or CHROMIUM_EXECUTABLE_PATH is required to use this route.');
- }
-
- // NOTE: 'picnob' is still available, but all requests to 'picnob' will be redirected to 'pixnoy' eventually
- const baseUrl = 'https://www.pixnoy.com';
+function handler(ctx) {
const id = ctx.req.param('id');
- const type = ctx.req.param('type') ?? 'profile';
- const profileUrl = `${baseUrl}/profile/${id}/${type === 'tagged' ? 'tagged/' : ''}`;
+ return ctx.set('redirect', `/picnob.info/user/${id}`);
- let conn: ConnectResult | null = null;
+ // // Original puppeteer-real-browser implementation (deprecated)
+ // if (!config.puppeteerRealBrowserService && !config.chromiumExecutablePath) {
+ // throw new Error('PUPPETEER_REAL_BROWSER_SERVICE or CHROMIUM_EXECUTABLE_PATH is required to use this route.');
+ // }
- if (!config.puppeteerRealBrowserService) {
- conn = await connect(realBrowserOption);
+ // // NOTE: 'picnob' is still available, but all requests to 'picnob' will be redirected to 'picnob.info' eventually
+ // const baseUrl = 'https://www.pixnoy.com';
+ // const id = ctx.req.param('id');
+ // const type = ctx.req.param('type') ?? 'profile';
+ // const profileUrl = `${baseUrl}/profile/${id}/${type === 'tagged' ? 'tagged/' : ''}`;
- setTimeout(async () => {
- if (conn) {
- await conn.browser.close();
- }
- }, 60000);
- }
+ // let conn: ConnectResult | null = null;
- const html = await getPageWithRealBrowser(profileUrl, '.post_box', conn);
- if (!html) {
- if (conn) {
- await conn.browser.close();
- conn = null;
- }
- throw new Error('Failed to fetch user profile page. User may not exist or there are no posts available.');
- }
+ // if (!config.puppeteerRealBrowserService) {
+ // conn = await connect(realBrowserOption);
- const $ = load(html);
+ // setTimeout(async () => {
+ // if (conn) {
+ // await conn.browser.close();
+ // }
+ // }, 60000);
+ // }
- const list = $('.post_box')
- .toArray()
- .map((item) => {
- const $item = $(item);
- const coverLink = $item.find('.cover_link').attr('href');
- const shortcode = coverLink?.split('/')?.[2];
- const image = $item.find('.cover .cover_link img');
- const title = image.attr('alt') || '';
+ // const html = await getPageWithRealBrowser(profileUrl, '.post_box', conn);
+ // if (!html) {
+ // if (conn) {
+ // await conn.browser.close();
+ // conn = null;
+ // }
+ // throw new Error('Failed to fetch user profile page. User may not exist or there are no posts available.');
+ // }
- return {
- title,
- description: `})
${title}`,
- link: `${baseUrl}${coverLink}`,
- guid: shortcode,
- pubDate: parseRelativeDate($item.find('.time .txt').text()),
- };
- });
+ // const $ = load(html);
- const jobs = list.map((item) => cache.tryGet(`picnob:user:${id}:${item.guid}:html`, async () => await getPageWithRealBrowser(item.link, '.view', conn)));
+ // const list = $('.post_box')
+ // .toArray()
+ // .map((item) => {
+ // const $item = $(item);
+ // const coverLink = $item.find('.cover_link').attr('href');
+ // const shortcode = coverLink?.split('/')?.[2];
+ // const image = $item.find('.cover .cover_link img');
+ // const title = image.attr('alt') || '';
- let htmlList: string[] = [];
- if (conn) {
- try {
- for (const job of jobs) {
- // eslint-disable-next-line no-await-in-loop
- const html = await job;
- htmlList.push(html);
- }
- } finally {
- await conn.browser.close();
- conn = null;
- }
- } else {
- htmlList = await Promise.all(jobs);
- }
+ // return {
+ // title,
+ // description: `})
${title}`,
+ // link: `${baseUrl}${coverLink}`,
+ // guid: shortcode,
+ // pubDate: parseRelativeDate($item.find('.time .txt').text()),
+ // };
+ // });
- const newDescription = htmlList.map((html) => {
- if (!html) {
- return '';
- }
- const $ = load(html);
- if ($('.video_img').length > 0) {
- return `
${$('.sum_full').text()}`;
- } else {
- let description = '';
- for (const pic of $('.pic img').toArray()) {
- const dataSrc = $(pic).attr('data-src');
- if (dataSrc) {
- description += `
`;
- }
- }
- description += $('.sum_full').text();
- return description;
- }
- });
+ // const jobs = list.map((item) => cache.tryGet(`picnob:user:${id}:${item.guid}:html`, async () => await getPageWithRealBrowser(item.link, '.view', conn)));
- return {
- title: `${$('h1.fullname').text()} (@${id}) ${type === 'tagged' ? 'tagged' : 'public'} posts - Picnob`,
- description: $('.info .sum').text(),
- link: profileUrl,
- image: $('.ava .pic img').attr('src'),
- item: list.map((item, index) => ({
- ...item,
- description: newDescription[index] || item.description,
- })),
- };
+ // let htmlList: string[] = [];
+ // if (conn) {
+ // try {
+ // for (const job of jobs) {
+ // // eslint-disable-next-line no-await-in-loop
+ // const html = await job;
+ // htmlList.push(html);
+ // }
+ // } finally {
+ // await conn.browser.close();
+ // conn = null;
+ // }
+ // } else {
+ // htmlList = await Promise.all(jobs);
+ // }
+
+ // const newDescription = htmlList.map((html) => {
+ // if (!html) {
+ // return '';
+ // }
+ // const $ = load(html);
+ // if ($('.video_img').length > 0) {
+ // return `
${$('.sum_full').text()}`;
+ // } else {
+ // let description = '';
+ // for (const pic of $('.pic img').toArray()) {
+ // const dataSrc = $(pic).attr('data-src');
+ // if (dataSrc) {
+ // description += `
`;
+ // }
+ // }
+ // description += $('.sum_full').text();
+ // return description;
+ // }
+ // });
+
+ // return {
+ // title: `${$('h1.fullname').text()} (@${id}) ${type === 'tagged' ? 'tagged' : 'public'} posts - Picnob`,
+ // description: $('.info .sum').text(),
+ // link: profileUrl,
+ // image: $('.ava .pic img').attr('src'),
+ // item: list.map((item, index) => ({
+ // ...item,
+ // description: newDescription[index] || item.description,
+ // })),
+ // };
}