tweetline 0.0.3 → 0.0.4
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/.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: []
|