Merge branch '36-show-youtube-thumbnail-in-now-playing-embed' into 'develop'

Resolve "Show youtube thumbnail in "Now playing:" embed"

Closes #36

See merge request ekzyis/musicube!28
This commit is contained in:
Ramdip Gill 2022-09-26 20:51:31 +00:00
commit 375a7c36cd
4 changed files with 45 additions and 20 deletions

View File

@ -1,5 +1,8 @@
{ {
"python.pythonPath": "venv/bin/python3.9", "python.pythonPath": "venv/bin/python3.9",
"python.testing.autoTestDiscoverOnSaveEnabled": true, "python.testing.autoTestDiscoverOnSaveEnabled": true,
"pythonTestExplorer.testFramework": "pytest" "pythonTestExplorer.testFramework": "pytest",
"python.testing.pytestArgs": ["test"],
"python.testing.unittestEnabled": false,
"python.testing.pytestEnabled": true
} }

View File

@ -2,8 +2,9 @@ import asyncio
import logging import logging
import os import os
import sys import sys
from dataclasses import dataclass from dataclasses import dataclass, field
from distutils.util import strtobool from distutils.util import strtobool
import re
import discord import discord
import youtube_dl import youtube_dl
@ -25,6 +26,14 @@ class Song:
title: str title: str
webpage_url: str webpage_url: str
audio_url: str audio_url: str
video_id: str = field(init=False)
image_url: str = field(init=False)
def __post_init__(self):
video_url = self.webpage_url
if match := re.search(r'youtube\.com\/watch\?v=(?P<video_id>[a-zA-Z0-9]+)', video_url):
self.video_id = match.group('video_id')
self.image_url = f'https://img.youtube.com/vi/{self.video_id}/hqdefault.jpg'
class Music(commands.Cog): class Music(commands.Cog):
@ -100,8 +109,8 @@ class Music(commands.Cog):
self._next() self._next()
self.logger.info('Now playing: %s (%s)', song.title, song.webpage_url) self.logger.info('Now playing: %s (%s)', song.title, song.webpage_url)
ctx.voice_client.play(audio, after=after) ctx.voice_client.play(audio, after=after)
embed = NowPlayingMessage(title=song.title, url=song.webpage_url) embed = NowPlayingMessage(title=song.title, url=song.webpage_url, image_url=song.image_url)
msg = await ctx.send(embed=embed) msg = await ctx.send(content=embed.content, embed=embed)
await self._add_skip_button(msg) await self._add_skip_button(msg)
# pylint: disable=broad-except # pylint: disable=broad-except
except Exception as err: except Exception as err:
@ -142,8 +151,8 @@ class Music(commands.Cog):
self.logger.info('Qeueing song: %s (%s)', song.title, song.webpage_url) self.logger.info('Qeueing song: %s (%s)', song.title, song.webpage_url)
await self._queue.put((ctx, song)) await self._queue.put((ctx, song))
if ctx.voice_client.is_playing(): if ctx.voice_client.is_playing():
embed = QueuedMessage(title=song.title, url=song.webpage_url) embed = QueuedMessage(title=song.title, url=song.webpage_url, image_url=song.image_url)
await ctx.send(embed=embed) await ctx.send(content=embed.content, embed=embed)
def _skip(self, voice_client): def _skip(self, voice_client):
"""Skip to next song.""" """Skip to next song."""

View File

@ -13,6 +13,11 @@ class BotMessage(discord.Embed):
**kwargs, **kwargs,
title=title title=title
) )
image_url = kwargs.pop('image_url', None)
if image_url:
super().set_image(url=image_url)
# Message content before embed
self.content = kwargs.pop('content', None)
class ErrorMessage(BotMessage): class ErrorMessage(BotMessage):
@ -31,18 +36,22 @@ class ErrorMessage(BotMessage):
class NowPlayingMessage(BotMessage): class NowPlayingMessage(BotMessage):
def __init__(self, title, url): def __init__(self, title, url, image_url):
super().__init__( super().__init__(
title=f'Now playing: {title}', content='Now playing:',
description=url, title=title,
url=url,
image_url=image_url,
color=discord.Color.green() color=discord.Color.green()
) )
class QueuedMessage(BotMessage): class QueuedMessage(BotMessage):
def __init__(self, title, url): def __init__(self, title, url, image_url):
super().__init__( super().__init__(
title=f'Queued: {title}', content='Queued:',
description=url, title=title,
url=url,
image_url=image_url,
color=discord.Color.blue() color=discord.Color.blue()
) )

View File

