tumblr-rb 1.3.0 → 2.0.0.alpha
Sign up to get free protection for your applications and to get access to all the features.
- data/.travis.yml +7 -0
- data/Gemfile +15 -8
- data/Gemfile.lock +65 -65
- data/LICENSE +4 -2
- data/README.md +31 -84
- data/Rakefile +8 -68
- data/bin/tumblr +3 -133
- data/lib/tumblr.rb +7 -184
- data/lib/tumblr/authentication.rb +71 -0
- data/lib/tumblr/client.rb +148 -0
- data/lib/tumblr/command_line_interface.rb +222 -0
- data/lib/tumblr/credentials.rb +31 -0
- data/lib/tumblr/post.rb +253 -171
- data/lib/tumblr/post/answer.rb +17 -0
- data/lib/tumblr/post/audio.rb +22 -10
- data/lib/tumblr/post/chat.rb +25 -0
- data/lib/tumblr/post/link.rb +22 -9
- data/lib/tumblr/post/photo.rb +29 -10
- data/lib/tumblr/post/quote.rb +17 -10
- data/lib/tumblr/post/text.rb +18 -0
- data/lib/tumblr/post/video.rb +26 -11
- data/lib/tumblr/version.rb +3 -0
- data/lib/tumblr/views/error.erb +6 -0
- data/lib/tumblr/views/form.erb +11 -0
- data/lib/tumblr/views/layout.erb +41 -0
- data/lib/tumblr/views/success.erb +6 -0
- data/man/tumblr.1 +67 -65
- data/man/tumblr.1.html +131 -108
- data/man/tumblr.1.ronn +76 -57
- data/man/tumblr.5 +48 -68
- data/man/tumblr.5.html +106 -114
- data/man/tumblr.5.ronn +38 -51
- data/spec/fixtures/posts.json +10 -0
- data/spec/fixtures/typical_animated_gif.gif +0 -0
- data/spec/spec_helper.rb +12 -0
- data/spec/tumblr/authentication_spec.rb +57 -0
- data/spec/tumblr/client_spec.rb +223 -0
- data/spec/tumblr/credentials_spec.rb +63 -0
- data/spec/tumblr/post_spec.rb +125 -0
- data/tumblr-rb.gemspec +16 -89
- metadata +101 -102
- data/lib/tumblr/authenticator.rb +0 -18
- data/lib/tumblr/post/conversation.rb +0 -15
- data/lib/tumblr/post/regular.rb +0 -14
- data/lib/tumblr/reader.rb +0 -191
- data/lib/tumblr/writer.rb +0 -39
- data/test/fixtures/vcr_cassettes/authenticate/authenticate.yml +0 -39
- data/test/fixtures/vcr_cassettes/read/all_pages.yml +0 -34
- data/test/fixtures/vcr_cassettes/read/authenticated.yml +0 -40
- data/test/fixtures/vcr_cassettes/read/authentication_failure.yml +0 -33
- data/test/fixtures/vcr_cassettes/read/like.yml +0 -31
- data/test/fixtures/vcr_cassettes/read/mwunsch.yml +0 -101
- data/test/fixtures/vcr_cassettes/read/optional.yml +0 -48
- data/test/fixtures/vcr_cassettes/read/pages.yml +0 -36
- data/test/fixtures/vcr_cassettes/read/tumblrgemtest.yml +0 -42
- data/test/fixtures/vcr_cassettes/read/unlike.yml +0 -31
- data/test/fixtures/vcr_cassettes/write/delete.yml +0 -31
- data/test/fixtures/vcr_cassettes/write/edit.yml +0 -31
- data/test/fixtures/vcr_cassettes/write/reblog.yml +0 -31
- data/test/fixtures/vcr_cassettes/write/write.yml +0 -31
- data/test/helper.rb +0 -44
- data/test/test_tumblr.rb +0 -710
data/lib/tumblr.rb
CHANGED
@@ -1,185 +1,8 @@
|
|
1
|
-
require '
|
1
|
+
require 'tumblr/version'
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
require 'tumblr/reader'
|
10
|
-
require 'tumblr/writer'
|
11
|
-
require 'tumblr/authenticator'
|
12
|
-
|
13
|
-
def initialize(*credentials)
|
14
|
-
@credentials = {:email => credentials[0], :password => credentials[1]} unless credentials.blank?
|
15
|
-
end
|
16
|
-
|
17
|
-
# Convenience method for Reader#read
|
18
|
-
def read(username, parameters={})
|
19
|
-
reader.read(username, parameters)
|
20
|
-
end
|
21
|
-
|
22
|
-
# Post a document to Tumblr. If the document has a post-id, it will be edited.
|
23
|
-
def post(doc)
|
24
|
-
tumblr_post = if doc.is_a?(Tumblr::Post)
|
25
|
-
doc.to_h
|
26
|
-
elsif doc.respond_to?(:keys)
|
27
|
-
doc
|
28
|
-
else
|
29
|
-
Tumblr.parse(doc).to_h
|
30
|
-
end
|
31
|
-
tumblr_post.has_key?(:'post-id') ? writer.edit(tumblr_post) : writer.write(tumblr_post)
|
32
|
-
end
|
33
|
-
|
34
|
-
def dashboard(parameters={})
|
35
|
-
raise 'Requires an e-mail address and password' unless @credentials
|
36
|
-
reader.dashboard(parameters)
|
37
|
-
end
|
38
|
-
|
39
|
-
def authenticate(theme = false)
|
40
|
-
raise 'Requires an e-mail address and password' unless @credentials
|
41
|
-
params = theme ? {:'include-theme' => 1} : {}
|
42
|
-
Authenticator.new(@credentials[:email],@credentials[:password]).authenticate(params)
|
43
|
-
end
|
44
|
-
|
45
|
-
def pages(username)
|
46
|
-
reader.pages(username)
|
47
|
-
end
|
48
|
-
|
49
|
-
def all_pages(username)
|
50
|
-
reader.all_pages(username)
|
51
|
-
end
|
52
|
-
|
53
|
-
def reader
|
54
|
-
if @credentials.blank?
|
55
|
-
Reader.new
|
56
|
-
else
|
57
|
-
Reader.new(@credentials[:email],@credentials[:password])
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
|
-
def writer
|
62
|
-
raise 'Requires an e-mail address and password' unless @credentials
|
63
|
-
Writer.new(@credentials[:email],@credentials[:password])
|
64
|
-
end
|
65
|
-
|
66
|
-
def self.execute(credentials, input)
|
67
|
-
request = new(credentials[:email],credentials[:password]).post(input)
|
68
|
-
request.perform
|
69
|
-
end
|
70
|
-
|
71
|
-
# Parse a post out of a string
|
72
|
-
def self.parse(doc)
|
73
|
-
document = {}
|
74
|
-
if doc =~ /^(\s*---(.*)---\s*)/m
|
75
|
-
document[:data] = YAML.load(Regexp.last_match[2].strip)
|
76
|
-
document[:body] = doc.sub(Regexp.last_match[1],'').strip
|
77
|
-
else
|
78
|
-
document[:data] = {'type' => infer_post_type(doc)}
|
79
|
-
document[:body] = doc
|
80
|
-
end
|
81
|
-
create_post document
|
82
|
-
end
|
83
|
-
|
84
|
-
# Guess the Type of Post for a given documents
|
85
|
-
def self.infer_post_type(doc)
|
86
|
-
begin
|
87
|
-
url = URI.parse(doc)
|
88
|
-
if url.is_a?(URI::HTTP)
|
89
|
-
(url.host.include?('youtube.com') || url.host.include?('vimeo.com')) ? :video : :link
|
90
|
-
else
|
91
|
-
:regular
|
92
|
-
end
|
93
|
-
rescue URI::InvalidURIError
|
94
|
-
:regular
|
95
|
-
end
|
96
|
-
end
|
97
|
-
|
98
|
-
# Map a post type key to its class
|
99
|
-
def self.map(key)
|
100
|
-
case key
|
101
|
-
when :regular
|
102
|
-
Post::Regular
|
103
|
-
when :photo
|
104
|
-
Post::Photo
|
105
|
-
when :quote
|
106
|
-
Post::Quote
|
107
|
-
when :link
|
108
|
-
Post::Link
|
109
|
-
when :conversation
|
110
|
-
Post::Conversation
|
111
|
-
when :video
|
112
|
-
Post::Video
|
113
|
-
when :audio
|
114
|
-
Post::Audio
|
115
|
-
else
|
116
|
-
raise "#{key} is not an understood Tumblr post type"
|
117
|
-
end
|
118
|
-
end
|
119
|
-
|
120
|
-
private
|
121
|
-
|
122
|
-
def self.create_post(document)
|
123
|
-
post_data = document[:data]
|
124
|
-
type = (post_data['type'] || infer_post_type(document[:body])).to_sym
|
125
|
-
post = case type
|
126
|
-
when :regular
|
127
|
-
create_regular document
|
128
|
-
when :photo
|
129
|
-
create_photo document
|
130
|
-
when :audio
|
131
|
-
create_audio document
|
132
|
-
when :quote, :link, :conversation, :video
|
133
|
-
create_simple type, document
|
134
|
-
else
|
135
|
-
raise "#{type} is not a recognized Tumblr post type."
|
136
|
-
end
|
137
|
-
basic_setup post, post_data
|
138
|
-
end
|
139
|
-
|
140
|
-
def self.basic_setup(post, post_data)
|
141
|
-
%w(format state private slug date group generator reblog-key).each do |basic|
|
142
|
-
post.send "#{basic}=".gsub('-','_').intern, post_data[basic] if post_data[basic]
|
143
|
-
end
|
144
|
-
%w(tags send-to-twitter publish-on).each do |attribute|
|
145
|
-
post.send attribute.gsub('-','_').intern, post_data[attribute] if post_data[attribute]
|
146
|
-
end
|
147
|
-
post
|
148
|
-
end
|
149
|
-
|
150
|
-
def self.setup_params(post, data)
|
151
|
-
post_params = post.class.parameters.collect {|param| param.to_s.gsub('_','-') }
|
152
|
-
post_params.each do |param|
|
153
|
-
post.send "#{param.gsub('-','_')}=".intern, data[param] if data[param]
|
154
|
-
end
|
155
|
-
post
|
156
|
-
end
|
157
|
-
|
158
|
-
def self.create_regular(doc)
|
159
|
-
data = doc[:data]
|
160
|
-
post = Tumblr::Post::Regular.new(data['post-id'])
|
161
|
-
post.body = doc[:body]
|
162
|
-
setup_params post, data
|
163
|
-
end
|
164
|
-
|
165
|
-
def self.create_photo(doc)
|
166
|
-
data = doc[:data]
|
167
|
-
post = Tumblr::Post::Photo.new(data['post-id'])
|
168
|
-
post.source = doc[:body]
|
169
|
-
setup_params post, data
|
170
|
-
end
|
171
|
-
|
172
|
-
def self.create_audio(doc)
|
173
|
-
data = doc[:data]
|
174
|
-
post = Tumblr::Post::Audio.new(data['post-id'])
|
175
|
-
post.externally_hosted_url = doc[:body]
|
176
|
-
setup_params post, data
|
177
|
-
end
|
178
|
-
|
179
|
-
def self.create_simple(type, doc)
|
180
|
-
data = doc[:data]
|
181
|
-
post = map(type).new(doc[:body], data['post-id'])
|
182
|
-
setup_params post, data
|
183
|
-
end
|
184
|
-
|
185
|
-
end
|
3
|
+
module Tumblr
|
4
|
+
require "tumblr/client"
|
5
|
+
require "tumblr/post"
|
6
|
+
|
7
|
+
autoload :Authentication, "tumblr/authentication"
|
8
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require 'sinatra/base'
|
2
|
+
require 'weary/request'
|
3
|
+
require 'weary/middleware'
|
4
|
+
|
5
|
+
module Tumblr
|
6
|
+
# http://www.tumblr.com/oauth/apps
|
7
|
+
class Authentication < Sinatra::Base
|
8
|
+
HOST = "http://www.tumblr.com/oauth"
|
9
|
+
|
10
|
+
enable :sessions
|
11
|
+
set :credential_path, nil
|
12
|
+
|
13
|
+
def request_token(key, secret, callback)
|
14
|
+
Weary::Request.new "#{HOST}/request_token", :POST do |req|
|
15
|
+
req.params :oauth_callback => callback
|
16
|
+
req.use Weary::Middleware::OAuth, :consumer_key => key,
|
17
|
+
:consumer_secret => secret
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def access_token(token, token_secret, verifier, consumer_key, consumer_secret)
|
22
|
+
Weary::Request.new "#{HOST}/access_token", :POST do |req|
|
23
|
+
req.use Weary::Middleware::OAuth, :token => token,
|
24
|
+
:token_secret => token_secret,
|
25
|
+
:verifier => verifier,
|
26
|
+
:consumer_key => consumer_key,
|
27
|
+
:consumer_secret => consumer_secret
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
get "/" do
|
32
|
+
halt 400, erb(:form) unless params["key"] && params["secret"]
|
33
|
+
session[:consumer_key] = params["key"]
|
34
|
+
session[:consumer_secret] = params["secret"]
|
35
|
+
response = request_token(session[:consumer_key], session[:consumer_secret], url("/auth")).perform
|
36
|
+
if response.success?
|
37
|
+
result = Rack::Utils.parse_query(response.body)
|
38
|
+
logger.info(request.host)
|
39
|
+
session[:request_token_secret] = result["oauth_token_secret"]
|
40
|
+
redirect to("#{HOST}/authorize?oauth_token=#{result['oauth_token']}")
|
41
|
+
else
|
42
|
+
status response.status
|
43
|
+
erb response.body
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
get "/auth" do
|
48
|
+
halt 401, erb(:error) if params.empty?
|
49
|
+
token = params["oauth_token"]
|
50
|
+
verifier = params["oauth_verifier"]
|
51
|
+
response = access_token(token, session[:request_token_secret], verifier,
|
52
|
+
session[:consumer_key], session[:consumer_secret]).perform
|
53
|
+
if response.success?
|
54
|
+
require 'tumblr/credentials'
|
55
|
+
result = Rack::Utils.parse_query(response.body)
|
56
|
+
credentials = Tumblr::Credentials.new(settings.credential_path)
|
57
|
+
credentials.write session[:consumer_key],
|
58
|
+
session[:consumer_secret],
|
59
|
+
result["oauth_token"],
|
60
|
+
result["oauth_token_secret"]
|
61
|
+
@credential_path = credentials.path
|
62
|
+
status response.status
|
63
|
+
erb :success
|
64
|
+
else
|
65
|
+
status response.status
|
66
|
+
erb response.body
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,148 @@
|
|
1
|
+
require "weary"
|
2
|
+
|
3
|
+
module Tumblr
|
4
|
+
class Client < Weary::Client
|
5
|
+
API_VERSION = "v2"
|
6
|
+
|
7
|
+
USER_AGENT = "Tumblr API Client (Ruby)/#{Tumblr::VERSION} (+http://github.com/mwunsch/tumblr)"
|
8
|
+
|
9
|
+
POST_OPTIONS = [
|
10
|
+
:state, :tags, :tweet, :date, :format, :slug,
|
11
|
+
:title, :body, # Text posts
|
12
|
+
:caption, :link, :source, :data, #Photo posts
|
13
|
+
:quote, # Quote posts
|
14
|
+
:url, :description, # Link posts
|
15
|
+
:conversation, # Chat posts
|
16
|
+
:external_url, # Audio posts
|
17
|
+
:embed, # Video posts
|
18
|
+
:answer # Answer posts ??
|
19
|
+
]
|
20
|
+
|
21
|
+
domain "http://api.tumblr.com/#{API_VERSION}"
|
22
|
+
|
23
|
+
user_agent USER_AGENT
|
24
|
+
|
25
|
+
get :info, "/blog/{hostname}/info" do |r|
|
26
|
+
r.required :api_key
|
27
|
+
end
|
28
|
+
|
29
|
+
get :avatar, "/blog/{hostname}/avatar" do |r|
|
30
|
+
r.optional :size
|
31
|
+
end
|
32
|
+
|
33
|
+
get :followers, "/blog/{hostname}/followers" do |r|
|
34
|
+
r.oauth!
|
35
|
+
r.optional :limit, :offset
|
36
|
+
end
|
37
|
+
|
38
|
+
get :posts, "/blog/{hostname}/posts" do |r|
|
39
|
+
r.required :api_key
|
40
|
+
r.optional :type, :id, :tag, :limit, :offset, :reblog_info,
|
41
|
+
:notes_info, :filter
|
42
|
+
end
|
43
|
+
|
44
|
+
get :queue, "/blog/{hostname}/posts/queue" do |r|
|
45
|
+
r.oauth!
|
46
|
+
end
|
47
|
+
|
48
|
+
get :draft, "/blog/{hostname}/posts/draft" do |r|
|
49
|
+
r.oauth!
|
50
|
+
end
|
51
|
+
|
52
|
+
get :submission, "/blog/{hostname}/posts/submission" do |r|
|
53
|
+
r.oauth!
|
54
|
+
end
|
55
|
+
|
56
|
+
post :post, "/blog/{hostname}/post" do |r|
|
57
|
+
r.oauth!
|
58
|
+
r.required :type
|
59
|
+
r.optional *POST_OPTIONS
|
60
|
+
end
|
61
|
+
|
62
|
+
post :edit, "/blog/{hostname}/post/edit" do |r|
|
63
|
+
r.oauth!
|
64
|
+
r.required :id
|
65
|
+
r.optional *POST_OPTIONS
|
66
|
+
end
|
67
|
+
|
68
|
+
post :reblog, "/blog/{hostname}/post/reblog" do |r|
|
69
|
+
r.oauth!
|
70
|
+
r.required :id, :reblog_key
|
71
|
+
r.optional *(POST_OPTIONS | [:comment])
|
72
|
+
end
|
73
|
+
|
74
|
+
post :delete, "/blog/{hostname}/post/delete" do |r|
|
75
|
+
r.oauth!
|
76
|
+
r.required :id
|
77
|
+
end
|
78
|
+
|
79
|
+
get :user, "/user/info" do |r|
|
80
|
+
r.oauth!
|
81
|
+
end
|
82
|
+
|
83
|
+
get :dashboard, "/user/dashboard" do |r|
|
84
|
+
r.oauth!
|
85
|
+
r.optional :limit, :offset, :type, :since_id, :reblog_info, :notes_info
|
86
|
+
end
|
87
|
+
|
88
|
+
get :likes, "/user/likes" do |r|
|
89
|
+
r.oauth!
|
90
|
+
r.optional :limit, :offset
|
91
|
+
end
|
92
|
+
|
93
|
+
get :following, "/user/following" do |r|
|
94
|
+
r.oauth!
|
95
|
+
r.optional :limit, :offset
|
96
|
+
end
|
97
|
+
|
98
|
+
post :follow, "/user/follow" do |r|
|
99
|
+
r.oauth!
|
100
|
+
r.required :url
|
101
|
+
end
|
102
|
+
|
103
|
+
post :unfollow, "/user/unfollow" do |r|
|
104
|
+
r.oauth!
|
105
|
+
r.required :url
|
106
|
+
end
|
107
|
+
|
108
|
+
post :like, "/user/like" do |r|
|
109
|
+
r.oauth!
|
110
|
+
r.required :id, :reblog_key
|
111
|
+
end
|
112
|
+
|
113
|
+
post :unlike, "/user/unlike" do |r|
|
114
|
+
r.oauth!
|
115
|
+
r.required :id, :reblog_key
|
116
|
+
end
|
117
|
+
|
118
|
+
get :tagged, "/tagged" do |r|
|
119
|
+
r.required :api_key, :tag
|
120
|
+
r.optional :before, :limit, :filter
|
121
|
+
end
|
122
|
+
|
123
|
+
def self.load(hostname = nil, path = nil)
|
124
|
+
require "tumblr/credentials"
|
125
|
+
credentials = Tumblr::Credentials.new(path).read
|
126
|
+
self.new(hostname, credentials)
|
127
|
+
end
|
128
|
+
|
129
|
+
def initialize(hostname = nil, oauth_params = {})
|
130
|
+
@defaults = {}
|
131
|
+
@defaults[:hostname] = hostname if hostname
|
132
|
+
[:consumer_key, :consumer_secret, :token, :token_secret].each do |param|
|
133
|
+
@defaults[param] = value_for_key_as_string_or_symbol(oauth_params, param) if hash_includes_key_as_string_or_symbol?(oauth_params, param)
|
134
|
+
end
|
135
|
+
@defaults[:api_key] = value_for_key_as_string_or_symbol(oauth_params, :consumer_key)
|
136
|
+
end
|
137
|
+
|
138
|
+
private
|
139
|
+
|
140
|
+
def value_for_key_as_string_or_symbol(hash, key)
|
141
|
+
hash[key.to_sym] || hash[key.to_s]
|
142
|
+
end
|
143
|
+
|
144
|
+
def hash_includes_key_as_string_or_symbol?(hash, key)
|
145
|
+
hash.keys.map(&:to_s).include? key.to_s
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
@@ -0,0 +1,222 @@
|
|
1
|
+
require 'thor'
|
2
|
+
require 'tumblr'
|
3
|
+
|
4
|
+
module Tumblr
|
5
|
+
class CommandLineInterface < Thor
|
6
|
+
include Thor::Actions
|
7
|
+
|
8
|
+
default_task :pipe
|
9
|
+
|
10
|
+
class_option :credentials, :type => :string,
|
11
|
+
:desc => "The file path where your Tumblr OAuth keys are stored. Defaults to ~/.tumblr."
|
12
|
+
class_option :host, :type => :string,
|
13
|
+
:desc => 'The hostname of the blog you want to post to i.e. "YOUR-NAME.tumblr.com"'
|
14
|
+
|
15
|
+
|
16
|
+
check_unknown_options!(:except => [])
|
17
|
+
|
18
|
+
|
19
|
+
desc "pipe", "Pipe post content in from STDIN"
|
20
|
+
method_option :publish, :type => :boolean,
|
21
|
+
:aliases => "-p",
|
22
|
+
:desc => "Publish this post"
|
23
|
+
method_option :queue, :type => :boolean,
|
24
|
+
:aliases => "-q",
|
25
|
+
:desc => "Add this post to the queue"
|
26
|
+
method_option :draft, :type => :boolean,
|
27
|
+
:aliases => "-d",
|
28
|
+
:desc => "Save this post as a draft"
|
29
|
+
long_desc <<-LONGDESC
|
30
|
+
Publish a post to tumblr from STDIN for HOST.
|
31
|
+
It is assumed that STDIN contains a document formatted according to `tumblr(5)`.
|
32
|
+
If STDIN contains a URL, it will create a post using the same rules as `tumblr post`.
|
33
|
+
|
34
|
+
Writes the serialized post to STDOUT.
|
35
|
+
LONGDESC
|
36
|
+
def pipe
|
37
|
+
if !$stdin.tty?
|
38
|
+
puts post($stdin).serialize
|
39
|
+
else
|
40
|
+
invoke :help
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
desc "post <POST> | <FILE> | <URL>", "Posts to tumblr"
|
45
|
+
method_option :publish, :type => :boolean,
|
46
|
+
:aliases => "-p",
|
47
|
+
:desc => "Publish this post"
|
48
|
+
method_option :queue, :type => :boolean,
|
49
|
+
:aliases => "-q",
|
50
|
+
:desc => "Add this post to the queue"
|
51
|
+
method_option :draft, :type => :boolean,
|
52
|
+
:aliases => "-d",
|
53
|
+
:desc => "Save this post as a draft"
|
54
|
+
long_desc <<-LONGDESC
|
55
|
+
Post a POST to Tumblr for HOST. If a FILE path is given, the file will be read and posted to Tumblr.
|
56
|
+
It is assumed the post follows the `tumblr(5)` format.
|
57
|
+
|
58
|
+
If the FILE is an audio, image, or video file, it will create the respective post type on tumblr.
|
59
|
+
|
60
|
+
If a URL is given, a link post will be created.
|
61
|
+
If URL is a YouTube or Vimeo link, it will create a video post.
|
62
|
+
If URL is a SoundCloud or Spotify link, an audio post will be published.
|
63
|
+
LONGDESC
|
64
|
+
def post(arg)
|
65
|
+
client = get_client
|
66
|
+
post = if arg.respond_to? :read
|
67
|
+
Tumblr::Post.load arg.read
|
68
|
+
elsif File.file?(file_path = File.expand_path(arg))
|
69
|
+
Tumblr::Post.load_from_path file_path
|
70
|
+
else
|
71
|
+
Tumblr::Post.load arg.to_s
|
72
|
+
end
|
73
|
+
post.publish! if options[:publish]
|
74
|
+
post.queue! if options[:queue]
|
75
|
+
post.draft! if options[:draft]
|
76
|
+
response = post.post(client).perform
|
77
|
+
tumblr_error(response) unless response.success?
|
78
|
+
ui_success %Q(Post was successfully created! Post ID: #{response.parse["response"]["id"]}) if $stdin.tty?
|
79
|
+
post
|
80
|
+
end
|
81
|
+
|
82
|
+
desc "edit POST_ID", "Edit a post"
|
83
|
+
long_desc "Open up your $EDITOR to edit a published post."
|
84
|
+
long_desc <<-LONGDESC
|
85
|
+
Get a post from Tumblr and edit it.
|
86
|
+
|
87
|
+
Behaves similar to `git commit`, in that it will open up your editor in the foreground.
|
88
|
+
Look for a $TUMBLREDITOR environment variable, and if that's not found, will use $EDITOR.
|
89
|
+
LONGDESC
|
90
|
+
def edit(id)
|
91
|
+
client = get_client
|
92
|
+
response = client.posts(:id => id, :filter => :raw).perform
|
93
|
+
tumblr_error(response) unless response.success?
|
94
|
+
post = Tumblr::Post.create(response.parse["response"]["posts"].first)
|
95
|
+
require 'tempfile'
|
96
|
+
tmp_file = Tempfile.new("post_#{id}")
|
97
|
+
tmp_file.write(post.serialize)
|
98
|
+
tmp_file.rewind
|
99
|
+
ui_abort "Something went wrong editing the post." unless system "#{editor} #{tmp_file.path}"
|
100
|
+
edited_post = Tumblr::Post.load_from_path tmp_file.path
|
101
|
+
edited_response = edited_post.edit(client).perform
|
102
|
+
tumblr_error(edited_response) unless edited_response.success?
|
103
|
+
ui_success "Post #{id} successfully edited."
|
104
|
+
ensure
|
105
|
+
if tmp_file
|
106
|
+
tmp_file.close
|
107
|
+
tmp_file.unlink
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
desc "fetch POST_ID", "Fetch a post and write out its serialized form."
|
112
|
+
def fetch(id)
|
113
|
+
client = get_client
|
114
|
+
response = client.posts(:id => id, :filter => :raw).perform
|
115
|
+
tumblr_error(response) unless response.success?
|
116
|
+
post = Tumblr::Post.create(response.parse["response"]["posts"].first)
|
117
|
+
puts post.serialize
|
118
|
+
post
|
119
|
+
end
|
120
|
+
|
121
|
+
desc "delete POST_ID", "Delete a post"
|
122
|
+
def delete(id)
|
123
|
+
client = get_client
|
124
|
+
response = client.delete(:id => id).perform
|
125
|
+
tumblr_error(response) unless response.success?
|
126
|
+
ui_success "Post #{id} successfully deleted."
|
127
|
+
end
|
128
|
+
|
129
|
+
desc "authorize", "Authenticate and authorize the cli to post on your behalf"
|
130
|
+
option :port, :type => :string,
|
131
|
+
:default => "4567",
|
132
|
+
:desc => "Use PORT"
|
133
|
+
option :bind, :type => :string,
|
134
|
+
:default => "0.0.0.0",
|
135
|
+
:desc => "listen on BIND"
|
136
|
+
long_desc <<-LONGDESC
|
137
|
+
`tumblr authorize` will start up a server (listening on BIND and PORT) running
|
138
|
+
a small app to do the OAuth handshake with tumblr.
|
139
|
+
|
140
|
+
The app will open in the default browser, allowing you to authenticate to Tumblr
|
141
|
+
and authorize `tumblr` to do actions on your behalf. You will need to register
|
142
|
+
an application and enter the consumer key and consumer secret. The application will
|
143
|
+
write the OAuth keys to your CREDENTIALS file.
|
144
|
+
|
145
|
+
After authorization, you will be prompted to return to your terminal and shut down
|
146
|
+
the server (using CTRL-C).
|
147
|
+
LONGDESC
|
148
|
+
def authorize(*soak)
|
149
|
+
require 'tumblr/authentication'
|
150
|
+
sinatra_options = {
|
151
|
+
:port => options[:port],
|
152
|
+
:bind => options[:bind],
|
153
|
+
:credential_path => options[:credentials]
|
154
|
+
}
|
155
|
+
Tumblr::Authentication.run!(sinatra_options) do |server|
|
156
|
+
`open http://#{options[:bind]}:#{options[:port]}/`
|
157
|
+
end
|
158
|
+
if has_credentials?
|
159
|
+
ui_success "Success! Your Tumblr OAuth credentials were written to #{credentials.path}"
|
160
|
+
else
|
161
|
+
ui_abort "Something went wrong in authorization, and credentials were not correctly written to #{credentials.path}"
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
desc "version", "Print Tumblr version information"
|
166
|
+
def version
|
167
|
+
puts Tumblr::VERSION
|
168
|
+
end
|
169
|
+
|
170
|
+
private
|
171
|
+
|
172
|
+
def credentials
|
173
|
+
require 'tumblr/credentials'
|
174
|
+
Tumblr::Credentials.new(options[:credentials] || ENV["TUMBLRCRED"])
|
175
|
+
end
|
176
|
+
|
177
|
+
def editor
|
178
|
+
ENV["TUMBLREDITOR"] || ENV["EDITOR"]
|
179
|
+
end
|
180
|
+
|
181
|
+
def has_credentials?
|
182
|
+
!credentials.read.empty?
|
183
|
+
end
|
184
|
+
|
185
|
+
def check_credentials
|
186
|
+
ui_abort "Unable to find your OAuth keys. Run `tumblr authorize` to authenticate with Tumblr." unless has_credentials?
|
187
|
+
end
|
188
|
+
|
189
|
+
def get_host
|
190
|
+
host = ask("What is your Tumblr hostname?") if options[:host].nil? and $stdin.tty?
|
191
|
+
host ||= options[:host]
|
192
|
+
ui_abort "You need to provide a hostname i.e. --host=YOUR-NAME.tumblr.com" if host.nil? or host.empty?
|
193
|
+
host
|
194
|
+
end
|
195
|
+
|
196
|
+
def get_client
|
197
|
+
check_credentials
|
198
|
+
host = get_host
|
199
|
+
Tumblr::Client.load host, options[:credentials]
|
200
|
+
end
|
201
|
+
|
202
|
+
def tumblr_error(response)
|
203
|
+
parsed_response = response.parse
|
204
|
+
msg = parsed_response["response"].empty? ? response.parse["meta"]["msg"] : parsed_response["response"]["errors"]
|
205
|
+
ui_abort %Q(Tumblr returned a #{response.status} Error: #{msg})
|
206
|
+
end
|
207
|
+
|
208
|
+
def ui_abort(msg, exit_status = 1)
|
209
|
+
ui_puts msg, :red
|
210
|
+
exit exit_status
|
211
|
+
end
|
212
|
+
|
213
|
+
def ui_success(msg)
|
214
|
+
ui_puts msg, :green
|
215
|
+
end
|
216
|
+
|
217
|
+
def ui_puts(msg, color = nil)
|
218
|
+
say msg, $stdout.tty? ? color : nil
|
219
|
+
end
|
220
|
+
|
221
|
+
end
|
222
|
+
end
|