From 545654f9a7ee7865d3380abb393ae330a89fe49e Mon Sep 17 00:00:00 2001 From: Joshua Arulsamy Date: Sun, 6 Sep 2020 15:32:40 -0600 Subject: [PATCH 1/2] :sparkles: Add lyrics command Optionally grab lyrics of a song using the lyrics command. Required LyricsGenius API token. --- PlexBot/__init__.py | 3 ++ PlexBot/__main__.py | 11 +++++- PlexBot/__version__.py | 2 +- PlexBot/bot.py | 81 +++++++++++++++++++++++++++++++++++++----- requirements.txt | 1 + sample-config.yaml | 3 ++ 6 files changed, 91 insertions(+), 10 deletions(-) diff --git a/PlexBot/__init__.py b/PlexBot/__init__.py index bfc5f1e..6768d27 100644 --- a/PlexBot/__init__.py +++ b/PlexBot/__init__.py @@ -56,4 +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 + return config diff --git a/PlexBot/__main__.py b/PlexBot/__main__.py index bd5dd58..fc8fb9c 100644 --- a/PlexBot/__main__.py +++ b/PlexBot/__main__.py @@ -20,6 +20,8 @@ BASE_URL = config["plex"]["base_url"] PLEX_TOKEN = config["plex"]["token"] LIBRARY_NAME = config["plex"]["library_name"] +LYRICS_TOKEN = config["lyrics"]["token"] + # Set appropiate log level root_log = logging.getLogger() plex_log = logging.getLogger("Plex") @@ -28,9 +30,16 @@ bot_log = logging.getLogger("Bot") plex_log.setLevel(config["plex"]["log_level"]) bot_log.setLevel(config["discord"]["log_level"]) +plex_args = { + "base_url": BASE_URL, + "plex_token": PLEX_TOKEN, + "lib_name": LIBRARY_NAME, + "lyrics_token": LYRICS_TOKEN, +} + bot = Bot(command_prefix=BOT_PREFIX) # Remove help command, we have our own custom one. bot.remove_command("help") bot.add_cog(General(bot)) -bot.add_cog(Plex(bot, BASE_URL, PLEX_TOKEN, LIBRARY_NAME, BOT_PREFIX)) +bot.add_cog(Plex(bot, **plex_args)) bot.run(TOKEN) diff --git a/PlexBot/__version__.py b/PlexBot/__version__.py index b72fdbd..6978d19 100644 --- a/PlexBot/__version__.py +++ b/PlexBot/__version__.py @@ -1,5 +1,5 @@ """Track version number of package.""" -VERSION = "1.0.1" +VERSION = "1.0.2" if __name__ == "__main__": print(VERSION) diff --git a/PlexBot/bot.py b/PlexBot/bot.py index 5dd7067..9a47547 100644 --- a/PlexBot/bot.py +++ b/PlexBot/bot.py @@ -5,6 +5,7 @@ import logging from urllib.request import urlopen import discord +import lyricsgenius from async_timeout import timeout from discord import FFmpegPCMAudio from discord.ext import commands @@ -28,6 +29,7 @@ General: Plex: play - Play a song from the plex server. album - Queue an entire album to play. + lyrics - Print the lyrics of the song (Requires Genius API) np - Print the current playing song. stop - Halt playback and leave vc. pause - Pause playback. @@ -119,6 +121,15 @@ class General(commands.Cog): except (discord.Forbidden, discord.NotFound, discord.HTTPException): pass + async for i in channel.history(limit=limit): + if i.author == ctx.message.author and i.content.startswith( + self.bot.command_prefix + ): + try: + await i.delete() + except (discord.Forbidden, discord.NotFound, discord.HTTPException): + pass + except discord.Forbidden: bot_log.info("Unable to delete messages, insufficient permissions.") await ctx.send("I don't have the necessary permissions to delete messages.") @@ -136,9 +147,7 @@ class Plex(commands.Cog): # All are necessary to detect global interactions # within the bot. - def __init__( - self, bot, base_url: str, plex_token: str, lib_name: str, bot_prefix: str - ): + def __init__(self, bot, **kwargs): """Initializes Plex resources Connects to Plex library and sets up @@ -149,7 +158,6 @@ class Plex(commands.Cog): base_url: str url to Plex server plex_token: str X-Token of Plex server lib_name: str name of Plex library to search through - bot_prefix: str prefix used to interact with bots Raises: plexapi.exceptions.Unauthorized: Invalid Plex token @@ -159,10 +167,16 @@ class Plex(commands.Cog): """ self.bot = bot - self.base_url = base_url - self.plex_token = plex_token - self.library_name = lib_name - self.bot_prefix = bot_prefix + self.base_url = kwargs["base_url"] + self.plex_token = kwargs["plex_token"] + self.library_name = kwargs["lib_name"] + self.bot_prefix = bot.command_prefix + + if kwargs["lyrics_token"]: + self.genius = lyricsgenius.Genius(kwargs["lyrics_token"]) + else: + plex_log.warning("No lyrics token specified, lyrics disabled") + self.genius = None # Log fatal invalid plex token try: @@ -618,3 +632,54 @@ class Plex(commands.Cog): self.play_queue = asyncio.Queue() bot_log.debug("Cleared queue") await ctx.send(":boom: Queue cleared.") + + @command() + async def lyrics(self, ctx): + """User command to get lyrics of a song. + + Args: + ctx: discord.ext.commands.Context message context from command + + Returns: + None + + Raises: + None + """ + if not self.current_track: + plex_log.info("No song currently playing") + return + + if self.genius: + plex_log.info( + "Searching for %s, %s", + self.current_track.title, + self.current_track.artist().title, + ) + try: + song = self.genius.search_song( + self.current_track.title, self.current_track.artist().title + ) + except TypeError: + self.genius = None + plex_log.error("Invalid genius token, disabling lyrics") + return + + try: + lyrics = song.lyrics + # Split into 1950 char chunks + # Discord max message length is 2000 + lines = [(lyrics[i : i + 1950]) for i in range(0, len(lyrics), 1950)] + + for i in lines: + if i == "": + continue + # Apply code block format + i = f"```{i}```" + await ctx.send(i) + + except (IndexError, TypeError): + plex_log.info("Could not find lyrics") + await ctx.send("Can't find lyrics for this song.") + else: + plex_log.warning("Attempted lyrics without valid token") diff --git a/requirements.txt b/requirements.txt index 044fb46..7791c31 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,3 +4,4 @@ fuzzywuzzy==0.18.0 pynacl==1.4.0 ffmpeg==1.4 PyYAML==5.3.1 +lyricsgenius==2.0.0 diff --git a/sample-config.yaml b/sample-config.yaml index 0b2f204..6101228 100644 --- a/sample-config.yaml +++ b/sample-config.yaml @@ -11,3 +11,6 @@ plex: token: "" library_name: "" log_level: "debug" + +lyrics: + token: From 5eceab7a22ba4cb64254f75441fd339b50f21baa Mon Sep 17 00:00:00 2001 From: Joshua Arulsamy Date: Sun, 6 Sep 2020 15:33:25 -0600 Subject: [PATCH 2/2] :pencil: Add lyrics updates --- README.md | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 1e4e37e..fd502b5 100644 --- a/README.md +++ b/README.md @@ -89,11 +89,27 @@ Plex-Bot runs entirely in a Docker container. Ensure you have Docker and docker- * Add it to `config/config.yaml` in the appropiate spot. -6. Customize remaining settings +6. Get your Lyrics Genius token (Optional): + + If you wanty to disable this feature, set token to `None` in `config/config.yaml` + + If you would like to enable the lyrics feature of the bot, you need to signup for a free GeniusLyrics account, [here](https://genius.com/api-clients). + + After you make an account: + + 1. Click New API Client + + 2. Set the app website url to: `https://github.com/jarulsamy/Plex-Bot` + + 3. Set the redirect url to: `http://localhost` + + 4. Copy the **Client Access Token** to `config/config.yaml` + +7. Customize remaining settings Set any remaining settings in the config file that you would like. Such as music library, and base url of the Plex server. -7. Start the service: +8. Start the service: ```bash docker-compose up -d @@ -121,6 +137,7 @@ General: Plex: play - Play a song from the plex server. album - Queue an entire album to play. + lyrics - Print the lyrics of the song (Requires Genius API) np - Print the current playing song. stop - Halt playback and leave vc. pause - Pause playback.