From d648da55495712f63328d006bd583e459612eaaa Mon Sep 17 00:00:00 2001 From: Tony Date: Wed, 4 Feb 2026 05:27:22 +0800 Subject: [PATCH] fix(route/javtrailers): replace ofetch with puppeteer for API requests (#21055) --- lib/routes/javtrailers/casts.ts | 14 ++++++++------ lib/routes/javtrailers/categories.ts | 14 ++++++++------ lib/routes/javtrailers/studios.ts | 14 ++++++++------ lib/routes/javtrailers/utils.ts | 24 ++++++++++++++++++++---- 4 files changed, 44 insertions(+), 22 deletions(-) diff --git a/lib/routes/javtrailers/casts.ts b/lib/routes/javtrailers/casts.ts index efc342027..f38ad0f08 100644 --- a/lib/routes/javtrailers/casts.ts +++ b/lib/routes/javtrailers/casts.ts @@ -1,8 +1,8 @@ import type { Route } from '@/types'; import cache from '@/utils/cache'; -import ofetch from '@/utils/ofetch'; +import puppeteer from '@/utils/puppeteer'; -import { baseUrl, getItem, headers, parseList } from './utils'; +import { baseUrl, getItem, parseList, puppeteerFetch } from './utils'; export const route: Route = { path: '/casts/:cast', @@ -20,19 +20,21 @@ export const route: Route = { handler, features: { nsfw: true, + requirePuppeteer: true, }, }; async function handler(ctx) { const { cast } = ctx.req.param(); - const response = await ofetch(`${baseUrl}/api/casts/${cast}?page=0`, { - headers, - }); + const browser = await puppeteer(); + const response = await puppeteerFetch(`${baseUrl}/api/casts/${cast}?page=0`, browser); const list = parseList(response.videos); - const items = await Promise.all(list.map((item) => cache.tryGet(item.link, () => getItem(item)))); + const items = await Promise.all(list.map((item) => cache.tryGet(item.link, () => getItem(item, browser)))); + + await browser.close(); return { title: `Watch ${response.cast.name} Jav Online | Japanese Adult Video - JavTrailers.com`, diff --git a/lib/routes/javtrailers/categories.ts b/lib/routes/javtrailers/categories.ts index 929d6533e..50b132e3c 100644 --- a/lib/routes/javtrailers/categories.ts +++ b/lib/routes/javtrailers/categories.ts @@ -1,8 +1,8 @@ import type { Route } from '@/types'; import cache from '@/utils/cache'; -import ofetch from '@/utils/ofetch'; +import puppeteer from '@/utils/puppeteer'; -import { baseUrl, getItem, headers, parseList } from './utils'; +import { baseUrl, getItem, parseList, puppeteerFetch } from './utils'; export const route: Route = { path: '/categories/:category', @@ -20,19 +20,21 @@ export const route: Route = { handler, features: { nsfw: true, + requirePuppeteer: true, }, }; async function handler(ctx) { const { category } = ctx.req.param(); - const response = await ofetch(`${baseUrl}/api/categories/${category}?page=0`, { - headers, - }); + const browser = await puppeteer(); + const response = await puppeteerFetch(`${baseUrl}/api/categories/${category}?page=0`, browser); const list = parseList(response.videos); - const items = await Promise.all(list.map((item) => cache.tryGet(item.link, () => getItem(item)))); + const items = await Promise.all(list.map((item) => cache.tryGet(item.link, () => getItem(item, browser)))); + + await browser.close(); return { title: `Watch ${response.category.name} Jav Online | Japanese Adult Video - JavTrailers.com`, diff --git a/lib/routes/javtrailers/studios.ts b/lib/routes/javtrailers/studios.ts index 66788017a..6eff6aebb 100644 --- a/lib/routes/javtrailers/studios.ts +++ b/lib/routes/javtrailers/studios.ts @@ -1,8 +1,8 @@ import type { Route } from '@/types'; import cache from '@/utils/cache'; -import ofetch from '@/utils/ofetch'; +import puppeteer from '@/utils/puppeteer'; -import { baseUrl, getItem, headers, parseList } from './utils'; +import { baseUrl, getItem, parseList, puppeteerFetch } from './utils'; export const route: Route = { path: '/studios/:studio', @@ -19,19 +19,21 @@ export const route: Route = { handler, features: { nsfw: true, + requirePuppeteer: true, }, }; async function handler(ctx) { const { studio } = ctx.req.param(); - const response = await ofetch(`${baseUrl}/api/studios/${studio}?page=0`, { - headers, - }); + const browser = await puppeteer(); + const response = await puppeteerFetch(`${baseUrl}/api/studios/${studio}?page=0`, browser); const list = parseList(response.videos); - const items = await Promise.all(list.map((item) => cache.tryGet(item.link, () => getItem(item)))); + const items = await Promise.all(list.map((item) => cache.tryGet(item.link, () => getItem(item, browser)))); + + await browser.close(); return { title: `${response.studio.hotDvdIds?.join(' ') ?? response.studio.name} Jav Online | Japanese Adult Video - JavTrailers.com`, diff --git a/lib/routes/javtrailers/utils.ts b/lib/routes/javtrailers/utils.ts index a33b73ef7..dd2b3f1bd 100644 --- a/lib/routes/javtrailers/utils.ts +++ b/lib/routes/javtrailers/utils.ts @@ -1,4 +1,4 @@ -import ofetch from '@/utils/ofetch'; +import logger from '@/utils/logger'; import { parseDate } from '@/utils/parse-date'; import { renderDescription } from './templates/description'; @@ -27,11 +27,27 @@ export const parseList = (videos) => contentId: item.contentId, })); -export const getItem = async (item) => { - const response = await ofetch(`${baseUrl}/api/video/${item.contentId}`, { - headers, +export const puppeteerFetch = async (url: string, browser) => { + const page = await browser.newPage(); + await page.setExtraHTTPHeaders(headers); + await page.setRequestInterception(true); + page.on('request', (request) => { + request.resourceType() === 'document' ? request.continue() : request.abort(); }); + logger.http(`Requesting ${url}`); + await page.goto(url, { waitUntil: 'domcontentloaded' }); + + const apiResponse = await page.evaluate(() => document.body.textContent || ''); + const response = JSON.parse(apiResponse); + await page.close(); + + return response; +}; + +export const getItem = async (item, browser) => { + const response = await puppeteerFetch(`${baseUrl}/api/video/${item.contentId}`, browser); + const videoInfo: Video = response.video; videoInfo.gallery = hdGallery(videoInfo.gallery);