87 lines
2.4 KiB
Ruby
Executable File
87 lines
2.4 KiB
Ruby
Executable File
#!/usr/bin/env ruby
|
|
|
|
ENV["RAILS_ENV"] ||= "production"
|
|
|
|
APP_PATH = File.expand_path("../../config/application", __FILE__)
|
|
require File.expand_path("../../config/boot", __FILE__)
|
|
require APP_PATH
|
|
Rails.application.require_environment!
|
|
|
|
TWITTER_LIST = "users".freeze
|
|
|
|
# find the id of our list name
|
|
res = Twitter.oauth_request("/1.1/lists/list.json", :get)
|
|
our_list = res.find { |l| l["name"] == TWITTER_LIST }
|
|
if our_list.blank?
|
|
raise "can't find list #{TWITTER_LIST.inspect} in #{res.inspect}"
|
|
end
|
|
list_id = our_list["id_str"]
|
|
|
|
# fetch its member list
|
|
res = Twitter.oauth_request("/1.1/lists/members.json?list_id=#{list_id}" \
|
|
"&count=5000&skip_status=true", :get)
|
|
their_users = res["users"].map { |u| [u["screen_name"].downcase, true] }.to_h
|
|
|
|
if their_users.empty?
|
|
raise "Intemittent Twitter bug: they said the list is empty when it's not"
|
|
end
|
|
if their_users.count >= 5000
|
|
warn "need to implement paging for list members"
|
|
end
|
|
|
|
# fetch our active users that have a linked twitter account
|
|
our_users = User.active.where("settings LIKE '%twitter_username:%'")
|
|
.select { |u| u.twitter_username.present? }
|
|
.map { |u| [u.twitter_username.downcase, true] }.to_h
|
|
|
|
# ignore users that have previously been determined to have protected accounts,
|
|
# which cannot be added to a public list
|
|
Keystore.where("`key` LIKE 'user:%:twitter_private'").find_each do |ks|
|
|
our_users.reject! do |k, _v|
|
|
k.downcase == ks.key.scan(/:(.+):/).first.first.downcase
|
|
end
|
|
end
|
|
|
|
# diff
|
|
to_add = our_users.keys.reject { |u| their_users[u] }
|
|
to_del = their_users.keys.reject { |u| our_users[u] }
|
|
|
|
to_add.each_slice(100) do |g|
|
|
# lookup and remove any protected users
|
|
Twitter.oauth_request("/1.1/users/lookup.json?screen_name=#{g.join(",")}")
|
|
.select { |u| u["protected"] }.each do |u|
|
|
# puts "user #{u["screen_name"]} protected, ignoring"
|
|
Keystore.put("user:#{u["screen_name"]}:twitter_private", 1)
|
|
|
|
g.reject! { |tu| tu.downcase == u["screen_name"].downcase }
|
|
end
|
|
|
|
if !g.any?
|
|
next
|
|
end
|
|
|
|
# puts "adding: #{g.inspect}"
|
|
|
|
begin
|
|
Twitter.oauth_request(
|
|
"/1.1/lists/members/create_all.json",
|
|
:post,
|
|
"list_id" => list_id,
|
|
"screen_name" => g.join(",")
|
|
)
|
|
rescue Net::OpenTimeout # Twitter's having a nap
|
|
exit
|
|
end
|
|
end
|
|
|
|
to_del.each_slice(100) do |g|
|
|
# puts "deleting: #{g.inspect}"
|
|
|
|
Twitter.oauth_request(
|
|
"/1.1/lists/members/destroy_all.json",
|
|
:post,
|
|
"list_id" => list_id,
|
|
"screen_name" => g.join(",")
|
|
)
|
|
end
|