This commit is contained in:
Zodiac 2025-02-18 23:48:49 -08:00
parent a64e9554c6
commit 3cd621d350

View File

@ -1,17 +1,41 @@
#!/usr/bin/env python #!/usr/bin/env python
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
"""
IRC Bot Plugin for Tracking User Activity with TinyDB.
This plugin tracks user join times, messages, and nickname changes. Provides """
a !seen command to check last activity. Stores data in "seen.json". IRC Bot Plugin for Tracking User Activity with TinyDB
This module implements an IRC bot plugin to track various activities of users in an IRC channel,
including their join times, messages sent, and nickname changes. The plugin uses TinyDB for
persistent storage of user data.
Features:
- Tracks when users join a channel.
- Logs user messages with timestamps.
- Monitors nickname changes.
- Provides a '!seen' command to retrieve the last activity of a specified user.
Dependencies: Dependencies:
- irc3 - irc3: For IRC protocol handling.
- tinydb - tinydb: For managing user data in a JSON file.
- ircstyle - ircstyle: For formatting IRC messages with color and style.
- logging - logging: For error logging.
- re - humanize: For converting time differences into human-readable format.
Usage:
- Install required packages: pip install irc3 tinydb ircstyle humanize
- Use within an IRC bot framework that utilizes irc3 plugins.
Storage:
- User data is stored in 'seen.json' in the same directory as this script.
Author:
- Zodiac
Date:
- 02/18/2025
Note:
- Ensure your bot environment has write permissions for the JSON database file.
""" """
from datetime import datetime from datetime import datetime
@ -20,6 +44,7 @@ import irc3
from irc3.plugins.command import command from irc3.plugins.command import command
import ircstyle import ircstyle
import logging import logging
import humanize
def truncate(text, length=50): def truncate(text, length=50):
"""Truncate text to specified length, appending "..." if truncated.""" """Truncate text to specified length, appending "..." if truncated."""
@ -114,7 +139,7 @@ class UserActivityTracker:
user = self.users.get(self.User.nick == requested_nick) user = self.users.get(self.User.nick == requested_nick)
if not user: if not user:
msg = ircstyle.style(f"🚫 {requested_nick} has never been observed.", fg="red") msg = ircstyle.style(f" {requested_nick} has never been observed.", fg="red")
self.bot.privmsg(target, msg) self.bot.privmsg(target, msg)
return return
@ -132,37 +157,33 @@ class UserActivityTracker:
# Last join - only if time exists # Last join - only if time exists
if 'last_join' in user and user['last_join']: if 'last_join' in user and user['last_join']:
try: response.append(ircstyle.style("🕒 Last join: ", fg="cyan") +
join_time = datetime.fromisoformat(user['last_join']).strftime('%Y-%m-%d %H:%M:%S') ircstyle.style(humanize.naturaltime(datetime.now() - datetime.fromisoformat(user['last_join'])), fg="white"))
response.append(ircstyle.style("🕒 Last join: ", fg="cyan") + ircstyle.style(join_time, fg="white"))
except ValueError:
response.append(ircstyle.style("🕒 Last join: ", fg="cyan") + ircstyle.style("Invalid Time Format", fg="white"))
# Last message # Last message
if 'last_message' in user and user['last_message']: if 'last_message' in user and user['last_message']:
try: try:
msg_time = datetime.fromisoformat(user['last_message']['time']).strftime('%Y-%m-%d %H:%M:%S')
msg_text = truncate(user['last_message']['text']) msg_text = truncate(user['last_message']['text'])
response.append( response.append(
ircstyle.style("💬 Last message: ", fg="green") + ircstyle.style("💬 Last message: ", fg="green") +
ircstyle.style(f"[{msg_time}] ", fg="grey") + ircstyle.style(humanize.naturaltime(datetime.now() - datetime.fromisoformat(user['last_message']['time'])), fg="grey") + " " +
ircstyle.style(msg_text, fg="white", italics=True) ircstyle.style(msg_text, fg="white", italics=True)
) )
except (ValueError, KeyError): except KeyError:
response.append(ircstyle.style("💬 Last message: ", fg="green") + ircstyle.style("Invalid or Missing Data", fg="white")) response.append(ircstyle.style("💬 Last message: ", fg="green") + ircstyle.style("Invalid or Missing Data", fg="white"))
# Last nick change # Last nick change
if 'last_nick_change' in user and user['last_nick_change']: if 'last_nick_change' in user and user['last_nick_change']:
try: try:
change_time = datetime.fromisoformat(user['last_nick_change']['time']).strftime('%Y-%m-%d %H:%M:%S')
old_nick = user['last_nick_change']['old'] old_nick = user['last_nick_change']['old']
new_nick = user['last_nick_change']['new'] new_nick = user['last_nick_change']['new']
response.append( response.append(
ircstyle.style(f"📛 Nickname change: ", fg="purple") + ircstyle.style(f"🆔 Nickname change: ", fg="purple") +
ircstyle.style(f"Changed from {old_nick} to {new_nick} at {change_time}", fg="white") ircstyle.style(f"Changed from {old_nick} to {new_nick} ", fg="white") +
ircstyle.style(humanize.naturaltime(datetime.now() - datetime.fromisoformat(user['last_nick_change']['time'])), fg="white")
) )
except (ValueError, KeyError): except KeyError:
response.append(ircstyle.style(f"📛 Nickname change: ", fg="purple") + ircstyle.style("Invalid or Missing Data", fg="white")) response.append(ircstyle.style(f"🆔 Nickname change: ", fg="purple") + ircstyle.style("Invalid or Missing Data", fg="white"))
if len(response) == 1: # Only header present if len(response) == 1: # Only header present
response.append(ircstyle.style("No tracked activities.", fg="yellow")) response.append(ircstyle.style("No tracked activities.", fg="yellow"))
@ -172,4 +193,4 @@ class UserActivityTracker:
except Exception as e: except Exception as e:
self.log.error(f"Error in !seen command: {e}") self.log.error(f"Error in !seen command: {e}")
self.bot.privmsg(target, ircstyle.style(" Internal error processing request.", fg="red", bold=True)) self.bot.privmsg(target, ircstyle.style("🚨 Internal error processing request.", fg="red", bold=True))