Example #1
0
class VideoPlayer(GridLayout):
    '''VideoPlayer class. See module documentation for more information.
    '''

    source = StringProperty('')
    '''Source of the video to read.

    :attr:`source` is a :class:`~kivy.properties.StringProperty` and
    defaults to ''.

    .. versionchanged:: 1.4.0
    '''

    thumbnail = StringProperty('')
    '''Thumbnail of the video to show. If None, VideoPlayer will try to find
    the thumbnail from the :attr:`source` + '.png'.

    :attr:`thumbnail` a :class:`~kivy.properties.StringProperty` and defaults
    to ''.

    .. versionchanged:: 1.4.0
    '''

    duration = NumericProperty(-1)
    '''Duration of the video. The duration defaults to -1 and is set to the
    real duration when the video is loaded.

    :attr:`duration` is a :class:`~kivy.properties.NumericProperty` and
    defaults to -1.
    '''

    position = NumericProperty(0)
    '''Position of the video between 0 and :attr:`duration`. The position
    defaults to -1 and is set to the real position when the video is loaded.

    :attr:`position` is a :class:`~kivy.properties.NumericProperty` and
    defaults to -1.
    '''

    volume = NumericProperty(1.0)
    '''Volume of the video in the range 0-1. 1 means full volume and 0 means
    mute.

    :attr:`volume` is a :class:`~kivy.properties.NumericProperty` and defaults
    to 1.
    '''

    state = OptionProperty('stop', options=('play', 'pause', 'stop'))
    '''String, indicates whether to play, pause, or stop the video::

        # start playing the video at creation
        video = VideoPlayer(source='movie.mkv', state='play')

        # create the video, and start later
        video = VideoPlayer(source='movie.mkv')
        # and later
        video.state = 'play'

    :attr:`state` is an :class:`~kivy.properties.OptionProperty` and defaults
    to 'play'.
    '''

    play = BooleanProperty(False)
    '''
    .. deprecated:: 1.4.0
        Use :attr:`state` instead.

    Boolean, indicates whether the video is playing or not. You can start/stop
    the video by setting this property::

        # start playing the video at creation
        video = VideoPlayer(source='movie.mkv', play=True)

        # create the video, and start later
        video = VideoPlayer(source='movie.mkv')
        # and later
        video.play = True

    :attr:`play` is a :class:`~kivy.properties.BooleanProperty` and defaults
    to False.
    '''

    image_overlay_play = StringProperty(
        'atlas://data/images/defaulttheme/player-play-overlay')
    '''Image filename used to show a "play" overlay when the video has not yet
    started.

    :attr:`image_overlay_play` is a
    :class:`~kivy.properties.StringProperty` and
    defaults to 'atlas://data/images/defaulttheme/player-play-overlay'.

    '''

    image_loading = StringProperty('data/images/image-loading.gif')
    '''Image filename used when the video is loading.

    :attr:`image_loading` is a :class:`~kivy.properties.StringProperty` and
    defaults to 'data/images/image-loading.gif'.
    '''

    image_play = StringProperty(
        'atlas://data/images/defaulttheme/media-playback-start')
    '''Image filename used for the "Play" button.

    :attr:`image_play` is a :class:`~kivy.properties.StringProperty` and
    defaults to 'atlas://data/images/defaulttheme/media-playback-start'.
    '''

    image_stop = StringProperty(
        'atlas://data/images/defaulttheme/media-playback-stop')
    '''Image filename used for the "Stop" button.

    :attr:`image_stop` is a :class:`~kivy.properties.StringProperty` and
    defaults to 'atlas://data/images/defaulttheme/media-playback-stop'.
    '''

    image_pause = StringProperty(
        'atlas://data/images/defaulttheme/media-playback-pause')
    '''Image filename used for the "Pause" button.

    :attr:`image_pause` is a :class:`~kivy.properties.StringProperty` and
    defaults to 'atlas://data/images/defaulttheme/media-playback-pause'.
    '''

    image_volumehigh = StringProperty(
        'atlas://data/images/defaulttheme/audio-volume-high')
    '''Image filename used for the volume icon when the volume is high.

    :attr:`image_volumehigh` is a :class:`~kivy.properties.StringProperty` and
    defaults to 'atlas://data/images/defaulttheme/audio-volume-high'.
    '''

    image_volumemedium = StringProperty(
        'atlas://data/images/defaulttheme/audio-volume-medium')
    '''Image filename used for the volume icon when the volume is medium.

    :attr:`image_volumemedium` is a :class:`~kivy.properties.StringProperty`
    and defaults to 'atlas://data/images/defaulttheme/audio-volume-medium'.
    '''

    image_volumelow = StringProperty(
        'atlas://data/images/defaulttheme/audio-volume-low')
    '''Image filename used for the volume icon when the volume is low.

    :attr:`image_volumelow` is a :class:`~kivy.properties.StringProperty`
    and defaults to 'atlas://data/images/defaulttheme/audio-volume-low'.
    '''

    image_volumemuted = StringProperty(
        'atlas://data/images/defaulttheme/audio-volume-muted')
    '''Image filename used for the volume icon when the volume is muted.

    :attr:`image_volumemuted` is a :class:`~kivy.properties.StringProperty`
    and defaults to 'atlas://data/images/defaulttheme/audio-volume-muted'.
    '''

    annotations = StringProperty('')
    '''If set, it will be used for reading annotations box.

    :attr:`annotations` is a :class:`~kivy.properties.StringProperty`
    and defaults to ''.
    '''

    fullscreen = BooleanProperty(False)
    '''Switch to fullscreen view. This should be used with care. When
    activated, the widget will remove itself from its parent, remove all
    children from the window and will add itself to it. When fullscreen is
    unset, all the previous children are restored and the widget is restored to
    its previous parent.

    .. warning::

        The re-add operation doesn't care about the index position of it's
        children within the parent.

    :attr:`fullscreen` is a :class:`~kivy.properties.BooleanProperty`
    and defaults to False.
    '''

    allow_fullscreen = BooleanProperty(True)
    '''By default, you can double-tap on the video to make it fullscreen. Set
    this property to False to prevent this behavior.

    :attr:`allow_fullscreen` is a :class:`~kivy.properties.BooleanProperty`
    defaults to True.
    '''

    options = DictProperty({})
    '''Optional parameters can be passed to a :class:`~kivy.uix.video.Video`
    instance with this property.

    :attr:`options` a :class:`~kivy.properties.DictProperty` and
    defaults to {}.
    '''

    # internals
    container = ObjectProperty(None)

    def __init__(self, **kwargs):
        self._video = None
        self._image = None
        self._annotations = ''
        self._annotations_labels = []
        super(VideoPlayer, self).__init__(**kwargs)
        self._load_thumbnail()
        self._load_annotations()

        if self.source:
            self._trigger_video_load()

    def _trigger_video_load(self, *largs):
        Clock.unschedule(self._do_video_load)
        Clock.schedule_once(self._do_video_load, -1)

    def on_source(self, instance, value):
        # we got a value, try to see if we have an image for it
        self._load_thumbnail()
        self._load_annotations()
        if self._video is not None:
            self._video.unload()
            self._video = None

    def _load_thumbnail(self):
        if not self.container:
            return
        self.container.clear_widgets()
        # get the source, remove extension, and use png
        thumbnail = self.thumbnail
        if not thumbnail:
            filename = self.source.rsplit('.', 1)
            thumbnail = filename[0] + '.png'
        self._image = VideoPlayerPreview(source=thumbnail, video=self)
        self.container.add_widget(self._image)

    def _load_annotations(self):
        if not self.container:
            return
        self._annotations_labels = []
        annotations = self.annotations
        if not annotations:
            filename = self.source.rsplit('.', 1)
            annotations = filename[0] + '.jsa'
        if exists(annotations):
            with open(annotations, 'r') as fd:
                self._annotations = load(fd)
        if self._annotations:
            for ann in self._annotations:
                self._annotations_labels.append(
                    VideoPlayerAnnotation(annotation=ann))

    def on_state(self, instance, value):
        if self._video is not None:
            self._video.state = value

    def _set_state(self, instance, value):
        self.state = value

    def _do_video_load(self, *largs):
        self._video = Video(source=self.source, state=self.state,
                            volume=self.volume, pos_hint={'x': 0, 'y': 0},
                            **self.options)
        self._video.bind(texture=self._play_started,
                         duration=self.setter('duration'),
                         position=self.setter('position'),
                         volume=self.setter('volume'),
                         state=self._set_state)

    def on_play(self, instance, value):
        value = 'play' if value else 'stop'
        return self.on_state(instance, value)

    def on_volume(self, instance, value):
        if not self._video:
            return
        self._video.volume = value

    def on_position(self, instance, value):
        labels = self._annotations_labels
        if not labels:
            return
        for label in labels:
            start = label.start
            duration = label.duration
            if start > value or (start + duration) < value:
                if label.parent:
                    label.parent.remove_widget(label)
            elif label.parent is None:
                self.container.add_widget(label)

    def seek(self, percent):
        '''Change the position to a percentage of the duration. Percentage must
        be a value between 0-1.

        .. warning::

            Calling seek() before video is loaded has no effect.
        '''
        if not self._video:
            return
        self._video.seek(percent)

    def _play_started(self, instance, value):
        self.container.clear_widgets()
        self.container.add_widget(self._video)

    def on_touch_down(self, touch):
        if not self.collide_point(*touch.pos):
            return False
        if touch.is_double_tap and self.allow_fullscreen:
            self.fullscreen = not self.fullscreen
            return True
        return super(VideoPlayer, self).on_touch_down(touch)

    def on_fullscreen(self, instance, value):
        window = self.get_parent_window()
        if not window:
            Logger.warning('VideoPlayer: Cannot switch to fullscreen, '
                           'window not found.')
            if value:
                self.fullscreen = False
            return
        if not self.parent:
            Logger.warning('VideoPlayer: Cannot switch to fullscreen, '
                           'no parent.')
            if value:
                self.fullscreen = False
            return

        if value:
            self._fullscreen_state = state = {
                'parent': self.parent,
                'pos': self.pos,
                'size': self.size,
                'pos_hint': self.pos_hint,
                'size_hint': self.size_hint,
                'window_children': window.children[:]}

            # remove all window children
            for child in window.children[:]:
                window.remove_widget(child)

            # put the video in fullscreen
            if state['parent'] is not window:
                state['parent'].remove_widget(self)
            window.add_widget(self)

            # ensure the video widget is in 0, 0, and the size will be
            # reajusted
            self.pos = (0, 0)
            self.size = (100, 100)
            self.pos_hint = {}
            self.size_hint = (1, 1)
        else:
            state = self._fullscreen_state
            window.remove_widget(self)
            for child in state['window_children']:
                window.add_widget(child)
            self.pos_hint = state['pos_hint']
            self.size_hint = state['size_hint']
            self.pos = state['pos']
            self.size = state['size']
            if state['parent'] is not window:
                state['parent'].add_widget(self)
