feat(sites): 内置公开 BT 站 Nyaa / 蜜柑 / AniBT / AnimeGarden / 萌番组
- 新专用解析器(spiders/public.ts):RSS / Torznab / JSON API,搜索 + 最新列表 + 按资源 ID 取种子或磁力 - 手写定义(definitions/public.ts,public: true),并入内置定义表;定义视图按 public 标为 public_bt - 添加站点:公开 BT 站可从内置站一键添加(专用适配器、默认定时抓取、默认不进搜索集合),手填 RSS 保留 - 样例取自 2026-10-02 公开接口,截前两条 Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
9cdf492291
commit
b8876542b8
16 files changed
+770
-18
No files matched your search
@@ -56,6 +56,11 @@ const T_SITES = ["sites"];
|
||||
const T_FEEDS = ["feed-sources"];
|
||||
const T_RELEASES = ["source-releases"];
|
||||
|
||||
/** 定义对应的站点类型:手写的公开 BT 站定义带 public */
|
||||
export function definitionKind(def: SiteDefinition): "pt" | "public_bt" {
|
||||
return "public" in def && def.public === true ? "public_bt" : "pt";
|
||||
}
|
||||
|
||||
export function adapterOf(def: SiteDefinition): SiteAdapter {
|
||||
return def.umt.kind === "mteam" ? "mteam_api" : def.umt.kind === "api" ? "api" : "nexusphp";
|
||||
}
|
||||
@@ -90,7 +95,7 @@ export function sourcesRoutes(app: ModuleApp, rt: () => SourcesRuntime) {
|
||||
items: listSiteDefinitions().map((d) => ({
|
||||
key: d.id,
|
||||
name: d.umt.kind === "nexusphp" ? (d.umt.displayName ?? d.name) : d.umt.displayName,
|
||||
kind: "pt" as const,
|
||||
kind: definitionKind(d),
|
||||
adapter: adapterOf(d),
|
||||
baseUrl: d.domain,
|
||||
shippedEnabled: d.enabled !== false,
|
||||
@@ -140,8 +145,10 @@ export function sourcesRoutes(app: ModuleApp, rt: () => SourcesRuntime) {
|
||||
route(app, D.sites.get, async ({ params }) => siteToApi(await getSite(params.id)));
|
||||
route(app, D.sites.create, async ({ body, actor }) => {
|
||||
const def = body.key ? listSiteDefinitions().find((d) => d.id === body.key) : undefined;
|
||||
// 类型缺省:注册表里有定义 = PT 站;否则按旧口径(generic_rss = 自定义 RSS 站点)
|
||||
const kind = body.kind ?? (def ? "pt" : "rss_feed");
|
||||
// 类型缺省:注册表里有定义 = 定义的类型(PT / 公开 BT);否则按旧口径(generic_rss = 自定义 RSS 站点)
|
||||
const kind = body.kind ?? (def ? definitionKind(def) : "rss_feed");
|
||||
// 内置公开 BT 站(Nyaa、蜜柑等):用定义的专用适配器,默认定时抓最新资源,不默认进资源搜索
|
||||
const publicDef = kind === "public_bt" && def && definitionKind(def) === "public_bt" ? def : undefined;
|
||||
if (!SITE_KINDS[kind].implemented) throw new ApiException("bad_request", `还不支持添加${SITE_KINDS[kind].label}`);
|
||||
if (kind === "pt") {
|
||||
if (!body.key) throw new ApiException("bad_request", "PT 站要从站点定义里选(缺 key)");
|
||||
@@ -151,6 +158,10 @@ export function sourcesRoutes(app: ModuleApp, rt: () => SourcesRuntime) {
|
||||
if (!def && body.adapter !== "generic_rss") {
|
||||
throw new ApiException("bad_request", `注册表中没有站点 ${body.key};未适配站点只能以 generic_rss 登记`);
|
||||
}
|
||||
if (def && definitionKind(def) !== "pt") throw new ApiException("bad_request", `${body.key} 不是 PT 站`);
|
||||
} else if (publicDef) {
|
||||
if (body.adapter !== adapterOf(publicDef))
|
||||
throw new ApiException("bad_request", `站点 ${body.key} 的适配器类型应为 ${adapterOf(publicDef)}`);
|
||||
} else if (body.adapter !== "generic_rss") {
|
||||
throw new ApiException("bad_request", `${SITE_KINDS[kind].label}只能以 generic_rss 登记`);
|
||||
}
|
||||
@@ -170,11 +181,13 @@ export function sourcesRoutes(app: ModuleApp, rt: () => SourcesRuntime) {
|
||||
enabled: body.enabled ?? true,
|
||||
rate_limit: jsonb(body.rateLimit ?? {}),
|
||||
config: jsonb(body.config ?? {}),
|
||||
snapshot_enabled: kind === "pt" ? (body.snapshotEnabled ?? false) : false,
|
||||
snapshot_enabled:
|
||||
kind === "pt" ? (body.snapshotEnabled ?? false) : publicDef ? (body.snapshotEnabled ?? true) : false,
|
||||
snapshot_interval_sec: body.snapshotIntervalSec ?? null,
|
||||
proxy: body.proxy ?? false,
|
||||
// 不能搜索的站点不进默认搜索集合
|
||||
search_default: kind === "pt" ? (body.searchDefault ?? true) : false,
|
||||
search_default:
|
||||
kind === "pt" ? (body.searchDefault ?? true) : publicDef ? (body.searchDefault ?? false) : false,
|
||||
})
|
||||
.returningAll()
|
||||
.executeTakeFirstOrThrow();
|
||||
|
||||
Reference in new issue
Block a user