mirror of
https://github.com/unshackle-dl/unshackle.git
synced 2026-03-12 17:39:01 +00:00
Compare commits
4 Commits
f8a58d966b
...
63c697f082
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
63c697f082 | ||
|
|
3e0835d9fb | ||
|
|
c6c83ee43b | ||
|
|
507690834b |
@@ -139,7 +139,13 @@ class dl:
|
|||||||
default=None,
|
default=None,
|
||||||
help="Wanted episodes, e.g. `S01-S05,S07`, `S01E01-S02E03`, `S02-S02E03`, e.t.c, defaults to all.",
|
help="Wanted episodes, e.g. `S01-S05,S07`, `S01E01-S02E03`, `S02-S02E03`, e.t.c, defaults to all.",
|
||||||
)
|
)
|
||||||
@click.option("-l", "--lang", type=LANGUAGE_RANGE, default="en", help="Language wanted for Video and Audio.")
|
@click.option(
|
||||||
|
"-l",
|
||||||
|
"--lang",
|
||||||
|
type=LANGUAGE_RANGE,
|
||||||
|
default="en",
|
||||||
|
help="Language wanted for Video and Audio. Use 'orig' to select the original language, e.g. 'orig,en' for both original and English.",
|
||||||
|
)
|
||||||
@click.option(
|
@click.option(
|
||||||
"-vl",
|
"-vl",
|
||||||
"--v-lang",
|
"--v-lang",
|
||||||
@@ -562,8 +568,31 @@ class dl:
|
|||||||
)
|
)
|
||||||
|
|
||||||
with console.status("Sorting tracks by language and bitrate...", spinner="dots"):
|
with console.status("Sorting tracks by language and bitrate...", spinner="dots"):
|
||||||
title.tracks.sort_videos(by_language=v_lang or lang)
|
video_sort_lang = v_lang or lang
|
||||||
title.tracks.sort_audio(by_language=lang)
|
processed_video_sort_lang = []
|
||||||
|
for language in video_sort_lang:
|
||||||
|
if language == "orig":
|
||||||
|
if title.language:
|
||||||
|
orig_lang = str(title.language) if hasattr(title.language, "__str__") else title.language
|
||||||
|
if orig_lang not in processed_video_sort_lang:
|
||||||
|
processed_video_sort_lang.append(orig_lang)
|
||||||
|
else:
|
||||||
|
if language not in processed_video_sort_lang:
|
||||||
|
processed_video_sort_lang.append(language)
|
||||||
|
|
||||||
|
processed_audio_sort_lang = []
|
||||||
|
for language in lang:
|
||||||
|
if language == "orig":
|
||||||
|
if title.language:
|
||||||
|
orig_lang = str(title.language) if hasattr(title.language, "__str__") else title.language
|
||||||
|
if orig_lang not in processed_audio_sort_lang:
|
||||||
|
processed_audio_sort_lang.append(orig_lang)
|
||||||
|
else:
|
||||||
|
if language not in processed_audio_sort_lang:
|
||||||
|
processed_audio_sort_lang.append(language)
|
||||||
|
|
||||||
|
title.tracks.sort_videos(by_language=processed_video_sort_lang)
|
||||||
|
title.tracks.sort_audio(by_language=processed_audio_sort_lang)
|
||||||
title.tracks.sort_subtitles(by_language=s_lang)
|
title.tracks.sort_subtitles(by_language=s_lang)
|
||||||
|
|
||||||
if list_:
|
if list_:
|
||||||
@@ -594,12 +623,27 @@ class dl:
|
|||||||
self.log.error(f"There's no {vbitrate}kbps Video Track...")
|
self.log.error(f"There's no {vbitrate}kbps Video Track...")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
# Filter out "best" from the video languages list.
|
|
||||||
video_languages = [lang for lang in (v_lang or lang) if lang != "best"]
|
video_languages = [lang for lang in (v_lang or lang) if lang != "best"]
|
||||||
if video_languages and "all" not in video_languages:
|
if video_languages and "all" not in video_languages:
|
||||||
title.tracks.videos = title.tracks.by_language(title.tracks.videos, video_languages)
|
processed_video_lang = []
|
||||||
|
for language in video_languages:
|
||||||
|
if language == "orig":
|
||||||
|
if title.language:
|
||||||
|
orig_lang = (
|
||||||
|
str(title.language) if hasattr(title.language, "__str__") else title.language
|
||||||
|
)
|
||||||
|
if orig_lang not in processed_video_lang:
|
||||||
|
processed_video_lang.append(orig_lang)
|
||||||
|
else:
|
||||||
|
self.log.warning(
|
||||||
|
"Original language not available for title, skipping 'orig' selection for video"
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
if language not in processed_video_lang:
|
||||||
|
processed_video_lang.append(language)
|
||||||
|
title.tracks.videos = title.tracks.by_language(title.tracks.videos, processed_video_lang)
|
||||||
if not title.tracks.videos:
|
if not title.tracks.videos:
|
||||||
self.log.error(f"There's no {video_languages} Video Track...")
|
self.log.error(f"There's no {processed_video_lang} Video Track...")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
if quality:
|
if quality:
|
||||||
@@ -702,8 +746,24 @@ class dl:
|
|||||||
self.log.error(f"There's no {abitrate}kbps Audio Track...")
|
self.log.error(f"There's no {abitrate}kbps Audio Track...")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
if lang:
|
if lang:
|
||||||
if "best" in lang:
|
processed_lang = []
|
||||||
# Get unique languages and select highest quality for each
|
for language in lang:
|
||||||
|
if language == "orig":
|
||||||
|
if title.language:
|
||||||
|
orig_lang = (
|
||||||
|
str(title.language) if hasattr(title.language, "__str__") else title.language
|
||||||
|
)
|
||||||
|
if orig_lang not in processed_lang:
|
||||||
|
processed_lang.append(orig_lang)
|
||||||
|
else:
|
||||||
|
self.log.warning(
|
||||||
|
"Original language not available for title, skipping 'orig' selection"
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
if language not in processed_lang:
|
||||||
|
processed_lang.append(language)
|
||||||
|
|
||||||
|
if "best" in processed_lang:
|
||||||
unique_languages = {track.language for track in title.tracks.audio}
|
unique_languages = {track.language for track in title.tracks.audio}
|
||||||
selected_audio = []
|
selected_audio = []
|
||||||
for language in unique_languages:
|
for language in unique_languages:
|
||||||
@@ -713,10 +773,13 @@ class dl:
|
|||||||
)
|
)
|
||||||
selected_audio.append(highest_quality)
|
selected_audio.append(highest_quality)
|
||||||
title.tracks.audio = selected_audio
|
title.tracks.audio = selected_audio
|
||||||
elif "all" not in lang:
|
elif "all" not in processed_lang:
|
||||||
title.tracks.audio = title.tracks.by_language(title.tracks.audio, lang, per_language=1)
|
per_language = 0 if len(processed_lang) > 1 else 1
|
||||||
|
title.tracks.audio = title.tracks.by_language(
|
||||||
|
title.tracks.audio, processed_lang, per_language=per_language
|
||||||
|
)
|
||||||
if not title.tracks.audio:
|
if not title.tracks.audio:
|
||||||
self.log.error(f"There's no {lang} Audio Track, cannot continue...")
|
self.log.error(f"There's no {processed_lang} Audio Track, cannot continue...")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
if video_only or audio_only or subs_only or chapters_only or no_subs or no_audio or no_chapters:
|
if video_only or audio_only or subs_only or chapters_only or no_subs or no_audio or no_chapters:
|
||||||
@@ -929,12 +992,15 @@ class dl:
|
|||||||
with console.status(f"Decrypting tracks with {decrypt_tool}..."):
|
with console.status(f"Decrypting tracks with {decrypt_tool}..."):
|
||||||
has_decrypted = False
|
has_decrypted = False
|
||||||
for track in drm_tracks:
|
for track in drm_tracks:
|
||||||
for drm in track.drm:
|
drm = track.get_drm_for_cdm(self.cdm)
|
||||||
if hasattr(drm, "decrypt"):
|
if drm and hasattr(drm, "decrypt"):
|
||||||
drm.decrypt(track.path, use_mp4decrypt=use_mp4decrypt)
|
drm.decrypt(track.path, use_mp4decrypt=use_mp4decrypt)
|
||||||
has_decrypted = True
|
has_decrypted = True
|
||||||
events.emit(events.Types.TRACK_REPACKED, track=track)
|
events.emit(events.Types.TRACK_REPACKED, track=track)
|
||||||
break
|
else:
|
||||||
|
self.log.warning(
|
||||||
|
f"No matching DRM found for track {track} with CDM type {type(self.cdm).__name__}"
|
||||||
|
)
|
||||||
if has_decrypted:
|
if has_decrypted:
|
||||||
self.log.info(f"Decrypted tracks with {decrypt_tool}")
|
self.log.info(f"Decrypted tracks with {decrypt_tool}")
|
||||||
|
|
||||||
|
|||||||
@@ -201,9 +201,10 @@ class Series(SortedKeyList, ABC):
|
|||||||
def tree(self, verbose: bool = False) -> Tree:
|
def tree(self, verbose: bool = False) -> Tree:
|
||||||
seasons = Counter(x.season for x in self)
|
seasons = Counter(x.season for x in self)
|
||||||
num_seasons = len(seasons)
|
num_seasons = len(seasons)
|
||||||
num_episodes = sum(seasons.values())
|
sum(seasons.values())
|
||||||
|
season_breakdown = ", ".join(f"S{season}({count})" for season, count in sorted(seasons.items()))
|
||||||
tree = Tree(
|
tree = Tree(
|
||||||
f"{num_seasons} Season{['s', ''][num_seasons == 1]}, {num_episodes} Episode{['s', ''][num_episodes == 1]}",
|
f"{num_seasons} seasons, {season_breakdown}",
|
||||||
guide_style="bright_black",
|
guide_style="bright_black",
|
||||||
)
|
)
|
||||||
if verbose:
|
if verbose:
|
||||||
|
|||||||
@@ -355,6 +355,14 @@ class Tracks:
|
|||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if hasattr(vt, "range") and vt.range == Video.Range.HLG:
|
||||||
|
video_args.extend(
|
||||||
|
[
|
||||||
|
"--color-transfer-characteristics",
|
||||||
|
"0:18", # ARIB STD-B67 (HLG)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
cl.extend(video_args + ["(", str(vt.path), ")"])
|
cl.extend(video_args + ["(", str(vt.path), ")"])
|
||||||
|
|
||||||
for i, at in enumerate(self.audio):
|
for i, at in enumerate(self.audio):
|
||||||
|
|||||||
Reference in New Issue
Block a user