parent
4f6550f269
commit
898ce41fb7
27
README.md
27
README.md
|
@ -7,7 +7,7 @@ The initial `ephemetoot` script was based on [this tweet-deleting script](https:
|
|||
|
||||
# Usage
|
||||
|
||||
You can use `ephemetoot` to delete [Mastodon](https://github.com/tootsuite/mastodon) toots that are older than a certain number of days. Toots can optionally be saved from deletion if:
|
||||
You can use `ephemetoot` to delete [Mastodon](https://github.com/tootsuite/mastodon) toots that are older than a certain number of days (default is 365). Toots can optionally be saved from deletion if:
|
||||
* they are pinned;
|
||||
* they include certain hashtags;
|
||||
* they have certain visibility; or
|
||||
|
@ -78,15 +78,24 @@ You can now enter the configuration details for each user:
|
|||
|
||||
| setting | description |
|
||||
| ---: | :--- |
|
||||
| access_token | The alphanumeric access token string from the app you created in Mastodon |
|
||||
| username | Your username without the '@' or server domain. e.g. `hugh`|
|
||||
| base_url | The base url of your Mastodon server, without the 'https://'. e.g. `ausglam.space`|
|
||||
| days_to_keep | Number of days to keep toots e.g. `30`|
|
||||
| keep_pinned | Either `True` or `False` - if `True`, any pinned toots will be kept regardless of age |
|
||||
| access_token | **required** - The alphanumeric access token string from the app you created in Mastodon |
|
||||
| username | **required** - Your username without the '@' or server domain. e.g. `hugh`|
|
||||
| base_url | **required** - The base url of your Mastodon server, without the 'https://'. e.g. `ausglam.space`|
|
||||
| days_to_keep | Number of days to keep toots e.g. `30`. If not value is provided the default number is 365 |
|
||||
| keep_pinned | Either `true` or `false` - if `true`, any pinned toots will be kept regardless of age |
|
||||
| toots_to_keep | A list of toot ids indicating toots to be kept regardless of other settings. The ID of a toot is the last part of its individual URL. e.g. for [https://ausglam.space/@hugh/101294246770105799](https://ausglam.space/@hugh/101294246770105799) the id is `101294246770105799` |
|
||||
| hashtags_to_keep | A Set of hashtags, where any toots with any of these hashtags will be kept regardless of age. Do not include the '#' symbol. Do remember the [rules for hashtags](https://docs.joinmastodon.org/user/posting/#hashtags) |
|
||||
| hashtags_to_keep | A list of hashtags, where any toots with any of these hashtags will be kept regardless of age. Do not include the '#' symbol. Do remember the [rules for hashtags](https://docs.joinmastodon.org/user/posting/#hashtags) |
|
||||
| visibility_to_keep | Toots with any of the visibility settings in this list will be kept regardless of age. Options are: `public`, `unlisted`, `private`, `direct`. |
|
||||
|
||||
All values other than `access_token`, `username` and `base_url` are optional, however if you include `toots_to_keep`, `hashtags_to_keep`, or `visibility_to_keep` you must make each a list, even if it is empty:
|
||||
|
||||
```yaml
|
||||
toots_to_keep: # this is not a list, it will throw an error
|
||||
hashtags_to_keep:
|
||||
- # this empty list is ok
|
||||
visibility_to_keep: [ ] # this empty list is also ok
|
||||
```
|
||||
|
||||
If you want to use `ephemetoot` for multiple accounts, separate the config for each user with a single dash (`-`), as shown in the example file.
|
||||
|
||||
# Running the script
|
||||
|
@ -188,9 +197,11 @@ git checkout [tagname]
|
|||
pip3 install .
|
||||
```
|
||||
|
||||
Alternatively download and unzip the zip file into your `ephemetoot` directory over the top of your existing installation, and then run `pip3 install .`.
|
||||
|
||||
# Uninstalling
|
||||
|
||||
Uninstall using pip;
|
||||
Uninstall using pip:
|
||||
```shell
|
||||
pip uninstall ephemetoot
|
||||
```
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
# access_token : the access token from the app you created in Mastodon at Settings - Development
|
||||
# username : your username without the '@' or server domain.
|
||||
# base_url : the base url of your Mastodon server, without the 'https://'
|
||||
# days_to_keep : number of days to keep toots.
|
||||
# keep_pinned : either True or False - if True, any pinned toots will be kept
|
||||
# toots_to_keep : a List of toot ids indicating toots to be kept regardless of other settings
|
||||
# hashtags_to_keep : a Set of hashtags, where any toots with any of these hashtags will be kept. Do not include the '#' symbol
|
||||
# days_to_keep : number of days to keep toots. Defaults to 365
|
||||
# keep_pinned : either true or false - if true, any pinned toots will be kept (default false)
|
||||
# toots_to_keep : a list of toot ids indicating toots to be kept regardless of other settings
|
||||
# hashtags_to_keep : a list of hashtags, where any toots with any of these hashtags will be kept. Do not include the '#' symbol
|
||||
# visibility_to_keep : any toots with visibility settings in this list will be kept. Options are: 'public', 'unlisted', 'private', 'direct'
|
||||
|
||||
# you can list only one user, or multiple users
|
||||
|
@ -15,28 +15,21 @@
|
|||
username : alice
|
||||
base_url : ausglam.space
|
||||
days_to_keep : 14
|
||||
keep_pinned : True
|
||||
keep_pinned : true
|
||||
toots_to_keep :
|
||||
- 103996285277439262
|
||||
- 103976473612749097
|
||||
- 103877521458738491
|
||||
hashtags_to_keep : !!set { python, glamblogclub }
|
||||
hashtags_to_keep :
|
||||
- python
|
||||
- glamblogclub
|
||||
visibility_to_keep :
|
||||
- direct
|
||||
- private
|
||||
-
|
||||
# aus.social account
|
||||
# values other than access_token, username, and base_url are all optional
|
||||
access_token : AZ-Yj3aBD8U8Cm7lKUp-lm9O9BmDgdhHzDeqsY8tlL9
|
||||
username : bob
|
||||
base_url : aus.social
|
||||
days_to_keep : 30
|
||||
keep_pinned : False
|
||||
# toots_to_keep can be empty
|
||||
toots_to_keep :
|
||||
-
|
||||
# hashtags_to_keep can be empty
|
||||
hashtags_to_keep : !!set { }
|
||||
# visibility_to_keep can be empty
|
||||
visibility_to_keep :
|
||||
-
|
||||
|
||||
days_to_keep : 30
|
|
@ -48,22 +48,48 @@ def schedule(options):
|
|||
|
||||
def checkToots(config, options, retry_count=0):
|
||||
|
||||
print("Fetching account details for @" + config['username'] + "@" + config['base_url'] + "...")
|
||||
keep_pinned = 'keep_pinned' in config and config['keep_pinned']
|
||||
toots_to_keep = config['toots_to_keep'] if 'toots_to_keep' in config else []
|
||||
visibility_to_keep = config['visibility_to_keep'] if 'visibility_to_keep' in config else []
|
||||
hashtags_to_keep = set(config['hashtags_to_keep']) if 'hashtags_to_keep' in config else set()
|
||||
days_to_keep = config['days_to_keep'] if 'days_to_keep' in config else 365
|
||||
|
||||
try:
|
||||
print(
|
||||
"Fetching account details for @"
|
||||
+ config['username']
|
||||
+ "@"
|
||||
+ config['base_url']
|
||||
)
|
||||
|
||||
def checkBatch(timeline, deleted_count=0):
|
||||
for toot in timeline:
|
||||
toot_tags = set()
|
||||
for tag in toot.tags:
|
||||
toot_tags.add(tag.name)
|
||||
try:
|
||||
if config['keep_pinned'] and hasattr(toot, "pinned") and toot.pinned:
|
||||
print("📌 skipping pinned toot - " + str(toot.id))
|
||||
elif toot.id in config['toots_to_keep']:
|
||||
print("💾 skipping saved toot - " + str(toot.id))
|
||||
elif toot.visibility in config['visibility_to_keep']:
|
||||
print("👀 skipping " + toot.visibility + " toot - " + str(toot.id))
|
||||
elif len(config['hashtags_to_keep'].intersection(toot_tags)) > 0:
|
||||
print("#️⃣ skipping toot with hashtag - " + str(toot.id))
|
||||
if keep_pinned and hasattr(toot, "pinned") and toot.pinned:
|
||||
print(
|
||||
"📌 skipping pinned toot - "
|
||||
+ str(toot.id)
|
||||
)
|
||||
elif toot.id in toots_to_keep:
|
||||
print(
|
||||
"💾 skipping saved toot - "
|
||||
+ str(toot.id)
|
||||
)
|
||||
elif toot.visibility in visibility_to_keep:
|
||||
print(
|
||||
"👀 skipping "
|
||||
+ toot.visibility
|
||||
+ " toot - "
|
||||
+ str(toot.id)
|
||||
)
|
||||
elif len(hashtags_to_keep.intersection(toot_tags)) > 0:
|
||||
print(
|
||||
"#️⃣ skipping toot with hashtag - "
|
||||
+ str(toot.id)
|
||||
)
|
||||
elif cutoff_date > toot.created_at:
|
||||
if hasattr(toot, "reblog") and toot.reblog:
|
||||
print(
|
||||
|
@ -77,7 +103,7 @@ def checkToots(config, options, retry_count=0):
|
|||
if not options.test:
|
||||
if mastodon.ratelimit_remaining == 0:
|
||||
print(
|
||||
"Rate limit reached. Waiting for a rate limit reset..."
|
||||
"Rate limit reached. Waiting for a rate limit reset"
|
||||
)
|
||||
mastodon.status_unreblog(toot.reblog)
|
||||
else:
|
||||
|
@ -94,12 +120,17 @@ def checkToots(config, options, retry_count=0):
|
|||
if not options.test:
|
||||
if mastodon.ratelimit_remaining == 0:
|
||||
print(
|
||||
"Rate limit reached. Waiting for a rate limit reset..."
|
||||
"Rate limit reached. Waiting for a rate limit reset"
|
||||
)
|
||||
mastodon.status_delete(toot)
|
||||
except MastodonError as e:
|
||||
print("🛑 ERROR deleting toot - " + str(toot.id) + " - " + e.args[3])
|
||||
print("Waiting 1 minute before re-trying...")
|
||||
print(
|
||||
"🛑 ERROR deleting toot - "
|
||||
+ str(toot.id)
|
||||
+ " - "
|
||||
+ e.args[3]
|
||||
)
|
||||
print("Waiting 1 minute before re-trying")
|
||||
time.sleep(60)
|
||||
try:
|
||||
print("Attempting delete again")
|
||||
|
@ -108,16 +139,36 @@ def checkToots(config, options, retry_count=0):
|
|||
2
|
||||
) # wait 2 secs between deletes to be a bit nicer to the server
|
||||
except Exception as e:
|
||||
print("🛑 ERROR deleting toot - " + str(toot.id))
|
||||
print(
|
||||
"🛑 ERROR deleting toot - "
|
||||
+ str(toot.id)
|
||||
)
|
||||
print(e)
|
||||
print("Exiting due to error.")
|
||||
break
|
||||
except KeyboardInterrupt:
|
||||
print("Operation aborted.")
|
||||
break
|
||||
except Exception as e:
|
||||
print("🛑 Unknown ERROR deleting toot - " + str(toot.id))
|
||||
print(e)
|
||||
except KeyError as e:
|
||||
print(
|
||||
"⚠️ There is an error in your config.yaml file. Please add a value for "
|
||||
+ str(e)
|
||||
+ " and try again."
|
||||
)
|
||||
break
|
||||
except:
|
||||
e = sys.exc_info()
|
||||
|
||||
print(
|
||||
"🛑 Unknown ERROR deleting toot - "
|
||||
+ str(toot.id)
|
||||
)
|
||||
|
||||
print("ERROR: "
|
||||
+ str(e[0])
|
||||
+ " - "
|
||||
+ str(e[1])
|
||||
)
|
||||
|
||||
# the account_statuses call is paginated with a 40-toot limit
|
||||
# get the id of the last toot to include as 'max_id' in the next API call.
|
||||
|
@ -130,12 +181,16 @@ def checkToots(config, options, retry_count=0):
|
|||
else:
|
||||
if options.test:
|
||||
print(
|
||||
"Test run completed. This would have removed "
|
||||
"\nTest run completed. This would have removed "
|
||||
+ str(deleted_count)
|
||||
+ " toots."
|
||||
)
|
||||
else:
|
||||
print("Removed " + str(deleted_count) + " toots.")
|
||||
print(
|
||||
"Removed "
|
||||
+ str(deleted_count)
|
||||
+ " toots."
|
||||
)
|
||||
|
||||
print('')
|
||||
print('---------------------------------------')
|
||||
|
@ -144,26 +199,37 @@ def checkToots(config, options, retry_count=0):
|
|||
|
||||
except IndexError:
|
||||
print("No toots found!")
|
||||
|
||||
|
||||
mastodon = Mastodon(
|
||||
access_token=config['access_token'],
|
||||
api_base_url="https://" + config['base_url'],
|
||||
ratelimit_method="wait",
|
||||
)
|
||||
|
||||
cutoff_date = datetime.now(timezone.utc) - timedelta(days=config['days_to_keep'])
|
||||
cutoff_date = datetime.now(timezone.utc) - timedelta(days=days_to_keep)
|
||||
user_id = mastodon.account_verify_credentials().id
|
||||
account = mastodon.account(user_id)
|
||||
timeline = mastodon.account_statuses(user_id, limit=40)
|
||||
|
||||
print("Checking " + str(account.statuses_count) + " toots...")
|
||||
print(
|
||||
"Checking "
|
||||
+ str(account.statuses_count)
|
||||
+ " toots"
|
||||
)
|
||||
|
||||
checkBatch(timeline)
|
||||
|
||||
except KeyError as val:
|
||||
print('\n⚠️ error with in your config.yaml file!')
|
||||
print(
|
||||
'Please ensure there is a value for '
|
||||
+ str(val)
|
||||
+ '\n'
|
||||
)
|
||||
|
||||
except MastodonAPIError:
|
||||
print('User and/or access token does not exist or has been deleted')
|
||||
print('\n🙅 User and/or access token does not exist or has been deleted')
|
||||
except MastodonNetworkError:
|
||||
print('ephemetoot cannot connect to the server - are you online?')
|
||||
print('\n📡 ephemetoot cannot connect to the server - are you online?')
|
||||
if retry_count < 4:
|
||||
print('Waiting 1 minute before trying again')
|
||||
time.sleep(60)
|
||||
|
|
Loading…
Reference in New Issue