Skip to content

Commit 482f08a

Browse files
committed
Release version 4.1.0
2 parents 721cc6f + d1b7273 commit 482f08a

File tree

9 files changed

+72
-38
lines changed

9 files changed

+72
-38
lines changed

compose.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ services:
2121
OPENAI_BASE_URL: http://localhost:5000/v1
2222
volumes:
2323
- dbot-vol:/app/volume
24+
depends_on:
25+
lavalink:
26+
condition: service_started
2427
restart: unless-stopped
2528

2629
lavalink:

migrations/versions/a29aedea6bce_first_migration.py renamed to migrations/versions/93832be8c5ae_first_migration.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
"""First migration
22
3-
Revision ID: a29aedea6bce
3+
Revision ID: 93832be8c5ae
44
Revises:
5-
Create Date: 2025-02-02 22:16:04.229508
5+
Create Date: 2025-02-04 00:13:49.353166
66
77
"""
88

@@ -12,7 +12,7 @@
1212
from alembic import op
1313

1414
# revision identifiers, used by Alembic.
15-
revision: str = "a29aedea6bce"
15+
revision: str = "93832be8c5ae"
1616
down_revision: Union[str, None] = None
1717
branch_labels: Union[str, Sequence[str], None] = None
1818
depends_on: Union[str, Sequence[str], None] = None
@@ -29,9 +29,9 @@ def upgrade() -> None:
2929
nullable=False,
3030
),
3131
sa.Column("guild_id", sa.Integer(), nullable=False),
32-
sa.Column("guild_name", sa.String(length=100), nullable=False),
32+
sa.Column("guild_name", sa.Unicode(length=100), nullable=False),
3333
sa.Column("bot_channel", sa.Integer(), nullable=True),
34-
sa.Column("welcome_message", sa.String(length=2000), nullable=True),
34+
sa.Column("welcome_message", sa.Unicode(length=2000), nullable=True),
3535
sa.PrimaryKeyConstraint("id", name=op.f("pk_guild")),
3636
sa.UniqueConstraint("guild_id", name=op.f("uq_guild_guild_id")),
3737
)

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "my-discord-bot"
3-
version = "4.0.1"
3+
version = "4.1.0"
44
description = "Discord Bot by Reguna"
55
readme = "README.md"
66
requires-python = ">=3.11"

src/my_discord_bot/bot.py

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
import logging
22
import os
3-
from inspect import getmembers, isclass
43

54
import discord
65
from discord.ext import commands
76
from sqlalchemy import delete, select
87
from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker
98

10-
from . import cogs, models
9+
from .cogs import cog_list
10+
from .models import Guild
1111

1212
logger = logging.getLogger(__name__)
1313

@@ -37,17 +37,17 @@ async def setup_hook(self) -> None:
3737
logger.info(f"Logged in as {self.user.name} ({str(self.user.id)}).")
3838

