-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathexample.py
More file actions
183 lines (148 loc) · 5.91 KB
/
example.py
File metadata and controls
183 lines (148 loc) · 5.91 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
#!/usr/bin/python3
import sys
import os
import base64
import json
import requests
import jwt
import logging
from logging.handlers import RotatingFileHandler # Import RotatingFileHandler
from typing import Any, Dict, Optional
# Utility function for parameter parsing
def parse_params(params: list[str], name: str, default: str = "") -> str:
return next((p.split('=')[1] for p in params if p.startswith(f"{name}=")), default)
# Fetch parameters from sys.argv
user = parse_params(sys.argv, 'user')
password = parse_params(sys.argv, 'password')
id = parse_params(sys.argv, 'id')
action = parse_params(sys.argv, 'action')
pssh = parse_params(sys.argv, 'pssh')
# Dynamically set the log filename based on the 'id' parameter
log_filename = f"{id}.log" if id else f"default.log"
# Setup logging to a dynamically named file
logging.basicConfig(
level=logging.DEBUG, # Capture all log messages
format='%(asctime)s - %(levelname)s - %(message)s',
handlers=[
RotatingFileHandler(log_filename, maxBytes=5*1024*1024, backupCount=3),
logging.StreamHandler()
]
)
# Constants for URLs
CHANNELS_API_URL = 'https://cbd46b77.cdn.cms.movetv.com/cms/publish3/domain/summary/ums/1.json'
PLAYBACK_API_URL = 'https://cbd46b77.cdn.cms.movetv.com/playermetadata/sling/v1/api/channels/{id}/schedule/now/playback_info.qvt'
# API headers
api_headers = {"ccdodlad-api-key": "bluechip_studio_696223755_api_and_extension_unlimited"}
# CDM process
def do_cdm(pssh: str, id: str) -> Optional[Dict[str, Any]]:
try:
# Use f-string for URL formatting
sling_key_api = f"id={id}&pssh={pssh}"
# Make the request
response = requests.get(sling_key_api)
response.raise_for_status() # Raise an error for bad HTTP status codes
try:
key_data = response.json() # Attempt to parse JSON
except ValueError:
logging.error(f"Invalid JSON response: {response.content}")
return None
# Check if 'status' is present in the response and handle 'false' status
if key_data.get('status') == 'false':
logging.error("Failed to Grab Key: Status is false")
return None
# Return the 'keys' field from the response if present
keys = key_data.get('keys', None)
if keys is None or not keys: # Check if keys is None or an empty list
logging.error("Keys are empty or not present")
return None
list = "\n".join(keys)
print(list)
except requests.exceptions.RequestException as e:
logging.error(f"RequestException: {e}")
except Exception as e:
logging.error(f"Unexpected error in do_cdm: {e}")
return None
# Function to process channels and fetch playback manifest
def process_channel(id: str) -> Optional[str]:
try:
response = requests.get(PLAYBACK_API_URL.format(id=id))
response.raise_for_status()
data = response.json()
dash_manifest_url = data.get('playback_info', {}).get('dash_manifest_url')
if dash_manifest_url:
return dash_manifest_url
else:
logging.error("dash_manifest_url not found in the response")
return None
except requests.exceptions.RequestException as e:
logging.error(f"API request error: {e}")
except KeyError as e:
logging.error(f"KeyError: {e}")
except Exception as e:
logging.error(f"Unexpected error: {e}")
return None
# Function to handle the channels action
def handle_channels() -> None:
output = {"Channels": []}
try:
response = requests.get(CHANNELS_API_URL).json()
channels = response.get('channels', [])
for channel_data in channels:
channelid = str(channel_data['channel_guid'])
channel_info = {
"Name": channel_data['metadata']['channel_name'],
"Mode": "live",
"SessionManifest": True,
"ManifestScript": f'id={channelid}',
"CdmType": "widevine",
"UseCdm": True,
"Cdm": f'id={channelid}',
"Video": "best",
"OnDemand": True,
"SpeedUp": True,
"CdmMode": "external"
}
output['Channels'].append(channel_info)
print(json.dumps(output, indent=2))
except (KeyError, ValueError, requests.RequestException) as e:
logging.error(f"Error while handling channels: {e}")
# Function to handle the manifest action
def handle_manifest(id: str) -> None:
try:
manifest_url = process_channel(id)
output = {
"ManifestUrl": manifest_url,
"Headers": {
"Manifest": {
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36'
},
"Media": {
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36'
}
},
"Heartbeat": {
"Url": '',
"Params": '',
"PeriodMs": 5 * 60 * 1000
}
}
print(json.dumps(output, indent=4))
except Exception as e:
logging.error(f"Error while handling manifest: {e}")
def fix_base64(encoded_str):
# Add necessary padding if needed
missing_padding = len(encoded_str) % 4
if missing_padding:
encoded_str += '=' * (4 - missing_padding) # Add '=' padding
return encoded_str
# Main control flow
logging.error("Running with action : " + action)
if action == "cdm":
logging.error("Requesting keys")
do_cdm(pssh, id)
elif action == "channels":
logging.error("Reloading channels")
handle_channels()
elif action == "manifest":
logging.error("Requesting manifest")
handle_manifest(id)