Added HLS Support
This commit is contained in:
parent
6509198610
commit
fa776a590a
@ -286,39 +286,69 @@ class KNPY(Service):
|
||||
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 library’s access region."
|
||||
"Playback blocked by region restriction. Try connecting through a supported country or verify your library's 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()
|
||||
play_data = response_json or r.json()
|
||||
|
||||
manifest_url = None
|
||||
manifest_type = None
|
||||
drm_info = {}
|
||||
|
||||
# Iterate through manifests: prefer DASH, fallback to HLS
|
||||
for manifest in play_data.get("manifests", []):
|
||||
if manifest["manifestType"] == "dash":
|
||||
url = manifest["url"]
|
||||
manifest_url = f"https://kanopy.com{url}" if url.startswith("/") else url
|
||||
drm_type = manifest.get("drmType")
|
||||
manifest_type_raw = manifest["manifestType"]
|
||||
url = manifest["url"].strip() # Strip whitespace from URLs
|
||||
|
||||
# Construct full URL if relative
|
||||
if url.startswith("/"):
|
||||
url = f"https://kanopy.com{url}"
|
||||
|
||||
drm_type = manifest.get("drmType")
|
||||
|
||||
if manifest_type_raw == "dash":
|
||||
manifest_url = url
|
||||
manifest_type = "dash"
|
||||
|
||||
if drm_type == "kanopyDrm":
|
||||
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"
|
||||
)
|
||||
elif drm_type == "studioDrm":
|
||||
license_id = manifest.get("drmLicenseID", f"{play_data.get('playId')}-1")
|
||||
self.widevine_license_url = self.config["endpoints"]["widevine_license"].format(license_id=license_id)
|
||||
self.widevine_license_url = self.config["endpoints"]["widevine_license"].format(
|
||||
license_id=license_id
|
||||
)
|
||||
else:
|
||||
self.log.warning(f"Unknown drmType: {drm_type}")
|
||||
self.log.warning(f"Unknown DASH drmType: {drm_type}")
|
||||
self.widevine_license_url = None
|
||||
break
|
||||
break # Prefer DASH, exit loop
|
||||
|
||||
elif manifest_type_raw == "hls" and not manifest_url:
|
||||
# Store HLS as fallback if DASH not found
|
||||
manifest_url = url
|
||||
manifest_type = "hls"
|
||||
|
||||
if drm_type == "fairplay":
|
||||
self.log.warning("HLS with FairPlay DRM detected - not currently supported by this service")
|
||||
self.widevine_license_url = None
|
||||
drm_info["fairplay"] = True
|
||||
else:
|
||||
# HLS with no DRM or unsupported DRM type
|
||||
self.widevine_license_url = None
|
||||
drm_info["clear"] = True
|
||||
|
||||
if not manifest_url:
|
||||
raise ValueError("Could not find a DASH manifest for this title.")
|
||||
if not self.widevine_license_url:
|
||||
raise ValueError("Could not construct Widevine license URL.")
|
||||
raise ValueError("Could not find a DASH or HLS manifest for this title.")
|
||||
if manifest_type == "dash" and not self.widevine_license_url:
|
||||
raise ValueError("Could not construct Widevine license URL for DASH manifest.")
|
||||
|
||||
self.log.info(f"Fetching DASH manifest from: {manifest_url}")
|
||||
self.log.info(f"Fetching {manifest_type.upper()} manifest from: {manifest_url}")
|
||||
r = self.session.get(manifest_url)
|
||||
r.raise_for_status()
|
||||
|
||||
@ -331,14 +361,35 @@ class KNPY(Service):
|
||||
"Connection": "keep-alive",
|
||||
})
|
||||
|
||||
tracks = DASH.from_text(r.text, url=manifest_url).to_tracks(language=title.language)
|
||||
# Parse manifest based on type
|
||||
if manifest_type == "dash":
|
||||
tracks = DASH.from_text(r.text, url=manifest_url).to_tracks(language=title.language)
|
||||
elif manifest_type == "hls":
|
||||
# Try to import HLS parser from unshackle
|
||||
try:
|
||||
from unshackle.core.manifests import HLS
|
||||
tracks = HLS.from_text(r.text, url=manifest_url).to_tracks(language=title.language)
|
||||
self.log.info("Successfully parsed HLS manifest")
|
||||
except ImportError:
|
||||
self.log.error(
|
||||
"HLS manifest parser not available in unshackle.core.manifests. "
|
||||
"Ensure your unshackle installation supports HLS parsing."
|
||||
)
|
||||
raise
|
||||
except Exception as e:
|
||||
self.log.error(f"Failed to parse HLS manifest: {e}")
|
||||
raise
|
||||
else:
|
||||
raise ValueError(f"Unsupported manifest type: {manifest_type}")
|
||||
|
||||
# Add subtitles/captions from play_data (works for both DASH and HLS)
|
||||
for caption_data in play_data.get("captions", []):
|
||||
lang = caption_data.get("language", "en")
|
||||
for file_info in caption_data.get("files", []):
|
||||
if file_info.get("type") == "webvtt":
|
||||
tracks.add(Subtitle(
|
||||
id_=f"caption-{lang}",
|
||||
url=file_info["url"],
|
||||
url=file_info["url"].strip(),
|
||||
codec=Subtitle.Codec.WebVTT,
|
||||
language=Language.get(lang)
|
||||
))
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user