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'])