Skip to content

Instantly share code, notes, and snippets.

@EhsanKia
Last active August 18, 2020 03:10
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save EhsanKia/0330132521ee3c6caf7e to your computer and use it in GitHub Desktop.
Save EhsanKia/0330132521ee3c6caf7e to your computer and use it in GitHub Desktop.
Outputs chunks for a specific section of a Twitch VOD
import requests
import m3u8
import sys
import re
CHUNK_RE = "(.+\.ts)\?start_offset=(\d+)&end_offset=(\d+)"
VOD_API = "https://api.twitch.tv/api/vods/{}/access_token"
INDEX_API = "http://usher.twitch.tv/vod/{}"
def get_vod_index(vod_id):
# Get access code
url = VOD_API.format(vod_id)
r = requests.get(url)
data = r.json()
# Fetch vod index
url = INDEX_API.format(vod_id)
payload = {'nauth': data['token'], 'nauthsig': data['sig']}
r = requests.get(url, params=payload)
m = m3u8.loads(r.content)
url = m.playlists[0].uri
return m3u8.load(url)
def extract_clip(index, start_time, end_time):
# Get the piece we need
position = 0
pieces = []
for seg in index.segments:
# Add duration of current segment
position += seg.duration
# Check if we have gotten to the start of the clip
if position < start_time:
continue
# Extract clip name and byte range
p = re.match(CHUNK_RE, seg.absolute_uri)
filename, start_byte, end_byte = p.groups()
# If we have a new file, add it tot he list
if not pieces or pieces[-1][0] != filename:
pieces.append([filename, start_byte, end_byte])
else: # Else, update the end byte
pieces[-1][2] = end_byte
# Check if we have reached the end of clip
if position > end_time:
break
return pieces
if __name__ == '__main__':
vod_id = sys.argv[1]
start = int(sys.argv[2])
end = int(sys.argv[3])
index = get_vod_index(vod_id)
pieces = extract_clip(index, start, end)
# Output all the chunks we need
for part in pieces:
print "{}?start_offset={}&end_offset={}".format(*part)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment