Compare commits

...

2 Commits

Author SHA1 Message Date
c486fac3ab
Update README.md 2025-10-11 23:51:50 +00:00
09a686cea7
Update NPO.py
added support for premium

use netscape cookies and call them cookies.txt
2025-10-11 23:49:35 +00:00
2 changed files with 42 additions and 10 deletions

49
NPO.py
View File

@ -2,14 +2,44 @@ import requests
import re import re
import json import json
import argparse import argparse
import os
def load_cookies(cookie_file):
"""Load cookies from a Netscape format cookie file and return a Cookie header string."""
cookie_header = []
try:
with open(cookie_file, 'r') as f:
for line in f:
if line.startswith('#') or not line.strip():
continue # Skip comments and empty lines
parts = line.strip().split('\t')
if len(parts) >= 7:
domain = parts[0]
# Ensure the domain is valid before creating the cookie string
if domain.startswith('.'):
domain = domain[1:] # Remove leading dot for correct formatting
# Collecting the cookie name and value
cookie_name = parts[5]
cookie_value = parts[6]
cookie_header.append(f"{cookie_name}={cookie_value}")
except Exception as e:
print(f"Error loading cookies: {str(e)}")
return '; '.join(cookie_header)
def get_stream_url(url): def get_stream_url(url):
if url.startswith("https://npo.nl/start/serie/") and url.endswith("/afspelen"): if url.startswith("https://npo.nl/start/serie/") and url.endswith("/afspelen"):
try: try:
# Step 1: Get the JSON data # Load cookies from cookies.txt if it exists
response = requests.get(url) cookie_file = 'cookies.txt'
cookie_header = load_cookies(cookie_file) if os.path.exists(cookie_file) else None
# Step 1: Make a request to the input URL
headers = {'Cookie': cookie_header} if cookie_header else {}
response = requests.get(url, headers=headers)
response.raise_for_status() response.raise_for_status()
# Extract the JSON data embedded in the HTML
match = re.search(r'<script id="__NEXT_DATA__" type="application/json">(.*?)</script>', response.text, re.DOTALL) match = re.search(r'<script id="__NEXT_DATA__" type="application/json">(.*?)</script>', response.text, re.DOTALL)
if match: if match:
json_data = match.group(1) json_data = match.group(1)
@ -18,7 +48,6 @@ def get_stream_url(url):
product_info = None product_info = None
for item in data.get('props', {}).get('pageProps', {}).get('dehydratedState', {}).get('queries', []): for item in data.get('props', {}).get('pageProps', {}).get('dehydratedState', {}).get('queries', []):
for episode_data in item.get('state', {}).get('data', []): for episode_data in item.get('state', {}).get('data', []):
# Debug output to understand structure
if isinstance(episode_data, dict) and episode_data.get('slug') == url.split('/')[-2]: if isinstance(episode_data, dict) and episode_data.get('slug') == url.split('/')[-2]:
product_info = { product_info = {
'productId': episode_data.get('productId'), 'productId': episode_data.get('productId'),
@ -29,20 +58,21 @@ def get_stream_url(url):
break break
if product_info: if product_info:
# Step 2: Get JWT # Step 2: Get JWT using the same cookies
token_url = f"https://npo.nl/start/api/domain/player-token?productId={product_info['productId']}" token_url = f"https://npo.nl/start/api/domain/player-token?productId={product_info['productId']}"
token_response = requests.get(token_url) token_response = requests.get(token_url, headers=headers)
token_response.raise_for_status() token_response.raise_for_status()
jwt = token_response.json().get('jwt') jwt = token_response.json().get('jwt')
if jwt: if jwt:
# Step 3: Make POST request to get stream link # Step 3: Make POST request to get stream link
headers = { post_headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36", "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36",
"Authorization": jwt, "Authorization": jwt,
"Content-Type": "application/json", "Content-Type": "application/json",
"Accept": "*/*", "Accept": "*/*",
"Referer": "https://npo.nl/" "Referer": "https://npo.nl/",
'Cookie': cookie_header
} }
body = { body = {
@ -56,7 +86,8 @@ def get_stream_url(url):
} }
} }
stream_response = requests.post("https://prod.npoplayer.nl/stream-link", headers=headers, json=body) # Send the POST request to get the stream link
stream_response = requests.post("https://prod.npoplayer.nl/stream-link", headers=post_headers, json=body)
stream_response.raise_for_status() stream_response.raise_for_status()
# Step 4: Extract streams URL and drmToken # Step 4: Extract streams URL and drmToken
@ -69,7 +100,7 @@ def get_stream_url(url):
return "Product ID and GUID not found for the given slug." return "Product ID and GUID not found for the given slug."
return "JSON script not found in the response." return "JSON script not found in the response."
except requests.exceptions.RequestException as e: except requests.exceptions.RequestException as e:
return f"An error occurred: {str(e)}" return f"An error occurred while making the request: {str(e)}"
except json.JSONDecodeError: except json.JSONDecodeError:
return "Failed to decode JSON data." return "Failed to decode JSON data."
return "Invalid URL. Please provide a URL that starts with 'https://npo.nl/start/serie/' and ends with '/afspelen'." return "Invalid URL. Please provide a URL that starts with 'https://npo.nl/start/serie/' and ends with '/afspelen'."

View File

@ -4,7 +4,8 @@ DISCLAMER: ALLEEN BEDOELT VOOR EDUCATIEVE DOELEINDEN
IK STEL MIJZELF NIET VERANDWOORDERLIJK VOOR WAT JIJ HIERMEE DOET IK STEL MIJZELF NIET VERANDWOORDERLIJK VOOR WAT JIJ HIERMEE DOET
DOWNLOAD ALLEEN ALS DAT OOK MAG DOWNLOAD ALLEEN ALS DAT OOK MAG
getest op Windows 10 (werkt niet voor premium) getest op Windows 10 (werkt nu wel voor premium cookies in netscape formaat nodig)
moet cookies.txt heten
benodigheden benodigheden
1 widevine cdm (hernoem hem naar cdm.wvd en stop hem in dezelfde map) 1 widevine cdm (hernoem hem naar cdm.wvd en stop hem in dezelfde map)