From dff1eb3185d088c0a83b9813a3e0d60fd25816bb Mon Sep 17 00:00:00 2001 From: Interitio Date: Wed, 25 Feb 2026 18:44:50 +1000 Subject: [PATCH] feat: Add db voice session tracking --- data/schema.sql | 11 ++++++++++ plugin/data.py | 13 ++++++++++++ plugin/discord/cog.py | 47 +++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 69 insertions(+), 2 deletions(-) diff --git a/data/schema.sql b/data/schema.sql index 61809bf..1bc9f82 100644 --- a/data/schema.sql +++ b/data/schema.sql @@ -10,4 +10,15 @@ CREATE TABLE voicelog_guilds( CREATE TRIGGER voicelog_guilds_timestamp BEFORE UPDATE ON voicelog_guilds FOR EACH ROW EXECUTE FUNCTION update_timestamp_column(); +CREATE TABLE voicelog_sessions( + sessionid INTEGER GENERATED ALWAYS AS IDENTITY PRIMARY KEY, + guildid BIGINT NOT NULL REFERENCES voicelog_guilds (guildid) ON DELETE CASCADE ON UPDATE CASCADE, + userid BIGINT NOT NULL, + channelid BIGINT NOT NULL, + joined_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), + duration INTEGER +); + +CREATE INDEX voicelog_sessions_guildid_userid ON voicelog_sessions (guildid, userid); + COMMIT; diff --git a/plugin/data.py b/plugin/data.py index 60b4a14..9ceb376 100644 --- a/plugin/data.py +++ b/plugin/data.py @@ -12,5 +12,18 @@ class VoiceLogGuild(RowModel): _timestamp = Timestamp() +class VoiceLogSession(RowModel): + _tablename_ = "voicelog_sessions" + _cache_ = {} + + sessionid = Integer(primary=True) + guildid = Integer() + userid = Integer() + channelid = Integer() + joined_at = Timestamp() + duration = Integer() + + class VoiceLogData(Registry): voicelog_guilds = VoiceLogGuild.table + voicelog_sessions = VoiceLogSession.table diff --git a/plugin/discord/cog.py b/plugin/discord/cog.py index eacba2e..f044674 100644 --- a/plugin/discord/cog.py +++ b/plugin/discord/cog.py @@ -1,3 +1,4 @@ +from data.queries import ORDER import discord from discord.ext import commands as cmds from discord import app_commands as appcmds @@ -7,7 +8,7 @@ from meta.logger import log_wrap from utils.lib import utc_now from . import logger -from ..data import VoiceLogData, VoiceLogGuild +from ..data import VoiceLogData, VoiceLogGuild, VoiceLogSession from .lib import ThreadedWebhook @@ -41,7 +42,8 @@ class VoiceLogCog(LionCog): hook = ThreadedWebhook.from_url(row.webhook_url, client=self.bot) - embed = discord.Embed(timestamp=utc_now()) + now = utc_now() + embed = discord.Embed(timestamp=now) if before_channel is None: embed.title = "User Joined Voice Channel" @@ -53,8 +55,49 @@ class VoiceLogCog(LionCog): embed.title = "User Switched Voice Channel" embed.description = f"{member.mention} moved from {before_channel.mention} to {after_channel.mention}" + session = None + if before_channel: + session = await self.end_voice_session(member, before_channel, now) + if not session: + embed.add_field( + name="Warning", + value="Could not find voice session to end, statistics may be incorrect.", + ) + if after_channel: + session = await self.start_voice_session(member, after_channel, now) + + if session: + embed.add_footer(f"Session #{session.sessionid}") + await hook.send(embed=embed) + async def start_voice_session(self, member, channel, started_at): + session = await VoiceLogSession.create( + guildid=member.guild.id, + userid=member.id, + channelid=channel.id, + joined_at=started_at, + ) + return session + + async def end_voice_session(self, member, channel, ended_at): + # Get the last open voice session to close it + open_sessions = await VoiceLogSession.fetch_where( + guildid=member.guildid, + userid=member.id, + channelid=channel.id, + duration=None, + ).order_by("joined_at", ORDER.DESC) + if not open_sessions: + session = None + else: + session = open_sessions[0] + await session.update( + duration=int((ended_at - session.joined_at).total_seconds()) + ) + + return session + @cmds.hybrid_group( name="voicelog", description="Base command group for the voice logging system" )