import datetime import re from typing import cast, Optional from edmond.plugin import Plugin from edmond.plugins.shrlok import ShrlokPlugin HTML_TEMPLATE = """\ 🎶 {} """ LINK_RE = re.compile(r"(https?://\S+)") class PlaylistOfTheDayPlugin(Plugin): """Collect music links from other platforms. This plugin requires a working Shrlok instance to post the playlist. Plugins that want to feed the playlist must do so by calling the add_link method of the plugin. Later this plugin may feed its playlist using links unhandled by other, more specialized plugins (bandcamp, soundcloud, …). The current behaviour for the playlist is that links are added for a same day, so the date at which the latest link was added is also stored. If a link is the first to be added on a new day (by using this date as reference), the previous list is emptied. But if the list is requested even if no links have been posted today and the playlist is therefore outdated, it is still posted by the bot, along with a message explaining that it's not the current day's playlist. Note that the playlist itself is just of bunch of lines, which should of course contain links, but can also contain titles and other metadata. """ REQUIRED_CONFIGS = ["commands"] DATE_KEY = "date_of_latest_link" PLAYLIST_KEY = "current_playlist" def __init__(self, bot): super().__init__(bot) self._shrlok_plugin = None @property def shrlok_plugin(self) -> Optional[ShrlokPlugin]: if self._shrlok_plugin is None: self._shrlok_plugin = cast( ShrlokPlugin, self.bot.get_plugin("shrlok"), ) return self._shrlok_plugin def on_welcome(self, _): if not (self.shrlok_plugin and self.shrlok_plugin.is_ready): self.bot.log_w("Shrlok plugin is not available.") self.is_ready = False def on_pubmsg(self, event): if not self.should_handle_command(event.arguments[0], no_content=True): return False self.post_playlist(event.target) return True def add_line(self, line: str) -> None: """Add this line to the current playlist.""" today = datetime.date.today() last_update_str = self.get_storage_value(self.DATE_KEY) if last_update_str: last_update_date = datetime.date.fromisoformat(last_update_str) else: last_update_date = today if last_update_date == today: current_playlist: list[str] = self.get_storage_value( self.PLAYLIST_KEY, default=[], ) current_playlist.append(line) else: current_playlist = [line] self.set_storage_value( self.PLAYLIST_KEY, current_playlist, skip_save=True, # save one write ) self.set_storage_value( self.DATE_KEY, today.isoformat(), ) def post_playlist(self, target): playlist: list[str] = self.get_storage_value(self.PLAYLIST_KEY, []) if not playlist: self.bot.log_e("Playlist empty.") self.signal_failure(target) linkified_items = map(PlaylistOfTheDayPlugin.linkify, playlist) html_items = map(lambda item: f"
  • {item}
  • ", linkified_items) html_list = "
      " + "".join(html_items) + "
    " data = HTML_TEMPLATE.format(html_list).encode() url = self.shrlok_plugin.post({"type": "raw"}, data) if not url: self.bot.log_e("Shrlok returned None.") self.signal_failure(target) date = self.get_storage_value(self.DATE_KEY, "") if date != datetime.date.today().isoformat(): reply = self.config["not_fresh_reply"].format(url=url) else: reply = url self.bot.say(target, reply) @staticmethod def linkify(text: str) -> str: """Put links in A tags.""" return LINK_RE.sub(r'\1', text)