This document is no longer accurate.

Vimeo recently purchased Livestream and took away the API access. This document is no longer accurate, but will stay up for legacy purposes.

Experienced Programmers

If you are an experienced programmer looking for where to get the Livestream API, here you go:

https://api.new.livestream.com/

Everyone else, read on.

Main Content

A little ways back I wanted to follow a couple Livestream channels and download their videos. There is a program called yt-dlp which helped with the backlog, but as the channels update fairly frequently, I didn’t want to have to keep running yt-dlp on the channel page every week or whatever, or if I renamed the file on my end, didn’t want to redownload the file under the original name.

My first thought was seeing if Livestream had an API. I figured it did, but after finding nothing after a brief Google search, I called it quits. Enter late November 2022 when this urge strikes me again. I wondered if maybe I can use Python with BeautifulSoup to nail down the latest upload, seeing if maybe getting a list of links with a specific class can help me. Testing this in the CLI Python interpreter, I noticed something: the beginning of the file looks a lot like JSON.

Parsing through the output, I found that yes, it was JSON and within the JSON was a direct link to the API dashboards. Livestream’s API is https://api.new.livestream.com, and it’s pretty powerful.

Let’s take the European Space Agency’s page, for example. The following code snippet would get the information of latest video from the ESA’s Livestream page:

import requests
import json
## Livestream account 362 is the European Space Agency
url = "https://api.new.livestream.com/accounts/362"

acoountData = requests.get(url).json()
latestEvent = accountData["past_events"]["data"][0]

We use Python’s requests package (pip3 install requests) to get the data, and then parse it using JSON. The raw output of the information looks something like this:

{'id': 10685475, 'short_name': 'cm22', 'full_name': 'Council Meeting at Ministerial Level', 
. . .
'created_at': '2022-11-16T11:01:10.804Z', 'updated_at': '2022-11-23T15:41:14.070Z', 'expires_at': None, 'draft': False, 'start_time': '2022-11-22T08:00:00.000Z', 'end_time': '2022-11-23T16:00:00.000Z',
. . .
'guest_chat_enabled': False, 'privacy_freeze': False}

Now, we’re not there yet, but we’re getting close; we just need to grab the ID of the event. Then we can do the same thing, but with the event ID to get the information of the latest video.

eventID = latestEvent["id"]
eventURL = "https://api.new.livestream.com/accounts/362/events/{}".format(eventID)

eventsData = request.get(eventURL).json()
latestVid = eventsData["feed"]["data"][0]

And that will look something like this:

{'type': 'video', 'data': {'id': 233887194, 'event_id': 10685475, 'caption': 'CM22 Press Conference',
. . .
'created_at': '2022-11-23T15:16:19.728Z', 'updated_at': '2022-11  
-23T15:41:15.211Z', 'streamed_at': '2022-11-23T12:45:14.979Z', 'publish_at': '2022-11-23T15:16:00.000Z',
. . .
'm3u8_url': 'http://api.new.livestream.com/accounts/362/events/10685475/videos/233887194.m3u8?token=638a739e_8267c473b4bb39  
c2e44bfa08ec826a897eae6ab7', 'secure_m3u8_url': 'https://api.new.livestream.com/accounts/362/events/10685475/videos/233887194.  
secure.m3u8?token=638a739e_f3baeafab3b81975ef020897f4a4f0d20c0cc53c'}}

Eagle-eyed readers may see the .m3u8 links at the bottom, but I’ve not gotten those to work. Instead, because we already know the event ID and the Video ID, I grab the Video ID and put both into the main website’s structure.

Since none of the links within the API lead to the actual videos, we need to go back to the main site and figure out its structure for downloading the video. In this case, it’s /accounts/{account_number}/events/{event_number}/videos/{video_number}. So to download the latest video with yt-dlp would look something like this:

latestVidID = latestVid["id"]
latestVidURL = "https://livestream.com/accounts/362/events/{}/videos/{}".format(eventID, latestVidID)

From there I’ll use yt-dlp to download the videos and we can use some templates to change the filename. In this case, I want the ISO date the file was uploaded, as well as the title.

While we can’t import yt-dlp, we can use os.system to run the program for us.

import os
os.system('yt-dlp -o "%(upload_date>%Y-%m-%d)s - %(title)s.%(ext)s {}"'.format(latestVidURL))

At the time of this writing, the file downloaded would be named 2022-11-23 - CM22 Press Conference.mp4.

I won’t bore you with the logic of how the script will decide what should be grabbed, but after I get the code working, I will make a cron job or systemD timer and run the script once a day to check for updates and download them. For information on those, see my AACS Updater post, or checkout the WineReleaseBot Github repo.