#!/usr/bin/python3
import sys
import os
import o11
import base64
import json
import datetime
import pytz
import requests
import urllib.parse
from pywidevine.cdm import Cdm
from pywidevine.device import Device
from pywidevine.pssh import PSSH

WVD_PATH = './WVD.wvd'

user = o11.parse_params(sys.argv, 'user')
password = o11.parse_params(sys.argv, 'password')
asin = o11.parse_params(sys.argv, 'asin')
region = o11.parse_params(sys.argv, 'region')
device_param = 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')

# Cookie parameters - get from browser DevTools
session_id_cookie = o11.parse_params(sys.argv, 'sessionId')
ubid_cookie = o11.parse_params(sys.argv, 'ubid')
at_main_cookie = o11.parse_params(sys.argv, 'atMain')
sess_at_main_cookie = o11.parse_params(sys.argv, 'sessAtMain')
session_token_cookie = o11.parse_params(sys.argv, 'sessionToken')

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

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

authFile = '/Amazon_' + user + '.tokens'
proxies = {"http": proxy, "https": proxy} if proxy else {}

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

# Service certificate for Amazon
CERT_B64 = "CAUSwgUKvAIIAxIQCuQRtZRasVgFt7DIvVtVHBi17OSpBSKOAjCCAQoCggEBAKU2UrYVOSDlcXajWhpEgGhqGraJtFdUPgu6plJGy9ViaRn5mhyXON5PXmw1krQdi0SLxf00FfIgnYFLpDfvNeItGn9rcx0RNPwP39PW7aW0Fbqi6VCaKWlR24kRpd7NQ4woyMXr7xlBWPwPNxK4xmR/6UuvKyYWEkroyeIjWHAqgCjCmpfIpVcPsyrnMuPFGl82MMVnAhTweTKnEPOqJpxQ1bdQvVNCvkba5gjOTbEnJ7aXegwhmCdRQzXjTeEV2dO8oo5YfxW6pRBovzF6wYBMQYpSCJIA24ptAP/2TkneyJuqm4hJNFvtF8fsBgTQQ4TIhnX4bZ9imuhivYLa6HsCAwEAAToPYW1hem9uLmNvbS1wcm9kEoADETQD6R0H/h9fyg0Hw7mj0M7T4s0bcBf4fMhARpwk2X4HpvB49bJ5Yvc4t41mAnXGe/wiXbzsddKMiMffkSE1QWK1CFPBgziU23y1PjQToGiIv/sJIFRKRJ4qMBxIl95xlvSEzKdt68n7wqGa442+uAgk7CXU3uTfVofYY76CrPBnEKQfad/CVqTh48geNTb4qRH1TX30NzCsB9NWlcdvg10pCnWSm8cSHu1d9yH+2yQgsGe52QoHHCqHNzG/wAxMYWTevXQW7EPTBeFySPY0xUN+2F2FhCf5/A7uFUHywd0zNTswh0QJc93LBTh46clRLO+d4RKBiBSj3rah6Y5iXMw9N9o58tCRc9gFHrjfMNubopWHjDOO3ATUgqXrTp+fKVCmsGuGl1ComHxXV9i1AqHwzzY2JY2vFqo73jR3IElr6oChPIwcNokmNc0D4TXtjE0BoYkbWKJfHvJJihzMOvDicWUsemVHvua9/FBtpbHgpbgwijFPjtQF9Ldb8Swf"

# Region-specific base URLs
REGION_URLS = {
    'US': 'https://atv-ps.amazon.com/cdp/catalog/GetPlaybackResources',
    'EU': 'https://atv-ps-eu.primevideo.com/cdp/catalog/GetPlaybackResources',
    'FE': 'https://atv-ps-fe.primevideo.com/cdp/catalog/GetPlaybackResources',
}

def get_license_url(asin_val, region_code='EU'):
    base_url = REGION_URLS.get(region_code, REGION_URLS['EU'])
    params = {
        'deviceID': 'f701efacbd06b41309fd98d09a08ba24b5b8a638009a564c09fb896f',
        'deviceTypeID': 'AOAGZA014O5RE',
        'gascEnabled': 'true',
        'marketplaceID': 'A15PK738MTQHSO',
        'uxLocale': 'en_US',
        'firmware': '1',
        'clientId': 'f22dbddb-ef2c-48c5-8876-bed0d47594fd',
        'operatingSystemName': 'Linux',
        'operatingSystemVersion': 'unknown',
        'asin': asin_val,
        'consumptionType': 'Streaming',
        'desiredResources': 'Widevine2License',
        'resourceUsage': 'ImmediateConsumption',
        'videoMaterialType': 'Feature',
        'deviceProtocolOverride': 'Https',
        'deviceStreamingTechnologyOverride': 'DASH',
        'deviceDrmOverride': 'CENC',
        'deviceAdInsertionTypeOverride': 'SSAI',
        'deviceHdrFormatsOverride': 'None',
        'deviceVideoCodecOverride': 'H264',
        'deviceVideoQualityOverride': 'SD',
        'deviceBitrateAdaptationsOverride': 'CVBR,CBR',
        'playerAttributes': '{"middlewareName":"Firefox64","middlewareVersion":"108.0","nativeApplicationName":"Firefox64","nativeApplicationVersion":"108.0","supportedAudioCodecs":"AAC","frameRate":"HFR","H264.codecLevel":"4.2","H265.codecLevel":"0.0","AV1.codecLevel":"0.0"}',
    }
    return base_url + "?" + urllib.parse.urlencode(params)

