#!/usr/bin/python3
import sys
import os
import o11
import json
import datetime
import pytz
import string
import secrets

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 = '/SaltTV_' + user + '.tokens'
user_agent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36'

def generate_random_string(length):
    alphabet = string.ascii_letters + string.digits
    return ''.join(secrets.choice(alphabet) for _ in range(length))

def get_client_app_token():
    headers = {'Content-Type': 'application/json', 'Referer': 'https://tv.salt.ch/', 'User-Agent': user_agent, 'X-Zapi-Stage': 'production'}
    params = {'id': generate_random_string(21)}
    response = req.get('https://tv.salt.ch/token.json', params=params, headers=headers)
    return response.json().get('session_token', '')

def get_hello():
    uuid_val = generate_random_string(20)
    cookies = {'uuid': uuid_val}
    headers = {'Origin': 'https://tv.salt.ch', 'Referer': 'https://tv.salt.ch/client', 'User-Agent': user_agent, 'accept': 'application/json', 'content-type': 'application/x-www-form-urlencoded', 'x-zapi-stage': 'production'}
    data = {'uuid': uuid_val, 'app_version': '3.2407.0', 'client_app_token': get_client_app_token()}
    response = req.post('https://tv.salt.ch/zapi/v3/session/hello', headers=headers, data=data, cookies=cookies)
    resp_data = response.json()
    return resp_data.get('power_guide_hash', ''), {**response.cookies.get_dict(), **cookies}

def get_channels(cookies, hello_hash):
    headers = {'Referer': 'https://tv.salt.ch/client', 'User-Agent': user_agent, 'accept': 'application/json', 'x-zapi-stage': 'production'}
    response = req.get(f'https://tv.salt.ch/zapi/v4/cached/{hello_hash}/channels', cookies=cookies, headers=headers)
    channels = response.json().get('channels', [])
    result = []
    for c in channels:
        for q in c.get('qualities', []):
            if 'drm_required' not in q:
                result.append(c)
                break
    return result

def get_single(cookies, channel_id):
    headers = {'Origin': 'https://tv.salt.ch', 'Referer': 'https://tv.salt.ch/client', 'User-Agent': user_agent, 'accept': 'application/json', 'content-type': 'application/x-www-form-urlencoded', 'x-zapi-stage': 'production'}
    data = {'stream_type': 'dash', 'https_watch_urls': 'True', 'thumbnail_seeking': 'False'}
    response = req.post(f'https://tv.salt.ch/zapi/watch/live/{channel_id}', cookies=cookies, headers=headers, data=data)
    return response.json().get('stream', {}).get('watch_urls', [{}])[0].get('url', '')

def do_login_request(cookies, username, pwd):
    headers = {'Origin': 'https://tv.salt.ch', 'Referer': 'https://tv.salt.ch/client', 'User-Agent': user_agent, 'accept': 'application/json', 'content-type': 'application/x-www-form-urlencoded', 'x-zapi-stage': 'production'}
    data = {'login': username, 'password': pwd, 'remember': 'True', 'keep_lang': 'True'}
    response = req.post('https://tv.salt.ch/zapi/v3/account/login', cookies=cookies, headers=headers, data=data)
    return response.cookies.get_dict()

def login():
    print("logging in...", file=sys.stderr)
    hello_hash, init_cookies = get_hello()
    login_cookies = do_login_request(init_cookies, user, password)
    auth_data = {'cookies': login_cookies, 'hello_hash': hello_hash}
    json.dump(auth_data, open(os.path.abspath(os.path.dirname(__file__)) + authFile, 'w'))
    print("logged in successfully", file=sys.stderr)

def get_auth():
    auth = json.load(open(os.path.abspath(os.path.dirname(__file__)) + authFile))
    hello_hash, init_cookies = get_hello()
    login_cookies = do_login_request(init_cookies, user, password)
    return login_cookies, hello_hash

def do_action():
    if action == "login":
        login()
        sys.exit()
    try:
        cookies, hello_hash = get_auth()
    except:
        return "error"

    if action == "channels":
        output = {'Channels': []}
        for c in get_channels(cookies, hello_hash):
            output['Channels'].append({'Name': c['title'], 'Mode': "live", 'SessionManifest': True, 'ManifestScript': 'cid=' + str(c['cid']), 'CdmType': "clear", 'UseCdm': False, 'Video': 'best'})
        print(json.dumps(output, indent=2))
    elif action == "events":
        output = {'Events': []}
        for c in get_channels(cookies, hello_hash):
            output['Events'].append({'Name': c['title'], 'Mode': "live", 'SessionManifest': True, 'ManifestScript': 'cid=' + str(c['cid']), 'CdmType': "clear", 'UseCdm': False, '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":
        channel_id = id.replace('cid=', '') if id.startswith('cid=') else id
        url = get_single(cookies, channel_id)
        output = {"Cdn": [], "ManifestUrl": url, "Headers": {"Manifest": {'User-Agent': user_agent}, "Media": {'User-Agent': user_agent}}}
        print(json.dumps(output))

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