Upload files to "/"

Reupload
This commit is contained in:
adef17286 2026-06-24 23:08:55 +00:00
commit 3609ef9351
7 changed files with 349 additions and 0 deletions

16
README.md Normal file
View File

@ -0,0 +1,16 @@
simpele downloader voor KIJK DISCLAMER: ALLEEN BEDOELT VOOR EDUCATIEVE DOELEINDEN IK STEL MIJZELF NIET VERANDWOORDERLIJK VOOR WAT JIJ HIERMEE DOET DOWNLOAD ALLEEN ALS DAT OOK MAG
getest op win 10 (met wat aanpassingen zou hij vast ook wel werken op Linux)
benodigheden 1 widevine cdm (hernoem hem naar cdm.wvd en stop hem in dezelfde map) Python, N_m3u8dl-re https://github.com/nilaoda/N_m3u8DL-RE Bento-mp4decrypt https://www.bento4.com/documentation/mp4decrypt/ https://www.bento4.com/downloads/ ffmpeg https://ffmpeg.org/
Hoe te gebruiken?
py ./DL.py KIJK_url bijv py ./DL.py https://www.kijk.nl/programmas/the-hunting-party/K2fsFS5ivIV
extra
--save-name hoejehemwiltnoemen
(niet super moelijke tekens gebruiken weet niet of hij dat aankan)
Nadeel:
Niet met DRM gecodeerde dingen werken niet dan geeft hij error. (denk ik)

53
dl.py Normal file
View File

@ -0,0 +1,53 @@
import os
import sys
import subprocess
def main():
args = sys.argv[1:]
savename = None
if '--save-name' in args:
idx = args.index('--save-name')
if idx + 1 < len(args):
savename = args[idx + 1]
args = args[:idx] + args[idx + 2:]
# Execute tasks.py and get the DASH link
tasks_result = subprocess.run([sys.executable, 'tasks.py'] + args, capture_output=True, text=True)
dash_link = None
for line in tasks_result.stdout.splitlines():
if line.startswith("DASH Link:"):
dash_link = line[len("DASH Link:"):].strip()
break
get_result = subprocess.run([sys.executable, 'keys.py'] + args, capture_output=True, text=True)
get_output = get_result.stdout.strip()
# Extract only the key part from get_output
key_part = get_output.split(':', 1)[0] + ':' + get_output.split(':', 1)[1].strip()
print(f"Executing command with key: {key_part}")
# Prepare the command
command = [
'N_m3u8dl-re',
'-M', 'mp4',
'-sv', 'best',
'-sa', 'best',
'--key', key_part,
]
# Append the dash_link without additional quotes
if dash_link:
command.append(dash_link)
# Run the N_m3u8dl-re command
try:
print("Running command...")
subprocess.run(command, check=True)
except subprocess.CalledProcessError as e:
print(f"Error running N_m3u8dl-re: {e}")
if __name__ == "__main__":
main()

43
get_lic.py Normal file
View File

@ -0,0 +1,43 @@
import requests
import json
# Define the API URL
url = "https://api.prd.video.talpa.network/graphql"
# Prepare the headers
headers = {
"Accept": "*/*",
"Accept-Language": "nl-NL,nl;q=0.9,en-US;q=0.8,en;q=0.7",
"Content-Type": "text/plain;charset=UTF-8",
"Priority": "u=1, i",
"Sec-CH-UA": "\"Google Chrome\";v=\"141\", \"Not?A_Brand\";v=\"8\", \"Chromium\";v=\"141\"",
"Sec-CH-UA-Mobile": "?0",
"Sec-CH-UA-Platform": "\"Windows\"",
"Sec-Fetch-Dest": "empty",
"Sec-Fetch-Mode": "cors",
"Sec-Fetch-Site": "cross-site",
}
# Prepare the body of the request
query = {
"query": """query DrmTokenQuery($provider: DrmProvider) {
drmToken(drmProvider: $provider) {
expiration
token
}
}""",
"variables": {
"provider": "JWP"
}
}
# Send the POST request
response = requests.post(url, headers=headers, data=json.dumps(query))
# Print the output
if response.status_code == 200:
# Extract the token
token = response.json()['data']['drmToken']['token']
print("Token:", token)
else:
print("Error:", response.status_code, response.text)

73
get_vid.py Normal file
View File

@ -0,0 +1,73 @@
import requests
import re
import sys
def fetch_video_info(guid):
url = f"https://api.prd.video.talpa.network/graphql?query=query+GetVideoQuery%28%24guid%3A%5BString%5D%29%7Bprograms%28guid%3A%24guid%29%7Bitems%7Bguid+type+metadata+availableRegion+...Media+...Tracks+...Sources%7D%7D%7Dfragment+Media+on+Program%7Bmedia%7Btype+availableDate+availabilityState+airedDateTime+expirationDate%7D%7Dfragment+Tracks+on+Program%7Btracks%7Bfile+kind+label%7D%7Dfragment+Sources+on+Program%7Bsources%7Btype+file+drm%7D%7D&variables=%7B%22guid%22%3A%22{guid}%22%7D"
headers = {
"accept": "*/*",
"accept-language": "nl-NL,nl;q=0.9,en-US;q=0.8,en;q=0.7",
"content-type": "application/json",
"priority": "u=1, i",
"sec-ch-ua": "\"Google Chrome\";v=\"141\", \"Not?A_Brand\";v=\"8\", \"Chromium\";v=\"141\"",
"sec-ch-ua-mobile": "?0",
"sec-ch-ua-platform": "\"Windows\"",
"sec-fetch-dest": "empty",
"sec-fetch-mode": "cors",
"sec-fetch-site": "cross-site",
}
response = requests.get(url, headers=headers)
if response.status_code == 200:
json_response = response.json()
dash_link = None
widevine_license_server = None
items = json_response.get('data', {}).get('programs', {}).get('items', [])
for item in items:
for source in item.get('sources', []):
if source['type'] == 'dash' and 'drm' in source and 'widevine' in source['drm']:
dash_link = source['file']
widevine_license_server = source['drm']['widevine']['url']
break # Exit loop once we find the first match
return {
"dash_link": dash_link,
"widevine_license_server": widevine_license_server
}
else:
return {"error": f"Request failed with status code {response.status_code}"}
def extract_guid(url):
# Check if the URL starts with the required base URL
if not url.startswith("https://www.kijk.nl/programmas/"):
return None
# Regex to extract GUID (the segment before the last slash)
match = re.match(r'https://www\.kijk\.nl/programmas/[^/]+/([^/?]+)', url)
if match:
return match.group(1)
return None
if __name__ == "__main__":
if len(sys.argv) != 2:
print("Usage: python script.py {url}")
sys.exit(1)
user_url = sys.argv[1]
guid = extract_guid(user_url)
if guid:
video_info = fetch_video_info(guid)
if 'error' not in video_info:
print(f"DASH Link: {video_info['dash_link']}")
print(f"Widevine License Server: {video_info['widevine_license_server']}")
else:
print(video_info['error'])
else:
print("Invalid URL. Please ensure it starts with 'https://www.kijk.nl/programmas/' and contains a GUID.")

145
keys.py Normal file
View File

