doomy_client 0.8.5
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.
- checksums.yaml +7 -0
- data/.gitignore +13 -0
- data/.travis.yml +11 -0
- data/CONTRIBUTING.md +22 -0
- data/Gemfile +3 -0
- data/LICENSE +202 -0
- data/README.md +107 -0
- data/Rakefile +23 -0
- data/bin/tumblr +80 -0
- data/lib/tumblr/blog.rb +59 -0
- data/lib/tumblr/client.rb +51 -0
- data/lib/tumblr/config.rb +36 -0
- data/lib/tumblr/connection.rb +33 -0
- data/lib/tumblr/helpers.rb +29 -0
- data/lib/tumblr/post.rb +147 -0
- data/lib/tumblr/request.rb +54 -0
- data/lib/tumblr/tagged.rb +13 -0
- data/lib/tumblr/user.rb +41 -0
- data/lib/tumblr/version.rb +5 -0
- data/lib/tumblr_client.rb +16 -0
- data/spec/examples/blog_spec.rb +193 -0
- data/spec/examples/client_spec.rb +66 -0
- data/spec/examples/post_spec.rb +279 -0
- data/spec/examples/request_spec.rb +101 -0
- data/spec/examples/tagged_spec.rb +31 -0
- data/spec/examples/user_spec.rb +114 -0
- data/spec/spec_helper.rb +7 -0
- data/tumblr_client.gemspec +27 -0
- metadata +216 -0
data/lib/tumblr/blog.rb
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
module Tumblr
|
|
2
|
+
module Blog
|
|
3
|
+
|
|
4
|
+
# Gets the info about the blog
|
|
5
|
+
def blog_info(blog_name)
|
|
6
|
+
get(blog_path(blog_name, 'info'), :api_key => @consumer_key)
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
# Gets the avatar URL of specified size
|
|
10
|
+
def avatar(blog_name, size = nil)
|
|
11
|
+
url = blog_path(blog_name, 'avatar')
|
|
12
|
+
url = "#{url}/#{size}" if size
|
|
13
|
+
get_redirect_url(url)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# Gets the list of followers for the blog
|
|
17
|
+
def followers(blog_name, options = {})
|
|
18
|
+
validate_options([:limit, :offset], options)
|
|
19
|
+
get(blog_path(blog_name, 'followers'), options)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Gets the list of likes for the blog
|
|
23
|
+
def blog_likes(blog_name, options = {})
|
|
24
|
+
validate_options([:limit, :offset, :before, :after], options)
|
|
25
|
+
url = blog_path(blog_name, 'likes')
|
|
26
|
+
|
|
27
|
+
params = { :api_key => @consumer_key }
|
|
28
|
+
params.merge! options
|
|
29
|
+
get(url, params)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def posts(blog_name, options = {})
|
|
33
|
+
url = blog_path(blog_name, 'posts')
|
|
34
|
+
if options.has_key?(:type)
|
|
35
|
+
url = "#{url}/#{options[:type]}"
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
params = { :api_key => @consumer_key }
|
|
39
|
+
params.merge! options
|
|
40
|
+
get(url, params)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def queue(blog_name, options = {})
|
|
44
|
+
validate_options([:limit, :offset], options)
|
|
45
|
+
get(blog_path(blog_name, 'posts/queue'), options)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def draft(blog_name, options = {})
|
|
49
|
+
validate_options([:limit, :offset], options)
|
|
50
|
+
get(blog_path(blog_name, 'posts/draft'), options)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def submissions(blog_name, options = {})
|
|
54
|
+
validate_options([:limit, :offset], options)
|
|
55
|
+
get(blog_path(blog_name, 'posts/submission'), options)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
end
|
|
59
|
+
end
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
require 'tumblr/blog'
|
|
2
|
+
require 'tumblr/user'
|
|
3
|
+
require 'tumblr/request'
|
|
4
|
+
require 'tumblr/connection'
|
|
5
|
+
require 'tumblr/post'
|
|
6
|
+
require 'tumblr/tagged'
|
|
7
|
+
require 'tumblr/helpers'
|
|
8
|
+
|
|
9
|
+
module Tumblr
|
|
10
|
+
class Client
|
|
11
|
+
|
|
12
|
+
class << self
|
|
13
|
+
def default_api_host
|
|
14
|
+
ENV['TUMBLR_API_HOST'] || 'api.tumblr.com'
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
include Tumblr::Request
|
|
19
|
+
include Tumblr::Blog
|
|
20
|
+
include Tumblr::User
|
|
21
|
+
include Tumblr::Post
|
|
22
|
+
include Tumblr::Tagged
|
|
23
|
+
include Tumblr::Helper
|
|
24
|
+
include Tumblr::Connection
|
|
25
|
+
|
|
26
|
+
def initialize(attrs= {})
|
|
27
|
+
attrs = Tumblr.options.merge(attrs)
|
|
28
|
+
Config::VALID_OPTIONS_KEYS.each do |key|
|
|
29
|
+
instance_variable_set("@#{key}".to_sym, attrs[key])
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def api_host
|
|
34
|
+
self.class.default_api_host
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def api_scheme
|
|
38
|
+
@api_scheme || 'https'
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def credentials
|
|
42
|
+
{
|
|
43
|
+
:consumer_key => @consumer_key,
|
|
44
|
+
:consumer_secret => @consumer_secret,
|
|
45
|
+
:token => @oauth_token,
|
|
46
|
+
:token_secret => @oauth_token_secret
|
|
47
|
+
}
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
end
|
|
51
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
module Tumblr
|
|
2
|
+
module Config
|
|
3
|
+
|
|
4
|
+
VALID_OPTIONS_KEYS = [
|
|
5
|
+
:consumer_key,
|
|
6
|
+
:consumer_secret,
|
|
7
|
+
:oauth_token,
|
|
8
|
+
:oauth_token_secret,
|
|
9
|
+
:client,
|
|
10
|
+
:api_scheme
|
|
11
|
+
]
|
|
12
|
+
|
|
13
|
+
attr_accessor *VALID_OPTIONS_KEYS
|
|
14
|
+
|
|
15
|
+
def configure
|
|
16
|
+
yield self
|
|
17
|
+
self
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def options
|
|
21
|
+
options = {}
|
|
22
|
+
VALID_OPTIONS_KEYS.each{ |pname| options[pname] = send(pname) }
|
|
23
|
+
options
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def credentials
|
|
27
|
+
{
|
|
28
|
+
:consumer_key => consumer_key,
|
|
29
|
+
:consumer_secret => consumer_secret,
|
|
30
|
+
:token => oauth_token,
|
|
31
|
+
:token_secret => oauth_token_secret
|
|
32
|
+
}
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
require 'faraday'
|
|
2
|
+
require 'faraday_middleware'
|
|
3
|
+
|
|
4
|
+
module Tumblr
|
|
5
|
+
module Connection
|
|
6
|
+
|
|
7
|
+
def connection(options={})
|
|
8
|
+
options = options.clone
|
|
9
|
+
|
|
10
|
+
default_options = {
|
|
11
|
+
:headers => {
|
|
12
|
+
:accept => 'application/json',
|
|
13
|
+
:user_agent => "tumblr_client/#{Tumblr::VERSION}"
|
|
14
|
+
},
|
|
15
|
+
:url => "#{api_scheme}://#{api_host}/"
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
client = Faraday.default_adapter
|
|
19
|
+
|
|
20
|
+
Faraday.new(default_options.merge(options)) do |conn|
|
|
21
|
+
data = { :api_host => api_host, :ignore_extra_keys => true}.merge(credentials)
|
|
22
|
+
unless credentials.empty?
|
|
23
|
+
conn.request :oauth, data
|
|
24
|
+
end
|
|
25
|
+
conn.request :multipart
|
|
26
|
+
conn.request :url_encoded
|
|
27
|
+
conn.response :json, :content_type => /\bjson$/
|
|
28
|
+
conn.adapter client
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
module Tumblr
|
|
2
|
+
module Helper
|
|
3
|
+
|
|
4
|
+
private
|
|
5
|
+
|
|
6
|
+
def blog_path(blog_name, ext)
|
|
7
|
+
"v2/blog/#{full_blog_name(blog_name)}/#{ext}"
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def full_blog_name(blog_name)
|
|
11
|
+
blog_name.include?('.') ? blog_name : "#{blog_name}.tumblr.com"
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def validate_options(valid_opts, opts)
|
|
15
|
+
bad_opts = opts.select { |val| !valid_opts.include?(val) }
|
|
16
|
+
if bad_opts.any?
|
|
17
|
+
raise ArgumentError.new "Invalid options (#{bad_opts.keys.join(', ')}) passed, only #{valid_opts} allowed."
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def validate_no_collision(options, attributes)
|
|
22
|
+
count = attributes.count { |attr| options.has_key?(attr) }
|
|
23
|
+
if count > 1
|
|
24
|
+
raise ArgumentError.new "Can only use one of: #{attributes.join(', ')} (Found #{count})"
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
end
|
|
29
|
+
end
|
data/lib/tumblr/post.rb
ADDED
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
require 'mime/types'
|
|
2
|
+
|
|
3
|
+
module Tumblr
|
|
4
|
+
module Post
|
|
5
|
+
|
|
6
|
+
STANDARD_POST_OPTIONS = [:is_private, :state, :tags, :tweet, :date, :markdown, :slug, :format]
|
|
7
|
+
DATA_POST_TYPES = [:audio, :video, :photo]
|
|
8
|
+
VALID_POST_TYPES = DATA_POST_TYPES + [:quote, :text, :link, :chat]
|
|
9
|
+
|
|
10
|
+
def edit(blog_name, options = {})
|
|
11
|
+
convert_source_array :source, options
|
|
12
|
+
extract_data!(options) if DATA_POST_TYPES.include?(options[:type])
|
|
13
|
+
|
|
14
|
+
post(blog_path(blog_name, 'post/edit'), options)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def reblog(blog_name, options = {})
|
|
18
|
+
post(blog_path(blog_name, 'post/reblog'), options)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def delete(blog_name, id)
|
|
22
|
+
post(blog_path(blog_name, 'post/delete'), :id => id)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def photo(blog_name, options = {})
|
|
26
|
+
valid_opts = STANDARD_POST_OPTIONS + [:caption, :link, :data, :source, :photoset_layout]
|
|
27
|
+
validate_options(valid_opts, options)
|
|
28
|
+
validate_no_collision options, [:data, :source]
|
|
29
|
+
convert_source_array :source, options
|
|
30
|
+
|
|
31
|
+
options[:type] = 'photo'
|
|
32
|
+
extract_data!(options)
|
|
33
|
+
post(post_path(blog_name), options)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def quote(blog_name, options = {})
|
|
37
|
+
valid_opts = STANDARD_POST_OPTIONS + [:quote, :source]
|
|
38
|
+
validate_options(valid_opts, options)
|
|
39
|
+
|
|
40
|
+
options[:type] = 'quote'
|
|
41
|
+
post(post_path(blog_name), options)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def text(blog_name, options = {})
|
|
45
|
+
valid_opts = STANDARD_POST_OPTIONS + [:title, :body]
|
|
46
|
+
validate_options(valid_opts, options)
|
|
47
|
+
|
|
48
|
+
options[:type] = 'text'
|
|
49
|
+
post(post_path(blog_name), options)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def link(blog_name, options = {})
|
|
53
|
+
valid_opts = STANDARD_POST_OPTIONS + [:title, :url, :description]
|
|
54
|
+
validate_options(valid_opts, options)
|
|
55
|
+
|
|
56
|
+
options[:type] = 'link'
|
|
57
|
+
post(post_path(blog_name), options)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def chat(blog_name, options = {})
|
|
61
|
+
valid_opts = STANDARD_POST_OPTIONS + [:title, :conversation]
|
|
62
|
+
validate_options(valid_opts, options)
|
|
63
|
+
|
|
64
|
+
options[:type] = 'chat'
|
|
65
|
+
post(post_path(blog_name), options)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def audio(blog_name, options = {})
|
|
69
|
+
valid_opts = STANDARD_POST_OPTIONS + [:data, :caption, :external_url]
|
|
70
|
+
validate_options(valid_opts, options)
|
|
71
|
+
validate_no_collision options, [:data, :external_url]
|
|
72
|
+
|
|
73
|
+
options[:type] = 'audio'
|
|
74
|
+
extract_data!(options)
|
|
75
|
+
post(post_path(blog_name), options)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def video(blog_name, options = {})
|
|
79
|
+
valid_opts = STANDARD_POST_OPTIONS + [:data, :embed, :caption]
|
|
80
|
+
validate_options(valid_opts, options)
|
|
81
|
+
validate_no_collision options, [:data, :embed]
|
|
82
|
+
|
|
83
|
+
options[:type] = 'video'
|
|
84
|
+
extract_data!(options)
|
|
85
|
+
post(post_path(blog_name), options)
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def create_post(type, blog_name, options = {})
|
|
89
|
+
if VALID_POST_TYPES.include?(type)
|
|
90
|
+
send(type, blog_name, options)
|
|
91
|
+
else
|
|
92
|
+
raise ArgumentError.new "\"#{type}\" is not a valid post type"
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
private
|
|
97
|
+
|
|
98
|
+
def post_path(blog_name)
|
|
99
|
+
blog_path(blog_name, 'post')
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
# Allow source to be passed as an Array
|
|
103
|
+
def convert_source_array(key, options)
|
|
104
|
+
if options.has_key?(key) && options[key].kind_of?(Array)
|
|
105
|
+
options[key].each.with_index do |src, idx|
|
|
106
|
+
options["#{key.to_s}[#{idx}]"] = src
|
|
107
|
+
end
|
|
108
|
+
options.delete(key)
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
# Look for the various ways that data can be passed, and normalize
|
|
113
|
+
# the result in this hash
|
|
114
|
+
def extract_data!(options)
|
|
115
|
+
if options.has_key?(:data)
|
|
116
|
+
data = options.delete :data
|
|
117
|
+
|
|
118
|
+
if Array === data
|
|
119
|
+
data.each.with_index do |filepath, idx|
|
|
120
|
+
if filepath.is_a?(Faraday::UploadIO)
|
|
121
|
+
options["data[#{idx}]"] = filepath
|
|
122
|
+
else
|
|
123
|
+
mime_type = extract_mimetype(filepath)
|
|
124
|
+
options["data[#{idx}]"] = Faraday::UploadIO.new(filepath, mime_type)
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
elsif data.is_a?(Faraday::UploadIO)
|
|
128
|
+
options["data"] = data
|
|
129
|
+
else
|
|
130
|
+
mime_type = extract_mimetype(data)
|
|
131
|
+
options["data"] = Faraday::UploadIO.new(data, mime_type)
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def extract_mimetype(filepath)
|
|
137
|
+
mime = MIME::Types.type_for(filepath)
|
|
138
|
+
if (mime.empty?)
|
|
139
|
+
mime_type = "application/octet-stream"
|
|
140
|
+
else
|
|
141
|
+
mime_type = MIME::Types.type_for(filepath)[0].content_type
|
|
142
|
+
end
|
|
143
|
+
mime_type
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
end
|
|
147
|
+
end
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
require 'json'
|
|
2
|
+
|
|
3
|
+
module Tumblr
|
|
4
|
+
module Request
|
|
5
|
+
|
|
6
|
+
# Perform a get request and return the raw response
|
|
7
|
+
def get_response(path, params = {})
|
|
8
|
+
connection.get do |req|
|
|
9
|
+
req.url path
|
|
10
|
+
req.params = params
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# get a redirect url
|
|
15
|
+
def get_redirect_url(path, params = {})
|
|
16
|
+
response = get_response path, params
|
|
17
|
+
if response.status == 301
|
|
18
|
+
response.headers['Location']
|
|
19
|
+
else
|
|
20
|
+
response.body['meta']
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# Performs a get request
|
|
25
|
+
def get(path, params={})
|
|
26
|
+
respond get_response(path, params)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Performs post request
|
|
30
|
+
def post(path, params={})
|
|
31
|
+
if Array === params[:tags]
|
|
32
|
+
params[:tags] = params[:tags].join(',')
|
|
33
|
+
end
|
|
34
|
+
response = connection.post do |req|
|
|
35
|
+
req.url path
|
|
36
|
+
req.body = params unless params.empty?
|
|
37
|
+
end
|
|
38
|
+
#Check for errors and encapsulate
|
|
39
|
+
respond(response)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def respond(response)
|
|
43
|
+
if [201, 200].include?(response.status)
|
|
44
|
+
response.body['response']
|
|
45
|
+
else
|
|
46
|
+
# surface the meta alongside response
|
|
47
|
+
res = response.body['meta'] || {}
|
|
48
|
+
res.merge! response.body['response'] if response.body['response'].is_a?(Hash)
|
|
49
|
+
res
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
end
|
|
54
|
+
end
|
data/lib/tumblr/user.rb
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
module Tumblr
|
|
2
|
+
module User
|
|
3
|
+
|
|
4
|
+
def info
|
|
5
|
+
get('v2/user/info')
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def dashboard(options = {})
|
|
9
|
+
valid_opts = [:limit, :offset, :type, :since_id, :reblog_info, :notes_info]
|
|
10
|
+
validate_options(valid_opts, options)
|
|
11
|
+
get('v2/user/dashboard', options)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def likes(options = {})
|
|
15
|
+
validate_options([:limit, :offset, :before, :after], options)
|
|
16
|
+
get('v2/user/likes', options)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def following(options = {})
|
|
20
|
+
validate_options([:limit, :offset], options)
|
|
21
|
+
get('v2/user/following', options)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def follow(url)
|
|
25
|
+
post('v2/user/follow', :url => url)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def unfollow(url)
|
|
29
|
+
post('v2/user/unfollow', :url => url)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def like(id, reblog_key)
|
|
33
|
+
post('v2/user/like', :id => id, :reblog_key => reblog_key)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def unlike(id, reblog_key)
|
|
37
|
+
post('v2/user/unlike', :id => id, :reblog_key => reblog_key)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
end
|
|
41
|
+
end
|