#!/usr/bin/python3
import sys
import os
import o11
import json
import datetime
import pytz
import uuid
import secrets
from pywidevine.cdm import Cdm
from pywidevine.device import Device
from pywidevine.pssh import PSSH
from bs4 import BeautifulSoup

WVD_PATH = './WVD.wvd'

user = o11.parse_params(sys.argv, 'user')
password = o11.parse_params(sys.argv, 'password')

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_param = o11.parse_params(sys.argv, 'cdm')
challenge = o11.parse_params(sys.argv, 'challenge')

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

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

authFile = '/TivifyTV_' + user + '.tokens'
user_agent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:122.0) Gecko/20100101 Firefox/122.0'

plan_id = '62e8e6a0efd20000219b57fa'

def generate_random_string(length=40):
    return secrets.token_hex(length // 2)

def do_cdm_external(pssh_data, plan_id, user_id, device_id):
    pssh_obj = PSSH(pssh_data)
    device_obj = Device.load(WVD_PATH)
    cdm_obj = Cdm.from_device(device_obj)
    session_id = cdm_obj.open()
    challenge_data = cdm_obj.get_license_challenge(session_id, pssh_obj)
    lic_headers = {'User-Agent': user_agent, 'Accept': '*/*', 'content-type': 'application/octet-stream', 'x-tvup-device': device_id, 'x-tvup-userid': user_id, 'x-tvup-planid': plan_id, 'x-tvup-platform': 'CHROME', 'Origin': 'https://tivify.tv', 'Referer': 'https://tivify.tv/'}
    licence = req.post('https://drmnew.tvup.cloud/freelicense/GNA01', headers=lic_headers, data=challenge_data)
    cdm_obj.parse_license(session_id, licence.content)
    keys = [f"{key.kid.hex}:{key.key.hex()}" for key in cdm_obj.get_keys(session_id) if key.type != 'SIGNING']
    cdm_obj.close(session_id)
    return keys

def get_pssh_from_mpd(url):
    headers = {'User-Agent': user_agent}
    response = req.get(url, headers=headers)
    for cp in BeautifulSoup(response.content, features="xml").findAll('ContentProtection'):
        if cp.get('schemeIdUri', '').lower() == 'urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed':
            pssh_tag = cp.find('cenc:pssh')
            if pssh_tag:
                return pssh_tag.text
    return None

def get_channels():
    headers = {'User-Agent': user_agent, 'Accept': 'application/json, text/plain, */*', 'Accept-Encoding': 'gzip, deflate, br', 'Origin': 'https://tivify.tv', 'Referer': 'https://tivify.tv/'}
    response = req.get('https://mediasync.tvup.cloud/media/carrier/5ea94948bf8cbb0072c89fa6/channels.json', headers=headers)
    data = response.json()
    unique = list({each['master']['title']: each for each in data}.values())
    return unique

def make_user_id(plan_id, device_id):
    headers = {'accept': 'application/json, text/plain, */*', 'content-type': 'application/x-www-form-urlencoded', 'origin': 'https://tivify.tv', 'platform': 'CHROME', 'referer': 'https://tivify.tv/', 'user-agent': user_agent, 'x-access-token': '', 'x-tvup-device': device_id, 'x-tvup-planid': plan_id, 'x-tvup-platform': 'CHROME'}
    params = {'token': '1706802044_' + generate_random_string()}
    response = req.post('https://api.tvup.cloud/user/createId', params=params, headers=headers)
    return response.json().get('userId', '')

def do_action():
    device_id = str(uuid.uuid4())
    user_id = make_user_id(plan_id, device_id)

    if action == "channels":
        output = {'Channels': []}
        for c in get_channels():
            title = c['master']['title']
            dash_url = c['master']['streaming'].get('DASH', '')
            output['Channels'].append({'Name': title, 'Mode': "live", 'SessionManifest': True, 'ManifestScript': 'url=' + dash_url, 'CdmType': "widevine", 'UseCdm': True, 'Cdm': 'url=' + dash_url, 'Video': 'best'})
        print(json.dumps(output, indent=2))
    elif action == "events":
        output = {'Events': []}
        for c in get_channels():
            title = c['master']['title']
            dash_url = c['master']['streaming'].get('DASH', '')
            output['Events'].append({'Name': title, 'Mode': "live", 'SessionManifest': True, 'ManifestScript': 'url=' + dash_url, 'CdmType': "widevine", 'UseCdm': True, 'Cdm': 'url=' + dash_url, 'Video': 'best', 'Autostart': True, 'Start': int(datetime.datetime.now(pytz.UTC).timestamp()), 'End': int((datetime.datetime.now(pytz.UTC) + datetime.timedelta(hours=4)).timestamp())})
        print(json.dumps(output, indent=2))
    elif action == "manifest":
        url = id.replace('url=', '') if id.startswith('url=') else id
        pssh_data = get_pssh_from_mpd(url)
        output = {"Cdn": [], "ManifestUrl": url, "Headers": {"Manifest": {'User-Agent': user_agent}, "Media": {'User-Agent': user_agent}}, "PlanId": plan_id, "UserId": user_id, "DeviceId": device_id}
        if pssh_data:
            output['Pssh'] = pssh_data
        print(json.dumps(output))
    elif action == "cdm" and cdm_param == "external":
        url = id.replace('url=', '') if id.startswith('url=') else id
        pssh_data = get_pssh_from_mpd(url)
        if pssh_data:
            for key in do_cdm_external(pssh_data, plan_id, user_id, device_id):
                print(key)

do_action()
