instagram_uploader 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +1 -1
- data/README.md +15 -3
- data/lib/instagram_uploader.rb +6 -0
- data/lib/instagram_uploader/uploader.rb +117 -0
- data/lib/instagram_uploader/version.rb +3 -0
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fc28370148b1c825f1890df9ef22bf105f0e489d
|
4
|
+
data.tar.gz: a77422c49b56bde09ede69d20c7bf10c43b83b26
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6afcba19d199da5117bc7bf4f8630891fc38f44bb1c102885a128a4eaaf7be5a6a07a3f6bdb4585bdef9a3e97575c09ece4c6cc1d3e3fce91c2bf1387707b069
|
7
|
+
data.tar.gz: 9b392230c2af730dadf1d2525eae5a9142984327bcf1f9f5ebba09260707c8d79c69efafd8836ff826bff141b9f06b0f97d6a88ee7fdb92b12083291f1679308
|
data/.gitignore
CHANGED
data/README.md
CHANGED
@@ -18,12 +18,24 @@ Or install it yourself as:
|
|
18
18
|
|
19
19
|
## Usage
|
20
20
|
|
21
|
+
Somewhere in your code:
|
22
|
+
```ruby
|
23
|
+
require 'instagram_uploader'
|
24
|
+
```
|
21
25
|
|
22
|
-
##
|
26
|
+
## Example
|
27
|
+
```ruby
|
28
|
+
require 'instagram_uploader'
|
23
29
|
|
24
|
-
|
30
|
+
uploader = InstagramUploader::Uploader.new('your_login', 'your_password')
|
31
|
+
uploader.upload('./image.jpg', 'image_description')
|
32
|
+
```
|
25
33
|
|
26
|
-
|
34
|
+
You can't upload an image with description that will include control characters or symbol ' ( or many other things)
|
35
|
+
before uploading i change my desc to
|
36
|
+
```ruby
|
37
|
+
desc.gsub(/[\'\n]/, ' ').gsub(/[^[:print:]]/) {|x| x.ord}
|
38
|
+
```
|
27
39
|
|
28
40
|
## Contributing
|
29
41
|
|
@@ -0,0 +1,117 @@
|
|
1
|
+
module InstagramUploader
|
2
|
+
class Uploader
|
3
|
+
def initialize(username, password)
|
4
|
+
@username = username
|
5
|
+
@password = password
|
6
|
+
@cookie = Tempfile.new('cookies').path
|
7
|
+
end
|
8
|
+
|
9
|
+
def upload(image_path, desc)
|
10
|
+
login
|
11
|
+
media_response = upload_photo(image_path)
|
12
|
+
commit_photo(media_response['media_id'], desc)
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def login
|
18
|
+
url = 'https://instagram.com/api/v1/accounts/login/'
|
19
|
+
|
20
|
+
data = "{'username':'#{@username}','password':'#{@password}','guid':'#{generate_guid}','device_id':'#{generate_device_id}','Content-Type':'application/x-www-form-urlencoded; charset=UTF-8'}".gsub("'", '"')
|
21
|
+
signature = generate_signature(data)
|
22
|
+
body = 'ig_sig_key_version=4&signed_body=' + signature + '.' + URI::encode(data, /\W/)
|
23
|
+
|
24
|
+
response = request(url, body, false, false)
|
25
|
+
raise Error, response['message'] if response['status'] != 'ok'
|
26
|
+
end
|
27
|
+
|
28
|
+
def upload_photo(image)
|
29
|
+
url = 'https://instagram.com/api/v1/media/upload/'
|
30
|
+
device_timestamp = Time.now.to_i.to_s
|
31
|
+
|
32
|
+
data = [
|
33
|
+
Curl::PostField.file('photo', image),
|
34
|
+
Curl::PostField.content('device_timestamp', device_timestamp)
|
35
|
+
]
|
36
|
+
|
37
|
+
response = request(url, data, true, true)
|
38
|
+
|
39
|
+
if response['status'] != 'ok'
|
40
|
+
raise Error, response['message']
|
41
|
+
else
|
42
|
+
response
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def commit_photo(media_id, desc)
|
47
|
+
url = 'https://instagram.com/api/v1/media/configure/'
|
48
|
+
|
49
|
+
device_timestamp = Time.now.to_i.to_s
|
50
|
+
data = "{'guid':'#{@guid}','device_id':'#{@device_id}','device_timestamp':'#{device_timestamp}','media_id':'#{media_id}','caption': '#{desc}','source_type':'5','filter_type':'0','extra':'{}','Content-Type':'application/x-www-form-urlencoded; charset=UTF-8'}".gsub("'", '"')
|
51
|
+
signature = generate_signature(data)
|
52
|
+
body = 'ig_sig_key_version=4&signed_body=' + signature + '.' + URI::encode(data, /\W/)
|
53
|
+
|
54
|
+
response = request(url, body, false, true)
|
55
|
+
if response['status'] != 'ok'
|
56
|
+
raise Error, response['message']
|
57
|
+
else
|
58
|
+
response
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def request(url, data, is_upload, cookies)
|
63
|
+
http = Curl::Easy.new(url)
|
64
|
+
|
65
|
+
http.headers["User-Agent"] = generate_user_agent
|
66
|
+
http.multipart_form_post = is_upload
|
67
|
+
http.verbose = true
|
68
|
+
http.follow_location = true
|
69
|
+
http.enable_cookies = true
|
70
|
+
|
71
|
+
if cookies
|
72
|
+
http.cookiefile = @cookie
|
73
|
+
else
|
74
|
+
http.cookiejar = @cookie
|
75
|
+
end
|
76
|
+
|
77
|
+
http.send('post', data)
|
78
|
+
response = JSON.parse(http.body)
|
79
|
+
http.close
|
80
|
+
|
81
|
+
response
|
82
|
+
end
|
83
|
+
|
84
|
+
def generate_guid
|
85
|
+
guid = sprintf('%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
|
86
|
+
rand(0..65535),
|
87
|
+
rand(0..65535),
|
88
|
+
rand(0..65535),
|
89
|
+
rand(16384..20479),
|
90
|
+
rand(32768..49151),
|
91
|
+
rand(0..65535),
|
92
|
+
rand(0..65535),
|
93
|
+
rand(0..65535))
|
94
|
+
end
|
95
|
+
|
96
|
+
def generate_device_id
|
97
|
+
guid = generate_guid
|
98
|
+
"android-#{guid}"
|
99
|
+
end
|
100
|
+
|
101
|
+
def generate_signature(data)
|
102
|
+
return OpenSSL::HMAC.hexdigest('sha256', 'b4a23f5e39b5929e0666ac5de94c89d1618a2916', data)
|
103
|
+
end
|
104
|
+
|
105
|
+
def generate_user_agent
|
106
|
+
resolution = ['720x1280', '320x480', '480x800', '1024x768', '1280x720', '768x1024', '480x320'].sample
|
107
|
+
version = ['GT-N7000', 'SM-N9000', 'GT-I9220', 'GT-I9100'].sample
|
108
|
+
dpi = ['120', '160', '320', '240'].sample
|
109
|
+
|
110
|
+
'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; ru_RU)"
|
111
|
+
end
|
112
|
+
|
113
|
+
class Error < RuntimeError
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
end
|