Features
Max audio compatibility added. Changes for Hybrid DV/HDR.
This commit is contained in:
parent
4fcd0748c0
commit
4a773d1db0
@ -4,6 +4,7 @@ python -m pip install poetry==1.8.5
|
||||
poetry config virtualenvs.in-project true
|
||||
poetry lock --no-update
|
||||
poetry install
|
||||
sudo add-apt-repository ppa:ubuntuhandbook1/apps
|
||||
sudo apt update
|
||||
sudo apt-get install ffmpeg aria2 mkvtoolnix libmediainfo0v5
|
||||
ffmpeg --version
|
||||
|
||||
@ -302,8 +302,9 @@ def dl(ctx, profile, cdm, *_, **__):
|
||||
except ValueError as e:
|
||||
raise log.exit(f" - {e}")
|
||||
|
||||
device_name = device.system_id if "vmp" in dir(device) else device.get_name()
|
||||
log.info(f" + Loaded {device.__class__.__name__}: {device_name} (L{device.security_level})")
|
||||
device_name = device.system_id if "vmp" in dir(device) else device.get_name().replace("_", " ").upper()
|
||||
s = "" if "vmp" in dir(device) else "S"
|
||||
log.info(f" + Loaded {device.__class__.__name__}: {device_name} ({s}L{device.security_level})")
|
||||
cdm = Cdm.from_device(device) if "vmp" in dir(device) else CdmPr.from_device(device)
|
||||
|
||||
if profile:
|
||||
@ -425,7 +426,10 @@ def result(ctx, service, quality, closest_resolution, range_, wanted, alang, sla
|
||||
log.warning(f" - No {quality}p resolution available, using closest available: {closest_res}p")
|
||||
quality = closest_res
|
||||
|
||||
title.tracks.select_videos(by_quality=quality, by_vbitrate=vbitrate, by_range=range_, one_only=True)
|
||||
if range_ == "DV+HDR":
|
||||
title.tracks.select_videos_multi(["HDR10", "DV"], by_quality=quality, by_vbitrate=vbitrate)
|
||||
else:
|
||||
title.tracks.select_videos(by_quality=quality, by_vbitrate=vbitrate, by_range=range_, one_only=True)
|
||||
title.tracks.select_audios(by_language=alang, by_bitrate=abitrate, with_descriptive=audio_description, by_codec=acodec, by_channels=audio_channels, max_audio_compatability=max_audio_compatability)
|
||||
title.tracks.select_subtitles(by_language=slang, with_forced=True)
|
||||
except ValueError as e:
|
||||
@ -714,12 +718,22 @@ def result(ctx, service, quality, closest_resolution, range_, wanted, alang, sla
|
||||
if isinstance(track, TextTrack) and strip_sdh:
|
||||
track.strip_sdh()
|
||||
log.info("Stripped SDH subtitles to CC with subby")
|
||||
|
||||
|
||||
if skip_title:
|
||||
for track in title.tracks:
|
||||
track.delete()
|
||||
continue
|
||||
if keys:
|
||||
continue
|
||||
|
||||
if range_ == "DV+HDR":
|
||||
try:
|
||||
hybrid_path = title.tracks.make_hybrid()
|
||||
log.info(f" + Hybrid DV+HDR created: {hybrid_path}")
|
||||
except Exception as e:
|
||||
log.warning(f" - Skipped Hybrid DV+HDR: {e}")
|
||||
|
||||
if not list(title.tracks) and not title.tracks.chapters:
|
||||
continue
|
||||
# mux all final tracks to a single mkv file
|
||||
|
||||
Binary file not shown.
@ -4,6 +4,7 @@ import logging
|
||||
import math
|
||||
import os
|
||||
import re
|
||||
import time
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
@ -1188,6 +1189,20 @@ class Tracks:
|
||||
if one_only and self.videos:
|
||||
self.videos = [self.videos[0]]
|
||||
|
||||
def select_videos_multi(self, ranges: list[str], by_quality=None, by_vbitrate=None) -> None:
|
||||
selected = []
|
||||
for r in ranges:
|
||||
temp = Tracks()
|
||||
temp.videos = self.videos.copy()
|
||||
temp.select_videos(by_range=r, by_quality=by_quality, one_only=False)
|
||||
if by_vbitrate:
|
||||
temp.videos = [x for x in temp.videos if int(x.bitrate) <= int(by_vbitrate * 1001)]
|
||||
if temp.videos:
|
||||
best = max(temp.videos, key=lambda x: x.bitrate)
|
||||
selected.append(best)
|
||||
unique = {(v.width, v.height, v.codec): v for v in selected}
|
||||
self.videos = list(unique.values())
|
||||
|
||||
def select_audios(
|
||||
self,
|
||||
with_descriptive: bool = True,
|
||||
@ -1214,18 +1229,20 @@ class Tracks:
|
||||
|
||||
try:
|
||||
inner_audios.extend(
|
||||
list(
|
||||
filter(
|
||||
lambda x: (
|
||||
any(y for y in self.AUDIO_CODEC_MAP[codec] if y in x.codec)
|
||||
and x.channels == channels
|
||||
),
|
||||
list(filter(
|
||||
lambda x: (any
|
||||
(
|
||||
y for y in self.AUDIO_CODEC_MAP[codec] if y in x.codec)
|
||||
and x.channels == channels
|
||||
),
|
||||
self.audios
|
||||
)
|
||||
)
|
||||
))
|
||||
)
|
||||
audios.append(max(inner_audios, key=lambda x: x.bitrate))
|
||||
|
||||
except: pass
|
||||
unique = {(v.bitrate, v.codec, v.channels): v for v in audios}
|
||||
self.audios = list(unique.values())
|
||||
|
||||
else:
|
||||
if by_codec:
|
||||
@ -1314,6 +1331,82 @@ class Tracks:
|
||||
from vinetrimmer import parsers
|
||||
return parsers.ism.parse(**kwargs)
|
||||
|
||||
def make_hybrid(self) -> str:
|
||||
start_time = time.time()
|
||||
logsi = logging.getLogger("Hybrid")
|
||||
logsi.info(" + Processing to Hybrid")
|
||||
|
||||
hdr = next((t for t in self.videos if t.hdr10 and not t.dv), None)
|
||||
dv = next((t for t in self.videos if t.dv and not t.hdr10), None)
|
||||
if not hdr or not dv:
|
||||
raise ValueError("Hybrid failed: track HDR10 and DV not correct.")
|
||||
hdr_path = Path(hdr.locate())
|
||||
dv_path = Path(dv.locate())
|
||||
hybrid_path = hdr_path.with_name(hdr_path.stem + "_hybrid.hevc")
|
||||
hybrid_path = Path(self.make_hybrid_dv_hdr(str(dv_path), str(hdr_path), str(hybrid_path)))
|
||||
timeout = 10
|
||||
waited = 0
|
||||
while not hybrid_path.exists() or os.path.getsize(hybrid_path) < 10000:
|
||||
time.sleep(0.25)
|
||||
waited += 0.25
|
||||
if waited >= timeout:
|
||||
raise FileNotFoundError(f"Hybrid file never appeared or too small: {hybrid_path}")
|
||||
hdr.swap(str(hybrid_path))
|
||||
# Hapus DV-only
|
||||
self.videos = [v for v in self.videos if not (v.dv and not v.hdr10)]
|
||||
#self._cleanup_paths = [dv_path, hybrid_path]
|
||||
try:
|
||||
if hdr_path.exists():
|
||||
hdr_path.unlink()
|
||||
if dv_path.exists():
|
||||
dv_path.unlink()
|
||||
except Exception as e:
|
||||
logsi.warning(f" - Failed to delete the temp file: {e}")
|
||||
end_time = time.time()
|
||||
duration = format_duration(end_time - start_time)
|
||||
logsi.info(gradient_text(f" + Finish processing Hybrid in {duration}!", (173, 255, 47), (0, 191, 255)))
|
||||
|
||||
return str(hybrid_path)
|
||||
|
||||
def make_hybrid_dv_hdr(dv_file: str, hdr_file: str, output_file: str = None) -> str:
|
||||
dovi_tool = shutil.which("dovi_tool") or "./binaries/dovi_tool"
|
||||
if not os.path.isfile(dovi_tool):
|
||||
raise FileNotFoundError("dovi_tool not found.")
|
||||
def extract_hevc(input_file, output_file):
|
||||
subprocess.run(
|
||||
["ffmpeg", "-y", "-i", input_file, "-c", "copy", "-bsf:v", "hevc_mp4toannexb", "-f", "hevc", output_file],
|
||||
check=True,
|
||||
stdout=subprocess.DEVNULL,
|
||||
stderr=subprocess.DEVNULL
|
||||
)
|
||||
|
||||
dv_file = Path(dv_file)
|
||||
hdr_file = Path(hdr_file)
|
||||
# Convert .mp4/.mkv to .hevc if needed
|
||||
if not dv_file.suffix == ".hevc":
|
||||
raw_dv = dv_file.with_suffix(".hevc")
|
||||
extract_hevc(str(dv_file), str(raw_dv))
|
||||
dv_file = raw_dv
|
||||
if not hdr_file.suffix == ".hevc":
|
||||
raw_hdr = hdr_file.with_suffix(".hevc")
|
||||
extract_hevc(str(hdr_file), str(raw_hdr))
|
||||
hdr_file = raw_hdr
|
||||
|
||||
output_file = Path(output_file or hdr_file.with_name(hdr_file.stem + "_hybrid.hevc")).resolve()
|
||||
rpu_file = Path("RPU.bin")
|
||||
temp_output = Path("temp_hybrid.hevc")
|
||||
subprocess.run([dovi_tool, "extract-rpu", "-i", str(dv_file), "-o", str(rpu_file)], check=True)
|
||||
subprocess.run([dovi_tool, "inject-rpu", "-i", str(hdr_file), "-r", str(rpu_file), "-o", str(temp_output)], check=True)
|
||||
if temp_output.exists():
|
||||
shutil.move(str(temp_output), str(output_file))
|
||||
|
||||
if rpu_file.exists():
|
||||
rpu_file.unlink()
|
||||
|
||||
if not output_file.exists():
|
||||
raise FileNotFoundError(f"Hybrid failed: {output_file} is not found.")
|
||||
return str(output_file)
|
||||
|
||||
def mux(self, prefix):
|
||||
"""
|
||||
Takes the Video, Audio and Subtitle Tracks, and muxes them into an MKV file.
|
||||
|
||||
@ -146,6 +146,8 @@ def range_param(ctx, param, value):
|
||||
"hlg": "HLG",
|
||||
"dv": "DV",
|
||||
"dovi": "DV",
|
||||
"dv+hdr": "DV+HDR",
|
||||
"hdr+dv": "DV+HDR",
|
||||
})
|
||||
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user