@ -0,0 +1,145 @@
import subprocess
import sys
import requests
import xml.etree.ElementTree as ET
import re
from pywidevine.cdm import Cdm
from pywidevine.device import Device
from pywidevine.pssh import PSSH
def call_tasks(subcommand, *args):
command = [sys.executable, 'tasks.py', subcommand] + list(args)
try:
result = subprocess.run(command, capture_output=True, text=True, check=True)
return result.stdout.strip()
except subprocess.CalledProcessError as e:
print(f"Error executing {subcommand}: {e}")
return None
def parse_output(output):
dash_link = None
widevine_license_server = None
token = None
lines = output.splitlines()
for line in lines:
if line.startswith("DASH Link:"):
dash_link = line.split("DASH Link: ", 1)[1].strip()
elif line.startswith("Widevine License Server:"):
widevine_license_server = line.split("Widevine License Server: ", 1)[1].strip()
elif line.startswith("Token:"):
token = line.split("Token: ", 1)[1].strip()
return dash_link, widevine_license_server, token
def download_mpd(dash_link):
try:
response = requests.get(dash_link)
response.raise_for_status()
return response.text
except requests.RequestException as e:
print(f"Error downloading MPD file: {e}")
return None
def extract_pssh(mpd_content):
pssh_strings = set()
root = ET.fromstring(mpd_content)
# More flexible approach to find <pssh> elements regardless of namespaces
for elem in root.iter():
if elem.tag.endswith('pssh') and elem.text:
pssh_strings.add(elem.text.strip())
return pssh_strings
KEY_REGEX = re.compile(r'\b([0-9a-fA-F]{32}):([0-9a-fA-F]{32})\b')
def extract_keys_from_cdm_output(text):
"""
Extract and return list of keys matching 32hex:32hex from CDM output text.
"""
matches = KEY_REGEX.findall(text)
return [f"{kid.lower()}:{key.lower()}" for kid, key in matches]
def fetch_keys_from_pssh(pssh_b64, license_url, token=None):
try:
pssh = PSSH(pssh_b64)
# Load device (adjust path to your provisioned .wvd file)
device = Device.load("cdm.wvd") # <-- Replace with your actual path
cdm = Cdm.from_device(device)
session_id = cdm.open()
# Get license challenge
challenge = cdm.get_license_challenge(session_id, pssh)
headers = {'x-vudrm-token': token} if token else {}
# Send license request
response = requests.post(license_url, data=challenge, headers=headers)
response.raise_for_status()
# Parse license
cdm.parse_license(session_id, response.content)
# Extract keys from CDM object
keys_text = ""
for key in cdm.get_keys(session_id):
keys_text += f"[{key.type}] {key.kid.hex}:{key.key.hex()}\n"
# Close session
cdm.close(session_id)
# Extract and print only keys matching 32hex:32hex pattern
keys = extract_keys_from_cdm_output(keys_text)
if keys:
for k in keys:
print(k)
else:
print("No 32hex:32hex keys found in this session.")
except Exception as e:
print(f"Error processing PSSH: {e}")
if __name__ == "__main__":
if len(sys.argv) < 2:
print("Usage: python wrapper.py <subcommand> [args...]")
sys.exit(1)
subcommand = sys.argv[1]
args = sys.argv[2:]
# Step 1: Run tasks.py and get output
output = call_tasks(subcommand, *args)
if output is not None:
# Step 2: Parse output
dash_link, widevine_license_server, token = parse_output(output)
# Step 3: Download MPD file
mpd_content = download_mpd(dash_link)
if mpd_content:
# Step 4: Extract PSSHs
pssh_strings = extract_pssh(mpd_content)
for pssh in pssh_strings:
print("")
# Step 5: Fetch keys using each PSSH
print("")
for pssh in sorted(pssh_strings):
print()
fetch_keys_from_pssh(pssh, widevine_license_server, token)

2
requirements.txt Normal file
View File

@ -0,0 +1,2 @@
pywidevine==1.8.0
Requests==2.32.5

17
tasks.py Normal file
View File

@ -0,0 +1,17 @@
import subprocess
import sys
def run_commands():
# Run get_vid.py with the provided subcommands
if len(sys.argv) > 1:
vid_command = ['python', 'get_vid.py'] + sys.argv[1:]
vid_output = subprocess.run(vid_command, capture_output=True, text=True)
print(vid_output.stdout)
# Run get_lic.py without any subcommands
lic_command = ['python', 'get_lic.py']
lic_output = subprocess.run(lic_command, capture_output=True, text=True)
print(lic_output.stdout)
if __name__ == '__main__':
run_commands()