reddit_auto 1.0.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
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