def do_api_webrequest(postdata): max_attempts = 5 attempts = 0 headers = { 'User-Agent': '', 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8', } url = 'http://iptvdroid.monster/IP11/api.php' while attempts < max_attempts: source = requests.post(url, data = postdata, headers = headers, verify = False) if source.status_code != 200: xbmcgui.Dialog().ok('Error', f"Failed to retrieve api data, retrying... (Status code: {source.status_code})") try: jsondata = source.json() except ValueError: pass #xbmcgui.Dialog().ok('Error', 'Invalid JSON response from api') if "LIVETV" in jsondata and len(jsondata["LIVETV"]) > 0: return jsondata attempts += 1 xbmcgui.Dialog().ok('Error', '(' + max_attempts + ') empty / invalid JSON responses from api, quiting') return None def getMAC_OLA(cid): salt_sign_1061 = 'eyJzYWx0IjoiNjYzIiwic2lnbiI6ImU2OWU3ZTliOWY5NTU0OTkzNzA1YmY5Y2QyMTYzYTA5Iiwi%0A' ##############{"salt":"663","sign":"e69e7e9b9f9554993705bf9cd2163a09"," categorytext = 'method_name":"getToken128910","cid":"' + cid + '"}' categorytextb64 = base64.b64encode(categorytext.encode()).decode() categorytextb64adjust = categorytextb64.replace('=', '%3D') + '%0A' payload = salt_sign_1061 + categorytextb64adjust postdata = 'data=' + payload channeljson = do_api_webrequest(postdata) if channeljson is None: return None token1 = channeljson['LIVETV'][0]['token1'] token2 = channeljson['LIVETV'][0]['token2'] #token1 = re.findall('"token1": "(.*?)"', source.text)[0] #token2 = re.findall('"token2": "(.*?)"', source.text)[0] hosturl = base64.b64decode(token1[16:]).decode("utf-8") if '_' in hosturl: hosturl = hosturl.replace('_', '') mac = base64.b64decode(token2[16:]).decode("utf-8") return mac def getcorsproxy(): headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:131.0) Gecko/20100101 Firefox/131.0', 'Referer': 'https://gist.githubusercontent.com'} try: response = requests.get('https://gist.githubusercontent.com/enerdude/d844a5ffdd53f3afb38f810524814db4/raw/corsproxy.txt', headers = headers, verify = False) response.raise_for_status() except (ConnectTimeout, HTTPError, ReadTimeout, Timeout, ConnectionError): headers['Referer'] = 'https://geocities.ws/enerdude/box/' response = requests.get('https://geocities.ws/enerdude/box/corsproxy.txt', headers = headers, verify = False) lines = response.text.strip().splitlines() mode = lines[0].strip().lower() if mode == 'fixed': return lines[1].strip() else: return random.choice([line.strip() for line in lines[1:] if line.strip()]) def getUrl(): max_mac_tries = 35 # max number of getHUP() calls max_request_retries = 5 # retries per URL on exception http_200_retries = 1 http_200_counter = 0 headers = {'User-Agent': 'Lavf53.32.100'} for mac_try in range(max_mac_tries): mac = getMAC_OLA(cid) if mac is None: break url = f"http://{domain}/play/live.php?mac={mac}&stream={video_id}&extension=ts" # Try the request up to 5 times if exceptions occur for req_try in range(max_request_retries): try: r = requests.get(url, headers=headers, allow_redirects=False, verify=False, timeout=10) if r.status_code == 200: http_200_counter += 1 if http_200_counter > http_200_retries: return "down" if r.status_code == 407: return "down" if r.status_code != 302: time.sleep(0.5) break if r.status_code == 302 and 'black.ts' in r.headers['Location']: #xbmcgui.Dialog().ok('Error','Channel down, please try again later') #return None break #must check but seems this is also for invalid / expired mac return url #success http 302 except requests.RequestException as e: # Retry up to 5 times, then give up on this URL if req_try == max_request_retries - 1: # all request retries failed --> return None return None # All hosts tried, no success return None import requests, re, xbmcgui, random from requests import ReadTimeout, ConnectTimeout, HTTPError, Timeout, ConnectionError import urllib.parse from datetime import datetime import base64 import time ### MAIN FUNCTION (CONNECTED TO KODI APP) ### cid = '20822' # server #1165 main domain tv.trexiptv.com domain = 'tv.trexiptv.com:80' video_id = params.get('id') usecorsproxy = xbmcgui.Dialog().yesno( heading='Confirm', message='Use proxy?', nolabel='No', yeslabel='Yes', autoclose=5000, defaultbutton=xbmcgui.DLG_YESNO_NO_BTN # Focus on No ) cors_proxy = None if usecorsproxy: cors_proxy = getcorsproxy() scraped_url = getUrl() if scraped_url == "down": print("Final Output: Channel is down.") xbmcgui.Dialog().ok('Error', 'Channel down, please try again later') stream_data = { "url": scraped_url, "inputstream": "ffmpegdirect", "mimetype": "video/mp2t", "headers": { "User-Agent": "Lavf53.32.100", #"Referer": "https://jxoxkplay.xyz", #"X-Token": token if token else "default_token" } } if usecorsproxy and scraped_url: stream_data["url"] = cors_proxy + scraped_url stream_data["headers"]["X-Requested-With"] = "XMLHttpRequest" #xbmcgui.Dialog().ok('streamdata',str(stream_data)) """ if category: custom_title = f"Live: {video_id} ({category}) [{quality}]" else: custom_title = f"Live: {video_id} [{quality}]" """ #### MAIN FUNCTION END ####