From 673e3892c13ea3d5c6729c877b6fec1eb467e445 Mon Sep 17 00:00:00 2001 From: Stefano Pigozzi Date: Sun, 27 May 2018 15:23:33 +0200 Subject: [PATCH] Rewrite del musicbot, supporto predownload canzoni --- discordbot.py | 320 +++++++++++++++++++++++++++----------------------- 1 file changed, 170 insertions(+), 150 deletions(-) diff --git a/discordbot.py b/discordbot.py index b7f6a251..8291a7e6 100644 --- a/discordbot.py +++ b/discordbot.py @@ -18,6 +18,7 @@ import subprocess import async_timeout import raven import cast +import pickle # Queue emojis queue_emojis = [":one:", @@ -38,10 +39,20 @@ loop = asyncio.get_event_loop() config = configparser.ConfigParser() config.read("config.ini") + class DurationError(Exception): pass -class LocalFileError(Exception): + +class InfoNotRetrievedError(Exception): + pass + + +class FileNotDownloadedError(Exception): + pass + + +class AlreadyDownloadedError(Exception): pass @@ -66,7 +77,8 @@ class OldVideo: async def download(self): # Retrieve info before downloading with youtube_dl.YoutubeDL() as ytdl: - info = await loop.run_in_executor(executor, functools.partial(ytdl.extract_info, self.ytdl_url, download=False)) + info = await loop.run_in_executor(executor, functools.partial(ytdl.extract_info, self.ytdl_url, + download=False)) if "entries" in info: info = info["entries"][0] file_id = info.get("title", str(hash(self.ytdl_url))) @@ -111,23 +123,54 @@ class OldVideo: class Video: - def __init__(self, url=None, file=None): + def __init__(self, url: str=None, file: str=None, info: dict=None): self.url = url - self.file = file + if file is None and info is None: + self.file = str(hash(url)) + ".opus" + elif info is not None: + self.file = re.sub(r'[/\\?*"<>|!]', "_", info["title"]) + ".opus" + else: + self.file = file + self.downloaded = False if file is None else True + self.info = info def __str__(self): - pass + if self.info is None or "title" not in self.info: + return f"`{self.file}`" + return f"_{self.info['title']}_" - async def retrieve_info(self): - if url is None: - raise LocalFileError() - with youtube_dl.YoutubeDL({"quiet": True, - "ignoreerrors": True, - "simulate": True}) as ytdl: - await loop.run_in_executor(executor, functools.partial(ytdl.extract_info, url=self.url, download=False) - # TODO + async def download(self, progress_hooks: typing.List["function"]=None): + # File already downloaded + if self.downloaded: + raise AlreadyDownloadedError() + # No progress hooks + if progress_hooks is None: + progress_hooks = [] + # Check if under max duration + if self.info is not None and self.info.get("duration", 0) > int(config["YouTube"]["max_duration"]): + raise DurationError() + # Download the file + with youtube_dl.YoutubeDL({"noplaylist": True, + "format": "best", + "postprocessors": [{ + "key": 'FFmpegExtractAudio', + "preferredcodec": 'opus' + }], + "outtmpl": f"./opusfiles/{self.file}", + "progress_hooks": progress_hooks, + "quiet": True}) as ytdl: + await loop.run_in_executor(executor, functools.partial(ytdl.download, [self.url])) + self.downloaded = True + + async def create_player(self) -> discord.voice_client.ProcessPlayer: + # Check if the file has been downloaded + if not self.downloaded: + raise FileNotDownloadedError() + global voice_client + return voice_client.create_ffmpeg_player(f"./opusfiles/{self.file}") +# noinspection PyUnreachableCode if __debug__: version = "Dev" commit_msg = "_in sviluppo_" @@ -150,9 +193,10 @@ if platform.system() == "Linux": elif platform.system() == "Windows": discord.opus.load_opus("libopus-0.dll") -voice_client: typing.Optional[discord.VoiceClient] = None -voice_player: typing.Optional[discord.voice_client.StreamPlayer] = None -voice_queue: typing.List[OldVideo] = [] +voice_client = None +voice_player = None +voice_queue = [] +old_voice_queue = [] # Init the executor executor = concurrent.futures.ThreadPoolExecutor(max_workers=3) @@ -198,7 +242,8 @@ async def on_ready(): @client.event async def on_message(message: discord.Message): - global voice_queue + global voice_client + global old_voice_queue global voice_player if not message.content.startswith("!"): return @@ -256,127 +301,13 @@ async def on_message(message: discord.Message): session.close() await client.send_message(message.channel, "✅ Sincronizzazione completata!") elif message.content.startswith("!cv"): - cmd_cv(channel=message.channel, - author=message.author, - params=message.content.split(" ")) + await cmd_cv(channel=message.channel, + author=message.author, + params=message.content.split(" ")) elif message.content.startswith("!play"): - # Find the sent url - try: - url = message.content.split(" ", 1)[1] - except IndexError: - await client.send_message(message.channel, "⚠️ Non hai specificato un url!\n" - "Sintassi corretta: `!play