akkoma2gotosocial
change
commit 80e8a1e8a4ebd69d30256fb8a4d4180146258d9e
author Alpha Chen <alpha@kejadlen.dev>
date
parent 964559d0
diff --git a/akkoma2gotosocial/.gitignore b/akkoma2gotosocial/.gitignore
new file mode 100644
index 0000000..d47b4eb
--- /dev/null
+++ b/akkoma2gotosocial/.gitignore
@@ -0,0 +1 @@
+friends.csv
diff --git a/akkoma2gotosocial/akkoma2gotosocial.rb b/akkoma2gotosocial/akkoma2gotosocial.rb
new file mode 100644
index 0000000..e54da90
--- /dev/null
+++ b/akkoma2gotosocial/akkoma2gotosocial.rb
@@ -0,0 +1,123 @@
+require "bundler/inline"
+
+gemfile do
+  source "https://rubygems.org"
+  gem "httpx", require: false
+end
+
+require "logger"
+require "net/http"
+require "json"
+
+require "httpx"
+
+LOGGER = Logger.new($stdout)
+GOTOSOCIAL_TOKEN = ENV.fetch("GOTOSOCIAL_TOKEN")
+PLEROMA_COOKIE = ENV.fetch("PLEROMA_COOKIE")
+PLEROMA_PASSWORD = ENV.fetch("PLEROMA_PASSWORD")
+
+API = Data.define(:subdomain, :http) do
+  def verify_credentials
+    resp = get("https://#{subdomain}.kejadlen.dev/api/v1/accounts/verify_credentials")
+    LOGGER.debug(resp)
+    JSON.parse(resp)
+  end
+
+  def following(id)
+    return enum_for(__method__, id) unless block_given?
+
+    uri = "https://#{subdomain}.kejadlen.dev/api/v1/accounts/#{id}/following?limit=100"
+
+    loop do
+      LOGGER.debug(uri)
+      resp = get(uri)
+      LOGGER.debug(resp)
+
+      link = resp.headers["Link"]
+      return if link.nil?
+
+      uri = link.scan(/<((?~>))>; rel="(next|prev|)"/).to_h(&:reverse).fetch("next")
+      followings = JSON.parse(resp)
+      return if followings.empty?
+
+      followings.each do |following|
+        yield following
+      end
+    end
+  end
+
+  def unfollow(user)
+    resp = post("https://#{subdomain}.kejadlen.dev/api/v1/accounts/#{user.fetch("id")}/unfollow")
+    LOGGER.debug(resp)
+  end
+
+  def search(username)
+    resp = get("https://#{subdomain}.kejadlen.dev/api/v1/search?q=@#{username}&resolve=true&type=accounts")
+    LOGGER.debug(resp)
+    json = JSON.parse(resp)
+    accounts = json.fetch("accounts")
+    if accounts.empty?
+      LOGGER.warn("#{username} not found")
+      return
+    end
+    accounts.fetch(0)
+  end
+
+  def follow(user)
+    resp = post("https://#{subdomain}.kejadlen.dev/api/v1/accounts/#{user.fetch("id")}/follow")
+    LOGGER.debug(resp)
+  end
+
+  def get(*) = http.get(*)
+  def post(*) = http.post(*)
+end
+
+GTS = API.new(
+  subdomain: "hey",
+  http: HTTPX.plugin(:auth).bearer_auth(GOTOSOCIAL_TOKEN),
+)
+AKK = API.new(
+  subdomain: "social",
+  http: HTTPX.plugin(:cookies).with_cookies("__Host-pleroma_key" => PLEROMA_COOKIE),
+)
+
+if __FILE__ == $0
+  gts_id = GTS.verify_credentials.fetch("id")
+  akk_id = AKK.verify_credentials.fetch("id")
+
+  gts_following = GTS.following(gts_id).to_a
+  akk_following = AKK.following(akk_id).to_a
+
+  # unfollow already followed
+  already_followed, to_follow = akk_following.partition {|akk|
+    gts_following.any? {|gts| gts.fetch("acct") == akk.fetch("acct") }
+  }
+  already_followed.each do |user|
+    AKK.unfollow(user)
+  end
+
+  # follow not already followed
+  ignore = File.read("friends.csv").scan(/# (.*)/).map { _1[0] }
+  to_follow = to_follow.map { _1.fetch("acct") }.reject { ignore.include?(_1) }
+  LOGGER.debug("To follow: #{to_follow}")
+
+  to_follow.sample(5).each do |username|
+    LOGGER.info("Following: #{username}")
+    user = GTS.search(username)
+    if user
+      GTS.unfollow(user)
+      GTS.follow(user)
+    else
+      LOGGER.warn("Couldn't find: #{username}")
+    end
+  end
+
+  # move account
+  # resp = AKK.http.post(
+  #   "https://#{AKK.subdomain}.kejadlen.dev/api/pleroma/move_account",
+  #   json: {
+  #     password: PLEROMA_PASSWORD,
+  #     target_account: "alpha@hey.kejadlen.dev",
+  #   },
+  # )
+end