Last active
January 31, 2023 15:00
-
-
Save thypon/1add28161eaa27743bead57076ea718d to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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