reddit_auto 1.0.0 → 1.1.0

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.
Files changed (3) hide show
  1. checksums.yaml +4 -4
  2. data/lib/reddit_auto.rb +433 -13
  3. metadata +1 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 93f5030b7d722f2eb99929cf9f48838e964e78840f89dd4e32bcc9da89cc12ff
4
- data.tar.gz: cf1b9fc23e4f52539f2086545cb6229cc216d7ea6772aa669eb033859055c730
3
+ metadata.gz: a8530bc55139335bb9f9603ad8278a1dbaa74e2c717a0c2985bc56c0f77f28ca
4
+ data.tar.gz: '093d9c8195bc166b696d17e6f4e8b9d744c9eafd289eee66764d31133f735d2a'
5
5
  SHA512:
6
- metadata.gz: f4631d0b5e13b58dd863e790bfb105ad2170df36c5c366ecc983be171c98187d4117d0cb7cb79872997447be8e99d5f17801e4db9f9f08259eb30a43480bf4f2
7
- data.tar.gz: 4b7f7ed4b8f6dcc711da055174531a2bc626c65949d9196c9e0b07f1cc6e896c164861cf901611ade348c1c204ced577fbd5265cf7de200e5e067c1a9efde674
6
+ metadata.gz: a84f3cf0c2c7da251eb228235b39454fb4779f62f715ebc04c851373f7b1a90dbd12f8fef8cf41281e7c47ef13beda0b9bb9c8287b87fcd465884c740b3d79fa
7
+ data.tar.gz: 60783c3ed4bf30a6124b4d3e915fbebd87b35259492b87a00881c0e442cc2c71dadd956609260c6edcae656a4f87a35f05652457ed476c5899b151f23c68c742
data/lib/reddit_auto.rb CHANGED
@@ -4,6 +4,16 @@ require 'watir'
4
4
  #Website: https://icaroaugusto.com
5
5
  #Github: https://github.com/IcaroAugusto
6
6
 
7
+ NewSub = Struct.new(
8
+ :name,
9
+ :title,
10
+ :description,
11
+ :sidebar,
12
+ :subtext,
13
+ :type,
14
+ :content
15
+ )
16
+
7
17
  class Reddit
8
18
  PAGE_MAIN = 'https://old.reddit.com/'
9
19
  PAGE_MAIN_NO_SLASH = 'https://old.reddit.com'
@@ -16,17 +26,40 @@ class Reddit
16
26
  SUBREDDIT_SUBPAGES = ['hot', 'new', 'rising', 'top', 'gilded']
17
27
  USER_SORTBYS = ['new', 'hot', 'top', 'controversial']
18
28
 
29
+ SUB_TYPES = {
30
+ 'public' => 'type_public',
31
+ 'restricted' => 'type_restricted',
32
+ 'private' => 'type_private',
33
+ 'premium only' => 'type_gold_only'
34
+ }
35
+
36
+ CONTENT_OPTIONS = {
37
+ 'any' => 'link_type_any',
38
+ 'links only' => 'link_type_link',
39
+ 'text posts only' => 'link_type_self'
40
+ }
41
+
19
42
  attr_accessor :browser
20
43
  attr_accessor :username
21
44
 
45
+ # Checks if the class has a browser assigned
46
+ #
47
+ # @return [Boolean]
22
48
  def has_browser
23
49
  return @browser != nil
24
50
  end
25
51
 
52
+ # Checks if a given account is logged in
53
+ #
54
+ # @param username [String] the account's username
55
+ # @return [Boolean] whether it is logged in or not
26
56
  def is_logged_in(username)
27
57
  return @browser.link(text: username).present?
28
58
  end
29
59
 
60
+ # Waits for a successful loggin, raises an exception if it fails to login
61
+ #
62
+ # @param username [String] the account's username
30
63
  def wait_login(username)
31
64
  count = 0.0
32
65
  while !is_logged_in(username)
@@ -38,6 +71,10 @@ class Reddit
38
71
  end
39
72
  end
40
73
 
74
+ # Logins the reddit website, raises an exception on failure
75
+ #
76
+ # @param username [String] the account's username
77
+ # @param password [String] the account's password
41
78
  def login(username, password)
42
79
  @username = username
43
80
  @browser.goto PAGE_MAIN
@@ -48,6 +85,7 @@ class Reddit
48
85
  wait_login(username)
49
86
  end
50
87
 
88
+ # Waits for logout, raises an exception on failure
51
89
  def wait_logout
52
90
  count = 0.0
53
91
  while is_logged_in(@username)
@@ -59,23 +97,32 @@ class Reddit
59
97
  end
60
98
  end
61
99
 
100
+ # Waits for logout, raises an exception on failure
62
101
  def logout
63
102
  @browser.link(text: 'logout').click
64
103
  wait_logout
65
104
  end
66
105
 
106
+ # Checks if reddit is asking if user is over 18 for nsfw content
107
+ #
108
+ # @return [Boolean] whether the prompt is present or not
67
109
  def has_over_18
68
110
  return @browser.button(name: 'over18').present?
69
111
  end
70
112
 
113
+ # Skips the are you over 18 prompt
71
114
  def skip_over_18
72
115
  @browser.button(text: 'continue').click
73
116
  end
74
117
 
118
+ # Checks if reddit is asking if user is over 18 for nsfw content, uses the new interface
119
+ #
120
+ # @return [Boolean] whether the prompt is present or not
75
121
  def has_over_18_new
76
- @browser.h3(text: 'You must be 18+ to view this community').present?
122
+ return @browser.h3(text: 'You must be 18+ to view this community').present?
77
123
  end
