twitter-lists-cli 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +33 -0
- data/Rakefile +26 -0
- data/VERSION.yml +5 -0
- data/bin/twitter-auth +32 -0
- data/bin/twitter-follow +83 -0
- data/bin/twitter-following +62 -0
- data/bin/twitter-lists +84 -0
- metadata +93 -0
data/README.md
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
twitter-lists-cli
|
2
|
+
=================
|
3
|
+
A command-line client for manipulating large Twitter lists in the shell, shell scripts, etc.
|
4
|
+
|
5
|
+
Currently supports
|
6
|
+
------------------
|
7
|
+
- OAuth authentication
|
8
|
+
- Showing a users's followers/following
|
9
|
+
- Following and unfollowing users
|
10
|
+
- Showing, adding, and removing a members from a list
|
11
|
+
|
12
|
+
License
|
13
|
+
-------
|
14
|
+
Copyright (c) 2010 Dwayne Litzenberger
|
15
|
+
|
16
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
17
|
+
a copy of this software and associated documentation files (the
|
18
|
+
"Software"), to deal in the Software without restriction, including
|
19
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
20
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
21
|
+
permit persons to whom the Software is furnished to do so, subject to
|
22
|
+
the following conditions:
|
23
|
+
|
24
|
+
The above copyright notice and this permission notice shall be
|
25
|
+
included in all copies or substantial portions of the Software.
|
26
|
+
|
27
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
28
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
29
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
30
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
31
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
32
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
33
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
begin
|
2
|
+
require 'jeweler'
|
3
|
+
Jeweler::Tasks.new do |s|
|
4
|
+
s.name = "twitter-lists-cli"
|
5
|
+
s.executables = ["twitter-auth", "twitter-follow", "twitter-following", "twitter-lists"]
|
6
|
+
s.summary = "Command-line client for manipulating Twitter lists."
|
7
|
+
s.email = "dlitz@dlitz.net"
|
8
|
+
s.homepage = "http://github.com/dlitz/twitter-lists-cli"
|
9
|
+
s.description = <<EOF
|
10
|
+
A command-line client for manipulating large Twitter lists in the shell, shell scripts, etc.
|
11
|
+
|
12
|
+
Currently supports
|
13
|
+
------------------
|
14
|
+
- OAuth authentication
|
15
|
+
- Showing a users's followers/following
|
16
|
+
- Following and unfollowing users
|
17
|
+
- Showing, adding, and removing a members from a list
|
18
|
+
EOF
|
19
|
+
s.authors = ["Dwayne Litzenberger"]
|
20
|
+
s.files = FileList["[A-Z]*", "bin/**/*"]
|
21
|
+
s.add_dependency "twitter", "~> 0.9.5" # John Nunemaker's twitter gem
|
22
|
+
end
|
23
|
+
Jeweler::GemcutterTasks.new
|
24
|
+
rescue LoadError
|
25
|
+
puts "Jeweler, or one of its dependencies, is not available. Install it with: gem install jeweler"
|
26
|
+
end
|
data/VERSION.yml
ADDED
data/bin/twitter-auth
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'optparse'
|
3
|
+
require 'twitter'
|
4
|
+
|
5
|
+
# Parse arguments
|
6
|
+
options = {:only => false, :unfollow=>false}
|
7
|
+
OptionParser.new do |opts|
|
8
|
+
opts.banner = "#{opts.program_name}"
|
9
|
+
opts.separator "Get OAuth credentials"
|
10
|
+
opts.separator ""
|
11
|
+
opts.separator "Global Options:"
|
12
|
+
opts.on("--auth FILE", "Read authentication data from the specified FILE") do |optarg|
|
13
|
+
options[:auth_file] = optarg
|
14
|
+
end
|
15
|
+
opts.separator ""
|
16
|
+
end.parse!
|
17
|
+
options[:auth_file] ||= ENV["TWITTER_AUTHFILE"]
|
18
|
+
options[:auth_file] ||= File.expand_path("~/.twitter")
|
19
|
+
raise "No --auth file specified" unless options[:auth_file] # XXX TODO - output usage information
|
20
|
+
raise "Too many arguments" unless ARGV.empty?
|
21
|
+
|
22
|
+
auth = YAML.load_file(options[:auth_file])
|
23
|
+
oauth = Twitter::OAuth.new(auth["token"], auth["secret"])
|
24
|
+
rt = oauth.request_token
|
25
|
+
puts "Go to https://#{rt.authorize_url}"
|
26
|
+
print "Enter the PIN here: "
|
27
|
+
$stdout.flush
|
28
|
+
pin = $stdin.readline.strip
|
29
|
+
|
30
|
+
atoken, asecret = oauth.authorize_from_request(rt.token, rt.secret, pin)
|
31
|
+
|
32
|
+
puts({"atoken" => atoken, "asecret" => asecret}.to_yaml)
|
data/bin/twitter-follow
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'optparse'
|
3
|
+
require 'twitter'
|
4
|
+
|
5
|
+
# Parse arguments
|
6
|
+
options = {:only => false, :unfollow=>false}
|
7
|
+
OptionParser.new do |opts|
|
8
|
+
opts.banner = "#{opts.program_name} [-l LISTNAME] [--only | -d] [USER...]"
|
9
|
+
opts.separator "Follow or unfollow users"
|
10
|
+
opts.separator ""
|
11
|
+
opts.on("-l", "--list LISTNAME", "act on the specified LISTNAME instead of the logged-in user") do |optarg|
|
12
|
+
options[:list] = optarg
|
13
|
+
end
|
14
|
+
opts.on("-d", "--unfollow", "unfollow the specified users") do |optarg|
|
15
|
+
options[:unfollow] = optarg
|
16
|
+
end
|
17
|
+
opts.separator ""
|
18
|
+
opts.separator "If no USERs are specified on the command line, they will be read from stdin."
|
19
|
+
opts.separator ""
|
20
|
+
opts.separator "Global Options:"
|
21
|
+
opts.on("--auth FILE", "Read authentication data from the specified FILE") do |optarg|
|
22
|
+
options[:auth_file] = optarg
|
23
|
+
end
|
24
|
+
opts.separator ""
|
25
|
+
end.parse!
|
26
|
+
options[:auth_file] ||= ENV["TWITTER_AUTHFILE"]
|
27
|
+
options[:auth_file] ||= File.expand_path("~/.twitter")
|
28
|
+
raise "No --auth file specified" unless options[:auth_file] # XXX TODO - output usage information
|
29
|
+
raise "--unfollow and --only are mutually exclusive" if options[:unfollow] and options[:only]
|
30
|
+
raise "--only not implemented yet" if options[:only]
|
31
|
+
if ARGV.empty?
|
32
|
+
users = []
|
33
|
+
begin
|
34
|
+
loop do
|
35
|
+
users << STDIN.readline.strip
|
36
|
+
end
|
37
|
+
rescue EOFError
|
38
|
+
end
|
39
|
+
users = users.select{|u| u =~ /[^\s]/} # skip blank lines
|
40
|
+
options[:users] = users
|
41
|
+
else
|
42
|
+
options[:users] = ARGV
|
43
|
+
end
|
44
|
+
|
45
|
+
auth = YAML.load_file(options[:auth_file])
|
46
|
+
oauth = Twitter::OAuth.new(auth["token"], auth["secret"])
|
47
|
+
oauth.authorize_from_access(auth["atoken"], auth["asecret"])
|
48
|
+
base = Twitter::Base.new(oauth)
|
49
|
+
|
50
|
+
# Knowing our own screen name is required when fetching list members
|
51
|
+
if options[:list]
|
52
|
+
options[:user] ||= auth["user"]
|
53
|
+
options[:user] ||= base.verify_credentials.screen_name
|
54
|
+
end
|
55
|
+
|
56
|
+
options[:users].each do |user|
|
57
|
+
if options[:list]
|
58
|
+
if options[:unfollow]
|
59
|
+
begin
|
60
|
+
base.list_remove_member(options[:user], options[:list], user)
|
61
|
+
rescue Twitter::TwitterError => e
|
62
|
+
# Don't raise exception if the user is already removed
|
63
|
+
raise unless e.data['error'] == "The user you are trying to remove from the list is not a member"
|
64
|
+
end
|
65
|
+
else
|
66
|
+
base.list_add_member(options[:user], options[:list], user)
|
67
|
+
end
|
68
|
+
else
|
69
|
+
if options[:unfollow]
|
70
|
+
begin
|
71
|
+
base.friendship_destroy(user)
|
72
|
+
rescue Twitter::TwitterError => e
|
73
|
+
raise unless e.data["error"] == "You are not friends with the specified user."
|
74
|
+
end
|
75
|
+
else
|
76
|
+
begin
|
77
|
+
base.friendship_create(user, true)
|
78
|
+
rescue Twitter::TwitterError => e
|
79
|
+
raise unless e.data["error"] =~ /\ACould not follow user: (.* is already on your list\.|You've already requested to follow .*)\Z/
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'optparse'
|
3
|
+
require 'twitter'
|
4
|
+
|
5
|
+
# Parse arguments
|
6
|
+
options = {}
|
7
|
+
OptionParser.new do |opts|
|
8
|
+
opts.banner = "#{opts.program_name} [-r] [-u USER] [LISTNAME]"
|
9
|
+
opts.separator "Show who is being followed by a user or a list"
|
10
|
+
opts.separator ""
|
11
|
+
opts.on("-u", "--user USER", "specify a username (default is the logged-in user)") do |optarg|
|
12
|
+
options[:user] = optarg
|
13
|
+
end
|
14
|
+
opts.on("-r", "--reverse", "show followers instead of who is following") do |optarg|
|
15
|
+
options[:reverse] = optarg
|
16
|
+
end
|
17
|
+
opts.separator ""
|
18
|
+
opts.separator "Global options:"
|
19
|
+
opts.on("--auth FILE", "Read authentication data from the specified FILE") do |optarg|
|
20
|
+
options[:auth_file] = optarg
|
21
|
+
end
|
22
|
+
opts.separator ""
|
23
|
+
end.parse!
|
24
|
+
options[:auth_file] ||= ENV["TWITTER_AUTHFILE"]
|
25
|
+
options[:auth_file] ||= File.expand_path("~/.twitter")
|
26
|
+
raise "No --auth file specified" unless options[:auth_file] # XXX TODO - output usage information
|
27
|
+
raise "Too many arguments specified" if ARGV.length > 1 # XXX TODO - output usage information
|
28
|
+
options[:list] = ARGV[0]
|
29
|
+
|
30
|
+
auth = YAML.load_file(options[:auth_file])
|
31
|
+
oauth = Twitter::OAuth.new(auth["token"], auth["secret"])
|
32
|
+
oauth.authorize_from_access(auth["atoken"], auth["asecret"])
|
33
|
+
base = Twitter::Base.new(oauth)
|
34
|
+
|
35
|
+
# Knowing our own screen name is required when fetching list members
|
36
|
+
if options[:list]
|
37
|
+
options[:user] ||= auth["user"]
|
38
|
+
options[:user] ||= base.verify_credentials.screen_name
|
39
|
+
end
|
40
|
+
|
41
|
+
cursor = -1
|
42
|
+
begin
|
43
|
+
query = {}
|
44
|
+
if options[:list]
|
45
|
+
if options[:reverse]
|
46
|
+
result = base.list_subscribers(options[:user], options[:list], query.merge(:cursor => cursor))
|
47
|
+
else
|
48
|
+
result = base.list_members(options[:user], options[:list], query.merge(:cursor => cursor))
|
49
|
+
end
|
50
|
+
else
|
51
|
+
query[:screen_name] = options[:user] if options[:user]
|
52
|
+
if options[:reverse]
|
53
|
+
result = base.followers(query.merge(:cursor => cursor))
|
54
|
+
else
|
55
|
+
result = base.friends(query.merge(:cursor => cursor))
|
56
|
+
end
|
57
|
+
end
|
58
|
+
result.users.each do |u|
|
59
|
+
puts u.screen_name
|
60
|
+
end
|
61
|
+
cursor = result.next_cursor
|
62
|
+
end until cursor == 0
|
data/bin/twitter-lists
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'optparse'
|
3
|
+
require 'twitter'
|
4
|
+
|
5
|
+
# Parse arguments
|
6
|
+
options = {:create => false, :delete => false}
|
7
|
+
OptionParser.new do |opts|
|
8
|
+
opts.banner = "#{opts.program_name} [-s] [-u USER] [-c LISTNAME... | -d LISTNAME...]"
|
9
|
+
opts.separator "Show, create, or delete lists"
|
10
|
+
opts.on("-u", "--user USER", "specify a username (default is the logged-in user)") do |optarg|
|
11
|
+
options[:user] = optarg
|
12
|
+
end
|
13
|
+
opts.on("-c", "--create", "create the specified list(s)") do |optarg|
|
14
|
+
options[:create] = true
|
15
|
+
end
|
16
|
+
opts.on("-d", "--delete", "delete the specified list(s)") do |optarg|
|
17
|
+
options[:delete] = true
|
18
|
+
end
|
19
|
+
opts.on("-s", "--slugs", "Use slugs instead of (possibly non-unique) names") do |optarg|
|
20
|
+
options[:slugs] = optarg
|
21
|
+
end
|
22
|
+
opts.separator ""
|
23
|
+
opts.separator "If no LISTNAMEs are specified on the command line, they will be read from stdin."
|
24
|
+
opts.separator ""
|
25
|
+
opts.separator "Global options:"
|
26
|
+
opts.on("--auth FILE", "Read authentication data from the specified FILE") do |optarg|
|
27
|
+
options[:auth_file] = optarg
|
28
|
+
end
|
29
|
+
opts.separator ""
|
30
|
+
end.parse!
|
31
|
+
options[:auth_file] ||= ENV["TWITTER_AUTHFILE"]
|
32
|
+
options[:auth_file] ||= File.expand_path("~/.twitter")
|
33
|
+
raise "No --auth file specified" unless options[:auth_file] # XXX TODO - output usage information
|
34
|
+
raise "--create and --delete are mutually exclusive" if options[:create] and options[:delete]
|
35
|
+
if (options[:create] || options[:delete])
|
36
|
+
if ARGV.empty?
|
37
|
+
lists = []
|
38
|
+
begin
|
39
|
+
loop do
|
40
|
+
lists << STDIN.readline.strip
|
41
|
+
end
|
42
|
+
rescue EOFError
|
43
|
+
end
|
44
|
+
lists = lists.select{|u| u =~ /[^\s]/} # skip blank lines
|
45
|
+
options[:lists] = lists
|
46
|
+
else
|
47
|
+
options[:lists] = ARGV
|
48
|
+
end
|
49
|
+
else
|
50
|
+
raise "No arguments are allowed without --create or --delete" unless ARGV.empty?
|
51
|
+
end
|
52
|
+
|
53
|
+
auth = YAML.load_file(options[:auth_file])
|
54
|
+
oauth = Twitter::OAuth.new(auth["token"], auth["secret"])
|
55
|
+
oauth.authorize_from_access(auth["atoken"], auth["asecret"])
|
56
|
+
base = Twitter::Base.new(oauth)
|
57
|
+
|
58
|
+
# Knowing our own screen name is required
|
59
|
+
options[:user] ||= auth["user"]
|
60
|
+
options[:user] ||= base.verify_credentials.screen_name
|
61
|
+
|
62
|
+
if options[:create]
|
63
|
+
options[:lists].each do |list|
|
64
|
+
base.list_create(options[:user], :name => list)
|
65
|
+
end
|
66
|
+
elsif options[:delete]
|
67
|
+
options[:lists].each do |list|
|
68
|
+
unless options[:slugs]
|
69
|
+
# convert list name to slug
|
70
|
+
list = list.downcase.gsub(/[^a-z0-9]+/, '-').gsub(/\A-+|-+\Z/, '').gsub(/-+/, '-')
|
71
|
+
end
|
72
|
+
base.list_delete(options[:user], list)
|
73
|
+
end
|
74
|
+
else
|
75
|
+
cursor = -1
|
76
|
+
begin
|
77
|
+
query = {}
|
78
|
+
result = base.lists(options[:user], query.merge(:cursor => cursor))
|
79
|
+
result.lists.each do |list|
|
80
|
+
puts options[:slugs] ? list.slug : list.name
|
81
|
+
end
|
82
|
+
cursor = result.next_cursor
|
83
|
+
end until cursor == 0
|
84
|
+
end
|
metadata
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: twitter-lists-cli
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 1
|
8
|
+
- 0
|
9
|
+
version: 0.1.0
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Dwayne Litzenberger
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2010-07-10 00:00:00 -04:00
|
18
|
+
default_executable:
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: twitter
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - ~>
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
segments:
|
28
|
+
- 0
|
29
|
+
- 9
|
30
|
+
- 5
|
31
|
+
version: 0.9.5
|
32
|
+
type: :runtime
|
33
|
+
version_requirements: *id001
|
34
|
+
description: |
|
35
|
+
A command-line client for manipulating large Twitter lists in the shell, shell scripts, etc.
|
36
|
+
|
37
|
+
Currently supports
|
38
|
+
------------------
|
39
|
+
- OAuth authentication
|
40
|
+
- Showing a users's followers/following
|
41
|
+
- Following and unfollowing users
|
42
|
+
- Showing, adding, and removing a members from a list
|
43
|
+
|
44
|
+
email: dlitz@dlitz.net
|
45
|
+
executables:
|
46
|
+
- twitter-auth
|
47
|
+
- twitter-follow
|
48
|
+
- twitter-following
|
49
|
+
- twitter-lists
|
50
|
+
extensions: []
|
51
|
+
|
52
|
+
extra_rdoc_files:
|
53
|
+
- README.md
|
54
|
+
files:
|
55
|
+
- README.md
|
56
|
+
- Rakefile
|
57
|
+
- VERSION.yml
|
58
|
+
- bin/twitter-auth
|
59
|
+
- bin/twitter-follow
|
60
|
+
- bin/twitter-following
|
61
|
+
- bin/twitter-lists
|
62
|
+
has_rdoc: true
|
63
|
+
homepage: http://github.com/dlitz/twitter-lists-cli
|
64
|
+
licenses: []
|
65
|
+
|
66
|
+
post_install_message:
|
67
|
+
rdoc_options:
|
68
|
+
- --charset=UTF-8
|
69
|
+
require_paths:
|
70
|
+
- lib
|
71
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
segments:
|
76
|
+
- 0
|
77
|
+
version: "0"
|
78
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
segments:
|
83
|
+
- 0
|
84
|
+
version: "0"
|
85
|
+
requirements: []
|
86
|
+
|
87
|
+
rubyforge_project:
|
88
|
+
rubygems_version: 1.3.6
|
89
|
+
signing_key:
|
90
|
+
specification_version: 3
|
91
|
+
summary: Command-line client for manipulating Twitter lists.
|
92
|
+
test_files: []
|
93
|
+
|