main_screen.py 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440
  1. import hashlib
  2. import json
  3. import logging
  4. import os
  5. import time
  6. import urllib
  7. import urllib2
  8. from threading import Thread
  9. import mopidy.core
  10. from base_screen import BaseScreen
  11. import pygame
  12. from ..graphic_utils import Progressbar, \
  13. ScreenObjectsManager, TouchAndTextItem
  14. from ..input import InputManager
  15. logger = logging.getLogger(__name__)
  16. class MainScreen(BaseScreen):
  17. def __init__(self, size, base_size, manager, fonts, cache, core,
  18. background):
  19. BaseScreen.__init__(self, size, base_size, manager, fonts)
  20. self.core = core
  21. self.track = None
  22. self.cache = cache
  23. self.image = None
  24. self.artists = None
  25. self.background = background
  26. self.track_duration = "00:00"
  27. self.touch_text_manager = ScreenObjectsManager()
  28. current_track = self.core.playback.current_track.get()
  29. if current_track is None:
  30. self.track_playback_ended(None, None)
  31. else:
  32. self.track_started(current_track)
  33. # Top bar
  34. self.top_bar = pygame.Surface((self.size[0], self.base_size),
  35. pygame.SRCALPHA)
  36. self.top_bar.fill((0, 0, 0, 128))
  37. # Play/pause
  38. button = TouchAndTextItem(self.fonts['icon'], u"\ue615 ",
  39. (0, 0), None)
  40. self.touch_text_manager.set_touch_object("pause_play", button)
  41. x = button.get_right_pos()
  42. # Random
  43. button = TouchAndTextItem(self.fonts['icon'], u"\ue629 ",
  44. (x, 0), None)
  45. self.touch_text_manager.set_touch_object("random", button)
  46. x = button.get_right_pos()
  47. # Repeat
  48. button = TouchAndTextItem(self.fonts['icon'], u"\ue626",
  49. (x, 0), None)
  50. self.touch_text_manager.set_touch_object("repeat", button)
  51. x = button.get_right_pos()
  52. # Single
  53. button = TouchAndTextItem(self.fonts['base'], " 1 ", (x, 0),
  54. None)
  55. self.touch_text_manager.set_touch_object("single", button)
  56. x = button.get_right_pos()
  57. # Internet
  58. button = TouchAndTextItem(self.fonts['icon'], u"\ue602 ",
  59. (x, 0), None)
  60. self.touch_text_manager.set_touch_object("internet", button)
  61. x = button.get_right_pos()
  62. # Mute
  63. button = TouchAndTextItem(self.fonts['icon'], u"\ue61f ",
  64. (x, 0), None)
  65. self.touch_text_manager.set_touch_object("mute", button)
  66. x = button.get_right_pos()
  67. # Volume
  68. progress = Progressbar(self.fonts['base'], "100", (x, 0),
  69. (self.size[0] - x, self.base_size),
  70. 100, True)
  71. self.touch_text_manager.set_touch_object("volume", progress)
  72. progress.set_value(self.core.playback.volume.get())
  73. def update(self, screen):
  74. screen.blit(self.top_bar, (0, 0))
  75. if self.track is not None:
  76. self.touch_text_manager.get_touch_object(
  77. "time_progress").set_value(
  78. self.core.playback.time_position.get() / 1000)
  79. self.touch_text_manager.get_touch_object(
  80. "time_progress").set_text(
  81. time.strftime('%M:%S', time.gmtime(
  82. self.core.playback.time_position.get() / 1000)) +
  83. "/" + self.track_duration)
  84. if self.image is not None:
  85. screen.blit(self.image, (
  86. self.base_size / 2, self.base_size +
  87. self.base_size / 2))
  88. self.touch_text_manager.render(screen)
  89. return screen
  90. def track_started(self, track):
  91. self.image = None
  92. x = self.base_size * 5
  93. width = self.size[0] - self.base_size / 2 - x
  94. self.track_duration = time.strftime('%M:%S', time.gmtime(
  95. track.length / 1000))
  96. # Load all artists
  97. self.artists = []
  98. for artist in track.artists:
  99. self.artists.append(artist)
  100. # Track name
  101. label = TouchAndTextItem(self.fonts['base'],
  102. MainScreen.get_track_name(track),
  103. (x, self.base_size * 2), (width, -1))
  104. self.touch_text_manager.set_touch_object("track_name", label)
  105. # Album name
  106. label = TouchAndTextItem(self.fonts['base'],
  107. MainScreen.get_track_album_name
  108. (track), (x, self.base_size * 3),
  109. (width, -1))
  110. self.touch_text_manager.set_touch_object("album_name", label)
  111. # Artist
  112. label = TouchAndTextItem(self.fonts['base'],
  113. self.get_artist_string(),
  114. (x, self.base_size * 4),
  115. (width, -1))
  116. self.touch_text_manager.set_touch_object("artist_name", label)
  117. # Previous track button
  118. button = TouchAndTextItem(self.fonts['icon'], u"\ue61c",
  119. (0, self.base_size * 6), None)
  120. self.touch_text_manager.set_touch_object("previous", button)
  121. size_1 = button.get_right_pos()
  122. size_2 = self.fonts['icon'].size(u"\ue61d")[0]
  123. button = TouchAndTextItem(self.fonts['icon'], u"\ue61d",
  124. (self.size[0] - size_2,
  125. self.base_size * 6),
  126. None)
  127. self.touch_text_manager.set_touch_object("next", button)
  128. # Progress
  129. progress = Progressbar(self.fonts['base'],
  130. time.strftime('%M:%S', time.gmtime(
  131. 0)) + "/" + time.strftime(
  132. '%M:%S', time.gmtime(0)),
  133. (size_1, self.base_size * 6),
  134. (
  135. self.size[0] - size_1 - size_2,
  136. self.base_size),
  137. track.length / 1000, False)
  138. self.touch_text_manager.set_touch_object("time_progress",
  139. progress)
  140. self.track = track
  141. if not self.is_image_in_cache():
  142. thread = Thread(target=self.download_image(0))
  143. thread.start()
  144. else:
  145. self.load_image()
  146. def get_artist_string(self):
  147. artists_string = ''
  148. for artist in self.artists:
  149. artists_string += artist.name + ', '
  150. if len(artists_string) > 2:
  151. artists_string = artists_string[:-2]
  152. elif len(artists_string) == 0:
  153. artists_string = "Unknow Artist"
  154. return artists_string
  155. def get_image_file_name(self):
  156. name = MainScreen.get_track_album_name(
  157. self.track) + '-' + self.get_artist_string()
  158. md5name = hashlib.md5(name.encode('utf-8')).hexdigest()
  159. return md5name
  160. def get_cover_folder(self):
  161. if not os.path.isdir(self.cache + "/covers"):
  162. os.makedirs(self.cache + "/covers")
  163. return self.cache + "/covers/"
  164. def is_image_in_cache(self):
  165. self.get_cover_folder()
  166. return os.path.isfile(
  167. self.get_cover_folder() + self.get_image_file_name())
  168. def download_image(self, artist_index):
  169. if artist_index < len(self.artists):
  170. try:
  171. safe_artist = urllib.quote_plus(
  172. self.artists[artist_index].name)
  173. safe_album = urllib.quote_plus(
  174. MainScreen.get_track_album_name(self.track))
  175. url = "http://ws.audioscrobbler.com/2.0/?"
  176. params = "method=album.getinfo&" + \
  177. "api_key=59a04c6a73fb99d6e8996e01db306829&" \
  178. + "artist=" \
  179. + safe_artist + "&album=" + safe_album + \
  180. "&format=json"
  181. response = urllib2.urlopen(url + params)
  182. data = json.load(response)
  183. image = data['album']['image'][-1]['#text']
  184. urllib.urlretrieve(image,
  185. self.get_cover_folder() +
  186. self.get_image_file_name())
  187. self.load_image()
  188. except:
  189. self.download_image(artist_index + 1)
  190. else:
  191. logger.info("Cover could not be downloaded")
  192. # There is no cover
  193. # so it will use all the screen size for the text
  194. width = self.size[0] - self.base_size
  195. current = TouchAndTextItem(self.fonts['base'],
  196. MainScreen.get_track_name
  197. (self.track),
  198. (self.base_size / 2,
  199. self.base_size * 2),
  200. (width, -1))
  201. self.touch_text_manager.set_touch_object("track_name",
  202. current)
  203. current = TouchAndTextItem(self.fonts['base'],
  204. MainScreen.get_track_album_name
  205. (self.track),
  206. (self.base_size / 2,
  207. self.base_size * 3),
  208. (width, -1))
  209. self.touch_text_manager.set_touch_object("album_name",
  210. current)
  211. current = TouchAndTextItem(self.fonts['base'],
  212. self.get_artist_string(),
  213. (self.base_size / 2,
  214. self.base_size * 4),
  215. (width, -1))
  216. self.touch_text_manager.set_touch_object("artist_name",
  217. current)
  218. def track_playback_ended(self, tl_track, time_position):
  219. self.background.set_target_color(None)
  220. self.image = None
  221. self.track_duration = "00:00"
  222. width = self.size[0] - self.base_size
  223. current = TouchAndTextItem(self.fonts['base'], "",
  224. (self.base_size / 2,
  225. self.base_size * 2),
  226. (width, -1))
  227. self.touch_text_manager.set_touch_object("track_name",
  228. current)
  229. current = TouchAndTextItem(self.fonts['base'], "",
  230. (self.base_size / 2,
  231. self.base_size * 3),
  232. (width, -1))
  233. self.touch_text_manager.set_touch_object("album_name",
  234. current)
  235. current = TouchAndTextItem(self.fonts['base'], "",
  236. (self.base_size / 2,
  237. self.base_size * 4),
  238. (width, -1))
  239. self.touch_text_manager.set_touch_object("artist_name",
  240. current)
  241. def load_image(self):
  242. size = self.base_size * 4
  243. image = pygame.transform.scale(pygame.image.load(
  244. self.get_cover_folder() +
  245. self.get_image_file_name()).convert(), (size, size))
  246. self.background.set_target_color(
  247. pygame.transform.average_color(image))
  248. self.image = image
  249. def touch_event(self, event):
  250. if event.type == InputManager.click:
  251. objects = \
  252. self.touch_text_manager.get_touch_objects_in_pos(
  253. event.current_pos)
  254. if objects is not None:
  255. self.click_on_objects(objects, event)
  256. elif event.type == InputManager.swipe:
  257. if event.direction == InputManager.left:
  258. self.core.playback.next()
  259. elif event.direction == InputManager.right:
  260. self.core.playback.previous()
  261. elif event.direction == InputManager.up:
  262. volume = self.core.playback.volume.get() + 10
  263. if volume > 100:
  264. volume = 100
  265. self.core.playback.volume = volume
  266. self.manager.volume_changed(volume)
  267. elif event.direction == InputManager.down:
  268. volume = self.core.playback.volume.get() - 10
  269. if volume < 0:
  270. volume = 0
  271. self.core.playback.volume = volume
  272. self.manager.volume_changed(volume)
  273. def click_on_objects(self, objects, event):
  274. if objects is not None:
  275. for key in objects:
  276. if key == "time_progress":
  277. value = self.touch_text_manager.get_touch_object(
  278. key).get_pos_value(
  279. event.current_pos) * 1000
  280. self.core.playback.seek(value)
  281. elif key == "previous":
  282. self.core.playback.previous()
  283. elif key == "next":
  284. self.core.playback.next()
  285. elif key == "volume":
  286. self.change_volume(event)
  287. elif key == "pause_play":
  288. if self.core.playback.state.get() == \
  289. mopidy.core.PlaybackState.PLAYING:
  290. self.core.playback.pause()
  291. else:
  292. self.core.playback.play()
  293. elif key == "mute":
  294. mute = not self.core.playback.mute.get()
  295. self.core.playback.set_mute(mute)
  296. self.mute_changed(mute)
  297. elif key == "random":
  298. random = not self.core.tracklist.random.get()
  299. self.core.tracklist.set_random(random)
  300. self.options_changed()
  301. elif key == "repeat":
  302. self.core.tracklist.set_repeat(
  303. not self.core.tracklist.repeat.get())
  304. elif key == "single":
  305. self.core.tracklist.set_single(
  306. not self.core.tracklist.single.get())
  307. elif key == "internet":
  308. self.manager.check_connection()
  309. elif key == "track_name":
  310. self.manager.search(self.track.name, 0)
  311. elif key == "album_name":
  312. self.manager.search(self.track.album.name, 1)
  313. elif key == "artist_name":
  314. self.manager.search(self.get_artist_string(), 2)
  315. def change_volume(self, event):
  316. manager = self.touch_text_manager
  317. volume = manager.get_touch_object("volume")
  318. pos = event.current_pos
  319. value = volume.get_pos_value(pos)
  320. self.core.playback.volume = value
  321. self.volume_changed(value)
  322. def volume_changed(self, volume):
  323. if not self.core.playback.mute.get():
  324. if volume > 80:
  325. self.touch_text_manager.get_touch_object(
  326. "mute").set_text(
  327. u"\ue61f", False)
  328. elif volume > 50:
  329. self.touch_text_manager.get_touch_object(
  330. "mute").set_text(
  331. u"\ue620", False)
  332. elif volume > 20:
  333. self.touch_text_manager.get_touch_object(
  334. "mute").set_text(
  335. u"\ue621", False)
  336. else:
  337. self.touch_text_manager.get_touch_object(
  338. "mute").set_text(
  339. u"\ue622", False)
  340. self.touch_text_manager.get_touch_object("volume").set_value(
  341. volume)
  342. def options_changed(self):
  343. self.touch_text_manager.get_touch_object("random").set_active(
  344. self.core.tracklist.random.get())
  345. self.touch_text_manager.get_touch_object("repeat").set_active(
  346. self.core.tracklist.repeat.get())
  347. self.touch_text_manager.get_touch_object("single").set_active(
  348. self.core.tracklist.single.get())
  349. def mute_changed(self, mute):
  350. self.touch_text_manager.get_touch_object("mute").set_active(
  351. not mute)
  352. if mute:
  353. self.touch_text_manager.get_touch_object("mute").set_text(
  354. u"\ue623", False)
  355. else:
  356. self.volume_changed(self.core.playback.volume.get())
  357. def playback_state_changed(self, old_state, new_state):
  358. if new_state == mopidy.core.PlaybackState.PLAYING:
  359. self.touch_text_manager.get_touch_object(
  360. "pause_play").set_text(u"\ue616", False)
  361. else:
  362. self.touch_text_manager.get_touch_object(
  363. "pause_play").set_text(u"\ue615", False)
  364. def set_connection(self, connection, loading):
  365. internet = self.touch_text_manager.get_touch_object(
  366. "internet")
  367. if loading:
  368. internet.set_text(u"\ue627", None)
  369. internet.set_active(False)
  370. else:
  371. internet.set_text(u"\ue602", None)
  372. internet.set_active(connection)
  373. @staticmethod
  374. def get_track_name(track):
  375. if track.name is None:
  376. return track.uri
  377. else:
  378. return track.name
  379. @staticmethod
  380. def get_track_album_name(track):
  381. if track.album is not None and track.album.name is not None\
  382. and len(track.album.name) > 0:
  383. return track.album.name
  384. else:
  385. return "Unknow Album"