I promise I'm not doing this on purpose (#4565)

* Prep for 0.7.2

* So What di i do here? I done Magic, magic only found in the tales of old.

* turns out formatting is something important

* fixes

* improved Error handling when Global API is enabled

* further improve resuming logic

* more of dat dark voodoo blood magic

* major tweaks to auto restore when auto play is enabled 👀

* fix duplicated "Auto play stated." message + Auto play restart :feelsgoodman:

* missed these

* fix the new duplicated fucking message bitch.

* Let discord handle player reconnects

* eh

* `Requires force install`, utilize new Exponential Backoff object on player and safer reconnect logic, emulating d.py and WL.

* hmmmmm gotta monitor

* mother fucking brackets

* Why didnt i consider this the first time?????????????

* new error code to handle?

* soooooooooooooooo these are import so why arent we ensuring they are set.

* improved logging

* improved logging

* aaaaaaaaaaaaaaa

* We need our own error and special handling to not conflict with dpy

* (Last Known Bug) Fix the infinite loop of 4006 that sometimes could happen as an edge case after a successful resume.

* This will require a force reinstall to install `RLL 0.8.0`, this properly fixes the bug mentioned on the previous commit.

* address "Localtrack names/paths need to be escaped." comment

* address Fixators crash mentioned in #AT

* style

* fix preda's crash mentioned in PR

* add a thing here add a thing there add a thing everywhere

* style

* fixes here, fixes there, and backbone for curated playlist.

* bypass aiohttp and githubs and cloudflare and yo mammas cache

* I propose the new style is no style.

* allow curated playlist to be updated it `[p]playlist update` and show the diff

* fix `[p]summon` not resuming playback until next track.

* Hopefully handle predas rate limits.

* what else did i break now

* Update Lavalink.jar build

* lets try this

* reset the queue

* Bring Edge commits over fix a bunch of shiz again

* Bring Edge commits over fix a bunch of shiz again

* Handle 4014 OPs, Change `skip_votes` key to be an int rather than guild object

* aaaaaaaaaaaaaaa im dumb

* ...

* Simplify some shiz + use a set instead of a list for votes.

Co-authored-by: aikaterna <20862007+aikaterna@users.noreply.github.com>
This commit is contained in:
Draper
2021-04-05 20:02:24 +01:00
committed by GitHub
parent 1199f160d0
commit b7d8b0552e
27 changed files with 890 additions and 113 deletions

View File

@@ -99,10 +99,14 @@ class FormattingUtilities(MixinMeta, metaclass=CompositeMetaClass):
description = _("Please check your console or logs for details.")
return await self.send_embed_msg(ctx, title=msg, description=description)
try:
await lavalink.connect(ctx.author.voice.channel)
await lavalink.connect(
ctx.author.voice.channel,
deafen=await self.config.guild_from_id(ctx.guild.id).auto_deafen(),
)
player = lavalink.get_player(ctx.guild.id)
player.store("connect", datetime.datetime.utcnow())
await self.self_deafen(player)
player.store("channel", ctx.channel.id)
player.store("guild", ctx.guild.id)
except AttributeError:
return await self.send_embed_msg(ctx, title=_("Connect to a voice channel first."))
except IndexError:
@@ -239,24 +243,26 @@ class FormattingUtilities(MixinMeta, metaclass=CompositeMetaClass):
if query.is_local:
search_list += "`{0}.` **{1}**\n[{2}]\n".format(
search_track_num,
track.title,
LocalPath(track.uri, self.local_folder_current_path).to_string_user(),
discord.utils.escape_markdown(track.title),
discord.utils.escape_markdown(
LocalPath(track.uri, self.local_folder_current_path).to_string_user()
),
)
else:
search_list += "`{0}.` **[{1}]({2})**\n".format(
search_track_num, track.title, track.uri
search_track_num, discord.utils.escape_markdown(track.title), track.uri
)
except AttributeError:
track = Query.process_input(track, self.local_folder_current_path)
if track.is_local and command != "search":
search_list += "`{}.` **{}**\n".format(
search_track_num, track.to_string_user()
search_track_num, discord.utils.escape_markdown(track.to_string_user())
)
if track.is_album:
folder = True
else:
search_list += "`{}.` **{}**\n".format(
search_track_num, track.to_string_user()
search_track_num, discord.utils.escape_markdown(track.to_string_user())
)
if hasattr(tracks[0], "uri") and hasattr(tracks[0], "track_identifier"):
title = _("Tracks Found:")

