#!./bin/python3 import os import yaml import pygame # type: ignore from typing import Dict import random import eyed3 import tempfile # Color constants BLACK = (0, 0, 0) GREEN = (0, 255, 0) WHITE = (255, 255, 255) class Display: ''' Display object ''' def __init__(self, config, pydsp): # Set config values self._dx = config.get("dimx", 128) # Drawing dimensions self._dy = config.get("dimy", 160) self._playlistFile = config.get("playlist", "music.yml") # Playlist data self._pydsp = pydsp # Pygame display object self._fontsize = config.get("fontsize", 12) # Fontsize to use self._drawlines = int(self._dy / 12) - 5 # Max number of drawn lines # Set initialisation values self._selection_pointer = 0 # Current selected value self._line_offset = 0 # Drawing offset in playlist self._current_item = None self._bgImg = None def getPlaylist(self) -> Dict: ''' Return the playlist for this display. ''' return yaml.safe_load(open(self._playlistFile)).get("playlist", []) def update(self): ''' Load the data from the given playlist file and draw it according to the current state. ''' self._pydsp.fill((0,0,0)) playlist = self.getPlaylist() # Correct offset and selection pointer if self._selection_pointer < 0: self._selection_pointer = 0 # Make sure the selection is at least at pos 0 if self._line_offset > 0: # Move the line offset down if possible self._line_offset-=1 elif self._selection_pointer > self._drawlines: # Make sure sure selection does not exceed list self._selection_pointer = self._drawlines # Move the line offset up if possible if self._line_offset < len(playlist) - self._drawlines - 1: self._line_offset+=1 # Draw lines font = pygame.font.Font('freesansbold.ttf', self._fontsize) drawline = 0 # Line currently drawm for i, item in enumerate(playlist): # Skip lines until we reached the offset if i < self._line_offset: continue # Draw the line if drawline == self._selection_pointer: text = font.render(item["name"], True, BLACK, GREEN) pygame.draw.rect(self._pydsp, BLACK, (0,0,self._dx,50)) try: self.drawArt(item) except Exception as e: print("Error while drawing art:", e) self._current_item = item else: text = font.render(item["name"], True, GREEN, BLACK) self._pydsp.blit(text, (0, drawline * self._fontsize+50)) # Increase number of drawn lines - stop when the maximum is reached drawline += 1 if drawline > self._drawlines: break def drawArt(self, item): ''' Beautify the display. ''' return font = pygame.font.Font('freesansbold.ttf', 10) path = item.get("path") title = item.get("name", "") artist = item.get("artist", "") album = item.get("album", "") date = item.get("date", "") # Try to extract meta data if path is not None and os.path.isfile(path): f = eyed3.load(path) title = f.tag.title artist = f.tag.artist album = f.tag.album if f.tag.best_release_date: date = str(f.tag.best_release_date) # Load album art for i in f.tag.images: with tempfile.TemporaryFile() as f: f.write(i.image_data) f.seek(0) i = pygame.image.load(f) i = pygame.transform.scale(i, (50, 50)) self._pydsp.blit(i, (0,0), (0, 0, self._dx, 50)) break text = font.render(title, True, WHITE, BLACK) self._pydsp.blit(text, (50, 0)) if artist != "": text = font.render(artist, True, WHITE, BLACK) self._pydsp.blit(text, (50, 10)) if album != "": text = font.render(album, True, WHITE, BLACK) self._pydsp.blit(text, (50, 20)) if date != "": text = font.render(date, True, WHITE, BLACK) self._pydsp.blit(text, (50, 30)) def currentItem(self) -> Dict: ''' Return the current selected item. ''' return self._current_item def action(self, action: str): ''' Perform an action to this display. ''' if action == "up": self._selection_pointer-=1 elif action == "down": self._selection_pointer+=1 self.update()