Implement a "schema guard" for `api` module
In order to catch errors related to assumed JSON schema, regroup all JSON data access under a context manager that catch related errors: - KeyError - IndexError - ValueError
This commit is contained in:
parent
fcadd531c4
commit
ed5ba06a98
|
@ -3,13 +3,22 @@
|
|||
|
||||
"""Provide ArteTV JSON API utilities."""
|
||||
|
||||
import contextlib
|
||||
|
||||
from .error import UnexpectedAPIResponse, UnsupportedHLSProtocol
|
||||
from .model import ProgramMeta
|
||||
|
||||
MIME_TYPE = "application/vnd.api+json; charset=utf-8"
|
||||
|
||||
|
||||
def _fetch_api_data(http_session, path, object_type):
|
||||
@contextlib.contextmanager
|
||||
def _schema_guard(*context):
|
||||
try:
|
||||
yield
|
||||
except (KeyError, IndexError, ValueError) as e:
|
||||
raise UnexpectedAPIResponse("SCHEMA", *context) from e
|
||||
|
||||
|
||||
def _fetch_api_object(http_session, path, object_type):
|
||||
# Fetch an API object.
|
||||
url = "https://api.arte.tv/api/player/v2/" + path
|
||||
|
||||
|
@ -19,35 +28,43 @@ def _fetch_api_data(http_session, path, object_type):
|
|||
if (_ := r.headers["content-type"]) != MIME_TYPE:
|
||||
raise UnexpectedAPIResponse("MIME_TYPE", path, MIME_TYPE, _)
|
||||
|
||||
obj = r.json()["data"]
|
||||
obj = r.json()
|
||||
|
||||
if (_ := obj["type"]) != object_type:
|
||||
with _schema_guard(path):
|
||||
data_type = obj["data"]["type"]
|
||||
data_attributes = obj["data"]["attributes"]
|
||||
|
||||
if data_type != object_type:
|
||||
raise UnexpectedAPIResponse("OBJECT_TYPE", path, object_type, _)
|
||||
|
||||
return obj["attributes"]
|
||||
return data_attributes
|
||||
|
||||
|
||||
def fetch_program_info(http_session, p_meta):
|
||||
"""Fetch the given program metadata and indexes."""
|
||||
obj = _fetch_api_data(
|
||||
obj = _fetch_api_object(
|
||||
http_session, f"config/{p_meta.site}/{p_meta.id}", "ConfigPlayer"
|
||||
)
|
||||
|
||||
if (_ := obj["metadata"]["providerId"]) != p_meta.id:
|
||||
with _schema_guard(p_meta.site, p_meta.id):
|
||||
provider_id = obj["metadata"]["providerId"]
|
||||
streams = [(s["protocol"], s["url"]) for s in obj["streams"]]
|
||||
|
||||
if provider_id != p_meta.id:
|
||||
raise UnexpectedAPIResponse(
|
||||
"PROGRAM_ID_MISMATCH",
|
||||
p_meta.site,
|
||||
p_meta.id,
|
||||
_,
|
||||
provider_id,
|
||||
)
|
||||
|
||||
program_index_urls = set()
|
||||
|
||||
for s in obj["streams"]:
|
||||
if (_ := s["protocol"]) != "HLS_NG":
|
||||
raise UnsupportedHLSProtocol(p_meta.site, p_meta.id, _)
|
||||
for protocol, program_index_url in streams:
|
||||
if protocol != "HLS_NG":
|
||||
raise UnsupportedHLSProtocol(p_meta.site, p_meta.id, protocol)
|
||||
|
||||
if (program_index_url := s["url"]) in program_index_urls:
|
||||
if program_index_url in program_index_urls:
|
||||
raise UnexpectedAPIResponse(
|
||||
"DUPLICATE_PROGRAM_INDEX_URL",
|
||||
p_meta.site,
|
||||
|
|
|
@ -3,8 +3,8 @@
|
|||
|
||||
"""Provide ArteTV website utilities."""
|
||||
|
||||
import contextlib
|
||||
import json
|
||||
from contextlib import contextmanager
|
||||
|
||||
from .error import InvalidPage, PageNotFound, PageNotSupported
|
||||
from .model import ProgramMeta
|
||||
|
@ -12,12 +12,12 @@ from .model import ProgramMeta
|
|||
_DATA_MARK = '<script id="__NEXT_DATA__" type="application/json">'
|
||||
|
||||
|
||||
@contextmanager
|
||||
@contextlib.contextmanager
|
||||
def _schema_guard(*context):
|
||||
try:
|
||||
yield
|
||||
except (KeyError, IndexError, ValueError) as e:
|
||||
raise InvalidPage("SCHEMA", *context, e)
|
||||
raise InvalidPage("SCHEMA", *context) from e
|
||||
|
||||
|
||||
def _process_programs_page(page_value):
|
||||
|
@ -56,7 +56,6 @@ def fetch_program(http_session, url):
|
|||
# special handling of 404
|
||||
if r.status_code == 404:
|
||||
raise PageNotFound(url)
|
||||
|
||||
# other network errors
|
||||
r.raise_for_status()
|
||||
|
||||
|
|
Loading…
Reference in New Issue