Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion src/config/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ export const config = {
instagram_base_z4: 'https://z-p4.www.instagram.com',
/** Instagram Api v1 */
instagram_api_v1: 'https://i.instagram.com/api/v1',
/** Instagram Api v2 */
instagram_api_v2: 'https://i.instagram.com/api/v2',
/** Instagram API Search User */
instagram_search_url: 'https://www.instagram.com/web/search/topsearch/?query=',
/** Android User-Agent */
Expand All @@ -12,4 +14,4 @@ export const config = {
desktop: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 Safari/537.36',
/** iPhone User-Agent */
iPhone: 'Instagram 123.0.0.21.114 (iPhone; CPU iPhone OS 11_4 like Mac OS X; en_US; en-US; scale=2.00; 750x1334) AppleWebKit/605.1.15'
}
}
128 changes: 124 additions & 4 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
/* Muhamad Ristiyanto _ https://github.com/Gimenz
* Created, Published at Selasa, 9 Maret 2021
* Modified, Updated at Minggu, 20 Februari 2022
* Modified, Updated at Minggu, 19 Januari 2025
*/

import fs from 'fs'
import FormData from 'form-data';
import axios, { AxiosRequestConfig, AxiosResponse } from 'axios';
import { bufferToStream, getPostType, parseCookie, randInt, shortcodeFormatter } from './utils/index';
import { username, userId, seachTerm, url, IgCookie, ProductType, MediaType, IChangedProfilePicture, ISearchFollow, IGPostMetadata, PostGraphQL } from './types';
import { username, userId, seachTerm, url, IgCookie, ProductType, MediaType, IChangedProfilePicture, ISearchFollow, IGPostMetadata, PostGraphQL, UserFollow } from './types';
import { IGUserMetadata, UserGraphQL } from './types/UserMetadata';
import { IGStoriesMetadata, ItemStories, StoriesGraphQL } from './types/StoriesMetadata';
import { highlight_ids_query, highlight_media_query, post_shortcode_query } from './helper/query';
Expand All @@ -25,6 +25,8 @@ import { IPaginatedPosts } from './types/PaginatedPosts';
export * from './utils'
export * as InstagramMetadata from './types'
export * from './helper/Session';
const sleep = (ms: number) => new Promise(resolve => setTimeout(resolve, ms));

export class igApi {
/**
* Recommended to set cookie for most all IG Request
Expand Down Expand Up @@ -94,7 +96,7 @@ export class igApi {
public searchFollower = async (userId: userId, seachTerm: seachTerm): Promise<ISearchFollow> => {
const res = await this.FetchIGAPI(
config.instagram_api_v1,
`/friendships/${userId}/followers/?count=12&query=${seachTerm}&search_surface=follow_list_page`,
`/friendships/${userId}/followers/?count=50&query=${seachTerm}&search_surface=follow_list_page`,
config.iPhone,
);
return res?.data || res
Expand All @@ -109,6 +111,124 @@ export class igApi {
return res?.data || res
}

public getAllFollowers = async (userId: string, searchTerm: string = ""): Promise<ISearchFollow> => {
let followers: UserFollow[] = [];
let nextMaxId: string | undefined = undefined;

do {
const res = await this.FetchIGAPI(
config.instagram_api_v1,
`/friendships/${userId}/followers/`,
config.iPhone,
{
params: {
count: 12, // Adjust `count` to the maximum allowed by Instagram
query: searchTerm,
max_id: nextMaxId, // Pagination parameter
search_surface: "follow_list_page",
},
}
);

const data: ISearchFollow = res?.data || res;
followers.push(...(data.users || []));
nextMaxId = data.next_max_id; // Update nextMaxId for the next page
await sleep(2000);
} while (nextMaxId);

return { users: followers, status: "success" };
};

public getAllFollowing = async (userId: string, searchTerm: string = ""): Promise<ISearchFollow> => {
let following: UserFollow[] = [];
let nextMaxId: string | undefined = undefined;

do {
const res = await this.FetchIGAPI(
config.instagram_api_v1,
`/friendships/${userId}/following/`,
config.iPhone,
{
params: {
count: 12, // Adjust `count` to the maximum allowed by Instagram
query: searchTerm,
max_id: nextMaxId, // Pagination parameter
},
}
);

const data: ISearchFollow = res?.data || res;
following.push(...(data.users || []));
nextMaxId = data.next_max_id; // Update nextMaxId for the next page
await sleep(2000);
} while (nextMaxId);

return { users: following, status: "success" };
};

/*
* add new for automate view stories & like stories
* fitur dari Rizka Nugraha
*/

public getStories = async (): Promise<ItemStories[]> => {
try {
const res = await this.FetchIGAPI(
config.instagram_api_v1,
`/feed/reels_tray/`,
config.android
);
return res?.data?.tray || [];
} catch (error) {
console.error("Error fetching stories:", error);
return [];
}
};

public getStoryById = async (reelId: string): Promise<any> => {
const res = await this.FetchIGAPI(config.instagram_api_v1, `/feed/reels_media/?reel_ids=${reelId}`, config.android)
if (res && res.data && res.data.reels_media && res.data.reels_media.length > 0) {
return res.data.reels_media[0];
}
}

public viewStories = async (reelId: string, itemId: string): Promise<AxiosResponse | undefined> => {
try {
const res = await this.FetchIGAPI(
config.instagram_api_v2,
`/media/seen/`,
config.android,
{
data: {
reels: { [`${reelId}_${itemId}`]: [0] }, // Reel ID and timestamp
reel_media_id: itemId,
reel_author_id: reelId,
view_source: "feed_timeline",
},
method: "POST",
}
);
return res;
} catch (error) {
console.error("Error viewing story:", error);
}
};

public likeStories = async (mediaId: string): Promise<AxiosResponse | undefined> => {
try {
const res = await this.FetchIGAPI(
config.instagram_api_v1,
`/media/${mediaId}/like/`,
config.android,
{ method: "POST" }
);
return res;
} catch (error) {
console.error("Error liking story:", error);
}
};


private _formatSidecar = (data: IRawBody): Array<MediaUrls> => {
const gql = data.items[0]
let urls: MediaUrls[] = []
Expand Down Expand Up @@ -405,7 +525,7 @@ export class igApi {
return graphql.data.reels_media[0].items.map((item) => ({
owner: graphql.data.reels_media[0].owner,
media_id: item.id,
mimetype: item.is_video ? 'video/mp4' || 'video/gif' : 'image/jpeg',
mimetype: item.is_video ? 'video/mp4' : 'image/jpeg',
taken_at: item.taken_at_timestamp,
type: item.is_video ? 'video' : 'image',
url: item.is_video ? item.video_resources[0].src : item.display_url,
Expand Down
22 changes: 12 additions & 10 deletions src/types/searchFollow.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
import { User } from "./PostModels";

export interface ISearchFollow {
users?: UserFollow[];
big_list?: boolean;
page_size?: number;
has_more?: boolean;
users?: UserFollow[];
big_list?: boolean;
page_size?: number;
has_more?: boolean;
should_limit_list_of_followers?: boolean;
use_clickable_see_more?: boolean;
show_spam_follow_request_tab?: boolean;
status?: string;
use_clickable_see_more?: boolean;
show_spam_follow_request_tab?: boolean;
status?: string;
next_max_id?: string;
}

export type UserFollow = User & {
pk_id?: string;
pk_id?: string;
third_party_downloads_enabled?: number;
strong_id__?: string;
}
strong_id__?: string;
}