#!/usr/bin/python3
import sys
import os
import base64
import json
import datetime
import pytz
import uuid
from base64 import b64encode, b64decode

# Add parent directory to path for o11 import
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
import o11

from Crypto.Cipher import AES
from Crypto.Hash import SHA256

# Parse command line parameters
user = o11.parse_params(sys.argv, 'user')
password = o11.parse_params(sys.argv, 'password')
device = o11.parse_params(sys.argv, 'device')
pin = o11.parse_params(sys.argv, 'pin')

id = o11.parse_params(sys.argv, 'id')
action = o11.parse_params(sys.argv, 'action')

bind = o11.parse_params(sys.argv, 'bind')
proxy = o11.parse_params(sys.argv, 'proxy')
doh = o11.parse_params(sys.argv, 'doh')
worker = o11.parse_params(sys.argv, 'worker')

cdm = o11.parse_params(sys.argv, 'cdm')
drm = o11.parse_params(sys.argv, 'drm')
kid = o11.parse_params(sys.argv, 'kid')
pssh = o11.parse_params(sys.argv, 'pssh')
challenge = o11.parse_params(sys.argv, 'challenge')

heartbeaturl = o11.parse_params(sys.argv, 'heartbeaturl')
heartbeatparams = o11.parse_params(sys.argv, 'heartbeatparams')

# Session setup
o11Session = o11.session(bind=bind, proxy=proxy, worker=worker)
req = o11Session.get_session()
if doh != "":
    o11.dns(doh)

if challenge == "cert":
    challenge = "CAQ="

# Configuration
WVD_PATH = './WVD.wvd'
authFile = '/USTVNow_auth.json'
SCRIPT_DIR = os.path.abspath(os.path.dirname(__file__))

USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36'

# Encryption keys
KEY = '80035ad42d7d-bb08-7a14-f726-78403b29'
IV = '3157b5680927cc4a'

headers = {
    'accept': 'application/json, text/plain, */*',
    'origin': 'https://www.ustvnow.com',
    'referer': 'https://www.ustvnow.com/',
    'tenant-code': 'ustvnow',
    'user-agent': USER_AGENT,
}

session_id = ''
box_id = ''

def get_auth():
    try:
        return json.load(open(SCRIPT_DIR + authFile))
    except:
        return None

def save_auth(auth_data):
    json.dump(auth_data, open(SCRIPT_DIR + authFile, 'w'), indent=2)

def encrypt_data(data):
    processed_key = KEY[::-1]
    processed_iv = IV[::-1]
    aes_key = SHA256.new(processed_key.encode()).digest().hex()[:32].encode('utf-8').hex()
    aes_iv = processed_iv.encode()
    cipher = AES.new(bytes.fromhex(aes_key), AES.MODE_CBC, aes_iv)
    padded_data = data.encode()
    padding_length = AES.block_size - len(padded_data) % AES.block_size
    padded_data += bytes([padding_length]) * padding_length
    encrypted_data = cipher.encrypt(padded_data)
    return b64encode(encrypted_data).decode()

def decrypt_data(encrypted_data):
    processed_key = KEY[::-1]
    processed_iv = IV[::-1]
    aes_key = SHA256.new(processed_key.encode()).digest().hex()[:32].encode('utf-8').hex()
    aes_iv = processed_iv.encode()
    cipher = AES.new(bytes.fromhex(aes_key), AES.MODE_CBC, aes_iv)
    decrypted_data = cipher.decrypt(b64decode(encrypted_data))
    padding_length = decrypted_data[-1]
    return decrypted_data[:-padding_length].decode()

def check_session(sid, bid):
    check_headers = {**headers, 'box-id': bid, 'session-id': sid}
    response = req.get('https://teleupapi.revlet.net/service/api/auth/user/info', headers=check_headers)
    data = response.json()
    if not data.get('status'):
        raise Exception('Invalid session')

def login():
    global session_id, box_id
    print("logging in...", file=sys.stderr)
    
    auth = get_auth()
    if auth and 'session_id' in auth:
        try:
            check_session(auth['session_id'], auth['box_id'])
            session_id = auth['session_id']
            box_id = auth['box_id']
            print("logged in successfully (cached session)", file=sys.stderr)
            return session_id
        except:
            pass
    
    print("No valid session found. Please add USTVNow auth to auth file.", file=sys.stderr)
    save_auth({'session_id': 'ENTER_SESSION_ID_HERE', 'box_id': 'ENTER_BOX_ID_HERE'})
    sys.exit(1)

def get_session():
    global session_id, box_id
    if session_id:
        return session_id
    return login()

def get_single(path):
    single_headers = {**headers, 'box-id': box_id, 'session-id': session_id, 'content-type': 'application/json'}
    json_data = {
        'data': encrypt_data('{"path":"' + path + '"}'),
        'metadata': encrypt_data('{"request":"page/stream"}'),
    }
    response = req.post('https://teleupapi.revlet.net/service/api/v1/send', headers=single_headers, json=json_data)
    try:
        data = response.json()
        decrypted = decrypt_data(data['data'])
        data = json.loads(decrypted)
        return data['response']['streams'][0]['url']
    except:
        return None

def do_action():
    get_session()
    
    if action == "login":
        login()
        sys.exit()
    
    if action == "channels":
        output = {'Channels': []}
        ch_headers = {**headers, 'box-id': box_id, 'session-id': session_id}
        params = {'path': 'live', 'count': '999'}
        response = req.get('https://teleupapi.revlet.net/service/api/v1/page/content', params=params, headers=ch_headers)
        try:
            data = response.json()
            channels = []
            for d in data['response'].get('data', []):
                channels += d['section']['sectionData'].get('data', [])
            
            for ch in channels:
                name = ch.get('display', {}).get('parentName', 'Unknown').strip()
                path = ch.get('target', {}).get('path', '')
                channel = {
                    'Name': name,
                    'Mode': 'live',
                    'SessionManifest': True,
                    'ManifestScript': f"id={path}",
                    'CdmType': 'none',
                    'UseCdm': False,
                    'Cdm': '',
                    'Video': 'best',
                    'OnDemand': True,
                    'SpeedUp': True,
                }
                output['Channels'].append(channel)
            print(json.dumps(output, indent=2))
        except Exception as e:
            print(f"Error: {e}", file=sys.stderr)
            return "error"
    
    elif action == "events":
        output = {'Events': []}
        print(json.dumps(output, indent=2))
    
    elif action == "heartbeat":
        sys.exit()
    
    elif action == "manifest":
        try:
            path = id
            video_url = get_single(path)
            if not video_url:
                return "error"
            output = {
                "Cdn": [{"Name": "default", "ManifestUrl": video_url}],
                "ManifestUrl": video_url,
                "Headers": {"Manifest": {'User-Agent': USER_AGENT}, "Media": {'User-Agent': USER_AGENT}},
                "Heartbeat": {"Url": '', "Params": '', "PeriodMs": 5*60*1000}
            }
            print(json.dumps(output))
        except Exception as e:
            print(f"Error: {e}", file=sys.stderr)
            return "error"
    
    elif action == "cdm":
        print("USTVNow streams are typically unencrypted HLS", file=sys.stderr)
    
    else:
        print("invalid action: " + action, file=sys.stderr)

if do_action() == "error":
    login()
    do_action()
