ISM Atmos fix for Amazon

This commit is contained in:
chu23465 2025-04-15 19:07:41 +05:30
parent 999c73d1e6
commit 11108223bc
12 changed files with 67 additions and 51 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -405,17 +405,6 @@ 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
# Modified video track selection to choose lowest bitrate if vbitrate == min
if isinstance(vbitrate, str) and vbitrate.lower() == "min":
if not quality:
quality = 1080
available_bitrate = [int(track.bitrate) for track in title.tracks.videos if track.height == quality]
if available_bitrate == []:
log.error(" - No video tracks available")
continue
vbitrate = min(available_bitrate) / 1000
log.warning(f" - Choosing minimum bitrate: {vbitrate}")
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)
title.tracks.select_subtitles(by_language=slang, with_forced=True)
@ -639,7 +628,9 @@ def result(ctx, service, quality, closest_resolution, range_, wanted, alang, sla
if not executable:
raise log.exit(" - Unable to find mp4decrypt binary")
dec = os.path.splitext(track.locate())[0] + ".dec.mp4"
os.makedirs(directories.temp, exist_ok=True)
try:
os.makedirs(directories.temp, exist_ok=True)
subprocess.run([
executable,
"--show-progress",
@ -657,6 +648,24 @@ def result(ctx, service, quality, closest_resolution, range_, wanted, alang, sla
if keys:
continue
if isinstance(track, AudioTrack) and track.descriptor == Track.Descriptor.ISM and track.atmos:
#--enable-libmfx is the only difference between 6.1.1 and 7.X.
#FFMPEG 6.1.1 is necessary as that version correctly puts in place an init.mp4 for EAC-3-JOC ie Atmos
#https://github.com/GyanD/codexffmpeg/releases/tag/6.1.1
#https://github.com/BtbN/FFmpeg-Builds/releases/tag/latest
executable = shutil.which("ffmpeg")
if not executable:
raise log.exit(" - Unable to find ffmpeg binary")
eac3 = os.path.splitext(track.locate())[0] + ".eac3"
os.makedirs(directories.temp, exist_ok=True)
try:
os.makedirs(directories.temp, exist_ok=True)
exec_string = f"{executable} -i {track.locate()} -hide_banner -loglevel error -map 0 -c:a copy {eac3}"
subprocess.run(exec_string)
except subprocess.CalledProcessError:
raise log.exit(" - Failed!")
track.swap(eac3)
log.info(" + Fixed ISM Atmos")
if track.needs_repack or (config.decrypter == "mp4decrypt" and isinstance(track, (VideoTrack, AudioTrack))):
log.info("Repackaging stream with FFmpeg (to fix malformed streams)")

Binary file not shown.

View File

@ -237,21 +237,17 @@ class Track:
self.psshPR = str(x).split("\"")[1].split(",")[-1]
break
try:
xml_str = base64.b64decode(self.psshPR).decode("utf-16-le", "ignore")
xml_str = xml_str[xml_str.index("<"):]
xml_str = base64.b64decode(self.psshPR).decode("utf-16-le", "ignore")
xml_str = xml_str[xml_str.index("<"):]
xml = load_xml(xml_str).find("DATA") # root: WRMHEADER
xml = load_xml(xml_str).find("DATA") # root: WRMHEADER
self.kid = xml.findtext("KID") # v4.0.0.0
if not self.kid: # v4.1.0.0
self.kid = next(iter(xml.xpath("PROTECTINFO/KID/@VALUE")), None)
if not self.kid: # v4.3.0.0
self.kid = next(iter(xml.xpath("PROTECTINFO/KIDS/KID/@VALUE")), None) # can be multiple?
self.kid = xml.findtext("KID") # v4.0.0.0
if not self.kid: # v4.1.0.0
self.kid = next(iter(xml.xpath("PROTECTINFO/KID/@VALUE")), None)
if not self.kid: # v4.3.0.0
self.kid = next(iter(xml.xpath("PROTECTINFO/KIDS/KID/@VALUE")), None) # can be multiple?
self.kid = uuid.UUID(base64.b64decode(self.kid).hex()).bytes_le.hex()
except: pass
self.kid = uuid.UUID(base64.b64decode(self.kid).hex()).bytes_le.hex()
if self.source == "NF":
self.kid = "{}{}{}".format(
@ -367,9 +363,11 @@ class Track:
if not Path(save_path).is_file():
save_path = save_path_orig.replace(".mp4", f".{str(self.language)[:2]}.m4a")
if not Path(save_path).is_file():
save_path = save_path_orig
save_path = save_path_orig.replace(".mp4", f".eng.m4a") # This is a hack as only english atmos audio is available in Amazon
if not Path(save_path).is_file():
raise
save_path = save_path_orig
if not Path(save_path).is_file():
raise
else:
asyncio.run(aria2c(
self.url,
@ -1134,8 +1132,17 @@ class Tracks:
if not videos_quality:
raise ValueError(f"There's no {by_quality}p resolution video track. Aborting.")
self.videos = videos_quality
if by_vbitrate:
# Modified video track selection to choose lowest bitrate if by_vbitrate == min
if isinstance(by_vbitrate, str) and by_vbitrate.lower() == "min":
available_bitrate = [int(track.bitrate) for track in self.videos]
bitrate = min(available_bitrate) / 1001
#if bitrate < 99999:
# bitrate = bitrate / 1000
self.videos = [x for x in self.videos if int(x.bitrate) <= int(bitrate * 1001)]
elif by_vbitrate:
self.videos = [x for x in self.videos if int(x.bitrate) <= int(by_vbitrate * 1001)]
if by_codec:
codec_videos = list(filter(lambda x: any(y for y in self.VIDEO_CODEC_MAP[by_codec] if y in x.codec), self.videos))
if not codec_videos and not should_fallback:

View File

@ -217,28 +217,28 @@ def parse(*, url=None, data=None, source, session=None, downloader=None):
# extra
extra=(list(quality_level), list(stream_info),) # Either set size as a attribute of VideoTrack or append to extra here.
))
"""
elif type_info == 'audio':
atmos = ( str( quality_level.get('@HasAtmos', 'N/A') ).lower() == "true" ) or ( "ATM" in stream_info.get('@Name', 'N/A') )
tracks.append(AudioTrack(
id_=track_id,
source=source,
url=url,
# metadata
codec="E-AC3" if codec == "EC-3" else (codec or "").split(".")[0],
language=lang,
bitrate=bitrate,
channels=quality_level.get('@Channels', 'N/A'),
atmos=atmos,
# switches/options
descriptor=Track.Descriptor.ISM,
# decryption
needs_repack=True, # Necessary
encrypted=encrypted,
pssh=pssh,
kid=kid,
# extra
extra=(dict(quality_level), dict(stream_info),)
))
"""
if atmos: # Only appending Atmos streams -> Other audios can be obtained from Amazon MPD
tracks.append(AudioTrack(
id_=track_id,
source=source,
url=url,
# metadata
codec="E-AC3" if codec == "EC-3" else (codec or "").split(".")[0],
language=lang,
bitrate=bitrate,
channels=quality_level.get('@Channels', 'N/A'),
atmos=atmos,
# switches/options
descriptor=Track.Descriptor.ISM,
# decryption
needs_repack=True, # Necessary
encrypted=encrypted,
psshPR=pssh,
kid=kid,
# extra
extra=(dict(quality_level), dict(stream_info),)
))
return tracks

View File

@ -296,8 +296,8 @@ async def m3u8dl(uri, out, track, headers=None, proxy=None):
"-dv", "all",
"-ds", "all",
])
if track.source != "HS":
arguments.extend(["-M", "format=mp4"])
#if track.source != "HS":
# arguments.extend(["-M", "format=mp4"])
else:
raise ValueError(f"{track.__class__.__name__} not supported yet!")