78
124
 
125
+ # Skips the are you over 18 prompt, uses the new interface
79
126
  def skip_over_18_new
80
127
  @browser.link(text: 'Yes').click
81
128
  end
@@ -84,26 +131,49 @@ class Reddit
84
131
  #Messages handling
85
132
  #---------------------------------------------------------------------------------
86
133
 
134
+ # Gets the type of a message
135
+ #
136
+ # @param div [Watir::Div] the div containing the message
137
+ # @return [String] the message type
87
138
  def get_message_type(div)
88
139
  return div.attribute_value('data-type')
89
140
  end
90
141
 
142
+ # Gets the post that a message belongs to
143
+ #
144
+ # @param div [Watir::Div] the div containing the message
145
+ # @return [String] a link to the post
91
146
  def get_message_post(div)
92
147
  return div.p(class: 'subject').link(class: 'title').href
93
148
  end
94
149
 
150
+ # Gets the reddit user who posted the message
151
+ #
152
+ # @param div [Watir::Div] the div containing the message
153
+ # @return [String] the username of the message's author
95
154
  def get_message_author(div)
96
155
  return div.attribute_value('data-author')
97
156
  end
98
157
 
158
+ # Gets the subreddit which the message was posted in
159
+ #
160
+ # @param div [Watir::Div] the div containing the message
161
+ # @return [String] the subreddit
99
162
  def get_message_subreddit(div)
100
163
  return div.attribute_value('data-subreddit')
101
164
  end
102
165
 
166
+ # Gets the content of the message
167
+ #
168
+ # @param div [Watir::Div] the div containing the message
169
+ # @return [String] the message's content
103
170
  def get_message_content(div)
104
171
  return div.div(class: 'md').text
105
172
  end
106
173
 
174
+ # Gets all message divs in the page
175
+ #
176
+ # @return [Array<Watir::Div>] an array containing all message divs in the page
107
177
  def get_message_divs
108
178
  all_divs = @browser.div(id: 'siteTable').divs
109
179
  result = []
@@ -113,27 +183,48 @@ class Reddit
113
183
  return result
114
184
  end
115
185
 
116
- def is_message_voted(div, type) #type is 'up' or 'down'
186
+ # Checks if a given message is voted by the logged in user
187
+ #
188
+ # @param div [Watir::Div] the div containing the message
189
+ # @param type [String] the type of vote, can be 'up' or 'down'
190
+ # @return [Boolean] whether the message is voted in the given type
191
+ def is_message_voted(div, type)
117
192
  return div.div(class: 'midcol').div(class: type + 'mod').present?
118
193
  end
119
194
 
195
+ # Gets the type of vote the given message received from the logged in user
196
+ #
197
+ # @param div [Watir::Div] the div containing the message
198
+ # @return [String, nil] returns 'up' or 'down' if voted or nil if not voted
120
199
  def get_message_vote(div)
121
200
  return 'up' if is_message_voted(div, 'up')
122
201
  return 'down' if is_message_voted(div, 'down')
123
202
  return nil
124
203
  end
125
204
 
126
- def vote_message(div, type) #type is 'up' or 'down'
205
+ # Votes the given message
206
+ #
207
+ # @param div [Watir::Div] the div containing the message
208
+ # @param type [String] the type of vote, can be 'up' or 'down'
209
+ def vote_message(div, type)
127
210
  return if is_message_voted(div, type)
128
211
  div.div(class: 'midcol').div(class: type).click
129
212
  end
130
213
 
214
+ # Replies the given message
215
+ #
216
+ # @param div [Watir::Div] the div containing the message
217
+ # @param answer [String] answer, the content of the reply
131
218
  def reply_message(div, answer)
132
219
  div.li(text: 'reply').click
133
220
  div.textarea.set answer
134
221
  div.button(text: 'save').click
135
222
  end
136
223
 
224
+ # Gets a hash object containing information about a given message
225
+ #
226
+ # @param div [Watir::Div] the div containing the message
227
+ # @return [Hash] a hash containing informaton about the given message
137
228
  def get_message(div) #returns a hash with message data
138
229
  result = {}
139
230
  result['type'] = get_message_type(div)
@@ -145,18 +236,30 @@ class Reddit
145
236
  return result
146
237
  end
147
238
 
148
- def message_move_page(direction) #directions: next for next page, prev for previous page
239
+ # Moves to the next or previous page in the message inbox
240
+ #
241
+ # @param direction [String] the direction to move, can be 'next' or 'prev'
242
+ # @return [Boolean] returns true if moved to the desired page or false if didn't because you're already in the last (move next) or first (move prev) page
243
+ def message_move_page(direction)
149
244
  button = @browser.span(class: direction + '-button')
150
245
  result = button.present?
151
246
  button.click if result
152
247
  return result
153
248
  end
154
249
 
250
+ # Opens the messages subpage, raises an exception if an unknown subpage is given
251
+ #
252
+ # @param subpage [String] the subpage to open, can be: 'inbox', 'unread', 'messages', 'comments' or 'sent'
155
253
  def open_messages_subpage(subpage)
156
254
  raise 'Unknown message subpage: ' + subpage if !MESSAGE_SUBPAGES.include? subpage
157
255
  @browser.goto PAGE_MESSAGES + subpage
158
256
  end
159
257
 
258
+ # Gets all the messages in a given subpage, raises an exception if an unknown subpage is given
259
+ #
260
+ # @param subpage [String] the subpage to open, can be: 'inbox', 'unread', 'messages', 'comments' or 'sent'
261
+ # @param all_pages [Boolean] if true will check all pages, if false will check only the first page
262
+ # @return [Array] an array containing hashes with information about all pages
160
263
  def get_messages(subpage, all_pages = false)
