Streamlit Player

Hello there :wave:

Have you ever wanted to integrate YouTube videos directly in your Streamlit apps? This is now possible with Streamlit Player :tada:

This component makes it possible to embed video and music players from many platforms: Youtube, Facebook, Twitch and SoundCloud to name a few. Streamlit Player works thanks to a great React component: React Player

Installation

pip install streamlit-player

Quick usage

from streamlit_player import st_player

# Embed a youtube video
st_player("https://youtu.be/CmSKVW1v0xM")

# Embed a music from SoundCloud
st_player("https://soundcloud.com/imaginedragons/demons")

Demo

Interested to see Streamlit Player in action? You can try it out now in Streamlit Sharing!

Demo’s source code and component’s documentation are also available there.


:link: Links

GitHub - Streamlit Player

GitHub - React Player

8 Likes

That’s really cool, seems like it didn’t take much effort at all on the Python side! What did you think about how the process of generating the component? Is there anything you’d suggest to us from an API perspective, or to users who might want to create their own component?

Making that component was quite simple. I’m not a web developer, I have almost no experience with React, yet it was really easy to wrap a react component to use it in a streamlit app. Great work on this!

My real interrogation was regarding where would be the best place to filter props and events like I did. I’ve done it python-side for now, but maybe for some reason it’d be better to do that sort of filtering react-side. Later, it’d be great in a best practice doc to have some rationale on where some specific logic should be implemented.

Other than that, regarding the API, I should play a little bit more with it to see what could be improved.

3 Likes

Hey! Just a small update to say that the react component I’m using to render videos doesn’t work without an iframe with allow-same-origin.

However, as suggested by tim here, we could serve this component from another local server. And unlike Disqus, the auto-height issue shouldn’t matter here.

How to use it? I mean I know python much better than React or even Javascript so is there a simple pip install that can make this react player avaiable to my web app or do I need to integrate the javascript and react code separately?

Thanks,
Travis

Hello @Travis_Horine,

Glad you’re interested in this component, but unfortunately it is not functional at the moment.
The embedding of remote services (like disqus, youtube, twitch, etc.) used to work with the beta version of the components API, but it is not possible anymore for security reasons.

Some workarounds may exist, but weren’t implemented yet in any component AFAIK.

@okld @randyzwitch

Hello,

Thanks for sharing this code which I found useful on two counts: using React (my first time) and the Streamlit component wrapper with property passing and eventing (I hadn’t understood how that works until I understood React’s component rendering life cycle).

I’m using the React app to forward an API call to a service (currently a simple Flask app with a /api/ping endpoint). In the Streamlit app browser dev tools I can see the ping return data, but finding it impossible to return the data in the fetch (tried axios too), and so can’t send this data back to Streamlit.

Here’s the React code. I think I’ve set all CORS headers correctly in the fetch(). Do you have any ideas? (There is a React proxy forwarding URL in package.json for the /api/ping API call.)

import React, { useState, useEffect } from 'react';
import './App.css';
import {
  withStreamlitConnection,
  ComponentProps,
  Streamlit,
} from "streamlit-component-lib";

let numClicks = 0
let hostname = 'No Name'
let action = 'Go!'
let message = 'No Message'

function PingApp(props: ComponentProps) {

  if ('hostname' in props.args) {
    hostname = props.args.hostname
    delete props.args.hostname
  }
  if ('action' in props.args) {
    action = props.args.action
    delete props.args.action
  }
  if ('initial_state' in props.args) {
    message = props.args['initial_state']['message']
    delete props.args.initial_state
  }

  if ("events" in props.args) {
    props.args.events.forEach((event: string) => {
      props.args[event] = (data?: any) => {
        Streamlit.setComponentValue({
          name: event,
          data: data
        })
      }
    })

    delete props.args.events
  }

  useEffect(() => {
    Streamlit.setFrameHeight()
  })

  const [state, setState] = useState({hostname: hostname, numClicks: numClicks, message: message, isError: false, error: ''})
  const [ping, setPing] = useState('No Ping')
  const [clicks, setClicks] = useState(numClicks)

  useEffect(() => {
    // https://javascript.info/async
    fetch('/api/ping', {
      credentials: 'same-origin',
      mode: 'no-cors',
      headers: {
        'Accept':'text/plain',
        'Content-Type': 'text/plain',
        'Access-Control-Allow-Origin': '*'
      }
    })
    .then(resp => resp.text())
    .then(data => setPing(data))

    message = ping + '(' + numClicks +')'

  }, [clicks, ping]);

  useEffect(() => {
    setState({hostname: hostname, numClicks: numClicks, message: message, isError: false, error: ''})
  }, [clicks, ping])

  useEffect(() => {
    Streamlit.setComponentValue({name: 'onStatusUpdate', data: state})
  }, [state])

  const handleClick = async () => {
    setClicks(numClicks += 1)
  }
  
  return (
    <div className="App">
      <header className="App-header">
          <div>
            <span>App Host: {hostname}</span>
          </div>
            <button onClick={handleClick}>{action}</button>
          <div>
            <span>Ping Message: {state.message}</span>
          </div>
      </header>
    </div>
  );
}

export default withStreamlitConnection(PingApp)
1 Like

With Streamlit 0.73 out, this component was updated and can now be used in your apps :tada:

4 Likes

@okld, this extension nice, so can I get frame (image) from raw data of video? Example take picture at 39th second

{
  "name": "onProgress",
  "data": {
    "playedSeconds": 39.047498,
    "played": 0.007432803625689339,
    "loadedSeconds": 103.703,
    "loaded": 0.019740164514378402
  }
}

Hi,
I love this feature!
However I am having a hard time implementing live video from Twitch
 I do add the “parent” argument in the url but the player isn’t working. Do you have a suggestion?

Thanks again !

Hey, I’ve been searching for a different video player for my app because I need interactivity with my videos - both to get the current timestamp, which this one seems to do nicely, but I also want to be able to tell it a timestamp to start playing at. Is that possible with this component, and if so, how?

It works pretty well with youtube, soundcloud and other websites but I am not able to play local mp4 or mp3 files. I tried giving the relative and absolute paths to the files
any idea what’s going wrong?

I tried:
st_player('x.mp3)
st_player(‘path/from/home/x.mp3’)
st_player(‘file:///x.mp3’)

Would appreciate help here.

AFAIK local files are not supported.
See this github issue for some possible workarounds:

you can also achieve this using streamlit-elements, which I am using, since its using the same react player, but the overall widget size seems a little smaller which better suits my purposes, i need to figure out overall size management of the widget,

and now wrapping the whole widget inside st.experimental fragment will allow you to play the content independently of other page interactions. :slight_smile:


url = "https://soundcloud.com/rick-astley-official/never-gonna-give-you-up-4"
   @st.experimental_fragment
    def return_music_player(url):
        st.subheader("Track o the Week.")
        with elements("media_player"):

            # Play video from many third-party sources: YouTube, Facebook, Twitch,
            # SoundCloud, Streamable, Vimeo, Wistia, Mixcloud, DailyMotion and Kaltura.
            #
            # This element is powered by ReactPlayer (GitHub link below).

            from streamlit_elements import media

            media.Player(url=url, controls=True)
    return_music_player(url=url)
1 Like