diff --git a/binaries/aria2c.exe b/binaries/aria2c.exe index 5004e10..18b2b7b 100644 Binary files a/binaries/aria2c.exe and b/binaries/aria2c.exe differ diff --git a/binaries/ffmpeg-6.1.1-essentials_build.7z b/binaries/ffmpeg-6.1.1-essentials_build.7z new file mode 100644 index 0000000..5415cbf Binary files /dev/null and b/binaries/ffmpeg-6.1.1-essentials_build.7z differ diff --git a/binaries/ffmpeg.exe b/binaries/ffmpeg.exe index db2987e..5626ea7 100644 Binary files a/binaries/ffmpeg.exe and b/binaries/ffmpeg.exe differ diff --git a/binaries/ffplay.exe b/binaries/ffplay.exe index 42ad6e0..a894102 100644 Binary files a/binaries/ffplay.exe and b/binaries/ffplay.exe differ diff --git a/binaries/ffprobe.exe b/binaries/ffprobe.exe index 2a6c4b3..9be8989 100644 Binary files a/binaries/ffprobe.exe and b/binaries/ffprobe.exe differ diff --git a/linux_binaries/ffmpeg-n6.1-latest-linux64-gpl-6.1.tar.xz b/linux_binaries/ffmpeg-n6.1-latest-linux64-gpl-6.1.tar.xz new file mode 100644 index 0000000..8813eb6 Binary files /dev/null and b/linux_binaries/ffmpeg-n6.1-latest-linux64-gpl-6.1.tar.xz differ diff --git a/vinetrimmer/commands/dl.py b/vinetrimmer/commands/dl.py index 3aa9ef7..7e08eab 100644 --- a/vinetrimmer/commands/dl.py +++ b/vinetrimmer/commands/dl.py @@ -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)") diff --git a/vinetrimmer/devices/hisense_smarttv_he55a7000euwts_sl3000.prd b/vinetrimmer/devices/hisense_smarttv_he55a7000euwts_sl3000.prd index f2a0e1d..cee30dc 100644 Binary files a/vinetrimmer/devices/hisense_smarttv_he55a7000euwts_sl3000.prd and b/vinetrimmer/devices/hisense_smarttv_he55a7000euwts_sl3000.prd differ diff --git a/vinetrimmer/key_store.db b/vinetrimmer/key_store.db index da3bef9..7bd7f3b 100644 Binary files a/vinetrimmer/key_store.db and b/vinetrimmer/key_store.db differ diff --git a/vinetrimmer/objects/tracks.py b/vinetrimmer/objects/tracks.py index 632553d..65c838c 100644 --- a/vinetrimmer/objects/tracks.py +++ b/vinetrimmer/objects/tracks.py @@ -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: diff --git a/vinetrimmer/parsers/ism.py b/vinetrimmer/parsers/ism.py index 21c9648..9d09c53 100644 --- a/vinetrimmer/parsers/ism.py +++ b/vinetrimmer/parsers/ism.py @@ -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 diff --git a/vinetrimmer/utils/io.py b/vinetrimmer/utils/io.py index ed4dec6..7947bac 100644 --- a/vinetrimmer/utils/io.py +++ b/vinetrimmer/utils/io.py @@ -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!")