nhentai-api
Version:
nHentai Node.JS API client.
641 lines (640 loc) • 28.2 kB
JavaScript
import http,{Agent as Agent$1}from"http";import https,{Agent}from"https";function _defineProperty(obj,key,value){return key in obj?Object.defineProperty(obj,key,{value:value,enumerable:!0,configurable:!0,writable:!0}):obj[key]=value,obj}
/**
* @module Tag
*/
/**
* Tag object from API.
* @global
* @typedef {object} APITag
* @property {number|string} id Tag id.
* @property {string} type Tag type.
* @property {string} name Tag name.
* @property {number|string} count Tagged books count.
* @property {string} url Tag URL.
*/
/**
* @typedef {object} TagTypes
* @property {UnknownTagType} Unknown Unknown tag type.
* @property {TagType} Tag Tag tag type.
* @property {TagType} Category Category tag type.
* @property {TagType} Artist Artist tag type.
* @property {TagType} Parody Parody tag type.
* @property {TagType} Character Character tag type.
* @property {TagType} Group Group tag type.
* @property {TagType} Language Language tag type.
*/
/**
* Class representing tag type.
* @class
*/class TagType{
/**
* @type {TagTypes}
* @static
* @default {}
*/
/**
* Tag type name.
* @type {?string}
* @default null
*/
/**
* Create tag type.
* @param {string} type Tag type.
*/
constructor(type){_defineProperty(this,"type",null),type&&(this.type=type,this.constructor.knownTypes[type]=this)}
/**
* Check if this tag type is unknown.
* @type {boolean}
*/get isKnown(){return!(this instanceof UnknownTagType)}
/**
* Tag type name.
* @returns {string}
*/toString(){return this.type}}
/**
* Class representing unknown tag type.
* @class
* @extends TagType
*/_defineProperty(TagType,"knownTypes",{});class UnknownTagType extends TagType{
/**
* Create unknown tag type.
* @param {string} [type="unknown"] Unknown tag type name.
*/
constructor(type="unknown"){super(null),this.type=type}}
/**
* Class representing tag.
* @class
*/class Tag{
/**
* Tag types.
* @type {TagTypes}
* @static
*/
/**
* Warp tag object with Tag class instance.
* @param {APITag|Tag} tag Tag to wrap.
* @returns {Tag} Tag.
* @static
*/
static get(tag){return tag instanceof this||(tag=new this({id:+tag.id,type:tag.type,name:tag.name,count:+tag.count,url:tag.url})),tag}
/**
* Tag ID.
* @type {number}
* @default 0
*/
/**
* Create tag.
* @param {object} [params] Tag parameters.
* @param {number} [params.id=0] Tag id.
* @param {string|TagType} [params.type=TagTypes.Unknown] Tag type.
* @param {string} [params.name=""] Tag name.
* @param {number} [params.count=0] Tagged books count.
* @param {string} [params.url=""] Tag URL.
*/constructor({id:id=0,type:type=this.constructor.types.Unknown,name:name="",count:count=0,url:url=""}={}){_defineProperty(this,"id",0),_defineProperty(this,"type",this.constructor.types.Unknown),_defineProperty(this,"name",""),_defineProperty(this,"count",0),_defineProperty(this,"url",""),Object.assign(this,{id:id,type:type instanceof TagType?type:this.constructor.types.get(type),name:name,count:count,url:url})}
/**
* Compare this to given one.
* By default tags with different id will return false.
* If you want to check whatever tag has any of properties from another tag pass `'any'` to `strict` parameter.
* @param {string|Tag} tag Tag to compare with.
* @param {boolean|string} [strict=false] Whatever all parameters must be the same.
* @returns {boolean} Whatever tags are equal.
*/compare(tag,strict=!1){if(tag=this.constructor.get(tag),"any"===strict)strict=!1;else if(this.id!==tag.id)return!1;return!!["id","type","name","count","url"].map((prop=>tag[prop]===this[prop])).reduce(((accum,current)=>strict?accum*current:accum+current))}
/**
* Get tag name or tag name with count of tagged books.
* @param {?boolean} [includeCount=false] Include count.
* @returns {string}
*/toString(includeCount=!1){return this.name+(includeCount?` (${this.count})`:"")}}_defineProperty(Tag,"types",{Unknown:new UnknownTagType,
// Symbol('unknown')
Tag:new TagType("tag"),Category:new TagType("category"),Artist:new TagType("artist"),Parody:new TagType("parody"),Character:new TagType("character"),Group:new TagType("group"),Language:new TagType("language"),
/**
* Known tag types.
* @type {TagTypes}
*/
known:TagType.knownTypes,
/**
* Get tag type class instance by name.
* @param {string} type Tag type.
* @returns {TagType|UnknownTagType} Tag type class instance.
*/
get(type){let known;return"string"==typeof type&&(type=type.toLowerCase()),(known=this.known[type])?known:new UnknownTagType(type)}});
/**
* Image object from API.
* @global
* @typedef {object} APIImage
* @property {string} t Image type.
* @property {number|string} w Image width.
* @property {number|string} h Image height.
*/
/**
* @typedef {object} ImageTypes
* @property {TagType} JPEG JPEG image type.
* @property {TagType} PNG PNG image type.
* @property {TagType} GIF GIF image type.
*/
/**
* Class representing image type.
* @class
*/
class ImageType{
/**
* @type {ImageTypes}
* @static
* @default {}
*/
/**
* Image type name.
* @type {?string}
* @default null
*/
/**
* Image type extension.
* @type {?string}
* @default null
*/
/**
* Create image type.
* @param {string} type Image type name.
* @param {string} extension Image type extension.
*/
constructor(type,extension){_defineProperty(this,"type",null),_defineProperty(this,"extension",null),type&&(this.type=type,this.constructor.knownTypes[type]=this),this.extension=extension}
/**
* Whatever this tag type is unknown.
* @type {boolean}
*/get isKnown(){return!(this instanceof UnknownImageType)}
/**
* Alias for type.
* @type {?string}
*/get name(){return this.type}}
/**
* Class representing unknown image type.
* @class
* @extends ImageType
*/_defineProperty(ImageType,"knownTypes",{});class UnknownImageType extends ImageType{
/**
* Create unknown image type.
* @param {string} type Unknown image type name.
* @param {string} extension Unknown image type extension.
*/
constructor(type,extension){super(null,extension),this.type=type}}
/**
* Class representing image.
* @class
*/class Image{
/**
* Image types.
* @type {ImageTypes}
* @static
*/
/**
* Parse pure image object from API into class instance.
* @param {APIImage} image Image object
* @param {number} [id=0] Image id (a.k.a. page number).
* @returns {Image} Image instance.
* @static
*/
static parse(image,id=0){let{t:type,w:width,h:height}=image;return new this({type:type,width:+width,height:+height,id:id})}
/**
* Image ID.
* @type {number}
* @default 0
*/
/**
* Create image.
* @param {object} [params] Image parameters.
* @param {number} [params.id=0] Image ID.
* @param {number} [params.width=0] Image width.
* @param {number} [params.height=0] Image height.
* @param {string|ImageType} [params.type=ImageTypes.JPEG] Image type.
* @param {Book} [params.book=Book.Unknown] Image's Book.
*/constructor({id:id=0,width:width=0,height:height=0,type:type=this.constructor.types.JPEG,book:book=Book.Unknown}={}){_defineProperty(this,"id",0),_defineProperty(this,"width",0),_defineProperty(this,"height",0),_defineProperty(this,"type",this.constructor.types.JPEG),_defineProperty(this,"book",Book.Unknown),Object.assign(this,{id:"number"==typeof id?id<1?0:id:0,width:width,height:height,type:type instanceof ImageType?type:this.constructor.types.get(type),book:book instanceof Book?book:Book.Unknown})}
/**
* Whatever this image is book cover.
* @type {boolean}
*/get isCover(){return this.id<1}
/**
* Image filename.
* @type {string}
*/get filename(){return`${this.isCover?"cover":this.id}.${this.type.extension}`}}_defineProperty(Image,"types",{JPEG:new ImageType("jpeg","jpg"),PNG:new ImageType("png","png"),GIF:new ImageType("gif","gif"),Unknown:new UnknownImageType("unknown","unknownExt"),
/**
* Known image types.
* @type {ImageType}
*/
known:ImageType.knownTypes,
/**
* Get image type class instance by name.
* @param {string} type Image type.
* @returns {ImageType|UnknownImageType} Image type class instance.
*/
get(type){let known;if("string"==typeof type)switch(type=type.toLowerCase()){case"j":case"jpg":case"jpeg":type="jpeg";break;case"p":case"png":type="png";break;case"g":case"gif":type="gif"}return(known=this.known[type])?known:new UnknownImageType(type)}});
// eslint-disable-next-line no-unused-vars
/**
* Array of Tags with helper methods.
* @class
* @extends Array<Tag>
*/
class TagsArray extends Array{constructor(...args){super(...args)}
/**
* Get array of tags names.
* @param {?boolean} [includeCount=false] Include count.
* @returns {String[]}
*/toNames(includeCount=!1){return Array.from(this,(tag=>tag.toString(includeCount)))}}
/**
* Book object from API.
* @global
* @typedef {object} APIBook
* @property {object} title Book title.
* @property {string} title.english Book english title.
* @property {string} title.japanese Book japanese title.
* @property {string} title.pretty Book short title.
* @property {number|string} id Book ID.
* @property {number|string} media_id Book Media ID.
* @property {number|string} num_favorites Book favours count.
* @property {number|string} num_pages Book pages count.
* @property {string} scanlator Book scanlator.
* @property {number|string} uploaded Upload UNIX timestamp.
* @property {APIImage} cover Book cover image.
* @property {APIImage[]} images Book pages' images.
* @property {APITag[]} tags Book tags.
*/
/**
* Book title.
* @typedef {object} BookTitle
* @property {string} english Book english title.
* @property {string} japanese Book japanese title.
* @property {string} pretty Book short title.
*/
/**
* Class representing Book.
* @class
*/class Book{
/**
* Unknown book instance.
* @type {UnknownBook}
* @static
*/
/**
* UnknownBook class.
* @type {UnknownBook}
* @static
*/
/**
* Parse book object into class instance.
* @param {APIBook} book Book.
* @returns {Book} Book instance.
* @static
*/
static parse(book){return new this({title:book.title,id:+book.id,media:+book.media_id,favorites:+book.num_favorites,scanlator:book.scanlator,uploaded:new Date(1e3*+book.upload_date),tags:TagsArray.from(book.tags,(tag=>Tag.get(tag))),cover:Image.parse(book.images.cover),pages:book.images.pages.map(((image,id)=>Image.parse(image,++id)))})}
/**
* Book title.
* @type {BookTitle}
*/
/**
* Create book.
* @param {object} [params] Book parameters.
* @param {BookTitle} [params.title] Book title.
* @param {number} [params.id=0] Book ID.
* @param {number} [params.media=0] Book Media ID.
* @param {number} [params.favorites=0] Book favours count.
* @param {string} [params.scanlator=''] Book scanlator.
* @param {Date} [params.uploaded] Book upload date.
* @param {Tag[]|TagsArray} [params.tags=[]] Book tags.
* @param {Image} [params.cover] Book cover.
* @param {Image[]} [params.pages=[]] Book pages.
*/constructor({title:title={english:"",japanese:"",pretty:""},id:id=0,media:media=0,favorites:favorites=0,scanlator:scanlator="",uploaded:uploaded=new Date(0),tags:tags=new TagsArray,cover:cover=new Image({id:0,book:this}),pages:pages=[]}={}){_defineProperty(this,"title",{english:"",japanese:"",pretty:""}),_defineProperty(this,"id",0),_defineProperty(this,"media",0),_defineProperty(this,"favorites",0),_defineProperty(this,"scanlator",""),_defineProperty(this,"uploaded",new Date(0)),_defineProperty(this,"tags",new TagsArray),_defineProperty(this,"cover",new Image({id:0,book:this})),_defineProperty(this,"pages",[]),this.setCover(cover),Array.isArray(pages)&&pages.forEach(this.pushPage.bind(this)),Array.isArray(tags)&&tags.forEach(this.pushTag.bind(this)),Object.assign(this,{title:title,id:id,media:media,favorites:favorites,scanlator:scanlator,uploaded:uploaded})}
/**
* Check whatever book is known.
* @type {boolean}
*/get isKnown(){return!(this instanceof UnknownBook)}
/**
* Set book cover image.
* @param {Image} cover Image.
* @returns {boolean} Whatever cover was set.
* @private
*/setCover(cover){return cover instanceof Image&&(cover.book=this,this.cover=cover,!0)}
/**
* Push image to book pages.
* @param {Image} page Image.
* @returns {boolean} Whatever page was added.
* @private
*/pushPage(page){return page instanceof Image&&(page.book=this,this.pages.push(page),!0)}
/**
* Push tag to book tags.
* @param {Tag} tag Tag.
* @returns {boolean} Whatever tag was added.
* @private
*/pushTag(tag){return tag=Tag.get(tag),!this.hasTag(tag)&&(this.tags.push(tag),!0)}
/**
* Check if book has certain tag.
* @param {Tag} tag Tag
* @param {boolean} [strict=false] Strict comparison.
*/hasTag(tag,strict=!0){return tag=Tag.get(tag),this.tags.some((elem=>elem.compare(tag,strict)))}
/**
* Check if book has any tags with certain properties.
* @param {object|Tag} tag Tag.
*/hasTagWith(tag){return this.hasTag(tag,"any")}
/**
* Get any tags with certain properties.
* @param {object|Tag} tag Tag.
* @returns {TagsArray}
*/getTagsWith(tag){return tag=Tag.get(tag),this.tags.filter((elem=>elem.compare(tag,"any")))}
/**
* Pure tags (with type {TagType.Tag}).
* @type {Tag[]}
*/get pureTags(){return this.getTagsWith({type:TagTypes.Tag})}
/**
* Category tags.
* @type {Tag[]}
*/get categories(){return this.getTagsWith({type:TagTypes.Category})}
/**
* Artist tags.
* @type {Tag[]}
*/get artists(){return this.getTagsWith({type:TagTypes.Artist})}
/**
* Parody tags.
* @type {Tag[]}
*/get parodies(){return this.getTagsWith({type:TagTypes.Parody})}
/**
* Character tags.
* @type {Tag[]}
*/get characters(){return this.getTagsWith({type:TagTypes.Character})}
/**
* Group tags.
* @type {Tag[]}
*/get groups(){return this.getTagsWith({type:TagTypes.Group})}
/**
* Language tags.
* @type {Tag[]}
*/get languages(){return this.getTagsWith({type:TagTypes.Language})}}
/**
* Class representing unknown book.
* @class
* @extends Book
*/_defineProperty(Book,"Unknown",void 0),_defineProperty(Book,"UnknownBook",void 0);class UnknownBook extends Book{
/**
* Create unknown book.
*/
constructor(){super({})}}Book.UnknownBook=UnknownBook,Book.Unknown=new UnknownBook;
/**
* Search object from API.
* @global
* @typedef {object} APISearch
* @property {APIBook[]} result Search results.
* @property {number|string} num_pages Number of search pages available.
* @property {number|string} per_page Number of books per page.
*/
/**
* @typedef {''|'popular'|'popular-week'|'popular-today'|'popular-month'} SearchSortMode
*/
class SearchSort{}
/**
* Class representing search request results.
* @class
*/_defineProperty(SearchSort,"Recent",""),_defineProperty(SearchSort,"Popular","popular"),_defineProperty(SearchSort,"PopularMonth","popular-month"),_defineProperty(SearchSort,"PopularWeek","popular-week"),_defineProperty(SearchSort,"PopularToday","poplar-today");class Search{
/**
* Parse search object into class instance.
* @param {APISearch} search Search object.
*/
static parse(search){return new this({pages:search.num_pages?+search.num_pages:1,perPage:search.per_page?+search.per_page:search.result.length,books:search.result.map(Book.parse.bind(Book))})}
/**
* API instance.
* @type {?API}
* @default null
*/
/**
* Create search.
* @param {?object} [params] Search parameters.
* @param {?string} [params.query=''] Query string.
* @param {?SearchSortMode} [params.sort=''] Search sort mode.
* @param {?number} [params.page=1] Search page ID.
* @param {?number} [params.pages=1] Search pages count.
* @param {?number} [params.perPage=0] Search books per page.
* @param {?Book[]} [params.books=[]] Books array.
*/constructor({query:query=null,sort:sort="",page:page=1,pages:pages=1,perPage:perPage=0,books:books=[]}={}){_defineProperty(this,"api",null),_defineProperty(this,"query",null),_defineProperty(this,"sort",""),_defineProperty(this,"page",1),_defineProperty(this,"perPage",0),_defineProperty(this,"books",[]),_defineProperty(this,"pages",1),Array.isArray(books)&&books.forEach(this.pushBook.bind(this)),Object.assign(this,{query:query,sort:sort,page:page,pages:pages,perPage:perPage})}
/**
* Push book to books array.
* @param {Book} book Book.
* @returns {boolean} Whatever was book added or not.
* @private
*/pushBook(book){return book instanceof Book&&(this.books.push(book),!0)}
/**
* Request next page.
* @throws Error if search request can't be paginated.
* @throws Error if `api` is missing as instance property or function argument.
* @param {API} [api=this.api] API instance.
* @returns {Promise<Search>} Next page search.
*/getNextPage(api=this.api){let{query:query,page:page,sort:sort}=this;if(null===query)throw Error("pagination impossible.");if(!(api instanceof API))throw Error("api must exists.");return query instanceof Tag?api.searchTagged(query,page+1,sort):api.search(query,page+1,sort)}}
/**
* Agent-like object or Agent class or it's instance.
* @global
* @typedef {object|Agent|SSLAgent} httpAgent
*/
/**
* Common nHentai API hosts object.
* @global
* @typedef {object} nHentaiHosts
* @property {?string} api Main API host.
* @property {?string} images Media API host.
* @property {?string} thumbs Media thumbnails API host.
*/
/**
* Common nHentai options object.
* @global
* @typedef {object} nHentaiOptions
* @property {?nHentaiHosts} hosts Hosts.
* @property {?boolean} ssl Prefer HTTPS over HTTP.
* @property {?httpAgent} agent HTTP(S) agent.
*/
/**
* Applies provided options on top of defaults.
* @param {?nHentaiOptions} [options={}] Options to apply.
* @returns {nHentaiOptions} Unified options.
*/class APIError extends Error{
/**
* Original error.
* @type {?Error}
* @default null
*/
/**
* HTTP response.
* @type {IncomingMessage}
* @default null
*/
/**
* Error message.
* @param {string} message Message.
*/
constructor(message="Unknown error"){super(message),_defineProperty(this,"originalError",null),_defineProperty(this,"httpResponse",null)}
/**
* Absorb error.
* @param {Error} [error=null] Original error.
* @param {?IncomingMessage} [httpResponse=null] HTTP response.
* @returns {APIError}
*/static absorb(error,httpResponse=null){return Object.assign(new APIError(error.message),{originalError:error,httpResponse:httpResponse})}}
/**
* API arguments
* @typedef {object} APIArgs
* @property {string} host API host.
* @property {Function} apiPath API endpoint URL path generator.
*/
/**
* Class used for building URL paths to nHentai API endpoints.
* This class is internal and has only static methods.
* @class
*/
/**
* Class used for interaction with nHentai API.
* @class
*/
class API{
/**
* API path class
* @type {APIPath}
* @static
* @private
*/
/**
* Hosts
* @type {?nHentaiHosts}
*/
/**
* Prefer HTTPS over HTTP.
* @type {?boolean}
*/
/**
* HTTP(S) agent.
* @property {?httpAgent}
*/
/**
* Applies provided options on top of defaults.
* @param {?nHentaiOptions} [options={}] Options to apply.
*/
constructor(options={}){_defineProperty(this,"hosts",void 0),_defineProperty(this,"ssl",void 0),_defineProperty(this,"agent",void 0);let params=function processOptions({hosts:{api:api="nhentai.net",images:images="i.nhentai.net",thumbs:thumbs="t.nhentai.net"}={},ssl:ssl=!0,agent:agent=null}={}){return agent||(agent=ssl?Agent:Agent$1),"Function"===agent.constructor.name&&(agent=new agent),{hosts:{api:api,images:images,thumbs:thumbs},ssl:ssl,agent:agent}}(options);Object.assign(this,params)}
/**
* Get http(s) module depending on `options.ssl`.
* @type {https|http}
*/get net(){return this.ssl?https:http}
/**
* JSON get request.
* @param {object} options HTTP(S) request options.
* @param {string} options.host Host.
* @param {string} options.path Path.
* @returns {Promise<object>} Parsed JSON.
*/request(options){let{net:net,agent:agent}=this;return new Promise(((resolve,reject)=>{Object.assign(options,{agent:agent,headers:{"User-Agent":`nhentai-api-client/3.4.3 Node.js/${process.versions.node}`}}),net.get(options,(_response=>{const
/** @type {IncomingMessage}*/
response=_response,{statusCode:statusCode}=response,contentType=response.headers["content-type"];let error;if(200!==statusCode?error=new Error(`Request failed with status code ${statusCode}`):/^application\/json/.test(contentType)||(error=new Error(`Invalid content-type - expected application/json but received ${contentType}`)),error)return response.resume(),void reject(APIError.absorb(error,response));response.setEncoding("utf8");let rawData="";response.on("data",(chunk=>rawData+=chunk)),response.on("end",(()=>{try{resolve(JSON.parse(rawData))}catch(error){reject(APIError.absorb(error,response))}}))})).on("error",(error=>reject(APIError.absorb(error))))}))}
/**
* Get API arguments.
* This is internal method.
* @param {string} hostType Host type.
* @param {string} api Endpoint type.
* @returns {APIArgs} API arguments.
* @private
*/getAPIArgs(hostType,api){let{hosts:{[hostType]:host},constructor:{APIPath:{[api]:apiPath}}}=this;return{host:host,apiPath:apiPath}}
/**
* Search by query.
* @param {string} query Query.
* @param {?number} [page=1] Page ID.
* @param {?SearchSortMode} [sort=''] Search sort mode.
* @returns {Promise<Search>} Search instance.
* @async
*/async search(query,page=1,sort=""){let{host:host,apiPath:apiPath}=this.getAPIArgs("api","search"),search=Search.parse(await this.request({host:host,path:apiPath(query,page,sort)}));return Object.assign(search,{api:this,query:query,page:page,sort:sort}),search}
/**
* Search by query.
* @param {string} query Query.
* @param {?number} [page=1] Starting page ID.
* @param {?SearchSortMode} [sort=''] Search sort mode.
* @yields {Search} Search instance.
* @async
* @returns {AsyncGenerator<Search, Search, Search>}
*/async*searchGenerator(query,page=1,sort=""){let search=await this.search(query,page,sort);for(;search.page<=search.pages;)yield search,search=await this.search(query,search.page+1,sort)}
/**
* Search related books.
* @param {number|Book} book Book instance or Book ID.
* @returns {Promise<Search>} Search instance.
* @async
*/async searchAlike(book){let{host:host,apiPath:apiPath}=this.getAPIArgs("api","searchAlike");return Search.parse(await this.request({host:host,path:apiPath(book instanceof Book?book.id:+book)}))}
/**
* Search by tag id.
* @param {number|Tag} tag Tag or Tag ID.
* @param {?number} [page=1] Page ID.
* @param {?SearchSortMode} [sort=''] Search sort mode.
* @returns {Promise<Search>} Search instance.
* @async
*/async searchTagged(tag,page=1,sort=""){tag instanceof Tag||(tag=Tag.get({id:+tag}));let{host:host,apiPath:apiPath}=this.getAPIArgs("api","searchTagged"),search=Search.parse(await this.request({host:host,path:apiPath(tag.id,page,sort)}));return Object.assign(search,{api:this,query:tag,page:page,sort:sort}),search}
/**
* Get book by id.
* @param {number} bookID Book ID.
* @returns {Promise<Book>} Book instance.
* @async
*/async getBook(bookID){let{host:host,apiPath:apiPath}=this.getAPIArgs("api","book");return Book.parse(await this.request({host:host,path:apiPath(bookID)}))}
/**
* Get random book.
* @returns {Promise<Book>} Book instance.
* @async
*/async getRandomBook(){let{host:host,apiPath:apiPath}=this.getAPIArgs("api","randomBookRedirect");try{await this.request({host:host,path:apiPath()});// Will always throw
}catch(error){if(!(error instanceof APIError))throw error;const response=error.httpResponse;if(!response||302!==response.statusCode)throw error;const id=+(/\d+/.exec(response.headers.location)||{})[0];if(isNaN(id))throw APIError.absorb(new Error("Bad redirect"),response);return await this.getBook(id)}}
/**
* Get image URL.
* @param {Image} image Image.
* @returns {string} Image URL.
*/getImageURL(image){if(image instanceof Image){let{host:host,apiPath:apiPath}=image.isCover?this.getAPIArgs("thumbs","bookCover"):this.getAPIArgs("images","bookPage");return`http${this.ssl?"s":""}://${host}`+(image.isCover?apiPath(image.book.media,image.type.extension):apiPath(image.book.media,image.id,image.type.extension))}throw new Error("image must be Image instance.")}
/**
* Get image thumbnail URL.
* @param {Image} image Image.
* @returns {string} Image thumbnail URL.
*/getThumbURL(image){if(image instanceof Image&&!image.isCover){let{host:host,apiPath:apiPath}=this.getAPIArgs("thumbs","bookThumb");return`http${this.ssl?"s":""}://${host}`+apiPath(image.book.media,image.id,image.type.extension)}throw new Error("image must be Image instance and not book cover.")}}_defineProperty(API,"APIPath",class APIPath{
/**
* Search by query endpoint.
* @param {string} query Search query.
* @param {?number} [page=1] Page ID.
* @param {?SearchSortMode} [sort=''] Search sort mode.
* @returns {string} URL path.
*/
static search(query,page=1,sort=""){return`/api/galleries/search?query=${query}&page=${page}${sort?"&sort="+sort:""}`}
/**
* Search by tag endpoint.
* @param {number} tagID Tag ID.
* @param {?number} [page=1] Page ID.
* @returns {string} URL path.
*/static searchTagged(tagID,page=1){return`/api/galleries/tagged?tag_id=${tagID}&page=${page}`}
/**
* Search alike endpoint.
* @param {number} bookID Book ID.
* @returns {string} URL path.
*/static searchAlike(bookID){return`/api/gallery/${bookID}/related`}
/**
* Book content endpoint.
* @param {number} bookID Book ID.
* @returns {string} URL path.
*/static book(bookID){return`/api/gallery/${bookID}`}
/**
* Book's cover image endpoint.
* @param {number} mediaID Media ID.
* @param {string} extension Image extension.
* @returns {string} URL path.
*/static bookCover(mediaID,extension){return`/galleries/${mediaID}/cover.${extension}`}
/**
* Book's page image endpoint.
* @param {number} mediaID Media ID.
* @param {number} page Page ID.
* @param {string} extension Image extension.
* @returns {string} URL path.
*/static bookPage(mediaID,page,extension){return`/galleries/${mediaID}/${page}.${extension}`}
/**
* Book's page's thumbnail image endpoint.
* @param {number} mediaID Media ID.
* @param {number} page Page ID.
* @param {string} extension Image extension.
* @returns {string} URL path.
*/static bookThumb(mediaID,page,extension){return`/galleries/${mediaID}/${page}t.${extension}`}
/**
* Redirect to random book at website.
* @returns {string} URL path.
*/static randomBookRedirect(){return"/random/"}});
/**
* @typedef { TagTypes } TagTypes
*/
/**
* @type {TagTypes}
*/
const TagTypes={Unknown:Tag.types.Unknown,Tag:Tag.types.Tag,Category:Tag.types.Category,Artist:Tag.types.Artist,Parody:Tag.types.Parody,Character:Tag.types.Character,Group:Tag.types.Group,Language:Tag.types.Language};export{API,Book,Image,Search,SearchSort,Tag,TagTypes};
//# sourceMappingURL=bundle.mjs.map