Files
dc-nogi/bot/undo.py
Minz 7b3c358b05 Add a live status line to the stats panel
Shows what's happening right now underneath the table (connecting,
resolving the friend, discovering targets, fetching channel history,
waiting out a jittered delay before reacting, sending a reaction,
removing a reaction during --undo, etc). Status updates are cheap
and DB-free, using the last fetched stats for re-rendering.
2026-08-01 18:53:48 +02:00

64 lines
2.5 KiB
Python

import asyncio
import logging
from typing import Optional
import discord
from bot.display import StatsDisplay
from bot.reactor import human_jitter
from bot.storage import Storage
log = logging.getLogger(__name__)
async def undo_all_reactions(client: discord.Client, storage: Storage, display: Optional[StatsDisplay] = None) -> None:
"""Remove every reaction this script has previously logged, then clear those log entries."""
rows = await asyncio.to_thread(storage.get_all_reactions)
total = len(rows)
log.info("Undo: removing %d previously-added reaction(s)...", total)
removed = 0
for i, row in enumerate(rows, start=1):
channel_id = int(row["channel_id"])
message_id = int(row["message_id"])
emoji = row["emoji"]
should_clear_log = True
if display is not None:
display.set_status(f"Removing reaction from message {message_id} ({i}/{total})...")
try:
channel = client.get_channel(channel_id) or await client.fetch_channel(channel_id)
message = await channel.fetch_message(message_id)
await message.remove_reaction(emoji, client.user)
removed += 1
log.info("[%d/%d] Removed reaction from message %s", i, total, message_id)
except discord.NotFound:
log.info("[%d/%d] Message/reaction %s already gone, clearing log entry", i, total, message_id)
except discord.HTTPException:
log.exception("[%d/%d] Failed to remove reaction from message %s, will retry next run", i, total, message_id)
should_clear_log = False
if should_clear_log:
await asyncio.to_thread(storage.delete_reaction, row["id"])
if display is not None:
await display.refresh()
delay = human_jitter()
if display is not None:
display.set_status(f"Waiting {delay:.1f}s before next removal...")
await asyncio.sleep(delay)
if display is not None:
display.set_status("Clearing channel resume points and found-message log...")
cleared = await asyncio.to_thread(storage.clear_scan_state)
await asyncio.to_thread(storage.reset_message_counts)
if display is not None:
display.set_status("Undo complete.")
await display.refresh()
log.info(
"Undo complete: removed %d/%d reaction(s), cleared %d channel resume point(s) — "
"the next normal run will do a full fresh backlog scan.",
removed, total, cleared,
)