Ruby-Cogs/trackdecoder/trackdecoder.py
2025-02-19 22:02:13 -05:00

110 lines
3.2 KiB
Python

from base64 import b64decode
import json
from io import BytesIO
import struct
from types import SimpleNamespace
from redbot.core import checks, commands
from redbot.core.utils.chat_formatting import box
class TrackDecoder(commands.Cog):
"""Decodes a b64 encoded audio track string."""
def __init__(self, bot):
self.bot = bot
async def red_delete_data_for_user(self, **kwargs):
"""Nothing to delete"""
return
@checks.is_owner()
@commands.command()
@commands.guild_only()
async def trackdecode(self, ctx: commands.Context, *, track: str):
"""
Decodes a b64 encoded audio track string.
This command is possible thanks to devoxin#0001's work.
`https://github.com/Devoxin/Lavalink.py`
"""
decoded = self.decode_track(track)
if not decoded:
return await ctx.send(f"Not a valid track.")
msg = (
f"[Title]: {decoded.title}\n"
f"[Author]: {decoded.author}\n"
f"[URL]: {decoded.uri}\n"
f"[Identifier]: {decoded.identifier}\n"
f"[Source]: {decoded.source}\n"
f"[Length]: {decoded.length}\n"
f"[Stream]: {decoded.is_stream}\n"
f"[Position]: {decoded.position}\n"
)
await ctx.send(box(msg, lang="ini"))
@staticmethod
def decode_track(track, decode_errors="ignore"):
"""
Source is derived from:
https://github.com/Devoxin/Lavalink.py/blob/3688fe6aff265ff53928ec811279177a88aa9664/lavalink/utils.py
"""
reader = DataReader(track)
try:
flags = (reader.read_int() & 0xC0000000) >> 30
except struct.error:
return None
(version,) = struct.unpack("B", reader.read_byte()) if flags & 1 != 0 else 1
track = SimpleNamespace(
title=reader.read_utf().decode(errors=decode_errors),
author=reader.read_utf().decode(),
length=reader.read_long(),
identifier=reader.read_utf().decode(),
is_stream=reader.read_boolean(),
uri=reader.read_utf().decode() if reader.read_boolean() else None,
source=reader.read_utf().decode(),
position=reader.read_long(),
)
return track
class DataReader:
"""
Source is from:
https://github.com/Devoxin/Lavalink.py/blob/3688fe6aff265ff53928ec811279177a88aa9664/lavalink/datarw.py
"""
def __init__(self, ts):
self._buf = BytesIO(b64decode(ts))
def _read(self, n):
return self._buf.read(n)
def read_byte(self):
return self._read(1)
def read_boolean(self):
(result,) = struct.unpack("B", self.read_byte())
return result != 0
def read_unsigned_short(self):
(result,) = struct.unpack(">H", self._read(2))
return result
def read_int(self):
(result,) = struct.unpack(">i", self._read(4))
return result
def read_long(self):
(result,) = struct.unpack(">Q", self._read(8))
return result
def read_utf(self):
text_length = self.read_unsigned_short()
return self._read(text_length)