161
264
  open_messages_subpage(subpage)
162
265
  result = []
@@ -172,14 +275,21 @@ class Reddit
172
275
  #Submit handling
173
276
  #---------------------------------------------------------------------------------
174
277
 
278
+ # Checks if there was an error when submiting to a subreddit, typically because of the 10 minute cooldown between posts enforced by reddit
279
+ #
280
+ # @return [Boolean] whether there as an error or not
175
281
  def has_submit_error
176
- return @browser.span(text: 'you are doing that too much. try again in 9 minutes.').present?
282
+ return @browser.span(text: 'you are doing that too much. try again in').present?
177
283
  end
178
284
 
285
+ # Checks if the submit page is open
286
+ #
287
+ # @return [Boolean] whether the page is open or not
179
288
  def is_submit_open
180
289
  return @browser.textarea(name: 'title').present? || @browser.textarea(placeholder: 'Title').present?
181
290
  end
182
291
 
292
+ # Waits for the submit page to open, raises an exception if it fails to open after 10 seconds
183
293
  def wait_submit
184
294
  count = 0.0
185
295
  while is_submit_open
@@ -189,6 +299,11 @@ class Reddit
189
299
  end
190
300
  end
191
301
 
302
+ # Submits a link to the given subreddit, raises an exception on failure
303
+ #
304
+ # @param subreddit [String] the name of the subreddit to submit the link to
305
+ # @param url [String] the url to submit
306
+ # @param title [String] the title of the post
192
307
  def submit_link(subreddit, url, title)
193
308
  @browser.goto PAGE_SUBREDDIT + subreddit + '/submit'
194
309
  skip_over_18 if has_over_18
@@ -198,10 +313,16 @@ class Reddit
198
313
  wait_submit
199
314
  end
200
315
 
316
+ # Checks if the subreddit has an option to add a flair to posts
317
+ #
318
+ # @return [Boolean] whether or not it has a flair option
201
319
  def sub_has_flair
202
320
  return !@browser.div('aria-label': 'Not available for this community').present?
203
321
  end
204
322
 
323
+ # Sets the given flair to the post, does nothing if the subreddit has no flair option
324
+ #
325
+ # @param flair [String] the desired flair
205
326
  def set_flair(flair)
206
327
  return if !sub_has_flair
207
328
  @browser.div('aria-label': 'Add flair').click
@@ -213,6 +334,12 @@ class Reddit
213
334
  @browser.button(text: 'Apply').click
214
335
  end
215
336
 
337
+ # Submits a link to the given subreddit using the new interface, raises an exception on failure
338
+ #
339
+ # @param subreddit [String] the name of the subreddit to submit the link to
340
+ # @param url [String] the url to submit
341
+ # @param title [String] the title of the post
342
+ # @param flair [String, nil] the flair to add, if nil will add no flair to the post
216
343
  def submit_link_new(subreddit, url, title, flair = nil) #uses new reddit
217
344
  @browser.goto 'https://www.reddit.com/r/' + subreddit + '/submit'
218
345
  skip_over_18_new if has_over_18_new
@@ -225,6 +352,11 @@ class Reddit
225
352
  wait_submit
226
353
  end
227
354
 
355
+ # Submits a text post to the given subreddit, raises an exception on failure
356
+ #
357
+ # @param subreddit [String] the name of the subreddit to submit the link to
358
+ # @param title [String] the title of the post
359
+ # @param text [String] the text content of the post
228
360
  def submit_text(subreddit, title, text)
229
361
  @browser.goto PAGE_SUBREDDIT + subreddit + '/submit?selftext=true'
230
362
  skip_over_18 if has_over_18
@@ -238,6 +370,10 @@ class Reddit
238
370
  #Post handling
239
371
  #---------------------------------------------------------------------------------
240
372
 
373
+ # Checks if the currently open post is voted by the logged in account, raises an exception if an unknown vote type is submitted
374
+ #
375
+ # @param type [String] the vote type, can be 'up' or 'down'
376
+ # @return [Boolean] whether or not the original post is voted in the given type
241
377
  def is_original_post_voted(type)
242
378
  div = @browser.div(id: 'siteTable').div(class: 'midcol')
243
379
  case type
@@ -250,22 +386,35 @@ class Reddit
250
386
  end
251
387
  end
252
388
 
389
+ # Gets the type of the vote the logged in account voted the original post that is currently open
390
+ #
391
+ # @return [String, nil] returns the vote type, 'up' or 'down' or nil if not voted
253
392
  def get_original_post_vote
254
393
  return 'up' if is_original_post_voted('up')
255
394
  return 'down' if is_original_post_voted('down')
256
395
  return nil
257
396
  end
258
397
 
398
+ # Votes the currently open original post, does nothing if already voted, raises an exception if an unknown vote type is submitted
399
+ #
400
+ # @param type [String] vote type: 'up' or 'down'
259
401
  def vote_original_post(type)
260
402
  return if is_original_post_voted(type)
261
403
  div = @browser.div(id: 'siteTable').div(class: 'midcol')
262
404
  div.div(class: type).click
263
405
  end
264
406
 
407
+ # Forms the full post url given the post's link
408
+ #
409
+ # @param link [String] the post's link
410
+ # @return [String] the full post url
265
411
  def form_post_url(link)
266
412
  return PAGE_MAIN_NO_SLASH + link
267
413
  end
268
414
 
415
+ # Opens the given post
416
+ #
417
+ # @param post [Hash, String] accepts either a post hash or the post's full url
269
418
  def open_post(post)
270
419
  case post
271
420
  when Hash
@@ -278,24 +427,43 @@ class Reddit
278
427
  skip_over_18 if has_over_18
279
428
  end
280
429
 
430
+ # Checks if the logged in account has already replied to the given post with the given answer
431
+ #
432
+ # @param answer [String] the answer to look for
433
+ # @return [Boolean] whether or not the logged in account replied to the post with the given answer
281
434
  def has_reply(answer)
282
435
  form = @browser.form(text: answer)
283
436
  return form.present? && form.parent.parent.attribute_value('data-author') == @username
284
437
  end
285
438
 
439
+ # Checks if there was an error when replying
440
+ #
441
+ # @return [Boolean] whether there was an error or not
286
442
  def has_reply_error
287
443
  return @browser.span(class: 'error', style: '').present?
288
444
  end
289
445
 
446
+ # Gets the reason for the reply error
447
+ #
448
+ # @return [String] the reason
290
449
  def get_reply_error
291
450
  return @browser.span(class: 'error', style: '').split(" ")[1]
292
451
  end
293
452
 
453
+ # Sleeps the given time then checks if there was an error when replying
454
+ #
455
+ # @param time [Integer] the number of seconds to sleep
456
+ # @return [Boolean] whether there was an error or not
294
457
  def wait_reply(time = 2)
295
458
  sleep time
296
459
  return !has_reply_error
297
460
  end
298
461
 
462
+ # Replies the given post
463
+ #
464
+ # @param post [Hash, String] the post to reply, can be a post hash or full url
465
+ # @param answer [String] the answer to the post
466
+ # @return [Boolean] if replying as successful
299
467
  def reply_post(post, answer)
300
468
  open_post(post)
301
469
  @browser.div(class: 'commentarea').textarea(name: 'text').set answer
@@ -303,26 +471,51 @@ class Reddit
303
471
  return wait_reply
304
472
  end
305
473
 
474
+ # Gets the number of replies the given comment received
475
+ #
476
+ # @param div [Watir::Div] a div containing the comment
477
+ # @return [Integer] the number of replies
306
478
  def get_comment_replies_count(div)
307
479
  return div.attribute_value('data-replies').to_i
308
480
  end
309
481
 
482
+ # Checks if a given comment has replies
483
+ #
484
+ # @param div [Watir::Div] a div containing the comment
485
+ # @return [Boolean] if the comment has replies or not
310
486
  def comment_has_replies(div)
311
487
  return div.attribute_value('data-replies') != '0'
312
488
  end
313
489
 
490
+ # Gets the author of the comment
491
+ #
492
+ # @param div [Watir::Div] a div containing the comment
493
+ # @return [String] the author's username
314
494
  def get_comment_author(div)
315
495
  return div.attribute_value('data-author')
316
496
  end
317
497
 
498
+ # Gets the link of the comment
499
+ #
500
+ # @param div [Watir::Div] a div containing the comment
501
+ # @return [String] the link of the comment
318
502
  def get_comment_link(div)
319
503
  return div.attribute_value('data-permalink')
320
504
  end
321
505
 
506
+ # Gets content of the comment
507
+ #
508
+ # @param div [Watir::Div] a div containing the comment
509
+ # @return [String] the content of the comment
322
510
  def get_comment_content(div)
323
511
  return div.div(class: 'usertext-body').text
324
512
  end
325
513
 
514
+ # Gets the amount of karma the comment received, 'up', 'down' or overall
515
+ #
516
+ # @param div [Watir::Div] a div containing the comment
517
+ # @param vote [String, nil] 'up' for number of upvotes, 'down' for downvotes, nil for total
518
+ # @return [Integer] the number of votes/karma
326
519
  def get_comment_karma(div, vote)
327
520
  case vote
328
521
  when 'up'
@@ -335,7 +528,12 @@ class Reddit
335
528
  return div.p(class: 'tagline').spans(class: 'score')[ind].text.split(' ')[0].to_i
336
529
  end
337
530
 
338
- def is_comment_voted(div, type) #type is 'up' or 'down'
531
+ # Checks if the comment is voted by the logged in account, 'up' or 'down', raises an exception if an unknown vote type is submitted
532
+ #
533
+ # @param div [Watir::Div] a div containing the comment
534
+ # @param type [String] the vote type, 'up' or 'down'
535
+ # @return [Boolean] if the comment is voted
536
+ def is_comment_voted(div, type)
339
537
  case type
340
538
  when 'up'
341
539
  buffer = 'likes'
@@ -347,16 +545,28 @@ class Reddit
347
545
  return div.div(class: 'entry').attribute_value('class') == 'entry ' + buffer
348
546
  end
349
547
 
548
+ # Gets the comment's vote by the logged in account
549
+ #
550
+ # @param div [Watir::Div] a div containing the comment
551
+ # @return [String, nil] 'up' if upvoted, 'down' if downvoted, nil if not voted
350
552
  def get_comment_vote(div)
351
553
  return 'up' if is_comment_voted(div, 'up')
352
554
  return 'down' if is_comment_voted(div, 'down')
353
555
  return nil
354
556
  end
355
557
 
558
+ # Checks if the given comment has karma
559
+ #
560
+ # @param div [Watir::Div] a div containing the comment
561
+ # @return [Boolean] whether the comment has karma or not
356
562
  def comment_has_karma(div)
357
563
  return div.span(class: 'score').present?
358
564
  end
359
565
 
566
+ # Gets a hash containing information about a given comment
567
+ #
568
+ # @param div [Watir::Div] a div containing the comment
569
+ # @return [Hash] a hash containing information about a given comment
360
570
  def get_comment(div)
