#!./bin/python3 import os import sys import threading import time import traceback from typing import Dict import pygame # type: ignore import tornado.ioloop, tornado.web import asyncio from display import Display from player import Player class WebHandler(tornado.web.RequestHandler): def initialize(self, musikautomat): self.musikautomat = musikautomat def get(self, a): if a.startswith("play"): if a == "play/dir": path = self.get_argument('path') self.musikautomat.play({ "type" : "dir", "name" : self.get_argument('name', path), "path" : path }, start=True) class Musikautomat: def __init__(self, pydsp, config: Dict): # Initialise state objects self._pydsp = pydsp self._display = Display(config, self._pydsp) self._display.update() self._eventSink = self._display self._player = Player(config, self._pydsp) self._dx = config.get("dimx", 128) threading.Thread(target=self.runWebServer, daemon=True).start() def runWebServer(self): ''' Run event loop for web interface. ''' urls = [ (r"/api/(.*)", WebHandler, dict(musikautomat=self)), (r"/(.*)", tornado.web.StaticFileHandler, {"path" : "./web", "default_filename" : "index.html" }), ] asyncio.set_event_loop(asyncio.new_event_loop()) app = tornado.web.Application(urls, debug=False) app.listen(8080) tornado.ioloop.IOLoop.instance().start() def runDisplay(self): ''' Run event loop for display and buttons. ''' clk = pygame.time.Clock() while True: clk.tick(10) # We only need 10 FPS try: for event in pygame.event.get(): # Handle exit event if event.type == pygame.QUIT: pygame.quit() sys.exit() # Handle key events if event.type == pygame.KEYDOWN: if event.key == pygame.K_DOWN: self._eventSink.action("down") elif event.key == pygame.K_UP: self._eventSink.action("up") elif event.key == pygame.K_RIGHT: if self._eventSink == self._player: self._player.togglePlay() else: self.play(self._display.currentItem()) elif event.key == pygame.K_LEFT: # Get back to display self._eventSink = self._display self._display.update() except Exception as e: # Display error traceback.print_exc() self._pydsp.fill((0,0,0)) font = pygame.font.Font('freesansbold.ttf', 12) s = str(e) n = int(self._dx / 6) for i, start in enumerate(range(0, len(s), n)): text = font.render(s[start:start+n], True, (255, 0, 0) , (0, 0, 0)) self._pydsp.blit(text, (0, i * 12)) self._eventSink = self._display pygame.display.update() def play(self, item, start=False): ''' Play an item. ''' print("Playing:", item) self._eventSink = self._player t = item.get("type") if t == "dir": self.playDir(item) else: raise Exception("Unknown type: %s" % t) if start: self._player.togglePlay() def playDir(self, item): ''' Play all files in a directory. ''' path = item.get("path") files = os.listdir(path) self._player.setPlaylist(sorted([{ "name" : f, "path" : os.path.join(path, f) } for f in files], key=lambda i: i["name"])) self._player.update()