Merge branch '9-skip' into 'develop'
Resolve "Implement !skip command" Closes #9 See merge request ekzyis/musicube!8
This commit is contained in:
commit
9c32b3d8a0
|
@ -4,6 +4,13 @@
|
||||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||||
"version": "0.2.0",
|
"version": "0.2.0",
|
||||||
"configurations": [
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "bot",
|
||||||
|
"type": "python",
|
||||||
|
"request": "launch",
|
||||||
|
"program": "src/bot.py",
|
||||||
|
"console": "integratedTerminal"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "pytest",
|
"name": "pytest",
|
||||||
"type": "python",
|
"type": "python",
|
||||||
|
|
|
@ -76,6 +76,13 @@ class Music(commands.Cog):
|
||||||
if ctx.voice_client.is_playing():
|
if ctx.voice_client.is_playing():
|
||||||
await ctx.send(f"Queued: {title}")
|
await ctx.send(f"Queued: {title}")
|
||||||
|
|
||||||
|
@commands.command()
|
||||||
|
async def skip(self, ctx):
|
||||||
|
async with ctx.typing():
|
||||||
|
if ctx.voice_client is None or not ctx.voice_client.is_playing():
|
||||||
|
raise commands.CommandError("Cannot skip: No song playing")
|
||||||
|
ctx.voice_client.stop()
|
||||||
|
|
||||||
@commands.command()
|
@commands.command()
|
||||||
async def stop(self, ctx):
|
async def stop(self, ctx):
|
||||||
await ctx.voice_client.disconnect()
|
await ctx.voice_client.disconnect()
|
||||||
|
|
|
@ -29,7 +29,9 @@ def mbot(bot):
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def ctx(mocker: MockerFixture):
|
def ctx(mocker: MockerFixture):
|
||||||
yield mocker.patch('discord.ext.commands.Context', autospec=True)
|
ctx_mock = mocker.patch('discord.ext.commands.Context', autospec=True)
|
||||||
|
ctx_mock.voice_client.stop = lambda: ctx_mock.voice_client.play.call_args.kwargs["after"](None)
|
||||||
|
return ctx_mock
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
|
|
|
@ -7,14 +7,14 @@ from discord.ext import commands
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_bot_ensure_voice(mbot, ctx):
|
async def test_bot_ensure_voice(mbot, ctx):
|
||||||
# Connects to voice channel of author if possible
|
# TEST: Connects to voice channel of author if possible
|
||||||
ctx.voice_client = None
|
ctx.voice_client = None
|
||||||
ctx.author.voice = AsyncMock()
|
ctx.author.voice = AsyncMock()
|
||||||
await mbot.ensure_voice(ctx)
|
await mbot.ensure_voice(ctx)
|
||||||
assert ctx.author.voice.channel.connect.call_count == 1, "Did not connect to voice channel of author"
|
assert ctx.author.voice.channel.connect.call_count == 1, "Did not connect to voice channel of author"
|
||||||
ctx.reset_mock(return_value=True)
|
ctx.reset_mock(return_value=True)
|
||||||
|
|
||||||
# Error if author not inside a channel
|
# TEST: Error if author not inside a channel
|
||||||
ctx.voice_client = None
|
ctx.voice_client = None
|
||||||
ctx.author.voice = None
|
ctx.author.voice = None
|
||||||
with pytest.raises(commands.CommandError):
|
with pytest.raises(commands.CommandError):
|
||||||
|
@ -35,6 +35,8 @@ def mock_ffmpeg_pcm_audio(ffmpeg_pcm_audio):
|
||||||
async def test_bot_playback(mbot, ctx):
|
async def test_bot_playback(mbot, ctx):
|
||||||
with patch.object(mbot, '_ytdl') as ytdl:
|
with patch.object(mbot, '_ytdl') as ytdl:
|
||||||
with patch('discord.FFmpegPCMAudio') as ffmpeg_pcm_audio:
|
with patch('discord.FFmpegPCMAudio') as ffmpeg_pcm_audio:
|
||||||
|
|
||||||
|
# TEST: First song queued is immediately played
|
||||||
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)"
|
||||||
|
@ -66,6 +68,7 @@ async def test_bot_playback(mbot, ctx):
|
||||||
ctx.send.call_args.args == (f"Now playing: {title}",), \
|
ctx.send.call_args.args == (f"Now playing: {title}",), \
|
||||||
"Did not send 'Now playing:' message"
|
"Did not send 'Now playing:' message"
|
||||||
|
|
||||||
|
# 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)"
|
||||||
|
@ -87,12 +90,66 @@ async def test_bot_playback(mbot, ctx):
|
||||||
ctx.send.call_args.args == (f"Queued: {title}",), \
|
ctx.send.call_args.args == (f"Queued: {title}",), \
|
||||||
"Did not send 'Queued:' message"
|
"Did not send 'Queued:' message"
|
||||||
await asyncio.sleep(0)
|
await asyncio.sleep(0)
|
||||||
# Still no playback because previous song not finished
|
# Assert that there is still no playback because previous song is not finished yet
|
||||||
assert \
|
assert \
|
||||||
not ffmpeg_pcm_audio.call_args.args == (url,), \
|
not ffmpeg_pcm_audio.call_args.args == (url,), \
|
||||||
f"FFmpegPCMAudio was called with {url} before previous song finished"
|
f"FFmpegPCMAudio was called with {url} before previous song finished"
|
||||||
ctx.voice_client.play.call_args.kwargs["after"](None) # Execute callback for song finish event
|
# Execute callback for song finish event
|
||||||
|
ctx.voice_client.play.call_args.kwargs["after"](None)
|
||||||
await asyncio.sleep(0)
|
await asyncio.sleep(0)
|
||||||
assert \
|
assert \
|
||||||
ffmpeg_pcm_audio.call_args.args == (url,), \
|
ctx.voice_client.play.call_args.args == (time_of_dying_audio,), \
|
||||||
f"FFmpegPCMAudio was not called with {url}"
|
"Did not queue next song"
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_bot_skip(mbot, ctx):
|
||||||
|
with patch.object(mbot, '_ytdl') as ytdl:
|
||||||
|
with patch('discord.FFmpegPCMAudio') as ffmpeg_pcm_audio:
|
||||||
|
|
||||||
|
# TEST: One can skip songs to immediately play the next song in queue
|
||||||
|
|
||||||
|
# Queue first song
|
||||||
|
ctx.voice_client.is_playing.return_value = False
|
||||||
|
url = "https://www.youtube.com/watch?v=Wr9LZ1hAFpQ"
|
||||||
|
title = "In Flames - Deliver Us (Official Video)"
|
||||||
|
mock_ytdl_extract_info(ytdl, url, title)
|
||||||
|
deliver_us_audio = mock_ffmpeg_pcm_audio(ffmpeg_pcm_audio)
|
||||||
|
query = 'in flames deliver us'
|
||||||
|
# pylint: disable=too-many-function-args
|
||||||
|
await mbot.play(mbot, ctx, query=query)
|
||||||
|
await asyncio.sleep(0)
|
||||||
|
assert \
|
||||||
|
ctx.voice_client.play.call_args.args == (deliver_us_audio,), \
|
||||||
|
"Did not playback correct audio"
|
||||||
|
|
||||||
|
# Queue second song
|
||||||
|
ctx.voice_client.is_playing.return_value = True
|
||||||
|
url = "https://www.youtube.com/watch?v=pMDcYX2wRSg"
|
||||||
|
title = "Three Days Grace - Time of Dying (lyrics)"
|
||||||
|
mock_ytdl_extract_info(ytdl, url, title)
|
||||||
|
time_of_dying_audio = mock_ffmpeg_pcm_audio(ffmpeg_pcm_audio)
|
||||||
|
# pylint: disable=too-many-function-args
|
||||||
|
query = "three days grace time of dying"
|
||||||
|
await mbot.play(mbot, ctx, query=query)
|
||||||
|
await asyncio.sleep(0)
|
||||||
|
assert \
|
||||||
|
not ctx.voice_client.play.call_args.args == (time_of_dying_audio,), \
|
||||||
|
"Did immediately playback audio instead of being queued"
|
||||||
|
|
||||||
|
# Now skip first song
|
||||||
|
await mbot.skip(mbot, ctx)
|
||||||
|
await asyncio.sleep(0)
|
||||||
|
assert \
|
||||||
|
ctx.voice_client.play.call_args.args == (time_of_dying_audio,), \
|
||||||
|
"Did not skip song"
|
||||||
|
|
||||||
|
# TEST: Error if no song playing
|
||||||
|
ctx.voice_client.is_playing.return_value = False
|
||||||
|
with pytest.raises(commands.CommandError):
|
||||||
|
await mbot.skip(mbot, ctx)
|
||||||
|
|
||||||
|
# TEST: Error if no voice client
|
||||||
|
ctx.voice_client = None
|
||||||
|
with pytest.raises(commands.CommandError):
|
||||||
|
await mbot.skip(mbot, ctx)
|
||||||
|
|
Loading…
Reference in New Issue