display.py 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. #!./bin/python3
  2. import os
  3. import yaml
  4. import pygame # type: ignore
  5. from typing import Dict
  6. import random
  7. import eyed3
  8. import tempfile
  9. # Color constants
  10. BLACK = (0, 0, 0)
  11. GREEN = (0, 255, 0)
  12. WHITE = (255, 255, 255)
  13. class Display:
  14. '''
  15. Display object
  16. '''
  17. def __init__(self, config, pydsp):
  18. # Set config values
  19. self._dx = config.get("dimx", 128) # Drawing dimensions
  20. self._dy = config.get("dimy", 160)
  21. self._playlistFile = config.get("playlist", "music.yml") # Playlist data
  22. self._pydsp = pydsp # Pygame display object
  23. self._fontsize = config.get("fontsize", 12) # Fontsize to use
  24. self._drawlines = int(self._dy / 12) - 5 # Max number of drawn lines
  25. # Set initialisation values
  26. self._selection_pointer = 0 # Current selected value
  27. self._line_offset = 0 # Drawing offset in playlist
  28. self._current_item = None
  29. self._bgImg = None
  30. def getPlaylist(self) -> Dict:
  31. '''
  32. Return the playlist for this display.
  33. '''
  34. return yaml.safe_load(open(self._playlistFile)).get("playlist", [])
  35. def update(self):
  36. '''
  37. Load the data from the given playlist file and draw it according to the current state.
  38. '''
  39. self._pydsp.fill((0,0,0))
  40. playlist = self.getPlaylist()
  41. # Correct offset and selection pointer
  42. if self._selection_pointer < 0:
  43. self._selection_pointer = 0 # Make sure the selection is at least at pos 0
  44. if self._line_offset > 0: # Move the line offset down if possible
  45. self._line_offset-=1
  46. elif self._selection_pointer > self._drawlines: # Make sure sure selection does not exceed list
  47. self._selection_pointer = self._drawlines # Move the line offset up if possible
  48. if self._line_offset < len(playlist) - self._drawlines - 1:
  49. self._line_offset+=1
  50. # Draw lines
  51. font = pygame.font.Font('freesansbold.ttf', self._fontsize)
  52. drawline = 0 # Line currently drawm
  53. for i, item in enumerate(playlist):
  54. # Skip lines until we reached the offset
  55. if i < self._line_offset:
  56. continue
  57. # Draw the line
  58. if drawline == self._selection_pointer:
  59. text = font.render(item["name"], True, BLACK, GREEN)
  60. pygame.draw.rect(self._pydsp, BLACK, (0,0,self._dx,50))
  61. try:
  62. self.drawArt(item)
  63. except Exception as e:
  64. print("Error while drawing art:", e)
  65. self._current_item = item
  66. else:
  67. text = font.render(item["name"], True, GREEN, BLACK)
  68. self._pydsp.blit(text, (0, drawline * self._fontsize+50))
  69. # Increase number of drawn lines - stop when the maximum is reached
  70. drawline += 1
  71. if drawline > self._drawlines:
  72. break
  73. def drawArt(self, item):
  74. '''
  75. Beautify the display.
  76. '''
  77. return
  78. font = pygame.font.Font('freesansbold.ttf', 10)
  79. path = item.get("path")
  80. title = item.get("name", "")
  81. artist = item.get("artist", "")
  82. album = item.get("album", "")
  83. date = item.get("date", "")
  84. # Try to extract meta data
  85. if path is not None and os.path.isfile(path):
  86. f = eyed3.load(path)
  87. title = f.tag.title
  88. artist = f.tag.artist
  89. album = f.tag.album
  90. if f.tag.best_release_date:
  91. date = str(f.tag.best_release_date)
  92. # Load album art
  93. for i in f.tag.images:
  94. with tempfile.TemporaryFile() as f:
  95. f.write(i.image_data)
  96. f.seek(0)
  97. i = pygame.image.load(f)
  98. i = pygame.transform.scale(i, (50, 50))
  99. self._pydsp.blit(i, (0,0), (0, 0, self._dx, 50))
  100. break
  101. text = font.render(title, True, WHITE, BLACK)
  102. self._pydsp.blit(text, (50, 0))
  103. if artist != "":
  104. text = font.render(artist, True, WHITE, BLACK)
  105. self._pydsp.blit(text, (50, 10))
  106. if album != "":
  107. text = font.render(album, True, WHITE, BLACK)
  108. self._pydsp.blit(text, (50, 20))
  109. if date != "":
  110. text = font.render(date, True, WHITE, BLACK)
  111. self._pydsp.blit(text, (50, 30))
  112. def currentItem(self) -> Dict:
  113. '''
  114. Return the current selected item.
  115. '''
  116. return self._current_item
  117. def action(self, action: str):
  118. '''
  119. Perform an action to this display.
  120. '''
  121. if action == "up":
  122. self._selection_pointer-=1
  123. elif action == "down":
  124. self._selection_pointer+=1
  125. self.update()