import json import requests import sys import xml.etree.ElementTree as ET import urllib3 urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) from datetime import datetime, timezone import re # Insira aqui o seu JWT (assertion) válido fornecido pela NOS ASSERTION_JWT = "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJzZXNzaW9uX2d1aWQiOiI5NjdmNmRhNC03NGFkLTQ3NTItYmJiMy1iNjcwNzdiZmEzZjQiLCJzdWIiOiJ1c2VyfDU3NDA4MGYzNTk1NDIwMmJmMDBiZWI0NiIsImVtYWlsX3ZlcmlmaWVkIjp0cnVlLCJ1c2VyX2NhIjoiYzgzMTExMTUyNyIsImlzcyI6Imh0dHBzOi8vYXBpLmNsZy5ub3MucHQvbm9zaWQvb2F1dGgyL3YzIiwicHJlZmVycmVkX3VzZXJuYW1lIjoidGlhZ29jcmF2ZWlyb0Bob3RtYWlsLmNvbSIsInBpY3R1cmUiOiJodHRwczovL2FwaS5jbGcubm9zLnB0L21hZ2UvdjEvaW1hZ2VzP3NvdXJjZVVyaT1odHRwJTNBJTJGJTJGdmlwLnBhbS5sb2NhbC5pbnRlcm5hbCUyRlBBTS5JbWFnZXMlMkZTdG9yZSUyRjgxODRkZmU0NjNhNTRmNzBhNDRhYjAzMTQ4ZWUwOGJiJnByb2ZpbGU9bm9zbG9naW4tdXNlci1hY2NvdW50JmNsaWVudF9pZD13NmxiT1FqanVwZk1qVkZsaWc1WFZ0dVF1dFY0aEJvaSIsImF1dGhfdXNlcl9hZ2VudCI6Ik1vemlsbGEvNS4wIChXaW5kb3dzIE5UIDEwLjA7IFdpbjY0OyB4NjQpIEFwcGxlV2ViS2l0LzUzNy4zNiAoS0hUTUwsIGxpa2UgR2Vja28pIENocm9tZS8xNDEuMC4wLjAgU2FmYXJpLzUzNy4zNiIsImF1dGhfY2xpZW50X2lwIjoiODEuMTAuMjIuMTEiLCJhdWQiOiJ4ZTFkZ3JTaHdkUjFEVk9LR21zajhVdDRRTGxHeU9GSSIsInVzZXJfaWQiOiI1NzQwODBmMzU5NTQyMDJiZjAwYmViNDYiLCJhdXRoX3RpbWUiOjEuNzYyMzg4Mjk5RTksInVzZXJfc2EiOiJzODMxMTExNTI4IiwibmFtZSI6IlRpYWdvY3JhdmVpcm8iLCJleHAiOjE3OTM5MjQyOTgsImlhdCI6MTc2MjM4ODI5OCwiZW1haWwiOiJ0aWFnb2NyYXZlaXJvQGhvdG1haWwuY29tIiwianRpIjoiZDU1YzI2MGMtYzU2Ni00YTExLWEwN2UtMGY2MzUxYzA0ZDUyIn0.IoWz_29EKQL1TN3O5NUbZEriPIQnf8hj72uoxmkJ8I20mljtqVjK3HbLZKSRVq226F-s-YB6amJvqI4SrPglwHdrjMlHHmGhkQiLNfxLKdpJiM5l6Am4zemst6FXWfa4tp0TqQz1DhtiR0Piqzfx1qmCX09Ss_g6MgtP4mnvcqY" # Credenciais codificadas em base64 BASIC_AUTH = "Basic eGUxZGdyU2h3ZFIxRFZPS0dtc2o4VXQ0UUxsR3lPRkk6VFc1RFZLb1pXbFpWRFc5Zg" def obter_token_nos(assertion): url = "https://api.clg.nos.pt/nosid/oauth2/v3/token?client_id=" headers = { 'Accept': 'application/json', 'Accept-Encoding': 'gzip', 'Authorization': BASIC_AUTH, 'Connection': 'Keep-Alive', 'Content-Type': 'application/x-www-form-urlencoded' } data = { 'grant_type': 'urn:ietf:params:oauth:grant-type:jwt-bearer', 'scope': 'openid profile customer_info offline_access', 'assertion': assertion } response = requests.post(url, data=data, headers=headers, verify=False) response.raise_for_status() token = response.json().get("access_token") return token def obter_mpd_nos(token): url = f"https://api.clg.nos.pt/nostv/ott/v2/assets/EPGC139/video/dash/path?access_token={token}&client_id=&sessionType=view" headers = { 'Authorization': f'Bearer {token}', 'User-Agent': 'Mozilla/5.0', 'Origin': 'https://nostv.pt', 'Referer': 'https://nostv.pt/', 'x-apikey': 'PEiAckyJSrZN2S9tbOgI3me4M2cA6b75', 'X-Core-AppVersion': '2.18.1.8', 'X-Core-AuthorizationTime': datetime.now(timezone.utc).strftime("%Y%m%dT%H%M%S+0000"), 'X-Core-DeviceBrandId': 'PC', 'X-Core-DeviceModelId': 'Chrome', 'X-Core-DeviceName': 'PC Chrome', 'X-Core-DeviceSubType': 'PC', 'X-Core-DeviceType': 'web' } resp = requests.get(url, headers=headers, verify=False) resp.raise_for_status() path = resp.json().get("Path") if not path: print("Erro: Path vazio") return None xml_resp = requests.get(path, verify=False) xml_root = ET.fromstring(xml_resp.content) location = xml_root.find(".//{urn:mpeg:dash:schema:mpd:2011}Location") if location is not None: mpd_url = location.text return mpd_url.split(".mpd")[0] + ".mpd" else: print("Erro: Location não encontrado no XML.") return None def do_action(): # Pega o ID da linha de comando no formato ID=137 if len(sys.argv) < 2 or not sys.argv[1].startswith("ID="): print("Uso: python nos.py ID=137") return asset_id = sys.argv[1].split("=")[1] if not asset_id.isdigit(): print("Erro: ID deve ser um número.") return try: token = obter_token_nos(ASSERTION_JWT) except Exception as e: print(f"Erro ao obter token NOS: {e}") return manifest_url = obter_mpd_nos(token) if not manifest_url: print("Erro: Não foi possível obter o ManifestUrl.") return def substituir_id(m): prefix = "EPGC" numero = m.group(0)[len(prefix):] # ex: "139" novo_numero = asset_id + numero[1:] if len(numero) > 1 else asset_id return prefix + novo_numero nova_url = re.sub(r'EPGC\d+', substituir_id, manifest_url, count=2) print(nova_url) if __name__ == "__main__": do_action()