@mohtasimalam/hentai.js
Version:
A library that fetches hentai data from different sources.
1,145 lines (1,134 loc) • 29.8 kB
TypeScript
interface PaginatedResult<T> {
results?: T[];
total?: number;
page?: number;
pages?: number;
next?: number;
previous?: number;
hasNextPage?: boolean;
}
declare const HANIME_BASE_URL = "https://hanime.tv";
declare const HANIME_SEARCH_URL = "https://search.htv-services.com";
declare const HANIME_SIGNATURE_GENERATOR: () => string;
declare const HAnime: {
new (options?: HAnimeOptions): {
BASE_URL: string;
SEARCH_URL: string;
generateSignature: () => string;
/**
* Searches for videos on Hanime.tv based on the provided query.
*
* @param {string} query - The search query string.
* @param {number} [page=1] - The page number to retrieve (default is 1).
* @param {number} [perPage=10] - The number of results per page (default is 10).
* @returns {Promise<PaginatedResult<HAnimeSearchResult>>} A promise that resolves to a paginated result of search results.
*/
search: (query: string, page?: number, perPage?: number) => Promise<PaginatedResult<HAnimeSearchResult>>;
/**
* Retrieves detailed information about a specific video by its slug.
*
* @param {string} slug - The unique slug identifier for the video.
* @returns {Promise<HAnimeVideoInfo>} A promise that resolves to detailed information about the video.
*/
getInfo: (slug: string) => Promise<HAnimeVideoInfo>;
/**
* Retrieves stream information for a specific video episode by its slug.
*
* @param {string} slug - The unique slug identifier for the video episode.
* @returns {Promise<HAnimeStream[]>} A promise that resolves to an array of available video streams.
*/
getEpisode: (slug: string) => Promise<HAnimeStream[]>;
mapToSearchResult: (raw: HAnimeRawSearchResult) => HAnimeSearchResult;
mapToEpisode: (raw: {
id: number;
name: string;
slug: string;
created_at: string;
released_at: string;
views: number;
interests: number;
poster_url: string;
cover_url: string;
is_hard_subtitled: boolean;
brand: string;
duration_in_ms: number;
is_censored: boolean;
rating: number;
likes: number;
dislikes: number;
downloads: number;
monthly_rank: number;
brand_id: string;
is_banned_in: string;
preview_url: null;
primary_color: null;
created_at_unix: number;
released_at_unix: number;
}) => {
id: number;
name: string;
slug: string;
views: number;
interests: number;
thumbnailUrl: string;
coverUrl: string;
isHardSubtitled: boolean;
brand: {
name: string;
id: string;
};
durationMs: number;
isCensored: boolean;
likes: number;
rating: number;
dislikes: number;
downloads: number;
rankMonthly: number;
brandId: string;
isBannedIn: string;
previewUrl: null;
color: null;
createdAt: number;
releasedAt: number;
};
};
};
interface HAnimeOptions {
baseUrl?: string;
searchUrl?: string;
signatureGenerator?: () => string;
}
interface HAnimeVideoInfo {
title: string;
slug: string;
id: number;
description?: string;
views: number;
interests: number;
posterUrl: string;
coverUrl: string;
brand: {
name: string;
id: string | number;
};
durationMs: number;
isCensored: boolean;
likes: number;
rating: number;
dislikes: number;
downloads: number;
rankMonthly: number;
tags: HentaiTag[];
createdAt: string;
releasedAt: string;
episodes: {
next: HentaiVideoEpisode;
all: HentaiVideoEpisode[];
random: HentaiVideoEpisode;
};
}
interface HentaiVideoEpisode {
id: number;
name: string;
slug: string;
views: number;
interests: number;
thumbnailUrl: string;
coverUrl: string;
isHardSubtitled: boolean;
brand: {
name: string;
id: string;
};
durationMs: number;
isCensored: boolean;
likes: number;
rating: number;
dislikes: number;
downloads: number;
rankMonthly: number;
brandId: string;
isBannedIn: string;
previewUrl: null;
color: null;
createdAt: number;
releasedAt: number;
}
interface HAnimeStream {
id: number;
serverId: number;
kind: string;
extension: string;
mimeType: string;
width: number;
height: string | number;
durationInMs: number;
filesizeMbs: number;
filename: string;
url: string;
}
interface HanimeResponse {
layout: string;
data: unknown[];
error: null;
serverRendered: boolean;
state: State;
videos_manifest?: VideosManifest;
pr?: boolean;
}
interface State {
scrollY: number;
version: number;
is_new_version: boolean;
r: null;
country_code: null;
page_name: string;
user_agent: string;
ip: null;
referrer: null;
geo: null;
is_dev: boolean;
is_wasm_supported: boolean;
is_mounted: boolean;
is_loading: boolean;
is_searching: boolean;
browser_width: number;
browser_height: number;
system_msg: string;
data: Data;
auth_claim: null;
session_token: string;
session_token_expire_time_unix: number;
env: Env;
user: null;
user_setting: null;
playlists: null;
shuffle: boolean;
account_dialog: AccountDialog;
contact_us_dialog: ContactUsDialog;
general_confirmation_dialog: GeneralConfirmationDialog;
snackbar: Snackbar;
search: Search;
}
interface Data {
video: Video;
}
interface Video {
player_base_url: string;
hentai_video: HentaiVideo;
hentai_tags: HentaiTag[];
hentai_franchise: HentaiFranchise;
hentai_franchise_hentai_videos: HentaiVideo[];
hentai_video_storyboards: HentaiVideoStoryboard[];
brand: Brand;
watch_later_playlist_hentai_videos: null;
like_dislike_playlist_hentai_videos: null;
playlist_hentai_videos: null;
similar_playlists_data: null;
next_hentai_video: HentaiVideo;
next_random_hentai_video: HentaiVideo;
videos_manifest?: VideosManifest;
user_license: null;
bs: Bs;
ap: number;
pre: string;
encrypted_user_license: null;
host: string;
}
interface HentaiVideo {
id: number;
is_visible: boolean;
name: string;
slug: string;
created_at: string;
released_at: string;
description?: string;
views: number;
interests: number;
poster_url: string;
cover_url: string;
is_hard_subtitled: boolean;
brand: string;
duration_in_ms: number;
is_censored: boolean;
rating: number;
likes: number;
dislikes: number;
downloads: number;
monthly_rank: number;
brand_id: string;
is_banned_in: string;
preview_url: null;
primary_color: null;
created_at_unix: number;
released_at_unix: number;
hentai_tags?: HentaiTag[];
titles?: unknown[];
}
interface HentaiTag {
id: number;
text: string;
count?: number;
description?: string;
wide_image_url?: string;
tall_image_url?: string;
}
interface HentaiFranchise {
id: number;
name: string;
slug: string;
title: string;
}
interface HentaiVideoStoryboard {
id: number;
num_total_storyboards: number;
sequence: number;
url: string;
frame_width: number;
frame_height: number;
num_total_frames: number;
num_horizontal_frames: number;
num_vertical_frames: number;
}
interface Brand {
id: number;
title: string;
slug: string;
website_url: null;
logo_url: null;
email: null;
count: number;
}
interface VideosManifest {
servers: Server[];
}
interface Server {
id: number;
name: string;
slug: string;
na_rating: number;
eu_rating: number;
asia_rating: number;
sequence: number;
is_permanent: boolean;
streams: Stream[];
}
interface Stream {
id: number;
server_id: number;
slug: string;
kind: string;
extension: string;
mime_type: string;
width: number;
height: string;
duration_in_ms: number;
filesize_mbs: number;
filename: string;
url: string;
is_guest_allowed: boolean;
is_member_allowed: boolean;
is_premium_allowed: boolean;
is_downloadable: boolean;
compatibility: string;
hv_id: number;
server_sequence: number;
video_stream_group_id: string;
extra2: null;
}
interface Bs {
ntv_1: Ntv1;
ntv_2: Ntv2;
footer_0: Footer0;
native_1: Native1;
native_0: Native0;
ntv_0: Ntv0;
}
interface Ntv1 {
desktop: DesktopAd;
}
interface Ntv2 {
desktop: DesktopAd;
}
interface Footer0 {
mobile: MobileAd;
desktop: DesktopAd;
}
interface Native1 {
mobile: NativeAd;
}
interface Native0 {
mobile: NativeAd;
}
interface Ntv0 {
desktop: DesktopAd;
}
interface DesktopAd {
id: number;
ad_id: string;
ad_type: string;
placement: string;
image_url: null;
iframe_url: string;
click_url: null | string;
width: number;
height: number;
page: string;
form_factor: string;
video_url: null;
impressions: number;
clicks: number;
seconds: number;
placement_x: null;
}
interface MobileAd {
id: number;
ad_id: string;
ad_type: string;
placement: string;
image_url: null;
iframe_url: string;
click_url: null;
width: number;
height: number;
page: string;
form_factor: string;
video_url: null;
impressions: number;
clicks: number;
seconds: number;
placement_x: null;
}
interface NativeAd {
id: number;
ad_id: string;
ad_type: string;
placement: string;
image_url: string;
iframe_url: null;
click_url: string;
width: number;
height: number;
page: string;
form_factor: string;
video_url: null;
impressions: number;
clicks: number;
seconds: number;
placement_x: string;
}
interface Env {
vhtv_version: number;
premium_coin_cost: number;
mobile_apps: MobileApps;
}
interface MobileApps {
code_name: string;
_build_number: number;
_semver: string;
_md5: string;
_url: string;
}
interface AccountDialog {
is_visible: boolean;
active_tab_id: string;
tabs: Tab[];
}
interface Tab {
id: string;
icon: string;
title: string;
}
interface ContactUsDialog {
is_visible: boolean;
is_video_report: boolean;
subject: string;
email: string;
message: string;
is_sent: boolean;
}
interface GeneralConfirmationDialog {
is_visible: boolean;
is_persistent: boolean;
is_mini_close_button_visible: boolean;
is_cancel_button_visible: boolean;
cancel_button_text: string;
title: string;
body: string;
confirm_button_text: string;
confirmation_callback: null;
}
interface Snackbar {
timeout: number;
context: string;
mode: string;
y: string;
x: string;
is_visible: boolean;
text: string;
}
interface Search {
cache_sorting_config: unknown[];
cache_tags_filter: null;
cache_active_brands: null;
cache_blacklisted_tags_filter: null;
search_text: string;
search_response_payload: null;
total_search_results_count: number;
order_by: string;
ordering: string;
tags_match: string;
page_size: number;
offset: number;
page: number;
number_of_pages: number;
tags: unknown[];
active_tags_count: number;
brands: unknown[];
active_brands_count: number;
blacklisted_tags: unknown[];
active_blacklisted_tags_count: number;
is_using_preferences: boolean;
}
interface HAnimeSearchResult {
id: number;
name: string;
titles: string[];
slug: string;
description: string;
views: number;
interests: number;
bannerImage: string;
coverImage: string;
brand: {
name: string;
id: number;
};
durationMs: number;
isCensored: boolean;
likes: number;
rating: number;
dislikes: number;
downloads: number;
rankMonthly: number;
tags: string[];
createdAt: number;
releasedAt: number;
}
interface HAnimeRawSearchResult {
id: number;
name: string;
titles: string[];
slug: string;
description: string;
views: number;
interests: number;
poster_url: string;
cover_url: string;
brand: string;
brand_id: number;
duration_in_ms: number;
is_censored: boolean;
likes: number;
rating: number;
dislikes: number;
downloads: number;
monthly_rank: number;
tags: string[] | string;
created_at: number;
released_at: number;
}
/**
* Base URL for the Hentai Haven website.
*/
declare const HENTAI_HAVEN_URL = "http://hentaihaven.xxx";
/**
* Client for interacting with the Hentai Haven website.
*/
declare const HentaiHaven: {
new (options?: HentaiHavenOptions): {
/**
* Base URL for API requests.
*/
BASE_URL: string;
/**
* Searches for hentai videos on Hentai Haven based on the provided query.
*
* @param {string} query - The search query string.
* @returns {Promise<HHSearchResult[]>} A promise that resolves to an array of search results.
* @throws {TypeError} If the query is empty or not a string.
*/
search: (query: string) => Promise<HHSearchResult[]>;
/**
* Retrieves detailed information about a hentai series by its ID.
*
* @param {string} id - The unique identifier of the hentai series.
* @param {HHEpisodesSort} [episodeSort="ASC"] - The sort order for episodes (ascending or descending).
* @returns {Promise<HHHentaiInfo>} A promise that resolves to detailed information about the hentai series.
* @throws {Error} If the ID is not provided or if there's an error fetching the data.
*/
getInfo: (id: string, episodeSort?: HHEpisodesSort) => Promise<HHHentaiInfo>;
/**
* Retrieves streaming sources for a specific episode by its ID.
*
* @param {string} id - The encoded episode ID.
* @returns {Promise<HHHentaiSources>} A promise that resolves to the streaming sources for the episode.
* @throws {TypeError} If the ID is invalid or not provided.
* @throws {Error} If the episode ID is not properly encoded.
*/
getEpisode: (id: string) => Promise<HHHentaiSources>;
/**
* Sorts an array of episodes based on the specified sort order.
*
* @param {HHHentaiEpisode[]} episodes - The array of episodes to sort.
* @param {HHEpisodesSort} sortOrder - The sort order to apply ("ASC" for ascending, "DESC" for descending).
*/
sortEpisodes(episodes: HHHentaiEpisode[], sortOrder: HHEpisodesSort): void;
};
};
/**
* Configuration options for the HentaiHaven client.
*/
interface HentaiHavenOptions {
/**
* Custom base URL for the HentaiHaven website.
*/
baseUrl?: string;
}
/**
* Sort order for episodes.
*/
type HHEpisodesSort = "ASC" | "DESC";
/**
* Represents a genre in Hentai Haven.
*/
interface HHGenre {
/**
* Unique identifier for the genre.
*/
id: string;
/**
* URL to the genre page.
*/
url: string;
/**
* Name of the genre.
*/
name: string;
}
/**
* Represents an episode of a hentai series.
*/
interface HHHentaiEpisode {
/**
* Unique identifier for the episode.
*/
id: string;
/**
* Title of the episode.
*/
title: string;
/**
* URL to the episode thumbnail image.
*/
thumbnail?: string;
/**
* Episode number.
*/
number: number;
/**
* Release date in UTC.
*/
releasedUTC: Date;
/**
* Relative time since release (e.g., "2 days ago").
*/
releasedRelative: string;
}
/**
* Detailed information about a hentai series.
*/
interface HHHentaiInfo {
/**
* Unique identifier for the series.
*/
id: string;
/**
* Title of the series.
*/
title: string;
/**
* URL to the cover image.
*/
cover: string;
/**
* Plot summary or description.
*/
summary: string;
/**
* Number of views.
*/
views: number;
/**
* Number of ratings received.
*/
ratingCount: number;
/**
* Year of release.
*/
released: number;
/**
* List of genres associated with the series.
*/
genres: HHGenre[];
/**
* Total number of episodes in the series.
*/
totalEpisodes: number;
/**
* List of episodes in the series.
*/
episodes: HHHentaiEpisode[];
}
/**
* Represents a video source for streaming.
*/
interface HHHentaiSource {
/**
* Label for the video quality or source.
*/
label: string;
/**
* URL to the video source.
*/
src: string;
/**
* MIME type of the video.
*/
type: string;
}
/**
* Collection of video sources for a hentai episode.
*/
interface HHHentaiSources {
/**
* List of available video sources.
*/
sources: HHHentaiSource[];
/**
* URL to the video thumbnail.
*/
thumbnail?: string;
}
/**
* Represents a search result from Hentai Haven.
*/
interface HHSearchResult {
/**
* Unique identifier for the series.
*/
id: string;
/**
* Title of the series.
*/
title: string;
/**
* URL to the cover image.
*/
cover: string;
/**
* Average rating of the series.
*/
rating: number;
/**
* Year of release.
*/
released: number;
/**
* List of genres associated with the series.
*/
genres: HHGenre[];
/**
* Total number of episodes in the series.
*/
totalEpisodes: number;
/**
* Date information.
*/
date: {
/**
* Unparsed date string.
*/
unparsed: string;
/**
* Parsed Date object.
*/
parsed: Date;
};
/**
* Alternative titles.
*/
alternative: string;
/**
* Author or creator of the series.
*/
author: string;
}
declare const HENTAI_STREAM_BASE_URL = "https://tube.hentaistream.com";
/**
* HentaiStream class for interacting with the HentaiStream API
*/
declare const HentaiStream: {
new (options?: HentaiStreamOptions): {
BASE_URL: string;
/**
* Search for anime on HentaiStream
* @param query - The search query
* @returns Promise resolving to an array of search results
* @throws {TypeError} If query is invalid
*/
search: (query: string) => Promise<HStreamResult[]>;
/**
* Get information about a specific episode
* @param id - The episode ID
* @returns Promise resolving to episode information
* @throws {TypeError} If ID is invalid
*/
getInfoEpisode: (id: string) => Promise<HStreamEpisodeInfo>;
/**
* Get detailed information about an anime series
* @param id - The anime ID or title
* @returns Promise resolving to anime information or null if not found
* @throws {TypeError} If ID is invalid
*/
getInfo: (id: string) => Promise<HStreamAnimeInfo | null>;
/**
* Get streaming information for a specific episode
* @param id - The encoded episode ID
* @returns Promise resolving to episode streaming information
* @throws {TypeError} If ID is invalid
* @throws {Error} If streams cannot be fetched
*/
getEpisode: (id: string) => Promise<HStreamEpisodeStream>;
};
};
/**
* Configuration options for HentaiStream
*/
interface HentaiStreamOptions {
baseUrl?: string;
}
/**
* Search result from HentaiStream
*/
interface HStreamResult {
id: string;
title?: string;
views?: number;
image?: string;
releaseDate?: Date | null;
}
/**
* Episode information
*/
interface HStreamEpisodeInfo {
title?: string;
releasedDate?: Date | null;
views?: number;
genres?: string[];
}
/**
* Anime series information
*/
interface HStreamAnimeInfo {
title: string;
image?: string;
genres: string[];
views: number;
episodes: HStreamEpisodeListItem[];
releasedDate?: Date | null;
}
/**
* Episode list item
*/
interface HStreamEpisodeListItem {
id: string;
number?: number | null;
views?: number;
releasedDate?: Date | null;
title?: string;
image?: string;
}
/**
* Episode streaming information
*/
interface HStreamEpisodeStream {
title?: string;
releasedDate?: Date | null;
views?: number;
source?: string;
}
/**
* Base URL for the Rule34 website.
*/
declare const RULE34_BASE_URL = "https://rule34.xxx";
/**
* API URL for Rule34 autocomplete functionality.
*/
declare const RULE34_API_URL = "https://ac.rule34.xxx";
/**
* Class representing a Rule34 client for interacting with the Rule34 website.
*/
declare const Rule34: {
new (options?: R34Options): {
/**
* Base URL for the Rule34 website.
*/
BASE_URL: string;
/**
* API URL for Rule34 autocomplete functionality.
*/
API_URL: string;
/**
* Searches for autocomplete suggestions based on the provided query.
*
* @param {string} query - The search query string.
* @returns {Promise<Array<{completedQuery: string, label: string, type: string}>>} A promise that resolves to an array of autocomplete suggestions.
* @throws {TypeError} If the query is empty or not a string.
*/
searchAutocomplete: (query: string) => Promise<{
completedQuery: string;
label: string;
type: string;
}[]>;
/**
* Searches for images on Rule34 based on the provided query.
*
* @param {string} query - The search query string.
* @param {number} [page=1] - The page number to retrieve (default is 1).
* @param {number} [perPage=10] - The number of results per page (default is 10).
* @returns {Promise<R34SearchResult>} A promise that resolves to a paginated result of search results.
* @throws {TypeError} If the query is empty or not a string.
*/
search: (query: string, page?: number, perPage?: number) => Promise<R34SearchResult>;
/**
* Gets detailed information about a specific image by its ID.
*
* @param {string} id - The ID of the image to retrieve information for.
* @returns {Promise<R34ImageInfo>} A promise that resolves to an object containing detailed information about the image.
*/
getInfo: (id: string) => Promise<R34ImageInfo>;
};
};
/**
* Configuration options for the Rule34 client.
*/
interface R34Options {
/**
* Custom base URL for the Rule34 website.
*/
baseUrl?: string;
/**
* Custom API URL for Rule34 autocomplete functionality.
*/
apiUrl?: string;
}
/**
* Represents a single search result from Rule34.
*/
interface R3SearchResult {
/**
* The unique identifier of the image.
*/
id: string;
/**
* The URL of the image.
*/
image: string;
/**
* Array of tags associated with the image.
*/
tags: string[];
/**
* The type of the result, always "preview" for search results.
*/
type: "preview";
}
/**
* Represents a comment on a Rule34 image.
*/
interface R34Comment {
/**
* The unique identifier of the comment.
*/
id?: string;
/**
* The username of the commenter.
*/
user: string;
/**
* The content of the comment.
*/
comment: string;
}
/**
* Represents size information for a Rule34 image.
*/
interface R34ImageSizes {
/**
* The aspect ratio of the image (e.g., "16:9").
*/
aspect?: string;
/**
* The width of the image in pixels.
*/
width?: number;
/**
* The height of the image in pixels.
*/
height?: number;
/**
* The width of the image in rem units.
*/
widthRem?: number;
/**
* The height of the image in rem units.
*/
heightRem?: number;
/**
* The total number of pixels in the image (width × height).
*/
fullSize?: number;
/**
* The formatted dimensions of the image (e.g., "1920x1080").
*/
formatted?: string;
}
/**
* Represents detailed information about a Rule34 image.
*/
interface R34ImageInfo {
/**
* The unique identifier of the image.
*/
id: string;
/**
* The URL of the full-size image.
*/
fullImage?: string;
/**
* The URL of the resized image.
*/
resizedImageUrl?: string;
/**
* Array of tags associated with the image.
*/
tags?: string[];
/**
* The timestamp when the image was created/posted.
*/
createdAt: number;
/**
* The username of the person who published the image.
*/
publishedBy: string;
/**
* The content rating of the image (e.g., "Safe", "Questionable", "Explicit").
*/
rating: string;
/**
* Size information about the image.
*/
sizes: R34ImageSizes;
/**
* Array of comments on the image.
*/
comments: R34Comment[];
}
/**
* Represents a paginated search result from Rule34.
*/
type R34SearchResult = PaginatedResult<R3SearchResult>;
declare class Dimension {
private width;
private height;
constructor(width: number, height: number);
getAspectRatio(): string;
getWidthInPx(): number;
getHeightInPx(): number;
getWidthInRem(baseFontSize?: number): number;
getHeightInRem(baseFontSize?: number): number;
private gcd;
static fromString(dimensionString: string): Dimension | null;
}
/**
* Extracts the first number from a string.
*
* @param {string} str - The input string to extract a number from.
* @returns {number | null} The first number found in the string, or null if no numbers are found.
* @throws {TypeError} If the input is not a string.
*
* @example
* // Returns 123
* getNumberFromString("abc123def456");
*
* @example
* // Returns null
* getNumberFromString("no numbers here");
*/
declare function getNumberFromString(str: string): number | null;
/**
* Normalizes a string by removing all symbols, special characters, and numbers,
* then converts it to lowercase.
*
* @param {string} str - The input string to normalize.
* @returns {string} The normalized string.
* @throws {TypeError} If the input is not a string.
*
* @example
* // Returns "hello world"
* normalize("Hello World! 123");
*
* @example
* // Returns "just text"
* normalize("Just TEXT! @#$%^&*()");
*/
declare function normalize(str: string): string;
/**
* Removes all numbers from a string.
*
* @param {string} str - The input string to remove numbers from.
* @returns {string} The string with all numbers removed.
* @throws {TypeError} If the input is not a string.
*
* @example
* // Returns "abcdef"
* removeNumberFromString("abc123def456");
*
* @example
* // Returns "no numbers here"
* removeNumberFromString("no numbers here");
*/
declare function removeNumberFromString(str: string): string;
/**
* Applies the ROT13 cipher to a string, shifting each letter 13 positions in the alphabet.
* Non-alphabetic characters remain unchanged.
*
* @param {string} str - The input string to be encoded or decoded with ROT13.
* @returns {string} The ROT13 transformed string.
* @throws {TypeError} If the input is not a string.
*
* @example
* // Returns "uryyb"
* rot13Cipher("hello");
*
* @example
* // Returns "hello"
* rot13Cipher("uryyb");
*
* @example
* // Returns "Uryyb, Jbeyq! 123"
* rot13Cipher("Hello, World! 123");
*/
declare const rot13Cipher: (str: string) => string;
export { type AccountDialog, type Brand, type Bs, type ContactUsDialog, type Data, type DesktopAd, Dimension, type Env, type Footer0, type GeneralConfirmationDialog, HANIME_BASE_URL, HANIME_SEARCH_URL, HANIME_SIGNATURE_GENERATOR, HAnime, type HAnimeOptions, type HAnimeRawSearchResult, type HAnimeSearchResult, type HAnimeStream, type HAnimeVideoInfo, HENTAI_HAVEN_URL, HENTAI_STREAM_BASE_URL, type HHEpisodesSort, type HHGenre, type HHHentaiEpisode, type HHHentaiInfo, type HHHentaiSource, type HHHentaiSources, type HHSearchResult, type HStreamAnimeInfo, type HStreamEpisodeInfo, type HStreamEpisodeListItem, type HStreamEpisodeStream, type HStreamResult, type HanimeResponse, type HentaiFranchise, HentaiHaven, HentaiStream, type HentaiStreamOptions, type HentaiTag, type HentaiVideo, type HentaiVideoEpisode, type HentaiVideoStoryboard, type MobileAd, type MobileApps, type Native0, type Native1, type NativeAd, type Ntv0, type Ntv1, type Ntv2, type R34Comment, type R34ImageInfo, type R34ImageSizes, type R34Options, type R34SearchResult, type R3SearchResult, RULE34_API_URL, RULE34_BASE_URL, Rule34, type Search, type Server, type Snackbar, type State, type Stream, type Tab, type Video, type VideosManifest, getNumberFromString, normalize, removeNumberFromString, rot13Cipher };