361
571
  result = {}
362
572
  result['author'] = get_comment_author(div)
@@ -367,6 +577,9 @@ class Reddit
367
577
  return result
368
578
  end
369
579
 
580
+ # Gets all the comments' divs in the open page
581
+ #
582
+ # @return [Array] an array containing all comments' divs in the open page
370
583
  def get_comments_divs
371
584
  divs = @browser.div(class: 'commentarea').div(class: 'sitetable nestedlisting').children
372
585
  result = []
@@ -376,9 +589,13 @@ class Reddit
376
589
  return result
377
590
  end
378
591
 
592
+ # Gets all replies' divs to the given comment
593
+ #
594
+ # @param div [Watir::Div] a div containing the comment
595
+ # @return [Array] an array containing all replies' divs to the given comment
379
596
  def get_replies_divs(main_div)
380
597
  divs = main_div.div(class: 'child').div.children
381
- begin #calling length if the length is 0 causes an exception
598
+ begin
382
599
  x = divs.length
383
600
  rescue
384
601
  return []
@@ -390,6 +607,10 @@ class Reddit
390
607
  return result
391
608
  end
392
609
 
610
+ # Parses all the comments divs and replies
611
+ #
612
+ # @param div [Watir::Div] a div containing the comment
613
+ # @return [Array] an array of hashes containing the comments and their replies
393
614
  def parse_comments_divs(divs)
394
615
  result = []
395
616
  divs.each do |div|
@@ -401,6 +622,7 @@ class Reddit
401
622
  return result
402
623
  end
403
624
 
625
+ # Expands all comments in the open page
404
626
  def expand_all_comments
405
627
  while true
406
628
  begin
@@ -412,18 +634,31 @@ class Reddit
412
634
  end
413
635
  end
414
636
 
637
+ # Gets all the comments in the given post
638
+ #
639
+ # @param post [String, Hash] a post hash or full url
640
+ # @param expand [Boolean] whether to expand all the comments first
641
+ # @return [Array] an array of hashes including information about all the comments and their replies
415
642
  def get_comments(post, expand = false)
416
643
  open_post(post)
417
644
  expand_all_comments if expand
418
645
  return parse_comments_divs(get_comments_divs)
419
646
  end
420
647
 
421
- def reply_comments(div, answer)
648
+ # Replies the given comment with the given anwer
649
+ #
650
+ # @param div [Watir::Div] a div containing the comment
651
+ # @param answer [String] the answer
652
+ def reply_comment(div, answer)
422
653
  div.li(text: 'reply').click
423
654
  div.textarea(name: 'text').set answer
424
655
  div.button(class: 'save').click
425
656
  end
426
657
 
658
+ # Votes the given comment
659
+ #
660
+ # @param div [Watir::Div] a div containing the comment
661
+ # @param type [String] the vote type can be 'up' or 'down'
427
662
  def vote_comment(div, type)
428
663
  return if is_comment_voted(div, type)
429
664
  div.div(class: 'midcol').div(class: type).click
@@ -433,6 +668,9 @@ class Reddit
433
668
  #Subreddit handling
434
669
  #---------------------------------------------------------------------------------
435
670
 
671
+ # Gets all the posts' divs
672
+ #
673
+ # @return [Array] an array containing all posts' divs
436
674
  def get_posts_divs
437
675
  divs = @browser.div(id: 'siteTable').children
438
676
  result = []
@@ -442,38 +680,75 @@ class Reddit
442
680
  return result
443
681
  end
444
682
 
683
+ # Gets the author of the post
684
+ #
685
+ # @param div [Watir::Div] a div containing the post
686
+ # @return [String] the author of the post
445
687
  def get_post_author(div)
446
688
  return div.attribute_value('data-author')
447
689
  end
448
690
 
691
+ # Gets the link of the post
692
+ #
693
+ # @param div [Watir::Div] a div containing the post
694
+ # @return [String] the link of the post
449
695
  def get_post_link(div)
450
696
  return div.attribute_value('data-permalink')
451
697
  end
452
698
 
699
+ # Gets the amount of karma of the post
700
+ #
701
+ # @param div [Watir::Div] a div containing the post
702
+ # @return [Integer] the amount of karma the post received
453
703
  def get_post_karma(div)
454
704
  return div.attribute_value('data-score').to_i
455
705
  end
456
706
 
707
+ # Gets the title of the post
708
+ #
709
+ # @param div [Watir::Div] a div containing the post
710
+ # @return [String] the title of the post
457
711
  def get_post_title(div)
458
712
  return div.link(class: 'title').text
459
713
  end
460
714
 
715
+ # Gets the number of comments in the post
716
+ #
717
+ # @param div [Watir::Div] a div containing the post
718
+ # @return [Integer] the number of comments in the post
461
719
  def get_post_number_of_comments(div)
462
720
  return div.attribute_value('data-comments-count').to_i
463
721
  end
464
722
 
465
- def isPostVoted(div, type)
723
+ # Checks if the post is voted in the given type
724
+ #
725
+ # @param div [Watir::Div] a div containing the post
726
+ # @param type [String] the type of vote: 'up' or 'down'
727
+ # @return [Boolean] whether the post is voted or not in the given type
728
+ def is_post_voted(div, type)
466
729
  return is_comment_voted(div, type)
467
730
  end
468
731
 
732
+ # Gets the type of vote the post has
733
+ #
734
+ # @param div [Watir::Div] a div containing the post
735
+ # @return [String, nil] the of vote, 'up', 'down' or nil if not voted
469
736
  def get_post_vote(div)
