From 36b06c574a09bf1d74a2b465818b5c5b83f22eff Mon Sep 17 00:00:00 2001 From: Stefano Pigozzi Date: Sat, 28 Mar 2020 19:38:14 +0100 Subject: [PATCH] Add !funkwhaleplaylist command --- poetry.lock | 45 +++++++++++++----------- pyproject.toml | 4 +-- royalpack/commands/__init__.py | 2 ++ royalpack/commands/funkwhale.py | 4 +-- royalpack/commands/funkwhaleplaylist.py | 32 +++++++++++++++++ royalpack/commands/googlevideo.py | 4 +-- royalpack/commands/play.py | 13 ++++--- royalpack/commands/soundcloud.py | 4 +-- royalpack/commands/yahoovideo.py | 4 +-- royalpack/commands/youtube.py | 4 +-- royalpack/events/discord_play.py | 46 ++++++++++--------------- royalpack/version.py | 2 +- 12 files changed, 99 insertions(+), 65 deletions(-) create mode 100644 royalpack/commands/funkwhaleplaylist.py diff --git a/poetry.lock b/poetry.lock index db53d3d1..653e5c50 100644 --- a/poetry.lock +++ b/poetry.lock @@ -86,7 +86,7 @@ description = "Composable command line interface toolkit" name = "click" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" -version = "7.1" +version = "7.1.1" [[package]] category = "main" @@ -186,7 +186,7 @@ description = "Python audio data toolkit (ID3 and MP3)" name = "eyed3" optional = false python-versions = "*" -version = "0.9.3" +version = "0.9.4" [package.dependencies] deprecation = "*" @@ -217,7 +217,7 @@ description = "Infer file type and MIME type of any file/buffer. No external dep name = "filetype" optional = false python-versions = "*" -version = "1.0.5" +version = "1.0.6" [[package]] category = "main" @@ -486,7 +486,7 @@ description = "Persistent/Functional/Immutable data structures" name = "pyrsistent" optional = false python-versions = "*" -version = "0.15.7" +version = "0.16.0" [package.dependencies] six = "*" @@ -586,7 +586,7 @@ description = "A multipurpose bot and web framework" name = "royalnet" optional = false python-versions = ">=3.8,<4.0" -version = "5.6.2" +version = "5.6.5" [package.dependencies] dateparser = ">=0.7.2,<0.8.0" @@ -716,7 +716,7 @@ description = "Database Abstraction Library" name = "sqlalchemy" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "1.3.13" +version = "1.3.15" [package.extras] mssql = ["pyodbc"] @@ -864,10 +864,10 @@ description = "YouTube video downloader" name = "youtube-dl" optional = false python-versions = "*" -version = "2020.3.8" +version = "2020.3.24" [metadata] -content-hash = "8d7780d1bc898479dda8255988247547650f4034a3ef6e37db47f7ccda1a9d5f" +content-hash = "f0931c9aade41f1ac239401a324cb550f0961b83c1759b5a84effb10e1bba7f2" python-versions = "^3.8" [metadata.files] @@ -952,8 +952,8 @@ chardet = [ {file = "chardet-3.0.4.tar.gz", hash = "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae"}, ] click = [ - {file = "click-7.1-py2.py3-none-any.whl", hash = "sha256:91eb2c43db0254aaf3b14a3c4e0db914a900aa09bbc33c6e87ede4a8f7c969dc"}, - {file = "click-7.1.tar.gz", hash = "sha256:482f552f2d5452b9eeffc44165e8b790dd53f75bcce099a812b65e0357e860e2"}, + {file = "click-7.1.1-py2.py3-none-any.whl", hash = "sha256:e345d143d80bf5ee7534056164e5e112ea5e22716bbb1ce727941f4c8b471b9a"}, + {file = "click-7.1.1.tar.gz", hash = "sha256:8a18b4ea89d8820c5d0c7da8a64b2c324b4dabb695804dbfea19b9be9d88c0cc"}, ] colorama = [ {file = "colorama-0.4.3-py2.py3-none-any.whl", hash = "sha256:7d73d2a99753107a36ac6b455ee49046802e59d9d076ef8e47b61499fa29afff"}, @@ -1002,17 +1002,17 @@ deprecation = [ {file = "discord.py-1.3.2-py3-none-any.whl", hash = "sha256:7424be26b07b37ecad4404d9383d685995a0e0b3df3f9c645bdd3a4d977b83b4"}, ] eyed3 = [ - {file = "eyeD3-0.9.3-py2.py3-none-any.whl", hash = "sha256:82e838a45db298bedf5bfa284e936f9c2216550106d47673bafa1ae262292a36"}, - {file = "eyeD3-0.9.3-py3.8.egg", hash = "sha256:cb750a56163a55181a840bd5f6a78299de247c19c97160055c65e39066a3e422"}, - {file = "eyeD3-0.9.3.tar.gz", hash = "sha256:33020d86aa1ffb4a130e10c27d0c3f9fa05989b862d454e95195ff08eeb67375"}, + {file = "eyeD3-0.9.4-py2.py3-none-any.whl", hash = "sha256:4cba88297ded486ac5b127b4dd5944c453be52c015ed82400fde30907e2972f8"}, + {file = "eyeD3-0.9.4-py3.8.egg", hash = "sha256:b7ac8695d7acdbd67d5e6edc48e9e082faae40ed852cf3e0fcd6d878624ee8d4"}, + {file = "eyeD3-0.9.4.tar.gz", hash = "sha256:11099464e438c11a1d701e723a5065c1556fb59878ad9dce29f924dac3a07a96"}, ] ffmpeg-python = [ {file = "ffmpeg-python-0.2.0.tar.gz", hash = "sha256:65225db34627c578ef0e11c8b1eb528bb35e024752f6f10b78c011f6f64c4127"}, {file = "ffmpeg_python-0.2.0-py3-none-any.whl", hash = "sha256:ac441a0404e053f8b6a1113a77c0f452f1cfc62f6344a769475ffdc0f56c23c5"}, ] filetype = [ - {file = "filetype-1.0.5-py2.py3-none-any.whl", hash = "sha256:4967124d982a71700d94a08c49c4926423500e79382a92070f5ab248d44fe461"}, - {file = "filetype-1.0.5.tar.gz", hash = "sha256:17a3b885f19034da29640b083d767e0f13c2dcb5dcc267945c8b6e5a5a9013c7"}, + {file = "filetype-1.0.6-py2.py3-none-any.whl", hash = "sha256:fd6d0ec56820acccf8c9fb6c3ba7e04a302f6ff6c70bcc09daf4842ae9e2ac30"}, + {file = "filetype-1.0.6.tar.gz", hash = "sha256:99d2b923921cadbe6e451249091ca7156b4beaee6e741bd711a582d4dd2f2881"}, ] future = [ {file = "future-0.18.2.tar.gz", hash = "sha256:b1bead90b70cf6ec3f0710ae53a525360fa360d306a86583adc6bf83a4db537d"}, @@ -1065,6 +1065,9 @@ greenlet = [ {file = "greenlet-0.4.15-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:8041e2de00e745c0e05a502d6e6db310db7faa7c979b3a5877123548a4c0b214"}, {file = "greenlet-0.4.15-cp37-cp37m-win32.whl", hash = "sha256:81fcd96a275209ef117e9ec91f75c731fa18dcfd9ffaa1c0adbdaa3616a86043"}, {file = "greenlet-0.4.15-cp37-cp37m-win_amd64.whl", hash = "sha256:37c9ba82bd82eb6a23c2e5acc03055c0e45697253b2393c9a50cef76a3985304"}, + {file = "greenlet-0.4.15-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:e538b8dae561080b542b0f5af64d47ef859f22517f7eca617bb314e0e03fd7ef"}, + {file = "greenlet-0.4.15-cp38-cp38-win32.whl", hash = "sha256:51155342eb4d6058a0ffcd98a798fe6ba21195517da97e15fca3db12ab201e6e"}, + {file = "greenlet-0.4.15-cp38-cp38-win_amd64.whl", hash = "sha256:7457d685158522df483196b16ec648b28f8e847861adb01a55d41134e7734122"}, {file = "greenlet-0.4.15.tar.gz", hash = "sha256:9416443e219356e3c31f1f918a91badf2e37acf297e2fa13d24d1cc2380f8fbc"}, ] h11 = [ @@ -1259,7 +1262,7 @@ pyreadline = [ {file = "pyreadline-2.1.zip", hash = "sha256:4530592fc2e85b25b1a9f79664433da09237c1a270e4d78ea5aa3a2c7229e2d1"}, ] pyrsistent = [ - {file = "pyrsistent-0.15.7.tar.gz", hash = "sha256:cdc7b5e3ed77bed61270a47d35434a30617b9becdf2478af76ad2c6ade307280"}, + {file = "pyrsistent-0.16.0.tar.gz", hash = "sha256:28669905fe725965daa16184933676547c5bb40a5153055a8dee2a4bd7933ad3"}, ] python-dateutil = [ {file = "python-dateutil-2.8.1.tar.gz", hash = "sha256:73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c"}, @@ -1308,8 +1311,8 @@ riotwatcher = [ {file = "riotwatcher-2.7.1.tar.gz", hash = "sha256:5349271c7e00637b7619491a6070e66603705db60558ea2a690e7016f6e6d9a4"}, ] royalnet = [ - {file = "royalnet-5.6.2-py3-none-any.whl", hash = "sha256:57c9c5de1bbc0a258af489c46eaca326a3b408fe7988fdf6e050f34d5feeaed3"}, - {file = "royalnet-5.6.2.tar.gz", hash = "sha256:b421b84d2cad1ea27016e300f7b005836dd6f5f14975e5b372a91f1f4d52dfd7"}, + {file = "royalnet-5.6.5-py3-none-any.whl", hash = "sha256:ee5d1774fc507cc1be291fefe5716ee7e6bec80ccf1ffd5a6d2278721c7a477b"}, + {file = "royalnet-5.6.5.tar.gz", hash = "sha256:4555bbdf2bc4c75e90f2b465a022178ad6cd6302906c0c5adfe7a7d6e1dbcb06"}, ] royalspells = [ {file = "royalspells-3.2.tar.gz", hash = "sha256:2bd4a9a66514532e35c02c3907425af48c7cb292364c4843c795719a82b25dfe"}, @@ -1323,7 +1326,7 @@ six = [ {file = "six-1.14.0.tar.gz", hash = "sha256:236bdbdce46e6e6a3d61a337c0f8b763ca1e8717c03b369e87a7ec7ce1319c0a"}, ] sqlalchemy = [ - {file = "SQLAlchemy-1.3.13.tar.gz", hash = "sha256:64a7b71846db6423807e96820993fa12a03b89127d278290ca25c0b11ed7b4fb"}, + {file = "SQLAlchemy-1.3.15.tar.gz", hash = "sha256:c4cca4aed606297afbe90d4306b49ad3a4cd36feb3f87e4bfd655c57fd9ef445"}, ] starlette = [ {file = "starlette-0.12.13.tar.gz", hash = "sha256:9597bc28e3c4659107c1c4a45ec32dc45e947d78fe56230222be673b2c36454a"}, @@ -1422,6 +1425,6 @@ yarl = [ {file = "yarl-1.4.2.tar.gz", hash = "sha256:58cd9c469eced558cd81aa3f484b2924e8897049e06889e8ff2510435b7ef74b"}, ] youtube-dl = [ - {file = "youtube_dl-2020.3.8-py2.py3-none-any.whl", hash = "sha256:f9d33129ea4941bea234cdba811c0f97e61c2235a877cf395a869aeea065e009"}, - {file = "youtube_dl-2020.3.8.tar.gz", hash = "sha256:1b098b7ae41551f46dbae70e56dbabdf39c8faf50e072d0c0b42c44d64afebf8"}, + {file = "youtube_dl-2020.3.24-py2.py3-none-any.whl", hash = "sha256:c0be39ea9bca72fa02a0d2d043c5e9bd8ea8e0fe79705e891161d6fcd29da59e"}, + {file = "youtube_dl-2020.3.24.tar.gz", hash = "sha256:4b03efe439f7cae26eba909821d1df00a9a4eb82741cb2e8b78fe29702bd4633"}, ] diff --git a/pyproject.toml b/pyproject.toml index ae318a03..30d27335 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -2,7 +2,7 @@ [tool.poetry] name = "royalpack" - version = "5.6.2" + version = "5.7" description = "A Royalnet command pack for the Royal Games community" authors = ["Stefano Pigozzi "] license = "AGPL-3.0+" @@ -25,7 +25,7 @@ steam = "^0.9.1" [tool.poetry.dependencies.royalnet] - version = "^5.6" + version = "~5.6.5" # Maybe... there is a way to make these selectable? extras = [ "telegram", diff --git a/royalpack/commands/__init__.py b/royalpack/commands/__init__.py index 0df9b6f8..3d102aea 100644 --- a/royalpack/commands/__init__.py +++ b/royalpack/commands/__init__.py @@ -37,6 +37,7 @@ from .dota import DotaCommand from .magickfiorygi import MagickfiorygiCommand from .brawlhalla import BrawlhallaCommand from .diarioshuffle import DiarioshuffleCommand +from .funkwhaleplaylist import FunkwhaleplaylistCommand # Enter the commands of your Pack here! available_commands = [ @@ -78,6 +79,7 @@ available_commands = [ MagickfiorygiCommand, BrawlhallaCommand, DiarioshuffleCommand, + FunkwhaleplaylistCommand, ] # Don't change this, it should automatically generate __all__ diff --git a/royalpack/commands/funkwhale.py b/royalpack/commands/funkwhale.py index 5571a017..8b2364a2 100644 --- a/royalpack/commands/funkwhale.py +++ b/royalpack/commands/funkwhale.py @@ -16,7 +16,7 @@ class FunkwhaleCommand(PlayCommand): def get_embed_color(self): return 0x009FE3 - async def get_url(self, args): + async def get_urls(self, args): search = urllib.parse.quote(args.joined(require_at_least=1)) async with aiohttp.ClientSession() as session: async with session.get(self.config["Funkwhale"]["instance_url"] + @@ -24,4 +24,4 @@ class FunkwhaleCommand(PlayCommand): j = await response.json() if len(j["tracks"]) < 1: raise UserError("Nessun file audio trovato con il nome richiesto.") - return f'{self.config["Funkwhale"]["instance_url"]}{j["tracks"][0]["listen_url"]}' + return [f'{self.config["Funkwhale"]["instance_url"]}{j["tracks"][0]["listen_url"]}'] diff --git a/royalpack/commands/funkwhaleplaylist.py b/royalpack/commands/funkwhaleplaylist.py new file mode 100644 index 00000000..8c9736bb --- /dev/null +++ b/royalpack/commands/funkwhaleplaylist.py @@ -0,0 +1,32 @@ +from .play import PlayCommand +from royalnet.commands import * +import aiohttp +import urllib.parse + + +class FunkwhaleplaylistCommand(PlayCommand): + name: str = "funkwhaleplaylist" + + aliases = ["fwp", "fwplaylist", "funkwhalep"] + + description: str = "Cerca una playlist su RoyalWhale e aggiungila alla coda della chat vocale." + + syntax = "{ricerca}" + + def get_embed_color(self): + return 0x009FE3 + + async def get_urls(self, args): + search = urllib.parse.quote(args.joined(require_at_least=1)) + async with aiohttp.ClientSession() as session: + async with session.get(self.config["Funkwhale"]["instance_url"] + + f"/api/v1/playlists/?q={search}&ordering=-creation_date&playable=true") as response: + j = await response.json() + if len(j["results"]) < 1: + raise UserError("Nessuna playlist trovata con il nome richiesto.") + playlist = j["results"][0] + playlist_id = playlist["id"] + async with session.get(self.config["Funkwhale"]["instance_url"] + + f"/api/v1/playlists/{playlist_id}/tracks") as response: + j = await response.json() + return list(map(lambda t: f'{self.config["Funkwhale"]["instance_url"]}{t["track"]["listen_url"]}', j["results"])) diff --git a/royalpack/commands/googlevideo.py b/royalpack/commands/googlevideo.py index d07fe2ae..27062794 100644 --- a/royalpack/commands/googlevideo.py +++ b/royalpack/commands/googlevideo.py @@ -10,7 +10,7 @@ class GooglevideoCommand(PlayCommand): syntax = "{ricerca}" - async def get_url(self, args): - return f"gvsearch:{args.joined()}" + async def get_urls(self, args): + return [f"gvsearch:{args.joined()}"] # Too bad gvsearch: always finds nothing. diff --git a/royalpack/commands/play.py b/royalpack/commands/play.py index 886bca37..c13bac9a 100644 --- a/royalpack/commands/play.py +++ b/royalpack/commands/play.py @@ -14,12 +14,12 @@ class PlayCommand(Command): syntax = "{url}" - async def get_url(self, args: CommandArgs): + async def get_urls(self, args: CommandArgs): url = args.joined(require_at_least=1) if not (url.startswith("http://") or url.startswith("https://")): raise InvalidInputError(f"L'URL specificato non inizia con il nome di un protocollo supportato" f" ([c]http://[/c] o [c]https://[/c]).") - return url + return [url] def get_embed_color(self) -> Optional[int]: return None @@ -46,14 +46,19 @@ class PlayCommand(Command): else: user_str = str(f"<@{user_discord.discord_id}>") + urls = await self.get_urls(args) + play_task: aio.Task = self.loop.create_task( self.interface.call_herald_event("discord", "discord_play", - url=await self.get_url(args), + urls=urls, guild_id=guild_id, user=user_str, force_color=self.get_embed_color()) ) - await data.reply("⌛ Attendi un attimo...") + if len(urls) > 1: + await data.reply("⌛ Attendi qualche minuto...") + else: + await data.reply("⌛ Attendi un attimo...") await play_task diff --git a/royalpack/commands/soundcloud.py b/royalpack/commands/soundcloud.py index 0090e3dd..f0e68061 100644 --- a/royalpack/commands/soundcloud.py +++ b/royalpack/commands/soundcloud.py @@ -10,5 +10,5 @@ class SoundcloudCommand(PlayCommand): syntax = "{ricerca}" - async def get_url(self, args): - return f"scsearch:{args.joined()}" + async def get_urls(self, args): + return [f"scsearch:{args.joined()}"] diff --git a/royalpack/commands/yahoovideo.py b/royalpack/commands/yahoovideo.py index 482b1042..a0ec05be 100644 --- a/royalpack/commands/yahoovideo.py +++ b/royalpack/commands/yahoovideo.py @@ -10,7 +10,7 @@ class YahoovideoCommand(PlayCommand): syntax = "{ricerca}" - async def get_url(self, args): - return f"yvsearch:{args.joined()}" + async def get_urls(self, args): + return [f"yvsearch:{args.joined()}"] # Too bad yvsearch: always finds nothing. diff --git a/royalpack/commands/youtube.py b/royalpack/commands/youtube.py index 870c8aca..f684a59a 100644 --- a/royalpack/commands/youtube.py +++ b/royalpack/commands/youtube.py @@ -10,5 +10,5 @@ class YoutubeCommand(PlayCommand): syntax = "{ricerca}" - async def get_url(self, args): - return f"ytsearch:{args.joined()}" + async def get_urls(self, args): + return [f"ytsearch:{args.joined()}"] diff --git a/royalpack/events/discord_play.py b/royalpack/events/discord_play.py index 0db80f3d..f122f3a4 100644 --- a/royalpack/events/discord_play.py +++ b/royalpack/events/discord_play.py @@ -13,7 +13,7 @@ class DiscordPlayEvent(rc.Event): name = "discord_play" async def run(self, - url: str, + urls: List[str], guild_id: Optional[int] = None, user: Optional[str] = None, force_color: Optional[int] = None, @@ -23,18 +23,8 @@ class DiscordPlayEvent(rc.Event): serf: rsd.DiscordSerf = self.serf client: discord.Client = self.serf.client - - # TODO: fix this in Royalnet sometime - candidate_players: List[rsd.VoicePlayer] = [] - for player in serf.voice_players: - player: rsd.VoicePlayer - if not player.voice_client.is_connected(): - continue - if guild_id is not None: - guild = client.get_guild(guild_id) - if guild != player.voice_client.guild: - continue - candidate_players.append(player) + guild: discord.Guild = client.get_guild(guild_id) if guild_id is not None else None + candidate_players: List[rsd.VoicePlayer] = serf.find_voice_players(guild) if len(candidate_players) == 0: raise rc.UserError("Il bot non è in nessun canale vocale.\n" @@ -45,21 +35,23 @@ class DiscordPlayEvent(rc.Event): raise rc.CommandError("Non so in che Server riprodurre questo file...\n" "Invia il comando su Discord, per favore!") - ytds = await rbd.YtdlDiscord.from_url(url) added: List[rbd.YtdlDiscord] = [] too_long: List[rbd.YtdlDiscord] = [] - if isinstance(voice_player.playing, RoyalQueue): - for index, ytd in enumerate(ytds): - if ytd.info.duration >= datetime.timedelta(seconds=self.config["Play"]["max_song_duration"]): - too_long.append(ytd) - continue - await ytd.convert_to_pcm() - added.append(ytd) - voice_player.playing.contents.append(ytd) - if not voice_player.voice_client.is_playing(): - await voice_player.start() - else: - raise rc.CommandError(f"Non so come aggiungere musica a [c]{voice_player.playing.__class__.__qualname__}[/c]!") + + for url in urls: + ytds = await rbd.YtdlDiscord.from_url(url) + if isinstance(voice_player.playing, RoyalQueue): + for index, ytd in enumerate(ytds): + if ytd.info.duration >= datetime.timedelta(seconds=self.config["Play"]["max_song_duration"]): + too_long.append(ytd) + continue + await ytd.convert_to_pcm() + added.append(ytd) + voice_player.playing.contents.append(ytd) + if not voice_player.voice_client.is_playing(): + await voice_player.start() + else: + raise rc.CommandError(f"Non so come aggiungere musica a [c]{voice_player.playing.__class__.__qualname__}[/c]!") main_channel: discord.TextChannel = client.get_channel(self.config["Discord"]["main_channel_id"]) @@ -85,7 +77,7 @@ class DiscordPlayEvent(rc.Event): )) if len(added) + len(too_long) == 0: - raise + raise rc.InvalidInputError("Non è stato aggiunto nessun file alla coda.") return { "added": [{ diff --git a/royalpack/version.py b/royalpack/version.py index 3e2df96c..4784f166 100644 --- a/royalpack/version.py +++ b/royalpack/version.py @@ -1 +1 @@ -semantic = "5.6.2" +semantic = "5.7"