- Correct CR to handle SDH & Force subtitle correctly

- Download VTT as SRT then convert to SRT using on_track_downloaded
This commit is contained in:
2026-03-30 22:03:26 +07:00
parent 3887d28d17
commit e3d6d0ce8b

View File

@@ -8,6 +8,7 @@ import click
import jwt
from langcodes import Language
from unshackle.core.constants import AnyTrack
from unshackle.core.manifests import DASH
from unshackle.core.search_result import SearchResult
from unshackle.core.service import Service
@@ -17,13 +18,16 @@ from unshackle.core.tracks import Chapters, Tracks
from unshackle.core.tracks.chapter import Chapter
from unshackle.core.tracks.subtitle import Subtitle
import pysubs2
from subby import WebVTTConverter,CommonIssuesFixer
from hashlib import md5
class CR(Service):
"""
Service code for Crunchyroll streaming service (https://www.crunchyroll.com).
\b
Version: 3.0.0
Version: 3.0.1
Author: sp4rk.y
Date: 2026-03-26
Authorization: Credentials
@@ -31,6 +35,11 @@ class CR(Service):
Widevine:
L3: 1080p, AAC2.0
Updated by: SeFree
Date: 2026-03-30
Change:
- Correct SDH and Force subtitle
\b
Tips:
- Input should be complete URL or series ID
@@ -71,6 +80,8 @@ class CR(Service):
self.token_expiration: Optional[int] = None
self.anonymous_id = str(uuid.uuid4())
self.skip_dl=ctx.parent.params.get("skip_dl")
super().__init__(ctx)
device_cache_key = "cr_device_id"
@@ -372,7 +383,7 @@ class CR(Service):
final_number = season_episode_counts[final_season]
original_language = None
versions = episode_data.get("versions", [])
versions = episode_data.get("versions", []) if episode_data.get("versions", []) else []
for version in versions:
if "main" in version.get("roles", []):
original_language = version.get("audio_locale")
@@ -527,12 +538,12 @@ class CR(Service):
self.close_stream(request_episode_id, version_token)
continue
if is_original and endpoint_key == "playback":
if endpoint_key == "playback":
captions = version_response.get("captions", {})
subtitles_data = version_response.get("subtitles", {})
all_subs = {**captions, **subtitles_data}
# all_subs = {**captions, **subtitles_data}
for lang_code, sub_data in all_subs.items():
for lang_code, sub_data in captions.items():
if lang_code == "none":
continue
@@ -540,21 +551,49 @@ class CR(Service):
try:
lang = Language.get(lang_code)
except (ValueError, LookupError):
lang = Language.get("fr")
lang = Language.get("en")
subtitle_format = sub_data.get("format", "vtt").lower()
if subtitle_format == "ass" or subtitle_format == "ssa":
codec = Subtitle.Codec.SubStationAlphav4
else:
codec = Subtitle.Codec.WebVTT
codec = Subtitle.Codec.SubRip
tracks.add(
Subtitle(
id_=f"subtitle-{audio_locale}-{lang_code}",
id_=f"subtitle-{audio_locale}-{lang_code}-sdh",
url=sub_data["url"],
codec=codec,
language=lang,
forced=False,
sdh=True,
),
warn_only=True,
)
for lang_code, sub_data in subtitles_data.items():
if lang_code == "none":
continue
if isinstance(sub_data, dict) and "url" in sub_data:
try:
lang = Language.get(lang_code)
except (ValueError, LookupError):
lang = Language.get("en")
subtitle_format = sub_data.get("format", "vtt").lower()
if subtitle_format == "ass" or subtitle_format == "ssa":
codec = Subtitle.Codec.SubStationAlphav4
else:
print(sub_data["url"])
codec = Subtitle.Codec.SubRip
tracks.add(
Subtitle(
id_=f"subtitle-{audio_locale}-{lang_code}"+("_force" if (Language.get(audio_locale)== Language.get(lang)) else ""),
url=sub_data["url"],
codec=codec,
language=lang,
forced=True if Language.get(audio_locale)== Language.get(lang) else False,
sdh=False,
),
warn_only=True,
@@ -973,3 +1012,27 @@ class CR(Service):
raise ValueError(f"Could not parse series ID from: {title_input}")
series_id = match.group("id")
return series_id
def on_track_downloaded(self, track: AnyTrack) -> None:
"""
Called when a Track has finished downloading.
Parameters:
track: The Track object that was downloaded.
"""
if isinstance(track,Subtitle) and not self.skip_dl:
if track.path.suffix == ".vtt" and track.path.name:
with open(track.path.__str__(), 'rb') as fd:
data = fd.read()
converter=WebVTTConverter()
if isinstance(data, bytes):
srt = converter.from_bytes(data)
else:
srt = converter.from_string(data)
fixer = CommonIssuesFixer()
fixed, status = fixer.from_srt(srt)
if status and fixed:
srt = fixed
srt.save(track.path)