Last active
March 25, 2025 21:33
-
-
Save bobbyflowstate/f706bc00d2283c5b412760f20b3e30fd to your computer and use it in GitHub Desktop.
Automated Instagram Poster — Node.js + Dropbox + instagram-private-api
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* 🤖 Automated Instagram Poster — Node.js + Dropbox + instagram-private-api | |
* | |
* This script: | |
* - Pulls a random image from your Dropbox `/Public` folder | |
* - Posts it to Instagram using instagram-private-api | |
* - Adds a random emoji-only caption | |
* - Deletes the file from Dropbox after posting | |
* - Runs daily with PM2 cron scheduling | |
* | |
* 🔧 SETUP INSTRUCTIONS: | |
* | |
* // P.S. Music while you code: FlowStateRadio.com | |
* | |
* 1. Create a Dropbox app and generate an API token (https://dropbox.com/developers/apps) | |
* - Enable `files.content.read`, `files.metadata.read`, and `sharing.write` scopes | |
* - Generate an access token and copy it | |
* | |
* 2. Create a `.env` file in the same folder with the following: | |
* | |
* IG_USERNAME=your_instagram_username | |
* IG_PASSWORD=your_instagram_password | |
* DROPBOX_TOKEN=your_dropbox_token | |
* DROPBOX_FOLDER=/Public/your_folder_path | |
* | |
* 3. Initialize your project and install dependencies: | |
* | |
* npm init -y | |
* npm install instagram-private-api axios dotenv fs | |
* | |
* 4. (Optional but recommended) Add this to `.gitignore`: | |
* | |
* .env | |
* ig-session.json | |
* | |
* 5. Run the script manually to test: | |
* | |
* node postToInstagram.js | |
* | |
* 6. Schedule it daily with PM2: | |
* | |
* npm install -g pm2 | |
* pm2 start /full/path/to/postToInstagram.js --name ig-poster --cron "30 14 * * *" --no-autorestart | |
* pm2 save | |
* pm2 startup | |
* | |
* # Confirm it's scheduled: | |
* pm2 list | |
* pm2 show ig-poster | |
* | |
* # Check logs: | |
* pm2 logs ig-poster | |
* | |
* ✅ Your Instagram post will now go out automatically every day at 2:30 PM. | |
* | |
* 🚫 DISCLAIMER: This is not using the official Instagram Graph API. | |
* It's intended for personal/creative use, not large-scale automation or spamming. | |
*/ | |
import { IgApiClient } from 'instagram-private-api'; | |
import fs from 'fs/promises'; | |
import axios from 'axios'; | |
import dotenv from 'dotenv'; | |
dotenv.config(); | |
const { | |
IG_USERNAME, | |
IG_PASSWORD, | |
DROPBOX_TOKEN, | |
DROPBOX_FOLDER | |
} = process.env; | |
const SESSION_FILE = 'ig-session.json'; | |
async function loadSession(ig) { | |
try { | |
const data = await fs.readFile(SESSION_FILE, 'utf8'); | |
await ig.state.deserialize(JSON.parse(data)); | |
console.log("✅ Session loaded."); | |
} catch { | |
console.log("⚠️ No existing session found."); | |
} | |
} | |
async function saveSession(ig) { | |
const state = await ig.state.serialize(); | |
delete state.constants; | |
await fs.writeFile(SESSION_FILE, JSON.stringify(state), 'utf8'); | |
console.log("✅ Session saved."); | |
} | |
async function deleteDropboxFile(path) { | |
console.log("🗑️ Deleting file from Dropbox:", path); | |
try { | |
await axios.post( | |
'https://api.dropboxapi.com/2/files/delete_v2', | |
{ path: path }, | |
{ | |
headers: { | |
Authorization: `Bearer ${DROPBOX_TOKEN}`, | |
'Content-Type': 'application/json', | |
}, | |
} | |
); | |
console.log("✅ File deleted successfully"); | |
} catch (error) { | |
console.error("❌ Error deleting file:", error.message); | |
throw error; | |
} | |
} | |
async function getRandomDropboxFile() { | |
console.log("📁 Fetching files from Dropbox folder..."); | |
const listRes = await axios.post( | |
'https://api.dropboxapi.com/2/files/list_folder', | |
{ path: DROPBOX_FOLDER }, | |
{ | |
headers: { | |
Authorization: `Bearer ${DROPBOX_TOKEN}`, | |
'Content-Type': 'application/json', | |
}, | |
}i | |
); | |
const files = listRes.data.entries.filter(f => f['.tag'] === 'file'); | |
console.log(`📊 Found ${files.length} files in Dropbox folder`); | |
if (files.length === 0) throw new Error('No files found in folder.'); | |
const randomFile = files[Math.floor(Math.random() * files.length)]; | |
console.log(`🎲 Selected random file: ${randomFile.name}`); | |
// Get share link | |
console.log("🔗 Getting share link..."); | |
let rawUrl; | |
try { | |
const shareRes = await axios.post( | |
'https://api.dropboxapi.com/2/sharing/create_shared_link_with_settings', | |
{ path: randomFile.path_lower, settings: { requested_visibility: "public" } }, | |
{ headers: { Authorization: `Bearer ${DROPBOX_TOKEN}`, 'Content-Type': 'application/json' } } | |
); | |
rawUrl = shareRes.data.url.replace("www.dropbox.com", "dl.dropboxusercontent.com").replace("?dl=0", "?raw=1"); | |
} catch (err) { | |
if ( | |
err.response?.data?.error?.['.tag'] === 'shared_link_already_exists' | |
) { | |
const listLinkRes = await axios.post( | |
'https://api.dropboxapi.com/2/sharing/list_shared_links', | |
{ path: randomFile.path_lower, direct_only: true }, | |
{ headers: { Authorization: `Bearer ${DROPBOX_TOKEN}` } } | |
); | |
const existing = listLinkRes.data.links[0]?.url; | |
rawUrl = existing.replace("www.dropbox.com", "dl.dropboxusercontent.com").replace("?dl=0", "?raw=1"); | |
} else { | |
throw err; | |
} | |
} | |
// Download file | |
console.log("⬇️ Downloading file..."); | |
const imgRes = await axios.get(rawUrl, { | |
responseType: 'arraybuffer', | |
headers: { 'User-Agent': 'Mozilla/5.0' } | |
}); | |
console.log("✅ File downloaded successfully"); | |
return { | |
buffer: imgRes.data, | |
name: randomFile.name, | |
path: randomFile.path_lower, | |
}; | |
} | |
function generateRandomCaption() { | |
const positiveEmojis = [ | |
// Nature & Light | |
"✨", "🌟", "💫", "🌈", "🎨", "📸", "🎉", "💖", "🌺", "🦋", | |
"🌅", "🌄", "🎆", "🌻", "🌸", "💝", "🔆", "⭐️", "🌞", "🌼", | |
"💫", "🍀", "🌿", "🪴", "🎵", "💕", "🌹", "🪷", "✌️", "🙌", | |
// Positive Faces & Expressions | |
"🥰", "😊", "😍", "🤗", "😌", "😎", "🥳", "😇", "☺️", "🤩", | |
// Additional Positive Symbols | |
"💫", "💝", "💞", "💓", "💗", "💜", "💙", "🧡", "💛", "💚", | |
"🌠", "🎵", "🎶", "🍃", "🌱", "🌊", "🎪", "🎈", "🎀", "🎇" | |
]; | |
const numEmojis = Math.floor(Math.random() * 4) + 3; // 3 to 6 emojis | |
const caption = Array.from({ length: numEmojis }, () => | |
positiveEmojis[Math.floor(Math.random() * positiveEmojis.length)] | |
).join(""); | |
return caption; | |
} | |
async function postToInstagram() { | |
console.log("🚀 Starting Instagram post process..."); | |
const ig = new IgApiClient(); | |
ig.state.generateDevice(IG_USERNAME); | |
await loadSession(ig); | |
if (!ig.state.checkpoint) { | |
console.log("🔐 Logging in..."); | |
await ig.account.login(IG_USERNAME, IG_PASSWORD); | |
await saveSession(ig); | |
} | |
console.log("📸 Getting random file from Dropbox..."); | |
const { buffer, name, path } = await getRandomDropboxFile(); | |
const caption = generateRandomCaption(); | |
console.log("💭 Generated caption:", caption); | |
console.log("📤 Publishing to Instagram..."); | |
const result = await ig.publish.photo({ | |
file: Buffer.from(buffer), | |
caption: caption, | |
}); | |
console.log("✅ Posted to Instagram:", result.media.code); | |
console.log(`🔗 Post URL: https://instagram.com/p/${result.media.code}`); | |
// Delete the file after successful upload | |
await deleteDropboxFile(path); | |
} | |
postToInstagram().catch(err => { | |
console.error("❌ Error posting to Instagram:", err.message); | |
process.exit(1); | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment