Fixed title bug on KOWP

This commit is contained in:
FairTrade 2025-11-10 09:22:41 +01:00
parent 28e5dcf395
commit 97c4ded708

View File

@ -13,7 +13,7 @@ from unshackle.core.service import Service
from unshackle.core.search_result import SearchResult from unshackle.core.search_result import SearchResult
from unshackle.core.titles import Episode, Series, Title_T, Titles_T from unshackle.core.titles import Episode, Series, Title_T, Titles_T
from unshackle.core.tracks import Subtitle, Tracks from unshackle.core.tracks import Subtitle, Tracks
from unshackle.core.utilities import is_close_match
class KOWP(Service): class KOWP(Service):
""" """
@ -22,14 +22,10 @@ class KOWP(Service):
Auth: Credential (username + password) Auth: Credential (username + password)
Security: FHD@L3 Security: FHD@L3
Note:
Brightcove account_id and policy key (pk) are configurable per region.
Put the custom Brightcove account ID and policy key on the config.yaml if the following doesn't work
""" """
TITLE_RE = r"^(?:https?://(?:www\.)?kocowa\.com/[^/]+/season/)?(?P<title_id>\d+)" TITLE_RE = r"^(?:https?://(?:www\.)?kocowa\.com/[^/]+/season/)?(?P<title_id>\d+)"
GEOFENCE = ("US", "CA", "PA") GEOFENCE = ()
NO_SUBTITLES = False NO_SUBTITLES = False
@staticmethod @staticmethod
@ -43,9 +39,10 @@ class KOWP(Service):
def __init__(self, ctx, title: str, extras: bool = False): def __init__(self, ctx, title: str, extras: bool = False):
super().__init__(ctx) super().__init__(ctx)
match = re.match(self.TITLE_RE, title) match = re.match(self.TITLE_RE, title)
if not match: if match:
raise ValueError("Invalid Kocowa title ID or URL")
self.title_id = match.group("title_id") self.title_id = match.group("title_id")
else:
self.title_id = title # fallback to use as search keyword
self.include_extras = extras self.include_extras = extras
self.brightcove_account_id = None self.brightcove_account_id = None
self.brightcove_pk = None self.brightcove_pk = None
@ -118,6 +115,7 @@ class KOWP(Service):
all_episodes = [] all_episodes = []
offset = 0 offset = 0
limit = 20 limit = 20
series_title = None # Store the title from the first request
while True: while True:
url = self.config["endpoints"]["metadata"].format(title_id=self.title_id) url = self.config["endpoints"]["metadata"].format(title_id=self.title_id)
@ -131,6 +129,10 @@ class KOWP(Service):
r.raise_for_status() r.raise_for_status()
data = r.json()["object"] data = r.json()["object"]
# Extract the series title only from the very first page
if series_title is None and "meta" in data:
series_title = data["meta"]["title"]["en"]
page_objects = data.get("next_episodes", {}).get("objects", []) page_objects = data.get("next_episodes", {}).get("objects", [])
if not page_objects: if not page_objects:
break break
@ -146,9 +148,11 @@ class KOWP(Service):
if len(all_episodes) >= total or len(page_objects) < limit: if len(all_episodes) >= total or len(page_objects) < limit:
break break
episodes = [] # If we never got the series title, exit with an error
series_title = data["meta"]["title"].get("en") or "Unknown" if series_title is None:
raise ValueError("Could not retrieve series metadata to get the title.")
episodes = []
for ep in all_episodes: for ep in all_episodes:
meta = ep["meta"] meta = ep["meta"]
ep_type = "Episode" if ep["detail_type"] == "episode" else ep["detail_type"].capitalize() ep_type = "Episode" if ep["detail_type"] == "episode" else ep["detail_type"].capitalize()
@ -215,20 +219,20 @@ class KOWP(Service):
self.widevine_license_url = widevine_url self.widevine_license_url = widevine_url
tracks = DASH.from_url(dash_url, session=self.session).to_tracks(language=title.language) tracks = DASH.from_url(dash_url, session=self.session).to_tracks(language=title.language)
# Add ALL subtitles from manifest
for sub in manifest.get("text_tracks", []): for sub in manifest.get("text_tracks", []):
srclang = sub.get("srclang") srclang = sub.get("srclang")
if not srclang or srclang == "thumbnails": if not srclang or srclang == "thumbnails":
continue continue
tracks.add(
Subtitle( subtitle_track = Subtitle(
id_=sub["id"], id_=sub["id"],
url=sub["src"], url=sub["src"],
codec=Subtitle.Codec.WebVTT, codec=Subtitle.Codec.WebVTT,
language=Language.get(srclang), language=Language.get(srclang),
sdh=True, sdh=True, # Kocowa subs are SDH - mark them as such
) forced=False,
) )
tracks.add(subtitle_track)
return tracks return tracks
@ -246,52 +250,48 @@ class KOWP(Service):
r.raise_for_status() r.raise_for_status()
return r.content return r.content
# def search(self) -> List[SearchResult]: def search(self) -> List[SearchResult]:
# if not hasattr(self, 'title_id') or not isinstance(self.title_id, str): url = "https://prod-fms.kocowa.com/api/v01/fe/gks/autocomplete"
# query = getattr(self, 'title', '') # fallback if title_id isn't set yet params = {
# else: "search_category": "All",
# query = self.title_id "search_input": self.title_id,
# "include_webtoon": "true",
# url = "https://prod-fms.kocowa.com/api/v01/fe/gks/autocomplete" }
# params = {
# "search_category": "All", r = self.session.get(
# "search_input": query, url,
# "include_webtoon": "true", params=params,
# } headers={
# "Authorization": self.access_token,
# r = self.session.get( "Origin": "https://www.kocowa.com ",
# url, "Referer": "https://www.kocowa.com/ ",
# params=params, }
# headers={ )
# "Authorization": self.access_token, r.raise_for_status()
# "Origin": "https://www.kocowa.com ", response = r.json()
# "Referer": "https://www.kocowa.com/ ", contents = response.get("object", {}).get("contents", [])
# }
# ) results = []
# r.raise_for_status() for item in contents:
# response = r.json() if item.get("detail_type") != "season":
# contents = response.get("object", {}).get("contents", []) continue
#
# results = [] meta = item["meta"]
# for item in contents: title_en = meta["title"].get("en") or "[No Title]"
# if item.get("detail_type") != "season": description_en = meta["description"].get("en") or ""
# continue # skip non-season items (e.g., actors, webtoons) show_id = str(item["id"])
#
# meta = item["meta"] results.append(
# title_en = meta["title"].get("en") or "[No Title]" SearchResult(
# description_en = meta["description"].get("en") or "" id_=show_id,
# show_id = str(item["id"]) title=title_en,
# description=description_en,
# results.append( label="season",
# SearchResult( url=f"https://www.kocowa.com/en_us/season/{show_id}/"
# id_=show_id, )
# title=title_en, )
# description=description_en, return results
# label="season",
# url=f"https://www.kocowa.com/en_us/season/{show_id}/placeholder"
# )
# )
# return results
def get_chapters(self, title: Title_T) -> list: def get_chapters(self, title: Title_T) -> list:
return [] return []