Skip to content

Instantly share code, notes, and snippets.

Last active March 26, 2024 12:31
Show Gist options
  • Save junian/b41dd8e544bf0e3980c971b0d015f5f6 to your computer and use it in GitHub Desktop.
Save junian/b41dd8e544bf0e3980c971b0d015f5f6 to your computer and use it in GitHub Desktop.
Record Twitch Streams Automatically in Python
# This code is based on tutorial by slicktechies modified as needed to use oauth token from Twitch.
# You can read more details at:
# original code is from
import requests
import os
import time
import json
import sys
import subprocess
import datetime
import getopt
class TwitchRecorder:
def __init__(self):
# global configuration
self.client_id = "jzkbprff40iqj646a697cyrvl0zt2m6" # don't change this
# get oauth token value by typing `streamlink --twitch-oauth-authenticate` in terminal
self.oauth_token = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
self.ffmpeg_path = 'ffmpeg'
self.refresh = 30.0
self.root_path = "/Users/junian/Documents/twitch"
# user configuration
self.username = "juniantr"
self.quality = "best"
def run(self):
# path to recorded stream
self.recorded_path = os.path.join(self.root_path, "recorded", self.username)
# path to finished video, errors removed
self.processed_path = os.path.join(self.root_path, "processed", self.username)
# create directory for recordedPath and processedPath if not exist
if(os.path.isdir(self.recorded_path) is False):
if(os.path.isdir(self.processed_path) is False):
# make sure the interval to check user availability is not less than 15 seconds
if(self.refresh < 15):
print("Check interval should not be lower than 15 seconds.")
self.refresh = 15
print("System set check interval to 15 seconds.")
# fix videos from previous recording session
video_list = [f for f in os.listdir(self.recorded_path) if os.path.isfile(os.path.join(self.recorded_path, f))]
if(len(video_list) > 0):
print('Fixing previously recorded files.')
for f in video_list:
recorded_filename = os.path.join(self.recorded_path, f)
print('Fixing ' + recorded_filename + '.')
try:[self.ffmpeg_path, '-err_detect', 'ignore_err', '-i', recorded_filename, '-c', 'copy', os.path.join(self.processed_path,f)])
except Exception as e:
except Exception as e:
print("Checking for", self.username, "every", self.refresh, "seconds. Record with", self.quality, "quality.")
def check_user(self):
# 0: online,
# 1: offline,
# 2: not found,
# 3: error
url = '' + self.username
info = None
status = 3
r = requests.get(url, headers = {"Client-ID" : self.client_id}, timeout = 15)
info = r.json()
if info['stream'] == None:
status = 1
status = 0
except requests.exceptions.RequestException as e:
if e.response:
if e.response.reason == 'Not Found' or e.response.reason == 'Unprocessable Entity':
status = 2
return status, info
def loopcheck(self):
while True:
status, info = self.check_user()
if status == 2:
print("Username not found. Invalid username or typo.")
elif status == 3:
print("%Hh%Mm%Ss")," ","unexpected error. will try again in 5 minutes.")
elif status == 1:
print(self.username, "currently offline, checking again in", self.refresh, "seconds.")
elif status == 0:
print(self.username, "online. Stream recording in session.")
filename = self.username + " - " +"%Y-%m-%d %Hh%Mm%Ss") + " - " + (info['stream']).get("channel").get("status") + ".mp4"
# clean filename from unecessary characters
filename = "".join(x for x in filename if x.isalnum() or x in [" ", "-", "_", "."])
recorded_filename = os.path.join(self.recorded_path, filename)
# start streamlink process["streamlink", "--twitch-oauth-token", self.oauth_token, "" + self.username, self.quality, "-o", recorded_filename])
print("Recording stream is done. Fixing video file.")
if(os.path.exists(recorded_filename) is True):
try:[self.ffmpeg_path, '-err_detect', 'ignore_err', '-i', recorded_filename, '-c', 'copy', os.path.join(self.processed_path, filename)])
except Exception as e:
print("Skip fixing. File not found.")
print("Fixing is done. Going back to checking..")
def main(argv):
twitch_recorder = TwitchRecorder()
usage_message = ' -u <username> -q <quality>'
opts, args = getopt.getopt(argv,"hu:q:",["username=","quality="])
except getopt.GetoptError:
print (usage_message)
for opt, arg in opts:
if opt == '-h':
elif opt in ("-u", "--username"):
twitch_recorder.username = arg
elif opt in ("-q", "--quality"):
twitch_recorder.quality = arg
if __name__ == "__main__":
Copy link

junian commented Jan 19, 2017

For complete tutorial and explanation about this gist, you can visit my blog post here: How to Record Twitch Streams Automatically in Python

Copy link

Possible to have it NOT record if it's a hosted stream?
It seems like that's the intended behavior, but on occasion, it actually does trigger a save during a hosted stream.

Copy link

ahmyboi commented Jun 13, 2017

Hi im experiencing issues. please help Here is my erro code:

File "C:\Users\Freddy\AppData\Local\Programs\Python\Python36-32\lib\", line 990, in _execute_child
FileNotFoundError: [WinError 2] Das System kann die angegebene Datei nicht finden

