API Reference
ContentLanguage
Section titled “ContentLanguage”type ContentLanguage = 'sub' | 'dub' | 'raw';| Value | Meaning |
|---|---|
'sub' | Original audio with subtitles |
'dub' | Dubbed audio (usually English) |
'raw' | Original audio, no subtitles |
MediaCatalogType
Section titled “MediaCatalogType”type MediaCatalogType = 'ANIME' | 'MOVIE' | 'TV' | 'MANGA' | 'LIVE_TV';Supported types include 'ANIME' and 'MANGA'.
IMediaSearchResult
Section titled “IMediaSearchResult”Returned by provider.search().
interface IMediaSearchResult { id: string; // opaque, pass to fetchContentUnits title: string; thumbnailUrl?: string; catalogType: MediaCatalogType; providerId: string; // matches provider.id availableLanguages?: ContentLanguage[]; // omitted if unknown}IContentUnit
Section titled “IContentUnit”Returned by provider.fetchContentUnits(). Represents a single episode or chapter in a unified, language-agnostic list: the caller picks a translation at resolveStream time.
interface IContentUnit { id: string; // opaque, pass to resolveStream title: string; number: number; // episode/chapter number (may be fractional, e.g. 1.5) availableLanguages?: ContentLanguage[]; // e.g. ['sub', 'dub']: omitted if unknown availableSubtitles?: ISubtitleAvailability[]; // optional, list-time metadata availableQualities?: IVideoPayload['quality'][]; // optional}ISubtitleTrack / ISubtitleAvailability
Section titled “ISubtitleTrack / ISubtitleAvailability”interface ISubtitleAvailability { language: string; // BCP-47 (e.g. 'en', 'pt-BR') label: string; // human-readable ('English') format?: 'vtt' | 'srt' | 'ass';}
interface ISubtitleTrack extends ISubtitleAvailability { url: string;}ISubtitleAvailability is the metadata-only shape used in list contexts; ISubtitleTrack adds the URL once resolved.
IUnitTracks
Section titled “IUnitTracks”Returned by the optional provider.fetchUnitTracks(). Lets a UI introspect tracks without paying the cost of a full stream resolution.
interface IUnitTracks { subtitles: ISubtitleTrack[]; qualities: IVideoPayload['quality'][]; headers?: Record<string, string>; // forwarded to the subtitle/stream fetcher when present}IVideoPayload
Section titled “IVideoPayload”A single playable stream.
interface IVideoPayload { sourceUrl: string; isHLS: boolean; // true → HLS manifest (.m3u8) quality: '1080p' | '720p' | '480p' | '360p' | 'auto'; language?: ContentLanguage; headers?: Record<string, string>; // forward to fetch/player (Referer, User-Agent) subtitles?: ISubtitleTrack[]; // external VTT tracks when the provider has them}SdkCache
Section titled “SdkCache”Minimal pluggable cache contract: bring whatever store you want (Map, Redis, SQLite, edge KV). Both methods may be sync or async; the SDK awaits either way.
interface SdkCache { get(key: string): unknown | Promise<unknown>; set(key: string, value: unknown): void | Promise<void>;}Keys are namespaced strings produced by startServer: search:<providerId>:<query>, content:<providerId>:<mediaId>, stream:<providerId>:<unitId>:<lang>, tracks:<providerId>:<unitId>:<lang>. get returns undefined for a miss; any other value (including null) is treated as a hit. Inspect the key prefix in your set to apply different TTLs per endpoint or refuse to cache (e.g. stream: if your provider hands out signed expiring URLs).
IMangaPayload
Section titled “IMangaPayload”interface IMangaPayload { imageUrls: string[]; headers?: Record<string, string>;}ResolvedMediaStream
Section titled “ResolvedMediaStream”Returned by provider.resolveStream(). A discriminated union: always check type before accessing the payload.
type ResolvedMediaStream = | { type: 'video'; streams: IVideoPayload[] } | { type: 'manga'; pages: IMangaPayload };Anime providers return type: 'video'; manga providers return type: 'manga'. The streams array on video results is sorted best-first by the provider.
HttpClient
Section titled “HttpClient”The shared HTTP transport. All providers and extractors accept one via constructor.
class HttpClient { constructor(config?: HttpClientConfig);}
interface HttpClientConfig { timeoutMs?: number; // default: 10000 (10s) proxyUrl?: string; // e.g. 'https://proxy.example.com' proxyType?: 'prepend' | 'query'; // default: 'prepend' proxyQueryParam?: string; // used when proxyType='query'; default: 'url' defaultHeaders?: Record<string, string>;}Methods
Section titled “Methods”get(url: string, options?: RequestInit): Promise<Response>post(url: string, body?: any, options?: RequestInit): Promise<Response>request(url: string, options?: RequestInit): Promise<Response>
// Convenience mutators (affect defaultHeaders)setCookie(name: string, value: string): voidsetUserAgent(userAgent: string): void
// Proxy internals (used by HlsUtils)getProxyUrl(): string | undefinedgetProxyType(): 'prepend' | 'query'getProxyQueryParam(): stringgetDefaultHeaders(): Record<string, string>requestUrl(url: string): string // applies proxy rewriting to a URLProxy modes
Section titled “Proxy modes”prepend: strips the protocol from the target and prepends the proxy base:
proxyUrl: 'https://proxy.example.com'target: 'https://cdn.site.com/video.m3u8'result: 'https://proxy.example.com/cdn.site.com/video.m3u8'query: passes the target as a query param:
proxyUrl: 'https://proxy.example.com/fetch'proxyQueryParam: 'url'result: 'https://proxy.example.com/fetch?url=https%3A%2F%2Fcdn.site.com%2Fvideo.m3u8'curl fallback
Section titled “curl fallback”When running in Node and fetch throws (timeout, TLS error, anti-bot rejection), HttpClient automatically retries the request using curl via child_process.execSync. The fallback synthesises a standard Response-shaped object, so callers see no difference. Cookie persistence uses a per-client temp file.
BaseProvider
Section titled “BaseProvider”abstract class BaseProvider { abstract readonly id: string; abstract readonly supportedTypes: MediaCatalogType[];
constructor(protected http: HttpClient);
abstract search(query: string): Promise<IMediaSearchResult[]>;
// Language-agnostic: returns one unified list. Each unit advertises its // available translations via `availableLanguages`. abstract fetchContentUnits(mediaId: string): Promise<IContentUnit[]>;
abstract resolveStream( unitId: string, language?: ContentLanguage ): Promise<ResolvedMediaStream>;
// Optional: list the subtitle/quality tracks for a single unit without // resolving the playable stream. Implement when the provider exposes a // cheap metadata endpoint. fetchUnitTracks?( unitId: string, language?: ContentLanguage ): Promise<IUnitTracks>;}BaseExtractor
Section titled “BaseExtractor”abstract class BaseExtractor { abstract readonly id: string; constructor(protected http: HttpClient); abstract extract(embedUrl: string): Promise<IVideoPayload[]>;}Extractors return an empty array (never throw) when they cannot handle the given URL.
Extractors
Section titled “Extractors”BloggerExtractor
Section titled “BloggerExtractor”Extracts googlevideo.com MP4 URLs from Blogger video embeds.
class BloggerExtractor extends BaseExtractor { readonly id = 'blogger'; static matches(url: string): boolean; // true for blogger.com/video.g?token=... extract(embedUrl: string): Promise<IVideoPayload[]>;}Flow:
- Fetch the embed page; extract
FdrFJe(session ID) andcfb2h(build hash). - POST to
/_/BloggerVideoPlayerUi/data/batchexecutewith theWcwnYdRPC. - Parse the response: find the stream array inside the
wrb.fr/WcwnYdenvelope; preferitag=22(720p) overitag=18(360p). - Falls back to a raw regex scan for
googlevideo.comURLs if structured parsing yields nothing.
Returned URLs require { Referer: 'https://www.blogger.com/' } headers.
Mp4UploadExtractor
Section titled “Mp4UploadExtractor”Extracts direct MP4 URLs from mp4upload.com embed pages.
class Mp4UploadExtractor extends BaseExtractor { readonly id = 'mp4upload'; static matches(url: string): boolean; // true for mp4upload.com URLs extract(embedUrl: string): Promise<IVideoPayload[]>;}Parses the player.src({ src: "https://...video.mp4" }) line from the embed HTML. Returned URLs require { Referer: 'https://mp4upload.com/' }.
GenericHlsExtractor
Section titled “GenericHlsExtractor”Best-effort extractor that scans any embed page for a .m3u8 or .mp4 URL.
class GenericHlsExtractor extends BaseExtractor { readonly id = 'generic-hls'; extract(embedUrl: string): Promise<IVideoPayload[]>;}Prefers .m3u8 over .mp4. Handles JSON-embedded URLs with escaped slashes. Cannot decrypt obfuscated players (filemoon, streamwish, ok.ru). Returns [] if nothing matches.
VidstreamingExtractor
Section titled “VidstreamingExtractor”Handles vidstreaming.io / gogoplay embeds with AES-CBC decryption.
class VidstreamingExtractor extends BaseExtractor { readonly id = 'vidstreaming'; extract(embedUrl: string): Promise<IVideoPayload[]>;}Flow:
- Fetch the embed page. Extract encryption key, IV, and decryption key from
container-N/videocontent-Nclass names. - Decrypt the
data-valueattribute with AES-CBC using the encryption key. - Encrypt the
idquery param with AES-CBC. - GET
{host}/encrypt-ajax.php?{decrypted_data}&id={encrypted_id}&alias={contentId}withX-Requested-With: XMLHttpRequest. - Decrypt the
datafield of the JSON response with AES-CBC using the decryption key. - Parse the resulting JSON:
sourceandsource_bkarrays each contain{ file, label }entries.
HlsUtils
Section titled “HlsUtils”class HlsUtils { static rewriteManifest(manifestText: string, playlistUrl: string, httpClient: HttpClient): string;}Rewrites every URI in an .m3u8 manifest to route through the HttpClient’s configured proxy:
- Plain URI lines (chunks, sub-playlists)
URI="..."attributes inside#EXT-X-KEY,#EXT-X-MAP, and similar tags- Relative URIs are first resolved to absolute using
playlistUrl
Returns the manifest unchanged if no proxy is configured on the client.
DomRegistry
Section titled “DomRegistry”class DomRegistry { static register(customParser: IDomParser): void; static getParser(): IDomParser; static parse(html: string): IDomElement;}Global singleton parser used by all providers that scrape HTML. The default is BrowserDomParser, which wraps globalThis.DOMParser.
linkedom is registered automatically on import in Node environments: no setup is needed. DomRegistry.register() is only needed when you want to swap in a fully custom parser.
Custom parser:
import { DomRegistry, IDomParser, IDomElement } from 'anime-sdk';
class MyParser implements IDomParser { parse(html: string): IDomElement { /* ... */ }}
DomRegistry.register(new MyParser());IDomElement / IDomParser
Section titled “IDomElement / IDomParser”interface IDomParser { parse(html: string): IDomElement;}
interface IDomElement { querySelector(selector: string): IDomElement | null; querySelectorAll(selector: string): IDomElement[]; getAttribute(name: string): string | null; readonly textContent: string | null; readonly outerHTML: string; readonly innerHTML: string;}startServer
Section titled “startServer”function startServer(options: ServerOptions): http.Server;
interface ServerOptions { providers: BaseProvider[]; port?: number; // default: 3000 auth?: { token: string }; proxy?: boolean; // enable /proxy and rewrite stream + subtitle URLs through it cache?: SdkCache; // memoize /search, /content, /stream, /tracks}Launches a Node http.Server. Returns the server instance so you can call server.close(). All requests must be GET; all responses are JSON. See HTTP Server for full route documentation and Stream Proxy for the proxy behaviour.
Routes: /search, /content, /stream, /tracks, /proxy (when proxy: true), and download routes /download/video, /download/video/progress, /download/video/file, /download/manga/page, /download/manga/chapter, /download/manga/chapter/progress, /download/manga/chapter/file.
Download utilities
Section titled “Download utilities”Functions for saving resolved streams to disk. Requires Node 20+; ffmpeg on PATH for HLS video downloads only.
downloadVideo
Section titled “downloadVideo”function downloadVideo( streams: IVideoPayload | IVideoPayload[], outputPath: string, options?: DownloadVideoOptions,): Promise<DownloadVideoResult>;Downloads an anime episode to a .mp4 file. Accepts a single stream or an array: if an array, each candidate is tried in order until one succeeds. Throws with a combined error message if all fail.
- HLS streams: downloads segments, strips PNG-wrapped bytes, concatenates into a
.tsfile, then callsffmpeg -c copyto mux to MP4. - Direct MP4: streams to disk via
fetch.
interface DownloadVideoOptions { onProgress?: (info: { phase: string; detail?: string }) => void; timeoutMs?: number; // default 300_000 (5 min)}
interface DownloadVideoResult { outputPath: string; stream: IVideoPayload; // the candidate that succeeded fileSize: number; // bytes}Progress phase values: 'resolving' → 'downloading' → 'muxing' → 'complete'.
downloadMangaPage
Section titled “downloadMangaPage”function downloadMangaPage( pages: IMangaPayload, pageIndex: number, outputDir: string, options?: DownloadMangaPageOptions,): Promise<DownloadMangaPageResult>;Downloads a single manga page. The filename is auto-generated as page_<NNN><ext> where the extension is inferred from the Content-Type header.
interface DownloadMangaPageOptions { headers?: Record<string, string>; // override the headers on IMangaPayload timeoutMs?: number; // default 30_000}
interface DownloadMangaPageResult { outputPath: string; pageIndex: number; fileSize: number; contentType: string;}downloadMangaChapter
Section titled “downloadMangaChapter”function downloadMangaChapter( pages: IMangaPayload, outputPath: string, options?: DownloadMangaChapterOptions,): Promise<DownloadMangaChapterResult>;Downloads all pages and packages them as an uncompressed .zip archive (STORE method: images are already compressed). No external dependencies.
interface DownloadMangaChapterOptions { onProgress?: (info: { downloaded: number; total: number }) => void; timeoutMs?: number; // per page; default 30_000}
interface DownloadMangaChapterResult { outputPath: string; pageCount: number; fileSize: number; // total ZIP size in bytes}HLS helpers
Section titled “HLS helpers”Low-level utilities exported for custom pipelines:
// Parse variant playlist URLs from a master playlistparseHlsMaster(content: string, baseUrl: string): string[]
// Parse segment descriptors from a media playlistparseHlsSegments(content: string, baseUrl: string): Array<{ url: string; duration: number }>
// Infer file extension from Content-TypedetectImageExtension(contentType: string): string
// CRC-32 checksum (used by the ZIP writer)crc32(buf: Buffer): number
// Build an uncompressed ZIP buffercreateZipBuffer(entries: Array<{ filename: string; data: Buffer }>): BufferSubtitle utilities
Section titled “Subtitle utilities”Exported helpers used internally by AnimeParadiseProvider and startServer; available for custom providers and self-hosted setups.
// Normalise an arbitrary array of {src|url, label, type|format} entries into// ISubtitleTrack[]. Non-http(s) entries (Drive IDs, etc.) are dropped.normalizeSubtitleEntries(entries: unknown): ISubtitleTrack[]
// Wrap a subtitle URL through the SDK's /proxy endpoint. Forces// Content-Type: text/vtt on VTT files so browsers parse them correctly.proxifySubtitleUrl( proxyBase: string, track: ISubtitleTrack, options?: { headers?: Record<string, string>; contentType?: string }): string
// BCP-47 inference from a human label (best-effort).labelToBcp47(label: string): stringCrypto utilities
Section titled “Crypto utilities”Exported for use in custom providers.
// AES-CBC decrypt: returns plaintext stringaesDecrypt(ciphertextBase64: string, keyStr: string, ivStr: string): Promise<string>
// AES-CBC encrypt: returns base64 stringaesEncrypt(plaintext: string, keyStr: string, ivStr: string): Promise<string>
// SHA-256 hashsha256(text: string): Promise<Uint8Array>
// AES-CTR decrypt (used by AllmangaProvider)aesDecryptCtr(ciphertext: Uint8Array, key: Uint8Array, iv: Uint8Array): Promise<Uint8Array>All functions use globalThis.crypto.subtle (available in Node 20+ and all modern browsers).