PerfectlyNormal-Twitorious 0.2.9 → 0.3.1
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.
- 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/
|