feat(identity): 豆瓣 / bgm.tv 辅助信息源与发现页
- adapters/meta:bgm.tv 官方 API(条目 / 搜索 / 每日放送)与豆瓣移动版接口(条目 / 实时热门) - 识别升级链:豆瓣条目缓存没有时在线查;AniBT 的 bgm ID、公开 BT 站标题搜 bgm → 名称 + 年份匹配 TMDB(季条目去季名与年份) - 条目缓存 30 天,查不到 6 小时负缓存;测试进程缺省不出外网 - 发现页:bgm 每日放送、豆瓣热门电影 / 剧集,点条目匹配 TMDB 作品 Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
b8876542b8
commit
709414778e
23 files changed
+958
-31
No files matched your search
@@ -198,6 +198,29 @@ export const libraryApi = {
|
||||
query: search.TmdbMediaQuery,
|
||||
response: search.TmdbMediaDetail,
|
||||
}),
|
||||
discoverCalendar: ep({
|
||||
method: "get",
|
||||
path: "/discover/bangumi-calendar",
|
||||
scope: "read",
|
||||
summary: "bgm.tv 每日放送(周一到周日;缓存 1 小时)",
|
||||
response: search.DiscoverCalendar,
|
||||
}),
|
||||
discoverHot: ep({
|
||||
method: "get",
|
||||
path: "/discover/douban-hot",
|
||||
scope: "read",
|
||||
summary: "豆瓣实时热门电影 / 剧集(缓存 1 小时)",
|
||||
query: search.DiscoverHotQuery,
|
||||
response: search.DiscoverList,
|
||||
}),
|
||||
discoverMatch: ep({
|
||||
method: "post",
|
||||
path: "/discover/tmdb-match",
|
||||
scope: "read",
|
||||
summary: "豆瓣 / bgm 条目 → TMDB 作品(名称 + 年份匹配,对照 MP 投影);确定的给 match,否则给候选",
|
||||
body: search.DiscoverMatchRequest,
|
||||
response: search.DiscoverMatchResult,
|
||||
}),
|
||||
tmdbSeason: ep({
|
||||
method: "get",
|
||||
path: "/media/tmdb/tv/{id}/season/{season}",
|
||||
|
||||
@@ -438,3 +438,55 @@ 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>;
|
||||
Reference in new issue
Block a user