UNPKG

n8n-nodes-instagram-private-api-wrapped

Version:

n8n community node for Instagram automation using private API capabilities

323 lines (322 loc) 15.6 kB
"use strict"; 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;