class VideoPlayer(GridLayout):
    '''VideoPlayer class. See module documentation for more information.
    '''

    source = StringProperty('')
    '''Source of the video to read.

    :attr:`source` is a :class:`~kivy.properties.StringProperty` and
    defaults to ''.

    .. versionchanged:: 1.4.0
    '''

    thumbnail = StringProperty('')
    '''Thumbnail of the video to show. If None, VideoPlayer will try to find
    the thumbnail from the :attr:`source` + '.png'.

    :attr:`thumbnail` a :class:`~kivy.properties.StringProperty` and defaults
    to ''.

    .. versionchanged:: 1.4.0
    '''

    duration = NumericProperty(-1)
    '''Duration of the video. The duration defaults to -1 and is set to the
    real duration when the video is loaded.

    :attr:`duration` is a :class:`~kivy.properties.NumericProperty` and
    defaults to -1.
    '''

    position = NumericProperty(0)
    '''Position of the video between 0 and :attr:`duration`. The position
    defaults to -1 and is set to the real position when the video is loaded.

    :attr:`position` is a :class:`~kivy.properties.NumericProperty` and
    defaults to -1.
    '''

    volume = NumericProperty(1.0)
    '''Volume of the video in the range 0-1. 1 means full volume and 0 means
    mute.

    :attr:`volume` is a :class:`~kivy.properties.NumericProperty` and defaults
    to 1.
    '''

    state = OptionProperty('stop', options=('play', 'pause', 'stop'))
    '''String, indicates whether to play, pause, or stop the video::

        # start playing the video at creation
        video = VideoPlayer(source='movie.mkv', state='play')

        # create the video, and start later
        video = VideoPlayer(source='movie.mkv')
        # and later
        video.state = 'play'

    :attr:`state` is an :class:`~kivy.properties.OptionProperty` and defaults
    to 'stop'.
    '''

    play = BooleanProperty(False, deprecated=True)
    '''
    .. deprecated:: 1.4.0
        Use :attr:`state` instead.

    Boolean, indicates whether the video is playing or not. You can start/stop
    the video by setting this property::

        # start playing the video at creation
        video = VideoPlayer(source='movie.mkv', play=True)

        # create the video, and start later
        video = VideoPlayer(source='movie.mkv')
        # and later
        video.play = True

    :attr:`play` is a :class:`~kivy.properties.BooleanProperty` and defaults
    to False.
    '''

    image_overlay_play = StringProperty(
        'atlas://data/images/defaulttheme/player-play-overlay')
    '''Image filename used to show a "play" overlay when the video has not yet
    started.

    :attr:`image_overlay_play` is a
    :class:`~kivy.properties.StringProperty` and
    defaults to 'atlas://data/images/defaulttheme/player-play-overlay'.

    '''

    image_loading = StringProperty('data/images/image-loading.gif')
    '''Image filename used when the video is loading.

    :attr:`image_loading` is a :class:`~kivy.properties.StringProperty` and
    defaults to 'data/images/image-loading.gif'.
    '''

    image_play = StringProperty(
        'atlas://data/images/defaulttheme/media-playback-start')
    '''Image filename used for the "Play" button.

    :attr:`image_play` is a :class:`~kivy.properties.StringProperty` and
    defaults to 'atlas://data/images/defaulttheme/media-playback-start'.
    '''

    image_stop = StringProperty(
        'atlas://data/images/defaulttheme/media-playback-stop')
    '''Image filename used for the "Stop" button.

    :attr:`image_stop` is a :class:`~kivy.properties.StringProperty` and
    defaults to 'atlas://data/images/defaulttheme/media-playback-stop'.
    '''

    image_pause = StringProperty(
        'atlas://data/images/defaulttheme/media-playback-pause')
    '''Image filename used for the "Pause" button.

    :attr:`image_pause` is a :class:`~kivy.properties.StringProperty` and
    defaults to 'atlas://data/images/defaulttheme/media-playback-pause'.
    '''

    image_volumehigh = StringProperty(
        'atlas://data/images/defaulttheme/audio-volume-high')
    '''Image filename used for the volume icon when the volume is high.

    :attr:`image_volumehigh` is a :class:`~kivy.properties.StringProperty` and
    defaults to 'atlas://data/images/defaulttheme/audio-volume-high'.
    '''

    image_volumemedium = StringProperty(
        'atlas://data/images/defaulttheme/audio-volume-medium')
    '''Image filename used for the volume icon when the volume is medium.

    :attr:`image_volumemedium` is a :class:`~kivy.properties.StringProperty`
    and defaults to 'atlas://data/images/defaulttheme/audio-volume-medium'.
    '''

    image_volumelow = StringProperty(
        'atlas://data/images/defaulttheme/audio-volume-low')
    '''Image filename used for the volume icon when the volume is low.

    :attr:`image_volumelow` is a :class:`~kivy.properties.StringProperty`
    and defaults to 'atlas://data/images/defaulttheme/audio-volume-low'.
    '''

    image_volumemuted = StringProperty(
        'atlas://data/images/defaulttheme/audio-volume-muted')
    '''Image filename used for the volume icon when the volume is muted.

    :attr:`image_volumemuted` is a :class:`~kivy.properties.StringProperty`
    and defaults to 'atlas://data/images/defaulttheme/audio-volume-muted'.
    '''

    annotations = StringProperty('')
    '''If set, it will be used for reading annotations box.

    :attr:`annotations` is a :class:`~kivy.properties.StringProperty`
    and defaults to ''.
    '''

    fullscreen = BooleanProperty(False)
    '''Switch to fullscreen view. This should be used with care. When
    activated, the widget will remove itself from its parent, remove all
    children from the window and will add itself to it. When fullscreen is
    unset, all the previous children are restored and the widget is restored to
    its previous parent.

    .. warning::

        The re-add operation doesn't care about the index position of its
        children within the parent.

    :attr:`fullscreen` is a :class:`~kivy.properties.BooleanProperty`
    and defaults to False.
    '''

    allow_fullscreen = BooleanProperty(True)
    '''By default, you can double-tap on the video to make it fullscreen. Set
    this property to False to prevent this behavior.

    :attr:`allow_fullscreen` is a :class:`~kivy.properties.BooleanProperty`
    defaults to True.
    '''

    options = DictProperty({})
    '''Optional parameters can be passed to a :class:`~kivy.uix.video.Video`
    instance with this property.

    :attr:`options` a :class:`~kivy.properties.DictProperty` and
    defaults to {}.
    '''

    # internals
    container = ObjectProperty(None)

    _video_load_ev = None

    def __init__(self, **kwargs):
        self._video = None
        self._image = None
        self._annotations = ''
        self._annotations_labels = []
        super(VideoPlayer, self).__init__(**kwargs)
        self._load_thumbnail()
        self._load_annotations()

        if self.source:
            self._trigger_video_load()

    def _trigger_video_load(self, *largs):
        ev = self._video_load_ev
        if ev is None:
            ev = self._video_load_ev = Clock.schedule_once(
                self._do_video_load, -1)
        ev()

    def on_source(self, instance, value):
        # we got a value, try to see if we have an image for it
        self._load_thumbnail()
        self._load_annotations()
        if self._video is not None:
            self._video.unload()
            self._video = None
        if value:
            self._trigger_video_load()

    def on_image_overlay_play(self, instance, value):
        self._image.image_overlay_play = value

    def on_image_loading(self, instance, value):
        self._image.image_loading = value

    def _load_thumbnail(self):
        if not self.container:
            return
        self.container.clear_widgets()
        # get the source, remove extension, and use png
        thumbnail = self.thumbnail
        if not thumbnail:
            filename = self.source.rsplit('.', 1)
            thumbnail = filename[0] + '.png'
            if not exists(thumbnail):
                thumbnail = ''
        self._image = VideoPlayerPreview(source=thumbnail, video=self)
        self.container.add_widget(self._image)

    def _load_annotations(self):
        if not self.container:
            return
        self._annotations_labels = []
        annotations = self.annotations
        if not annotations:
            filename = self.source.rsplit('.', 1)
            annotations = filename[0] + '.jsa'
        if exists(annotations):
            with open(annotations, 'r') as fd:
                self._annotations = load(fd)
        if self._annotations:
            for ann in self._annotations:
                self._annotations_labels.append(
                    VideoPlayerAnnotation(annotation=ann))

    def on_state(self, instance, value):
        if self._video is not None:
            self._video.state = value

    def _set_state(self, instance, value):
        self.state = value

    def _do_video_load(self, *largs):
        self._video = Video(source=self.source,
                            state=self.state,
                            volume=self.volume,
                            pos_hint={
                                'x': 0,
                                'y': 0
                            },
                            **self.options)
        self._video.bind(texture=self._play_started,
                         duration=self.setter('duration'),
                         position=self.setter('position'),
                         volume=self.setter('volume'),
                         state=self._set_state)

    def on_play(self, instance, value):
        value = 'play' if value else 'stop'
        return self.on_state(instance, value)

    def on_volume(self, instance, value):
        if not self._video:
            return
        self._video.volume = value

    def on_position(self, instance, value):
        labels = self._annotations_labels
        if not labels:
            return
        for label in labels:
            start = label.start
            duration = label.duration
            if start > value or (start + duration) < value:
                if label.parent:
                    label.parent.remove_widget(label)
            elif label.parent is None:
                self.container.add_widget(label)

    def seek(self, percent, precise=True):
        '''Change the position to a percentage of duration.

        :Parameters:
            `percent`: float or int
                Position to seek, must be between 0-1.
            `precise`: bool, defaults to True
                Precise seeking is slower, but seeks to exact requested
                percent.

        .. warning::
            Calling seek() before the video is loaded has no effect.

        .. versionadded:: 1.2.0

        .. versionchanged:: 1.10.1
            The `precise` keyword argument has been added.
        '''
        if not self._video:
            return
        self._video.seek(percent, precise=precise)

    def _play_started(self, instance, value):
        self.container.clear_widgets()
        self.container.add_widget(self._video)

    def on_touch_down(self, touch):
        if not self.collide_point(*touch.pos):
            return False
        if touch.is_double_tap and self.allow_fullscreen:
            self.fullscreen = not self.fullscreen
            return True
        return super(VideoPlayer, self).on_touch_down(touch)

    def on_fullscreen(self, instance, value):
        window = self.get_parent_window()
        if not window:
            Logger.warning('VideoPlayer: Cannot switch to fullscreen, '
                           'window not found.')
            if value:
                self.fullscreen = False
            return
        if not self.parent:
            Logger.warning('VideoPlayer: Cannot switch to fullscreen, '
                           'no parent.')
            if value:
                self.fullscreen = False
            return

        if value:
            self._fullscreen_state = state = {
                'parent': self.parent,
                'pos': self.pos,
                'size': self.size,
                'pos_hint': self.pos_hint,
                'size_hint': self.size_hint,
                'window_children': window.children[:]
            }

            # remove all window children
            for child in window.children[:]:
                window.remove_widget(child)

            # put the video in fullscreen
            if state['parent'] is not window:
                state['parent'].remove_widget(self)
            window.add_widget(self)

            # ensure the video widget is in 0, 0, and the size will be
            # readjusted
            self.pos = (0, 0)
            self.size = (100, 100)
            self.pos_hint = {}
            self.size_hint = (1, 1)
        else:
            state = self._fullscreen_state
            window.remove_widget(self)
            for child in state['window_children']:
                window.add_widget(child)
            self.pos_hint = state['pos_hint']
            self.size_hint = state['size_hint']
            self.pos = state['pos']
            self.size = state['size']
            if state['parent'] is not window:
                state['parent'].add_widget(self)
