nyaa.si-client
Version:
<div align="center">
439 lines (434 loc) • 14.2 kB
text/typescript
// Generated by dts-bundle-generator v9.5.1
import { AxiosInstance } from 'axios';
import { Browser, Page } from 'puppeteer';
import UserAgent from 'user-agents';
export declare abstract class Method<RunTime extends RunTimes, const in out AdditionalDetails extends (DetailsOptions | boolean) = false> {
readonly job: Job<RunTime>;
readonly url: string;
readonly loadAdditionalInfo: AdditionalDetails;
constructor({ job, url, loadAdditionalInfo }: MethodOptions<RunTime, AdditionalDetails>);
abstract extract(params: string): Promise<ListData<AdditionalDetails>>;
abstract details<AdditionalDetails extends (DetailsOptions | boolean)>(id: number | string | TorrentData, options?: AdditionalDetails): Promise<MapDetailsOptions<AdditionalDetails>>;
}
export declare class Cheerio<RunTime extends RunTimes.Cheerio, const in out AdditionalDetails extends (DetailsOptions | boolean) = false> extends Method<RunTime, AdditionalDetails> {
extract(params: string): Promise<ListData<AdditionalDetails>>;
details<AdditionalDetails extends (DetailsOptions | boolean)>(url: string, options?: AdditionalDetails): Promise<MapDetailsOptions<AdditionalDetails>>;
static parseTorrentComponents(parent: string | null): (FileEntity | FolderEntity)[];
static parseSizeToBytes(sizeString: string): number;
static extractPageNumber(url: string): number | undefined;
}
export declare class Client<const in out RunTime extends RunTimes = RunTimes.Cheerio> {
static session: SessionManager;
readonly runTime: RunTime;
browser: BrowserInstance<RunTime>;
readonly jobs: Map<string, Job<RunTime>>;
readonly timeout: number;
readonly showNavigator: boolean;
readonly concurrentJobs: number;
readonly requestQueue: ((job: Job<RunTime>) => void)[];
private host;
private readonly emitter;
on<K extends keyof JobEvents<RunTime>>(event: K, listener: (...args: JobEvents<RunTime>[K]) => void): void;
emit<K extends keyof JobEvents<RunTime>>(event: K, ...args: JobEvents<RunTime>[K]): void;
constructor(options?: ClientOptions<RunTime>);
initialize(): Promise<void>;
setupPuppeteer(): Promise<this>;
setupCheerio(): this;
set setURL(url: string);
getURL(): string;
newAxiosInstance(): {
instance: import("axios").AxiosInstance;
instanceId: string;
};
newPage(): Promise<{
page: import("puppeteer").Page;
pageId: string;
}>;
requestJob(): Promise<Job<RunTime>>;
private setupQueueListener;
}
export declare class Exporter<AdditionalDetails extends (DetailsOptions | boolean), RunTime extends RunTimes> {
private scraper;
private search;
private data;
constructor(options: ExporterProps<AdditionalDetails, RunTime>);
getData(): ListData<AdditionalDetails>;
private setData;
addNextPage(loadPages?: number): Promise<this>;
getNextPage(loadPages?: number): Promise<Exporter<AdditionalDetails, RunTime>>;
}
export declare class Job<RunTime extends RunTimes> {
id: string;
status: JobStatus;
readonly timeout: number;
readonly runTime: RunTime;
api: RunTimeAPI<RunTime>;
client: Client<RunTime>;
constructor({ runTime, timeout, client, api, id }: JobProps<RunTime>);
finishedTask(): Promise<void>;
stop(): void;
}
export declare class Puppeteer<RunTime extends RunTimes.Puppeteer, const in out AdditionalDetails extends (DetailsOptions | boolean) = false> extends Method<RunTime, AdditionalDetails> {
extract(params: string): Promise<ListData<AdditionalDetails>>;
details<AdditionalDetails extends (DetailsOptions | boolean)>(id: number | string | TorrentData, options?: AdditionalDetails): Promise<MapDetailsOptions<AdditionalDetails>>;
private waitForConnect;
}
export declare class Scraper<AdditionalDetails extends (DetailsOptions | boolean), RunTime extends RunTimes> {
readonly pagesToLoad: number;
readonly loadAdditionalInfo: AdditionalDetails;
readonly client: Client<RunTime>;
constructor(options: ({
client: Client<RunTime>;
}) & ScraperProps<AdditionalDetails>);
search<PageNumber extends number | undefined = undefined>(content: string, options?: {
filter?: FilterParams;
page?: PageNumber;
loadOnlyPage?: PageNumber extends number ? boolean : never;
}, cache?: Exporter<AdditionalDetails, RunTime>): Promise<Exporter<AdditionalDetails, RunTime>>;
/**
* @example
*
* const scraper = new Scraper()
*
* await scraper.details(1918530)
* await scraper.details('1918530')
* await scraper.details('https://nyaa.si/view/1918530')
*
* const extract = await scraper.search('re: zero')
* scraper.details(extract.getData().torrents[0])
*
* @public
* @param {(number | string | TorrentData)} id - Identifier for the torrent (ID, URL, or object).
* @param {DetailsOptions} options - Options for fetching details.
*/
details(id: number | string | TorrentData, options?: AdditionalDetails): Promise<MapDetailsOptions<AdditionalDetails>>;
static getSearchParams(content: string, page?: number | undefined, filter?: FilterParams): string;
/**
* Normalizes various input types into a numeric ID.
*
* @private
* @param {(number | string | TorrentData)} id - Input data to normalize.
* @returns {(number | null)} - Normalized numeric ID, or `null` if invalid.
*/
static normalizeId(id: number | string | TorrentData): number | null;
/**
* Extracts the Id from a url
*
* @example
*
* Scraper.extractId('https://nyaa.si/view/1918510') // 1918510
*
* @param {string} url
* @returns {*}
*/
static extractId(url: string): number | undefined;
}
export declare class SessionManager {
private options?;
private sessions;
constructor(options?: SessionOptions | undefined);
create(id: string, filter?: SessionOptions["userAgentOptions"]): string;
get(id: string): string | undefined;
createOrGet(id: string, filter?: SessionOptions["userAgentOptions"]): string;
clear(id: string): boolean;
}
export declare class TypedEventEmitter<Events extends Record<string, unknown[]>> {
private readonly emitter;
on<K extends keyof Events>(event: K, listener: (...args: Events[K]) => void): this;
emit<K extends keyof Events>(event: K, ...args: Events[K]): boolean;
off<K extends keyof Events>(event: K, listener: (...args: Events[K]) => void): this;
}
export declare const FilterObject: {
readonly anime: readonly [
"anime_music_video",
"english_translated",
"non_english_translated",
"raw"
];
readonly audio: readonly [
"lossless",
"lossy"
];
readonly literature: readonly [
"english_translated",
"non_english_translated",
"raw"
];
readonly live_action: readonly [
"english_translated",
"idol_promotional_video",
"non_english_translated",
"raw"
];
readonly pictures: readonly [
"graphics",
"photos"
];
readonly software: readonly [
"applications",
"games"
];
};
export declare enum DataTypes {
List = "list",
Details = "details"
}
export declare enum ElementPropertyTypes {
TextContent = "textContent",
Href = "href",
GetAttribute = "getAttribute"
}
export declare enum FileEntityType {
File = "file",
Folder = "folder"
}
export declare enum Filters {
/**
* All torrents.
*/
NoFilter = 0,
/**
* entries (remake) are torrents that match any of the following:
* -> Reencode of original release.
* -> Remux of another uploader's original release for hardsubbing and/or fixing purposes.
* -> Reupload of original release using non-original file names.
* -> Reupload of original release with missing and/or unrelated additional files.
*/
NoRemakes = 1,
/**
* Torrents uploaded by trusted users.
*/
TrustedOnly = 2
}
export declare enum JobStatus {
Reserved = "reserved",
Listening = "listening",
Dead = "dead"
}
export declare enum RunTimes {
Puppeteer = "puppeteer",
Cheerio = "cheerio"
}
export type BrowserInstance<RunTime extends RunTimes> = RunTime extends RunTimes.Puppeteer ? Browser : never;
export type ClientOptions<RunTime extends RunTimes> = {
session?: SessionManager;
/**
* Total number of pages to be processed in parallel
*
* @default 1
*/
concurrentJobs?: number;
/**
* This limits the time for the next job request, I don't recommend decreasing this to less than 3000 ms
*
* @default 3000
*/
timeout?: number;
runTime?: RunTime;
/**
* Shows the browser and the actions being taken to perform webscraping
*
* @default false
*/
showNavigator?: RunTime extends RunTimes.Puppeteer ? boolean : never;
};
export type ConditionalField<T, K extends keyof T, Condition> = Condition extends true | string ? Pick<T, K> : OptionalField<T, K>;
export type DetailsEntity = {
type: DataTypes.Details;
description: string;
submitter: Submitter;
information: string;
files: (FileEntity | FolderEntity)[];
comments: Comment$1[];
};
export type DetailsOptions = {
/**
* @default 'markdown'
* @type {?(boolean | 'markdown' | 'html' | 'text')}
*/
description?: boolean | "markdown" | "html" | "text";
submitter?: boolean | undefined;
information?: boolean;
files?: boolean;
comments?: boolean;
};
export type ElementGetAttribute = {
type: ElementPropertyTypes.GetAttribute;
attributeName: string;
element: HTMLElement;
};
export type ElementHref = {
type: ElementPropertyTypes.Href;
element: HTMLAnchorElement;
};
export type ElementPropertyOptions = (ElementHref | ElementTextContent | ElementGetAttribute);
export type ElementSelector = {
row: Element;
selector: string;
subSelector?: string;
};
export type ElementTextContent = {
type: ElementPropertyTypes.TextContent;
element: HTMLElement;
};
export type ExporterProps<AdditionalDetails extends (DetailsOptions | boolean), RunTime extends RunTimes> = {
scraper: Scraper<AdditionalDetails, RunTime>;
search: {
content: string;
filter?: FilterParams;
};
data: ListData<AdditionalDetails>;
};
export type FileEntity = {
type: FileEntityType.File;
/**
* The name of the file.
*/
fileName: string;
/**
* The size of the file as a human-readable string (e.g., "1 MiB").
*/
readableSize: string;
/**
* The size of the file in bytes.
*/
sizeInBytes: number;
};
export type FilterKeys = keyof FilterSearch;
export type FilterParams = {
category?: FilterSearchPaths;
/**
* @default Filters.NoFilter
*/
filter?: Filters;
};
export type FilterSearch = typeof FilterObject;
export type FilterSearchPaths = NestedKeys<FilterSearch>;
export type FilterValues = FilterSearch[keyof FilterSearch][number];
export type FolderEntity = {
type: FileEntityType.Folder;
/**
* The name of the folder.
*/
name: string;
/**
* The list of files contained within the folder.
*/
files: (FileEntity | FolderEntity)[];
};
export type JobEvents<RunTime extends RunTimes> = {
died: [
Omit<Job<RunTime>, "create" | "finishedTask">
];
started: [
Omit<Job<RunTime>, "create" | "finishedTask">
];
reserved: [
Omit<Job<RunTime>, "create" | "finishedTask">
];
listening: [
Omit<Job<RunTime>, "create" | "finishedTask">
];
};
export type JobProps<RunTime extends RunTimes> = {
id: string;
api: RunTimeAPI<RunTime>;
client: Client<RunTime>;
timeout: number;
runTime: RunTime;
};
export type ListData<AdditionalDetails extends (DetailsOptions | boolean)> = {
type: DataTypes.List;
metadata: {
hasPreviousPage: boolean;
previousPage?: number;
previousPageLink?: string;
hasNextPage: boolean;
nextPage?: number;
nextPageLink?: string;
current: number;
total: number;
timestamp: number;
timeTaken: number;
};
count: number;
torrents: (AdditionalDetails extends (DetailsOptions | boolean) ? TorrentDataWithDetails<AdditionalDetails> : TorrentData)[];
};
export type MapDetailsOptions<AdditionalDetails extends (DetailsOptions | boolean)> = {
type: DataTypes.Details;
} & (AdditionalDetails extends true ? DetailsEntity : AdditionalDetails extends DetailsOptions ? ConditionalField<DetailsEntity, "description", AdditionalDetails["description"]> & ConditionalField<DetailsEntity, "submitter", AdditionalDetails["submitter"]> & ConditionalField<DetailsEntity, "information", AdditionalDetails["information"]> & ConditionalField<DetailsEntity, "files", AdditionalDetails["files"]> & ConditionalField<DetailsEntity, "comments", AdditionalDetails["comments"]> & ConditionalField<DetailsEntity, "description", AdditionalDetails["description"]> : undefined);
export type MethodOptions<RunTime extends RunTimes, AdditionalDetails extends (DetailsOptions | boolean)> = {
job: Job<RunTime>;
url: string;
loadAdditionalInfo: AdditionalDetails;
};
export type NestedKeys<T> = T extends readonly unknown[] ? T[number] & string : T extends Record<string, unknown> ? {
[K in keyof T]: `${K & string}` | `${K & string}.${NestedKeys<T[K]>}`;
}[keyof T] : never;
export type OptionalField<T, K extends keyof T> = {
[P in K]?: T[P];
};
export type RunTimeAPI<RunTime extends RunTimes> = RunTime extends RunTimes.Puppeteer ? Page : AxiosInstance;
export type ScraperProps<AdditionalDetails extends (DetailsOptions | boolean)> = {
/**
* How many pages will be loaded for web scraping, each page has 75 torrents
*
* @default 1
*/
pagesToLoad?: number;
/**
* This carries additional information such as:
* description, submitter, information, files, comments
*
* But it results in 75 requests per page, so I don't recommend using it!
* @default false
*/
loadAdditionalInfo: AdditionalDetails | DetailsOptions;
};
export type SessionOptions = {
/**
* @link https://www.npmjs.com/package/user-agents
*/
userAgentOptions?: Partial<UserAgent["data"]>;
/**
* If not defined, it will generate a userAgent on every call (recommended)
*/
defaultUserAgent?: string;
};
export type Submitter = {
name: string;
url: string;
};
export type TorrentData = {
id: number;
hash: string;
name: string;
timestamp: number;
size: string;
category: string;
links: {
page: string;
magnet: string;
torrent: string;
};
stats: {
seeders: number;
leechers: number;
downloaded: number;
};
};
export type TorrentDataWithDetails<AdditionalDetails extends (DetailsOptions | boolean)> = {
details: MapDetailsOptions<AdditionalDetails>;
} & TorrentData;
type Comment$1 = {
userName: string;
avatarURL: string;
timestamp: number;
publishDate: string;
message: string;
isUploader: boolean;
};
export {
Comment$1 as Comment,
};
export {};