it cant find a file, what file?

there have been many traceback errors or they relevant?

Checking for imaqtpie every 30.0 seconds. Record with best quality.
imaqtpie online. Stream recording in session.
Traceback (most recent call last):
File "C:\Users\Freddy\Desktop\TwitchMomentsGetter\", line 148, in
File "C:\Users\Freddy\Desktop\TwitchMomentsGetter\", line 145, in main
File "C:\Users\Freddy\Desktop\TwitchMomentsGetter\", line 65, in run
File "C:\Users\Freddy\Desktop\TwitchMomentsGetter\", line 112, in loopcheck["streamlink", "--twitch-oauth-token", self.oauth_token, "" + self.username, self.quality, "-o", recorded_filename])
File "C:\Users\Freddy\AppData\Local\Programs\Python\Python36-32\lib\", line 267, in call
with Popen(*popenargs, **kwargs) as p:
File "C:\Users\Freddy\AppData\Local\Programs\Python\Python36-32\lib\", line 707, in init
restore_signals, start_new_session)

Copy link

oLaudix commented Jan 5, 2018

python twitch-recorder --user=geekandsundry
C:\Program Files\Python36\python.exe: can't open file 'twitch-recorder': [Errno 2] No such file or directory

python --user=geekandsundry
Traceback (most recent call last):
File "", line 5, in
import requests
ModuleNotFoundError: No module named 'requests'

Any idea why this is happening or how to fix it? I have streamlink and python installed but can't get it to work
Im on Windows.

Copy link

File "", line 5, in import requests ModuleNotFoundError: No module named 'requests'
I am getting the same error, does anyone know how to fix it? I'm unfamiliar with python, I'm more knowledgeable about c style programming languages.

Copy link

nemsia commented Nov 9, 2018

to remove hosted channel, add this on line 111:

Copy link

What would cause the unexpected error?

Copy link

If you don't want the script to record reruns, add the following two lines after line 79:
elif info['stream']['stream_type'] == 'rerun':
status = 1

Copy link

M08s commented Nov 2, 2019

Anyone else have the problem where the loop stops looping and freezes on a "USER currently offline, check again in X seconds." ?

Copy link

How long is your interval set?
You might be sending queries too quickly.
I use an interval of 15,1 seconds and it works fine.

Copy link

LPLe21 commented Nov 22, 2019

I've recently been getting a 410 Client Error. The old URL doesn't seem to work anymore.

Copy link

Yes, I can confirm that. Twitch recently started changing many things and the Kraken API is one of them.
Other software has similar problems. Twitch Leecher for example shows the exact same error 410.
I don't think we can do anything about it until someone engineers his way back into their new API.

Copy link

LPLe21 commented Nov 26, 2019

@Kampfsemmel Thanks for letting us know.

Copy link

EnterGin commented Dec 4, 2019

@Kampfsemmel Thanks for letting us know.

You can use my version of script. It has more features and has no delay before recording.

Copy link

LPLe21 commented Dec 27, 2019

@EnterGin Thanks for the link. I think the 410 Client Error was caused by my install of Streamlink 1.3.0.

Copy link

@LPLe21 yes, update Streamlink.

Copy link

z7wish7z commented Jun 5, 2020

hello, since yesterday 2020/06/05, the code doesn't work anymore
got status 3: error causing unexpected error
i think its because the kraken API used won't accept twitch display name as self.username anymore, it requires channel "_id" instead

john@WisH:~/streamlink$ python3
Checking for verizon every 15.1 seconds. Record with best quality.
09h11m06s unexpected error. will try again in 5 minutes.

Copy link

starvald commented Jun 5, 2020

confirming what @z7wish7z posted.

Copy link

Third confirmation, it stopped working for me on June 4th 2020 with the same error. Are there any alternatives or is it possible to (easily) change this code?

Copy link

ancalentari commented Jun 6, 2020

@z7wish7z @starvald @VicVaccuum I have my own version of this script, migrated to new twitch helix API:
This one does not work anymore with old kraken API

Copy link

Now I already made an account at Git and someone was faster :) Thanks for the fix, now I don't need to post mine anymore.

Copy link

Do you know how to get your script working on windows? I'm not super linux savvy so I'm not sure what steps to take. Thank you for your script nonetheless.

Copy link

ancalentari commented Jun 10, 2020

You should be able to use exact same command except on windows when you install python, it's not going to be python3.8 but python so:
python --username forsen
You should be able to do it from cmd once you change the directory to where the script is.
If its a fresh install you might need to install requests module this one with python -m pip install requests or something like that.
Before you run the scrip also make sure streamlink is at least 1.4.1
streamlink --version-check
If the result is not:
[cli][info] Your Streamlink version (1.4.1) is up to date!
Then install newest streamlink. (The older one uses kraken api and thats not going to work).
If you have older versions of python on your windows, you might need to play around with your env variables as well.

Copy link

Id like to use this Recorder for twitch. But i may need some help setting it up. Would anyone mind or be able to help me out here?
thanks in advance :D

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