Added geoblocking error on KNPY

This commit is contained in:
FairTrade 2025-11-26 15:13:19 +01:00
parent 4513b1c0d4
commit 630b2e1099

View File

@ -269,29 +269,38 @@ class KNPY(Service):
"visitorId": self._visitor_id "visitorId": self._visitor_id
} }
if "authorization" not in self.session.headers: self.session.headers.setdefault("authorization", f"Bearer {self._jwt}")
self.session.headers["authorization"] = f"Bearer {self._jwt}" self.session.headers.setdefault("x-version", self.API_VERSION)
self.session.headers["x-version"] = self.API_VERSION self.session.headers.setdefault("user-agent", self.USER_AGENT)
self.session.headers["user-agent"] = self.USER_AGENT
r = self.session.post( r = self.session.post(self.config["endpoints"]["plays"], json=play_payload)
self.config["endpoints"]["plays"], response_json = None
json=play_payload, try:
) response_json = r.json()
except Exception:
pass
# Handle known errors gracefully
if r.status_code == 403:
if response_json and response_json.get("errorSubcode") == "playRegionRestricted":
self.log.error("Kanopy reports: This video is not available in your country.")
raise PermissionError(
"Playback blocked by region restriction. Try connecting through a supported country or verify your librarys access region."
)
else:
self.log.error(f"Access forbidden (HTTP 403). Response: {response_json}")
raise PermissionError("Kanopy denied access to this video. It may require a different library membership or authentication.")
# Raise for any other HTTP errors
r.raise_for_status() r.raise_for_status()
play_data = r.json() play_data = response_json or r.json()
manifest_url = None manifest_url = None
for manifest in play_data.get("manifests", []): for manifest in play_data.get("manifests", []):
if manifest["manifestType"] == "dash": if manifest["manifestType"] == "dash":
manifest_relative_url = manifest["url"] url = manifest["url"]
if manifest_relative_url.startswith("/"): manifest_url = f"https://kanopy.com{url}" if url.startswith("/") else url
manifest_url = f"https://kanopy.com{manifest_relative_url}"
else:
manifest_url = manifest_relative_url
drm_type = manifest.get("drmType") drm_type = manifest.get("drmType")
if drm_type == "kanopyDrm": if drm_type == "kanopyDrm":
play_id = play_data.get("playId") play_id = play_data.get("playId")
self.widevine_license_url = self.config["endpoints"]["widevine_license"].format(license_id=f"{play_id}-0") self.widevine_license_url = self.config["endpoints"]["widevine_license"].format(license_id=f"{play_id}-0")
@ -311,7 +320,8 @@ class KNPY(Service):
self.log.info(f"Fetching DASH manifest from: {manifest_url}") self.log.info(f"Fetching DASH manifest from: {manifest_url}")
r = self.session.get(manifest_url) r = self.session.get(manifest_url)
r.raise_for_status() r.raise_for_status()
# Refresh headers for manifest parsing
self.session.headers.clear() self.session.headers.clear()
self.session.headers.update({ self.session.headers.update({
"User-Agent": self.WIDEVINE_UA, "User-Agent": self.WIDEVINE_UA,
@ -319,23 +329,23 @@ class KNPY(Service):
"Accept-Encoding": "gzip, deflate", "Accept-Encoding": "gzip, deflate",
"Connection": "keep-alive", "Connection": "keep-alive",
}) })
tracks = DASH.from_text(r.text, url=manifest_url).to_tracks(language=title.language) tracks = DASH.from_text(r.text, url=manifest_url).to_tracks(language=title.language)
for caption_data in play_data.get("captions", []): for caption_data in play_data.get("captions", []):
lang_code = caption_data.get("language", "en") lang = caption_data.get("language", "en")
for file_info in caption_data.get("files", []): for file_info in caption_data.get("files", []):
if file_info.get("type") == "webvtt": if file_info.get("type") == "webvtt":
tracks.add(Subtitle( tracks.add(Subtitle(
id_=f"caption-{lang_code}", id_=f"caption-{lang}",
url=file_info["url"], url=file_info["url"],
codec=Subtitle.Codec.WebVTT, codec=Subtitle.Codec.WebVTT,
language=Language.get(lang_code) language=Language.get(lang)
)) ))
break break
return tracks return tracks
def get_widevine_license(self, *, challenge: bytes, title: Title_T, track: AnyTrack) -> bytes: def get_widevine_license(self, *, challenge: bytes, title: Title_T, track: AnyTrack) -> bytes:
if not self.widevine_license_url: if not self.widevine_license_url:
raise ValueError("Widevine license URL was not set. Call get_tracks first.") raise ValueError("Widevine license URL was not set. Call get_tracks first.")
@ -394,4 +404,4 @@ class KNPY(Service):
# return results # return results
def get_chapters(self, title: Title_T) -> list: def get_chapters(self, title: Title_T) -> list:
return [] return []