From 667eb1be3b6c7c290367e068f675d693392522fb Mon Sep 17 00:00:00 2001 From: Andrei Zbikowski Date: Mon, 17 Jul 2017 08:07:40 -0700 Subject: [PATCH] [voice] Better Queue (#44) * Add built-in Playable queue * More functionality --- disco/voice/client.py | 2 +- disco/voice/player.py | 6 ++-- disco/voice/queue.py | 50 +++++++++++++++++++++++++++++ tests/tests_voice_queue.py | 66 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 120 insertions(+), 4 deletions(-) create mode 100644 disco/voice/queue.py create mode 100644 tests/tests_voice_queue.py diff --git a/disco/voice/client.py b/disco/voice/client.py index e747d02..62fb63e 100644 --- a/disco/voice/client.py +++ b/disco/voice/client.py @@ -226,7 +226,7 @@ class VoiceClient(LoggingClass): if self.token and self.token != data.token: return - self.log.info('[%s] Recieved VOICE_SERVER_UPDATE (state = %s)', self, self.state) + self.log.info('[%s] Recieved VOICE_SERVER_UPDATE (state = %s / endpoint = %s)', self, self.state, data.endpoint) self.token = data.token self.set_state(VoiceState.AUTHENTICATING) diff --git a/disco/voice/player.py b/disco/voice/player.py index bc1add2..56c023c 100644 --- a/disco/voice/player.py +++ b/disco/voice/player.py @@ -1,11 +1,11 @@ import time import gevent -from six.moves import queue from holster.enum import Enum from holster.emitter import Emitter from disco.voice.client import VoiceState +from disco.voice.queue import PlayableQueue MAX_TIMESTAMP = 4294967295 @@ -19,11 +19,11 @@ class Player(object): 'DISCONNECT' ) - def __init__(self, client): + def __init__(self, client, queue=None): self.client = client # Queue contains playable items - self.queue = queue.Queue() + self.queue = queue or PlayableQueue() # Whether we're playing music (true for lifetime) self.playing = True diff --git a/disco/voice/queue.py b/disco/voice/queue.py new file mode 100644 index 0000000..8670d14 --- /dev/null +++ b/disco/voice/queue.py @@ -0,0 +1,50 @@ +import abc +import six +import gevent +import random + + +@six.add_metaclass(abc.ABCMeta) +class BaseQueue(object): + @abc.abstractmethod + def get(self): + raise NotImplementedError + + +class PlayableQueue(BaseQueue): + def __init__(self): + self._data = [] + self._event = gevent.event.Event() + + def append(self, item): + self._data.append(item) + + if self._event: + self._event.set() + self._event = None + + def _get(self): + if not len(self._data): + if not self._event: + self._event = gevent.event.Event() + self._event.wait() + return self._get() + return self._data.pop(0) + + def get(self): + return self._get() + + def shuffle(self): + random.shuffle(self._data) + + def clear(self): + self._data = [] + + def __len__(self): + return len(self._data) + + def __iter__(self): + return self._data.__iter__() + + def __nonzero__(self): + return True diff --git a/tests/tests_voice_queue.py b/tests/tests_voice_queue.py new file mode 100644 index 0000000..914e8ea --- /dev/null +++ b/tests/tests_voice_queue.py @@ -0,0 +1,66 @@ +import gevent +from unittest import TestCase + +from disco.voice.queue import PlayableQueue + + +class TestPlayableQueue(TestCase): + def test_append(self): + q = PlayableQueue() + q.append(1) + q.append(2) + q.append(3) + + self.assertEqual(q._data, [1, 2, 3]) + self.assertEqual(q.get(), 1) + self.assertEqual(q.get(), 2) + self.assertEqual(q.get(), 3) + + def test_len(self): + q = PlayableQueue() + + for idx in range(1234): + q.append(idx) + + self.assertEqual(len(q), 1234) + + def test_iter(self): + q = PlayableQueue() + + for idx in range(5): + q.append(idx) + + self.assertEqual(sum(q), 10) + + def test_blocking_get(self): + q = PlayableQueue() + result = gevent.event.AsyncResult() + + def get(): + result.set(q.get()) + + gevent.spawn(get) + q.append(5) + self.assertEqual(result.get(), 5) + + def test_shuffle(self): + q = PlayableQueue() + + for idx in range(10000): + q.append(idx) + + self.assertEqual(q._data[0], 0) + q.shuffle() + self.assertNotEqual(q._data[0], 0) + + def test_clear(self): + q = PlayableQueue() + + for idx in range(100): + q.append(idx) + + self.assertEqual(q._data[0], 0) + self.assertEqual(q._data[-1], 99) + self.assertEqual(len(q), 100) + q.clear() + self.assertEqual(len(q), 0)