470
737
  return get_comment_vote(div)
471
738
  end
472
739
 
740
+ # Votes the given post, 'up' or 'down', raises exception if unknown vote type is sumited
741
+ #
742
+ # @param div [Watir::Div] a div containing the post
743
+ # @param type [String] the type of vote: 'up' or 'down'
473
744
  def vote_post(div, type)
474
745
  vote_comment(div, type)
475
746
  end
476
747
 
748
+ # Gets a hash containing information about a given post
749
+ #
750
+ # @param div [Watir::Div] a div containing the post
751
+ # @return [Hash] a hash containing information about a given post
477
752
  def get_post(div)
478
753
  result = {}
479
754
  result['author'] = get_post_author(div)
@@ -485,14 +760,27 @@ class Reddit
485
760
  return result
486
761
  end
487
762
 
763
+ # Moves to the next or previous page in the subreddit
764
+ #
765
+ # @param direction [String] the direction to move, can be 'next' or 'prev'
766
+ # @return [Boolean] returns true if moved to the desired page or false if didn't because you're already in the last (move next) or first (move prev) page
488
767
  def subreddit_move_page(direction)
489
768
  return message_move_page(direction)
490
769
  end
491
770
 
771
+ # Forms the full subreddit url given the subreddit's name
772
+ #
773
+ # @param name [String] the subreddit's name
774
+ # @param subpage [String] the subreddit's subpage, defaults to 'hot'
775
+ # @return [String] the full subreddit url
492
776
  def form_subreddit_url(name, subpage = 'hot')
493
777
  return PAGE_SUBREDDIT + name + '/' + subpage
494
778
  end
495
779
 
780
+ # Opens the given subreddit in the given subpage, raises an exception if an unknown subpage is given, known subpages: 'hot', 'new', 'rising', 'top', 'gilded'
781
+ #
782
+ # @param subreddit [String, Hash] a subreddit's name or hash
783
+ # @param subpage [String] the subreddit's subpage, defaults to 'hot'
496
784
  def open_subreddit(subreddit, subpage = 'hot')
497
785
  raise 'Unknown subreddit subpage: ' + subpage if !SUBREDDIT_SUBPAGES.include? subpage
498
786
  case subreddit
@@ -510,8 +798,13 @@ class Reddit
510
798
  skip_over_18 if has_over_18
511
799
  end
512
800
 
801
+ # Gets all the posts in the given subreddit
802
+ #
803
+ # @param subreddit [String, Hash] a subreddit's name or hash
804
+ # @param subpage [String] the subreddit's subpage, defaults to 'hot'
805
+ # @param max_pages [Integer] maximum amount of pages to gather posts from
806
+ # @return [Array] an array containing hashes with information about the subreddit's posts
513
807
  def get_posts(subreddit, subpage = 'hot', max_pages = 1)
514
- raise 'Unknown subreddit subpage: ' + subpage if !SUBREDDIT_SUBPAGES.include? subpage
515
808
  open_subreddit(subreddit, subpage)
516
809
  result = []
517
810
  count = 0
@@ -526,6 +819,10 @@ class Reddit
526
819
  return result
527
820
  end
528
821
 
822
+ # Forms the full url for the subreddit's moderator's page
823
+ #
824
+ # @param subreddit [String, Hash] a subreddit's name or hash
825
+ # @return [String] the full url for the subreddit's moderator's page
529
826
  def form_subreddit_mod_url(subreddit)
530
827
  case subreddit
531
828
  when Hash
@@ -535,7 +832,11 @@ class Reddit
535
832
  end
536
833
  end
537
834
 
538
- def get_moderators(subreddit) #an array of user names, not user structs itself
835
+ # Gets an array including the usernames of the moderators of the given subreddit
836
+ #
837
+ # @param subreddit [String, Hash] a subreddit's name or hash
838
+ # @return [Array] an array including the usernames of the moderators of the given subreddit
839
+ def get_moderators(subreddit)
539
840
  @browser.goto form_subreddit_mod_url(subreddit)
540
841
  spans = @browser.div(class: 'moderator-table').spans(class: 'user')
541
842
  result = []
@@ -545,18 +846,31 @@ class Reddit
545
846
  return result
546
847
  end
547
848
 
849
+ # Gets the number of subscribers the subreddit currently open has
850
+ #
851
+ # @return [Integer] the number of subscribers the subreddit currently open has
548
852
  def get_subscribers
549
853
  return @browser.span(class: 'subscribers').span(class: 'number').text.gsub(',', '').to_i
550
854
  end
551
855
 
856
+ # Gets the number of online users the subreddit currently open has
857
+ #
858
+ # @return [Integer] the number of online users the subreddit currently open has
552
859
  def get_users_online
553
860
  return @browser.p(class: 'users-online').span(class: 'number').text.gsub(',', '').to_i
554
861
  end
555
862
 
863
+ # Gets content of the subreddit currently open sidebar
864
+ #
865
+ # @return [String] the content of the subreddit's sidebar
556
866
  def get_side_bar
557
867
  return @browser.div(class: 'usertext-body').text
558
868
  end
559
869
 
870
+ # Gets a hash with information about the given subreddit
871
+ #
872
+ # @param subreddit [String] the subreddit's name
873
+ # @return [Hash] a hash with information about the given subreddit
560
874
  def get_subreddit(subreddit)
561
875
  result = {}
562
876
  result['name'] = subreddit
@@ -568,10 +882,16 @@ class Reddit
568
882
  return result
569
883
  end
570
884
 
885
+ # Checks if the subreddit was successfully created
886
+ #
887
+ # @return [Boolean] whether the subreddit was successfully created
571
888
  def did_create_sub
572
889
  return @browser.p(text: 'your subreddit has been created').present?
573
890
  end
574
891
 
892
+ # Waits for the creation of the subreddit
893
+ #
894
+ # @return [Boolean] whether the subreddit was successfully created
575
895
  def wait_sub_creation
576
896
  count = 0.0
577
897
  while true
@@ -582,6 +902,10 @@ class Reddit
582
902
  end
583
903
  end
584
904
 
905
+ # Creates a subreddit with the given parameters
906
+ #
907
+ # @param subreddit [NewSub] A Struct containing the subreddit's parameters
908
+ # @return [Boolean] whether the subreddit was successfully created
585
909
  def create_subreddit(subreddit)
586
910
  @browser.goto CREATE_SUB_PAGE
587
911
  @browser.text_field(id: 'name').set subreddit.name
@@ -599,18 +923,30 @@ class Reddit
599
923
  #User handling
600
924
  #---------------------------------------------------------------------------------
601
925
 
926
+ # Gets the currently open user's post karma
927
+ #
928
+ # @return [Integer] the currently open user's post karma
602
929
  def get_user_post_karma
603
930
  return @browser.span(class: 'karma').text.gsub(',', '').to_i
604
931
  end
605
932
 
933
+ # Gets the currently open user's comment karma
934
+ #
935
+ # @return [Integer] the currently open user's comment karma
606
936
  def get_user_comment_karma
607
937
  return @browser.spans(class: 'karma')[1].text.gsub(',', '').to_i
608
938
  end
609
939
 
940
+ # Checks if the currently open user is a moderator of any subreddit
941
+ #
942
+ # @return [Boolean] if the currently open user is a moderator of any subreddit
610
943
  def is_moderator
611
944
  return @browser.ul(id: 'side-mod-list').present?
612
945
  end
613
946
 
947
+ # Gets the currently open user's moderating pages
948
+ #
949
+ # @return [Array] an array of strings containing the names of the subreddits
614
950
  def get_moderating
615
951
  result = []
616
952
  @browser.ul(id: 'side-mod-list').lis.each do |li|
@@ -619,25 +955,37 @@ class Reddit
619
955
  return result
620
956
  end
621
957
 
958
+ # Checks if the currently open user is a friend of the logged in account
959
+ #
960
+ # @return [Boolean] if the currently open user is a friend of the logged in account
622
961
  def is_friend
623
962
  return @browser.span(class: 'fancy-toggle-button').link(text: '- friends').attribute_value('class').include?('active')
624
963
  end
625
964
 
965
+ # Adds the currently open user as a friend, does nothing if the user is already a friend
626
966
  def add_friend
627
967
  return if is_friend
628
968
  @browser.link(text: '+ friends').click
629
969
  end
630
970
 
971
+ # Removes the currently open user as a friend, does nothing if the user is not a friend
631
972
  def remove_friend
632
973
  return if !is_friend
633
974
  @browser.link(text: '- friends').click
634
975
  end
635
976
 
977
+ # Opens the page of the given username
978
+ #
979
+ # @param user [String] the username
636
980
  def open_user_page(user)
637
981
  @browser.goto PAGE_USER + user
638
982
  skip_over_18 if has_over_18
639
983
  end
640
984
 
985
+ # Gets a hash containing information about the given user
986
+ #
987
+ # @param user [String] the username
988
+ # @return [Hash] a hash containing information about the given user
641
989
  def get_user(user)
642
990
  open_user_page(user)
643
991
  return nil if @browser.div(id: 'classy-error').present?
@@ -654,6 +1002,9 @@ class Reddit
654
1002
  #User Activity handling
655
1003
  #---------------------------------------------------------------------------------
656
1004
 
1005
+ # Gets all the ativity divs from the currently open user
1006
+ #
1007
+ # @return [Array] an array including the divs
657
1008
  def get_activity_divs
658
1009
  divs = @browser.div(id: 'siteTable').children
659
1010
  result = []
@@ -663,26 +1014,51 @@ class Reddit
663
1014
  return result
664
1015
  end
665
1016
 
1017
+ # Gets the type of the activity
1018
+ #
1019
+ # @param div [Watir::Div] the activity's div
1020
+ # @return [String] the activity's type
666
1021
  def get_activity_type(div)
667
1022
  return div.attribute_value('data-type')
668
1023
  end
669
1024
 
1025
+ # Gets the link of the activity
1026
+ #
1027
+ # @param div [Watir::Div] the activity's div
1028
+ # @return [String] the activity's link
670
1029
  def get_activity_link(div)
671
1030
  return div.attribute_value('data-permalink')
672
1031
  end
673
1032
 
1033
+ # Gets the subreddit of the activity
1034
+ #
1035
+ # @param div [Watir::Div] the activity's div
1036
+ # @return [String] the activity's subreddit
674
1037
  def get_activity_subreddit(div)
675
1038
  return div.attribute_value('data-subreddit')
676
1039
  end
677
1040
 
1041
+ # Gets the title of the activity
1042
+ #
1043
+ # @param div [Watir::Div] the activity's div
1044
+ # @return [String] the activity's title
678
1045
  def get_activity_title(div)
679
1046
  return div.link(class: 'title').text
680
1047
  end
681
1048
 
1049
+ # Gets the activity's content if it is a comment
1050
+ #
1051
+ # @param div [Watir::Div] the activity's div
1052
+ # @return [String] the activity's text content
682
1053
  def get_activity_content(div) #only for comments
683
1054
  return div.div(class: 'usertext-body').text
684
1055
  end
685
1056
 
