New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Media elements improvements #8203
Conversation
@kajarenc The end time and looping behavior work as expected, according to the specs 😄 LGTM |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM 👍 What happens if the configured end time or start time is larger than the video time?
e2e_playwright/st_audio_test.py
Outdated
audio_element.evaluate("el => el.play()") | ||
app.wait_for_timeout(5000) | ||
expect(audio_element).to_have_js_property("paused", True) | ||
assert int(audio_element.evaluate("el => el.currentTime")) == 13 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: To prevent flakiness we probably need to use wait_until
method from conftest. See this as an example:
wait_until(app, check_dimensions) |
e2e_playwright/st_audio_test.py
Outdated
# approximately 17 (4 seconds until end_time and 2 seconds starting from start time) | ||
app.wait_for_timeout(6000) | ||
expect(audio_element).to_have_js_property("paused", False) | ||
assert 16 < audio_element.evaluate("el => el.currentTime") < 18 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as above :)
@pytest.mark.parametrize( | ||
"nth_element", | ||
[ | ||
pytest.param(5, marks=pytest.mark.skip_browser("webkit")), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
interesting :) didn't know this trick 👍
e2e_playwright/st_video_test.py
Outdated
# Wait until video will reach end_time | ||
app.wait_for_timeout(3000) | ||
expect(video_element).to_have_js_property("paused", True) | ||
assert int(video_element.evaluate("el => el.currentTime")) == 33 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Replace with wait_until
(see comments above)
e2e_playwright/st_video_test.py
Outdated
# 4 seconds until end_time and 2 seconds starting from start time | ||
app.wait_for_timeout(6000) | ||
expect(video_element).to_have_js_property("paused", False) | ||
assert 36 < video_element.evaluate("el => el.currentTime") < 38 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Replace with wait_until (see comments above)
if (loop) { | ||
youtubeUrl.searchParams.append("loop", "1") | ||
// When using the loop parameter, YouTube requires the playlist parameter to be set to the same video ID | ||
const videoId = youtubeUrl.pathname.split("/").pop() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does that work for all the different types of youtube URLs?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It should work with different youtube URLs, because we standardize URL on the backend
streamlit/lib/streamlit/elements/media.py
Line 268 in e1960fb
return f"https://www.youtube.com/embed/{code}" |
@@ -79,6 +81,10 @@ def audio( | |||
sample_rate: int or None | |||
The sample rate of the audio data in samples per second. Only required if | |||
``data`` is a numpy array. | |||
end_time: int | |||
The time at which this element should stop playing. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: Maybe add that its the number of seconds
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: in some other time-related parameters (e.g. ttl), we also support timedelta
and str
(parsed by Pandas) in addition to the number of seconds. Maybe also something to consider here:
This could work here as well, but maybe not the best fit
cc @snehankekre
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The smallest reasonable measure to configure a video/audio start/end time is probably seconds or? So no need to use float
here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The smallest reasonable measure to configure a video/audio start/end time is probably seconds or? So no need to use float here?
@LukasMasuch The currentTime
property of the HTMLMediaElement
interface from which HTMLVideoElement
inherits is specified in seconds according to the docs: https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/currentTime
And it can be set or returned as "a double-precision floating-point value indicating the current playback time in seconds", so we can support float
here. Should we do it in this PR or another one scoped specifically to this change?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we also support timedelta and str (parsed by Pandas) in addition to the number of seconds. Maybe also something to consider here
@LukasMasuch really good point! This is a suggestion Thiago also had when we presented these specs in office hours.
Supporting timedelta
objects from datetime and a string specifying the time in a format supported by Pandas's Timedelta constructor, in addition to seconds, would be nice for consistency across the API and will reduce the learning curve for new users.
+1 to supporting them.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That would let devs do things like:
import streamlit as st
from datetime import timedelta
start_time_td = timedelta(seconds=15)
end_time_td = timedelta(minutes=2, seconds=30)
st.video(data="video.mp4", start_time=start_time_td, end_time=end_time_td)
# Assuming in our internal implementation we call .total_seconds() on the timedelta objects
import streamlit as st
start_time_str = "15s"
end_time_str = "2m 30s"
# These values are parsed using Pandas's Timedelta constructor
st.video(data="video.mp4", start_time=start_time_str, end_time=end_time_str)
We raise an exception if end_time < start_time, but for end time or start time is larger than video length handled by the browser (and behavior is very expected). If start_time > video.length then the player on the last frame, but when you click play it starts from the beginning of the video. If end_time > video.length the player stops on the last frame of the video (if loop == True, we continue from start_time). |
Add end_time and loop parameters to st.audio and st.video
Describe your changes
Add
end_time
andloop
parameters tost.audio
andst.video
Specs:
End time https://www.notion.so/snowflake-corp/Spec-cf910f5811a84a6a9976d230c85a044e
Loop: https://www.notion.so/snowflake-corp/Spec-18bbbb288f4c4a0ba129d95eeb9c0260
GitHub Issue Link (if applicable)
Testing Plan
Contribution License Agreement
By submitting this pull request you agree that all contributions to this project are made under the Apache 2.0 license.