import gobject; gobject.threads_init() # gst needs this! import pygame from pygame.locals import * pygame.init() import pygst pygst.require("0.10") import gst, gtk import time, urllib, random import daapsource daapsource.register_daap_source("name") class PygameRenderer(object): def __init__(self, media): self.media = media self.screen = pygame.display.set_mode((0,0), pygame.FULLSCREEN) pygame.display.set_caption('media menu') pygame.mouse.set_visible(0) self.background = pygame.Surface(self.screen.get_size()) self.background = self.background.convert() self.background.fill((20,0,0)) pygame.key.set_repeat(300, 1) self.CURRENT_LIST = self.media self.CURRENT_ITEM = 0 self.onstep = 1 self.repeat_count = 0 self.mode = "BROWSING" self.window_id = pygame.display.get_wm_info()["window"] pygame.event.set_allowed([KEYDOWN, KEYUP, QUIT]) self.pipeline = None self.last_keypress = None self.last_keypress_time = 0 self.playlist = [] def main(self): self.setup_keybindings() self.browse_render() self.mainloop() def setup_keybindings(self): self.keybindings = { "PLAYING": { K_RETURN: self.play_select, K_RIGHT: self.play_seek_forward, K_LEFT: self.play_seek_backward, K_KP_ENTER: self.play_select, K_KP6: self.play_seek_forward, K_KP4: self.play_seek_backward }, "BROWSING": { K_RETURN: self.browse_select, K_UP: self.browse_up, K_DOWN: self.browse_down, K_LEFT: self.browse_left, K_RIGHT: self.browse_right, K_KP_ENTER: self.browse_select, K_KP6: self.browse_right, K_KP4: self.browse_left, K_KP2: self.browse_down, K_KP8: self.browse_up } } def mainloop(self): while 1: gtk.main_iteration(block=False) if self.mode == "PLAYING": # need to spin when playing to do gtk mainloop event = pygame.event.poll() else: event = pygame.event.wait() # when not playing, block if event.type == NOEVENT: continue if event.type == QUIT: break elif event.type == KEYDOWN and event.key == K_ESCAPE: break elif (self.mode == "PLAYING" and event.type == KEYUP) or \ (self.mode == "BROWSING" and event.type == KEYDOWN and event.key != K_RETURN and event.key != K_KP_ENTER) or \ (self.mode == "BROWSING" and event.type == KEYUP and (event.key == K_RETURN or event.key == K_KP_ENTER)): current_time = time.time() if current_time - self.last_keypress_time > 0.2: self.repeat_count = 0 self.onstep = 1 self.last_keypress_time = current_time handler = self.keybindings[self.mode].get(event.key, None) if handler: handler() def render_progress_bar(self, position, duration): self.screen.blit(self.background, (0, 0)) pygame.draw.rect(self.screen, (255, 255, 255), (100, 300, 600, 100), 5) w = int(580 * float(position) / duration) pygame.draw.rect(self.screen, (255, 255, 255), (110, 310, w, 80),0) pygame.display.flip() def surfaceFromText(self, tText=None, cColour=(255, 255, 255), fsSize=36): font = pygame.font.Font(None, fsSize) sText = font.render(unicode(tText), 1, cColour) return sText def browse_render(self): self.screen.blit(self.background, (0, 0)) fsSize = 30 parents = [self.CURRENT_LIST.name] parent = self.CURRENT_LIST.parent while parent is not None: parents.insert(0, parent.name) parent = parent.parent for i in range(-3, 10): ixThisItem = self.CURRENT_ITEM + i if ixThisItem >= len(self.CURRENT_LIST) or ixThisItem < 0: continue if i == 0: col = (255, 255, 255) else: col = (160,160,160) sThisSurface = self.surfaceFromText(self.CURRENT_LIST[ixThisItem], cColour=col, fsSize=fsSize) y = 100 + (i * fsSize) # XXX change self.screen.blit(sThisSurface, (150, y)) for i in range(len(parents)): txt = parents[i] if len(txt) > 12: txt = txt[:9] + "..." sParentSurface = self.surfaceFromText(txt, fsSize=fsSize) y = 100 + (i * fsSize) # XXX change self.screen.blit(sParentSurface, (10, y)) pygame.display.flip() def get_playlist(self, itemlist): playlist = [] for item in itemlist: if hasattr(item, "url"): if not item.url.startswith("playall://"): playlist.append(item.url) else: playlist += self.get_playlist(item) return playlist # key handlers def browse_select(self): self.mode = "PLAYING" uri = self.CURRENT_LIST[self.CURRENT_ITEM].url if uri.startswith("playall://"): self.playlist = self.get_playlist(self.CURRENT_LIST) if uri == "playall://random": random.shuffle(self.playlist) uri = self.playlist.pop(0) self.playlist.append(uri) self.playback_uri(uri) def playback_uri(self, uri): self.pipeline = gst.parse_launch("playbin uri=%s" % uri) self.vis = gst.element_factory_make("goom", "goom") self.pipeline.set_property("vis-plugin", self.vis) self.sink = gst.element_factory_make("xvimagesink", "xvimagesink") self.pipeline.set_property("video-sink", self.sink) self.sink.set_xwindow_id(self.window_id) self.sink.set_property("force-aspect-ratio", True) bus = self.pipeline.get_bus() bus.add_signal_watch() bus.connect('message::eos', self.end_playback) self.pipeline.set_state(gst.STATE_PLAYING) self.last_forward_seek = 0 self.last_backward_seek = 0 self.forward_increment = 5 # seconds self.backward_increment = 5 # seconds pygame.event.set_grab(True) def browse_up(self): self.CURRENT_ITEM -= self.onstep if self.CURRENT_ITEM < 0: self.CURRENT_ITEM = 0 self.CURRENT_LIST.current_item = self.CURRENT_ITEM self.repeat_count += 1 if self.repeat_count > 20: self.onstep = 5 if self.repeat_count > 40: self.onstep = 20 if self.repeat_count > 60: self.onstep = 50 self.browse_render() def browse_down(self): self.CURRENT_ITEM += self.onstep if self.CURRENT_ITEM > len(self.CURRENT_LIST) - 1: self.CURRENT_ITEM = len(self.CURRENT_LIST) - 1 self.CURRENT_LIST.current_item = self.CURRENT_ITEM self.repeat_count += 1 if self.repeat_count > 20: self.onstep = 5 if self.repeat_count > 40: self.onstep = 20 if self.repeat_count > 60: self.onstep = 50 self.browse_render() def browse_right(self): if not hasattr(self.CURRENT_LIST[self.CURRENT_ITEM], "url"): # can't descend into a leaf self.CURRENT_LIST = self.CURRENT_LIST[self.CURRENT_ITEM] self.CURRENT_ITEM = self.CURRENT_LIST.current_item self.browse_render() def browse_left(self): if self.CURRENT_LIST.parent: self.CURRENT_LIST = self.CURRENT_LIST.parent self.CURRENT_ITEM = self.CURRENT_LIST.current_item self.browse_render() def play_select(self): self.playlist = [] self.end_playback() def end_playback(self, *args): self.pipeline.set_state(gst.STATE_NULL) if self.playlist: uri = self.playlist.pop(0) self.playlist.append(uri) # repeat forever self.playback_uri(uri) return self.mode = "BROWSING" pygame.event.set_grab(False) self.browse_render() def play_seek_forward(self): current_time = time.time() gap = current_time - self.last_forward_seek if gap < 1: self.forward_increment += 5 else: self.forward_increment = 5 self.last_forward_seek = current_time duration = self.pipeline.query_duration(gst.FORMAT_TIME, None)[0] if duration <= 0: duration = 0 try: position = self.pipeline.query_position(gst.FORMAT_TIME, None)[0] except: # sometimes it fails; catch and ignore return self.pipeline.set_state(gst.STATE_PAUSED) if duration: self.render_progress_bar(position, duration) position += (self.forward_increment * 1000 * 1000 * 1000) if duration: if position > duration: position = duration self.pipeline.seek_simple(gst.FORMAT_TIME, gst.SEEK_FLAG_FLUSH, position) self.pipeline.set_state(gst.STATE_PLAYING) def play_seek_backward(self): current_time = time.time() gap = current_time - self.last_backward_seek if gap < 1: self.backward_increment += 1 else: self.backward_increment = 5 self.last_backward_seek = current_time duration = self.pipeline.query_duration(gst.FORMAT_TIME, None)[0] if duration <= 0: duration = 0 try: position = self.pipeline.query_position(gst.FORMAT_TIME, None)[0] except: # sometimes it fails; catch and ignore return self.pipeline.set_state(gst.STATE_PAUSED) if duration: self.render_progress_bar(position, duration) position -= (self.backward_increment * 1000 * 1000 * 1000) if position < 0 : position = 0 self.pipeline.seek_simple(gst.FORMAT_TIME, gst.SEEK_FLAG_FLUSH, position) self.pipeline.set_state(gst.STATE_PLAYING)