snoo 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,23 @@
1
+ This is a simple flairbot you can use to automatically add flair to a subreddit.
2
+
3
+ It is currently in use on [r/TheWalkingDead](http://www.reddit.com/r/thewalkingdead) and [r/BreakingBad](http://www.reddit.com/r/breakingbad). It provides automatic spoiler detection
4
+
5
+ # Configuration
6
+
7
+ ## Account
8
+ Configuring the bot's account is very simple. Simply edit `config.yaml` and fill out the username and password fields.
9
+
10
+ ## Subreddits
11
+ Each subreddit can have multiple regexes, and the bot can run on multiple subreddits. It needs to have moderator on all subreddits.
12
+
13
+ To add new subreddits, make a new first-level entry under `subreddits:`
14
+
15
+ To add new flair parsers, add a new entry, with a regular expression as the name. Ex `(show|comic) spoilers`. Beneath this, set if you want to ignore case (recommended) and the flair id of the linkflair to apply. This shows up if you inspect the HTML source of the reddit flair dialog on links.
16
+
17
+ # Caveats
18
+
19
+ This bot scrapes new, and as such, will ususally catch most things. That said, it is imperfect, and things may slip through.
20
+
21
+ To prevent re-duplicating flair calls, it hides a post on flair. This allows you to see which post a bot has flaired, simply by logging into its account.
22
+
23
+ Finally, regexes are applied in a top-down cascade. Regexes at the bottom will override ones at the top. A post can only have one linkflair, so go from general to specific in your regexes.
@@ -0,0 +1,27 @@
1
+ # Batch size, cannot go above 100
2
+ limit: 100
3
+ # Login details
4
+ username: flair-o-tron
5
+ password:
6
+ # Logging
7
+ logging: false
8
+ # Uncomment the following line to enable logging to file
9
+ # logfile: /home/paradox/ruby/log/flair.log
10
+ # Log rotation
11
+ logrotate: weekly
12
+ # Your subreddits
13
+ # Just copy and paste what you see
14
+ subreddits:
15
+ thewalkingdead:
16
+ 'comic.spoiler':
17
+ ignore_case: true
18
+ id: 'e9452e44-846f-11e1-994b-12313d2c1af1'
19
+ '[(show)(tv)].spoiler':
20
+ ignore_case: true
21
+ id: 'ed8c5612-846f-11e1-837a-12313b08a511'
22
+ breakingbad:
23
+ 'spoiler':
24
+ ignore_case: true
25
+ id: '083ccbc2-ce0d-11e1-85b5-12313b0c247a'
26
+
27
+
@@ -0,0 +1,108 @@
1
+ require 'ostruct'
2
+ require 'yaml'
3
+ require 'snoo'
4
+ require 'logger'
5
+
6
+ class String
7
+ def colorize(color, options = {})
8
+ background = options[:background] || options[:bg] || false
9
+ style = options[:style]
10
+ offsets = ["gray","red", "green", "yellow", "blue", "magenta", "cyan","white"]
11
+ styles = ["normal","bold","dark","italic","underline","xx","xx","underline","xx","strikethrough"]
12
+ start = background ? 40 : 30
13
+ color_code = start + (offsets.index(color) || 8)
14
+ style_code = styles.index(style) || 0
15
+ "\e[#{style_code};#{color_code}m#{self}\e[0m"
16
+ end
17
+ end
18
+
19
+ config = OpenStruct.new YAML.load(File.read("/home/paradox/ruby/config.yaml"))
20
+
21
+ log = config.logfile.nil? ? Logger.new(STDOUT) : Logger.new(config.logfile, config.logrotate)
22
+
23
+ log.level = config.logging ? Logger::DEBUG : Logger::FATAL
24
+
25
+ log.info("Starting log on #{Time.now}")
26
+ reddit = Snoo::Client.new
27
+ log.debug('Logging into reddit')
28
+ reddit.log_in config.username, config.password
29
+ log.debug('Success!')
30
+
31
+ queue = Queue.new
32
+ retried = nil
33
+ config.subreddits.each do |subreddit, flairs|
34
+ begin
35
+ log.debug("Getting #{config.limit} new links for #{subreddit}")
36
+ listing = reddit.get_listing(subreddit: subreddit, page: 'new', sort: 'new', limit: config.limit)['data']['children']
37
+ log.debug("Getting #{config.limit} hot links for #{subreddit}")
38
+ listing.concat reddit.get_listing(subreddit: subreddit, limit: config.limit)['data']['children']
39
+ listing.uniq!
40
+ rescue
41
+ log.error("Got error #{$!}".colorize "red")
42
+ if !retried.nil?
43
+ retried = true
44
+ log.debug('Trying again')
45
+ retry
46
+ else
47
+ next
48
+ retried = nil
49
+ end
50
+ ensure
51
+ retried = nil
52
+ end
53
+ flairs.each do |reg, options|
54
+ r = Regexp.new reg, options['ignore_case']
55
+ log.debug("Matching against #{r}")
56
+ listing.each do |thing|
57
+ # binding.pry
58
+ if thing['data']['title'] =~ r
59
+ q = {
60
+ subreddit: subreddit,
61
+ template: options['id'],
62
+ thing: 't3_' + thing['data']['id']
63
+ }
64
+ log.debug("Queueing #{q}")
65
+ queue << q
66
+ log.debug("Hiding (#{thing['data']['id']}) #{thing['data']['title']}")
67
+ begin
68
+ reddit.hide 't3_' + thing['data']['id']
69
+ sleep 2
70
+ rescue
71
+ log.error("Got error #{$!}".colorize "red")
72
+ if retried.nil?
73
+ retried = true
74
+ sleep 5
75
+ log.debug('Trying again')
76
+ retry
77
+ else
78
+ next
79
+ end
80
+ ensure
81
+ retried = nil
82
+ end
83
+ end
84
+ end
85
+ end
86
+ sleep 2
87
+ end
88
+
89
+ queue.length.times do
90
+ flair = queue.pop
91
+ begin
92
+ log.debug("Setting flair on #{flair}")
93
+ reddit.select_flair_template( flair[:template], flair[:subreddit], link: flair[:thing])
94
+ sleep 2 # For reddit api limits, we sleep 2
95
+ rescue
96
+ log.error("Got error #{$!}".colorize "red")
97
+ if retried.nil?
98
+ retried = true
99
+ sleep 5
100
+ log.debug('Trying again')
101
+ retry
102
+ else
103
+ next
104
+ end
105
+ ensure
106
+ retried = nil
107
+ end
108
+ end
@@ -16,7 +16,7 @@ module Snoo
16
16
  include inc
17
17
  end
18
18
 
19
- attr_reader(:modhash, :username, :userid, :cookie)
19
+ attr_reader(:modhash, :username, :userid, :cookies)
20
20
 
21
21
 
22
22
  # Creates a new instance of Snoo.
@@ -13,17 +13,29 @@ module Snoo
13
13
  login = post("/api/login", :body => {user: username, passwd: password, api_type: 'json'})
14
14
  errors = login['json']['errors']
15
15
  raise errors[0][1] unless errors.size == 0
16
- cookies login.headers['set-cookie']
16
+ set_cookies login.headers['set-cookie']
17
17
  @modhash = login['json']['data']['modhash']
18
18
  @username = username
19
19
  @userid = 't2_' + get('/api/me.json')['data']['id']
20
20
  return login
21
21
  end
22
22
 
23
+ # Auth into reddit via modhash and cookie. This has the advantage of not throttling you if you call it a lot
24
+ #
25
+ # @param modhash [String] The modhash to use
26
+ # @param cookies [String] The cookies string to give to the header
27
+ def auth modhash, cookies
28
+ set_cookies cookies
29
+ @modhash = modhash
30
+ meinfo = get("/api/me.json")
31
+ @username = meinfo['data']['name']
32
+ @userid = 't2_' + meinfo['data']['id']
33
+ end
34
+
23
35
  # Logs out of a reddit account. This is usually uneeded, you can just log_in as a new account to replace the current one.
24
36
  # This just nils the cookies and modhash
25
37
  def log_out
26
- cookies nil
38
+ set_cookies nil
27
39
  @modhash = nil
28
40
  @userid = nil
29
41
  @username = nil
@@ -38,7 +50,7 @@ module Snoo
38
50
  def clear_sessions password
39
51
  logged_in?
40
52
  clear = post('/api/clear_sessions', body: { curpass: password, dest: @baseurl, uh: @modhash })
41
- cookies clear.headers['set-cookie']
53
+ set_cookies clear.headers['set-cookie']
42
54
  return clear
43
55
  end
44
56
 
@@ -85,7 +97,7 @@ module Snoo
85
97
  }
