PerfectlyNormal-Twitorious 0.2.9 → 0.3.1
Sign up to get free protection for your applications and to get access to all the features.
- data/TODO +4 -0
- data/bin/twit +32 -0
- data/lib/twitorious.rb +6 -2
- data/lib/twitorious/api/twitter.rb +25 -32
- data/lib/twitorious/auth/basic.rb +60 -0
- data/lib/twitorious/auth/oauth.rb +44 -0
- data/lib/twitorious/url/bitly.rb +19 -0
- data/lib/twitorious/url/isgd.rb +18 -0
- data/twitorious.gemspec +7 -2
- metadata +16 -2
data/TODO
CHANGED
@@ -12,5 +12,9 @@
|
|
12
12
|
* Daemon that runs in the background
|
13
13
|
* Let the app run in a loop where it constantly prompts for new tweets
|
14
14
|
* Make more of a CLI
|
15
|
+
* Display how many more characters there's room for
|
15
16
|
* Update the timeline and get text-tweets in the app
|
16
17
|
* Open profile pages if there's a username in the tweet
|
18
|
+
* Support subscribing and unsubscribing to people
|
19
|
+
* Create the ~/twit-file if it doesn't exist
|
20
|
+
* Tab-complete followers
|
data/bin/twit
CHANGED
@@ -16,7 +16,39 @@ module Twitorious
|
|
16
16
|
|
17
17
|
while true
|
18
18
|
begin
|
19
|
+
Readline.completion_append_character = " "
|
20
|
+
Readline.completion_proc = Proc.new do |url|
|
21
|
+
if !url.match(/^(ftp|http|https):\/\//)
|
22
|
+
print "\a"
|
23
|
+
[]
|
24
|
+
elsif !@config[:url_shortening]
|
25
|
+
print "\a"
|
26
|
+
[]
|
27
|
+
else
|
28
|
+
# FIXME: Maybe add some magic here, so we don't need a 'case'
|
29
|
+
case @config.url_shortening[:service].downcase
|
30
|
+
when "bitly":
|
31
|
+
if(!@config.url_shortening[:user] || !@config.url_shortening[:pass])
|
32
|
+
puts "Invalid configuration for Bit.ly"
|
33
|
+
[]
|
34
|
+
else
|
35
|
+
bitly = Twitorious::URL::Bitly.new(@config.url_shortening[:user], @config.url_shortening[:pass])
|
36
|
+
[bitly.shorten(url)]
|
37
|
+
end
|
38
|
+
when "isgd":
|
39
|
+
[Twitorious::URL::Isgd.new.shorten(url)]
|
40
|
+
else
|
41
|
+
[]
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
19
45
|
status = Readline.readline("> ", true)
|
46
|
+
|
47
|
+
unless status # So we quit with a ^D
|
48
|
+
puts # And I hate that there's no newline before the prompt by default
|
49
|
+
exit
|
50
|
+
end
|
51
|
+
|
20
52
|
raise Twitorious::TooLongUpdate.new(status) if status.length > 140
|
21
53
|
|
22
54
|
cmd, *args = status.split(" ")
|
data/lib/twitorious.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
module Twitorious
|
2
|
-
VERSION = '0.
|
2
|
+
VERSION = '0.3.1'
|
3
3
|
|
4
4
|
class TooLongUpdate < StandardError; end
|
5
5
|
|
@@ -42,4 +42,8 @@ require 'twitorious/timeline'
|
|
42
42
|
require 'twitorious/update'
|
43
43
|
require 'twitorious/image'
|
44
44
|
require 'twitorious/notifier'
|
45
|
-
require 'twitorious/api/twitter'
|
45
|
+
require 'twitorious/api/twitter'
|
46
|
+
require 'twitorious/auth/basic'
|
47
|
+
require 'twitorious/auth/oauth'
|
48
|
+
require 'twitorious/url/bitly'
|
49
|
+
require 'twitorious/url/isgd'
|
@@ -10,14 +10,30 @@ module Twitorious
|
|
10
10
|
@config = config
|
11
11
|
@site = site
|
12
12
|
@notifier = Twitorious::Notifier.new
|
13
|
+
@auth = @site[:oauth_enabled] ?
|
14
|
+
Twitorious::Auth::OAuth.new :
|
15
|
+
Twitorious::Auth::Basic.new(@site[:user], @site[:pass])
|
16
|
+
|
17
|
+
if(@site[:oauth_enabled] && !@site[:oauth_authorized])
|
18
|
+
rt = @auth.get_request_token
|
19
|
+
puts "You need to authorize first"
|
20
|
+
%x{open #{@auth.authorize_url}}
|
21
|
+
puts "Press enter when done"
|
22
|
+
gets
|
23
|
+
at = rt.get_access_token
|
24
|
+
@site[:oauth_authorized] = true
|
25
|
+
@site[:oauth_token] = at.token
|
26
|
+
@site[:oauth_secret] = at.secret
|
27
|
+
end
|
28
|
+
|
29
|
+
if @site[:oauth_enabled] && @site[:oauth_authorized]
|
30
|
+
@auth.set_token(@site[:oauth_token], @site[:oauth_secret])
|
31
|
+
end
|
13
32
|
end
|
14
33
|
|
15
34
|
def update(status)
|
16
35
|
puts "Updating #{@site[:name]}"
|
17
|
-
|
18
|
-
req.basic_auth @site[:user], @site[:pass]
|
19
|
-
req.set_form_data({'status' => status}, ';')
|
20
|
-
res = Net::HTTP.new(@site[:url].host, @site[:url].port).start { |http| http.request(req) }
|
36
|
+
res = @auth.post(@site[:url], @site[:url].path + "/statuses/update.json", {"status" => status})
|
21
37
|
end
|
22
38
|
|
23
39
|
def fetch_timeline
|
@@ -25,9 +41,9 @@ module Twitorious
|
|
25
41
|
|
26
42
|
path = @site[:url].path + "/statuses/friends_timeline.json"
|
27
43
|
path += "?count=200&since_id=#{@site[:timeline_since_id]}" if @site[:timeline_since_id]
|
28
|
-
|
44
|
+
body = @auth.get(@site[:url], path)
|
29
45
|
|
30
|
-
updates = JSON.parse(
|
46
|
+
updates = JSON.parse(body)
|
31
47
|
puts " No updates" if updates.empty?
|
32
48
|
return if updates.empty?
|
33
49
|
|
@@ -42,10 +58,11 @@ module Twitorious
|
|
42
58
|
puts "Fetching mentions from #{@site[:name]}"
|
43
59
|
|
44
60
|
path = @site[:url].path + "/statuses/mentions.json"
|
61
|
+
path = @site[:url].path + "/statuses/replies.json" if @site[:name] == "Identi.ca"
|
45
62
|
path += "?since_id=#{@site[:mentions_since_id]}" if @site[:mentions_since_id]
|
46
|
-
|
63
|
+
body = @auth.get(@site[:url], path)
|
47
64
|
|
48
|
-
updates = JSON.parse(
|
65
|
+
updates = JSON.parse(body)
|
49
66
|
puts " No new mentions" if updates.empty?
|
50
67
|
return if updates.empty?
|
51
68
|
|
@@ -60,30 +77,6 @@ module Twitorious
|
|
60
77
|
|
61
78
|
private
|
62
79
|
|
63
|
-
def fetch_body(host, port, path, username = nil, password = nil)
|
64
|
-
res = nil
|
65
|
-
begin
|
66
|
-
Net::HTTP.start(host, port) do |http|
|
67
|
-
req = Net::HTTP::Get.new(path, { "User-Agent" => "Twitorious/#{Twitorious::VERSION}"})
|
68
|
-
req.basic_auth username, password if username
|
69
|
-
res = http.request(req)
|
70
|
-
end
|
71
|
-
rescue => e
|
72
|
-
$stderr.puts "Unhandled exception! #{e.message}"
|
73
|
-
rescue Timeout::Error
|
74
|
-
$stderr.puts "Request to #{host} timed out. Retrying in five seconds"
|
75
|
-
sleep 5
|
76
|
-
retry
|
77
|
-
end
|
78
|
-
|
79
|
-
if res.kind_of?(Net::HTTPNotFound)
|
80
|
-
$stderr.puts "404 Not Found! #{host}:#{port}/#{path}"
|
81
|
-
return "{}"
|
82
|
-
elsif res.kind_of?(Net::HTTPOK)
|
83
|
-
return res.body
|
84
|
-
end
|
85
|
-
end
|
86
|
-
|
87
80
|
def show_notifications(updates)
|
88
81
|
updates.each do |update|
|
89
82
|
image = Twitorious::Image.from_url(update["user"]["profile_image_url"], @config.image_store)
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module Twitorious
|
2
|
+
module Auth
|
3
|
+
class Basic
|
4
|
+
def initialize(username, password)
|
5
|
+
@username = username
|
6
|
+
@password = password
|
7
|
+
end
|
8
|
+
|
9
|
+
def get(url, path)
|
10
|
+
res = nil
|
11
|
+
begin
|
12
|
+
Net::HTTP.start(url.host, url.port) do |http|
|
13
|
+
req = Net::HTTP::Get.new(path, { "User-Agent" => "Twitorious/#{Twitorious::VERSION}"})
|
14
|
+
req.basic_auth @username, @password
|
15
|
+
res = http.request(req)
|
16
|
+
end
|
17
|
+
rescue => e
|
18
|
+
$stderr.puts "Unhandled exception! #{e.message}"
|
19
|
+
rescue Timeout::Error
|
20
|
+
$stderr.puts "Request to #{url.host} timed out. Retrying in five seconds"
|
21
|
+
sleep 5
|
22
|
+
retry
|
23
|
+
end
|
24
|
+
|
25
|
+
case res.code.to_i
|
26
|
+
when 400:
|
27
|
+
$stderr.puts "400 Rate Limited!"
|
28
|
+
return "{}"
|
29
|
+
when 401:
|
30
|
+
$stderr.puts "401 Unauthorized"
|
31
|
+
return "{}"
|
32
|
+
when 403:
|
33
|
+
$stderr.puts "403: #{res.message}!"
|
34
|
+
$stderr.puts res.body
|
35
|
+
return "{}"
|
36
|
+
when 404:
|
37
|
+
$stderr.puts "404 Not Found! #{url.host}:#{url.port}#{path}"
|
38
|
+
return "{}"
|
39
|
+
when 500:
|
40
|
+
$stderr.puts "An internal server error occured. (#{res.code}): #{res.message}"
|
41
|
+
return "{}"
|
42
|
+
when 502..503:
|
43
|
+
$stderr.puts "Unavailable!"
|
44
|
+
return "{}"
|
45
|
+
end
|
46
|
+
|
47
|
+
return res.body
|
48
|
+
end
|
49
|
+
|
50
|
+
def post(url, path, form_data)
|
51
|
+
req = Net::HTTP::Post.new(path, { "User-Agent" => "Twitorious/#{Twitorious::VERSION}"})
|
52
|
+
req.basic_auth @username, @password
|
53
|
+
req.set_form_data(form_data, ';')
|
54
|
+
res = Net::HTTP.new(url.host, url.port).start { |http| http.request(req) }
|
55
|
+
|
56
|
+
return res.body
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'oauth'
|
2
|
+
require 'oauth/consumer'
|
3
|
+
|
4
|
+
module Twitorious
|
5
|
+
module Auth
|
6
|
+
class OAuth
|
7
|
+
def initialize
|
8
|
+
@consumer = ::OAuth::Consumer.new(
|
9
|
+
"oZglZozO6F3p1Ed8n9F6fw",
|
10
|
+
"onR6S9HS54D40Qg1KfI16c9A72KRoJKJwaXe73Tv0",
|
11
|
+
{ :site => "http://twitter.com" })
|
12
|
+
end
|
13
|
+
|
14
|
+
def get_request_token
|
15
|
+
@request_token = @consumer.get_request_token
|
16
|
+
@request_token
|
17
|
+
end
|
18
|
+
|
19
|
+
def authorize_url
|
20
|
+
@request_token.authorize_url
|
21
|
+
end
|
22
|
+
|
23
|
+
def set_token(token, secret)
|
24
|
+
@token, @secret = token, secret
|
25
|
+
get_access_token
|
26
|
+
end
|
27
|
+
|
28
|
+
def get_access_token
|
29
|
+
@access_token ||= ::OAuth::AccessToken.new(@consumer, @token, @secret)
|
30
|
+
@access_token
|
31
|
+
end
|
32
|
+
|
33
|
+
def get(url, path)
|
34
|
+
res = @access_token.get path
|
35
|
+
return res.body
|
36
|
+
end
|
37
|
+
|
38
|
+
def post(url, path, form_data)
|
39
|
+
res = @access_token.post path, form_data
|
40
|
+
return res.body
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'cgi'
|
2
|
+
|
3
|
+
module Twitorious
|
4
|
+
module URL
|
5
|
+
class Bitly
|
6
|
+
def initialize(user, pass)
|
7
|
+
@auth = Twitorious::Auth::Basic.new(user, pass)
|
8
|
+
@host = URI.parse("http://api.bit.ly")
|
9
|
+
end
|
10
|
+
|
11
|
+
def shorten(url)
|
12
|
+
path = "/shorten?version=2.0.1&longUrl=#{CGI.escape(url)}"
|
13
|
+
body = @auth.get(@host, path)
|
14
|
+
json = JSON.parse(body)
|
15
|
+
return json["results"][url]["shortUrl"]
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'cgi'
|
2
|
+
|
3
|
+
module Twitorious
|
4
|
+
module URL
|
5
|
+
class Isgd
|
6
|
+
def initialize
|
7
|
+
@auth = Twitorious::Auth::Basic.new("not", "needed")
|
8
|
+
@host = URI.parse("http://is.gd")
|
9
|
+
end
|
10
|
+
|
11
|
+
def shorten(url)
|
12
|
+
body = @auth.get @host, "/api.php?longurl=#{CGI.escape(url)}"
|
13
|
+
return nil if body == "{}"
|
14
|
+
return body
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
data/twitorious.gemspec
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = "Twitorious"
|
3
|
-
s.version = "0.
|
4
|
-
s.date = "2009-04-
|
3
|
+
s.version = "0.3.1"
|
4
|
+
s.date = "2009-04-20"
|
5
5
|
s.author = "Per Christian B. Viken"
|
6
6
|
s.email = "perchr@northblue.org"
|
7
7
|
s.homepage = "http://eastblue.org/projects/twitorious/"
|
@@ -15,10 +15,15 @@ Gem::Specification.new do |s|
|
|
15
15
|
"lib/twitorious/update.rb",
|
16
16
|
"lib/twitorious/notifier.rb",
|
17
17
|
"lib/twitorious/api/twitter.rb",
|
18
|
+
"lib/twitorious/auth/basic.rb",
|
19
|
+
"lib/twitorious/auth/oauth.rb",
|
20
|
+
"lib/twitorious/url/isgd.rb",
|
21
|
+
"lib/twitorious/url/bitly.rb",
|
18
22
|
"TODO"]
|
19
23
|
s.executables << 'twit'
|
20
24
|
s.executables << 'twit-notifier'
|
21
25
|
s.add_dependency("meow", ">= 2.1.0")
|
22
26
|
s.add_dependency("json", ">= 1.1.0")
|
27
|
+
s.add_dependency("oauth", ">= 0.3.2")
|
23
28
|
s.has_rdoc = true
|
24
29
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: PerfectlyNormal-Twitorious
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Per Christian B. Viken
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-04-
|
12
|
+
date: 2009-04-20 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -32,6 +32,16 @@ dependencies:
|
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: 1.1.0
|
34
34
|
version:
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: oauth
|
37
|
+
type: :runtime
|
38
|
+
version_requirement:
|
39
|
+
version_requirements: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: 0.3.2
|
44
|
+
version:
|
35
45
|
description:
|
36
46
|
email: perchr@northblue.org
|
37
47
|
executables:
|
@@ -50,6 +60,10 @@ files:
|
|
50
60
|
- lib/twitorious/update.rb
|
51
61
|
- lib/twitorious/notifier.rb
|
52
62
|
- lib/twitorious/api/twitter.rb
|
63
|
+
- lib/twitorious/auth/basic.rb
|
64
|
+
- lib/twitorious/auth/oauth.rb
|
65
|
+
- lib/twitorious/url/isgd.rb
|
66
|
+
- lib/twitorious/url/bitly.rb
|
53
67
|
- TODO
|
54
68
|
has_rdoc: true
|
55
69
|
homepage: http://eastblue.org/projects/twitorious/
|