main_screen.py 17 KB

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