mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-09-19 05:16:27 -07:00
feat(stats): add TMDB metadata for live-action dramas in the Library
Anime covers come from AniList, which has no live-action titles, so dramas and movies showed blank cards with no description and split across season folders. Library entries now carry a media kind plus a TMDB link, and the cover-art fetcher falls back to TMDB when AniList has no match, accepting only a Japanese non-animated title whose TMDB names match the parsed title exactly. Entries that resolve to the same TMDB title merge into one card regardless of season, and a Link to TMDB action in the detail view covers anything the automatic match missed. Release builds bundle a project-owned TMDB key injected from the SUBMINER_TMDB_API_KEY secret at build time; tmdb.apiKey/apiKeyCommand override it and are required when running from source. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
@@ -27,6 +27,7 @@ import type {
|
||||
WatchTimePerAnime,
|
||||
WordDetailData,
|
||||
} from './stats-wire';
|
||||
import type { TmdbMediaType } from '../shared/media-kind';
|
||||
|
||||
export type StatsTrendRange = '7d' | '30d' | '90d' | '365d' | 'all';
|
||||
export type StatsTrendGroupBy = 'day' | 'month';
|
||||
@@ -78,6 +79,25 @@ export interface StatsAnilistSearchResult {
|
||||
title: { romaji: string | null; english: string | null; native: string | null } | null;
|
||||
}
|
||||
|
||||
export interface StatsTmdbSearchResult {
|
||||
tmdbId: number;
|
||||
tmdbType: TmdbMediaType;
|
||||
/** English title when TMDB has one, otherwise the original title. */
|
||||
title: string;
|
||||
originalTitle: string;
|
||||
originalLanguage: string;
|
||||
overview: string | null;
|
||||
posterUrl: string | null;
|
||||
year: number | null;
|
||||
/** True when TMDB tags the title with the Animation genre. */
|
||||
isAnimation: boolean;
|
||||
}
|
||||
|
||||
export interface StatsTmdbAssignment {
|
||||
tmdbId: number;
|
||||
tmdbType: TmdbMediaType;
|
||||
}
|
||||
|
||||
export interface StatsAnilistAssignment {
|
||||
anilistId: number;
|
||||
titleRomaji?: string | null;
|
||||
@@ -209,11 +229,13 @@ export interface StatsJsonResponseMap {
|
||||
moveVideoToAnime: StatsMoveVideoResponse;
|
||||
dismissAnimeMergeRecommendation: StatsOkResponse;
|
||||
anilistSearch: StatsAnilistSearchResult[];
|
||||
tmdbSearch: StatsTmdbSearchResult[];
|
||||
knownWords: string[];
|
||||
knownWordsSummary: StatsKnownWordsSummary;
|
||||
animeKnownWordsSummary: StatsKnownWordsSummary;
|
||||
mediaKnownWordsSummary: StatsKnownWordsSummary;
|
||||
reassignAnimeAnilist: StatsOkResponse;
|
||||
reassignAnimeTmdb: StatsOkResponse;
|
||||
coverImages: StatsCoverImagesData;
|
||||
episodeDetail: EpisodeDetailData;
|
||||
ankiBrowse: StatsAnkiBrowseResponse;
|
||||
@@ -302,6 +324,8 @@ export interface StatsHttpClient {
|
||||
getMediaKnownWordsSummary: (videoId: number) => Promise<StatsKnownWordsSummary>;
|
||||
searchAnilist: (query: string) => Promise<StatsAnilistSearchResult[]>;
|
||||
reassignAnimeAnilist: (animeId: number, info: StatsAnilistAssignment) => Promise<void>;
|
||||
searchTmdb: (query: string) => Promise<StatsTmdbSearchResult[]>;
|
||||
reassignAnimeTmdb: (animeId: number, info: StatsTmdbAssignment) => Promise<void>;
|
||||
mineCard: (params: StatsMineCardParams) => Promise<StatsMineCardResponse>;
|
||||
ankiBrowse: (noteId: number) => Promise<void>;
|
||||
ankiNotesInfo: (noteIds: number[]) => Promise<StatsAnkiNoteInfo[]>;
|
||||
|
||||
Reference in New Issue
Block a user