def do_cdm_external(pssh_data, asin_val, cookies, region_code='EU'):
    """Extract Widevine keys using pywidevine library with service certificate"""
    pssh_obj = PSSH(pssh_data)
    device_obj = Device.load(WVD_PATH)
    cdm_obj = Cdm.from_device(device_obj)
    session_id = cdm_obj.open()
    
    # Set service certificate
    cdm_obj.set_service_certificate(session_id, CERT_B64)
    
    challenge_data = cdm_obj.get_license_challenge(session_id, pssh_obj)
    
    lic_url = get_license_url(asin_val, region_code)
    
    lic_headers = {
        'Accept': 'application/json',
        'Content-Type': 'application/x-www-form-urlencoded',
        'User-Agent': user_agent,
    }
    
    license_form_data = {
        'widevine2Challenge': base64.b64encode(challenge_data).decode(),
        'includeHdcpTestKeyInLicense': 'false'
    }
    
    licence = req.post(lic_url, data=license_form_data, headers=lic_headers, cookies=cookies)

    try:
        licence.raise_for_status()
        resp_data = licence.json()
        license_b64 = resp_data['widevine2License']['license']
        
        cdm_obj.parse_license(session_id, base64.b64decode(license_b64))
        keys = []
        for key in cdm_obj.get_keys(session_id):
            if key.type != 'SIGNING':
                keys.append(f"{key.kid.hex}:{key.key.hex()}")
        cdm_obj.close(session_id)
        return keys
    except Exception as e:
        print(f'License request failed: {e}', file=sys.stderr)
        return []

def login():
    print("Saving cookies...", file=sys.stderr)
    if not session_id_cookie or not at_main_cookie:
        print("Please provide cookie parameters from browser DevTools:", file=sys.stderr)
        print("  sessionId, ubid, atMain, sessAtMain, sessionToken", file=sys.stderr)
        sys.exit(1)
    
    auth_data = {
        'session-id': session_id_cookie,
        'ubid-main-av': ubid_cookie,
        'at-main-av': at_main_cookie,
        'sess-at-main-av': sess_at_main_cookie,
        'session-token': session_token_cookie,
        'region': region if region else 'EU'
    }
    json.dump(auth_data, open(os.path.abspath(os.path.dirname(__file__)) + authFile, 'w'))
    print("Cookies saved successfully", file=sys.stderr)

def do_action():
    if action == "login":
        login()
        sys.exit()

    try:
        auth = json.load(open(os.path.abspath(os.path.dirname(__file__)) + authFile))
        cookies = {
            'session-id': auth.get('session-id', ''),
            'ubid-main-av': auth.get('ubid-main-av', ''),
            'at-main-av': auth.get('at-main-av', ''),
            'sess-at-main-av': auth.get('sess-at-main-av', ''),
            'session-token': auth.get('session-token', ''),
        }
        region_code = auth.get('region', 'EU')
    except:
        return "error"

    if action == "channels":
        print("Amazon Prime Video does not have traditional channels. Use action=cdm with asin and pssh parameters.", file=sys.stderr)
        output = {'Channels': []}
        print(json.dumps(output, indent=2))

    elif action == "events":
        print("Amazon Prime Video does not have traditional events. Use action=cdm with asin and pssh parameters.", file=sys.stderr)
        output = {'Events': []}
        print(json.dumps(output, indent=2))

    elif action == "heartbeat":
        sys.exit()

    elif action == "manifest":
        # Amazon requires ASIN for content
        asin_val = id if id else asin
        if not asin_val:
            print("Please provide asin parameter", file=sys.stderr)
            return "error"
        
        output = {
            "Cdn": [],
            "Note": "Amazon Prime Video requires ASIN and PSSH to get keys. Use browser DevTools to get the manifest URL.",
            "LicenseUrl": get_license_url(asin_val, region_code),
            "Headers": {
                "Manifest": {'User-Agent': user_agent},
                "Media": {'User-Agent': user_agent}
            },
            "Heartbeat": {
                "Url": '',
                "Params": '',
                "PeriodMs": 5*60*1000
            }
        }
        print(json.dumps(output))

    elif action == "cdm" and cdm == "internal":
        asin_val = id if id else asin
        if not asin_val:
            print("Please provide asin parameter", file=sys.stderr)
            return "error"
        
        try:
            lic_url = get_license_url(asin_val, region_code)
            lic_headers = {
                'Accept': 'application/json',
                'Content-Type': 'application/x-www-form-urlencoded',
                'User-Agent': user_agent,
            }
            license_form_data = {
                'widevine2Challenge': challenge,
                'includeHdcpTestKeyInLicense': 'false'
            }
            response = req.post(lic_url, data=license_form_data, headers=lic_headers, cookies=cookies)
            resp_data = response.json()
            print(resp_data['widevine2License']['license'])
        except Exception as e:
            print(f"Error: {e}", file=sys.stderr)
            return "error"

    elif action == "cdm" and cdm == "external":
        asin_val = id if id else asin
        pssh_val = pssh
        if not asin_val or not pssh_val:
            print("Please provide asin and pssh parameters", file=sys.stderr)
            return "error"
        
        try:
            keys = do_cdm_external(pssh_val, asin_val, cookies, region_code)
            for key in keys:
                print(key)
        except Exception as e:
            print(f"Error: {e}", file=sys.stderr)
            return "error"

    else:
        print("invalid action: " + action, file=sys.stderr)

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