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
View File
@@ -28,6 +28,22 @@ export const subtitlesApi = {
body: subtitles.SubtitleApplyRequest,
response: subtitles.SubtitleApplyResult,
}),
search: ep({
method: "post",
path: "/subtitles/search",
scope: "read",
summary: "在已启用的字幕站(SubHD、字幕库)搜这部作品的字幕;按季集、语言、下载量排序",
body: subtitles.SubtitleSearchRequest,
response: subtitles.SubtitleSearchResponse,
}),
fetch: ep({
method: "post",
path: "/subtitles/fetch",
scope: "read",
summary: "下载一条在线字幕并解析(同上传:解压、转 UTF-8、语言与季集、配对建议;不写文件)",
body: subtitles.SubtitleFetchRequest,
response: subtitles.SubtitleParseResponse,
}),
writes: ep({
method: "get",
path: "/subtitles/writes",
+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 [];
+55
View File
@@ -69,6 +69,9 @@ export const SubtitleParsedItem = z.object({
content: z.string(),
/** 建议的视频位置 */
targetLocationId: Id.nullable(),
/** 在线下载的:字幕站与条目地址(写入时记进历史) */
source: SubtitleSource.optional(),
sourceRef: z.string().optional(),
});
export type SubtitleParsedItem = z.infer<typeof SubtitleParsedItem>;
@@ -91,6 +94,8 @@ export const SubtitleApplyRequest = z.object({
targetLocationId: Id,
/** 在线来源的条目地址 */
sourceRef: z.string().max(1000).optional(),
/** 这一项的来源(不给用整批的 source) */
source: SubtitleSource.optional(),
}),
)
.min(1)
@@ -140,3 +145,53 @@ export const SubtitleWriteRow = z.object({
export const SubtitleWritesQuery = z.object({ entityId: Id });
export const SubtitleWritesResponse = z.object({ items: z.array(SubtitleWriteView) });
// ── 在线(字幕站:SubHD、字幕库) ──
export const SubtitleSearchRequest = z.object({
entityId: Id,
/** 剧集:只要这一季(集)的字幕;不给 = 全部 */
season: z.number().int().min(0).optional(),
episode: z.number().int().min(0).optional(),
/** 额外的搜索词(作品名搜不到时手动填) */
keyword: z.string().trim().max(100).optional(),
});
export type SubtitleSearchRequest = z.infer<typeof SubtitleSearchRequest>;
export const SubtitleSearchResult = z.object({
siteId: Id,
siteKey: z.string(),
siteName: z.string(),
/** 站内引用(下载时原样提交) */
ref: z.string(),
title: z.string(),
pageUrl: z.string(),
languages: z.array(z.string()),
format: z.string().nullable(),
downloads: z.number().int().nullable(),
uploader: z.string().nullable(),
publishedAt: z.string().nullable(),
season: z.number().int().nullable(),
episode: z.number().int().nullable(),
score: z.number(),
});
export type SubtitleSearchResult = z.infer<typeof SubtitleSearchResult>;
export const SubtitleSearchResponse = z.object({
results: z.array(SubtitleSearchResult),
/** 用到的搜索词 */
keywords: z.array(z.string()),
/** 各站出错 / 需要人工处理 */
errors: z.array(z.object({ siteName: z.string(), reason: z.string() })),
/** 没有启用的字幕站 */
noSites: z.boolean(),
});
export type SubtitleSearchResponse = z.infer<typeof SubtitleSearchResponse>;
export const SubtitleFetchRequest = z.object({
entityId: Id,
siteId: Id,
ref: z.string().min(1).max(500),
title: z.string().max(500).default(""),
});
export type SubtitleFetchRequest = z.input<typeof SubtitleFetchRequest>;
@@ -0,0 +1,31 @@
import type { Kysely } from "kysely";
import { execDdl, oneOf } from "../src/migration-helpers.ts";
// 字幕站(docs/plan/subtitles.md 第 2 步):站点类型 subtitle、适配器 subtitle(SubHD、字幕库),
// 复用站点的代理 / 限流 / 健康 / 浏览器会话;不参与资源搜索、快照、RSS。
const KINDS = ["pt", "public_bt", "rss_feed", "torznab", "subtitle"];
const ADAPTERS = ["nexusphp", "mteam_api", "api", "generic_rss", "subtitle"];
const OLD_KINDS = ["pt", "public_bt", "rss_feed", "torznab"];
const OLD_ADAPTERS = ["nexusphp", "mteam_api", "api", "generic_rss"];
// biome-ignore lint/suspicious/noExplicitAny: 迁移不依赖应用表类型
export async function up(db: Kysely<any>): Promise<void> {
await execDdl(
db,
`alter table site drop constraint if exists site_kind_check;
alter table site add constraint site_kind_check ${oneOf("kind", KINDS)};
alter table site drop constraint if exists site_adapter_check;
alter table site add constraint site_adapter_check ${oneOf("adapter", ADAPTERS)};`,
);
}
// biome-ignore lint/suspicious/noExplicitAny: 同上
export async function down(db: Kysely<any>): Promise<void> {
await execDdl(
db,
`delete from site where kind = 'subtitle';
alter table site drop constraint if exists site_kind_check;
alter table site add constraint site_kind_check ${oneOf("kind", OLD_KINDS)};
alter table site drop constraint if exists site_adapter_check;
alter table site add constraint site_adapter_check ${oneOf("adapter", OLD_ADAPTERS)};`,
);
}
+2 -2
View File
@@ -241,10 +241,10 @@ export type SecretPurpose =
| "other";
export type ServerMappingItemType = "movie" | "series" | "season" | "episode" | "other";
export type ServerMappingMatchStatus = "matched" | "ambiguous" | "unmatched" | "stale";
export type SiteAdapter = "nexusphp" | "mteam_api" | "api" | "generic_rss";
export type SiteAdapter = "nexusphp" | "mteam_api" | "api" | "generic_rss" | "subtitle";
export type SiteHealthStatus = "unknown" | "healthy" | "degraded" | "failing" | "disabled";
export type SiteCircuitState = "closed" | "open" | "half_open";
export type SiteKind = "pt" | "public_bt" | "rss_feed" | "torznab";
export type SiteKind = "pt" | "public_bt" | "rss_feed" | "torznab" | "subtitle";
export type SiteAccountAuthKind = "cookie" | "passkey" | "api_key" | "password";
export type SiteAccountStatus = "unknown" | "active" | "invalid" | "expired" | "challenge";
export type SiteSnapshotKind = "periodic" | "backfill" | "live_search" | "manual";
+1
View File
@@ -6,4 +6,5 @@ export * from "./fs/index.ts";
export * from "./qbittorrent/index.ts";
export * from "./rss/index.ts";
export * from "./sites/index.ts";
export * from "./subtitles.ts";
export * from "./tmdb/index.ts";
+32
View File
@@ -0,0 +1,32 @@
/**
* 补字幕 / 沙箱的二进制样本:
* - 字幕库验证码:2026-10-03 从 zmk.pw 取得,识别结果经站点接受;
* - RAR5:rarfile 4.5 测试文件 rar5-solid.rar(ISC 许可,Copyright (c) 2005-2024 Marko Kreen),内含 stest1.txt / stest2.txt;
* - 7z:本机 7z 生成,内含 s7/a.chs.srt(「你好」一条)。
*/
export const ZIMUKU_CAPTCHA = {
bmpBase64:
"Qk3aHwAAAAAAADYAAAAoAAAAZAAAABsAAAABABgAAAAAAKQfAAAAAQAAAAEAAAAAAAAAAAAA3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS29vbrrSupqymtry2rrSuyMjI5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubmrrSupqymtry2rrSupqymtry2rrSupqym5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzct7q3try20tPS0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm0dLRpqymtry2rrSupqym29vb3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS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 truncated
code: "62485",
};
export const RAR5_SAMPLE_BASE64 =
"UmFyIRoHAQAJ78hvCwEFBwQGAQGAgIAA3vVwchwCAroABIAQtoMCoua3xYAbAQpzdGVzdDEudHh0waw3REQj+iP2l/1iU1G+TJGBQQKMwQN5XL9Ho6otoDaT3aBYAEACANRQBHb2xH8y6p8ypcTM14PfABDoLYkcAgKNAASAELaDAqLmt8XAGwEKc3Rlc3QyLnR4dEUVCmABAAgD37f79vwdd1ZRAwUEAA==";
export const SEVENZIP_SUBTITLE_BASE64 =
"N3q8ryccAARZ0i3uJwAAAAAAAABiAAAAAAAAACUGHgPgACYAH10AGIKCXAxmLN3AjXSfYB8suiGnGQuFuRrPg2a0pjCUAAABBAYAAQknAAcLAQABISEBAAwnAAgKAXGBapIAAAUBGQwAAAAAAAAAAAAAAAARGwBzADcALwBhAC4AYwBoAHMALgBzAHIAdAAAABkAFAoBAPAj1DaXUt0BFQYBACCApIEAAA==";
// ── 字幕站页面(2026-10-03 实测截取,只留解析用到的片段) ──
export const SUBHD_DETAIL_PAGE =
'<html><body><div class="float-end">\n <a class="btn btn-sm f11 btn-outline-secondary" href="/upload?d=37068446">上传</a>\n \n <div class="btn-group ms-1">\n <button class="btn btn-sm f11 btn-outline-secondary dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false">\n 默认排序\n </button>\n <ul class="dropdown-menu dropdown-menu-end f12">\n <li><a class="dropdown-item active" href="/d/37068446">默认排序</a></li>\n <li><a class="dropdown-item " href="/d/37068446?order=time">按时间</a></li>\n </ul>\n </div>\n \n </div>\n </div>\n\n <div class="bg-white shadow-sm rounded-3 mb-5">\n <div class="rounded-top bg-purple">\n <div class="row">\n <div class="col-8">\n <div class="px-3 py-2">字幕信息</div>\n </div>\n <div class="col-2 d-none d-lg-block">\n <div class="px-3 py-2 text-end">下载次数</div>\n </div>\n <div class="col-2 d-none d-lg-block">\n <div class="px-3 py-2 text-end">上传人</div>\n </div>\n </div>\n </div>\n\n \n \n <div class="row pt-2 mb-2">\n <div class="col-12 col-lg-8">\n <div class="px-3 py-2">\n <div class="view-text">\n <a class="link-dark" href="/a/Fp90EG">生化危机:爆发夜 Resident.Evil.2026.1080p.TELESYNC.MULTi.x264-DKS-GPT 6.0 V4</a>\n \n </div>\n <div class="pt-1 f11">\n <span class="rounded p-1 me-1 text-white" style="background-color:#ae3ec9!important">AI校对</span>\n \n <span class="p-1 fw-bold">简体</span>\n <span class="p-1 text-secondary">SRT</span>\n <span class="p-1 text-primary"><svg class="bi bi-chat align-baseline me-1" xmlns="http://www.w3.org/2000/svg" width="11" height="11" fill="currentColor" viewBox="0 0 16 16"><path d="M2.678 11.894a1 1 0 0 1 .287.801 10.97 10.97 0 0 1-.398 2c1.395-.323 2.247-.697 2.634-.893a1 1 0 0 1 .71-.074A8.06 8.06 0 0 0 8 14c3.996 0 7-2.807 7-6 0-3.192-3.004-6-7-6S1 4.808 1 8c0 1.468.617 2.83 1.678 3.894zm-.493 3.905a21.682 21.682 0 0 1-.713.129c-.2.032-.352-.176-.273-.362a9.68 9.68 0 0 0 .244-.637l.003-.01c.248-.72.45-1.548.524-2.319C.743 11.37 0 9.76 0 8c0-3.866 3.582-7 8-7s8 3.134 8 7-3.582 7-8 7a9.06 9.06 0 0 1-2.347-.306c-.52.263-1.639.742-3.468 1.105z"/></svg>2</span>\n \n <span class="p-1 text-danger">\n <svg class="align-top" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="14px" height="14px" fill="currentColor"><path d="M3,11h3v10H3V11z M18.77,11h-4.23l1.52-4.94C16.38,5.03,15.54,4,14.38,4c-0.58,0-1.14,0.24-1.52,0.65L7,11v10h10.43 c1.06,0,1.98-0.67,2.19-1.61l1.34-6C21.23,12.15,20.18,11,18.77,11z"/></svg>\n <span class="align-baseline">1</span>\n </span>\n \n \n </div>\n </div>\n </div>\n <div class="col-2 d-none d-lg-block">\n <div class="px-3 py-2 text-end text-secondary">4165</div>\n </div>\n <div class="col-2 d-none d-lg-block">\n <div class="px-3 py-2 text-end">\n <span class="fw-bold me-1">\n <a class="link-dark" href="/u/彬冷的心">彬冷的心</a>\n </span>\n <div class="text-black-50"><time datetime="2026-09-19T08:53:03.000Z" data-local-time="relative">09-19 08:53</time></div>\n </div>\n </div>\n </div>\n <hr class="my-0">\n \n \n <div class="row pt-2 mb-2">\n <div class="col-12 col-lg-8">\n <div class="px-3 py-2">\n <div class="view-text">\n <a class="link-dark" href="/a/6XeICg">惡靈古堡:爆發夜 Resident.Evil.2026.TS-DKS(clean).1080p【ChatGPT 台灣用語】V2</a>\n \n </div>\n <div class="pt-1 f11">\n <span class="rounded p-1 me-1 text-white" style="background-color:#ae3ec9!important">AI校对</span>\n \n <span class="p-1 fw-bold">繁体</span>\n <span class="p-1 text-secondary">SRT</span>\n <span class="p-1 text-primary"><svg class="bi bi-chat align-baseline me-1" xmlns="http://www.w3.org/2 Line truncated
export const SUBHD_SUB_PAGE =
'<html><body>ton>\n </div>\n </div>\n </div>\n\n\n <div class="mb-3 d-flex align-items-center justify-content-between gap-2 subtitle-detail-actions">\n <div class="d-flex align-items-center flex-wrap gap-2 subtitle-download-action">\n <button type="button"\n class="btn btn-danger down subtitle-prepare-download"\n data-sid="Fp90EG"\n data-loading-text="处理中…"\n data-error-text="准备下载失败,请稍后再试。">\n <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" fill="currentColor" class="bi bi-arrow-down-circle" viewBox="0 0 16 16">\n <path fill-rule="evenodd" d="M1 8a7 7 0 1 0 14 0A7 7 0 0 0 1 8zm15 0A8 8 0 1 1 0 8a8 8 0 0 1 16 0zM8.5 4.5a.5.</body></html>';
export const ZIMUKU_SEARCH_PAGE =
'<html><body><div class="tbhd clearfix">\n<ul class="l tb">\n<li class="this"><a href="/search?q=%E8%91%AC%E9%80%81%E7%9A%84%E8%8A%99%E8%8E%89%E8%8E%B2&chost=zimuku.org"><strong>综合搜索</strong></a></li>\n<li ><a href="/search?q=%E8%91%AC%E9%80%81%E7%9A%84%E8%8A%99%E8%8E%89%E8%8E%B2&t=onlyst&chost=zimuku.org"><strong>仅射手老字幕 </strong></a></li>\n</ul>\n<div class="pagination r clearfix">\n <div> <span class="rows">共 2 条记录</span></div> </div>\n</div>\n \n<div class="item prel clearfix">\n<div class="litpic hidden-xs"><a href="//zimuku.org/subs/69877.html" target="_blank"><img src="/images/v2/no_litpic.gif" class="lazy" data-original="/Uploads/Picture/litpic/2024/05Aug2024181110.jpg" alt="葬送的芙莉莲 葬送のフリーレン 字幕下载"/></a></div>\n<div class="title"><p class="tt clearfix"><a href="//zimuku.org/subs/69877.html" target="_blank"><b>葬送的芙莉莲 葬送のフリーレン (2023)</b></a></p>\n<p>又名:<a href="//zimuku.org/subs/69877.html" target="_blank">Frieren: Beyond Journey\'s End</a></p>\n<div class="sublist">\n<table class="table tborder2">\n<tbody>\n<tr class="odd">\n<td class="first">\n<img class="tooltips" data-toggle="tooltip" data-placement="top" alt="&nbsp;简体中文字幕" title="&nbsp;简体中文字幕" border="0" src="/images/v2/flag/china.gif" style="padding-bottom: 4px">\n<a href="//zimuku.org/detail/234732.html" target="_blank" title="Sousou no Frieren.zip"><b>Sousou no Frieren.zip</b></a>\n<span class="label label-info">SRT</span>&nbsp;</td>\n<td class="tac"><div class="hidden-xs"><i class="rating-star allstar00 tooltips" data-toggle="tooltip" data-placement="top" title="字幕质量:0分"></i></div></td>\n<td class="last"><div class="hidden-xs"><span class="glyphicon glyphicon-save"></span>2781</div></td>\n</tr><tr class="even">\n<td class="first">\n<img class="tooltips" data-toggle="tooltip" data-placement="top" alt="&nbsp;简体中文字幕&nbsp;繁體中文字幕&nbsp;双语字幕&nbsp;日语字幕" title="&nbsp;简体中文字幕&nbsp;繁體中文字幕&nbsp;双语字幕&nbsp;日语字幕" border="0" src="/images/v2/flag/jollyroger.gif" style="padding-bottom: 4px">\n<a href="//zimuku.org/detail/203404.html" target="_blank" title="[DBD-Raws][葬送的芙莉莲][01-28TV全集+特典映像][1080P][BDRip][HEVC-10bit][简繁日双语字幕][FLAC][MKV]"><b>[DBD-Raws][葬送的芙莉莲][01-28TV全集+特典映像][1080P][BDRip][HEVC-10bit][简繁日双语字幕][FLAC][MKV]</b></a>\n<span class="label label-info">ASS/SSA</span>&nbsp;</td>\n<td class="tac"><div class="hidden-xs"><i class="rating-star allstar50 tooltips" data-toggle="tooltip" data-placement="top" title="字幕质量:10分"></i></div></td>\n<td class="last"><div class="hidden-xs"><span class="glyphicon glyphicon-save"></span>1.7万</div></td>\n</tr></tbody>\n</table>\n</div>\n</div>\n\n\n</div><div class="item prel clearfix">\n<div class="litpic hidden-xs"><a href="//zimuku.org/subs/76121.html" target="_blank"><img src="/images/v2/no_litpic.gif" class="lazy" data-original="/Uploads/Picture/litpic/2026/01Apr2026102159.jpg" alt="葬送的芙莉莲 第二季 葬送のフリーレン 第2期 字幕下载"/></a></div>\n<div class="title"><p class="tt clearfix"><a href="//zimuku.org/subs/76121.html" target="_blank"><b>葬送的芙莉莲 第二季 葬送のフリーレン 第2期 (2026)</b></a></p>\n<p>又名:<a href="//zimuku.org/subs/76121.html" target="_blank">Frieren: Beyond Journey\'s End Season 2</a></p>\n<div class="sublist">\n<table class="table tborder2">\n<tbody>\n<tr class="odd">\n<td class="first">\n<img class="tooltips" data-toggle="tooltip" data-placement="top" alt="&nbsp;简体中文字幕&nbsp;双语字幕&nbsp;日语字幕" title="&nbsp;简体中文字幕&nbsp;双语字幕&nbsp;日语字幕" border="0" src="/images/v2/flag/jollyroger.gif" style="padding-bottom: 4px">\n<a href="//zimuku.org/detail/235222.html" target="_blank" title="葬送的芙莉莲第二季"><b>葬送的芙莉莲第二季</b></a>\n<span class="label label-info">ASS/SSA</span>&nbsp;</td>\n<td class="tac"><div class="hidden-xs"><i class="rating-star allstar00 tooltips" data-toggle="tooltip" data-placement="top" title="字幕质量:0分"></i></div></body></html>';
export const ZIMUKU_SUBS_PAGE =
'<html><body><table class="table" id="subtb">\n<thead>\n<tr>\n<th class="clr"></th><th class="first">字幕</th>\n<th class="tac lang">语言</th>\n<th class="tac hidden-xs">质量</th>\n<th class="tac hidden-xs">下载</th>\n<th class="last hidden-xs">上传/时间</th>\n</tr>\n</thead>\n<tbody>\n<tr class="odd" >\n<td class="clr clr28"></td>\n<td class="first">\n<a href="/detail/234732.html" target="_blank" title="Sousou no Frieren.zip"><b>Sousou no Frieren.zip</b></a>\n<span class="label label-info">SRT</span>&nbsp;<br>\n<span class="gray"><em>制作:</em>见字幕文件</span>\n<span class="gray"><em>校订:</em>见字幕文件</span>\n<span class="gray"><em>来源:</em><span class="label label-danger">个人原创翻译</span></span>\n</td>\n<td class="tac lang"><img border="0" src="/images/v2/flag/china.gif" alt="简体中文字幕" class="tooltips" data-toggle="tooltip" data-placement="top" title="简体中文字幕" style="padding-bottom: 2px"></td>\n<td class="tac hidden-xs"><i class="rating-star allstar00 tooltips" data-toggle="tooltip" data-placement="top" title="字幕质量:0分"></i></td>\n<td class="tac hidden-xs">2781</td>\n<td class="last hidden-xs">\n<span class="glyphicon glyphicon-user"></span> <a href="/u/A3pbKZkw0">blade0701</a>\n<br>\n<span class="glyphicon glyphicon-time"></span> 8月11日</td>\n</tr><tr class="even" >\n<td class="clr clr28"></td>\n<td class="first">\n<a href="/detail/203404.html" target="_blank" title="[DBD-Raws][葬送的芙莉莲][01-28TV全集+特典映像][1080P][BDRip][HEVC-10bit][简繁日双语字幕][FLAC][MKV]"><b>[DBD-Raws][葬送的芙莉莲][01-28TV全集+特典映像][1080P][BDRip][HEVC-10bit][简繁日双语字幕][FLAC][MKV]</b></a>\n<span class="label label-info">ASS/SSA</span>&nbsp;<br>\n<span class="gray"><em>制作:</em>喵萌奶茶屋</span>\n<span class="gray"><em>校订:</em>DBD制作组</span>\n<span class="gray"><em>来源:</em><span class="">转载/未知/其他</span></span>\n</td>\n<td class="tac lang"><img border="0" src="/images/v2/flag/china.gif" alt="简体中文字幕" class="tooltips" data-toggle="tooltip" data-placement="top" title="简体中文字幕" style="padding-bottom: 2px"><img border="0" src="/images/v2/flag/hongkong.gif" alt="繁體中文字幕" class="tooltips" data-toggle="tooltip" data-placement="top" title="繁體中文字幕" style="padding-bottom: 2px"><img border="0" src="/images/v2/flag/jollyroger.gif" alt="双语字幕" class="tooltips" data-toggle="tooltip" data-placement="top" title="双语字幕" style="padding-bottom: 2px"><img border="0" src="/images/v2/flag/japan.gif" alt="日语字幕" class="tooltips" data-toggle="tooltip" data-placement="top" title="日语字幕" style="padding-bottom: 2px"></td>\n<td class="tac hidden-xs"><i class="rating-star allstar50 tooltips" data-toggle="tooltip" data-placement="top" title="字幕质量:10分"></i></td>\n<td class="tac hidden-xs">1.7万</td>\n<td class="last hidden-xs">\n<span class="glyphicon glyphicon-user"></span> <a href="/u/A34xQmde0">dongzige98</a>\n<br>\n<span class="glyphicon glyphicon-time"></span> 24/8/4</td>\n</tr>\n</tbody>\n</table></body></html>';
export const ZIMUKU_DETAIL_PAGE =
'<html><body><ul><li class="li dlsub">\n<div class="clearfix"><a id="down1" href="/dld/203404.html" target="_blank" rel="nofollow"><span class="dl"><i class="glyphicon glyphicon-save"></i> 下载字幕 |<small style="padding-left:3px">1.13MB</small></span></a>\n<span style="padding:0 0 0 10px"><font color="#ca6445">所有从字幕库下载字幕的人均需同意:</font><br/><font color="#ca6445">仅作为个人学习、研究,不得用于商业用途</font><br/><font color="#ca6445">任何情况均不得去掉字幕文件相关制作人信息,请尊重他人劳动成果</font></span>\n</div>\n\n</li></ul></body></html>';
export const ZIMUKU_DL_PAGE =
'<!DOCTYPE html>\n<html lang="zh-CN">\n<head>\n<meta charset="utf-8">\n<meta http-equiv="Cache-Control" content="no-transform" />\n<meta http-equiv="X-UA-Compatible" content="IE=edge">\n<meta name="viewport" content="width=device-width, initial-scale=1">\n<meta name="keywords" content="" />\n<meta name="description" content="" />\n<title>字幕高速下载页 - 字幕库</title>\n<!-- 最新版本的 Bootstrap 核心 CSS 文件 -->\n<link rel="stylesheet" href="/images/v2/css/bootstrap.min.css">\n<style>\n.clearfix{zoom:1}.clearfix:after{content:".";display:block;height:0;clear:both;visibility:hidden}\n.down{margin:20px 0;}\n.down ul,h4{padding-left:15px;margin-left:0;}\n.down li{list-style: none;padding:3px 15px 2px 0;float:left; }\n </style>\n\n</head>\n<body>\n<main class="main" role="main">\n <div class="container">\n <div class="row">\n\n <div class="col-xs-12 col-sm-12">\n <table style="border:1px solid #dcdcdc; margin:10% auto 0;">\n <tr>\n <td width="400px" align="left" >\n \n\n \n <div class="down clearfix">\n <ul>\n \n <li><a rel="nofollow" href="/download/MjAzNDA0fDIyN2VkNzg0NWU5YTIwNmFlMDhiMzdiM3wxNzkwOTYzMTE2fGRkMWNiZGI1fHJlbW90ZQ%3D%3D/svr/d0" class="btn btn-danger btn-sm"><span class="glyphicon glyphicon-save icon_size"></span> 电信高速下载(一)</a></li>\n <li><a rel="nofollow" href="/download/MjAzNDA0fDIyN2VkNzg0NWU5YTIwNmFlMDhiMzdiM3wxNzkwOTYzMTE2fGRkMWNiZGI1fHJlbW90ZQ%3D%3D/svr/d1" class="btn btn-danger btn-sm"><span class="glyphicon glyphicon-save icon_size"></span> 电信高速下载(二)</a></li>\n <li><a rel="nofollow" href="/download/MjAzNDA0fDIyN2VkNzg0NWU5YTIwNmFlMDhiMzdiM3wxNzkwOTYzMTE2fGRkMWNiZGI1fGxvY2Fs/svr/l0" class="btn btn-default btn-sm"><span class="glyphicon glyphicon-save icon_size"></span> 联通高速下载(新)</a></li>\n <li><a rel="nofollow" href="/download/MjAzNDA0fDIyN2VkNzg0NWU5YTIwNmFlMDhiMzdiM3wxNzkwOTYzMTE2fGRkMWNiZGI1fGxvY2Fs/svr/l1" class="btn btn-default btn-sm"><span class="glyphicon glyphicon-save icon_size"></span> 联通高速下载(新)</a></li>\n <li><a rel="nofollow" href="/download/MjAzNDA0fDIyN2VkNzg0NWU5YTIwNmFlMDhiMzdiM3wxNzkwOTYzMTE2fGRkMWNiZGI1fGxvY2Fs/svr/y0" class="btn btn-default btn-sm"><span class="glyphicon glyphicon-save icon_size"></span> 移动高速下载(新)</a></li>\n\n \n\n \n \n \n </ul>\n </div>\n \n</td>\n<td width="300px" height="250px" align="center">\n\n</td>\n\n</tr>\n</table>\n<div style="text-align:center;margin:15px auto;">\n\n</div> \t\n \t\n \n </div> \n </div>\n </div> \n</main>\n \n</body>\n</html>';
/** 云锁验证码页(BMP 换成 ZIMUKU_CAPTCHA 里那张,答案已知) */
export const ZIMUKU_CAPTCHA_PAGE =
'<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><meta http-equiv="Cache-Control" content="no-store, no-cache, must-revalidate, post-check=0, pre-check=0"/><meta http-equiv="Connection" content="Close" /><script type="text/javascript">function EnterJump(){ if (event.keyCode == 13) {YunsuoAutoJump(); } }function stringToHex(str){var val="";for(var i = 0; i < str.length; i++){if(val == "")val = str.charCodeAt(i).toString(16);else val += str.charCodeAt(i).toString(16);}return val;}function YunsuoAutoJump() {var text = document.getElementById("intext").value;if (text == "") {alert(\'验证码不能为空\');}else {var curlocation = window.location.href;if(-1 == curlocation.indexOf("security_verify_")){ document.cookie="srcurl=" + stringToHex(window.location.href) + ";path=/;";}self.location = "/search?q=葬送的芙莉莲&security_verify_img=" + stringToHex(text);}}</script><title>&#x7F51;&#x7AD9;&#x9632;&#x706B;&#x5899;</title><style type="text/css">.c1{margin-left:70px; _margin-left:1px;}body{text-align:center;}</style></head><body onkeypress="EnterJump()"><br/><br/><div style="margin: 0 auto; width: 515px; height: 200px; border: 2px solid #134f7c; background: #e7eff2; font-family:微软雅黑"><div style="text-align: center; color: white; height: 30px; font-size: 14px; background: #074773; line-height:30px">&#x7F51;&#x7AD9;&#x8BBF;&#x95EE;&#x8BA4;&#x8BC1;&#x9875;&#x9762;</div><br/><br/><div style="text-align: center; font-size: 14px;"><table class="c1"><tr><td style="width: 168px; font-size: 14px;">&#x8BF7;&#x8F93;&#x5165;&#x9A8C;&#x8BC1;&#x7801;&#x540E;&#x7EE7;&#x7EED;&#x8BBF;&#x95EE;&#xFF1A;</td><td style="width: 30px; text-align: left;"> <input id="intext" type="text" style="width: 100px; height: 28px;" /></td><td style="letter-spacing: 4; text-align: center; float: left; margin-left: 8px;"><img class="verifyimg" alt="verify_img" src="data:image/bmp;base64,Qk3aHwAAAAAAADYAAAAoAAAAZAAAABsAAAABABgAAAAAAKQfAAAAAQAAAAEAAAAAAAAAAAAA3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS29vbrrSupqymtry2rrSuyMjI5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubmrrSupqymtry2rrSupqymtry2rrSupqym5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzct7q3try20tPS0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm0dLRpqymtry2rrSupqym29vb3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzczc3Ntry2rrSupqymtry2zM3M0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS3Nzc0tLS5ubm3Nzc0tLS5ubm1dbVepV6AJkAAJkAAJkAAJkAgJqAzMzM5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLSAJkAAJkAAJkAAJkAAJkAAJkAAJkAAJkA0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubmV49XAJkAuL643Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3NzczMzMhqCGAJkAAJkAAJkAAJkAepV639/f3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubmkqOSAJkAAJkAAJkAAJkAc5lzpa6lzMzM5ubm3Nzc0tLS5ubm3Nzc5ubm3Nzc0tLS5ubm3Nzc0tLSzM7MAJkAFJEUQ49DQIxAFJEUAJkAip+K0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3NzcNoo2AJkAFZIVPYo9Q49DQIxAPYo9Q49D3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0tLS5ubm3Nzc0Line truncated