feat(subtitles): 字幕站(SubHD、字幕库)在线搜索与下载;rar / 7z 解压;验证码与页面解析在沙箱里

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
rootandClaude Opus 5.5 committed 2026-10-03 02:28:29 +08:00
1 parent 92d456d123
commit 59b3680f35
32 files changed
+1704 -166

No files matched your search

+16 -2
View File
@@ -6,7 +6,7 @@ import { QuickFilterParam, ReleaseQuickFacets } from "./release-facets.ts";
// 含 passkey 的 Feed URL 只以 urlSecretRef 保存,对外只给脱敏的 urlDisplay。
/** api = MP 专用 API spider(Haidan/HDDolby/RousiPro/SunnyPT/TNode/TorrentLeech/Yema) */
export const SiteAdapter = z.enum(["nexusphp", "mteam_api", "api", "generic_rss"]);
export const SiteAdapter = z.enum(["nexusphp", "mteam_api", "api", "generic_rss", "subtitle"]);
export type SiteAdapter = z.infer<typeof SiteAdapter>;
/**
@@ -14,7 +14,7 @@ export type SiteAdapter = z.infer<typeof SiteAdapter>;
* 站点实际可用的方式 = 类型允许的 ∩ 适配器(站点定义)实现的,见 siteCapabilities。
* torznab 只定义结构(Jackett / Prowlarr 的 Torznab 接口),尚未实现:不能添加,也不参与调度。
*/
export const SiteKind = z.enum(["pt", "public_bt", "rss_feed", "torznab"]);
export const SiteKind = z.enum(["pt", "public_bt", "rss_feed", "torznab", "subtitle"]);
export type SiteKind = z.infer<typeof SiteKind>;
/** 获取方式:搜索 / 列表抓取 / RSS / 详情页 / 登录 / 账号数据(上传量、分享率、等级) */
export const SiteCapability = z.enum(["search", "list", "rss", "detail", "login", "userinfo"]);
@@ -62,6 +62,13 @@ export const SITE_KINDS: Record<SiteKind, SiteKindSpec> = {
implemented: false,
fromDefinition: false,
},
subtitle: {
label: "字幕站",
description: "给媒体库里的作品搜字幕、下载字幕:SubHD、字幕库",
capabilities: [],
implemented: true,
fromDefinition: false,
},
};
/** 站点定义(适配器)声明的能力;没有定义的站点传 null */
@@ -71,6 +78,13 @@ export type SiteDefinitionCaps = { search: boolean; list: boolean; detail: boole
* 站点实际可用的获取方式:类型允许的 ∩ 适配器实现的。RSS 走通用解析器,不依赖站点定义;
* 搜索 / 列表 / 详情要站点定义声明支持;登录与账号数据要有站点定义(没有定义就没有登录流程)。
*/
/** 内置字幕站(docs/plan/subtitles.md):站点页「字幕站」一键添加,搜索与下载在 subtitles 模块 */
export const SUBTITLE_SITES = [
{ key: "subhd", name: "SubHD", baseUrl: "https://subhd.tv/" },
{ key: "zimuku", name: "字幕库", baseUrl: "https://zmk.pw/" },
] as const;
export type SubtitleSiteKey = (typeof SUBTITLE_SITES)[number]["key"];
export function siteCapabilities(kind: SiteKind, def: SiteDefinitionCaps): SiteCapability[] {
const spec = SITE_KINDS[kind];
if (!spec.implemented) return [];