Skip to content

Instantly share code, notes, and snippets.

@vadv
Last active October 30, 2018 13:24
Show Gist options
  • Save vadv/a092d8b4551872030c643b3c0fd29b81 to your computer and use it in GitHub Desktop.
Save vadv/a092d8b4551872030c643b3c0fd29b81 to your computer and use it in GitHub Desktop.
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os
import re
import requests
import sys
from Crypto.Cipher import AES
def decrypt(data, key, iv):
"""Decrypt using AES CBC"""
decryptor = AES.new(key, AES.MODE_CBC, IV=iv)
return decryptor.decrypt(data)
def get_binary(url):
data = ''
for chunk in requests.get(url, stream=True):
data += chunk
return data
def main(url, output_folder):
# download playlist
r = requests.get(url)
if r.status_code != 200:
raise Exception("bad status code: {0}".format(r.status_code))
playlist = r.text
base_url = url.split('?')[0]
base_url = base_url.split('playlist.m3u8')[0]
# process playlist
counter = 0
for line in playlist.split("\n"):
# process keys
if line.startswith('#EXT-X-KEY'):
keys = re.findall('#EXT-X-KEY: METHOD=AES-128, IV=(.*), URI="(.*)"', line)
for key in keys:
key_url = key[1]
iv_val = key[0][2:]
iv = iv_val.decode('hex')
print("[INFO] download key: {0} iv: {1}".format(key_url, iv_val))
key_data = get_binary(key_url)
# process chunks
if not line.startswith('#') and line != "":
chunk_url = base_url + line
chunk = get_binary(chunk_url)
out_file = os.path.join(output_folder, '{0}.ts'.format(counter))
print("[INFO] download && decrypt chunk {0} to {1}".format(chunk_url, out_file))
decrypt_data = decrypt(chunk, key_data, iv)
if decrypt_data[0] != "G":
print("[ERROR] bad magic for ts: '{0}'".format(decrypt_data[0]))
with open(out_file, 'wb') as f:
f.write(decrypt_data)
counter = counter + 1
if __name__ == '__main__':
if len(sys.argv) < 3:
sys.exit('Usage: %s <playlist_url_m3u8> <out_folder>' % os.path.basename(sys.argv[0]))
main(sys.argv[1], sys.argv[2])
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment