n8n-nodes-instagram-private-api-wrapped
Version:
n8n community node for Instagram automation using private API capabilities
323 lines (322 loc) • 15.6 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.InstagramClient = void 0;
const instagram_private_api_1 = require("instagram-private-api");
class InstagramClient {
constructor(credentials) {
this.isAuthenticated = false;
this.client = new instagram_private_api_1.IgApiClient();
if (credentials) {
// Generate a generic device since we don't have username
this.client.state.generateDevice('instagram_user');
if (credentials.proxyUrl) {
this.client.state.proxyUrl = credentials.proxyUrl;
}
}
}
async authenticate(credentials) {
try {
// Configure proxy if provided
if (credentials.proxyUrl) {
this.client.state.proxyUrl = credentials.proxyUrl;
}
console.log('🔄 Starting Instagram session authentication...');
if (!credentials.sessionData) {
throw new Error('Session data is required. Please use the extract-session.sh script to obtain session data.');
}
try {
// Parse and load session data
const sessionData = typeof credentials.sessionData === 'string'
? JSON.parse(credentials.sessionData)
: credentials.sessionData;
console.log('📂 Loading session data...');
await this.client.state.deserialize(sessionData);
// Verify session is still valid
console.log('🔍 Verifying session validity...');
const userInfo = await this.client.user.info(this.client.state.cookieUserId);
console.log(`✅ Session authentication successful for user: ${userInfo.username}`);
this.isAuthenticated = true;
return;
}
catch (sessionError) {
console.log('❌ Session data error:', sessionError);
throw new Error(`Invalid or expired session data. Please extract fresh session data using the extract-session.sh script. Error: ${sessionError instanceof Error ? sessionError.message : 'Unknown error'}`);
}
}
catch (error) {
this.isAuthenticated = false;
console.log('❌ Authentication failed:', error);
// Enhanced error handling
if (error instanceof Error) {
const errorMessage = error.message.toLowerCase();
// Check for specific Instagram errors
if (errorMessage.includes('login_required') || errorMessage.includes('unauthorized')) {
throw new Error(`Session expired or invalid. Please extract fresh session data using the extract-session.sh script and update your credentials.`);
}
else if (errorMessage.includes('challenge_required')) {
throw new Error(`Instagram session requires verification. Please: 1) Login through Instagram mobile app, 2) Complete any verification challenges, 3) Extract fresh session data using extract-session.sh script.`);
}
else if (errorMessage.includes('checkpoint_required')) {
throw new Error(`Instagram account requires verification. Please: 1) Open Instagram mobile app, 2) Complete account verification, 3) Wait 24-48 hours, 4) Extract fresh session data using extract-session.sh script.`);
}
else if (errorMessage.includes('429') || errorMessage.includes('too many requests')) {
throw new Error(`Rate limited by Instagram. Please wait 2-4 hours and extract fresh session data using extract-session.sh script.`);
}
throw error;
}
throw new Error(`Authentication failed: Unknown error occurred. Please extract fresh session data using extract-session.sh script.`);
}
}
// Helper method for realistic delays
async delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async authenticateWithRetry(credentials, maxRetries = 3) {
let lastError = null;
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
console.log(`Authentication attempt ${attempt}/${maxRetries}`);
// Wait between attempts (except first)
if (attempt > 1) {
const delay = Math.min(1000 * Math.pow(2, attempt - 1), 10000); // Exponential backoff
await new Promise(resolve => setTimeout(resolve, delay));
}
await this.authenticate(credentials);
console.log('Authentication successful');
return; // Success, exit retry loop
}
catch (error) {
lastError = error instanceof Error ? error : new Error('Unknown error');
console.log(`Authentication attempt ${attempt} failed: ${lastError.message}`);
// Don't retry on certain errors
if (lastError.message.includes('challenge_required') ||
lastError.message.includes('checkpoint_required')) {
throw lastError; // These errors won't be fixed by retrying
}
}
}
// All attempts failed
throw new Error(`Authentication failed after ${maxRetries} attempts. Last error: ${(lastError === null || lastError === void 0 ? void 0 : lastError.message) || 'Unknown error'}`);
}
ensureAuthenticated() {
if (!this.isAuthenticated) {
throw new Error('Client is not authenticated. Please call authenticate() first.');
}
}
async getUserInfo(username) {
this.ensureAuthenticated();
try {
const user = await this.client.user.searchExact(username);
const userInfo = await this.client.user.info(user.pk);
return {
pk: user.pk.toString(),
username: user.username,
full_name: user.full_name,
profile_pic_url: user.profile_pic_url,
is_verified: user.is_verified || false,
follower_count: userInfo.follower_count || 0,
following_count: userInfo.following_count || 0,
media_count: userInfo.media_count || 0,
biography: userInfo.biography || '',
is_private: userInfo.is_private || false
};
}
catch (error) {
throw new Error(`Failed to get user info: ${error instanceof Error ? error.message : 'Unknown error'}`);
}
}
async searchUsers(query) {
var _a;
this.ensureAuthenticated();
try {
const response = await this.client.user.search(query);
return ((_a = response.users) === null || _a === void 0 ? void 0 : _a.map((user) => ({
pk: user.pk.toString(),
username: user.username,
full_name: user.full_name,
profile_pic_url: user.profile_pic_url,
is_verified: user.is_verified || false,
follower_count: user.follower_count || 0,
following_count: user.following_count || 0,
media_count: user.media_count || 0,
biography: user.biography || '',
is_private: user.is_private || false
}))) || [];
}
catch (error) {
throw new Error(`Failed to search users: ${error instanceof Error ? error.message : 'Unknown error'}`);
}
}
async getTimelineFeed(maxId) {
this.ensureAuthenticated();
try {
const feed = this.client.feed.timeline();
const response = await feed.request();
return {
items: response.feed_items.map((item) => {
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v;
return ({
id: ((_a = item.media) === null || _a === void 0 ? void 0 : _a.id) || item.id,
code: ((_b = item.media) === null || _b === void 0 ? void 0 : _b.code) || item.code,
taken_at: ((_c = item.media) === null || _c === void 0 ? void 0 : _c.taken_at) || item.taken_at,
media_type: ((_d = item.media) === null || _d === void 0 ? void 0 : _d.media_type) || item.media_type,
image_versions2: (_e = item.media) === null || _e === void 0 ? void 0 : _e.image_versions2,
video_versions: (_f = item.media) === null || _f === void 0 ? void 0 : _f.video_versions,
caption: ((_g = item.media) === null || _g === void 0 ? void 0 : _g.caption) ? { text: item.media.caption.text } : null,
like_count: ((_h = item.media) === null || _h === void 0 ? void 0 : _h.like_count) || 0,
comment_count: ((_j = item.media) === null || _j === void 0 ? void 0 : _j.comment_count) || 0,
user: {
id: ((_m = (_l = (_k = item.media) === null || _k === void 0 ? void 0 : _k.user) === null || _l === void 0 ? void 0 : _l.pk) === null || _m === void 0 ? void 0 : _m.toString()) || ((_p = (_o = item.user) === null || _o === void 0 ? void 0 : _o.pk) === null || _p === void 0 ? void 0 : _p.toString()),
username: ((_r = (_q = item.media) === null || _q === void 0 ? void 0 : _q.user) === null || _r === void 0 ? void 0 : _r.username) || ((_s = item.user) === null || _s === void 0 ? void 0 : _s.username),
full_name: ((_u = (_t = item.media) === null || _t === void 0 ? void 0 : _t.user) === null || _u === void 0 ? void 0 : _u.full_name) || ((_v = item.user) === null || _v === void 0 ? void 0 : _v.full_name)
}
});
}),
more_available: response.more_available || false,
next_max_id: response.next_max_id
};
}
catch (error) {
throw new Error(`Failed to get timeline feed: ${error instanceof Error ? error.message : 'Unknown error'}`);
}
}
async getMediaInfo(mediaId) {
this.ensureAuthenticated();
try {
const media = await this.client.media.info(mediaId);
const item = media.items[0];
return {
id: item.id,
code: item.code,
taken_at: item.taken_at,
media_type: item.media_type,
like_count: item.like_count,
comment_count: item.comment_count,
user: {
pk: item.user.pk.toString(),
username: item.user.username,
full_name: item.user.full_name
},
image_versions2: item.image_versions2,
video_versions: item.video_versions || []
};
}
catch (error) {
throw new Error(`Failed to get media info: ${error instanceof Error ? error.message : 'Unknown error'}`);
}
}
async likeMedia(mediaId) {
this.ensureAuthenticated();
try {
await this.client.media.like({
mediaId,
d: 1
});
}
catch (error) {
throw new Error(`Failed to like media: ${error instanceof Error ? error.message : 'Unknown error'}`);
}
}
async unlikeMedia(mediaId) {
this.ensureAuthenticated();
try {
await this.client.media.unlike({
mediaId,
d: 1
});
}
catch (error) {
throw new Error(`Failed to unlike media: ${error instanceof Error ? error.message : 'Unknown error'}`);
}
}
async getFollowers(userId, limit) {
this.ensureAuthenticated();
try {
const feed = this.client.feed.accountFollowers(userId);
const response = await feed.request();
const followers = limit ? response.users.slice(0, limit) : response.users;
return followers.map((user) => ({
pk: user.pk.toString(),
username: user.username,
full_name: user.full_name,
profile_pic_url: user.profile_pic_url,
is_verified: user.is_verified || false,
follower_count: 0,
following_count: 0,
media_count: 0,
biography: '',
is_private: user.is_private || false
}));
}
catch (error) {
throw new Error(`Failed to get followers: ${error instanceof Error ? error.message : 'Unknown error'}`);
}
}
async getFollowing(userId, limit) {
this.ensureAuthenticated();
try {
const feed = this.client.feed.accountFollowing(userId);
const response = await feed.request();
const following = limit ? response.users.slice(0, limit) : response.users;
return following.map((user) => ({
pk: user.pk.toString(),
username: user.username,
full_name: user.full_name,
profile_pic_url: user.profile_pic_url,
is_verified: user.is_verified || false,
follower_count: 0,
following_count: 0,
media_count: 0,
biography: '',
is_private: user.is_private || false
}));
}
catch (error) {
throw new Error(`Failed to get following: ${error instanceof Error ? error.message : 'Unknown error'}`);
}
}
async getUserMedia(userId, limit) {
this.ensureAuthenticated();
try {
const feed = this.client.feed.user(userId);
const response = await feed.request();
const media = limit ? response.items.slice(0, limit) : response.items;
return media.map((item) => ({
id: item.id,
code: item.code,
taken_at: item.taken_at,
media_type: item.media_type,
caption: item.caption ? { text: item.caption.text } : null,
like_count: item.like_count,
comment_count: item.comment_count,
user: {
id: item.user.pk.toString(),
username: item.user.username,
full_name: item.user.full_name
}
}));
}
catch (error) {
throw new Error(`Failed to get user media: ${error instanceof Error ? error.message : 'Unknown error'}`);
}
}
async saveSession() {
try {
return JSON.stringify(await this.client.state.serialize());
}
catch (error) {
throw new Error(`Failed to save session: ${error instanceof Error ? error.message : 'Unknown error'}`);
}
}
async loadSession(sessionData) {
try {
await this.client.state.deserialize(sessionData);
this.isAuthenticated = true;
}
catch (error) {
this.isAuthenticated = false;
throw new Error(`Failed to load session: ${error instanceof Error ? error.message : 'Unknown error'}`);
}
}
}
exports.InstagramClient = InstagramClient;