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 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.9'
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
- req = Net::HTTP::Post.new(@site[:url].path + "/statuses/update.json", { "User-Agent" => "Twitorious/#{Twitorious::VERSION}"})
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
- res = fetch_body(@site[:url].host, @site[:url].port, path, @site[:user], @site[:pass])
44
+ body = @auth.get(@site[:url], path)
29
45
 
30
- updates = JSON.parse(res)
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
- res = fetch_body(@site[:url].host, @site[:url].port, path, @site[:user], @site[:pass])
63
+ body = @auth.get(@site[:url], path)
47
64
 
48
- updates = JSON.parse(res)
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.2.9"
4
- s.date = "2009-04-16"
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.2.9
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-16 00:00:00 -07:00
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/