twitter-lists-cli 0.1.0
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/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
|
+
|