Example #1
0
    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
Example #2
0
    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")
Example #3
0
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
Example #4
0
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)
Example #5
0
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()
Example #7
0
    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')
Example #8
0
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")
Example #11
0
    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")
Example #12
0
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
Example #14
0
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     
Example #16
0
    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")            
Example #17
0
    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']
Example #18
0
    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