diff --git a/.gitignore b/.gitignore index 15ca555d..8d1ac075 100644 --- a/.gitignore +++ b/.gitignore @@ -28,4 +28,5 @@ dist/ .idea/**/markdown-navigator.xml .idea/**/markdown-exported-files.xml .idea/**/misc.xml -.idea/**/*.iml \ No newline at end of file +.idea/**/discord.xml +.idea/**/*.iml diff --git a/royalpack/commands/__init__.py b/royalpack/commands/__init__.py index 5f05b712..1982a093 100644 --- a/royalpack/commands/__init__.py +++ b/royalpack/commands/__init__.py @@ -23,7 +23,7 @@ from .emojify import EmojifyCommand from .leagueoflegends import LeagueoflegendsCommand from .diarioquote import DiarioquoteCommand # from .mp3 import Mp3Command -from .peertube import PeertubeCommand +from .peertubeupdates import PeertubeUpdatesCommand from .googlevideo import GooglevideoCommand from .yahoovideo import YahoovideoCommand from .userinfo import UserinfoCommand @@ -58,7 +58,7 @@ available_commands = [ LeagueoflegendsCommand, DiarioquoteCommand, # Mp3Command, - PeertubeCommand, + PeertubeUpdatesCommand, GooglevideoCommand, YahoovideoCommand, UserinfoCommand, diff --git a/royalpack/commands/eat.py b/royalpack/commands/eat.py index 32b32d52..da10a809 100644 --- a/royalpack/commands/eat.py +++ b/royalpack/commands/eat.py @@ -10,7 +10,7 @@ class EatCommand(Command): _FOODS = { "_default": "🍗 Hai mangiato {food}!\n[i]Ma non è successo nulla.[/i]", - + # Sezione nonna "tutto": "👵🏻 Hai mangiato {food}. Si vede che hai gradito il pasto!\n[i]Tua nonna ti serve un'altra" " porzione.[/i]", @@ -21,8 +21,8 @@ class EatCommand(Command): "qualcosa di non cucinato dalla nonna": "👵🏻 Hai mangiato {food}!\n[i]Potresti essere appena stato " "diseredato...[/i]", "qualcosa di non preparato dalla nonna": "👵🏻 Hai mangiato {food}!\n[i]Potresti essere appena stato " - "diseredato...[/i]", - + "diseredato...[/i]", + # Sezione in cui mangi i membri Royal Games "balu": "🚹 Hai mangiato {food}.\n[i]Sa di snado.[/i]", "evilbalu": "🚹 Hai mangiato {food}.\n[i]Sa di snado.[/i]", @@ -37,14 +37,14 @@ class EatCommand(Command): "max": "🚹 Hai mangiato {food}.\n[i]Sa di merda.[/i]", "maxsensei": "🚹 Hai mangiato {food}.\n[i]Sa di merda.[/i]", "steffo": "🚹 Hai mangiato {food}.\n[i]Sa di gelato e di Coca-Cola.[/i]", - - #Sezione delle supercazzole + + # Sezione delle supercazzole "antani": "❔ Hai mangiato {food}. \n[i]Con tarapia tapioco o scherziamo? No, mi permetta. Noi siamo in 4.\n" "Come se fosse antani anche per lei soltanto in due, oppure in quattro anche scribàcchi confaldina?\n" - "Come antifurto, per esempio.[/i]" + "Come antifurto, per esempio.[/i]", "indice": "☝️ Hai mangiato l'{food}. \n[i]Ecco, lo alzi. Lo vede, lo vede che stuzzica?[/i]", - - #sezione con piante e anmali + + # sezione con piante e anmali "cactus": "🌵 Hai mangiato un {food}.\n[i]Gli hai tolto le spine prima, vero?[/i]", "tango": "🌳 Hai mangiato un {food}, e un albero insieme ad esso.\n[i]Senti le tue ferite curarsi...[/i]", "gatto": "🐱 Vieni fermato prima di poter compiere questo gesto orribile.\n" @@ -55,8 +55,8 @@ class EatCommand(Command): "ragno": "🕸 Hai mangiato un {food}.\n[i]Ewww![/i]", "crab": "🦀 Hai mangiato un {food}. {food} is gone!\n[i]Senti il tuo stomaco ballare.[/i]", "granchio": "🦀 Hai mangiato un {food}. {food} is gone!\n[i]Senti il tuo stomaco ballare.[/i]", - - #Sezione con il cibo "normale" + + # Sezione con il cibo "normale" "zucca": "🎃 Hai mangiato una {food}. Solo che era una lanterna di Halloween.\n[i]Inizi a fare luce al" " buio.[/i]", "mela": "🍎 Hai mangiato una Mela, e hai fatto bene perché una mela al giorno toglie il medico di torno!\n" @@ -80,8 +80,8 @@ class EatCommand(Command): "gelato": "🍨 Mangiando del {food}, hai invocato Steffo.\n[i]Cedigli ora il tuo gelato.[/i]", "biscotto": "🍪 Hai mangiato un {food} di contrabbando.\n[i]L'Inquisizione non lo saprà mai![/i]", "biscotti": "🍪 Hai mangiato tanti {food} di contrabbando.\n[i]Attento! L'Inquisizione è sulle tue tracce![/i]", - - #Sezione delle bevande + + # Sezione delle bevande "acqua": "💧 Hai bevuto un po' d'{food}.\n[i]Ti depura e ti fa fare tanta plin plin![/i}", "cochina": "🥫 Hai bevuto una {food}. \n[i]Bella fresca.[/i]", "caffè": "☕️ Oh, no! Questo era il {food} della Peppina!\n[i]Ha provato col tritolo, salti in aria col" @@ -97,7 +97,7 @@ class EatCommand(Command): "birra": "🍺 Hai mangiato {food}.\n[i]Adesso sei un povero barbone alcolizzato.[/i]", "redbull": "🍾 Hai mangiato {food}.\n[i]Adesso puoi volare![/i]", "red bull": "🍾 Hai mangiato {food}.\n[i]Adesso puoi volare![/i]", - + # Distribuzioni "linux": "🐧 Hai mangiato {food}.\n[i]Senti systemd battere nel tuo cuore, adesso.[/i]", "arch": "🐧 Hai mangiato {food}, btw.\n[i]Ti senti più vicino a pacman, adesso.[/i]", @@ -109,7 +109,7 @@ class EatCommand(Command): "red hat": "🐧 Hai mangiato {food}.\n[i]La tua anima appartiene a IBM, ora.[/i]", "redhat": "🐧 Hai mangiato {food}.\n[i]La tua anima appartiene a IBM, ora.[/i]", "linux from scratch": "🐧 Hai mangiato {food}.\n[i]Sei diventato un puzzle.[/i]", - + # Altro "demone": "👿 Hai mangiato un {food}. Non l'ha presa bene...\n[i]Hai terribili bruciori di stomaco.[/i]", "diavolo": "👿 Hai mangiato un {food}. Non l'ha presa bene...\n[i]Hai terribili bruciori di stomaco.[/i]", @@ -137,7 +137,7 @@ class EatCommand(Command): "niente": "⬜️ Non hai mangiato {food}.\n[i]Hai ancora più fame.[/i]", "nulla": "⬜️ Non hai mangiato {food}.\n[i]Hai ancora più fame.[/i]", "torta": "⬜️ Non hai mangiato niente.\n[i]La {food} è una menzogna![/i]", - "cake": "⬜️ Non hai mangiato niente.\n[i]The {food} is a lie![/i]", + "cake": "⬜️ Non hai mangiato niente.\n[i]The {food} is a lie![/i]", } async def run(self, args: CommandArgs, data: CommandData) -> None: diff --git a/royalpack/commands/googlevideo.py b/royalpack/commands/googlevideo.py index 45c5e30d..d07fe2ae 100644 --- a/royalpack/commands/googlevideo.py +++ b/royalpack/commands/googlevideo.py @@ -10,6 +10,7 @@ class GooglevideoCommand(PlayCommand): syntax = "{ricerca}" - _URL_FORMAT = "gvsearch:{url}" + async def get_url(self, args): + return f"gvsearch:{args.joined()}" # Too bad gvsearch: always finds nothing. diff --git a/royalpack/commands/peertube.py b/royalpack/commands/peertube.py index 111b1dcc..9a8648dc 100644 --- a/royalpack/commands/peertube.py +++ b/royalpack/commands/peertube.py @@ -1,75 +1,24 @@ -import aiohttp -import asyncio -import datetime -import logging -import dateparser +from .play import PlayCommand from royalnet.commands import * -from royalnet.serf.telegram.escape import escape +import aiohttp +import urllib.parse -log = logging.getLogger(__name__) - - -class PeertubeCommand(Command): +class PeertubeCommand(PlayCommand): name: str = "peertube" - description: str = "Guarda quando è uscito l'ultimo video su RoyalTube." + aliases = ["pt", "royaltube", "rt"] - _ready = asyncio.Event() + description: str = "Cerca un video su RoyalTube e lo aggiunge alla coda della chat vocale." - _latest_date: datetime.datetime = None + syntax = "{ricerca}" - def __init__(self, interface: CommandInterface): - super().__init__(interface) - if self.interface.name == "telegram": - self.loop.create_task(self._ready_up()) - self.loop.create_task(self._update()) - - async def _get_json(self): - log.debug("Getting jsonfeed") + async def get_url(self, args): + search = urllib.parse.quote(args.joined(require_at_least=1)) async with aiohttp.ClientSession() as session: - async with session.get(self.config["Peertube"]["feed_url"]) as response: - log.debug("Parsing jsonfeed") + async with session.get(self.config["Peertube"]["instance_url"] + + f"/api/v1/search/videos?search={search}") as response: j = await response.json() - log.debug("Jsonfeed parsed successfully") - return j - - async def _send(self, message): - client = self.interface.bot.client - await self.interface.bot.safe_api_call(client.send_message, - chat_id=self.config["Telegram"]["main_group_id"], - text=escape(message), - parse_mode="HTML", - disable_webpage_preview=True) - - async def _ready_up(self): - j = await self._get_json() - if j["version"] != "https://jsonfeed.org/version/1": - raise ConfigurationError("url is not a jsonfeed") - videos = j["items"] - for video in reversed(videos): - date_modified = dateparser.parse(video["date_modified"]) - if self._latest_date is None or date_modified > self._latest_date: - log.debug(f"Found newer video: {date_modified}") - self._latest_date = date_modified - self._ready.set() - - async def _update(self): - await self._ready.wait() - while True: - j = await self._get_json() - videos = j["items"] - for video in reversed(videos): - date_modified = dateparser.parse(video["date_modified"]) - if date_modified > self._latest_date: - log.debug(f"Found newer video: {date_modified}") - self._latest_date = date_modified - await self._send(f"🆕 Nuovo video su RoyalTube!\n" - f"[b]{video['title']}[/b]\n" - f"{video['url']}") - await asyncio.sleep(self.config["Peertube"]["feed_update_timeout"]) - - async def run(self, args: CommandArgs, data: CommandData) -> None: - if self.interface.name != "telegram": - raise UnsupportedError() - await data.reply(f"ℹ️ Ultimo video caricato il: [b]{self._latest_date.isoformat()}[/b]") + if j["total"] < 1: + raise InvalidInputError("Nessun video trovato.") + return f'{self.config["Peertube"]["instance_url"]}/videos/watch/{j["data"][0]["uuid"]}' diff --git a/royalpack/commands/peertubeupdates.py b/royalpack/commands/peertubeupdates.py new file mode 100644 index 00000000..03e37078 --- /dev/null +++ b/royalpack/commands/peertubeupdates.py @@ -0,0 +1,78 @@ +import aiohttp +import asyncio +import datetime +import logging +import dateparser +from royalnet.commands import * +from royalnet.serf.telegram.escape import escape + + +log = logging.getLogger(__name__) + + +class PeertubeUpdatesCommand(Command): + name: str = "peertubeupdates" + + description: str = "Guarda quando è uscito l'ultimo video su PeerTube." + + aliases = ["ptu"] + + _ready = asyncio.Event() + + _latest_date: datetime.datetime = None + + def __init__(self, interface: CommandInterface): + super().__init__(interface) + if self.interface.name == "telegram": + self.loop.create_task(self._ready_up()) + self.loop.create_task(self._update()) + + async def _get_json(self): + log.debug("Getting jsonfeed") + async with aiohttp.ClientSession() as session: + async with session.get(self.config["Peertube"]["instance_url"] + + "/feeds/videos.json?sort=-publishedAt&filter=local") as response: + log.debug("Parsing jsonfeed") + j = await response.json() + log.debug("Jsonfeed parsed successfully") + return j + + async def _send(self, message): + client = self.interface.bot.client + await self.interface.bot.safe_api_call(client.send_message, + chat_id=self.config["Telegram"]["main_group_id"], + text=escape(message), + parse_mode="HTML", + disable_webpage_preview=True) + + async def _ready_up(self): + j = await self._get_json() + if j["version"] != "https://jsonfeed.org/version/1": + raise ConfigurationError("url is not a jsonfeed") + videos = j["items"] + for video in reversed(videos): + date_modified = dateparser.parse(video["date_modified"]) + if self._latest_date is None or date_modified > self._latest_date: + log.debug(f"Found newer video: {date_modified}") + self._latest_date = date_modified + self._ready.set() + + async def _update(self): + await self._ready.wait() + while True: + j = await self._get_json() + videos = j["items"] + for video in reversed(videos): + date_modified = dateparser.parse(video["date_modified"]) + if date_modified > self._latest_date: + log.debug(f"Found newer video: {date_modified}") + self._latest_date = date_modified + await self._send(f"🆕 Nuovo video su RoyalTube!\n" + f"[b]{video['title']}[/b]\n" + f"{video['url']}") + await asyncio.sleep(self.config["Peertube"]["feed_update_timeout"]) + + async def run(self, args: CommandArgs, data: CommandData) -> None: + if self.interface.name != "telegram": + raise UnsupportedError() + await data.reply(f"ℹ️ Ultimo video caricato il: [b]{self._latest_date.isoformat()}[/b]") diff --git a/royalpack/commands/play.py b/royalpack/commands/play.py index 7212467e..90ca08e5 100644 --- a/royalpack/commands/play.py +++ b/royalpack/commands/play.py @@ -15,10 +15,10 @@ class PlayCommand(Command): syntax = "{url}" - _URL_FORMAT = "{url}" + async def get_url(self, args: CommandArgs): + return args.joined() async def run(self, args: CommandArgs, data: CommandData) -> None: - url = args.joined() # if not (url.startswith("http://") or url.startswith("https://")): # raise CommandError(f"Il comando [c]{self.interface.prefix}play[/c] funziona solo per riprodurre file da" # f" un URL.\n" @@ -27,11 +27,14 @@ class PlayCommand(Command): if self.interface.name == "discord": message: discord.Message = data.message guild: discord.Guild = message.guild - guild_id: Optional[int] = guild.id + if guild is None: + guild_id = None + else: + guild_id: Optional[int] = guild.id else: guild_id = None response: Dict[str, Any] = await self.interface.call_herald_event("discord", "discord_play", - url=self._URL_FORMAT.format(url=url), + url=await self.get_url(args), guild_id=guild_id) too_long: List[Dict[str, Any]] = response["too_long"] @@ -56,4 +59,4 @@ class PlayCommand(Command): await data.reply(reply) if len(added) + len(too_long) == 0: - raise ExternalError("Nessun video trovato.") \ No newline at end of file + raise ExternalError("Nessun video trovato.") diff --git a/royalpack/commands/reminder.py b/royalpack/commands/reminder.py index ae50896c..e5c63497 100644 --- a/royalpack/commands/reminder.py +++ b/royalpack/commands/reminder.py @@ -76,11 +76,11 @@ class ReminderCommand(Command): else: raise UnsupportedError("This command does not support the current interface.") creator = await data.get_author() - reminder = self.interface.alchemy.Reminder(creator=creator, - interface_name=self.interface.name, - interface_data=interface_data, - datetime=date, - message=reminder_text) + reminder = self.interface.alchemy.get(Reminder)(creator=creator, + interface_name=self.interface.name, + interface_data=interface_data, + datetime=date, + message=reminder_text) self.interface.loop.create_task(self._remind(reminder)) data.session.add(reminder) await asyncify(data.session.commit) diff --git a/royalpack/commands/soundcloud.py b/royalpack/commands/soundcloud.py index 372f4981..0090e3dd 100644 --- a/royalpack/commands/soundcloud.py +++ b/royalpack/commands/soundcloud.py @@ -10,4 +10,5 @@ class SoundcloudCommand(PlayCommand): syntax = "{ricerca}" - _URL_FORMAT = "scsearch:{url}" + async def get_url(self, args): + return f"scsearch:{args.joined()}" diff --git a/royalpack/commands/yahoovideo.py b/royalpack/commands/yahoovideo.py index 7e61c115..482b1042 100644 --- a/royalpack/commands/yahoovideo.py +++ b/royalpack/commands/yahoovideo.py @@ -10,6 +10,7 @@ class YahoovideoCommand(PlayCommand): syntax = "{ricerca}" - _URL_FORMAT = "yvsearch:{url}" + async def get_url(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 ca9743e6..870c8aca 100644 --- a/royalpack/commands/youtube.py +++ b/royalpack/commands/youtube.py @@ -10,4 +10,5 @@ class YoutubeCommand(PlayCommand): syntax = "{ricerca}" - _URL_FORMAT = "ytsearch:{url}" + async def get_url(self, args): + return f"ytsearch:{args.joined()}" diff --git a/royalpack/commands/zawarudo.py b/royalpack/commands/zawarudo.py deleted file mode 100644 index 06f1c946..00000000 --- a/royalpack/commands/zawarudo.py +++ /dev/null @@ -1,91 +0,0 @@ -import typing -import discord -import asyncio -import datetime -from royalnet.commands import * -from royalnet.utils import asyncify -from royalnet.audio import YtdlDiscord -from royalnet.audio.playmodes import Playlist -from royalnet.bots import DiscordBot - - -class ZawarudoCommand(Command): - name: str = "zawarudo" - - aliases = ["theworld", "world"] - - description: str = "Ferma il tempo!" - - syntax = "[ [guild] ] [1-9]" - - @staticmethod - async def _legacy_zawarudo_handler(bot: "DiscordBot", guild_name: typing.Optional[str], time: int): - # Find the matching guild - if guild_name: - guilds: typing.List[discord.Guild] = bot.client.find_guild_by_name(guild_name) - else: - guilds = bot.client.guilds - if len(guilds) == 0: - raise CommandError("Server non trovato.") - if len(guilds) > 1: - raise CommandError("Il nome del server è ambiguo.") - guild = list(bot.client.guilds)[0] - # Ensure the guild has a PlayMode before adding the file to it - if not bot.music_data.get(guild): - raise CommandError("Il bot non è in nessun canale vocale.") - # Create url - ytdl_args = { - "format": "bestaudio", - "outtmpl": f"./downloads/{datetime.datetime.now().timestamp()}_%(title)s.%(ext)s" - } - # Start downloading - zw_start: typing.List[YtdlDiscord] = await asyncify(YtdlDiscord.create_from_url, - "https://scaleway.steffo.eu/jojo/zawarudo_intro.mp3", - **ytdl_args) - zw_end: typing.List[YtdlDiscord] = await asyncify(YtdlDiscord.create_from_url, - "https://scaleway.steffo.eu/jojo/zawarudo_outro.mp3", - **ytdl_args) - old_playlist = bot.music_data[guild] - bot.music_data[guild].playmode = Playlist() - # Get voice client - vc: discord.VoiceClient = bot.client.find_voice_client_by_guild(guild) - channel: discord.VoiceChannel = vc.channel - affected: typing.List[typing.Union[discord.User, discord.Member]] = channel.members - await bot.add_to_music_data(zw_start, guild) - for member in affected: - if member.bot: - continue - await member.edit(mute=True) - await asyncio.sleep(time) - await bot.add_to_music_data(zw_end, guild) - for member in affected: - member: typing.Union[discord.User, discord.Member] - if member.bot: - continue - await member.edit(mute=False) - bot.music_data[guild] = old_playlist - await bot.advance_music_data(guild) - return {} - - _event_name = "_legacy_zawarudo" - - def __init__(self, interface: CommandInterface): - super().__init__(interface) - if interface.name == "discord": - interface.register_herald_action(self._event_name, self._legacy_zawarudo_handler) - - async def run(self, args: CommandArgs, data: CommandData) -> None: - guild_name, time = args.match(r"(?:\[(.+)])?\s*(.+)?") - if time is None: - time = 5 - else: - time = int(time) - if time < 1: - raise InvalidInputError("The World can't stop time for less than a second.") - if time > 10: - raise InvalidInputError("The World can stop time only for 10 seconds.") - await data.reply(f"🕒 ZA WARUDO! TOKI WO TOMARE!") - await self.interface.call_herald_action("discord", self._event_name, { - "guild_name": guild_name, - "time": time - })