1057
+ # Gets the amount of karma the activity received, 'up', 'down' or overall
1058
+ #
1059
+ # @param div [Watir::Div] a div containing the activity
1060
+ # @param vote [String, nil] 'up' for number of upvotes, 'down' for downvotes, nil for total
1061
+ # @return [Integer] the number of votes/karma
686
1062
  def get_activity_karma(div, vote)
687
1063
  case get_activity_type(div)
688
1064
  when 'comment'
@@ -701,18 +1077,35 @@ class Reddit
701
1077
  end
702
1078
  end
703
1079
 
1080
+ # Checks if the activity is voted by the logged in account, 'up' or 'down', raises an exception if an unknown vote type is submitted
1081
+ #
1082
+ # @param div [Watir::Div] a div containing the activity
1083
+ # @param type [String] the vote type, 'up' or 'down'
1084
+ # @return [Boolean] if the activity is voted
704
1085
  def is_activity_voted(div, type)
705
1086
  return is_comment_voted(div, type)
706
1087
  end
707
1088
 
1089
+ # Gets the activity's vote by the logged in account
1090
+ #
1091
+ # @param div [Watir::Div] a div containing the activity
1092
+ # @return [String, nil] 'up' if upvoted, 'down' if downvoted, nil if not voted
708
1093
  def get_activity_vote(div)
709
1094
  return get_comment_vote(div)
710
1095
  end
711
1096
 
1097
+ # Votes the given activity
1098
+ #
1099
+ # @param div [Watir::Div] a div containing the activity
1100
+ # @param [String] the vote type can be 'up' or 'down'
712
1101
  def vote_activity(div, type)
713
1102
  vote_message(div, type)
714
1103
  end
715
1104
 
1105
+ # Gets a hash containing information about the given activity
1106
+ #
1107
+ # @param div [Watir::Div] a div containing the activity
1108
+ # @return a hash containing information about the given activity
716
1109
  def get_activity(div)
717
1110
  result = {}
718
1111
  result['type'] = get_activity_type(div)
@@ -725,10 +1118,20 @@ class Reddit
725
1118
  return result
726
1119
  end
727
1120
 
1121
+ # Moves to the next or previous page in the user's activity box
1122
+ #
1123
+ # @param direction [String] the direction to move, can be 'next' or 'prev'
1124
+ # @return [Boolean] returns true if moved to the desired page or false if didn't because you're already in the last (move next) or first (move prev) page
728
1125
  def user_move_page(direction)
729
1126
  return message_move_page(direction)
730
1127
  end
731
1128
 
1129
+ # Gets all the user activities from the given user, raises exception if unknown sorting method is used
1130
+ #
1131
+ # @param user [String] the username
1132
+ # @param sortby [String] sorting method, can be: 'new', 'hot', 'top', 'controversial'
1133
+ # @param max_pages [Integer] maximum amounts of pages to get activies from
1134
+ # @return [Array] an array containing all the activities hashes
732
1135
  def get_user_activities(user, sortby = 'new', max_pages = 1)
733
1136
  raise 'Unknown user sortby: ' + sortby if !USER_SORTBYS.include? sortby
734
1137
  @browser.goto PAGE_USER + user + '/?sort=' + sortby
@@ -749,6 +1152,9 @@ class Reddit
749
1152
  #Extra functions
750
1153
  #---------------------------------------------------------------------------------
751
1154
 
1155
+ # Gets all the subreddits the currently logged user is banned in
1156
+ #
1157
+ # @return [Array] an array of strings containing the subreddits the user is banned in
752
1158
  def get_banned_subreddits
753
1159
  msgs = get_messages('messages', true)
754
1160
  result = []
@@ -801,6 +1207,12 @@ class Reddit
801
1207
  return @browser.button(class: 'c-btn c-btn-primary subreddit-picker__subreddit-button').present? ? 'picksubs' : 'enterdata'
802
1208
  end
803
1209
 
1210
+ # Creates an account on reddit
1211
+ #
1212
+ # @param username [String] the account's username
1213
+ # @param password [String] the account's password
1214
+ # @param captcha_token [String] the google's captcha's token, it's up to you how to get it
1215
+ # @return [Hash] a hash containing the account's username and password
804
1216
  def create_account(username, password, captcha_token) #if username is nil, selects username from reddit's suggestions
805
1217
  @browser.goto PAGE_MAIN
806
1218
  @browser.div(id: 'header-bottom-right').link(text: 'sign up').click
@@ -822,14 +1234,22 @@ class Reddit
822
1234
  return result
823
1235
  end
824
1236
 
1237
+ # Checks if the given user is banned
1238
+ #
1239
+ # @param user [String] the username
1240
+ # @return [Boolean] whether the user is banned or not
825
1241
  def is_user_banned(user)
826
1242
  @browser.goto PAGE_USER + user
827
1243
  skip_over_18 if has_over_18
828
1244
  return @browser.div(id: 'classy-error').present? || @browser.h3(text: 'This account has been suspended').present?
829
1245
  end
830
1246
 
831
- def is_subreddit_banned(subr)
832
- @browser.goto PAGE_SUBREDDIT + subr
1247
+ # Checks if the given subreddit is banned
1248
+ #
1249
+ # @param subreddit [String] the subreddit's name
1250
+ # @return [Boolean] whether the subreddit is banned or not
1251
+ def is_subreddit_banned(subreddit)
1252
+ @browser.goto PAGE_SUBREDDIT + subreddit
833
1253
  skip_over_18 if has_over_18
834
1254
  return @browser.h3(text: 'This community has been banned').present?
835
1255
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: reddit_auto
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ícaro Augusto