tit 2.0.4 → 2.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/ChangeLog.markdown +6 -0
- data/VERSION.yml +2 -2
- data/bin/tit +15 -15
- data/lib/tit.rb +56 -25
- data/tit.gemspec +1 -1
- metadata +1 -1
data/ChangeLog.markdown
CHANGED
@@ -1,3 +1,9 @@
|
|
1
|
+
# tit 2.1.0 2011-09-10
|
2
|
+
|
3
|
+
* got direct messaging working -- requires reauthorization
|
4
|
+
* notifies user of need to reauthorize the app for dm permissions
|
5
|
+
* can now handle missing tweet, whereas it was just throwing a Ruby error before
|
6
|
+
|
1
7
|
# tit 2.0.4 2011-09-09
|
2
8
|
|
3
9
|
* fixes issue with replacing t.co urls, where the ridiculous set of chars at the end remained
|
data/VERSION.yml
CHANGED
data/bin/tit
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
3
|
require 'tit'
|
4
|
-
|
5
4
|
require 'optparse'
|
6
5
|
|
7
6
|
def main
|
@@ -35,33 +34,34 @@ def main
|
|
35
34
|
options[:action] = :mentions
|
36
35
|
unchanged = false
|
37
36
|
end
|
38
|
-
opts.on("-u", "--user
|
37
|
+
opts.on("-u", "--user USERNAME",
|
39
38
|
"Show a particular user's timeline") do |user|
|
40
39
|
unchanged = false
|
41
40
|
options[:action] = :user_timeline
|
42
41
|
options[:payload] ||= {}
|
43
42
|
options[:payload]["user"] = user
|
44
43
|
end
|
45
|
-
opts.on("-
|
46
|
-
unchanged = false
|
47
|
-
options[:action] = :update
|
48
|
-
options[:payload] ||= {}
|
49
|
-
options[:payload]["status"] = status
|
50
|
-
end
|
51
|
-
opts.on("-d", "--dm [USERNAME] [MESSAGE]", "Read direct messages. Send a direct message if USERNAME and MESSAGE are set") do |user, message|
|
52
|
-
"Tit does not presently have access to Twitter's Direct Messaging functionality. This will be rectified soon.".wrapped(@cols-2).each do |l|
|
53
|
-
puts " #{l}"
|
54
|
-
end
|
44
|
+
opts.on("-d", "--dm [USERNAME]", "Read direct messages. Send a direct message if USERNAME is set and -t or --tweet accompanies it") do |user|
|
55
45
|
unchanged = false
|
56
|
-
if not user.nil?
|
46
|
+
if not user.nil?
|
57
47
|
options[:action] = :new_direct_message
|
58
48
|
options[:payload] ||= {}
|
59
49
|
options[:payload]["screen_name"] = user
|
60
|
-
options[:payload]["text"] = message
|
61
50
|
else
|
51
|
+
puts "Displaying dms."
|
62
52
|
options[:action] = :direct_messages
|
63
53
|
end
|
64
54
|
end
|
55
|
+
opts.on("-t", "--tweet [STATUS]", "Update status (required when using -G)") do |status|
|
56
|
+
unchanged = false
|
57
|
+
if not options[:action].nil? and options[:action].eql?(:new_direct_message)
|
58
|
+
options[:payload]["text"] = status
|
59
|
+
else
|
60
|
+
options[:action] = :update
|
61
|
+
options[:payload] ||= {}
|
62
|
+
options[:payload]["status"] = status
|
63
|
+
end
|
64
|
+
end
|
65
65
|
opts.on("--pin PIN", ("Set auth pin if this is your first time playing " +
|
66
66
|
"with this tit")) do |pin|
|
67
67
|
unchanged = false
|
@@ -156,7 +156,7 @@ def main
|
|
156
156
|
not options[:notify].nil?)
|
157
157
|
end
|
158
158
|
if options[:action] == :update
|
159
|
-
tit.abort("need status message") unless options[:payload].include? "status"
|
159
|
+
tit.abort("need status message") unless options[:payload].include? "status" and not options[:payload]["status"].nil?
|
160
160
|
tit.abort("can't repeatedly update status") unless options[:wait].nil?
|
161
161
|
tit.abort("can't notify when updating status") unless options[:notify].nil?
|
162
162
|
end
|
data/lib/tit.rb
CHANGED
@@ -26,7 +26,7 @@ class String
|
|
26
26
|
replace(replace_with_expanded_url(expanded))
|
27
27
|
end
|
28
28
|
def replace_with_expanded_url(expanded)
|
29
|
-
replace_uris(/http:\/\/t.co\/[a-zA-Z0-9]{
|
29
|
+
replace_uris(/http:\/\/t.co\/[a-zA-Z0-9]{1,8}$/i, expanded)
|
30
30
|
end
|
31
31
|
def replace_uris(old, newt)
|
32
32
|
split(URI_REGEX).collect do |s|
|
@@ -91,7 +91,7 @@ end
|
|
91
91
|
Why are you reading the documentation, you cunt?
|
92
92
|
=end
|
93
93
|
class Tit
|
94
|
-
VERSION = [2,
|
94
|
+
VERSION = [2, 1, 0]
|
95
95
|
|
96
96
|
RCFILE = File.join(ENV["HOME"], ".titrc")
|
97
97
|
RTFILE = File.join(ENV["HOME"], ".titrt")
|
@@ -136,7 +136,7 @@ class Tit
|
|
136
136
|
YAML.dump(request_token.params, rt)
|
137
137
|
end
|
138
138
|
File.open(RCFILE, "w") do |rc|
|
139
|
-
YAML.dump({count
|
139
|
+
YAML.dump({:count => 10}, rc)
|
140
140
|
end
|
141
141
|
tuts "Please visit '#{request_token.authorize_url}'."
|
142
142
|
tuts "When you finish, provide your pin with `tit --pin PIN'"
|
@@ -171,6 +171,7 @@ class Tit
|
|
171
171
|
end
|
172
172
|
|
173
173
|
def get_tits(action, payload)
|
174
|
+
# Build the API Endpoint
|
174
175
|
api_endpoint = URLS[action]
|
175
176
|
if(action == :user_timeline and not payload.nil?)
|
176
177
|
api_endpoint.concat("?screen_name=".concat(payload['user'])).concat("&count=#{@prefs[:count]}")
|
@@ -178,30 +179,53 @@ class Tit
|
|
178
179
|
api_endpoint.concat("?count=#{@prefs[:count]}")
|
179
180
|
end
|
180
181
|
api_endpoint.concat("&include_entities=true")
|
182
|
+
|
181
183
|
coder = HTMLEntities.new
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
184
|
+
|
185
|
+
# Parse XML
|
186
|
+
xmlbody = @access_token.get(api_endpoint).body
|
187
|
+
# Errors
|
188
|
+
Nokogiri.XML(xmlbody).xpath("//errors").map do |xml|
|
189
|
+
if xml.at_xpath("./error").content == "This application is not allowed to access or delete your direct messages"
|
190
|
+
abort("Your OAuth key is not authorized for direct messaging.\nDelete #{TITAT} and run tit without arguments to reauthorize.")
|
191
|
+
end
|
192
|
+
end
|
193
|
+
# no errors - get tits
|
194
|
+
if action != :direct_messages
|
195
|
+
Nokogiri.XML(xmlbody).xpath("//status").map do |xml|
|
196
|
+
{
|
197
|
+
:username => xml.at_xpath("./user/name").content,
|
198
|
+
:userid => xml.at_xpath("./user/screen_name").content,
|
199
|
+
:text => xml.xpath("./text").map do |n|
|
200
|
+
txt = coder.decode(n.content)
|
201
|
+
if not xml.xpath("./entities/urls").nil?
|
202
|
+
xml.xpath("./entities/urls/url").map do |url|
|
203
|
+
txt.replace_with_expanded_url!(url.xpath("./expanded_url").map { |expurl| expurl.content })
|
204
|
+
end
|
205
|
+
end
|
206
|
+
txt
|
207
|
+
end,
|
208
|
+
:timestamp => Time.parse(xml.at_xpath("./created_at").content),
|
209
|
+
:id => xml.at_xpath("./id").content.to_i,
|
210
|
+
:geo => xml.at_xpath("./geo").instance_eval do
|
211
|
+
unless children.empty?
|
212
|
+
n, e = children[1].content.split.map { |s| s.to_f }
|
213
|
+
"#{n.abs}#{n >= 0 ? 'N' : 'S'} #{e.abs}#{e >= 0 ? 'E' : 'W'}"
|
192
214
|
end
|
193
215
|
end
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
216
|
+
}
|
217
|
+
end
|
218
|
+
else
|
219
|
+
# get the dms
|
220
|
+
Nokogiri.XML(xmlbody).xpath("//direct_message").map do |xml|
|
221
|
+
{
|
222
|
+
:username => xml.at_xpath("./sender/name").content,
|
223
|
+
:userid => xml.at_xpath("./sender_screen_name").content,
|
224
|
+
:text => xml.xpath("./text").map {|n| coder.decode(n.content)},
|
225
|
+
:timestamp => Time.parse(xml.at_xpath("./created_at").content),
|
226
|
+
:id => xml.at_xpath("./id").content.to_i,
|
227
|
+
}
|
228
|
+
end
|
205
229
|
end
|
206
230
|
end
|
207
231
|
|
@@ -231,7 +255,14 @@ class Tit
|
|
231
255
|
exit(-1)
|
232
256
|
end
|
233
257
|
|
234
|
-
@access_token.post(URLS[:new_direct_message], payload)
|
258
|
+
response = @access_token.post(URLS[:new_direct_message], payload)
|
259
|
+
|
260
|
+
# Check the response for errors
|
261
|
+
Nokogiri.XML(response).xpath("//hash").map do |xml|
|
262
|
+
if not xml.at_xpath("./error").content.eql?("")
|
263
|
+
abort("you cannot send a dm to someone who doesn't follow you")
|
264
|
+
end
|
265
|
+
end
|
235
266
|
end
|
236
267
|
|
237
268
|
def show_tit(status)
|
data/tit.gemspec
CHANGED