Skip to content

Instantly share code, notes, and snippets.

@glubsy
Last active May 3, 2024 07:27
Show Gist options
  • Star 40 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save glubsy/744d3f91b80347b3f684d3dc2fcb12e2 to your computer and use it in GitHub Desktop.
Save glubsy/744d3f91b80347b3f684d3dc2fcb12e2 to your computer and use it in GitHub Desktop.
How to properly record Youtube & Twitch live streams

How to record Youtube live streams:

  • use livestream_saver to download from the first segment. Can also record membership-only streams by supplying it your cookies (uses yt-dlp to download)

  • use ytarchive which basically does the same thing, except a bit better.

  • use youtube_stream_capture. You can use cookies file to get member-only streams too. Be aware that this script currently fails to download chunks as soon as the stream has ended (this might be a bug).

  • or use live-dl which does monitoring of streams too. This is a wrapper around streamlink and yt-dlp.

How to record Twitch live streams:

  • streamlink, to download from the segment being broadcast currently
  • yt-dlp which downloads from the first segment BUT stops downloading once it reaches the currently broadcast segment (or maybe there is a way to avoid this, in which case, leave a comment).

A reliable way to get the best quality and not miss any data currently is this:

  • (RECOMMENDED) run streamlink in a loop with save_livestream.py script to download [x% ----> 100%]. Setting the retry delay to about 1 minute reduces the chance of missing a big chunk of the beginning of a stream, so this solution should be enough for now.

  • run yt-dlp to download from the beginning but lose the rest [0% ----> x%]. A script to handle this better would be nice.

  • Note: better download the best video quality possible for two reasons. 1) Audio quality depends on video quality ("progressive" streams) 2) Lower resolutions on Twitch are very poorly compressed, so it is better to compress ourselves.

  • Streams downloaded by streamlink-based solutions are in TS format which may cause issues with some players or when uploading to VOD services. You might want to convert them to mp4 (or whatever container you prefer) with ffmpeg like so: ffmpeg -i twitch_live.ts -c copy twitch_live.mp4

  • If you get warnings from streamlink saying Encountered a stream discontinuity. This is unsupported and will result in incoherent output data, the resulting .ts file will be corrupted. This is because of ads served by Twitch. The only way to avoid this is to pay the streamer for a subscription, then pass the following argument to streamlink: --twitch-api-header 'Authorization=OAuth YOUR_TOKEN'. You can get the header from your web browser's devtool while logged into Twitch. You can pass this argument to the save_livestream.py script by calling it like this:

python3 livestream_scripts/save_livestream.py --author-name 'nanobites' https://www.twitch.tv/nanobites_ "--twitch-api-header 'Authorization=OAuth YOUR_TOKEN'"

Video concatenation

In order to concatenate the videos (and audio) you will most likely need to fix the container files.

Example case: we have two recordings of the same live stream, one partial from the start, and one full but with muted audio segments. Exactly same audio and video codecs (1080p x264/aac). First, split the full video file at the (shared) junction timestamp.

# ffmpeg -i full.mp4 -ss 1:06:36.0 -c copy full_split.mp4

To avoid the "Non-monotonous DTS in output stream", we have to fix the containers by recreating them (do it for all of them just in case), use "-fflags +igndts" to regenerate DTS based on PTS:

# ffmpeg -i full_split.mp4 -fflags +igndts -c copy -movflags +faststart full_split_dts_fix.mp4
# ffmpeg -i start.mp4 -fflags +igndts -c copy -movflags +faststart start_dts_fix.mp4

Then concatenate with the concat demuxer as normal (create list.txt with files to concatenate)

# ffmpeg -f concat -safe 0 -i list.txt -c copy -movflags +faststart final_full.mp4

Then compress the video, but keep audio (and reduce fps from 60 to 30 while we are at it):

# ffmpeg -i final_full -c:v libx264 -crf 30 -vf scale=iw/3:ih/3 -c:a copy -r 30 final_compressed.mp4

Cookies extraction

To extract from Firefox you may use this: https://github.com/rotemdan/ExportCookies (add-on page)

To extract from Chromium-based browsers: https://github.com/dandv/convert-chrome-cookies-to-netscape-format

If you use streamlink, you may want to avoid passing cookies as arguments, in which case you can create the following file ~/.config/streamlink/config.twitch:

twitch-api-header=Authorization=OAuth <auth_token value>

This is especially useful if you use the save_livestream.py script mentioned above.

@glubsy
Copy link
Author

glubsy commented Jul 19, 2023

As of 2023/07/20, the /live tab in Youtube is redirecting to /streams, which unfortunately breaks the following yt-dlp based solution:

while true; do yt-dlp --fragment-retries 50 -o '%(upload_date)s [%(uploader)s] %(title)s [%(height)s][%(id)s].%(ext)s' -ciw -f 'bestvideo+bestaudio' --add-metadata --embed-thumbnail --live-from-start --match-filter 'is_live' 'https://www.youtube.com/@inukaipuwin/live'; sleep $((10*60)); done

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