def init_show( self, show_id, selected_show, show_canvas, ): if selected_show['type'] == "mediashow": return MediaShow(show_id, selected_show, self.root, show_canvas, self.showlist, self.pp_dir, self.pp_home, self.pp_profile, ShowManager.command_callback) elif selected_show['type'] == "radiomediashow": return RadioMediaShow(show_id, selected_show, self.root, show_canvas, self.showlist, self.pp_dir, self.pp_home, self.pp_profile, ShowManager.command_callback) elif selected_show['type'] == "liveshow": return LiveShow(show_id, selected_show, self.root, show_canvas, self.showlist, self.pp_dir, self.pp_home, self.pp_profile, ShowManager.command_callback) elif selected_show['type'] == "radiobuttonshow": return RadioButtonShow(show_id, selected_show, self.root, show_canvas, self.showlist, self.pp_dir, self.pp_home, self.pp_profile, ShowManager.command_callback) elif selected_show['type'] == "hyperlinkshow": return HyperlinkShow(show_id, selected_show, self.root, show_canvas, self.showlist, self.pp_dir, self.pp_home, self.pp_profile, ShowManager.command_callback) elif selected_show['type'] == "menu": return MenuShow(show_id, selected_show, self.root, show_canvas, self.showlist, self.pp_dir, self.pp_home, self.pp_profile, ShowManager.command_callback) elif selected_show['type'] == "artmediashow": return ArtMediaShow(show_id, selected_show, self.root, show_canvas, self.showlist, self.pp_dir, self.pp_home, self.pp_profile, ShowManager.command_callback) elif selected_show['type'] == "artliveshow": return ArtLiveShow(show_id, selected_show, self.root, show_canvas, self.showlist, self.pp_dir, self.pp_home, self.pp_profile, ShowManager.command_callback) else: return None
def play_selected_track(self, selected_track): """ selects the appropriate player from type field of the medialist and computes the parameters for that type selected track is a dictionary for the track/show """ self.delete_eggtimer() if self.show_params['progress'] == "manual": self.display_eggtimer(self.resource('mediashow', 'm04')) # is menu required if self.show_params['has-child'] == "yes": self.enable_child = True else: self.enable_child = False #dispatch track by type self.player = None self.shower = None track_type = selected_track['type'] self.mon.log( self, self.show_params['show-ref'] + ' ' + str(self.show_id) + ": Track type is: " + track_type) if track_type == "video": # create a videoplayer track_file = self.complete_path(selected_track) self.player = VideoPlayer(self.show_id, self.root, self.canvas, self.show_params, selected_track, self.pp_dir, self.pp_home, self.pp_profile) self.player.play(track_file, self.showlist, self.end_player, self.ready_callback, enable_menu=self.enable_child) elif track_type == "audio": # create a audioplayer track_file = self.complete_path(selected_track) self.player = AudioPlayer(self.show_id, self.root, self.canvas, self.show_params, selected_track, self.pp_dir, self.pp_home, self.pp_profile) self.player.play(track_file, self.showlist, self.end_player, self.ready_callback, enable_menu=self.enable_child) elif track_type == "web": # create a browser track_file = self.complete_path(selected_track) self.player = BrowserPlayer(self.show_id, self.root, self.canvas, self.show_params, selected_track, self.pp_dir, self.pp_home, self.pp_profile) self.player.play(track_file, self.showlist, self.end_player, self.ready_callback, enable_menu=self.enable_child) elif track_type == "image": track_file = self.complete_path(selected_track) # images played from menus don't have children self.player = ImagePlayer(self.show_id, self.root, self.canvas, self.show_params, selected_track, self.pp_dir, self.pp_home, self.pp_profile) self.player.play(track_file, self.showlist, self.end_player, self.ready_callback, enable_menu=self.enable_child) elif track_type == "message": # bit odd because MessagePlayer is used internally to display text. text = selected_track['text'] self.player = MessagePlayer(self.show_id, self.root, self.canvas, self.show_params, selected_track, self.pp_dir, self.pp_home, self.pp_profile) self.player.play(text, self.showlist, self.end_player, self.ready_callback, enable_menu=self.enable_child) elif track_type == "show": # get the show from the showlist index = self.showlist.index_of_show(selected_track['sub-show']) if index >= 0: self.showlist.select(index) selected_show = self.showlist.selected_show() else: self.mon.err( self, "Show not found in showlist: " + selected_track['sub-show']) self.end('error', "Unknown show") if selected_show['type'] == "mediashow": self.shower = MediaShow(selected_show, self.root, self.canvas, self.showlist, self.pp_dir, self.pp_home, self.pp_profile) self.shower.play(self.show_id, self.end_shower, self.ready_callback, top=False, command=self.direction) elif selected_show['type'] == "liveshow": self.shower = LiveShow(selected_show, self.root, self.canvas, self.showlist, self.pp_dir, self.pp_home, self.pp_profile) self.shower.play(self.show_id, self.end_shower, self.ready_callback, top=False, command='nil') elif selected_show['type'] == "radiobuttonshow": self.shower = RadioButtonShow(selected_show, self.root, self.canvas, self.showlist, self.pp_dir, self.pp_home, self.pp_profile) self.shower.play(self.show_id, self.end_shower, self.ready_callback, top=False, command='nil') elif selected_show['type'] == "hyperlinkshow": self.shower = HyperlinkShow(selected_show, self.root, self.canvas, self.showlist, self.pp_dir, self.pp_home, self.pp_profile) self.shower.play(self.show_id, self.end_shower, self.ready_callback, top=False, command='nil') elif selected_show['type'] == "menu": self.shower = MenuShow(selected_show, self.root, self.canvas, self.showlist, self.pp_dir, self.pp_home, self.pp_profile) self.shower.play(self.show_id, self.end_shower, self.ready_callback, top=False, command='nil') else: self.mon.err(self, "Unknown Show Type: " + selected_show['type']) self.end('error' "Unknown show type") else: self.mon.err(self, "Unknown Track Type: " + track_type) self.end('error', "Unknown track type")
class MediaShow: # ******************* # External interface # ******************** def __init__(self, show_params, root, canvas, showlist, pp_dir, pp_home, pp_profile): """ canvas - the canvas that the menu is to be written on show - the dictionary fo the show to be played pp_home - Pi presents data_home directory pp_profile - Pi presents profile directory """ self.mon = Monitor() self.mon.on() #instantiate arguments self.show_params = show_params self.showlist = showlist self.root = root self.canvas = canvas self.pp_dir = pp_dir self.pp_home = pp_home self.pp_profile = pp_profile # open resources self.rr = ResourceReader() # Init variables self.player = None self.shower = None self.poll_for_interval_timer = None self.poll_for_continue_timer = None self.waiting_for_interval = False self.interval_timer = None self.duration_timer = None self.error = False self.interval_timer_signal = False self.end_trigger_signal = False self.end_mediashow_signal = False self.next_track_signal = False self.previous_track_signal = False self.play_child_signal = False self.req_next = 'nil' #create and instance of TimeOfDay scheduler so we can add events self.tod = TimeOfDay() self.state = 'closed' def play(self, show_id, end_callback, show_ready_callback, top=False, command='nil'): """ displays the mediashow end_callback - function to be called when the menu exits ready_callback - callback when menu is ready to display (not used) top is True when the show is top level (run from [start]) """ #instantiate the arguments self.show_id = show_id self.end_callback = end_callback self.show_ready_callback = show_ready_callback self.top = top self.command = command self.mon.log( self, self.show_params['show-ref'] + ' ' + str(self.show_id) + ": Starting show") # check data files are available. self.media_file = self.pp_profile + "/" + self.show_params['medialist'] if not os.path.exists(self.media_file): self.mon.err(self, "Medialist file not found: " + self.media_file) self.end('error', "Medialist file not found") #create a medialist for the mediashow and read it. self.medialist = MediaList() if self.medialist.open_list(self.media_file, self.showlist.sissue()) == False: self.mon.err(self, "Version of medialist different to Pi Presents") self.end('error', "Version of medialist different to Pi Presents") #get controls for this show if top level controlsmanager = ControlsManager() if self.top == True: self.controls_list = controlsmanager.default_controls() # and merge in controls from profile self.controls_list = controlsmanager.merge_show_controls( self.controls_list, self.show_params['controls']) #set up the time of day triggers for the show if self.show_params['trigger'] in ('time', 'time-quiet'): error_text = self.tod.add_times(self.show_params['trigger-input'], id(self), self.tod_start_callback, self.show_params['trigger']) if error_text <> '': self.mon.err(self, error_text) self.end('error', error_text) if self.show_params['trigger-end'] == 'time': # print self.show_params['trigger-end-time'] error_text = self.tod.add_times( self.show_params['trigger-end-time'], id(self), self.tod_end_callback, 'n/a') if error_text <> '': self.mon.err(self, error_text) self.end('error', error_text) if self.show_params['trigger-end'] == 'duration': error_text = self.calculate_duration( self.show_params['trigger-end-time']) if error_text <> '': self.mon.err(self, error_text) self.end('error', error_text) self.state = 'closed' self.egg_timer = None self.wait_for_trigger() # ******************************** # Respond to external events # ******************************** #stop received from another concurrent show def managed_stop(self): # if next lower show is running pass down to stop the show and lower level if self.shower <> None: self.shower.managed_stop() else: #stop the show if not at top self.end_mediashow_signal = True # and if track is runing stop that first if self.player <> None: self.player.input_pressed('stop') # kill or error def terminate(self, reason): if self.shower <> None: self.shower.terminate(reason) elif self.player <> None: self.player.terminate(reason) else: self.end(reason, ' terminated with no shower or player to terminate') # respond to input events def input_pressed(self, symbol, edge, source): self.mon.log( self, self.show_params['show-ref'] + ' ' + str(self.show_id) + ": received input: " + symbol) # check symbol against mediashow triggers, triggers can be used at top or lower level # and not affected by disable-controls if self.state == 'waiting' and self.show_params['trigger'] in ( 'input', 'input-quiet') and symbol == self.show_params['trigger-input']: self.start_show() elif self.state == 'playing' and self.show_params[ 'trigger-next'] == 'input' and symbol == self.show_params[ 'next-input']: self.next() # internal functions are triggered only when disable-controls is 'no' if self.show_params['disable-controls'] == 'yes': return # if at top convert symbolic name to operation otherwise lower down we have received an operation # look through list of standard symbols to find match (symbolic-name, function name) operation =lookup (symbol if self.top == True: operation = self.lookup_control(symbol, self.controls_list) else: operation = symbol # print 'operation',operation self.do_operation(operation, edge, source) #service the standard inputs for this show def do_operation(self, operation, edge, source): if self.shower <> None: # if next lower show is running pass down to stop the show and lower level self.shower.input_pressed(operation, edge, source) else: # control this show and its tracks # print 'operation',operation if operation == 'stop': if self.top == False: # not at top so stop the current show self.end_mediashow_signal = True # and if a track is running stop that first if self.player <> None: self.player.input_pressed('stop') else: # top = True, just stop track if running if self.player <> None: self.player.input_pressed('stop') elif operation in ('up', 'down'): #if playing rather than waiting use keys for next or previous if operation == 'up' and self.state == 'playing': self.previous() else: self.next() elif operation == 'play': # use 'play' to start child if state=playing or to trigger the show if waiting for trigger if self.state == 'playing': if self.show_params['has-child'] == 'yes': self.play_child_signal = True self.child_track_ref = 'pp-child-show' # and stop the current track if its running if self.player <> None: self.player.input_pressed('stop') else: if self.state == 'waiting': self.start_show() elif operation == 'pause': if self.player <> None: self.player.input_pressed(operation) #if the operation is omxplayer or mplayer runtime control then pass it to player if running elif operation[0:4] == 'omx-' or operation[ 0:6] == 'mplay-' or operation[0:5] == 'uzbl-': if self.player <> None: self.player.input_pressed(operation) def lookup_control(self, symbol, controls_list): for control in controls_list: if symbol == control[0]: return control[1] return '' # *************************** # Show sequencer # *************************** def end_interval_timer(self): self.interval_timer_signal = True # callback from time of day scheduler def tod_start_callback(self): if self.state == 'waiting' and self.show_params['trigger'] in ( 'time', 'time-quiet'): self.start_show() def tod_end_callback(self): if self.state == 'playing' and self.show_params['trigger-end'] in ( 'time', 'duration'): self.end_trigger_signal = True if self.shower <> None: self.shower.input_pressed('stop') elif self.player <> None: self.player.input_pressed('stop') def stop(self, message): self.end_mediashow_signal = True if self.interval_timer <> None: self.canvas.after_cancel(self.interval_timer) def next(self): # stop track if running and set signal self.next_track_signal = True if self.shower <> None: self.shower.input_pressed("stop") else: if self.player <> None: self.player.input_pressed("stop") def previous(self): self.previous_track_signal = True if self.shower <> None: self.shower.input_pressed("stop") else: if self.player <> None: self.player.input_pressed("stop") # wait for trigger sets the state to waiting so that events can do a start show. def wait_for_trigger(self): self.state = 'waiting' if self.show_ready_callback <> None: self.show_ready_callback() self.mon.log( self, self.show_params['show-ref'] + ' ' + str(self.show_id) + ": Waiting for trigger: " + self.show_params['trigger']) if self.show_params['trigger'] == "input": # blank screen waiting for trigger if auto, otherwise display something if self.show_params['progress'] == "manual": text = self.resource('mediashow', 'm01') else: text = self.resource('mediashow', 'm02') self.display_message(self.canvas, 'text', text, 0, self.start_show) elif self.show_params['trigger'] == "input-quiet": # blank screen waiting for trigger text = self.resource('mediashow', 'm10') self.display_message(self.canvas, 'text', text, 0, self.start_show) pass elif self.show_params['trigger'] in ('time', 'time-quiet'): # show next show notice quiet = 3 # if next show is this one display text next_show = self.tod.next_event_time() if next_show[quiet] == False: if next_show[1] == 'tomorrow': text = self.resource('mediashow', 'm09') else: text = self.resource('mediashow', 'm08') text = text.replace('%tt', next_show[0]) self.display_message(self.canvas, 'text', text, 0, self.start_show) elif self.show_params['trigger'] == "start": self.start_show() else: self.mon.err(self, "Unknown trigger: " + self.show_params['trigger']) self.end('error', "Unknown trigger type") def start_show(self): self.state = 'playing' self.direction = 'forward' # self.canvas.delete(ALL) # start interval timer if self.show_params['repeat'] == "interval" and self.show_params[ 'repeat-interval'] <> 0: self.interval_timer_signal = False self.interval_timer = self.canvas.after( int(self.show_params['repeat-interval']) * 1000, self.end_interval_timer) # start duration timer if self.show_params['trigger-end'] == 'duration': # print 'set alarm ', self.duration self.duration_timer = self.canvas.after(self.duration * 1000, self.tod_end_callback) # and play the first track unless commanded otherwise if self.command == 'backward': self.medialist.finish() else: self.medialist.start() self.play_selected_track(self.medialist.selected_track()) def what_next(self): self.direction = 'forward' # end of show trigger caused by tod if self.end_trigger_signal == True: self.end_trigger_signal = False if self.top == True: self.state = 'waiting' self.wait_for_trigger() else: # not at top so stop the show self.end('normal', 'sub-show end time trigger') # user wants to end, wait for any shows or tracks to have ended then end show # probalby will get here with end_m set when player and shower has finished elif self.end_mediashow_signal == True: if self.player == None and self.shower == None: self.end_mediashow_signal = False self.end('normal', "show ended by user") #returning from a subshow needing to move onward elif self.req_next == 'do-next': self.req_next = 'nil' self.medialist.next(self.show_params['sequence']) self.play_selected_track(self.medialist.selected_track()) #returning from a subshow needing to move backward elif self.req_next == 'do-previous': self.req_next = 'nil' self.direction = 'backward' self.medialist.previous(self.show_params['sequence']) self.play_selected_track(self.medialist.selected_track()) # user wants to play child elif self.play_child_signal == True: self.play_child_signal = False index = self.medialist.index_of_track(self.child_track_ref) if index >= 0: #don't use select the track as need to preserve mediashow sequence. child_track = self.medialist.track(index) self.display_eggtimer(self.resource('mediashow', 'm07')) self.play_selected_track(child_track) else: self.mon.err( self, "Child show not found in medialist: " + self.show_params['pp-child-show']) self.end('error', "child show not found in medialist") # skip to next track on user input elif self.next_track_signal == True: self.next_track_signal = False if self.medialist.at_end() == True: if self.show_params[ 'sequence'] == "ordered" and self.show_params[ 'repeat'] == 'oneshot' and self.top == False: self.end('do-next', "Return from Sub Show") elif self.show_params[ 'sequence'] == "ordered" and self.show_params[ 'repeat'] == 'single-run' and self.top == False: self.end('do-next', "Return from Sub Show") else: self.medialist.next(self.show_params['sequence']) self.play_selected_track(self.medialist.selected_track()) else: self.medialist.next(self.show_params['sequence']) self.play_selected_track(self.medialist.selected_track()) # skip to previous track on user input elif self.previous_track_signal == True: self.previous_track_signal = False self.direction = 'backward' if self.medialist.at_start() == True: if self.show_params[ 'sequence'] == "ordered" and self.show_params[ 'repeat'] == 'oneshot' and self.top == False: self.end('do-previous', "Return from Sub Show") elif self.show_params[ 'sequence'] == "ordered" and self.show_params[ 'repeat'] == 'single-run' and self.top == False: self.end('do-previous', "Return from Sub Show") else: self.medialist.previous(self.show_params['sequence']) self.play_selected_track(self.medialist.selected_track()) else: self.medialist.previous(self.show_params['sequence']) self.play_selected_track(self.medialist.selected_track()) # track is finished and we are on auto elif self.show_params['progress'] == "auto": if self.medialist.at_end() == True: # oneshot if self.show_params[ 'sequence'] == "ordered" and self.show_params[ 'repeat'] == 'oneshot' and self.top == False: self.end('normal', "End of Oneshot in subshow") elif self.show_params[ 'sequence'] == "ordered" and self.show_params[ 'repeat'] == 'oneshot' and self.top == True: self.wait_for_trigger() # single run elif self.show_params[ 'sequence'] == "ordered" and self.show_params[ 'repeat'] == 'single-run' and self.top == True: self.end('normal', "End of Single Run") elif self.show_params[ 'sequence'] == "ordered" and self.show_params[ 'repeat'] == 'single-run' and self.top == False: self.end('do-next', "End of single run - Return from Sub Show") # repeating and waiting to restart elif self.waiting_for_interval == True: if self.interval_timer_signal == True: self.interval_timer_signal = False self.waiting_for_interval = False self.start_show() else: self.poll_for_interval_timer = self.canvas.after( 1000, self.what_next) elif self.show_params[ 'sequence'] == "ordered" and self.show_params[ 'repeat'] == 'interval' and int( self.show_params['repeat-interval']) > 0: self.waiting_for_interval = True self.poll_for_interval_timer = self.canvas.after( 1000, self.what_next) #elif self.show_params['sequence']=="ordered" and self.show_params['repeat']=='interval' and int(self.show_params['repeat-interval'])==0: elif self.show_params['repeat'] == 'interval' and int( self.show_params['repeat-interval']) == 0: self.medialist.next(self.show_params['sequence']) self.play_selected_track(self.medialist.selected_track()) # shuffling so there is no end condition elif self.show_params['sequence'] == "shuffle": self.medialist.next(self.show_params['sequence']) self.play_selected_track(self.medialist.selected_track()) else: self.mon.err( self, "Unhandled playing event: " + self.show_params['sequence'] + ' with ' + self.show_params['repeat'] + " of " + self.show_params['repeat-interval']) self.end('error', "Unhandled playing event") else: self.medialist.next(self.show_params['sequence']) self.play_selected_track(self.medialist.selected_track()) # track has finished and we are on manual progress elif self.show_params['progress'] == "manual": self.delete_eggtimer() self.canvas.delete('pp-content') if self.show_params['trigger-next'] == 'input': self.display_eggtimer(self.resource('mediashow', 'm03')) self.poll_for_continue_timer = self.canvas.after( 2000, self.what_next) else: #unhandled state self.mon.err(self, "Unhandled playing event: ") self.end('error', "Unhandled playing event") # *************************** # Dispatching to Players/Shows # *************************** def ready_callback(self): self.delete_eggtimer() def play_selected_track(self, selected_track): """ selects the appropriate player from type field of the medialist and computes the parameters for that type selected track is a dictionary for the track/show """ self.delete_eggtimer() if self.show_params['progress'] == "manual": self.display_eggtimer(self.resource('mediashow', 'm04')) # is menu required if self.show_params['has-child'] == "yes": self.enable_child = True else: self.enable_child = False #dispatch track by type self.player = None self.shower = None track_type = selected_track['type'] self.mon.log( self, self.show_params['show-ref'] + ' ' + str(self.show_id) + ": Track type is: " + track_type) if track_type == "video": # create a videoplayer track_file = self.complete_path(selected_track) self.player = VideoPlayer(self.show_id, self.root, self.canvas, self.show_params, selected_track, self.pp_dir, self.pp_home, self.pp_profile) self.player.play(track_file, self.showlist, self.end_player, self.ready_callback, enable_menu=self.enable_child) elif track_type == "audio": # create a audioplayer track_file = self.complete_path(selected_track) self.player = AudioPlayer(self.show_id, self.root, self.canvas, self.show_params, selected_track, self.pp_dir, self.pp_home, self.pp_profile) self.player.play(track_file, self.showlist, self.end_player, self.ready_callback, enable_menu=self.enable_child) elif track_type == "web": # create a browser track_file = self.complete_path(selected_track) self.player = BrowserPlayer(self.show_id, self.root, self.canvas, self.show_params, selected_track, self.pp_dir, self.pp_home, self.pp_profile) self.player.play(track_file, self.showlist, self.end_player, self.ready_callback, enable_menu=self.enable_child) elif track_type == "image": track_file = self.complete_path(selected_track) # images played from menus don't have children self.player = ImagePlayer(self.show_id, self.root, self.canvas, self.show_params, selected_track, self.pp_dir, self.pp_home, self.pp_profile) self.player.play(track_file, self.showlist, self.end_player, self.ready_callback, enable_menu=self.enable_child) elif track_type == "message": # bit odd because MessagePlayer is used internally to display text. text = selected_track['text'] self.player = MessagePlayer(self.show_id, self.root, self.canvas, self.show_params, selected_track, self.pp_dir, self.pp_home, self.pp_profile) self.player.play(text, self.showlist, self.end_player, self.ready_callback, enable_menu=self.enable_child) elif track_type == "show": # get the show from the showlist index = self.showlist.index_of_show(selected_track['sub-show']) if index >= 0: self.showlist.select(index) selected_show = self.showlist.selected_show() else: self.mon.err( self, "Show not found in showlist: " + selected_track['sub-show']) self.end('error', "Unknown show") if selected_show['type'] == "mediashow": self.shower = MediaShow(selected_show, self.root, self.canvas, self.showlist, self.pp_dir, self.pp_home, self.pp_profile) self.shower.play(self.show_id, self.end_shower, self.ready_callback, top=False, command=self.direction) elif selected_show['type'] == "liveshow": self.shower = LiveShow(selected_show, self.root, self.canvas, self.showlist, self.pp_dir, self.pp_home, self.pp_profile) self.shower.play(self.show_id, self.end_shower, self.ready_callback, top=False, command='nil') elif selected_show['type'] == "radiobuttonshow": self.shower = RadioButtonShow(selected_show, self.root, self.canvas, self.showlist, self.pp_dir, self.pp_home, self.pp_profile) self.shower.play(self.show_id, self.end_shower, self.ready_callback, top=False, command='nil') elif selected_show['type'] == "hyperlinkshow": self.shower = HyperlinkShow(selected_show, self.root, self.canvas, self.showlist, self.pp_dir, self.pp_home, self.pp_profile) self.shower.play(self.show_id, self.end_shower, self.ready_callback, top=False, command='nil') elif selected_show['type'] == "menu": self.shower = MenuShow(selected_show, self.root, self.canvas, self.showlist, self.pp_dir, self.pp_home, self.pp_profile) self.shower.play(self.show_id, self.end_shower, self.ready_callback, top=False, command='nil') else: self.mon.err(self, "Unknown Show Type: " + selected_show['type']) self.end('error' "Unknown show type") else: self.mon.err(self, "Unknown Track Type: " + track_type) self.end('error', "Unknown track type") def end_player(self, reason, message): self.mon.log( self, self.show_params['show-ref'] + ' ' + str(self.show_id) + ": Returned from player with message: " + message) self.player = None self.req_next = 'nil' if reason in ("killed", "error"): self.end(reason, message) else: # elif>else move to what-next? if self.show_params['progress'] == "manual": self.display_eggtimer(self.resource('mediashow', 'm05')) self.req_next = reason self.what_next() else: self.req_next = reason self.what_next() def end_shower(self, show_id, reason, message): self.mon.log( self, self.show_params['show-ref'] + ' ' + str(self.show_id) + ": Returned from shower with message: " + message) self.shower = None self.req_next = 'nil' if reason in ("killed", "error"): self.end(reason, message) else: if self.show_params['progress'] == "manual": self.display_eggtimer(self.resource('mediashow', 'm06')) self.req_next = reason self.what_next() else: self.req_next = reason self.what_next() # *************************** # end of show # *************************** def end(self, reason, message): self.end_mediashow_signal = False self.mon.log( self, self.show_params['show-ref'] + ' ' + str(self.show_id) + ": Ending Mediashow") self.tidy_up() self.end_callback(self.show_id, reason, message) self = None return def tidy_up(self): #clear outstanding time of day events for this show # self.tod.clear_times_list(id(self)) if self.poll_for_continue_timer <> None: self.canvas.after_cancel(self.poll_for_continue_timer) self.poll_for_continue_timer = None if self.poll_for_interval_timer <> None: self.canvas.after_cancel(self.poll_for_interval_timer) self.poll_for_interval_timer = None if self.interval_timer <> None: self.canvas.after_cancel(self.interval_timer) self.interval_timer = None if self.duration_timer <> None: self.canvas.after_cancel(self.duration_timer) self.duration_timer = None # *************************** # displaying things # *************************** def display_eggtimer(self, text): self.canvas.create_text(int(self.canvas['width']) / 2, int(self.canvas['height']) / 2, text=text, fill='white', font="Helvetica 20 bold", tag='pp-eggtimer') self.canvas.update_idletasks() def delete_eggtimer(self): self.canvas.delete('pp-eggtimer') self.canvas.update_idletasks() # used to display internal messages in situations where a medialist entry could not be used. def display_message(self, canvas, source, content, duration, _display_message_callback): self.display_message_callback = _display_message_callback tp = { 'duration': duration, 'message-colour': 'white', 'message-font': 'Helvetica 20 bold', 'background-colour': '', 'message-justify': 'left', 'background-image': '', 'show-control-begin': '', 'show-control-end': '', 'animate-begin': '', 'animate-clear': '', 'animate-end': '', 'message-x': '', 'message-y': '', 'display-show-background': 'no', 'display-show-text': 'no', 'show-text': '', 'track-text': '', 'plugin': '' } self.player = MessagePlayer(self.show_id, self.root, canvas, tp, tp, self.pp_dir, self.pp_home, self.pp_profile) self.player.play(content, self.showlist, self.display_message_end, None, False) def display_message_end(self, reason, message): self.player = None if reason in ('error', 'killed'): self.end(reason, message) else: self.display_message_callback() # *************************** # utilities # *************************** def calculate_duration(self, line): fields = line.split(':') if len(fields) == 1: secs = fields[0] minutes = '0' hours = '0' if len(fields) == 2: secs = fields[1] minutes = fields[0] hours = '0' if len(fields) == 3: secs = fields[2] minutes = fields[1] hours = fields[0] self.duration = 3600 * long(hours) + 60 * long(minutes) + long(secs) return '' def resource(self, section, item): value = self.rr.get(section, item) if value == False: self.mon.err(self, "resource: " + section + ': ' + item + " not found") self.terminate("error") else: return value def complete_path(self, selected_track): # complete path of the filename of the selected entry track_file = selected_track['location'] if track_file <> '' and track_file[0] == "+": track_file = self.pp_home + track_file[1:] self.mon.log( self, self.show_params['show-ref'] + ' ' + str(self.show_id) + ": Track to play is: " + track_file) return track_file
class MediaShow: # ******************* # External interface # ******************** def __init__(self, show, canvas, showlist, pp_home, pp_profile): """ canvas - the canvas that the menu is to be written on show - the dictionary fo the show to be played pp_home - Pi presents data_home directory pp_profile - Pi presents profile directory """ self.mon = Monitor() self.mon.on() #instantiate arguments self.show = show self.showlist = showlist self.canvas = canvas self.pp_home = pp_home self.pp_profile = pp_profile # open resources self.rr = ResourceReader() # Init variables self.player = None self.shower = None self._poll_for_interval_timer = None self._poll_for_continue_timer = None self._waiting_for_interval = False self._interval_timer = None self.error = False self._interval_timer_signal = False self._end_mediashow_signal = False self._next_track_signal = False self._previous_track_signal = False self._play_child_signal = False self._req_next = 'nil' self._state = 'closed' def play(self, end_callback, ready_callback=None, top=False, command='nil'): """ displays the mediashow end_callback - function to be called when the menu exits ready_callback - callback when menu is ready to display (not used) top is True when the show is top level (run from [start]) """ #instantiate the arguments self._end_callback = end_callback self._ready_callback = ready_callback self.top = top self.command = command self.mon.log(self, "Starting show: " + self.show['show-ref']) # check data files are available. self.media_file = self.pp_profile + "/" + self.show['medialist'] if not os.path.exists(self.media_file): self.mon.err(self, "Medialist file not found: " + self.media_file) self._end('error', "Medialist file not found") #create a medialist for the mediashow and read it. self.medialist = MediaList() if self.medialist.open_list(self.media_file, self.showlist.sissue()) == False: self.mon.err(self, "Version of medialist different to Pi Presents") self._end('error', "Version of medialist different to Pi Presents") self._wait_for_trigger() # respond to key presses. def key_pressed(self, key_name): self.mon.log(self, "received key: " + key_name) if key_name == '': pass elif key_name == 'escape': # if next lower show is running pass down to stop the show and lower level if self.shower <> None: self.shower.key_pressed(key_name) # if not at top stop the show else: if self.top == False: self._end_mediashow_signal = True # and if a track is running stop that first if self.player <> None: self.player.key_pressed(key_name) else: # at top level in a manual presentation stop the track if self.show['progress'] == 'manual': if self.player <> None: self.player.key_pressed(key_name) elif key_name in ('up', 'down'): # if child or sub-show is running and is a show pass to show, track does not use up/down # otherwise use keys for next or previous if self.shower <> None: self.shower.key_pressed(key_name) else: if key_name == 'up': self._previous() else: self._next() elif key_name == 'return': # if child show or sub-show is running and is show - pass down- player does not use return # ELSE use Return to start child or to start the show if waiting if self.shower <> None: self.shower.key_pressed(key_name) else: if self._state == 'playing': if self.show['has-child'] == 'yes': self._play_child_signal = True # and stop the current track if its running if self.player <> None: self.player.key_pressed("escape") else: self._start_show() elif key_name == 'pir': self._start_show() elif key_name in ('p', ' '): # pass down if show or track running. if self.shower <> None: self.shower.key_pressed(key_name) elif self.player <> None: self.player.key_pressed(key_name) def button_pressed(self, button, edge): if button == 'play': self.key_pressed("return") elif button == 'up': self.key_pressed("up") elif button == 'down': self.key_pressed("down") elif button == 'stop': self.key_pressed("escape") elif button == 'pause': self.key_pressed('p') elif button == 'PIR': self.key_pressed('pir') # kill or error def terminate(self, reason): if self.shower <> None: self.mon.log(self, "sent terminate to shower") self.shower.terminate(reason) elif self.player <> None: self.mon.log(self, "sent terminate to player") self.player.terminate(reason) else: self._end(reason, 'terminated without terminating shower or player') def _tidy_up(self): if self._poll_for_continue_timer <> None: self.canvas.after_cancel(self._poll_for_continue_timer) self._poll_for_continue_timer = None if self._poll_for_interval_timer <> None: self.canvas.after_cancel(self._poll_for_interval_timer) self._poll_for_interval_timer = None if self._interval_timer <> None: self.canvas.after_cancel(self._interval_timer) self._interval_timer = None def resource(self, section, item): value = self.rr.get(section, item) if value == False: self.mon.err(self, "resource: " + section + ': ' + item + " not found") self.terminate("error") else: return value # *************************** # Respond to key/button presses # *************************** def _stop(self, message): self._end_mediashow_signal = True if self._interval_timer <> None: self.canvas.after_cancel(self._interval_timer) def _next(self): # stop track if running and set signal self._next_track_signal = True if self.shower <> None: self.shower.key_pressed("escape") else: if self.player <> None: self.player.key_pressed("escape") def _previous(self): self._previous_track_signal = True if self.shower <> None: self.shower.key_pressed("escape") else: if self.player <> None: self.player.key_pressed("escape") # *************************** # end of show functions # *************************** def _end(self, reason, message): self._end_mediashow_signal = False self.mon.log(self, "Ending Mediashow: " + self.show['show-ref']) self._tidy_up() self._end_callback(reason, message) self = None return # *************************** # Show sequencer # *************************** def _wait_for_trigger(self): self._state = 'waiting' if self.ready_callback <> None: self.ready_callback() self.mon.log(self, "Waiting for trigger: " + self.show['trigger']) if self.show['trigger'] == "button": # blank screen waiting for trigger if auto, otherwise display something if self.show['progress'] == "manual": text = self.resource('mediashow', 'm01') else: text = "" self.display_message(self.canvas, 'text', text, 0, self._start_show) elif self.show['trigger'] == "PIR": # blank screen waiting for trigger text = self.resource('mediashow', 'm02') self.display_message(self.canvas, 'text', text, 0, self._start_show) elif self.show['trigger'] == "start": self._start_show() else: self.mon.err(self, "Unknown trigger: " + self.show['trigger']) self._end('error', "Unknown trigger type") def _start_show(self): self._state = 'playing' self._direction = 'forward' # start interval timer if self.show[ 'repeat'] == "interval" and self.show['repeat-interval'] <> 0: self._interval_timer_signal = False self._interval_timer = self.canvas.after( int(self.show['repeat-interval']) * 1000, self._end_interval_timer) # and play the first track unless commanded otherwise if self.command == 'backward': self.medialist.finish() else: self.medialist.start() self._play_selected_track(self.medialist.selected_track()) def _what_next(self): self._direction = 'forward' # user wants to end, wait for any shows or tracks to have ended then end show if self._end_mediashow_signal == True: if self.player == None and self.shower == None: self._end_mediashow_signal = False self._end('normal', "show ended by user") else: pass #returning from a subshow needing to move onward elif self._req_next == 'do-next': self._req_next = 'nil' self.medialist.next() self._play_selected_track(self.medialist.selected_track()) #returning from a subshow needing to move backward elif self._req_next == 'do-previous': self._req_next = 'nil' self._direction = 'backward' self.medialist.previous() self._play_selected_track(self.medialist.selected_track()) # user wants to play child elif self._play_child_signal == True: self._play_child_signal = False index = self.medialist.index_of_track('pp-child-show') if index >= 0: #don't select the track as need to preserve mediashow sequence. child_track = self.medialist.track(index) self._display_eggtimer(self.resource('mediashow', 'm07')) self._play_selected_track(child_track) else: self.mon.err( self, "Child show not found in medialist: " + self.show['pp-child-show']) self._end('error', "child show not found in medialist") # skip to next track on user input elif self._next_track_signal == True: self._next_track_signal = False if self.medialist.at_end() == True: if self.show['sequence'] == "ordered" and self.show[ 'repeat'] == 'oneshot' and self.top == False: self._end('do-next', "Return from Sub Show") else: self.medialist.next() self._play_selected_track(self.medialist.selected_track()) else: self.medialist.next() self._play_selected_track(self.medialist.selected_track()) # skip to previous track on user input elif self._previous_track_signal == True: self._previous_track_signal = False self._direction = 'backward' if self.medialist.at_start() == True: if self.show['sequence'] == "ordered" and self.show[ 'repeat'] == 'oneshot' and self.top == False: self._end('do-previous', "Return from Sub Show") else: self.medialist.previous() self._play_selected_track(self.medialist.selected_track()) else: self.medialist.previous() self._play_selected_track(self.medialist.selected_track()) # track is finished and we are on auto elif self.show['progress'] == "auto": if self.medialist.at_end() == True: if self.show['sequence'] == "ordered" and self.show[ 'repeat'] == 'oneshot' and self.top == False: self._end('do-next', "Return from Sub Show") #### elif elif self.show['sequence'] == "ordered" and self.show[ 'repeat'] == 'oneshot' and self.top == True: self._wait_for_trigger() elif self._waiting_for_interval == True: if self._interval_timer_signal == True: self._interval_timer_signal = False self._waiting_for_interval = False self._start_show() else: self._poll_for_interval_timer = self.canvas.after( 1000, self._what_next) elif self.show['sequence'] == "ordered" and self.show[ 'repeat'] == 'interval' and int( self.show['repeat-interval']) > 0: self._waiting_for_interval = True self._poll_for_interval_timer = self.canvas.after( 1000, self._what_next) elif self.show['sequence'] == "ordered" and self.show[ 'repeat'] == 'interval' and int( self.show['repeat-interval']) == 0: self.medialist.next() self._play_selected_track(self.medialist.selected_track()) else: self.mon.err(self, "Unhandled playing event: ") self._end('error', "Unhandled playing event") else: self.medialist.next() self._play_selected_track(self.medialist.selected_track()) # track has finished and we are on manual progress elif self.show['progress'] == "manual": self._delete_eggtimer() self._display_eggtimer(self.resource('mediashow', 'm03')) self._poll_for_continue_timer = self.canvas.after( 500, self._what_next) else: #unhandled state self.mon.err(self, "Unhandled playing event: ") self._end('error', "Unhandled playing event") def _end_interval_timer(self): self._interval_timer_signal = True # *************************** # Dispatching to Players/Shows # *************************** # used to display internal messages in situations where a medialist entry could be used. def display_message(self, canvas, source, content, duration, _display_message_callback): self._display_message_callback = _display_message_callback tp = { 'duration': duration, 'message-colour': 'white', 'message-font': 'Helvetica 20 bold' } self.player = MessagePlayer(canvas, tp, tp) self.player.play(content, self._display_message_end, None) def _display_message_end(self, reason, message): self.player = None if reason in ('error', 'killed'): self._end(reason, message) else: self._display_message_callback() def complete_path(self, selected_track): # complete path of the filename of the selected entry track_file = selected_track['location'] if track_file[0] == "+": track_file = self.pp_home + track_file[1:] self.mon.log(self, "Track to play is: " + track_file) return track_file def _play_selected_track(self, selected_track): """ selects the appropriate player from type field of the medialist and computes the parameters for that type selected track is a dictionary for the track/show """ self.canvas.delete(ALL) if self.show['progress'] == "manual": self._display_eggtimer(self.resource('mediashow', 'm04')) # is menu required if self.show['has-child'] == "yes": enable_child = True else: enable_child = False #dispatch track by type self.player = None self.shower = None track_type = selected_track['type'] self.mon.log(self, "Track type is: " + track_type) if track_type == "video": # create a videoplayer track_file = self.complete_path(selected_track) self.player = VideoPlayer(self.canvas, self.show, selected_track) self.player.play(track_file, self.end_player, self.ready_callback, enable_menu=enable_child) elif track_type == "image": track_file = self.complete_path(selected_track) # images played from menus don't have children self.player = ImagePlayer(self.canvas, self.show, selected_track) self.player.play(track_file, self.end_player, self.ready_callback, enable_menu=enable_child) elif track_type == "message": # bit odd because MessagePlayer is used internally to display text. text = selected_track['text'] self.player = MessagePlayer(self.canvas, self.show, selected_track) self.player.play(text, self.end_player, self.ready_callback, enable_menu=enable_child) elif track_type == "show": # get the show from the showlist index = self.showlist.index_of_show(selected_track['sub-show']) if index >= 0: self.showlist.select(index) selected_show = self.showlist.selected_show() else: self.mon.err( self, "Show not found in showlist: " + selected_track['sub-show']) self._end('error', "Unknown show") if selected_show['type'] == "mediashow": self.shower = MediaShow(selected_show, self.canvas, self.showlist, self.pp_home, self.pp_profile) self.shower.play(self.end_shower, top=False, command=self._direction) elif selected_show['type'] == "liveshow": self.shower = LiveShow(selected_show, self.canvas, self.showlist, self.pp_home, self.pp_profile) self.shower.play(self.end_shower, top=False, command='nil') elif selected_show['type'] == "menu": self.shower = MenuShow(selected_show, self.canvas, self.showlist, self.pp_home, self.pp_profile) self.shower.play(self.end_shower, top=False, command='nil') else: self.mon.err(self, "Unknown Show Type: " + selected_show['type']) self._end('error' "Unknown show type") else: self.mon.err(self, "Unknown Track Type: " + track_type) self._end('error', "Unknown track type") def ready_callback(self): self._delete_eggtimer() def end_player(self, reason, message): self._req_next = 'nil' self.mon.log(self, "Returned from player with message: " + message) self.player = None if reason in ("killed", "error"): self._end(reason, message) elif self.show['progress'] == "manual": self._display_eggtimer(self.resource('mediashow', 'm05')) self._req_next = reason self._what_next() else: self._req_next = reason self._what_next() def end_shower(self, reason, message): self._req_next = 'nil' self.mon.log(self, "Returned from shower with message: " + message) self.shower = None if reason in ("killed", "error"): self._end(reason, message) elif self.show['progress'] == "manual": self._display_eggtimer(self.resource('mediashow', 'm06')) self._req_next = reason self._what_next() else: self._req_next = reason self._what_next() def _display_eggtimer(self, text): self.canvas.create_text(int(self.canvas['width']) / 2, int(self.canvas['height']) / 2, text=text, fill='white', font="Helvetica 20 bold") self.canvas.update_idletasks() def _delete_eggtimer(self): self.canvas.delete(ALL)
class LiveShow: NEW_TRACKS={'image':{'title':'New Image','track-ref':'','type':'image','location':'','duration':'','transition':'', 'track-text':'','track-text-font':'','track-text-colour':'','track-text-x':'0','track-text-y':'0'}, 'video':{'title':'New Video','track-ref':'','type':'video','location':'','omx-audio':''}} IMAGE_FILES=('.gif','.jpg','.jpeg','.bmp','.png','.tif') VIDEO_FILES=('.mp4','.mkv','.avi','.mp2','.wmv', '.vob') AUDIO_FILES=('.mp3','.wav','.ogg') # ******************* # External interface # ******************** def __init__(self, show, canvas, showlist, pp_home, pp_profile): """ canvas - the canvas that the show is to be written on showlist - used jus to check the issue of medialist against showlist show - the dictionary for the show to be played pp_home - Pi presents data_home directory pp_profile - Pi presents profile directory """ self.mon=Monitor() self.mon.on() #instantiate arguments self.show =show self.showlist=showlist self.canvas=canvas self.pp_home=pp_home self.pp_profile=pp_profile # open resources self.rr=ResourceReader() # Init variables self.player=None self.shower=None self._end_liveshow_signal=False self._play_child_signal = False self.error=False self._livelist=None self._new_livelist= None def play(self,end_callback,ready_callback=None, top=False,command='nil'): """ displays the liveshow end_callback - function to be called when the liveshow exits ready_callback - callback when liveshow is ready to display top is True when the show is top level (i.e. run from start show) """ #instantiate the arguments self._end_callback=end_callback self._ready_callback=ready_callback self.top=top self.mon.log(self,"Starting show: " + self.show['show-ref']) # check data files are available. self.media_file = self.pp_profile + os.sep + self.show['medialist'] if not os.path.exists(self.media_file): self.mon.err(self,"Medialist file not found: "+ self.media_file) self._stop("Medialist file not found") self.options=command_options() self._pp_live_dir1 = self.pp_home + os.sep + 'pp_live_tracks' if not os.path.exists(self._pp_live_dir1): os.mkdir(self._pp_live_dir1) self._pp_live_dir2='' if self.options['liveshow'] <>"": self._pp_live_dir2 = self.options['liveshow'] if not os.path.exists(self._pp_live_dir2): self.mon.err(self,"live tracks directory not found " + self._pp_live_dir2) self._end('error',"live tracks directory not found") #create a medialist for the liveshow and read it. # it should be empty of anonymous tracks but read it to check its version. self.medialist=MediaList() if self.medialist.open_list(self.media_file,self.showlist.sissue())==False: self.mon.err(self,"Version of medialist different to Pi Presents") self._end('error',"Version of medialist different to Pi Presents") if self.ready_callback<>None: self.ready_callback() self._play_first_track() # respond to key presses. def key_pressed(self,key_name): self.mon.log(self,"received key: " + key_name) if key_name=='': pass elif key_name=='escape': # if next lower show eor player is running pass down to stop the show/track # ELSE stop this show except for exceptions if self.shower<>None: self.shower.key_pressed(key_name) elif self.player<>None: self.player.key_pressed(key_name) else: # not at top so stop the show if self.top == False: self._stop("exit show to higher level") else: pass elif key_name in ('up','down'): # if child or sub-show is running and is a show pass to show, track does not use up/down if self.shower<>None: self.shower.key_pressed(key_name) elif key_name=='return': # if child show or sub-show is running and is show - pass down # ELSE use Return to start child if self.shower<>None: self.shower.key_pressed(key_name) else: if self.show['has-child']=="yes": self._play_child() elif key_name in ('p',' '): # pass down if show or track running. if self.shower<>None: self.shower.key_pressed(key_name) elif self.player<>None: self.player.key_pressed(key_name) def button_pressed(self,button,edge): if button=='play': self.key_pressed("return") elif button =='up': self.key_pressed("up") elif button=='down': self.key_pressed("down") elif button=='stop': self.key_pressed("escape") elif button=='pause': self.key_pressed('p') # kill or error def terminate(self,reason): if self.shower<>None: self.mon.log(self,"sent terminate to shower") self.shower.terminate(reason) elif self.player<>None: self.mon.log(self,"sent terminate to player") self.player.terminate(reason) else: self._end(reason,'terminated without terminating shower or player') def _tidy_up(self): pass def resource(self,section,item): value=self.rr.get(section,item) if value==False: self.mon.err(self, "resource: "+section +': '+ item + " not found" ) self.terminate("error",'Cannot find resource') else: return value # *************************** # Respond to key/button presses # *************************** def _stop(self,message): self._end_liveshow_signal=True def _play_child(self): self._play_child_signal=True if self.player<>None: self.player.key_pressed("escape") # *************************** # end of show functions # *************************** def _end(self,reason,message): self._end_liveshow_signal=False self.mon.log(self,"Ending Liveshow: "+ self.show['show-ref']) self._tidy_up() self._end_callback(reason,message) self=None return def _nend(self): self._end('normal','end from state machine') # *************************** # Livelist # *************************** def _livelist_add_track(self,afile): (root,title)=os.path.split(afile) (root,ext)= os.path.splitext(afile) if ext.lower() in LiveShow.IMAGE_FILES: self._livelist_new_track(LiveShow.NEW_TRACKS['image'],{'title':title,'track-ref':'','location':afile}) if ext.lower() in LiveShow.VIDEO_FILES: self._livelist_new_track(LiveShow.NEW_TRACKS['video'],{'title':title,'track-ref':'','location':afile}) if ext.lower() in LiveShow.AUDIO_FILES: self._livelist_new_track(LiveShow.NEW_TRACKS['video'],{'title':title,'track-ref':'','location':afile}) def _livelist_new_track(self,fields,values): new_track=fields self._new_livelist.append(copy.deepcopy(new_track)) last = len(self._new_livelist)-1 self._new_livelist[last].update(values) def _new_livelist_create(self): self._new_livelist=[] if os.path.exists(self._pp_live_dir1): for file in os.listdir(self._pp_live_dir1): file = self._pp_live_dir1 + os.sep + file (root_file,ext_file)= os.path.splitext(file) if ext_file.lower() in LiveShow.IMAGE_FILES+LiveShow.VIDEO_FILES+LiveShow.AUDIO_FILES: self._livelist_add_track(file) if os.path.exists(self._pp_live_dir2): for file in os.listdir(self._pp_live_dir2): file = self._pp_live_dir2 + os.sep + file (root_file,ext_file)= os.path.splitext(file) if ext_file.lower() in LiveShow.IMAGE_FILES+LiveShow.VIDEO_FILES+LiveShow.AUDIO_FILES: self._livelist_add_track(file) self._new_livelist= sorted(self._new_livelist, key= lambda track: os.path.basename(track['location']).lower()) # for it in self._new_livelist: # print it['location'] # print '' def _livelist_replace_if_changed(self): self._new_livelist_create() if self._new_livelist<>self._livelist: self._livelist=copy.deepcopy(self._new_livelist) self._livelist_index=0 def _livelist_next(self): if self._livelist_index== len(self._livelist)-1: self._livelist_index=0 else: self._livelist_index +=1 # *************************** # Play Loop # *************************** def _play_first_track(self): self._new_livelist_create() self._livelist = copy.deepcopy(self._new_livelist) self._livelist_index = 0 self._play_track() def _play_track(self): self._livelist_replace_if_changed() if len(self._livelist)>0: self._play_selected_track(self._livelist[self._livelist_index]) else: self.display_message(self.canvas,None,self.resource('liveshow','m01'),5,self._what_next) def _what_next(self): # user wants to end if self._end_liveshow_signal==True: self._end_liveshow_signal=False self._end('normal',"show ended by user") # play child? elif self._play_child_signal == True: self._play_child_signal=False index = self.medialist.index_of_track('pp-child-show') if index >=0: #don't select the track as need to preserve mediashow sequence. child_track=self.medialist.track(index) self._display_eggtimer(self.resource('liveshow','m02')) self._play_selected_track(child_track) else: self.mon.err(self,"Child show not found in medialist: "+ self.show['pp-child-show']) self._end('error',"child show not found in medialist") # otherwise loop to next track else: self._livelist_next() self._play_track() # *************************** # Dispatching to Players/Shows # *************************** # used to display internal messages in situations where a medialist entry could not be used. def display_message(self,canvas,source,content,duration,_display_message_callback): self._display_message_callback=_display_message_callback tp={'duration':duration,'message-colour':'white','message-font':'Helvetica 20 bold'} self.player=MessagePlayer(canvas,tp,tp) self.player.play(content,self._display_message_end,None) def _display_message_end(self,reason,message): self.player=None if reason in ("killed",'error'): self._end(reason,message) else: self._display_message_callback() def complete_path(self,selected_track): # complete path of the filename of the selected entry track_file = selected_track['location'] if track_file[0]=="+": track_file=self.pp_home+track_file[1:] self.mon.log(self,"Track to play is: "+ track_file) return track_file def _play_selected_track(self,selected_track): """ selects the appropriate player from type field of the medialist and computes the parameters for that type selected_track is a dictionary for the track/show """ # self.canvas.delete(ALL) # is menu required if self.show['has-child']=="yes": enable_child=True else: enable_child=False #dispatch track by type self.player=None self.shower=None track_type = selected_track['type'] self.mon.log(self,"Track type is: "+ track_type) if track_type=="image": track_file=self.complete_path(selected_track) # images played from menus don't have children self.player=ImagePlayer(self.canvas,self.show,selected_track) self.player.play(track_file, self.end_player, self.ready_callback, enable_menu=enable_child) elif track_type=="video": # create a videoplayer track_file=self.complete_path(selected_track) self.player=VideoPlayer(self.canvas,self.show,selected_track) self.player.play(track_file, self.end_player, self.ready_callback, enable_menu=enable_child) elif track_type=="show": # get the show from the showlist index = self.showlist.index_of_show(selected_track['sub-show']) if index >=0: self.showlist.select(index) selected_show=self.showlist.selected_show() else: self.mon.err(self,"Show not found in showlist: "+ selected_track['sub-show']) self._stop("Unknown show") if selected_show['type']=="mediashow": self.shower= MediaShow(selected_show, self.canvas, self.showlist, self.pp_home, self.pp_profile) self.shower.play(self.end_shower,top=False,command='nil') elif selected_show['type']=="menu": self.shower= MenuShow(selected_show, self.canvas, self.showlist, self.pp_home, self.pp_profile) self.shower.play(self.end_shower,top=False,command='nil') else: self.mon.err(self,"Unknown Show Type: "+ selected_show['type']) self._stop("Unknown show type") else: self.mon.err(self,"Unknown Track Type: "+ track_type) self._stop("Unknown track type") def ready_callback(self): self._delete_eggtimer() def end_player(self,reason,message): self.mon.log(self,"Returned from player with message: "+ message) self.player=None if reason in("killed","error"): self._end(reason,message) else: self._what_next() def end_shower(self,reason,message): self.mon.log(self,"Returned from shower with message: "+ message) self.shower=None if reason in("killed","error"): self._end(reason,message) else: self._what_next() def _display_eggtimer(self,text): self.canvas.create_text(int(self.canvas['width'])/2, int(self.canvas['height'])/2, text= text, fill='white', font="Helvetica 20 bold") self.canvas.update_idletasks( ) def _delete_eggtimer(self): self.canvas.delete(ALL)
class MediaShow: # ******************* # External interface # ******************** def __init__(self, show_params, canvas, showlist, pp_home, pp_profile): """ canvas - the canvas that the menu is to be written on show - the dictionary fo the show to be played pp_home - Pi presents data_home directory pp_profile - Pi presents profile directory """ self.mon = Monitor() self.mon.on() # instantiate arguments self.show_params = show_params self.showlist = showlist self.canvas = canvas self.pp_home = pp_home self.pp_profile = pp_profile # open resources self.rr = ResourceReader() # Init variables self.player = None self.shower = None self._poll_for_interval_timer = None self._poll_for_continue_timer = None self._waiting_for_interval = False self._interval_timer = None self.duration_timer = None self.error = False self._interval_timer_signal = False self._end_trigger_signal = False self._end_mediashow_signal = False self._next_track_signal = False self._previous_track_signal = False self._play_child_signal = False self._req_next = "nil" # create and instance of TimeOfDay scheduler so we can add events self.tod = TimeOfDay() self._state = "closed" def play(self, show_id, end_callback, ready_callback=None, top=False, command="nil"): """ displays the mediashow end_callback - function to be called when the menu exits ready_callback - callback when menu is ready to display (not used) top is True when the show is top level (run from [start]) """ # instantiate the arguments self.show_id = show_id self._end_callback = end_callback self._ready_callback = ready_callback self.top = top self.command = command self.mon.log(self, "Starting show: Id= " + str(self.show_id) + " " + self.show_params["show-ref"]) # check data files are available. self.media_file = self.pp_profile + "/" + self.show_params["medialist"] if not os.path.exists(self.media_file): self.mon.err(self, "Medialist file not found: " + self.media_file) self._end("error", "Medialist file not found") # create a medialist for the mediashow and read it. self.medialist = MediaList() if self.medialist.open_list(self.media_file, self.showlist.sissue()) == False: self.mon.err(self, "Version of medialist different to Pi Presents") self._end("error", "Version of medialist different to Pi Presents") # set up the time of day triggers for the show if self.show_params["trigger"] in ("time", "time-quiet"): error_text = self.tod.add_times( self.show_params["trigger-input"], id(self), self.tod_start_callback, self.show_params["trigger"] ) if error_text <> "": self.mon.err(self, error_text) self._end("error", error_text) if self.show_params["trigger-end"] == "time": # print self.show_params['trigger-end-time'] error_text = self.tod.add_times( self.show_params["trigger-end-time"], id(self), self.tod_end_callback, "n/a" ) if error_text <> "": self.mon.err(self, error_text) self._end("error", error_text) if self.show_params["trigger-end"] == "duration": error_text = self.calculate_duration(self.show_params["trigger-end-time"]) if error_text <> "": self.mon.err(self, error_text) self._end("error", error_text) self._state = "closed" self.egg_timer = None self._wait_for_trigger() def calculate_duration(self, line): fields = line.split(":") if len(fields) == 1: secs = fields[0] minutes = "0" hours = "0" if len(fields) == 2: secs = fields[1] minutes = fields[0] hours = "0" if len(fields) == 3: secs = fields[2] minutes = fields[1] hours = fields[0] self.duration = 3600 * long(hours) + 60 * long(minutes) + long(secs) return "" # ******************************** # Respond to external events # ******************************** # respond to key presses def key_pressed(self, key_name): self.mon.log(self, "received key: " + key_name) if self.show_params["disable-controls"] == "yes": return if key_name == "": pass elif key_name == "escape": # if next lower show is running pass down to stop the show and lower level if self.shower <> None: self.shower.key_pressed(key_name) # if not at top stop the show else: if self.top == False: self._end_mediashow_signal = True # and if a track is running stop that first if self.player <> None: self.player.key_pressed(key_name) else: # at top level in a manual presentation stop the track if self.show_params["progress"] == "manual": if self.player <> None: self.player.key_pressed(key_name) elif key_name in ("up", "down"): # if child or sub-show is running and is a show pass to show, track does not use up/down # otherwise use keys for next or previous if self.shower <> None: self.shower.key_pressed(key_name) else: if key_name == "up" and self._state == "playing": self._previous() else: self._next() elif key_name == "return": # if child show or sub-show is running and is show - pass down- player does not use return # ELSE use Return to start child or to start the show if waiting if self.shower <> None: self.shower.key_pressed(key_name) else: if self._state == "playing": if self.show_params["has-child"] == "yes": self._play_child_signal = True # and stop the current track if its running if self.player <> None: self.player.key_pressed("escape") else: if self._state == "waiting": self._start_show() elif key_name in ("p", " "): # pass down if show or track running. if self.shower <> None: self.shower.key_pressed(key_name) elif self.player <> None: self.player.key_pressed(key_name) def button_pressed(self, button, edge): # print 'mediashow button pressed', button if button == "play": self.key_pressed("return") elif button == "up": self.key_pressed("up") elif button == "down": self.key_pressed("down") elif button == "stop": self.key_pressed("escape") elif button == "pause": self.key_pressed("p") else: self.input_pressed(button) def input_pressed(self, xinput): # print self._state, self.show_params['trigger-next'], self.show_params['next-input'] if ( self._state == "waiting" and self.show_params["trigger"] == "GPIO" and xinput == self.show_params["trigger-input"] ): self.key_pressed("return") elif ( self._state == "playing" and self.show_params["trigger-next"] == "GPIO" and xinput == self.show_params["next-input"] ): self.key_pressed("down") # callback from time of day scheduler def tod_start_callback(self): if self._state == "waiting" and self.show_params["trigger"] in ("time", "time-quiet"): self._start_show() def tod_end_callback(self): if self._state == "playing" and self.show_params["trigger-end"] in ("time", "duration"): self._end_trigger_signal = True if self.shower <> None: self.shower.key_pressed("escape") elif self.player <> None: self.player.key_pressed("escape") # kill or error def terminate(self, reason): if self.shower <> None: self.mon.log(self, "sent terminate to shower") self.shower.terminate(reason) elif self.player <> None: self.mon.log(self, "sent terminate to player") self.player.terminate(reason) else: self._end(reason, "terminated without terminating shower or player") def _tidy_up(self): # clear outstanding time of day events for this show self.tod.clear_times_list(id(self)) if self._poll_for_continue_timer <> None: self.canvas.after_cancel(self._poll_for_continue_timer) self._poll_for_continue_timer = None if self._poll_for_interval_timer <> None: self.canvas.after_cancel(self._poll_for_interval_timer) self._poll_for_interval_timer = None if self._interval_timer <> None: self.canvas.after_cancel(self._interval_timer) self._interval_timer = None if self.duration_timer <> None: self.canvas.after_cancel(self.duration_timer) self.duration_timer = None def resource(self, section, item): value = self.rr.get(section, item) if value == False: self.mon.err(self, "resource: " + section + ": " + item + " not found") self.terminate("error") else: return value # *************************** # Do actions as a result of events # *************************** def _stop(self, message): self._end_mediashow_signal = True if self._interval_timer <> None: self.canvas.after_cancel(self._interval_timer) def _next(self): # stop track if running and set signal self._next_track_signal = True if self.shower <> None: self.shower.key_pressed("escape") else: if self.player <> None: self.player.key_pressed("escape") def _previous(self): self._previous_track_signal = True if self.shower <> None: self.shower.key_pressed("escape") else: if self.player <> None: self.player.key_pressed("escape") # *************************** # end of show functions # *************************** def _end(self, reason, message): self._end_mediashow_signal = False self.mon.log(self, "Ending Mediashow: " + self.show_params["show-ref"]) self._tidy_up() self._end_callback(self.show_id, reason, message) self = None return # *************************** # Show sequencer # *************************** # wait for trigger sets the state to waiting so that key/button presses can do a start show. def _wait_for_trigger(self): self._state = "waiting" if self.ready_callback <> None: self.ready_callback() self.mon.log(self, "Waiting for trigger: " + self.show_params["trigger"]) if self.show_params["trigger"] == "button": # blank screen waiting for trigger if auto, otherwise display something if self.show_params["progress"] == "manual": text = self.resource("mediashow", "m01") else: text = "" self.display_message(self.canvas, "text", text, 0, self._start_show) elif self.show_params["trigger"] == "GPIO": # blank screen waiting for trigger # text = self.resource('mediashow','m02') # self.display_message(self.canvas,'text',text,0,self._start_show) pass elif self.show_params["trigger"] in ("time", "time-quiet"): # show next show notice quiet = 3 # if next show is this one display text next_show = self.tod.next_event_time() if next_show[quiet] == False: if next_show[1] == "tomorrow": text = self.resource("mediashow", "m09") else: text = self.resource("mediashow", "m08") text = text.replace("%tt", next_show[0]) self.display_message(self.canvas, "text", text, 0, self._start_show) elif self.show_params["trigger"] == "start": self._start_show() else: self.mon.err(self, "Unknown trigger: " + self.show_params["trigger"]) self._end("error", "Unknown trigger type") def _start_show(self): self._state = "playing" self._direction = "forward" # self.canvas.delete(ALL) # start interval timer if self.show_params["repeat"] == "interval" and self.show_params["repeat-interval"] <> 0: self._interval_timer_signal = False self._interval_timer = self.canvas.after( int(self.show_params["repeat-interval"]) * 1000, self._end_interval_timer ) # start duration timer if self.show_params["trigger-end"] == "duration": # print 'set alarm ', self.duration self.duration_timer = self.canvas.after(self.duration * 1000, self.tod_end_callback) # and play the first track unless commanded otherwise if self.command == "backward": self.medialist.finish() else: self.medialist.start() self._play_selected_track(self.medialist.selected_track()) def _what_next(self): self._direction = "forward" # end of show trigger if self._end_trigger_signal == True: self._end_trigger_signal = False if self.top == True: self._state = "waiting" self._wait_for_trigger() else: # not at top so stop the show self._end("normal", "sub-show end time trigger") # user wants to end, wait for any shows or tracks to have ended then end show elif self._end_mediashow_signal == True: if self.player == None and self.shower == None: self._end_mediashow_signal = False self._end("normal", "show ended by user") else: pass # returning from a subshow needing to move onward elif self._req_next == "do-next": self._req_next = "nil" self.medialist.next(self.show_params["sequence"]) self._play_selected_track(self.medialist.selected_track()) # returning from a subshow needing to move backward elif self._req_next == "do-previous": self._req_next = "nil" self._direction = "backward" self.medialist.previous(self.show_params["sequence"]) self._play_selected_track(self.medialist.selected_track()) # user wants to play child elif self._play_child_signal == True: self._play_child_signal = False index = self.medialist.index_of_track("pp-child-show") if index >= 0: # don't select the track as need to preserve mediashow sequence. child_track = self.medialist.track(index) self._display_eggtimer(self.resource("mediashow", "m07")) self._play_selected_track(child_track) else: self.mon.err(self, "Child show not found in medialist: " + self.show_params["pp-child-show"]) self._end("error", "child show not found in medialist") # skip to next track on user input elif self._next_track_signal == True: self._next_track_signal = False if self.medialist.at_end() == True: if ( self.show_params["sequence"] == "ordered" and self.show_params["repeat"] == "oneshot" and self.top == False ): self._end("do-next", "Return from Sub Show") else: self.medialist.next(self.show_params["sequence"]) self._play_selected_track(self.medialist.selected_track()) else: self.medialist.next(self.show_params["sequence"]) self._play_selected_track(self.medialist.selected_track()) # skip to previous track on user input elif self._previous_track_signal == True: self._previous_track_signal = False self._direction = "backward" if self.medialist.at_start() == True: if ( self.show_params["sequence"] == "ordered" and self.show_params["repeat"] == "oneshot" and self.top == False ): self._end("do-previous", "Return from Sub Show") else: self.medialist.previous(self.show_params["sequence"]) self._play_selected_track(self.medialist.selected_track()) else: self.medialist.previous(self.show_params["sequence"]) self._play_selected_track(self.medialist.selected_track()) # track is finished and we are on auto elif self.show_params["progress"] == "auto": if self.medialist.at_end() == True: if ( self.show_params["sequence"] == "ordered" and self.show_params["repeat"] == "oneshot" and self.top == False ): self._end("do-next", "Return from Sub Show") elif ( self.show_params["sequence"] == "ordered" and self.show_params["repeat"] == "oneshot" and self.top == True ): self._wait_for_trigger() elif self._waiting_for_interval == True: if self._interval_timer_signal == True: self._interval_timer_signal = False self._waiting_for_interval = False self._start_show() else: self._poll_for_interval_timer = self.canvas.after(1000, self._what_next) elif ( self.show_params["sequence"] == "ordered" and self.show_params["repeat"] == "interval" and int(self.show_params["repeat-interval"]) > 0 ): self._waiting_for_interval = True self._poll_for_interval_timer = self.canvas.after(1000, self._what_next) # elif self.show_params['sequence']=="ordered" and self.show_params['repeat']=='interval' and int(self.show_params['repeat-interval'])==0: elif self.show_params["repeat"] == "interval" and int(self.show_params["repeat-interval"]) == 0: self.medialist.next(self.show_params["sequence"]) self._play_selected_track(self.medialist.selected_track()) # shffling so there is no end condition elif self.show_params["sequence"] == "shuffle": self.medialist.next(self.show_params["sequence"]) self._play_selected_track(self.medialist.selected_track()) else: self.mon.err( self, "Unhandled playing event: " + self.show_params["sequence"] + " with " + self.show_params["repeat"] + " of " + self.show_params["repeat-interval"], ) self._end("error", "Unhandled playing event") else: self.medialist.next(self.show_params["sequence"]) self._play_selected_track(self.medialist.selected_track()) # track has finished and we are on manual progress elif self.show_params["progress"] == "manual": self._delete_eggtimer() self.canvas.delete(ALL) if self.show_params["trigger-next"] == "button": self._display_eggtimer(self.resource("mediashow", "m03")) self._poll_for_continue_timer = self.canvas.after(2000, self._what_next) else: # unhandled state self.mon.err(self, "Unhandled playing event: ") self._end("error", "Unhandled playing event") def _end_interval_timer(self): self._interval_timer_signal = True # *************************** # Dispatching to Players/Shows # *************************** # used to display internal messages in situations where a medialist entry could be used. def display_message(self, canvas, source, content, duration, _display_message_callback): self._display_message_callback = _display_message_callback tp = { "duration": duration, "message-colour": "white", "message-font": "Helvetica 20 bold", "background-colour": "", "background-image": "", } self.player = MessagePlayer(self.show_id, canvas, self.pp_home, tp, tp) self.player.play(content, self._display_message_end, None) def _display_message_end(self, reason, message): self.player = None if reason in ("error", "killed"): self._end(reason, message) else: self._display_message_callback() def complete_path(self, selected_track): # complete path of the filename of the selected entry track_file = selected_track["location"] if track_file <> "" and track_file[0] == "+": track_file = self.pp_home + track_file[1:] self.mon.log(self, "Track to play is: " + track_file) return track_file def _play_selected_track(self, selected_track): """ selects the appropriate player from type field of the medialist and computes the parameters for that type selected track is a dictionary for the track/show """ # self.canvas.delete(ALL) if self.show_params["progress"] == "manual": self._display_eggtimer(self.resource("mediashow", "m04")) # is menu required if self.show_params["has-child"] == "yes": enable_child = True else: enable_child = False # dispatch track by type self.player = None self.shower = None track_type = selected_track["type"] self.mon.log(self, "Track type is: " + track_type) if track_type == "video": # create a videoplayer track_file = self.complete_path(selected_track) self.player = VideoPlayer(self.show_id, self.canvas, self.pp_home, self.show_params, selected_track) self.player.play(track_file, self.end_player, self.ready_callback, enable_menu=enable_child) elif track_type == "audio": # create a audioplayer track_file = self.complete_path(selected_track) self.player = AudioPlayer(self.show_id, self.canvas, self.pp_home, self.show_params, selected_track) self.player.play(track_file, self.end_player, self.ready_callback, enable_menu=enable_child) elif track_type == "image": track_file = self.complete_path(selected_track) # images played from menus don't have children self.player = ImagePlayer(self.show_id, self.canvas, self.pp_home, self.show_params, selected_track) self.player.play(track_file, self.end_player, self.ready_callback, enable_menu=enable_child) elif track_type == "message": # bit odd because MessagePlayer is used internally to display text. text = selected_track["text"] self.player = MessagePlayer(self.show_id, self.canvas, self.pp_home, self.show_params, selected_track) self.player.play(text, self.end_player, self.ready_callback, enable_menu=enable_child) elif track_type == "show": # get the show from the showlist index = self.showlist.index_of_show(selected_track["sub-show"]) if index >= 0: self.showlist.select(index) selected_show = self.showlist.selected_show() else: self.mon.err(self, "Show not found in showlist: " + selected_track["sub-show"]) self._end("error", "Unknown show") if selected_show["type"] == "mediashow": self.shower = MediaShow(selected_show, self.canvas, self.showlist, self.pp_home, self.pp_profile) self.shower.play(self.show_id, self.end_shower, top=False, command=self._direction) elif selected_show["type"] == "liveshow": self.shower = LiveShow(selected_show, self.canvas, self.showlist, self.pp_home, self.pp_profile) self.shower.play(self.show_id, self.end_shower, top=False, command="nil") elif selected_show["type"] == "menu": self.shower = MenuShow(selected_show, self.canvas, self.showlist, self.pp_home, self.pp_profile) self.shower.play(self.show_id, self.end_shower, top=False, command="nil") else: self.mon.err(self, "Unknown Show Type: " + selected_show["type"]) self._end("error" "Unknown show type") else: self.mon.err(self, "Unknown Track Type: " + track_type) self._end("error", "Unknown track type") def ready_callback(self): self._delete_eggtimer() def end_player(self, reason, message): self._req_next = "nil" self.mon.log(self, " Show Id: " + str(self.show_id) + " Returned from player with message: " + message) self.player = None if reason in ("killed", "error"): self._end(reason, message) elif self.show_params["progress"] == "manual": self._display_eggtimer(self.resource("mediashow", "m05")) self._req_next = reason self._what_next() else: self._req_next = reason self._what_next() def end_shower(self, show_id, reason, message): self._req_next = "nil" self.mon.log(self, "Returned from shower with message: " + message) self.shower = None if reason in ("killed", "error"): self._end(reason, message) elif self.show_params["progress"] == "manual": self._display_eggtimer(self.resource("mediashow", "m06")) self._req_next = reason self._what_next() else: self._req_next = reason self._what_next() def _display_eggtimer(self, text): self.egg_timer = self.canvas.create_text( int(self.canvas["width"]) / 2, int(self.canvas["height"]) / 2, text=text, fill="white", font="Helvetica 20 bold", ) self.canvas.update_idletasks() def _delete_eggtimer(self): if self.egg_timer != None: self.canvas.delete(self.egg_timer) self.canvas.update_idletasks()
def __init__(self): self.pipresents_issue="1.1" StopWatch.global_enable=False #**************************************** # INTERPRET COMMAND LINE # *************************************** self.options=command_options() pp_dir=sys.path[0] if not os.path.exists(pp_dir+"/pipresents.py"): tkMessageBox.showwarning("Pi Presents","Bad Application Directory") exit() #Initialise logging Monitor.log_path=pp_dir self.mon=Monitor() self.mon.on() if self.options['debug']==True: Monitor.global_enable=True else: Monitor.global_enable=False self.mon.log (self, "Pi Presents is starting") #self.show=None # create profile for pp_editor test files if already not there. if not os.path.exists(pp_dir+"/pp_home/pp_profiles/pp_editor"): self.mon.log(self,"Making pp_editor directory") os.makedirs(pp_dir+"/pp_home/pp_profiles/pp_editor") #profile path from -p option if self.options['profile']<>"": self.pp_profile_path="/pp_profiles/"+self.options['profile'] else: self.pp_profile_path = "/pp_profiles/pp_profile" #get directory containing pp_home from the command, if self.options['home'] =="": home = os.path.expanduser('~')+ os.sep+"pp_home" else: home = self.options['home'] + os.sep+ "pp_home" #check if pp_home exists. # try for 10 seconds to allow usb stick to automount # fall back to pipresents/pp_home self.pp_home=pp_dir+"/pp_home" for i in range (1, 10): self.mon.log(self,"Trying pp_home at: " + home + " " + str(i)) if os.path.exists(home): self.mon.log(self,"Using pp_home at: " + home) self.pp_home=home break time.sleep (1) #check profile exists, if not default to error profile inside pipresents self.pp_profile=self.pp_home+self.pp_profile_path if not os.path.exists(self.pp_profile): self.pp_profile=pp_dir+"/pp_home/pp_profiles/pp_profile" if self.options['verify']==True: val =Validator() if val.validate_profile(None,self.pp_home,self.pp_profile,self.pipresents_issue,False) == False: tkMessageBox.showwarning("Pi Presents","Validation Failed") exit() # open the resources self.rr=ResourceReader() # read the file, done once for all the other classes to use. self.rr.read(pp_dir,self.pp_home) #initialise the showlists and read the showlists self.showlist=ShowList() self.showlist_file= self.pp_profile+ "/pp_showlist.json" if os.path.exists(self.showlist_file): self.showlist.open_json(self.showlist_file) else: self.mon.err(self,"showlist not found at "+self.showlist_file) self._end('error','showlist not found') if float(self.showlist.sissue())<>float(self.pipresents_issue): self.mon.err(self,"Version of profile " + self.showlist.sissue() + " is not same as Pi Presents, must exit") self._end('error','wrong version of profile') # get the starter show from the showlist index = self.showlist.index_of_show('start') if index >=0: self.showlist.select(index) self.starter_show=self.showlist.selected_show() else: self.mon.err(self,"Show [start] not found in showlist") self._end('error','start show not found') # ******************** # SET UP THE GUI # ******************** #turn off the screenblanking and saver if self.options['noblank']==True: call(["xset","s", "off"]) call(["xset","s", "-dpms"]) # control display of window decorations if self.options['fullscreen']<>"partial": self.root = Tk(className="fspipresents") os.system('unclutter &') else: self.root = Tk(className="pipresents") self.title='Pi Presents - '+ self.pp_profile self.icon_text= 'Pi Presents' self.root.title(self.title) self.root.iconname(self.icon_text) self.root.config(bg='black') # get size of the screen self.screen_width = self.root.winfo_screenwidth() self.screen_height = self.root.winfo_screenheight() # set window dimensions self.window_height=self.screen_height self.window_width=self.screen_width self.window_x=0 self.window_y=0 if self.options['fullscreen']<>"partial": bar=self.options['fullscreen'] # allow just 2 pixels for the hidden taskbar if bar in ('left','right'): self.window_width=self.screen_width-2 else: self.window_height=self.screen_height-2 if bar =="left": self.window_x=2 if bar =="top": self.window_y=2 self.root.geometry("%dx%d%+d%+d" % (self.window_width,self.window_height,self.window_x,self.window_y)) self.root.attributes('-zoomed','1') else: self.window_width=self.screen_width-200 self.window_height=self.screen_height-200 self.window_x=50 self.root.geometry("%dx%d%+d%+d" % (self.window_width,self.window_height,self.window_x,self.window_y)) #canvas covers the whole window self.canvas_height=self.window_height self.canvas_width=self.window_width # make sure focus is set. self.root.focus_set() #define response to main window closing. self.root.protocol ("WM_DELETE_WINDOW", self.on_break_key) # Always use CTRL-Break key to close the program as a get out of jail self.root.bind("<Break>",self.e_on_break_key) #pass all other keys along to 'shows' and hence to 'players' self.root.bind("<Escape>", self._escape_pressed) self.root.bind("<Up>", self._up_pressed) self.root.bind("<Down>", self._down_pressed) self.root.bind("<Return>", self._return_pressed) self.root.bind("<space>", self._pause_pressed) self.root.bind("p", self._pause_pressed) #setup a canvas onto which will be drawn the images or text self.canvas = Canvas(self.root, bg='black') self.canvas.config(height=self.canvas_height, width=self.canvas_width) #self.canvas.grid(row=1,columnspan=2) self.canvas.pack() # make sure focus is set on canvas. self.canvas.focus_set() # **************************************** # INITIALISE THE APPLICATION AND START # **************************************** self.shutdown_required=False #kick off GPIO if enabled by command line option if self.options['gpio']==True: from pp_buttons import Buttons # initialise the buttons connected to GPIO self.Buttons=Buttons self.buttons = Buttons(self.root,20,self.button_pressed) self.buttons.poll() # kick off the initial show self.show=None # get the start show from the showlist index = self.showlist.index_of_show(self.starter_show['start-show']) if index >=0: self.showlist.select(index) self.start_show=self.showlist.selected_show() else: self.mon.err(self,"Show not found in showlist: "+ self.starter_show['start-show']) self._end('error','show not found in showlist') if self.start_show['type']=="mediashow": self.show= MediaShow(self.start_show, self.canvas, self.showlist, self.pp_home, self.pp_profile) self.show.play(self._end_play_show,top=True,command='nil') self.root.mainloop( ) elif self.start_show['type']=="menu": self.show= MenuShow(self.start_show, self.canvas, self.showlist, self.pp_home, self.pp_profile) self.show.play(self._end_play_show,top=True,command='nil') self.root.mainloop( ) elif self.start_show['type']=="liveshow": self.show= LiveShow(self.start_show, self.canvas, self.showlist, self.pp_home, self.pp_profile) self.show.play(self._end_play_show,top=True,command='nil') self.root.mainloop( ) else: self.mon.err(self,"unknown mediashow type in start show - "+ self.start_show['type']) self._end('error','unknown mediashow type')
class LiveShow: NEW_TRACKS = { 'image': { 'title': 'New Image', 'track-ref': '', 'type': 'image', 'location': '', 'duration': '', 'transition': '', 'track-text': '', 'track-text-font': '', 'track-text-colour': '', 'track-text-x': '0', 'track-text-y': '0' }, 'video': { 'title': 'New Video', 'track-ref': '', 'type': 'video', 'location': '', 'omx-audio': '' } } IMAGE_FILES = ('.gif', '.jpg', '.jpeg', '.bmp', '.png', '.tif') VIDEO_FILES = ('.mp4', '.mkv', '.avi', '.mp2', '.wmv') AUDIO_FILES = ('.mp3', '.wav', '.ogg') # ******************* # External interface # ******************** def __init__(self, show, canvas, showlist, pp_home, pp_profile): """ canvas - the canvas that the show is to be written on showlist - used jus to check the issue of medialist against showlist show - the dictionary for the show to be played pp_home - Pi presents data_home directory pp_profile - Pi presents profile directory """ self.mon = Monitor() self.mon.on() #instantiate arguments self.show = show self.showlist = showlist self.canvas = canvas self.pp_home = pp_home self.pp_profile = pp_profile # open resources self.rr = ResourceReader() # Init variables self.player = None self.shower = None self._end_liveshow_signal = False self._play_child_signal = False self.error = False self._livelist = None self._new_livelist = None def play(self, end_callback, ready_callback=None, top=False, command='nil'): """ displays the liveshow end_callback - function to be called when the liveshow exits ready_callback - callback when liveshow is ready to display top is True when the show is top level (i.e. run from start show) """ #instantiate the arguments self._end_callback = end_callback self._ready_callback = ready_callback self.top = top self.mon.log(self, "Starting show: " + self.show['show-ref']) # check data files are available. self.media_file = self.pp_profile + os.sep + self.show['medialist'] if not os.path.exists(self.media_file): self.mon.err(self, "Medialist file not found: " + self.media_file) self._stop("Medialist file not found") self.options = command_options() self._pp_live_dir1 = self.pp_home + os.sep + 'pp_live_tracks' if not os.path.exists(self._pp_live_dir1): os.mkdir(self._pp_live_dir1) self._pp_live_dir2 = '' if self.options['liveshow'] <> "": self._pp_live_dir2 = self.options['liveshow'] if not os.path.exists(self._pp_live_dir2): self.mon.err( self, "live tracks directory not found " + self._pp_live_dir2) self._end('error', "live tracks directory not found") #create a medialist for the liveshow and read it. # it should be empty of anonymous tracks but read it to check its version. self.medialist = MediaList() if self.medialist.open_list(self.media_file, self.showlist.sissue()) == False: self.mon.err(self, "Version of medialist different to Pi Presents") self._end('error', "Version of medialist different to Pi Presents") if self.ready_callback <> None: self.ready_callback() self._play_first_track() # respond to key presses. def key_pressed(self, key_name): self.mon.log(self, "received key: " + key_name) if key_name == '': pass elif key_name == 'escape': # if next lower show eor player is running pass down to stop the show/track # ELSE stop this show except for exceptions if self.shower <> None: self.shower.key_pressed(key_name) elif self.player <> None: self.player.key_pressed(key_name) else: # not at top so stop the show if self.top == False: self._stop("exit show to higher level") else: pass elif key_name in ('up', 'down'): # if child or sub-show is running and is a show pass to show, track does not use up/down if self.shower <> None: self.shower.key_pressed(key_name) elif key_name == 'return': # if child show or sub-show is running and is show - pass down # ELSE use Return to start child if self.shower <> None: self.shower.key_pressed(key_name) else: if self.show['has-child'] == "yes": self._play_child() elif key_name in ('p', ' '): # pass down if show or track running. if self.shower <> None: self.shower.key_pressed(key_name) elif self.player <> None: self.player.key_pressed(key_name) def button_pressed(self, button, edge): if button == 'play': self.key_pressed("return") elif button == 'up': self.key_pressed("up") elif button == 'down': self.key_pressed("down") elif button == 'stop': self.key_pressed("escape") elif button == 'pause': self.key_pressed('p') # kill or error def terminate(self, reason): if self.shower <> None: self.mon.log(self, "sent terminate to shower") self.shower.terminate(reason) elif self.player <> None: self.mon.log(self, "sent terminate to player") self.player.terminate(reason) else: self._end(reason, 'terminated without terminating shower or player') def _tidy_up(self): pass def resource(self, section, item): value = self.rr.get(section, item) if value == False: self.mon.err(self, "resource: " + section + ': ' + item + " not found") self.terminate("error", 'Cannot find resource') else: return value # *************************** # Respond to key/button presses # *************************** def _stop(self, message): self._end_liveshow_signal = True def _play_child(self): self._play_child_signal = True if self.player <> None: self.player.key_pressed("escape") # *************************** # end of show functions # *************************** def _end(self, reason, message): self._end_liveshow_signal = False self.mon.log(self, "Ending Liveshow: " + self.show['show-ref']) self._tidy_up() self._end_callback(reason, message) self = None return def _nend(self): self._end('normal', 'end from state machine') # *************************** # Livelist # *************************** def _livelist_add_track(self, afile): (root, title) = os.path.split(afile) (root, ext) = os.path.splitext(afile) if ext.lower() in LiveShow.IMAGE_FILES: self._livelist_new_track(LiveShow.NEW_TRACKS['image'], { 'title': title, 'track-ref': '', 'location': afile }) if ext.lower() in LiveShow.VIDEO_FILES: self._livelist_new_track(LiveShow.NEW_TRACKS['video'], { 'title': title, 'track-ref': '', 'location': afile }) if ext.lower() in LiveShow.AUDIO_FILES: self._livelist_new_track(LiveShow.NEW_TRACKS['video'], { 'title': title, 'track-ref': '', 'location': afile }) def _livelist_new_track(self, fields, values): new_track = fields self._new_livelist.append(copy.deepcopy(new_track)) last = len(self._new_livelist) - 1 self._new_livelist[last].update(values) def _new_livelist_create(self): self._new_livelist = [] if os.path.exists(self._pp_live_dir1): for file in os.listdir(self._pp_live_dir1): file = self._pp_live_dir1 + os.sep + file (root_file, ext_file) = os.path.splitext(file) if ext_file.lower( ) in LiveShow.IMAGE_FILES + LiveShow.VIDEO_FILES + LiveShow.AUDIO_FILES: self._livelist_add_track(file) if os.path.exists(self._pp_live_dir2): for file in os.listdir(self._pp_live_dir2): file = self._pp_live_dir2 + os.sep + file (root_file, ext_file) = os.path.splitext(file) if ext_file.lower( ) in LiveShow.IMAGE_FILES + LiveShow.VIDEO_FILES + LiveShow.AUDIO_FILES: self._livelist_add_track(file) self._new_livelist = sorted( self._new_livelist, key=lambda track: os.path.basename(track['location']).lower()) # for it in self._new_livelist: # print it['location'] # print '' def _livelist_replace_if_changed(self): self._new_livelist_create() if self._new_livelist <> self._livelist: self._livelist = copy.deepcopy(self._new_livelist) self._livelist_index = 0 def _livelist_next(self): if self._livelist_index == len(self._livelist) - 1: self._livelist_index = 0 else: self._livelist_index += 1 # *************************** # Play Loop # *************************** def _play_first_track(self): self._new_livelist_create() self._livelist = copy.deepcopy(self._new_livelist) self._livelist_index = 0 self._play_track() def _play_track(self): self._livelist_replace_if_changed() if len(self._livelist) > 0: self._play_selected_track(self._livelist[self._livelist_index]) else: self.display_message(self.canvas, None, self.resource('liveshow', 'm01'), 5, self._what_next) def _what_next(self): # user wants to end if self._end_liveshow_signal == True: self._end_liveshow_signal = False self._end('normal', "show ended by user") # play child? elif self._play_child_signal == True: self._play_child_signal = False index = self.medialist.index_of_track('pp-child-show') if index >= 0: #don't select the track as need to preserve mediashow sequence. child_track = self.medialist.track(index) self._display_eggtimer(self.resource('liveshow', 'm02')) self._play_selected_track(child_track) else: self.mon.err( self, "Child show not found in medialist: " + self.show['pp-child-show']) self._end('error', "child show not found in medialist") # otherwise loop to next track else: self._livelist_next() self._play_track() # *************************** # Dispatching to Players/Shows # *************************** # used to display internal messages in situations where a medialist entry could not be used. def display_message(self, canvas, source, content, duration, _display_message_callback): self._display_message_callback = _display_message_callback tp = { 'duration': duration, 'message-colour': 'white', 'message-font': 'Helvetica 20 bold' } self.player = MessagePlayer(canvas, tp, tp) self.player.play(content, self._display_message_end, None) def _display_message_end(self, reason, message): self.player = None if reason in ("killed", 'error'): self._end(reason, message) else: self._display_message_callback() def complete_path(self, selected_track): # complete path of the filename of the selected entry track_file = selected_track['location'] if track_file[0] == "+": track_file = self.pp_home + track_file[1:] self.mon.log(self, "Track to play is: " + track_file) return track_file def _play_selected_track(self, selected_track): """ selects the appropriate player from type field of the medialist and computes the parameters for that type selected_track is a dictionary for the track/show """ # self.canvas.delete(ALL) # is menu required if self.show['has-child'] == "yes": enable_child = True else: enable_child = False #dispatch track by type self.player = None self.shower = None track_type = selected_track['type'] self.mon.log(self, "Track type is: " + track_type) if track_type == "image": track_file = self.complete_path(selected_track) # images played from menus don't have children self.player = ImagePlayer(self.canvas, self.show, selected_track) self.player.play(track_file, self.end_player, self.ready_callback, enable_menu=enable_child) elif track_type == "video": # create a videoplayer track_file = self.complete_path(selected_track) self.player = VideoPlayer(self.canvas, self.show, selected_track) self.player.play(track_file, self.end_player, self.ready_callback, enable_menu=enable_child) elif track_type == "show": # get the show from the showlist index = self.showlist.index_of_show(selected_track['sub-show']) if index >= 0: self.showlist.select(index) selected_show = self.showlist.selected_show() else: self.mon.err( self, "Show not found in showlist: " + selected_track['sub-show']) self._stop("Unknown show") if selected_show['type'] == "mediashow": self.shower = MediaShow(selected_show, self.canvas, self.showlist, self.pp_home, self.pp_profile) self.shower.play(self.end_shower, top=False, command='nil') elif selected_show['type'] == "menu": self.shower = MenuShow(selected_show, self.canvas, self.showlist, self.pp_home, self.pp_profile) self.shower.play(self.end_shower, top=False, command='nil') else: self.mon.err(self, "Unknown Show Type: " + selected_show['type']) self._stop("Unknown show type") else: self.mon.err(self, "Unknown Track Type: " + track_type) self._stop("Unknown track type") def ready_callback(self): self._delete_eggtimer() def end_player(self, reason, message): self.mon.log(self, "Returned from player with message: " + message) self.player = None if reason in ("killed", "error"): self._end(reason, message) else: self._what_next() def end_shower(self, reason, message): self.mon.log(self, "Returned from shower with message: " + message) self.shower = None if reason in ("killed", "error"): self._end(reason, message) else: self._what_next() def _display_eggtimer(self, text): self.canvas.create_text(int(self.canvas['width']) / 2, int(self.canvas['height']) / 2, text=text, fill='white', font="Helvetica 20 bold") self.canvas.update_idletasks() def _delete_eggtimer(self): self.canvas.delete(ALL)
class RadioButtonShow: """ starts at 'first-track' which can be any type of track or a show The show has links of the form symbolic-name play track-ref key, gpio or click area will play the referenced track at the end of that track control will return to first-track links in the tracks are ignored. Links are inherited from the show. timeout returns to first-track interface: * play - selects the first track to play (first-track) * input_pressed, - receives user events passes them to a Shower/Player if a track is playing, otherwise actions them depending on the symbolic name supplied """ # ********************* # external interface # ******************** def __init__(self, show_params, root, canvas, showlist, pp_dir, pp_home, pp_profile): """ canvas - the canvas that the tracks of the event show are to be written on show_params - the name of the configuration dictionary section for the radiobuttonshow showlist - the showlist, to enable runningnof show type tracks. pp_home - Pi presents data_home directory pp_profile - Pi presents profile directory """ self.mon=Monitor() self.mon.on() #instantiate arguments self.show_params=show_params self.showlist=showlist self.root=root self.canvas=canvas self.pp_dir=pp_dir self.pp_home=pp_home self.pp_profile=pp_profile # open resources self.rr=ResourceReader() #create a path stack - only used to parse the links. self.path = PathManager() # init variables self.drawn = None self.player=None self.shower=None self.timeout_running=None self.error=False def play(self,show_id,end_callback,ready_callback,top=False,command='nil'): """ starts the hyperlink show at start-track end_callback - function to be called when the show exits ready_callback - callback when event-show is ready to display its forst track (not used?) top is True when the show is top level (run from [start] or from show control) command is not used """ #instantiate arguments self.show_id=show_id self.end_callback=end_callback self.ready_callback=ready_callback self.top=top self.command=command # check data files are available. self.medialist_file = self.pp_profile + "/" + self.show_params['medialist'] if not os.path.exists(self.medialist_file): self.mon.err(self,"Medialist file not found: "+ self.medialist_file) self.end('error',"Medialist file not found") #create a medialist object for the radiobuttonshow and read the file into it. self.medialist=MediaList() if self.medialist.open_list(self.medialist_file,self.showlist.sissue()) == False: self.mon.err(self,"Version of medialist different to Pi Presents") self.end('error',"Version of medialist different to Pi Presents") # read show destinations self.first_track_ref=self.show_params['first-track-ref'] #get control bindings for this show if top level controlsmanager=ControlsManager() if self.top==True: self.controls_list=controlsmanager.default_controls() # and merge in controls from profile self.controls_list=controlsmanager.merge_show_controls(self.controls_list,self.show_params['controls']) #read the show links. Track links will be added by ready_callback links_text=self.show_params['links'] reason,message,self.links=self.path.parse_links(links_text) if reason=='error': self.mon.err(self,message + " in show") self.end('error',message) # state variables and signals self.end_radiobuttonshow_signal= False self.egg_timer=None self.next_track_signal=False self.next_track_ref='' self.current_track_ref='' self.current_track_type='' # ready callback for show if self.ready_callback<>None: self.ready_callback() self.canvas.delete('pp-content') self.canvas.config(bg='black') self.do_first_track() #stop received from another concurrent show via ShowManager def managed_stop(self): # set signal to stop the radiobuttonshow when all sub-shows and players have ended self.end_radiobuttonshow_signal=True # then stop and shows or tracks. if self.shower<>None: self.shower.managed_stop() elif self.player<>None: self.player.input_pressed('stop') else: self.end('normal','stopped by ShowManager') # kill or error def terminate(self,reason): self.end_radiobuttonshow_signal=True if self.shower<>None: self.shower.terminate(reason) elif self.player<>None: self.player.terminate(reason) else: self.end(reason,'terminated without terminating shower or player') # respond to inputs def input_pressed(self,symbol,edge,source): self.mon.log(self,"received symbol: " + symbol) #does the symbol match a link, if so execute it if self.is_link(symbol,edge,source)==True: return # controls are disabled so ignore inputs if self.show_params['disable-controls']=='yes': return # does it match a control # if at top convert symbolic name to operation otherwise lower down we have received an operatio # look through list of controls to find match if self.top==True: operation=self.lookup_control(symbol,self.controls_list) else: operation=symbol # print 'operation',operation if operation<>'': self.do_operation(operation,edge,source) def do_operation(self,operation,edge,source): if self.shower<>None: # if next lower show is running pass down to stop the show and lower level self.shower.input_pressed(operation,edge,source) else: #control this show and its tracks if operation=='stop': if self.player<>None: if self.current_track_ref==self.first_track_ref and self.top==False: self.end_radiobuttonshow_signal=True self.player.input_pressed('stop') elif operation == 'pause': if self.player<>None: self.player.input_pressed(operation) elif operation[0:4]=='omx-' or operation[0:6]=='mplay-'or operation[0:5]=='uzbl-': if self.player<>None: self.player.input_pressed(operation) def lookup_control(self,symbol,controls_list): for control in controls_list: if symbol == control[0]: return control[1] return '' def is_link(self,symbol,edge,source): # we have links which locally define symbolic names to be converted to radiobuttonshow operations # find the first entry in links that matches the symbol and execute its operation #print 'radiobuttonshow ',symbol found=False for link in self.links: #print link if symbol==link[0]: found=True if link[1]<>'null': #print 'match',link[0] link_operation=link[1] if link_operation=='play': self.do_play(link[2],edge,source) return found # ********************* # INTERNAL FUNCTIONS # ******************** # ********************* # Show Sequencer # ********************* def timeout_callback(self): self.do_play(self.first_track_ref,'front','timeout') def do_play(self,track_ref,edge,source): if track_ref<>self.current_track_ref: # print 'executing play ',track_ref self.next_track_signal=True self.next_track_op='play' self.next_track_arg=track_ref if self.shower<>None: self.shower.input_pressed('stop',edge,source) elif self.player<>None: self.player.input_pressed('stop') else: self.what_next() def do_first_track(self): index = self.medialist.index_of_track(self.first_track_ref) if index >=0: #don't use select the track as not using selected_track in radiobuttonshow first_track=self.medialist.track(index) self.path.append(first_track['track-ref']) self.current_track_ref=self.first_track_ref self.play_selected_track(first_track) else: self.mon.err(self,"first-track not found in medialist: "+ self.show_params['first-frack-ref']) self.end('error',"first track not found in medialist") def what_next(self): # user wants to end the show if self.end_radiobuttonshow_signal==True: self.end_radiobuttonshow_signal=False self.end('normal',"show ended by user") # user has selected another track elif self.next_track_signal==True: self.next_track_signal=False self.next_track_ref=self.next_track_arg self.current_track_ref=self.next_track_ref index = self.medialist.index_of_track(self.next_track_ref) if index >=0: #don't use select the track as not using selected_track in radiobuttonshow next_track=self.medialist.track(index) self.play_selected_track(next_track) else: self.mon.err(self,"next-track not found in medialist: "+ self.next_track_ref) self.end('error',"next track not found in medialist") else: #track ends naturally self.next_track_ref=self.first_track_ref self.current_track_ref=self.next_track_ref index = self.medialist.index_of_track(self.next_track_ref) if index >=0: #don't use select the track as not using selected_track in radiobuttonshow next_track=self.medialist.track(index) self.play_selected_track(next_track) else: self.mon.err(self,"next-track not found in medialist: "+ self.next_track_ref) self.end('error',"next track not found in medialist") # ********************* # Dispatching to Players # ********************* def page_callback(self): # called from a Player when ready to play, if first-track merge the links from the track with those from the show self.delete_eggtimer() if self.current_track_ref==self.first_track_ref: #links_text=self.player.get_links() #reason,message,track_links=self.path.parse_links(links_text) #if reason=='error': #self.mon.err(self,message + " in page") #self.end('error',message) #self.path.merge_links(self.links,track_links) pass def play_selected_track(self,selected_track): """ selects the appropriate player from type field of the medialist and computes the parameters for that type selected track is a dictionary for the track/show """ if self.timeout_running<>None: self.canvas.after_cancel(self.timeout_running) self.timeout_running=None # self.display_eggtimer(self.resource('radiobuttonshow','m01')) self.current_track_type = selected_track['type'] #start timeout for the track if required if self.current_track_ref<>self.first_track_ref and int(self.show_params['timeout'])<>0: self.timeout_running=self.canvas.after(int(self.show_params['timeout'])*1000,self.timeout_callback) # dispatch track by type self.player=None self.shower=None track_type = selected_track['type'] self.mon.log(self,"Track type is: "+ track_type) if track_type=="video": # create a videoplayer track_file=self.complete_path(selected_track) self.player=VideoPlayer(self.show_id,self.root,self.canvas,self.show_params,selected_track,self.pp_dir,self.pp_home,self.pp_profile) self.player.play(track_file, self.showlist, self.end_player, self.page_callback, enable_menu=False) elif track_type=="audio": # create a audioplayer track_file=self.complete_path(selected_track) self.player=AudioPlayer(self.show_id,self.root,self.canvas,self.show_params,selected_track,self.pp_dir,self.pp_home,self.pp_profile) self.player.play(track_file, self.showlist, self.end_player, self.page_callback, enable_menu=False) elif track_type=="image": track_file=self.complete_path(selected_track) self.player=ImagePlayer(self.show_id,self.root,self.canvas,self.show_params,selected_track,self.pp_dir,self.pp_home,self.pp_profile) self.player.play(track_file, self.showlist, self.end_player, self.page_callback, enable_menu=False, ) elif track_type=="web": # create a browser track_file=self.complete_path(selected_track) self.player=BrowserPlayer(self.show_id,self.root,self.canvas,self.show_params,selected_track,self.pp_dir,self.pp_home,self.pp_profile) self.player.play(track_file, self.showlist, self.end_player, self.page_callback, enable_menu=False) elif track_type=="message": # bit odd because MessagePlayer is used internally to display text. text=selected_track['text'] self.player=MessagePlayer(self.show_id,self.root,self.canvas,self.show_params,selected_track,self.pp_dir,self.pp_home,self.pp_profile) self.player.play(text, self.showlist, self.end_player, self.page_callback, enable_menu=False ) elif track_type=="show": # self.enable_click_areas() # get the show from the showlist index = self.showlist.index_of_show(selected_track['sub-show']) if index >=0: self.showlist.select(index) selected_show=self.showlist.selected_show() else: self.mon.err(self,"Show not found in showlist: "+ selected_track['sub-show']) self.end("Unknown show") if selected_show['type']=="mediashow": self.shower= MediaShow(selected_show, self.root, self.canvas, self.showlist, self.pp_dir, self.pp_home, self.pp_profile) self.shower.play(self.show_id,self.end_shower,self.ready_callback,top=False,command='nil') elif selected_show['type']=="liveshow": self.shower= LiveShow(selected_show, self.root, self.canvas, self.showlist, self.pp_dir, self.pp_home, self.pp_profile) self.shower.play(self.show_id,self.end_shower,self.ready_callback,top=False,command='nil') elif selected_show['type']=="radiobuttonshow": self.shower= RadioButtonShow(selected_show, self.root, self.canvas, self.showlist, self.pp_dir, self.pp_home, self.pp_profile) self.shower.play(self.show_id,self.end_shower,self.ready_callback,top=False,command='nil') elif selected_show['type']=="hyperlinkshow": self.shower= HyperlinkShow(selected_show, self.root, self.canvas, self.showlist, self.pp_dir, self.pp_home, self.pp_profile) self.shower.play(self.show_id,self.end_shower,self.ready_callback,top=False,command='nil') elif selected_show['type']=="menu": self.shower= MenuShow(selected_show, self.root, self.canvas, self.showlist, self.pp_dir, self.pp_home, self.pp_profile) self.shower.play(self.show_id,self.end_shower,self.ready_callback,top=False,command='nil') else: self.mon.err(self,"Unknown Show Type: "+ selected_show['type']) self.end("Unknown show type") else: self.mon.err(self,"Unknown Track Type: "+ track_type) self.end("Unknown track type") # callback from when player ends def end_player(self,reason,message): self.mon.log(self,"Returned from player with message: "+ message) self.player=None # this does not seem to change the colour of the polygon # self.canvas.itemconfig('pp-click-area',state='hidden') self.canvas.update_idletasks( ) if reason in("killed","error"): self.end(reason,message) else: #self.display_eggtimer(self.resource('radiobuttonshow','m02')) self.what_next() # callback from when shower ends def end_shower(self,show_id,reason,message): self.mon.log(self,"Returned from shower with message: "+ message) self.shower=None # self.canvas.itemconfig('pp-click-area',state='hidden') self.canvas.update_idletasks( ) if reason in ("killed","error"): self.end(reason,message) else: #self.display_eggtimer(self.resource('radiobuttonshow','m03')) self.what_next() # ********************* # End the show # ********************* # finish the player for killing, error or normally # this may be called directly sub/child shows or players are not running # if they might be running then need to call terminate. def end(self,reason,message): self.mon.log(self,"Ending radiobuttonshow: "+ self.show_params['show-ref']) self.end_callback(self.show_id,reason,message) self=None return # ********************* # displaying things # ********************* def display_eggtimer(self,text): #self.egg_timer=self.canvas.create_text(int(self.canvas['width'])/2, #int(self.canvas['height'])/2, #text= text, # fill='white', # font="Helvetica 20 bold") #self.canvas.update_idletasks( ) pass def delete_eggtimer(self): if self.egg_timer!=None: self.canvas.delete(self.egg_timer) # ********************* # utilities # ********************* def complete_path(self,selected_track): # complete path of the filename of the selected entry track_file = selected_track['location'] if track_file<>'' and track_file[0]=="+": track_file=self.pp_home+track_file[1:] self.mon.log(self,"Track to play is: "+ track_file) return track_file def resource(self,section,item): value=self.rr.get(section,item) if value==False: self.mon.err(self, "resource: "+section +': '+ item + " not found" ) # players or showers may be running so need terminate self.terminate("error") else: return value
def play_selected_track(self,selected_track): """ selects the appropriate player from type field of the medialist and computes the parameters for that type selected track is a dictionary for the track/show """ if self.timeout_running<>None: self.canvas.after_cancel(self.timeout_running) self.timeout_running=None # self.display_eggtimer(self.resource('radiobuttonshow','m01')) self.current_track_type = selected_track['type'] #start timeout for the track if required if self.current_track_ref<>self.first_track_ref and int(self.show_params['timeout'])<>0: self.timeout_running=self.canvas.after(int(self.show_params['timeout'])*1000,self.timeout_callback) # dispatch track by type self.player=None self.shower=None track_type = selected_track['type'] self.mon.log(self,"Track type is: "+ track_type) if track_type=="video": # create a videoplayer track_file=self.complete_path(selected_track) self.player=VideoPlayer(self.show_id,self.root,self.canvas,self.show_params,selected_track,self.pp_dir,self.pp_home,self.pp_profile) self.player.play(track_file, self.showlist, self.end_player, self.page_callback, enable_menu=False) elif track_type=="audio": # create a audioplayer track_file=self.complete_path(selected_track) self.player=AudioPlayer(self.show_id,self.root,self.canvas,self.show_params,selected_track,self.pp_dir,self.pp_home,self.pp_profile) self.player.play(track_file, self.showlist, self.end_player, self.page_callback, enable_menu=False) elif track_type=="image": track_file=self.complete_path(selected_track) self.player=ImagePlayer(self.show_id,self.root,self.canvas,self.show_params,selected_track,self.pp_dir,self.pp_home,self.pp_profile) self.player.play(track_file, self.showlist, self.end_player, self.page_callback, enable_menu=False, ) elif track_type=="web": # create a browser track_file=self.complete_path(selected_track) self.player=BrowserPlayer(self.show_id,self.root,self.canvas,self.show_params,selected_track,self.pp_dir,self.pp_home,self.pp_profile) self.player.play(track_file, self.showlist, self.end_player, self.page_callback, enable_menu=False) elif track_type=="message": # bit odd because MessagePlayer is used internally to display text. text=selected_track['text'] self.player=MessagePlayer(self.show_id,self.root,self.canvas,self.show_params,selected_track,self.pp_dir,self.pp_home,self.pp_profile) self.player.play(text, self.showlist, self.end_player, self.page_callback, enable_menu=False ) elif track_type=="show": # self.enable_click_areas() # get the show from the showlist index = self.showlist.index_of_show(selected_track['sub-show']) if index >=0: self.showlist.select(index) selected_show=self.showlist.selected_show() else: self.mon.err(self,"Show not found in showlist: "+ selected_track['sub-show']) self.end("Unknown show") if selected_show['type']=="mediashow": self.shower= MediaShow(selected_show, self.root, self.canvas, self.showlist, self.pp_dir, self.pp_home, self.pp_profile) self.shower.play(self.show_id,self.end_shower,self.ready_callback,top=False,command='nil') elif selected_show['type']=="liveshow": self.shower= LiveShow(selected_show, self.root, self.canvas, self.showlist, self.pp_dir, self.pp_home, self.pp_profile) self.shower.play(self.show_id,self.end_shower,self.ready_callback,top=False,command='nil') elif selected_show['type']=="radiobuttonshow": self.shower= RadioButtonShow(selected_show, self.root, self.canvas, self.showlist, self.pp_dir, self.pp_home, self.pp_profile) self.shower.play(self.show_id,self.end_shower,self.ready_callback,top=False,command='nil') elif selected_show['type']=="hyperlinkshow": self.shower= HyperlinkShow(selected_show, self.root, self.canvas, self.showlist, self.pp_dir, self.pp_home, self.pp_profile) self.shower.play(self.show_id,self.end_shower,self.ready_callback,top=False,command='nil') elif selected_show['type']=="menu": self.shower= MenuShow(selected_show, self.root, self.canvas, self.showlist, self.pp_dir, self.pp_home, self.pp_profile) self.shower.play(self.show_id,self.end_shower,self.ready_callback,top=False,command='nil') else: self.mon.err(self,"Unknown Show Type: "+ selected_show['type']) self.end("Unknown show type") else: self.mon.err(self,"Unknown Track Type: "+ track_type) self.end("Unknown track type")
def play_selected_track(self, selected_track): """ selects the appropriate player from type field of the medialist and computes the parameters for that type selected track is a dictionary for the track/show """ if self.timeout_running <> None: self.canvas.after_cancel(self.timeout_running) self.timeout_running = None # self.canvas.delete(ALL) self.display_eggtimer(self.resource('hyperlinkshow', 'm01')) self.current_track_type = selected_track['type'] #read the show links. Track links will be added by ready_callback links_text = self.show_params['links'] reason, message, self.links = self.path.parse_links(links_text) if reason == 'error': self.mon.err(self, message + " in show") self.end('error', message) #start timeout for the track if required if self.current_track_ref <> self.first_track_ref and int( self.show_params['timeout']) <> 0: self.timeout_running = self.canvas.after( int(self.show_params['timeout']) * 1000, self.timeout_callback) # dispatch track by type self.player = None self.shower = None track_type = selected_track['type'] self.mon.log(self, "Track type is: " + track_type) if track_type == "video": # create a videoplayer track_file = self.complete_path(selected_track) self.player = VideoPlayer(self.show_id, self.root, self.canvas, self.show_params, selected_track, self.pp_dir, self.pp_home, self.pp_profile) self.player.play(track_file, self.showlist, self.end_player, self.page_callback, enable_menu=False) elif track_type == "audio": # create a audioplayer track_file = self.complete_path(selected_track) self.player = AudioPlayer(self.show_id, self.root, self.canvas, self.show_params, selected_track, self.pp_dir, self.pp_home, self.pp_profile) self.player.play(track_file, self.showlist, self.end_player, self.page_callback, enable_menu=False) elif track_type == "image": track_file = self.complete_path(selected_track) self.player = ImagePlayer(self.show_id, self.root, self.canvas, self.show_params, selected_track, self.pp_dir, self.pp_home, self.pp_profile) self.player.play( track_file, self.showlist, self.end_player, self.page_callback, enable_menu=False, ) elif track_type == "web": # create a browser track_file = self.complete_path(selected_track) self.player = BrowserPlayer(self.show_id, self.root, self.canvas, self.show_params, selected_track, self.pp_dir, self.pp_home, self.pp_profile) self.player.play(track_file, self.showlist, self.end_player, self.page_callback, enable_menu=False) elif track_type == "message": # bit odd because MessagePlayer is used internally to display text. text = selected_track['text'] self.player = MessagePlayer(self.show_id, self.root, self.canvas, self.show_params, selected_track, self.pp_dir, self.pp_home, self.pp_profile) self.player.play(text, self.showlist, self.end_player, self.page_callback, enable_menu=False) elif track_type == "show": self.enable_click_areas() # get the show from the showlist index = self.showlist.index_of_show(selected_track['sub-show']) if index >= 0: self.showlist.select(index) selected_show = self.showlist.selected_show() else: self.mon.err( self, "Show not found in showlist: " + selected_track['sub-show']) self.end("Unknown show") if selected_show['type'] == "mediashow": self.shower = MediaShow(selected_show, self.root, self.canvas, self.showlist, self.pp_dir, self.pp_home, self.pp_profile) self.shower.play(self.show_id, self.end_shower, self.ready_callback, top=False, command='nil') elif selected_show['type'] == "liveshow": self.shower = LiveShow(selected_show, self.root, self.canvas, self.showlist, self.pp_dir, self.pp_home, self.pp_profile) self.shower.play(self.show_id, self.end_shower, self.ready_callback, top=False, command='nil') elif selected_show['type'] == "radiobuttonshow": self.shower = RadioButtonShow(selected_show, self.root, self.canvas, self.showlist, self.pp_dir, self.pp_home, self.pp_profile) self.shower.play(self.show_id, self.end_shower, self.ready_callback, top=False, command='nil') elif selected_show['type'] == "hyperlinkshow": self.shower = HyperlinkShow(selected_show, self.root, self.canvas, self.showlist, self, pp_dir, self.pp_home, self.pp_profile) self.shower.play(self.show_id, self.end_shower, self.ready_callback, top=False, command='nil') elif selected_show['type'] == "menu": self.shower = MenuShow(selected_show, self.root, self.canvas, self.showlist, self.pp_dir, self.pp_home, self.pp_profile) self.shower.play(self.show_id, self.end_shower, self.ready_callback, top=False, command='nil') else: self.mon.err(self, "Unknown Show Type: " + selected_show['type']) self.end("Unknown show type") else: self.mon.err(self, "Unknown Track Type: " + track_type) self.end("Unknown track type")
class HyperlinkShow: """ Aimed at touchscreens but can be used for any purpose where the user is required to follow hyperlinks between tracks Profiles for media tracks (message, image, video, audio ) specify links to other tracks in a link a symbolic name of an input is associated with a track-reference The show begins at first-track and then uses events (GPIO, keypresses etc.) to link to other tracks via their symbolic names If using 'call' keeps a record of the tracks it has visited so the 'return' command can go back. Executes timeout-track if no user input is received. links are of the form: symbolic-name command [track-ref] link commands: call <track-ref> play track-ref and add it to the path return - return 1 back up the path removing the track from the path, stops at home-track. return n - return n tracks back up the path removing the track from the path, stops at home-track. return <track-ref> return to <track-ref> removing tracks from the path home - return to home-track removing tracks from the path jump <track-ref-> - play trck-ref forgetting the path back to home-track goto <track-ref> - play track-ref, forget the path exit - end the hyperlink show null - inhibits the link defined in the show with the same symbolic name. reserved symbolic names pp-onend command - pseudo symbolic name for end of a track interface: * play - selects the first track to play (first-track) * input_pressed, - receives user events passes them to a Shower/Player if a track is playing, otherwise actions them depending on the symbolic name supplied """ # ********************* # external interface # ******************** def __init__(self, show_params, root, canvas, showlist, pp_dir, pp_home, pp_profile): """ canvas - the canvas that the tracks of the event show are to be written on show_params - the name of the configuration dictionary section for the hyperlinkshow showlist - the showlist, to enable runningnof show type tracks. pp_home - Pi presents data_home directory pp_profile - Pi presents profile directory """ self.mon = Monitor() self.mon.on() #instantiate arguments self.show_params = show_params self.root = root self.showlist = showlist self.canvas = canvas self.pp_dir = pp_dir self.pp_home = pp_home self.pp_profile = pp_profile # open resources self.rr = ResourceReader() #create a path stack self.path = PathManager() # init variables self.drawn = None self.player = None self.shower = None self.timeout_running = None self.error = False def play(self, show_id, end_callback, ready_callback, top=False, command='nil'): """ starts the hyperlink show at start-track end_callback - function to be called when the show exits ready_callback - callback when event-show is ready to display its forst track (not used?) top is True when the show is top level (run from [start] or from show control) command is not used """ #instantiate arguments self.show_id = show_id self.end_callback = end_callback self.ready_callback = ready_callback self.top = top self.command = command # check data files are available. self.medialist_file = self.pp_profile + "/" + self.show_params[ 'medialist'] if not os.path.exists(self.medialist_file): self.mon.err(self, "Medialist file not found: " + self.medialist_file) self.end('error', "Medialist file not found") #create a medialist object for the hyperlinkshow and read the file into it. self.medialist = MediaList() if self.medialist.open_list(self.medialist_file, self.showlist.sissue()) == False: self.mon.err(self, "Version of medialist different to Pi Presents") self.end('error', "Version of medialist different to Pi Presents") #get controls for this show if top level controlsmanager = ControlsManager() if self.top == True: self.controls_list = controlsmanager.default_controls() # and merge in controls from profile self.controls_list = controlsmanager.merge_show_controls( self.controls_list, self.show_params['controls']) # read show links and destinations self.first_track_ref = self.show_params['first-track-ref'] self.home_track_ref = self.show_params['home-track-ref'] self.timeout_track_ref = self.show_params['timeout-track-ref'] # state variables and signals self.end_hyperlinkshow_signal = False self.egg_timer = None self.next_track_signal = False self.next_track_ref = '' self.current_track_ref = '' self.current_track_type = '' # ready callback for show if self.ready_callback <> None: self.ready_callback() self.canvas.delete('pp-content') self.canvas.config(bg='black') self.do_first_track() #stop received from another concurrent show via ShowManager def managed_stop(self): # set signal to stop the hyperlinkshow when all sub-shows and players have ended self.end_hyperlinkshow_signal = True # then stop and shows or tracks. if self.shower <> None: self.shower.managed_stop() elif self.player <> None: self.player.input_pressed('stop') else: self.end('normal', 'stopped by ShowManager') # kill or error def terminate(self, reason): self.end_hyperlinkshow_signal = True if self.shower <> None: self.shower.terminate(reason) elif self.player <> None: self.player.terminate(reason) else: self.end(reason, 'terminated without terminating shower or player') # respond to inputs def input_pressed(self, symbol, edge, source): self.mon.log(self, "received symbol: " + symbol) #does the symbol match a link, if so execute it if self.is_link(symbol, edge, source) == True: return # controls are disabled so ignore anything else if self.show_params['disable-controls'] == 'yes': return # does it match a control # if at top convert symbolic name to operation otherwise lower down we have received an operatio # look through list of controls to find match if self.top == True: operation = self.lookup_control(symbol, self.controls_list) else: operation = symbol # print 'operation',operation if operation <> '': self.do_operation(operation, edge, source) def do_operation(self, operation, edge, source): if self.shower <> None: # if next lower show is running pass down to stop the show and lower level self.shower.input_pressed(operation, edge, source) else: # control this show and its tracks if operation == 'stop': if self.player <> None: if self.current_track_ref == self.first_track_ref and self.top == False: self.end_radiobuttonshow_signal = True self.player.input_pressed('stop') elif operation == 'pause': if self.player <> None: self.player.input_pressed(operation) elif operation[0:4] == 'omx-' or operation[ 0:6] == 'mplay-' or operation[0:5] == 'uzbl-': if self.player <> None: self.player.input_pressed(operation) def is_link(self, symbol, edge, source): # find the first entry in links that matches the symbol and execute its operation # print 'hyperlinkshow ',symbol found = False for link in self.links: #print link if symbol == link[0]: found = True if link[1] <> 'null': # print 'match',link[0] link_operation = link[1] if link_operation == 'home': self.do_home(edge, source) elif link_operation == 'return': self.do_return(link[2], edge, source) elif link_operation == 'call': self.do_call(link[2], edge, source) elif link_operation == 'goto': self.do_goto(link[2], edge, source) elif link_operation == 'jump': self.do_jump(link[2], edge, source) elif link_operation == 'exit': self.end('normal', 'executed exit command') return found def lookup_control(self, symbol, controls_list): for control in controls_list: if symbol == control[0]: return control[1] return '' # ********************* # INTERNAL FUNCTIONS # ******************** # ********************* # Show Sequencer # ********************* def timeout_callback(self): self.do_call(self.timeout_track_ref, 'front', 'timeout') def do_call(self, track_ref, edge, source): if track_ref <> self.current_track_ref: self.mon.log(self, 'call: ' + track_ref) self.next_track_signal = True self.next_track_op = 'call' self.next_track_arg = track_ref if self.shower <> None: self.shower.input_pressed('stop', edge, source) elif self.player <> None: self.player.input_pressed('stop') else: self.what_next() def do_goto(self, to, edge, source): if to <> self.current_track_ref: self.mon.log(self, 'goto: ' + to) self.next_track_signal = True self.next_track_op = 'goto' self.next_track_arg = to if self.shower <> None: self.shower.input_pressed('stop', edge, source) elif self.player <> None: self.player.input_pressed('stop') else: self.what_next() def do_jump(self, to, edge, source): if to <> self.current_track_ref: self.mon.log(self, 'jump to: ' + to) self.next_track_signal = True self.next_track_op = 'jump' self.next_track_arg = to if self.shower <> None: self.shower.input_pressed('stop', edge, source) elif self.player <> None: self.player.input_pressed('stop') else: self.what_next() def do_return(self, to, edge, source): self.next_track_signal = True if to.isdigit() or to == '': self.mon.log(self, 'hyperlink command - return by: ' + to) self.next_track_op = 'return-by' if to == '': self.next_track_arg = '1' else: self.next_track_arg = to else: self.mon.log(self, 'hyperlink command - return to: ' + to) self.next_track_op = 'return-to' self.next_track_arg = to if self.shower <> None: self.shower.input_pressed('stop', edge, source) elif self.player <> None: self.player.input_pressed('stop') else: self.what_next() def do_home(self, edge, source): if self.current_track_ref <> self.home_track_ref: self.mon.log(self, 'hyperlink command - home') self.next_track_signal = True self.next_track_op = 'home' if self.shower <> None: self.shower.input_pressed('stop', edge, source) elif self.player <> None: self.player.input_pressed('stop') else: self.what_next() def do_first_track(self): index = self.medialist.index_of_track(self.first_track_ref) if index >= 0: #don't use select the track as not using selected_track in hyperlinkshow first_track = self.medialist.track(index) self.current_track_ref = first_track['track-ref'] self.path.append(first_track['track-ref']) self.play_selected_track(first_track) else: self.mon.err( self, "first-track not found in medialist: " + self.show_params['first-track-ref']) self.end('error', "first track not found in medialist") def what_next(self): # user wants to end the show if self.end_hyperlinkshow_signal == True: self.end_hyperlinkshow_signal = False self.end('normal', "show ended by user") # user has selected another track elif self.next_track_signal == True: self.next_track_signal = False # home if self.next_track_op in ('home'): # back to 1 before home back_ref = self.path.back_to(self.home_track_ref) if back_ref == '': self.mon.err( self, "home - home track not in path: " + self.home_track_ref) self.end('error', "home - home track not in path") # play home self.next_track_ref = self.home_track_ref self.path.append(self.next_track_ref) # return-by elif self.next_track_op in ('return-by'): if self.current_track_ref <> self.home_track_ref: # back n stopping at home # back one more and return it back_ref = self.path.back_by(self.home_track_ref, self.next_track_arg) # use returned track self.next_track_ref = back_ref self.path.append(self.next_track_ref) # return-to elif self.next_track_op in ('return-to'): #back to one before return-to track back_ref = self.path.back_to(self.next_track_arg) if back_ref == '': self.mon.err( self, "return-to - track not in path: " + self.next_track_arg) self.end('error', "return-to - track not in path") # and append the return to track self.next_track_ref = self.next_track_arg self.path.append(self.next_track_ref) # call elif self.next_track_op in ('call'): # append the required track self.path.append(self.next_track_arg) self.next_track_ref = self.next_track_arg # goto elif self.next_track_op in ('goto'): self.path.pop_for_sibling() ## #back to first track and remove it ## back_ref=self.path.back_to(self.first_track_ref) ## if back_ref=='': ## self.mon.err(self,"goto - first track not in path: "+self.first_track_ref) ## self.end('error',"goto - first track not in path") #add the goto track self.next_track_ref = self.next_track_arg self.path.append(self.next_track_arg) # jump elif self.next_track_op in ('jump'): # back to home and remove it back_ref = self.path.back_to(self.home_track_ref) if back_ref == '': self.mon.err( self, "jump - home track not in path: " + self.home_track_ref) self.end('error', "jump - track not in path") # add back the home track without playing it self.path.append(self.home_track_ref) # append the jumped to track self.next_track_ref = self.next_track_arg self.path.append(self.next_track_ref) else: self.mon.err( self, "unaddressed what next: " + self.next_track_op + ' ' + self.next_track_arg) self.end('error', "unaddressed what next") self.current_track_ref = self.next_track_ref index = self.medialist.index_of_track(self.next_track_ref) if index >= 0: #don't use select the track as not using selected_track in hyperlinkshow next_track = self.medialist.track(index) self.play_selected_track(next_track) else: self.mon.err( self, "next-track not found in medialist: " + self.next_track_ref) self.end('error', "next track not found in medialist") else: #track ends naturally #then input pp-onend symbolic name self.input_pressed('pp-onend', 'front', 'key') # ********************* # Dispatching to Players # ********************* def page_callback(self): # called from a Player when ready to play, merge the links from the track with those from the show # and then enable the click areas self.delete_eggtimer() links_text = self.player.get_links() reason, message, track_links = self.path.parse_links(links_text) if reason == 'error': self.mon.err(self, message + " in page") self.end('error', message) self.path.merge_links(self.links, track_links) # enable the click-area that are in the list of links self.enable_click_areas() def enable_click_areas(self): for link in self.links: #print 'trying link ',link[0] if not ('key-' in link[0]) and link[1] <> 'null' and link[0] <> 'pp-auto': # print 'enabling link ',link[0] self.canvas.itemconfig(link[0], state='normal') def play_selected_track(self, selected_track): """ selects the appropriate player from type field of the medialist and computes the parameters for that type selected track is a dictionary for the track/show """ if self.timeout_running <> None: self.canvas.after_cancel(self.timeout_running) self.timeout_running = None # self.canvas.delete(ALL) self.display_eggtimer(self.resource('hyperlinkshow', 'm01')) self.current_track_type = selected_track['type'] #read the show links. Track links will be added by ready_callback links_text = self.show_params['links'] reason, message, self.links = self.path.parse_links(links_text) if reason == 'error': self.mon.err(self, message + " in show") self.end('error', message) #start timeout for the track if required if self.current_track_ref <> self.first_track_ref and int( self.show_params['timeout']) <> 0: self.timeout_running = self.canvas.after( int(self.show_params['timeout']) * 1000, self.timeout_callback) # dispatch track by type self.player = None self.shower = None track_type = selected_track['type'] self.mon.log(self, "Track type is: " + track_type) if track_type == "video": # create a videoplayer track_file = self.complete_path(selected_track) self.player = VideoPlayer(self.show_id, self.root, self.canvas, self.show_params, selected_track, self.pp_dir, self.pp_home, self.pp_profile) self.player.play(track_file, self.showlist, self.end_player, self.page_callback, enable_menu=False) elif track_type == "audio": # create a audioplayer track_file = self.complete_path(selected_track) self.player = AudioPlayer(self.show_id, self.root, self.canvas, self.show_params, selected_track, self.pp_dir, self.pp_home, self.pp_profile) self.player.play(track_file, self.showlist, self.end_player, self.page_callback, enable_menu=False) elif track_type == "image": track_file = self.complete_path(selected_track) self.player = ImagePlayer(self.show_id, self.root, self.canvas, self.show_params, selected_track, self.pp_dir, self.pp_home, self.pp_profile) self.player.play( track_file, self.showlist, self.end_player, self.page_callback, enable_menu=False, ) elif track_type == "web": # create a browser track_file = self.complete_path(selected_track) self.player = BrowserPlayer(self.show_id, self.root, self.canvas, self.show_params, selected_track, self.pp_dir, self.pp_home, self.pp_profile) self.player.play(track_file, self.showlist, self.end_player, self.page_callback, enable_menu=False) elif track_type == "message": # bit odd because MessagePlayer is used internally to display text. text = selected_track['text'] self.player = MessagePlayer(self.show_id, self.root, self.canvas, self.show_params, selected_track, self.pp_dir, self.pp_home, self.pp_profile) self.player.play(text, self.showlist, self.end_player, self.page_callback, enable_menu=False) elif track_type == "show": self.enable_click_areas() # get the show from the showlist index = self.showlist.index_of_show(selected_track['sub-show']) if index >= 0: self.showlist.select(index) selected_show = self.showlist.selected_show() else: self.mon.err( self, "Show not found in showlist: " + selected_track['sub-show']) self.end("Unknown show") if selected_show['type'] == "mediashow": self.shower = MediaShow(selected_show, self.root, self.canvas, self.showlist, self.pp_dir, self.pp_home, self.pp_profile) self.shower.play(self.show_id, self.end_shower, self.ready_callback, top=False, command='nil') elif selected_show['type'] == "liveshow": self.shower = LiveShow(selected_show, self.root, self.canvas, self.showlist, self.pp_dir, self.pp_home, self.pp_profile) self.shower.play(self.show_id, self.end_shower, self.ready_callback, top=False, command='nil') elif selected_show['type'] == "radiobuttonshow": self.shower = RadioButtonShow(selected_show, self.root, self.canvas, self.showlist, self.pp_dir, self.pp_home, self.pp_profile) self.shower.play(self.show_id, self.end_shower, self.ready_callback, top=False, command='nil') elif selected_show['type'] == "hyperlinkshow": self.shower = HyperlinkShow(selected_show, self.root, self.canvas, self.showlist, self, pp_dir, self.pp_home, self.pp_profile) self.shower.play(self.show_id, self.end_shower, self.ready_callback, top=False, command='nil') elif selected_show['type'] == "menu": self.shower = MenuShow(selected_show, self.root, self.canvas, self.showlist, self.pp_dir, self.pp_home, self.pp_profile) self.shower.play(self.show_id, self.end_shower, self.ready_callback, top=False, command='nil') else: self.mon.err(self, "Unknown Show Type: " + selected_show['type']) self.end("Unknown show type") else: self.mon.err(self, "Unknown Track Type: " + track_type) self.end("Unknown track type") # callback from when player ends def end_player(self, reason, message): self.mon.log(self, "Returned from player with message: " + message) self.player = None # this does not seem to change the colour of the polygon self.canvas.itemconfig('pp-click-area', state='hidden') self.canvas.update_idletasks() if reason in ("killed", "error"): self.end(reason, message) else: self.display_eggtimer(self.resource('hyperlinkshow', 'm02')) self.what_next() # callback from when shower ends def end_shower(self, show_id, reason, message): self.mon.log(self, "Returned from shower with message: " + message) self.shower = None self.canvas.itemconfig('pp-click-area', state='hidden') self.canvas.update_idletasks() if reason in ("killed", "error"): self.end(reason, message) else: self.display_eggtimer(self.resource('hyperlinkshow', 'm03')) self.what_next() # ********************* # End the show # ********************* # finish the player for killing, error or normally # this may be called directly sub/child shows or players are not running # if they might be running then need to call terminate. def end(self, reason, message): self.mon.log(self, "Ending hyperlinkshow: " + self.show_params['show-ref']) self.end_callback(self.show_id, reason, message) self = None return # ********************* # displaying things # ********************* def display_eggtimer(self, text): #self.egg_timer=self.canvas.create_text(int(self.canvas['width'])/2, #int(self.canvas['height'])/2, #text= text, # fill='white', # font="Helvetica 20 bold") #self.canvas.update_idletasks( ) pass def delete_eggtimer(self): if self.egg_timer != None: self.canvas.delete(self.egg_timer) # ********************* # utilities # ********************* def complete_path(self, selected_track): # complete path of the filename of the selected entry track_file = selected_track['location'] if track_file <> '' and track_file[0] == "+": track_file = self.pp_home + track_file[1:] self.mon.log(self, "Track to play is: " + track_file) return track_file def resource(self, section, item): value = self.rr.get(section, item) if value == False: self.mon.err(self, "resource: " + section + ': ' + item + " not found") # players or showers may be running so need terminate self.terminate("error") else: return value
class RadioButtonShow: """ starts at 'first-track' which can be any type of track or a show The show has links of the form symbolic-name play track-ref key, gpio or click area will play the referenced track at the end of that track control will return to first-track links in the tracks are ignored. Links are inherited from the show. timeout returns to first-track interface: * play - selects the first track to play (first-track) * input_pressed, - receives user events passes them to a Shower/Player if a track is playing, otherwise actions them depending on the symbolic name supplied """ # ********************* # external interface # ******************** def __init__(self, show_params, root, canvas, showlist, pp_dir, pp_home, pp_profile): """ canvas - the canvas that the tracks of the event show are to be written on show_params - the name of the configuration dictionary section for the radiobuttonshow showlist - the showlist, to enable runningnof show type tracks. pp_home - Pi presents data_home directory pp_profile - Pi presents profile directory """ self.mon = Monitor() self.mon.on() #instantiate arguments self.show_params = show_params self.showlist = showlist self.root = root self.canvas = canvas self.pp_dir = pp_dir self.pp_home = pp_home self.pp_profile = pp_profile # open resources self.rr = ResourceReader() #create a path stack - only used to parse the links. self.path = PathManager() # init variables self.drawn = None self.player = None self.shower = None self.timeout_running = None self.error = False def play(self, show_id, end_callback, ready_callback, top=False, command='nil'): """ starts the hyperlink show at start-track end_callback - function to be called when the show exits ready_callback - callback when event-show is ready to display its forst track (not used?) top is True when the show is top level (run from [start] or from show control) command is not used """ #instantiate arguments self.show_id = show_id self.end_callback = end_callback self.ready_callback = ready_callback self.top = top self.command = command # check data files are available. self.medialist_file = self.pp_profile + "/" + self.show_params[ 'medialist'] if not os.path.exists(self.medialist_file): self.mon.err(self, "Medialist file not found: " + self.medialist_file) self.end('error', "Medialist file not found") #create a medialist object for the radiobuttonshow and read the file into it. self.medialist = MediaList() if self.medialist.open_list(self.medialist_file, self.showlist.sissue()) == False: self.mon.err(self, "Version of medialist different to Pi Presents") self.end('error', "Version of medialist different to Pi Presents") # read show destinations self.first_track_ref = self.show_params['first-track-ref'] #get control bindings for this show if top level controlsmanager = ControlsManager() if self.top == True: self.controls_list = controlsmanager.default_controls() # and merge in controls from profile self.controls_list = controlsmanager.merge_show_controls( self.controls_list, self.show_params['controls']) #read the show links. Track links will be added by ready_callback links_text = self.show_params['links'] reason, message, self.links = self.path.parse_links(links_text) if reason == 'error': self.mon.err(self, message + " in show") self.end('error', message) # state variables and signals self.end_radiobuttonshow_signal = False self.egg_timer = None self.next_track_signal = False self.next_track_ref = '' self.current_track_ref = '' self.current_track_type = '' # ready callback for show if self.ready_callback <> None: self.ready_callback() self.canvas.delete('pp-content') self.canvas.config(bg='black') self.do_first_track() #stop received from another concurrent show via ShowManager def managed_stop(self): # set signal to stop the radiobuttonshow when all sub-shows and players have ended self.end_radiobuttonshow_signal = True # then stop and shows or tracks. if self.shower <> None: self.shower.managed_stop() elif self.player <> None: self.player.input_pressed('stop') else: self.end('normal', 'stopped by ShowManager') # kill or error def terminate(self, reason): self.end_radiobuttonshow_signal = True if self.shower <> None: self.shower.terminate(reason) elif self.player <> None: self.player.terminate(reason) else: self.end(reason, 'terminated without terminating shower or player') # respond to inputs def input_pressed(self, symbol, edge, source): self.mon.log(self, "received symbol: " + symbol) #does the symbol match a link, if so execute it if self.is_link(symbol, edge, source) == True: return # controls are disabled so ignore inputs if self.show_params['disable-controls'] == 'yes': return # does it match a control # if at top convert symbolic name to operation otherwise lower down we have received an operatio # look through list of controls to find match if self.top == True: operation = self.lookup_control(symbol, self.controls_list) else: operation = symbol # print 'operation',operation if operation <> '': self.do_operation(operation, edge, source) def do_operation(self, operation, edge, source): if self.shower <> None: # if next lower show is running pass down to stop the show and lower level self.shower.input_pressed(operation, edge, source) else: #control this show and its tracks if operation == 'stop': if self.player <> None: if self.current_track_ref == self.first_track_ref and self.top == False: self.end_radiobuttonshow_signal = True self.player.input_pressed('stop') elif operation == 'pause': if self.player <> None: self.player.input_pressed(operation) elif operation[0:4] == 'omx-' or operation[ 0:6] == 'mplay-' or operation[0:5] == 'uzbl-': if self.player <> None: self.player.input_pressed(operation) def lookup_control(self, symbol, controls_list): for control in controls_list: if symbol == control[0]: return control[1] return '' def is_link(self, symbol, edge, source): # we have links which locally define symbolic names to be converted to radiobuttonshow operations # find the first entry in links that matches the symbol and execute its operation #print 'radiobuttonshow ',symbol found = False for link in self.links: #print link if symbol == link[0]: found = True if link[1] <> 'null': #print 'match',link[0] link_operation = link[1] if link_operation == 'play': self.do_play(link[2], edge, source) return found # ********************* # INTERNAL FUNCTIONS # ******************** # ********************* # Show Sequencer # ********************* def timeout_callback(self): self.do_play(self.first_track_ref, 'front', 'timeout') def do_play(self, track_ref, edge, source): if track_ref <> self.current_track_ref: # print 'executing play ',track_ref self.next_track_signal = True self.next_track_op = 'play' self.next_track_arg = track_ref if self.shower <> None: self.shower.input_pressed('stop', edge, source) elif self.player <> None: self.player.input_pressed('stop') else: self.what_next() def do_first_track(self): index = self.medialist.index_of_track(self.first_track_ref) if index >= 0: #don't use select the track as not using selected_track in radiobuttonshow first_track = self.medialist.track(index) self.path.append(first_track['track-ref']) self.current_track_ref = self.first_track_ref self.play_selected_track(first_track) else: self.mon.err( self, "first-track not found in medialist: " + self.show_params['first-frack-ref']) self.end('error', "first track not found in medialist") def what_next(self): # user wants to end the show if self.end_radiobuttonshow_signal == True: self.end_radiobuttonshow_signal = False self.end('normal', "show ended by user") # user has selected another track elif self.next_track_signal == True: self.next_track_signal = False self.next_track_ref = self.next_track_arg self.current_track_ref = self.next_track_ref index = self.medialist.index_of_track(self.next_track_ref) if index >= 0: #don't use select the track as not using selected_track in radiobuttonshow next_track = self.medialist.track(index) self.play_selected_track(next_track) else: self.mon.err( self, "next-track not found in medialist: " + self.next_track_ref) self.end('error', "next track not found in medialist") else: #track ends naturally self.next_track_ref = self.first_track_ref self.current_track_ref = self.next_track_ref index = self.medialist.index_of_track(self.next_track_ref) if index >= 0: #don't use select the track as not using selected_track in radiobuttonshow next_track = self.medialist.track(index) self.play_selected_track(next_track) else: self.mon.err( self, "next-track not found in medialist: " + self.next_track_ref) self.end('error', "next track not found in medialist") # ********************* # Dispatching to Players # ********************* def page_callback(self): # called from a Player when ready to play, if first-track merge the links from the track with those from the show self.delete_eggtimer() if self.current_track_ref == self.first_track_ref: #links_text=self.player.get_links() #reason,message,track_links=self.path.parse_links(links_text) #if reason=='error': #self.mon.err(self,message + " in page") #self.end('error',message) #self.path.merge_links(self.links,track_links) pass def play_selected_track(self, selected_track): """ selects the appropriate player from type field of the medialist and computes the parameters for that type selected track is a dictionary for the track/show """ if self.timeout_running <> None: self.canvas.after_cancel(self.timeout_running) self.timeout_running = None # self.display_eggtimer(self.resource('radiobuttonshow','m01')) self.current_track_type = selected_track['type'] #start timeout for the track if required if self.current_track_ref <> self.first_track_ref and int( self.show_params['timeout']) <> 0: self.timeout_running = self.canvas.after( int(self.show_params['timeout']) * 1000, self.timeout_callback) # dispatch track by type self.player = None self.shower = None track_type = selected_track['type'] self.mon.log(self, "Track type is: " + track_type) if track_type == "video": # create a videoplayer track_file = self.complete_path(selected_track) self.player = VideoPlayer(self.show_id, self.root, self.canvas, self.show_params, selected_track, self.pp_dir, self.pp_home, self.pp_profile) self.player.play(track_file, self.showlist, self.end_player, self.page_callback, enable_menu=False) elif track_type == "audio": # create a audioplayer track_file = self.complete_path(selected_track) self.player = AudioPlayer(self.show_id, self.root, self.canvas, self.show_params, selected_track, self.pp_dir, self.pp_home, self.pp_profile) self.player.play(track_file, self.showlist, self.end_player, self.page_callback, enable_menu=False) elif track_type == "image": track_file = self.complete_path(selected_track) self.player = ImagePlayer(self.show_id, self.root, self.canvas, self.show_params, selected_track, self.pp_dir, self.pp_home, self.pp_profile) self.player.play( track_file, self.showlist, self.end_player, self.page_callback, enable_menu=False, ) elif track_type == "web": # create a browser track_file = self.complete_path(selected_track) self.player = BrowserPlayer(self.show_id, self.root, self.canvas, self.show_params, selected_track, self.pp_dir, self.pp_home, self.pp_profile) self.player.play(track_file, self.showlist, self.end_player, self.page_callback, enable_menu=False) elif track_type == "message": # bit odd because MessagePlayer is used internally to display text. text = selected_track['text'] self.player = MessagePlayer(self.show_id, self.root, self.canvas, self.show_params, selected_track, self.pp_dir, self.pp_home, self.pp_profile) self.player.play(text, self.showlist, self.end_player, self.page_callback, enable_menu=False) elif track_type == "show": # self.enable_click_areas() # get the show from the showlist index = self.showlist.index_of_show(selected_track['sub-show']) if index >= 0: self.showlist.select(index) selected_show = self.showlist.selected_show() else: self.mon.err( self, "Show not found in showlist: " + selected_track['sub-show']) self.end("Unknown show") if selected_show['type'] == "mediashow": self.shower = MediaShow(selected_show, self.root, self.canvas, self.showlist, self.pp_dir, self.pp_home, self.pp_profile) self.shower.play(self.show_id, self.end_shower, self.ready_callback, top=False, command='nil') elif selected_show['type'] == "liveshow": self.shower = LiveShow(selected_show, self.root, self.canvas, self.showlist, self.pp_dir, self.pp_home, self.pp_profile) self.shower.play(self.show_id, self.end_shower, self.ready_callback, top=False, command='nil') elif selected_show['type'] == "radiobuttonshow": self.shower = RadioButtonShow(selected_show, self.root, self.canvas, self.showlist, self.pp_dir, self.pp_home, self.pp_profile) self.shower.play(self.show_id, self.end_shower, self.ready_callback, top=False, command='nil') elif selected_show['type'] == "hyperlinkshow": self.shower = HyperlinkShow(selected_show, self.root, self.canvas, self.showlist, self.pp_dir, self.pp_home, self.pp_profile) self.shower.play(self.show_id, self.end_shower, self.ready_callback, top=False, command='nil') elif selected_show['type'] == "menu": self.shower = MenuShow(selected_show, self.root, self.canvas, self.showlist, self.pp_dir, self.pp_home, self.pp_profile) self.shower.play(self.show_id, self.end_shower, self.ready_callback, top=False, command='nil') else: self.mon.err(self, "Unknown Show Type: " + selected_show['type']) self.end("Unknown show type") else: self.mon.err(self, "Unknown Track Type: " + track_type) self.end("Unknown track type") # callback from when player ends def end_player(self, reason, message): self.mon.log(self, "Returned from player with message: " + message) self.player = None # this does not seem to change the colour of the polygon # self.canvas.itemconfig('pp-click-area',state='hidden') self.canvas.update_idletasks() if reason in ("killed", "error"): self.end(reason, message) else: #self.display_eggtimer(self.resource('radiobuttonshow','m02')) self.what_next() # callback from when shower ends def end_shower(self, show_id, reason, message): self.mon.log(self, "Returned from shower with message: " + message) self.shower = None # self.canvas.itemconfig('pp-click-area',state='hidden') self.canvas.update_idletasks() if reason in ("killed", "error"): self.end(reason, message) else: #self.display_eggtimer(self.resource('radiobuttonshow','m03')) self.what_next() # ********************* # End the show # ********************* # finish the player for killing, error or normally # this may be called directly sub/child shows or players are not running # if they might be running then need to call terminate. def end(self, reason, message): self.mon.log(self, "Ending radiobuttonshow: " + self.show_params['show-ref']) self.end_callback(self.show_id, reason, message) self = None return # ********************* # displaying things # ********************* def display_eggtimer(self, text): #self.egg_timer=self.canvas.create_text(int(self.canvas['width'])/2, #int(self.canvas['height'])/2, #text= text, # fill='white', # font="Helvetica 20 bold") #self.canvas.update_idletasks( ) pass def delete_eggtimer(self): if self.egg_timer != None: self.canvas.delete(self.egg_timer) # ********************* # utilities # ********************* def complete_path(self, selected_track): # complete path of the filename of the selected entry track_file = selected_track['location'] if track_file <> '' and track_file[0] == "+": track_file = self.pp_home + track_file[1:] self.mon.log(self, "Track to play is: " + track_file) return track_file def resource(self, section, item): value = self.rr.get(section, item) if value == False: self.mon.err(self, "resource: " + section + ': ' + item + " not found") # players or showers may be running so need terminate self.terminate("error") else: return value
class MediaShow: # ******************* # External interface # ******************** def __init__(self, show, canvas, showlist, pp_home, pp_profile): """ canvas - the canvas that the menu is to be written on show - the dictionary fo the show to be played pp_home - Pi presents data_home directory pp_profile - Pi presents profile directory """ self.mon=Monitor() self.mon.on() #instantiate arguments self.show =show self.showlist=showlist self.canvas=canvas self.pp_home=pp_home self.pp_profile=pp_profile # open resources self.rr=ResourceReader() # Init variables self.player=None self.shower=None self._poll_for_interval_timer=None self._poll_for_continue_timer=None self._waiting_for_interval=False self._interval_timer=None self.error=False self._interval_timer_signal=False self._end_mediashow_signal=False self._next_track_signal=False self._previous_track_signal=False self._play_child_signal = False self._req_next='nil' self._state='closed' def play(self,end_callback,ready_callback=None, top=False,command='nil'): """ displays the mediashow end_callback - function to be called when the menu exits ready_callback - callback when menu is ready to display (not used) top is True when the show is top level (run from [start]) """ #instantiate the arguments self._end_callback=end_callback self._ready_callback=ready_callback self.top=top self.command=command self.mon.log(self,"Starting show: " + self.show['show-ref']) # check data files are available. self.media_file = self.pp_profile + "/" + self.show['medialist'] if not os.path.exists(self.media_file): self.mon.err(self,"Medialist file not found: "+ self.media_file) self._end('error',"Medialist file not found") #create a medialist for the mediashow and read it. self.medialist=MediaList() if self.medialist.open_list(self.media_file,self.showlist.sissue())==False: self.mon.err(self,"Version of medialist different to Pi Presents") self._end('error',"Version of medialist different to Pi Presents") self._wait_for_trigger() # respond to key presses. def key_pressed(self,key_name): self.mon.log(self,"received key: " + key_name) if key_name=='': pass elif key_name=='escape': # if next lower show is running pass down to stop the show and lower level if self.shower<>None: self.shower.key_pressed(key_name) # if not at top stop the show else: if self.top == False: self._end_mediashow_signal=True # and if a track is running stop that first if self.player<>None: self.player.key_pressed(key_name) else: # at top level in a manual presentation stop the track if self.show['progress']=='manual': if self.player<>None: self.player.key_pressed(key_name) elif key_name in ('up','down'): # if child or sub-show is running and is a show pass to show, track does not use up/down # otherwise use keys for next or previous if self.shower<>None: self.shower.key_pressed(key_name) else: if key_name=='up': self._previous() else: self._next() elif key_name=='return': # if child show or sub-show is running and is show - pass down- player does not use return # ELSE use Return to start child or to start the show if waiting if self.shower<>None: self.shower.key_pressed(key_name) else: if self._state=='playing': if self.show['has-child']=='yes': self._play_child_signal=True # and stop the current track if its running if self.player<>None: self.player.key_pressed("escape") else: self._start_show() elif key_name=='pir': self._start_show() elif key_name in ('p',' '): # pass down if show or track running. if self.shower<>None: self.shower.key_pressed(key_name) elif self.player<>None: self.player.key_pressed(key_name) def button_pressed(self,button,edge): if button=='play': self.key_pressed("return") elif button =='up': self.key_pressed("up") elif button=='down': self.key_pressed("down") elif button=='stop': self.key_pressed("escape") elif button=='pause': self.key_pressed('p') elif button=='PIR': self.key_pressed('pir') # kill or error def terminate(self,reason): if self.shower<>None: self.mon.log(self,"sent terminate to shower") self.shower.terminate(reason) elif self.player<>None: self.mon.log(self,"sent terminate to player") self.player.terminate(reason) else: self._end(reason,'terminated without terminating shower or player') def _tidy_up(self): if self._poll_for_continue_timer<>None: self.canvas.after_cancel(self._poll_for_continue_timer) self._poll_for_continue_timer=None if self._poll_for_interval_timer<>None: self.canvas.after_cancel(self._poll_for_interval_timer) self._poll_for_interval_timer=None if self._interval_timer<>None: self.canvas.after_cancel(self._interval_timer) self._interval_timer=None def resource(self,section,item): value=self.rr.get(section,item) if value==False: self.mon.err(self, "resource: "+section +': '+ item + " not found" ) self.terminate("error") else: return value # *************************** # Respond to key/button presses # *************************** def _stop(self,message): self._end_mediashow_signal=True if self._interval_timer<>None: self.canvas.after_cancel(self._interval_timer) def _next(self): # stop track if running and set signal self._next_track_signal=True if self.shower<>None: self.shower.key_pressed("escape") else: if self.player<>None: self.player.key_pressed("escape") def _previous(self): self._previous_track_signal=True if self.shower<>None: self.shower.key_pressed("escape") else: if self.player<>None: self.player.key_pressed("escape") # *************************** # end of show functions # *************************** def _end(self,reason,message): self._end_mediashow_signal=False self.mon.log(self,"Ending Mediashow: "+ self.show['show-ref']) self._tidy_up() self._end_callback(reason,message) self=None return # *************************** # Show sequencer # *************************** def _wait_for_trigger(self): self._state='waiting' if self.ready_callback<>None: self.ready_callback() self.mon.log(self,"Waiting for trigger: "+ self.show['trigger']) if self.show['trigger']=="button": # blank screen waiting for trigger if auto, otherwise display something if self.show['progress']=="manual": text= self.resource('mediashow','m01') else: text="" self.display_message(self.canvas,'text',text,0,self._start_show) elif self.show['trigger']=="PIR": # blank screen waiting for trigger text = self.resource('mediashow','m02') self.display_message(self.canvas,'text',text,0,self._start_show) elif self.show['trigger']=="start": self._start_show() else: self.mon.err(self,"Unknown trigger: "+ self.show['trigger']) self._end('error',"Unknown trigger type") def _start_show(self): self._state='playing' self._direction='forward' # start interval timer if self.show['repeat']=="interval" and self.show['repeat-interval']<>0: self._interval_timer_signal=False self._interval_timer=self.canvas.after(int(self.show['repeat-interval'])*1000,self._end_interval_timer) # and play the first track unless commanded otherwise if self.command=='backward': self.medialist.finish() else: self.medialist.start() self._play_selected_track(self.medialist.selected_track()) def _what_next(self): self._direction='forward' # user wants to end, wait for any shows or tracks to have ended then end show if self._end_mediashow_signal==True: if self.player==None and self.shower==None: self._end_mediashow_signal=False self._end('normal',"show ended by user") else: pass #returning from a subshow needing to move onward elif self._req_next=='do-next': self._req_next='nil' self.medialist.next() self._play_selected_track(self.medialist.selected_track()) #returning from a subshow needing to move backward elif self._req_next=='do-previous': self._req_next='nil' self._direction='backward' self.medialist.previous() self._play_selected_track(self.medialist.selected_track()) # user wants to play child elif self._play_child_signal == True: self._play_child_signal=False index = self.medialist.index_of_track('pp-child-show') if index >=0: #don't select the track as need to preserve mediashow sequence. child_track=self.medialist.track(index) self._display_eggtimer(self.resource('mediashow','m07')) self._play_selected_track(child_track) else: self.mon.err(self,"Child show not found in medialist: "+ self.show['pp-child-show']) self._end('error',"child show not found in medialist") # skip to next track on user input elif self._next_track_signal==True: self._next_track_signal=False if self.medialist.at_end()==True: if self.show['sequence']=="ordered" and self.show['repeat']=='oneshot' and self.top==False: self._end('do-next',"Return from Sub Show") else: self.medialist.next() self._play_selected_track(self.medialist.selected_track()) else: self.medialist.next() self._play_selected_track(self.medialist.selected_track()) # skip to previous track on user input elif self._previous_track_signal==True: self._previous_track_signal=False self._direction='backward' if self.medialist.at_start()==True: if self.show['sequence']=="ordered" and self.show['repeat']=='oneshot' and self.top==False: self._end('do-previous',"Return from Sub Show") else: self.medialist.previous() self._play_selected_track(self.medialist.selected_track()) else: self.medialist.previous() self._play_selected_track(self.medialist.selected_track()) # track is finished and we are on auto elif self.show['progress']=="auto": if self.medialist.at_end()==True: if self.show['sequence']=="ordered" and self.show['repeat']=='oneshot' and self.top==False: self._end('do-next',"Return from Sub Show") #### elif elif self.show['sequence']=="ordered" and self.show['repeat']=='oneshot' and self.top==True: self._wait_for_trigger() elif self._waiting_for_interval==True: if self._interval_timer_signal==True: self._interval_timer_signal=False self._waiting_for_interval=False self._start_show() else: self._poll_for_interval_timer=self.canvas.after(1000,self._what_next) elif self.show['sequence']=="ordered" and self.show['repeat']=='interval' and int(self.show['repeat-interval'])>0: self._waiting_for_interval=True self._poll_for_interval_timer=self.canvas.after(1000,self._what_next) elif self.show['sequence']=="ordered" and self.show['repeat']=='interval' and int(self.show['repeat-interval'])==0: self.medialist.next() self._play_selected_track(self.medialist.selected_track()) else: self.mon.err(self,"Unhandled playing event: ") self._end('error',"Unhandled playing event") else: self.medialist.next() self._play_selected_track(self.medialist.selected_track()) # track has finished and we are on manual progress elif self.show['progress']=="manual": self._delete_eggtimer() self._display_eggtimer(self.resource('mediashow','m03')) self._poll_for_continue_timer=self.canvas.after(500,self._what_next) else: #unhandled state self.mon.err(self,"Unhandled playing event: ") self._end('error',"Unhandled playing event") def _end_interval_timer(self): self._interval_timer_signal=True # *************************** # Dispatching to Players/Shows # *************************** # used to display internal messages in situations where a medialist entry could be used. def display_message(self,canvas,source,content,duration,_display_message_callback): self._display_message_callback=_display_message_callback tp={'duration':duration,'message-colour':'white','message-font':'Helvetica 20 bold'} self.player=MessagePlayer(canvas,tp,tp) self.player.play(content,self._display_message_end,None) def _display_message_end(self,reason,message): self.player=None if reason in ('error','killed'): self._end(reason,message) else: self._display_message_callback() def complete_path(self,selected_track): # complete path of the filename of the selected entry track_file = selected_track['location'] if track_file[0]=="+": track_file=self.pp_home+track_file[1:] self.mon.log(self,"Track to play is: "+ track_file) return track_file def _play_selected_track(self,selected_track): """ selects the appropriate player from type field of the medialist and computes the parameters for that type selected track is a dictionary for the track/show """ self.canvas.delete(ALL) if self.show['progress']=="manual": self._display_eggtimer(self.resource('mediashow','m04')) # is menu required if self.show['has-child']=="yes": enable_child=True else: enable_child=False #dispatch track by type self.player=None self.shower=None track_type = selected_track['type'] self.mon.log(self,"Track type is: "+ track_type) if track_type=="video": # create a videoplayer track_file=self.complete_path(selected_track) self.player=VideoPlayer(self.canvas,self.show,selected_track) self.player.play(track_file, self.end_player, self.ready_callback, enable_menu=enable_child) elif track_type=="image": track_file=self.complete_path(selected_track) # images played from menus don't have children self.player=ImagePlayer(self.canvas,self.show,selected_track) self.player.play(track_file, self.end_player, self.ready_callback, enable_menu=enable_child) elif track_type=="message": # bit odd because MessagePlayer is used internally to display text. text=selected_track['text'] self.player=MessagePlayer(self.canvas,self.show,selected_track) self.player.play(text, self.end_player, self.ready_callback, enable_menu=enable_child ) elif track_type=="show": # get the show from the showlist index = self.showlist.index_of_show(selected_track['sub-show']) if index >=0: self.showlist.select(index) selected_show=self.showlist.selected_show() else: self.mon.err(self,"Show not found in showlist: "+ selected_track['sub-show']) self._end('error',"Unknown show") if selected_show['type']=="mediashow": self.shower= MediaShow(selected_show, self.canvas, self.showlist, self.pp_home, self.pp_profile) self.shower.play(self.end_shower,top=False,command=self._direction) elif selected_show['type']=="liveshow": self.shower= LiveShow(selected_show, self.canvas, self.showlist, self.pp_home, self.pp_profile) self.shower.play(self.end_shower,top=False,command='nil') elif selected_show['type']=="menu": self.shower= MenuShow(selected_show, self.canvas, self.showlist, self.pp_home, self.pp_profile) self.shower.play(self.end_shower,top=False,command='nil') else: self.mon.err(self,"Unknown Show Type: "+ selected_show['type']) self._end('error'"Unknown show type") else: self.mon.err(self,"Unknown Track Type: "+ track_type) self._end('error',"Unknown track type") def ready_callback(self): self._delete_eggtimer() def end_player(self,reason,message): self._req_next='nil' self.mon.log(self,"Returned from player with message: "+ message) self.player=None if reason in("killed","error"): self._end(reason,message) elif self.show['progress']=="manual": self._display_eggtimer(self.resource('mediashow','m05')) self._req_next=reason self._what_next() else: self._req_next=reason self._what_next() def end_shower(self,reason,message): self._req_next='nil' self.mon.log(self,"Returned from shower with message: "+ message) self.shower=None if reason in("killed","error"): self._end(reason,message) elif self.show['progress']=="manual": self._display_eggtimer(self.resource('mediashow','m06')) self._req_next=reason self._what_next() else: self._req_next=reason self._what_next() def _display_eggtimer(self,text): self.canvas.create_text(int(self.canvas['width'])/2, int(self.canvas['height'])/2, text= text, fill='white', font="Helvetica 20 bold") self.canvas.update_idletasks( ) def _delete_eggtimer(self): self.canvas.delete(ALL)
class MediaShow: # ******************* # External interface # ******************** def __init__(self, show_params, root, canvas, showlist, pp_dir, pp_home, pp_profile): """ canvas - the canvas that the menu is to be written on show - the dictionary fo the show to be played pp_home - Pi presents data_home directory pp_profile - Pi presents profile directory """ self.mon=Monitor() self.mon.on() #instantiate arguments self.show_params =show_params self.showlist=showlist self.root=root self.canvas=canvas self.pp_dir=pp_dir self.pp_home=pp_home self.pp_profile=pp_profile # open resources self.rr=ResourceReader() # Init variables self.player=None self.shower=None self.poll_for_interval_timer=None self.poll_for_continue_timer=None self.waiting_for_interval=False self.interval_timer=None self.duration_timer=None self.error=False self.interval_timer_signal=False self.end_trigger_signal=False self.end_mediashow_signal=False self.next_track_signal=False self.previous_track_signal=False self.play_child_signal = False self.req_next='nil' #create and instance of TimeOfDay scheduler so we can add events self.tod=TimeOfDay() self.state='closed' def play(self,show_id,end_callback,show_ready_callback, top=False,command='nil'): """ displays the mediashow end_callback - function to be called when the menu exits ready_callback - callback when menu is ready to display (not used) top is True when the show is top level (run from [start]) """ #instantiate the arguments self.show_id=show_id self.end_callback=end_callback self.show_ready_callback=show_ready_callback self.top=top self.command=command self.mon.log(self,self.show_params['show-ref']+ ' '+ str(self.show_id)+ ": Starting show") # check data files are available. self.media_file = self.pp_profile + "/" + self.show_params['medialist'] if not os.path.exists(self.media_file): self.mon.err(self,"Medialist file not found: "+ self.media_file) self.end('error',"Medialist file not found") #create a medialist for the mediashow and read it. self.medialist=MediaList(self.show_params['sequence']) if self.medialist.open_list(self.media_file,self.showlist.sissue())==False: self.mon.err(self,"Version of medialist different to Pi Presents") self.end('error',"Version of medialist different to Pi Presents") #get controls for this show if top level controlsmanager=ControlsManager() if self.top==True: self.controls_list=controlsmanager.default_controls() # and merge in controls from profile self.controls_list=controlsmanager.merge_show_controls(self.controls_list,self.show_params['controls']) #set up the time of day triggers for the show if self.show_params['trigger']in('time','time-quiet'): error_text=self.tod.add_times(self.show_params['trigger-input'],id(self),self.tod_start_callback,self.show_params['trigger']) if error_text<>'': self.mon.err(self,error_text) self.end('error',error_text) if self.show_params['trigger-end']=='time': # print self.show_params['trigger-end-time'] error_text=self.tod.add_times(self.show_params['trigger-end-time'],id(self),self.tod_end_callback,'n/a') if error_text<>'': self.mon.err(self,error_text) self.end('error',error_text) if self.show_params['trigger-end']=='duration': error_text=self.calculate_duration(self.show_params['trigger-end-time']) if error_text<>'': self.mon.err(self,error_text) self.end('error',error_text) self.state='closed' self.egg_timer=None self.wait_for_trigger() # ******************************** # Respond to external events # ******************************** #stop received from another concurrent show def managed_stop(self): # if next lower show is running pass down to stop the show and lower level if self.shower<>None: self.shower.managed_stop() else: #stop the show if not at top self.end_mediashow_signal=True # and if track is runing stop that first if self.player<>None: self.player.input_pressed('stop') # kill or error def terminate(self,reason): if self.shower<>None: self.shower.terminate(reason) elif self.player<>None: self.player.terminate(reason) else: self.end(reason,' terminated with no shower or player to terminate') # respond to input events def input_pressed(self,symbol,edge,source): self.mon.log(self, self.show_params['show-ref']+ ' '+ str(self.show_id)+": received input: " + symbol) # check symbol against mediashow triggers, triggers can be used at top or lower level # and not affected by disable-controls if self.state=='waiting' and self.show_params['trigger'] in ('input','input-quiet')and symbol == self.show_params['trigger-input']: self.start_show() elif self.state=='playing' and self.show_params['trigger-next']=='input' and symbol == self.show_params['next-input']: self.next() # internal functions are triggered only when disable-controls is 'no' if self.show_params['disable-controls']=='yes': return # if at top convert symbolic name to operation otherwise lower down we have received an operation # look through list of standard symbols to find match (symbolic-name, function name) operation =lookup (symbol if self.top==True: operation=self.lookup_control(symbol,self.controls_list) else: operation=symbol # print 'operation',operation self.do_operation(operation,edge,source) #service the standard inputs for this show def do_operation(self,operation,edge,source): if self.shower<>None: # if next lower show is running pass down to stop the show and lower level self.shower.input_pressed(operation,edge,source) else: # control this show and its tracks # print 'operation',operation if operation=='stop': if self.top == False: # not at top so stop the current show self.end_mediashow_signal=True # and if a track is running stop that first if self.player<>None: self.player.input_pressed('stop') else: # top = True, just stop track if running if self.player<>None: self.player.input_pressed('stop') elif operation in ('up','down'): #if playing rather than waiting use keys for next or previous if operation=='up' and self.state=='playing': self.previous() else: self.next() elif operation=='play': # use 'play' to start child if state=playing or to trigger the show if waiting for trigger if self.state=='playing': if self.show_params['has-child']=='yes': self.play_child_signal=True self.child_track_ref='pp-child-show' # and stop the current track if its running if self.player<>None: self.player.input_pressed('stop') else: if self.state=='waiting': self.start_show() elif operation == 'pause': if self.player<>None: self.player.input_pressed(operation) #if the operation is omxplayer or mplayer runtime control then pass it to player if running elif operation[0:4]=='omx-' or operation[0:6]=='mplay-'or operation[0:5]=='uzbl-': if self.player<>None: self.player.input_pressed(operation) def lookup_control(self,symbol,controls_list): for control in controls_list: if symbol == control[0]: return control[1] return '' # *************************** # Show sequencer # *************************** def end_interval_timer(self): self.interval_timer_signal=True # callback from time of day scheduler def tod_start_callback(self): if self.state=='waiting' and self.show_params['trigger']in('time','time-quiet'): self.start_show() def tod_end_callback(self): if self.state=='playing' and self.show_params['trigger-end'] in ('time','duration'): self.end_trigger_signal=True if self.shower<>None: self.shower.input_pressed('stop') elif self.player<>None: self.player.input_pressed('stop') def stop(self,message): self.end_mediashow_signal=True if self.interval_timer<>None: self.canvas.after_cancel(self.interval_timer) def next(self): # stop track if running and set signal self.next_track_signal=True if self.shower<>None: self.shower.input_pressed("stop") else: if self.player<>None: self.player.input_pressed("stop") def previous(self): self.previous_track_signal=True if self.shower<>None: self.shower.input_pressed("stop") else: if self.player<>None: self.player.input_pressed("stop") # wait for trigger sets the state to waiting so that events can do a start show. def wait_for_trigger(self): self.state='waiting' if self.show_ready_callback<>None: self.show_ready_callback() self.mon.log(self,self.show_params['show-ref']+ ' '+ str(self.show_id)+ ": Waiting for trigger: "+ self.show_params['trigger']) if self.show_params['trigger']=="input": # blank screen waiting for trigger if auto, otherwise display something if self.show_params['progress']=="manual": text= self.resource('mediashow','m01') else: text= self.resource('mediashow','m02') self.display_message(self.canvas,'text',text,0,self.start_show) elif self.show_params['trigger']=="input-quiet": # blank screen waiting for trigger text = self.resource('mediashow','m10') self.display_message(self.canvas,'text',text,0,self.start_show) pass elif self.show_params['trigger'] in ('time','time-quiet'): # show next show notice quiet=3 # if next show is this one display text next_show=self.tod.next_event_time() if next_show[quiet]==False: if next_show[1]=='tomorrow': text = self.resource('mediashow','m09') else: text = self.resource('mediashow','m08') text=text.replace('%tt',next_show[0]) self.display_message(self.canvas,'text',text,0,self.start_show) elif self.show_params['trigger']=="start": self.start_show() else: self.mon.err(self,"Unknown trigger: "+ self.show_params['trigger']) self.end('error',"Unknown trigger type") def start_show(self): self.state='playing' self.direction='forward' # self.canvas.delete(ALL) # start interval timer if self.show_params['repeat']=="interval" and self.show_params['repeat-interval']<>0: self.interval_timer_signal=False self.interval_timer=self.canvas.after(int(self.show_params['repeat-interval'])*1000,self.end_interval_timer) # start duration timer if self.show_params['trigger-end']=='duration': # print 'set alarm ', self.duration self.duration_timer = self.canvas.after(self.duration*1000,self.tod_end_callback) # and play the first track unless commanded otherwise if self.command=='backward': self.medialist.finish() else: self.medialist.start() self.play_selected_track(self.medialist.selected_track()) def what_next(self): self.direction='forward' # end of show trigger caused by tod if self.end_trigger_signal==True: self.end_trigger_signal=False if self.top==True: self.state='waiting' self.wait_for_trigger() else: # not at top so stop the show self.end('normal','sub-show end time trigger') # user wants to end, wait for any shows or tracks to have ended then end show # probalby will get here with end_m set when player and shower has finished elif self.end_mediashow_signal==True: if self.player==None and self.shower==None: self.end_mediashow_signal=False self.end('normal',"show ended by user") #returning from a subshow needing to move onward elif self.req_next=='do-next': self.req_next='nil' self.medialist.next(self.show_params['sequence']) self.play_selected_track(self.medialist.selected_track()) #returning from a subshow needing to move backward elif self.req_next=='do-previous': self.req_next='nil' self.direction='backward' self.medialist.previous(self.show_params['sequence']) self.play_selected_track(self.medialist.selected_track()) # user wants to play child elif self.play_child_signal == True: self.play_child_signal=False index = self.medialist.index_of_track(self.child_track_ref) if index >=0: #don't use select the track as need to preserve mediashow sequence. child_track=self.medialist.track(index) self.display_eggtimer(self.resource('mediashow','m07')) self.play_selected_track(child_track) else: self.mon.err(self,"Child show not found in medialist: "+ self.show_params['pp-child-show']) self.end('error',"child show not found in medialist") # skip to next track on user input elif self.next_track_signal==True: self.next_track_signal=False if self.medialist.at_end()==True: if self.show_params['sequence']=="ordered" and self.show_params['repeat']=='oneshot' and self.top==False: self.end('do-next',"Return from Sub Show") elif self.show_params['sequence']=="ordered" and self.show_params['repeat']=='single-run' and self.top==False: self.end('do-next',"Return from Sub Show") else: self.medialist.next(self.show_params['sequence']) self.play_selected_track(self.medialist.selected_track()) else: self.medialist.next(self.show_params['sequence']) self.play_selected_track(self.medialist.selected_track()) # skip to previous track on user input elif self.previous_track_signal==True: self.previous_track_signal=False self.direction='backward' if self.medialist.at_start()==True: if self.show_params['sequence']=="ordered" and self.show_params['repeat']=='oneshot' and self.top==False: self.end('do-previous',"Return from Sub Show") elif self.show_params['sequence']=="ordered" and self.show_params['repeat']=='single-run' and self.top==False: self.end('do-previous',"Return from Sub Show") else: self.medialist.previous(self.show_params['sequence']) self.play_selected_track(self.medialist.selected_track()) else: self.medialist.previous(self.show_params['sequence']) self.play_selected_track(self.medialist.selected_track()) # track is finished and we are on auto elif self.show_params['progress']=="auto": if self.medialist.at_end()==True: # oneshot if self.show_params['repeat']=='oneshot' and self.top==False: self.end('normal',"End of Oneshot in subshow") elif self.show_params['sequence']=="ordered" and self.show_params['repeat']=='oneshot' and self.top==True: self.wait_for_trigger() # single run elif self.show_params['repeat']=='single-run' and self.top==True: self.end('normal',"End of Single Run") elif self.show_params['repeat']=='single-run' and self.top==False: self.end('do-next',"End of single run - Return from Sub Show") # repeating and waiting to restart elif self.waiting_for_interval==True: if self.interval_timer_signal==True: self.interval_timer_signal=False self.waiting_for_interval=False self.start_show() else: self.poll_for_interval_timer=self.canvas.after(1000,self.what_next) elif self.show_params['repeat']=='interval' and int(self.show_params['repeat-interval'])>0: self.waiting_for_interval=True self.poll_for_interval_timer=self.canvas.after(1000,self.what_next) #elif self.show_params['sequence']=="ordered" and self.show_params['repeat']=='interval' and int(self.show_params['repeat-interval'])==0: elif self.show_params['repeat']=='interval' and int(self.show_params['repeat-interval'])==0: self.medialist.next(self.show_params['sequence']) self.play_selected_track(self.medialist.selected_track()) # shuffling so there is no end condition elif self.show_params['sequence']=="shuffle": self.medialist.next(self.show_params['sequence']) self.play_selected_track(self.medialist.selected_track()) else: self.mon.err(self,"Unhandled playing event: "+self.show_params['sequence'] +' with ' + self.show_params['repeat']+" of "+ self.show_params['repeat-interval']) self.end('error',"Unhandled playing event") else: self.medialist.next(self.show_params['sequence']) self.play_selected_track(self.medialist.selected_track()) # track has finished and we are on manual progress elif self.show_params['progress']=="manual": self.delete_eggtimer() self.canvas.delete('pp-content') if self.show_params['trigger-next']=='input': self.display_eggtimer(self.resource('mediashow','m03')) self.poll_for_continue_timer=self.canvas.after(2000,self.what_next) else: #unhandled state self.mon.err(self,"Unhandled playing event: ") self.end('error',"Unhandled playing event") # *************************** # Dispatching to Players/Shows # *************************** def ready_callback(self): self.delete_eggtimer() def play_selected_track(self,selected_track): """ selects the appropriate player from type field of the medialist and computes the parameters for that type selected track is a dictionary for the track/show """ self.delete_eggtimer() if self.show_params['progress']=="manual": self.display_eggtimer(self.resource('mediashow','m04')) # is menu required if self.show_params['has-child']=="yes": self.enable_child=True else: self.enable_child=False #dispatch track by type self.player=None self.shower=None track_type = selected_track['type'] self.mon.log(self,self.show_params['show-ref']+ ' '+ str(self.show_id)+ ": Track type is: "+ track_type) if track_type=="video": # create a videoplayer track_file=self.complete_path(selected_track) self.player=VideoPlayer(self.show_id,self.root,self.canvas,self.show_params,selected_track,self.pp_dir,self.pp_home,self.pp_profile) self.player.play(track_file, self.showlist, self.end_player, self.ready_callback, enable_menu=self.enable_child) elif track_type=="audio": # create a audioplayer track_file=self.complete_path(selected_track) self.player=AudioPlayer(self.show_id,self.root,self.canvas,self.show_params,selected_track,self.pp_dir,self.pp_home,self.pp_profile) self.player.play(track_file, self.showlist, self.end_player, self.ready_callback, enable_menu=self.enable_child) elif track_type=="web": # create a browser track_file=self.complete_path(selected_track) self.player=BrowserPlayer(self.show_id,self.root,self.canvas,self.show_params,selected_track,self.pp_dir,self.pp_home,self.pp_profile) self.player.play(track_file, self.showlist, self.end_player, self.ready_callback, enable_menu=self.enable_child) elif track_type=="image": track_file=self.complete_path(selected_track) # images played from menus don't have children self.player=ImagePlayer(self.show_id,self.root,self.canvas,self.show_params,selected_track,self.pp_dir,self.pp_home,self.pp_profile) self.player.play(track_file, self.showlist, self.end_player, self.ready_callback, enable_menu=self.enable_child) elif track_type=="message": # bit odd because MessagePlayer is used internally to display text. text=selected_track['text'] self.player=MessagePlayer(self.show_id,self.root,self.canvas,self.show_params,selected_track,self.pp_dir,self.pp_home,self.pp_profile) self.player.play(text, self.showlist, self.end_player, self.ready_callback, enable_menu=self.enable_child ) elif track_type=="show": # get the show from the showlist index = self.showlist.index_of_show(selected_track['sub-show']) if index >=0: self.showlist.select(index) selected_show=self.showlist.selected_show() else: self.mon.err(self,"Show not found in showlist: "+ selected_track['sub-show']) self.end('error',"Unknown show") if selected_show['type']=="mediashow": self.shower= MediaShow(selected_show, self.root, self.canvas, self.showlist, self.pp_dir, self.pp_home, self.pp_profile) print "Starting MediaShow: {0}".format(selected_track['sub-show']) self.shower.play(self.show_id,self.end_shower,self.ready_callback,top=False,command=self.direction) elif selected_show['type']=="liveshow": self.shower= LiveShow(selected_show, self.root, self.canvas, self.showlist, self.pp_dir, self.pp_home, self.pp_profile) self.shower.play(self.show_id,self.end_shower,self.ready_callback,top=False,command='nil') elif selected_show['type']=="radiobuttonshow": self.shower= RadioButtonShow(selected_show, self.root, self.canvas, self.showlist, self.pp_dir, self.pp_home, self.pp_profile) self.shower.play(self.show_id,self.end_shower,self.ready_callback,top=False,command='nil') elif selected_show['type']=="hyperlinkshow": self.shower= HyperlinkShow(selected_show, self.root, self.canvas, self.showlist, self.pp_dir, self.pp_home, self.pp_profile) self.shower.play(self.show_id,self.end_shower,self.ready_callback,top=False,command='nil') elif selected_show['type']=="menu": self.shower= MenuShow(selected_show, self.root, self.canvas, self.showlist, self.pp_dir, self.pp_home, self.pp_profile) self.shower.play(self.show_id,self.end_shower,self.ready_callback,top=False,command='nil') else: self.mon.err(self,"Unknown Show Type: "+ selected_show['type']) self.end('error'"Unknown show type") else: self.mon.err(self,"Unknown Track Type: "+ track_type) self.end('error',"Unknown track type") def end_player(self,reason,message): self.mon.log(self,self.show_params['show-ref']+ ' '+ str(self.show_id)+ ": Returned from player with message: "+ message) self.player=None self.req_next='nil' if reason in("killed","error"): self.end(reason,message) else: # elif>else move to what-next? if self.show_params['progress']=="manual": self.display_eggtimer(self.resource('mediashow','m05')) self.req_next=reason self.what_next() else: self.req_next=reason self.what_next() def end_shower(self,show_id,reason,message): self.mon.log(self,self.show_params['show-ref']+ ' '+ str(self.show_id)+ ": Returned from shower with message: "+ message) self.shower=None self.req_next='nil' if reason in("killed","error"): self.end(reason,message) else: if self.show_params['progress']=="manual": self.display_eggtimer(self.resource('mediashow','m06')) self.req_next=reason self.what_next() else: self.req_next=reason self.what_next() # *************************** # end of show # *************************** def end(self,reason,message): self.end_mediashow_signal=False self.mon.log(self,self.show_params['show-ref']+ ' '+ str(self.show_id)+ ": Ending Mediashow") self.tidy_up() self.end_callback(self.show_id,reason,message) self=None return def tidy_up(self): #clear outstanding time of day events for this show # self.tod.clear_times_list(id(self)) if self.poll_for_continue_timer<>None: self.canvas.after_cancel(self.poll_for_continue_timer) self.poll_for_continue_timer=None if self.poll_for_interval_timer<>None: self.canvas.after_cancel(self.poll_for_interval_timer) self.poll_for_interval_timer=None if self.interval_timer<>None: self.canvas.after_cancel(self.interval_timer) self.interval_timer=None if self.duration_timer<>None: self.canvas.after_cancel(self.duration_timer) self.duration_timer=None # *************************** # displaying things # *************************** def display_eggtimer(self,text): self.canvas.create_text(int(self.canvas['width'])/2, int(self.canvas['height'])/2, text= text, fill='white', font="Helvetica 20 bold", tag='pp-eggtimer') self.canvas.update_idletasks( ) def delete_eggtimer(self): self.canvas.delete('pp-eggtimer') self.canvas.update_idletasks( ) # used to display internal messages in situations where a medialist entry could not be used. def display_message(self,canvas,source,content,duration,_display_message_callback): self.display_message_callback=_display_message_callback tp={'duration':duration,'message-colour':'white','message-font':'Helvetica 20 bold','background-colour':'', 'message-justify':'left','background-image':'','show-control-begin':'','show-control-end':'', 'animate-begin':'','animate-clear':'','animate-end':'','message-x':'','message-y':'', 'display-show-background':'no','display-show-text':'no','show-text':'','track-text':'', 'plugin':''} self.player=MessagePlayer(self.show_id,self.root,canvas,tp,tp,self.pp_dir,self.pp_home,self.pp_profile) self.player.play(content,self.showlist,self.display_message_end,None,False) def display_message_end(self,reason,message): self.player=None if reason in ('error','killed'): self.end(reason,message) else: self.display_message_callback() # *************************** # utilities # *************************** def calculate_duration(self,line): fields=line.split(':') if len(fields)==1: secs=fields[0] minutes='0' hours='0' if len(fields)==2: secs=fields[1] minutes=fields[0] hours='0' if len(fields)==3: secs=fields[2] minutes=fields[1] hours=fields[0] self.duration=3600*long(hours)+60*long(minutes)+long(secs) return '' def resource(self,section,item): value=self.rr.get(section,item) if value==False: self.mon.err(self, "resource: "+section +': '+ item + " not found" ) self.terminate("error") else: return value def complete_path(self,selected_track): # complete path of the filename of the selected entry track_file = selected_track['location'] if track_file<>'' and track_file[0]=="+": track_file=self.pp_home+track_file[1:] self.mon.log(self,self.show_params['show-ref']+ ' '+ str(self.show_id)+ ": Track to play is: "+ track_file) return track_file
def _play_selected_track(self,selected_track): """ selects the appropriate player from type field of the medialist and computes the parameters for that type selected track is a dictionary for the track/show """ self.canvas.delete(ALL) if self.show['progress']=="manual": self._display_eggtimer(self.resource('mediashow','m04')) # is menu required if self.show['has-child']=="yes": enable_child=True else: enable_child=False #dispatch track by type self.player=None self.shower=None track_type = selected_track['type'] self.mon.log(self,"Track type is: "+ track_type) if track_type=="video": # create a videoplayer track_file=self.complete_path(selected_track) self.player=VideoPlayer(self.canvas,self.show,selected_track) self.player.play(track_file, self.end_player, self.ready_callback, enable_menu=enable_child) elif track_type=="image": track_file=self.complete_path(selected_track) # images played from menus don't have children self.player=ImagePlayer(self.canvas,self.show,selected_track) self.player.play(track_file, self.end_player, self.ready_callback, enable_menu=enable_child) elif track_type=="message": # bit odd because MessagePlayer is used internally to display text. text=selected_track['text'] self.player=MessagePlayer(self.canvas,self.show,selected_track) self.player.play(text, self.end_player, self.ready_callback, enable_menu=enable_child ) elif track_type=="show": # get the show from the showlist index = self.showlist.index_of_show(selected_track['sub-show']) if index >=0: self.showlist.select(index) selected_show=self.showlist.selected_show() else: self.mon.err(self,"Show not found in showlist: "+ selected_track['sub-show']) self._end('error',"Unknown show") if selected_show['type']=="mediashow": self.shower= MediaShow(selected_show, self.canvas, self.showlist, self.pp_home, self.pp_profile) self.shower.play(self.end_shower,top=False,command=self._direction) elif selected_show['type']=="liveshow": self.shower= LiveShow(selected_show, self.canvas, self.showlist, self.pp_home, self.pp_profile) self.shower.play(self.end_shower,top=False,command='nil') elif selected_show['type']=="menu": self.shower= MenuShow(selected_show, self.canvas, self.showlist, self.pp_home, self.pp_profile) self.shower.play(self.end_shower,top=False,command='nil') else: self.mon.err(self,"Unknown Show Type: "+ selected_show['type']) self._end('error'"Unknown show type") else: self.mon.err(self,"Unknown Track Type: "+ track_type) self._end('error',"Unknown track type")
def start_show(self, show_ref): show_index = self.showlist.index_of_show(show_ref) if show_index < 0: return 'error', "Show not found in showlist: " + show_ref show = self.showlist.show(show_index) index = self.register_show(show_ref) self.mon.log( self, self.show_params['show-ref'] + ' ' + str(self.show_id) + ": Starting show " + show_ref + ' ' + str(index)) if self.show_running(index): self.mon.log(self, "show already running " + show_ref) return 'normal', 'this concurrent show already running' if show['type'] == "mediashow": show_obj = MediaShow(show, self.root, self.canvas, self.showlist, self.pp_dir, self.pp_home, self.pp_profile) self.set_running(index, show_obj) show_obj.play(index, self._end_play_show, None, top=True, command='nil') return 'normal', 'concurrent show started' if show['type'] == "radiobuttonshow": show_obj = RadioButtonShow(show, self.root, self.canvas, self.showlist, self.pp_dir, self.pp_home, self.pp_profile) self.set_running(index, show_obj) show_obj.play(index, self._end_play_show, None, top=True, command='nil') return 'normal', 'concurrent show started' if show['type'] == "hyperlinkshow": show_obj = HyperlinkShow(show, self.root, self.canvas, self.showlist, self.pp_dir, self.pp_home, self.pp_profile) self.set_running(index, show_obj) show_obj.play(index, self._end_play_show, None, top=True, command='nil') return 'normal', 'concurrent show started' elif show['type'] == "menu": show_obj = MenuShow(show, self.root, self.canvas, self.showlist, self.pp_dir, self.pp_home, self.pp_profile) self.set_running(index, show_obj) show_obj.play(index, self._end_play_show, None, top=True, command='nil') return 'normal', 'concurrent show started' elif show['type'] == "liveshow": show_obj = LiveShow(show, self.root, self.canvas, self.showlist, self.pp_dir, self.pp_home, self.pp_profile) self.set_running(index, show_obj) show_obj.play(index, self._end_play_show, None, top=True, command='nil') return 'normal', 'concurrent show started' else: return 'error', "unknown show type in start concurrent show - " + show[ 'type']
def _play_selected_track(self, selected_track): """ selects the appropriate player from type field of the medialist and computes the parameters for that type selected_track is a dictionary for the track/show """ # self.canvas.delete(ALL) # is menu required if self.show['has-child'] == "yes": enable_child = True else: enable_child = False #dispatch track by type self.player = None self.shower = None track_type = selected_track['type'] self.mon.log(self, "Track type is: " + track_type) if track_type == "image": track_file = self.complete_path(selected_track) # images played from menus don't have children self.player = ImagePlayer(self.canvas, self.show, selected_track) self.player.play(track_file, self.end_player, self.ready_callback, enable_menu=enable_child) elif track_type == "video": # create a videoplayer track_file = self.complete_path(selected_track) self.player = VideoPlayer(self.canvas, self.show, selected_track) self.player.play(track_file, self.end_player, self.ready_callback, enable_menu=enable_child) elif track_type == "show": # get the show from the showlist index = self.showlist.index_of_show(selected_track['sub-show']) if index >= 0: self.showlist.select(index) selected_show = self.showlist.selected_show() else: self.mon.err( self, "Show not found in showlist: " + selected_track['sub-show']) self._stop("Unknown show") if selected_show['type'] == "mediashow": self.shower = MediaShow(selected_show, self.canvas, self.showlist, self.pp_home, self.pp_profile) self.shower.play(self.end_shower, top=False, command='nil') elif selected_show['type'] == "menu": self.shower = MenuShow(selected_show, self.canvas, self.showlist, self.pp_home, self.pp_profile) self.shower.play(self.end_shower, top=False, command='nil') else: self.mon.err(self, "Unknown Show Type: " + selected_show['type']) self._stop("Unknown show type") else: self.mon.err(self, "Unknown Track Type: " + track_type) self._stop("Unknown track type")
class HyperlinkShow: """ Aimed at touchscreens but can be used for any purpose where the user is required to follow hyperlinks between tracks Profiles for media tracks (message, image, video, audio ) specify links to other tracks in a link a symbolic name of an input is associated with a track-reference The show begins at first-track and then uses events (GPIO, keypresses etc.) to link to other tracks via their symbolic names If using 'call' keeps a record of the tracks it has visited so the 'return' command can go back. Executes timeout-track if no user input is received. links are of the form: symbolic-name command [track-ref] link commands: call <track-ref> play track-ref and add it to the path return - return 1 back up the path removing the track from the path, stops at home-track. return n - return n tracks back up the path removing the track from the path, stops at home-track. return <track-ref> return to <track-ref> removing tracks from the path home - return to home-track removing tracks from the path jump <track-ref-> - play trck-ref forgetting the path back to home-track goto <track-ref> - play track-ref, forget the path exit - end the hyperlink show null - inhibits the link defined in the show with the same symbolic name. reserved symbolic names pp-onend command - pseudo symbolic name for end of a track interface: * play - selects the first track to play (first-track) * input_pressed, - receives user events passes them to a Shower/Player if a track is playing, otherwise actions them depending on the symbolic name supplied """ # ********************* # external interface # ******************** def __init__(self, show_params, root, canvas, showlist, pp_dir, pp_home, pp_profile): """ canvas - the canvas that the tracks of the event show are to be written on show_params - the name of the configuration dictionary section for the hyperlinkshow showlist - the showlist, to enable runningnof show type tracks. pp_home - Pi presents data_home directory pp_profile - Pi presents profile directory """ self.mon=Monitor() self.mon.on() #instantiate arguments self.show_params=show_params self.root=root self.showlist=showlist self.canvas=canvas self.pp_dir=pp_dir self.pp_home=pp_home self.pp_profile=pp_profile # open resources self.rr=ResourceReader() #create a path stack self.path = PathManager() # init variables self.drawn = None self.player=None self.shower=None self.timeout_running=None self.error=False def play(self,show_id,end_callback,ready_callback,top=False,command='nil'): """ starts the hyperlink show at start-track end_callback - function to be called when the show exits ready_callback - callback when event-show is ready to display its forst track (not used?) top is True when the show is top level (run from [start] or from show control) command is not used """ #instantiate arguments self.show_id=show_id self.end_callback=end_callback self.ready_callback=ready_callback self.top=top self.command=command # check data files are available. self.medialist_file = self.pp_profile + "/" + self.show_params['medialist'] if not os.path.exists(self.medialist_file): self.mon.err(self,"Medialist file not found: "+ self.medialist_file) self.end('error',"Medialist file not found") #create a medialist object for the hyperlinkshow and read the file into it. self.medialist=MediaList() if self.medialist.open_list(self.medialist_file,self.showlist.sissue()) == False: self.mon.err(self,"Version of medialist different to Pi Presents") self.end('error',"Version of medialist different to Pi Presents") #get controls for this show if top level controlsmanager=ControlsManager() if self.top==True: self.controls_list=controlsmanager.default_controls() # and merge in controls from profile self.controls_list=controlsmanager.merge_show_controls(self.controls_list,self.show_params['controls']) # read show links and destinations self.first_track_ref=self.show_params['first-track-ref'] self.home_track_ref=self.show_params['home-track-ref'] self.timeout_track_ref=self.show_params['timeout-track-ref'] # state variables and signals self.end_hyperlinkshow_signal= False self.egg_timer=None self.next_track_signal=False self.next_track_ref='' self.current_track_ref='' self.current_track_type='' # ready callback for show if self.ready_callback<>None: self.ready_callback() self.canvas.delete('pp-content') self.canvas.config(bg='black') self.do_first_track() #stop received from another concurrent show via ShowManager def managed_stop(self): # set signal to stop the hyperlinkshow when all sub-shows and players have ended self.end_hyperlinkshow_signal=True # then stop and shows or tracks. if self.shower<>None: self.shower.managed_stop() elif self.player<>None: self.player.input_pressed('stop') else: self.end('normal','stopped by ShowManager') # kill or error def terminate(self,reason): self.end_hyperlinkshow_signal=True if self.shower<>None: self.shower.terminate(reason) elif self.player<>None: self.player.terminate(reason) else: self.end(reason,'terminated without terminating shower or player') # respond to inputs def input_pressed(self,symbol,edge,source): self.mon.log(self,"received symbol: " + symbol) #does the symbol match a link, if so execute it if self.is_link(symbol,edge,source)==True: return # controls are disabled so ignore anything else if self.show_params['disable-controls']=='yes': return # does it match a control # if at top convert symbolic name to operation otherwise lower down we have received an operatio # look through list of controls to find match if self.top==True: operation=self.lookup_control(symbol,self.controls_list) else: operation=symbol # print 'operation',operation if operation<>'': self.do_operation(operation,edge,source) def do_operation(self,operation,edge,source): if self.shower<>None: # if next lower show is running pass down to stop the show and lower level self.shower.input_pressed(operation,edge,source) else: # control this show and its tracks if operation=='stop': if self.player<>None: if self.current_track_ref==self.first_track_ref and self.top==False: self.end_radiobuttonshow_signal=True self.player.input_pressed('stop') elif operation == 'pause': if self.player<>None: self.player.input_pressed(operation) elif operation[0:4]=='omx-' or operation[0:6]=='mplay-'or operation[0:5]=='uzbl-': if self.player<>None: self.player.input_pressed(operation) def is_link(self,symbol,edge,source): # find the first entry in links that matches the symbol and execute its operation # print 'hyperlinkshow ',symbol found=False for link in self.links: #print link if symbol==link[0]: found=True if link[1]<>'null': # print 'match',link[0] link_operation=link[1] if link_operation=='home': self.do_home(edge,source) elif link_operation =='return': self.do_return(link[2],edge,source) elif link_operation =='call': self.do_call(link[2],edge,source) elif link_operation =='goto': self.do_goto(link[2],edge,source) elif link_operation =='jump': self.do_jump(link[2],edge,source) elif link_operation=='exit': self.end('normal','executed exit command') return found def lookup_control(self,symbol,controls_list): for control in controls_list: if symbol == control[0]: return control[1] return '' # ********************* # INTERNAL FUNCTIONS # ******************** # ********************* # Show Sequencer # ********************* def timeout_callback(self): self.do_call(self.timeout_track_ref,'front','timeout') def do_call(self,track_ref,edge,source): if track_ref<>self.current_track_ref: self.mon.log(self, 'call: '+track_ref) self.next_track_signal=True self.next_track_op='call' self.next_track_arg=track_ref if self.shower<>None: self.shower.input_pressed('stop',edge,source) elif self.player<>None: self.player.input_pressed('stop') else: self.what_next() def do_goto(self,to,edge,source): if to<>self.current_track_ref: self.mon.log(self,'goto: '+to) self.next_track_signal=True self.next_track_op='goto' self.next_track_arg=to if self.shower<>None: self.shower.input_pressed('stop',edge,source) elif self.player<>None: self.player.input_pressed('stop') else: self.what_next() def do_jump(self,to,edge,source): if to<>self.current_track_ref: self.mon.log(self,'jump to: '+to) self.next_track_signal=True self.next_track_op='jump' self.next_track_arg=to if self.shower<>None: self.shower.input_pressed('stop',edge,source) elif self.player<>None: self.player.input_pressed('stop') else: self.what_next() def do_return(self,to,edge,source): self.next_track_signal=True if to.isdigit() or to=='': self.mon.log(self,'hyperlink command - return by: '+to) self.next_track_op='return-by' if to == '': self.next_track_arg='1' else: self.next_track_arg=to else: self.mon.log(self,'hyperlink command - return to: '+to) self.next_track_op='return-to' self.next_track_arg=to if self.shower<>None: self.shower.input_pressed('stop',edge,source) elif self.player<>None: self.player.input_pressed('stop') else: self.what_next() def do_home(self,edge,source): if self.current_track_ref<>self.home_track_ref: self.mon.log(self,'hyperlink command - home') self.next_track_signal=True self.next_track_op='home' if self.shower<>None: self.shower.input_pressed('stop',edge,source) elif self.player<>None: self.player.input_pressed('stop') else: self.what_next() def do_first_track(self): index = self.medialist.index_of_track(self.first_track_ref) if index >=0: #don't use select the track as not using selected_track in hyperlinkshow first_track=self.medialist.track(index) self.current_track_ref=first_track['track-ref'] self.path.append(first_track['track-ref']) self.play_selected_track(first_track) else: self.mon.err(self,"first-track not found in medialist: "+ self.show_params['first-track-ref']) self.end('error',"first track not found in medialist") def what_next(self): # user wants to end the show if self.end_hyperlinkshow_signal==True: self.end_hyperlinkshow_signal=False self.end('normal',"show ended by user") # user has selected another track elif self.next_track_signal==True: self.next_track_signal=False # home if self.next_track_op in ('home'): # back to 1 before home back_ref=self.path.back_to(self.home_track_ref) if back_ref=='': self.mon.err(self,"home - home track not in path: "+self.home_track_ref) self.end('error',"home - home track not in path") # play home self.next_track_ref=self.home_track_ref self.path.append(self.next_track_ref) # return-by elif self.next_track_op in ('return-by'): if self.current_track_ref<>self.home_track_ref: # back n stopping at home # back one more and return it back_ref=self.path.back_by(self.home_track_ref,self.next_track_arg) # use returned track self.next_track_ref=back_ref self.path.append(self.next_track_ref) # return-to elif self.next_track_op in ('return-to'): #back to one before return-to track back_ref=self.path.back_to(self.next_track_arg) if back_ref=='': self.mon.err(self,"return-to - track not in path: "+self.next_track_arg) self.end('error',"return-to - track not in path") # and append the return to track self.next_track_ref=self.next_track_arg self.path.append(self.next_track_ref) # call elif self.next_track_op in ('call'): # append the required track self.path.append(self.next_track_arg) self.next_track_ref=self.next_track_arg # goto elif self.next_track_op in ('goto'): self.path.pop_for_sibling() ## #back to first track and remove it ## back_ref=self.path.back_to(self.first_track_ref) ## if back_ref=='': ## self.mon.err(self,"goto - first track not in path: "+self.first_track_ref) ## self.end('error',"goto - first track not in path") #add the goto track self.next_track_ref=self.next_track_arg self.path.append(self.next_track_arg) # jump elif self.next_track_op in ('jump'): # back to home and remove it back_ref=self.path.back_to(self.home_track_ref) if back_ref=='': self.mon.err(self,"jump - home track not in path: "+self.home_track_ref) self.end('error',"jump - track not in path") # add back the home track without playing it self.path.append(self.home_track_ref) # append the jumped to track self.next_track_ref=self.next_track_arg self.path.append(self.next_track_ref) else: self.mon.err(self,"unaddressed what next: "+ self.next_track_op+ ' '+self.next_track_arg) self.end('error',"unaddressed what next") self.current_track_ref=self.next_track_ref index = self.medialist.index_of_track(self.next_track_ref) if index >=0: #don't use select the track as not using selected_track in hyperlinkshow next_track=self.medialist.track(index) self.play_selected_track(next_track) else: self.mon.err(self,"next-track not found in medialist: "+ self.next_track_ref) self.end('error',"next track not found in medialist") else: #track ends naturally #then input pp-onend symbolic name self.input_pressed('pp-onend','front','key') # ********************* # Dispatching to Players # ********************* def page_callback(self): # called from a Player when ready to play, merge the links from the track with those from the show # and then enable the click areas self.delete_eggtimer() links_text=self.player.get_links() reason,message,track_links=self.path.parse_links(links_text) if reason=='error': self.mon.err(self,message + " in page") self.end('error',message) self.path.merge_links(self.links,track_links) # enable the click-area that are in the list of links self.enable_click_areas() def enable_click_areas(self): for link in self.links: #print 'trying link ',link[0] if not('key-' in link[0]) and link[1]<>'null' and link[0]<>'pp-auto': # print 'enabling link ',link[0] self.canvas.itemconfig(link[0],state='normal') def play_selected_track(self,selected_track): """ selects the appropriate player from type field of the medialist and computes the parameters for that type selected track is a dictionary for the track/show """ if self.timeout_running<>None: self.canvas.after_cancel(self.timeout_running) self.timeout_running=None # self.canvas.delete(ALL) self.display_eggtimer(self.resource('hyperlinkshow','m01')) self.current_track_type = selected_track['type'] #read the show links. Track links will be added by ready_callback links_text=self.show_params['links'] reason,message,self.links=self.path.parse_links(links_text) if reason=='error': self.mon.err(self,message + " in show") self.end('error',message) #start timeout for the track if required if self.current_track_ref<>self.first_track_ref and int(self.show_params['timeout'])<>0: self.timeout_running=self.canvas.after(int(self.show_params['timeout'])*1000,self.timeout_callback) # dispatch track by type self.player=None self.shower=None track_type = selected_track['type'] self.mon.log(self,"Track type is: "+ track_type) if track_type=="video": # create a videoplayer track_file=self.complete_path(selected_track) self.player=VideoPlayer(self.show_id,self.root,self.canvas,self.show_params,selected_track,self.pp_dir,self.pp_home,self.pp_profile) self.player.play(track_file, self.showlist, self.end_player, self.page_callback, enable_menu=False) elif track_type=="audio": # create a audioplayer track_file=self.complete_path(selected_track) self.player=AudioPlayer(self.show_id,self.root,self.canvas,self.show_params,selected_track,self.pp_dir,self.pp_home,self.pp_profile) self.player.play(track_file, self.showlist, self.end_player, self.page_callback, enable_menu=False) elif track_type=="image": track_file=self.complete_path(selected_track) self.player=ImagePlayer(self.show_id,self.root,self.canvas,self.show_params,selected_track,self.pp_dir,self.pp_home,self.pp_profile) self.player.play(track_file, self.showlist, self.end_player, self.page_callback, enable_menu=False, ) elif track_type=="web": # create a browser track_file=self.complete_path(selected_track) self.player=BrowserPlayer(self.show_id,self.root,self.canvas,self.show_params,selected_track,self.pp_dir,self.pp_home,self.pp_profile) self.player.play(track_file, self.showlist, self.end_player, self.page_callback, enable_menu=False) elif track_type=="message": # bit odd because MessagePlayer is used internally to display text. text=selected_track['text'] self.player=MessagePlayer(self.show_id,self.root,self.canvas,self.show_params,selected_track,self.pp_dir,self.pp_home,self.pp_profile) self.player.play(text, self.showlist, self.end_player, self.page_callback, enable_menu=False ) elif track_type=="show": self.enable_click_areas() # get the show from the showlist index = self.showlist.index_of_show(selected_track['sub-show']) if index >=0: self.showlist.select(index) selected_show=self.showlist.selected_show() else: self.mon.err(self,"Show not found in showlist: "+ selected_track['sub-show']) self.end("Unknown show") if selected_show['type']=="mediashow": self.shower= MediaShow(selected_show, self.root, self.canvas, self.showlist, self.pp_dir, self.pp_home, self.pp_profile) self.shower.play(self.show_id,self.end_shower,self.ready_callback,top=False,command='nil') elif selected_show['type']=="liveshow": self.shower= LiveShow(selected_show, self.root, self.canvas, self.showlist, self.pp_dir, self.pp_home, self.pp_profile) self.shower.play(self.show_id,self.end_shower,self.ready_callback,top=False,command='nil') elif selected_show['type']=="radiobuttonshow": self.shower= RadioButtonShow(selected_show, self.root, self.canvas, self.showlist, self.pp_dir, self.pp_home, self.pp_profile) self.shower.play(self.show_id,self.end_shower,self.ready_callback,top=False,command='nil') elif selected_show['type']=="hyperlinkshow": self.shower= HyperlinkShow(selected_show, self.root, self.canvas, self.showlist, self,pp_dir, self.pp_home, self.pp_profile) self.shower.play(self.show_id,self.end_shower,self.ready_callback,top=False,command='nil') elif selected_show['type']=="menu": self.shower= MenuShow(selected_show, self.root, self.canvas, self.showlist, self.pp_dir, self.pp_home, self.pp_profile) self.shower.play(self.show_id,self.end_shower,self.ready_callback,top=False,command='nil') else: self.mon.err(self,"Unknown Show Type: "+ selected_show['type']) self.end("Unknown show type") else: self.mon.err(self,"Unknown Track Type: "+ track_type) self.end("Unknown track type") # callback from when player ends def end_player(self,reason,message): self.mon.log(self,"Returned from player with message: "+ message) self.player=None # this does not seem to change the colour of the polygon self.canvas.itemconfig('pp-click-area',state='hidden') self.canvas.update_idletasks( ) if reason in("killed","error"): self.end(reason,message) else: self.display_eggtimer(self.resource('hyperlinkshow','m02')) self.what_next() # callback from when shower ends def end_shower(self,show_id,reason,message): self.mon.log(self,"Returned from shower with message: "+ message) self.shower=None self.canvas.itemconfig('pp-click-area',state='hidden') self.canvas.update_idletasks( ) if reason in ("killed","error"): self.end(reason,message) else: self.display_eggtimer(self.resource('hyperlinkshow','m03')) self.what_next() # ********************* # End the show # ********************* # finish the player for killing, error or normally # this may be called directly sub/child shows or players are not running # if they might be running then need to call terminate. def end(self,reason,message): self.mon.log(self,"Ending hyperlinkshow: "+ self.show_params['show-ref']) self.end_callback(self.show_id,reason,message) self=None return # ********************* # displaying things # ********************* def display_eggtimer(self,text): #self.egg_timer=self.canvas.create_text(int(self.canvas['width'])/2, #int(self.canvas['height'])/2, #text= text, # fill='white', # font="Helvetica 20 bold") #self.canvas.update_idletasks( ) pass def delete_eggtimer(self): if self.egg_timer!=None: self.canvas.delete(self.egg_timer) # ********************* # utilities # ********************* def complete_path(self,selected_track): # complete path of the filename of the selected entry track_file = selected_track['location'] if track_file<>'' and track_file[0]=="+": track_file=self.pp_home+track_file[1:] self.mon.log(self,"Track to play is: "+ track_file) return track_file def resource(self,section,item): value=self.rr.get(section,item) if value==False: self.mon.err(self, "resource: "+section +': '+ item + " not found" ) # players or showers may be running so need terminate self.terminate("error") else: return value