@ -21,8 +21,8 @@ async def test_bot_ensure_voice(mbot, ctx):
await mbot.ensure_voice(ctx) await mbot.ensure_voice(ctx)
def mock_ytdl_extract_info(ytdl, url, title): def mock_ytdl_extract_info(ytdl, *, title, webpage_url, audio_url):
ytdl.extract_info.return_value = {'entries': [{'url': url, 'title': title}]} ytdl.extract_info.return_value = {'entries': [{'title': title, 'webpage_url': webpage_url, 'url': audio_url}]}
def mock_ffmpeg_pcm_audio(ffmpeg_pcm_audio): def mock_ffmpeg_pcm_audio(ffmpeg_pcm_audio):
@ -40,7 +40,7 @@ async def test_bot_playback(mbot, ctx):
ctx.voice_client.is_playing.return_value = False ctx.voice_client.is_playing.return_value = False
url = 'https://www.youtube.com/watch?v=Wr9LZ1hAFpQ' url = 'https://www.youtube.com/watch?v=Wr9LZ1hAFpQ'
title = 'In Flames - Deliver Us (Official Video)' title = 'In Flames - Deliver Us (Official Video)'
mock_ytdl_extract_info(ytdl, url, title) mock_ytdl_extract_info(ytdl, title=title, webpage_url=url, audio_url=url)
deliver_us_audio = mock_ffmpeg_pcm_audio(ffmpeg_pcm_audio) deliver_us_audio = mock_ffmpeg_pcm_audio(ffmpeg_pcm_audio)
query = 'in flames deliver us' query = 'in flames deliver us'
# pylint: disable=too-many-function-args # pylint: disable=too-many-function-args
@ -64,14 +64,16 @@ async def test_bot_playback(mbot, ctx):
assert \ assert \
ctx.voice_client.play.call_args.args == (deliver_us_audio,), \ ctx.voice_client.play.call_args.args == (deliver_us_audio,), \
'Did not playback correct audio' 'Did not playback correct audio'
content = ctx.send.call_args.kwargs['content']
assert content == 'Now playing:', "Did not send 'Now playing:' message"
embed = ctx.send.call_args.kwargs['embed'] embed = ctx.send.call_args.kwargs['embed']
assert embed.title == f'Now playing: {title}', "Did not send 'Now playing:' message" assert embed.title == title, "Did not send 'Now playing:' embed"
# TEST: Following songs are put inside a queue # TEST: Following songs are put inside a queue
ctx.voice_client.is_playing.return_value = True ctx.voice_client.is_playing.return_value = True
url = 'https://www.youtube.com/watch?v=pMDcYX2wRSg' url = 'https://www.youtube.com/watch?v=pMDcYX2wRSg'
title = 'Three Days Grace - Time of Dying (lyrics)' title = 'Three Days Grace - Time of Dying (lyrics)'
mock_ytdl_extract_info(ytdl, url, title) mock_ytdl_extract_info(ytdl, title=title, webpage_url=url, audio_url=url)
time_of_dying_audio = mock_ffmpeg_pcm_audio(ffmpeg_pcm_audio) time_of_dying_audio = mock_ffmpeg_pcm_audio(ffmpeg_pcm_audio)
# pylint: disable=too-many-function-args # pylint: disable=too-many-function-args
query = 'three days grace time of dying' query = 'three days grace time of dying'
@ -85,8 +87,10 @@ async def test_bot_playback(mbot, ctx):
assert \ assert \
not ctx.voice_client.play.call_args.args == (time_of_dying_audio,), \ not ctx.voice_client.play.call_args.args == (time_of_dying_audio,), \
'Did immediately playback audio instead of being queued' 'Did immediately playback audio instead of being queued'
content = ctx.send.call_args.kwargs['content']
assert content == 'Queued:', "Did not send 'Queued:' message"
embed = ctx.send.call_args.kwargs['embed'] embed = ctx.send.call_args.kwargs['embed']
assert embed.title == f'Queued: {title}', "Did not send 'Queued:' message" assert embed.title == title, "Did not send 'Queued:' embed"
await asyncio.sleep(0) await asyncio.sleep(0)
# Assert that there is still no playback because previous song is not finished yet # Assert that there is still no playback because previous song is not finished yet
assert \ assert \
@ -111,7 +115,7 @@ async def test_bot_skip(mbot, ctx):
ctx.voice_client.is_playing.return_value = False ctx.voice_client.is_playing.return_value = False
url = 'https://www.youtube.com/watch?v=Wr9LZ1hAFpQ' url = 'https://www.youtube.com/watch?v=Wr9LZ1hAFpQ'
title = 'In Flames - Deliver Us (Official Video)' title = 'In Flames - Deliver Us (Official Video)'
mock_ytdl_extract_info(ytdl, url, title) mock_ytdl_extract_info(ytdl, title=title, webpage_url=url, audio_url=url)
deliver_us_audio = mock_ffmpeg_pcm_audio(ffmpeg_pcm_audio) deliver_us_audio = mock_ffmpeg_pcm_audio(ffmpeg_pcm_audio)
query = 'in flames deliver us' query = 'in flames deliver us'
# pylint: disable=too-many-function-args # pylint: disable=too-many-function-args
@ -125,7 +129,7 @@ async def test_bot_skip(mbot, ctx):
ctx.voice_client.is_playing.return_value = True ctx.voice_client.is_playing.return_value = True
url = 'https://www.youtube.com/watch?v=pMDcYX2wRSg' url = 'https://www.youtube.com/watch?v=pMDcYX2wRSg'
title = 'Three Days Grace - Time of Dying (lyrics)' title = 'Three Days Grace - Time of Dying (lyrics)'
mock_ytdl_extract_info(ytdl, url, title) mock_ytdl_extract_info(ytdl, title=title, webpage_url=url, audio_url=url)
time_of_dying_audio = mock_ffmpeg_pcm_audio(ffmpeg_pcm_audio) time_of_dying_audio = mock_ffmpeg_pcm_audio(ffmpeg_pcm_audio)
# pylint: disable=too-many-function-args # pylint: disable=too-many-function-args
query = 'three days grace time of dying' query = 'three days grace time of dying'