Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save nicholasklick/67101d48a15de4a69fc3b12f4439a472 to your computer and use it in GitHub Desktop.
Save nicholasklick/67101d48a15de4a69fc3b12f4439a472 to your computer and use it in GitHub Desktop.
Upload photos to Instagram via private API with Ruby
# 'direct_v2/threads/broadcast/text/'
class InstagramPrivateController < ApplicationController
def initialize(username, password, photo, caption)
@username = username
@password = password
@photo = photo
@caption = caption
@cookiepath = Tempfile.new('cookies').path
@user_agent = generate_user_agent()
@guid = generate_guid()
@device_id = generate_device_id(@guid)
end
def send
login = login()
if login['status'] == 'ok'
media = upload()
if media['status'] == 'ok'
configure = configure(media['media_id'])
return configure
end
return media
end
return login
end
def generate_user_agent
resolution = ['720x1280', '320x480', '480x800', '1024x768', '1280x720', '768x1024', '480x320'].sample
version = ['GT-N7000', 'SM-N9000', 'GT-I9220', 'GT-I9100'].sample
dpi = ['120', '160', '320', '240'].sample
return 'Instagram 4.' + rand(1..2).to_s + '.' + rand(0..2).to_s + ' Android (' + rand(10..11).to_s + '/' + rand(1..3).to_s + '.' + rand(3..5).to_s + '.' + rand(0..5).to_s + '; #{dpi}; #{resolution}; samsung; #{version }; #{version}; smdkc210; en_US)'
end
def generate_guid
guid = sprintf('%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
rand(0..65535),
rand(0..65535),
rand(0..65535),
rand(16384..20479),
rand(32768..49151),
rand(0..65535),
rand(0..65535),
rand(0..65535))
return guid
end
def generate_device_id(guid)
return 'android-#{guid}'
end
def generate_signature(data)
return OpenSSL::HMAC.hexdigest('sha256', 'b4a23f5e39b5929e0666ac5de94c89d1618a2916', data)
end
def request(url, data, upload, cookies)
http = Curl::Easy.new(url)
http.headers["User-Agent"] = @user_agent
http.multipart_form_post = upload
http.verbose = true
http.follow_location = true
http.enable_cookies = true
if cookies
http.cookiefile = @cookiepath
else
http.cookiejar = @cookiepath
end
if data.kind_of?(Array)
http.send('post', *data)
else
http.send('post', data)
end
response = JSON.parse(http.body)
http.close
return response
end
def login
url = 'https://instagram.com/api/v1/accounts/login/'
data = "{'username':'#{@username}','password':'#{@password}','guid':'#{@guid}','device_id':'#{@device_id}','Content-Type':'application/x-www-form-urlencoded; charset=UTF-8'}".gsub("'", '"')
signature = generate_signature(data)
body = 'ig_sig_key_version=4&signed_body=' + signature + '.' + URI::encode(data, /\W/)
response = request(url, body, false, false)
return response
end
def upload
url = 'https://instagram.com/api/v1/media/upload/'
device_timestamp = Time.now.to_i.to_s
data = [
Curl::PostField.file('photo', @photo),
Curl::PostField.content('device_timestamp', device_timestamp)
]
response = request(url, data, true, true)
return response
end
def configure(media_id)
url = 'https://instagram.com/api/v1/media/configure/'
device_timestamp = Time.now.to_i.to_s
data = "{'guid':'#{@guid}','device_id':'#{@device_id}','device_timestamp':'#{device_timestamp}','media_id':'#{media_id}','caption':'#{@caption}','source_type':'5','filter_type':'0','extra':'{}','Content-Type':'application/x-www-form-urlencoded; charset=UTF-8'}".gsub("'", '"')
signature = generate_signature(data)
body = 'ig_sig_key_version=4&signed_body=' + signature + '.' + URI::encode(data, /\W/)
response = request(url, body, false, true)
return response
end
end
Fonts:
http://lancenewman.me/posting-a-photo-to-instagram-without-a-phone/
http://mokhdzanifaeq.github.io/reverse-engineering-instagram-private-api/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment