use setuptools and add multi-user

Resolves #20 - now uses setuptools for easy installation with pip
Resolves #13 - can now manage multiple accounts
Config file is now in YAML and is passed to script with --config flag
Can now execute from anywhere
This commit is contained in:
Hugh Rundle 2020-04-20 20:14:58 +10:00
parent ff448a45bd
commit 61d0d01f12
8 changed files with 253 additions and 109 deletions

3
.gitignore vendored
View File

@ -1 +1,2 @@
config.py
config.py
config.yaml

160
README.md
View File

@ -1,90 +1,160 @@
A script for deleting old toots.
A tool for deleting old toots, written in Python 3.
Based partially on [tweet-deleting script](https://gist.github.com/flesueur/bcb2d9185b64c5191915d860ad19f23f) by [@flesueur](https://github.com/flesueur)
# Prior work
The initial `ephemetoot` script was based on [this tweet-deleting script](https://gist.github.com/flesueur/bcb2d9185b64c5191915d860ad19f23f) by [@flesueur](https://github.com/flesueur)
`ephemetoot` relies heavily on the Mastodon.py package by [@halcy](https://github.com/halcy)
# Usage
You can use this script to delete [Mastodon](https://github.com/tootsuite/mastodon) toots that are older than a certain number of days. By default it will keep any pinned toots, but if you want them to be deleted as well you can change `keep_pinned` to `False` in `config.py`. You can also make a list toots that you want to keep, by adding the ID numbers to the `toots_to_keep` list in `config.py` (see point 9 below). 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`
This script requires Python3, the `mastodon.py` package and an API access token.
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:
* they are pinned;
* they include certain hashtags;
* they have certain visibility; or
* they are individually listed to be kept
# Setup
1. Install Python3 if you don't already have it (recommended approach is to [use Homebrew](https://docs.brew.sh/Homebrew-and-Python) if you're on MacOS)
2. Install the mastodon package: `pip3 install mastodon.py`
3. Copy _example.config.py_ to a new file called _config.py_ (e.g. `cp example.config.py config.py`)
4. Log in to your Mastodon account using a web browser
1. Click the settings cog
2. Click on Development
3. Click 'NEW APPLICATION'
4. Enter an application name, and give the app 'read' and 'write' Scopes
5. Click 'SUBMIT'
6. Click on the name of the new app
7. Copy the 'access token' string
5. Replace `YOUR_ACCESS_TOKEN_HERE` in config.py with the access token string
6. Set the `base_url` to match your mastodon server
7. Set the `days_to_keep` to the number of days you want to keep toots before deleting them
8. If you do **not** wish to keep all pinned toots regardless of age, change `keep_pinned` to `False`
9. If there are any other toots you want to keep, put the ID numbers (without quotes) in the `toots_to_keep` list, separated by commas. For example:
```python
toots_to_keep = [100029521330725397, 100013562864734780, 100044187305250752]
## Install Python 3
You need to [install Python 3](https://wiki.python.org/moin/BeginnersGuide/Download) to use `ephemetoot`. Python 2 is now end-of-life, however it continued to be installed as the default Python on MacOS until very recently, and may also be installed on your server.
## Install ephemetoot
### get code with git
If you already have `git` installed on the machine where you're running ephemetoot, you can download the latest release with:
```shell
git clone https://github.com/hughrun/ephemetoot.git
```
10. If you want to keep toots with a particular hashtag, list each hashtag in the `hashtags_to_keep` set (omitting the `#`):
```python
hashtags_to_keep = {'introduction', 'announcement'}
### get code by downloading zip file
If you don't have `git` or don't want to use it, you can download the zip file by clicking the green `Clone or download` button above and selecting `Download ZIP`. You will then need to unzip the file into a new directory where you want to run it.
### install using pip
From a command line, move into the main `ephemetoot` directory (i.e. where the README file is) and run:
```shell
pip install .
```
11. You can keep toots with particular visibility (e.g. direct messages) by including that visibility in `visibility_to_keep`. For example the following would only delete public toots:
```python
visibility_to_keep = ['unlisted', 'private', 'direct']
With some Python 3 installations (e.g on MacOS with Homebrew) you may need to use:
```shell
pip3 install .
```
## Obtain an access token
Now you've installed `ephemetoot`, in order to actually use it you will need an application "access token" from each user. Log in to your Mastodon account using a web browser:
1. Click the `settings` cog
2. Click on `Development`
3. Click `NEW APPLICATION`
4. Enter an application name (e.g. 'ephemetoot'), and give the app both 'read' and 'write' Scopes
5. Click `SUBMIT`
6. Click on the name of the new app, which should be a link
7. Copy the `Your access token` string
## Configuration file
As of version 2, you can use a single `ephemetoot` installation to delete toots from multiple accounts. Configuration for each user is set up in the `config.yaml` file. This uses [yaml syntax](https://yaml.org/spec/1.2/spec.html) and can be updated at any time without having to reload `ephemetoot`.
Copy `example-config.yaml` to a new file called `config.yml`:
```shell
cp example-config.yam config.yaml
```
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 |
| 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, and remember the [rules for hashtags](https://docs.joinmastodon.org/user/posting/#hashtags) |
| visibility_to_keep | Any toots with visibility settings in this list will be kept regardless of age. Options are: `public`, `unlisted`, `private`, `direct`. For example the following would only delete public toots:
```yaml
- unlisted
- private
- direct
```
|
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
## Test mode
It is **strongly recommended** that you do a [test run](#running-in-test-mode) before using `ephemetoot` live.
To call the script you can simply enter:
```shell
ephemetoot
```
Depending on how many toots you have and how long you want to keep them, it may take a minute or two before you see any results.
## Specifying the config location
By default ephemetoot expects there to be a config file called `config.yaml` in the directory from where you run the `ephemetoot` command. If you want to call it from elsewhere (e.g. from `cron`), you need to specify where your config file is:
```shell
ephemetoot --config 'directory/config.yaml'
```
## Running in test mode
To do a test-run without actually deleting anything, run the script with the `--test` flag:
```shell
python3 ephemetoot.py --test
ephemetoot --test
```
Depending on how many toots you have and how long you want to keep them, it may take a minute or two before you see any results.
## Live mode
## Other flag options
Run the script with no flags:
You can use both flags together:
```shell
python3 ephemetoot.py
ephemetoot --config 'directory/config.yaml' --test
```
Use them in any order:
```shell
ephemetoot --test --config 'directory/config.yaml'
```
Instead of coming back to this page when you forget the flags, you can just use the help option:
```shell
ephemetoot --help
```
Depending on how many toots you have and how long you want to keep them, it may take a minute or two before you see any results.
## Rate limits
As of v2.7.2 the Mastodon API has a rate limit of 30 deletions per 30 minutes. `mastodon.py` automatically handles this. If you are running `ephemetoot` for the first time and/or have a lot of toots to delete, it may take a while as the script will pause when it hits a rate limit, until the required time has expired. Note that the rate limit is per access token, so using ephemetoot for multiple accounts on the same server shouldn't be a big problem, however one new user may delay action on subsequent accounts in the config file.
## Scheduling
Deleting old toots daily is the best approach to keeping your timeline clean and avoiding problems wiht the API rate limit.
To run automatically every day you could try using crontab:
To run automatically every day on a n*x server you could try using crontab:
1. `crontab -e`
2. `@daily python3 ~/ephemetoot/ephemetoot.py`
2. `@daily ephemetoot`
Alternatively on MacOS you could use [launchd](https://www.launchd.info/) or Automator.
Alternatively on MacOS you could use [launchd](https://www.launchd.info/). Some further work on an example setup for launchd is coming soonish.
## Rate limits
As of v2.7.2 the Mastodon API has a rate limit of 30 deletions per 30 minutes. `mastodon.py` automatically handles this. If you are running `ephemetoot` for the first time and/or have a lot of toots to delete, it may take a while as the script will pause when it hits a rate limit, until the required time has expired.
## ASCII / utf-8 errors
# ASCII / utf-8 errors
Prior to Python 3.7, running a Python script on some BSD and Linux systems may throw an error. This can be resolved by:
* setting a _locale_ that encodes utf-8, by using the environment setting `PYTHONIOENCODING=utf-8` when running the script, or
* upgrading your Python version to 3.7 or higher. See [Issue 11](https://github.com/hughrun/ephemetoot/issues/11) for more information.
# Uninstalling
Uninstall using pip;
```
pip uninstall ephemetoot
```
# Bugs and suggestions
Please check existing [issues](https://github.com/hughrun/ephemetoot/issues) and if your issue is not already listed, create a new one with as much detail as possible (but don't include your access token!).
# Contributing
Contributions are very welcome, but if you want to suggest any changes or improvements, please log an issue or have a chat to [me on Mastodon](https://ausglam.space/@hugh) _before_ lodging a pull request.
Contributions are very welcome, but if you want to suggest any changes or improvements, please log an issue or have a chat to [me on Mastodon](https://ausglam.space/@hugh) _before_ making a pull request.
# License

56
bin/ephemetoot Normal file
View File

@ -0,0 +1,56 @@
#!/usr/bin/env python3
# #####################################################################
# Ephemetoot - A script to delete your old toots
# Copyright (C) 2018 Hugh Rundle, 2019-2020 Hugh Rundle & Mark Eaton
# Initial work based on tweet-deleting script by @flesueur
# (https://gist.github.com/flesueur/bcb2d9185b64c5191915d860ad19f23f)
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# You can contact Hugh on Mastodon @hugh@ausglam.space
# or email hugh [at] hughrundle [dot] net
# #####################################################################
# import
import yaml
# from standard library
from argparse import ArgumentParser
import os
# local files
from lib import ephemetoot
parser = ArgumentParser()
parser.add_argument(
"--config", action="store", metavar="'filepath'", default="config.yaml", help="filepath of your config file, relative to the current directory. If no --config path is provided, ephemetoot will use 'config.yaml'."
)
parser.add_argument(
"--test", action="store_true", help="do a test run without deleting any toots"
)
options = parser.parse_args()
if options.config[0] == '~':
config_file = os.path.expanduser(options.config)
elif options.config[0] == '/':
config_file = options.config
else:
config_file = os.path.join( os.getcwd(), options.config )
if __name__ == "__main__":
with open(config_file) as config:
for accounts in yaml.safe_load_all(config):
for user in accounts:
ephemetoot.checkToots(user, options)

42
example-config.yaml Normal file
View File

@ -0,0 +1,42 @@
# 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
# 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
# each user account should be preceded by a single dash, and indented, as per below
-
# ausglam.space account
access_token : ZA-Yj3aBD8U8Cm7lKUp-lm9O9BmDgdhHzDeqsY8tlL0
username : alice
base_url : ausglam.space
days_to_keep : 14
keep_pinned : True
toots_to_keep :
- 103996285277439262
- 103976473612749097
- 103877521458738491
hashtags_to_keep : !!set { python, glamblogclub }
visibility_to_keep :
- direct
- private
-
# aus.social account
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 :
-

View File

@ -1,7 +0,0 @@
access_token = 'YOUR_ACCESS_TOKEN_HERE'
base_url = 'https://ausglam.space'
days_to_keep = 30
keep_pinned = True
toots_to_keep = []
hashtags_to_keep = {'introduction', 'announcement'} # comma separated Set as strings, e.g. 'introduction'
visibility_to_keep = ['private', 'unlisted'] # options are: 'public', 'unlisted', 'private', 'direct'

0
lib/__init__.py Normal file
View File

View File

@ -1,68 +1,38 @@
# #####################################################################
# Ephemetoot - A script to delete your old toots
# Copyright (C) 2018, 2020 Hugh Rundle, 2019 Hugh Rundle & Mark Eaton
# Based partially on tweet-deleting script by @flesueur
# (https://gist.github.com/flesueur/bcb2d9185b64c5191915d860ad19f23f)
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# You can contact Hugh on Mastodon @hugh@ausglam.space
# or email hugh [at] hughrundle [dot] net
# #####################################################################
from argparse import ArgumentParser
import config
import json
from mastodon import Mastodon, MastodonError
from datetime import datetime, timedelta, timezone
import time
parser = ArgumentParser()
parser.add_argument(
"--test", action="store_true", help="do a test run without deleting any toots"
)
options = parser.parse_args()
if options.test:
print("This is a test run...")
def checkToots(config, options, deleted_count=0):
if options.test:
print("This is a test run...")
print("Fetching account details for @" + config['username'] + "@" + config['base_url'] + "...")
mastodon = Mastodon(
access_token=config['access_token'],
api_base_url="https://" + config['base_url'],
ratelimit_method="wait",
)
print("Fetching account details...")
cutoff_date = datetime.now(timezone.utc) - timedelta(days=config['days_to_keep'])
user_id = mastodon.account_verify_credentials().id
account = mastodon.account(user_id)
timeline = mastodon.account_statuses(user_id, limit=40)
mastodon = Mastodon(
access_token=config.access_token,
api_base_url=config.base_url,
ratelimit_method="wait",
)
print("Checking " + str(account.statuses_count) + " toots...")
cutoff_date = datetime.now(timezone.utc) - timedelta(days=config.days_to_keep)
user_id = mastodon.account_verify_credentials().id
timeline = mastodon.account_statuses(user_id, limit=40)
def checkToots(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:
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:
elif toot.id in config['toots_to_keep']:
print("💾 skipping saved toot - " + str(toot.id))
elif toot.visibility in config.visibility_to_keep:
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:
elif len(config['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:
@ -137,11 +107,4 @@ def checkToots(timeline, deleted_count=0):
else:
print("Removed " + str(deleted_count) + " toots.")
except IndexError:
print("No toots found!")
# trigger from here
if __name__ == "__main__":
account = mastodon.account(user_id)
print("Checking " + str(account.statuses_count) + " toots...")
checkToots(timeline)
print("No toots found!")

19
setup.py Normal file
View File

@ -0,0 +1,19 @@
from setuptools import setup, find_packages
setup(name='ephemetoot',
version='2.0.0',
url='https://github.com/hughrun/ephemetoot',
license='GPL-3.0-or-later',
packages=find_packages(),
scripts=['bin/ephemetoot'],
install_requires=['Mastodon.py', 'pyyaml'],
zip_safe=False,
author='Hugh Rundle',
author_email='hugh@hughrundle.net',
description='A command line tool for selectively deleting old toots.',
keywords='mastodon, mastodon api',
project_urls={
'Source Code': 'https://github.com/hughrun/ephemetoot',
'Documentation': 'https://github.com/hughrun/ephemetoot'
}
)