refactor(ITV): Change authentication from credentials to cookies
- ITV has started to add telemetry to login requests to combat bot usage, so we now use cookies to authenticate. - The cookie should hopefully only be needed once per account. Any subsequent session will use cached tokens.
This commit is contained in:
parent
601a6a55d4
commit
f7428845e8
@ -3,7 +3,7 @@ from __future__ import annotations
|
|||||||
import hashlib
|
import hashlib
|
||||||
import json
|
import json
|
||||||
import re
|
import re
|
||||||
import time
|
import sys
|
||||||
from collections.abc import Generator
|
from collections.abc import Generator
|
||||||
from http.cookiejar import MozillaCookieJar
|
from http.cookiejar import MozillaCookieJar
|
||||||
from typing import Any, Optional, Union
|
from typing import Any, Optional, Union
|
||||||
@ -25,7 +25,7 @@ class ITV(Service):
|
|||||||
|
|
||||||
\b
|
\b
|
||||||
Author: stabbedbybrick
|
Author: stabbedbybrick
|
||||||
Authorization: Credentials (Optional for free content | Required for premium content)
|
Authorization: Cookies (Optional for free content | Required for premium content)
|
||||||
Robustness:
|
Robustness:
|
||||||
L1: 1080p
|
L1: 1080p
|
||||||
L3: 720p
|
L3: 720p
|
||||||
@ -66,14 +66,34 @@ class ITV(Service):
|
|||||||
self.title = title
|
self.title = title
|
||||||
super().__init__(ctx)
|
super().__init__(ctx)
|
||||||
|
|
||||||
|
self.profile = ctx.parent.params.get("profile")
|
||||||
|
if not self.profile:
|
||||||
|
self.profile = "default"
|
||||||
|
|
||||||
self.session.headers.update(self.config["headers"])
|
self.session.headers.update(self.config["headers"])
|
||||||
|
|
||||||
def authenticate(self, cookies: Optional[MozillaCookieJar] = None, credential: Optional[Credential] = None) -> None:
|
def authenticate(self, cookies: Optional[MozillaCookieJar] = None, credential: Optional[Credential] = None) -> None:
|
||||||
super().authenticate(cookies, credential)
|
super().authenticate(cookies, credential)
|
||||||
self.authorization = None
|
self.authorization = None
|
||||||
|
|
||||||
if credential is not None:
|
if credential and not cookies:
|
||||||
cache = self.cache.get(f"tokens_{credential.sha1}")
|
self.log.error(" - Error: This service requires cookies for authentication.")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
if cookies is not None:
|
||||||
|
self.log.info(f"\n + Cookies for '{self.profile}' profile found, authenticating...")
|
||||||
|
itv_session = next((cookie.value for cookie in cookies if cookie.name == "Itv.Session"), None)
|
||||||
|
if not itv_session:
|
||||||
|
self.log.error(" - Error: Session cookie not found. Cookies may be invalid.")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
itv_session = json.loads(itv_session)
|
||||||
|
refresh_token = itv_session["tokens"]["content"].get("refresh_token")
|
||||||
|
if not refresh_token:
|
||||||
|
self.log.error(" - Error: Access tokens not found. Try refreshing your cookies.")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
cache = self.cache.get(f"tokens_{self.profile}")
|
||||||
|
|
||||||
headers = {
|
headers = {
|
||||||
"Host": "auth.prd.user.itv.com",
|
"Host": "auth.prd.user.itv.com",
|
||||||
@ -85,38 +105,19 @@ class ITV(Service):
|
|||||||
"Referer": "https://www.itv.com/",
|
"Referer": "https://www.itv.com/",
|
||||||
}
|
}
|
||||||
|
|
||||||
if cache:
|
params = {"refresh": cache.data["refresh_token"]} if cache else {"refresh": refresh_token}
|
||||||
self.log.info(" + Using cached Tokens...")
|
|
||||||
r = self.session.get(
|
r = self.session.get(
|
||||||
self.config["endpoints"]["refresh"],
|
self.config["endpoints"]["refresh"],
|
||||||
headers=headers,
|
headers=headers,
|
||||||
params={"refresh": cache.data["refresh_token"]},
|
params=params,
|
||||||
)
|
)
|
||||||
if r.status_code != 200:
|
if r.status_code != 200:
|
||||||
raise ConnectionError(f"Failed to refresh tokens: {r.text}")
|
raise ConnectionError(f"Failed to refresh tokens: {r.text}")
|
||||||
|
|
||||||
tokens = r.json()
|
tokens = r.json()
|
||||||
else:
|
|
||||||
r = self.session.post(
|
|
||||||
self.config["endpoints"]["login"],
|
|
||||||
headers=headers,
|
|
||||||
data=json.dumps(
|
|
||||||
{
|
|
||||||
"username": credential.username,
|
|
||||||
"password": credential.password,
|
|
||||||
"scope": "content",
|
|
||||||
"grant_type": "password",
|
|
||||||
"nonce": f"cerberus-auth-request-{int(time.time())}",
|
|
||||||
}
|
|
||||||
),
|
|
||||||
)
|
|
||||||
if r.status_code != 200:
|
|
||||||
raise ConnectionError(f"Failed to authenticate: {r.text}")
|
|
||||||
|
|
||||||
tokens = r.json()
|
|
||||||
self.log.info(" + Acquired Tokens...")
|
|
||||||
|
|
||||||
cache.set(tokens)
|
cache.set(tokens)
|
||||||
|
self.log.info(" + Tokens refreshed and placed in cache\n")
|
||||||
|
|
||||||
self.authorization = tokens["access_token"]
|
self.authorization = tokens["access_token"]
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user