fix the error redirect of jable
This commit is contained in:
@@ -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",
|
||||
|
||||
381
src/utils/xhr.ts
381
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<HTMLElement>(subQuery) : "";
|
||||
const subNodeText = subNode ? subNode.innerHTML : "";
|
||||
const leakNode = leakQuery ? doc.querySelector<HTMLElement>(leakQuery) : null;
|
||||
// 部分网站收录视频,但是未提供播放资源,所以需要使用 videoQuery 进一步检测是否存在在线播放
|
||||
/** videoQuery 为 undefine 时,不需要查找 video */
|
||||
const videoNode = videoQuery ? doc.querySelector<HTMLElement>(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<HTMLAnchorElement>(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<xhrResult> = 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<string> {
|
||||
// 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<HTMLElement>(`.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<dbResult> {
|
||||
// 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<HTMLElement>(`.movie-list>.item`)[0];
|
||||
// const titleString = firstItem.querySelector<HTMLElement>(`.video-title>strong`)?.innerHTML;
|
||||
// const releaseString = firstItem.querySelector<HTMLElement>(`.meta`)?.innerHTML.trim();
|
||||
// if (titleString !== code || !releaseString) {
|
||||
// reject("没找到");
|
||||
// } else {
|
||||
// const fullScoreText = firstItem.querySelector<HTMLElement>(`.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<HTMLElement>(subQuery) : "";
|
||||
const subNodeText = subNode ? subNode.innerHTML : "";
|
||||
const leakNode = leakQuery ? doc.querySelector<HTMLElement>(leakQuery) : null;
|
||||
// 部分网站收录视频,但是未提供播放资源,所以需要使用 videoQuery 进一步检测是否存在在线播放
|
||||
/** videoQuery 为 undefine 时,不需要查找 video */
|
||||
const videoNode = videoQuery ? doc.querySelector<HTMLElement>(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<HTMLAnchorElement>(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<xhrResult> = 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<string> {
|
||||
// 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<HTMLElement>(`.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<dbResult> {
|
||||
// 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<HTMLElement>(`.movie-list>.item`)[0];
|
||||
// const titleString = firstItem.querySelector<HTMLElement>(`.video-title>strong`)?.innerHTML;
|
||||
// const releaseString = firstItem.querySelector<HTMLElement>(`.meta`)?.innerHTML.trim();
|
||||
// if (titleString !== code || !releaseString) {
|
||||
// reject("没找到");
|
||||
// } else {
|
||||
// const fullScoreText = firstItem.querySelector<HTMLElement>(`.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);
|
||||
// },
|
||||
// });
|
||||
// });
|
||||
// }
|
||||
|
||||
Reference in New Issue
Block a user