From 898ce41fb7e0c8d114daec73074b6769d0a98a75 Mon Sep 17 00:00:00 2001 From: Hugh Rundle Date: Sat, 9 May 2020 14:45:38 +1000 Subject: [PATCH] Simplify config options and improve error handling Fix #21 --- README.md | 27 ++++++++--- example-config.yaml | 27 ++++------- lib/ephemetoot.py | 116 ++++++++++++++++++++++++++++++++++---------- 3 files changed, 120 insertions(+), 50 deletions(-) diff --git a/README.md b/README.md index 54dea2d..b3faf00 100644 --- a/README.md +++ b/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 ``` diff --git a/example-config.yaml b/example-config.yaml index 9e651d6..450fd4e 100644 --- a/example-config.yaml +++ b/example-config.yaml @@ -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 : - - - \ No newline at end of file + days_to_keep : 30 \ No newline at end of file diff --git a/lib/ephemetoot.py b/lib/ephemetoot.py index 6b21265..f88b95b 100644 --- a/lib/ephemetoot.py +++ b/lib/ephemetoot.py @@ -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)