1
Fork 0
mirror of https://github.com/RYGhub/royalnet.git synced 2024-11-27 13:34:28 +00:00

Merge branch 'unity' into unity-docs

This commit is contained in:
Steffo 2019-04-23 16:46:12 +02:00
commit e300926f4c
8 changed files with 92 additions and 16 deletions

View file

@ -10,10 +10,15 @@ class RoyalPCMAudio(AudioSource):
self._file = open(self.rpf.audio_filename, "rb")
@staticmethod
def create_from_url(url) -> typing.List["RoyalPCMAudio"]:
def create_from_url(url: str) -> typing.List["RoyalPCMAudio"]:
rpf_list = RoyalPCMFile.create_from_url(url)
return [RoyalPCMAudio(rpf) for rpf in rpf_list]
@staticmethod
def create_from_ytsearch(search: str, amount: int = 1) -> typing.List["RoyalPCMAudio"]:
rpf_list = RoyalPCMFile.create_from_ytsearch(search, amount)
return [RoyalPCMAudio(rpf) for rpf in rpf_list]
def is_opus(self):
return False

View file

@ -48,7 +48,14 @@ class RoyalPCMFile(YtdlFile):
@staticmethod
def create_from_url(url, **ytdl_args) -> typing.List["RoyalPCMFile"]:
info_list = YtdlInfo.create_from_url(url)
return [RoyalPCMFile(info) for info in info_list]
return [RoyalPCMFile(info, **ytdl_args) for info in info_list]
@staticmethod
def create_from_ytsearch(search: str, amount: int = 1, **ytdl_args) -> typing.List["RoyalPCMFile"]:
"""Search a string on YouTube and download the first amount videos found."""
url = f"ytsearch{amount}:{search}"
info_list = YtdlInfo.create_from_url(url)
return [RoyalPCMFile(info, **ytdl_args) for info in info_list]
@property
def _ytdl_filename(self):

View file

@ -53,7 +53,9 @@ class DiscordBot(GenericBot):
.replace("[u]", "__") \
.replace("[/u]", "__") \
.replace("[c]", "`") \
.replace("[/c]", "`")
.replace("[/c]", "`") \
.replace("[p]", "```") \
.replace("[/p]", "```")
await call.channel.send(escaped_text)
async def net_request(call, message: Message, destination: str):
@ -203,11 +205,9 @@ class DiscordBot(GenericBot):
await self.client.connect()
# TODO: how to stop?
async def add_to_music_data(self, url: str, guild: discord.Guild):
async def add_to_music_data(self, audio_sources: typing.List[discord.AudioSource], guild: discord.Guild):
"""Add a file to the corresponding music_data object."""
log.debug(f"Adding {url} to music_data of {guild}")
guild_music_data = self.music_data[guild]
audio_sources = await asyncify(RoyalPCMAudio.create_from_url, url)
for audio_source in audio_sources:
log.debug(f"Adding {audio_source} to music_data")
guild_music_data.add(audio_source)

View file

@ -48,7 +48,9 @@ class TelegramBot(GenericBot):
.replace("[u]", "<b>") \
.replace("[/u]", "</b>") \
.replace("[c]", "<code>") \
.replace("[/c]", "</code>")
.replace("[/c]", "</code>") \
.replace("[p]", "<pre>") \
.replace("[/p]", "</pre>")
await asyncify(call.channel.send_message, escaped_text, parse_mode="HTML")
async def net_request(call, message: Message, destination: str):

View file

@ -42,10 +42,10 @@ class ErrorHandlerCommand(Command):
await call.reply("⚠️ Il bot non è stato configurato correttamente, quindi questo comando non può essere eseguito. L'errore è stato segnalato all'amministratore.")
return
if isinstance(exception, RoyalnetError):
await call.reply(f"⚠️ La richiesta a Royalnet ha restituito un errore: {exception.exc}")
await call.reply(f"⚠️ La richiesta a Royalnet ha restituito un errore: [p]{exception.exc}[/p]")
return
if isinstance(exception, ExternalError):
await call.reply("⚠️ Una risorsa esterna necessaria per l'esecuzione del comando non ha funzionato correttamente, quindi il comando è stato annullato.")
return
await call.reply(f"❌ Eccezione non gestita durante l'esecuzione del comando:\n[b]{exception.__class__.__name__}[/b]\n{exception}")
await call.reply(f"❌ Eccezione non gestita durante l'esecuzione del comando:\n[b]{exception.__class__.__name__}[/b]\n[p]{exception}[/p]")
log.error(f"Unhandled exception - {exception.__class__.__name__}: {exception}")

View file

