Skip to content

Instantly share code, notes, and snippets.

@glubsy
Last active November 16, 2024 20:15
Show Gist options
  • 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.

Download chat messages

If you know a program that downloads chat messages while the stream is live, please leave a comment.

Currently, the only reliable way of downloading chat messages is to use yt-dlp with the following arguments to generate a JSON file. The JSON file can be compressed afterward. For example: bzip2 *.json.

yt-dlp --skip-download --write-subs --sub-langs "live_chat" -o "%(upload_date)s [%(uploader)s] %(title)s [%(id)s].%(ext)s" <video_id>

Known downside: this only works after the video has become a VOD, it won't work during live stream.

This is an example script that does this automatically: glubsy/ytdl_batch/subs.py

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'"

Download chat messages

If you know a program that downloads chat messages while the stream is live, please leave a comment.

Once a stream has become a VOD, you may use TwitchDownloader. You can embed the emoticons inside the resulting chat log for archival purposes with the -E or --embed-images parameter. For example:

TwitchDownloader chatdownload --id $video_Id -E -o $video_Id.json

This is an example script that does this automatically: glubsy/ytdl_batch/subs.py

Video tracks 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.

@Qwerty-Space
Copy link

Do you have any recommendations for monitoring Twitch channels to start recording when they go live?

@glubsy
Copy link
Author

glubsy commented Nov 16, 2024

@Qwerty-Space as mentioned in the guide, I recommend https://github.com/mrwnwttk/livestream_scripts which is just a basic script that starts Streamlink every 40 seconds.
Although you could achieve the same thing with a systemd unit I suppose.

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