From 5ffa45c3c5d9cc9b6434a188089d765c65ff40bf Mon Sep 17 00:00:00 2001 From: Gabriel Augendre Date: Mon, 30 Dec 2019 21:02:20 +0100 Subject: [PATCH] Display protected toots and reason. Close #4 --- cleantoots/commands/clean.py | 149 ++++++++++++++++++++++++----------- 1 file changed, 102 insertions(+), 47 deletions(-) diff --git a/cleantoots/commands/clean.py b/cleantoots/commands/clean.py index 56c3704..1691fca 100644 --- a/cleantoots/commands/clean.py +++ b/cleantoots/commands/clean.py @@ -1,4 +1,5 @@ import logging.handlers +from typing import Optional, List import click import html2text @@ -44,69 +45,123 @@ def clean(config: CleanTootsConfig, delete: bool, headless: bool): user = mastodon.me() page = mastodon.account_statuses(user["id"]) would_delete = [] + protected = [] while page: for toot in page: - boost_count = toot["reblogs_count"] - favorite_count = toot["favourites_count"] - id_ = toot["id"] - original_id = None - if toot.get("reblog"): - original_id = toot["reblog"].get("id") - created_at = toot["created_at"] - protected_toots = map(int, section.get("protected_toots", "").split()) - time_limit = pendulum.now(tz=section.get("timezone")).subtract( - days=section.getint("days_count") - ) - if ( - boost_count >= section.getint("boost_limit") - or favorite_count >= section.getint("favorite_limit") - or id_ in protected_toots - or original_id in protected_toots - or created_at >= time_limit - ): - continue - would_delete.append(toot) + protection_reason = _toot_protection_reason(toot, section) + if protection_reason: + protected.append({"toot": toot, "reason": protection_reason}) + else: + would_delete.append(toot) page = mastodon.fetch_next(page) - if not delete: - if not would_delete: - log("No toot would be deleted given the rules.", headless, fg="blue") - return - log( - "Would delete {count} toots/boost:".format(count=len(would_delete)), - headless, - fg="blue", - ) - for toot in would_delete: - message = format_toot(toot) - log(message, headless, bold=True) - content = h.handle(toot["content"]).replace("\n", " ").strip() - if len(content) > CONTENT_PREVIEW: - content = content[: CONTENT_PREVIEW - 3] + "..." - else: - content = content[:CONTENT_PREVIEW] - log(content, headless) - log("", headless) - else: - log("Deleting toots...", headless) - with click.progressbar(would_delete) as bar: - for toot in bar: - mastodon.status_delete(toot) - log("Deleted {}".format(format_toot(toot)), headless, fg="green") + _delete_or_log(delete, h, headless, mastodon, protected, would_delete) -def format_toot(toot): +def _delete_or_log(delete, html_handler, headless, mastodon, protected, would_delete): + if not delete: + _log_item_list( + would_delete, + headless, + html_handler, + no_item_message="No toot would be deleted given the rules.", + count_message_format="Would delete {count} toots/boost:", + ) + _log_item_list( + protected, + headless, + html_handler, + no_item_message="No toot would be protected given the rules.", + count_message_format="Would protect {count} toots/boost:", + ) + else: + log("Deleting toots...", headless) + with click.progressbar(would_delete) as bar: + for toot in bar: + mastodon.status_delete(toot) + log("Deleted {}".format(_format_toot(toot)), headless, fg="green") + + +def _log_item_list( + items: List[dict], + headless: bool, + html_handler: html2text.HTML2Text, + no_item_message: str, + count_message_format: str, +): + if not items: + log(no_item_message, headless, fg="blue") + else: + log( + count_message_format.format(count=len(items)), headless, fg="blue", + ) + for toot in items: + _log_item(toot, headless, html_handler) + + +def _log_item(item, headless, html_handler): + if "reason" in item and "toot" in item: + toot = item["toot"] + reason = item["reason"] + else: + toot = item + reason = "" + message = _format_toot(toot, reason) + log(message, headless, bold=True) + content = html_handler.handle(toot["content"]).replace("\n", " ").strip() + if len(content) > CONTENT_PREVIEW: + content = content[: CONTENT_PREVIEW - 3] + "..." + else: + content = content[:CONTENT_PREVIEW] + log(content, headless) + log("", headless) + + +def _format_toot(toot: dict, protection_reason: str = ""): if toot.get("reblog"): message = f"boost of toot {toot['reblog']['url']}" else: message = f"original toot {toot['url']}" + if protection_reason: + message = f"{message} protected because of {protection_reason}" return message -def log(message, headless, level=logging.INFO, *args, **kwargs): +def log(message: str, headless: bool, level: int = logging.INFO, *args, **kwargs): if headless: if message and message.strip(): logger.log(level, message) else: click.secho(message, *args, **kwargs) + + +def _toot_protection_reason(toot: dict, section) -> Optional[str]: + """ + Return a protection reason or None if the toot should not be protected. + + :param toot: The toot to check. + :param section: The section of the config file to check against. + :return: The protection reason or None. + """ + boost_count = toot["reblogs_count"] + favorite_count = toot["favourites_count"] + id_ = toot["id"] + original_id = None + if toot.get("reblog"): + original_id = toot["reblog"].get("id") + created_at = toot["created_at"] + protected_toots = map(int, section.get("protected_toots", "").split()) + time_limit = pendulum.now(tz=section.get("timezone")).subtract( + days=section.getint("days_count") + ) + if boost_count >= section.getint("boost_limit"): + return "boost count" + if favorite_count >= section.getint("favorite_limit"): + return "favorite count" + if id_ in protected_toots or original_id in protected_toots: + return "protected id" + if created_at >= time_limit: + return "creation time" + + return None