View File

@@ -4,6 +4,7 @@ import logging
from pathlib import Path
from typing import List, Union
import discord
import lavalink
from fuzzywuzzy import process
@@ -121,7 +122,7 @@ class LocalTrackUtilities(MixinMeta, metaclass=CompositeMetaClass):
if percent_match > 85:
search_list.extend(
[
i.to_string_user()
discord.utils.escape_markdown(i.to_string_user())
for i in to_search
if i.local_track_path is not None
and i.local_track_path.name == track_match

View File

@@ -5,14 +5,14 @@ import functools
import json
import logging
import re
import struct
from pathlib import Path
from typing import Any, Final, Mapping, MutableMapping, Pattern, Union, cast
import discord
import lavalink
from discord.embeds import EmptyEmbed
from redbot.core import bank, commands
from redbot.core.commands import Context
from redbot.core.i18n import Translator
@@ -22,7 +22,7 @@ from redbot.core.utils.chat_formatting import humanize_number
from ...apis.playlist_interface import get_all_playlist_for_migration23
from ...utils import PlaylistScope, task_callback
from ..abc import MixinMeta
from ..cog_utils import CompositeMetaClass
from ..cog_utils import CompositeMetaClass, DataReader
log = logging.getLogger("red.cogs.Audio.cog.Utilities.miscellaneous")
_ = Translator("Audio", Path(__file__))
@@ -338,3 +338,47 @@ class MiscellaneousUtilities(MixinMeta, metaclass=CompositeMetaClass):
if database_entries:
await self.api_interface.local_cache_api.lavalink.insert(database_entries)
def decode_track(self, track: str, decode_errors: str = "ignore") -> MutableMapping:
"""
Decodes a base64 track string into an AudioTrack object.
Parameters
----------
track: :class:`str`
The base64 track string.
decode_errors: :class:`str`
The action to take upon encountering erroneous characters within track titles.
Returns
-------
:class:`AudioTrack`
"""
reader = DataReader(track)
flags = (reader.read_int() & 0xC0000000) >> 30
(version,) = (
struct.unpack("B", reader.read_byte()) if flags & 1 != 0 else 1
) # pylint: disable=unused-variable
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() # noqa: F841 pylint: disable=unused-variable
track_object = {
"track": track,
"info": {
"title": title,
"author": author,
"length": length,
"identifier": identifier,
"isStream": is_stream,
"uri": uri,
"isSeekable": not is_stream,
},
}
return track_object

View File

@@ -218,10 +218,7 @@ class PlayerUtilities(MixinMeta, metaclass=CompositeMetaClass):
return
if not await self.config.guild_from_id(guild_id).auto_deafen():
return
channel_id = player.channel.id
node = player.manager.node
voice_ws = node.get_voice_ws(guild_id)
await voice_ws.voice_state(guild_id, channel_id, self_deaf=True)
await player.channel.guild.change_voice_state(channel=player.channel, self_deaf=True)
async def _get_spotify_tracks(
self, ctx: commands.Context, query: Query, forced: bool = False
@@ -646,7 +643,7 @@ class PlayerUtilities(MixinMeta, metaclass=CompositeMetaClass):
lock=self.update_player_lock,
notifier=notifier,
forced=forced,
query_global=await self.config.global_db_enabled(),
query_global=self.global_api_user.get("can_read"),
)
except SpotifyFetchError as error:
self.update_player_lock(ctx, False)
@@ -716,8 +713,10 @@ class PlayerUtilities(MixinMeta, metaclass=CompositeMetaClass):
and player.position == 0
and len(player.queue) == 0
):
await player.move_to(user_channel)
await self.self_deafen(player)
await player.move_to(
user_channel,
deafen=await self.config.guild_from_id(ctx.guild.id).auto_deafen(),
)
return True
else:
return False

View File

@@ -4,14 +4,17 @@ import datetime
import json
import logging
import math
import random
import time
from pathlib import Path
from typing import List, MutableMapping, Optional, Tuple, Union
import aiohttp
import discord
import lavalink
from discord.embeds import EmptyEmbed
from redbot.core import commands
from redbot.core.i18n import Translator
from redbot.core.utils import AsyncIter
@@ -19,7 +22,7 @@ from redbot.core.utils.chat_formatting import box
from redbot.core.utils.menus import start_adding_reactions
from redbot.core.utils.predicates import ReactionPredicate
from ...apis.playlist_interface import Playlist, create_playlist
from ...apis.playlist_interface import Playlist, PlaylistCompat23, create_playlist
from ...audio_dataclasses import _PARTIALLY_SUPPORTED_MUSIC_EXT, Query
from ...audio_logging import debug_exc_log
from ...errors import TooManyMatches, TrackEnqueueError
@@ -29,6 +32,9 @@ from ..cog_utils import CompositeMetaClass
log = logging.getLogger("red.cogs.Audio.cog.Utilities.playlists")
_ = Translator("Audio", Path(__file__))
CURRATED_DATA = (
"https://gist.githubusercontent.com/Drapersniper/cbe10d7053c844f8c69637bb4fd9c5c3/raw/json"
)
class PlaylistUtilities(MixinMeta, metaclass=CompositeMetaClass):
@@ -470,6 +476,18 @@ class PlaylistUtilities(MixinMeta, metaclass=CompositeMetaClass):
async def _maybe_update_playlist(
self, ctx: commands.Context, player: lavalink.player_manager.Player, playlist: Playlist
) -> Tuple[List[lavalink.Track], List[lavalink.Track], Playlist]:
if playlist.id == 42069:
_, updated_tracks = await self._get_bundled_playlist_tracks()
results = {}
old_tracks = playlist.tracks_obj
new_tracks = [lavalink.Track(data=track) for track in updated_tracks]
removed = list(set(old_tracks) - set(new_tracks))
added = list(set(new_tracks) - set(old_tracks))
if removed or added:
await playlist.edit(results)
return added, removed, playlist
if playlist.url is None:
return [], [], playlist
results = {}
@@ -517,10 +535,14 @@ class PlaylistUtilities(MixinMeta, metaclass=CompositeMetaClass):
description=_("I don't have permission to connect to your channel."),
)
return False
await lavalink.connect(ctx.author.voice.channel)
await lavalink.connect(
ctx.author.voice.channel,
deafen=await self.config.guild_from_id(ctx.guild.id).auto_deafen(),
)
player = lavalink.get_player(ctx.guild.id)
player.store("connect", datetime.datetime.utcnow())
await self.self_deafen(player)
player.store("channel", ctx.channel.id)
player.store("guild", ctx.guild.id)
except IndexError:
await self.send_embed_msg(
ctx,
@@ -659,3 +681,50 @@ class PlaylistUtilities(MixinMeta, metaclass=CompositeMetaClass):
return ctx.name if ctx else _("the Server") if the else _("Server")
elif scope == PlaylistScope.USER.value:
return str(ctx) if ctx else _("the User") if the else _("User")
async def _get_bundled_playlist_tracks(self):
async with aiohttp.ClientSession(json_serialize=json.dumps) as session:
async with session.get(
CURRATED_DATA + f"?timestamp={int(time.time())}",
headers={"content-type": "application/json"},
) as response:
if response.status != 200:
return 0, []
try:
data = json.loads(await response.read())
except Exception:
log.exception("Curated playlist couldn't be parsed, report this error.")
data = {}
web_version = data.get("version", 0)
entries = data.get("entries", [])
if entries:
random.shuffle(entries)
tracks = []
async for entry in AsyncIter(entries, steps=25):
with contextlib.suppress(Exception):
tracks.append(self.decode_track(entry))
return web_version, tracks
async def _build_bundled_playlist(self, forced=False):
current_version = await self.config.bundled_playlist_version()
web_version, tracks = await self._get_bundled_playlist_tracks()
if not forced and current_version >= web_version:
return
playlist_data = dict()
playlist_data["name"] = "Aikaterna's curated tracks"
playlist_data["tracks"] = tracks
playlist = await PlaylistCompat23.from_json(
bot=self.bot,
playlist_api=self.playlist_api,
scope=PlaylistScope.GLOBAL.value,
playlist_number=42069,
data=playlist_data,
guild=None,
author=self.bot.user.id,
)
await playlist.save()
await self.config.bundled_playlist_version.set(web_version)
log.info("Curated playlist has been updated.")