Added the ability to play a playlist with a new "playlist" command.

Ex. ?playlist MyPlaylistName
This commit is contained in:
profesaurus 2021-05-26 09:28:57 -07:00
parent efdd604d65
commit 9fb091e9e1

View File

@ -11,6 +11,7 @@ from discord import FFmpegPCMAudio
from discord.ext import commands from discord.ext import commands
from discord.ext.commands import command from discord.ext.commands import command
from plexapi.exceptions import Unauthorized from plexapi.exceptions import Unauthorized
from plexapi.exceptions import NotFound
from plexapi.server import PlexServer from plexapi.server import PlexServer
from .exceptions import MediaNotFoundError from .exceptions import MediaNotFoundError
@ -237,6 +238,24 @@ class Plex(commands.Cog):
except IndexError: except IndexError:
raise MediaNotFoundError("Album cannot be found") raise MediaNotFoundError("Album cannot be found")
def _search_playlists(self, title: str):
"""Search the Plex music db for playlist
Args:
title: str title of playlist to search for
Returns:
plexapi.playlist pointing to best matching title
Raises:
MediaNotFoundError: Title of playlist can't be found in plex db
"""
try:
return self.pms.playlist(title)
except NotFound:
raise MediaNotFoundError("Playlist cannot be found")
async def _play(self): async def _play(self):
"""Heavy lifting of playing songs """Heavy lifting of playing songs
@ -401,6 +420,42 @@ class Plex(commands.Cog):
return embed, art_file return embed, art_file
@staticmethod
def _build_embed_playlist(self, playlist):
"""Creates a pretty embed card for playlists
Builds a helpful status embed with the following info:
playlist art. All pertitent information
is grabbed dynamically from the Plex db.
Args:
playlist: plexapi.playlist object of playlist
Returns:
embed: discord.embed fully constructed payload.
thumb_art: io.BytesIO of playlist thumbnail img.
Raises:
None
"""
# Grab the relevant thumbnail
img_stream = urlopen(self.pms.url(playlist.composite, True))
img = io.BytesIO(img_stream.read())
# 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()
)
embed.set_author(name="Plex")
embed.set_thumbnail(url="attachment://image0.png")
bot_log.debug("Built embed for playlist - %s", playlist.title)
return embed, art_file
async def _validate(self, ctx): async def _validate(self, ctx):
"""Ensures user is in a vc """Ensures user is in a vc
@ -506,6 +561,47 @@ class Plex(commands.Cog):
for track in album.tracks(): for track in album.tracks():
await self.play_queue.put(track) await self.play_queue.put(track)
@command()
async def playlist(self, ctx, *args):
"""User command to play playlist
Searchs plex db and either, initiates playback, or
adds to queue. Handles invalid usage from the user.
Args:
ctx: discord.ext.commands.Context message context from command
*args: Title of playlist to play
Returns:
None
Raises:
None
"""
# Save the context to use with async callbacks
self.ctx = ctx
title = " ".join(args)
try:
playlist = self._search_playlists(title)
except MediaNotFoundError:
await ctx.send(f"Can't find playlist: {title}")
bot_log.debug("Failed to queue playlist, can't find - %s", title)
return
try:
await self._validate(ctx)
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)
for item in playlist.items():
if (item.TYPE == "track"):
await self.play_queue.put(item)
@command() @command()
async def stop(self, ctx): async def stop(self, ctx):
"""User command to stop playback """User command to stop playback