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.
@@ -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.
@@ -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
@@ -0,0 +1,5 @@
1
+ ---
2
+ :patch: 0
3
+ :major: 0
4
+ :minor: 1
5
+ :build:
@@ -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)
@@ -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
@@ -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
+