tweetline 0.0.3 → 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/MIT-LICENSE +20 -0
- data/README.rdoc +39 -0
- data/bin/tl +2 -2
- data/lib/tweetline/cli.rb +146 -0
- data/lib/tweetline.rb +82 -0
- data/tweetline.gemspec +27 -0
- metadata +9 -3
data/.gitignore
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
*.gem
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2011 Anthony Crumley
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
This is the initial proof of concept for a twitter command line tool. Now that I understand the problem, I am currently in the process of writing a more robust implementation.
|
2
|
+
|
3
|
+
== Getting Started
|
4
|
+
|
5
|
+
1. Install Tweetline at the command prompt if you haven't yet:
|
6
|
+
|
7
|
+
gem install tweetline
|
8
|
+
|
9
|
+
2. Until Twitter approves xAuth for Tweetline, you will have to create a ~/.tweetlinerc yaml file with your authentication credentials like the following...
|
10
|
+
|
11
|
+
:consumer_key: "your-key"
|
12
|
+
:consumer_secret: "your-secret"
|
13
|
+
:oauth_token: "your-token"
|
14
|
+
:oauth_token_secret: "your-secret"
|
15
|
+
|
16
|
+
3. Enter commands with tl:
|
17
|
+
|
18
|
+
tl ls
|
19
|
+
|
20
|
+
ESV Daily Verse (@esvdaily) [04:46 AM]
|
21
|
+
A friend loves at all times, and a brother is born for adversity. http://esv.to/Pr17.17 (54842265859915777)
|
22
|
+
|
23
|
+
DHH (@dhh) [04/02/11 11:43 AM]
|
24
|
+
I've tried many answers for "what do you get out of working on open source?", but the truth is the act of creation is its own reward. (54222543829213184)
|
25
|
+
|
26
|
+
== Tasks
|
27
|
+
|
28
|
+
tl cat [ID] # Display the details of a tweet with responses based on twitter id or piped in tweets.
|
29
|
+
tl follow [SCREEN_NAME] # Follows the twitter user based on their screen name or piped in tweets.
|
30
|
+
tl help [TASK] # Describe available tasks or one specific task
|
31
|
+
tl json # Lists tweets from the timeline in JSON format.
|
32
|
+
tl ls [SCREEN_NAME] # Lists tweets from the timeline.
|
33
|
+
tl retweet [ID] # Retweets the tweet by the Twitter id or a group of piped in tweets.
|
34
|
+
tl rm [ID] # Removes the tweet by it's id or a list of piped in tweets.
|
35
|
+
tl say # Speaks the tweet at the top of your timeline.
|
36
|
+
tl tail # Displays recent tweets in chronological order.
|
37
|
+
tl unfollow [SCREEN_NAME] # Unfollows the twitter user based on their screen name or piped in tweets.
|
38
|
+
tl update STATUS # Updates your current Twitter status.
|
39
|
+
tl yaml # Lists tweets from the timeline in YAML format.
|
data/bin/tl
CHANGED
@@ -0,0 +1,146 @@
|
|
1
|
+
module Tweetline
|
2
|
+
class CLI < Thor
|
3
|
+
def initialize(*)
|
4
|
+
super
|
5
|
+
Tweetline.configure_twitter
|
6
|
+
Tweetline.configure_pipes
|
7
|
+
end
|
8
|
+
|
9
|
+
default_task :ls
|
10
|
+
|
11
|
+
desc "cat [ID]", "Display the details of a tweet with responses based on twitter id or piped in tweets."
|
12
|
+
def cat(twitter_id = "")
|
13
|
+
if twitter_id.strip.length > 0
|
14
|
+
tweet = Twitter.status(ARGV[1])
|
15
|
+
Tweetline.cat_tweet(tweet.id, tweet.created_at, tweet.user.name, tweet.user.screen_name, tweet.text)
|
16
|
+
else
|
17
|
+
Tweetline.each_tweet do |tweet|
|
18
|
+
Tweetline.cat_tweet(tweet["id"], tweet["created_at"], tweet["name"], tweet["screen_name"], tweet["text"])
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
desc "follow [SCREEN_NAME]", "Follows the twitter user based on their screen name or piped in tweets."
|
24
|
+
def follow(screen_name = "")
|
25
|
+
if screen_name.strip.length > 0
|
26
|
+
Twitter.follow(screen_name)
|
27
|
+
else
|
28
|
+
Tweetline.each_tweet do |tweet|
|
29
|
+
Twitter.follow(tweet["screen_name"])
|
30
|
+
puts "Followed -> #{tweet["screen_name"]}" unless Twitter.is_piped_to_tweetline?
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
desc "json", "Lists tweets from the timeline in JSON format."
|
36
|
+
def json
|
37
|
+
Tweetline.each_tweet do |tweet|
|
38
|
+
puts tweet.to_json
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
desc "ls [SCREEN_NAME]", "Lists tweets from the timeline."
|
43
|
+
def ls(screen_name = "")
|
44
|
+
options = {:count => 10}
|
45
|
+
options[:screen_name] = screen_name if screen_name.strip.length > 0
|
46
|
+
Tweetline.each_tweet(options) do |tweet|
|
47
|
+
Tweetline.put_tweet(tweet["id"], tweet["created_at"], tweet["name"], tweet["screen_name"], tweet["text"])
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
desc "raw", "Raw output for testing."
|
52
|
+
def raw
|
53
|
+
STDIN.each do |text|
|
54
|
+
puts text
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
desc "retweet [ID]", "Retweets the tweet by the Twitter id or a group of piped in tweets."
|
59
|
+
def retweet(twitter_id = "")
|
60
|
+
if twitter_id.strip.length > 0
|
61
|
+
Twitter.retweet(twitter_id)
|
62
|
+
else
|
63
|
+
Tweetline.each_tweet do |tweet|
|
64
|
+
Twitter.retweet(tweet["id"])
|
65
|
+
puts "Retweeted:" unless Twitter.is_piped_to_tweetline?
|
66
|
+
Twitter.put_tweet(tweet["id"], tweet["created_at"], tweet["name"], tweet["screen_name"], tweet["text"])
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
desc "rm [ID]", "Removes the tweet by it's id or a list of piped in tweets."
|
72
|
+
def rm(twitter_id = "")
|
73
|
+
if twitter_id.strip.length > 0
|
74
|
+
Twitter.status_destroy(twitter_id)
|
75
|
+
else
|
76
|
+
Tweetline.each_tweet do |tweet|
|
77
|
+
Twitter.status_destroy(tweet["id"])
|
78
|
+
puts "Removed:" unless Twitter.is_piped_to_tweetline?
|
79
|
+
Twitter.put_tweet(tweet["id"], tweet["created_at"], tweet["name"], tweet["screen_name"], tweet["text"])
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
desc "say", "Speaks the tweet at the top of your timeline."
|
85
|
+
def say
|
86
|
+
Tweetline.each_tweet(:count => 1) do |tweet|
|
87
|
+
Tweetline.say_tweet(tweet["id"], tweet["created_at"], tweet["name"], tweet["screen_name"], tweet["text"])
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
desc "tail", "Displays recent tweets in chronological order."
|
92
|
+
method_option :follow, :type => :boolean, :aliases => "-f", :defatul => false, :banner => "Continue following tweets as they are added."
|
93
|
+
method_option :number, :type => :numeric, :aliases => "-n", :default => 10, :banner => "Specifies the number of tweets to display."
|
94
|
+
def tail
|
95
|
+
opts = options.dup
|
96
|
+
|
97
|
+
Signal.trap("SIGINT") do
|
98
|
+
exit!
|
99
|
+
end
|
100
|
+
|
101
|
+
previous_id = "1"
|
102
|
+
begin
|
103
|
+
tweets = Twitter.home_timeline(:count => opts[:number], :since_id => previous_id) rescue []
|
104
|
+
tweets.reverse_each do |tweet|
|
105
|
+
Tweetline.put_tweet(tweet.id, tweet.created_at, tweet.user.name, tweet.user.screen_name, tweet.text)
|
106
|
+
previous_id = tweet.id
|
107
|
+
end
|
108
|
+
|
109
|
+
sleep(30) if opts[:follow]
|
110
|
+
|
111
|
+
end while opts[:follow]
|
112
|
+
end
|
113
|
+
|
114
|
+
desc "unfollow [SCREEN_NAME]", "Unfollows the twitter user based on their screen name or piped in tweets."
|
115
|
+
def unfollow(screen_name = "")
|
116
|
+
if screen_name.strip.length > 0
|
117
|
+
Twitter.unfollow(screen_name)
|
118
|
+
else
|
119
|
+
Tweetline.each_tweet do |tweet|
|
120
|
+
Twitter.unfollow(tweet["screen_name"])
|
121
|
+
puts "Followed -> #{tweet["screen_name"]}" unless Twitter.is_piped_to_tweetline?
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
desc "update STATUS", "Updates your current Twitter status."
|
127
|
+
def update(status)
|
128
|
+
if status.length > 140
|
129
|
+
puts ""
|
130
|
+
puts "This status is too long."
|
131
|
+
puts ""
|
132
|
+
puts " #{status[0..139]}"
|
133
|
+
puts ""
|
134
|
+
else
|
135
|
+
Twitter.update(status)
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
desc "yaml", "Lists tweets from the timeline in YAML format."
|
140
|
+
def yaml
|
141
|
+
Tweetline.each_tweet do |tweet|
|
142
|
+
puts tweet.to_yaml
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
data/lib/tweetline.rb
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
require 'thor'
|
2
|
+
require 'twitter'
|
3
|
+
require 'json'
|
4
|
+
|
5
|
+
module Tweetline
|
6
|
+
class << self
|
7
|
+
|
8
|
+
def cat_tweet(tweet_id, created_at, name, screen_name, text)
|
9
|
+
Tweetline.put_tweet(tweet_id, created_at, name, screen_name, text)
|
10
|
+
|
11
|
+
tweet = Twitter.status(tweet_id)
|
12
|
+
puts "Conversation:", "" if tweet.in_reply_to_status_id
|
13
|
+
while tweet.in_reply_to_status_id
|
14
|
+
tweet = Twitter.status(tweet.in_reply_to_status_id)
|
15
|
+
Tweetline.put_tweet(tweet.id, tweet.created_at, tweet.user.name, tweet.user.screen_name, tweet.text)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def configure_twitter
|
20
|
+
Twitter.configure do |config|
|
21
|
+
File.open(File.expand_path('~/.tweetlinerc')) do |yaml|
|
22
|
+
options = YAML.load(yaml)
|
23
|
+
config.consumer_key = options[:consumer_key]
|
24
|
+
config.consumer_secret = options[:consumer_secret]
|
25
|
+
config.oauth_token = options[:oauth_token]
|
26
|
+
config.oauth_token_secret = options[:oauth_token_secret]
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def configure_pipes
|
32
|
+
STDOUT.sync = true
|
33
|
+
end
|
34
|
+
|
35
|
+
def each_tweet(options={:count => 10})
|
36
|
+
if STDIN.fcntl(Fcntl::F_GETFL, 0) == 0
|
37
|
+
STDIN.each do |line|
|
38
|
+
yield JSON.load(line)
|
39
|
+
end
|
40
|
+
else
|
41
|
+
if options[:screen_name]
|
42
|
+
screen_name = options.delete(:screen_name)
|
43
|
+
timeline = Twitter.user_timeline(screen_name, options)
|
44
|
+
else
|
45
|
+
timeline = Twitter.home_timeline(options)
|
46
|
+
end
|
47
|
+
timeline.each do |tweet|
|
48
|
+
yield({"id" => tweet.id, "created_at" => tweet.created_at, "name" => tweet.user.name, "screen_name" => tweet.user.screen_name, "text" => tweet.text})
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def is_piped_to_tweetline?
|
54
|
+
@is_piped_to_tweetline |= `ps -ax -o pid,args | grep -E "^[ ]*#{Process.pid+1}"` =~ /\/tl[^\/]*$/
|
55
|
+
end
|
56
|
+
|
57
|
+
def put_tweet(tweet_id, created_at, name, screen_name, text)
|
58
|
+
if STDOUT.fcntl(Fcntl::F_GETFL, 0) == 1 and Tweetline.is_piped_to_tweetline?
|
59
|
+
puts({"id" => tweet_id, "created_at" => created_at, "name" => name, "screen_name" => screen_name, "text" => text}.to_json)
|
60
|
+
else
|
61
|
+
puts "#{name} (@#{screen_name}) [#{time_stamp(created_at)}]", " #{text} (#{tweet_id})", ""
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def say_tweet(tweet_id, created_at, name, screen_name, text)
|
66
|
+
tweet_text = text.strip.gsub(/http:.*?( |$)/, '').gsub(/^RT/, '').gsub(/@/, '').split(/ /).map{|s| s.gsub(/[^A-Za-z0-9.!?,']/, '')}.join(' ')
|
67
|
+
connector = text.strip =~ /^RT/ ? " retweets " : "says"
|
68
|
+
# puts name, " #{connector} #{tweet_text}", ""
|
69
|
+
Tweetline.put_tweet(tweet_id, created_at, name, screen_name, text)
|
70
|
+
`say #{name} #{connector} "#{tweet_text}"`
|
71
|
+
end
|
72
|
+
|
73
|
+
def time_stamp(time)
|
74
|
+
time = Time.parse(time)
|
75
|
+
format = '%I:%M %p'
|
76
|
+
format = '%m/%d/%y ' + format unless time.yday == Time.now.yday
|
77
|
+
|
78
|
+
return time.strftime(format)
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
82
|
+
end
|
data/tweetline.gemspec
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.platform = Gem::Platform::RUBY
|
3
|
+
s.name = "tweetline"
|
4
|
+
s.version = "0.0.4"
|
5
|
+
s.summary = "Command line client for Twitter."
|
6
|
+
s.description = "Tweetline is a command line Twitter client for those who can't imagine a better interface to anything than the command line. Also, some folks may find it useful for automating Twitter interactions."
|
7
|
+
|
8
|
+
s.required_ruby_version = ">= 1.8.7"
|
9
|
+
s.required_rubygems_version = ">= 1.3.6"
|
10
|
+
|
11
|
+
s.author = "Anthony Crumley"
|
12
|
+
s.email = "anthony.crumley@gmail.com"
|
13
|
+
s.homepage = "https://github.com/craftycode/tweetline"
|
14
|
+
s.rubyforge_project = "tweetline"
|
15
|
+
|
16
|
+
s.files = `git ls-files`.split("\n")
|
17
|
+
s.test_files = `git ls-files -- {test}/*`.split("\n")
|
18
|
+
|
19
|
+
s.bindir = "bin"
|
20
|
+
s.executables = ["tl"]
|
21
|
+
s.default_executable = "tl"
|
22
|
+
s.require_paths = ['lib']
|
23
|
+
|
24
|
+
s.add_dependency('twitter', '~> 1.2.0')
|
25
|
+
s.add_dependency('json', '~> 1.5.1')
|
26
|
+
s.add_dependency('thor', '~> 0.14.6')
|
27
|
+
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tweetline
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 23
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 0
|
9
|
-
-
|
10
|
-
version: 0.0.
|
9
|
+
- 4
|
10
|
+
version: 0.0.4
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Anthony Crumley
|
@@ -75,7 +75,13 @@ extensions: []
|
|
75
75
|
extra_rdoc_files: []
|
76
76
|
|
77
77
|
files:
|
78
|
+
- .gitignore
|
79
|
+
- MIT-LICENSE
|
80
|
+
- README.rdoc
|
78
81
|
- bin/tl
|
82
|
+
- lib/tweetline.rb
|
83
|
+
- lib/tweetline/cli.rb
|
84
|
+
- tweetline.gemspec
|
79
85
|
has_rdoc: true
|
80
86
|
homepage: https://github.com/craftycode/tweetline
|
81
87
|
licenses: []
|