From 2818fae6af25b566c0e7085b5355221ba5c44f48 Mon Sep 17 00:00:00 2001 From: mrbunker Date: Sat, 11 Mar 2023 12:32:23 +0800 Subject: [PATCH] fix the error redirect of jable --- src/utils/siteList.ts | 40 ++++- src/utils/xhr.ts | 381 +++++++++++++++++++++--------------------- 2 files changed, 225 insertions(+), 196 deletions(-) diff --git a/src/utils/siteList.ts b/src/utils/siteList.ts index e1ef65d..e15d8b7 100644 --- a/src/utils/siteList.ts +++ b/src/utils/siteList.ts @@ -1,25 +1,46 @@ export interface DomQuery_parser { - /** 部分网站搜索页结果第一个是广告,所以要加一个 index */ + /** 部分网站搜索页结果第一个是广告,加入一个 index,来指定到固定的位置。 + * 点名:GGJAV + */ listIndex?: number; - /** code 是用空格分割的 */ + + /** 大部分 code 格式是 `xxx-000`,还有一部分用空格 `xxx 000`。 + * 点名:GGJAV + */ spaceCode?: boolean; + + /** a 标签 href 的 query */ linkQuery: string; + /** 在 title 里检测是否包含「字幕」等文本 */ titleQuery: string; + + /** 检测有无字幕的方法 + * 点名:Jable + */ + checkFn?: (arg: any) => boolean; } export interface DomQuery_get { - /** 收录视频,但是未提供在线播放资源 */ + /** 收录视频,但是未提供在线播放资源。加入这个 query 来检测是否提供播放。 + * 点名:JAVMENU + */ videoQuery?: string; + subQuery?: string; leakQuery?: string; } interface SiteItemBase { name: string; + /** 用户定义的 disable */ disable: boolean; - /** 针对 matchList 的 hostname */ + + /** 在指定 hostname 下不显示 + * 点名:都是针对的 matchList 里的三个,防止出现自己检索自己站。 + */ disableHostname?: string; + hostname: string; url: string; /** 没用 */ @@ -50,9 +71,13 @@ export const siteList: SiteItem[] = [ name: "Jable", disable: false, hostname: "jable.tv", - url: "https://jable.tv/videos/{{code}}/", - fetcher: "get", - domQuery: { subQuery: ".header-right>h6" }, + url: "https://jable.tv/search/{{code}}/", + fetcher: "parser", + domQuery: { + linkQuery: `.container .detail>.title>a`, + titleQuery: `.container .detail>.title>a`, + checkFn: (linkResult: string) => /-c\/$/.test(linkResult), + }, method: print, }, { @@ -254,7 +279,6 @@ export const siteList: SiteItem[] = [ }, method: print, }, - { name: "JAVLib", disableHostname: "javlibrary", diff --git a/src/utils/xhr.ts b/src/utils/xhr.ts index 68b7683..8327c76 100644 --- a/src/utils/xhr.ts +++ b/src/utils/xhr.ts @@ -1,188 +1,193 @@ -import { GM_xmlhttpRequest } from "$"; -import type { DomQuery_get, DomQuery_parser, SiteItem } from "./siteList"; - -export type xhrResult = { - isSuccess: boolean; - targetLink: string; - hasSubtitle: boolean; - hasLeakage: boolean; - msg: string; -}; - -/** 针对视频播放页进行解析,寻找字幕等信息 */ -function videoPageParser(responseText: string, { subQuery, leakQuery, videoQuery }: DomQuery_get) { - const doc = new DOMParser().parseFromString(responseText, "text/html"); - - const subNode = subQuery ? doc.querySelector(subQuery) : ""; - const subNodeText = subNode ? subNode.innerHTML : ""; - const leakNode = leakQuery ? doc.querySelector(leakQuery) : null; - // 部分网站收录视频,但是未提供播放资源,所以需要使用 videoQuery 进一步检测是否存在在线播放 - /** videoQuery 为 undefine 时,不需要查找 video */ - const videoNode = videoQuery ? doc.querySelector(videoQuery) : true; - return { - isSuccess: !!videoNode, - hasSubtitle: subNodeText.includes("字幕") || subNodeText.includes("subtitle"), - hasLeakage: !!leakNode, - }; -} - -/** 针对 fetcher==="parser" 时的搜索结果页进行解析,寻找是否存在视频资源。 - * linkQuery、titleQuery 都是必须, - * linkQuery 有结果且 titleQuery 结果包含 code,返回 isSuccess。 - * 再检查下 title 中是否含有字幕信息等 - */ -function serachPageParser( - responseText: string, - { linkQuery, titleQuery, listIndex = 0, spaceCode = false }: DomQuery_parser, - siteHostName: string, - CODE: string, -) { - const doc = new DOMParser().parseFromString(responseText, "text/html"); - - const linkNode = linkQuery ? doc.querySelectorAll(linkQuery)[listIndex] : null; - const titleNode = titleQuery ? doc.querySelectorAll(titleQuery)[listIndex] : null; - const titleNodeText = titleNode ? titleNode?.outerHTML : ""; - - function query() { - /** 空格版本的 code */ - const envCodeWithSpace = spaceCode ? CODE.replace("-", " ") : CODE; - const condition = - linkNode && - titleNode && - (titleNodeText.includes(envCodeWithSpace) || titleNodeText.includes(CODE)); - - if (condition) { - return { - isSuccess: true, - targetLink: linkNode.href.replace(linkNode.hostname, siteHostName), - hasLeakage: titleNodeText.includes("无码") || titleNodeText.includes("Uncensored"), - hasSubtitle: titleNodeText.includes("字幕") || titleNodeText.includes("subtitle"), - }; - } else { - return { targetLink: "", isSuccess: false, hasSubtitle: false, hasLeakage: false }; - } - } - return query(); -} - -async function xhr(siteItem: SiteItem, targetLink: string, CODE: string) { - const xhrPromise: Promise = new Promise((resolve) => { - GM_xmlhttpRequest({ - method: "GET", - url: targetLink, - onload: (response) => { - if (siteItem.fetcher === "get") { - // 直接 get 网页,且 get 结果为 404,大概是对应网站没有资源 - if (response.status === 404) { - resolve({ - isSuccess: false, - targetLink, - hasSubtitle: false, - hasLeakage: false, - msg: "应该是没有资源", - }); - } - // 直接 get 网页,成功,需要进一步解析 videoPage,获取字幕等信息 - else { - const { hasSubtitle, hasLeakage, isSuccess } = videoPageParser( - response.responseText, - siteItem.domQuery, - ); - resolve({ isSuccess, targetLink, hasSubtitle, hasLeakage, msg: "[get],存在资源" }); - } - } - // 需要解析 searchPage - else if (siteItem.fetcher === "parser") { - const { targetLink, isSuccess, hasLeakage, hasSubtitle } = serachPageParser( - response.responseText, - siteItem.domQuery, - siteItem.hostname, - CODE, - ); - resolve({ - isSuccess, - targetLink: isSuccess ? targetLink : targetLink, - hasSubtitle, - hasLeakage, - msg: "[parser]存在资源", - }); - } - }, - onerror: (error) => { - resolve({ - isSuccess: false, - targetLink: targetLink, - hasSubtitle: false, - hasLeakage: false, - msg: error.error, - }); - }, - }); - }); - return xhrPromise; -} -export default xhr; - -/** 获取 javdb 的分数 - * 没用了,白写 - */ -// export function getDbScore(url: string): Promise { -// return new Promise((resolve, reject) => { -// GM_xmlhttpRequest({ -// method: "GET", -// url, -// onload: (response) => { -// const doc = new DOMParser().parseFromString(response.responseText, "text/html"); -// const plist = doc.querySelector(`.panel.movie-panel-info`); -// const innerHtml = plist?.innerHTML; -// const matchResult = innerHtml?.match(/\d\.\d分/); -// if (!innerHtml || !matchResult) { -// reject("无评分"); -// return; -// } else { -// resolve(matchResult[0]); -// } -// }, -// onerror(error) { -// reject(error); -// }, -// }); -// }); -// } - -// interface dbResult { -// score: string; -// release: string; -// } -/** 没用了,白写 */ -// export function parserJavdb(code?: string): Promise { -// return new Promise((resolve, reject) => { -// if (!code) reject("没找到"); -// GM_xmlhttpRequest({ -// url: `https://javdb005.com/search?q=${code}`, -// method: "GET", -// onload: (response) => { -// const doc = new DOMParser().parseFromString(response.responseText, "text/html"); -// const firstItem = doc.querySelectorAll(`.movie-list>.item`)[0]; -// const titleString = firstItem.querySelector(`.video-title>strong`)?.innerHTML; -// const releaseString = firstItem.querySelector(`.meta`)?.innerHTML.trim(); -// if (titleString !== code || !releaseString) { -// reject("没找到"); -// } else { -// const fullScoreText = firstItem.querySelector(`.score .value`)?.innerHTML; -// const matchResult = fullScoreText?.match(/\d\.\d*分/); -// if (!matchResult) reject("没找到"); -// else -// resolve({ -// // score: matchResult[0], -// score: matchResult[0].replace("分", ""), -// release: releaseString, -// }); -// } -// }, -// onerror(error) { -// reject(error); -// }, -// }); -// }); -// } +import { GM_xmlhttpRequest } from "$"; +import type { DomQuery_get, DomQuery_parser, SiteItem } from "./siteList"; + +export type xhrResult = { + isSuccess: boolean; + targetLink: string; + hasSubtitle: boolean; + hasLeakage: boolean; + msg: string; +}; + +/** 针对视频播放页进行解析,寻找字幕等信息 */ +function videoPageParser(responseText: string, { subQuery, leakQuery, videoQuery }: DomQuery_get) { + const doc = new DOMParser().parseFromString(responseText, "text/html"); + + const subNode = subQuery ? doc.querySelector(subQuery) : ""; + const subNodeText = subNode ? subNode.innerHTML : ""; + const leakNode = leakQuery ? doc.querySelector(leakQuery) : null; + // 部分网站收录视频,但是未提供播放资源,所以需要使用 videoQuery 进一步检测是否存在在线播放 + /** videoQuery 为 undefine 时,不需要查找 video */ + const videoNode = videoQuery ? doc.querySelector(videoQuery) : true; + return { + isSuccess: !!videoNode, + hasSubtitle: subNodeText.includes("字幕") || subNodeText.includes("subtitle"), + hasLeakage: !!leakNode, + }; +} + +/** 针对 fetcher==="parser" 时的搜索结果页进行解析,寻找是否存在视频资源。 + * linkQuery & titleQuery 都是必须, + * linkQuery 有结果且 titleQuery 有结果包含 code,返回 isSuccess。 + * 再检查下 title 中是否含有字幕信息等 + */ +function serachPageParser( + responseText: string, + { + linkQuery, + titleQuery, + listIndex = 0, + spaceCode = false, + checkFn: checkTextFn, + }: DomQuery_parser, + siteHostName: string, + CODE: string, +) { + const doc = new DOMParser().parseFromString(responseText, "text/html"); + + const linkNode = linkQuery ? doc.querySelectorAll(linkQuery)[listIndex] : null; + const titleNode = titleQuery ? doc.querySelectorAll(titleQuery)[listIndex] : null; + const titleNodeText = titleNode ? titleNode?.outerHTML : ""; + + /** 空格版本的 code */ + const formatCode = spaceCode ? CODE.replace("-", " ") : CODE; + + const isSuccess = linkNode && titleNode && titleNodeText.includes(formatCode); + + if (isSuccess) { + const targetLinkText = linkNode.href.replace(linkNode.hostname, siteHostName); + const meSub = checkTextFn ? checkTextFn(targetLinkText) : false; + const hasSubtitle = + titleNodeText.includes("字幕") || titleNodeText.includes("subtitle") || meSub; + return { + isSuccess: true, + targetLink: targetLinkText, + hasLeakage: titleNodeText.includes("无码") || titleNodeText.includes("Uncensored"), + hasSubtitle, + }; + } else { + return { targetLink: "", isSuccess: false, hasSubtitle: false, hasLeakage: false }; + } +} + +function xhr(siteItem: SiteItem, targetLink: string, CODE: string) { + const xhrPromise: Promise = new Promise((resolve) => { + GM_xmlhttpRequest({ + method: "GET", + url: targetLink, + onload: (response) => { + if (siteItem.fetcher === "get") { + // 直接 get 网页,且 get 结果为 404,大概是对应网站没有资源 + if (response.status === 404) { + resolve({ + isSuccess: false, + targetLink, + hasSubtitle: false, + hasLeakage: false, + msg: "应该是没有资源", + }); + } + // 直接 get 网页,成功,需要进一步解析 videoPage,获取字幕等信息 + else { + const { hasSubtitle, hasLeakage, isSuccess } = videoPageParser( + response.responseText, + siteItem.domQuery, + ); + resolve({ isSuccess, targetLink, hasSubtitle, hasLeakage, msg: "[get],存在资源" }); + } + } + // 需要解析 searchPage + else if (siteItem.fetcher === "parser") { + const { targetLink, isSuccess, hasLeakage, hasSubtitle } = serachPageParser( + response.responseText, + siteItem.domQuery, + siteItem.hostname, + CODE, + ); + resolve({ + isSuccess, + targetLink: isSuccess ? targetLink : targetLink, + hasSubtitle, + hasLeakage, + msg: "[parser]存在资源", + }); + } + }, + onerror: (error) => { + resolve({ + isSuccess: false, + targetLink: targetLink, + hasSubtitle: false, + hasLeakage: false, + msg: error.error, + }); + }, + }); + }); + return xhrPromise; +} +export default xhr; + +/** 获取 javdb 的分数 + * 没用了,白写 + */ +// export function getDbScore(url: string): Promise { +// return new Promise((resolve, reject) => { +// GM_xmlhttpRequest({ +// method: "GET", +// url, +// onload: (response) => { +// const doc = new DOMParser().parseFromString(response.responseText, "text/html"); +// const plist = doc.querySelector(`.panel.movie-panel-info`); +// const innerHtml = plist?.innerHTML; +// const matchResult = innerHtml?.match(/\d\.\d分/); +// if (!innerHtml || !matchResult) { +// reject("无评分"); +// return; +// } else { +// resolve(matchResult[0]); +// } +// }, +// onerror(error) { +// reject(error); +// }, +// }); +// }); +// } + +// interface dbResult { +// score: string; +// release: string; +// } +/** 没用了,白写 */ +// export function parserJavdb(code?: string): Promise { +// return new Promise((resolve, reject) => { +// if (!code) reject("没找到"); +// GM_xmlhttpRequest({ +// url: `https://javdb005.com/search?q=${code}`, +// method: "GET", +// onload: (response) => { +// const doc = new DOMParser().parseFromString(response.responseText, "text/html"); +// const firstItem = doc.querySelectorAll(`.movie-list>.item`)[0]; +// const titleString = firstItem.querySelector(`.video-title>strong`)?.innerHTML; +// const releaseString = firstItem.querySelector(`.meta`)?.innerHTML.trim(); +// if (titleString !== code || !releaseString) { +// reject("没找到"); +// } else { +// const fullScoreText = firstItem.querySelector(`.score .value`)?.innerHTML; +// const matchResult = fullScoreText?.match(/\d\.\d*分/); +// if (!matchResult) reject("没找到"); +// else +// resolve({ +// // score: matchResult[0], +// score: matchResult[0].replace("分", ""), +// release: releaseString, +// }); +// } +// }, +// onerror(error) { +// reject(error); +// }, +// }); +// }); +// }