Compare commits

..

2 commits

5 changed files with 88 additions and 13 deletions

View file

@ -148,7 +148,8 @@
"negative": ["I don't like it."] "negative": ["I don't like it."]
}, },
"playlistoftheday": { "playlistoftheday": {
"commands": ["playlist of the day"] "commands": ["playlist of the day"],
"not_fresh_reply": "It's not from today but here it is: {url}"
}, },
"plus": { "plus": {
"commands": ["plus"], "commands": ["plus"],

View file

@ -162,7 +162,10 @@ class Bot(irc.client.SimpleIRCClient, Logger):
def get_plugin(self, name: str) -> Optional[Plugin]: def get_plugin(self, name: str) -> Optional[Plugin]:
"""Get a loaded plugin by its name (e.g. 'mood'), or None.""" """Get a loaded plugin by its name (e.g. 'mood'), or None."""
matching_plugins = filter(lambda plugin: plugin.name == name, self.plugins) matching_plugins = filter(
lambda plugin: plugin.name == name,
self.plugins,
)
return next(matching_plugins, None) return next(matching_plugins, None)
def say(self, target: str, message: str) -> None: def say(self, target: str, message: str) -> None:

View file

@ -1,11 +1,25 @@
import datetime import datetime
import re
from typing import cast, Optional
from edmond.plugin import Plugin from edmond.plugin import Plugin
from edmond.plugins.shrlok import ShrlokPlugin
HTML_TEMPLATE = """\
<html>
<head> <meta charset="utf-8"> <title>🎶</title> </head>
<body> {} </body>
</html>
"""
LINK_RE = re.compile(r"(https?://\S+)")
class PlaylistOfTheDayPlugin(Plugin): class PlaylistOfTheDayPlugin(Plugin):
"""Collect music links from other platforms. """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 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, the plugin. Later this plugin may feed its playlist using links unhandled by other,
more specialized plugins (bandcamp, soundcloud, ). more specialized plugins (bandcamp, soundcloud, ).
@ -27,12 +41,26 @@ class PlaylistOfTheDayPlugin(Plugin):
def __init__(self, bot): def __init__(self, bot):
super().__init__(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): def on_pubmsg(self, event):
if not self.should_handle_command(event.arguments[0], no_content=True): if not self.should_handle_command(event.arguments[0], no_content=True):
return False return False
self.post_playlist(event.target)
# self.post_playlist(event.target)
return True return True
def add_line(self, line: str) -> None: def add_line(self, line: str) -> None:
@ -62,5 +90,29 @@ class PlaylistOfTheDayPlugin(Plugin):
today.isoformat(), today.isoformat(),
) )
# def post_playlist(self): def post_playlist(self, target):
# pass 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"<li>{item}</li>", linkified_items)
html_list = "<ol>" + "".join(html_items) + "</ol>"
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'<a href="\1">\1</a>', text)

View file

@ -1,5 +1,6 @@
import json import json
import socket import socket
from typing import Optional
from edmond.bot import Bot from edmond.bot import Bot
from edmond.plugin import Plugin from edmond.plugin import Plugin
@ -31,7 +32,7 @@ class ShrlokPlugin(Plugin):
self.bot.log_d("No socket path specified, shrlok plugin disabled.") self.bot.log_d("No socket path specified, shrlok plugin disabled.")
self.is_ready = False self.is_ready = False
def post(self, header: dict, data: bytes): def post(self, header: dict, data: bytes) -> Optional[str]:
encoded_header = json.dumps(header).encode() encoded_header = json.dumps(header).encode()
try: try:
with socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) as sock: with socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) as sock:
@ -45,4 +46,4 @@ class ShrlokPlugin(Plugin):
self.bot.log_e(f"Can't post data: {exc}") self.bot.log_e(f"Can't post data: {exc}")
return None return None
url = response.decode().replace(self.file_root, self.url_root, 1) url = response.decode().replace(self.file_root, self.url_root, 1)
return url return url or None # returning empty strings could cause confusion

View file

@ -1,3 +1,5 @@
from typing import cast, Optional
try: try:
from googleapiclient.discovery import build as gapi_discovery_build from googleapiclient.discovery import build as gapi_discovery_build
from googleapiclient.errors import Error as GoogleApiError from googleapiclient.errors import Error as GoogleApiError
@ -7,6 +9,7 @@ except ImportError:
DEPENDENCIES_FOUND = False DEPENDENCIES_FOUND = False
from edmond.plugin import Plugin from edmond.plugin import Plugin
from edmond.plugins.playlist_of_the_day import PlaylistOfTheDayPlugin
class YoutubePlugin(Plugin): class YoutubePlugin(Plugin):
@ -19,21 +22,33 @@ class YoutubePlugin(Plugin):
def __init__(self, bot): def __init__(self, bot):
super().__init__(bot) super().__init__(bot)
self._youtube = None self._youtube = None
self._playlist_of_the_day_plugin = None
@property @property
def youtube(self): def youtube(self):
if self._youtube is None: if self._youtube is None:
self._youtube = gapi_discovery_build( self._youtube = gapi_discovery_build(
"youtube", "v3", developerKey=self.config["api_key"] "youtube",
"v3",
developerKey=self.config["api_key"],
) )
return self._youtube return self._youtube
def has_api_key(self): @property
return self.config["api_key"] != "" def playlist_of_the_day_plugin(self) -> Optional[PlaylistOfTheDayPlugin]:
if self._playlist_of_the_day_plugin is None:
self._playlist_of_the_day_plugin = cast(
PlaylistOfTheDayPlugin,
self.bot.get_plugin("playlistoftheday"),
)
return self._playlist_of_the_day_plugin
def on_welcome(self, _):
if not self.config["api_key"]:
self.bot.log_w("API key unavailable.")
self.is_ready = False
def on_pubmsg(self, event): def on_pubmsg(self, event):
if not self.has_api_key():
return False
if self.should_handle_command(event.arguments[0]): if self.should_handle_command(event.arguments[0]):
self.handle_commands(event.target) self.handle_commands(event.target)
return True return True
@ -80,3 +95,6 @@ class YoutubePlugin(Plugin):
self.signal_failure(target) self.signal_failure(target)
return return
self.bot.say(target, f"{icon} {link} {title}") self.bot.say(target, f"{icon} {link} {title}")
if self.playlist_of_the_day_plugin:
self.playlist_of_the_day_plugin.add_line(f"{link} {title}")