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.
@@ -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
@@ -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