65 lines
2.3 KiB
Python
65 lines
2.3 KiB
Python
|
import threading
|
||
|
from queue import Queue, Empty
|
||
|
import miniaudio
|
||
|
import logging
|
||
|
from lib.renderer import Renderer
|
||
|
|
||
|
class Player:
|
||
|
def __init__(self, renderer: Renderer, play_finished_handler):
|
||
|
self._queue = Queue()
|
||
|
self._next_event = threading.Event()
|
||
|
self._exit_event = threading.Event()
|
||
|
self._logger = logging.getLogger('Jamendo Player')
|
||
|
self._renderer = renderer
|
||
|
self._play_finished_handler = play_finished_handler
|
||
|
threading.Thread(target=self.worker, args=()).start()
|
||
|
|
||
|
def worker(self):
|
||
|
while True:
|
||
|
try:
|
||
|
item = self._queue.get(block=True, timeout=1)
|
||
|
if item:
|
||
|
self._renderer.render(item['cover_file'], item['artist'], item['album'], item['title'])
|
||
|
self._logger.info('playing {artist}, {album}, {title}...'.format(artist=item['artist'], album=item['album'], title=item['title']))
|
||
|
file_stream = miniaudio.stream_file(item['audio_file'])
|
||
|
callback_stream = miniaudio.stream_with_callbacks(file_stream, end_callback=self.stream_end_callback)
|
||
|
next(callback_stream)
|
||
|
with miniaudio.PlaybackDevice() as device:
|
||
|
device.start(callback_stream)
|
||
|
self._next_event.wait()
|
||
|
self._next_event.clear()
|
||
|
self._queue.task_done()
|
||
|
self._play_finished_handler(item['audio_file'], item['cover_file'])
|
||
|
except Empty:
|
||
|
pass
|
||
|
|
||
|
if self._exit_event.is_set():
|
||
|
break
|
||
|
|
||
|
def stream_end_callback(self):
|
||
|
self.next()
|
||
|
|
||
|
def add_file(self, audio_file, artist: str, album: str, title: str, cover_file):
|
||
|
self._queue.put(
|
||
|
{
|
||
|
'audio_file': audio_file,
|
||
|
'artist': artist,
|
||
|
'album': album,
|
||
|
'title': title,
|
||
|
'cover_file': cover_file
|
||
|
}
|
||
|
)
|
||
|
|
||
|
@property
|
||
|
def queue_size(self):
|
||
|
return self._queue.qsize()
|
||
|
|
||
|
def next(self):
|
||
|
self._next_event.set()
|
||
|
|
||
|
def quit(self):
|
||
|
self._exit_event.set()
|
||
|
self.next()
|
||
|
while not self._queue.empty():
|
||
|
item = self._queue.get()
|
||
|
self._play_finished_handler(item['audio_file'], item['cover_file'])
|