Example #3
0
class LitePlayer(App):
    video = None
    _wink_sdk_ver = ''

    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self._wink_index = WinkParams('https://wink.rt.ru/', COOKIE)
        self._wink_tv = WinkParams('https://wink.rt.ru/tv', COOKIE)
        self._wink_client = WincClientConnection(params=self._wink_index,
                                                 tv=self._wink_tv)
        self._playlist = self._wink_client.get_tv_playlist()
        self._current_ch = 0

    def build(self):
        Window.bind(on_keyboard=self.on_keyboard)  # bind our handler
        self._list_channels = self._wink_client.get_list_channels()
        ch_url, err = self._wink_client.get_channel_url(
            str(self._list_channels[self._current_ch]
                ['nc_channel_id']))  #self._wink_client._fairplay_cert_url)
        #url_key_1 = 'https://s40757.cdn.ngenix.net/certificates/8BA6D7AC942DE15E1B375DEF7FA20918757A6533'
        #self._wink_client.load_cert_ott(url_key_1)

        self.video = Video(source=ch_url)
        self.video.state = 'play'
        self.video.options = {'eos': 'loop'}
        self.video.allow_stretch = True
        #self.video.pos_hint = {'top': 1.0}
        self._grid_1 = GridLayout(cols=2,
                                  row_force_default=True,
                                  row_default_height=40)
        self._grid_menu = GridLayout(cols=8)
        self._grid_channels = GridLayout(cols=3)

        self.video.add_widget(self._grid_1)
        self.l = Label(text='Hello world',
                       font_size='20sp',
                       size_hint=(1, 0.17))
        #self.l.pos(
        print(self.l.pos)
        self.img1 = AsyncImage(source=self._wink_tv.__IMAGES_URL__ +
                               '/sdp/nc-snapshot1569398092010.jpg',
                               pos_hint={
                                   'x': 0.0,
                                   'y': 0.8
                               })
        self.video.add_widget(self._grid_menu)
        self.video.add_widget(self.img1)
        self.video.add_widget(self.l)
        self._grid_1.add_widget(self._grid_channels)
        self.l_ch = []
        for i in range(5):
            lab1 = Label(text=self._list_channels[i]['name'], font_size='20sp')
            self._grid_channels.add_widget(lab1)
            self.l_ch += [lab1]

        print(Window.size)
        return self.video

    def VideoDone(self, value, value2):
        print("video done", value, value2)

    def _get_utc(self):
        return round(
            (datetime.datetime.now() -
             datetime.datetime(1970, 1, 1)).total_seconds() * 1000) + 338055300

    def get_drm_parse(self):
        root = xmltodict.parse(self._drm_xml)
        _mpd = root['MPD']
        print(_mpd)
        self._baseurl_drm = self._url_drm
        for adaptation_set in _mpd['Period']['AdaptationSet']:
            shab = adaptation_set['SegmentTemplate']
            #print (shab)
            self._drm_shablon = shab['@media']
            for key in adaptation_set['Representation']:
                for inkey in key:
                    if inkey == '@height' and key[inkey] == '1080':
                        self._video_1080 = key['@id']
                    if inkey == '@bandwidth' and key[inkey] == '500000':
                        self._audio_1080 = key['@id']
        _tmp_url = self._baseurl_drm.replace('/manifest.mpd?profile=web_auto',
                                             '/')
        _tmp_utc_str = str(self._get_utc())
        _tmp_url_video = ''.join([
            _tmp_url,
            self._drm_shablon.replace('$RepresentationID$',
                                      self._video_1080).replace(
                                          '$Time$', _tmp_utc_str)
        ])
        print(_tmp_url_video)
        _tmp_url_audio = ''.join([
            _tmp_url,
            self._drm_shablon.replace('$RepresentationID$',
                                      self._audio_1080).replace(
                                          '$Time$', _tmp_utc_str)
        ])

        print(_tmp_url_audio)

    def on_stop(self):
        # The Kivy event loop is about to stop, set a stop signal;
        # otherwise the app window will close, but the Python process will
        # keep running until all secondary threads exit.
        print('stopping and closing kivy')
        #self.video.state='stop'

    def on_keyboard(self, window, key, scancode, codepoint, modifier):
        print(window, key, scancode, codepoint, modifier)
        if key == 13:
            pass
        elif codepoint == 'p':
            print('pausing with p pressed')
            self.video.state = 'stop'
        elif codepoint == 's':
            print('starting with s pressed')
            self.video.state = 'play'
        elif codepoint == 'r':
            #self.video.source=self._wink_client.get_channel_url('5')
            self.video.state = 'play'
            print('re-starting with r pressed')
            self.video.seek(0, precise=True)
        if key == 280:
            self._current_ch += 1
            if self._current_ch > (len(self._list_channels) - 1):
                self._current_ch = 0
            ch_url, err = self._wink_client.get_channel_url(
                str(self._list_channels[self._current_ch]['nc_channel_id']))
            if not err:
                self.img1.source = self._wink_tv.__IMAGES_URL__ + self._wink_client._current_channel[
                    'logo']
                self.img1.reload()
                self.video.source = ch_url
                self.video.state = 'play'
                print('re-starting with r pressed')
                #self.video.seek(0, precise=True)
            self.l.text = self._wink_client._current_channel['description']
        if key == 281:
            self._current_ch -= 1
            if self._current_ch < 0:
                self._current_ch = len(self._list_channels) - 1
            ch_url, err = self._wink_client.get_channel_url(
                str(self._list_channels[self._current_ch]['nc_channel_id']))
            if not err:
                self.img1.source = self._wink_tv.__IMAGES_URL__ + self._wink_client._current_channel[
                    'logo']
                self.img1.reload()
                self.video.source = ch_url
                self.video.state = 'play'
                print('re-starting with r pressed')
                #self.video.seek(0, precise=True)
            self.l.text = self._wink_client._current_channel['description']
        else:
            print(key)
Example #4
0
class VideoPlayer(GridLayout):
    '''VideoPlayer class, see module documentation for more information.
    '''

    source = StringProperty(None)
    '''Source of the video to read

    :data:`source` a :class:`~kivy.properties.StringProperty`, default to None.
    '''

    thumbnail = StringProperty(None)
    '''Thumbnail of the video to show. If None, it will try to search the
    thumbnail from the :data:`source` + .png.

    :data:`thumbnail` a :class:`~kivy.properties.StringProperty`, default to
    None.
    '''

    duration = NumericProperty(-1)
    '''Duration of the video. The duration is default to -1, and set to real
    duration when the video is loaded.

    :data:`duration` is a :class:`~kivy.properties.NumericProperty`, default to
    -1.
    '''

    position = NumericProperty(0)
    '''Position of the video between 0 and :data:`duration`. The position is
    default to -1, and set to real position when the video is loaded.

    :data:`position` is a :class:`~kivy.properties.NumericProperty`, default to
    -1.
    '''

    volume = NumericProperty(1.0)
    '''Volume of the video, in the range 0-1. 1 mean full volume, 0 mean mute.

    :data:`volume` is a :class:`~kivy.properties.NumericProperty`, default to
    1.
    '''

    play = BooleanProperty(False)
    '''Boolean, indicates if the video is playing.
    You can start/stop the video by setting this property. ::

        # start playing the video at creation
        video = VideoPlayer(source='movie.mkv', play=True)

        # create the video, and start later
        video = VideoPlayer(source='movie.mkv')
        # and later
        video.play = True

    :data:`play` is a :class:`~kivy.properties.BooleanProperty`, default to
    False.
    '''

    image_overlay_play = StringProperty(
        'atlas://data/images/defaulttheme/player-play-overlay')
    '''Image filename used to show an "play" overlay when the video is not yet
    started.

    :data:`image_overlay_play` a :class:`~kivy.properties.StringProperty`
    '''

    image_loading = StringProperty('data/images/image-loading.gif')
    '''Image filename used when the video is loading.

    :data:`image_loading` a :class:`~kivy.properties.StringProperty`
    '''

    image_play = StringProperty(
        'atlas://data/images/defaulttheme/media-playback-start')
    '''Image filename used for the "Play" button.

    :data:`image_loading` a :class:`~kivy.properties.StringProperty`
    '''

    image_pause = StringProperty(
        'atlas://data/images/defaulttheme/media-playback-pause')
    '''Image filename used for the "Pause" button.

    :data:`image_pause` a :class:`~kivy.properties.StringProperty`
    '''

    image_volumehigh = StringProperty(
        'atlas://data/images/defaulttheme/audio-volume-high')
    '''Image filename used for the volume icon, when the volume is high.

    :data:`image_volumehigh` a :class:`~kivy.properties.StringProperty`
    '''

    image_volumemedium = StringProperty(
        'atlas://data/images/defaulttheme/audio-volume-medium')
    '''Image filename used for the volume icon, when the volume is medium.

    :data:`image_volumemedium` a :class:`~kivy.properties.StringProperty`
    '''

    image_volumelow = StringProperty(
        'atlas://data/images/defaulttheme/audio-volume-low')
    '''Image filename used for the volume icon, when the volume is low.

    :data:`image_volumelow` a :class:`~kivy.properties.StringProperty`
    '''

    image_volumemuted = StringProperty(
        'atlas://data/images/defaulttheme/audio-volume-muted')
    '''Image filename used for the volume icon, when the volume is muted.

    :data:`image_volumemuted` a :class:`~kivy.properties.StringProperty`
    '''

    annotations = StringProperty(None)
    '''If set, it will be used for reading annotations box.
    '''

    fullscreen = BooleanProperty(False)
    '''Switch to a fullscreen view. This must be used with care. When activated,
    the widget will remove itself from its parent, remove all children from the
    window and add itself to it. When fullscreen is unset, all the previous
    children are restored, and the widget is readded to its previous parent.

    .. warning::

        The re-add operation doesn't care about it's children index position
        within the parent.

    :data:`fullscreen` a :class:`~kivy.properties.BooleanProperty`, default to
    False
    '''

    allow_fullscreen = BooleanProperty(True)
    '''By default, you can double-tap on the video to make it fullscreen. Set
    this property to False to prevent this behavior.

    :data:`allow_fullscreen` a :class:`~kivy.properties.BooleanProperty`,
    default to True
    '''

    options = DictProperty({})
    '''Optionals parameters can be passed to :class:`~kivy.uix.video.Video`
    instance with this property.

    :data:`options` a :class:`~kivy.properties.DictProperty`,
    default to {}
    '''

    # internals
    container = ObjectProperty(None)

    def __init__(self, **kwargs):
        self._video = None
        self._image = None
        self._annotations = None
        self._annotations_labels = []
        super(VideoPlayer, self).__init__(**kwargs)
        self._load_thumbnail()
        self._load_annotations()

    def on_source(self, instance, value):
        # we got a value, try to see if we have an image for it
        self._load_thumbnail()
        self._load_annotations()

    def _load_thumbnail(self):
        if not self.container:
            return
        self.container.clear_widgets()
        # get the source, remove extension, and use png
        thumbnail = self.thumbnail
        if thumbnail is None:
            filename = self.source.rsplit('.', 1)
            thumbnail = filename[0] + '.png'
        self._image = VideoPlayerPreview(source=thumbnail, video=self)
        self.container.add_widget(self._image)

    def _load_annotations(self):
        if not self.container:
            return
        self._annotations_labels = []
        annotations = self.annotations
        if annotations is None:
            filename = self.source.rsplit('.', 1)
            annotations = filename[0] + '.jsa'
        if exists(annotations):
            with open(annotations, 'r') as fd:
                self._annotations = load(fd)
        if self._annotations:
            for ann in self._annotations:
                self._annotations_labels.append(
                    VideoPlayerAnnotation(annotation=ann))

    def on_play(self, instance, value):
        if self._video is None:
            self._video = Video(source=self.source,
                                play=True,
                                volume=self.volume,
                                pos_hint={
                                    'x': 0,
                                    'y': 0
                                },
                                **self.options)
            self._video.bind(texture=self._play_started,
                             duration=self.setter('duration'),
                             position=self.setter('position'),
                             volume=self.setter('volume'))
        self._video.play = value

    def on_volume(self, instance, value):
        if not self._video:
            return
        self._video.volume = value

    def on_position(self, instance, value):
        labels = self._annotations_labels
        if not labels:
            return
        for label in labels:
            start = label.start
            duration = label.duration
            if start > value or (start + duration) < value:
                if label.parent:
                    label.parent.remove_widget(label)
            elif label.parent is None:
                self.container.add_widget(label)

    def seek(self, percent):
        '''Change the position to a percentage of duration. Percentage must be a
        value between 0-1.

        .. warning::

            Calling seek() before video is loaded have no impact.
        '''
        if not self._video:
            return
        self._video.seek(percent)

    def _play_started(self, instance, value):
        self.container.clear_widgets()
        self.container.add_widget(self._video)

    def on_touch_down(self, touch):
        if not self.collide_point(*touch.pos):
            return False
        if touch.is_double_tap and self.allow_fullscreen:
            self.fullscreen = not self.fullscreen
            return True
        return super(VideoPlayer, self).on_touch_down(touch)

    def on_fullscreen(self, instance, value):
        window = self.get_parent_window()
        if not window:
            Logger.warning('VideoPlayer: Cannot switch to fullscreen, '
                           'window not found.')
            if value:
                self.fullscreen = False
            return
        if not self.parent:
            Logger.warning('VideoPlayer: Cannot switch to fullscreen, '
                           'no parent.')
            if value:
                self.fullscreen = False
            return

        if value:
            self._fullscreen_state = state = {
                'parent': self.parent,
                'pos': self.pos,
                'size': self.size,
                'pos_hint': self.pos_hint,
                'size_hint': self.size_hint,
                'window_children': window.children[:]
            }

            # remove all window children
            for child in window.children[:]:
                window.remove_widget(child)

            # put the video in fullscreen
            if state['parent'] is not window:
                state['parent'].remove_widget(self)
            window.add_widget(self)

            # ensure the video widget is in 0, 0, and the size will be reajusted
            self.pos = (0, 0)
            self.size = (100, 100)
            self.pos_hint = {}
            self.size_hint = (1, 1)
        else:
            state = self._fullscreen_state
            window.remove_widget(self)
            for child in state['window_children']:
                window.add_widget(child)
            self.pos_hint = state['pos_hint']
            self.size_hint = state['size_hint']
            self.pos = state['pos']
            self.size = state['size']
            if state['parent'] is not window:
                state['parent'].add_widget(self)
class TestApp(App):
    def build(self):

        # open config.ini to access the user's settings

        self.config = configparser.ConfigParser()
        self.config.read(os.environ['HOME'] + "/.config_showoff.ini")

        # ******************* DECIDE WINDOW SIZE *******************
        # in fullscreen is enable go full screen; otherwise use width and height provided
        if ConfigStuff.get_config_video_fullscreen(self.config):
            Window.fullscreen = "auto"
        else:
            # set the width and height from config.ini
            Window.size = (
            ConfigStuff.get_config_video_width(self.config), ConfigStuff.get_config_video_height(self.config))

        # ******************* DECIDE WHAT VIDEO IS PLAYED *******************
        # set the directory where the videos will be taken from
        self.video_directory = ConfigStuff.get_config_video_directory(self.config)

        # get the list of video files found
        self.video_list = PlaylistFromDir.create_playlist(self.video_directory)
        # the number of the file form video_list currently played
        self.curr_video_iterator = -1

        # todo: [ERROR  ] [Image       ] Error loading texture , try to deal with it at some point
        self.video1 = Video(source="./1_Second_of_Blank.mp4", state="play", volume=0)
        self.video1.fullscreen = True
        self.video1.allow_stretch = True
        self.video1.image_loading = "./GUI/loading.png"

        self.video1.pos_hint = {"center_x": .5, "center_y": .5}
        # when the video reaches its end, on_eos is called (eos= end of stream)
        self.video1.bind(position=self.on_position_change, eos=self.on_eos)

        # ******************* DEAL UI STUFF *******************
        self.label_help = Label(
            text="Approach your hand to control the Billboard. Hover over a button for 2s to activate it.",
            color=(1, 0, 0, 1))
        self.label_help.pos_hint = {"center_x": .5, "center_y": 0.98}

        self.button_loop = Button(text="Reset", background_normal="./GUI/loop.png", border=(0, 0, 0, 0),
                                  size_hint=(.2, .2), color=(1, 0, 0, 1))
        self.button_loop.pos_hint = {"center_x": 0.85, "center_y": 0.2}
        self.button_loop.opacity = 0.5
        self.button_loop.bind(on_press=self.callback_button_loop)

        self.button_next = Button(text="NEXT", background_normal="./GUI/arrow_next.png", border=(0, 0, 0, 0),
                                  size_hint=(.2, .2), color=(1, 0, 0, 1))
        self.button_next.pos_hint = {"center_x": 0.85, "center_y": 0.5}
        self.button_next.opacity = 0.5
        self.button_next.bind(on_press=self.callback_button_next)

        self.button_previous = Button(text="PREVIOUS", background_normal="./GUI/arrow_previous.png",
                                      border=(0, 0, 0, 0), size_hint=(.2, .2), color=(1, 0, 0, 1))
        self.button_previous.pos_hint = {"center_x": 0.15, "center_y": 0.5}
        self.button_previous.opacity = 0.5
        self.button_previous.bind(on_press=self.callback_button_previous)

        self.button_next_ppt = Button(text="NEXT SLIDE", background_normal="./GUI/arrow_next_2.png",
                                      border=(0, 0, 0, 0), size_hint=(.2, .2), color=(1, 0, 0, 1))
        self.button_next_ppt.pos_hint = {"center_x": 0.85, "center_y": 0.7}
        self.button_next_ppt.opacity = 0.5
        self.button_next_ppt.bind(on_press=self.callback_button_next_ppt)

        self.button_previous_ppt = Button(text="PREVIOUS SLIDE", background_normal="./GUI/arrow_previous_2.png",
                                          border=(0, 0, 0, 0), size_hint=(.2, .2), color=(1, 0, 0, 1))
        self.button_previous_ppt.pos_hint = {"center_x": 0.15, "center_y": 0.7}
        self.button_previous_ppt.opacity = 0.5
        self.button_previous_ppt.bind(on_press=self.callback_button_previous_ppt)

        self.label_help_ppt = Label(text="The power point will pause if you approach your hand", color=(1, 0, 0, 1))
        self.label_help_ppt.pos_hint = {"center_x": .5, "center_y": 0.02}

        # ******************* DEAL WITH LAYOUT *******************
        self.root = FloatLayout(size=Window.size)
        self.root_video = FloatLayout(size=Window.size)
        self.root_UI = FloatLayout(size=Window.size)
        self.root_UI.opacity=0.8

        if ConfigStuff.get_config_kinect_enable(self.config):
            self.faceAndEmotionAnalyser = apiFaceAndEmotion.apiFaceDetectAndClassifier()
            self.handTracking = HandTracking.MyHandTrackingApp()
            self.handTracking.pos_hint = {"center_x": .5, "center_y": .5}
            self.root_UI.add_widget(self.label_help)

        self.root_video.add_widget(self.video1)

        self.root.add_widget(self.root_video)
        self.root.add_widget(self.root_UI)

        # ******************* VIDEO MANAGEMENT ATTRIBUTES *******************
        self.playlist_management_event = None
        # ******************* PPT MANAGEMENT ATTRIBUTES *******************
        self.list_of_correct_extension_image = (".jpg", ".png")
        self.delay_image = ConfigStuff.get_config_image_delay(self.config)
        self.playing_ppt = False
        self.bool_ppt_UI_shown = False
        self.next_slide = False
        self.previous_slide = False
        self.bool_show_UI = False
        self.event_ppt = None  # used to cancel several power point management at the same time
        self.iterator_check_if_click = 0
        self.time_limit_beetween_clicks = 2  # in seconds

        # ******************* USER MANAGEMENT ATTRIBUTES *******************
        self.seen_users = set()
        self.current_people = None
        self.smart_video_choice = ConfigStuff.get_config_smart_video_enable(
            self.config) and ConfigStuff.get_config_kinect_enable(self.config)

        # ******************* CALL LOOPS *******************
        Clock.schedule_interval(self.check_mouse_position, 1)
        Clock.schedule_interval(self.hide_mouse_if_unmoved, 10)
        return self.root

    def callback_button_loop(self, instance):
        print("button loop")
        if(self.video1.source.endswith(self.list_of_correct_extension_image)):
            filename, file_extension = os.path.splitext(self.video1.source)
            # extract image number
            number_old = re.search('(\d+)$', filename).group(0)
            number_new = 1
            # replace the current image number to the next one
            filename = re.sub(str(number_old) + "$", str(number_new), filename)
            self.video1.source = filename + file_extension
            self.video1.reload()
            self.set_ppt_event(Clock.schedule_once(self.play_next_image, self.delay_image))
        else:
            self.video1.seek(0)

    def callback_button_next(self, instance):
        print("from button next")
        self.set_playlist_management_event(Clock.schedule_once(partial(self.playlist_management_next), 0))

    def callback_button_previous(self, instance):
        print("from button previous")
        self.set_playlist_management_event(Clock.schedule_once(partial(self.playlist_management_previous), 0))

    def callback_button_next_ppt(self, instance):
        self.next_slide = True
        self.set_ppt_event(Clock.schedule_once(self.play_next_image, 0))

    def callback_button_previous_ppt(self, instance):
        self.previous_slide = True
        self.set_ppt_event(Clock.schedule_once(self.play_next_image, 0))

    def check_users(self):
        self.current_people = self.faceAndEmotionAnalyser.check_who_it_is()
        for name in self.current_people:
            if name not in self.seen_users:
                self.seen_users.add(name)
                self.show_greetings("Hi " + name, 400, (1, 0, 0, 1))
        self.faceAndEmotionAnalyser.quitAndSave()
        self.faceAndEmotionAnalyser = apiFaceAndEmotion.apiFaceDetectAndClassifier()

    def check_users_watching_habits(self):
        # sort the list in accordance to what they have seen
        # print("Before:", self.video_list)
        list_video_with_score = []
        for video in self.video_list:
            list_video_with_score.append([video, 0])
        # print("Before 0:", list_video_with_score)
        # for all the people in front
        for person in self.current_people:
            parser = configparser.ConfigParser()
            parser.read("./pics/" + person + '.ini')
            # for all the videos found
            for i in range(len(self.video_list)):
                # if the video has been seen
                if parser.has_option("WATCHING_HABITS", self.video_list[i]):
                    # add a score base on how many time it was seen, and when was the last time
                    # todo: maybe think of a better formula
                    list_video_with_score[i] = (list_video_with_score[i][0],
                                                list_video_with_score[i][1] + parser.getint("WATCHING_HABITS",
                                                                                            self.video_list[i]) / (
                                                time.time() - parser.getfloat("WATCHING_HABITS_TIME_TICKS",
                                                                              self.video_list[i])))

                    # for all the video
                    # sort based on their score
        # print("Before1:", list_video_with_score)
        list_video_with_score = sorted(list_video_with_score, key=lambda score: score[1])  # sort by score
        # print("After 1:", list_video_with_score)
        # put the previously shown video at the end
        index = -1
        for i in range(len(list_video_with_score)):
            if (list_video_with_score[i][0] == self.video1.source):
                index = i
                break
        if (index != -1):
            list_video_with_score.append(list_video_with_score.pop(index))
        self.video_list = []
        for video in list_video_with_score:
            self.video_list.append(video[0])
            # print("After 2:", self.video_list)

    def update_users_watching_habits(self):
        if (not self.video1.source == "./1_second_of_blank.mp4"):
            # for all the people in front
            for person in self.current_people:
                parser = configparser.ConfigParser()
                parser.read("./pics/" + person + '.ini')
                # if the person has already seen the video
                if (parser.has_section("WATCHING_HABITS")):
                    try:
                        parser.set("WATCHING_HABITS", self.video1.source,
                                   str(parser.getint("WATCHING_HABITS", self.video1.source) + 1))

                    except:
                        parser.set("WATCHING_HABITS", self.video1.source, str(1))
                    # set it to the current time
                    parser.set("WATCHING_HABITS_TIME_TICKS", self.video1.source, str(time.time()))
                    parser.set("WATCHING_HABITS_TIME_DATE", self.video1.source,
                               str(time.asctime(time.localtime(time.time()))))

                else:
                    # create the section
                    parser.add_section("WATCHING_HABITS")
                    parser.add_section("WATCHING_HABITS_TIME_TICKS")
                    parser.add_section("WATCHING_HABITS_TIME_DATE")
                    parser.set("WATCHING_HABITS", self.video1.source, str(1))
                    # set it to the current time
                    parser.set("WATCHING_HABITS_TIME_TICKS", self.video1.source, str(time.time()))
                    parser.set("WATCHING_HABITS_TIME_DATE", self.video1.source,
                               str(time.asctime(time.localtime(time.time()))))
                # print("writing in:",person+'.ini' )
                with open("./pics/" + person + '.ini', "w") as config_file:
                    parser.write(config_file)

    # decide which video is played next
    def playlist_management_next(self, dt=None):
        if (self.playing_ppt or self.video1.source.endswith(self.list_of_correct_extension_image)):
            self.root_UI.remove_widget(self.label_help_ppt)
            if (self.bool_show_UI):
                self.root_UI.remove_widget(self.button_next_ppt)
                self.root_UI.remove_widget(self.button_previous_ppt)
                self.bool_ppt_UI_shown = False
            self.playing_ppt = False

            filename, file_extension = os.path.splitext(self.video1.source)
            # extract image number
            number_old = re.search('(\d+)$', filename).group(0)
            number_new = 1
            # replace the current image number to the next one
            filename = re.sub(str(number_old) + "$", str(number_new), filename)
            self.video1.source = filename + file_extension
            # print("new:", self.video1.source)

        self.video1.state = 'pause'
        self.video_list = PlaylistFromDir.create_playlist(self.video_directory)

        if not self.video_list:
            print("no video to play")
            self.video1.source = "./1_Second_of_Blank.mp4"
            self.video1.state = 'play'
        else:

            # todo check users activity with App and adjust list
            if (self.smart_video_choice):
                # check who is there
                self.check_users()
                if(self.current_people):
                    # check what the people there have seen and choose a content
                    self.check_users_watching_habits()
                    self.video1.source = self.video_list[0]  # the most appropriate is the first one
                    # for those there, add the chosen content to their watching habits
                    self.update_users_watching_habits()

            if(not self.current_people):
                self.curr_video_iterator = self.video_list.index(
                    self.video1.source) if self.video1.source in self.video_list else 0
                self.curr_video_iterator += 1
                if (len(self.video_list) == self.curr_video_iterator):
                    self.curr_video_iterator = 0
                self.video1.source = self.video_list[self.curr_video_iterator]

            if (self.video1.source.endswith(self.list_of_correct_extension_image)):
                self.video1.source = self.video1.source
                self.playing_ppt = True
                self.root_UI.add_widget(self.label_help_ppt)
                if (self.bool_show_UI):
                    self.root_UI.add_widget(self.button_next_ppt)
                    self.root_UI.add_widget(self.button_previous_ppt)
                    self.bool_ppt_UI_shown = True
                self.set_ppt_event(Clock.schedule_once(self.play_next_image, self.delay_image))
            else:
                self.video1.state = 'play'
        print("Playing:", self.video1.source)

    # decide which video is played next
    def playlist_management_previous(self, dt=None):
        if (self.playing_ppt):
            self.root_UI.remove_widget(self.label_help_ppt)
            if (self.bool_show_UI):
                self.root_UI.remove_widget(self.button_next_ppt)
                self.root_UI.remove_widget(self.button_previous_ppt)
                self.bool_ppt_UI_shown = False
            self.playing_ppt = False
            filename, file_extension = os.path.splitext(self.video1.source)
            # extract image number
            number_old = re.search('(\d+)$', filename).group(0)
            number_new = 1
            # replace the current image number to the next one
            filename = re.sub(str(number_old) + "$", str(number_new), filename)
            self.video1.source = filename + file_extension

        self.video1.state = 'pause'
        self.video_list = PlaylistFromDir.create_playlist(self.video_directory)

        if not self.video_list:
            print("no video to play")
            self.video1.source = "./1_Second_of_Blank.mp4"
            self.video1.state = 'play'
        else:
            self.curr_video_iterator = self.video_list.index(
                self.video1.source) if self.video1.source in self.video_list else 0
            self.curr_video_iterator -= 1
            if (self.curr_video_iterator < 0):
                self.curr_video_iterator = len(self.video_list) - 1
            self.video1.source = self.video_list[self.curr_video_iterator]

            # todo check users activity with App and adjust list
            if (self.smart_video_choice):
                # check who is there
                self.check_users()
                if(self.current_people):
                    # for those there, add the chosen content to their watching habits
                    self.update_users_watching_habits()

            # if ppt treat it accordingly
            if (self.video1.source.endswith(self.list_of_correct_extension_image)):
                self.video1.source = self.video1.source
                self.playing_ppt = True
                self.root_UI.add_widget(self.label_help_ppt)
                if (self.bool_show_UI):
                    self.root_UI.add_widget(self.button_next_ppt)
                    self.root_UI.add_widget(self.button_previous_ppt)
                    self.bool_ppt_UI_shown = True
                self.set_ppt_event(Clock.schedule_once(self.play_next_image, self.delay_image))
            else:
                self.video1.state = 'play'
        print("Playing:", self.video1.source)

    def set_ppt_event(self, event):
        if (self.event_ppt != None):
            self.event_ppt.cancel()
        self.event_ppt = event

    def set_playlist_management_event(self, event):
        if (self.playlist_management_event != None):
            self.playlist_management_event.cancel()
        self.playlist_management_event = event

    def play_next_image(self, dt):
        print("Entering play_next_image")
        if (self.playing_ppt):
            if (self.previous_slide):
                # print("play next")
                # get name and extension
                filename, file_extension = os.path.splitext(self.video1.source)
                # extract image number
                number_old = re.search('(\d+)$', filename).group(0)
                number_new = int(number_old) - 1

                # print("before :",filename)
                # replace the current image number to the next one
                filename = re.sub(str(number_old) + "$", str(number_new), filename)

                # print("after :", filename)
                # if the file does no exist we pass to the video/powerpoint
                if (os.path.isfile(filename + file_extension)):
                    # if it exist we update the image drawn
                    new_source = filename + file_extension
                    # print(self.video1.source," new image is :",new_source)
                    self.video1.source = new_source
                    self.previous_slide = False
                    self.next_slide = False
                    self.set_ppt_event(Clock.schedule_once(self.play_next_image, self.delay_image))

            elif (self.next_slide):
                # print("play next")
                # get name and extension
                filename, file_extension = os.path.splitext(self.video1.source)
                # extract image number
                number_old = re.search('(\d+)$', filename).group(0)
                number_new = int(number_old) + 1

                # print("before :",filename)
                # replace the current image number to the next one
                filename = re.sub(str(number_old) + "$", str(number_new), filename)

                # print("after :", filename)
                # if the file does no exist we pass to the video/powerpoint
                if (os.path.isfile(filename + file_extension)):
                    # if it exist we update the image drawn
                    new_source = filename + file_extension
                    # print(self.video1.source," new image is :",new_source)
                    self.video1.source = new_source
                    self.previous_slide = False
                    self.next_slide = False
                    self.set_ppt_event(Clock.schedule_once(self.play_next_image, self.delay_image))
            else:
                # print("play next")
                # get name and extension
                filename, file_extension = os.path.splitext(self.video1.source)
                # extract image number
                number_old = re.search('(\d+)$', filename).group(0)
                number_new = int(number_old) + 1

                # print("before :",filename)
                # replace the current image number to the next one
                filename = re.sub(str(number_old) + "$", str(number_new), filename)

                # print("after :", filename)
                # if the file does no exist we pass to the video/powerpoint
                if (not os.path.isfile(filename + file_extension)):
                    print("from play_next_image")
                    self.set_playlist_management_event(Clock.schedule_once(partial(self.playlist_management_next), 0))
                else:
                    # if it exist we update the image drawn
                    new_source = filename + file_extension
                    # print(self.video1.source," new image is :",new_source)
                    self.video1.source = new_source
                    self.previous_slide = False
                    self.next_slide = False
                    self.set_ppt_event(Clock.schedule_once(self.play_next_image, self.delay_image))

    def show_overlay(self):
        if (self.bool_show_UI == False):
            self.root_UI.add_widget(self.handTracking.painter)
            self.root_UI.add_widget(self.button_next)
            self.root_UI.add_widget(self.button_previous)
            self.root_UI.add_widget(self.button_loop)
            if (not self.bool_ppt_UI_shown and self.playing_ppt):
                self.root_UI.add_widget(self.button_next_ppt)
                self.root_UI.add_widget(self.button_previous_ppt)
                self.bool_ppt_UI_shown = True
            self.bool_show_UI = True

            self.check_users()

    def hide_overlay(self):
        if (self.bool_show_UI == True):
            self.root_UI.remove_widget(self.handTracking.painter)
            self.root_UI.remove_widget(self.button_next)
            self.root_UI.remove_widget(self.button_previous)
            self.root_UI.remove_widget(self.button_loop)
            if (self.bool_ppt_UI_shown):
                self.root_UI.remove_widget(self.button_next_ppt)
                self.root_UI.remove_widget(self.button_previous_ppt)
                self.bool_ppt_UI_shown = False
            self.bool_show_UI = False

    # move the mouse to the middle of the window and hide fullscreen (works best when full screen)
    def hide_mouse_if_unmoved(self, dt):
        if (Window.mouse_pos[0] == self.last_mouse_pose[0] and Window.mouse_pos[1] == self.last_mouse_pose[
            1] and self.bool_show_UI == False):
            pyautogui.moveTo(Window.width / 2, Window.height / 2)
            Window.show_cursor = False

    # check the mouse position, if situated on the right, the grid is show
    def check_mouse_position(self, dt):
        # show mouse cursor if hidden and not in the center of the screen
        x = Window.mouse_pos[0]
        y = Window.mouse_pos[1]
        if (x != Window.width / 2 and y != Window.height / 2 and Window.show_cursor == False):
            Window.show_cursor = True
        # todo: check if mouse over widget for click
        if (self.bool_show_UI):
            if (self.iterator_check_if_click == self.time_limit_beetween_clicks):
                self.check_if_click(0)
                self.iterator_check_if_click = 0
            else:
                self.iterator_check_if_click += 1
        self.last_mouse_pose = (Window.mouse_pos[0], Window.mouse_pos[1])
        # print(Window.mouse_pos)

    def check_if_click(self, dt):

        x = Window.mouse_pos[0]
        y = Window.mouse_pos[1]
        if (self.button_next.collide_point(x, y)):
            self.callback_button_next(None)

        if (self.button_previous.collide_point(x, y)):
            self.callback_button_previous(None)

        if (self.button_loop.collide_point(x, y)):
            self.callback_button_loop(None)

        if (self.bool_ppt_UI_shown):
            if (self.button_next_ppt.collide_point(x, y)):
                self.callback_button_next_ppt(None)

            if (self.button_previous_ppt.collide_point(x, y)):
                self.callback_button_previous_ppt(None)

    # todo: that may be a bit heavy on processing
    def on_position_change(self, instance, value):
        if (value > 30):
            print("from 30 sec !")
            self.set_playlist_management_event(Clock.schedule_once(partial(self.playlist_management_next), 0))

    def show_greetings(self, text, size=200, color=(1, 1, 1, 1)):
        label_hello = Label(
            text=text
        )
        self.root_UI.add_widget(label_hello)
        # Animate and fade out the message
        anim = Animation(font_size=size,
                         color=color, t='in_quad', s=1 / 30)
        anim.start(label_hello)

        def tick_hello_anim(dt):
            label_hello.canvas.ask_update()
            Clock.schedule_once(tick_hello_anim)

            tick_hello_anim(0)

        def end_hello_anim(dt):
            self.root_UI.remove_widget(label_hello)
            Clock.unschedule(end_hello_anim)

        Clock.schedule_once(end_hello_anim, 1)

    # on end of stream, playlist_management is shown
    def on_eos(self, instance, value):
        if (not self.video1.source.endswith(self.list_of_correct_extension_image)):
            print("from eos", self.video1.source)
            self.set_playlist_management_event(Clock.schedule_once(partial(self.playlist_management_next), 0))

    def __init__(self, **kwargs):
        super(TestApp, self).__init__(**kwargs)
        self._keyboard = Window.request_keyboard(self._keyboard_closed, self)
        self._keyboard.bind(on_key_down=self._on_keyboard_down)
        self._keyboard.bind(on_key_up=self._on_keyboard_up)

    def _keyboard_closed(self):
        self._keyboard.unbind(on_key_down=self._on_keyboard_down)
        self._keyboard = None

    def _on_keyboard_down(self, *args):
        # print ('down', args)
        if args[1][1] == 'f':
            Window.fullscreen = "auto"
        if args[1][1] == 'right':
            print("from right")
            self.set_playlist_management_event(Clock.schedule_once(partial(self.playlist_management_next), 0))
        if args[1][1] == 'left':
            print("from left")
            self.set_playlist_management_event(Clock.schedule_once(partial(self.playlist_management_previous), 0))
        if args[1][1] == 'enter':
            self.show_greetings("Hi Yoann")
        if args[1][1] == 's':
            self.faceAndEmotionAnalyser.quitAndSave()
            self.faceAndEmotionAnalyser = apiFaceAndEmotion.apiFaceDetectAndClassifier()
        if args[1][1] == 'c':
            self.faceAndEmotionAnalyser.changeName("36", "Yoann", self.faceAndEmotionAnalyser.personsDB)

    def _on_keyboard_up(self, *args):
        print(args[1][1])