playlist_of_the_day: add plugin

Simply support adding lines from other plugins, the playlist can't be
posted yet.
This commit is contained in:
dece 2022-09-09 19:08:46 +02:00
parent e601a77f72
commit a7d3a18ea7
3 changed files with 110 additions and 13 deletions

View file

@ -147,6 +147,9 @@
"positive": ["I like it."],
"negative": ["I don't like it."]
},
"playlistoftheday": {
"commands": ["playlist of the day"]
},
"plus": {
"commands": ["plus"],
"aliases": {

View file

@ -0,0 +1,66 @@
import datetime
from edmond.plugin import Plugin
class PlaylistOfTheDayPlugin(Plugin):
"""Collect music links from other platforms.
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)
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):
# pass

View file

@ -1,13 +1,16 @@
import re
from typing import cast, Optional
try:
from googleapiclient.errors import Error as GoogleApiError
from googleapiclient.errors import Error as GoogleApiError # type: ignore
DEPENDENCIES_FOUND = True
except ImportError:
DEPENDENCIES_FOUND = False
from edmond.plugin import Plugin
from edmond.plugins.playlist_of_the_day import PlaylistOfTheDayPlugin
from edmond.plugins.youtube import YoutubePlugin
class YoutubeParserPlugin(Plugin):
@ -20,14 +23,29 @@ class YoutubeParserPlugin(Plugin):
def __init__(self, bot):
super().__init__(bot)
self.priority = -3
self._youtube_plugin = None
self._youtube_plugin: Optional[YoutubePlugin] = None
self._playlist_of_the_day_plugin: Optional[
PlaylistOfTheDayPlugin
] = None
@property
def youtube_plugin(self):
def youtube_plugin(self) -> Optional[YoutubePlugin]:
if self._youtube_plugin is None:
self._youtube_plugin = self.bot.get_plugin("youtube")
self._youtube_plugin = cast(
YoutubePlugin,
self.bot.get_plugin("youtube"),
)
return self._youtube_plugin
@property
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.youtube_plugin and self.youtube_plugin.is_ready):
self.bot.log_w("Youtube plugin is not available.")
@ -40,14 +58,22 @@ class YoutubeParserPlugin(Plugin):
for word in words:
matched = self.VIDEO_URL_RE.match(word)
if matched:
return self.handle_match(matched, event.target)
title = self.get_video_title(matched)
if title:
self.bot.say(event.target, title)
self.add_to_playlist(word, title)
return True
else:
self.signal_failure(event.target)
return False
def handle_match(self, matched, target):
def get_video_title(self, matched) -> Optional[str]:
if self.youtube_plugin is None:
return None
groupdict = matched.groupdict()
code = groupdict.get("code1") or groupdict.get("code2")
if not code:
return False
return None
try:
search_response = (
self.youtube_plugin.youtube.videos()
@ -55,15 +81,17 @@ class YoutubeParserPlugin(Plugin):
.execute()
)
except GoogleApiError:
self.signal_failure(target)
return False
return None
title = ""
for result in search_response.get("items", []):
if result["kind"] == "youtube#video":
title = result["snippet"]["title"]
break
else:
self.signal_failure(target)
return False
self.bot.say(target, title)
return True
return None
return title
def add_to_playlist(self, url: str, title: str):
if self.playlist_of_the_day_plugin is None:
return
self.playlist_of_the_day_plugin.add_line(f"{url} {title}")