lghorizon 0.6.13__tar.gz → 0.7.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {lghorizon-0.6.13 → lghorizon-0.7.1}/.github/workflows/build-on-pr.yml +1 -1
- {lghorizon-0.6.13 → lghorizon-0.7.1}/.github/workflows/publish-to-pypi.yml +1 -1
- {lghorizon-0.6.13 → lghorizon-0.7.1}/PKG-INFO +1 -1
- {lghorizon-0.6.13 → lghorizon-0.7.1}/lghorizon/const.py +0 -2
- {lghorizon-0.6.13 → lghorizon-0.7.1}/lghorizon/lghorizon_api.py +40 -106
- {lghorizon-0.6.13 → lghorizon-0.7.1}/lghorizon.egg-info/PKG-INFO +1 -1
- {lghorizon-0.6.13 → lghorizon-0.7.1}/test.py +6 -0
- {lghorizon-0.6.13 → lghorizon-0.7.1}/.coverage +0 -0
- {lghorizon-0.6.13 → lghorizon-0.7.1}/.flake8 +0 -0
- {lghorizon-0.6.13 → lghorizon-0.7.1}/.gitignore +0 -0
- {lghorizon-0.6.13 → lghorizon-0.7.1}/LICENSE +0 -0
- {lghorizon-0.6.13 → lghorizon-0.7.1}/README.md +0 -0
- {lghorizon-0.6.13 → lghorizon-0.7.1}/instructions.txt +0 -0
- {lghorizon-0.6.13 → lghorizon-0.7.1}/lghorizon/__init__.py +0 -0
- {lghorizon-0.6.13 → lghorizon-0.7.1}/lghorizon/exceptions.py +0 -0
- {lghorizon-0.6.13 → lghorizon-0.7.1}/lghorizon/helpers.py +0 -0
- {lghorizon-0.6.13 → lghorizon-0.7.1}/lghorizon/models.py +0 -0
- {lghorizon-0.6.13 → lghorizon-0.7.1}/lghorizon/py.typed +0 -0
- {lghorizon-0.6.13 → lghorizon-0.7.1}/lghorizon.egg-info/SOURCES.txt +0 -0
- {lghorizon-0.6.13 → lghorizon-0.7.1}/lghorizon.egg-info/dependency_links.txt +0 -0
- {lghorizon-0.6.13 → lghorizon-0.7.1}/lghorizon.egg-info/not-zip-safe +0 -0
- {lghorizon-0.6.13 → lghorizon-0.7.1}/lghorizon.egg-info/requires.txt +0 -0
- {lghorizon-0.6.13 → lghorizon-0.7.1}/lghorizon.egg-info/top_level.txt +0 -0
- {lghorizon-0.6.13 → lghorizon-0.7.1}/lib64 +0 -0
- {lghorizon-0.6.13 → lghorizon-0.7.1}/pyvenv.cfg +0 -0
- {lghorizon-0.6.13 → lghorizon-0.7.1}/renovate.json +0 -0
- {lghorizon-0.6.13 → lghorizon-0.7.1}/secrets_stub.json +0 -0
- {lghorizon-0.6.13 → lghorizon-0.7.1}/setup.cfg +0 -0
- {lghorizon-0.6.13 → lghorizon-0.7.1}/setup.py +0 -0
|
@@ -119,9 +119,7 @@ COUNTRY_SETTINGS = {
|
|
|
119
119
|
},
|
|
120
120
|
"gb": {
|
|
121
121
|
"api_url": "https://spark-prod-gb.gnp.cloud.virgintvgo.virginmedia.com",
|
|
122
|
-
"oauth_url": "https://id.virginmedia.com/rest/v40/session/start?protocol=oidc&rememberMe=true",
|
|
123
122
|
"channels": [],
|
|
124
|
-
"oesp_url": "https://prod.oesp.virginmedia.com/oesp/v4/GB/eng/web",
|
|
125
123
|
"language": "en",
|
|
126
124
|
},
|
|
127
125
|
"ie": {
|
|
@@ -63,10 +63,12 @@ class LGHorizonApi:
|
|
|
63
63
|
password: str,
|
|
64
64
|
country_code: str = "nl",
|
|
65
65
|
identifier: str = None,
|
|
66
|
+
refresh_token=None,
|
|
66
67
|
) -> None:
|
|
67
68
|
"""Create LGHorizon API."""
|
|
68
69
|
self.username = username
|
|
69
70
|
self.password = password
|
|
71
|
+
self.refresh_token = refresh_token
|
|
70
72
|
self._session = Session()
|
|
71
73
|
self._country_settings = COUNTRY_SETTINGS[country_code]
|
|
72
74
|
self._country_code = country_code
|
|
@@ -113,92 +115,38 @@ class LGHorizonApi:
|
|
|
113
115
|
self._auth.fill(auth_response.json())
|
|
114
116
|
_logger.debug("Authorization succeeded")
|
|
115
117
|
|
|
116
|
-
def authorize_gb(self):
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
if not auth_response.ok:
|
|
124
|
-
raise LGHorizonApiConnectionError("Can't connect to authorization URL")
|
|
125
|
-
auth_response_json = auth_response.json()
|
|
126
|
-
auth_session = auth_response_json["session"]
|
|
127
|
-
auth_state = auth_session["state"]
|
|
128
|
-
authorizationUri = auth_session["authorizationUri"]
|
|
129
|
-
authValidityToken = auth_session["validityToken"]
|
|
130
|
-
####################################
|
|
131
|
-
_logger.debug("Step 2 - Get Authorization cookie")
|
|
132
|
-
|
|
133
|
-
auth_cookie_response = login_session.get(authorizationUri)
|
|
134
|
-
if not auth_cookie_response.ok:
|
|
135
|
-
raise LGHorizonApiConnectionError("Can't connect to authorization URL")
|
|
136
|
-
####################################
|
|
137
|
-
_logger.debug("Step 3 - Login")
|
|
138
|
-
payload = {"username": self.username, "credential": self.password}
|
|
139
|
-
headers = {"accept": "application/json; charset=UTF-8, */*"}
|
|
118
|
+
def authorize_gb(self) -> None:
|
|
119
|
+
_logger.debug("Authorizing via refresh")
|
|
120
|
+
refresh_url = (
|
|
121
|
+
f"{self._country_settings['api_url']}/auth-service/v1/authorization/refresh"
|
|
122
|
+
)
|
|
123
|
+
headers = {"content-type": "application/json", "charset": "utf-8"}
|
|
124
|
+
payload = '{"refreshToken":"' + self.refresh_token + '"}'
|
|
140
125
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
headers=headers,
|
|
145
|
-
allow_redirects=False,
|
|
126
|
+
try:
|
|
127
|
+
auth_response = self._session.post(
|
|
128
|
+
refresh_url, headers=headers, data=payload
|
|
146
129
|
)
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
if not "x-redirect-location" in login_response.headers:
|
|
151
|
-
raise LGHorizonApiConnectionError("No redirect location in headers.")
|
|
130
|
+
except Exception as ex:
|
|
131
|
+
raise LGHorizonApiConnectionError("Unknown connection failure") from ex
|
|
152
132
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
if
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
raise LGHorizonApiConnectionError("
|
|
165
|
-
authorizationCode = codeMatches[0]
|
|
166
|
-
stateMatches = re.findall(r"state=(.*)", success_url)
|
|
167
|
-
if len(codeMatches) == 0:
|
|
168
|
-
raise LGHorizonApiConnectionError("No state in redirect headers")
|
|
169
|
-
authorizationState = stateMatches[0]
|
|
170
|
-
_logger.debug(
|
|
171
|
-
f"Auth code: {authorizationCode}, Auth state: {authorizationState}"
|
|
172
|
-
)
|
|
173
|
-
####################################
|
|
174
|
-
_logger.debug("Step 6 - Post auth data with valid code")
|
|
175
|
-
authorization_payload = {
|
|
176
|
-
"authorizationGrant": {
|
|
177
|
-
"authorizationCode": authorizationCode,
|
|
178
|
-
"validityToken": authValidityToken,
|
|
179
|
-
"state": authorizationState,
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
headers = {
|
|
183
|
-
"content-type": "application/json",
|
|
184
|
-
}
|
|
185
|
-
# VM requires the client to pass the response from /authorization verbatim to /session?token=true
|
|
186
|
-
post_authorization_result = login_session.post(
|
|
187
|
-
self._country_settings["oesp_url"] + "/authorization",
|
|
188
|
-
json.dumps(authorization_payload),
|
|
189
|
-
headers=headers,
|
|
190
|
-
)
|
|
191
|
-
post_session_result = login_session.post(
|
|
192
|
-
self._country_settings["oesp_url"] + "/session?token=true",
|
|
193
|
-
json.dumps(post_authorization_result.json()),
|
|
194
|
-
headers=headers,
|
|
195
|
-
)
|
|
133
|
+
if not auth_response.ok:
|
|
134
|
+
_logger.debug("response %s", auth_response)
|
|
135
|
+
error_json = auth_response.json()
|
|
136
|
+
error = None
|
|
137
|
+
if "error" in error_json:
|
|
138
|
+
error = error_json["error"]
|
|
139
|
+
if error and error["statusCode"] == 97401:
|
|
140
|
+
raise LGHorizonApiUnauthorizedError("Invalid credentials")
|
|
141
|
+
elif error:
|
|
142
|
+
raise LGHorizonApiConnectionError(error["message"])
|
|
143
|
+
else:
|
|
144
|
+
raise LGHorizonApiConnectionError("Unknown connection error")
|
|
196
145
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
pass
|
|
146
|
+
self._auth.fill(auth_response.json())
|
|
147
|
+
self.refresh_token = self._auth.refreshToken
|
|
148
|
+
self._session.cookies["ACCESSTOKEN"] = self._auth.accessToken
|
|
149
|
+
_logger.debug("Authorization succeeded")
|
|
202
150
|
|
|
203
151
|
def authorize_telenet(self):
|
|
204
152
|
try:
|
|
@@ -276,32 +224,14 @@ class LGHorizonApi:
|
|
|
276
224
|
self._auth.mqttToken = mqtt_response["token"]
|
|
277
225
|
_logger.debug(f"MQTT token: {self._auth.mqttToken}")
|
|
278
226
|
|
|
279
|
-
def _obtain_mqtt_token_gb(self):
|
|
280
|
-
_logger.debug("Obtain Virgin GB mqtt token...")
|
|
281
|
-
self._session.headers["x-oesp-token"] = self._auth.accessToken
|
|
282
|
-
self._session.headers["x-oesp-username"] = self._auth.username
|
|
283
|
-
|
|
284
|
-
mqtt_response = self._do_api_call(
|
|
285
|
-
f"{self._country_settings['oesp_url']}/tokens/jwt"
|
|
286
|
-
)
|
|
287
|
-
self._auth.mqttToken = mqtt_response["token"]
|
|
288
|
-
_logger.debug(f"MQTT token: {self._auth.mqttToken}")
|
|
289
|
-
|
|
290
227
|
@backoff.on_exception(
|
|
291
|
-
backoff.expo,
|
|
292
|
-
BaseException,
|
|
293
|
-
jitter=None,
|
|
294
|
-
max_tries=3,
|
|
295
|
-
logger=_logger,
|
|
228
|
+
backoff.expo, BaseException, jitter=None, max_time=600, logger=_logger
|
|
296
229
|
)
|
|
297
230
|
def connect(self) -> None:
|
|
298
231
|
self._config = self._get_config(self._country_code)
|
|
299
232
|
_logger.debug("Connect to API")
|
|
300
233
|
self._authorize()
|
|
301
|
-
|
|
302
|
-
self._obtain_mqtt_token_gb()
|
|
303
|
-
else:
|
|
304
|
-
self._obtain_mqtt_token()
|
|
234
|
+
self._obtain_mqtt_token()
|
|
305
235
|
self._mqttClient = LGHorizonMqttClient(
|
|
306
236
|
self._auth,
|
|
307
237
|
self._config["mqttBroker"]["URL"],
|
|
@@ -362,10 +292,14 @@ class LGHorizonApi:
|
|
|
362
292
|
self.settop_boxes[deviceId].playing_info.set_paused(
|
|
363
293
|
playerState["speed"] == 0
|
|
364
294
|
)
|
|
365
|
-
if
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
295
|
+
if (
|
|
296
|
+
source_type
|
|
297
|
+
in (
|
|
298
|
+
BOX_PLAY_STATE_CHANNEL,
|
|
299
|
+
BOX_PLAY_STATE_BUFFER,
|
|
300
|
+
BOX_PLAY_STATE_REPLAY,
|
|
301
|
+
)
|
|
302
|
+
and "eventId" in state_source
|
|
369
303
|
):
|
|
370
304
|
eventId = state_source["eventId"]
|
|
371
305
|
raw_replay_event = self._do_api_call(
|
|
@@ -52,11 +52,17 @@ if __name__ == "__main__":
|
|
|
52
52
|
try:
|
|
53
53
|
secrets_file_path = "secrets.json"
|
|
54
54
|
secrets = read_secrets(secrets_file_path)
|
|
55
|
+
|
|
56
|
+
refresh_token = None
|
|
57
|
+
if "refresh_token" in secrets:
|
|
58
|
+
refresh_token = secrets["refresh_token"]
|
|
59
|
+
|
|
55
60
|
api = LGHorizonApi(
|
|
56
61
|
secrets["username"],
|
|
57
62
|
secrets["password"],
|
|
58
63
|
secrets["country"],
|
|
59
64
|
# identifier="DTV3907048",
|
|
65
|
+
refresh_token = refresh_token,
|
|
60
66
|
)
|
|
61
67
|
api.connect()
|
|
62
68
|
event_loop()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|