chore: snapshot 2026-02-08

This commit is contained in:
joelilas
2026-02-08 17:04:57 +01:00
parent 2d19d17d8e
commit 2fd0f622f7
5 changed files with 83 additions and 10 deletions

View File

@@ -23,7 +23,7 @@ A discord music bot that seamlessly streams music from your personal music serve
| `/queue` | View the current queue |
| `/clear` | Clear the current queue |
| `/shuffle` | Shuffles the current queue |
| `/skip` | Skip the current track |
| `/skip [count]` | Skip the current track or `count` tracks |
| `/stop` | Stop playing the current track |
| `/autoplay` | Toggle autoplay |
| `/playlists` | List available playlists |

View File

@@ -76,8 +76,7 @@ class DiscodromeClient(commands.Bot):
async def on_ready(self) -> None:
''' Event called when the client is done preparing. '''
activity = discord.Activity(type=discord.ActivityType.playing, name=env.BOT_STATUS)
await self.change_presence(activity=activity)
await self.set_default_presence()
logger.info(
"Logged as: %s | Connected Guilds: %s | Loaded Extensions: %s",
@@ -87,6 +86,22 @@ class DiscodromeClient(commands.Bot):
)
logger.info("Bot status set to: '%s'", env.BOT_STATUS)
async def set_default_presence(self) -> None:
''' Sets the default bot presence (idle status). '''
activity = discord.Activity(type=discord.ActivityType.playing, name=env.BOT_STATUS)
await self.change_presence(activity=activity)
async def set_now_playing(self, song_title: str, artist: str, cover_url: str = None) -> None:
''' Sets the bot presence to show the currently playing song. '''
activity = discord.Activity(
type=discord.ActivityType.listening,
name=f"{song_title} - {artist}",
large_image=cover_url,
large_text=f"{song_title} - {artist}"
)
await self.change_presence(activity=activity)
logger.debug("Bot presence updated: Listening to '%s - %s'", song_title, artist)
if __name__ == "__main__":
logs.setup_logging()
logger = logging.getLogger(__name__)

View File

@@ -209,6 +209,12 @@ class MusicCog(commands.Cog):
# Add current song back to the queue if exists
player.queue.insert(0, player.current_song)
# Reset bot presence to default
try:
await self.bot.set_default_presence()
except Exception as e:
logger.error(f"Failed to reset bot presence: {e}")
# Display disconnect confirmation
await ui.SysMsg.stopping_queue_playback(interaction)
@@ -269,8 +275,9 @@ class MusicCog(commands.Cog):
await ui.ErrMsg.msg(ctx, f"An unknown error has occurred and has been logged to console. Please contact an administrator. {error}")
@app_commands.command(name="skip", description="Skip the current track")
async def skip(self, interaction: discord.Interaction) -> None:
@app_commands.command(name="skip", description="Skip one or more tracks")
@app_commands.describe(count="Optional number of tracks to skip (>= 1)")
async def skip(self, interaction: discord.Interaction, count: int=None) -> None:
''' Skip the current track '''
# Get the voice client instance
@@ -281,12 +288,17 @@ class MusicCog(commands.Cog):
await ui.ErrMsg.bot_not_in_voice_channel(interaction)
return
# Validate count if provided
if count is not None and count < 1:
await ui.ErrMsg.msg(interaction, "Skip count must be at least 1.")
return
# Check if the bot is playing music
if not voice_client.is_playing():
await ui.ErrMsg.not_playing(interaction)
return
await data.guild_data(interaction.guild_id).player.skip_track(interaction, voice_client)
await data.guild_data(interaction.guild_id).player.skip_track(interaction, voice_client, count=count)
@skip.error
async def skip_error(self, ctx, error):
@@ -463,6 +475,11 @@ class MusicCog(commands.Cog):
player = data.guild_data(member.guild.id).player
player.queue.clear()
player.current_song = None
# Reset bot presence to default
try:
await self.bot.set_default_presence()
except Exception as e:
logger.error(f"Failed to reset bot presence: {e}")
logger.info("The bot has disconnected and cleared the queue as there are no users in the voice channel.")
else:
logger.debug("Bot is no longer alone in voice channel, aborting disconnect...")

View File

@@ -8,7 +8,7 @@ import data
import ui
import logging
from subsonic import Song, APIError, get_random_songs, get_similar_songs, stream, scrobble
from subsonic import Song, APIError, get_random_songs, get_similar_songs, stream, scrobble, get_album_art_url
logger = logging.getLogger(__name__)
@@ -263,6 +263,12 @@ class Player():
song = self.queue.pop(0)
self.current_song = song
await ui.SysMsg.now_playing(interaction, song)
# Update bot presence with now playing info
try:
cover_url = get_album_art_url(song.cover_id)
await interaction.client.set_now_playing(song.title, song.artist, cover_url)
except Exception as e:
logger.error(f"Failed to update bot presence: {e}")
await self.stream_track(interaction, song, voice_client)
else:
logger.debug("Queue is empty.")
@@ -278,10 +284,15 @@ class Player():
return
# If the queue is empty, playback has ended; we should let the user know
await ui.SysMsg.playback_ended(interaction)
# Reset bot presence to default
try:
await interaction.client.set_default_presence()
except Exception as e:
logger.error(f"Failed to reset bot presence: {e}")
async def skip_track(self, interaction: discord.Interaction, voice_client: discord.VoiceClient) -> None:
''' Skips the current track and plays the next one in the queue '''
async def skip_track(self, interaction: discord.Interaction, voice_client: discord.VoiceClient, count: int=None) -> None:
''' Skips the current track and optionally additional tracks from the queue '''
# Check if the bot is connected to a voice channel; it's the caller's responsibility to open a voice channel
if voice_client is None:
@@ -290,8 +301,25 @@ class Player():
logger.debug("Skipping track...")
# Check if the bot is already playing something
if voice_client.is_playing():
# Determine how many tracks to skip in total (current + additional)
total_skips = 1 if count is None or count < 1 else count
# Stop current playback (this counts as 1 skip)
voice_client.stop()
# Remove additional tracks from the front of the queue, if any
additional_to_skip = max(0, total_skips - 1)
if additional_to_skip > 0 and self.queue:
removed = min(additional_to_skip, len(self.queue))
# Slice off the skipped items
self.queue = self.queue[removed:]
logger.debug(f"Skipped {removed} additional track(s) from queue")
# Notify user
if total_skips <= 1:
await ui.SysMsg.skipping(interaction)
else:
await ui.SysMsg.msg(interaction, f"Skipped {total_skips} track{'s' if total_skips != 1 else ''}", ephemeral=True)
else:
await ui.ErrMsg.not_playing(interaction)

View File

@@ -449,6 +449,19 @@ async def get_artist_discography(query: str) -> Album:
return album_list
def get_album_art_url(cover_id: str, size: int=300) -> str:
''' Get the URL for album art from the subsonic API '''
if not cover_id:
return None
params = {
**SUBSONIC_REQUEST_PARAMS,
"id": cover_id,
"size": str(size)
}
query_string = "&".join(f"{k}={v}" for k, v in params.items())
return f"{env.SUBSONIC_SERVER}/rest/getCoverArt?{query_string}"
async def get_album_art_file(cover_id: str, size: int=300) -> str:
''' Request album art from the subsonic API '''
target_path = f"cache/{cover_id}.jpg"