/mastodon-utils

Utilities for working with Mastodon's API

Primary LanguageClojureOtherNOASSERTION

Mastodon Utils

Miscallaneous scripts for working with Mastodon.

Setup

Everything we do via the API needs the URL for the instance, the auth token, etc. We store this in a "Mastodon map", which you build once, then re-use.

(require '[com.aphyr.mastodon-utils :as m] :reload)
; Register an app
(def m (m/register-app! {:url "https://your.instance"}))

; Get the URL to get a code to authorize the app. Visit this in your browser
; and copy the code...
(m/auth-code-url m)

; Get auth token
(def m (m/access-token! m "ABC..."))

; And save to ~/.mastodon-utils.edn, so you can use it later
(m/save! m)

; Load it on future runs with
(def m (m/load))

Examples

; Fetch a local account (accounts is a lazy seq with automatic pagination)
(first (m/accounts m {:origin "local"}))

; Find all local accounts
(def locals (vec (m/accounts m {:origin "local", :limit 200})))

; And for each of those, find their followers on 4bear
(def bear->woof
  (->> locals
       (mapcat (fn [{:keys [username] :as local}]
         (prn :local username)
         (->> (m/followers m local {:limit 80})
              (keep (fn [{:keys [acct] :as follower}]
                      (when (re-find #"@4bear.com$" acct)
                        [acct (str username "@woof.group")]))))))
       vec))

; Vice-versa, locals who follow people on 4bear
(def woof->bear
  (->> locals
       (mapcat (fn [{:keys [username] :as local}]
         (prn :local username)
         (->> (m/following m local {:limit 80})
              (keep (fn [{:keys [acct] :as following}]
                      (when (re-find #"@4bear.com$" acct)
                        [(str username "@woof.group") acct]))))))
       vec))

; Spit those to JSON files
(require '[cheshire.core :as json])
(spit "bear->woof.json" (json/generate-string bear->woof))
(spit "woof->bear.json" (json/generate-string woof->bear))

Iterating over [follower, following] pairs and re-following each. Run this at the rails console (RAILS_ENV=production bin/rails console):

fs = FollowService.new
ufs = UnfollowService.new
rels = JSON.parse(File.read("/home/mastodon/woof->bear.json"))
rels.each do |rel|
  follower, following = rel
  follower_username, _ = follower.split('@')
  following_username, following_domain = following.split('@')
  follower_account = Account.find_by(username: follower_username, domain: nil)
  following_account = Account.find_by(username: following_username, domain: following_domain)

  if follower_account and following_account
    sleep 5 # Not sure how much we should sleep here
    puts "#{follower} -> #{following}"
    ufs.call(follower_account, following_account)
    fs.call(follower_account, following_account)
  else
    if follower_account
      puts "Couldn't find following #{following_username}@#{following_domain}"
    else
      puts "Couldn't find follower #{follower_username}"
    end
  end
end

Copyright (c) 2023 Kyle Kingsbury