Skip to content

Instantly share code, notes, and snippets.

@thypon
Last active January 31, 2023 15:00
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save thypon/1add28161eaa27743bead57076ea718d to your computer and use it in GitHub Desktop.
Save thypon/1add28161eaa27743bead57076ea718d to your computer and use it in GitHub Desktop.
require 'httparty'
require 'date'
require 'pry'
# In order to use:
#
# 1. Create a token with
# scopes read:accounts read:favourites read:statuses write:favourites write:statuses
# in https://mastodon.social/settings/applications, copy "Your access token"
# 2. Find your user ID by inspecting the /search queries through an intercepting proxy
# 3. Add this script to a cronjob with the following arguments
# ruby cleanup_mastodon.rb ${MASTODON_URL} ${YOUR_USER_ID} ${YOUR_ACCESS_TOKEN}
# E.G. ruby amnesic_mastodon.rb https://mastodon.social 1 ...
USER_ID = ARGV[1]
HEADERS = {"Authorization" => "Bearer #{ARGV[2]} "}
QUERY = {}
OPTIONS = {headers: HEADERS, query: QUERY}
MAX_REBLOG = 2
class Fixnum
def days
self
end
def ago
DateTime.now - self
end
end
X_DAYS = 1.days
def rate_limit_wait(minutes, limit)
s = minutes.to_f*60/limit
puts "Rate limiting request: sleeping #{minutes.to_f*60/limit} seconds"
sleep s
end
class Mastodon
include HTTParty
base_uri "#{ARGV[0]}/api/v1"
def self.statuses
self.get_batched("/accounts/#{USER_ID}/statuses").select { |s| s['visibility'] == 'public' }.each { |s| s['created_at'] = DateTime.parse s['created_at'] }
end
def self.nonpublic
self.get_batched("/accounts/#{USER_ID}/statuses").select { |s| s['visibility'] != 'public' }.each { |s| s['created_at'] = DateTime.parse s['created_at'] }
end
def self.toots
self.statuses.select { |s| !s['reblog'] && s['account']['id'] == USER_ID }
end
def self.toots_replies
self.toots.select { |s| s['in_reply_to_id'] || s['in_reply_to_account_id'] }
end
def self.toots_original_posts
self.toots.select { |s| !s['in_reply_to_id'] && !s['in_reply_to_account_id'] }
end
def self.reblogged
self.statuses.select { |s| s['reblog'] }
end
def self.delete_status(status)
puts "Deleting #{status['id']}"
self.delete("/statuses/#{status['id']}", OPTIONS)
end
def self.favourites
self.get_batched("/favourites").each { |s| s['created_at'] = DateTime.parse s['created_at'] }
end
def self.unfavourite(status)
puts "Deleting #{status['id']}"
self.post("/statuses/#{status['id']}/unfavourite", OPTIONS)
end
def self.next_url(response)
response.header['Link'].split(';')[0][1..-2] if response.header['Link'].include? 'rel="next"'
rescue
nil
end
def self.get_batched(url)
result = []
new_values = self.get(url, OPTIONS)
next_url = self.next_url(new_values.response)
result.push *new_values
while next_url
new_values = self.get(next_url, OPTIONS)
next_url = self.next_url(new_values.response)
result.push *new_values
end
result
end
end
# binding.pry
# exit
older_than_x_days_reblogged = Mastodon.reblogged.select { |e| !e['pinned'] && !e['bookmarked'] }.select { |s| s['created_at'] < X_DAYS.ago }
puts "Deleting #{older_than_x_days_reblogged.length} reblogs" if older_than_x_days_reblogged.length > 0
older_than_x_days_reblogged.each do |status|
Mastodon.delete_status(status)
rate_limit_wait(30, 30) # Avoid the rate limiter
end
newer_than_x_days_reblogged = Mastodon.reblogged.select { |e| !e['pinned'] && !e['bookmarked'] }.select { |s| s['created_at'] > X_DAYS.ago }.sort_by { |e| -(e['reblog']['replies_count'] + e['reblog']['favourites_count'] + e['reblog']['reblogs_count']) }
newer_than_x_days_reblogged_to_be_removed = newer_than_x_days_reblogged.length - MAX_REBLOG
newer_than_x_days_reblogged_to_be_removed = 0 if newer_than_x_days_reblogged_to_be_removed < 0
newer_than_x_days_reblogged_selection = newer_than_x_days_reblogged.first(newer_than_x_days_reblogged_to_be_removed)
# binding.pry
puts "Deleting #{newer_than_x_days_reblogged_selection.length} reblogs, the already most reblogged" if newer_than_x_days_reblogged_selection.length > 0
newer_than_x_days_reblogged_selection.each do |status|
Mastodon.delete_status(status)
rate_limit_wait(30, 30) # Avoid the rate limiter
end
older_than_x_days_favourites = Mastodon.favourites.select { |s| s['created_at'] < X_DAYS.ago }
puts "Deleting #{older_than_x_days_favourites.length} favourites" if older_than_x_days_favourites.length > 0
older_than_x_days_favourites.each do |status|
Mastodon.unfavourite(status)
rate_limit_wait(5, 300) # Avoid the rate limiter
end
old_and_uninteresting_toots = Mastodon.toots_original_posts.select { |e| !e['pinned'] && !e['bookmarked'] }.select { |e| e['replies_count'] + e['favourites_count'] + e['reblogs_count'] < 5 }.select { |s| s['created_at'] < 7.days.ago }
puts "Deleting #{old_and_uninteresting_toots.length} uninteresting toots" if old_and_uninteresting_toots.length > 0
old_and_uninteresting_toots.each do |status|
Mastodon.delete_status(status)
rate_limit_wait(30, 30) # Avoid the rate limiter
end
old_and_uninteresting_replies = Mastodon.toots_replies.select { |e| !e['pinned'] && !e['bookmarked'] }.select { |e| e['replies_count'] + e['favourites_count'] + e['reblogs_count'] < 2 }.select { |s| s['created_at'] < X_DAYS.ago }
puts "Deleting #{old_and_uninteresting_replies.length} uninteresting replies" if old_and_uninteresting_replies.length > 0
old_and_uninteresting_replies.each do |status|
Mastodon.delete_status(status)
rate_limit_wait(30, 30) # Avoid the rate limiter
end
nonpublic_statuses = Mastodon.nonpublic.select { |e| !e['pinned'] && !e['bookmarked'] }.select { |s| s['created_at'] < 7.days.ago }
puts "Deleting #{nonpublic_statuses.length} nonpublic statuses" if nonpublic_statuses.length > 0
nonpublic_statuses.each do |status|
Mastodon.delete_status(status)
rate_limit_wait(30, 30) # Avoid the rate limiter
end
older_than_x_days_statuses = Mastodon.statuses.select { |e| !e['pinned'] && !e['bookmarked'] }.select { |s| s['created_at'] < 31.days.ago } # Remove older than
puts "Deleting #{older_than_x_days_statuses.length} statuses, very old, not pinned or bookmarked, and not representing who I am" if older_than_x_days_statuses.length > 0
older_than_x_days_statuses.each do |status|
Mastodon.delete_status(status)
rate_limit_wait(30, 30) # Avoid the rate limiter
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment