streamlit-nightly 1.32.2.dev20240312__py2.py3-none-any.whl → 1.32.2.dev20240313__py2.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.
Files changed (22) hide show
  1. streamlit/elements/media.py +55 -2
  2. streamlit/proto/Audio_pb2.py +2 -2
  3. streamlit/proto/Audio_pb2.pyi +9 -1
  4. streamlit/proto/Video_pb2.py +4 -4
  5. streamlit/proto/Video_pb2.pyi +9 -1
  6. streamlit/runtime/runtime.py +17 -7
  7. streamlit/static/asset-manifest.json +4 -4
  8. streamlit/static/index.html +1 -1
  9. streamlit/static/static/js/178.3b9ac62d.chunk.js +1 -0
  10. streamlit/static/static/js/9330.d29313d4.chunk.js +1 -0
  11. streamlit/static/static/js/{main.af27280e.js → main.15ed35a4.js} +2 -2
  12. streamlit/testing/v1/app_test.py +33 -6
  13. streamlit/testing/v1/local_script_runner.py +6 -1
  14. {streamlit_nightly-1.32.2.dev20240312.dist-info → streamlit_nightly-1.32.2.dev20240313.dist-info}/METADATA +1 -1
  15. {streamlit_nightly-1.32.2.dev20240312.dist-info → streamlit_nightly-1.32.2.dev20240313.dist-info}/RECORD +20 -20
  16. streamlit/static/static/js/178.2203b5c2.chunk.js +0 -1
  17. streamlit/static/static/js/9330.c0dd1723.chunk.js +0 -1
  18. /streamlit/static/static/js/{main.af27280e.js.LICENSE.txt → main.15ed35a4.js.LICENSE.txt} +0 -0
  19. {streamlit_nightly-1.32.2.dev20240312.data → streamlit_nightly-1.32.2.dev20240313.data}/scripts/streamlit.cmd +0 -0
  20. {streamlit_nightly-1.32.2.dev20240312.dist-info → streamlit_nightly-1.32.2.dev20240313.dist-info}/WHEEL +0 -0
  21. {streamlit_nightly-1.32.2.dev20240312.dist-info → streamlit_nightly-1.32.2.dev20240313.dist-info}/entry_points.txt +0 -0
  22. {streamlit_nightly-1.32.2.dev20240312.dist-info → streamlit_nightly-1.32.2.dev20240313.dist-info}/top_level.txt +0 -0
@@ -55,6 +55,8 @@ class MediaMixin:
55
55
  start_time: int = 0,
56
56
  *,
57
57
  sample_rate: int | None = None,
58
+ end_time: int | None = None,
59
+ loop: bool = False,
58
60
  ) -> DeltaGenerator:
59
61
  """Display an audio player.
60
62
 
@@ -79,6 +81,10 @@ class MediaMixin:
79
81
  sample_rate: int or None
80
82
  The sample rate of the audio data in samples per second. Only required if
81
83
  ``data`` is a numpy array.
84
+ end_time: int
85
+ The time at which this element should stop playing.
86
+ loop: bool
87
+ Whether the audio should loop playback.
82
88
 
83
89
  Example
84
90
  -------
@@ -120,7 +126,16 @@ class MediaMixin:
120
126
  "array."
121
127
  )
122
128
 
123
- marshall_audio(coordinates, audio_proto, data, format, start_time, sample_rate)
129
+ marshall_audio(
130
+ coordinates,
131
+ audio_proto,
132
+ data,
133
+ format,
134
+ start_time,
135
+ sample_rate,
136
+ end_time,
137
+ loop,
138
+ )
124
139
  return self.dg._enqueue("audio", audio_proto)
125
140
 
126
141
  @gather_metrics("video")
@@ -131,6 +146,8 @@ class MediaMixin:
131
146
  start_time: int = 0,
132
147
  *, # keyword-only arguments:
133
148
  subtitles: SubtitleData = None,
149
+ end_time: int | None = None,
150
+ loop: bool = False,
134
151
  ) -> DeltaGenerator:
135
152
  """Display a video player.
136
153
 
@@ -174,6 +191,11 @@ class MediaMixin:
174
191
 
175
192
  Not supported for YouTube videos.
176
193
 
194
+ end_time: int or None
195
+ The time at which this element should stop playing
196
+ loop: bool
197
+ Whether the video should loop playback.
198
+
177
199
  Example
178
200
  -------
179
201
  >>> import streamlit as st
@@ -226,7 +248,16 @@ class MediaMixin:
226
248
  """
227
249
  video_proto = VideoProto()
228
250
  coordinates = self.dg._get_delta_path_str()
229
- marshall_video(coordinates, video_proto, data, format, start_time, subtitles)
251
+ marshall_video(
252
+ coordinates,
253
+ video_proto,
254
+ data,
255
+ format,
256
+ start_time,
257
+ subtitles,
258
+ end_time,
259
+ loop,
260
+ )
230
261
  return self.dg._enqueue("video", video_proto)
231
262
 
232
263
  @property
@@ -330,6 +361,8 @@ def marshall_video(
330
361
  mimetype: str = "video/mp4",
331
362
  start_time: int = 0,
332
363
  subtitles: SubtitleData = None,
364
+ end_time: int | None = None,
365
+ loop: bool = False,
333
366
  ) -> None:
334
367
  """Marshalls a video proto, using url processors as needed.
335
368
 
@@ -359,10 +392,21 @@ def marshall_video(
359
392
  * io.BytesIO: A BytesIO stream that contains valid '.vtt' or '.srt' formatted subtitle data.
360
393
  When provided, subtitles are displayed by default. For multiple tracks, the first one is displayed by default.
361
394
  Not supported for YouTube videos.
395
+ end_time: int
396
+ The time at which this element should stop playing
397
+ loop: bool
398
+ Whether the video should loop playback.
362
399
  """
363
400
 
401
+ if start_time < 0 or (end_time is not None and end_time <= start_time):
402
+ raise StreamlitAPIException("Invalid start_time and end_time combination.")
403
+
364
404
  proto.start_time = start_time
365
405
 
406
+ if end_time is not None:
407
+ proto.end_time = end_time
408
+ proto.loop = loop
409
+
366
410
  # "type" distinguishes between YouTube and non-YouTube links
367
411
  proto.type = VideoProto.Type.NATIVE
368
412
 
@@ -501,6 +545,8 @@ def marshall_audio(
501
545
  mimetype: str = "audio/wav",
502
546
  start_time: int = 0,
503
547
  sample_rate: int | None = None,
548
+ end_time: int | None = None,
549
+ loop: bool = False,
504
550
  ) -> None:
505
551
  """Marshalls an audio proto, using data and url processors as needed.
506
552
 
@@ -520,9 +566,16 @@ def marshall_audio(
520
566
  The time from which this element should start playing. (default: 0)
521
567
  sample_rate: int or None
522
568
  Optional param to provide sample_rate in case of numpy array
569
+ end_time: int
570
+ The time at which this element should stop playing
571
+ loop: bool
572
+ Whether the audio should loop playback.
523
573
  """
524
574
 
525
575
  proto.start_time = start_time
576
+ if end_time is not None:
577
+ proto.end_time = end_time
578
+ proto.loop = loop
526
579
 
527
580
  if isinstance(data, str) and url_util.is_url(
528
581
  data, allowed_schemas=("http", "https", "data")
@@ -13,7 +13,7 @@ _sym_db = _symbol_database.Default()
13
13
 
14
14
 
15
15
 
16
- DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1bstreamlit/proto/Audio.proto\"H\n\x05\x41udio\x12\x0b\n\x03url\x18\x05 \x01(\t\x12\x12\n\nstart_time\x18\x03 \x01(\x05J\x04\x08\x01\x10\x02J\x04\x08\x02\x10\x03J\x04\x08\x04\x10\x05R\x04\x64\x61taR\x06\x66ormatB*\n\x1c\x63om.snowflake.apps.streamlitB\nAudioProtob\x06proto3')
16
+ DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1bstreamlit/proto/Audio.proto\"h\n\x05\x41udio\x12\x0b\n\x03url\x18\x05 \x01(\t\x12\x12\n\nstart_time\x18\x03 \x01(\x05\x12\x10\n\x08\x65nd_time\x18\x06 \x01(\x05\x12\x0c\n\x04loop\x18\x07 \x01(\x08J\x04\x08\x01\x10\x02J\x04\x08\x02\x10\x03J\x04\x08\x04\x10\x05R\x04\x64\x61taR\x06\x66ormatB*\n\x1c\x63om.snowflake.apps.streamlitB\nAudioProtob\x06proto3')
17
17
 
18
18
  _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals())
19
19
  _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'streamlit.proto.Audio_pb2', globals())
@@ -22,5 +22,5 @@ if _descriptor._USE_C_DESCRIPTORS == False:
22
22
  DESCRIPTOR._options = None
23
23
  DESCRIPTOR._serialized_options = b'\n\034com.snowflake.apps.streamlitB\nAudioProto'
24
24
  _AUDIO._serialized_start=31
25
- _AUDIO._serialized_end=103
25
+ _AUDIO._serialized_end=135
26
26
  # @@protoc_insertion_point(module_scope)
@@ -33,15 +33,23 @@ class Audio(google.protobuf.message.Message):
33
33
 
34
34
  URL_FIELD_NUMBER: builtins.int
35
35
  START_TIME_FIELD_NUMBER: builtins.int
36
+ END_TIME_FIELD_NUMBER: builtins.int
37
+ LOOP_FIELD_NUMBER: builtins.int
36
38
  url: builtins.str
37
39
  start_time: builtins.int
38
40
  """The currentTime attribute of the HTML <audio> tag's <source> subtag."""
41
+ end_time: builtins.int
42
+ """The time at which the audio should stop playing. If not specified, plays to the end."""
43
+ loop: builtins.bool
44
+ """Indicates whether the audio should start over from the beginning once it ends."""
39
45
  def __init__(
40
46
  self,
41
47
  *,
42
48
  url: builtins.str = ...,
43
49
  start_time: builtins.int = ...,
50
+ end_time: builtins.int = ...,
51
+ loop: builtins.bool = ...,
44
52
  ) -> None: ...
45
- def ClearField(self, field_name: typing_extensions.Literal["start_time", b"start_time", "url", b"url"]) -> None: ...
53
+ def ClearField(self, field_name: typing_extensions.Literal["end_time", b"end_time", "loop", b"loop", "start_time", b"start_time", "url", b"url"]) -> None: ...
46
54
 
47
55
  global___Audio = Audio
@@ -13,7 +13,7 @@ _sym_db = _symbol_database.Default()
13
13
 
14
14
 
15
15
 
16
- DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1bstreamlit/proto/Video.proto\"+\n\rSubtitleTrack\x12\r\n\x05label\x18\x01 \x01(\t\x12\x0b\n\x03url\x18\x02 \x01(\t\"\xba\x01\n\x05Video\x12\x0b\n\x03url\x18\x06 \x01(\t\x12\x12\n\nstart_time\x18\x03 \x01(\x05\x12\x19\n\x04type\x18\x05 \x01(\x0e\x32\x0b.Video.Type\x12!\n\tsubtitles\x18\x07 \x03(\x0b\x32\x0e.SubtitleTrack\"2\n\x04Type\x12\n\n\x06UNUSED\x10\x00\x12\n\n\x06NATIVE\x10\x01\x12\x12\n\x0eYOUTUBE_IFRAME\x10\x02J\x04\x08\x01\x10\x02J\x04\x08\x02\x10\x03J\x04\x08\x04\x10\x05R\x06\x66ormatR\x04\x64\x61taB*\n\x1c\x63om.snowflake.apps.streamlitB\nVideoProtob\x06proto3')
16
+ DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1bstreamlit/proto/Video.proto\"+\n\rSubtitleTrack\x12\r\n\x05label\x18\x01 \x01(\t\x12\x0b\n\x03url\x18\x02 \x01(\t\"\xda\x01\n\x05Video\x12\x0b\n\x03url\x18\x06 \x01(\t\x12\x12\n\nstart_time\x18\x03 \x01(\x05\x12\x19\n\x04type\x18\x05 \x01(\x0e\x32\x0b.Video.Type\x12!\n\tsubtitles\x18\x07 \x03(\x0b\x32\x0e.SubtitleTrack\x12\x10\n\x08\x65nd_time\x18\x08 \x01(\x05\x12\x0c\n\x04loop\x18\t \x01(\x08\"2\n\x04Type\x12\n\n\x06UNUSED\x10\x00\x12\n\n\x06NATIVE\x10\x01\x12\x12\n\x0eYOUTUBE_IFRAME\x10\x02J\x04\x08\x01\x10\x02J\x04\x08\x02\x10\x03J\x04\x08\x04\x10\x05R\x06\x66ormatR\x04\x64\x61taB*\n\x1c\x63om.snowflake.apps.streamlitB\nVideoProtob\x06proto3')
17
17
 
18
18
  _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals())
19
19
  _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'streamlit.proto.Video_pb2', globals())
@@ -24,7 +24,7 @@ if _descriptor._USE_C_DESCRIPTORS == False:
24
24
  _SUBTITLETRACK._serialized_start=31
25
25
  _SUBTITLETRACK._serialized_end=74
26
26
  _VIDEO._serialized_start=77
27
- _VIDEO._serialized_end=263
28
- _VIDEO_TYPE._serialized_start=181
29
- _VIDEO_TYPE._serialized_end=231
27
+ _VIDEO._serialized_end=295
28
+ _VIDEO_TYPE._serialized_start=213
29
+ _VIDEO_TYPE._serialized_end=263
30
30
  # @@protoc_insertion_point(module_scope)
@@ -74,6 +74,8 @@ class Video(google.protobuf.message.Message):
74
74
  START_TIME_FIELD_NUMBER: builtins.int
75
75
  TYPE_FIELD_NUMBER: builtins.int
76
76
  SUBTITLES_FIELD_NUMBER: builtins.int
77
+ END_TIME_FIELD_NUMBER: builtins.int
78
+ LOOP_FIELD_NUMBER: builtins.int
77
79
  url: builtins.str
78
80
  """A url pointing to a video file"""
79
81
  start_time: builtins.int
@@ -83,6 +85,10 @@ class Video(google.protobuf.message.Message):
83
85
  @property
84
86
  def subtitles(self) -> google.protobuf.internal.containers.RepeatedCompositeFieldContainer[global___SubtitleTrack]:
85
87
  """Repeated field for subtitle tracks"""
88
+ end_time: builtins.int
89
+ """The time at which the video should stop playing. If not specified, plays to the end."""
90
+ loop: builtins.bool
91
+ """Indicates whether the video should start over from the beginning once it ends."""
86
92
  def __init__(
87
93
  self,
88
94
  *,
@@ -90,7 +96,9 @@ class Video(google.protobuf.message.Message):
90
96
  start_time: builtins.int = ...,
91
97
  type: global___Video.Type.ValueType = ...,
92
98
  subtitles: collections.abc.Iterable[global___SubtitleTrack] | None = ...,
99
+ end_time: builtins.int = ...,
100
+ loop: builtins.bool = ...,
93
101
  ) -> None: ...
94
- def ClearField(self, field_name: typing_extensions.Literal["start_time", b"start_time", "subtitles", b"subtitles", "type", b"type", "url", b"url"]) -> None: ...
102
+ def ClearField(self, field_name: typing_extensions.Literal["end_time", b"end_time", "loop", b"loop", "start_time", b"start_time", "subtitles", b"subtitles", "type", b"type", "url", b"url"]) -> None: ...
95
103
 
96
104
  global___Video = Video
@@ -609,7 +609,22 @@ class Runtime:
609
609
  async_objs.started.set_result(None)
610
610
 
611
611
  while not async_objs.must_stop.is_set():
612
- if self._state == RuntimeState.ONE_OR_MORE_SESSIONS_CONNECTED:
612
+ if self._state == RuntimeState.NO_SESSIONS_CONNECTED: # type: ignore[comparison-overlap]
613
+ # mypy 1.4 incorrectly thinks this if-clause is unreachable,
614
+ # because it thinks self._state must be INITIAL | ONE_OR_MORE_SESSIONS_CONNECTED.
615
+
616
+ # Wait for new websocket connections (new sessions):
617
+ _, pending_tasks = await asyncio.wait( # type: ignore[unreachable]
618
+ (
619
+ asyncio.create_task(async_objs.must_stop.wait()),
620
+ asyncio.create_task(async_objs.has_connection.wait()),
621
+ ),
622
+ return_when=asyncio.FIRST_COMPLETED,
623
+ )
624
+ # Clean up pending tasks to avoid memory leaks
625
+ for task in pending_tasks:
626
+ task.cancel()
627
+ elif self._state == RuntimeState.ONE_OR_MORE_SESSIONS_CONNECTED:
613
628
  async_objs.need_send_data.clear()
614
629
 
615
630
  for active_session_info in self._session_mgr.list_active_sessions():
@@ -628,16 +643,11 @@ class Runtime:
628
643
  # Yield for a few milliseconds between session message
629
644
  # flushing.
630
645
  await asyncio.sleep(0.01)
631
- elif self._state == RuntimeState.NO_SESSIONS_CONNECTED: # type: ignore[comparison-overlap]
632
- # mypy 1.4 incorrectly thinks this if-clause is unreachable,
633
- # because it thinks self._state must be INITIAL | ONE_OR_MORE_SESSIONS_CONNECTED.
634
-
635
- # This will jump to the asyncio.wait below.
636
- pass
637
646
  else:
638
647
  # Break out of the thread loop if we encounter any other state.
639
648
  break
640
649
 
650
+ # Wait for new proto messages that need to be sent out:
641
651
  _, pending_tasks = await asyncio.wait(
642
652
  (
643
653
  asyncio.create_task(async_objs.must_stop.wait()),
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "files": {
3
3
  "main.css": "./static/css/main.77d1c464.css",
4
- "main.js": "./static/js/main.af27280e.js",
4
+ "main.js": "./static/js/main.15ed35a4.js",
5
5
  "static/js/9336.2d95d840.chunk.js": "./static/js/9336.2d95d840.chunk.js",
6
- "static/js/9330.c0dd1723.chunk.js": "./static/js/9330.c0dd1723.chunk.js",
6
+ "static/js/9330.d29313d4.chunk.js": "./static/js/9330.d29313d4.chunk.js",
7
7
  "static/js/7217.d970c074.chunk.js": "./static/js/7217.d970c074.chunk.js",
8
8
  "static/js/3301.1d1b10bb.chunk.js": "./static/js/3301.1d1b10bb.chunk.js",
9
9
  "static/css/3092.f719e2e6.chunk.css": "./static/css/3092.f719e2e6.chunk.css",
@@ -19,7 +19,7 @@
19
19
  "static/js/2469.3e9c3ce9.chunk.js": "./static/js/2469.3e9c3ce9.chunk.js",
20
20
  "static/js/4113.1e7eff4d.chunk.js": "./static/js/4113.1e7eff4d.chunk.js",
21
21
  "static/js/1168.6deb594c.chunk.js": "./static/js/1168.6deb594c.chunk.js",
22
- "static/js/178.2203b5c2.chunk.js": "./static/js/178.2203b5c2.chunk.js",
22
+ "static/js/178.3b9ac62d.chunk.js": "./static/js/178.3b9ac62d.chunk.js",
23
23
  "static/js/1792.16c16498.chunk.js": "./static/js/1792.16c16498.chunk.js",
24
24
  "static/js/3513.57cff89c.chunk.js": "./static/js/3513.57cff89c.chunk.js",
25
25
  "static/js/7602.f0420392.chunk.js": "./static/js/7602.f0420392.chunk.js",
@@ -150,6 +150,6 @@
150
150
  },
151
151
  "entrypoints": [
152
152
  "static/css/main.77d1c464.css",
153
- "static/js/main.af27280e.js"
153
+ "static/js/main.15ed35a4.js"
154
154
  ]
155
155
  }
@@ -1 +1 @@
1
- <!doctype html><html lang="en"><head><meta charset="UTF-8"/><meta name="viewport" content="width=device-width,initial-scale=1,shrink-to-fit=no"/><link rel="shortcut icon" href="./favicon.png"/><link rel="preload" href="./static/media/SourceSansPro-Regular.0d69e5ff5e92ac64a0c9.woff2" as="font" type="font/woff2" crossorigin><link rel="preload" href="./static/media/SourceSansPro-SemiBold.abed79cd0df1827e18cf.woff2" as="font" type="font/woff2" crossorigin><link rel="preload" href="./static/media/SourceSansPro-Bold.118dea98980e20a81ced.woff2" as="font" type="font/woff2" crossorigin><title>Streamlit</title><script>window.prerenderReady=!1</script><script defer="defer" src="./static/js/main.af27280e.js"></script><link href="./static/css/main.77d1c464.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>
1
+ <!doctype html><html lang="en"><head><meta charset="UTF-8"/><meta name="viewport" content="width=device-width,initial-scale=1,shrink-to-fit=no"/><link rel="shortcut icon" href="./favicon.png"/><link rel="preload" href="./static/media/SourceSansPro-Regular.0d69e5ff5e92ac64a0c9.woff2" as="font" type="font/woff2" crossorigin><link rel="preload" href="./static/media/SourceSansPro-SemiBold.abed79cd0df1827e18cf.woff2" as="font" type="font/woff2" crossorigin><link rel="preload" href="./static/media/SourceSansPro-Bold.118dea98980e20a81ced.woff2" as="font" type="font/woff2" crossorigin><title>Streamlit</title><script>window.prerenderReady=!1</script><script defer="defer" src="./static/js/main.15ed35a4.js"></script><link href="./static/css/main.77d1c464.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>
@@ -0,0 +1 @@
1
+ "use strict";(self.webpackChunk_streamlit_app=self.webpackChunk_streamlit_app||[]).push([[178],{178:(e,t,r)=>{r.r(t),r.d(t,{default:()=>c});var n=r(66845),a=r(16295),s=r(68785),i=r(40864);const d=528;function c(e){let{element:t,width:r,endpoints:c}=e;const l=(0,n.useRef)(null),{type:o,url:u,startTime:p,subtitles:m,endTime:f,loop:h}=t;(0,n.useEffect)((()=>{l.current&&(l.current.currentTime=p)}),[p]),(0,n.useEffect)((()=>{const e=l.current,r=()=>{e&&(e.currentTime=t.startTime)};return e&&e.addEventListener("loadedmetadata",r),()=>{e&&e.removeEventListener("loadedmetadata",r)}}),[t]),(0,n.useEffect)((()=>{const e=l.current;if(!e)return;let t=!1;const r=()=>{f>0&&e.currentTime>=f&&(h?(e.currentTime=p||0,e.play()):t||(t=!0,e.pause()))};return f>0&&e.addEventListener("timeupdate",r),()=>{e&&f>0&&e.removeEventListener("timeupdate",r)}}),[f,h,p]),(0,n.useEffect)((()=>{const e=l.current;if(!e)return;const t=()=>{h&&(e.currentTime=p||0,e.play())};return e.addEventListener("ended",t),()=>{e&&e.removeEventListener("ended",t)}}),[h,p]);const v=e=>{const{startTime:r,endTime:n,loop:a}=t,s=new URL(e);if(r&&!isNaN(r)&&s.searchParams.append("start",r.toString()),n&&!isNaN(n)&&s.searchParams.append("end",n.toString()),a){s.searchParams.append("loop","1");const e=s.pathname.split("/").pop();e&&s.searchParams.append("playlist",e)}return s.toString()};if(o===a.nk.Type.YOUTUBE_IFRAME){const e=0!==r?.75*r:d;return(0,i.jsx)("iframe",{"data-testid":"stVideo",title:u,src:v(u),width:r,height:e,style:{colorScheme:"light dark"},frameBorder:"0",allow:"autoplay; encrypted-media",allowFullScreen:!0})}return(0,i.jsx)("video",{"data-testid":"stVideo",ref:l,controls:!0,src:c.buildMediaURL(u),className:"stVideo",style:{width:r,height:0===r?d:void 0},crossOrigin:s.td&&m.length>0?"anonymous":void 0,children:m&&m.map(((e,t)=>(0,i.jsx)("track",{kind:"captions",src:c.buildMediaURL(e.url),label:e.label,default:0===t},t)))})}}}]);
@@ -0,0 +1 @@
1
+ "use strict";(self.webpackChunk_streamlit_app=self.webpackChunk_streamlit_app||[]).push([[9330],{69330:(e,t,r)=>{r.r(t),r.d(t,{default:()=>u});var n=r(66845),s=r(40864);function u(e){let{element:t,width:r,endpoints:u}=e;const a=(0,n.useRef)(null),{startTime:d,endTime:i,loop:c}=t;(0,n.useEffect)((()=>{a.current&&(a.current.currentTime=d)}),[d]),(0,n.useEffect)((()=>{const e=a.current,r=()=>{e&&(e.currentTime=t.startTime)};return e&&e.addEventListener("loadedmetadata",r),()=>{e&&e.removeEventListener("loadedmetadata",r)}}),[t]),(0,n.useEffect)((()=>{const e=a.current;if(!e)return;let t=!1;const r=()=>{i>0&&e.currentTime>=i&&(c?(e.currentTime=d||0,e.play()):t||(t=!0,e.pause()))};return i>0&&e.addEventListener("timeupdate",r),()=>{e&&i>0&&e.removeEventListener("timeupdate",r)}}),[i,c,d]),(0,n.useEffect)((()=>{const e=a.current;if(!e)return;const t=()=>{c&&(e.currentTime=d||0,e.play())};return e.addEventListener("ended",t),()=>{e&&e.removeEventListener("ended",t)}}),[c,d]);const o=u.buildMediaURL(t.url);return(0,s.jsx)("audio",{"data-testid":"stAudio",id:"audio",ref:a,controls:!0,src:o,className:"stAudio",style:{width:r}})}}}]);