From b6ac632863d35f2cd45c7e4b6c918440b8a41774 Mon Sep 17 00:00:00 2001 From: Pari Malam Date: Sat, 27 Jun 2026 06:33:49 +0800 Subject: [PATCH] released v1.3.5 --- .gitignore | 4 +- setup.sh | 49 +- src/RunMe.sh | 86 +--- src/modules/hls_proxy.py | 117 ++++- src/modules/monitoring.py | 4 +- src/o11.cfg | 1021 +++++++++++++++++++++++++++++++++++++ 6 files changed, 1149 insertions(+), 132 deletions(-) create mode 100644 src/o11.cfg diff --git a/.gitignore b/.gitignore index b023cb4..db1a99b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,6 @@ .vscode/ launcher.go /build/ -o11pro workspace-69e17692-9d10-431b-adee-503d25eb1a71.tar -venv/ \ No newline at end of file +venv/ +cache/ \ No newline at end of file diff --git a/setup.sh b/setup.sh index 2575300..8320dec 100644 --- a/setup.sh +++ b/setup.sh @@ -71,61 +71,20 @@ if [ -f "$RUNME" ]; then # Make it executable chmod +x "$RUNME" - # Check if we already patched it (look for our marker) - if ! grep -q "# VENV_PATCHED" "$RUNME"; then - echo "Patching RunMe.sh to use virtual environment..." - # Insert venv PATH right after the existing export PATH line - sed -i.bak \ - -e 's|^export PATH="/usr/bin:/bin:/usr/local/bin:${PATH:-}"|# VENV_PATCHED\nexport PATH="'"$VENV_DIR"'/bin:/usr/bin:/bin:/usr/local/bin:${PATH:-}"|' \ - "$RUNME" - echo "RunMe.sh patched (backup saved as RunMe.sh.bak)" - else - echo "RunMe.sh already patched." - fi + echo "RunMe.sh PATH is configured dynamically." else echo "ERROR: RunMe.sh not found at $RUNME" exit 1 fi echo "Checking required files in $SRC_DIR ..." -REQUIRED_FILES=("o11pro" "o11.cfg" "providers/sample.cfg") -MISSING=0 -for f in "${REQUIRED_FILES[@]}"; do - if [ ! -f "$SRC_DIR/$f" ]; then - echo "ERROR: Required file 'src/$f' not found." - MISSING=1 - fi -done -if [ $MISSING -eq 1 ]; then - echo "Please place all required files under src/." +if [ ! -f "$SRC_DIR/o11pro" ]; then + echo "ERROR: Required file 'src/o11pro' not found." + echo "Please place o11pro binary under src/." exit 1 fi echo "All required files present." -echo "Building hls_proxy channel URL config ..." -"$VENV_DIR/bin/python3" -c " -import json, sys -cfg_path = '$SRC_DIR/providers/sample.cfg' -out_path = '/tmp/o11pro_orig_urls.json' -try: - d = json.load(open(cfg_path)) - urls = {} - for s in d.get('Streams', []): - name = s.get('Name', '') - manifest = s.get('Manifest', '') - if name and manifest: - urls[name] = manifest - if urls: - json.dump(urls, open(out_path, 'w'), indent=2, ensure_ascii=False) - print(f' Wrote {len(urls)} channel URLs to {out_path}') - else: - print(' WARNING: No channel URLs found in provider config') - json.dump({}, open(out_path, 'w')) -except Exception as e: - print(f' WARNING: Could not build URL config: {e}') - json.dump({}, open(out_path, 'w')) -" - echo "" MODE_PARTS=("o11pro :${1:-19999}") # FIX: was $1 (unbound when no args) if [ "${HLS_PROXY:-true}" = "true" ]; then diff --git a/src/RunMe.sh b/src/RunMe.sh index 49a6f93..a8da23a 100644 --- a/src/RunMe.sh +++ b/src/RunMe.sh @@ -10,7 +10,7 @@ # - Correct PATH for python3.13 dependencies # # Usage: -# ./RunMe.sh # Run with defaults (port 19999, verbose=2) +# ./RunMe.sh # Run with defaults (port 1337, verbose=2) # ./RunMe.sh 8080 # Run on custom port # ./RunMe.sh 8080 4 # Run on port 8080 with verbose=4 (trace) # GOMEMLIMIT=4G ./RunMe.sh # Override memory limit @@ -20,8 +20,6 @@ # # Files required (in same directory as this script): # o11pro Patched binary -# o11.cfg Global config -# providers/sample.cfg Provider config # keys.txt DRM KID:key pairs (optional) set -euo pipefail @@ -29,32 +27,31 @@ set -euo pipefail # Configuration # Security monitor: set to true to run through the HTTP proxy/monitor -# Architecture: Client -> :19998 (proxy/monitor) -> :19999 (real o11 API) -MONITOR="${MONITOR:-false}" +# Architecture: Client -> :1339 (proxy/monitor) -> :1337 (real o11 API) +MONITOR="${MONITOR:-true}" # Monitor proxy listen port (only used when MONITOR=true) -MONITOR_PORT="${MONITOR_PORT:-19998}" +MONITOR_PORT="${MONITOR_PORT:-1339}" # FIX: HLS Proxy config was missing entirely -# Architecture: Player -> :9999 (hls_proxy) -> upstream CDN +# Architecture: Player -> :1338 (hls_proxy) -> upstream CDN HLS_PROXY="${HLS_PROXY:-true}" -HLS_PROXY_PORT="${HLS_PROXY_PORT:-9999}" -HLS_PROXY_BIND="${HLS_PROXY_BIND:-0.0.0.0}" -HLS_PROXY_CONFIG="${HLS_PROXY_CONFIG:-/tmp/o11pro_orig_urls.json}" - +HLS_PROXY_PORT="${HLS_PROXY_PORT:-1338}" +HLS_PROXY_BIND="${HLS_PROXY_BIND:-127.0.0.1}" # Path setup: need /usr/bin first so binary spawns python3.13 (has deps) # instead of venv python3.12 (lacks deps like curl_cffi, cloudscraper) # VENV_PATCHED -export PATH="/home/z/my-project/o11/venv/bin:/usr/bin:/bin:/usr/local/bin:${PATH:-}" -# Port for HTTP API and streaming (default 19999, override with $1) -PORT="${1:-19999}" +KID_PATCH_OFFSET="${KID_PATCH_OFFSET:-0x15625cd}" + +# Port for HTTP API and streaming (default 1337, override with $1) +PORT="${1:-1337}" # FIX: was VERBOSE="${2:-2}" (always defaulted to 2 even when $2 was set) VERBOSE="${2:-2}" -# Bind address: 0.0.0.0 = all interfaces (use 127.0.0.1 for localhost-only) -BIND="${BIND:-0.0.0.0}" +# Bind address: 127.0.0.1 = all interfaces (use 127.0.0.1 for localhost-only) +BIND="${BIND:-127.0.0.1}" GOMEMLIMIT="${GOMEMLIMIT:-2GiB}" KEEP_FALSE=true @@ -65,6 +62,9 @@ ADMIN_PASS="${ADMIN_PASS:-}" # Working directory (where binary and configs live) SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" +export PATH="$PROJECT_ROOT/venv/bin:/usr/bin:/bin:/usr/local/bin:${PATH:-}" +HLS_PROXY_CONFIG="${HLS_PROXY_CONFIG:-$PROJECT_ROOT/cache/orig_urls.json}" cd "$SCRIPT_DIR" # Pre-flight checks @@ -83,7 +83,7 @@ fi # Verify the binary has the KID patch (not the original REDA bug) KID_PATCH=$(python3 -c " with open('$BINARY','rb') as f: - f.seek(0x15625cd) + f.seek($KID_PATCH_OFFSET) b = f.read(4) print('OK' if b == b'%02x' else 'MISSING') " 2>/dev/null || echo "CHECK_FAILED") @@ -93,31 +93,8 @@ if [ "$KID_PATCH" != "OK" ]; then echo "" fi -# Verify the string patch (nulled!! -> Ap0dexMe0) -STRING_PATCH=$(python3 -c " -with open('$BINARY','rb') as f: - f.seek(0x1a6c350) - b = f.read(9) - print('OK' if b == b'Ap0dexMe0' else 'MISSING') -" 2>/dev/null || echo "CHECK_FAILED") - -if [ "$STRING_PATCH" != "OK" ]; then - echo "NOTE: String patch (nulled!! -> Ap0dexMe0) not detected." - echo "" -fi - chmod +x "$BINARY" -if [ ! -f "o11.cfg" ]; then - echo "ERROR: Global config 'o11.cfg' not found" - exit 1 -fi - -if [ ! -f "providers/sample.cfg" ]; then - echo "ERROR: Provider config 'providers/sample.cfg' not found" - exit 1 -fi - if [ ! -f "keys.txt" ]; then echo "WARNING: keys.txt not found encrypted streams will fail" echo "" @@ -142,29 +119,15 @@ fi # Prepare directories echo "Preparing directories..." -mkdir -p hls/live keys epg dl manifests offair overlay logos fonts rec scripts logs providers +mkdir -p hls/live keys epg dl manifests offair overlay logos fonts rec scripts logs providers cache if [ -f "keys.txt" ] && [ ! -f "keys/keys.txt" ]; then cp keys.txt keys/ 2>/dev/null || true fi -# Apply config overrides - -if [ "$MAX_STREAMS" != "0" ]; then - echo "Setting MaxConcurrentStreams=$MAX_STREAMS in provider config..." - python3 -c " -import json -with open('providers/sample.cfg') as f: - cfg = json.load(f) -cfg['MaxConcurrentStreams'] = $MAX_STREAMS -with open('providers/sample.cfg', 'w') as f: - json.dump(cfg, f, indent=4, ensure_ascii=False) -" 2>/dev/null || echo " (failed to patch config continuing with existing value)" -fi - # Build command line -ARGS="-c o11.cfg -p $PORT -b $BIND -headless -stdout -v $VERBOSE" +ARGS="-c o11.cfg -p $PORT -b $BIND -stdout -v $VERBOSE" if [ "$KEEP_FALSE" = "true" ]; then ARGS="$ARGS -keep=false" @@ -234,7 +197,6 @@ echo " Max streams: ${MAX_STREAMS:-unlimited}" echo " HTTPS: $HTTPS" echo " HLS Proxy: $HLS_PROXY${HLS_PROXY:+ (port $HLS_PROXY_PORT)}" echo " Security mon: $MONITOR${MONITOR:+ (port $MONITOR_PORT)}" -echo " Config: o11.cfg + providers/sample.cfg" echo "==========================================" echo "" echo "Service endpoints:" @@ -251,7 +213,7 @@ if [ "$MONITOR" = "true" ]; then echo " Audit log: logs/audit.log" echo " Alert log: logs/audit_alerts.log" fi -echo " (use 127.0.0.1 instead of 0.0.0.0 in your browser)" +echo " (use 127.0.0.1 instead of 127.0.0.1 in your browser)" echo "" echo "Login: admin / " echo "" @@ -284,12 +246,14 @@ if [ "$MONITOR" = "true" ] || [ "$HLS_PROXY" = "true" ]; then # Wait for o11pro to be ready echo "Waiting for o11pro to be ready on port $PORT..." - for i in $(seq 1 30); do + _O11_TRIES=0 + while [ $_O11_TRIES -lt 30 ]; do + _O11_TRIES=$((_O11_TRIES + 1)) if python3 -c "import socket; s=socket.socket(); s.settimeout(1); s.connect(('127.0.0.1',$PORT)); s.close()" 2>/dev/null; then echo "o11pro is ready" break fi - if [ $i -eq 30 ]; then + if [ $_O11_TRIES -eq 30 ]; then echo "ERROR: o11pro did not start in time" kill "$O11_PID" 2>/dev/null || true exit 1 @@ -343,7 +307,7 @@ if [ "$MONITOR" = "true" ] || [ "$HLS_PROXY" = "true" ]; then echo "Security monitor enabled" echo " Proxy port: $MONITOR_PORT (-> o11 API :$PORT)" echo " Process scan: PID $O11_PID" - echo " File watch: keys.txt, providers/, o11.cfg, logs/, hls/" + echo " File watch: keys.txt, providers/, logs/, hls/" echo " Audit log: logs/audit.log" echo " Alert log: logs/audit_alerts.log" echo "" diff --git a/src/modules/hls_proxy.py b/src/modules/hls_proxy.py index 3ea5099..1e5a9bd 100644 --- a/src/modules/hls_proxy.py +++ b/src/modules/hls_proxy.py @@ -10,7 +10,7 @@ import base64 import time import sys import os -import argparse # FIX: was missing +import argparse import threading import traceback import gc @@ -20,7 +20,7 @@ from http.server import HTTPServer, BaseHTTPRequestHandler from urllib.parse import urlparse, parse_qs from concurrent.futures import ThreadPoolExecutor -CONFIG_FILE = '/tmp/o11pro_orig_urls.json' +CONFIG_FILE = os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', '..', 'cache', 'orig_urls.json') PROXY_PORT = 9999 PROXY_BIND = '127.0.0.1' UA = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36' @@ -32,6 +32,9 @@ MAX_THREAD_POOL = 32 GC_INTERVAL_SEC = 60 SEGMENT_STREAM_BUF = 65536 +# Global default auth (user, pass) +_global_auth = None + # Cached channel URLs (loaded once) _channel_urls = {} _channel_urls_lock = threading.Lock() @@ -41,10 +44,25 @@ def _load_channel_urls(): with _channel_urls_lock: if not _channel_urls: with open(CONFIG_FILE) as f: - _channel_urls = json.load(f) + raw = json.load(f) + # Support both {"name": "url"} and {"name": {"url":"...","auth":[...]}} + for k, v in raw.items(): + _channel_urls[k] = v log(f"Loaded {len(_channel_urls)} channel URLs") return _channel_urls +def _get_channel_entry(name): + """Return (url, auth) tuple for a channel. auth may be None.""" + urls = _load_channel_urls() + entry = urls.get(name) + if entry is None: + return None, None + if isinstance(entry, dict): + url = entry.get('url', '') + auth = entry.get('auth') # list [user, pass] or None + return url, auth + return entry, None # plain string URL + # Bounded CookieJar class BoundedCookieJar(http.cookiejar.CookieJar): def __init__(self, *args, **kwargs): @@ -101,35 +119,64 @@ def _get_opener(cookie_jar=None): _opener_cache.popitem(last=False) return opener -# URL fetching -def fetch_url(url, timeout=15, cookie_jar=None, referer=None): +# URL fetching — returns (body, status, content_type, final_url) +def fetch_url(url, timeout=15, cookie_jar=None, referer=None, auth=None): + """Fetch a URL, following redirects. Returns (body, status, content_type, final_url). + + final_url is the URL after any HTTP redirects, which must be used as the + base for resolving relative URLs in HLS manifests. + """ opener = _get_opener(cookie_jar) - headers = {'User-Agent': UA} + headers = { + 'User-Agent': UA, + 'Accept-Encoding': 'identity', # prevent transparent gzip to avoid double-decode issues + } if referer: headers['Referer'] = referer + # Auth: per-request > global default + effective_auth = auth or _global_auth + if effective_auth: + if isinstance(effective_auth, (list, tuple)) and len(effective_auth) == 2: + cred = base64.b64encode(f"{effective_auth[0]}:{effective_auth[1]}".encode()).decode() + headers['Authorization'] = f"Basic {cred}" + elif isinstance(effective_auth, str) and ':' in effective_auth: + cred = base64.b64encode(effective_auth.encode()).decode() + headers['Authorization'] = f"Basic {cred}" req = urllib.request.Request(url, headers=headers) try: with opener.open(req, timeout=timeout) as resp: - return resp.read(), resp.status, resp.headers.get('Content-Type', 'application/octet-stream') + # Capture the final URL after any redirects + final_url = getattr(resp, 'url', None) or getattr(resp, 'geturl', lambda: url)() or url + return resp.read(), resp.status, resp.headers.get('Content-Type', 'application/octet-stream'), final_url except urllib.error.HTTPError as e: body = e.read() if e.fp else b'' ct = e.headers.get('Content-Type', 'application/octet-stream') if e.headers else 'text/html' - return body, e.code, ct + final_url = getattr(e, 'url', None) or url + return body, e.code, ct, final_url except (urllib.error.URLError, OSError) as e: - return b'', 0, 'text/plain' + return b'', 0, 'text/plain', url # Manifest URL rewriting _compiled_uri_re = re.compile(r'URI="([^"]+)"') def rewrite_manifest(body, base_url): + """Rewrite all relative URLs in an HLS manifest to absolute proxy URLs.""" lines = body.split('\n') rewritten = [] for line in lines: stripped = line.strip() - if 'URI="' in stripped and stripped.startswith('#EXT-X-'): + if not stripped: + rewritten.append(line) + continue + # Handle #EXT-X-* tags that contain URI="..." + if stripped.startswith('#EXT-X-') and 'URI="' in stripped: rewritten.append(_compiled_uri_re.sub( lambda m: f'URI="{_abs(m.group(1), base_url)}"', stripped)) - elif stripped and not stripped.startswith('#'): + elif stripped.startswith('#'): + # Other comment/tag lines — keep as-is + rewritten.append(line) + elif not stripped.startswith('#'): + # Non-comment, non-empty line — treat as a resource URL rewritten.append(_abs(stripped, base_url)) else: rewritten.append(line) @@ -194,6 +241,7 @@ class RobustHandler(BaseHTTPRequestHandler): except Exception as e: with _stats_lock: _stats['errors'] += 1 + log(f"Handler error: {traceback.format_exc()}") try: self._err(500, str(e)) except: @@ -203,20 +251,26 @@ class RobustHandler(BaseHTTPRequestHandler): parts = path.split('/') if len(parts) >= 4 and parts[3] == 'master.m3u8': name = urllib.parse.unquote(parts[2]) - urls = _load_channel_urls() - if name in urls: - url = urls[name] + url, auth = _get_channel_entry(name) + if url: q = query if q: url += ('&' if '?' in url else '?') + q jar = _get_jar(urlparse(url).netloc) - body, st, ct = fetch_url(url, cookie_jar=jar) + body, st, ct, final_url = fetch_url(url, cookie_jar=jar, auth=auth) if st == 200: with _stats_lock: _stats['manifests'] += 1 - rw = rewrite_manifest(body.decode('utf-8', 'replace'), url) + # Use final_url (after redirects) as the base for resolving relative URLs + text = body.decode('utf-8', 'replace') + # Strip BOM if present + if text and text[0] == '\ufeff': + text = text[1:] + rw = rewrite_manifest(text, final_url) + log(f"[channel/{name}] base={url} final={final_url}") self._ok('application/vnd.apple.mpegurl', rw.encode()) else: + log(f"[channel/{name}] upstream returned {st} for {url}") self._err(502, f"Upstream {st}") else: self._err(404, "Channel not found") @@ -227,13 +281,18 @@ class RobustHandler(BaseHTTPRequestHandler): target = _from_proxy(path[3:]) referer = _get_referer(query) jar = _get_jar(urlparse(target).netloc) - body, st, ct = fetch_url(target, cookie_jar=jar, referer=referer) + body, st, ct, final_url = fetch_url(target, cookie_jar=jar, referer=referer) if st == 200: with _stats_lock: _stats['manifests'] += 1 - rw = rewrite_manifest(body.decode('utf-8', 'replace'), target) + # Use final_url (after redirects) as the base for resolving relative URLs + text = body.decode('utf-8', 'replace') + if text and text[0] == '\ufeff': + text = text[1:] + rw = rewrite_manifest(text, final_url) self._ok('application/vnd.apple.mpegurl', rw.encode()) else: + log(f"[manifest] upstream returned {st} for {target}") self._err(502, f"Upstream {st}") def _handle_segment(self, path, query): @@ -247,9 +306,15 @@ class RobustHandler(BaseHTTPRequestHandler): return referer = _get_referer(query) jar = _get_jar(urlparse(target).netloc) - headers = {'User-Agent': UA} + headers = { + 'User-Agent': UA, + 'Accept-Encoding': 'identity', + } if referer: headers['Referer'] = referer + if _global_auth: + cred = base64.b64encode(_global_auth.encode()).decode() + headers['Authorization'] = f"Basic {cred}" opener = _get_opener(jar) req = urllib.request.Request(target, headers=headers) try: @@ -374,33 +439,41 @@ def log(msg): # Main if __name__ == '__main__': - # FIX: was hardcoded, now accepts CLI arguments - parser = argparse.ArgumentParser(description='HLS Proxy for o11pro (memory-leak fixed)') + parser = argparse.ArgumentParser(description='HLS Proxy for o11pro (redirect-aware + auth)') parser.add_argument('--config', default=CONFIG_FILE, help=f'Path to channel URLs JSON (default: {CONFIG_FILE})') parser.add_argument('--port', type=int, default=PROXY_PORT, help=f'Proxy listen port (default: {PROXY_PORT})') parser.add_argument('--bind', default=PROXY_BIND, help=f'Proxy bind address (default: {PROXY_BIND})') + parser.add_argument('--auth', default=None, + help='Global Basic Auth credentials as user:pass ' + '(e.g. 1acd2d7afd8cb34099cb832862e3c08d:b85491a27c2852323ac704a07cf7b779)') args = parser.parse_args() CONFIG_FILE = args.config PROXY_PORT = args.port PROXY_BIND = args.bind + if args.auth: + _global_auth = args.auth + log(f"Global auth enabled") + _load_channel_urls() assert _compiled_uri_re is not None maint = threading.Thread(target=_maintenance_loop, daemon=True) maint.start() - print(f"HLS Proxy on {PROXY_BIND}:{PROXY_PORT} (memory-optimized)", flush=True) + print(f"HLS Proxy on {PROXY_BIND}:{PROXY_PORT} (redirect-aware + auth)", flush=True) print(f" Config: {CONFIG_FILE}", flush=True) print(f" Channels: {len(_channel_urls)}", flush=True) print(f" Thread pool: {MAX_THREAD_POOL} workers", flush=True) print(f" Cookie limit: {MAX_COOKIES_PER_JAR}/jar", flush=True) print(f" Streaming buffer: {SEGMENT_STREAM_BUF} bytes", flush=True) print(f" GC interval: {GC_INTERVAL_SEC}s", flush=True) + if _global_auth: + print(f" Global auth: enabled", flush=True) print(f"", flush=True) print(f" Routes:", flush=True) print(f" /channel/{{name}}/master.m3u8 - Channel master manifest", flush=True) diff --git a/src/modules/monitoring.py b/src/modules/monitoring.py index 7073626..14caf69 100644 --- a/src/modules/monitoring.py +++ b/src/modules/monitoring.py @@ -18,7 +18,7 @@ from http.server import HTTPServer, BaseHTTPRequestHandler from socketserver import ThreadingMixIn VERSION = "1.0.0" -DEFAULT_PID_FILE = "/tmp/o11_pid" +DEFAULT_PID_FILE = os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', '..', 'cache', 'o11_pid') DEFAULT_AUDIT_LOG = "audit.log" DEFAULT_ALERT_LOG = "audit_alerts.log" DEFAULT_PROXY_PORT = 19998 @@ -777,7 +777,7 @@ def find_o11_pid(): except (FileNotFoundError, ValueError): pass - for pid_file in (DEFAULT_PID_FILE, '/tmp/o11e2e/pid'): + for pid_file in (DEFAULT_PID_FILE, os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', '..', 'cache', 'o11_pid')): try: with open(pid_file) as f: pid = int(f.read().strip()) diff --git a/src/o11.cfg b/src/o11.cfg new file mode 100644 index 0000000..cc2706b --- /dev/null +++ b/src/o11.cfg @@ -0,0 +1,1021 @@ +{ + "Name": "HLS", + "Id": "hls", + "RunningMode": "internalremuxer", + "OutputMode": "directhls", + "Script": "", + "ScriptAccounts": null, + "ScriptAccountsUser": "none", + "LogoUrl": "", + "UseIPV6": false, + "ScriptNetwork": "", + "ScriptProxy": "", + "ScriptBind": "", + "ScriptDoh": "", + "ScriptDns": "", + "ScriptWorker": "", + "ManifestNetwork": "same", + "ManifestProxy": "", + "ManifestBind": "", + "ManifestDoh": "", + "ManifestDns": "", + "ManifestWorker": "", + "MediaNetwork": "same", + "MediaProxy": "", + "MediaBind": "", + "MediaDoh": "", + "MediaDns": "", + "MediaWorker": "", + "UserAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36", + "XForwardedFor": "", + "AppendResolution": false, + "EventsAutorefresh": false, + "EventsAutoremove": false, + "EventsAppendDate": false, + "EventsSqlUrl": "", + "EventsSqlStreamingUrl": "", + "EventsFirstId": 0, + "ChannelsAutoremove": false, + "MaxConcurrentStreams": 0, + "MaxConcurrentScript": 0, + "MaxStreamsPerAccount": 0, + "LastEventIndex": 0, + "LastVodIndex": 0, + "AlwaysResetSession": false, + "RestartDelay": 30, + "PipeOutputCmdFormated": "tsplay -pace-pcr2-pmt -stdin %s", + "NbAnnouncedFragments": 0, + "HlsFragmentsDuration": 0, + "PlaylistDuration": 15, + "AutorestartPeriod": 0, + "RandomAutorestartOffset": 0, + "NoRestartOnError": false, + "RestartFinished": false, + "NoRestartOnTrackChange": false, + "AlwaysAutorestart": false, + "RestartCoolDown": false, + "UseJsonRedirectUrl": false, + "OffAirFallback": false, + "PlaybackDelay": 0, + "RandomAutostartPeriod": 0, + "SequencialAutostartPeriod": 0, + "EpgTimezone": "", + "ReuseEventIndex": false, + "EventsReversedIds": false, + "EventsRefreshPeriod": 3600, + "HttpGetRetries": 2, + "NoWaitFullPlaylist": false, + "IgnoreStaticDash": false, + "UseDashDelay": false, + "StallDetectTimeout": 60, + "VmxUniqueId": "", + "DefaultCdn": "", + "DefaultVideo": "", + "DefaultAudio": "", + "DefaultSubtitles": "", + "MaxEventsCount": 0, + "ScriptTimeout": 30, + "UseSessionCookies": false, + "LegacyDashParser": false, + "PropagateManifestUrlParams": false, + "ForcePropagateManifestUrlParams": false, + "RetryDownloadWithNewManifestCount": 1, + "HttpGetTimeout": 30, + "MaxDownloadConcurrency": 50, + "SSAI": false, + "HlsIsTs": false, + "HlsIsMp4": false, + "DVBSubsNoColors": false, + "DVBSubsNoStyleParsing": false, + "DVBSubsColorsFilter": "", + "DVBSubsTranslationSrcLang": "", + "DVBSubsTranslationDstLang": "", + "DVBSubsSizePercentage": 100, + "DVBSubsVerticalOffsetPercentage": 95, + "DVBSubsQuality": 2, + "UseProviderScriptForSubtitles": false, + "UseVttTimestampMap": false, + "HwAccel": "none", + "BurnMessage": "", + "AddOverlay": false, + "AlwaysTranscode": false, + "DefaultEventDuration": 14400, + "PreProcessPssh": false, + "Headers2": { + "Manifest": {}, + "Media": {} + }, + "StreamsCount": 0, + "Streams": [ + { + "Name": "Spectrum Sportsnet+", + "Category": "", + "Description": "", + "Id": "spectrumsportsnet", + "LogoUrl": "", + "ExtraStatus": "", + "RecordEvent": false, + "RecordTs": false, + "Start": 0, + "End": 0, + "DailyStartTime": 0, + "DailyEndTime": 0, + "Type": "linear", + "RunningMode": "internalremuxer", + "OutputMode": "directhls", + "ScriptParams": "", + "ScriptAccountsUser": "provider", + "ScriptNetwork": "", + "ScriptProxy": "", + "ScriptBind": "", + "ScriptDoh": "", + "ScriptDns": "", + "ScriptWorker": "", + "ManifestNetwork": "same", + "ManifestProxy": "", + "ManifestBind": "", + "ManifestDoh": "", + "ManifestDns": "", + "ManifestWorker": "", + "MediaNetwork": "same", + "MediaProxy": "", + "MediaBind": "", + "MediaDoh": "", + "MediaDns": "", + "MediaWorker": "", + "OnDemand": true, + "Autostart": true, + "PipeOutputParams": "", + "ProtoOutputParams": "", + "SessionManifest": false, + "SpeedUp": true, + "ProcessDVBSubs": false, + "UseCdm": false, + "CdmType": "widevine", + "CdmMode": "internal", + "PRLAVersion": "", + "PRClientVersion": "", + "PRCustomData": "", + "NetworkOverride": false, + "ModeOverride": false, + "IgnoreUpdate": false, + "ManualEvent": false, + "TimeRange": false, + "DailyOnAir": false, + "Manifest": "https://lpnba.akamaized.net/live-pz/p/hls-wvpr/e0092490089e1001041/index.m3u8?State=GP\u0026PostalCode=\u0026Zip=\u0026LatLongRadius=\u0026ISO3166=\u0026_is_lat=0\u0026_fw_ae=\u0026_fw_h_user_agent=Mozilla%2F5.0+%28Windows+NT+10.0%3B+Win64%3B+x64%29+AppleWebKit%2F537.36+%28KHTML%2C+like+Gecko%29+Chrome%2F135.0.0.0+Safari%2F537.36+Edg%2F135.0.0.0\u0026sessionId=246854a4-2cb4-40d4-8c81-da8cd4ec3c9d", + "CdnName": "Custom", + "Cdn": null, + "ManifestType": "hls", + "ManifestInfo": "Format: \u003ci\u003e\u003cb\u003ehls/ts (live)\u003c/b\u003e\u003c/i\u003e\u003cbr\u003eBest video: \u003ci\u003e\u003cb\u003e1080p59\u003c/b\u003e\u003c/i\u003e\u003cbr\u003e", + "ManifestInfo2": { + "Type": "hls/ts", + "Mode": "live", + "BestVideo": "1080p59", + "DrmVendors": null + }, + "Video": "best", + "Audio": "mp4a.40.5-104400-48000-2-ENG-en-", + "Subtitles": "none", + "VideoList": [ + { + "Id": "-400x224-14.985-262502-", + "Resolution": "224", + "FrameRate": 14.985, + "Timescale": 0, + "Codec": "avc1.4D400C", + "Lang": "", + "Bandwidth": 262502, + "SamplingRate": 0, + "Channels": 0, + "Desc": "224p14 (avc1.4D400C 0.3Mbps)", + "Kid": "", + "IsInternal": false + }, + { + "Id": "-400x224-14.985-372538-", + "Resolution": "224", + "FrameRate": 14.985, + "Timescale": 0, + "Codec": "avc1.4D400C", + "Lang": "", + "Bandwidth": 372538, + "SamplingRate": 0, + "Channels": 0, + "Desc": "224p14 (avc1.4D400C 0.4Mbps)", + "Kid": "", + "IsInternal": false + }, + { + "Id": "-400x224-29.970-488347-", + "Resolution": "224", + "FrameRate": 29.97, + "Timescale": 0, + "Codec": "avc1.4D400D", + "Lang": "", + "Bandwidth": 488347, + "SamplingRate": 0, + "Channels": 0, + "Desc": "224p29 (avc1.4D400D 0.5Mbps)", + "Kid": "", + "IsInternal": false + }, + { + "Id": "-640x360-29.970-928347-", + "Resolution": "360", + "FrameRate": 29.97, + "Timescale": 0, + "Codec": "avc1.4D401E", + "Lang": "", + "Bandwidth": 928347, + "SamplingRate": 0, + "Channels": 0, + "Desc": "360p29 (avc1.4D401E 0.9Mbps)", + "Kid": "", + "IsInternal": false + }, + { + "Id": "-960x540-29.970-1828204-", + "Resolution": "540", + "FrameRate": 29.97, + "Timescale": 0, + "Codec": "avc1.4D401F", + "Lang": "", + "Bandwidth": 1828204, + "SamplingRate": 0, + "Channels": 0, + "Desc": "540p29 (avc1.4D401F 1.7Mbps)", + "Kid": "", + "IsInternal": false + }, + { + "Id": "-1280x720-29.970-3349284-", + "Resolution": "720", + "FrameRate": 29.97, + "Timescale": 0, + "Codec": "avc1.64001F", + "Lang": "", + "Bandwidth": 3349284, + "SamplingRate": 0, + "Channels": 0, + "Desc": "720p29 (avc1.64001F 3.2Mbps)", + "Kid": "", + "IsInternal": false + }, + { + "Id": "-1280x720-29.970-4999249-", + "Resolution": "720", + "FrameRate": 29.97, + "Timescale": 0, + "Codec": "avc1.64001F", + "Lang": "", + "Bandwidth": 4999249, + "SamplingRate": 0, + "Channels": 0, + "Desc": "720p29 (avc1.64001F 4.8Mbps)", + "Kid": "", + "IsInternal": false + }, + { + "Id": "-1280x720-59.940-6674208-", + "Resolution": "720", + "FrameRate": 59.94, + "Timescale": 0, + "Codec": "avc1.640020", + "Lang": "", + "Bandwidth": 6674208, + "SamplingRate": 0, + "Channels": 0, + "Desc": "720p59 (avc1.640020 6.4Mbps)", + "Kid": "", + "IsInternal": false + }, + { + "Id": "-1920x1080-59.940-9895008-", + "Resolution": "1080", + "FrameRate": 59.94, + "Timescale": 0, + "Codec": "avc1.64002A", + "Lang": "", + "Bandwidth": 9895008, + "SamplingRate": 0, + "Channels": 0, + "Desc": "1080p59 (avc1.64002A 9.4Mbps)", + "Kid": "", + "IsInternal": false + } + ], + "AudioList": [ + { + "Id": "mp4a.40.5-104400-48000-2-ENG-en-", + "Resolution": "", + "FrameRate": 0, + "Timescale": 0, + "Codec": "mp4a.40.5,", + "Lang": "en", + "Bandwidth": 0, + "SamplingRate": 0, + "Channels": 0, + "Desc": "ENG (en, mp4a.40.5,)", + "Kid": "", + "IsInternal": false + }, + { + "Id": "mp4a.40.5-73600-44100-2-ENG-en-", + "Resolution": "", + "FrameRate": 0, + "Timescale": 0, + "Codec": "mp4a.40.5,", + "Lang": "en", + "Bandwidth": 0, + "SamplingRate": 0, + "Channels": 0, + "Desc": "ENG (en, mp4a.40.5,)-1", + "Kid": "", + "IsInternal": false + }, + { + "Id": "mp4a.40.5-135200-48000-2-ENG-en-", + "Resolution": "", + "FrameRate": 0, + "Timescale": 0, + "Codec": "mp4a.40.5,", + "Lang": "en", + "Bandwidth": 0, + "SamplingRate": 0, + "Channels": 0, + "Desc": "ENG (en, mp4a.40.5,)-2", + "Kid": "", + "IsInternal": false + } + ], + "SubtitlesList": [], + "IgnoreKid": false, + "Keys": [ + "8e77b10817743706b55a47524ea7677b:e4deb130808022d4ad2ad4f75dad7bce" + ], + "Drm": { + "Vendor": null + }, + "Heartbeat": { + "Url": "", + "Params": "", + "PeriodMs": 0, + "RandomMs": 0 + }, + "License": { + "Url": "", + "Params": "" + }, + "Headers": { + "Manifest": {}, + "Media": {} + }, + "Info": "", + "LogLevel": 2, + "StreamingUrl": null, + "StreamingResolutions": null + }, + { + "Name": "TNT East", + "Category": "", + "Description": "", + "Id": "tnteast", + "LogoUrl": "", + "ExtraStatus": "", + "RecordEvent": false, + "RecordTs": false, + "Start": 0, + "End": 0, + "DailyStartTime": 0, + "DailyEndTime": 0, + "Type": "linear", + "RunningMode": "internalremuxer", + "OutputMode": "directhls", + "ScriptParams": "", + "ScriptAccountsUser": "provider", + "ScriptNetwork": "", + "ScriptProxy": "", + "ScriptBind": "", + "ScriptDoh": "", + "ScriptDns": "", + "ScriptWorker": "", + "ManifestNetwork": "same", + "ManifestProxy": "", + "ManifestBind": "", + "ManifestDoh": "", + "ManifestDns": "", + "ManifestWorker": "", + "MediaNetwork": "same", + "MediaProxy": "", + "MediaBind": "", + "MediaDoh": "", + "MediaDns": "", + "MediaWorker": "", + "OnDemand": true, + "Autostart": true, + "PipeOutputParams": "", + "ProtoOutputParams": "", + "SessionManifest": false, + "SpeedUp": false, + "ProcessDVBSubs": false, + "UseCdm": false, + "CdmType": "widevine", + "CdmMode": "internal", + "PRLAVersion": "", + "PRClientVersion": "", + "PRCustomData": "", + "NetworkOverride": false, + "ModeOverride": false, + "IgnoreUpdate": false, + "ManualEvent": false, + "TimeRange": false, + "DailyOnAir": false, + "Manifest": "https://live-media-fly.warnermediacdn.com/cmaf/live/2023191/tnteast-cenc/master_wv_de.m3u8", + "CdnName": "Custom", + "Cdn": null, + "ManifestType": "hls", + "ManifestInfo": "Format: \u003ci\u003e\u003cb\u003ehls/mp4 (live)\u003c/b\u003e\u003c/i\u003e\u003cbr\u003eBest video: \u003ci\u003e\u003cb\u003e1080p29\u003c/b\u003e\u003c/i\u003e\u003cbr\u003e\nDRM: \u003ci\u003e\u003cb\u003ewidevine \u003c/b\u003e\u003c/i\u003e\u003cbr\u003e", + "ManifestInfo2": { + "Type": "hls/mp4", + "Mode": "live", + "BestVideo": "1080p29", + "DrmVendors": [ + "widevine" + ] + }, + "Video": "best", + "Audio": "aac-128kbps-English-eng-", + "Subtitles": "none", + "VideoList": [ + { + "Id": "---147985-", + "Resolution": "", + "FrameRate": 0, + "Timescale": 0, + "Codec": "", + "Lang": "", + "Bandwidth": 147985, + "SamplingRate": 0, + "Channels": 0, + "Desc": "p ( 0.1Mbps)", + "Kid": "", + "IsInternal": false + }, + { + "Id": "-416x234-29.97-433817-", + "Resolution": "234", + "FrameRate": 29.97, + "Timescale": 0, + "Codec": "avc1.4d400d", + "Lang": "", + "Bandwidth": 433817, + "SamplingRate": 0, + "Channels": 0, + "Desc": "234p29 (avc1.4d400d 0.4Mbps)", + "Kid": "", + "IsInternal": false + }, + { + "Id": "-416x234-29.97-837797-", + "Resolution": "234", + "FrameRate": 29.97, + "Timescale": 0, + "Codec": "avc1.4d400d", + "Lang": "", + "Bandwidth": 837797, + "SamplingRate": 0, + "Channels": 0, + "Desc": "234p29 (avc1.4d400d 0.8Mbps)", + "Kid": "", + "IsInternal": false + }, + { + "Id": "-640x360-29.97-1491279-", + "Resolution": "360", + "FrameRate": 29.97, + "Timescale": 0, + "Codec": "avc1.4d401e", + "Lang": "", + "Bandwidth": 1491279, + "SamplingRate": 0, + "Channels": 0, + "Desc": "360p29 (avc1.4d401e 1.4Mbps)", + "Kid": "", + "IsInternal": false + }, + { + "Id": "-768x432-29.97-2511812-", + "Resolution": "432", + "FrameRate": 29.97, + "Timescale": 0, + "Codec": "avc1.4d401e", + "Lang": "", + "Bandwidth": 2511812, + "SamplingRate": 0, + "Channels": 0, + "Desc": "432p29 (avc1.4d401e 2.4Mbps)", + "Kid": "", + "IsInternal": false + }, + { + "Id": "-960x540-29.97-3389817-", + "Resolution": "540", + "FrameRate": 29.97, + "Timescale": 0, + "Codec": "avc1.4d401f", + "Lang": "", + "Bandwidth": 3389817, + "SamplingRate": 0, + "Channels": 0, + "Desc": "540p29 (avc1.4d401f 3.2Mbps)", + "Kid": "", + "IsInternal": false + }, + { + "Id": "-1280x720-29.97-6460913-", + "Resolution": "720", + "FrameRate": 29.97, + "Timescale": 0, + "Codec": "avc1.4d401f", + "Lang": "", + "Bandwidth": 6460913, + "SamplingRate": 0, + "Channels": 0, + "Desc": "720p29 (avc1.4d401f 6.2Mbps)", + "Kid": "", + "IsInternal": false + }, + { + "Id": "-1920x1080-29.97-10067540-", + "Resolution": "1080", + "FrameRate": 29.97, + "Timescale": 0, + "Codec": "avc1.640028", + "Lang": "", + "Bandwidth": 10067540, + "SamplingRate": 0, + "Channels": 0, + "Desc": "1080p29 (avc1.640028 9.6Mbps)", + "Kid": "", + "IsInternal": false + } + ], + "AudioList": [ + { + "Id": "aac-128kbps-English-eng-", + "Resolution": "", + "FrameRate": 0, + "Timescale": 0, + "Codec": "mp4a.40.2,", + "Lang": "eng", + "Bandwidth": 0, + "SamplingRate": 0, + "Channels": 0, + "Desc": "English (eng, mp4a.40.2,)", + "Kid": "", + "IsInternal": false + } + ], + "SubtitlesList": [], + "IgnoreKid": false, + "Keys": [ + "119a1b15e686ff9d2a0eecd50000003a:ac231eec15fa8fcbe1b3063627a37ade" + ], + "Drm": { + "Vendor": null + }, + "Heartbeat": { + "Url": "", + "Params": "", + "PeriodMs": 0, + "RandomMs": 0 + }, + "License": { + "Url": "", + "Params": "" + }, + "Headers": { + "Manifest": {}, + "Media": {} + }, + "Info": "", + "LogLevel": 2, + "StreamingUrl": null, + "StreamingResolutions": null + }, + { + "Name": "TBS East", + "Category": "", + "Description": "", + "Id": "tbseast", + "LogoUrl": "", + "ExtraStatus": "Error: HTTP Get returned status code 403 after 0.04s", + "RecordEvent": false, + "RecordTs": false, + "Start": 0, + "End": 0, + "DailyStartTime": 0, + "DailyEndTime": 0, + "Type": "linear", + "RunningMode": "internalremuxer", + "OutputMode": "directhls", + "ScriptParams": "", + "ScriptAccountsUser": "provider", + "ScriptNetwork": "", + "ScriptProxy": "", + "ScriptBind": "", + "ScriptDoh": "", + "ScriptDns": "", + "ScriptWorker": "", + "ManifestNetwork": "same", + "ManifestProxy": "", + "ManifestBind": "", + "ManifestDoh": "", + "ManifestDns": "", + "ManifestWorker": "", + "MediaNetwork": "same", + "MediaProxy": "", + "MediaBind": "", + "MediaDoh": "", + "MediaDns": "", + "MediaWorker": "", + "OnDemand": true, + "Autostart": true, + "PipeOutputParams": "", + "ProtoOutputParams": "", + "SessionManifest": false, + "SpeedUp": false, + "ProcessDVBSubs": false, + "UseCdm": false, + "CdmType": "widevine", + "CdmMode": "internal", + "PRLAVersion": "", + "PRClientVersion": "", + "PRCustomData": "", + "NetworkOverride": false, + "ModeOverride": false, + "IgnoreUpdate": false, + "ManualEvent": false, + "TimeRange": false, + "DailyOnAir": false, + "Manifest": "https://turnerlive.warnermediacdn.com/hls/live/2023172/tbseast/slate/VIDEO_0_3564000.m3u8", + "CdnName": "Custom", + "Cdn": null, + "ManifestType": "", + "ManifestInfo": "", + "ManifestInfo2": { + "Type": "", + "Mode": "", + "BestVideo": "", + "DrmVendors": null + }, + "Video": "", + "Audio": "", + "Subtitles": "", + "VideoList": null, + "AudioList": null, + "SubtitlesList": null, + "IgnoreKid": false, + "Keys": null, + "Drm": { + "Vendor": null + }, + "Heartbeat": { + "Url": "", + "Params": "", + "PeriodMs": 0, + "RandomMs": 0 + }, + "License": { + "Url": "", + "Params": "" + }, + "Headers": { + "Manifest": {}, + "Media": {} + }, + "Info": "", + "LogLevel": 2, + "StreamingUrl": null, + "StreamingResolutions": null + }, + { + "Name": "TBS West", + "Category": "", + "Description": "", + "Id": "tbswest", + "LogoUrl": "", + "ExtraStatus": "", + "RecordEvent": false, + "RecordTs": false, + "Start": 0, + "End": 0, + "DailyStartTime": 0, + "DailyEndTime": 0, + "Type": "linear", + "RunningMode": "internalremuxer", + "OutputMode": "directhls", + "ScriptParams": "", + "ScriptAccountsUser": "provider", + "ScriptNetwork": "", + "ScriptProxy": "", + "ScriptBind": "", + "ScriptDoh": "", + "ScriptDns": "", + "ScriptWorker": "", + "ManifestNetwork": "same", + "ManifestProxy": "", + "ManifestBind": "", + "ManifestDoh": "", + "ManifestDns": "", + "ManifestWorker": "", + "MediaNetwork": "same", + "MediaProxy": "", + "MediaBind": "", + "MediaDoh": "", + "MediaDns": "", + "MediaWorker": "", + "OnDemand": true, + "Autostart": true, + "PipeOutputParams": "", + "ProtoOutputParams": "", + "SessionManifest": false, + "SpeedUp": false, + "ProcessDVBSubs": false, + "UseCdm": false, + "CdmType": "widevine", + "CdmMode": "internal", + "PRLAVersion": "", + "PRClientVersion": "", + "PRCustomData": "", + "NetworkOverride": false, + "ModeOverride": false, + "IgnoreUpdate": false, + "ManualEvent": false, + "TimeRange": false, + "DailyOnAir": false, + "Manifest": "https://turnerlive.warnermediacdn.com/hls/live/2023174/tbswest/slate/VIDEO_0_3564000.m3u8", + "CdnName": "Custom", + "Cdn": null, + "ManifestType": "", + "ManifestInfo": "", + "ManifestInfo2": { + "Type": "", + "Mode": "", + "BestVideo": "", + "DrmVendors": null + }, + "Video": "", + "Audio": "", + "Subtitles": "", + "VideoList": null, + "AudioList": null, + "SubtitlesList": null, + "IgnoreKid": false, + "Keys": null, + "Drm": { + "Vendor": null + }, + "Heartbeat": { + "Url": "", + "Params": "", + "PeriodMs": 0, + "RandomMs": 0 + }, + "License": { + "Url": "", + "Params": "" + }, + "Headers": { + "Manifest": {}, + "Media": {} + }, + "Info": "", + "LogLevel": 2, + "StreamingUrl": null, + "StreamingResolutions": null + }, + { + "Name": "TruTV East", + "Category": "", + "Description": "", + "Id": "trutveast", + "LogoUrl": "", + "ExtraStatus": "", + "RecordEvent": false, + "RecordTs": false, + "Start": 0, + "End": 0, + "DailyStartTime": 0, + "DailyEndTime": 0, + "Type": "linear", + "RunningMode": "internalremuxer", + "OutputMode": "directhls", + "ScriptParams": "", + "ScriptAccountsUser": "provider", + "ScriptNetwork": "", + "ScriptProxy": "", + "ScriptBind": "", + "ScriptDoh": "", + "ScriptDns": "", + "ScriptWorker": "", + "ManifestNetwork": "same", + "ManifestProxy": "", + "ManifestBind": "", + "ManifestDoh": "", + "ManifestDns": "", + "ManifestWorker": "", + "MediaNetwork": "same", + "MediaProxy": "", + "MediaBind": "", + "MediaDoh": "", + "MediaDns": "", + "MediaWorker": "", + "OnDemand": true, + "Autostart": true, + "PipeOutputParams": "", + "ProtoOutputParams": "", + "SessionManifest": false, + "SpeedUp": false, + "ProcessDVBSubs": false, + "UseCdm": false, + "CdmType": "widevine", + "CdmMode": "internal", + "PRLAVersion": "", + "PRClientVersion": "", + "PRCustomData": "", + "NetworkOverride": false, + "ModeOverride": false, + "IgnoreUpdate": false, + "ManualEvent": false, + "TimeRange": false, + "DailyOnAir": false, + "Manifest": "https://turnerlive.warnermediacdn.com/hls/live/2023176/trueast/slate/VIDEO_0_3564000.m3u8", + "CdnName": "Custom", + "Cdn": null, + "ManifestType": "", + "ManifestInfo": "", + "ManifestInfo2": { + "Type": "", + "Mode": "", + "BestVideo": "", + "DrmVendors": null + }, + "Video": "", + "Audio": "", + "Subtitles": "", + "VideoList": null, + "AudioList": null, + "SubtitlesList": null, + "IgnoreKid": false, + "Keys": null, + "Drm": { + "Vendor": null + }, + "Heartbeat": { + "Url": "", + "Params": "", + "PeriodMs": 0, + "RandomMs": 0 + }, + "License": { + "Url": "", + "Params": "" + }, + "Headers": { + "Manifest": {}, + "Media": {} + }, + "Info": "", + "LogLevel": 2, + "StreamingUrl": null, + "StreamingResolutions": null + }, + { + "Name": "FilAmTV Network", + "Category": "", + "Description": "", + "Id": "filamtvnetwork", + "LogoUrl": "", + "ExtraStatus": "", + "RecordEvent": false, + "RecordTs": false, + "Start": 0, + "End": 0, + "DailyStartTime": 0, + "DailyEndTime": 0, + "Type": "linear", + "RunningMode": "internalremuxer", + "OutputMode": "directhls", + "ScriptParams": "", + "ScriptAccountsUser": "provider", + "ScriptNetwork": "", + "ScriptProxy": "", + "ScriptBind": "", + "ScriptDoh": "", + "ScriptDns": "", + "ScriptWorker": "", + "ManifestNetwork": "same", + "ManifestProxy": "", + "ManifestBind": "", + "ManifestDoh": "", + "ManifestDns": "", + "ManifestWorker": "", + "MediaNetwork": "same", + "MediaProxy": "", + "MediaBind": "", + "MediaDoh": "", + "MediaDns": "", + "MediaWorker": "", + "OnDemand": true, + "Autostart": true, + "PipeOutputParams": "", + "ProtoOutputParams": "", + "SessionManifest": false, + "SpeedUp": false, + "ProcessDVBSubs": false, + "UseCdm": false, + "CdmType": "widevine", + "CdmMode": "internal", + "PRLAVersion": "", + "PRClientVersion": "", + "PRCustomData": "", + "NetworkOverride": false, + "ModeOverride": false, + "IgnoreUpdate": false, + "ManualEvent": false, + "TimeRange": false, + "DailyOnAir": false, + "Manifest": "https://streams.comclark.com/pknsd/filamtv/playlist.m3u8", + "CdnName": "Custom", + "Cdn": null, + "ManifestType": "hls", + "ManifestInfo": "Format: \u003ci\u003e\u003cb\u003ehls/ts (live)\u003c/b\u003e\u003c/i\u003e\u003cbr\u003eBest video: \u003ci\u003e\u003cb\u003e1080p23\u003c/b\u003e\u003c/i\u003e\u003cbr\u003e", + "ManifestInfo2": { + "Type": "hls/ts", + "Mode": "live", + "BestVideo": "1080p23", + "DrmVendors": null + }, + "Video": "best", + "Audio": "internalaudio0", + "Subtitles": "none", + "VideoList": [ + { + "Id": "-1920x1080-23.976-4428071-", + "Resolution": "1080", + "FrameRate": 23.976, + "Timescale": 0, + "Codec": "avc1.640032", + "Lang": "", + "Bandwidth": 4428071, + "SamplingRate": 0, + "Channels": 0, + "Desc": "1080p23 (avc1.640032 4.2Mbps)", + "Kid": "", + "IsInternal": false + } + ], + "AudioList": [ + { + "Id": "internalaudio0", + "Resolution": "", + "FrameRate": 0, + "Timescale": 0, + "Codec": "mp4a.40.2", + "Lang": "", + "Bandwidth": 4428071, + "SamplingRate": 0, + "Channels": 0, + "Desc": "internal audio 0 (mp4a.40.2)", + "Kid": "", + "IsInternal": true + } + ], + "SubtitlesList": [], + "IgnoreKid": false, + "Keys": null, + "Drm": { + "Vendor": null + }, + "Heartbeat": { + "Url": "", + "Params": "", + "PeriodMs": 0, + "RandomMs": 0 + }, + "License": { + "Url": "", + "Params": "" + }, + "Headers": { + "Manifest": {}, + "Media": {} + }, + "Info": "", + "LogLevel": 2, + "StreamingUrl": null, + "StreamingResolutions": null + } + ] +} \ No newline at end of file