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)
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)
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])