123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169 |
- #!./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()
|