packageDocumentation module import fetch , { FetchError } from 'node-fetch' ; import { BooruError , defaultOptions , searchURI } from '../Constants' ; import { jsonfy , resolveSite , shuffle } from '../Utils' ; import InternalSearchParameters from '../structures/InternalSearchParameters' ; import Post from '../structures/Post' ; import SearchParameters from '../structures/SearchParameters' ; import SearchResults from '../structures/SearchResults' ; import Site from '../structures/Site' ; declare const window ; const resolvedFetch = typeof window !== 'undefined' ? window . fetch . bind ( window ) : fetch ; export interface BooruCredentials { token : string ; } interface SearchUrlParams { tags : string [ ] ; limit : number ; page : number ; } example export class Booru { /** The domain of the booru */ public domain : string ; /** The site object representing this booru */ public site : Site ; /** The credentials to use for this booru */ public credentials ? : BooruCredentials ; private param site param credentials constructor ( site , credentials ? ) { const domain = resolveSite ( site . domain ) ; if ( domain === null ) { throw new Error ( `Invalid site passed: ${ site }` ) ; } this . domain = domain ; this . site = site ; this . credentials = credentials ; } param { String | String [ ] } tags param { SearchParameters } searchArgs return { Promise < SearchResults > } public async search ( tags , { limit = 1 , random = false , page = 0 , showUnavailable = false , } = { } ) { const fakeLimit = random && ! this . site . random ? 100 : 0 ; try { const searchResult = await this . doSearchRequest ( tags , { limit , random , page , showUnavailable , } ) ; return this . parseSearchResult ( searchResult , { fakeLimit , tags , limit , random , page , showUnavailable , } ) ; } catch ( err ) { if ( err instanceof Error ) { throw new BooruError ( err ) ; } else { throw err ; } } } param { String } id return { String } public postView ( id ) { if ( typeof id === 'string' && Number . isNaN ( parseInt ( id , 10 ) ) ) { throw new BooruError ( `Not a valid id for postView: ${ id }` ) ; } return `http${ this . site . insecure ? '' : 's' }://${ this . domain }${ this . site . api . postView }${ id }` ; } protected param { String [ ] | String } tags param { InternalSearchParameters } searchArgs return { Promise < Object > } protected async doSearchRequest ( tags , { uri = null , limit = 1 , random = false , page = 0 , } = { } ) { if ( ! Array . isArray ( tags ) ) tags = [ tags ] ; let fakeLimit ; if ( random ) { if ( this . site . random ) { tags . push ( 'order:random' ) ; } else { fakeLimit = 100 ; } } if ( this . site . defaultTags ) { tags = tags . concat ( this . site . defaultTags . filter ( ( v ) => ! tags . includes ( v ) ) ) ; } const fetchuri = uri || this . getSearchUrl ( { tags , limit : fakeLimit || limit , page } ) ; const options = defaultOptions ; const xml = this . site . type === 'xml' ; try { const response = await resolvedFetch ( fetchuri , options ) ; if ( response . status === 503 ) { const body = await response . clone ( ) . text ( ) ; if ( body . includes ( 'cf-browser-verification' ) ) { throw new BooruError ( "Received a CloudFlare browser verification request. Can't proceed." ) ; } } const data = xml ? await response . text ( ) : await response . json ( ) ; const posts = xml ? jsonfy ( data as string ) : data ; if ( ! response . ok ) { throw new BooruError ( `Received HTTP ${ response . status } ` + `from booru: '${ posts . error || posts . message || JSON . stringify ( posts ) }'` ) ; } else { return posts ; } } catch ( err ) { if ( ( err as FetchError ) . type === 'invalid-json' ) return '' ; throw err ; } } param opt param { string [ ] } opt . tags param { number } opt . limit param { number } opt . page returns getSearchUrl ( { tags = [ ] , limit = 100 , page = 1 , } ) { return searchURI ( this . site , tags , limit , page ) ; } protected param { Object } result param { InternalSearchParameters } searchArgs return { SearchResults } protected parseSearchResult ( result , { fakeLimit , tags , limit , random , page , showUnavailable , } ) { if ( result . success === false ) { throw new BooruError ( result . message || result . reason ) ; } if ( result [ '@attributes' ] ) { const attributes = result [ '@attributes' ] ; if ( attributes . count === '0' || ! result . post ) { result = [ ] ; } else if ( Array . isArray ( result . post ) ) { result = result . post ; } else { result = [ result . post ] ; } } if ( result . posts ) { result = result . posts ; } if ( result . images ) { result = result . images ; } let r ; if ( result === '' ) { r = [ ] ; } else if ( fakeLimit ) { r = shuffle ( result ) ; } else if ( result . constructor === Object ) { r = [ result ] ; } const results = r || result ; let posts = results . slice ( 0 , limit ) . map ( ( v ) => new Post ( v , this ) ) ; const options = { limit , random , page , showUnavailable } ; if ( tags === undefined ) { tags = [ ] ; } if ( ! Array . isArray ( tags ) ) { tags = [ tags ] ; } if ( ! showUnavailable ) { posts = posts . filter ( ( p ) => p . available ) ; } return new SearchResults ( posts , tags , options , this ) ; } } export default Booru ;