import { Type } from "io-ts" ; import { Browser } from "puppeteer" ; import * as winston from "winston" ; import { DType , IPlugin } from "../../plugins" ; import { Instagram } from "./instagram" ; import { ISearchOptions , ISearchOptionsPlugins , Search , TSearchResult , } from "./search" ; import { FullApiPost , Post as PostValidator , SinglePost , TFullApiPost , TPost , TSinglePost , } from "./types" ; /**
 * Optional arguments for the API
 */ export interface IOptionsCommon { total ? : number ; headless ? : boolean ; logger ? : winston . Logger ; silent ? : boolean ; sleepTime ? : number ; strict ? : boolean ; hibernationTime ? : number ; enableGrafting ? : boolean ; sameBrowser ? : boolean ; fullAPI ? : boolean ; proxyURL ? : string ; executablePath ? : string ; validator ? : Type < unknown > ; browserInstance ? : Browser ; } export interface IOptionsFullApi extends IOptionsCommon { fullAPI : true ; } export interface IOptionsRegular extends IOptionsCommon { fullAPI ? : false ; } export interface IOptionsFullApiPlugins < PostType > extends IOptionsFullApi { plugins ? : IPlugin < PostType > [ ] ; } export interface IOptionsRegularPlugins < PostType > extends IOptionsRegular { plugins ? : IPlugin < PostType > [ ] ; } export type IOptions = IOptionsFullApi | IOptionsRegular | IOptionsFullApiPlugins < DType > | IOptionsRegularPlugins < DType > ; /**
 * An Instagram post API wrapper
 */ export class Post extends Instagram < TSinglePost > { private readonly ids : string [ ] ; constructor ( ids , options = { } ) { options . fullAPI = false ; super ( "https://instagram.com/p/[id]" , ids [ 0 ] , "" , "" , options , SinglePost ) ; this . ids = ids ; } /**
     * Get the post metadata
     */ protected async getNext ( ) { for ( const id of this . ids ) { this . id = id ; await this . postPage ( id , 5 ) ; await this . sleep ( 2 ) ; } this . finished = true ; } } const getPageValidator = ( options ) => options . fullAPI ? FullApiPost : PostValidator ; export type InstagramPostClass = Hashtag < TPost > | User < TPost > ; export type InstagramFullPostClass = Hashtag < TFullApiPost > | User < TFullApiPost > ; export function createApi ( type , query , options ? ) ; export function createApi ( type , id , options ? ) ; export function createApi ( type , id , options ? ) ; export function createApi ( type , id , options ? ) ; export function createApi ( type , id , options ? ) { let ClassConstructor ; switch ( type ) { case "search" : return new Search ( id as string , options as ISearchOptions ) ; case "post" : return new Post ( id as string [ ] , options ) ; case "hashtag" : ClassConstructor = Hashtag ; break ; case "user" : ClassConstructor = User ; break ; } if ( options . fullAPI ) { return new ClassConstructor < TFullApiPost > ( id as string , options ) ; } return new ClassConstructor < TPost > ( id as string , options ) ; } /**
 * An Instagram hashtag API wrapper
 */ export class Hashtag < T > extends Instagram < T > { constructor ( id , options = { } ) { super ( "https://instagram.com/explore/tags/[id]" , id , "data.hashtag.edge_hashtag_to_media.page_info" , "data.hashtag.edge_hashtag_to_media.edges" , options , getPageValidator ( options ) ) ; } } /**
 * An Instagram user API wrapper
 */ export class User < T > extends Instagram < T > { defaultPageFunctions = [ ( ) => { let morePostsIntervalCounter = 0 ; const morePostsInterval = setInterval ( ( ) => { const searchDiv = Array . from ( document . getElementsByTagName ( "div" ) ) . filter ( ( d ) => d . innerHTML . startsWith ( "Show More Posts from" ) ) [ 0 ] ; morePostsIntervalCounter ++ ; if ( searchDiv !== undefined ) { searchDiv . parentElement . parentElement . click ( ) ; clearInterval ( morePostsInterval ) ; } else if ( morePostsIntervalCounter > 10 ) { clearInterval ( morePostsInterval ) ; } } , 1000 ) ; } , ] ; constructor ( id , options = { } ) { super ( "https://instagram.com/[id]" , id , "data.user.edge_owner_to_timeline_media.page_info" , "data.user.edge_owner_to_timeline_media.edges" , options , getPageValidator ( options ) ) ; } }