export interface IProviderStats { name: string; baseUrl: string; lang: string[] | string; isNSFW: boolean; logo: string; classPath: string; isWorking: boolean; } /** * What a provider supports, declared by the provider itself so the declaration arrives with * registry code. Meta providers choose behaviour from this instead of the provider's class, * which registry-only providers don't have. */ export interface ProviderCapabilities { /** META.Anilist merges this provider's episode list with ani.zip titles, images and keys. */ aniZipEpisodes?: boolean; /** * `combined`: one entry whose episode ids end in `$both`; the caller picks `$sub` or `$dub`. * `separate`: sub and dub are separate entries. */ subDub?: 'separate' | 'combined'; } /** * An anime provider instance, whether built from a bundled class or loaded from registry code * (registry-loaded providers are plain objects, not class instances). */ export interface IAnimeProvider { readonly name: string; capabilities?: ProviderCapabilities; search(query: string, ...args: any[]): Promise>; fetchAnimeInfo(animeId: string, ...args: any[]): Promise; fetchEpisodeSources(episodeId: string, ...args: any[]): Promise; fetchEpisodeServers(episodeId: string, ...args: any[]): Promise; } /** A movie/TV provider instance, whether built from a bundled class or loaded from registry code. */ export interface IMovieProvider { readonly name: string; capabilities?: ProviderCapabilities; search(query: string, ...args: any[]): Promise>; fetchMediaInfo(mediaId: string, ...args: any[]): Promise; fetchEpisodeSources(episodeId: string, ...args: any[]): Promise; fetchEpisodeServers(episodeId: string, ...args: any[]): Promise; } export interface ITitle { romaji?: string; english?: string; native?: string; userPreferred?: string; } export interface IAnimeResult { id: string; title: string | ITitle; url?: string; image?: string; imageHash?: string; cover?: string; coverHash?: string; status?: MediaStatus; rating?: number; type?: MediaFormat; releaseDate?: string; relationType?: string; [x: string]: any; // other fields } export interface ISearch { currentPage?: number; hasNextPage?: boolean; totalPages?: number; /** * total results must include results from all pages */ totalResults?: number; results: T[]; } export interface Trailer { id: string; url?: string; site?: string; thumbnail?: string; thumbnailHash?: string | null; } export interface FuzzyDate { year?: number; month?: number; day?: number; } export enum MediaFormat { TV = 'TV', TV_SHORT = 'TV_SHORT', TV_SPECIAL = 'TV_SPECIAL', MOVIE = 'MOVIE', SPECIAL = 'SPECIAL', OVA = 'OVA', ONA = 'ONA', MUSIC = 'MUSIC', MANGA = 'MANGA', NOVEL = 'NOVEL', ONE_SHOT = 'ONE_SHOT', PV = 'PV', COMIC = 'COMIC', } export interface IAnimeInfo extends IAnimeResult { malId?: number | string; genres?: string[]; description?: string; status?: MediaStatus; totalEpisodes?: number; /** * @deprecated use `hasSub` or `hasDub` instead */ subOrDub?: SubOrDub; hasSub?: boolean; hasDub?: boolean; synonyms?: string[]; /** * two letter representation of coutnry: e.g JP for japan */ countryOfOrigin?: string; isAdult?: boolean; isLicensed?: boolean; /** * `FALL`, `WINTER`, `SPRING`, `SUMMER` */ season?: string; studios?: string[]; color?: string; cover?: string; trailer?: Trailer; episodes?: IAnimeEpisode[]; startDate?: FuzzyDate; endDate?: FuzzyDate; recommendations?: IAnimeResult[]; relations?: IAnimeResult[]; } export interface IAnimeEpisodeV2 { [x: string]: { id: string; season_number: number; title: string; image: string; imageHash: string; description: string; releaseDate: string; isHD: boolean; isAdult: boolean; isDubbed: boolean; isSubbed: boolean; duration: number; }[]; } export interface IAnimeEpisode { id: string; uniqueId?: string; number: number; title?: string; description?: string; isFiller?: boolean; isSubbed?: boolean; isDubbed?: boolean; url?: string; image?: string; imageHash?: string; releaseDate?: string; [x: string]: unknown; // other fields } /** * An episode returned by a meta provider (e.g. `META.Anilist.fetchEpisodesListById`). `number` is * always the provider's own number. */ export interface IMetaAnimeEpisode extends IAnimeEpisode { /** * Stable key to store watch progress under: `${anilistId}$ep=${n}`, where `n` is the AniDB * episode number from ani.zip when the episode was matched, otherwise the provider's `number`. */ uniqueId: string; /** TVDB season-relative episode number, when ani.zip matched the episode. */ tvdbNumber?: number; /** TVDB absolute episode number, when ani.zip matched the episode. */ absoluteNumber?: number; } /** One entry of `episodes` in an ani.zip `/mappings` response. */ export interface AniZipEpisode { /** TVDB season-relative number; missing for specials. */ episodeNumber?: number; /** TVDB absolute number; missing for specials. */ absoluteEpisodeNumber?: number; seasonNumber?: number; title: { 'ja': string; 'en': string; 'fr': string; 'hu': string; 'x-jat': string; }; airDate: string; airDateUtc: string; overview: string; image: string; /** AniDB episode, same as the object key: `"1"` for regular episodes, `"S1"`, `"O1"`… for specials and extras. */ episode: string; airdate: string; rating: string; summary: string; } export interface IEpisodeServer { name: string; url: string; [x: string]: unknown; } export interface IVideo { /** * The **MAIN URL** of the video provider that should take you to the video */ url: string; /** * The name of the server providing this video stream */ server?: string; /** * The Quality of the video should include the `p` suffix */ quality?: string; /** * make sure to set this to `true` if the video is hls */ isM3U8?: boolean; /** * set this to `true` if the video is dash (mpd) */ isDASH?: boolean; /** * size of the video in **bytes** */ size?: number; [x: string]: unknown; // other fields } export enum StreamingServers { AsianLoad = 'asianload', GogoCDN = 'gogocdn', StreamSB = 'streamsb', MixDrop = 'mixdrop', Mp4Upload = 'mp4upload', UpCloud = 'upcloud', StreamTape = 'streamtape', VizCloud = 'vizcloud', // same as vizcloud MyCloud = 'mycloud', Filemoon = 'filemoon', VidStreaming = 'vidstreaming', BuiltIn = 'builtin', SmashyStream = 'smashystream', StreamHub = 'streamhub', StreamWish = 'streamwish', VidHide = 'vidhide', VidMoly = 'vidmoly', Voe = 'voe', MegaUp = 'megaup', MegaCloud = 'megacloud', Luffy = 'luffy', Multi = 'multi', Kwik = 'kwik', MegaPlay = 'megaplay', GDFlix = 'gdflix', Gofile = 'gofile', HubCloud = 'hubcloud', FlixCloud = 'flixcloud', } export enum MediaStatus { ONGOING = 'Ongoing', COMPLETED = 'Completed', HIATUS = 'Hiatus', CANCELLED = 'Cancelled', NOT_YET_AIRED = 'Not yet aired', UNKNOWN = 'Unknown', } export enum WatchListType { WATCHING = 'watching', ONHOLD = 'on-hold', PLAN_TO_WATCH = 'plan to watch', DROPPED = 'dropped', COMPLETED = 'completed', NONE = 'none', } export enum SubOrDub { SUB = 'sub', DUB = 'dub', BOTH = 'both', } /** * A manga search result. Sites describe titles differently, so most fields are optional; every * provider fills the ones its site has, in the same shape (see docs/guides/manga.md). */ export interface IMangaResult { /** Provider id of the title, passed to `fetchMangaInfo`. Stable across calls. */ id: string; /** Display title. Manga providers return a string; meta providers (AniList) return an `ITitle`. */ title: string | ITitle; /** The title in other languages or spellings. */ altTitles?: string[]; /** Absolute cover image URL. */ image?: string; /** Headers the cover image request needs (e.g. Referer) when the image host refuses hotlinks. */ headerForImage?: Record; /** Plain-text synopsis. */ description?: string; status?: MediaStatus; releaseDate?: number | string; /** Absolute URL of the title's page on the site. */ url?: string; [x: string]: unknown; // other fields } /** One chapter of a title. */ export interface IMangaChapter { /** Provider id of the chapter, passed to `fetchChapterPages`. */ id: string; /** Always a string: the chapter's name, or `Chapter 12` when the site gives none. */ title: string; /** Chapter number (`12`, `10.5`) when the site gives one; chapter lists are ordered by it. */ chapterNumber?: number; /** Volume number when the site gives one. */ volumeNumber?: number; /** @deprecated Use `volumeNumber`. */ volume?: number; pages?: number; /** ISO 8601 date when it can be parsed, otherwise the site's own text. */ releaseDate?: string; /** Scanlation group, when the site credits one. */ scanlator?: string; /** Language of the chapter (ISO 639-1, e.g. `en`, with a region when the site has one, e.g. `pt-br`). */ language?: string; /** Absolute URL of the chapter on the site. */ url?: string; [x: string]: unknown; // other fields } export interface IMangaInfo extends IMangaResult { malId?: number | string; authors?: string[]; artists?: string[]; genres?: string[]; links?: string[]; characters?: any[]; recommendations?: IMangaResult[]; /** In reading order: the first chapter first (see `sortChaptersForReading`). */ chapters?: IMangaChapter[]; } /** One page image of a chapter. */ export interface IMangaChapterPage { /** Absolute image URL. */ img: string; /** Position in the chapter, starting at 1. */ page: number; /** Headers the image request needs (e.g. Referer). Set on every page when the host needs them. */ headerForImage?: Record; [x: string]: unknown; // other fields } export interface ILightNovelResult { id: string; title: string | ITitle; url: string; image?: string; [x: string]: unknown; // other fields } export interface ILightNovelChapter { id: string; title: string; volume?: number | string; url?: string; } export interface ILightNovelChapterContent { novelTitle: string; chapterTitle: string; text: string; } export interface ILightNovelInfo extends ILightNovelResult { authors?: string[]; genres?: string[]; description?: string; chapters?: ILightNovelChapter[]; status?: MediaStatus; views?: number; rating?: number; } export interface ISubtitle { /** * The id of the subtitle. **not** required */ id?: string; /** * The **url** that should take you to the subtitle **directly**. */ url: string; /** * The language of the subtitle */ lang: string; } /** * The start, and the end of the intro or opening in seconds. */ export interface Intro { start: number; end: number; } export interface ISource { headers?: { [k: string]: string }; intro?: Intro; outro?: Intro; subtitles?: ISubtitle[]; sources: IVideo[]; download?: string | { url?: string; quality?: string }[]; embedURL?: string; } /** * Used **only** for movie/tvshow providers */ export enum TvType { TVSERIES = 'TV Series', MOVIE = 'Movie', ANIME = 'Anime', PEOPLE = 'People', } export interface IMovieEpisode { /** * Provider episode id. Providers always set it; TMDB meta leaves it unset for episodes TMDB lists * but the provider doesn't have (nothing to play). */ id?: string; uniqueId?: string; title: string; url?: string; number?: number; /** @deprecated same as `number`; TMDB meta sets both */ episode?: number; season?: number; description?: string; /** A URL from providers; TMDB meta gives `{ mobile, hd }` (300 px and 780 px wide stills) */ image?: | string | { mobile?: string; hd?: string; }; releaseDate?: string; [x: string]: unknown; // other fields } export interface IMovieResult { id: string; title: string | ITitle; url?: string; image?: string; releaseDate?: string; type?: TvType; [x: string]: unknown; // other unkown fields } export interface IPeopleResult { id: string; name: string; rating?: string; image?: string; movies: IMovieResult[]; [x: string]: unknown; // other unkown fields } export interface INewsFeed extends INews { /** topics of the feed */ topics: Topics[]; /** preview of the news feed */ preview: INewsFeedPreview; } export interface INewsInfo extends INews { /** intro of the news */ intro: string; /** description of the news */ description: string; } interface INews { /** id of the news */ id: string; /** title of the news */ title: string; /** time at which the news was uploaded */ uploadedAt: string; /** thumbnail image URL of the news */ thumbnail: string; /** thumbnail image blurhash code of the news */ thumbnailHash: string; /** URL of the news */ url: string; } interface INewsFeedPreview { /** intro of the feed */ intro: string; /** some contents of the feed */ full: string; } export interface IMovieSeason { season: number; image?: { mobile?: string; hd?: string; }; /** Empty when the season has no episodes listed yet */ episodes: IMovieEpisode[]; /** False when the season's first episode hasn't aired yet */ isReleased?: boolean; /** * TMDB meta only: true when TMDB's request for this season failed. `episodes` is empty; fetching * the info again may fill it. */ failed?: boolean; } export interface IMovieInfo extends IMovieResult { /** * TMDB meta only: the provider's media id when the title was found on the provider (pass it to the * provider as the media id). Unset when nothing matched; `id` stays the TMDB id either way. */ providerId?: string; /** TMDB meta only, for movies: the provider episode id that plays the movie */ episodeId?: string; cover?: string; recommendations?: IMovieResult[]; similar?: IMovieResult[]; genres?: string[]; description?: string; rating?: number; status?: MediaStatus; /** Text from providers; minutes (a number) from TMDB meta */ duration?: string | number; production?: string; casts?: string[]; tags?: string[]; directors?: string[]; writers?: string[]; actors?: string[]; characters?: { id: number; name: string; url?: string; character?: string; image?: string; }[]; totalEpisodes?: number; totalSeasons?: number; nextAiringEpisode?: { season?: number; episode?: number; releaseDate?: string; title?: string; description?: string; runtime?: number; }; mappings?: { imdb?: string; tmdb?: number; }; trailer?: Trailer; seasons?: IMovieSeason[]; episodes?: IMovieEpisode[]; } export enum Genres { ACTION = 'Action', ADVENTURE = 'Adventure', CARS = 'Cars', COMEDY = 'Comedy', DRAMA = 'Drama', FANTASY = 'Fantasy', HORROR = 'Horror', MAHOU_SHOUJO = 'Mahou Shoujo', MECHA = 'Mecha', MUSIC = 'Music', MYSTERY = 'Mystery', PSYCHOLOGICAL = 'Psychological', ROMANCE = 'Romance', SCI_FI = 'Sci-Fi', SLICE_OF_LIFE = 'Slice of Life', SPORTS = 'Sports', SUPERNATURAL = 'Supernatural', THRILLER = 'Thriller', } export enum Topics { ANIME = 'anime', ANIMATION = 'animation', MANGA = 'manga', GAMES = 'games', NOVELS = 'novels', LIVE_ACTION = 'live-action', COVID_19 = 'covid-19', INDUSTRY = 'industry', MUSIC = 'music', PEOPLE = 'people', MERCH = 'merch', EVENTS = 'events', } export interface ProxyConfig { /** * The proxy URL * @example https://proxy.com **/ url: string | string[]; /** * X-API-Key header value (if any) **/ key?: string; /** * The proxy rotation interval in milliseconds. (default: 5000) */ rotateInterval?: number; } export interface IRoles { id: string; title: ITitle; type?: string; image: { extraLarge?: string; large?: string; medium?: string; }; color?: string; } export interface IStaff { id: string; name: { first?: string; last?: string; native?: string; full?: string; }; image?: { large?: string; medium?: string; }; description?: string; siteUrl?: string; roles?: IRoles[]; }