tit 1.0.1 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/ChangeLog.markdown +4 -0
- data/README.markdown +32 -6
- data/Rakefile +2 -2
- data/VERSION.yml +2 -2
- data/bin/tit +20 -2
- data/lib/tit.rb +70 -46
- data/tit.gemspec +8 -8
- metadata +5 -5
data/ChangeLog.markdown
CHANGED
data/README.markdown
CHANGED
@@ -12,28 +12,54 @@ install
|
|
12
12
|
usage
|
13
13
|
-----
|
14
14
|
|
15
|
+
### authz ###
|
16
|
+
|
17
|
+
first, you need to authenticate yourself with the stupid fucking twitter oauth
|
18
|
+
stuff
|
19
|
+
|
20
|
+
to do this, just run tit by itself
|
21
|
+
|
15
22
|
$ tit
|
16
23
|
|
17
|
-
|
24
|
+
it'll prompt you with the auth url, so plug that in your fucking browser, click
|
25
|
+
"ok", and twitter will give you a stupid fucking pin number
|
18
26
|
|
19
|
-
$ tit
|
27
|
+
$ tit --pin 8675309
|
28
|
+
|
29
|
+
now you're done and your goddamn access token should be stored for a real
|
30
|
+
fucking long time
|
31
|
+
|
32
|
+
### looking at tits ###
|
33
|
+
|
34
|
+
get the shit you'd see by visiting twitter's fucking homepage:
|
20
35
|
|
21
|
-
|
36
|
+
$ tit
|
37
|
+
|
38
|
+
annoyingly poll twitter and add some stupid fucking notifications too:
|
22
39
|
|
23
40
|
$ tit -P -n
|
24
41
|
|
42
|
+
there's some more fucking options for you if you look at `tit -h`
|
43
|
+
|
44
|
+
### showing other people your tits ###
|
45
|
+
|
46
|
+
$ tit -u "look at my stupid fucking tweet" -G 88.918:-34.879
|
47
|
+
|
25
48
|
dependencies
|
26
49
|
------------
|
27
50
|
|
28
|
-
[
|
51
|
+
[oauth][] and [nokogiri][]
|
52
|
+
|
53
|
+
[oauth]: http://oauth.rubyforge.org/
|
54
|
+
[nokogiri]: http://nokogiri.org/
|
29
55
|
|
30
56
|
caveats
|
31
57
|
-------
|
32
58
|
|
33
59
|
geotags are of the form `LAT:LONG`, where `LAT` and `LONG` are floating point
|
34
60
|
numbers, indicating, respectively, the number of degrees north or east of the
|
35
|
-
center of the earth; make them negative if you live on one or both of
|
36
|
-
hemispheres
|
61
|
+
fucking center of the earth; make them negative if you live on one or both of
|
62
|
+
the dark hemispheres
|
37
63
|
|
38
64
|
bugs
|
39
65
|
----
|
data/Rakefile
CHANGED
@@ -7,8 +7,8 @@ begin
|
|
7
7
|
gemspec.email = "leif.walsh@gmail.com"
|
8
8
|
gemspec.homepage = "http://github.com/adlaiff6/tit"
|
9
9
|
gemspec.authors = ["Leif Walsh"]
|
10
|
-
gemspec.add_dependency('nokogiri', '>=
|
11
|
-
gemspec.add_dependency('
|
10
|
+
gemspec.add_dependency('nokogiri', '>= 0')
|
11
|
+
gemspec.add_dependency('oauth', '>= 0')
|
12
12
|
end
|
13
13
|
Jeweler::GemcutterTasks.new
|
14
14
|
rescue LoadError
|
data/VERSION.yml
CHANGED
data/bin/tit
CHANGED
@@ -2,6 +2,8 @@
|
|
2
2
|
|
3
3
|
require 'tit'
|
4
4
|
|
5
|
+
require 'optparse'
|
6
|
+
|
5
7
|
def main
|
6
8
|
options = {
|
7
9
|
:debug => false,
|
@@ -35,6 +37,10 @@ def main
|
|
35
37
|
options[:payload] ||= {}
|
36
38
|
options[:payload]["status"] = status || STDIN
|
37
39
|
end
|
40
|
+
opts.on("--pin PIN", ("Set auth pin if this is your first time playing " +
|
41
|
+
"with this tit")) do |pin|
|
42
|
+
options[:pin] = pin
|
43
|
+
end
|
38
44
|
|
39
45
|
opts.separator ""
|
40
46
|
opts.separator "Receive options (public/home/mentions):"
|
@@ -86,6 +92,12 @@ def main
|
|
86
92
|
tit.abort(e.message)
|
87
93
|
end
|
88
94
|
|
95
|
+
if options.include? :pin
|
96
|
+
tit.use_pin(options[:pin])
|
97
|
+
end
|
98
|
+
|
99
|
+
tit.get_access
|
100
|
+
|
89
101
|
# check for option errors
|
90
102
|
if Tit::READERS.include? options[:action]
|
91
103
|
tit.abort("cannot provide geotag when reading") unless options[:payload].nil?
|
@@ -102,18 +114,24 @@ def main
|
|
102
114
|
if options[:debug]
|
103
115
|
begin
|
104
116
|
tit.run(options)
|
105
|
-
rescue SocketError, Errno::ENETUNREACH, Errno::ETIMEDOUT
|
117
|
+
rescue SocketError, Errno::ENETUNREACH, Errno::ETIMEDOUT => e
|
106
118
|
tit.error "got a networking error, are you connected to the intarbutts?"
|
107
119
|
puts e
|
108
120
|
exit(-1)
|
121
|
+
rescue NoMethodError
|
122
|
+
tit.error "might have gotten a networking error, check your intarbutts."
|
123
|
+
exit(-1)
|
109
124
|
end
|
110
125
|
else
|
111
126
|
begin
|
112
127
|
tit.run(options)
|
113
|
-
rescue SocketError, Errno::ENETUNREACH, Errno::ETIMEDOUT
|
128
|
+
rescue SocketError, Errno::ENETUNREACH, Errno::ETIMEDOUT => e
|
114
129
|
tit.error "got a networking error, are you connected to the intarbutts?"
|
115
130
|
puts e
|
116
131
|
exit(-1)
|
132
|
+
rescue NoMethodError
|
133
|
+
tit.error "might have gotten a networking error, check your intarbutts."
|
134
|
+
exit(-1)
|
117
135
|
rescue => e
|
118
136
|
tit.error "unknown error"
|
119
137
|
puts e
|
data/lib/tit.rb
CHANGED
@@ -3,8 +3,7 @@
|
|
3
3
|
require 'rubygems'
|
4
4
|
require 'ftools'
|
5
5
|
require 'nokogiri'
|
6
|
-
require '
|
7
|
-
require 'rest_client'
|
6
|
+
require 'oauth/consumer'
|
8
7
|
require 'time' # heh.
|
9
8
|
require 'yaml'
|
10
9
|
|
@@ -75,56 +74,76 @@ end
|
|
75
74
|
Why are you reading the documentation, you cunt?
|
76
75
|
=end
|
77
76
|
class Tit
|
78
|
-
|
77
|
+
RTFILE = File.join(ENV["HOME"], ".titrt")
|
78
|
+
ATFILE = File.join(ENV["HOME"], ".titat")
|
79
79
|
|
80
80
|
READERS = [:public, :home, :mentions]
|
81
81
|
WRITERS = [:update]
|
82
82
|
|
83
83
|
URLS = {
|
84
|
-
:public => "statuses/public_timeline.xml",
|
85
|
-
:home => "statuses/home_timeline.xml",
|
86
|
-
:mentions => "statuses/mentions.xml",
|
87
|
-
:update => "statuses/update.xml"
|
84
|
+
:public => "/statuses/public_timeline.xml",
|
85
|
+
:home => "/statuses/home_timeline.xml",
|
86
|
+
:mentions => "/statuses/mentions.xml",
|
87
|
+
:update => "/statuses/update.xml"
|
88
88
|
}
|
89
89
|
|
90
|
+
KEY = "K2OOlWbQodfm4YV9Fmeg"
|
91
|
+
SECRET = "B1HuqK8zoDDLboRAWPqlHTFbLVdkQfquzoUC1MkuM"
|
92
|
+
|
90
93
|
def initialize
|
91
|
-
@
|
92
|
-
|
94
|
+
@consumer = OAuth::Consumer.new(KEY, SECRET,
|
95
|
+
{ :site => "https://twitter.com" })
|
96
|
+
|
97
|
+
# get terminal width
|
98
|
+
@cols = %x[tput cols].to_i
|
99
|
+
end
|
100
|
+
attr_accessor :opts
|
101
|
+
|
102
|
+
def get_access
|
93
103
|
begin
|
94
|
-
File.open(
|
95
|
-
|
96
|
-
@
|
97
|
-
@password = data["password"]
|
104
|
+
@access_token = File.open(ATFILE, "r") do |at|
|
105
|
+
params = YAML.load(at)
|
106
|
+
OAuth::AccessToken.from_hash(@consumer, params)
|
98
107
|
end
|
99
108
|
rescue Errno::ENOENT => e
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
"password" => "<password>"
|
104
|
-
}, rc)
|
109
|
+
request_token = @consumer.get_request_token
|
110
|
+
File.open(RTFILE, "w") do |rt|
|
111
|
+
YAML.dump(request_token.params, rt)
|
105
112
|
end
|
113
|
+
tuts "Please visit '#{request_token.authorize_url}'."
|
114
|
+
tuts "When you finish, provide your pin with `tit --pin PIN'"
|
115
|
+
exit(0)
|
106
116
|
end
|
107
|
-
|
108
|
-
if @username.nil? or @username.eql? "<username>" or
|
109
|
-
@password.nil? or @password.eql? "<password>"
|
110
|
-
puts "Please fill in your username and password in #{RCFILE}"
|
111
|
-
exit(-1)
|
112
|
-
end
|
113
|
-
|
114
|
-
# set up proxy
|
115
|
-
RestClient.proxy = ENV['https_proxy']
|
116
|
-
|
117
|
-
# get terminal width
|
118
|
-
@cols = %x[tput cols].to_i
|
119
117
|
end
|
120
|
-
attr_accessor :opts
|
121
118
|
|
122
|
-
def
|
123
|
-
|
119
|
+
def use_pin(pin)
|
120
|
+
begin
|
121
|
+
request_token = File.open(RTFILE, "r") do |rt|
|
122
|
+
params = YAML.load(rt)
|
123
|
+
OAuth::RequestToken.from_hash(@consumer, params)
|
124
|
+
end
|
125
|
+
rescue Errno::ENOENT => e
|
126
|
+
tuts "You lost your old token, gotta try again."
|
127
|
+
get_access
|
128
|
+
end
|
129
|
+
begin
|
130
|
+
@access_token = request_token.get_access_token(:oauth_verifier => pin)
|
131
|
+
rescue OAuth::Unauthorized => e
|
132
|
+
tuts "Sorry, that's an old pin."
|
133
|
+
File.delete(RTFILE)
|
134
|
+
get_access
|
135
|
+
end
|
136
|
+
File.open(ATFILE, "w") do |at|
|
137
|
+
YAML.dump(@access_token.params, at)
|
138
|
+
end
|
139
|
+
File.delete(RTFILE)
|
140
|
+
tuts "Thanks, you're done with authentication."
|
141
|
+
tuts "Keep #{ATFILE} secure and intact. If it's compromised, I can't " +
|
142
|
+
"revoke your token."
|
124
143
|
end
|
125
144
|
|
126
145
|
def get_tits(action)
|
127
|
-
Nokogiri.XML(
|
146
|
+
Nokogiri.XML(@access_token.get(URLS[action]).body).xpath("//status").map do |xml|
|
128
147
|
{
|
129
148
|
:username => xml.at_xpath("./user/name").content,
|
130
149
|
:userid => xml.at_xpath("./user/screen_name").content,
|
@@ -147,13 +166,13 @@ class Tit
|
|
147
166
|
end
|
148
167
|
|
149
168
|
if payload["status"].length > 140
|
150
|
-
|
151
|
-
|
169
|
+
tuts "your status is too long (by #{payload["status"].length - 140} characters)"
|
170
|
+
tuts "here is what would get posted:"
|
152
171
|
payload["status"][0...140].wrapped(@cols - 2).each { |l| puts " #{l}" }
|
153
172
|
exit(-1)
|
154
173
|
end
|
155
174
|
|
156
|
-
|
175
|
+
@access_token.post(URLS[:update], payload)
|
157
176
|
end
|
158
177
|
|
159
178
|
def show_tit(status)
|
@@ -164,9 +183,9 @@ class Tit
|
|
164
183
|
end
|
165
184
|
at = status[:timestamp].time_ago_in_words
|
166
185
|
if status[:geo].nil?
|
167
|
-
|
186
|
+
tuts "#{person} said, #{at}:"
|
168
187
|
else
|
169
|
-
|
188
|
+
tuts "#{person} said, #{at}, from #{status[:geo]}:"
|
170
189
|
end
|
171
190
|
|
172
191
|
status[:text].each do |line|
|
@@ -194,15 +213,16 @@ class Tit
|
|
194
213
|
tits.include? status[:id]
|
195
214
|
end.each_with_index do |status, i|
|
196
215
|
if i == 0
|
197
|
-
|
216
|
+
tuts "more updates (at #{Time.now.strftime "%X"}):"
|
217
|
+
puts ""
|
198
218
|
end
|
199
219
|
show_tit(status)
|
200
220
|
tits[status[:id]] = status
|
201
221
|
end.length
|
202
222
|
%x[#{notify} '#{num_tits} new tit#{num_tits == 1 ? '' : 's'}!'] unless notify.nil? or num_tits == 0
|
203
223
|
last_update = Time.now()
|
204
|
-
rescue SocketError, Errno::ENETUNREACH, Errno::ETIMEDOUT,
|
205
|
-
|
224
|
+
rescue SocketError, Errno::ENETUNREACH, Errno::ETIMEDOUT, NoMethodError => e
|
225
|
+
tuts "networking error, will try again later"
|
206
226
|
end
|
207
227
|
end
|
208
228
|
end
|
@@ -219,13 +239,17 @@ class Tit
|
|
219
239
|
end
|
220
240
|
end
|
221
241
|
|
222
|
-
def
|
223
|
-
puts
|
242
|
+
def tuts(*strs)
|
243
|
+
strs.each { |s| puts s.wrapped(@cols) }
|
244
|
+
end
|
245
|
+
|
246
|
+
def error(msg)
|
247
|
+
tuts "#{File.basename $0}: #{msg}"
|
224
248
|
end
|
225
249
|
|
226
|
-
def abort
|
250
|
+
def abort(msg)
|
227
251
|
error(msg)
|
228
|
-
|
252
|
+
tuts @opts
|
229
253
|
exit(-1)
|
230
254
|
end
|
231
255
|
end
|
data/tit.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{tit}
|
8
|
-
s.version = "1.0
|
8
|
+
s.version = "1.1.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Leif Walsh"]
|
12
|
-
s.date = %q{2010-01-
|
12
|
+
s.date = %q{2010-01-23}
|
13
13
|
s.default_executable = %q{tit}
|
14
14
|
s.description = %q{a stupid fucking twitter client}
|
15
15
|
s.email = %q{leif.walsh@gmail.com}
|
@@ -41,15 +41,15 @@ Gem::Specification.new do |s|
|
|
41
41
|
s.specification_version = 3
|
42
42
|
|
43
43
|
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
44
|
-
s.add_runtime_dependency(%q<nokogiri>, [">=
|
45
|
-
s.add_runtime_dependency(%q<
|
44
|
+
s.add_runtime_dependency(%q<nokogiri>, [">= 0"])
|
45
|
+
s.add_runtime_dependency(%q<oauth>, [">= 0"])
|
46
46
|
else
|
47
|
-
s.add_dependency(%q<nokogiri>, [">=
|
48
|
-
s.add_dependency(%q<
|
47
|
+
s.add_dependency(%q<nokogiri>, [">= 0"])
|
48
|
+
s.add_dependency(%q<oauth>, [">= 0"])
|
49
49
|
end
|
50
50
|
else
|
51
|
-
s.add_dependency(%q<nokogiri>, [">=
|
52
|
-
s.add_dependency(%q<
|
51
|
+
s.add_dependency(%q<nokogiri>, [">= 0"])
|
52
|
+
s.add_dependency(%q<oauth>, [">= 0"])
|
53
53
|
end
|
54
54
|
end
|
55
55
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tit
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Leif Walsh
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2010-01-
|
12
|
+
date: 2010-01-23 00:00:00 +01:00
|
13
13
|
default_executable: tit
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -20,17 +20,17 @@ dependencies:
|
|
20
20
|
requirements:
|
21
21
|
- - ">="
|
22
22
|
- !ruby/object:Gem::Version
|
23
|
-
version:
|
23
|
+
version: "0"
|
24
24
|
version:
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
|
-
name:
|
26
|
+
name: oauth
|
27
27
|
type: :runtime
|
28
28
|
version_requirement:
|
29
29
|
version_requirements: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version:
|
33
|
+
version: "0"
|
34
34
|
version:
|
35
35
|
description: a stupid fucking twitter client
|
36
36
|
email: leif.walsh@gmail.com
|