Skip to content

Instantly share code, notes, and snippets.

@guilhermebkel
Last active February 18, 2021 21:37
Show Gist options
  • Save guilhermebkel/bbea4f264454dc8c502a513eca26ab2c to your computer and use it in GitHub Desktop.
Save guilhermebkel/bbea4f264454dc8c502a513eca26ab2c to your computer and use it in GitHub Desktop.
Instagram HTTP/Queue Integration
const { IgApiClient } = require("instagram-private-api")
const { withRealtime } = require("instagram_mqtt")
const fs = require("fs")
const INSTAGRAM_USERNAME = ""
const INSTAGRAM_PASSWORD = ""
const SESSION_FILE_PATH = "./session.json"
const SEQ_ID_FILE_PATH = "./seq_id.txt"
const formatMessage = (message) => ({
content: message.text || message.link,
user_id: message.user_id,
type: message.item_type,
timestamp: message.timestamp
})
const timeout = async (timeInMilliseconds = 1000) => {
await new Promise(resolve => setTimeout(resolve, timeInMilliseconds))
}
const saveLastSeqId = async (seqId) => {
await fs.promises.writeFile(SEQ_ID_FILE_PATH, seqId)
}
const getLastSeqId = async () => {
try {
const lastSeqIdBuffer = await fs.promises.readFile(SEQ_ID_FILE_PATH)
return +lastSeqIdBuffer.toString()
} catch (error) {
return null
}
}
const saveSession = async (session) => {
await fs.promises.writeFile(SESSION_FILE_PATH, JSON.stringify(session))
}
const getSession = async () => {
try {
const stringifiedSession = await fs.promises.readFile(SESSION_FILE_PATH)
return JSON.parse(stringifiedSession)
} catch (error) {
return null
}
}
const login = async (username, password) => {
const instagramClient = withRealtime(new IgApiClient())
instagramClient.request.end$.subscribe(async () => {
const serialized = await instagramClient.state.serialize()
delete serialized.constants
await saveSession(serialized)
})
const session = await getSession()
if (session) {
await instagramClient.state.deserialize(session)
} else {
instagramClient.state.generateDevice(username)
await instagramClient.simulate.preLoginFlow()
await instagramClient.account.login(username, password)
}
process.nextTick(async () => await instagramClient.simulate.postLoginFlow())
return instagramClient
}
const getInboxThreads = async ({
instagramClient = new IgApiClient()
}) => {
const threadsWithMessages = []
const directInbox = instagramClient.feed.directInbox()
const directInboxThreads = await directInbox.items()
directInboxThreads.forEach(async thread => {
const users = thread.users
.map(user => ({
id: user.pk,
name: user.full_name,
username: user.username,
avatar: user.profile_pic_url
}))
const messages = thread.items.map(formatMessage)
const existentThreadIndex = threadsWithMessages
.findIndex(threadWithMessage => threadWithMessage.id === thread.thread_id)
if (existentThreadIndex !== -1) {
const existentThread = threadsWithMessages[existentThreadIndex]
threadsWithMessages[existentThreadIndex] = {
...existentThread,
messages: [
...existentThread.messages,
...messages
]
}
} else {
threadsWithMessages.push({
id: thread.thread_id,
title: thread.thread_title,
type: thread.thread_type,
users,
messages,
})
}
})
return threadsWithMessages
}
const getInboxThreadMessages = async ({
instagramClient = new IgApiClient(),
threadId,
pages = 3
}) => {
let messages = []
const directThread = instagramClient.feed.directThread({
thread_id: threadId
})
for (let page = 0; page < pages; page++) {
await timeout(3000)
const rawMessages = await directThread.items()
const formattedMessages = rawMessages.map(formatMessage)
messages = [
...formattedMessages,
...messages
]
}
messages = messages.sort((a, b) => +a.timestamp - +b.timestamp)
return messages
}
/**
* HTTP Integration
*/
const httpIntegration = async () => {
const instagramClient = await login(INSTAGRAM_USERNAME, INSTAGRAM_PASSWORD)
const inboxThreads = await getInboxThreads({
instagramClient
})
const firstThread = inboxThreads[0]
const messages = await getInboxThreadMessages({
instagramClient,
threadId: firstThread.id,
pages: 3
})
console.log(inboxThreads, messages)
}
/**
* Queue Integration
*/
const queueIntegration = async () => {
const instagramListener = await login(INSTAGRAM_USERNAME, INSTAGRAM_PASSWORD)
instagramListener.realtime.on("message", async (data) => {
const { seq_id } = data
await saveLastSeqId(seq_id)
const formattedMessage = formatMessage(data.message)
console.log(formattedMessage)
})
const inboxThreadData = await instagramListener.feed.directInbox().request()
const lastSeqId = await getLastSeqId()
await instagramListener.realtime.connect({
irisData: {
...inboxThreadData,
...(lastSeqId ? { seq_id: lastSeqId } : {})
}
})
}
queueIntegration()
@floverfelt
Copy link

Hey, keep in mind, these Gists are public by default and you've checked in a username and password which I was able to enumerate here: https://gistsecrets.io/about

You may want to delete this Gist or make it private.

@guilhermebkel
Copy link
Author

Hey, keep in mind, these Gists are public by default and you've checked in a username and password which I was able to enumerate here: https://gistsecrets.io/about

You may want to delete this Gist or make it private.

Thanks for giving a feedback!

I have already done some modifications to remove these exposed credentials.

@floverfelt
Copy link

@guilhermebkel they are technically still available in the revisions: https://gist.github.com/guilhermebkel/bbea4f264454dc8c502a513eca26ab2c/revisions

But this is much better! Good luck with your project!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment