Twitterのfollowingとfollowersを0にするスクリプト

#!/usr/bin/env ruby

require "pathname"
require "yaml"
require "rubygems"
require "oauth"
require "json"

# -> [access_token, access_secret]
def authorize(consumer)
	request_token = consumer.get_request_token

	puts "Access following URL: %s" % request_token.authorize_url
	print 'and input OAuth verifier: '
	oauth_verifier = STDIN.gets.chomp.strip

	access_token = request_token.get_access_token(:oauth_verifier => oauth_verifier)
	[access_token.token, access_token.secret]
end

def save_access_token!(token, secret)
	atoken = Pathname.new('~/.friendship_cleaner/atoken').expand_path
	atoken.parent.mkdir(0700) unless atoken.parent.exist?
	YAML.dump({
		:token => token,
		:secret => secret
	}, atoken.open('w+', 0600))
end

# -> [access_token, access_secret]
def get_access_token
	atoken_file = Pathname.new('~/.friendship_cleaner/atoken').expand_path
	access_token = YAML.load(atoken_file.open)
	[access_token[:token], access_token[:secret]]
end

def main(args)
	abort "Usage: #{$0} [user_id]" unless args.size > 0
	config = YAML.load(DATA)
	consumer = OAuth::Consumer.new(
		config[:ckey], config[:csecret], :site => 'https://api.twitter.com'
	)
	token, secret = *get_access_token
	access_token = OAuth::AccessToken.new(consumer, token, secret)

	ers = followers(access_token, :self => self_id)
	ing = following(access_token, :self => self_id)

	ers.reject {|i|
		!i.has_key?('users') || i['next_cursor'].zero?
	}.map {|i|
		i['users']['screen_name']
	}

	ing.reject {|i|
		!i.has_key?('users') || i['next_cursor'].zero?
	}.map {|i|
		i['users']['screen_name']
	}

	ers.each do |user|
		block(access_token, user)
		unblock(access_token, user)
	end

	(ing - ers).each do |user|
		remove(access_token, user)
	end
rescue Errno::ENOENT
	_atoken = authorize(consumer)
	save_access_token!(*_atoken)
	retry
end

def block(access_token, user)
	access_token.post("/blocks/create.json", :screen_name => user)
end

def unblock(access_token, user)
	access_token.post("/blocks/destroy.json", :screen_name => user)
end

def remove(access_token, user)
	access_token.post("/friendships/destroy.json", :screen_name => user)
end

def following(access_token, opts={})
	cursor = opts.fetch(:cursor, -1)
	response = access_token.get("/statuses/friends/#{opts[:self]}.json?lite=true&cursor=#{cursor}")
	body = JSON.parse(response.body)
	ret = [body]
	ret << following(access_token, :cursor => body['next_cursor']) if body.has_key?('next_cursor')
	ret.flatten
end

def followers(access_token, opts={})
	cursor = opts.fetch(:cursor, -1)
	response = access_token.get("/statuses/followers/#{opts[:self]}.json?lite=true&cursor=#{cursor}")
	body = JSON.parse(response.body)
	ret = [body]
	ret << followers(access_token, :cursor => body['next_cursor']) if body.has_key?('next_cursor')
	ret.flatten
end

main(ARGV.dup) if $0 == __FILE__

__END__
---
:ckey:    hoge
:csecret: fuga

定期的にやってくる人間関係を精算したくなる病気が発症したので対処療法としてfollowingとfollowersを0にする。そのためのスクリプトを書いた。

consumer keyとconsumer secretは各々で取得しましょう。

OAuthの実装をほとんど oauth に任せてしまっているので、実際に OAuth 認証でなにをすればいいのかよくわかっていない。その内、しらべてみる。かもしれない。

あと、あまり深く考えずに書いたので、膨大な数のfollowingやfollowersだとメモリをばくばく食うとおもいます。ご利用は計画的に。