fix m3u8 parser no resolution find

This commit is contained in:
Ghost 2024-04-12 22:50:50 +02:00
parent 768589ed48
commit cc96066bc8
2 changed files with 118 additions and 28 deletions

View File

@ -587,8 +587,13 @@ class Downloader():
# Get obj codec # Get obj codec
self.codec: M3U8_Codec = parse_class_m3u8.codec self.codec: M3U8_Codec = parse_class_m3u8.codec
logging.info(f"Get codeds: {self.codec}")
console.log(f"[cyan]Find codecs: [red]({self.codec.video_codec_name};{self.codec.audio_codec_name})") # If codec exist print log
if self.codec is not None:
logging.info(f"Get codeds: {self.codec}")
console.log(f"[cyan]Find codecs: [red]({self.codec.video_codec_name};{self.codec.audio_codec_name})")
else:
logging.info(f"Codec obj dont exist")
def manage_subtitle(self): def manage_subtitle(self):
""" """

View File

@ -38,6 +38,35 @@ CODEC_MAPPINGS = {
} }
def extract_resolution(uri: str) -> int:
"""
Extracts the video resolution from the given URI.
Args:
- uri (str): The URI containing video information.
Returns:
- int: The video resolution if found, otherwise 0.
"""
# Common video resolutions
resolutions = [
480,
720,
1080,
2160,
3840
]
for resolution in resolutions:
if str(resolution) in uri:
return resolution
# Default resolution return (not best)
logging.error("No resolution find")
return 0
class M3U8_Codec(): class M3U8_Codec():
""" """
@ -169,46 +198,99 @@ class M3U8_Parser:
self.codec: M3U8_Codec = None self.codec: M3U8_Codec = None
self.DOWNLOAD_SPECIFIC_SUBTITLE = DOWNLOAD_SPECIFIC_SUBTITLE self.DOWNLOAD_SPECIFIC_SUBTITLE = DOWNLOAD_SPECIFIC_SUBTITLE
def parse_data(self, m3u8_content: str) -> (None): def parse_data(self, m3u8_content: str) -> None:
""" """
Extracts all information present in the provided M3U8 content. Extracts all information present in the provided M3U8 content.
Args: Args:
- m3u8_content (str): The content of the M3U8 file. - m3u8_content (str): The content of the M3U8 file.
""" """
try: try:
# Basic input validation
if not m3u8_content.strip():
logging.error("M3U8 content is empty or whitespace.")
return
# Get obj of the m3u8 text content download, dictionary with video, audio, segments, subtitles # Get obj of the m3u8 text content download, dictionary with video, audio, segments, subtitles
m3u8_obj = M3U8(m3u8_content) m3u8_obj = M3U8(m3u8_content)
# Collect video info with url, resolution and codecs self.parse_video_info(m3u8_obj)
self.parse_encryption_keys(m3u8_obj)
self.parse_subtitles_and_audio(m3u8_obj)
self.parse_segments(m3u8_obj)
except Exception as e:
logging.error(f"Error parsing M3U8 content: {e}")
def parse_video_info(self, m3u8_obj) -> None:
"""
Extracts video information from the M3U8 object.
Args:
- m3u8_obj: The M3U8 object containing video playlists.
"""
try:
for playlist in m3u8_obj.playlists: for playlist in m3u8_obj.playlists:
# Try to access the 'resolution' key in playlist.stream_info
try:
resolution = playlist.stream_info.get('resolution')
except:
# If the key 'resolution' does not exist, use extract_resolution
resolution = extract_resolution(playlist.uri)
self.video_playlist.append({ self.video_playlist.append({
"uri": playlist.uri, "uri": playlist.uri,
"width": playlist.stream_info.resolution, "width": resolution
}) })
self.codec = M3U8_Codec( # Check if all key is present to create codec
playlist.stream_info.bandwidth, if all(key in playlist.stream_info for key in ('bandwidth', 'resolution', 'codecs')):
playlist.stream_info.resolution, self.codec = M3U8_Codec(
playlist.stream_info.codecs playlist.stream_info.get('bandwidth'),
) playlist.stream_info.get('resolution'),
logging.info(f"Parse: {playlist.stream_info}") playlist.stream_info.get('codecs')
logging.info(f"Coded test: {self.codec.bandwidth}") )
# Collect info of encryption if present, method, uri and iv # if not we cant create codec
else:
self.codec = None
logging.info(f"Parse: {playlist.stream_info}")
if self.codec:
logging.info(f"Coded test: {self.codec.bandwidth}")
except Exception as e:
logging.error(f"Error parsing video info: {e}")
def parse_encryption_keys(self, m3u8_obj) -> None:
"""
Extracts encryption keys from the M3U8 object.
Args:
- m3u8_obj: The M3U8 object containing encryption keys.
"""
try:
for key in m3u8_obj.keys: for key in m3u8_obj.keys:
if key is not None: if key is not None:
self.keys = ({ self.keys = {
"method": key.method, "method": key.method,
"uri": key.uri, "uri": key.uri,
"iv": key.iv "iv": key.iv
}) }
# Collect info of subtitles, type, name, language and uri except Exception as e:
# for audio and subtitles logging.error(f"Error parsing encryption keys: {e}")
def parse_subtitles_and_audio(self, m3u8_obj) -> None:
"""
Extracts subtitles and audio information from the M3U8 object.
Args:
- m3u8_obj: The M3U8 object containing subtitles and audio data.
"""
try:
for media in m3u8_obj.media: for media in m3u8_obj.media:
if media.type == "SUBTITLES": if media.type == "SUBTITLES":
self.subtitle_playlist.append({ self.subtitle_playlist.append({
@ -219,7 +301,6 @@ class M3U8_Parser:
"uri": media.uri "uri": media.uri
}) })
if media.type == "AUDIO": if media.type == "AUDIO":
self.audio_ts.append({ self.audio_ts.append({
"type": media.type, "type": media.type,
@ -229,21 +310,25 @@ class M3U8_Parser:
"uri": media.uri "uri": media.uri
}) })
# Collect info about url of subtitles or segmenets except Exception as e:
# m3u8 playlist logging.error(f"Error parsing subtitles and audio: {e}")
# m3u8 index
for segment in m3u8_obj.segments:
# Collect uri of request to vtt def parse_segments(self, m3u8_obj) -> None:
"""
Extracts segment information from the M3U8 object.
Args:
- m3u8_obj: The M3U8 object containing segment data.
"""
try:
for segment in m3u8_obj.segments:
if "vtt" not in segment.uri: if "vtt" not in segment.uri:
self.segments.append(segment.uri) self.segments.append(segment.uri)
# Collect info of subtitle
else: else:
self.subtitle.append(segment.uri) self.subtitle.append(segment.uri)
except Exception as e: except Exception as e:
logging.error(f"Error parsing M3U8 content: {e}") logging.error(f"Error parsing segments: {e}")
def get_resolution(self, uri: str) -> (int): def get_resolution(self, uri: str) -> (int):
""" """