3939
# Add all cogs
40-
for module in getmembers(cogs, isclass):
40+
for cog in cog_list:
4141
# Disable specific cogs if specific environment variables are not set
42-
if module[1].__name__ == "AI" and not (
42+
if cog.__name__ == "AI" and not (
4343
len(os.getenv("OPENAI_API_KEY", ""))
4444
and len(os.getenv("OPENAI_MODEL_NAME", ""))
4545
):
4646
continue
47-
if module[1].__name__ == "Music" and not len(os.getenv("LAVALINK_URL", "")):
47+
if cog.__name__ == "Music" and not len(os.getenv("LAVALINK_URL", "")):
4848
continue
4949

50-
await self.add_cog(module[1](self, self.sessionmaker))
50+
await self.add_cog(cog(self, self.sessionmaker))
5151

5252
async def on_guild_join(self, guild: discord.Guild) -> None:
5353
"""Called when a Guild is either created by the Client or when the Client joins a guild."""
@@ -58,7 +58,7 @@ async def on_guild_join(self, guild: discord.Guild) -> None:
5858
async with self.sessionmaker() as session:
5959
try:
6060
session.add(
61-
models.Guild(
61+
Guild(
6262
guild_id=guild.id,
6363
guild_name=guild.name,
6464
bot_channel=guild.system_channel.id
@@ -80,19 +80,17 @@ async def on_guild_remove(self, guild: discord.Guild) -> None:
8080
logger.info(f"Left a guild. Guild ID: {guild.id}; Guild Name: {guild.name}")
8181
async with self.sessionmaker() as session:
8282
# Delete removed guild from database
83-
await session.execute(
84-
delete(models.Guild).where(models.Guild.guild_id == guild.id)
85-
)
83+
await session.execute(delete(Guild).where(Guild.guild_id == guild.id))
8684
await session.commit()
8785

8886
async def on_member_join(self, member: discord.Member) -> None:
8987
"""Called when a Member joins a Guild."""
9088

9189
channel = member.guild.system_channel
9290
async with self.sessionmaker() as session:
93-
guild: models.Guild | None = (
91+
guild: Guild | None = (
9492
await session.execute(
95-
select(models.Guild).where(models.Guild.guild_id == member.guild.id)
93+
select(Guild).where(Guild.guild_id == member.guild.id)
9694
)
9795
).scalar()
9896
if not guild:

src/my_discord_bot/cogs/__init__.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,6 @@
44
from .meta import Meta
55
from .music import Music
66

7-
__all__ = ("ErrorHandler", "General", "Meta", "Music", "AI")
7+
cog_list = [ErrorHandler, General, Meta, Music, AI]
8+
9+
__all__ = ("ErrorHandler", "General", "Meta", "Music", "AI", "cog_list")

src/my_discord_bot/cogs/music.py

Lines changed: 40 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -112,9 +112,7 @@ async def leave_inactive_voice_channel_task(self) -> None:
112112

113113
async def check_user_bot_same_channel(self, ia: discord.Interaction) -> bool:
114114
"""Return True if the user is in the same channel as the bot."""
115-
vc: discord.VoiceProtocol = discord.utils.get(
116-
self.bot.voice_clients, guild=ia.guild
117-
)
115+
vc = discord.utils.get(self.bot.voice_clients, guild=ia.guild)
118116
if vc:
119117
channel: discord.VoiceChannel | discord.StageChannel = vc.channel
120118
try:
@@ -124,6 +122,20 @@ async def check_user_bot_same_channel(self, ia: discord.Interaction) -> bool:
124122
else:
125123
return True
126124

125+
async def play_track(
126+
self, player: wavelink.Player, track: wavelink.Playable
127+
) -> None:
128+
"""Play a track. Also handles seeking to a specific start time."""
129+
await player.play(track, end=dict(track.extras)["end"])
130+
if dict(track.extras)["start"] != 0:
131+
# https://github.com/lavalink-devs/youtube-source/issues/97
132+
await player.pause(True)
133+
await asyncio.sleep(1)
134+
await player.pause(False)
135+
await player.seek(dict(track.extras)["start"])
136+
137+
logger.info(f"Playing track: {track.title}")
138+
127139
# UTILITIES END
128140
######################################
129141

@@ -146,7 +158,7 @@ async def on_wavelink_track_start(
146158
for member in payload.player.channel.members:
147159
if not member.bot:
148160
await payload.player.channel.send(
149-
"Now playing *{title}*{looping}!".format(
161+
"Now playing `{title}`{looping}!".format(
150162
title=payload.track.title,
151163
looping=" (looping)"
152164
if payload.player.queue.mode != wavelink.QueueMode.normal
@@ -179,7 +191,7 @@ async def on_wavelink_track_end(
179191
return
180192

181193
await asyncio.sleep(1)
182-
await payload.player.play(track)
194+
await self.play_track(payload.player, track)
183195
else:
184196
logger.error(f"Music playing stopped. Reason: {payload.reason.upper()}")
185197
await payload.player.channel.send(
@@ -198,9 +210,17 @@ async def on_wavelink_track_end(
198210
@discord.app_commands.guild_only()
199211
@discord.app_commands.describe(
200212
youtube_url="URL of the Youtube video you want to play.",
213+
start="Start time of the song in seconds. Default: 0",
214+
end="End time of the song in seconds. Default: None",
201215
)
202216
@check_node_exist
203-
async def play(self, ia: discord.Interaction, youtube_url: str) -> None:
217+
async def play(
218+
self,
219+
ia: discord.Interaction,
220+
youtube_url: str,
221+
start: int = 0,
222+
end: None | int = None,
223+
) -> None:
204224
"""Play a song with the given search query."""
205225

206226
# User must be in a voice channel
@@ -218,6 +238,10 @@ async def play(self, ia: discord.Interaction, youtube_url: str) -> None:
218238
)
219239
return
220240

241+
if end and start >= end:
242+
await ia.response.send_message("Start time must be earlier than end time!")
243+
return
244+
221245
# Delay response, maximum 15 mins
222246
await ia.response.defer()
223247

@@ -245,8 +269,14 @@ async def play(self, ia: discord.Interaction, youtube_url: str) -> None:
245269
)
246270

247271
track = tracks[0]
248-
# Add requester name to track, so that the `queue` command can show it
249-
track.extras = {"requester": ia.user.name}
272+
# Extra information of the track
273+
track.extras = {
274+
# Add requester name to track, so that the `queue` command can show it
275+
"requester": ia.user.name,
276+
# Add start and end time to track (used by the voice player)
277+
"start": start * 1000,
278+
"end": end * 1000 if end is not None else None,
279+
}
250280

251281
await vc.queue.put_wait(track)
252282
await ia.followup.send(
@@ -258,7 +288,8 @@ async def play(self, ia: discord.Interaction, youtube_url: str) -> None:
258288
)
259289
)
260290
if not vc.playing:
261-
await vc.play(vc.queue.get())
291+
track = vc.queue.get()
292+
await self.play_track(vc, track)
262293

263294
@discord.app_commands.command()
264295
@discord.app_commands.guild_only()

src/my_discord_bot/models/_model_base.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
from sqlalchemy.orm import DeclarativeBase, MappedAsDataclass
33

44

5-
class ModelBase(DeclarativeBase, MappedAsDataclass):
5+
class ModelBase(MappedAsDataclass, DeclarativeBase):
66
metadata = MetaData(
77
naming_convention={
88
"ix": "ix_%(column_0_label)s",

src/my_discord_bot/models/guild.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from sqlalchemy import Identity, String
1+
from sqlalchemy import Identity, Unicode
22
from sqlalchemy.orm import Mapped, mapped_column
33

44
from ._model_base import ModelBase
@@ -8,9 +8,9 @@ class Guild(ModelBase):
88
__tablename__ = "guild"
99

1010
id: Mapped[int] = mapped_column(
11-
Identity(always=True, start=1, increment=1), primary_key=True
11+
Identity(always=True, start=1, increment=1), primary_key=True, init=False
1212
)
1313
guild_id: Mapped[int] = mapped_column(unique=True)
14-
guild_name: Mapped[str] = mapped_column(String(100))
15-
bot_channel: Mapped[None | int] = mapped_column()
16-
welcome_message: Mapped[None | str] = mapped_column(String(2000))
14+
guild_name: Mapped[str] = mapped_column(Unicode(100))
15+
bot_channel: Mapped[None | int] = mapped_column(default=None)
16+
welcome_message: Mapped[None | str] = mapped_column(Unicode(2000), default=None)

uv.lock

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)