feat(adapters): TMDB 列表与筛选、豆瓣榜单 / 标签 / 筛选 / 搜索、bgm 浏览与趋势,豆瓣 / bgm 请求缓存端口

- TMDB:流行趋势(日 / 周)、电影 / 剧集榜单、discover 参数映射、分页搜索;列表类请求 TTL 6 小时
- 豆瓣 / bgm:列表与搜索请求经 MetaRequestCache 与限流,失败(403 / 风控页)不缓存
- contracts:发现页条目、分页、查询校验与筛选字典;storage.cacheTtl 追加 meta* 字段
- testkit:mock TMDB 加列表接口

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Cxwgnn2pbzQ7rXv3rq7fei
This commit is contained in:
rootandClaude Opus 5.5 committed 2026-10-06 18:04:43 +08:00
1 parent 27514f4985
commit e46eb0e3c3
13 files changed
+1344 -91

No files matched your search

-52
View File
@@ -475,55 +475,3 @@ export const TmdbSeasonDetailView = z.object({
episodes: z.array(MediaEpisodeInfo),
});
export type TmdbSeasonDetailView = z.infer<typeof TmdbSeasonDetailView>;
// ── 发现:bgm.tv 每日放送、豆瓣热门(辅助信息源,点开后匹配 TMDB 作品) ──
export const DiscoverItem = z.object({
source: z.enum(["bangumi", "douban"]),
id: z.string(),
title: z.string(),
aliases: z.array(z.string()),
year: z.number().int().nullable(),
kind: z.enum(["movie", "tv"]).nullable(),
cover: z.string().nullable(),
rating: z.number().nullable(),
date: z.string().nullable(),
episodes: z.number().int().nullable(),
url: z.string(),
});
export type DiscoverItem = z.infer<typeof DiscoverItem>;
export const DiscoverCalendar = z.object({
days: z.array(z.object({ weekday: z.number().int(), label: z.string(), items: z.array(DiscoverItem) })),
});
export type DiscoverCalendar = z.infer<typeof DiscoverCalendar>;
export const DiscoverHotQuery = z.object({ kind: z.enum(["movie", "tv"]).default("movie") });
export type DiscoverHotQuery = z.infer<typeof DiscoverHotQuery>;
export const DiscoverList = z.object({ items: z.array(DiscoverItem) });
export type DiscoverList = z.infer<typeof DiscoverList>;
export const DiscoverMatchRequest = DiscoverItem.pick({
source: true,
id: true,
title: true,
aliases: true,
year: true,
kind: true,
});
export type DiscoverMatchRequest = z.infer<typeof DiscoverMatchRequest>;
export const DiscoverMatchCandidate = z.object({
type: z.enum(["movie", "tv"]),
id: z.string(),
title: z.string(),
year: z.number().int().nullable(),
posterPath: z.string().nullable(),
});
export const DiscoverMatchResult = z.object({
/** 能确定的 TMDB 作品;不确定为 null,看 candidates */
match: DiscoverMatchCandidate.nullable(),
candidates: z.array(DiscoverMatchCandidate),
});
export type DiscoverMatchResult = z.infer<typeof DiscoverMatchResult>;