social_profile 0.2.1 → 0.2.2
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/lib/social_profile/people/facebook.rb +23 -4
- data/lib/social_profile/people/twitter.rb +50 -0
- data/lib/social_profile/people/vkontakte.rb +186 -0
- data/lib/social_profile/providers/odnoklassniki.rb +74 -0
- data/lib/social_profile/version.rb +1 -1
- data/lib/social_profile.rb +2 -0
- data/social_profile.gemspec +3 -3
- data/spec/mock_json/facebook/followers_5_0.json +34 -0
- data/spec/mock_json/facebook/followers_5_10.json +35 -0
- data/spec/mock_json/facebook/followers_5_15.json +26 -0
- data/spec/mock_json/twitter/auth.json +1 -1
- data/spec/mock_json/twitter/last_posts.json +4326 -0
- data/spec/mock_json/vkontakte/comments_photos.json +707 -0
- data/spec/mock_json/vkontakte/comments_post_655.json +42 -0
- data/spec/mock_json/vkontakte/followers.json +187 -0
- data/spec/mock_json/vkontakte/followers_20.json +127 -0
- data/spec/mock_json/vkontakte/followers_20_2.json +67 -0
- data/spec/mock_json/vkontakte/friends.json +1728 -0
- data/spec/mock_json/vkontakte/last_posts.json +4279 -0
- data/spec/mock_json/vkontakte/last_posts_2.json +2736 -0
- data/spec/mock_json/vkontakte/last_posts_3.json +533 -0
- data/spec/mock_json/vkontakte/likes_photo_290498375.json +24 -0
- data/spec/mock_json/vkontakte/likes_post_655.json +14 -0
- data/spec/mock_json/vkontakte/shares_post_3675.json +1373 -0
- data/spec/people/facebook_spec.rb +25 -0
- data/spec/people/twitter_spec.rb +21 -1
- data/spec/people/vkontakte_spec.rb +95 -3
- data/spec/spec_helper.rb +1 -1
- metadata +47 -14
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9ff2a46cb1b8edb78c457fb204d2efac1035b642
|
4
|
+
data.tar.gz: e843f72028951caa385e61478566a2eda9ba31ae
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 889b1b58ae675301c69a86282700b552cae13d99f441bacf9b2d74c579e06110942fddaadd687a1f075420b9fc0436d5d953628be875fe7c2315db83245f00dc
|
7
|
+
data.tar.gz: 9108fb8234539617a98bf26c94247515a10b32b7e804b697e365e5d6d45fd7048f944c990086815ebabec2ffd90e1c6c72b718ec0ea4b2f2ba354f0b4cbedc6f
|
@@ -70,11 +70,16 @@ module SocialProfile
|
|
70
70
|
def last_post_by_days(days, options={})
|
71
71
|
date = (options[:date_end] || Time.now) - days.days
|
72
72
|
limit = options[:limit] || 100
|
73
|
+
max_iteration = options[:max_iteration] || 100
|
74
|
+
iteration = 0
|
73
75
|
|
74
76
|
posts = collection = last_posts(limit, options)
|
77
|
+
return [] if posts.blank?
|
78
|
+
|
75
79
|
last_created_time = posts.last.created_time
|
76
80
|
|
77
|
-
while last_created_time > date
|
81
|
+
while last_created_time > date && !last_created_time.blank? && iteration < max_iteration
|
82
|
+
iteration += 1
|
78
83
|
collection = collection.next
|
79
84
|
posts += collection
|
80
85
|
last_created_time = posts.last.created_time
|
@@ -86,15 +91,29 @@ module SocialProfile
|
|
86
91
|
# Get all friends list
|
87
92
|
#
|
88
93
|
def friends(options={})
|
89
|
-
limit = options[:limit] ||
|
94
|
+
limit = options[:limit] || 5000
|
90
95
|
user.friends(:limit => limit)
|
91
96
|
end
|
92
97
|
|
93
98
|
# Get all followers list
|
94
99
|
#
|
95
100
|
def followers(options={})
|
96
|
-
limit = options[:limit] ||
|
97
|
-
|
101
|
+
limit = options[:limit] || 5000
|
102
|
+
fetch_all = options[:fetch_all] || false
|
103
|
+
iteration = 0
|
104
|
+
|
105
|
+
_followers = collection = user.subscribers(:limit => limit)
|
106
|
+
max_iteration = _followers.total_count / limit + 1
|
107
|
+
|
108
|
+
if fetch_all
|
109
|
+
while iteration < max_iteration
|
110
|
+
iteration += 1
|
111
|
+
collection = collection.next
|
112
|
+
_followers += collection
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
_followers
|
98
117
|
end
|
99
118
|
|
100
119
|
protected
|
@@ -3,6 +3,7 @@ require "twitter"
|
|
3
3
|
module SocialProfile
|
4
4
|
module People
|
5
5
|
class Twitter < Person
|
6
|
+
MAX_ATTEMPTS = 3
|
6
7
|
|
7
8
|
# Get friends count
|
8
9
|
def friends_count
|
@@ -12,6 +13,55 @@ module SocialProfile
|
|
12
13
|
def fetch_friends_count
|
13
14
|
client.user.followers_count
|
14
15
|
end
|
16
|
+
|
17
|
+
# Get last limited tweets from user_timeline, max 200 by query
|
18
|
+
#
|
19
|
+
def last_posts(uid, options = {})
|
20
|
+
params = {
|
21
|
+
:count => 200,
|
22
|
+
:exclude_replies => true,
|
23
|
+
:trim_user => true,
|
24
|
+
:include_rts => false
|
25
|
+
}
|
26
|
+
|
27
|
+
params.merge!(options)
|
28
|
+
|
29
|
+
with_atterms do
|
30
|
+
client.user_timeline(uid, params)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def get_all_tweets(uid, options = {})
|
35
|
+
collect_with_max_id do |max_id|
|
36
|
+
options[:max_id] = max_id unless max_id.nil?
|
37
|
+
last_posts(uid, options)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def collect_with_max_id(collection=[], max_id=nil, &block)
|
42
|
+
response = yield(max_id)
|
43
|
+
collection += response
|
44
|
+
response.empty? ? collection.flatten : collect_with_max_id(collection, response.last.id - 1, &block)
|
45
|
+
end
|
46
|
+
|
47
|
+
def with_atterms
|
48
|
+
num_attempts = 0
|
49
|
+
|
50
|
+
begin
|
51
|
+
num_attempts += 1
|
52
|
+
yield if block_given?
|
53
|
+
rescue ::Twitter::Error::TooManyRequests => error
|
54
|
+
if num_attempts <= MAX_ATTEMPTS
|
55
|
+
# NOTE: Your process could go to sleep for up to 15 minutes but if you
|
56
|
+
# retry any sooner, it will almost certainly fail with the same exception.
|
57
|
+
sleep error.rate_limit.reset_in
|
58
|
+
retry
|
59
|
+
else
|
60
|
+
raise
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
15
65
|
|
16
66
|
protected
|
17
67
|
|
@@ -33,12 +33,198 @@ module SocialProfile
|
|
33
33
|
|
34
34
|
counters["friends"].to_i + counters["followers"].to_i
|
35
35
|
end
|
36
|
+
|
37
|
+
# Get last limited posts from user_timeline, max 100 by query
|
38
|
+
#
|
39
|
+
def last_posts(options = {})
|
40
|
+
params = {
|
41
|
+
:owner_id => user.identifier,
|
42
|
+
:count => 100,
|
43
|
+
:filter => "owner",
|
44
|
+
:offset => 0
|
45
|
+
}
|
46
|
+
|
47
|
+
params.merge!(options)
|
48
|
+
|
49
|
+
fetch_all_method_items_with_days("wall.get", params)
|
50
|
+
end
|
51
|
+
|
52
|
+
# Get last posts by N days from user_timeline
|
53
|
+
#
|
54
|
+
def last_post_by_days(days, options = {})
|
55
|
+
options = { :days => days }.merge(options)
|
56
|
+
|
57
|
+
last_posts(options)
|
58
|
+
end
|
59
|
+
|
60
|
+
# Get object likes (post, comment, photo, audio, video, note, photo_comment, video_comment, topic_comment, sitepage)
|
61
|
+
#
|
62
|
+
def object_likes(uid, options = {})
|
63
|
+
fetch_all = options.delete(:fetch_all)
|
64
|
+
|
65
|
+
params = {
|
66
|
+
:owner_id => user.identifier,
|
67
|
+
:count => 1000,
|
68
|
+
:type => "post",
|
69
|
+
:item_id => uid,
|
70
|
+
:offset => 0
|
71
|
+
}
|
72
|
+
params.merge!(options)
|
73
|
+
|
74
|
+
if fetch_all
|
75
|
+
return fetch_all_method_items("likes.getList", params)
|
76
|
+
end
|
77
|
+
|
78
|
+
|
79
|
+
user.likes.getList(params)
|
80
|
+
end
|
81
|
+
|
82
|
+
# Get post comments
|
83
|
+
#
|
84
|
+
def post_comments(uid, options = {})
|
85
|
+
fetch_all = options.delete(:fetch_all)
|
86
|
+
|
87
|
+
params = {
|
88
|
+
:owner_id => user.identifier,
|
89
|
+
:count => 100,
|
90
|
+
:preview_length => 0,
|
91
|
+
:need_likes => 1,
|
92
|
+
:post_id => uid,
|
93
|
+
:offset => 0
|
94
|
+
}
|
95
|
+
params.merge!(options)
|
96
|
+
|
97
|
+
if fetch_all
|
98
|
+
return fetch_all_method_items("wall.getComments", params)
|
99
|
+
end
|
100
|
+
|
101
|
+
user.wall.getComments(params)
|
102
|
+
end
|
103
|
+
|
104
|
+
# Get post shares
|
105
|
+
#
|
106
|
+
def post_shares(uid, options = {})
|
107
|
+
fetch_all = options.delete(:fetch_all)
|
108
|
+
|
109
|
+
params = {
|
110
|
+
:owner_id => user.identifier,
|
111
|
+
:count => 1000,
|
112
|
+
:post_id => uid,
|
113
|
+
:offset => 0
|
114
|
+
}
|
115
|
+
params.merge!(options)
|
116
|
+
|
117
|
+
if fetch_all
|
118
|
+
return fetch_all_method_items("wall.getReposts", params)
|
119
|
+
end
|
120
|
+
|
121
|
+
user.wall.getReposts(params)
|
122
|
+
end
|
123
|
+
|
124
|
+
# Get all photos comments
|
125
|
+
#
|
126
|
+
def photos_comments(options = {})
|
127
|
+
params = {
|
128
|
+
:owner_id => user.identifier,
|
129
|
+
:count => 100,
|
130
|
+
:need_likes => 1,
|
131
|
+
:offset => 0
|
132
|
+
}
|
133
|
+
|
134
|
+
params.merge!(options)
|
135
|
+
|
136
|
+
fetch_all_method_items_with_days("photos.getAllComments", params)
|
137
|
+
end
|
138
|
+
|
139
|
+
# Get all photos comments by days
|
140
|
+
#
|
141
|
+
def photos_comments_by_days(days, options = {})
|
142
|
+
options = { :days => days }.merge(options)
|
143
|
+
|
144
|
+
photos_comments(options)
|
145
|
+
end
|
146
|
+
|
147
|
+
# Get all friends list
|
148
|
+
#
|
149
|
+
def friends(options={})
|
150
|
+
options = {
|
151
|
+
:count => 5000,
|
152
|
+
:offset => 0,
|
153
|
+
:fields => "domain"
|
154
|
+
}.merge(options)
|
155
|
+
|
156
|
+
fetch_all_method_items(:fetch_friends, options)
|
157
|
+
end
|
158
|
+
|
159
|
+
# Get all followers list
|
160
|
+
#
|
161
|
+
def followers(options={})
|
162
|
+
options = {
|
163
|
+
:count => 1000,
|
164
|
+
:offset => 0,
|
165
|
+
:fields => "screen_name"
|
166
|
+
}.merge(options)
|
167
|
+
|
168
|
+
fetch_all_method_items(:fetch_followers, options)
|
169
|
+
end
|
36
170
|
|
37
171
|
protected
|
38
172
|
|
39
173
|
def user
|
40
174
|
@user ||= ::Vkontakte::App::User.new(uid, :access_token => access_token)
|
41
175
|
end
|
176
|
+
|
177
|
+
def fetch_all_method_items(name, options)
|
178
|
+
methods = name.to_s.split(".")
|
179
|
+
response = methods.size == 2 ? user.send(methods[0]).send(methods[1], options) : user.send(name, options)
|
180
|
+
|
181
|
+
_items = response["items"]
|
182
|
+
return [] if _items.blank?
|
183
|
+
|
184
|
+
iteration = (response["count"].to_i / _items.size.to_f).ceil
|
185
|
+
|
186
|
+
iteration.times do |index|
|
187
|
+
next if index == 0
|
188
|
+
|
189
|
+
options[:offset] += options[:count]
|
190
|
+
_items += (methods.size == 2 ? user.send(methods[0]).send(methods[1], options) : user.send(name, options))["items"]
|
191
|
+
end
|
192
|
+
|
193
|
+
_items
|
194
|
+
end
|
195
|
+
|
196
|
+
def fetch_all_method_items_with_days(name, options)
|
197
|
+
days = options.delete(:days)
|
198
|
+
date_end = options.delete(:date_end)
|
199
|
+
|
200
|
+
methods = name.to_s.split(".")
|
201
|
+
response = methods.size == 2 ? user.send(methods[0]).send(methods[1], options) : user.send(name, options)
|
202
|
+
|
203
|
+
return [] if response.blank? || !response.is_a?(Hash)
|
204
|
+
|
205
|
+
_items = response["items"]
|
206
|
+
return [] if _items.blank?
|
207
|
+
|
208
|
+
if days
|
209
|
+
date = (date_end || Time.now) - days.days
|
210
|
+
iteration = (response["count"].to_i / _items.size.to_f).ceil
|
211
|
+
last_date = _items.last ? Time.at(_items.last["date"].to_i).to_datetime : nil
|
212
|
+
|
213
|
+
iteration.times do |index|
|
214
|
+
next if index == 0
|
215
|
+
|
216
|
+
options[:offset] += options[:count]
|
217
|
+
_items += (methods.size == 2 ? user.send(methods[0]).send(methods[1], options) : user.send(name, options))["items"]
|
218
|
+
|
219
|
+
last_date = _items.last ? Time.at(_items.last["date"].to_i).to_datetime : nil
|
220
|
+
break if last_date.blank? || last_date < date
|
221
|
+
end if !last_date.blank? && last_date > date
|
222
|
+
|
223
|
+
return _items.select { |item| Time.at(item["date"].to_i).to_datetime > date }
|
224
|
+
end
|
225
|
+
|
226
|
+
_items
|
227
|
+
end
|
42
228
|
end
|
43
229
|
|
44
230
|
class Album
|
@@ -0,0 +1,74 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module SocialProfile
|
4
|
+
module Providers
|
5
|
+
class Odnoklassniki < Base
|
6
|
+
|
7
|
+
def picture_url
|
8
|
+
@picture_url ||= begin
|
9
|
+
url = info('image').gsub("photoType=4", "photoType=3")
|
10
|
+
check_url(url)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def profile_url
|
15
|
+
@profile_url ||= begin
|
16
|
+
urls = info('urls')
|
17
|
+
urls.nil? ? nil : urls['Odnoklassniki']
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# 0 - unknown
|
22
|
+
# 1 - female
|
23
|
+
# 2 - male
|
24
|
+
# Возвращаемые значения: 1 - женский, 2 - мужской, 0 - без указания пола.
|
25
|
+
def gender
|
26
|
+
@gender ||= case extra('raw_info')['gender']
|
27
|
+
when 'male' then 2
|
28
|
+
when 'female' then 1
|
29
|
+
else 0
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def birthday
|
34
|
+
@birthday ||= begin
|
35
|
+
Date.strptime(extra('raw_info')['birthday'],'%m/%d/%Y')
|
36
|
+
rescue Exception => e
|
37
|
+
nil
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def city_name
|
42
|
+
@city_name ||= begin
|
43
|
+
location('city')
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def location?
|
48
|
+
raw_info? && extra('raw_info')['location'] && extra('raw_info')['location'].is_a?(Hash)
|
49
|
+
end
|
50
|
+
|
51
|
+
def location(key)
|
52
|
+
if location? && Utils.exists?(extra('raw_info')['location'][key])
|
53
|
+
extra('raw_info')['location'][key]
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
protected
|
58
|
+
|
59
|
+
def check_url(url)
|
60
|
+
response = Utils.head(url, :follow_redirects => false)
|
61
|
+
|
62
|
+
if response.code == 302 && response.headers['location']
|
63
|
+
[response.headers['location']].flatten.first
|
64
|
+
else
|
65
|
+
url
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def raw_info?
|
70
|
+
extra('raw_info') && extra('raw_info').is_a?(Hash)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
data/lib/social_profile.rb
CHANGED
@@ -11,6 +11,7 @@ module SocialProfile
|
|
11
11
|
autoload :Vkontakte, "social_profile/providers/vkontakte"
|
12
12
|
autoload :Twitter, "social_profile/providers/twitter"
|
13
13
|
autoload :Instagram, "social_profile/providers/instagram"
|
14
|
+
autoload :Odnoklassniki, "social_profile/providers/odnoklassniki"
|
14
15
|
end
|
15
16
|
|
16
17
|
module People
|
@@ -27,6 +28,7 @@ module SocialProfile
|
|
27
28
|
when "vkontakte" then Providers::Vkontakte
|
28
29
|
when "twitter" then Providers::Twitter
|
29
30
|
when "instagram" then Providers::Instagram
|
31
|
+
when "odnoklassniki" then Providers::Odnoklassniki
|
30
32
|
else Providers::Base
|
31
33
|
end
|
32
34
|
|
data/social_profile.gemspec
CHANGED
@@ -21,9 +21,9 @@ Gem::Specification.new do |spec|
|
|
21
21
|
spec.add_development_dependency "bundler", "~> 1.3"
|
22
22
|
spec.add_development_dependency "rake"
|
23
23
|
|
24
|
-
spec.add_dependency "fb_graph"
|
25
|
-
spec.add_dependency "vkontakte"
|
26
|
-
spec.add_dependency "twitter"
|
24
|
+
spec.add_dependency "fb_graph", '~> 2.7.16'
|
25
|
+
spec.add_dependency "vkontakte", '~> 0.0.6'
|
26
|
+
spec.add_dependency "twitter", '~> 5.11.0'
|
27
27
|
spec.add_dependency "httpclient"
|
28
28
|
spec.add_dependency "multi_json"
|
29
29
|
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
{
|
2
|
+
"data": [
|
3
|
+
{
|
4
|
+
"name": "Sergey Kochergan",
|
5
|
+
"id": "100002162037770"
|
6
|
+
},
|
7
|
+
{
|
8
|
+
"name": "Lyudmila Bublik",
|
9
|
+
"id": "100006720518271"
|
10
|
+
},
|
11
|
+
{
|
12
|
+
"name": "Victoria Zhurbas",
|
13
|
+
"id": "1425672521"
|
14
|
+
},
|
15
|
+
{
|
16
|
+
"name": "Марина Николаева",
|
17
|
+
"id": "100002446576144"
|
18
|
+
},
|
19
|
+
{
|
20
|
+
"name": "Alex Filatov",
|
21
|
+
"id": "1198544135"
|
22
|
+
}
|
23
|
+
],
|
24
|
+
"paging": {
|
25
|
+
"cursors": {
|
26
|
+
"after": "MTE5ODU0NDEzNQ==",
|
27
|
+
"before": "MTAwMDAyMTYyMDM3Nzcw"
|
28
|
+
},
|
29
|
+
"next": "https://graph.facebook.com/v1.0/100000730417342/subscribers?limit=5&after=MTE5ODU0NDEzNQ=="
|
30
|
+
},
|
31
|
+
"summary": {
|
32
|
+
"total_count": 14
|
33
|
+
}
|
34
|
+
}
|
@@ -0,0 +1,35 @@
|
|
1
|
+
{
|
2
|
+
"data": [
|
3
|
+
{
|
4
|
+
"name": "Max Solomianyi",
|
5
|
+
"id": "100000419905855"
|
6
|
+
},
|
7
|
+
{
|
8
|
+
"name": "Олег Гардаш",
|
9
|
+
"id": "100001535481251"
|
10
|
+
},
|
11
|
+
{
|
12
|
+
"name": "Oleg Pavlov",
|
13
|
+
"id": "100004742075897"
|
14
|
+
},
|
15
|
+
{
|
16
|
+
"name": "Тепли Викна",
|
17
|
+
"id": "100003304746675"
|
18
|
+
},
|
19
|
+
{
|
20
|
+
"name": "Rashed Mohammad",
|
21
|
+
"id": "100004427467621"
|
22
|
+
}
|
23
|
+
],
|
24
|
+
"paging": {
|
25
|
+
"cursors": {
|
26
|
+
"after": "MTAwMDA0NDI3NDY3NjIx",
|
27
|
+
"before": "MTAwMDAwNDE5OTA1ODU1"
|
28
|
+
},
|
29
|
+
"previous": "https://graph.facebook.com/v1.0/100000730417342/subscribers?limit=5&before=MTAwMDAwNDE5OTA1ODU1",
|
30
|
+
"next": "https://graph.facebook.com/v1.0/100000730417342/subscribers?limit=5&after=MTAwMDA0NDI3NDY3NjIx"
|
31
|
+
},
|
32
|
+
"summary": {
|
33
|
+
"total_count": 14
|
34
|
+
}
|
35
|
+
}
|
@@ -0,0 +1,26 @@
|
|
1
|
+
{
|
2
|
+
"data": [
|
3
|
+
{
|
4
|
+
"name": "Zyazyaveka Ad Critic",
|
5
|
+
"id": "100001860144695"
|
6
|
+
},
|
7
|
+
{
|
8
|
+
"name": "Aleksandr Mykoliuk",
|
9
|
+
"id": "1043306710"
|
10
|
+
},
|
11
|
+
{
|
12
|
+
"name": "Solmaz Fooladi",
|
13
|
+
"id": "1413023193"
|
14
|
+
}
|
15
|
+
],
|
16
|
+
"paging": {
|
17
|
+
"cursors": {
|
18
|
+
"after": "MTQxMzAyMzE5Mw==",
|
19
|
+
"before": "MTAwMDAxODYwMTQ0Njk1"
|
20
|
+
},
|
21
|
+
"previous": "https://graph.facebook.com/v1.0/100000730417342/subscribers?limit=5&before=MTAwMDAxODYwMTQ0Njk1"
|
22
|
+
},
|
23
|
+
"summary": {
|
24
|
+
"total_count": 14
|
25
|
+
}
|
26
|
+
}
|
@@ -1 +1 @@
|
|
1
|
-
{"id":7505382,"id_str":"7505382","name":"Erik Michaels-Ober","screen_name":"sferik","location":"","description":"May contain forward-looking statements.","url":"https:\/\/t.co\/L2xIBazMPf","entities":{"url":{"urls":[{"url":"https:\/\/t.co\/L2xIBazMPf","expanded_url":"https:\/\/github.com\/sferik","display_url":"github.com\/sferik","indices":[0,23]}]},"description":{"urls":[]}},"protected":false,"followers_count":
|
1
|
+
{"id":7505382,"id_str":"7505382","name":"Erik Michaels-Ober","screen_name":"sferik","location":"","description":"May contain forward-looking statements.","url":"https:\/\/t.co\/L2xIBazMPf","entities":{"url":{"urls":[{"url":"https:\/\/t.co\/L2xIBazMPf","expanded_url":"https:\/\/github.com\/sferik","display_url":"github.com\/sferik","indices":[0,23]}]},"description":{"urls":[]}},"protected":false,"followers_count":69,"friends_count":361,"listed_count":238,"created_at":"Mon Jul 16 12:59:01 +0000 2007","favourites_count":8976,"utc_offset":3600,"time_zone":"Berlin","geo_enabled":true,"verified":false,"statuses_count":13844,"lang":"en","status":{"created_at":"Wed Mar 19 00:50:35 +0000 2014","id":446086297866993665,"id_str":"446086297866993665","text":"RT @AntonWSJ: Okean Elzy, #Ukraine's biggest rock band, performed in Berlin tonight amid many \"Glory to Ukraine!\" chants http:\/\/t.co\/dkIF8X\u2026","source":"\u003ca href=\"http:\/\/itunes.apple.com\/us\/app\/twitter\/id409789998?mt=12\" rel=\"nofollow\"\u003eTwitter for Mac\u003c\/a\u003e","truncated":false,"in_reply_to_status_id":null,"in_reply_to_status_id_str":null,"in_reply_to_user_id":null,"in_reply_to_user_id_str":null,"in_reply_to_screen_name":null,"geo":null,"coordinates":null,"place":null,"contributors":null,"retweeted_status":{"created_at":"Tue Mar 18 23:56:08 +0000 2014","id":446072592227909632,"id_str":"446072592227909632","text":"Okean Elzy, #Ukraine's biggest rock band, performed in Berlin tonight amid many \"Glory to Ukraine!\" chants http:\/\/t.co\/dkIF8XvFyw","source":"\u003ca href=\"http:\/\/www.apple.com\" rel=\"nofollow\"\u003eiOS\u003c\/a\u003e","truncated":false,"in_reply_to_status_id":null,"in_reply_to_status_id_str":null,"in_reply_to_user_id":null,"in_reply_to_user_id_str":null,"in_reply_to_screen_name":null,"geo":null,"coordinates":null,"place":null,"contributors":null,"retweet_count":4,"favorite_count":2,"entities":{"hashtags":[{"text":"Ukraine","indices":[12,20]}],"symbols":[],"urls":[],"user_mentions":[],"media":[{"id":446072592047538176,"id_str":"446072592047538176","indices":[107,129],"media_url":"http:\/\/pbs.twimg.com\/media\/BjDEqLkIAAAIpE4.jpg","media_url_https":"https:\/\/pbs.twimg.com\/media\/BjDEqLkIAAAIpE4.jpg","url":"http:\/\/t.co\/dkIF8XvFyw","display_url":"pic.twitter.com\/dkIF8XvFyw","expanded_url":"http:\/\/twitter.com\/AntonWSJ\/status\/446072592227909632\/photo\/1","type":"photo","sizes":{"medium":{"w":600,"h":450,"resize":"fit"},"large":{"w":1024,"h":768,"resize":"fit"},"thumb":{"w":150,"h":150,"resize":"crop"},"small":{"w":340,"h":255,"resize":"fit"}}}]},"favorited":true,"retweeted":true,"possibly_sensitive":false,"lang":"en"},"retweet_count":4,"favorite_count":0,"entities":{"hashtags":[{"text":"Ukraine","indices":[26,34]}],"symbols":[],"urls":[],"user_mentions":[{"screen_name":"AntonWSJ","name":"Anton Troianovski","id":76773876,"id_str":"76773876","indices":[3,12]}],"media":[{"id":446072592047538176,"id_str":"446072592047538176","indices":[139,140],"media_url":"http:\/\/pbs.twimg.com\/media\/BjDEqLkIAAAIpE4.jpg","media_url_https":"https:\/\/pbs.twimg.com\/media\/BjDEqLkIAAAIpE4.jpg","url":"http:\/\/t.co\/dkIF8XvFyw","display_url":"pic.twitter.com\/dkIF8XvFyw","expanded_url":"http:\/\/twitter.com\/AntonWSJ\/status\/446072592227909632\/photo\/1","type":"photo","sizes":{"medium":{"w":600,"h":450,"resize":"fit"},"large":{"w":1024,"h":768,"resize":"fit"},"thumb":{"w":150,"h":150,"resize":"crop"},"small":{"w":340,"h":255,"resize":"fit"}}}]},"favorited":true,"retweeted":true,"possibly_sensitive":false,"lang":"en"},"contributors_enabled":false,"is_translator":false,"is_translation_enabled":false,"profile_background_color":"000000","profile_background_image_url":"http:\/\/pbs.twimg.com\/profile_background_images\/677717672\/bb0b3653dcf0644e344823e0a2eb3382.png","profile_background_image_url_https":"https:\/\/pbs.twimg.com\/profile_background_images\/677717672\/bb0b3653dcf0644e344823e0a2eb3382.png","profile_background_tile":false,"profile_image_url":"http:\/\/pbs.twimg.com\/profile_images\/378800000757402331\/d8dfba561e2e94112a737f17e7d138ca_normal.jpeg","profile_image_url_https":"https:\/\/pbs.twimg.com\/profile_images\/378800000757402331\/d8dfba561e2e94112a737f17e7d138ca_normal.jpeg","profile_banner_url":"https:\/\/pbs.twimg.com\/profile_banners\/7505382\/1385736840","profile_link_color":"0084B4","profile_sidebar_border_color":"000000","profile_sidebar_fill_color":"DDEEF6","profile_text_color":"333333","profile_use_background_image":true,"default_profile":false,"default_profile_image":false,"following":false,"follow_request_sent":false,"notifications":false,"suspended":false,"needs_phone_verification":false}
|