86
98
  params[:email] = email if email
87
99
  update = post('/api/update', body: params )
88
- cookies update.headers['set-cookie']
100
+ set_cookies update.headers['set-cookie']
89
101
  return update
90
102
  end
91
103
  end
@@ -42,7 +42,7 @@ module Snoo
42
42
  # @param opts [Hash] An options hash.
43
43
  # @option opts [String] :css_class The class(es) applied to the flair. Whitespace separated
44
44
  # @option opts [String] :text The flair text
45
- # @option opts [String] :name The user who we are flairing. This requires a username.r
45
+ # @option opts [String] :name The user who we are flairing. This requires a username
46
46
  # @option opts [String] :link The thing id of the link (if a link). Begins with `t3_`
47
47
  # @return (see #clear_sessions)
48
48
  def flair subreddit, opts = {}
@@ -1,9 +1,17 @@
1
1
  module Snoo
2
2
  # Utility functions.
3
- # These are all private
4
3
  #
5
4
  # @author (see Snoo)
6
5
  module Utilities
6
+
7
+ # Set the cookie header and instance variable
8
+ #
9
+ # @param cookie [String] The cookie text, as show in a 'set-cookie' header
10
+ def set_cookies cookie
11
+ @cookies = cookie
12
+ self.class.headers 'Cookie' => cookie
13
+ end
14
+
7
15
  private
