snoo 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +19 -0
- data/.yardopts +1 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/README.md +86 -0
- data/Rakefile +8 -0
- data/lib/snoo.rb +38 -0
- data/lib/snoo/account.rb +92 -0
- data/lib/snoo/exceptions.rb +13 -0
- data/lib/snoo/flair.rb +184 -0
- data/lib/snoo/links_comments.rb +151 -0
- data/lib/snoo/listings.rb +89 -0
- data/lib/snoo/moderation.rb +61 -0
- data/lib/snoo/pms.rb +69 -0
- data/lib/snoo/subreddits.rb +242 -0
- data/lib/snoo/users.rb +60 -0
- data/lib/snoo/utilities.rb +73 -0
- data/lib/snoo/version.rb +4 -0
- data/snoo.gemspec +25 -0
- data/spec/auth.rb +6 -0
- data/spec/snoo_spec.rb +164 -0
- metadata +105 -0
data/.gitignore
ADDED
data/.yardopts
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--markup markdown
|
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 Jeff Sandberg
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
# Snoo
|
2
|
+
|
3
|
+
Snoo is a *simple* wrapper for the reddit.com api. Its designed to provide an interface as close to the official api as possible, while freeing you from the problems of dealing with json, webserver requests, and session/cookie management.
|
4
|
+
|
5
|
+
Unlike other API wrappers, this one doesn't make use of complicated objects or classes, once you instantiate it once, you are good to go.
|
6
|
+
|
7
|
+
Since it's designed to be simple, it leaves things like rate limiting up to you. Please follow the [reddit api rules](https://github.com/reddit/reddit/wiki/API) and only send one request every 2 seconds (you can use `sleep 2` between requests).
|
8
|
+
|
9
|
+
Also, if you build programs with it, please change the user agent to your specific use case.
|
10
|
+
|
11
|
+
## Installation
|
12
|
+
|
13
|
+
Add this line to your application's Gemfile:
|
14
|
+
|
15
|
+
gem 'snoo'
|
16
|
+
|
17
|
+
And then execute:
|
18
|
+
|
19
|
+
$ bundle
|
20
|
+
|
21
|
+
Or install it yourself as:
|
22
|
+
|
23
|
+
$ gem install snoo
|
24
|
+
|
25
|
+
## Usage
|
26
|
+
|
27
|
+
Here's a simple script that sends a private message:
|
28
|
+
|
29
|
+
```ruby
|
30
|
+
require 'snoo'
|
31
|
+
|
32
|
+
# Create a new instance of the client
|
33
|
+
reddit = Snoo::Client.new
|
34
|
+
|
35
|
+
# Log into reddit
|
36
|
+
reddit.log_in 'Username', 'Password'
|
37
|
+
|
38
|
+
# Send a private message to me (Paradox!)
|
39
|
+
reddit.send_pm 'Paradox', 'Snoo rubygem rocks!', "Hey Paradox, I'm trying your Snoo rubygem out and it rocks. Thanks for providing such an awesome thing!"
|
40
|
+
|
41
|
+
# Log back out of reddit
|
42
|
+
reddit.log_out
|
43
|
+
```
|
44
|
+
|
45
|
+
See the [docs](http://rubydoc.info/github/paradox460/snoo/) for more info.
|
46
|
+
|
47
|
+
## Contributing
|
48
|
+
|
49
|
+
1. Fork it
|
50
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
51
|
+
3. Commit your changes (`git commit -am 'Added some feature'`)
|
52
|
+
4. Test your changes (via `rspec`)
|
53
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
54
|
+
5. Create new Pull Request
|
55
|
+
|
56
|
+
## Testing
|
57
|
+
|
58
|
+
1. Edit `spec/auth.rb` and fill out all the globals with a test user account and test reddit
|
59
|
+
2. Run rspec
|
60
|
+
|
61
|
+
## License
|
62
|
+
|
63
|
+
```
|
64
|
+
Copyright (c) 2012 Jeff Sandberg
|
65
|
+
|
66
|
+
MIT License
|
67
|
+
|
68
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
69
|
+
a copy of this software and associated documentation files (the
|
70
|
+
"Software"), to deal in the Software without restriction, including
|
71
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
72
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
73
|
+
permit persons to whom the Software is furnished to do so, subject to
|
74
|
+
the following conditions:
|
75
|
+
|
76
|
+
The above copyright notice and this permission notice shall be
|
77
|
+
included in all copies or substantial portions of the Software.
|
78
|
+
|
79
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
80
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
81
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
82
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
83
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
84
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
85
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
86
|
+
```
|
data/Rakefile
ADDED
data/lib/snoo.rb
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'httparty'
|
2
|
+
|
3
|
+
%w{version exceptions utilities account flair links_comments listings moderation pms subreddits users}.each do |local|
|
4
|
+
require "snoo/#{local}"
|
5
|
+
end
|
6
|
+
# Snoo reddit API wrapper
|
7
|
+
#
|
8
|
+
# @author Jeff Sandberg <paradox460@gmail.com>
|
9
|
+
module Snoo
|
10
|
+
# Snoo reddit API wrapper
|
11
|
+
#
|
12
|
+
# @author (see Snoo)
|
13
|
+
class Client
|
14
|
+
include HTTParty
|
15
|
+
[Account, Flair, LinksComments, Listings, Moderation, PM, Utilities, User, Subreddit].each do |inc|
|
16
|
+
include inc
|
17
|
+
end
|
18
|
+
|
19
|
+
attr_reader(:modhash, :username, :userid, :cookie)
|
20
|
+
|
21
|
+
|
22
|
+
# Creates a new instance of Snoo.
|
23
|
+
#
|
24
|
+
# Please change the useragent if you write your own program.
|
25
|
+
#
|
26
|
+
# @param url [String] url The base url of reddit.
|
27
|
+
# @param useragent [String] The User-Agent this bot will use.
|
28
|
+
def initialize( url = "http://www.reddit.com", useragent = "Snoo ruby reddit api wrapper v#{VERSION}" )
|
29
|
+
@baseurl = url
|
30
|
+
self.class.base_uri url
|
31
|
+
@headers = {'User-Agent' => useragent }
|
32
|
+
self.class.headers @headers
|
33
|
+
@cookies = nil
|
34
|
+
@modhash = nil
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
data/lib/snoo/account.rb
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
module Snoo
|
2
|
+
# Account related methods, such as logging in, deleting the current user, changing passwords, etc
|
3
|
+
#
|
4
|
+
# @author (see Snoo)
|
5
|
+
module Account
|
6
|
+
|
7
|
+
# Log into a reddit account. You need to do this to use any restricted or write APIs
|
8
|
+
#
|
9
|
+
# @param username [String] The reddit account's username you wish to log in as
|
10
|
+
# @param password [String] The password of the reddit account
|
11
|
+
# @return [HTTParty::Response] The httparty request object.
|
12
|
+
def log_in username, password
|
13
|
+
login = post("/api/login", :body => {user: username, passwd: password, api_type: 'json'})
|
14
|
+
errors = login['json']['errors']
|
15
|
+
raise errors[0][1] unless errors.size == 0
|
16
|
+
cookies login.headers['set-cookie']
|
17
|
+
@modhash = login['json']['data']['modhash']
|
18
|
+
@username = username
|
19
|
+
@userid = 't2_' + get('/api/me.json')['data']['id']
|
20
|
+
return login
|
21
|
+
end
|
22
|
+
|
23
|
+
# 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
|
+
# This just nils the cookies and modhash
|
25
|
+
def log_out
|
26
|
+
cookies nil
|
27
|
+
@modhash = nil
|
28
|
+
@userid = nil
|
29
|
+
@username = nil
|
30
|
+
end
|
31
|
+
|
32
|
+
# Invalidates all other reddit session cookies, and updates the current one.
|
33
|
+
# This will log out all other reddit clients, as described in the [reddit API](http://www.reddit.com/dev/api#POST_api_clear_sessions)
|
34
|
+
#
|
35
|
+
# @note This method provides no verification or checking, so use with care
|
36
|
+
# @param password [String] The password of the reddit account
|
37
|
+
# @return (see #log_in)
|
38
|
+
def clear_sessions password
|
39
|
+
logged_in?
|
40
|
+
clear = post('/api/clear_sessions', body: { curpass: password, dest: @baseurl, uh: @modhash })
|
41
|
+
cookies clear.headers['set-cookie']
|
42
|
+
return clear
|
43
|
+
end
|
44
|
+
|
45
|
+
# Deletes the current user. This requires a password for security reasons.
|
46
|
+
#
|
47
|
+
# @note (see #clear_sessions)
|
48
|
+
# @param password [String] The password for the current user
|
49
|
+
# @param reason [String] The reason the current user account is being deleted.
|
50
|
+
# @return (see #clear_sessions)
|
51
|
+
def delete_user password, reason = "deleted by script command"
|
52
|
+
logged_in?
|
53
|
+
delete = post('/api/delete_user', body: {
|
54
|
+
confirm: true,
|
55
|
+
delete_message: reason,
|
56
|
+
passwd: password,
|
57
|
+
uh: @modhash,
|
58
|
+
user: @username
|
59
|
+
})
|
60
|
+
return delete
|
61
|
+
end
|
62
|
+
|
63
|
+
# Gets info about the currently logged in user.
|
64
|
+
# @return (see #clear_sessions)
|
65
|
+
def me
|
66
|
+
logged_in?
|
67
|
+
get("/api/me.json")
|
68
|
+
end
|
69
|
+
|
70
|
+
# Changes the current user's password/email.
|
71
|
+
#
|
72
|
+
# @note (see #clear_sessions)
|
73
|
+
# @param currentPass [String] The current password
|
74
|
+
# @param newPass [String] The new password
|
75
|
+
# @param email [String] The email address you would like to update to. Optional
|
76
|
+
# @return (see #clear_sessions)
|
77
|
+
def update_user currentPass, newPass, email = nil
|
78
|
+
logged_in?
|
79
|
+
params = {
|
80
|
+
curpass: currentPass,
|
81
|
+
newpass: newPass,
|
82
|
+
uh: @modhash,
|
83
|
+
verify: true,
|
84
|
+
verpass: newPass
|
85
|
+
}
|
86
|
+
params[:email] = email if email
|
87
|
+
update = post('/api/update', body: params )
|
88
|
+
cookies update.headers['set-cookie']
|
89
|
+
return update
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Snoo
|
2
|
+
# Not Authenticated exception. Thrown whenever a user is not logged into reddit and they should be
|
3
|
+
#
|
4
|
+
# @author (see Snoo)
|
5
|
+
class NotAuthenticated < StandardError
|
6
|
+
end
|
7
|
+
|
8
|
+
# Thrown whenever the webserver returns anyting but 200
|
9
|
+
#
|
10
|
+
# @author (see Snoo)
|
11
|
+
class WebserverError < StandardError
|
12
|
+
end
|
13
|
+
end
|
data/lib/snoo/flair.rb
ADDED
@@ -0,0 +1,184 @@
|
|
1
|
+
module Snoo
|
2
|
+
# Flair related methods.
|
3
|
+
# These are used for interacting with flair in reddit. Things like giving flair, setting templates, and whatnot.
|
4
|
+
#
|
5
|
+
# @author (see Snoo)
|
6
|
+
module Flair
|
7
|
+
|
8
|
+
# Clear all the flair templates of a particular type
|
9
|
+
#
|
10
|
+
# @param type [USER_FLAIR, LINK_FLAIR] The type of template to clear.
|
11
|
+
# @param subreddit [String] The subreddit targeted.
|
12
|
+
# @return (see #clear_sessions)
|
13
|
+
def clear_flair_templates type, subreddit
|
14
|
+
logged_in?
|
15
|
+
tests = ['USER_FLAIR', 'LINK_FLAIR']
|
16
|
+
raise ArgumentError, 'type needs to be either USER_FLAIR or LINK_FLAIR' unless tests.include?(type)
|
17
|
+
post('/api/clearflairtemplates', body: { flair_type: type, r: subreddit, uh: @modhash})
|
18
|
+
end
|
19
|
+
|
20
|
+
# Deletes a user's flair
|
21
|
+
#
|
22
|
+
# @param user [String] The user who'se flair is affected
|
23
|
+
# @param subreddit [String] The subreddit targeted.
|
24
|
+
# @return (see #clear_sessions)
|
25
|
+
def delete_user_flair user, subreddit
|
26
|
+
logged_in?
|
27
|
+
post('/api/deleteflair', body: {name: user, r: subreddit, uh: @modhash})
|
28
|
+
end
|
29
|
+
|
30
|
+
# Deletes a flair template by ID.
|
31
|
+
#
|
32
|
+
# @param id [String] The flair template's ID to delete. Get this from {#flair_template_list}
|
33
|
+
# @param subreddit [String] The subreddit targeted.
|
34
|
+
def delete_flair_template id, subreddit
|
35
|
+
logged_in?
|
36
|
+
post('/api/deleteflairtemplate', body: {flair_template_id: id, r: subreddit, uh: @modhash})
|
37
|
+
end
|
38
|
+
|
39
|
+
# Sets flair on a thing, currently supports links and users. Must specify **either** link *or* user, **not** both
|
40
|
+
#
|
41
|
+
# @param subreddit [String] The subreddit targeted.
|
42
|
+
# @param opts [Hash] An options hash.
|
43
|
+
# @option opts [String] :css_class The class(es) applied to the flair. Whitespace separated
|
44
|
+
# @option opts [String] :text The flair text
|
45
|
+
# @option opts [String] :name The user who we are flairing. This requires a username.r
|
46
|
+
# @option opts [String] :link The thing id of the link (if a link). Begins with `t3_`
|
47
|
+
# @return (see #clear_sessions)
|
48
|
+
def flair subreddit, opts = {}
|
49
|
+
logged_in?
|
50
|
+
raise ArgumentError, "link or name, not both" if opts[:link] && opts[:name]
|
51
|
+
params = {
|
52
|
+
r: subreddit,
|
53
|
+
uh: @modhash,
|
54
|
+
}
|
55
|
+
params.merge! opts
|
56
|
+
|
57
|
+
post('/api/flair', body: params)
|
58
|
+
end
|
59
|
+
|
60
|
+
# Configures flair options for a subreddit. All options are required
|
61
|
+
#
|
62
|
+
# @param enabled [true, false] Flair enabled?
|
63
|
+
# @param position [left, right] Position of user flair.
|
64
|
+
# @param self_assign [true, false] Allow users to assign their own flair from templates
|
65
|
+
# @param link_position [none, left, right] The position of link flair. Set to `none` to disable
|
66
|
+
# @param link_assign [true, false] Allow a submitter to assign their own link flair
|
67
|
+
# @param subreddit [String] The subreddit targeted.
|
68
|
+
# @return (see #clear_sessions)
|
69
|
+
def flair_config enabled, position, self_assign, link_position, link_assign, subreddit
|
70
|
+
logged_in?
|
71
|
+
# Test the params
|
72
|
+
tests = [true, false]
|
73
|
+
raise "parameter error" unless tests.include?(enabled) && tests.include?(self_assign) && tests.include?(link_assign)
|
74
|
+
tests << "none"
|
75
|
+
raise "parameter error" unless tests.include?(link_position)
|
76
|
+
|
77
|
+
post('/api/flairconfig', body: {
|
78
|
+
flair_enabled: enabled,
|
79
|
+
flair_position: position,
|
80
|
+
flair_self_assign_enabled: self_assign,
|
81
|
+
link_flair_position: link_position,
|
82
|
+
link_flair_self_assign_enabled: link_assign,
|
83
|
+
uh: @modhash,
|
84
|
+
r: subreddit
|
85
|
+
})
|
86
|
+
end
|
87
|
+
|
88
|
+
# Post flair in a CSV file to reddit
|
89
|
+
#
|
90
|
+
# @param csv [String] A string, in CSV format, of `user,flair-text,css_class` per line, with no more than 100 flairs, and **no header line**.
|
91
|
+
# @param subreddit [String] The subreddit targeted.
|
92
|
+
# @return [HTTParty::Response] The request object. Note that this request object contains a json confirming the status of each line of the CSV
|
93
|
+
def flair_csv csv, subreddit
|
94
|
+
logged_in?
|
95
|
+
post('/api/flaircsv.json', body: {flair_csv: csv, r: subreddit, uh: @modhash})
|
96
|
+
end
|
97
|
+
|
98
|
+
# Downloads flair from the subreddit
|
99
|
+
# This is limited to 1000 per request, use before/after to get "pages"
|
100
|
+
#
|
101
|
+
# @param (see #flair)
|
102
|
+
# @option opts [Fixnum] :limit (1000) The amount of flairs to get. Must be between 1 and 1000
|
103
|
+
# @option opts [String] :before Return entries just before this user id
|
104
|
+
# @option opts [String] :after Return entries just after this user id
|
105
|
+
# @return (see #clear_sessions)
|
106
|
+
def get_flair_list subreddit, opts = {}
|
107
|
+
logged_in?
|
108
|
+
raise ArgumentError, 'limit is too high/low' unless (1..1000).include?(opts[:limit]) or opts[:limit].nil?
|
109
|
+
query = {
|
110
|
+
limit: 1000,
|
111
|
+
uh: @modhash
|
112
|
+
}
|
113
|
+
query.merge! opts
|
114
|
+
get("/r/#{subreddit}/api/flairlist.json", query: query)
|
115
|
+
end
|
116
|
+
|
117
|
+
# Create or edit a flair template.
|
118
|
+
#
|
119
|
+
# @param css_class [String] The list of css classes applied to this style, space separated
|
120
|
+
# @param type [USER_FLAIR, LINK_FLAIR] The type of flair template.
|
121
|
+
# @param text [String] The flair template's text.
|
122
|
+
# @param user_editable [true, false] If the templ
|
123
|
+
# @param subreddit [String] The subreddit targeted.ate allows users to specify their own text
|
124
|
+
# @param template_id [String] The flair template ID, for editing. Get this from {#flair_template_list}
|
125
|
+
# @return (see #clear_sessions)
|
126
|
+
def flair_template css_class, type, text, user_editable, subreddit, template_id = nil
|
127
|
+
logged_in?
|
128
|
+
test = ['USER_FLAIR', 'LINK_FLAIR']
|
129
|
+
raise ArgumentError, 'type is either USER_FLAIR or LINK_FLAIR' unless test.include?(type)
|
130
|
+
test = [true, false]
|
131
|
+
raise ArgumentError, 'user_editable needs to be true or false' unless test.include?(user_editable)
|
132
|
+
|
133
|
+
params = {
|
134
|
+
css_class: css_class,
|
135
|
+
flair_type: type,
|
136
|
+
text: text,
|
137
|
+
text_editable: user_editable,
|
138
|
+
uh: @modhash,
|
139
|
+
r: subreddit
|
140
|
+
}
|
141
|
+
params[:flair_template_id] = template_id if template_id
|
142
|
+
post('/api/flairtemplate', body: params)
|
143
|
+
end
|
144
|
+
|
145
|
+
# Select a flair template and apply it to a user or link
|
146
|
+
#
|
147
|
+
# @param template_id [String] The template id to apply. Get this from {#flair_template_list}
|
148
|
+
# @param text [String] The flair text
|
149
|
+
# @param subreddit [String] The subreddit targeted.
|
150
|
+
# @param (see LinksComments#info)
|
151
|
+
# @option opts [String] :link The link id to apply to
|
152
|
+
# @option opts [String] :user The username to apply flair to
|
153
|
+
# @return (see #clear_sessions)
|
154
|
+
def select_flair_template template_id, text, subreddit, opts = {}
|
155
|
+
logged_in?
|
156
|
+
raise ArgumentError, 'link or user, not both' if link && user
|
157
|
+
params = {
|
158
|
+
flair_template_id: template_id,
|
159
|
+
text: text,
|
160
|
+
uh: @modhash,
|
161
|
+
r: subreddit
|
162
|
+
}
|
163
|
+
params.merge! opts
|
164
|
+
post('/api/selectflair', body: params)
|
165
|
+
end
|
166
|
+
|
167
|
+
# Toggle flair on and off for a subreddit
|
168
|
+
#
|
169
|
+
# @param enabled [true, false] Enable/disable flair
|
170
|
+
# @param subreddit [String] The subreddit targeted.
|
171
|
+
# @return (see #clear_sessions)
|
172
|
+
def flair_toggle enabled, subreddit
|
173
|
+
logged_in?
|
174
|
+
test = [true, false]
|
175
|
+
raise ArgumentError, 'enabled must be boolean' unless test.include?(enabled)
|
176
|
+
post('/api/setflairenabled', body: {flair_enabled: enabled, uh: @modhash, r: subreddit})
|
177
|
+
end
|
178
|
+
|
179
|
+
# @todo implement this.
|
180
|
+
# it will probably require nokogiri and some trickery.
|
181
|
+
def flair_template_list
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|