@ -1,8 +1,11 @@
import typing
import asyncio
from ..utils import Command, Call, NetworkHandler
import youtube_dl
import ffmpeg
from ..utils import Command, Call, NetworkHandler, asyncify
from ..network import Message, RequestSuccessful
from ..error import TooManyFoundError, NoneFoundError
from ..audio import RoyalPCMAudio, YtdlInfo
if typing.TYPE_CHECKING:
from ..bots import DiscordBot
@ -16,6 +19,11 @@ class PlayMessage(Message):
self.guild_name: typing.Optional[str] = guild_name
class PlaySuccessful(RequestSuccessful):
def __init__(self, info_list: typing.List[YtdlInfo]):
self.info_list: typing.List[YtdlInfo] = info_list
class PlayNH(NetworkHandler):
message_type = PlayMessage
@ -36,9 +44,21 @@ class PlayNH(NetworkHandler):
# TODO: change Exception
raise Exception("No music_data for this guild")
# Start downloading
# noinspection PyAsyncCall
loop.create_task(bot.add_to_music_data(message.url, guild))
return RequestSuccessful()
try:
audio_sources: typing.List[RoyalPCMAudio] = await asyncify(RoyalPCMAudio.create_from_url, message.url)
except youtube_dl.utils.DownloadError:
audio_sources = await asyncify(RoyalPCMAudio.create_from_ytsearch, message.url)
await bot.add_to_music_data(audio_sources, guild)
return PlaySuccessful(info_list=[source.rpf.info for source in audio_sources])
async def notify_on_timeout(call: Call, url: str, time: float, repeat: bool = False):
"""Send a message after a while to let the user know that the bot is still downloading the files and hasn't crashed."""
while True:
await asyncio.sleep(time)
await call.reply(f" Il download di [c]{url}[/c] sta richiedendo più tempo del solito, ma è ancora in corso!")
if not repeat:
break
class PlayCommand(Command):
@ -51,5 +71,46 @@ class PlayCommand(Command):
@classmethod
async def common(cls, call: Call):
guild, url = call.args.match(r"(?:\[(.+)])?\s*(.+)")
await call.net_request(PlayMessage(url, guild), "discord")
await call.reply(f"✅ Richiesta la riproduzione di [c]{url}[/c].")
download_task = loop.create_task(call.net_request(PlayMessage(url, guild), "discord"))
notify_task = loop.create_task(notify_on_timeout(call, url, time=20, repeat=True))
try:
response: PlaySuccessful = await download_task
except Exception as exc:
# RoyalPCMFile errors
if isinstance(exc, FileExistsError):
await call.reply(f"❌ Scaricare [c]{url}[/c] significherebbe sovrascrivere un file già esistente.\nQuesto è un bug, e non dovrebbe mai succedere. Se è appena successo, segnalate il problema a https://github.com/Steffo99/royalnet/issues.\n[p]{exc}[/p]")
return
# ffmpeg errors
if isinstance(exc, ffmpeg.Error):
await call.reply(f"⚠️ Errore durante la conversione a PCM di [c]{url}[/c]:\n[p]{exc}[/p]")
return
# youtube_dl errors
if isinstance(exc, youtube_dl.utils.ContentTooShortError):
await call.reply(f"⚠️ Mentre era in corso il download di [c]{url}[/c], la connessione è stata interrotta, quindi la riproduzione è stata annullata.\n[p]{exc}[/p]")
return
if isinstance(exc, youtube_dl.utils.UnavailableVideoError):
await call.reply(f"⚠️ Non è disponibile nessun audio su [c]{url}[/c].\n[p]{exc}[/p]")
return
if isinstance(exc, youtube_dl.utils.SameFileError):
await call.reply(f"❌ Scaricare [c]{url}[/c] significherebbe scaricare due file diversi sullo stesso nome.\nQuesto è un bug, e non dovrebbe mai succedere. Se è appena successo, segnalate il problema a https://github.com/Steffo99/royalnet/issues.\n[p]{exc}[/p]")
return
if isinstance(exc, youtube_dl.utils.GeoRestrictedError):
await call.reply(f"⚠️ [c]{url}[/c] non può essere visualizzato nel paese in cui si trova il bot e non può essere scaricato.\n[p]{exc}[/p]")
return
if isinstance(exc, youtube_dl.utils.UnsupportedError):
await call.reply(f"⚠️ [c]{url}[/c] non è supportato da YoutubeDL e non può essere scaricato.\n[p]{exc}[/p]")
return
if isinstance(exc, youtube_dl.utils.ExtractorError):
await call.reply(f"⚠️ Errore nella ricerca di info per [c]{url}[/c]:\n[p]{exc}[/p]")
return
if isinstance(exc, youtube_dl.utils.DownloadError):
await call.reply(f"⚠️ Errore nel download di [c]{url}[/c]:\n[p]{exc}[/p]")
return
if isinstance(exc, youtube_dl.utils.YoutubeDLError):
await call.reply(f"⚠️ Errore di youtube_dl per [c]{url}[/c]:\n[p]{exc}[/p]")
return
raise
finally:
notify_task.cancel()
for info in response.info_list:
await call.reply(f"⬇️ Download di [i]{info.title}[/i] completato.")

View file

@ -22,7 +22,7 @@ class PlaymodeNH(NetworkHandler):
@classmethod
async def discord(cls, bot: "DiscordBot", message: PlaymodeMessage):
"""Handle a play Royalnet request. That is, add audio to a PlayMode."""
"""Handle a playmode Royalnet request. That is, change current PlayMode."""
# Find the matching guild
if message.guild_name:
guild = bot.client.find_guild(message.guild_name)

View file

@ -4,5 +4,6 @@ import typing
async def asyncify(function: typing.Callable, *args, **kwargs):
# TODO: make cancellable somehow
loop = asyncio.get_running_loop()
return await loop.run_in_executor(None, functools.partial(function, *args, **kwargs))