FbRuby 0.0.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 +7 -0
- data/Gemfile +6 -0
- data/LICENSE +21 -0
- data/README.md +876 -0
- data/lib/FbRuby/chats.rb +369 -0
- data/lib/FbRuby/comments.rb +178 -0
- data/lib/FbRuby/createaccount.rb +142 -0
- data/lib/FbRuby/exceptions.rb +25 -0
- data/lib/FbRuby/facebook.rb +453 -0
- data/lib/FbRuby/groups.rb +260 -0
- data/lib/FbRuby/login.rb +297 -0
- data/lib/FbRuby/messenger.rb +272 -0
- data/lib/FbRuby/posts.rb +267 -0
- data/lib/FbRuby/settings.rb +282 -0
- data/lib/FbRuby/tempmail.rb +56 -0
- data/lib/FbRuby/user.rb +550 -0
- data/lib/FbRuby/utils.rb +412 -0
- data/lib/FbRuby.rb +21 -0
- metadata +114 -0
@@ -0,0 +1,272 @@
|
|
1
|
+
require 'uri'
|
2
|
+
require 'cgi'
|
3
|
+
require_relative 'utils.rb'
|
4
|
+
require_relative 'chats.rb'
|
5
|
+
require_relative 'exceptions.rb'
|
6
|
+
|
7
|
+
# Modul FbRuby untuk melakukan scraping web Facebook.
|
8
|
+
module FbRuby
|
9
|
+
# Class Messenger untuk mengelola pesan di Facebook Messenger.
|
10
|
+
class Messenger
|
11
|
+
|
12
|
+
# Inisialisasi objek Messenger.
|
13
|
+
#
|
14
|
+
# @param request_session [Session] Sesi permintaan yang diperlukan untuk otentikasi.
|
15
|
+
def initialize(request_session:)
|
16
|
+
@url = URI("https://mbasic.facebook.com")
|
17
|
+
@sessions = request_session
|
18
|
+
@req = @sessions.get(URI.join(@url,"/messages"))
|
19
|
+
@res = @req.parse_html
|
20
|
+
|
21
|
+
@new_message = @res.at_xpath("//a[starts-with(@href, '/messages/')]")
|
22
|
+
@message_pending = @res.at_xpath("//a[starts-with(@href,'/messages/?folder=pending')]")
|
23
|
+
@message_filter = @res.at_xpath("//a[starts-with(@href,'/messages/?folder=other')]")
|
24
|
+
@message_archive = @res.at_xpath("//a[starts-with(@href,'/messages/?folder=action') and contains(@href,'Aarchived')]")
|
25
|
+
@message_unread = @res.at_xpath("//a[starts-with(@href,'/messages/?folder=unread')]")
|
26
|
+
@message_spam = @res.at_xpath("//a[starts-with(@href,'/messages/?folder=spam')]")
|
27
|
+
end
|
28
|
+
|
29
|
+
# Mengembalikan string representasi dari objek Messenger.
|
30
|
+
#
|
31
|
+
# @return [String] Representasi string dari objek Messenger.
|
32
|
+
def to_s
|
33
|
+
return "Facebook Messenger"
|
34
|
+
end
|
35
|
+
|
36
|
+
# Mengembalikan string representasi dari objek Messenger.
|
37
|
+
#
|
38
|
+
# @return [String] Representasi string dari objek Messenger.
|
39
|
+
def inspect
|
40
|
+
return to_s
|
41
|
+
end
|
42
|
+
|
43
|
+
# Membuat chat baru dengan pengguna tertentu.
|
44
|
+
#
|
45
|
+
# @param username [String] Username pengguna Facebook.
|
46
|
+
# @return [FbRuby::Chats] Objek chat baru.
|
47
|
+
# @raise [FbRuby::Exceptions::PageNotFound] Jika pengguna tidak di temukan.
|
48
|
+
# @raise [FbRuby::Exceptions::FacebookError] Jika ada masalah dalam proses membuat chat baru.
|
49
|
+
#
|
50
|
+
# @example Membuat chat baru
|
51
|
+
# messenger = FbRuby::Messenger.new(request_session: session)
|
52
|
+
# chat = messenger.new_chat('username')
|
53
|
+
def new_chat(username)
|
54
|
+
cek = @sessions.get(URI.join(@url,username)).parse_html
|
55
|
+
raise FbRuby::Exceptions::PageNotFound.new("Akun dengan username #{@username} tidak di temukan") unless cek.at_xpath("//a[starts-with(@href,'/home.php?rand=')]").nil?
|
56
|
+
chatUrl = cek.at_xpath("//a[starts-with(@href, '/messages/thread')]")
|
57
|
+
raise FbRuby::Exceptions::FacebookError.new("Tidak dapat mengirim pesan ke #{cek.at_css('title').text}") if chatUrl.nil?
|
58
|
+
return FbRuby::Chats.new(chats_url: URI.join(@url, chatUrl['href']), request_session: @sessions)
|
59
|
+
end
|
60
|
+
|
61
|
+
#Membuat grup chat baru dengan anggota tertentu.
|
62
|
+
#
|
63
|
+
# @param members [Array, String] Daftar anggota grup atau string yang dipisahkan koma.
|
64
|
+
# @param exception [Boolean] Menentukan apakah akan mengangkat pengecualian jika gagal.
|
65
|
+
# @param message [String] Pesan awal yang dikirim ke grup.
|
66
|
+
# @return (Boolean)Method ini akan mengembalikan true jika berhasil membuat grup, dan akan mengembalikan false jika gagal membuat grup
|
67
|
+
# @raise [FbRuby::Exceptions::FacebookError] Jika tidak dapat membuat grup chat.
|
68
|
+
def new_group(members, exception: true, message: "Hello:)")
|
69
|
+
members = members.split(",") if members.class == String
|
70
|
+
urlGroup = @res.xpath_regex("//a[@href~=/^(\/friends\/selector)/]").last
|
71
|
+
raise FbRuby::Exceptions::FacebookError.new("Tidak dapat membuat grup chat:(") if urlGroup.nil?
|
72
|
+
html = @sessions.get(URI.join(@url, urlGroup['href'])).parse_html
|
73
|
+
suges = html.xpath("//input[@name = 'friend_ids[]']")
|
74
|
+
raise FbRuby::Exceptions::FacebookError.new("Akun facebook kamu tidak memiliki teman, tambahkan teman agar bisa membuat pesan grup") if suges.length == 0
|
75
|
+
form = html.xpath_regex("//form[@action~=/^(\/friends\/selector)/]").first
|
76
|
+
formUrl = URI.join(@url, form['action'])
|
77
|
+
formData = {}
|
78
|
+
ids = []
|
79
|
+
form.css("input[type = 'hidden']").each{|i| formData[i['name']] = i['value']}
|
80
|
+
|
81
|
+
for name in members
|
82
|
+
name = name.to_s if name.class != String
|
83
|
+
name.strip!
|
84
|
+
if !name.match(/^\d+$/)
|
85
|
+
data = formData.clone
|
86
|
+
data['search'] = 'Search'
|
87
|
+
data['query'] = name
|
88
|
+
cari = @sessions.post(formUrl, data = data).parse_html
|
89
|
+
result = cari.xpath("//input[@name = 'friend_ids[]' and not(@checked)]")
|
90
|
+
raise FbRuby::Exceptions::FacebookError.new("Akun dengan nama #{name}, tidak di temukan dari daftar teman:(") if result.length == 0 and exception
|
91
|
+
ids << result.first['value'] if result.length > 0
|
92
|
+
else
|
93
|
+
ids << name
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
formData['friend_ids[]'] = ids.join(' , ')
|
98
|
+
formData['done'] = "Submit"
|
99
|
+
buat = @sessions.post(formUrl, data = formData).parse_html
|
100
|
+
buatForm = buat.xpath_regex("//form[@action~=/^(\/messages\/send)/]").first
|
101
|
+
buatData = {}
|
102
|
+
raise FbRuby::Exceptions::FacebookError.new("Gagal membuat grup chat:(") if buatForm.nil?
|
103
|
+
buatForm.xpath("//input[@type = 'hidden']").each{|i| buatData[i['name']] = i['value']}
|
104
|
+
ids.each{|i|
|
105
|
+
puts i
|
106
|
+
buatData["ids[#{i}]"] = i
|
107
|
+
buatData["text_ids[#{i}]"] = i
|
108
|
+
}
|
109
|
+
buatData['body'] = message
|
110
|
+
buatData['Send'] = 'Submit'
|
111
|
+
action = @sessions.post(URI.join(@url, buatForm['action']), data = buatData)
|
112
|
+
return action.ok?
|
113
|
+
end
|
114
|
+
|
115
|
+
# Mendapatkan chat yang perlu persetujuan
|
116
|
+
#
|
117
|
+
# @param limit [Integer] jumblah maksimal pesan yang di ambil, minimal limit adalah 1
|
118
|
+
# @return [Array<Chats>] method ini akan mengembalikan Array yang di dalamnya terdapat object Chats
|
119
|
+
def get_chat_pending(limit)
|
120
|
+
return getChat(@message_pending, limit)
|
121
|
+
end
|
122
|
+
|
123
|
+
# Mendapatkan chat yang di filter
|
124
|
+
#
|
125
|
+
# @param limit [Integer] jumblah maksimal pesan yang di ambil, minimal limit adalah 1
|
126
|
+
# @return [Array<Chats>] method ini akan mengembalikan Array yang di dalamnya terdapat object Chats
|
127
|
+
def get_chat_filter(limit)
|
128
|
+
return getChat(@message_filter, limit)
|
129
|
+
end
|
130
|
+
|
131
|
+
|
132
|
+
# Mendapatkan chat yang di arsip
|
133
|
+
#
|
134
|
+
# @param limit [Integer] jumblah maksimal pesan yang di ambil, minimal limit adalah 1
|
135
|
+
# @return [Array<Chats>] method ini akan mengembalikan Array yang di dalamnya terdapat object Chats
|
136
|
+
def get_chat_archive(limit)
|
137
|
+
return getChat(@message_archive, limit)
|
138
|
+
end
|
139
|
+
|
140
|
+
|
141
|
+
# Mendapatkan chat yang belum di baca
|
142
|
+
#
|
143
|
+
# @param limit [Integer] jumblah maksimal pesan yang di ambil, minimal limit adalah 1
|
144
|
+
# @return [Array<Chats>] method ini akan mengembalikan Array yang di dalamnya terdapat object Chats
|
145
|
+
def get_chat_unread(limit)
|
146
|
+
return getChat(@message_unread, limit)
|
147
|
+
end
|
148
|
+
|
149
|
+
|
150
|
+
# Mendapatkan chat yang ada di dalam folder spam
|
151
|
+
#
|
152
|
+
# @param limit [Integer] jumblah maksimal pesan yang di ambil, minimal limit adalah 1
|
153
|
+
# @return [Array<Chats>] method ini akan mengembalikan Array yang di dalamnya terdapat object Chats
|
154
|
+
def get_chat_spam(limit)
|
155
|
+
return getChat(@message_spam, limit)
|
156
|
+
end
|
157
|
+
|
158
|
+
# Mendapatkan chat terbaru
|
159
|
+
#
|
160
|
+
# @param limit [Integer] jumblah maksimal pesan yang di ambil, minimal limit adalah 1
|
161
|
+
# @return [Array<Chats>] method ini akan mengembalikan Array yang di dalamnya terdapat object Chats
|
162
|
+
def get_new_chat(limit)
|
163
|
+
return getChat(@new_message, limit)
|
164
|
+
end
|
165
|
+
|
166
|
+
# Mendapatkan pesan terbaru
|
167
|
+
#
|
168
|
+
# @param limit [Integer] jumblah maksimal pesan yang di ambil, minimal limit adalah 1
|
169
|
+
# @return [Array<Hash>] method ini akan mengembalikan Array yang di dalamnya terdapat Hash yang memuat informasi chat
|
170
|
+
def get_new_message(limit)
|
171
|
+
return getMessage(@new_message, limit)
|
172
|
+
end
|
173
|
+
|
174
|
+
# Mendapatkan pesan yang perlu persetujuan
|
175
|
+
#
|
176
|
+
# @param limit [Integer] jumblah maksimal pesan yang di ambil, minimal limit adalah 1
|
177
|
+
# @return [Array<Hash>] method ini akan mengembalikan Array yang di dalamnya terdapat Hash yang memuat informasi chat
|
178
|
+
def get_message_pending(limit)
|
179
|
+
return getMessage(@message_pending, limit)
|
180
|
+
end
|
181
|
+
|
182
|
+
# Mendapatkan pesan yang di filter
|
183
|
+
#
|
184
|
+
# @param limit [Integer] jumblah maksimal pesan yang di ambil, minimal limit adalah 1
|
185
|
+
# @return [Array<Hash>] method ini akan mengembalikan Array yang di dalamnya terdapat Hash yang memuat informasi chat
|
186
|
+
def get_message_filter(limit)
|
187
|
+
return getMessage(@message_filter, limit)
|
188
|
+
end
|
189
|
+
|
190
|
+
# Mendapatkan pesan yang di arsip
|
191
|
+
#
|
192
|
+
# @param limit [Integer] jumblah maksimal pesan yang di ambil, minimal limit adalah 1
|
193
|
+
# @return [Array<Hash>] method ini akan mengembalikan Array yang di dalamnya terdapat Hash yang memuat informasi chat
|
194
|
+
def get_message_archive(limit)
|
195
|
+
return getMessage(@message_archive, limit)
|
196
|
+
end
|
197
|
+
|
198
|
+
|
199
|
+
# Mendapatkan pesan yang belum di baca
|
200
|
+
#
|
201
|
+
# @param limit [Integer] jumblah maksimal pesan yang di ambil, minimal limit adalah 1
|
202
|
+
# @return [Array<Hash>] method ini akan mengembalikan Array yang di dalamnya terdapat Hash yang memuat informasi chat
|
203
|
+
def get_message_unread(limit)
|
204
|
+
return getMessage(@message_unread, limit)
|
205
|
+
end
|
206
|
+
|
207
|
+
# Mendapatkan pesan yang ada di folder spam
|
208
|
+
#
|
209
|
+
# @param limit [Integer] jumblah maksimal pesan yang di ambil, minimal limit adalah 1
|
210
|
+
# @return [Array<Hash>] method ini akan mengembalikan Array yang di dalamnya terdapat Hash yang memuat informasi chat
|
211
|
+
def get_message_spam(limit)
|
212
|
+
return getMessage(@message_spam, limit)
|
213
|
+
end
|
214
|
+
|
215
|
+
|
216
|
+
private
|
217
|
+
# Private method untuk scraping chat html
|
218
|
+
#
|
219
|
+
# @param url [String] URL percakapan di Facebook Messenger.
|
220
|
+
# @param limit [Integer] Jumlah maksimum pesan yang diambil.
|
221
|
+
# @return [Array<Hash>] Array dari pesan yang diambil.
|
222
|
+
def getMessage(url, limit)
|
223
|
+
msgArray = []
|
224
|
+
return msgArray if url.nil?
|
225
|
+
msgUrl = URI.join(@url, url['href'])
|
226
|
+
limit.times do
|
227
|
+
html = @sessions.get(msgUrl).parse_html
|
228
|
+
for data in html.css("a[href^='/messages/read'][href*='#fua']")
|
229
|
+
chat_url = URI.join(@url, data['href']).to_s
|
230
|
+
data = data.ancestors("div")
|
231
|
+
name = data.at_css("a[href^='/messages/read']")
|
232
|
+
message = data.at_css("span[class]")
|
233
|
+
waktu = data.at_css("abbr")
|
234
|
+
uid = nil
|
235
|
+
|
236
|
+
uid = CGI.unescape(name['href']).match(/tid=cid\.(?:c|g)\.(\d+)/)[1] if !name.nil?
|
237
|
+
message = message.text if !message.nil?
|
238
|
+
waktu = waktu.text if !message.nil?
|
239
|
+
name = name.text if !name.nil?
|
240
|
+
|
241
|
+
msgArray << {"name"=>name,"id"=>uid,"last_chat"=>message,"chat_url"=>chat_url,"time"=>waktu}
|
242
|
+
break if msgArray.length >= limit
|
243
|
+
end
|
244
|
+
next_url = html.xpath_regex("//a[@href~=/^(\/messages\/\?pageNum=\d(.*)selectable)/]").first
|
245
|
+
break if next_url.nil? or msgArray.length >= limit
|
246
|
+
msgUrl = URI.join(@url, next_url['href'])
|
247
|
+
end
|
248
|
+
|
249
|
+
return msgArray[0..limit]
|
250
|
+
end
|
251
|
+
|
252
|
+
# Mendapatkan chat dari percakapan tertentu.
|
253
|
+
#
|
254
|
+
# @param url [String] URL percakapan di Facebook Messenger.
|
255
|
+
# @param limit [Integer] Jumlah maksimum chat yang diambil.
|
256
|
+
# @return [Array<FbRuby::Chats>] Array dari chat yang diambil.
|
257
|
+
def getChat(url, limit)
|
258
|
+
chatsArray = []
|
259
|
+
chatsRead = getMessage(url,limit)
|
260
|
+
|
261
|
+
th = FbRuby::Utils::ThreadPool.new(size: 6)
|
262
|
+
chatsRead.each{|u|
|
263
|
+
th.schedule{
|
264
|
+
chatsArray << FbRuby::Chats.new(chats_url: u['chat_url'], request_session: @sessions)
|
265
|
+
}
|
266
|
+
}
|
267
|
+
th.shutdown
|
268
|
+
|
269
|
+
return chatsArray[0..limit]
|
270
|
+
end
|
271
|
+
end
|
272
|
+
end
|
data/lib/FbRuby/posts.rb
ADDED
@@ -0,0 +1,267 @@
|
|
1
|
+
require 'uri'
|
2
|
+
require_relative 'utils.rb'
|
3
|
+
require_relative 'comments.rb'
|
4
|
+
require_relative 'exceptions.rb'
|
5
|
+
|
6
|
+
module FbRuby
|
7
|
+
# class Posts di gunakan untuk parsing postingan facebook
|
8
|
+
class Posts
|
9
|
+
|
10
|
+
@@REGEX_URL = Regexp.new(/https:\/\/((?:(?:.*?)\.facebook.com|facebook\.com)\/((\d+|groups|[a-zA-Z0-9_.-]+)\/(\d+|posts|videos|\w+)\/(?:\d+|permalink\/\d+|\w+)|story\.php\?story_fbid|photo\.php\?fbid=\w+|watch(?:\/\?|\?)v=\d+)|fb\.(?:gg|watch)\/\w+)/)
|
11
|
+
@@REACT_TYPE = {"1"=>"like", "2"=>"love", "3"=>"wow", "4"=>"haha", "7"=>"sad", "8"=>"angry", "16"=>"care"}
|
12
|
+
@@REACT_LIST = ["like", "love", "care", "haha", "wow", "sad", "angry"]
|
13
|
+
attr_reader :post_url, :author, :author_url, :caption, :post_url, :post_file, :upload_time, :can_comment
|
14
|
+
|
15
|
+
def self.REACT_TYPE
|
16
|
+
return @@REACT_TYPE
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.REACT_LIST
|
20
|
+
return @@REACT_LIST
|
21
|
+
end
|
22
|
+
|
23
|
+
# Inisialisasi object Posts
|
24
|
+
#
|
25
|
+
# @param post_url [String] Url postingan facebook
|
26
|
+
# @param request_session [Session] Object Session
|
27
|
+
def initialize(post_url:, request_session:)
|
28
|
+
raise FbRuby::Exceptions::FacebookError.new("#{post_url} bukanlah url yang valid, silahkan cek lagi post url anda:)") unless @@REGEX_URL.match?(post_url)
|
29
|
+
if post_url.to_s.match?(/https:\/\/fb\.watch\/(?:.*?)\//)
|
30
|
+
vidId = post_url.to_s.match(/https:\/\/fb\.watch\/(.*?)\//)
|
31
|
+
post_url = "https://fb.gg/v/#{vidId}/" unless vidId.nil?
|
32
|
+
end
|
33
|
+
|
34
|
+
@url = URI("https://mbasic.facebook.com/")
|
35
|
+
@sessions = request_session
|
36
|
+
@post_url = URI(post_url.to_s)
|
37
|
+
@post_url.hostname = @url.hostname if @post_url.hostname != @url.hostname
|
38
|
+
|
39
|
+
@html = @sessions.get(@post_url).parse_html
|
40
|
+
@div_article = @html.at_xpath("//div[@role = 'article']")
|
41
|
+
|
42
|
+
unless @div_article.nil?
|
43
|
+
@html = @div_article
|
44
|
+
url = @html.xpath_regex("//a[@href~=/(^\/story\.php(.*)footer_action_list|https:\/\/(.*)\.facebook\.com\/groups\/\d+\/permalink)/]").first
|
45
|
+
@html = @sessions.get(URI.join(@url, url['href'])).parse_html unless url.nil?
|
46
|
+
end
|
47
|
+
|
48
|
+
@div_post = @html.at_xpath("//div[@data-ft and @id]")
|
49
|
+
@div_post = @html if @div_post.nil?
|
50
|
+
@post_file = {"image"=>[],"video"=>[]}
|
51
|
+
@form_komen = @html.at_xpath("//form[starts-with(@action,'/a/comment.php')]")
|
52
|
+
@like_action = @html.at_xpath("//a[starts-with(@href,'/a/like.php')]")
|
53
|
+
@react_url = @html.at_xpath("//a[starts-with(@href,'/reactions/picker')]")
|
54
|
+
@data = {}
|
55
|
+
@html.css("input[type = 'hidden'][name][value]").each{|d| @data[d['name']] = d['value']}
|
56
|
+
@auhor_url = nil
|
57
|
+
@author = @div_post.at_xpath("//a[@class = 'actor-link']")
|
58
|
+
@author = @div_post.at_css('a[href]:not([class])')
|
59
|
+
@caption = @div_post.css('p').map(&:text).join("\n")
|
60
|
+
@upload_time = @div_post.at_css('abbr')
|
61
|
+
@upload_time = @upload_time.text unless @upload_time.nil?
|
62
|
+
@can_comment = !@form_komen.nil?
|
63
|
+
|
64
|
+
unless @author.nil?
|
65
|
+
@author_url = URI.join(@url, @author['href'])
|
66
|
+
@author = @author.text
|
67
|
+
end
|
68
|
+
|
69
|
+
for tiaraMaharani in @div_post.css("a[href^='/photo.php'], a[href*='photos']")
|
70
|
+
yayaData = {"link"=>nil,"id"=>nil,"preview"=>nil,"content-type"=>"image"}
|
71
|
+
photo = URI.join(@url, tiaraMaharani['href'])
|
72
|
+
thubmnail = tiaraMaharani.at_css('img')
|
73
|
+
fullPhoto = @sessions.get(photo).parse_html.xpath_regex("//img[@src~=/^https:\/\/(?:z-m-scontent|scontent)/]").first
|
74
|
+
|
75
|
+
yayaData['link'] = fullPhoto['src'] unless fullPhoto.nil?
|
76
|
+
yayaData['id'] = fullPhoto['src'].match(/(\d+_\d+_\d+)/)[1] unless fullPhoto.nil?
|
77
|
+
yayaData['preview'] = thubmnail['src'] unless thubmnail.nil?
|
78
|
+
@post_file['image'] << yayaData
|
79
|
+
end
|
80
|
+
|
81
|
+
for rahmatAdha in @div_post.css("a[href^='/video_redirect']")
|
82
|
+
matData = {"link"=>nil,"id"=>nil,"preview"=>nil,"content-type"=>"video"}
|
83
|
+
video = URI.decode_www_form_component(rahmatAdha['href']).match(/src=(.*)/)
|
84
|
+
|
85
|
+
unless video.nil?
|
86
|
+
matData['link'] = video[1]
|
87
|
+
matData['id'] = matData['link'].match(/&id=(\d+)/)[1]
|
88
|
+
matData['preview'] = rahmatAdha.at_css('img')['src']
|
89
|
+
end
|
90
|
+
|
91
|
+
@post_file['video'] << matData
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
# Mengembalikan string representasi dari objek Posts.
|
96
|
+
#
|
97
|
+
# @return [String] Representasi string dari objek Posts.
|
98
|
+
def to_s
|
99
|
+
return "Facebook Posts : author=#{@author} upload_time=#{@upload_time} post_url=#{@post_url} can_comment=#{@can_comment}"
|
100
|
+
end
|
101
|
+
|
102
|
+
# Mengembalikan string representasi dari objek Posts.
|
103
|
+
#
|
104
|
+
# @return [String] Representasi string dari objek Posts.
|
105
|
+
def inspect
|
106
|
+
return to_s
|
107
|
+
end
|
108
|
+
|
109
|
+
# Refresh page Posts
|
110
|
+
def refresh
|
111
|
+
initialize(post_url: @post_url.to_s, request_session: @sessions)
|
112
|
+
end
|
113
|
+
|
114
|
+
# Kirim komentar ke post
|
115
|
+
#
|
116
|
+
# @param message [String] Isi komentar
|
117
|
+
# @param file [String] Path file foto
|
118
|
+
# @example Kirim Komentar tanpa foto
|
119
|
+
# post.send_comment("Ini komentar")
|
120
|
+
# @example Kirim komentar dengan foto
|
121
|
+
# post.send_comment("Ini komentar dengan foto", "/sdcard/photo.jpg")
|
122
|
+
def send_comment(message, file = nil)
|
123
|
+
raise FbRuby::Exceptions::FacebookError.new("Tidak dapat memposting komentar ke postingan ini:(") unless @can_comment
|
124
|
+
formData = {}
|
125
|
+
@form_komen.css("input[type = 'hidden'][name][value]").each{|i| formData[i['name']] = i['value']}
|
126
|
+
unless file.nil?
|
127
|
+
formData['view_photo'] = "Submit"
|
128
|
+
zHtml = @sessions.post(URI.join(@url, @form_komen['action']), data = formData).parse_html
|
129
|
+
zForm = zHtml.xpath_regex("//form[@action~=/https:\/\/(z-upload\.facebook\.com|upload\.facebook\.com)/]").first
|
130
|
+
zData = {"comment_text"=>message,"post"=>"Submit"}
|
131
|
+
zForm.css("input[type = 'hidden']").each {|i| zData[i['name']] = i['value']}
|
132
|
+
return FbRuby::Utils::upload_photo(@sessions, zForm["action"], files = file, data = zData, headers = {}, separator = "|", default_key = "photo", max_number = 1).last.ok?
|
133
|
+
else
|
134
|
+
formData['comment_text'] = message
|
135
|
+
return @sessions.post(URI.join(@url, @form_komen['action']), data = formData).ok?
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
# Berikan reaksi ke postingan
|
140
|
+
#
|
141
|
+
# @param react_type [String] Jenis reaksi
|
142
|
+
def send_react(react_type)
|
143
|
+
react_type.downcase!
|
144
|
+
raise FbRuby::Exceptions::FacebookError.new("Tidak dapat memberikan react ke postingan ini:(") if @react_url.nil?
|
145
|
+
raise FbRuby::Exceptions::FacebookError.new("Invalid React Type!!") if !@@REACT_LIST.include?(react_type)
|
146
|
+
reactions = @sessions.get(URI.join(@url, @react_url['href'])).parse_html
|
147
|
+
getReact = reactions.xpath("//a[starts-with(@href,'/ufi/reaction')]")
|
148
|
+
send = @sessions.get_without_sessions(URI.join(@url,getReact[@@REACT_LIST.index(react_type)]['href']))
|
149
|
+
return send.ok?
|
150
|
+
end
|
151
|
+
|
152
|
+
# Bagikan postingan ke profile
|
153
|
+
#
|
154
|
+
# @param message[String] Caption dari postingan
|
155
|
+
# @param location[String] Nama Kota / Nama tempat
|
156
|
+
# @param feeling[String] Nama Perasaan
|
157
|
+
def share_post(message = '', location = nil, feeling = nil, **kwargs)
|
158
|
+
shareUrl = @html.at_xpath("//a[starts-with(@href,'/composer/mbasic') and contains(@href,'c_src=share')]")
|
159
|
+
raise FbRuby::Exceptions::FacebookError.new("Tidak dapat membagikan postingan ini") if shareUrl.nil?
|
160
|
+
html = @sessions.get_without_sessions(URI.join(@url, shareUrl['href'])).parse_html
|
161
|
+
return FbRuby::Utils::create_timeline(html, @sessions, message, nil, location, feeling, nil, **kwargs)
|
162
|
+
end
|
163
|
+
|
164
|
+
# Dapatkan Reaksi di postingan
|
165
|
+
#
|
166
|
+
# @return [Hash]
|
167
|
+
def get_react
|
168
|
+
reactData = {}
|
169
|
+
@@REACT_LIST.each{|i| reactData[i] = 0}
|
170
|
+
ufi = @html.at_xpath("//a[starts-with(@href,'/ufi/reaction/profile')]")
|
171
|
+
|
172
|
+
unless ufi.nil?
|
173
|
+
html = @sessions.get(URI.join(@url, ufi['href'])).parse_html
|
174
|
+
reactUrl = html.xpath("//a[starts-with(@href,'/ufi/reaction/profile') and contains(@href,'total_count') and contains(@href,'reaction_type')]")
|
175
|
+
reactUrl.each do |f|
|
176
|
+
total = (f['href'].match(/total_count=(\d+)/)[1]).to_i
|
177
|
+
type = f['href'].match(/reaction_type=(\d+)/)[1]
|
178
|
+
next unless @@REACT_TYPE.include?(type)
|
179
|
+
reactData[@@REACT_TYPE[type]] = total
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
return reactData
|
184
|
+
end
|
185
|
+
|
186
|
+
# Dapatkan Reaksi di postingan dengan user
|
187
|
+
#
|
188
|
+
# @param limit [Integer] Jumblah maksimal reaksi yang di ambil
|
189
|
+
# @return [Hash]
|
190
|
+
def get_react_with_user(limit = 10)
|
191
|
+
ufi = @html.at_xpath("//a[starts-with(@href,'/ufi/reaction/profile')]")
|
192
|
+
yaya = {}
|
193
|
+
result = []
|
194
|
+
get_react.each{|i| yaya.update({i.first=>{"user"=>[],"total_count"=>i.last}})}
|
195
|
+
|
196
|
+
unless ufi.nil?
|
197
|
+
html = @sessions.get(URI.join(@url, ufi['href'])).parse_html
|
198
|
+
reactUrl = html.xpath("//a[starts-with(@href,'/ufi/reaction/profile') and contains(@href,'total_count') and contains(@href,'reaction_type') and not(contains(@href,'reaction_type=0'))]")
|
199
|
+
thread = FbRuby::Utils::ThreadPool.new(size: reactUrl.length)
|
200
|
+
reactUrl.each do |url|
|
201
|
+
thread.schedule do
|
202
|
+
result << get_user_from_react(url,limit)
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
thread.shutdown
|
207
|
+
result.each do |r|
|
208
|
+
yaya[@@REACT_TYPE[r['react_type']]]['user'].concat(r['user'])
|
209
|
+
end
|
210
|
+
return yaya
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
# Dapatkan komentar di post
|
215
|
+
#
|
216
|
+
# @param limit [Integer] Jumblah maksimal komentar
|
217
|
+
# @return [Array<Comments>]
|
218
|
+
def get_comment(limit = 10)
|
219
|
+
comment = []
|
220
|
+
html = @html.clone
|
221
|
+
|
222
|
+
while comment.length < limit
|
223
|
+
for i in html.xpath_regex("//a[@href~=/^\/(profile\.php|[a-zA-Z0-9_.-]+\?eav)/]")
|
224
|
+
next if i['class'].nil?
|
225
|
+
div_comment = i.ancestors('div[class][id]').find { |div| div['id'] =~ /^\d+$/ }
|
226
|
+
div_comment = i.ancestors.css('div:not([class]):not([id]:not([role]))')[2] if div_comment.nil?
|
227
|
+
next if div_comment.nil?
|
228
|
+
comment << FbRuby::Comments.new(nokogiriObj: div_comment, request_session: @sessions)
|
229
|
+
end
|
230
|
+
|
231
|
+
begin
|
232
|
+
next_url = html.at_css("a[href^='/story.php'][href*='p=']")
|
233
|
+
if next_url.nil?
|
234
|
+
next_url = html.at_css("div[class][id^='see_next']")
|
235
|
+
next_url = next_url.at_css("a")
|
236
|
+
end
|
237
|
+
rescue
|
238
|
+
next_url = nil
|
239
|
+
end
|
240
|
+
|
241
|
+
break if next_url.nil? or comment.length >= limit
|
242
|
+
html = @sessions.get(URI.join(@url, next_url['href'])).parse_html
|
243
|
+
end
|
244
|
+
|
245
|
+
return comment
|
246
|
+
end
|
247
|
+
|
248
|
+
private
|
249
|
+
def get_user_from_react(url, limit)
|
250
|
+
yaya = []
|
251
|
+
react = url['href'].match(/reaction_type=(\d+)/)[1]
|
252
|
+
while yaya.length < limit
|
253
|
+
html = @sessions.get(URI.join(@url, url['href'])).parse_html
|
254
|
+
user = html.xpath_regex("//a[@href~=/^\/([a-zA-Z0-9_.-]+\?eav|profile\.php)/]")
|
255
|
+
user.each do |usr|
|
256
|
+
uid = usr['href'].match(/^\/(([a-zA-Z0-9_.-]+)\?eav|profile\.php\?id=(\d+))/)
|
257
|
+
yaya << {"name"=>usr.text,"username"=>(usr['href'].include?('profile.php') ? uid[3] : uid[2])}
|
258
|
+
end
|
259
|
+
|
260
|
+
url = html.at_xpath("//a[starts-with(@href,'/ufi/reaction/profile') and contains(@href,'shown_ids')]")
|
261
|
+
break if yaya.length >= limit or url.nil?
|
262
|
+
end
|
263
|
+
|
264
|
+
return {"react_type"=>react,"user"=>yaya[0...limit]}
|
265
|
+
end
|
266
|
+
end
|
267
|
+
end
|