mirror of
https://github.com/Cog-Creators/Red-DiscordBot.git
synced 2025-11-06 11:18:54 -05:00
Audio Fixes (#4492)
* handles #4491 * add typing indicators to audio playlists commands like discussed with aika. * recheck perms upon change of token to avoid needing a reload. * Ensure the player lock is always released... on rewrite to this as a callback to the task. * ffs * resolves#4495 * missed one * aaaaaaaaa * fix https://canary.discord.com/channels/133049272517001216/387398816317440000/766711707921678396 * some tweaks * Clear errors to users around YouTube Quota
This commit is contained in:
parent
335e2a7c25
commit
e31196d19f
@ -3,18 +3,21 @@ import json
|
|||||||
import logging
|
import logging
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
from dataclasses import dataclass, field
|
from dataclasses import dataclass, field
|
||||||
|
from pathlib import Path
|
||||||
from typing import List, MutableMapping, Optional, Union
|
from typing import List, MutableMapping, Optional, Union
|
||||||
|
|
||||||
import discord
|
import discord
|
||||||
import lavalink
|
import lavalink
|
||||||
|
|
||||||
from redbot.core.bot import Red
|
from redbot.core.bot import Red
|
||||||
|
from redbot.core.i18n import Translator
|
||||||
from redbot.core.utils.chat_formatting import humanize_list
|
from redbot.core.utils.chat_formatting import humanize_list
|
||||||
|
|
||||||
from ..errors import InvalidPlaylistScope, MissingAuthor, MissingGuild
|
from ..errors import InvalidPlaylistScope, MissingAuthor, MissingGuild
|
||||||
from ..utils import PlaylistScope
|
from ..utils import PlaylistScope
|
||||||
|
|
||||||
log = logging.getLogger("red.cogs.Audio.api.utils")
|
log = logging.getLogger("red.cogs.Audio.api.utils")
|
||||||
|
_ = Translator("Audio", Path(__file__))
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import json
|
|||||||
import logging
|
import logging
|
||||||
|
|
||||||
from copy import copy
|
from copy import copy
|
||||||
|
from pathlib import Path
|
||||||
from typing import TYPE_CHECKING, Mapping, Optional, Union
|
from typing import TYPE_CHECKING, Mapping, Optional, Union
|
||||||
|
|
||||||
import aiohttp
|
import aiohttp
|
||||||
@ -12,6 +13,7 @@ from lavalink.rest_api import LoadResult
|
|||||||
from redbot.core import Config
|
from redbot.core import Config
|
||||||
from redbot.core.bot import Red
|
from redbot.core.bot import Red
|
||||||
from redbot.core.commands import Cog
|
from redbot.core.commands import Cog
|
||||||
|
from redbot.core.i18n import Translator
|
||||||
|
|
||||||
from ..audio_dataclasses import Query
|
from ..audio_dataclasses import Query
|
||||||
from ..audio_logging import IS_DEBUG, debug_exc_log
|
from ..audio_logging import IS_DEBUG, debug_exc_log
|
||||||
@ -20,7 +22,7 @@ if TYPE_CHECKING:
|
|||||||
from .. import Audio
|
from .. import Audio
|
||||||
|
|
||||||
_API_URL = "https://api.redbot.app/"
|
_API_URL = "https://api.redbot.app/"
|
||||||
|
_ = Translator("Audio", Path(__file__))
|
||||||
log = logging.getLogger("red.cogs.Audio.api.GlobalDB")
|
log = logging.getLogger("red.cogs.Audio.api.GlobalDB")
|
||||||
|
|
||||||
|
|
||||||
@ -38,8 +40,9 @@ class GlobalCacheWrapper:
|
|||||||
self._token: Mapping[str, str] = {}
|
self._token: Mapping[str, str] = {}
|
||||||
self.cog = cog
|
self.cog = cog
|
||||||
|
|
||||||
def update_token(self, new_token: Mapping[str, str]):
|
async def update_token(self, new_token: Mapping[str, str]):
|
||||||
self._token = new_token
|
self._token = new_token
|
||||||
|
await self.get_perms()
|
||||||
|
|
||||||
async def _get_api_key(
|
async def _get_api_key(
|
||||||
self,
|
self,
|
||||||
@ -165,7 +168,6 @@ class GlobalCacheWrapper:
|
|||||||
global_api_user = copy(self.cog.global_api_user)
|
global_api_user = copy(self.cog.global_api_user)
|
||||||
await self._get_api_key()
|
await self._get_api_key()
|
||||||
is_enabled = await self.config.global_db_enabled()
|
is_enabled = await self.config.global_db_enabled()
|
||||||
await self._get_api_key()
|
|
||||||
if (not is_enabled) or self.api_key is None:
|
if (not is_enabled) or self.api_key is None:
|
||||||
return global_api_user
|
return global_api_user
|
||||||
with contextlib.suppress(Exception):
|
with contextlib.suppress(Exception):
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import random
|
|||||||
import time
|
import time
|
||||||
|
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
|
from pathlib import Path
|
||||||
from typing import TYPE_CHECKING, Callable, List, MutableMapping, Optional, Tuple, Union, cast
|
from typing import TYPE_CHECKING, Callable, List, MutableMapping, Optional, Tuple, Union, cast
|
||||||
|
|
||||||
import aiohttp
|
import aiohttp
|
||||||
@ -23,7 +24,7 @@ from redbot.core.utils.dbtools import APSWConnectionWrapper
|
|||||||
|
|
||||||
from ..audio_dataclasses import Query
|
from ..audio_dataclasses import Query
|
||||||
from ..audio_logging import IS_DEBUG, debug_exc_log
|
from ..audio_logging import IS_DEBUG, debug_exc_log
|
||||||
from ..errors import DatabaseError, SpotifyFetchError, TrackEnqueueError
|
from ..errors import DatabaseError, SpotifyFetchError, TrackEnqueueError, YouTubeApiError
|
||||||
from ..utils import CacheLevel, Notifier
|
from ..utils import CacheLevel, Notifier
|
||||||
from .api_utils import LavalinkCacheFetchForGlobalResult
|
from .api_utils import LavalinkCacheFetchForGlobalResult
|
||||||
from .global_db import GlobalCacheWrapper
|
from .global_db import GlobalCacheWrapper
|
||||||
@ -37,7 +38,7 @@ from .youtube import YouTubeWrapper
|
|||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from .. import Audio
|
from .. import Audio
|
||||||
|
|
||||||
_ = Translator("Audio", __file__)
|
_ = Translator("Audio", Path(__file__))
|
||||||
log = logging.getLogger("red.cogs.Audio.api.AudioAPIInterface")
|
log = logging.getLogger("red.cogs.Audio.api.AudioAPIInterface")
|
||||||
_TOP_100_US = "https://www.youtube.com/playlist?list=PL4fGSI1pDJn5rWitrRWFKdm-ulaFiIyoK"
|
_TOP_100_US = "https://www.youtube.com/playlist?list=PL4fGSI1pDJn5rWitrRWFKdm-ulaFiIyoK"
|
||||||
# TODO: Get random from global Cache
|
# TODO: Get random from global Cache
|
||||||
@ -209,6 +210,7 @@ class AudioAPIInterface:
|
|||||||
track_count = 0
|
track_count = 0
|
||||||
time_now = int(datetime.datetime.now(datetime.timezone.utc).timestamp())
|
time_now = int(datetime.datetime.now(datetime.timezone.utc).timestamp())
|
||||||
youtube_cache = CacheLevel.set_youtube().is_subset(current_cache_level)
|
youtube_cache = CacheLevel.set_youtube().is_subset(current_cache_level)
|
||||||
|
youtube_api_error = None
|
||||||
async for track in AsyncIter(tracks):
|
async for track in AsyncIter(tracks):
|
||||||
if isinstance(track, str):
|
if isinstance(track, str):
|
||||||
break
|
break
|
||||||
@ -248,9 +250,13 @@ class AudioAPIInterface:
|
|||||||
debug_exc_log(log, exc, f"Failed to fetch {track_info} from YouTube table")
|
debug_exc_log(log, exc, f"Failed to fetch {track_info} from YouTube table")
|
||||||
|
|
||||||
if val is None:
|
if val is None:
|
||||||
|
try:
|
||||||
val = await self.fetch_youtube_query(
|
val = await self.fetch_youtube_query(
|
||||||
ctx, track_info, current_cache_level=current_cache_level
|
ctx, track_info, current_cache_level=current_cache_level
|
||||||
)
|
)
|
||||||
|
except YouTubeApiError as err:
|
||||||
|
val = None
|
||||||
|
youtube_api_error = err.message
|
||||||
if youtube_cache and val:
|
if youtube_cache and val:
|
||||||
task = ("update", ("youtube", {"track": track_info}))
|
task = ("update", ("youtube", {"track": track_info}))
|
||||||
self.append_task(ctx, *task)
|
self.append_task(ctx, *task)
|
||||||
@ -261,6 +267,13 @@ class AudioAPIInterface:
|
|||||||
track_count += 1
|
track_count += 1
|
||||||
if notifier is not None and ((track_count % 2 == 0) or (track_count == total_tracks)):
|
if notifier is not None and ((track_count % 2 == 0) or (track_count == total_tracks)):
|
||||||
await notifier.notify_user(current=track_count, total=total_tracks, key="youtube")
|
await notifier.notify_user(current=track_count, total=total_tracks, key="youtube")
|
||||||
|
if notifier is not None and youtube_api_error:
|
||||||
|
error_embed = discord.Embed(
|
||||||
|
colour=await ctx.embed_colour(),
|
||||||
|
title=_("Failing to get tracks, skipping remaining."),
|
||||||
|
)
|
||||||
|
await notifier.update_embed(error_embed)
|
||||||
|
break
|
||||||
if CacheLevel.set_spotify().is_subset(current_cache_level):
|
if CacheLevel.set_spotify().is_subset(current_cache_level):
|
||||||
task = ("insert", ("spotify", database_entries))
|
task = ("insert", ("spotify", database_entries))
|
||||||
self.append_task(ctx, *task)
|
self.append_task(ctx, *task)
|
||||||
@ -438,6 +451,7 @@ class AudioAPIInterface:
|
|||||||
global_entry = globaldb_toggle and query_global
|
global_entry = globaldb_toggle and query_global
|
||||||
track_list: List = []
|
track_list: List = []
|
||||||
has_not_allowed = False
|
has_not_allowed = False
|
||||||
|
youtube_api_error = None
|
||||||
try:
|
try:
|
||||||
current_cache_level = CacheLevel(await self.config.cache_level())
|
current_cache_level = CacheLevel(await self.config.cache_level())
|
||||||
guild_data = await self.config.guild(ctx.guild).all()
|
guild_data = await self.config.guild(ctx.guild).all()
|
||||||
@ -461,7 +475,6 @@ class AudioAPIInterface:
|
|||||||
return track_list
|
return track_list
|
||||||
database_entries = []
|
database_entries = []
|
||||||
time_now = int(datetime.datetime.now(datetime.timezone.utc).timestamp())
|
time_now = int(datetime.datetime.now(datetime.timezone.utc).timestamp())
|
||||||
|
|
||||||
youtube_cache = CacheLevel.set_youtube().is_subset(current_cache_level)
|
youtube_cache = CacheLevel.set_youtube().is_subset(current_cache_level)
|
||||||
spotify_cache = CacheLevel.set_spotify().is_subset(current_cache_level)
|
spotify_cache = CacheLevel.set_spotify().is_subset(current_cache_level)
|
||||||
async for track_count, track in AsyncIter(tracks_from_spotify).enumerate(start=1):
|
async for track_count, track in AsyncIter(tracks_from_spotify).enumerate(start=1):
|
||||||
@ -506,9 +519,14 @@ class AudioAPIInterface:
|
|||||||
llresponse = LoadResult(llresponse)
|
llresponse = LoadResult(llresponse)
|
||||||
val = llresponse or None
|
val = llresponse or None
|
||||||
if val is None:
|
if val is None:
|
||||||
|
try:
|
||||||
val = await self.fetch_youtube_query(
|
val = await self.fetch_youtube_query(
|
||||||
ctx, track_info, current_cache_level=current_cache_level
|
ctx, track_info, current_cache_level=current_cache_level
|
||||||
)
|
)
|
||||||
|
except YouTubeApiError as err:
|
||||||
|
val = None
|
||||||
|
youtube_api_error = err.message
|
||||||
|
if not youtube_api_error:
|
||||||
if youtube_cache and val and llresponse is None:
|
if youtube_cache and val and llresponse is None:
|
||||||
task = ("update", ("youtube", {"track": track_info}))
|
task = ("update", ("youtube", {"track": track_info}))
|
||||||
self.append_task(ctx, *task)
|
self.append_task(ctx, *task)
|
||||||
@ -537,7 +555,9 @@ class AudioAPIInterface:
|
|||||||
lock(ctx, False)
|
lock(ctx, False)
|
||||||
error_embed = discord.Embed(
|
error_embed = discord.Embed(
|
||||||
colour=await ctx.embed_colour(),
|
colour=await ctx.embed_colour(),
|
||||||
title=_("The connection was reset while loading the playlist."),
|
title=_(
|
||||||
|
"The connection was reset while loading the playlist."
|
||||||
|
),
|
||||||
)
|
)
|
||||||
if notifier is not None:
|
if notifier is not None:
|
||||||
await notifier.update_embed(error_embed)
|
await notifier.update_embed(error_embed)
|
||||||
@ -554,6 +574,8 @@ class AudioAPIInterface:
|
|||||||
track_object = result.tracks
|
track_object = result.tracks
|
||||||
else:
|
else:
|
||||||
track_object = []
|
track_object = []
|
||||||
|
else:
|
||||||
|
track_object = []
|
||||||
if (track_count % 2 == 0) or (track_count == total_tracks):
|
if (track_count % 2 == 0) or (track_count == total_tracks):
|
||||||
key = "lavalink"
|
key = "lavalink"
|
||||||
seconds = "???"
|
seconds = "???"
|
||||||
@ -567,13 +589,16 @@ class AudioAPIInterface:
|
|||||||
seconds=seconds,
|
seconds=seconds,
|
||||||
)
|
)
|
||||||
|
|
||||||
if consecutive_fails >= (100 if global_entry else 10):
|
if youtube_api_error or consecutive_fails >= (20 if global_entry else 10):
|
||||||
error_embed = discord.Embed(
|
error_embed = discord.Embed(
|
||||||
colour=await ctx.embed_colour(),
|
colour=await ctx.embed_colour(),
|
||||||
title=_("Failing to get tracks, skipping remaining."),
|
title=_("Failing to get tracks, skipping remaining."),
|
||||||
)
|
)
|
||||||
if notifier is not None:
|
if notifier is not None:
|
||||||
await notifier.update_embed(error_embed)
|
await notifier.update_embed(error_embed)
|
||||||
|
if youtube_api_error:
|
||||||
|
lock(ctx, False)
|
||||||
|
raise SpotifyFetchError(message=youtube_api_error)
|
||||||
break
|
break
|
||||||
if not track_object:
|
if not track_object:
|
||||||
consecutive_fails += 1
|
consecutive_fails += 1
|
||||||
@ -631,16 +656,6 @@ class AudioAPIInterface:
|
|||||||
|
|
||||||
if not player.current:
|
if not player.current:
|
||||||
await player.play()
|
await player.play()
|
||||||
if not track_list and not has_not_allowed:
|
|
||||||
raise SpotifyFetchError(
|
|
||||||
message=_(
|
|
||||||
"Nothing found.\nThe YouTube API key may be invalid "
|
|
||||||
"or you may be rate limited on YouTube's search service.\n"
|
|
||||||
"Check the YouTube API key again and follow the instructions "
|
|
||||||
"at `{prefix}audioset youtubeapi`."
|
|
||||||
)
|
|
||||||
)
|
|
||||||
player.maybe_shuffle()
|
|
||||||
if enqueue and tracks_from_spotify:
|
if enqueue and tracks_from_spotify:
|
||||||
if total_tracks > enqueued_tracks:
|
if total_tracks > enqueued_tracks:
|
||||||
maxlength_msg = _(" {bad_tracks} tracks cannot be queued.").format(
|
maxlength_msg = _(" {bad_tracks} tracks cannot be queued.").format(
|
||||||
@ -667,6 +682,16 @@ class AudioAPIInterface:
|
|||||||
if notifier is not None:
|
if notifier is not None:
|
||||||
await notifier.update_embed(embed)
|
await notifier.update_embed(embed)
|
||||||
lock(ctx, False)
|
lock(ctx, False)
|
||||||
|
if not track_list and not has_not_allowed:
|
||||||
|
raise SpotifyFetchError(
|
||||||
|
message=_(
|
||||||
|
"Nothing found.\nThe YouTube API key may be invalid "
|
||||||
|
"or you may be rate limited on YouTube's search service.\n"
|
||||||
|
"Check the YouTube API key again and follow the instructions "
|
||||||
|
"at `{prefix}audioset youtubeapi`."
|
||||||
|
)
|
||||||
|
)
|
||||||
|
player.maybe_shuffle()
|
||||||
|
|
||||||
if spotify_cache:
|
if spotify_cache:
|
||||||
task = ("insert", ("spotify", database_entries))
|
task = ("insert", ("spotify", database_entries))
|
||||||
@ -718,9 +743,12 @@ class AudioAPIInterface:
|
|||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
debug_exc_log(log, exc, f"Failed to fetch {track_info} from YouTube table")
|
debug_exc_log(log, exc, f"Failed to fetch {track_info} from YouTube table")
|
||||||
if val is None:
|
if val is None:
|
||||||
|
try:
|
||||||
youtube_url = await self.fetch_youtube_query(
|
youtube_url = await self.fetch_youtube_query(
|
||||||
ctx, track_info, current_cache_level=current_cache_level
|
ctx, track_info, current_cache_level=current_cache_level
|
||||||
)
|
)
|
||||||
|
except YouTubeApiError as err:
|
||||||
|
youtube_url = None
|
||||||
else:
|
else:
|
||||||
if cache_enabled:
|
if cache_enabled:
|
||||||
task = ("update", ("youtube", {"track": track_info}))
|
task = ("update", ("youtube", {"track": track_info}))
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import datetime
|
|||||||
import logging
|
import logging
|
||||||
import random
|
import random
|
||||||
import time
|
import time
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
from types import SimpleNamespace
|
from types import SimpleNamespace
|
||||||
from typing import TYPE_CHECKING, Callable, List, MutableMapping, Optional, Tuple, Union
|
from typing import TYPE_CHECKING, Callable, List, MutableMapping, Optional, Tuple, Union
|
||||||
@ -11,6 +12,7 @@ from typing import TYPE_CHECKING, Callable, List, MutableMapping, Optional, Tupl
|
|||||||
from redbot.core import Config
|
from redbot.core import Config
|
||||||
from redbot.core.bot import Red
|
from redbot.core.bot import Red
|
||||||
from redbot.core.commands import Cog
|
from redbot.core.commands import Cog
|
||||||
|
from redbot.core.i18n import Translator
|
||||||
from redbot.core.utils import AsyncIter
|
from redbot.core.utils import AsyncIter
|
||||||
from redbot.core.utils.dbtools import APSWConnectionWrapper
|
from redbot.core.utils.dbtools import APSWConnectionWrapper
|
||||||
|
|
||||||
@ -59,7 +61,7 @@ if TYPE_CHECKING:
|
|||||||
|
|
||||||
|
|
||||||
log = logging.getLogger("red.cogs.Audio.api.LocalDB")
|
log = logging.getLogger("red.cogs.Audio.api.LocalDB")
|
||||||
|
_ = Translator("Audio", Path(__file__))
|
||||||
_SCHEMA_VERSION = 3
|
_SCHEMA_VERSION = 3
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import concurrent
|
|||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
import time
|
import time
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
from types import SimpleNamespace
|
from types import SimpleNamespace
|
||||||
from typing import TYPE_CHECKING, List, Union
|
from typing import TYPE_CHECKING, List, Union
|
||||||
@ -11,6 +12,7 @@ import lavalink
|
|||||||
from redbot.core import Config
|
from redbot.core import Config
|
||||||
from redbot.core.bot import Red
|
from redbot.core.bot import Red
|
||||||
from redbot.core.commands import Cog
|
from redbot.core.commands import Cog
|
||||||
|
from redbot.core.i18n import Translator
|
||||||
from redbot.core.utils import AsyncIter
|
from redbot.core.utils import AsyncIter
|
||||||
from redbot.core.utils.dbtools import APSWConnectionWrapper
|
from redbot.core.utils.dbtools import APSWConnectionWrapper
|
||||||
|
|
||||||
@ -33,6 +35,7 @@ from ..sql_statements import (
|
|||||||
from .api_utils import QueueFetchResult
|
from .api_utils import QueueFetchResult
|
||||||
|
|
||||||
log = logging.getLogger("red.cogs.Audio.api.PersistQueueWrapper")
|
log = logging.getLogger("red.cogs.Audio.api.PersistQueueWrapper")
|
||||||
|
_ = Translator("Audio", Path(__file__))
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from .. import Audio
|
from .. import Audio
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
import logging
|
import logging
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
from typing import List, MutableMapping, Optional, Union
|
from typing import List, MutableMapping, Optional, Union
|
||||||
|
|
||||||
@ -7,6 +8,7 @@ import lavalink
|
|||||||
|
|
||||||
from redbot.core import Config, commands
|
from redbot.core import Config, commands
|
||||||
from redbot.core.bot import Red
|
from redbot.core.bot import Red
|
||||||
|
from redbot.core.i18n import Translator
|
||||||
from redbot.core.utils import AsyncIter
|
from redbot.core.utils import AsyncIter
|
||||||
|
|
||||||
from ..errors import NotAllowed
|
from ..errors import NotAllowed
|
||||||
@ -15,6 +17,7 @@ from .api_utils import PlaylistFetchResult, prepare_config_scope, standardize_sc
|
|||||||
from .playlist_wrapper import PlaylistWrapper
|
from .playlist_wrapper import PlaylistWrapper
|
||||||
|
|
||||||
log = logging.getLogger("red.cogs.Audio.api.PlaylistsInterface")
|
log = logging.getLogger("red.cogs.Audio.api.PlaylistsInterface")
|
||||||
|
_ = Translator("Audio", Path(__file__))
|
||||||
|
|
||||||
|
|
||||||
class Playlist:
|
class Playlist:
|
||||||
|
|||||||
@ -1,12 +1,14 @@
|
|||||||
import concurrent
|
import concurrent
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
from types import SimpleNamespace
|
from types import SimpleNamespace
|
||||||
from typing import List, MutableMapping, Optional
|
from typing import List, MutableMapping, Optional
|
||||||
|
|
||||||
from redbot.core import Config
|
from redbot.core import Config
|
||||||
from redbot.core.bot import Red
|
from redbot.core.bot import Red
|
||||||
|
from redbot.core.i18n import Translator
|
||||||
from redbot.core.utils import AsyncIter
|
from redbot.core.utils import AsyncIter
|
||||||
from redbot.core.utils.dbtools import APSWConnectionWrapper
|
from redbot.core.utils.dbtools import APSWConnectionWrapper
|
||||||
|
|
||||||
@ -33,6 +35,7 @@ from ..utils import PlaylistScope
|
|||||||
from .api_utils import PlaylistFetchResult
|
from .api_utils import PlaylistFetchResult
|
||||||
|
|
||||||
log = logging.getLogger("red.cogs.Audio.api.Playlists")
|
log = logging.getLogger("red.cogs.Audio.api.Playlists")
|
||||||
|
_ = Translator("Audio", Path(__file__))
|
||||||
|
|
||||||
|
|
||||||
class PlaylistWrapper:
|
class PlaylistWrapper:
|
||||||
|
|||||||
@ -3,6 +3,7 @@ import contextlib
|
|||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
import time
|
import time
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
from typing import TYPE_CHECKING, List, Mapping, MutableMapping, Optional, Tuple, Union
|
from typing import TYPE_CHECKING, List, Mapping, MutableMapping, Optional, Tuple, Union
|
||||||
|
|
||||||
@ -19,7 +20,7 @@ from ..errors import SpotifyFetchError
|
|||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from .. import Audio
|
from .. import Audio
|
||||||
|
|
||||||
_ = Translator("Audio", __file__)
|
_ = Translator("Audio", Path(__file__))
|
||||||
|
|
||||||
log = logging.getLogger("red.cogs.Audio.api.Spotify")
|
log = logging.getLogger("red.cogs.Audio.api.Spotify")
|
||||||
|
|
||||||
@ -104,7 +105,7 @@ class SpotifyWrapper:
|
|||||||
log.debug(f"Issue making GET request to {url}: [{r.status}] {data}")
|
log.debug(f"Issue making GET request to {url}: [{r.status}] {data}")
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def update_token(self, new_token: Mapping[str, str]):
|
async def update_token(self, new_token: Mapping[str, str]):
|
||||||
self._token = new_token
|
self._token = new_token
|
||||||
|
|
||||||
async def get_token(self) -> None:
|
async def get_token(self) -> None:
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
from typing import TYPE_CHECKING, Mapping, Optional, Union
|
from typing import TYPE_CHECKING, Mapping, Optional, Union
|
||||||
|
|
||||||
@ -8,6 +9,7 @@ import aiohttp
|
|||||||
from redbot.core import Config
|
from redbot.core import Config
|
||||||
from redbot.core.bot import Red
|
from redbot.core.bot import Red
|
||||||
from redbot.core.commands import Cog
|
from redbot.core.commands import Cog
|
||||||
|
from redbot.core.i18n import Translator
|
||||||
|
|
||||||
from ..errors import YouTubeApiError
|
from ..errors import YouTubeApiError
|
||||||
|
|
||||||
@ -15,7 +17,7 @@ if TYPE_CHECKING:
|
|||||||
from .. import Audio
|
from .. import Audio
|
||||||
|
|
||||||
log = logging.getLogger("red.cogs.Audio.api.YouTube")
|
log = logging.getLogger("red.cogs.Audio.api.YouTube")
|
||||||
|
_ = Translator("Audio", Path(__file__))
|
||||||
SEARCH_ENDPOINT = "https://www.googleapis.com/youtube/v3/search"
|
SEARCH_ENDPOINT = "https://www.googleapis.com/youtube/v3/search"
|
||||||
|
|
||||||
|
|
||||||
@ -32,7 +34,7 @@ class YouTubeWrapper:
|
|||||||
self._token: Mapping[str, str] = {}
|
self._token: Mapping[str, str] = {}
|
||||||
self.cog = cog
|
self.cog = cog
|
||||||
|
|
||||||
def update_token(self, new_token: Mapping[str, str]):
|
async def update_token(self, new_token: Mapping[str, str]):
|
||||||
self._token = new_token
|
self._token = new_token
|
||||||
|
|
||||||
async def _get_api_key(
|
async def _get_api_key(
|
||||||
@ -54,11 +56,28 @@ class YouTubeWrapper:
|
|||||||
"type": "video",
|
"type": "video",
|
||||||
}
|
}
|
||||||
async with self.session.request("GET", SEARCH_ENDPOINT, params=params) as r:
|
async with self.session.request("GET", SEARCH_ENDPOINT, params=params) as r:
|
||||||
if r.status in [400, 404]:
|
if r.status == 400:
|
||||||
|
if r.reason == "Bad Request":
|
||||||
|
raise YouTubeApiError(
|
||||||
|
_(
|
||||||
|
"Your YouTube Data API token is invalid.\n"
|
||||||
|
"Check the YouTube API key again and follow the instructions "
|
||||||
|
"at `{prefix}audioset youtubeapi`."
|
||||||
|
)
|
||||||
|
)
|
||||||
return None
|
return None
|
||||||
elif r.status in [403, 429]:
|
elif r.status == 404:
|
||||||
if r.reason == "quotaExceeded":
|
return None
|
||||||
raise YouTubeApiError("Your YouTube Data API quota has been reached.")
|
elif r.status == 403:
|
||||||
|
if r.reason in ["Forbidden", "quotaExceeded"]:
|
||||||
|
raise YouTubeApiError(
|
||||||
|
_(
|
||||||
|
"YouTube API error code: 403\nYour YouTube API key may have "
|
||||||
|
"reached the account's query limit for today. Please check "
|
||||||
|
"<https://developers.google.com/youtube/v3/getting-started#quota> "
|
||||||
|
"for more information."
|
||||||
|
)
|
||||||
|
)
|
||||||
return None
|
return None
|
||||||
else:
|
else:
|
||||||
search_response = await r.json(loads=json.loads)
|
search_response = await r.json(loads=json.loads)
|
||||||
|
|||||||
@ -22,8 +22,11 @@ from urllib.parse import urlparse
|
|||||||
|
|
||||||
import lavalink
|
import lavalink
|
||||||
|
|
||||||
|
from redbot.core.i18n import Translator
|
||||||
from redbot.core.utils import AsyncIter
|
from redbot.core.utils import AsyncIter
|
||||||
|
|
||||||
|
_ = Translator("Audio", Path(__file__))
|
||||||
|
|
||||||
_RE_REMOVE_START: Final[Pattern] = re.compile(r"^(sc|list) ")
|
_RE_REMOVE_START: Final[Pattern] = re.compile(r"^(sc|list) ")
|
||||||
_RE_YOUTUBE_TIMESTAMP: Final[Pattern] = re.compile(r"[&|?]t=(\d+)s?")
|
_RE_YOUTUBE_TIMESTAMP: Final[Pattern] = re.compile(r"[&|?]t=(\d+)s?")
|
||||||
_RE_YOUTUBE_INDEX: Final[Pattern] = re.compile(r"&index=(\d+)")
|
_RE_YOUTUBE_INDEX: Final[Pattern] = re.compile(r"&index=(\d+)")
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import argparse
|
import argparse
|
||||||
import functools
|
import functools
|
||||||
import re
|
import re
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
from typing import Final, MutableMapping, Optional, Pattern, Tuple, Union
|
from typing import Final, MutableMapping, Optional, Pattern, Tuple, Union
|
||||||
|
|
||||||
@ -16,7 +17,7 @@ from .apis.playlist_interface import get_all_playlist_converter
|
|||||||
from .errors import NoMatchesFound, TooManyMatches
|
from .errors import NoMatchesFound, TooManyMatches
|
||||||
from .utils import PlaylistScope
|
from .utils import PlaylistScope
|
||||||
|
|
||||||
_ = Translator("Audio", __file__)
|
_ = Translator("Audio", Path(__file__))
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
"ComplexScopeParser",
|
"ComplexScopeParser",
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import asyncio
|
|||||||
import json
|
import json
|
||||||
|
|
||||||
from collections import Counter
|
from collections import Counter
|
||||||
|
from pathlib import Path
|
||||||
from typing import Mapping
|
from typing import Mapping
|
||||||
|
|
||||||
import aiohttp
|
import aiohttp
|
||||||
@ -11,11 +12,13 @@ from redbot.core import Config
|
|||||||
from redbot.core.bot import Red
|
from redbot.core.bot import Red
|
||||||
from redbot.core.commands import Cog
|
from redbot.core.commands import Cog
|
||||||
from redbot.core.data_manager import cog_data_path
|
from redbot.core.data_manager import cog_data_path
|
||||||
from redbot.core.i18n import cog_i18n
|
from redbot.core.i18n import Translator, cog_i18n
|
||||||
|
|
||||||
from ..utils import PlaylistScope
|
from ..utils import PlaylistScope
|
||||||
from . import abc, cog_utils, commands, events, tasks, utilities
|
from . import abc, cog_utils, commands, events, tasks, utilities
|
||||||
from .cog_utils import CompositeMetaClass, _
|
from .cog_utils import CompositeMetaClass
|
||||||
|
|
||||||
|
_ = Translator("Audio", Path(__file__))
|
||||||
|
|
||||||
|
|
||||||
@cog_i18n(_)
|
@cog_i18n(_)
|
||||||
|
|||||||
@ -1,10 +1,8 @@
|
|||||||
from abc import ABC
|
from abc import ABC
|
||||||
from pathlib import Path
|
|
||||||
from typing import Final
|
from typing import Final
|
||||||
|
|
||||||
from redbot import VersionInfo
|
from redbot import VersionInfo
|
||||||
from redbot.core import commands
|
from redbot.core import commands
|
||||||
from redbot.core.i18n import Translator
|
|
||||||
|
|
||||||
from ..converters import get_lazy_converter, get_playlist_converter
|
from ..converters import get_lazy_converter, get_playlist_converter
|
||||||
|
|
||||||
@ -12,7 +10,6 @@ __version__ = VersionInfo.from_json({"major": 2, "minor": 3, "micro": 0, "releas
|
|||||||
|
|
||||||
__author__ = ["aikaterna", "Draper"]
|
__author__ = ["aikaterna", "Draper"]
|
||||||
|
|
||||||
_ = Translator("Audio", Path(__file__).parent)
|
|
||||||
_SCHEMA_VERSION: Final[int] = 3
|
_SCHEMA_VERSION: Final[int] = 3
|
||||||
_OWNER_NOTIFICATION: Final[int] = 1
|
_OWNER_NOTIFICATION: Final[int] = 1
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import asyncio
|
import asyncio
|
||||||
import contextlib
|
import contextlib
|
||||||
import logging
|
import logging
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
from typing import Union
|
from typing import Union
|
||||||
|
|
||||||
@ -9,6 +10,7 @@ import lavalink
|
|||||||
|
|
||||||
from redbot.core import bank, commands
|
from redbot.core import bank, commands
|
||||||
from redbot.core.data_manager import cog_data_path
|
from redbot.core.data_manager import cog_data_path
|
||||||
|
from redbot.core.i18n import Translator
|
||||||
from redbot.core.utils.chat_formatting import box, humanize_number
|
from redbot.core.utils.chat_formatting import box, humanize_number
|
||||||
from redbot.core.utils.menus import DEFAULT_CONTROLS, menu, start_adding_reactions
|
from redbot.core.utils.menus import DEFAULT_CONTROLS, menu, start_adding_reactions
|
||||||
from redbot.core.utils.predicates import MessagePredicate, ReactionPredicate
|
from redbot.core.utils.predicates import MessagePredicate, ReactionPredicate
|
||||||
@ -18,10 +20,12 @@ from ...converters import ScopeParser
|
|||||||
from ...errors import MissingGuild, TooManyMatches
|
from ...errors import MissingGuild, TooManyMatches
|
||||||
from ...utils import CacheLevel, PlaylistScope
|
from ...utils import CacheLevel, PlaylistScope
|
||||||
from ..abc import MixinMeta
|
from ..abc import MixinMeta
|
||||||
from ..cog_utils import CompositeMetaClass, PlaylistConverter, _, __version__
|
from ..cog_utils import CompositeMetaClass, PlaylistConverter, __version__
|
||||||
|
|
||||||
log = logging.getLogger("red.cogs.Audio.cog.Commands.audioset")
|
log = logging.getLogger("red.cogs.Audio.cog.Commands.audioset")
|
||||||
|
|
||||||
|
_ = Translator("Audio", Path(__file__))
|
||||||
|
|
||||||
|
|
||||||
class AudioSetCommands(MixinMeta, metaclass=CompositeMetaClass):
|
class AudioSetCommands(MixinMeta, metaclass=CompositeMetaClass):
|
||||||
@commands.group(name="audioset")
|
@commands.group(name="audioset")
|
||||||
@ -1378,7 +1382,7 @@ class AudioSetCommands(MixinMeta, metaclass=CompositeMetaClass):
|
|||||||
async def command_audioset_audiodb_toggle(self, ctx: commands.Context):
|
async def command_audioset_audiodb_toggle(self, ctx: commands.Context):
|
||||||
"""Toggle the server settings.
|
"""Toggle the server settings.
|
||||||
|
|
||||||
Default is ON
|
Default is OFF
|
||||||
"""
|
"""
|
||||||
state = await self.config.global_db_enabled()
|
state = await self.config.global_db_enabled()
|
||||||
await self.config.global_db_enabled.set(not state)
|
await self.config.global_db_enabled.set(not state)
|
||||||
|
|||||||
@ -3,6 +3,7 @@ import contextlib
|
|||||||
import datetime
|
import datetime
|
||||||
import logging
|
import logging
|
||||||
import time
|
import time
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
from typing import Optional, Union
|
from typing import Optional, Union
|
||||||
|
|
||||||
@ -10,15 +11,17 @@ import discord
|
|||||||
import lavalink
|
import lavalink
|
||||||
|
|
||||||
from redbot.core import commands
|
from redbot.core import commands
|
||||||
|
from redbot.core.i18n import Translator
|
||||||
from redbot.core.utils import AsyncIter
|
from redbot.core.utils import AsyncIter
|
||||||
from redbot.core.utils.chat_formatting import humanize_number
|
from redbot.core.utils.chat_formatting import humanize_number
|
||||||
from redbot.core.utils.menus import start_adding_reactions
|
from redbot.core.utils.menus import start_adding_reactions
|
||||||
from redbot.core.utils.predicates import ReactionPredicate
|
from redbot.core.utils.predicates import ReactionPredicate
|
||||||
|
|
||||||
from ..abc import MixinMeta
|
from ..abc import MixinMeta
|
||||||
from ..cog_utils import CompositeMetaClass, _
|
from ..cog_utils import CompositeMetaClass
|
||||||
|
|
||||||
log = logging.getLogger("red.cogs.Audio.cog.Commands.player_controller")
|
log = logging.getLogger("red.cogs.Audio.cog.Commands.player_controller")
|
||||||
|
_ = Translator("Audio", Path(__file__))
|
||||||
|
|
||||||
|
|
||||||
class PlayerControllerCommands(MixinMeta, metaclass=CompositeMetaClass):
|
class PlayerControllerCommands(MixinMeta, metaclass=CompositeMetaClass):
|
||||||
@ -98,9 +101,8 @@ class PlayerControllerCommands(MixinMeta, metaclass=CompositeMetaClass):
|
|||||||
await self.get_track_description(player.current, self.local_folder_current_path)
|
await self.get_track_description(player.current, self.local_folder_current_path)
|
||||||
or ""
|
or ""
|
||||||
)
|
)
|
||||||
song += _("\n Requested by: **{track.requester}**")
|
song += _("\n Requested by: **{track.requester}**").format(track=player.current)
|
||||||
song += "\n\n{arrow}`{pos}`/`{dur}`"
|
song += "\n\n{arrow}`{pos}`/`{dur}`".format(arrow=arrow, pos=pos, dur=dur)
|
||||||
song = song.format(track=player.current, arrow=arrow, pos=pos, dur=dur)
|
|
||||||
else:
|
else:
|
||||||
song = _("Nothing.")
|
song = _("Nothing.")
|
||||||
|
|
||||||
|
|||||||
@ -2,20 +2,23 @@ import asyncio
|
|||||||
import contextlib
|
import contextlib
|
||||||
import logging
|
import logging
|
||||||
import re
|
import re
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
import discord
|
import discord
|
||||||
import lavalink
|
import lavalink
|
||||||
|
|
||||||
from redbot.core import commands
|
from redbot.core import commands
|
||||||
|
from redbot.core.i18n import Translator
|
||||||
from redbot.core.utils.chat_formatting import box, humanize_number, pagify
|
from redbot.core.utils.chat_formatting import box, humanize_number, pagify
|
||||||
from redbot.core.utils.menus import DEFAULT_CONTROLS, menu, start_adding_reactions
|
from redbot.core.utils.menus import DEFAULT_CONTROLS, menu, start_adding_reactions
|
||||||
from redbot.core.utils.predicates import MessagePredicate, ReactionPredicate
|
from redbot.core.utils.predicates import MessagePredicate, ReactionPredicate
|
||||||
|
|
||||||
from ...equalizer import Equalizer
|
from ...equalizer import Equalizer
|
||||||
from ..abc import MixinMeta
|
from ..abc import MixinMeta
|
||||||
from ..cog_utils import CompositeMetaClass, _
|
from ..cog_utils import CompositeMetaClass
|
||||||
|
|
||||||
log = logging.getLogger("red.cogs.Audio.cog.Commands.equalizer")
|
log = logging.getLogger("red.cogs.Audio.cog.Commands.equalizer")
|
||||||
|
_ = Translator("Audio", Path(__file__))
|
||||||
|
|
||||||
|
|
||||||
class EqualizerCommands(MixinMeta, metaclass=CompositeMetaClass):
|
class EqualizerCommands(MixinMeta, metaclass=CompositeMetaClass):
|
||||||
|
|||||||
@ -4,11 +4,13 @@ from pathlib import Path
|
|||||||
import discord
|
import discord
|
||||||
|
|
||||||
from redbot.core import commands
|
from redbot.core import commands
|
||||||
|
from redbot.core.i18n import Translator
|
||||||
|
|
||||||
from ..abc import MixinMeta
|
from ..abc import MixinMeta
|
||||||
from ..cog_utils import CompositeMetaClass, _
|
from ..cog_utils import CompositeMetaClass
|
||||||
|
|
||||||
log = logging.getLogger("red.cogs.Audio.cog.Commands.lavalink_setup")
|
log = logging.getLogger("red.cogs.Audio.cog.Commands.lavalink_setup")
|
||||||
|
_ = Translator("Audio", Path(__file__))
|
||||||
|
|
||||||
|
|
||||||
class LavalinkSetupCommands(MixinMeta, metaclass=CompositeMetaClass):
|
class LavalinkSetupCommands(MixinMeta, metaclass=CompositeMetaClass):
|
||||||
|
|||||||
@ -7,13 +7,15 @@ from typing import MutableMapping
|
|||||||
import discord
|
import discord
|
||||||
|
|
||||||
from redbot.core import commands
|
from redbot.core import commands
|
||||||
|
from redbot.core.i18n import Translator
|
||||||
from redbot.core.utils.menus import DEFAULT_CONTROLS, close_menu, menu, next_page, prev_page
|
from redbot.core.utils.menus import DEFAULT_CONTROLS, close_menu, menu, next_page, prev_page
|
||||||
|
|
||||||
from ...audio_dataclasses import LocalPath, Query
|
from ...audio_dataclasses import LocalPath, Query
|
||||||
from ..abc import MixinMeta
|
from ..abc import MixinMeta
|
||||||
from ..cog_utils import CompositeMetaClass, _
|
from ..cog_utils import CompositeMetaClass
|
||||||
|
|
||||||
log = logging.getLogger("red.cogs.Audio.cog.Commands.local_track")
|
log = logging.getLogger("red.cogs.Audio.cog.Commands.local_track")
|
||||||
|
_ = Translator("Audio", Path(__file__))
|
||||||
|
|
||||||
|
|
||||||
class LocalTrackCommands(MixinMeta, metaclass=CompositeMetaClass):
|
class LocalTrackCommands(MixinMeta, metaclass=CompositeMetaClass):
|
||||||
|
|||||||
@ -3,19 +3,22 @@ import heapq
|
|||||||
import logging
|
import logging
|
||||||
import math
|
import math
|
||||||
import random
|
import random
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
import discord
|
import discord
|
||||||
import lavalink
|
import lavalink
|
||||||
|
|
||||||
from redbot.core import commands
|
from redbot.core import commands
|
||||||
|
from redbot.core.i18n import Translator
|
||||||
from redbot.core.utils import AsyncIter
|
from redbot.core.utils import AsyncIter
|
||||||
from redbot.core.utils.chat_formatting import humanize_number, pagify
|
from redbot.core.utils.chat_formatting import humanize_number, pagify
|
||||||
from redbot.core.utils.menus import DEFAULT_CONTROLS, menu
|
from redbot.core.utils.menus import DEFAULT_CONTROLS, menu
|
||||||
|
|
||||||
from ..abc import MixinMeta
|
from ..abc import MixinMeta
|
||||||
from ..cog_utils import CompositeMetaClass, _
|
from ..cog_utils import CompositeMetaClass
|
||||||
|
|
||||||
log = logging.getLogger("red.cogs.Audio.cog.Commands.miscellaneous")
|
log = logging.getLogger("red.cogs.Audio.cog.Commands.miscellaneous")
|
||||||
|
_ = Translator("Audio", Path(__file__))
|
||||||
|
|
||||||
|
|
||||||
class MiscellaneousCommands(MixinMeta, metaclass=CompositeMetaClass):
|
class MiscellaneousCommands(MixinMeta, metaclass=CompositeMetaClass):
|
||||||
|
|||||||
@ -3,6 +3,7 @@ import datetime
|
|||||||
import logging
|
import logging
|
||||||
import math
|
import math
|
||||||
import time
|
import time
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
from typing import MutableMapping
|
from typing import MutableMapping
|
||||||
|
|
||||||
@ -12,6 +13,7 @@ import lavalink
|
|||||||
from discord.embeds import EmptyEmbed
|
from discord.embeds import EmptyEmbed
|
||||||
from redbot.core import commands
|
from redbot.core import commands
|
||||||
from redbot.core.commands import UserInputOptional
|
from redbot.core.commands import UserInputOptional
|
||||||
|
from redbot.core.i18n import Translator
|
||||||
from redbot.core.utils import AsyncIter
|
from redbot.core.utils import AsyncIter
|
||||||
from redbot.core.utils.menus import DEFAULT_CONTROLS, close_menu, menu, next_page, prev_page
|
from redbot.core.utils.menus import DEFAULT_CONTROLS, close_menu, menu, next_page, prev_page
|
||||||
|
|
||||||
@ -24,9 +26,10 @@ from ...errors import (
|
|||||||
TrackEnqueueError,
|
TrackEnqueueError,
|
||||||
)
|
)
|
||||||
from ..abc import MixinMeta
|
from ..abc import MixinMeta
|
||||||
from ..cog_utils import CompositeMetaClass, _
|
from ..cog_utils import CompositeMetaClass
|
||||||
|
|
||||||
log = logging.getLogger("red.cogs.Audio.cog.Commands.player")
|
log = logging.getLogger("red.cogs.Audio.cog.Commands.player")
|
||||||
|
_ = Translator("Audio", Path(__file__))
|
||||||
|
|
||||||
|
|
||||||
class PlayerCommands(MixinMeta, metaclass=CompositeMetaClass):
|
class PlayerCommands(MixinMeta, metaclass=CompositeMetaClass):
|
||||||
@ -125,6 +128,9 @@ class PlayerCommands(MixinMeta, metaclass=CompositeMetaClass):
|
|||||||
return await self.send_embed_msg(
|
return await self.send_embed_msg(
|
||||||
ctx, title=_("Unable To Play Tracks"), description=err.message
|
ctx, title=_("Unable To Play Tracks"), description=err.message
|
||||||
)
|
)
|
||||||
|
except Exception as e:
|
||||||
|
self.update_player_lock(ctx, False)
|
||||||
|
raise e
|
||||||
|
|
||||||
@commands.command(name="bumpplay")
|
@commands.command(name="bumpplay")
|
||||||
@commands.guild_only()
|
@commands.guild_only()
|
||||||
@ -230,6 +236,9 @@ class PlayerCommands(MixinMeta, metaclass=CompositeMetaClass):
|
|||||||
return await self.send_embed_msg(
|
return await self.send_embed_msg(
|
||||||
ctx, title=_("Unable To Play Tracks"), description=err.message
|
ctx, title=_("Unable To Play Tracks"), description=err.message
|
||||||
)
|
)
|
||||||
|
except Exception as e:
|
||||||
|
self.update_player_lock(ctx, False)
|
||||||
|
raise e
|
||||||
if isinstance(tracks, discord.Message):
|
if isinstance(tracks, discord.Message):
|
||||||
return
|
return
|
||||||
elif not tracks:
|
elif not tracks:
|
||||||
@ -248,7 +257,7 @@ class PlayerCommands(MixinMeta, metaclass=CompositeMetaClass):
|
|||||||
title = _("Track is not playable.")
|
title = _("Track is not playable.")
|
||||||
embed = discord.Embed(title=title)
|
embed = discord.Embed(title=title)
|
||||||
embed.description = _(
|
embed.description = _(
|
||||||
"**{suffix}** is not a fully supported format and some " "tracks may not play."
|
"**{suffix}** is not a fully supported format and some tracks may not play."
|
||||||
).format(suffix=query.suffix)
|
).format(suffix=query.suffix)
|
||||||
return await self.send_embed_msg(ctx, embed=embed)
|
return await self.send_embed_msg(ctx, embed=embed)
|
||||||
queue_dur = await self.track_remaining_duration(ctx)
|
queue_dur = await self.track_remaining_duration(ctx)
|
||||||
@ -611,6 +620,9 @@ class PlayerCommands(MixinMeta, metaclass=CompositeMetaClass):
|
|||||||
"minutes."
|
"minutes."
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
except Exception as e:
|
||||||
|
self.update_player_lock(ctx, False)
|
||||||
|
raise e
|
||||||
|
|
||||||
if not guild_data["auto_play"]:
|
if not guild_data["auto_play"]:
|
||||||
await ctx.invoke(self.command_audioset_autoplay_toggle)
|
await ctx.invoke(self.command_audioset_autoplay_toggle)
|
||||||
@ -745,6 +757,9 @@ class PlayerCommands(MixinMeta, metaclass=CompositeMetaClass):
|
|||||||
"try again in a few minutes."
|
"try again in a few minutes."
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
except Exception as e:
|
||||||
|
self.update_player_lock(ctx, False)
|
||||||
|
raise e
|
||||||
|
|
||||||
tracks = result.tracks
|
tracks = result.tracks
|
||||||
else:
|
else:
|
||||||
@ -761,6 +776,9 @@ class PlayerCommands(MixinMeta, metaclass=CompositeMetaClass):
|
|||||||
"try again in a few minutes."
|
"try again in a few minutes."
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
except Exception as e:
|
||||||
|
self.update_player_lock(ctx, False)
|
||||||
|
raise e
|
||||||
if not tracks:
|
if not tracks:
|
||||||
embed = discord.Embed(title=_("Nothing found."))
|
embed = discord.Embed(title=_("Nothing found."))
|
||||||
if await self.config.use_external_lavalink() and query.is_local:
|
if await self.config.use_external_lavalink() and query.is_local:
|
||||||
@ -877,6 +895,9 @@ class PlayerCommands(MixinMeta, metaclass=CompositeMetaClass):
|
|||||||
"try again in a few minutes."
|
"try again in a few minutes."
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
except Exception as e:
|
||||||
|
self.update_player_lock(ctx, False)
|
||||||
|
raise e
|
||||||
tracks = result.tracks
|
tracks = result.tracks
|
||||||
if not tracks:
|
if not tracks:
|
||||||
embed = discord.Embed(title=_("Nothing found."))
|
embed = discord.Embed(title=_("Nothing found."))
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import tarfile
|
|||||||
import time
|
import time
|
||||||
|
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
|
from pathlib import Path
|
||||||
from typing import cast
|
from typing import cast
|
||||||
|
|
||||||
import discord
|
import discord
|
||||||
@ -15,6 +16,7 @@ import lavalink
|
|||||||
from redbot.core import commands
|
from redbot.core import commands
|
||||||
from redbot.core.commands import UserInputOptional
|
from redbot.core.commands import UserInputOptional
|
||||||
from redbot.core.data_manager import cog_data_path
|
from redbot.core.data_manager import cog_data_path
|
||||||
|
from redbot.core.i18n import Translator
|
||||||
from redbot.core.utils import AsyncIter
|
from redbot.core.utils import AsyncIter
|
||||||
from redbot.core.utils.chat_formatting import bold, pagify
|
from redbot.core.utils.chat_formatting import bold, pagify
|
||||||
from redbot.core.utils.menus import DEFAULT_CONTROLS, menu
|
from redbot.core.utils.menus import DEFAULT_CONTROLS, menu
|
||||||
@ -28,9 +30,10 @@ from ...converters import ComplexScopeParser, ScopeParser
|
|||||||
from ...errors import MissingGuild, TooManyMatches, TrackEnqueueError
|
from ...errors import MissingGuild, TooManyMatches, TrackEnqueueError
|
||||||
from ...utils import PlaylistScope
|
from ...utils import PlaylistScope
|
||||||
from ..abc import MixinMeta
|
from ..abc import MixinMeta
|
||||||
from ..cog_utils import CompositeMetaClass, LazyGreedyConverter, PlaylistConverter, _
|
from ..cog_utils import CompositeMetaClass, LazyGreedyConverter, PlaylistConverter
|
||||||
|
|
||||||
log = logging.getLogger("red.cogs.Audio.cog.Commands.playlist")
|
log = logging.getLogger("red.cogs.Audio.cog.Commands.playlist")
|
||||||
|
_ = Translator("Audio", Path(__file__))
|
||||||
|
|
||||||
|
|
||||||
class PlaylistCommands(MixinMeta, metaclass=CompositeMetaClass):
|
class PlaylistCommands(MixinMeta, metaclass=CompositeMetaClass):
|
||||||
@ -107,6 +110,7 @@ class PlaylistCommands(MixinMeta, metaclass=CompositeMetaClass):
|
|||||||
(scope, author, guild, specified_user) = scope_data
|
(scope, author, guild, specified_user) = scope_data
|
||||||
if not await self._playlist_check(ctx):
|
if not await self._playlist_check(ctx):
|
||||||
return
|
return
|
||||||
|
async with ctx.typing():
|
||||||
try:
|
try:
|
||||||
(playlist, playlist_arg, scope) = await self.get_playlist_match(
|
(playlist, playlist_arg, scope) = await self.get_playlist_match(
|
||||||
ctx, playlist_matches, scope, author, guild, specified_user
|
ctx, playlist_matches, scope, author, guild, specified_user
|
||||||
@ -117,7 +121,9 @@ class PlaylistCommands(MixinMeta, metaclass=CompositeMetaClass):
|
|||||||
return await self.send_embed_msg(
|
return await self.send_embed_msg(
|
||||||
ctx,
|
ctx,
|
||||||
title=_("Playlist Not Found"),
|
title=_("Playlist Not Found"),
|
||||||
description=_("Could not match '{arg}' to a playlist").format(arg=playlist_arg),
|
description=_("Could not match '{arg}' to a playlist").format(
|
||||||
|
arg=playlist_arg
|
||||||
|
),
|
||||||
)
|
)
|
||||||
if not await self.can_manage_playlist(scope, playlist, ctx, author, guild):
|
if not await self.can_manage_playlist(scope, playlist, ctx, author, guild):
|
||||||
return
|
return
|
||||||
@ -156,7 +162,10 @@ class PlaylistCommands(MixinMeta, metaclass=CompositeMetaClass):
|
|||||||
description=_(
|
description=_(
|
||||||
"{track} is already in {playlist} (`{id}`) [**{scope}**]."
|
"{track} is already in {playlist} (`{id}`) [**{scope}**]."
|
||||||
).format(
|
).format(
|
||||||
track=to.title, playlist=playlist.name, id=playlist.id, scope=scope_name
|
track=to.title,
|
||||||
|
playlist=playlist.name,
|
||||||
|
id=playlist.id,
|
||||||
|
scope=scope_name,
|
||||||
),
|
),
|
||||||
footer=_("Playlist limit reached: Could not add track.").format(not_added)
|
footer=_("Playlist limit reached: Could not add track.").format(not_added)
|
||||||
if not_added > 0
|
if not_added > 0
|
||||||
@ -192,9 +201,9 @@ class PlaylistCommands(MixinMeta, metaclass=CompositeMetaClass):
|
|||||||
)
|
)
|
||||||
if to_append_count > appended:
|
if to_append_count > appended:
|
||||||
diff = to_append_count - appended
|
diff = to_append_count - appended
|
||||||
desc += _("\n{existing} {plural} already in the playlist and were skipped.").format(
|
desc += _(
|
||||||
existing=diff, plural=_("tracks are") if diff != 1 else _("track is")
|
"\n{existing} {plural} already in the playlist and were skipped."
|
||||||
)
|
).format(existing=diff, plural=_("tracks are") if diff != 1 else _("track is"))
|
||||||
|
|
||||||
embed = discord.Embed(title=_("Playlist Modified"), description=desc)
|
embed = discord.Embed(title=_("Playlist Modified"), description=desc)
|
||||||
await self.send_embed_msg(
|
await self.send_embed_msg(
|
||||||
@ -282,6 +291,7 @@ class PlaylistCommands(MixinMeta, metaclass=CompositeMetaClass):
|
|||||||
specified_to_user,
|
specified_to_user,
|
||||||
) = scope_data
|
) = scope_data
|
||||||
to_scope = to_scope or PlaylistScope.GUILD.value
|
to_scope = to_scope or PlaylistScope.GUILD.value
|
||||||
|
async with ctx.typing():
|
||||||
try:
|
try:
|
||||||
from_playlist, playlist_arg, from_scope = await self.get_playlist_match(
|
from_playlist, playlist_arg, from_scope = await self.get_playlist_match(
|
||||||
ctx, playlist_matches, from_scope, from_author, from_guild, specified_from_user
|
ctx, playlist_matches, from_scope, from_author, from_guild, specified_from_user
|
||||||
@ -295,11 +305,15 @@ class PlaylistCommands(MixinMeta, metaclass=CompositeMetaClass):
|
|||||||
return await self.send_embed_msg(
|
return await self.send_embed_msg(
|
||||||
ctx,
|
ctx,
|
||||||
title=_("Playlist Not Found"),
|
title=_("Playlist Not Found"),
|
||||||
description=_("Could not match '{arg}' to a playlist.").format(arg=playlist_arg),
|
description=_("Could not match '{arg}' to a playlist.").format(
|
||||||
|
arg=playlist_arg
|
||||||
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
temp_playlist = cast(Playlist, FakePlaylist(to_author.id, to_scope))
|
temp_playlist = cast(Playlist, FakePlaylist(to_author.id, to_scope))
|
||||||
if not await self.can_manage_playlist(to_scope, temp_playlist, ctx, to_author, to_guild):
|
if not await self.can_manage_playlist(
|
||||||
|
to_scope, temp_playlist, ctx, to_author, to_guild
|
||||||
|
):
|
||||||
ctx.command.reset_cooldown(ctx)
|
ctx.command.reset_cooldown(ctx)
|
||||||
return
|
return
|
||||||
|
|
||||||
@ -392,6 +406,7 @@ class PlaylistCommands(MixinMeta, metaclass=CompositeMetaClass):
|
|||||||
scope_name = self.humanize_scope(
|
scope_name = self.humanize_scope(
|
||||||
scope, ctx=guild if scope == PlaylistScope.GUILD.value else author
|
scope, ctx=guild if scope == PlaylistScope.GUILD.value else author
|
||||||
)
|
)
|
||||||
|
async with ctx.typing():
|
||||||
if not await self.can_manage_playlist(scope, temp_playlist, ctx, author, guild):
|
if not await self.can_manage_playlist(scope, temp_playlist, ctx, author, guild):
|
||||||
return
|
return
|
||||||
playlist_name = playlist_name.split(" ")[0].strip('"')[:32]
|
playlist_name = playlist_name.split(" ")[0].strip('"')[:32]
|
||||||
@ -465,7 +480,7 @@ class PlaylistCommands(MixinMeta, metaclass=CompositeMetaClass):
|
|||||||
if scope_data is None:
|
if scope_data is None:
|
||||||
scope_data = [None, ctx.author, ctx.guild, False]
|
scope_data = [None, ctx.author, ctx.guild, False]
|
||||||
scope, author, guild, specified_user = scope_data
|
scope, author, guild, specified_user = scope_data
|
||||||
|
async with ctx.typing():
|
||||||
try:
|
try:
|
||||||
playlist, playlist_arg, scope = await self.get_playlist_match(
|
playlist, playlist_arg, scope = await self.get_playlist_match(
|
||||||
ctx, playlist_matches, scope, author, guild, specified_user
|
ctx, playlist_matches, scope, author, guild, specified_user
|
||||||
@ -476,7 +491,9 @@ class PlaylistCommands(MixinMeta, metaclass=CompositeMetaClass):
|
|||||||
return await self.send_embed_msg(
|
return await self.send_embed_msg(
|
||||||
ctx,
|
ctx,
|
||||||
title=_("Playlist Not Found"),
|
title=_("Playlist Not Found"),
|
||||||
description=_("Could not match '{arg}' to a playlist.").format(arg=playlist_arg),
|
description=_("Could not match '{arg}' to a playlist.").format(
|
||||||
|
arg=playlist_arg
|
||||||
|
),
|
||||||
)
|
)
|
||||||
if not await self.can_manage_playlist(scope, playlist, ctx, author, guild):
|
if not await self.can_manage_playlist(scope, playlist, ctx, author, guild):
|
||||||
return
|
return
|
||||||
@ -688,7 +705,7 @@ class PlaylistCommands(MixinMeta, metaclass=CompositeMetaClass):
|
|||||||
if scope_data is None:
|
if scope_data is None:
|
||||||
scope_data = [None, ctx.author, ctx.guild, False]
|
scope_data = [None, ctx.author, ctx.guild, False]
|
||||||
scope, author, guild, specified_user = scope_data
|
scope, author, guild, specified_user = scope_data
|
||||||
|
async with ctx.typing():
|
||||||
try:
|
try:
|
||||||
playlist, playlist_arg, scope = await self.get_playlist_match(
|
playlist, playlist_arg, scope = await self.get_playlist_match(
|
||||||
ctx, playlist_matches, scope, author, guild, specified_user
|
ctx, playlist_matches, scope, author, guild, specified_user
|
||||||
@ -701,7 +718,9 @@ class PlaylistCommands(MixinMeta, metaclass=CompositeMetaClass):
|
|||||||
return await self.send_embed_msg(
|
return await self.send_embed_msg(
|
||||||
ctx,
|
ctx,
|
||||||
title=_("Playlist Not Found"),
|
title=_("Playlist Not Found"),
|
||||||
description=_("Could not match '{arg}' to a playlist.").format(arg=playlist_arg),
|
description=_("Could not match '{arg}' to a playlist.").format(
|
||||||
|
arg=playlist_arg
|
||||||
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
schema = 2
|
schema = 2
|
||||||
@ -746,7 +765,9 @@ class PlaylistCommands(MixinMeta, metaclass=CompositeMetaClass):
|
|||||||
|
|
||||||
with tarfile.open(str(temp_tar), "w:gz") as tar:
|
with tarfile.open(str(temp_tar), "w:gz") as tar:
|
||||||
tar.add(
|
tar.add(
|
||||||
str(temp_file), arcname=str(temp_file.relative_to(datapath)), recursive=False
|
str(temp_file),
|
||||||
|
arcname=str(temp_file.relative_to(datapath)),
|
||||||
|
recursive=False,
|
||||||
)
|
)
|
||||||
try:
|
try:
|
||||||
if os.path.getsize(str(temp_tar)) > ctx.guild.filesize_limit - 10000:
|
if os.path.getsize(str(temp_tar)) > ctx.guild.filesize_limit - 10000:
|
||||||
@ -817,6 +838,7 @@ class PlaylistCommands(MixinMeta, metaclass=CompositeMetaClass):
|
|||||||
if scope_data is None:
|
if scope_data is None:
|
||||||
scope_data = [None, ctx.author, ctx.guild, False]
|
scope_data = [None, ctx.author, ctx.guild, False]
|
||||||
scope, author, guild, specified_user = scope_data
|
scope, author, guild, specified_user = scope_data
|
||||||
|
async with ctx.typing():
|
||||||
try:
|
try:
|
||||||
playlist, playlist_arg, scope = await self.get_playlist_match(
|
playlist, playlist_arg, scope = await self.get_playlist_match(
|
||||||
ctx, playlist_matches, scope, author, guild, specified_user
|
ctx, playlist_matches, scope, author, guild, specified_user
|
||||||
@ -833,7 +855,9 @@ class PlaylistCommands(MixinMeta, metaclass=CompositeMetaClass):
|
|||||||
return await self.send_embed_msg(
|
return await self.send_embed_msg(
|
||||||
ctx,
|
ctx,
|
||||||
title=_("Playlist Not Found"),
|
title=_("Playlist Not Found"),
|
||||||
description=_("Could not match '{arg}' to a playlist.").format(arg=playlist_arg),
|
description=_("Could not match '{arg}' to a playlist.").format(
|
||||||
|
arg=playlist_arg
|
||||||
|
),
|
||||||
)
|
)
|
||||||
track_len = len(playlist.tracks)
|
track_len = len(playlist.tracks)
|
||||||
|
|
||||||
@ -841,7 +865,9 @@ class PlaylistCommands(MixinMeta, metaclass=CompositeMetaClass):
|
|||||||
if track_len > 0:
|
if track_len > 0:
|
||||||
spaces = "\N{EN SPACE}" * (len(str(len(playlist.tracks))) + 2)
|
spaces = "\N{EN SPACE}" * (len(str(len(playlist.tracks))) + 2)
|
||||||
async for track_idx, track in AsyncIter(playlist.tracks).enumerate(start=1):
|
async for track_idx, track in AsyncIter(playlist.tracks).enumerate(start=1):
|
||||||
query = Query.process_input(track["info"]["uri"], self.local_folder_current_path)
|
query = Query.process_input(
|
||||||
|
track["info"]["uri"], self.local_folder_current_path
|
||||||
|
)
|
||||||
if query.is_local:
|
if query.is_local:
|
||||||
if track["info"]["title"] != "Unknown title":
|
if track["info"]["title"] != "Unknown title":
|
||||||
msg += "`{}.` **{} - {}**\n{}{}\n".format(
|
msg += "`{}.` **{} - {}**\n{}{}\n".format(
|
||||||
@ -862,9 +888,9 @@ class PlaylistCommands(MixinMeta, metaclass=CompositeMetaClass):
|
|||||||
msg = "No tracks."
|
msg = "No tracks."
|
||||||
|
|
||||||
if not playlist.url:
|
if not playlist.url:
|
||||||
embed_title = _("Playlist info for {playlist_name} (`{id}`) [**{scope}**]:\n").format(
|
embed_title = _(
|
||||||
playlist_name=playlist.name, id=playlist.id, scope=scope_name
|
"Playlist info for {playlist_name} (`{id}`) [**{scope}**]:\n"
|
||||||
)
|
).format(playlist_name=playlist.name, id=playlist.id, scope=scope_name)
|
||||||
else:
|
else:
|
||||||
embed_title = _(
|
embed_title = _(
|
||||||
"Playlist info for {playlist_name} (`{id}`) [**{scope}**]:\nURL: {url}"
|
"Playlist info for {playlist_name} (`{id}`) [**{scope}**]:\nURL: {url}"
|
||||||
@ -935,7 +961,7 @@ class PlaylistCommands(MixinMeta, metaclass=CompositeMetaClass):
|
|||||||
if scope_data is None:
|
if scope_data is None:
|
||||||
scope_data = [None, ctx.author, ctx.guild, False]
|
scope_data = [None, ctx.author, ctx.guild, False]
|
||||||
scope, author, guild, specified_user = scope_data
|
scope, author, guild, specified_user = scope_data
|
||||||
|
async with ctx.typing():
|
||||||
if scope is None:
|
if scope is None:
|
||||||
|
|
||||||
global_matches = await get_all_playlist(
|
global_matches = await get_all_playlist(
|
||||||
@ -1003,9 +1029,9 @@ class PlaylistCommands(MixinMeta, metaclass=CompositeMetaClass):
|
|||||||
return await self.send_embed_msg(
|
return await self.send_embed_msg(
|
||||||
ctx,
|
ctx,
|
||||||
title=_("Playlist Not Found"),
|
title=_("Playlist Not Found"),
|
||||||
description=_("No saved playlists for {scope} created by {author}.").format(
|
description=_(
|
||||||
scope=name, author=author
|
"No saved playlists for {scope} created by {author}."
|
||||||
),
|
).format(scope=name, author=author),
|
||||||
)
|
)
|
||||||
elif not playlists:
|
elif not playlists:
|
||||||
ctx.command.reset_cooldown(ctx)
|
ctx.command.reset_cooldown(ctx)
|
||||||
@ -1029,7 +1055,9 @@ class PlaylistCommands(MixinMeta, metaclass=CompositeMetaClass):
|
|||||||
or playlist.author
|
or playlist.author
|
||||||
or _("Unknown")
|
or _("Unknown")
|
||||||
),
|
),
|
||||||
_("Scope: {scope}\n").format(scope=self.humanize_scope(playlist.scope)),
|
_("Scope: {scope}\n").format(
|
||||||
|
scope=self.humanize_scope(playlist.scope)
|
||||||
|
),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@ -1199,6 +1227,7 @@ class PlaylistCommands(MixinMeta, metaclass=CompositeMetaClass):
|
|||||||
if scope_data is None:
|
if scope_data is None:
|
||||||
scope_data = [None, ctx.author, ctx.guild, False]
|
scope_data = [None, ctx.author, ctx.guild, False]
|
||||||
scope, author, guild, specified_user = scope_data
|
scope, author, guild, specified_user = scope_data
|
||||||
|
async with ctx.typing():
|
||||||
try:
|
try:
|
||||||
playlist, playlist_arg, scope = await self.get_playlist_match(
|
playlist, playlist_arg, scope = await self.get_playlist_match(
|
||||||
ctx, playlist_matches, scope, author, guild, specified_user
|
ctx, playlist_matches, scope, author, guild, specified_user
|
||||||
@ -1212,7 +1241,9 @@ class PlaylistCommands(MixinMeta, metaclass=CompositeMetaClass):
|
|||||||
return await self.send_embed_msg(
|
return await self.send_embed_msg(
|
||||||
ctx,
|
ctx,
|
||||||
title=_("Playlist Not Found"),
|
title=_("Playlist Not Found"),
|
||||||
description=_("Could not match '{arg}' to a playlist.").format(arg=playlist_arg),
|
description=_("Could not match '{arg}' to a playlist.").format(
|
||||||
|
arg=playlist_arg
|
||||||
|
),
|
||||||
)
|
)
|
||||||
if not await self.can_manage_playlist(scope, playlist, ctx, author, guild):
|
if not await self.can_manage_playlist(scope, playlist, ctx, author, guild):
|
||||||
return
|
return
|
||||||
@ -1231,7 +1262,9 @@ class PlaylistCommands(MixinMeta, metaclass=CompositeMetaClass):
|
|||||||
guild=guild,
|
guild=guild,
|
||||||
author=playlist.author,
|
author=playlist.author,
|
||||||
)
|
)
|
||||||
return await self.send_embed_msg(ctx, title=_("No tracks left, removing playlist."))
|
return await self.send_embed_msg(
|
||||||
|
ctx, title=_("No tracks left, removing playlist.")
|
||||||
|
)
|
||||||
update = {"tracks": clean_list, "url": None}
|
update = {"tracks": clean_list, "url": None}
|
||||||
await playlist.edit(update)
|
await playlist.edit(update)
|
||||||
if del_count > 1:
|
if del_count > 1:
|
||||||
@ -1242,7 +1275,10 @@ class PlaylistCommands(MixinMeta, metaclass=CompositeMetaClass):
|
|||||||
"{num} entries have been removed "
|
"{num} entries have been removed "
|
||||||
"from the playlist {playlist_name} (`{id}`) [**{scope}**]."
|
"from the playlist {playlist_name} (`{id}`) [**{scope}**]."
|
||||||
).format(
|
).format(
|
||||||
num=del_count, playlist_name=playlist.name, id=playlist.id, scope=scope_name
|
num=del_count,
|
||||||
|
playlist_name=playlist.name,
|
||||||
|
id=playlist.id,
|
||||||
|
scope=scope_name,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
@ -1313,6 +1349,7 @@ class PlaylistCommands(MixinMeta, metaclass=CompositeMetaClass):
|
|||||||
scope_name = self.humanize_scope(
|
scope_name = self.humanize_scope(
|
||||||
scope, ctx=guild if scope == PlaylistScope.GUILD.value else author
|
scope, ctx=guild if scope == PlaylistScope.GUILD.value else author
|
||||||
)
|
)
|
||||||
|
async with ctx.typing():
|
||||||
temp_playlist = cast(Playlist, FakePlaylist(author.id, scope))
|
temp_playlist = cast(Playlist, FakePlaylist(author.id, scope))
|
||||||
if not await self.can_manage_playlist(scope, temp_playlist, ctx, author, guild):
|
if not await self.can_manage_playlist(scope, temp_playlist, ctx, author, guild):
|
||||||
return ctx.command.reset_cooldown(ctx)
|
return ctx.command.reset_cooldown(ctx)
|
||||||
@ -1360,9 +1397,14 @@ class PlaylistCommands(MixinMeta, metaclass=CompositeMetaClass):
|
|||||||
description=_(
|
description=_(
|
||||||
"Playlist {name} (`{id}`) [**{scope}**] saved: {num} tracks added."
|
"Playlist {name} (`{id}`) [**{scope}**] saved: {num} tracks added."
|
||||||
).format(
|
).format(
|
||||||
name=playlist.name, num=len(tracklist), id=playlist.id, scope=scope_name
|
name=playlist.name,
|
||||||
|
num=len(tracklist),
|
||||||
|
id=playlist.id,
|
||||||
|
scope=scope_name,
|
||||||
),
|
),
|
||||||
footer=_("Playlist limit reached: Could not add {} tracks.").format(not_added)
|
footer=_("Playlist limit reached: Could not add {} tracks.").format(
|
||||||
|
not_added
|
||||||
|
)
|
||||||
if not_added > 0
|
if not_added > 0
|
||||||
else None,
|
else None,
|
||||||
)
|
)
|
||||||
@ -1440,7 +1482,7 @@ class PlaylistCommands(MixinMeta, metaclass=CompositeMetaClass):
|
|||||||
description=_("You need the DJ role to start playing playlists."),
|
description=_("You need the DJ role to start playing playlists."),
|
||||||
)
|
)
|
||||||
return False
|
return False
|
||||||
|
async with ctx.typing():
|
||||||
try:
|
try:
|
||||||
playlist, playlist_arg, scope = await self.get_playlist_match(
|
playlist, playlist_arg, scope = await self.get_playlist_match(
|
||||||
ctx, playlist_matches, scope, author, guild, specified_user
|
ctx, playlist_matches, scope, author, guild, specified_user
|
||||||
@ -1453,7 +1495,9 @@ class PlaylistCommands(MixinMeta, metaclass=CompositeMetaClass):
|
|||||||
return await self.send_embed_msg(
|
return await self.send_embed_msg(
|
||||||
ctx,
|
ctx,
|
||||||
title=_("Playlist Not Found"),
|
title=_("Playlist Not Found"),
|
||||||
description=_("Could not match '{arg}' to a playlist").format(arg=playlist_arg),
|
description=_("Could not match '{arg}' to a playlist").format(
|
||||||
|
arg=playlist_arg
|
||||||
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
if not await self._playlist_check(ctx):
|
if not await self._playlist_check(ctx):
|
||||||
@ -1608,6 +1652,8 @@ class PlaylistCommands(MixinMeta, metaclass=CompositeMetaClass):
|
|||||||
if scope_data is None:
|
if scope_data is None:
|
||||||
scope_data = [None, ctx.author, ctx.guild, False]
|
scope_data = [None, ctx.author, ctx.guild, False]
|
||||||
scope, author, guild, specified_user = scope_data
|
scope, author, guild, specified_user = scope_data
|
||||||
|
embeds = None
|
||||||
|
async with ctx.typing():
|
||||||
try:
|
try:
|
||||||
playlist, playlist_arg, scope = await self.get_playlist_match(
|
playlist, playlist_arg, scope = await self.get_playlist_match(
|
||||||
ctx, playlist_matches, scope, author, guild, specified_user
|
ctx, playlist_matches, scope, author, guild, specified_user
|
||||||
@ -1621,7 +1667,9 @@ class PlaylistCommands(MixinMeta, metaclass=CompositeMetaClass):
|
|||||||
return await self.send_embed_msg(
|
return await self.send_embed_msg(
|
||||||
ctx,
|
ctx,
|
||||||
title=_("Playlist Not Found"),
|
title=_("Playlist Not Found"),
|
||||||
description=_("Could not match '{arg}' to a playlist.").format(arg=playlist_arg),
|
description=_("Could not match '{arg}' to a playlist.").format(
|
||||||
|
arg=playlist_arg
|
||||||
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
if not await self._playlist_check(ctx):
|
if not await self._playlist_check(ctx):
|
||||||
@ -1632,7 +1680,9 @@ class PlaylistCommands(MixinMeta, metaclass=CompositeMetaClass):
|
|||||||
return
|
return
|
||||||
if playlist.url:
|
if playlist.url:
|
||||||
player = lavalink.get_player(ctx.guild.id)
|
player = lavalink.get_player(ctx.guild.id)
|
||||||
added, removed, playlist = await self._maybe_update_playlist(ctx, player, playlist)
|
added, removed, playlist = await self._maybe_update_playlist(
|
||||||
|
ctx, player, playlist
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
ctx.command.reset_cooldown(ctx)
|
ctx.command.reset_cooldown(ctx)
|
||||||
return await self.send_embed_msg(
|
return await self.send_embed_msg(
|
||||||
@ -1679,7 +1729,9 @@ class PlaylistCommands(MixinMeta, metaclass=CompositeMetaClass):
|
|||||||
if i % 10 == 0 or i == total_removed:
|
if i % 10 == 0 or i == total_removed:
|
||||||
page_count += 1
|
page_count += 1
|
||||||
embed = discord.Embed(
|
embed = discord.Embed(
|
||||||
title=_("Tracks removed"), colour=_colour, description=removed_text
|
title=_("Tracks removed"),
|
||||||
|
colour=_colour,
|
||||||
|
description=removed_text,
|
||||||
)
|
)
|
||||||
text = _("Page {page_num}/{total_pages}").format(
|
text = _("Page {page_num}/{total_pages}").format(
|
||||||
page_num=page_count, total_pages=total_pages
|
page_num=page_count, total_pages=total_pages
|
||||||
@ -1708,7 +1760,6 @@ class PlaylistCommands(MixinMeta, metaclass=CompositeMetaClass):
|
|||||||
added_embeds.append(embed)
|
added_embeds.append(embed)
|
||||||
added_text = ""
|
added_text = ""
|
||||||
embeds = removed_embeds + added_embeds
|
embeds = removed_embeds + added_embeds
|
||||||
await menu(ctx, embeds, DEFAULT_CONTROLS)
|
|
||||||
else:
|
else:
|
||||||
return await self.send_embed_msg(
|
return await self.send_embed_msg(
|
||||||
ctx,
|
ctx,
|
||||||
@ -1717,6 +1768,8 @@ class PlaylistCommands(MixinMeta, metaclass=CompositeMetaClass):
|
|||||||
id=playlist.id, name=playlist.name, scope=scope_name
|
id=playlist.id, name=playlist.name, scope=scope_name
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
if embeds:
|
||||||
|
await menu(ctx, embeds, DEFAULT_CONTROLS)
|
||||||
|
|
||||||
@command_playlist.command(name="upload", usage="[args]")
|
@command_playlist.command(name="upload", usage="[args]")
|
||||||
@commands.is_owner()
|
@commands.is_owner()
|
||||||
@ -1770,9 +1823,9 @@ class PlaylistCommands(MixinMeta, metaclass=CompositeMetaClass):
|
|||||||
scope, author, guild, specified_user = scope_data
|
scope, author, guild, specified_user = scope_data
|
||||||
scope = scope or PlaylistScope.GUILD.value
|
scope = scope or PlaylistScope.GUILD.value
|
||||||
temp_playlist = cast(Playlist, FakePlaylist(author.id, scope))
|
temp_playlist = cast(Playlist, FakePlaylist(author.id, scope))
|
||||||
|
async with ctx.typing():
|
||||||
if not await self.can_manage_playlist(scope, temp_playlist, ctx, author, guild):
|
if not await self.can_manage_playlist(scope, temp_playlist, ctx, author, guild):
|
||||||
return
|
return
|
||||||
|
|
||||||
if not await self._playlist_check(ctx):
|
if not await self._playlist_check(ctx):
|
||||||
return
|
return
|
||||||
player = lavalink.get_player(ctx.guild.id)
|
player = lavalink.get_player(ctx.guild.id)
|
||||||
@ -1834,7 +1887,9 @@ class PlaylistCommands(MixinMeta, metaclass=CompositeMetaClass):
|
|||||||
await self.api_interface.fetch_track(
|
await self.api_interface.fetch_track(
|
||||||
ctx,
|
ctx,
|
||||||
player,
|
player,
|
||||||
Query.process_input(uploaded_playlist_url, self.local_folder_current_path),
|
Query.process_input(
|
||||||
|
uploaded_playlist_url, self.local_folder_current_path
|
||||||
|
),
|
||||||
)
|
)
|
||||||
)[0].tracks
|
)[0].tracks
|
||||||
):
|
):
|
||||||
@ -1874,6 +1929,9 @@ class PlaylistCommands(MixinMeta, metaclass=CompositeMetaClass):
|
|||||||
"minutes."
|
"minutes."
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
except Exception as e:
|
||||||
|
self.update_player_lock(ctx, False)
|
||||||
|
raise e
|
||||||
|
|
||||||
@commands.cooldown(1, 60, commands.BucketType.member)
|
@commands.cooldown(1, 60, commands.BucketType.member)
|
||||||
@command_playlist.command(
|
@command_playlist.command(
|
||||||
@ -1929,7 +1987,7 @@ class PlaylistCommands(MixinMeta, metaclass=CompositeMetaClass):
|
|||||||
if scope_data is None:
|
if scope_data is None:
|
||||||
scope_data = [None, ctx.author, ctx.guild, False]
|
scope_data = [None, ctx.author, ctx.guild, False]
|
||||||
scope, author, guild, specified_user = scope_data
|
scope, author, guild, specified_user = scope_data
|
||||||
|
async with ctx.typing():
|
||||||
new_name = new_name.split(" ")[0].strip('"')[:32]
|
new_name = new_name.split(" ")[0].strip('"')[:32]
|
||||||
if new_name.isnumeric():
|
if new_name.isnumeric():
|
||||||
ctx.command.reset_cooldown(ctx)
|
ctx.command.reset_cooldown(ctx)
|
||||||
@ -1941,7 +1999,6 @@ class PlaylistCommands(MixinMeta, metaclass=CompositeMetaClass):
|
|||||||
"characters) and not numbers only."
|
"characters) and not numbers only."
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
playlist, playlist_arg, scope = await self.get_playlist_match(
|
playlist, playlist_arg, scope = await self.get_playlist_match(
|
||||||
ctx, playlist_matches, scope, author, guild, specified_user
|
ctx, playlist_matches, scope, author, guild, specified_user
|
||||||
@ -1954,7 +2011,9 @@ class PlaylistCommands(MixinMeta, metaclass=CompositeMetaClass):
|
|||||||
return await self.send_embed_msg(
|
return await self.send_embed_msg(
|
||||||
ctx,
|
ctx,
|
||||||
title=_("Playlist Not Found"),
|
title=_("Playlist Not Found"),
|
||||||
description=_("Could not match '{arg}' to a playlist.").format(arg=playlist_arg),
|
description=_("Could not match '{arg}' to a playlist.").format(
|
||||||
|
arg=playlist_arg
|
||||||
|
),
|
||||||
)
|
)
|
||||||
if not await self.can_manage_playlist(scope, playlist, ctx, author, guild):
|
if not await self.can_manage_playlist(scope, playlist, ctx, author, guild):
|
||||||
ctx.command.reset_cooldown(ctx)
|
ctx.command.reset_cooldown(ctx)
|
||||||
|
|||||||
@ -3,6 +3,7 @@ import contextlib
|
|||||||
import datetime
|
import datetime
|
||||||
import logging
|
import logging
|
||||||
import math
|
import math
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
from typing import MutableMapping, Optional
|
from typing import MutableMapping, Optional
|
||||||
|
|
||||||
@ -10,6 +11,7 @@ import discord
|
|||||||
import lavalink
|
import lavalink
|
||||||
|
|
||||||
from redbot.core import commands
|
from redbot.core import commands
|
||||||
|
from redbot.core.i18n import Translator
|
||||||
from redbot.core.utils import AsyncIter
|
from redbot.core.utils import AsyncIter
|
||||||
from redbot.core.utils.menus import (
|
from redbot.core.utils.menus import (
|
||||||
DEFAULT_CONTROLS,
|
DEFAULT_CONTROLS,
|
||||||
@ -22,9 +24,10 @@ from redbot.core.utils.menus import (
|
|||||||
from redbot.core.utils.predicates import ReactionPredicate
|
from redbot.core.utils.predicates import ReactionPredicate
|
||||||
|
|
||||||
from ..abc import MixinMeta
|
from ..abc import MixinMeta
|
||||||
from ..cog_utils import CompositeMetaClass, _
|
from ..cog_utils import CompositeMetaClass
|
||||||
|
|
||||||
log = logging.getLogger("red.cogs.Audio.cog.Commands.queue")
|
log = logging.getLogger("red.cogs.Audio.cog.Commands.queue")
|
||||||
|
_ = Translator("Audio", Path(__file__))
|
||||||
|
|
||||||
|
|
||||||
class QueueCommands(MixinMeta, metaclass=CompositeMetaClass):
|
class QueueCommands(MixinMeta, metaclass=CompositeMetaClass):
|
||||||
@ -71,9 +74,8 @@ class QueueCommands(MixinMeta, metaclass=CompositeMetaClass):
|
|||||||
await self.get_track_description(player.current, self.local_folder_current_path)
|
await self.get_track_description(player.current, self.local_folder_current_path)
|
||||||
or ""
|
or ""
|
||||||
)
|
)
|
||||||
song += _("\n Requested by: **{track.requester}**")
|
song += _("\n Requested by: **{track.requester}**").format(track=player.current)
|
||||||
song += "\n\n{arrow}`{pos}`/`{dur}`"
|
song += f"\n\n{arrow}`{pos}`/`{dur}`"
|
||||||
song = song.format(track=player.current, arrow=arrow, pos=pos, dur=dur)
|
|
||||||
embed = discord.Embed(title=_("Now Playing"), description=song)
|
embed = discord.Embed(title=_("Now Playing"), description=song)
|
||||||
guild_data = await self.config.guild(ctx.guild).all()
|
guild_data = await self.config.guild(ctx.guild).all()
|
||||||
if guild_data["thumbnail"] and player.current and player.current.thumbnail:
|
if guild_data["thumbnail"] and player.current and player.current.thumbnail:
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import asyncio
|
|||||||
import datetime
|
import datetime
|
||||||
import logging
|
import logging
|
||||||
import time
|
import time
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
@ -9,6 +10,7 @@ import discord
|
|||||||
import lavalink
|
import lavalink
|
||||||
|
|
||||||
from redbot.core import commands
|
from redbot.core import commands
|
||||||
|
from redbot.core.i18n import Translator
|
||||||
|
|
||||||
from ...apis.playlist_interface import Playlist, delete_playlist, get_playlist
|
from ...apis.playlist_interface import Playlist, delete_playlist, get_playlist
|
||||||
from ...audio_logging import debug_exc_log
|
from ...audio_logging import debug_exc_log
|
||||||
@ -17,6 +19,7 @@ from ..abc import MixinMeta
|
|||||||
from ..cog_utils import CompositeMetaClass
|
from ..cog_utils import CompositeMetaClass
|
||||||
|
|
||||||
log = logging.getLogger("red.cogs.Audio.cog.Events.audio")
|
log = logging.getLogger("red.cogs.Audio.cog.Events.audio")
|
||||||
|
_ = Translator("Audio", Path(__file__))
|
||||||
|
|
||||||
|
|
||||||
class AudioEvents(MixinMeta, metaclass=CompositeMetaClass):
|
class AudioEvents(MixinMeta, metaclass=CompositeMetaClass):
|
||||||
|
|||||||
@ -13,15 +13,16 @@ import lavalink
|
|||||||
from aiohttp import ClientConnectorError
|
from aiohttp import ClientConnectorError
|
||||||
from discord.ext.commands import CheckFailure
|
from discord.ext.commands import CheckFailure
|
||||||
from redbot.core import commands
|
from redbot.core import commands
|
||||||
|
from redbot.core.i18n import Translator
|
||||||
from redbot.core.utils.chat_formatting import box, humanize_list
|
from redbot.core.utils.chat_formatting import box, humanize_list
|
||||||
|
|
||||||
from ...audio_logging import debug_exc_log
|
from ...audio_logging import debug_exc_log
|
||||||
from ...errors import TrackEnqueueError
|
from ...errors import TrackEnqueueError
|
||||||
from ..abc import MixinMeta
|
from ..abc import MixinMeta
|
||||||
from ..cog_utils import HUMANIZED_PERM, CompositeMetaClass, _
|
from ..cog_utils import HUMANIZED_PERM, CompositeMetaClass
|
||||||
|
|
||||||
log = logging.getLogger("red.cogs.Audio.cog.Events.dpy")
|
log = logging.getLogger("red.cogs.Audio.cog.Events.dpy")
|
||||||
|
_ = Translator("Audio", Path(__file__))
|
||||||
RE_CONVERSION: Final[Pattern] = re.compile('Converting to "(.*)" failed for parameter "(.*)".')
|
RE_CONVERSION: Final[Pattern] = re.compile('Converting to "(.*)" failed for parameter "(.*)".')
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -1,15 +1,18 @@
|
|||||||
import asyncio
|
import asyncio
|
||||||
import contextlib
|
import contextlib
|
||||||
import logging
|
import logging
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
import discord
|
import discord
|
||||||
import lavalink
|
import lavalink
|
||||||
|
|
||||||
|
from redbot.core.i18n import Translator
|
||||||
from ...errors import DatabaseError, TrackEnqueueError
|
from ...errors import DatabaseError, TrackEnqueueError
|
||||||
from ..abc import MixinMeta
|
from ..abc import MixinMeta
|
||||||
from ..cog_utils import CompositeMetaClass, _
|
from ..cog_utils import CompositeMetaClass
|
||||||
|
|
||||||
log = logging.getLogger("red.cogs.Audio.cog.Events.lavalink")
|
log = logging.getLogger("red.cogs.Audio.cog.Events.lavalink")
|
||||||
|
_ = Translator("Audio", Path(__file__))
|
||||||
|
|
||||||
|
|
||||||
class LavalinkEvents(MixinMeta, metaclass=CompositeMetaClass):
|
class LavalinkEvents(MixinMeta, metaclass=CompositeMetaClass):
|
||||||
@ -174,6 +177,7 @@ class LavalinkEvents(MixinMeta, metaclass=CompositeMetaClass):
|
|||||||
player.current = None
|
player.current = None
|
||||||
if not guild_id:
|
if not guild_id:
|
||||||
return
|
return
|
||||||
|
guild_id = int(guild_id)
|
||||||
self._error_counter.setdefault(guild_id, 0)
|
self._error_counter.setdefault(guild_id, 0)
|
||||||
if guild_id not in self._error_counter:
|
if guild_id not in self._error_counter:
|
||||||
self._error_counter[guild_id] = 0
|
self._error_counter[guild_id] = 0
|
||||||
|
|||||||
@ -1,12 +1,15 @@
|
|||||||
import asyncio
|
import asyncio
|
||||||
import logging
|
import logging
|
||||||
|
from pathlib import Path
|
||||||
from typing import Literal, Mapping
|
from typing import Literal, Mapping
|
||||||
|
|
||||||
from redbot.core import commands
|
from redbot.core import commands
|
||||||
|
from redbot.core.i18n import Translator
|
||||||
from ..abc import MixinMeta
|
from ..abc import MixinMeta
|
||||||
from ..cog_utils import CompositeMetaClass
|
from ..cog_utils import CompositeMetaClass
|
||||||
|
|
||||||
log = logging.getLogger("red.cogs.Audio.cog.Events.red")
|
log = logging.getLogger("red.cogs.Audio.cog.Events.red")
|
||||||
|
_ = Translator("Audio", Path(__file__))
|
||||||
|
|
||||||
|
|
||||||
class RedEvents(MixinMeta, metaclass=CompositeMetaClass):
|
class RedEvents(MixinMeta, metaclass=CompositeMetaClass):
|
||||||
@ -15,11 +18,11 @@ class RedEvents(MixinMeta, metaclass=CompositeMetaClass):
|
|||||||
self, service_name: str, api_tokens: Mapping[str, str]
|
self, service_name: str, api_tokens: Mapping[str, str]
|
||||||
) -> None:
|
) -> None:
|
||||||
if service_name == "youtube":
|
if service_name == "youtube":
|
||||||
self.api_interface.youtube_api.update_token(api_tokens)
|
await self.api_interface.youtube_api.update_token(api_tokens)
|
||||||
elif service_name == "spotify":
|
elif service_name == "spotify":
|
||||||
self.api_interface.spotify_api.update_token(api_tokens)
|
await self.api_interface.spotify_api.update_token(api_tokens)
|
||||||
elif service_name == "audiodb":
|
elif service_name == "audiodb":
|
||||||
self.api_interface.global_cache_api.update_token(api_tokens)
|
await self.api_interface.global_cache_api.update_token(api_tokens)
|
||||||
|
|
||||||
async def red_delete_data_for_user(
|
async def red_delete_data_for_user(
|
||||||
self,
|
self,
|
||||||
|
|||||||
@ -1,14 +1,17 @@
|
|||||||
import asyncio
|
import asyncio
|
||||||
import logging
|
import logging
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
import lavalink
|
import lavalink
|
||||||
|
|
||||||
|
from redbot.core.i18n import Translator
|
||||||
from ...errors import LavalinkDownloadFailed
|
from ...errors import LavalinkDownloadFailed
|
||||||
from ...manager import ServerManager
|
from ...manager import ServerManager
|
||||||
from ..abc import MixinMeta
|
from ..abc import MixinMeta
|
||||||
from ..cog_utils import CompositeMetaClass
|
from ..cog_utils import CompositeMetaClass
|
||||||
|
|
||||||
log = logging.getLogger("red.cogs.Audio.cog.Tasks.lavalink")
|
log = logging.getLogger("red.cogs.Audio.cog.Tasks.lavalink")
|
||||||
|
_ = Translator("Audio", Path(__file__))
|
||||||
|
|
||||||
|
|
||||||
class LavalinkTasks(MixinMeta, metaclass=CompositeMetaClass):
|
class LavalinkTasks(MixinMeta, metaclass=CompositeMetaClass):
|
||||||
|
|||||||
@ -1,11 +1,13 @@
|
|||||||
import asyncio
|
import asyncio
|
||||||
import logging
|
import logging
|
||||||
import time
|
import time
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
from typing import Dict
|
from typing import Dict
|
||||||
|
|
||||||
import lavalink
|
import lavalink
|
||||||
|
|
||||||
|
from redbot.core.i18n import Translator
|
||||||
from redbot.core.utils import AsyncIter
|
from redbot.core.utils import AsyncIter
|
||||||
|
|
||||||
from ...audio_logging import debug_exc_log
|
from ...audio_logging import debug_exc_log
|
||||||
@ -13,6 +15,7 @@ from ..abc import MixinMeta
|
|||||||
from ..cog_utils import CompositeMetaClass
|
from ..cog_utils import CompositeMetaClass
|
||||||
|
|
||||||
log = logging.getLogger("red.cogs.Audio.cog.Tasks.player")
|
log = logging.getLogger("red.cogs.Audio.cog.Tasks.player")
|
||||||
|
_ = Translator("Audio", Path(__file__))
|
||||||
|
|
||||||
|
|
||||||
class PlayerTasks(MixinMeta, metaclass=CompositeMetaClass):
|
class PlayerTasks(MixinMeta, metaclass=CompositeMetaClass):
|
||||||
|
|||||||
@ -2,12 +2,14 @@ import asyncio
|
|||||||
import datetime
|
import datetime
|
||||||
import itertools
|
import itertools
|
||||||
import logging
|
import logging
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
import lavalink
|
import lavalink
|
||||||
|
|
||||||
from redbot.core.data_manager import cog_data_path
|
from redbot.core.data_manager import cog_data_path
|
||||||
|
from redbot.core.i18n import Translator
|
||||||
from redbot.core.utils._internal_utils import send_to_owners_with_prefix_replaced
|
from redbot.core.utils._internal_utils import send_to_owners_with_prefix_replaced
|
||||||
from redbot.core.utils.dbtools import APSWConnectionWrapper
|
from redbot.core.utils.dbtools import APSWConnectionWrapper
|
||||||
|
|
||||||
@ -16,9 +18,10 @@ from ...apis.playlist_wrapper import PlaylistWrapper
|
|||||||
from ...audio_logging import debug_exc_log
|
from ...audio_logging import debug_exc_log
|
||||||
from ...utils import task_callback
|
from ...utils import task_callback
|
||||||
from ..abc import MixinMeta
|
from ..abc import MixinMeta
|
||||||
from ..cog_utils import _, _OWNER_NOTIFICATION, _SCHEMA_VERSION, CompositeMetaClass
|
from ..cog_utils import _OWNER_NOTIFICATION, _SCHEMA_VERSION, CompositeMetaClass
|
||||||
|
|
||||||
log = logging.getLogger("red.cogs.Audio.cog.Tasks.startup")
|
log = logging.getLogger("red.cogs.Audio.cog.Tasks.startup")
|
||||||
|
_ = Translator("Audio", Path(__file__))
|
||||||
|
|
||||||
|
|
||||||
class StartUpTasks(MixinMeta, metaclass=CompositeMetaClass):
|
class StartUpTasks(MixinMeta, metaclass=CompositeMetaClass):
|
||||||
|
|||||||
@ -3,6 +3,7 @@ import logging
|
|||||||
import math
|
import math
|
||||||
import re
|
import re
|
||||||
import time
|
import time
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
from typing import List, Optional
|
from typing import List, Optional
|
||||||
|
|
||||||
@ -11,16 +12,17 @@ import lavalink
|
|||||||
|
|
||||||
from discord.embeds import EmptyEmbed
|
from discord.embeds import EmptyEmbed
|
||||||
from redbot.core import commands
|
from redbot.core import commands
|
||||||
|
from redbot.core.i18n import Translator
|
||||||
from redbot.core.utils import AsyncIter
|
from redbot.core.utils import AsyncIter
|
||||||
from redbot.core.utils.chat_formatting import box, escape
|
from redbot.core.utils.chat_formatting import box, escape
|
||||||
|
|
||||||
from ...audio_dataclasses import LocalPath, Query
|
from ...audio_dataclasses import LocalPath, Query
|
||||||
from ...audio_logging import IS_DEBUG
|
from ...audio_logging import IS_DEBUG
|
||||||
from ..abc import MixinMeta
|
from ..abc import MixinMeta
|
||||||
from ..cog_utils import CompositeMetaClass, _
|
from ..cog_utils import CompositeMetaClass
|
||||||
|
|
||||||
log = logging.getLogger("red.cogs.Audio.cog.Utilities.formatting")
|
log = logging.getLogger("red.cogs.Audio.cog.Utilities.formatting")
|
||||||
|
_ = Translator("Audio", Path(__file__))
|
||||||
RE_SQUARE = re.compile(r"[\[\]]")
|
RE_SQUARE = re.compile(r"[\[\]]")
|
||||||
|
|
||||||
|
|
||||||
@ -157,7 +159,7 @@ class FormattingUtilities(MixinMeta, metaclass=CompositeMetaClass):
|
|||||||
if not await self.is_query_allowed(
|
if not await self.is_query_allowed(
|
||||||
self.config,
|
self.config,
|
||||||
ctx,
|
ctx,
|
||||||
f"{search_choice.title} {search_choice.author} {search_choice.uri} " f"{str(query)}",
|
f"{search_choice.title} {search_choice.author} {search_choice.uri} {str(query)}",
|
||||||
query_obj=query,
|
query_obj=query,
|
||||||
):
|
):
|
||||||
if IS_DEBUG:
|
if IS_DEBUG:
|
||||||
@ -295,7 +297,7 @@ class FormattingUtilities(MixinMeta, metaclass=CompositeMetaClass):
|
|||||||
if shorten:
|
if shorten:
|
||||||
string = f"{track.author} - {track.title}"
|
string = f"{track.author} - {track.title}"
|
||||||
if len(string) > 40:
|
if len(string) > 40:
|
||||||
string = "{}...".format((string[:40]).rstrip(" "))
|
string = f"{(string[:40]).rstrip(' ')}..."
|
||||||
string = f'**{escape(f"{string}", formatting=True)}**'
|
string = f'**{escape(f"{string}", formatting=True)}**'
|
||||||
else:
|
else:
|
||||||
string = (
|
string = (
|
||||||
@ -306,7 +308,7 @@ class FormattingUtilities(MixinMeta, metaclass=CompositeMetaClass):
|
|||||||
if shorten:
|
if shorten:
|
||||||
string = f"{track.title}"
|
string = f"{track.title}"
|
||||||
if len(string) > 40:
|
if len(string) > 40:
|
||||||
string = "{}...".format((string[:40]).rstrip(" "))
|
string = f"{(string[:40]).rstrip(' ')}..."
|
||||||
string = f'**{escape(f"{string}", formatting=True)}**'
|
string = f'**{escape(f"{string}", formatting=True)}**'
|
||||||
else:
|
else:
|
||||||
string = f'**{escape(f"{track.title}", formatting=True)}**' + escape(
|
string = f'**{escape(f"{track.title}", formatting=True)}**' + escape(
|
||||||
@ -315,7 +317,7 @@ class FormattingUtilities(MixinMeta, metaclass=CompositeMetaClass):
|
|||||||
else:
|
else:
|
||||||
string = query.to_string_user()
|
string = query.to_string_user()
|
||||||
if shorten and len(string) > 40:
|
if shorten and len(string) > 40:
|
||||||
string = "{}...".format((string[:40]).rstrip(" "))
|
string = f"{(string[:40]).rstrip(' ')}..."
|
||||||
string = f'**{escape(f"{string}", formatting=True)}**'
|
string = f'**{escape(f"{string}", formatting=True)}**'
|
||||||
else:
|
else:
|
||||||
if track.is_stream:
|
if track.is_stream:
|
||||||
@ -330,13 +332,13 @@ class FormattingUtilities(MixinMeta, metaclass=CompositeMetaClass):
|
|||||||
title = track.title
|
title = track.title
|
||||||
string = f"{title}"
|
string = f"{title}"
|
||||||
if shorten and len(string) > 40:
|
if shorten and len(string) > 40:
|
||||||
string = "{}...".format((string[:40]).rstrip(" "))
|
string = f"{(string[:40]).rstrip(' ')}..."
|
||||||
string = re.sub(RE_SQUARE, "", string)
|
string = re.sub(RE_SQUARE, "", string)
|
||||||
string = f"**[{escape(string, formatting=True)}]({track.uri}) **"
|
string = f"**[{escape(string, formatting=True)}]({track.uri}) **"
|
||||||
elif hasattr(track, "to_string_user") and track.is_local:
|
elif hasattr(track, "to_string_user") and track.is_local:
|
||||||
string = track.to_string_user() + " "
|
string = track.to_string_user() + " "
|
||||||
if shorten and len(string) > 40:
|
if shorten and len(string) > 40:
|
||||||
string = "{}...".format((string[:40]).rstrip(" "))
|
string = f"{(string[:40]).rstrip(' ')}..."
|
||||||
string = f'**{escape(f"{string}", formatting=True)}**'
|
string = f'**{escape(f"{string}", formatting=True)}**'
|
||||||
return string
|
return string
|
||||||
|
|
||||||
@ -391,7 +393,7 @@ class FormattingUtilities(MixinMeta, metaclass=CompositeMetaClass):
|
|||||||
async def draw_time(self, ctx) -> str:
|
async def draw_time(self, ctx) -> str:
|
||||||
player = lavalink.get_player(ctx.guild.id)
|
player = lavalink.get_player(ctx.guild.id)
|
||||||
paused = player.paused
|
paused = player.paused
|
||||||
pos = player.position
|
pos = player.position or 1
|
||||||
dur = getattr(player.current, "length", player.position or 1)
|
dur = getattr(player.current, "length", player.position or 1)
|
||||||
sections = 12
|
sections = 12
|
||||||
loc_time = round((pos / dur if dur != 0 else pos) * sections)
|
loc_time = round((pos / dur if dur != 0 else pos) * sections)
|
||||||
|
|||||||
@ -8,14 +8,16 @@ import lavalink
|
|||||||
|
|
||||||
from fuzzywuzzy import process
|
from fuzzywuzzy import process
|
||||||
from redbot.core import commands
|
from redbot.core import commands
|
||||||
|
from redbot.core.i18n import Translator
|
||||||
from redbot.core.utils import AsyncIter
|
from redbot.core.utils import AsyncIter
|
||||||
|
|
||||||
from ...audio_dataclasses import LocalPath, Query
|
from ...audio_dataclasses import LocalPath, Query
|
||||||
from ...errors import TrackEnqueueError
|
from ...errors import TrackEnqueueError
|
||||||
from ..abc import MixinMeta
|
from ..abc import MixinMeta
|
||||||
from ..cog_utils import CompositeMetaClass, _
|
from ..cog_utils import CompositeMetaClass
|
||||||
|
|
||||||
log = logging.getLogger("red.cogs.Audio.cog.Utilities.local_tracks")
|
log = logging.getLogger("red.cogs.Audio.cog.Utilities.local_tracks")
|
||||||
|
_ = Translator("Audio", Path(__file__))
|
||||||
|
|
||||||
|
|
||||||
class LocalTrackUtilities(MixinMeta, metaclass=CompositeMetaClass):
|
class LocalTrackUtilities(MixinMeta, metaclass=CompositeMetaClass):
|
||||||
|
|||||||
@ -5,6 +5,7 @@ import functools
|
|||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
import re
|
import re
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
from typing import Any, Final, Mapping, MutableMapping, Pattern, Union, cast
|
from typing import Any, Final, Mapping, MutableMapping, Pattern, Union, cast
|
||||||
|
|
||||||
@ -14,16 +15,17 @@ import lavalink
|
|||||||
from discord.embeds import EmptyEmbed
|
from discord.embeds import EmptyEmbed
|
||||||
from redbot.core import bank, commands
|
from redbot.core import bank, commands
|
||||||
from redbot.core.commands import Context
|
from redbot.core.commands import Context
|
||||||
|
from redbot.core.i18n import Translator
|
||||||
from redbot.core.utils import AsyncIter
|
from redbot.core.utils import AsyncIter
|
||||||
from redbot.core.utils.chat_formatting import humanize_number
|
from redbot.core.utils.chat_formatting import humanize_number
|
||||||
|
|
||||||
from ...apis.playlist_interface import get_all_playlist_for_migration23
|
from ...apis.playlist_interface import get_all_playlist_for_migration23
|
||||||
from ...utils import PlaylistScope, task_callback
|
from ...utils import PlaylistScope, task_callback
|
||||||
from ..abc import MixinMeta
|
from ..abc import MixinMeta
|
||||||
from ..cog_utils import CompositeMetaClass, _
|
from ..cog_utils import CompositeMetaClass
|
||||||
|
|
||||||
log = logging.getLogger("red.cogs.Audio.cog.Utilities.miscellaneous")
|
log = logging.getLogger("red.cogs.Audio.cog.Utilities.miscellaneous")
|
||||||
|
_ = Translator("Audio", Path(__file__))
|
||||||
_RE_TIME_CONVERTER: Final[Pattern] = re.compile(r"(?:(\d+):)?([0-5]?[0-9]):([0-5][0-9])")
|
_RE_TIME_CONVERTER: Final[Pattern] = re.compile(r"(?:(\d+):)?([0-5]?[0-9]):([0-5][0-9])")
|
||||||
_prefer_lyrics_cache = {}
|
_prefer_lyrics_cache = {}
|
||||||
|
|
||||||
@ -204,11 +206,8 @@ class MiscellaneousUtilities(MixinMeta, metaclass=CompositeMetaClass):
|
|||||||
|
|
||||||
async def queue_duration(self, ctx: commands.Context) -> int:
|
async def queue_duration(self, ctx: commands.Context) -> int:
|
||||||
player = lavalink.get_player(ctx.guild.id)
|
player = lavalink.get_player(ctx.guild.id)
|
||||||
duration = []
|
dur = [i.length async for i in AsyncIter(player.queue, steps=50)]
|
||||||
async for i in AsyncIter(range(len(player.queue))):
|
queue_dur = sum(dur)
|
||||||
if not player.queue[i].is_stream:
|
|
||||||
duration.append(player.queue[i].length)
|
|
||||||
queue_dur = sum(duration)
|
|
||||||
if not player.queue:
|
if not player.queue:
|
||||||
queue_dur = 0
|
queue_dur = 0
|
||||||
try:
|
try:
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
import logging
|
import logging
|
||||||
import time
|
import time
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
from typing import List, Optional, Tuple, Union
|
from typing import List, Optional, Tuple, Union
|
||||||
|
|
||||||
@ -9,6 +10,7 @@ import lavalink
|
|||||||
|
|
||||||
from discord.embeds import EmptyEmbed
|
from discord.embeds import EmptyEmbed
|
||||||
from redbot.core import commands
|
from redbot.core import commands
|
||||||
|
from redbot.core.i18n import Translator
|
||||||
from redbot.core.utils import AsyncIter
|
from redbot.core.utils import AsyncIter
|
||||||
from redbot.core.utils.chat_formatting import bold, escape
|
from redbot.core.utils.chat_formatting import bold, escape
|
||||||
|
|
||||||
@ -17,9 +19,10 @@ from ...audio_logging import IS_DEBUG, debug_exc_log
|
|||||||
from ...errors import QueryUnauthorized, SpotifyFetchError, TrackEnqueueError
|
from ...errors import QueryUnauthorized, SpotifyFetchError, TrackEnqueueError
|
||||||
from ...utils import Notifier
|
from ...utils import Notifier
|
||||||
from ..abc import MixinMeta
|
from ..abc import MixinMeta
|
||||||
from ..cog_utils import CompositeMetaClass, _
|
from ..cog_utils import CompositeMetaClass
|
||||||
|
|
||||||
log = logging.getLogger("red.cogs.Audio.cog.Utilities.player")
|
log = logging.getLogger("red.cogs.Audio.cog.Utilities.player")
|
||||||
|
_ = Translator("Audio", Path(__file__))
|
||||||
|
|
||||||
|
|
||||||
class PlayerUtilities(MixinMeta, metaclass=CompositeMetaClass):
|
class PlayerUtilities(MixinMeta, metaclass=CompositeMetaClass):
|
||||||
@ -279,6 +282,9 @@ class PlayerUtilities(MixinMeta, metaclass=CompositeMetaClass):
|
|||||||
return await self.send_embed_msg(
|
return await self.send_embed_msg(
|
||||||
ctx, title=error.message.format(prefix=ctx.prefix)
|
ctx, title=error.message.format(prefix=ctx.prefix)
|
||||||
)
|
)
|
||||||
|
except Exception as e:
|
||||||
|
self.update_player_lock(ctx, False)
|
||||||
|
raise e
|
||||||
self.update_player_lock(ctx, False)
|
self.update_player_lock(ctx, False)
|
||||||
try:
|
try:
|
||||||
if enqueue_tracks:
|
if enqueue_tracks:
|
||||||
@ -327,7 +333,11 @@ class PlayerUtilities(MixinMeta, metaclass=CompositeMetaClass):
|
|||||||
"\nUse `{prefix}audioset spotifyapi` for instructions."
|
"\nUse `{prefix}audioset spotifyapi` for instructions."
|
||||||
).format(prefix=ctx.prefix),
|
).format(prefix=ctx.prefix),
|
||||||
)
|
)
|
||||||
|
except Exception as e:
|
||||||
|
self.update_player_lock(ctx, False)
|
||||||
|
raise e
|
||||||
elif query.is_album or query.is_playlist:
|
elif query.is_album or query.is_playlist:
|
||||||
|
try:
|
||||||
self.update_player_lock(ctx, True)
|
self.update_player_lock(ctx, True)
|
||||||
track_list = await self.fetch_spotify_playlist(
|
track_list = await self.fetch_spotify_playlist(
|
||||||
ctx,
|
ctx,
|
||||||
@ -336,6 +346,7 @@ class PlayerUtilities(MixinMeta, metaclass=CompositeMetaClass):
|
|||||||
enqueue_tracks,
|
enqueue_tracks,
|
||||||
forced=forced,
|
forced=forced,
|
||||||
)
|
)
|
||||||
|
finally:
|
||||||
self.update_player_lock(ctx, False)
|
self.update_player_lock(ctx, False)
|
||||||
return track_list
|
return track_list
|
||||||
else:
|
else:
|
||||||
@ -387,6 +398,9 @@ class PlayerUtilities(MixinMeta, metaclass=CompositeMetaClass):
|
|||||||
"try again in a few minutes."
|
"try again in a few minutes."
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
except Exception as e:
|
||||||
|
self.update_player_lock(ctx, False)
|
||||||
|
raise e
|
||||||
tracks = result.tracks
|
tracks = result.tracks
|
||||||
playlist_data = result.playlist_info
|
playlist_data = result.playlist_info
|
||||||
if not enqueue:
|
if not enqueue:
|
||||||
@ -581,6 +595,9 @@ class PlayerUtilities(MixinMeta, metaclass=CompositeMetaClass):
|
|||||||
if await self.bot.is_owner(ctx.author):
|
if await self.bot.is_owner(ctx.author):
|
||||||
desc = _("Please check your console or logs for details.")
|
desc = _("Please check your console or logs for details.")
|
||||||
return await self.send_embed_msg(ctx, title=title, description=desc)
|
return await self.send_embed_msg(ctx, title=title, description=desc)
|
||||||
|
except Exception as e:
|
||||||
|
self.update_player_lock(ctx, False)
|
||||||
|
raise e
|
||||||
description = await self.get_track_description(
|
description = await self.get_track_description(
|
||||||
single_track, self.local_folder_current_path
|
single_track, self.local_folder_current_path
|
||||||
)
|
)
|
||||||
@ -659,6 +676,7 @@ class PlayerUtilities(MixinMeta, metaclass=CompositeMetaClass):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.update_player_lock(ctx, False)
|
self.update_player_lock(ctx, False)
|
||||||
raise e
|
raise e
|
||||||
|
finally:
|
||||||
self.update_player_lock(ctx, False)
|
self.update_player_lock(ctx, False)
|
||||||
return track_list
|
return track_list
|
||||||
|
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import datetime
|
|||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
import math
|
import math
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
from typing import List, MutableMapping, Optional, Tuple, Union
|
from typing import List, MutableMapping, Optional, Tuple, Union
|
||||||
|
|
||||||
@ -12,6 +13,7 @@ import lavalink
|
|||||||
|
|
||||||
from discord.embeds import EmptyEmbed
|
from discord.embeds import EmptyEmbed
|
||||||
from redbot.core import commands
|
from redbot.core import commands
|
||||||
|
from redbot.core.i18n import Translator
|
||||||
from redbot.core.utils import AsyncIter
|
from redbot.core.utils import AsyncIter
|
||||||
from redbot.core.utils.chat_formatting import box
|
from redbot.core.utils.chat_formatting import box
|
||||||
from redbot.core.utils.menus import start_adding_reactions
|
from redbot.core.utils.menus import start_adding_reactions
|
||||||
@ -23,9 +25,10 @@ from ...audio_logging import debug_exc_log
|
|||||||
from ...errors import TooManyMatches, TrackEnqueueError
|
from ...errors import TooManyMatches, TrackEnqueueError
|
||||||
from ...utils import Notifier, PlaylistScope
|
from ...utils import Notifier, PlaylistScope
|
||||||
from ..abc import MixinMeta
|
from ..abc import MixinMeta
|
||||||
from ..cog_utils import CompositeMetaClass, _
|
from ..cog_utils import CompositeMetaClass
|
||||||
|
|
||||||
log = logging.getLogger("red.cogs.Audio.cog.Utilities.playlists")
|
log = logging.getLogger("red.cogs.Audio.cog.Utilities.playlists")
|
||||||
|
_ = Translator("Audio", Path(__file__))
|
||||||
|
|
||||||
|
|
||||||
class PlaylistUtilities(MixinMeta, metaclass=CompositeMetaClass):
|
class PlaylistUtilities(MixinMeta, metaclass=CompositeMetaClass):
|
||||||
@ -413,6 +416,9 @@ class PlaylistUtilities(MixinMeta, metaclass=CompositeMetaClass):
|
|||||||
"try again in a few minutes."
|
"try again in a few minutes."
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
except Exception as e:
|
||||||
|
self.update_player_lock(ctx, False)
|
||||||
|
raise e
|
||||||
|
|
||||||
track = result.tracks[0]
|
track = result.tracks[0]
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
@ -599,6 +605,9 @@ class PlaylistUtilities(MixinMeta, metaclass=CompositeMetaClass):
|
|||||||
"minutes."
|
"minutes."
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
except Exception as e:
|
||||||
|
self.update_player_lock(ctx, False)
|
||||||
|
raise e
|
||||||
|
|
||||||
tracks = result.tracks
|
tracks = result.tracks
|
||||||
if not tracks:
|
if not tracks:
|
||||||
@ -625,6 +634,9 @@ class PlaylistUtilities(MixinMeta, metaclass=CompositeMetaClass):
|
|||||||
"minutes."
|
"minutes."
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
except Exception as e:
|
||||||
|
self.update_player_lock(ctx, False)
|
||||||
|
raise e
|
||||||
|
|
||||||
tracks = result.tracks
|
tracks = result.tracks
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
import logging
|
import logging
|
||||||
import math
|
import math
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
from typing import List, Tuple
|
from typing import List, Tuple
|
||||||
|
|
||||||
@ -8,14 +9,16 @@ import lavalink
|
|||||||
|
|
||||||
from fuzzywuzzy import process
|
from fuzzywuzzy import process
|
||||||
from redbot.core import commands
|
from redbot.core import commands
|
||||||
|
from redbot.core.i18n import Translator
|
||||||
from redbot.core.utils import AsyncIter
|
from redbot.core.utils import AsyncIter
|
||||||
from redbot.core.utils.chat_formatting import humanize_number
|
from redbot.core.utils.chat_formatting import humanize_number
|
||||||
|
|
||||||
from ...audio_dataclasses import LocalPath, Query
|
from ...audio_dataclasses import LocalPath, Query
|
||||||
from ..abc import MixinMeta
|
from ..abc import MixinMeta
|
||||||
from ..cog_utils import CompositeMetaClass, _
|
from ..cog_utils import CompositeMetaClass
|
||||||
|
|
||||||
log = logging.getLogger("red.cogs.Audio.cog.Utilities.queue")
|
log = logging.getLogger("red.cogs.Audio.cog.Utilities.queue")
|
||||||
|
_ = Translator("Audio", Path(__file__))
|
||||||
|
|
||||||
|
|
||||||
class QueueUtilities(MixinMeta, metaclass=CompositeMetaClass):
|
class QueueUtilities(MixinMeta, metaclass=CompositeMetaClass):
|
||||||
|
|||||||
@ -1,7 +1,12 @@
|
|||||||
# The equalizer class and some audio eq functions are derived from
|
# The equalizer class and some audio eq functions are derived from
|
||||||
# 180093157554388993's work, with his permission
|
# 180093157554388993's work, with his permission
|
||||||
|
from pathlib import Path
|
||||||
from typing import Final
|
from typing import Final
|
||||||
|
|
||||||
|
from redbot.core.i18n import Translator
|
||||||
|
|
||||||
|
_ = Translator("Audio", Path(__file__))
|
||||||
|
|
||||||
|
|
||||||
class Equalizer:
|
class Equalizer:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
|||||||
@ -1,5 +1,11 @@
|
|||||||
|
from pathlib import Path
|
||||||
|
|
||||||
import aiohttp
|
import aiohttp
|
||||||
|
|
||||||
|
from redbot.core.i18n import Translator
|
||||||
|
|
||||||
|
_ = Translator("Audio", Path(__file__))
|
||||||
|
|
||||||
|
|
||||||
class AudioError(Exception):
|
class AudioError(Exception):
|
||||||
"""Base exception for errors in the Audio cog."""
|
"""Base exception for errors in the Audio cog."""
|
||||||
@ -91,6 +97,10 @@ class SpotifyFetchError(SpotifyApiError):
|
|||||||
class YouTubeApiError(ApiError):
|
class YouTubeApiError(ApiError):
|
||||||
"""Base exception for YouTube Data API errors."""
|
"""Base exception for YouTube Data API errors."""
|
||||||
|
|
||||||
|
def __init__(self, message, *args):
|
||||||
|
self.message = message
|
||||||
|
super().__init__(*args)
|
||||||
|
|
||||||
|
|
||||||
class DatabaseError(AudioError):
|
class DatabaseError(AudioError):
|
||||||
"""Base exception for database errors in the Audio cog."""
|
"""Base exception for database errors in the Audio cog."""
|
||||||
|
|||||||
@ -10,17 +10,18 @@ import shutil
|
|||||||
import sys
|
import sys
|
||||||
import tempfile
|
import tempfile
|
||||||
import time
|
import time
|
||||||
|
|
||||||
from typing import ClassVar, Final, List, Optional, Pattern, Tuple
|
from typing import ClassVar, Final, List, Optional, Pattern, Tuple
|
||||||
|
|
||||||
import aiohttp
|
import aiohttp
|
||||||
|
from tqdm import tqdm
|
||||||
|
|
||||||
from redbot.core import data_manager
|
from redbot.core import data_manager
|
||||||
from tqdm import tqdm
|
from redbot.core.i18n import Translator
|
||||||
|
|
||||||
from .errors import LavalinkDownloadFailed
|
from .errors import LavalinkDownloadFailed
|
||||||
from .utils import task_callback
|
from .utils import task_callback
|
||||||
|
|
||||||
|
_ = Translator("Audio", pathlib.Path(__file__))
|
||||||
log = logging.getLogger("red.audio.manager")
|
log = logging.getLogger("red.audio.manager")
|
||||||
JAR_VERSION: Final[str] = "3.3.1.4"
|
JAR_VERSION: Final[str] = "3.3.1.4"
|
||||||
JAR_BUILD: Final[int] = 1115
|
JAR_BUILD: Final[int] = 1115
|
||||||
|
|||||||
@ -4,13 +4,16 @@ import logging
|
|||||||
import time
|
import time
|
||||||
|
|
||||||
from enum import Enum, unique
|
from enum import Enum, unique
|
||||||
|
from pathlib import Path
|
||||||
from typing import MutableMapping
|
from typing import MutableMapping
|
||||||
|
|
||||||
import discord
|
import discord
|
||||||
|
|
||||||
from redbot.core import commands
|
from redbot.core import commands
|
||||||
|
from redbot.core.i18n import Translator
|
||||||
|
|
||||||
log = logging.getLogger("red.cogs.Audio.task.callback")
|
log = logging.getLogger("red.cogs.Audio.task.callback")
|
||||||
|
_ = Translator("Audio", Path(__file__))
|
||||||
|
|
||||||
|
|
||||||
class CacheLevel:
|
class CacheLevel:
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user