Quick wins: Lower default volume to 25% and add file upload support

- Scale volume by 0.25x to prevent earrape (user still sees 0-200%)
  - Add support for direct audio file URL links (.mp3, .mp4, etc.)
  - New =playfile command for Discord file uploads
  - Supports MP3, MP4, WAV, OGG, FLAC, M4A, WEBM, AAC, OPUS formats
This commit is contained in:
2025-11-29 17:02:15 +00:00
parent 125c9e53eb
commit d8952577ad
6 changed files with 930 additions and 359 deletions

View File

@@ -141,6 +141,72 @@ class music(commands.Cog):
await queue.play(ctx)
@commands.command(
help="Upload and play an audio file (MP3, MP4, WAV, etc.)",
aliases=['pf', 'file'])
async def playfile(self, ctx: Context):
"""Play an uploaded audio file from Discord attachment"""
if ctx.guild is None:
await ctx.send("❌ This command must be used in a server!")
return
# Check if there's an attachment
if not ctx.message.attachments:
await ctx.send(
"❌ No file attached! Please upload an audio file with your message.\n"
"**Supported formats:** MP3, MP4, WAV, OGG, FLAC, M4A, WEBM, AAC, OPUS"
)
return
server = ctx.guild.id
attachment = ctx.message.attachments[0]
# Validate file extension
audio_extensions = ('.mp3', '.mp4', '.wav', '.ogg', '.flac', '.m4a', '.webm', '.aac', '.opus')
if not any(attachment.filename.lower().endswith(ext) for ext in audio_extensions):
await ctx.send(
f"❌ Invalid file type: `{attachment.filename}`\n"
f"**Supported formats:** MP3, MP4, WAV, OGG, FLAC, M4A, WEBM, AAC, OPUS"
)
return
await util.join_vc(ctx)
await ctx.message.add_reaction('📎')
msg = await ctx.send(f"Processing file: `{attachment.filename}`...")
# Discord provides a CDN URL for the attachment
file_url = attachment.url
# Use translate to process the file URL (yt-dlp handles direct URLs)
audio = await translate.main(file_url, self.sp)
await msg.delete()
if len(audio) == 0:
await ctx.message.add_reaction('🚫')
await ctx.send("❌ Failed to process the audio file!")
return
# Override title with filename if yt-dlp didn't get a good title
if audio[0]['title'] == 'Unknown' or not audio[0]['title']:
audio[0]['title'] = attachment.filename
# Queue the file
audio[0]['position'] = await queue.add_song(
server,
audio[0],
ctx.author.display_name)
await util.queue_message(ctx, audio[0])
if await queue.is_server_playing(server):
return
await queue.update_server(server, True)
await queue.play(ctx)
@commands.command(
help="Queue a song to play next (top of queue)",
aliases=['pt', 'pn', 'playnext'])
@@ -347,8 +413,9 @@ class music(commands.Cog):
new_vol = await queue.set_volume(server.id, level)
# Update the current playing song's volume if something is playing
# Scale down by 0.25 to match queue.py playback scaling
if ctx.voice_client and ctx.voice_client.source:
ctx.voice_client.source.volume = new_vol / 100.0
ctx.voice_client.source.volume = new_vol / 100.0 * 0.25
# Pick an emoji based on volume
if new_vol == 0:

View File

@@ -497,7 +497,10 @@ async def play(ctx):
return
try:
vol = await get_volume(server_id) / 100.0
# Scale volume down to prevent earrape
# User sees 0-200%, but internally we scale by 0.25
# So user's 100% = 0.25 actual volume (25%)
vol = await get_volume(server_id) / 100.0 * 0.25
fx = await get_effect(server_id)
opts = get_effect_options(fx)

View File

@@ -27,7 +27,7 @@ async def main(url, sp):
#url = url.lower()
# Check if link or search
if url.startswith("https://") is False:
if not url.startswith("https://") and not url.startswith("http://"):
return await search_song(url)
#TODO add better regex or something
@@ -44,7 +44,14 @@ async def main(url, sp):
youtube_song = 'watch?v=' in url or 'youtu.be/' in url
youtube_playlist = 'playlist?list=' in url
if soundcloud_song or youtube_song:
# Check for direct audio/video file URLs
# Supported formats: mp3, mp4, wav, ogg, flac, m4a, webm, aac, opus
audio_extensions = ('.mp3', '.mp4', '.wav', '.ogg', '.flac', '.m4a', '.webm', '.aac', '.opus')
is_direct_file = any(url.lower().endswith(ext) for ext in audio_extensions)
# Also check for URLs with query parameters (e.g., file.mp3?download=true)
is_direct_file = is_direct_file or any(ext in url.lower() for ext in audio_extensions)
if soundcloud_song or youtube_song or is_direct_file:
return await song_download(url)
if youtube_playlist: