flet-video 0.0.1__py3-none-any.whl → 0.1.0.dev18__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of flet-video might be problematic. Click here for more details.

flet_video/__init__.py CHANGED
@@ -1 +1,7 @@
1
-
1
+ from flet_video.video import (
2
+ PlaylistMode,
3
+ Video,
4
+ VideoConfiguration,
5
+ VideoMedia,
6
+ VideoSubtitleConfiguration,
7
+ )
flet_video/video.py ADDED
@@ -0,0 +1,552 @@
1
+ import dataclasses
2
+ from enum import Enum
3
+ from typing import Any, Dict, List, Optional, Union, cast
4
+
5
+ from flet.core.alignment import Alignment
6
+ from flet.core.animation import AnimationValue
7
+ from flet.core.badge import BadgeValue
8
+ from flet.core.box import FilterQuality
9
+ from flet.core.constrained_control import ConstrainedControl
10
+ from flet.core.control import OptionalNumber
11
+ from flet.core.ref import Ref
12
+ from flet.core.text_style import TextStyle
13
+ from flet.core.tooltip import TooltipValue
14
+ from flet.core.types import (
15
+ ColorEnums,
16
+ ColorValue,
17
+ ImageFit,
18
+ OffsetValue,
19
+ OptionalControlEventCallable,
20
+ OptionalEventCallable,
21
+ PaddingValue,
22
+ ResponsiveNumber,
23
+ RotateValue,
24
+ ScaleValue,
25
+ TextAlign,
26
+ )
27
+ from flet.utils import deprecated
28
+
29
+
30
+ class PlaylistMode(Enum):
31
+ NONE = "none"
32
+ SINGLE = "single"
33
+ LOOP = "loop"
34
+
35
+
36
+ @dataclasses.dataclass
37
+ class VideoMedia:
38
+ resource: Optional[str] = dataclasses.field(default=None)
39
+ http_headers: Optional[Dict[str, str]] = dataclasses.field(default=None)
40
+ extras: Optional[Dict[str, str]] = dataclasses.field(default=None)
41
+
42
+
43
+ @dataclasses.dataclass
44
+ class VideoConfiguration:
45
+ output_driver: Optional[str] = dataclasses.field(default=None)
46
+ hardware_decoding_api: Optional[str] = dataclasses.field(default=None)
47
+ enable_hardware_acceleration: Optional[bool] = dataclasses.field(default=None)
48
+
49
+
50
+ @dataclasses.dataclass
51
+ class VideoSubtitleConfiguration:
52
+ src: Optional[str] = dataclasses.field(default=None)
53
+ title: Optional[str] = dataclasses.field(default=None)
54
+ language: Optional[str] = dataclasses.field(default=None)
55
+ text_style: Optional[TextStyle] = dataclasses.field(default=None)
56
+ text_scale_factor: Optional[OptionalNumber] = dataclasses.field(default=None)
57
+ text_align: Optional[TextAlign] = dataclasses.field(default=None)
58
+ padding: Optional[PaddingValue] = dataclasses.field(default=None)
59
+ visible: Optional[bool] = dataclasses.field(default=None)
60
+
61
+
62
+ class Video(ConstrainedControl):
63
+ """
64
+ A control that displays a video from a playlist.
65
+
66
+ -----
67
+
68
+ Online docs: https://flet.dev/docs/controls/video
69
+ """
70
+
71
+ def __init__(
72
+ self,
73
+ playlist: Optional[List[VideoMedia]] = None,
74
+ title: Optional[str] = None,
75
+ fit: Optional[ImageFit] = None,
76
+ fill_color: Optional[ColorValue] = None,
77
+ wakelock: Optional[bool] = None,
78
+ autoplay: Optional[bool] = None,
79
+ show_controls: Optional[bool] = None,
80
+ muted: Optional[bool] = None,
81
+ playlist_mode: Optional[PlaylistMode] = None,
82
+ shuffle_playlist: Optional[bool] = None,
83
+ volume: OptionalNumber = None,
84
+ playback_rate: OptionalNumber = None,
85
+ alignment: Optional[Alignment] = None,
86
+ filter_quality: Optional[FilterQuality] = None,
87
+ pause_upon_entering_background_mode: Optional[bool] = None,
88
+ resume_upon_entering_foreground_mode: Optional[bool] = None,
89
+ aspect_ratio: OptionalNumber = None,
90
+ pitch: OptionalNumber = None,
91
+ configuration: Optional[VideoConfiguration] = None,
92
+ subtitle_configuration: Optional[VideoSubtitleConfiguration] = None,
93
+ on_loaded: OptionalControlEventCallable = None,
94
+ on_enter_fullscreen: OptionalControlEventCallable = None,
95
+ on_exit_fullscreen: OptionalControlEventCallable = None,
96
+ on_error: OptionalControlEventCallable = None,
97
+ on_completed: OptionalControlEventCallable = None,
98
+ on_track_changed: OptionalControlEventCallable = None,
99
+ #
100
+ # ConstrainedControl
101
+ #
102
+ ref: Optional[Ref] = None,
103
+ key: Optional[str] = None,
104
+ width: OptionalNumber = None,
105
+ height: OptionalNumber = None,
106
+ left: OptionalNumber = None,
107
+ top: OptionalNumber = None,
108
+ right: OptionalNumber = None,
109
+ bottom: OptionalNumber = None,
110
+ expand: Union[None, bool, int] = None,
111
+ col: Optional[ResponsiveNumber] = None,
112
+ opacity: OptionalNumber = None,
113
+ rotate: RotateValue = None,
114
+ scale: ScaleValue = None,
115
+ offset: OffsetValue = None,
116
+ animate_opacity: Optional[AnimationValue] = None,
117
+ animate_size: Optional[AnimationValue] = None,
118
+ animate_position: Optional[AnimationValue] = None,
119
+ animate_rotation: Optional[AnimationValue] = None,
120
+ animate_scale: Optional[AnimationValue] = None,
121
+ animate_offset: Optional[AnimationValue] = None,
122
+ on_animation_end: OptionalEventCallable = None,
123
+ tooltip: TooltipValue = None,
124
+ badge: Optional[BadgeValue] = None,
125
+ visible: Optional[bool] = None,
126
+ disabled: Optional[bool] = None,
127
+ data: Any = None,
128
+ ):
129
+ ConstrainedControl.__init__(
130
+ self,
131
+ ref=ref,
132
+ key=key,
133
+ width=width,
134
+ height=height,
135
+ left=left,
136
+ top=top,
137
+ right=right,
138
+ bottom=bottom,
139
+ expand=expand,
140
+ col=col,
141
+ opacity=opacity,
142
+ rotate=rotate,
143
+ scale=scale,
144
+ offset=offset,
145
+ aspect_ratio=aspect_ratio,
146
+ animate_opacity=animate_opacity,
147
+ animate_size=animate_size,
148
+ animate_position=animate_position,
149
+ animate_rotation=animate_rotation,
150
+ animate_scale=animate_scale,
151
+ animate_offset=animate_offset,
152
+ on_animation_end=on_animation_end,
153
+ tooltip=tooltip,
154
+ badge=badge,
155
+ visible=visible,
156
+ disabled=disabled,
157
+ data=data,
158
+ )
159
+
160
+ self.__playlist = playlist or []
161
+ self.subtitle_configuration = subtitle_configuration
162
+ self.configuration = configuration
163
+ self.fit = fit
164
+ self.pitch = pitch
165
+ self.fill_color = fill_color
166
+ self.volume = volume
167
+ self.playback_rate = playback_rate
168
+ self.alignment = alignment
169
+ self.wakelock = wakelock
170
+ self.autoplay = autoplay
171
+ self.show_controls = show_controls
172
+ self.shuffle_playlist = shuffle_playlist
173
+ self.muted = muted
174
+ self.title = title
175
+ self.filter_quality = filter_quality
176
+ self.playlist_mode = playlist_mode
177
+ self.pause_upon_entering_background_mode = pause_upon_entering_background_mode
178
+ self.resume_upon_entering_foreground_mode = resume_upon_entering_foreground_mode
179
+ self.on_enter_fullscreen = on_enter_fullscreen
180
+ self.on_exit_fullscreen = on_exit_fullscreen
181
+ self.on_loaded = on_loaded
182
+ self.on_error = on_error
183
+ self.on_completed = on_completed
184
+ self.on_track_changed = on_track_changed
185
+
186
+ def _get_control_name(self):
187
+ return "video"
188
+
189
+ def before_update(self):
190
+ super().before_update()
191
+ self._set_attr_json("alignment", self.__alignment)
192
+ self._set_attr_json("playlist", self.__playlist if self.__playlist else None)
193
+ if isinstance(self.__subtitle_configuration, VideoSubtitleConfiguration):
194
+ self._set_attr_json("subtitleConfiguration", self.__subtitle_configuration)
195
+
196
+ if isinstance(self.__configuration, VideoConfiguration):
197
+ self._set_attr_json("configuration", self.__configuration)
198
+
199
+ def play(self):
200
+ self.invoke_method("play")
201
+
202
+ def pause(self):
203
+ self.invoke_method("pause")
204
+
205
+ def play_or_pause(self):
206
+ self.invoke_method("play_or_pause")
207
+
208
+ def stop(self):
209
+ self.invoke_method("stop")
210
+
211
+ def next(self):
212
+ self.invoke_method("next")
213
+
214
+ def previous(self):
215
+ self.invoke_method("previous")
216
+
217
+ def seek(self, position_milliseconds: int):
218
+ self.invoke_method("seek", {"position": str(position_milliseconds)})
219
+
220
+ def jump_to(self, media_index: int):
221
+ assert self.__playlist[media_index], "media_index is out of range"
222
+ if media_index < 0:
223
+ # dart doesn't support negative indexes
224
+ media_index = len(self.__playlist) + media_index
225
+ self.invoke_method("jump_to", {"media_index": str(media_index)})
226
+
227
+ def playlist_add(self, media: VideoMedia):
228
+ assert media.resource, "media has no resource"
229
+ self.invoke_method(
230
+ "playlist_add",
231
+ {
232
+ "resource": media.resource,
233
+ "http_headers": str(media.http_headers or {}),
234
+ "extras": str(media.extras or {}),
235
+ },
236
+ )
237
+ self.__playlist.append(media)
238
+
239
+ def playlist_remove(self, media_index: int):
240
+ assert self.__playlist[media_index], "index out of range"
241
+ self.invoke_method("playlist_remove", {"media_index": str(media_index)})
242
+ self.__playlist.pop(media_index)
243
+
244
+ def is_playing(self, wait_timeout: Optional[float] = 5) -> bool:
245
+ playing = self.invoke_method(
246
+ "is_playing",
247
+ wait_for_result=True,
248
+ wait_timeout=wait_timeout,
249
+ )
250
+ return playing == "true"
251
+
252
+ async def is_playing_async(self, wait_timeout: Optional[float] = 5) -> bool:
253
+ playing = await self.invoke_method_async(
254
+ "is_playing",
255
+ wait_for_result=True,
256
+ wait_timeout=wait_timeout,
257
+ )
258
+ return playing == "true"
259
+
260
+ def is_completed(self, wait_timeout: Optional[float] = 5) -> bool:
261
+ completed = self.invoke_method(
262
+ "is_completed",
263
+ wait_for_result=True,
264
+ wait_timeout=wait_timeout,
265
+ )
266
+ return completed == "true"
267
+
268
+ async def is_completed_async(self, wait_timeout: Optional[float] = 5) -> bool:
269
+ completed = await self.invoke_method_async(
270
+ "is_completed",
271
+ wait_for_result=True,
272
+ wait_timeout=wait_timeout,
273
+ )
274
+ return completed == "true"
275
+
276
+ def get_duration(self, wait_timeout: Optional[float] = 5) -> Optional[int]:
277
+ sr = self.invoke_method(
278
+ "get_duration",
279
+ wait_for_result=True,
280
+ wait_timeout=wait_timeout,
281
+ )
282
+ return int(sr) if sr else None
283
+
284
+ async def get_duration_async(
285
+ self, wait_timeout: Optional[float] = 5
286
+ ) -> Optional[int]:
287
+ sr = await self.invoke_method_async(
288
+ "get_duration",
289
+ wait_for_result=True,
290
+ wait_timeout=wait_timeout,
291
+ )
292
+ return int(sr) if sr else None
293
+
294
+ def get_current_position(self, wait_timeout: Optional[float] = 5) -> Optional[int]:
295
+ sr = self.invoke_method(
296
+ "get_current_position",
297
+ wait_for_result=True,
298
+ wait_timeout=wait_timeout,
299
+ )
300
+ return int(sr) if sr else None
301
+
302
+ async def get_current_position_async(
303
+ self, wait_timeout: Optional[float] = 5
304
+ ) -> Optional[int]:
305
+ sr = await self.invoke_method_async(
306
+ "get_current_position",
307
+ wait_for_result=True,
308
+ wait_timeout=wait_timeout,
309
+ )
310
+ return int(sr) if sr else None
311
+
312
+ # playlist
313
+ @property
314
+ def playlist(self) -> Optional[List[VideoMedia]]:
315
+ return self.__playlist
316
+
317
+ # fit
318
+ @property
319
+ def fit(self) -> Optional[ImageFit]:
320
+ return self.__fit
321
+
322
+ @fit.setter
323
+ def fit(self, value: Optional[ImageFit]):
324
+ self.__fit = value
325
+ self._set_attr("fit", value.value if isinstance(value, ImageFit) else value)
326
+
327
+ # subtitle_configuration
328
+ @property
329
+ def subtitle_configuration(self) -> Optional[VideoSubtitleConfiguration]:
330
+ return self.__subtitle_configuration
331
+
332
+ @subtitle_configuration.setter
333
+ def subtitle_configuration(self, value: Optional[VideoSubtitleConfiguration]):
334
+ self.__subtitle_configuration = value
335
+
336
+ # configuration
337
+ @property
338
+ def configuration(self) -> Optional[VideoConfiguration]:
339
+ return self.__configuration
340
+
341
+ @configuration.setter
342
+ def configuration(self, value: Optional[VideoConfiguration]):
343
+ self.__configuration = value
344
+
345
+ # fill_color
346
+ @property
347
+ def fill_color(self) -> Optional[ColorValue]:
348
+ return self.__fill_color
349
+
350
+ @fill_color.setter
351
+ def fill_color(self, value: Optional[ColorValue]):
352
+ self.__fill_color = value
353
+ self._set_enum_attr("fillColor", value, ColorEnums)
354
+
355
+ # wakelock
356
+ @property
357
+ def wakelock(self) -> bool:
358
+ return self._get_attr("wakelock", data_type="bool", def_value=True)
359
+
360
+ @wakelock.setter
361
+ def wakelock(self, value: Optional[bool]):
362
+ self._set_attr("wakelock", value)
363
+
364
+ # autoplay
365
+ @property
366
+ def autoplay(self) -> bool:
367
+ return self._get_attr("autoPlay", data_type="bool", def_value=False)
368
+
369
+ @autoplay.setter
370
+ def autoplay(self, value: Optional[bool]):
371
+ self._set_attr("autoPlay", value)
372
+
373
+ # muted
374
+ @property
375
+ def muted(self) -> bool:
376
+ return self._get_attr("muted", data_type="bool", def_value=False)
377
+
378
+ @muted.setter
379
+ def muted(self, value: Optional[bool]):
380
+ self._set_attr("muted", value)
381
+
382
+ # shuffle_playlist
383
+ @property
384
+ def shuffle_playlist(self) -> bool:
385
+ return self._get_attr("shufflePlaylist", data_type="bool", def_value=False)
386
+
387
+ @shuffle_playlist.setter
388
+ def shuffle_playlist(self, value: Optional[bool]):
389
+ self._set_attr("shufflePlaylist", value)
390
+
391
+ # show_controls
392
+ @property
393
+ def show_controls(self) -> bool:
394
+ return self._get_attr("showControls", data_type="bool", def_value=True)
395
+
396
+ @show_controls.setter
397
+ def show_controls(self, value: Optional[bool]):
398
+ self._set_attr("showControls", value)
399
+
400
+ # pitch
401
+ @property
402
+ def pitch(self) -> OptionalNumber:
403
+ return self._get_attr("pitch", data_type="float")
404
+
405
+ @pitch.setter
406
+ def pitch(self, value: OptionalNumber):
407
+ self._set_attr("pitch", value)
408
+
409
+ # volume
410
+ @property
411
+ def volume(self) -> OptionalNumber:
412
+ return self._get_attr("volume", data_type="float")
413
+
414
+ @volume.setter
415
+ def volume(self, value: OptionalNumber):
416
+ assert value is None or 0 <= value <= 100, "volume must be between 0 and 100"
417
+ self._set_attr("volume", value)
418
+
419
+ # playback_rate
420
+ @property
421
+ def playback_rate(self) -> OptionalNumber:
422
+ return self._get_attr("playbackRate", data_type="float")
423
+
424
+ @playback_rate.setter
425
+ def playback_rate(self, value: OptionalNumber):
426
+ self._set_attr("playbackRate", value)
427
+
428
+ # title
429
+ @property
430
+ def title(self) -> Optional[str]:
431
+ return self._get_attr("title")
432
+
433
+ @title.setter
434
+ def title(self, value: Optional[str]):
435
+ self._set_attr("title", value)
436
+
437
+ # pause_upon_entering_background_mode
438
+ @property
439
+ def pause_upon_entering_background_mode(self) -> bool:
440
+ return cast(
441
+ bool,
442
+ self._get_attr(
443
+ "pauseUponEnteringBackgroundMode", data_type="bool", def_value=True
444
+ ),
445
+ )
446
+
447
+ @pause_upon_entering_background_mode.setter
448
+ def pause_upon_entering_background_mode(self, value: Optional[bool]):
449
+ self._set_attr("pauseUponEnteringBackgroundMode", value)
450
+
451
+ # resume_upon_entering_foreground_mode
452
+ @property
453
+ def resume_upon_entering_foreground_mode(self) -> bool:
454
+ return cast(
455
+ bool,
456
+ self._get_attr(
457
+ "resumeUponEnteringForegroundMode", data_type="bool", def_value=False
458
+ ),
459
+ )
460
+
461
+ @resume_upon_entering_foreground_mode.setter
462
+ def resume_upon_entering_foreground_mode(self, value: Optional[bool]):
463
+ self._set_attr("resumeUponEnteringForegroundMode", value)
464
+
465
+ # alignment
466
+ @property
467
+ def alignment(self) -> Optional[Alignment]:
468
+ return self.__alignment
469
+
470
+ @alignment.setter
471
+ def alignment(self, value: Optional[Alignment]):
472
+ self.__alignment = value
473
+
474
+ # filter_quality
475
+ @property
476
+ def filter_quality(self) -> Optional[FilterQuality]:
477
+ return self.__filter_quality
478
+
479
+ @filter_quality.setter
480
+ def filter_quality(self, value: Optional[FilterQuality]):
481
+ self.__filter_quality = value
482
+ self._set_enum_attr("filterQuality", value, FilterQuality)
483
+
484
+ # playlist_mode
485
+ @property
486
+ def playlist_mode(self) -> Optional[PlaylistMode]:
487
+ return self.__playlist_mode
488
+
489
+ @playlist_mode.setter
490
+ def playlist_mode(self, value: Optional[PlaylistMode]):
491
+ self.__playlist_mode = value
492
+ self._set_enum_attr("playlistMode", value, PlaylistMode)
493
+
494
+ # on_enter_fullscreen
495
+ @property
496
+ def on_enter_fullscreen(self):
497
+ return self._get_event_handler("enter_fullscreen")
498
+
499
+ @on_enter_fullscreen.setter
500
+ def on_enter_fullscreen(self, handler: OptionalControlEventCallable):
501
+ self._add_event_handler("enter_fullscreen", handler)
502
+ self._set_attr("onEnterFullscreen", True if handler is not None else None)
503
+
504
+ # on_exit_fullscreen
505
+ @property
506
+ def on_exit_fullscreen(self) -> OptionalControlEventCallable:
507
+ return self._get_event_handler("exit_fullscreen")
508
+
509
+ @on_exit_fullscreen.setter
510
+ def on_exit_fullscreen(self, handler: OptionalControlEventCallable):
511
+ self._add_event_handler("exit_fullscreen", handler)
512
+ self._set_attr("onExitFullscreen", True if handler is not None else None)
513
+
514
+ # on_loaded
515
+ @property
516
+ def on_loaded(self) -> OptionalControlEventCallable:
517
+ return self._get_event_handler("loaded")
518
+
519
+ @on_loaded.setter
520
+ def on_loaded(self, handler: OptionalControlEventCallable):
521
+ self._set_attr("onLoaded", True if handler is not None else None)
522
+ self._add_event_handler("loaded", handler)
523
+
524
+ # on_error
525
+ @property
526
+ def on_error(self) -> OptionalControlEventCallable:
527
+ return self._get_event_handler("error")
528
+
529
+ @on_error.setter
530
+ def on_error(self, handler: OptionalControlEventCallable):
531
+ self._set_attr("onError", True if handler is not None else None)
532
+ self._add_event_handler("error", handler)
533
+
534
+ # on_completed
535
+ @property
536
+ def on_completed(self) -> OptionalControlEventCallable:
537
+ return self._get_event_handler("completed")
538
+
539
+ @on_completed.setter
540
+ def on_completed(self, handler: OptionalControlEventCallable):
541
+ self._set_attr("onCompleted", True if handler is not None else None)
542
+ self._add_event_handler("completed", handler)
543
+
544
+ # on_track_changed
545
+ @property
546
+ def on_track_changed(self) -> OptionalControlEventCallable:
547
+ return self._get_event_handler("track_changed")
548
+
549
+ @on_track_changed.setter
550
+ def on_track_changed(self, handler: OptionalControlEventCallable):
551
+ self._set_attr("onTrackChanged", True if handler is not None else None)
552
+ self._add_event_handler("track_changed", handler)