8
16
  # HTTParty get wrapper. This serves to clean up code, as well as throw webserver errors wherever needed
9
17
  #
@@ -20,18 +28,11 @@ module Snoo
20
28
  raise WebserverError, response.code unless response.code == 200
21
29
  response
22
30
  end
23
- # Set the cookie header and instance variable
24
- #
25
- # @param cookie [String] The cookie text, as show in a 'set-cookie' header
26
- def cookies cookie
27
- @cookie = cookie
28
- self.class.headers 'Cookie' => cookie
29
- end
30
31
 
31
32
  # Raises an error if we aren't currently logged in
32
33
  #
33
34
  def logged_in?
34
- raise NotAuthenticated if @cookie.nil? or @modhash.nil?
35
+ raise NotAuthenticated if @cookies.nil? or @modhash.nil?
35
36
  end
36
37
 
37
38
  # Posts to '/api/friend'. This method exists because there are tons of things that use this
@@ -1,4 +1,4 @@
1
1
  module Snoo
2
2
  # The version string (duh)
3
- VERSION = "0.0.2"
3
+ VERSION = "0.0.3"
4
4
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: snoo
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-07-15 00:00:00.000000000 Z
12
+ date: 2012-08-06 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: httparty
@@ -59,6 +59,9 @@ files:
59
59
  - LICENSE
60
60
  - README.md
61
61
  - Rakefile
62
+ - examples/flairbot/README.md
63
+ - examples/flairbot/config.yaml
64
+ - examples/flairbot/flair.rb
62
65
  - lib/snoo.rb
63
66
  - lib/snoo/account.rb
64
67
  - lib/snoo/exceptions.rb