Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions commands/utility_commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

import scratchattach as scratch

import config
from config import scratch_orange


Expand Down Expand Up @@ -316,6 +317,27 @@ async def scratchblocks(
filename = await render_blocks_image(code=code, style=style)
await ctx.send(file=interactions.File(file=filename))

@interactions.slash_command(
name="community",
description="Check what the Scratch community is up to.",
)
async def community(self, ctx: interactions.SlashContext):
stats = config.activity_stats
await ctx.send(
embed=interactions.Embed(
title="<a:onlineGreendot:1551223053021880330> What the community is up to:",
description=(
f"<:scratch:1330550333751169104> **{stats['scratch3']}** people are using Scratch 3\n"
f"- **{stats['streaming_scratch3']}** people are streaming it\n"
f"<:Turbowarp:1330552274774396979> **{stats['turbowarp']}** people are using TurboWarp Desktop\n"
f"- **{stats['streaming_turbowarp']}** people are streaming it\n"
f"**{stats['scratch2']}** people are using Scratch 2\n"
f"**{stats['scratch1']}** people are using Scratch 1.4\n"
),
color=scratch_orange,
)
)


def setup(bot: interactions.Client):
UtilityCommands(bot)
12 changes: 11 additions & 1 deletion config.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,14 @@
pending_verifiers: dict = {}

# Variable to indicate if the bot is ready
bot_ready = False
bot_ready = False

# Activity statistics
activity_stats = {
"turbowarp": 0,
"streaming_turbowarp": 0,
"scratch3": 0,
"streaming_scratch3": 0,
"scratch2": 0,
"scratch1": 0,
}
63 changes: 62 additions & 1 deletion events/bot_events.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,58 @@
Discord bot events.
"""

from re import match
import interactions
import logging
from interactions.api.events import CommandError

import config
from config import bot, bot_statuses, button_states, bot_ready
from database import add_server

# ------------------------------------------------------------------ #
# Helper functions #
# ------------------------------------------------------------------ #
def classify(activity) -> str | None:
"""Map an activity to a stats key, or None if irrelevant."""
T = interactions.ActivityType
name = activity.name or ""
playing = activity.type == T.PLAYING
streaming = activity.type == T.STREAMING

if name == "TurboWarp Desktop":
return "streaming_turbowarp" if streaming else "turbowarp" if playing else None
if match(r"Scratch 3\.\d+\.\d+", name):
return "streaming_scratch3" if streaming else "scratch3" if playing else None
if playing and name == "Scratch 2 Offline Editor":
return "scratch2"
if playing and match(r"Scratch 1\.4 of \d{2}-[A-Za-z]{3}-\d{2}", name):
return "scratch1"
return None

_presence: dict[int, set[str]] = {} # people currently using Scratch or TurboWarp
_streaming: set[int] = set() # people currently streaming Scratch or TurboWarp
_applied: dict[int, set[str]] = {} # keys currently counted in stats

def _effective(uid: int) -> set[str]:
keys = set(_presence.get(uid, set()))
if uid in _streaming:
for base in ("turbowarp", "scratch3"):
if base in keys:
keys.add(f"streaming_{base}")
return keys

def _refresh(uid: int):
stats = config.activity_stats
new, old = _effective(uid), _applied.get(uid, set())
for k in old - new:
stats[k] -= 1
for k in new - old:
stats[k] += 1
_applied[uid] = new

_user_states: dict[int, set[str]] = {}


class BotEvents(interactions.Extension):
"""Extension for core bot lifecycle events."""
Expand Down Expand Up @@ -45,6 +90,22 @@ async def on_guild_join(self, event: interactions.events.GuildJoin):
if bot_ready:
add_server(event.guild.id)

@interactions.listen(interactions.events.PresenceUpdate)
async def on_presence_update(self, event: interactions.events.PresenceUpdate):
uid = int(event.user.id)
_presence[uid] = {k for a in event.activities if (k := classify(a))}
_refresh(uid)

@interactions.listen(interactions.events.VoiceStateUpdate)
async def on_voice_state_update(self, event: interactions.events.VoiceStateUpdate):
state = event.after or event.before
uid = int(state.member.id)
if event.after and event.after.self_stream:
_streaming.add(uid)
else:
_streaming.discard(uid) # stopped streaming or left voice
_refresh(uid)

# ------------------------------------------------------------------ #
# Component interaction handler (settings buttons) #
# ------------------------------------------------------------------ #
Expand Down Expand Up @@ -109,7 +170,7 @@ async def on_component(self, event: interactions.events.Component):
# ------------------------------------------------------------------ #

@interactions.listen()
async def on_command_error(event: CommandError):
async def on_command_error(self, event: CommandError):
logging.exception(f"Error in command", exc_info=event.error)

try:
Expand Down
Loading