2020-03-05 01:47:52 +00:00
'use strict' ;
2020-03-05 02:44:27 +00:00
const util = require ( 'util' ) ;
2020-03-05 01:47:52 +00:00
2020-11-15 22:50:04 +00:00
const qu = require ( '../utils/q' ) ;
2020-03-05 01:47:52 +00:00
const slugify = require ( '../utils/slugify' ) ;
2020-11-15 03:33:24 +00:00
const { feetInchesToCm , inchesToCm } = require ( '../utils/convert' ) ;
2020-03-05 01:47:52 +00:00
2020-03-05 19:31:11 +00:00
function deriveEntryId ( release ) {
2020-11-15 03:33:24 +00:00
if ( release . date && release . url ) {
const slug = new URL ( release . url ) . pathname . match ( /\/trailers\/(.*).html/ ) [ 1 ] ;
2020-11-15 22:50:04 +00:00
return ` ${ slugify ( qu . formatDate ( release . date , 'YYYY-MM-DD' ) ) } - ${ slugify ( slug ) } ` ;
2020-11-15 03:33:24 +00:00
}
2020-05-14 02:26:05 +00:00
if ( release . date && release . title ) {
2020-11-15 22:50:04 +00:00
return ` ${ slugify ( qu . formatDate ( release . date , 'YYYY-MM-DD' ) ) } - ${ slugify ( release . title ) } ` ;
2020-05-14 02:26:05 +00:00
}
2020-03-06 01:49:55 +00:00
2020-05-14 02:26:05 +00:00
return null ;
2020-03-05 19:31:11 +00:00
}
2020-03-05 02:44:27 +00:00
function extractPoster ( posterPath , site , baseRelease ) {
2020-05-14 02:26:05 +00:00
if ( posterPath && ! /400.jpg/ . test ( posterPath ) ) {
const poster = ` ${ site . parameters ? . media || site . url } ${ posterPath } ` ;
const posterSources = [
poster ,
// upscaled
poster . replace ( '-1x' , '-2x' ) ,
poster . replace ( '-1x' , '-3x' ) ,
] ;
if ( baseRelease ? . poster ) {
return [ posterSources , [ baseRelease . poster ] ] ;
}
return [ posterSources , [ ] ] ;
}
return [ baseRelease ? . poster || null , [ ] ] ;
2020-03-05 02:44:27 +00:00
}
2020-03-06 01:49:55 +00:00
function getImageWithFallbacks ( q , selector , site , el ) {
2020-05-14 02:26:05 +00:00
const sources = el
? [
q ( el , selector , 'src0_3x' ) ,
q ( el , selector , 'src0_2x' ) ,
q ( el , selector , 'src0_1x' ) ,
]
: [
q ( selector , 'src0_3x' ) ,
q ( selector , 'src0_2x' ) ,
q ( selector , 'src0_1x' ) ,
] ;
return sources . filter ( Boolean ) . map ( src => ` ${ site . parameters ? . media || site . url } ${ src } ` ) ;
2020-03-06 01:49:55 +00:00
}
2020-11-15 03:33:24 +00:00
function scrapeAll ( scenes , channel ) {
return scenes . map ( ( { query } ) => {
2020-05-14 02:26:05 +00:00
const release = { } ;
2020-03-05 01:47:52 +00:00
2020-11-15 03:33:24 +00:00
release . title = query . q ( 'h4 a' , true ) ;
release . url = query . url ( 'a' ) ;
2020-03-05 01:47:52 +00:00
2020-11-15 03:33:24 +00:00
release . date = query . date ( '.date' , 'YYYY-MM-DD' ) ;
release . duration = query . duration ( '.time' ) ;
2020-03-05 01:47:52 +00:00
2020-11-15 03:33:24 +00:00
const count = query . number ( 'a img' , null , 'cnt' ) ;
2020-03-05 01:47:52 +00:00
2020-11-15 03:33:24 +00:00
[ release . poster , ... release . photos ] = Array . from ( { length : count } , ( value , index ) => [
query . img ( 'a img' , ` src ${ index } _3x ` , { origin : channel . url } ) ,
query . img ( 'a img' , ` src ${ index } _2x ` , { origin : channel . url } ) ,
query . img ( 'a img' , ` src ${ index } _1x ` , { origin : channel . url } ) ,
] ) ;
2020-03-05 01:47:52 +00:00
2020-11-15 03:33:24 +00:00
release . stars = query . count ( 'img[src*="star_full"]' ) + ( query . count ( 'img[src*="star_half"]' ) * 0.5 ) ;
2020-05-14 02:26:05 +00:00
release . entryId = deriveEntryId ( release ) ;
2020-03-06 02:15:49 +00:00
2020-05-14 02:26:05 +00:00
return release ;
} ) ;
2020-03-05 01:47:52 +00:00
}
2020-08-22 02:22:56 +00:00
function scrapeAllT1 ( scenes , site , accNetworkReleases ) {
2020-11-15 22:50:04 +00:00
return scenes . map ( ( { query } ) => {
2020-05-14 02:26:05 +00:00
const release = { } ;
2020-03-05 01:47:52 +00:00
2020-11-15 22:50:04 +00:00
release . title = query . q ( 'h4 a' , 'title' ) || query . q ( 'h4 a' , true ) ;
release . url = query . url ( 'h4 a' ) ;
2020-03-05 01:47:52 +00:00
2020-11-15 22:50:04 +00:00
release . date = query . date ( '.more-info-div' , 'MMM D, YYYY' ) ;
release . duration = query . dur ( '.more-info-div' ) ;
2020-03-05 01:47:52 +00:00
2020-05-14 02:26:05 +00:00
if ( /bts|behind the scenes/i . test ( release . title ) ) release . tags = [ 'behind the scenes' ] ;
2020-03-06 01:49:55 +00:00
2020-11-15 22:50:04 +00:00
const posterPath = query . q ( '.img-div img' , 'src0_1x' ) || query . img ( 'img.video_placeholder' ) ;
2020-03-05 01:47:52 +00:00
2020-05-14 02:26:05 +00:00
if ( posterPath ) {
const poster = /^http/ . test ( posterPath ) ? posterPath : ` ${ site . parameters ? . media || site . url } ${ posterPath } ` ;
2020-03-05 01:47:52 +00:00
2020-05-14 02:26:05 +00:00
release . poster = [
poster . replace ( '-1x' , '-3x' ) ,
poster . replace ( '-1x' , '-2x' ) ,
poster ,
] ;
}
2020-03-05 01:47:52 +00:00
2020-05-14 02:26:05 +00:00
// release.entryId = q('.img-div img', 'id')?.match(/set-target-(\d+)/)[1];
release . entryId = deriveEntryId ( release ) ;
2020-03-05 19:31:11 +00:00
2020-08-22 02:22:56 +00:00
if ( site . parameters ? . accFilter && accNetworkReleases ? . map ( accRelease => accRelease . entryId ) . includes ( release . entryId ) ) {
2020-11-15 22:50:04 +00:00
// filter out releases that were already scraped from a categorized site, requeryires sequeryential site scraping
2020-05-14 02:26:05 +00:00
return null ;
}
2020-03-05 22:01:03 +00:00
2020-05-14 02:26:05 +00:00
return release ;
} ) . filter ( Boolean ) ;
2020-03-05 19:31:11 +00:00
}
2020-11-15 03:33:24 +00:00
function scrapeScene ( { html , query } , channel , url ) {
const release = { url } ; // url used for entry ID
2020-03-05 19:31:11 +00:00
2020-11-15 03:33:24 +00:00
release . title = query . cnt ( '.videoDetails h3' ) ;
release . description = query . cnt ( '.videoDetails p' ) ;
2020-03-05 19:31:11 +00:00
2020-11-15 03:33:24 +00:00
release . date = query . date ( '.videoInfo p' , [ 'MM/DD/YYYY' , 'YYYY-MM-DD' ] ) ;
release . duration = Number ( query . cnt ( '.videoInfo p:nth-of-type(2)' ) ? . match ( /(\d+) min/i ) ? . [ 1 ] ) * 60 ;
2020-03-05 19:31:11 +00:00
2020-11-15 03:33:24 +00:00
release . actors = query . cnts ( '.update_models a' ) ;
2020-03-05 01:47:52 +00:00
2020-05-14 02:26:05 +00:00
const posterPath = html . match ( /poster="([\w-/.]+)"/ ) ? . [ 1 ] ;
2020-11-15 22:50:04 +00:00
const poster = qu . prefixUrl ( posterPath , channel . url ) || query . img ( '.update_thumb' , 'src0_1x' , { origin : channel . url } ) ; // latter used when trailer requires signup
2020-11-15 03:33:24 +00:00
[ release . poster , ... release . photos ] = [ poster , ... query . imgs ( '.item-thumb img' , 'src0_1x' , { origin : channel . url } ) ]
2020-11-15 22:50:04 +00:00
. map ( src => src && [
2020-11-15 03:33:24 +00:00
src . replace ( '-1x' , '-3x' ) ,
src . replace ( '-1x' , '-2x' ) ,
src ,
] ) ;
2020-03-05 01:47:52 +00:00
2020-12-19 01:35:41 +00:00
const trailerPath = html . match ( /\/trailers?\/.*.mp4/ ) ;
2020-03-05 01:47:52 +00:00
2020-11-15 03:33:24 +00:00
if ( trailerPath ) {
2020-11-15 22:50:04 +00:00
release . trailer = qu . prefixUrl ( trailerPath , channel . parameters ? . media || channel . url ) ;
2020-11-15 03:33:24 +00:00
}
release . tags = query . cnts ( '.featuring a[href*="categories/"]' ) ;
release . stars = query . count ( '.stars img[src*="star_full"]' ) + ( query . count ( '.stars img[src*="star_half"]' ) * 0.5 ) ;
2020-03-05 01:47:52 +00:00
2020-05-14 02:26:05 +00:00
release . entryId = deriveEntryId ( release ) ;
2020-03-06 02:15:49 +00:00
2020-05-14 02:26:05 +00:00
return release ;
2020-03-05 01:47:52 +00:00
}
2020-11-15 22:50:04 +00:00
function scrapeSceneT1 ( { html , query } , site , url , baseRelease ) {
2020-05-14 02:26:05 +00:00
const release = { url } ;
2020-03-05 01:47:52 +00:00
2020-11-15 22:50:04 +00:00
release . title = query . q ( '.trailer-section-head .section-title' , true ) ;
release . description = query . text ( '.row .update-info-block' ) ;
2020-03-05 01:47:52 +00:00
2020-11-15 22:50:04 +00:00
release . date = query . date ( '.update-info-row' , 'MMM D, YYYY' , /\w+ \d{1,2}, \d{4}/ ) ;
release . duration = query . dur ( '.update-info-row:nth-child(2)' ) ;
2020-03-05 01:47:52 +00:00
2020-11-15 22:50:04 +00:00
release . actors = query . all ( '.models-list-thumbs a' ) . map ( el => ( {
name : query . q ( el , 'span' , true ) ,
avatar : getImageWithFallbacks ( query . q , 'img' , site , el ) ,
2020-05-14 02:26:05 +00:00
} ) ) ;
2020-03-05 01:47:52 +00:00
2020-11-15 22:50:04 +00:00
release . tags = query . all ( '.tags a' , true ) ;
2020-03-05 01:47:52 +00:00
2020-05-14 02:26:05 +00:00
// const posterPath = html.match(/poster="(.*\.jpg)/)?.[1];
2020-11-15 22:50:04 +00:00
const posterPath = query . q ( '.player-thumb img' , 'src0_1x' ) ;
2020-05-14 02:26:05 +00:00
[ release . poster , release . photos ] = extractPoster ( posterPath , site , baseRelease ) ;
2020-03-05 01:47:52 +00:00
2020-05-14 02:26:05 +00:00
const trailer = html . match ( /<video.*src="(.*\.mp4)/ ) ? . [ 1 ] ;
if ( trailer && /^http/ . test ( trailer ) ) release . trailer = { src : trailer , referer : url } ;
else if ( trailer ) release . trailer = { src : ` ${ site . parameters ? . media || site . url } ${ trailer } ` , referer : url } ;
2020-03-05 01:47:52 +00:00
2020-11-15 22:50:04 +00:00
const stars = query . q ( '.update-rating' , true ) . match ( /\d.\d/ ) ? . [ 0 ] ;
2020-05-14 02:26:05 +00:00
if ( stars ) release . stars = Number ( stars ) ;
2020-03-05 01:47:52 +00:00
2020-08-23 01:31:37 +00:00
if ( site . type === 'network' ) {
const channelRegExp = new RegExp ( site . children . map ( channel => channel . parameters ? . match || channel . name ) . join ( '|' ) , 'i' ) ;
2020-05-14 02:26:05 +00:00
const channel = release . tags . find ( tag => channelRegExp . test ( tag ) ) ;
2020-03-05 04:07:14 +00:00
2020-05-14 02:26:05 +00:00
if ( channel ) {
2020-08-23 01:31:37 +00:00
release . channel = slugify ( channel , '' ) ;
2020-05-14 02:26:05 +00:00
}
}
2020-03-05 02:44:27 +00:00
2020-05-14 02:26:05 +00:00
// release.entryId = q('.player-thumb img', 'id')?.match(/set-target-(\d+)/)[1];
release . entryId = deriveEntryId ( release ) ;
2020-03-05 19:31:11 +00:00
2020-05-14 02:26:05 +00:00
return release ;
2020-03-05 19:31:11 +00:00
}
2020-11-15 22:50:04 +00:00
function scrapeProfileT1 ( { el , query } , site ) {
2020-05-14 02:26:05 +00:00
const profile = { } ;
2020-03-06 01:49:55 +00:00
2020-11-15 22:50:04 +00:00
const bio = query . all ( '.detail-div + .detail-div p, .detail-div p' , true ) . reduce ( ( acc , info ) => {
2020-05-14 02:26:05 +00:00
const [ key , value ] = info . split ( ':' ) ;
2020-03-06 01:49:55 +00:00
2020-05-14 02:26:05 +00:00
if ( ! value ) return acc ;
2020-03-06 01:49:55 +00:00
2020-05-14 02:26:05 +00:00
return {
... acc ,
[ slugify ( key , '_' ) ] : value . trim ( ) ,
} ;
} , { } ) ;
2020-03-06 01:49:55 +00:00
2020-05-14 02:26:05 +00:00
if ( bio . measurements ) {
const [ bust , waist , hip ] = bio . measurements . split ( '-' ) ;
2020-03-06 01:49:55 +00:00
2020-05-14 02:26:05 +00:00
if ( bust ) profile . bust = bust ;
if ( waist ) profile . waist = Number ( waist ) ;
if ( hip ) profile . hip = Number ( hip ) ;
}
2020-03-06 01:49:55 +00:00
2020-05-14 02:26:05 +00:00
if ( bio . fun _fact ) profile . description = bio . fun _fact ;
if ( bio . age ) profile . age = Number ( bio . age ) ;
2020-03-06 01:49:55 +00:00
2020-05-14 02:26:05 +00:00
const heightMetric = bio . height ? . match ( /(\d{3})(\b|c)/ ) ;
const heightImperial = bio . height ? . match ( /\d{1}(\.\d)?/g ) ;
if ( heightMetric ) profile . height = Number ( heightMetric [ 1 ] ) ;
if ( heightImperial ) profile . height = feetInchesToCm ( Number ( heightImperial [ 0 ] ) , Number ( heightImperial [ 1 ] ) ) ;
2020-03-06 01:49:55 +00:00
2020-11-15 22:50:04 +00:00
profile . avatar = getImageWithFallbacks ( query . q , '.img-div img' , site ) ;
2020-03-06 01:49:55 +00:00
2020-11-15 22:50:04 +00:00
const qReleases = qu . initAll ( el , '.item-video' ) ;
2020-05-14 02:26:05 +00:00
profile . releases = scrapeAllT1 ( qReleases , site ) ;
2020-03-06 01:49:55 +00:00
2020-05-14 02:26:05 +00:00
return profile ;
2020-03-06 01:49:55 +00:00
}
2020-11-15 22:50:04 +00:00
async function fetchActorScenes ( { query , el } , channel , accScenes = [ ] ) {
const scenes = scrapeAll ( qu . initAll ( el , '.item-video' ) , channel ) ;
const nextPage = query . url ( '.next a' ) ;
if ( nextPage ) {
const res = await qu . get ( nextPage ) ;
if ( res . ok ) {
return fetchActorScenes ( res . item , channel , scenes . concat ( accScenes ) ) ;
}
}
return accScenes . concat ( scenes ) ;
}
async function scrapeProfile ( { query , el } , channel , options ) {
2020-05-14 02:26:05 +00:00
const profile = { } ;
2020-03-06 01:49:55 +00:00
2020-11-15 03:33:24 +00:00
const bio = query . all ( '.stats li' ) . reduce ( ( acc , bioEl ) => {
const key = query . cnt ( bioEl , 'strong' ) ;
const value = query . url ( bioEl ) || query . text ( bioEl ) ;
2020-03-06 01:49:55 +00:00
2020-05-14 02:26:05 +00:00
return {
... acc ,
2020-11-15 03:33:24 +00:00
[ slugify ( key , '_' ) ] : value ,
2020-05-14 02:26:05 +00:00
} ;
} , { } ) ;
2020-03-06 01:49:55 +00:00
2020-11-15 22:50:04 +00:00
if ( bio . date _of _birth ) profile . birthdate = qu . extractDate ( bio . date _of _birth , 'MMMM D, YYYY' ) ;
2020-05-14 02:26:05 +00:00
if ( bio . birthplace ) profile . birthPlace = bio . birthplace ;
if ( bio . fun _fact ) profile . description = bio . fun _fact ;
2020-03-06 01:49:55 +00:00
2020-05-14 02:26:05 +00:00
if ( bio . ethnicity ) profile . ethnicity = bio . ethnicity ;
2020-03-06 01:49:55 +00:00
2020-05-14 02:26:05 +00:00
if ( bio . height ) profile . height = Number ( bio . height . match ( /^\d{2,3}/ ) ? . [ 0 ] ) ;
if ( bio . weight ) profile . weight = Number ( bio . weight . match ( /^\d{2,3}/ ) ? . [ 0 ] ) ;
2020-03-06 01:49:55 +00:00
2020-05-14 02:26:05 +00:00
if ( bio . measurements ) {
const [ bust , waist , hip ] = bio . measurements . split ( '-' ) ;
2020-03-06 01:49:55 +00:00
2020-05-14 02:26:05 +00:00
if ( bust ) profile . bust = bust ;
if ( waist ) profile . waist = Number ( waist ) ;
if ( hip ) profile . hip = Number ( hip ) ;
}
2020-03-06 01:49:55 +00:00
2020-11-15 03:33:24 +00:00
if ( bio . penis _length ) profile . penisLength = Number ( bio . penis _length . match ( /(\d+)\s*cm/i ) ? . [ 1 ] || inchesToCm ( bio . penis _length . match ( /(\d+\.?\d+)\s*in/i ) ? . [ 1 ] ) ) || null ;
if ( bio . penis _girth ) profile . penisGirth = Number ( bio . penis _girth . match ( /(\d+)\s*cm/i ) ? . [ 1 ] || inchesToCm ( bio . penis _girth . match ( /(\d+\.?\d+)\s*in/i ) ? . [ 1 ] ) ) || null ;
if ( bio . circumcised && /yes/i . test ( bio . circumcised ) ) profile . circumcised = true ;
if ( bio . circumcised && /no/i . test ( bio . circumcised ) ) profile . circumcised = false ;
2020-05-14 02:26:05 +00:00
if ( bio . natural _breasts && /yes/i . test ( bio . natural _breasts ) ) profile . naturalBoobs = true ;
if ( bio . natural _breasts && /no/i . test ( bio . natural _breasts ) ) profile . naturalBoobs = false ;
2020-03-06 01:49:55 +00:00
2020-05-14 02:26:05 +00:00
if ( bio . tattoos && /yes/i . test ( bio . tattoos ) ) profile . hasTattoos = true ;
if ( bio . tattoos && /no/i . test ( bio . tattoos ) ) profile . hasTattoos = false ;
if ( bio . piercings && /yes/i . test ( bio . piercings ) ) profile . hasPiercings = true ;
if ( bio . piercings && /no/i . test ( bio . piercings ) ) profile . hasPiercings = false ;
2020-03-06 01:49:55 +00:00
2020-05-14 02:26:05 +00:00
if ( bio . aliases ) profile . aliases = bio . aliases . split ( ',' ) . map ( alias => alias . trim ( ) ) ;
2020-03-06 01:49:55 +00:00
2020-11-15 03:33:24 +00:00
profile . social = [ bio . onlyfans , bio . twitter , bio . instagram ] . filter ( Boolean ) ;
2020-03-06 01:49:55 +00:00
2020-11-15 03:33:24 +00:00
profile . avatar = [
query . img ( '.profile-pic img' , 'src0_3x' , { origin : channel . url } ) ,
query . img ( '.profile-pic img' , 'src0_2x' , { origin : channel . url } ) ,
query . img ( '.profile-pic img' , 'src0_1x' , { origin : channel . url } ) ,
] ;
2020-03-06 01:49:55 +00:00
2020-11-15 22:50:04 +00:00
if ( options . includeActorScenes ) {
profile . releases = await fetchActorScenes ( { query , el } , channel ) ;
}
2020-05-14 02:26:05 +00:00
return profile ;
2020-03-06 01:49:55 +00:00
}
2020-11-15 03:33:24 +00:00
async function fetchLatest ( site , page = 1 , include , { uniqueReleases = [ ] , duplicateReleases = [ ] } ) {
2020-05-14 02:26:05 +00:00
const url = ( site . parameters ? . latest && util . format ( site . parameters . latest , page ) )
2020-03-05 02:44:27 +00:00
|| ( site . parameters ? . t1 && ` ${ site . url } /t1/categories/movies_ ${ page } _d.html ` )
|| ` ${ site . url } /categories/movies_ ${ page } _d.html ` ;
2020-11-15 22:50:04 +00:00
const res = await qu . getAll ( url , '.modelfeature, .item-video, .updateItem' ) ;
2020-03-05 01:47:52 +00:00
2020-11-15 03:33:24 +00:00
if ( ! res . ok ) {
return res . status ;
}
if ( site . parameters ? . t1 ) {
return scrapeAllT1 ( res . items , site , [ ... uniqueReleases , ... duplicateReleases ] ) ;
}
2020-03-05 01:47:52 +00:00
2020-08-23 00:43:10 +00:00
return scrapeAll ( res . items , site , uniqueReleases ) ;
2020-03-05 01:47:52 +00:00
}
2020-08-23 01:31:37 +00:00
async function fetchScene ( url , site , baseRelease ) {
2020-11-15 22:50:04 +00:00
const res = await qu . get ( url ) ;
2020-03-05 01:47:52 +00:00
2020-11-15 03:33:24 +00:00
if ( ! res . ok ) {
return res . status ;
}
if ( site . parameters ? . t1 ) {
return scrapeSceneT1 ( res . item , site , url , baseRelease ) ;
}
2020-03-05 01:47:52 +00:00
2020-05-14 02:26:05 +00:00
return scrapeScene ( res . item , site , url , baseRelease ) ;
2020-03-05 01:47:52 +00:00
}
2020-11-15 22:50:04 +00:00
async function fetchProfile ( { name : actorName } , { site } , options ) {
2020-05-14 02:26:05 +00:00
const actorSlugA = slugify ( actorName , '' ) ;
const actorSlugB = slugify ( actorName ) ;
2020-03-06 01:49:55 +00:00
2020-05-14 02:26:05 +00:00
const t1 = site . parameters ? . t1 ? 't1/' : '' ;
2020-03-06 01:49:55 +00:00
2020-05-14 02:26:05 +00:00
const res1 = site . parameters ? . profile
2020-11-15 22:50:04 +00:00
? await qu . get ( util . format ( site . parameters . profile , actorSlugA ) )
: await qu . get ( ` ${ site . url } / ${ t1 } models/ ${ actorSlugA } .html ` , null , null , { followRedirects : false } ) ;
2020-03-08 03:23:10 +00:00
2020-05-14 02:26:05 +00:00
const res = ( res1 . ok && res1 )
2020-11-15 22:50:04 +00:00
|| ( site . parameters ? . profile && await qu . get ( util . format ( site . parameters . profile , actorSlugB ) ) )
|| await qu . get ( ` ${ site . url } / ${ t1 } models/ ${ actorSlugB } .html ` , null , null , { followRedirects : false } ) ;
2020-11-15 03:33:24 +00:00
if ( ! res . ok ) {
return res . status ;
}
2020-03-08 03:23:10 +00:00
2020-11-15 03:33:24 +00:00
if ( site . parameters ? . t1 ) {
return scrapeProfileT1 ( res . item , site ) ;
}
2020-03-06 01:49:55 +00:00
2020-11-15 22:50:04 +00:00
return scrapeProfile ( res . item , site , options ) ;
2020-03-06 01:49:55 +00:00
}
2020-03-05 01:47:52 +00:00
module . exports = {
2020-05-14 02:26:05 +00:00
fetchLatest ,
fetchScene ,
fetchProfile ,
2021-02-13 03:49:00 +00:00
scrapeAllT1 ,
2020-03-05 01:47:52 +00:00
} ;