110 lines
3.2 KiB
Python
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)
|