Skip to content

YouTube Live Streaming API - minimal working example #202

Open

Description

@sgbaird

@Jonathan-Woo could you work on creating a minimal working example for use of the YouTube Live Streaming API? This would be standalone from the Raspberry Pi devices and manifest as two files:

  1. Create the new stream, add it to a specified playlist, and return the stream URL and stream key
  2. Find the latest stream that matches the piece of equipment (open to thoughts on "how")

These can get added to a separate folder within src, called yt_livestream_api

I think everything you need to get started is covered at:

  1. Equipment monitoring for Opentrons OT-2 (camera stream to YouTube) #80 (comment)
  2. Equipment monitoring for Opentrons OT-2 (camera stream to YouTube) #80 (comment)

It would be great if you could start small, document, and then progressively work up to the full implementation.

Once we have a handle on it, then we'll merge with the RPi Zero 2W monitoring cameras

Activity

  1. sgbaird commented on Mar 23, 2025

    @sgbaird
    CollaboratorAuthor

    Cc @Neil-YL - once we get the livestreaming API figured out, I think we'll be able to expand to ~6+ livestreams going simultaneously, relevant for other demos such as pioreactor and mycobot.

  2. Neil-YL commented on Mar 24, 2025

    @Neil-YL
    Contributor

    Both streaming went down during the weekend, should I restart it?
    Not sure where the logs were stored when running with auto-start and if a restart will overwrite the logs or not.

  3. sgbaird commented on Mar 24, 2025

    @sgbaird
    CollaboratorAuthor

    Hmm.. You can use instructions in the README (some kind of journal command) to check the logs. My guess is it still restarted (and has been trying to restart), but can't until it has a new stream available, since yt shuts it down so quickly if it stops receiving data. If I set it up correctly, it's meant to only retry up to 3 times per 8 hours.

  4. Neil-YL commented on Mar 24, 2025

    @Neil-YL
    Contributor

    Hmm.. You can use instructions in the README (some kind of journal command) to check the logs. My guess is it still restarted (and has been trying to restart), but can't until it has a new stream available, since yt shuts it down so quickly if it stops receiving data. If I set it up correctly, it's meant to only retry up to 3 times per 8 hours.

    From previous experience, YT provides quite a bit of room for the streaming device to reconnect if it receives no data. I have turned off auto-stop, so it will not end immediately.

    I think I could set up a new stream but don't touch the Pi to see if the new stream can receive data.

  5. Jonathan-Woo commented on Mar 24, 2025

    @Jonathan-Woo
    Contributor

    @Jonathan-Woo could you work on creating a minimal working example for use of the YouTube Live Streaming API? This would be standalone from the Raspberry Pi devices and manifest as two files:

    1. Create the new stream, add it to a specified playlist, and return the stream URL and stream key
    2. Find the latest stream that matches the piece of equipment (open to thoughts on "how")

    These can get added to a separate folder within src, called yt_livestream_api

    I think everything you need to get started is covered at:

    1. Equipment monitoring for Opentrons OT-2 (camera stream to YouTube) #80 (comment)
    2. Equipment monitoring for Opentrons OT-2 (camera stream to YouTube) #80 (comment)

    It would be great if you could start small, document, and then progressively work up to the full implementation.

    Once we have a handle on it, then we'll merge with the RPi Zero 2W monitoring cameras

    Yep I'm working on this this week.

  6. Neil-YL commented on Mar 24, 2025

    @Neil-YL
    Contributor

    Mar 21 21:11:51 rpi-zerow2-ot2-stream python3[604]: [flv @ 0x5597449a50] Failed to update header with correct duration.
    Mar 21 21:11:51 rpi-zerow2-ot2-stream python3[604]: [flv @ 0x5597449a50] Failed to update header with correct filesize.
    Mar 21 21:11:51 rpi-zerow2-ot2-stream python3[604]: Error writing trailer of rtmp://a.rtmp.youtube.com/live2/ydj7-frx3-u6p3-8z4z-f6jp: Network is unreachable
    Mar 21 21:11:51 rpi-zerow2-ot2-stream python3[604]: frame=344291 fps= 14 q=-1.0 Lsize= 1884843kB time=06:22:39.93 bitrate= 672.5kbits/s speed=0.96x
    Mar 21 21:11:51 rpi-zerow2-ot2-stream python3[604]: video:1855851kB audio:5858kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 1.242629%
    Mar 21 21:11:51 rpi-zerow2-ot2-stream python3[604]: Error closing file rtmp://a.rtmp.youtube.com/live2/ydj7-frx3-u6p3-8z4z-f6jp: Broken pipe
    Mar 21 21:11:51 rpi-zerow2-ot2-stream python3[604]: [aac @ 0x55973e72f0] Qavg: 65536.000
    Mar 21 21:11:51 rpi-zerow2-ot2-stream python3[604]: Conversion failed!
    Mar 21 21:11:53 rpi-zerow2-ot2-stream systemd[1]: picam.service: Deactivated successfully.
    Mar 21 21:11:53 rpi-zerow2-ot2-stream systemd[1]: picam.service: Consumed 1h 41min 584ms CPU time.

    The logs seems it did not retry after the Broken pipe error

    and the service is inactive

    ac@rpi-zerow2-ot2-stream:~ $ sudo systemctl status picam.service
    ○ picam.service - Start picam device.py script
    Loaded: loaded (/etc/systemd/system/picam.service; enabled; preset: enabled)
    Active: inactive (dead) since Fri 2025-03-21 21:11:53 EDT; 2 days ago
    Duration: 6h 38min 58.311s
    Process: 562 ExecStart=/home/ac/ac-training-lab/src/ac_training_lab/picam/venv/bin/python3 device.py (code=exited, status=0/SUCCESS)
    Main PID: 562 (code=exited, status=0/SUCCESS)
    CPU: 1h 41min 584ms

    Same for the A1mini

    ○ picam.service - Start picam device.py script
    Loaded: loaded (/etc/systemd/system/picam.service; enabled; preset: enabled)
    Active: inactive (dead) since Thu 2025-03-20 20:09:15 EDT; 3 days ago
    Duration: 21h 38min 46.101s
    Process: 576 ExecStart=/home/ac/ac-training-lab/src/ac_training_lab/picam/venv/bin/python3 device.py (code=exited, status=0/SUCCESS)
    Main PID: 576 (code=exited, status=0/SUCCESS)
    CPU: 6h 24min 24.599s

    Mar 20 20:09:12 rpi-zero2w-a1mini-stream python3[614]: [flv @ 0x55b5d78c90] Failed to update header with correct duration.
    Mar 20 20:09:12 rpi-zero2w-a1mini-stream python3[614]: [flv @ 0x55b5d78c90] Failed to update header with correct filesize.
    Mar 20 20:09:12 rpi-zero2w-a1mini-stream python3[614]: Error writing trailer of rtmp://a.rtmp.youtube.com/live2/902j-wzqz-sdz1-7de6-fpc0: Br>
    Mar 20 20:09:12 rpi-zero2w-a1mini-stream python3[614]: frame=1168737 fps= 15 q=-1.0 Lsize= 9609552kB time=21:38:35.23 bitrate=1010.3kbits/s >
    Mar 20 20:09:12 rpi-zero2w-a1mini-stream python3[614]: video:9511148kB audio:19879kB subtitle:0kB other streams:0kB global headers:0kB muxin>
    Mar 20 20:09:12 rpi-zero2w-a1mini-stream python3[614]: Error closing file rtmp://a.rtmp.youtube.com/live2/902j-wzqz-sdz1-7de6-fpc0: Broken p>
    Mar 20 20:09:12 rpi-zero2w-a1mini-stream python3[614]: [aac @ 0x55b5d169f0] Qavg: 65536.000
    Mar 20 20:09:12 rpi-zero2w-a1mini-stream python3[614]: Conversion failed!
    Mar 20 20:09:15 rpi-zero2w-a1mini-stream systemd[1]: picam.service: Deactivated successfully.
    Mar 20 20:09:15 rpi-zero2w-a1mini-stream systemd[1]: picam.service: Consumed 6h 24min 24.599s CPU time.

  7. sgbaird commented on Mar 24, 2025

    @sgbaird
    CollaboratorAuthor
  8. Jonathan-Woo commented on Mar 28, 2025

    @Jonathan-Woo
    Contributor

    Schematic of discussed approach:

    Image

  9. sgbaird commented on Mar 28, 2025

    @sgbaird
    CollaboratorAuthor

    Lmk how it goes!

  10. sgbaird commented on Mar 31, 2025

    @sgbaird
    CollaboratorAuthor

    @Jonathan-Woo do you have a status update on this / what you've tried?

  11. sgbaird commented on Apr 1, 2025

    @sgbaird
    CollaboratorAuthor

    Given @Jonathan-Woo's constraints, @Neil-YL do you mind taking a stab at this today? (Just a minimal working example as a Python script or notebook, and if you could share the API key over slack, if applicable)

  12. Neil-YL commented on Apr 1, 2025

    @Neil-YL
    Contributor

    Given @Jonathan-Woo's constraints, @Neil-YL do you mind taking a stab at this today? (Just a minimal working example as a Python script or notebook, and if you could share the API key over slack, if applicable)

    Sure. I will look into that.

  13. Neil-YL commented on Apr 1, 2025

    @Neil-YL
    Contributor

    Documentation on YouTube API Setup

    YouTube Data API, API Key and OAuth 2.0 Setup

    Official getting started documentation of YouTube Data API: https://developers.google.com/youtube/v3/live/getting-started

    OAuth 2.0 is required to access all features of the YouTube Data API.

    Below is a step-by-step guide on how to enable YouTube Data API, obtain API Key, configure OAuth in the Google Cloud Console and generate a token.pickle file on your local machine.

    You can complete this setup using your own Google account — it doesn't have to be the same account as the YouTube channel owner (but you do need to know the owner account email).


    Create a Google Cloud Project

    1. Go to the Google Cloud Console.
    2. Click the project dropdown (top left) and select "New Project".
    3. Give the project a name (e.g., YouTube Stream) and click Create.
    Image

    Enable YouTube Data API v3

    1. In your newly created project, go to APIs & Services then Library on the left.
    2. Search for YouTube Data API v3.
    3. Click on it, then click Enable.
    Image

    Obtain API Key

    1. Navigate to APIs & Services > Credentials.
    2. Create an API Key
    Image
    1. On the list of the API Keys, select your newly created API key and click three dots under Actions > Edit API Key
    2. Give it a preferred name and turn on API restrictions, then select YouTube Data API v3.
    Image

    Note: API key will be used for public data access on YouTube, for management level features like starting stream or add video to playlist, you will need OAuth for account authentication. Continue with following steps for OAuth set up.

    Configure OAuth Consent Screen

    1. Navigate to APIs & Services > OAuth consent screen.
    Image
    1. Fill in the following required fields:
      • App name: (e.g., YouTube Stream API)
      • User support email: your email
    2. Audience: select External.
    3. Contact Information: your email.
    4. Click Continue until you reach Finish, then click Create

    Create OAuth 2.0 Client

    1. Go to Clients on the left.
    Image
    1. Click Create Clients > OAuth client ID.
    2. Choose Desktop App as the application type.
    3. Give it a name (e.g., Stream Auth) and click Create.
    4. An OAuth Client page will pop up. Click “Download JSON” and save the file as client_secrets.json.
    Image

    Add Test Users

    1. Close the OAuth Client page, in the OAuth consent screen, go to Audience on the left , scroll down to Test users.
    Image
    1. Add the mail address of the owner account of the YouTube channel. (YouTube API can only work with the main channel under OAuth)

    Generate token.pickle from OAuth JSON

    After creating your OAuth 2.0 credentials in Google Cloud and downloading the client_secrets.json file, follow these steps to generate a token.pickle file for future API access.

    1. On your local IDE (e.g., VS Code), install google-auth-oauthlib via pip:
    pip install google-auth-oauthlib
    1. Place the downloaded client_secrets.json in your working directory.
    2. Run the following Python script (get_token.py):
    from google_auth_oauthlib.flow import InstalledAppFlow
    import pickle
    
    SCOPES = ['https://www.googleapis.com/auth/youtube.force-ssl']
    
    def main():
        flow = InstalledAppFlow.from_client_secrets_file(
            'client_secrets.json', SCOPES
        )
        creds = flow.run_local_server(port=0)
    
        with open('token.pickle', 'wb') as token_file:
            pickle.dump(creds, token_file)
            print("Saved token to token.pickle")
    
    if __name__ == '__main__':
        main()
    1. After you run the script, a browser window will open to let you sign in and authorize access, please use the same account in the previous Audience > Test users set up, not the Google Cloud Project account (if they are different).

    2. You will see a page says "Google hasn’t verified this app". If you're testing it yourself and everything is under your control, it's safe to click Continue and proceed.

    3. After successful login, a token.pickle file will be saved locally. This token will be used in your application to authenticate YouTube API requests without needing to re-login.

    Quota on using YouTube API

    The YouTube Data API uses a quota system. Projects that enable the YouTube Data API have a default quota allocation of 10,000 units per day, an amount sufficient for the majority of our API users.


    I’ve tested it under the same account, but if anyone would like to follow this documentation and share feedback (in case that I missed any previous setting), it would be greatly appreciated.

  14. sgbaird commented on Apr 1, 2025

    @sgbaird
    CollaboratorAuthor

    Nice! Do you have a link that served as a starting point for these instructions? Also, I'm realizing we can probably port this over to the README within picam/.

  15. sgbaird commented on Apr 1, 2025

    @sgbaird
    CollaboratorAuthor

    Any follow-up thoughts on how to retrieve the "latest stream" from a particular playlist? Not sure what kind of metadata we can extract related to the playlists.

  16. Neil-YL commented on Apr 1, 2025

    @Neil-YL
    Contributor

    Nice! Do you have a link that served as a starting point for these instructions? Also, I'm realizing we can probably port this over to the README within picam/.

    starting point: https://developers.google.com/youtube/v3/live/getting-started
    Most of the setup will be on Google Cloud Console. If everything is going to be under our account (AC Hardware Streams) , you won’t need to repeat this process—but it will be required for any other YouTube channels.

  17. Neil-YL commented on Apr 1, 2025

    @Neil-YL
    Contributor

    Any follow-up thoughts on how to retrieve the "latest stream" from a particular playlist? Not sure what kind of metadata we can extract related to the playlists.

    I will get into it tomorrow as well. I believe (hopefully) it would be something with a simpler API-KEY if we would like to use it on the Hugging Face. OAuth2.0 is required to start and manage stream/video.

  18. sgbaird commented on Apr 2, 2025

    @sgbaird
    CollaboratorAuthor

    Technically I think we could have a separate cloud service (i.e., virtual machine) running 24/7 that monitors for when streams go down and then reinstantiates them when they do. This could handle streams across all devices, and then the devices could just worry about retrieving stream keys rather than starting streams. More from an access/security/limiting scope point of view. Thoughts?

    I'm ok with sticking with having the pickle file on each streaming device.

    Aside: the owner account was my AC Gmail.

  19. Neil-YL commented on Apr 2, 2025

    @Neil-YL
    Contributor

    Have a update on the API key setup on the documentation above

  20. sgbaird commented on Apr 2, 2025

    @sgbaird
    CollaboratorAuthor

    Great! Were you able to verify that the API key is usable? (I would imagine it's fine)

  21. Neil-YL commented on Apr 3, 2025

    @Neil-YL
    Contributor

    Great! Were you able to verify that the API key is usable? (I would imagine it's fine)

    I've tested it with a colab demo on getting latest video from a playlist. Very easy to implement.

    Image
  22. Neil-YL commented on Apr 3, 2025

    @Neil-YL
    Contributor
  23. sgbaird commented on Apr 3, 2025

    @sgbaird
    CollaboratorAuthor

    Aside: we chatted about unique naming, and likely that we'll add something related to serial number (probably RPi, could encrypt first if we want to) to both the hostname (since it's the same tailscale) and as a way to distinguish devices on the YouTube streaming side. On our end, we decide which camera faces which equipment (which could be multiple), and we can reconfigure at will, which puts that relationship on us to track and record. YouTube limits to 5000 videos per playlist (mostly due to constraints on RAM for Chrome, etc.), which gives us ~4.5 years assuming 8 hour chunks and minimal sub-divisions of the 8 hours (i.e., no 5a, 5b - type splits due to failures).

    Current example of a hostname: rpi-zero2w-a1mini-stream, which also gets a bit problematic if we want to rearrange things. However, easy mid-term solution is to append some unique ID at the end.

  24. Neil-YL commented on Apr 4, 2025

    @Neil-YL
    Contributor
    Image

    Stream started by API has this pop-up on YouTube Studio. Will look into it later.

  25. Neil-YL commented on Apr 4, 2025

    @Neil-YL
    Contributor
    Image Stream started by API has this pop-up on YouTube Studio. Will look into it later.

    Quote from https://stackoverflow.com/questions/59412711/how-to-set-made-for-children-in-youtube-api:

    September 21, 2020
    The definition of the liveBroadcast resource's status.madeForKids property has been updated to clarify that the property is read-only. This does not reflect a change in API functionality.

    To designate a live broadcast as being child-directed, set the status.selfDeclaredMadeForKids property to true when calling the liveBroadcasts.insert method to create the broadcast.

    Added to start stream colab

  26. sgbaird commented on Apr 4, 2025

    @sgbaird
    CollaboratorAuthor

    Could you include the colab links here? (Maybe I missed it from above) - ok if it's private to the two of us, just for convenience

  27. sgbaird commented on Apr 5, 2025

    @sgbaird
    CollaboratorAuthor

    I added video lookup to OT-2 hugging face

    Unrelated EDIT (to avoid triggering notification): #80 (comment) has some documentation about channel setup, which we might want to incorporate into docs

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions