Add support for Jellyfin library-to-category mappings used during import. Key changes: - UI: ImporterView now lets users fetch Jellyfin libraries, configure per-library category (TV/Anime/Movies/Music/skip) and optional path segments, and persists mappings to API settings and localStorage. - API/types: Add jellyfin_library_mappings to ApiSettingsItem/CreateSettingsInput and UserSettings (JSON string of LibraryMapping[]), and wire conversion helpers in src/api.ts and src/types.ts. - Jellyfin importer: Introduce LibraryMapping type, fetchJellyfinLibraries, helper functions to resolve library from ParentId or Path (extractLibraryFromPath, findLibraryForItem), and update item conversion (movies/series/albums) to apply mappings and skip items marked 'skip'. Import flow now fetches libraries to build id->name map and passes mappings through to converters. This enables category-aware imports and allows skipping libraries during Jellyfin imports.
133 lines
3.2 KiB
TypeScript
133 lines
3.2 KiB
TypeScript
export type MediaCategory = 'Anime' | 'Movies' | 'TV Series' | 'Music' | 'Books' | 'Adult' | 'Consoles' | 'Games';
|
|
|
|
export interface Media {
|
|
id: string;
|
|
title: string;
|
|
year: string;
|
|
poster: string;
|
|
category: MediaCategory;
|
|
aspectRatio?: '2/3' | '16/9' | '1/1';
|
|
type?: 'TV' | 'Movie' | 'OVA' | 'ONA' | 'Album' | 'Single' | 'Hardcover' | 'E-book' | 'Console' | 'Game';
|
|
banner?: string;
|
|
description?: string;
|
|
rating?: number;
|
|
genres?: string[];
|
|
tags?: string[];
|
|
studios?: string[];
|
|
status?: 'watching' | 'completed' | 'planned' | 'dropped' | 'reading' | 'listening' | 'playing' | 'on-hold';
|
|
episodes?: Episode[];
|
|
tracks?: Track[];
|
|
staff?: Staff[];
|
|
categories?: string[];
|
|
platforms?: string[];
|
|
developers?: string[];
|
|
completionStatus?: string;
|
|
source?: string;
|
|
playCount?: number;
|
|
lastActivity?: string | null;
|
|
playtime?: number;
|
|
}
|
|
|
|
export interface Episode {
|
|
id: number;
|
|
media_id: number;
|
|
season: number;
|
|
episode_number: number;
|
|
title: string;
|
|
description: string;
|
|
air_date: string;
|
|
duration: number;
|
|
thumbnail: string;
|
|
}
|
|
|
|
export interface Track {
|
|
id: number;
|
|
media_id: number;
|
|
track_number: number;
|
|
title: string;
|
|
duration: number | null;
|
|
artist: string;
|
|
}
|
|
|
|
export interface Staff {
|
|
id: string;
|
|
name: string;
|
|
cleanname?: string;
|
|
role: string;
|
|
photo: string;
|
|
characterName?: string;
|
|
characterImage?: string;
|
|
mediaId?: string;
|
|
mediaTitle?: string;
|
|
bio?: string;
|
|
birthDate?: string;
|
|
birthPlace?: string;
|
|
occupations?: string[];
|
|
createdAt?: string;
|
|
updatedAt?: string;
|
|
bust_size?: number | null;
|
|
cup_size?: string | null;
|
|
waist_size?: number | null;
|
|
hip_size?: number | null;
|
|
height?: number | null;
|
|
weight?: number | null;
|
|
hair_color?: string | null;
|
|
eye_color?: string | null;
|
|
ethnicity?: string | null;
|
|
filmography?: CastMediaItem[];
|
|
media_types?: string[];
|
|
adult_specifics?: AdultSpecifics;
|
|
}
|
|
|
|
export interface CastMediaItem {
|
|
id: number;
|
|
title: string;
|
|
year: number;
|
|
poster: string | null;
|
|
category: string | null;
|
|
type: string;
|
|
role: string;
|
|
characterName?: string | null;
|
|
}
|
|
|
|
export interface AdultSpecifics {
|
|
id: number;
|
|
cast_id: number;
|
|
bust_size?: number | null;
|
|
cup_size?: string | null;
|
|
waist_size?: number | null;
|
|
hip_size?: number | null;
|
|
height?: number | null;
|
|
weight?: number | null;
|
|
hair_color?: string | null;
|
|
eye_color?: string | null;
|
|
ethnicity?: string | null;
|
|
tattoos?: string | null;
|
|
piercings?: string | null;
|
|
measurements?: string | null;
|
|
shoe_size?: number | null;
|
|
}
|
|
|
|
export interface UserSettings {
|
|
id?: number;
|
|
enabledCategories: MediaCategory[];
|
|
itemsPerPage: number;
|
|
gridItemSize: number; // 1-10 scale
|
|
defaultView: 'grid' | 'list';
|
|
showAdultContent: boolean;
|
|
autoPlayTrailers: boolean;
|
|
language: string;
|
|
theme: 'light' | 'dark' | 'system';
|
|
jellyfinLibraryMappings?: string; // JSON string of LibraryMapping[]
|
|
createdAt?: string;
|
|
updatedAt?: string;
|
|
}
|
|
|
|
// Source to Category mapping - ensures sources are only used with appropriate categories
|
|
export const SOURCE_CATEGORY_MAPPING: Record<string, MediaCategory[]> = {
|
|
'xbvr': ['Adult'],
|
|
'stashapp': ['Adult'],
|
|
'playnite': ['Games'],
|
|
'manual': ['Anime', 'Movies', 'TV Series', 'Music', 'Books', 'Adult', 'Consoles', 'Games'],
|
|
};
|