import { Response } from 'node-fetch' ; import { JSDOM } from 'jsdom' ; import contentDisposition from 'content-disposition' ; import fs from 'fs' ; import { CssSelectors , doRequest , getEntries , Entry } from './search-api' ; export const findDownloadURL = async ( mirrorURL , onErr , errorTolarance , delay ) : Promise < string | null > => { const response = await doRequest ( mirrorURL , onErr , errorTolarance , delay ) ; if ( response == null ) return null ; const plainText = await response . text ( ) ; const document = new JSDOM ( plainText ) . window . document ; return document . querySelector ( CssSelectors . downloadURL ) ?. getAttribute ( 'href' ) || null ; } ; export const startDownloading = ( endpoint , errorTolarance , delay , onErr , onData , onEnd ) : Promise < true | null > => ( new Promise ( async ( resolve ) => { const downloadResponse = await doRequest ( endpoint , onErr , errorTolarance , delay ) ; if ( ! downloadResponse ) resolve ( null ) ; let responseContentDisposition = '' ; try { responseContentDisposition = downloadResponse ?. headers . get ( 'content-disposition' ) || '' ; } catch ( e ) { resolve ( null ) ; } const parsedContentDisposition = contentDisposition . parse ( responseContentDisposition ) ; if ( parsedContentDisposition . type != 'attachment' ) { resolve ( null ) ; } if ( Buffer . byteLength ( parsedContentDisposition . parameters . filename , 'utf8' ) > 255 ) { const contLen = parsedContentDisposition . parameters . filename . length ; parsedContentDisposition . parameters . filename = parsedContentDisposition . parameters . filename . substring ( contLen - 100 , contLen ) ; } const path = `./${ parsedContentDisposition . parameters . filename }` ; const file = fs . createWriteStream ( path ) ; const total = Number ( downloadResponse ?. headers . get ( 'content-length' ) || 0 ) ; const filename = parsedContentDisposition . parameters . filename ; downloadResponse ?. body . on ( 'data' , chunk => { onData ( chunk . length , total , filename ) ; } ) ; downloadResponse ?. body . on ( 'finish' , ( ) => { onEnd ( filename ) ; resolve ( true ) ; } ) ; downloadResponse ?. body . on ( 'error' , ( ) => { resolve ( null ) ; } ) ; downloadResponse ?. body . pipe ( file ) ; } ) ) ; export const findDownloadMirror = async ( mirror , searchByMD5Pattern , md5 , onErr , errorTolarance , delay ) : Promise < string | null > => { const reqURL = searchByMD5Pattern . replace ( '{mirror}' , mirror ) . replace ( '{md5}' , md5 ) ; const response = await doRequest ( reqURL , onErr , errorTolarance , delay ) ; if ( response == null ) return null ; const plainText = await response . text ( ) ; const document = new JSDOM ( plainText ) . window . document ; const entries = getEntries ( document ) ; return entries [ 0 ] . mirror ; } ; export const findMD5s = async ( mirror , ids , MD5ReqPattern , onErr , errorTolarance , delay ) : Promise < string [ ] | null > => { const idStr = ids . join ( ', ' ) ; const reqURL = MD5ReqPattern . replace ( '{mirror}' , mirror ) . replace ( '{id}' , idStr ) ; const response = await doRequest ( reqURL , onErr , errorTolarance , delay ) ; if ( response == null ) return null ; try { const md5JSON = await response . json ( ) ; return md5JSON . map ( ( { md5 } ) => md5 ) ; } catch ( e ) { return null ; } } ;