From bcbce98d91584e095ddf14ac61964eb3c2db2e02 Mon Sep 17 00:00:00 2001 From: Carsten Burgard Date: Sun, 13 Feb 2022 12:02:15 +0100 Subject: [PATCH 1/6] allow lyrics section in yml file to be missing --- PlexBot/__init__.py | 4 ++-- PlexBot/__main__.py | 7 +++++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/PlexBot/__init__.py b/PlexBot/__init__.py index 6768d27..badc36c 100644 --- a/PlexBot/__init__.py +++ b/PlexBot/__init__.py @@ -56,7 +56,7 @@ def load_config(filename: str) -> Dict[str, str]: config["plex"]["log_level"] = levels[config["plex"]["log_level"].upper()] config["discord"]["log_level"] = levels[config["discord"]["log_level"].upper()] - if config["lyrics"]["token"].lower() == "none": - config["lyrics"]["token"] = None + if config["lyrics"] and config["lyrics"]["token"].lower() == "none": + config["lyrics"] = None return config diff --git a/PlexBot/__main__.py b/PlexBot/__main__.py index fc8fb9c..1434d00 100644 --- a/PlexBot/__main__.py +++ b/PlexBot/__main__.py @@ -20,8 +20,11 @@ BASE_URL = config["plex"]["base_url"] PLEX_TOKEN = config["plex"]["token"] LIBRARY_NAME = config["plex"]["library_name"] -LYRICS_TOKEN = config["lyrics"]["token"] - +if config["lyrics"]: + LYRICS_TOKEN = config["lyrics"]["token"] +else: + LYRICS_TOKEN = None + # Set appropiate log level root_log = logging.getLogger() plex_log = logging.getLogger("Plex") From a45ccb657e1acd08cd937cb76aa45c525d40a623 Mon Sep 17 00:00:00 2001 From: Carsten Burgard Date: Sun, 13 Feb 2022 12:02:49 +0100 Subject: [PATCH 2/6] make dependency on lyricsgenius optional by moving import --- PlexBot/bot.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PlexBot/bot.py b/PlexBot/bot.py index 9dbb53c..efc51b3 100644 --- a/PlexBot/bot.py +++ b/PlexBot/bot.py @@ -6,7 +6,6 @@ from urllib.request import urlopen import requests import discord -import lyricsgenius from async_timeout import timeout from discord import FFmpegPCMAudio from discord.ext import commands @@ -182,6 +181,7 @@ class Plex(commands.Cog): self.bot_prefix = bot.command_prefix if kwargs["lyrics_token"]: + import lyricsgenius self.genius = lyricsgenius.Genius(kwargs["lyrics_token"]) else: plex_log.warning("No lyrics token specified, lyrics disabled") From f8e5af87b68b904635a79eddeba49bef2de89c03 Mon Sep 17 00:00:00 2001 From: Carsten Burgard Date: Sun, 13 Feb 2022 12:04:34 +0100 Subject: [PATCH 3/6] allow executing outside of docker env by checking if user is root user for config path --- PlexBot/__init__.py | 8 +++----- PlexBot/__main__.py | 6 +++++- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/PlexBot/__init__.py b/PlexBot/__init__.py index badc36c..0b1228c 100644 --- a/PlexBot/__init__.py +++ b/PlexBot/__init__.py @@ -1,8 +1,6 @@ """ Plex music bot for discord. -Do not import this module, it is intended to be -used exclusively within a docker environment. """ import logging import sys @@ -19,7 +17,7 @@ plex_log = logging.getLogger("Plex") bot_log = logging.getLogger("Bot") -def load_config(filename: str) -> Dict[str, str]: +def load_config(basedir: str,filename: str) -> Dict[str, str]: """Loads config from yaml file Grabs key/value config pairs from a file. @@ -35,12 +33,12 @@ def load_config(filename: str) -> Dict[str, str]: """ # All config files should be in /config # for docker deployment. - filename = Path("/config", filename) + filename = Path(basedir, filename) try: with open(filename, "r") as config_file: config = yaml.safe_load(config_file) except FileNotFoundError: - root_log.fatal("Configuration file not found.") + root_log.fatal("Configuration file not found at '"+str(filename)+"'.") sys.exit(-1) # Convert str level type to logging constant diff --git a/PlexBot/__main__.py b/PlexBot/__main__.py index 1434d00..57d1982 100644 --- a/PlexBot/__main__.py +++ b/PlexBot/__main__.py @@ -11,7 +11,11 @@ from .bot import General from .bot import Plex # Load config from file -config = load_config("config.yaml") +configdir = "config" +from os import geteuid +if geteuid() == 0: + configdir = "/config" +config = load_config(configdir,"config.yaml") BOT_PREFIX = config["discord"]["prefix"] TOKEN = config["discord"]["token"] From 5f9c83b75e616d9408777594eb0fed1c65835b97 Mon Sep 17 00:00:00 2001 From: Carsten Burgard Date: Sun, 13 Feb 2022 13:03:07 +0100 Subject: [PATCH 4/6] added documentation for missing option --- PlexBot/bot.py | 1 + 1 file changed, 1 insertion(+) diff --git a/PlexBot/bot.py b/PlexBot/bot.py index efc51b3..6bdee04 100644 --- a/PlexBot/bot.py +++ b/PlexBot/bot.py @@ -36,6 +36,7 @@ Plex: stop - Halt playback and leave vc. pause - Pause playback. resume - Resume playback. + skip - Skip the current song. clear - Clear play queue. [] - Optional args. From 139ce07d244776101b72ecc02885ebf74f8faac5 Mon Sep 17 00:00:00 2001 From: Carsten Burgard Date: Sun, 13 Feb 2022 13:10:59 +0100 Subject: [PATCH 5/6] fix bug related to empty playlists --- PlexBot/bot.py | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/PlexBot/bot.py b/PlexBot/bot.py index 6bdee04..b1e5bce 100644 --- a/PlexBot/bot.py +++ b/PlexBot/bot.py @@ -437,7 +437,7 @@ class Plex(commands.Cog): return embed, art_file @staticmethod - def _build_embed_playlist(self, playlist): + def _build_embed_playlist(self, playlist, title, descrip): """ Creates a pretty embed card for playlists @@ -456,13 +456,14 @@ class Plex(commands.Cog): None """ # Grab the relevant thumbnail - img_stream = requests.get(self.pms.url(playlist.composite, True), stream=True).raw - img = io.BytesIO(img_stream.read()) + try: + img_stream = requests.get(self.pms.url(playlist.composite, True), stream=True).raw + img = io.BytesIO(img_stream.read()) + except: + raise MediaNotFoundError("no image available") # Attach to discord embed art_file = discord.File(img, filename="image0.png") - title = "Added playlist to queue" - descrip = f"{playlist.title}" embed = discord.Embed( title=title, description=descrip, colour=discord.Color.red() @@ -615,13 +616,17 @@ class Plex(commands.Cog): except VoiceChannelError: pass - bot_log.debug("Added to queue - %s", title) - embed, img = self._build_embed_playlist(self, playlist) - await ctx.send(embed=embed, file=img) + try: + embed, img = self._build_embed_playlist(self, playlist, "Added playlist to queue", playlist.title) + await ctx.send(embed=embed, file=img) - for item in playlist.items(): - if (item.TYPE == "track"): - await self.play_queue.put(item) + for item in playlist.items(): + if (item.TYPE == "track"): + await self.play_queue.put(item) + bot_log.debug("Added to queue - %s", title) + except MediaNotFoundError: + await ctx.send(message="Playlist "+title+" seems to be empty!") + bot_log.debug("Playlist empty - %s", title) @command() async def stop(self, ctx): From 52099fa794af469d8bdaaa1b2965bb7a4641a3b1 Mon Sep 17 00:00:00 2001 From: Carsten Burgard Date: Sun, 13 Feb 2022 13:12:35 +0100 Subject: [PATCH 6/6] added option to show available playlists --- PlexBot/bot.py | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/PlexBot/bot.py b/PlexBot/bot.py index b1e5bce..d077981 100644 --- a/PlexBot/bot.py +++ b/PlexBot/bot.py @@ -31,6 +31,7 @@ Plex: play - Play a song from the plex server. album - Queue an entire album to play. playlist - Queue an entire playlist to play. + show_playlists - Query for playlists with a name matching any of the arguments. lyrics - Print the lyrics of the song (Requires Genius API) np - Print the current playing song. stop - Halt playback and leave vc. @@ -267,6 +268,15 @@ class Plex(commands.Cog): except NotFound: raise MediaNotFoundError("Playlist cannot be found") + def _get_playlists(self): + """ + Search the Plex music db for playlist + + Returns: + List of plexapi.playlist + """ + return self.pms.playlists() + async def _play(self): """ Heavy lifting of playing songs @@ -627,6 +637,41 @@ class Plex(commands.Cog): except MediaNotFoundError: await ctx.send(message="Playlist "+title+" seems to be empty!") bot_log.debug("Playlist empty - %s", title) + @command() + async def show_playlists(self, ctx, *args): + """ + User command to show playlists + + Searchs plex db and shows playlists matching. + + Args: + ctx: discord.ext.commands.Context message context from command + *args: String filter for playlist names + + Returns: + None + + Raises: + None + """ + # Save the context to use with async callbacks + self.ctx = ctx + + playlists = self._get_playlists() + + try: + await self._validate(ctx) + except VoiceChannelError: + pass + + for playlist in playlists: + if args and not any(arg in playlist.title for arg in args): + continue + from datetime import timedelta + if playlist.duration: + seconds = playlist.duration / 1000 + embed, img = self._build_embed_playlist(self, playlist, playlist.title, "{:0>8}".format(str(timedelta(seconds=seconds)))) + await ctx.send(embed=embed, file=img) @command() async def stop(self, ctx):