Fixing erros due to processing

This commit is contained in:
Rafael Vargas
2022-07-24 14:25:44 -03:00
parent 56456bf2ed
commit b904c75caa
16 changed files with 179 additions and 305 deletions

View File

@@ -1,10 +1,11 @@
import asyncio
from typing import List
from Config.Configs import Configs
from yt_dlp import YoutubeDL
from yt_dlp import YoutubeDL, DownloadError
from concurrent.futures import ThreadPoolExecutor
from Music.Song import Song
from Utils.Utils import Utils, run_async
from Config.Exceptions import DownloadingError
class Downloader:
@@ -40,16 +41,20 @@ class Downloader:
self.__playlist_keys = ['entries']
def finish_one_song(self, song: Song) -> Song:
if song.identifier is None:
return None
try:
if song.identifier is None:
return None
if Utils.is_url(song.identifier):
song_info = self.__download_url(song.identifier)
else:
song_info = self.__download_title(song.identifier)
if Utils.is_url(song.identifier):
song_info = self.__download_url(song.identifier)
else:
song_info = self.__download_title(song.identifier)
song.finish_down(song_info)
return song
song.finish_down(song_info)
return song
# Convert yt_dlp error to my own error
except DownloadError:
raise DownloadingError()
async def preload(self, songs: List[Song]) -> None:
for song in songs:
@@ -81,8 +86,11 @@ class Downloader:
else: # Failed to extract the songs
print(f'DEVELOPER NOTE -> Failed to Extract URL {url}')
return []
# Convert the yt_dlp download error to own error
except DownloadError:
raise DownloadingError()
except Exception as e:
print(f'DEVELOPER NOTE -> Error Extracting Music: {e}')
print(f'DEVELOPER NOTE -> Error Extracting Music: {e}, {type(e)}')
raise e
else:
return []

View File

@@ -1,116 +0,0 @@
import asyncio
from discord.ext import commands
from discord import Client, Guild, FFmpegPCMAudio
from discord.ext.commands import Context
from Music.Downloader import Downloader
from Music.Playlist import Playlist
from Music.Song import Song
from Utils.Utils import Timer
class Player(commands.Cog):
def __init__(self, bot: Client, guild: Guild):
self.__down: Downloader = Downloader()
self.__playlist: Playlist = Playlist()
self.__bot: Client = bot
self.__guild: Guild = guild
self.__timer = Timer(self.__timeout_handler)
self.__playing = False
# Flag to control if the player should stop totally the playing
self.__force_stop = False
self.FFMPEG_OPTIONS = {'before_options': '-reconnect 1 -reconnect_streamed 1 -reconnect_delay_max 5',
'options': '-vn'}
@property
def playing(self) -> bool:
return self.__playing
@property
def playlist(self) -> Playlist:
return self.__playlist
async def play(self, ctx: Context) -> str:
if not self.__playing:
first_song = self.__playlist.next_song()
await self.__play_music(ctx, first_song)
async def play_prev(self, ctx: Context) -> None:
song = self.__playlist.prev_song()
if song is not None:
if self.__guild.voice_client.is_playing() or self.__guild.voice_client.is_paused():
# Will forbidden next_song to execute after stopping current player
self.__force_stop = True
self.__guild.voice_client.stop()
self.__playing = False
await self.__play_music(ctx, song)
async def force_stop(self) -> None:
try:
if self.__guild.voice_client is None:
return
self.__guild.voice_client.stop()
await self.__guild.voice_client.disconnect()
self.__playlist.clear()
self.__playlist.loop_off()
except Exception as e:
print(f'DEVELOPER NOTE -> Force Stop Error: {e}')
def __play_next(self, error, ctx: Context) -> None:
if self.__force_stop: # If it's forced to stop player
self.__force_stop = False
return None
song = self.__playlist.next_song()
if song is not None:
coro = self.__play_music(ctx, song)
self.__bot.loop.create_task(coro)
else:
self.__playing = False
async def __play_music(self, ctx: Context, song: Song) -> None:
try:
source = await self.__ensure_source(song)
if source is None:
self.__play_next(None, ctx)
self.__playing = True
player = FFmpegPCMAudio(song.source, **self.FFMPEG_OPTIONS)
voice = self.__guild.voice_client
voice.play(player, after=lambda e: self.__play_next(e, ctx))
self.__timer.cancel()
self.__timer = Timer(self.__timeout_handler)
await ctx.invoke(self.__bot.get_command('np'))
songs = self.__playlist.getSongsToPreload()
asyncio.create_task(self.__down.preload(songs))
except:
self.__play_next(None, ctx)
async def __timeout_handler(self) -> None:
if self.__guild.voice_client is None:
return
if self.__guild.voice_client.is_playing() or self.__guild.voice_client.is_paused():
self.__timer = Timer(self.__timeout_handler)
elif self.__guild.voice_client.is_connected():
self.__playlist.clear()
self.__playlist.loop_off()
await self.__guild.voice_client.disconnect()
async def __ensure_source(self, song: Song) -> str:
while True:
await asyncio.sleep(0.1)
if song.source is not None: # If song got downloaded
return song.source
if song.problematic: # If song got any error
return None

View File

@@ -44,6 +44,9 @@ class Playlist:
def getCurrentSong(self) -> Song:
return self.__current
def setCurrentSong(self, song: Song) -> Song:
self.__current = song
def getSongsToPreload(self) -> List[Song]:
return list(self.__queue)[:self.__configs.MAX_PRELOAD_SONGS]
@@ -73,6 +76,7 @@ class Playlist:
# Get the new song
if len(self.__queue) == 0:
self.__current = None
return None
self.__current = self.__queue.popleft()

View File

@@ -1,4 +1,4 @@
from Config.Exceptions import DeezerError, InvalidInput, SpotifyError, YoutubeError
from Config.Exceptions import DeezerError, InvalidInput, SpotifyError, VulkanError, YoutubeError
from Music.Downloader import Downloader
from Music.Types import Provider
from Music.SpotifySearcher import SpotifySearch
@@ -25,7 +25,10 @@ class Searcher():
track = self.__cleanYoutubeInput(track)
musics = await self.__down.extract_info(track)
return musics
except:
except VulkanError as error:
raise error
except Exception as error:
print(f'[Error in Searcher] -> {error}, {type(error)}')
raise YoutubeError(self.__messages.YOUTUBE_NOT_FOUND, self.__messages.GENERIC_TITLE)
elif provider == Provider.Spotify:

View File

@@ -23,6 +23,7 @@ class Song:
else:
print(f'DEVELOPER NOTE -> {key} not found in info of music: {self.identifier}')
self.destroy()
return
for key in self.__useful_keys:
if key in info.keys():