- 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:
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user