mirror of
https://github.com/Arrowar/StreamingCommunity.git
synced 2025-06-07 12:05:35 +00:00
try fix stuttering
This commit is contained in:
parent
37b2161a1a
commit
dafb0f201b
@ -44,13 +44,14 @@ from .util import (
|
|||||||
M3U8_Decryption,
|
M3U8_Decryption,
|
||||||
M3U8_Ts_Files,
|
M3U8_Ts_Files,
|
||||||
M3U8_Parser,
|
M3U8_Parser,
|
||||||
|
M3U8_Codec,
|
||||||
M3U8_UrlFix
|
M3U8_UrlFix
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
# Config
|
# Config
|
||||||
Download_audio = config_manager.get_bool('M3U8_OPTIONS', 'download_audio')
|
DOWNLOAD_AUDIO = config_manager.get_bool('M3U8_OPTIONS', 'download_audio')
|
||||||
Donwload_subtitles = config_manager.get_bool('M3U8_OPTIONS', 'download_subtitles')
|
DOWNLOAD_SUBTITLES = config_manager.get_bool('M3U8_OPTIONS', 'download_subtitles')
|
||||||
DOWNLOAD_SPECIFIC_AUDIO = config_manager.get_list('M3U8_OPTIONS', 'specific_list_audio')
|
DOWNLOAD_SPECIFIC_AUDIO = config_manager.get_list('M3U8_OPTIONS', 'specific_list_audio')
|
||||||
DOWNLOAD_SPECIFIC_SUBTITLE = config_manager.get_list('M3U8_OPTIONS', 'specific_list_subtitles')
|
DOWNLOAD_SPECIFIC_SUBTITLE = config_manager.get_list('M3U8_OPTIONS', 'specific_list_subtitles')
|
||||||
TQDM_MAX_WORKER = config_manager.get_int('M3U8', 'tdqm_workers')
|
TQDM_MAX_WORKER = config_manager.get_int('M3U8', 'tdqm_workers')
|
||||||
@ -394,10 +395,10 @@ class M3U8_Segments:
|
|||||||
# Refresh progress bar
|
# Refresh progress bar
|
||||||
progress_counter.refresh()
|
progress_counter.refresh()
|
||||||
|
|
||||||
def join(self, output_filename: str, video_decoding: str = None, audio_decoding: str = None):
|
def join(self, output_filename: str):
|
||||||
"""
|
"""
|
||||||
Join all segments file to a mp4 file name
|
Join all segments file to a mp4 file name
|
||||||
!! NOT USED
|
!! NOT USED IN THIS VERSION
|
||||||
|
|
||||||
Parameters:
|
Parameters:
|
||||||
- video_decoding(str): video decoding to use with ffmpeg for only video
|
- video_decoding(str): video decoding to use with ffmpeg for only video
|
||||||
@ -437,9 +438,7 @@ class M3U8_Segments:
|
|||||||
# ADD IF
|
# ADD IF
|
||||||
concatenate_and_save(
|
concatenate_and_save(
|
||||||
file_list_path = file_list_path,
|
file_list_path = file_list_path,
|
||||||
output_filename = output_filename,
|
output_filename = output_filename
|
||||||
video_decoding = video_decoding,
|
|
||||||
audio_decoding = audio_decoding
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -455,7 +454,6 @@ class Downloader():
|
|||||||
- key (str, optional): Hexadecimal representation of the encryption key.
|
- key (str, optional): Hexadecimal representation of the encryption key.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
self.m3u8_playlist = m3u8_playlist
|
self.m3u8_playlist = m3u8_playlist
|
||||||
self.m3u8_index = m3u8_index
|
self.m3u8_index = m3u8_index
|
||||||
self.key = bytes.fromhex(key) if key is not None else key
|
self.key = bytes.fromhex(key) if key is not None else key
|
||||||
@ -471,15 +469,16 @@ class Downloader():
|
|||||||
if self.key != None:
|
if self.key != None:
|
||||||
hex_data = convert_to_hex(self.key)
|
hex_data = convert_to_hex(self.key)
|
||||||
console.log(f"[cyan]Key use [white]=> [red]{hex_data}")
|
console.log(f"[cyan]Key use [white]=> [red]{hex_data}")
|
||||||
|
logging.info(f"Key use: {self.key}")
|
||||||
|
|
||||||
# Initialize temp base path
|
# Initialize temp base path
|
||||||
self.base_path = os.path.join(str(self.output_filename).replace(".mp4", ""))
|
self.base_path = os.path.join(str(self.output_filename).replace(".mp4", ""))
|
||||||
self.video_segments_path = os.path.join(self.base_path, "tmp", "video")
|
self.video_segments_path = os.path.join(self.base_path, "tmp", "video")
|
||||||
self.audio_segments_path = os.path.join(self.base_path, "tmp", "audio")
|
self.audio_segments_path = os.path.join(self.base_path, "tmp", "audio")
|
||||||
self.subtitle_segments_path = os.path.join(self.base_path, "tmp", "subtitle")
|
self.subtitle_segments_path = os.path.join(self.base_path, "tmp", "subtitle")
|
||||||
|
logging.info(f"Output base path: {self.base_path}")
|
||||||
|
|
||||||
# Create temp folder
|
# Create temp folder
|
||||||
logging.info("Create temp folder")
|
|
||||||
os.makedirs(self.video_segments_path, exist_ok=True)
|
os.makedirs(self.video_segments_path, exist_ok=True)
|
||||||
os.makedirs(self.audio_segments_path, exist_ok=True)
|
os.makedirs(self.audio_segments_path, exist_ok=True)
|
||||||
os.makedirs(self.subtitle_segments_path, exist_ok=True)
|
os.makedirs(self.subtitle_segments_path, exist_ok=True)
|
||||||
@ -488,14 +487,10 @@ class Downloader():
|
|||||||
self.downloaded_audio = []
|
self.downloaded_audio = []
|
||||||
self.downloaded_subtitle = []
|
self.downloaded_subtitle = []
|
||||||
self.downloaded_video = []
|
self.downloaded_video = []
|
||||||
|
|
||||||
# Default decoding
|
|
||||||
self.video_decoding = "avc1.640028"
|
|
||||||
self.audio_decoding = "mp4a.40.2"
|
|
||||||
|
|
||||||
def __df_make_req__(self, url: str) -> str:
|
def __df_make_req__(self, url: str) -> str:
|
||||||
"""
|
"""
|
||||||
Make a request to get text from the provided URL.
|
Make a request to get text from the provided URL to test if index or m3u8 work correcly.
|
||||||
|
|
||||||
Parameters:
|
Parameters:
|
||||||
- url (str): The URL to make the request to.
|
- url (str): The URL to make the request to.
|
||||||
@ -503,23 +498,30 @@ class Downloader():
|
|||||||
Returns:
|
Returns:
|
||||||
- str: The text content of the response.
|
- str: The text content of the response.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
||||||
# Send a GET request to the provided URL
|
# Send a GET request to the provided URL
|
||||||
config_headers.get('index')['user-agent'] = get_headers()
|
config_headers.get('index')['user-agent'] = get_headers()
|
||||||
response = requests.get(url, headers=config_headers.get('index'))
|
response = requests.get(url, headers=config_headers.get('index'))
|
||||||
|
|
||||||
|
# Check status response of request
|
||||||
|
logging.info(f"Test url: {url}")
|
||||||
|
response.raise_for_status()
|
||||||
|
|
||||||
if response.ok:
|
if response.ok:
|
||||||
return response.text
|
return response.text
|
||||||
|
|
||||||
else:
|
else:
|
||||||
logging.error(f"[df_make_req] Request to {url} failed with status code: {response.status_code}")
|
logging.error(f"Request to {url} failed with status code: {response.status_code}")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
except requests.RequestException as req_err:
|
except requests.RequestException as req_err:
|
||||||
logging.error(f"[df_make_req] Error occurred during request: {req_err}")
|
logging.error(f"Error occurred during request: {req_err}")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.error(f"[df_make_req] An unexpected error occurred: {e}")
|
logging.error(f"An unexpected error occurred: {e}")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def manage_playlist(self, m3u8_playlist_text):
|
def manage_playlist(self, m3u8_playlist_text):
|
||||||
@ -530,7 +532,7 @@ class Downloader():
|
|||||||
m3u8_playlist_text (str): The text content of the M3U8 playlist.
|
m3u8_playlist_text (str): The text content of the M3U8 playlist.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
global Download_audio, Donwload_subtitles
|
global DOWNLOAD_AUDIO, DOWNLOAD_SUBTITLES
|
||||||
|
|
||||||
# Create an instance of the M3U8_Parser class
|
# Create an instance of the M3U8_Parser class
|
||||||
parse_class_m3u8 = M3U8_Parser(DOWNLOAD_SPECIFIC_SUBTITLE)
|
parse_class_m3u8 = M3U8_Parser(DOWNLOAD_SPECIFIC_SUBTITLE)
|
||||||
@ -547,7 +549,7 @@ class Downloader():
|
|||||||
console.log(f"[cyan]Find audios language: [red]{[obj_audio.get('language') for obj_audio in self.list_available_audio]}")
|
console.log(f"[cyan]Find audios language: [red]{[obj_audio.get('language') for obj_audio in self.list_available_audio]}")
|
||||||
else:
|
else:
|
||||||
console.log("[red]Cant find a list of audios")
|
console.log("[red]Cant find a list of audios")
|
||||||
Download_audio = False
|
DOWNLOAD_AUDIO = False
|
||||||
|
|
||||||
# Collect available subtitles and default subtitle
|
# Collect available subtitles and default subtitle
|
||||||
self.list_available_subtitles = parse_class_m3u8.get_subtitles()
|
self.list_available_subtitles = parse_class_m3u8.get_subtitles()
|
||||||
@ -558,7 +560,7 @@ class Downloader():
|
|||||||
console.log(f"[cyan]Find subtitles language: [red]{[obj_sub.get('language') for obj_sub in self.list_available_subtitles]}")
|
console.log(f"[cyan]Find subtitles language: [red]{[obj_sub.get('language') for obj_sub in self.list_available_subtitles]}")
|
||||||
else:
|
else:
|
||||||
console.log("[red]Cant find a list of audios")
|
console.log("[red]Cant find a list of audios")
|
||||||
Donwload_subtitles = False
|
DOWNLOAD_SUBTITLES = False
|
||||||
|
|
||||||
# Collect best quality video
|
# Collect best quality video
|
||||||
m3u8_index_obj = parse_class_m3u8.get_best_quality()
|
m3u8_index_obj = parse_class_m3u8.get_best_quality()
|
||||||
@ -566,7 +568,6 @@ class Downloader():
|
|||||||
# Get URI of the best quality and codecs parameters
|
# Get URI of the best quality and codecs parameters
|
||||||
console.log(f"[cyan]Select resolution: [red]{m3u8_index_obj.get('width')}")
|
console.log(f"[cyan]Select resolution: [red]{m3u8_index_obj.get('width')}")
|
||||||
m3u8_index = m3u8_index_obj.get('uri')
|
m3u8_index = m3u8_index_obj.get('uri')
|
||||||
m3u8_index_decoding = m3u8_index_obj.get('codecs')
|
|
||||||
|
|
||||||
# Fix URL if it is not complete with http:\\site_name.domain\...
|
# Fix URL if it is not complete with http:\\site_name.domain\...
|
||||||
if "http" not in m3u8_index:
|
if "http" not in m3u8_index:
|
||||||
@ -581,13 +582,12 @@ class Downloader():
|
|||||||
logging.warning("[download_m3u8] Can't find a valid m3u8 index")
|
logging.warning("[download_m3u8] Can't find a valid m3u8 index")
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
||||||
# Collect best index, video decoding, and audio decoding
|
# Set m3u8_index
|
||||||
self.m3u8_index = m3u8_index
|
self.m3u8_index = m3u8_index
|
||||||
|
|
||||||
# if is present in playlist
|
# Get obj codec
|
||||||
if m3u8_index_decoding != None:
|
self.codec: M3U8_Codec = parse_class_m3u8.codec
|
||||||
self.video_decoding = m3u8_index_decoding.split(",")[0]
|
logging.info(f"Get coded: {self.codec}")
|
||||||
self.audio_decoding = m3u8_index_decoding.split(",")[1]
|
|
||||||
|
|
||||||
def manage_subtitle(self):
|
def manage_subtitle(self):
|
||||||
"""
|
"""
|
||||||
@ -622,8 +622,8 @@ class Downloader():
|
|||||||
'path': os.path.abspath(sub_full_path)
|
'path': os.path.abspath(sub_full_path)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
# If the subtitle file doesn't exist, download it
|
# If the subtitle file doesn't exist, download it
|
||||||
|
logging.info(f"Download uri subtitles: {obj_subtitle.get('uri')} => {sub_full_path}")
|
||||||
response = requests.get(obj_subtitle.get('uri'))
|
response = requests.get(obj_subtitle.get('uri'))
|
||||||
open(sub_full_path, "wb").write(response.content)
|
open(sub_full_path, "wb").write(response.content)
|
||||||
|
|
||||||
@ -658,6 +658,7 @@ class Downloader():
|
|||||||
if not os.path.exists(full_path_audio):
|
if not os.path.exists(full_path_audio):
|
||||||
|
|
||||||
# If the audio segment directory doesn't exist, download audio segments
|
# If the audio segment directory doesn't exist, download audio segments
|
||||||
|
logging.info(f"Download uri audio: {obj_audio.get('uri')} => {full_path_audio}")
|
||||||
audio_m3u8 = M3U8_Segments(obj_audio.get('uri'), full_path_audio, self.key)
|
audio_m3u8 = M3U8_Segments(obj_audio.get('uri'), full_path_audio, self.key)
|
||||||
console.log(f"[purple]Download audio segments [white]=> [red]{obj_audio.get('language')}.")
|
console.log(f"[purple]Download audio segments [white]=> [red]{obj_audio.get('language')}.")
|
||||||
|
|
||||||
@ -716,7 +717,6 @@ class Downloader():
|
|||||||
ts_files = [f for f in os.listdir(full_path) if f.endswith(".ts")]
|
ts_files = [f for f in os.listdir(full_path) if f.endswith(".ts")]
|
||||||
ts_files.sort(key=Downloader.extract_number)
|
ts_files.sort(key=Downloader.extract_number)
|
||||||
logging.info(f"Find {len(ts_files)} stream files to join")
|
logging.info(f"Find {len(ts_files)} stream files to join")
|
||||||
logging.info(f"Using parameter: \n-c:v = {self.video_decoding} -c:a = {self.audio_decoding}])")
|
|
||||||
|
|
||||||
# Check if there are enough .ts files to join (at least 10)
|
# Check if there are enough .ts files to join (at least 10)
|
||||||
if len(ts_files) < 10:
|
if len(ts_files) < 10:
|
||||||
@ -735,8 +735,9 @@ class Downloader():
|
|||||||
return concatenate_and_save(
|
return concatenate_and_save(
|
||||||
file_list_path=file_list_path,
|
file_list_path=file_list_path,
|
||||||
output_filename=out_file_name,
|
output_filename=out_file_name,
|
||||||
video_decoding=self.video_decoding,
|
v_codec=self.codec.video_codec,
|
||||||
audio_decoding=self.audio_decoding
|
a_codec=self.codec.audio_codec,
|
||||||
|
bandwidth=self.codec.bandwidth
|
||||||
)
|
)
|
||||||
|
|
||||||
def download_audios(self):
|
def download_audios(self):
|
||||||
@ -903,12 +904,12 @@ class Downloader():
|
|||||||
self.manage_playlist(m3u8_playlist_text)
|
self.manage_playlist(m3u8_playlist_text)
|
||||||
|
|
||||||
# Download subtitles
|
# Download subtitles
|
||||||
if Donwload_subtitles:
|
if DOWNLOAD_SUBTITLES:
|
||||||
logging.info("Download subtitles ...")
|
logging.info("Download subtitles ...")
|
||||||
self.manage_subtitle()
|
self.manage_subtitle()
|
||||||
|
|
||||||
# Download segmenets of audio tracks
|
# Download segmenets of audio tracks
|
||||||
if Download_audio:
|
if DOWNLOAD_AUDIO:
|
||||||
logging.info("Download audios ...")
|
logging.info("Download audios ...")
|
||||||
self.manage_audio()
|
self.manage_audio()
|
||||||
|
|
||||||
|
@ -13,5 +13,5 @@ from .helper import (
|
|||||||
from .decryption import M3U8_Decryption
|
from .decryption import M3U8_Decryption
|
||||||
from .installer import check_ffmpeg
|
from .installer import check_ffmpeg
|
||||||
from .math_calc import M3U8_Ts_Files
|
from .math_calc import M3U8_Ts_Files
|
||||||
from .parser import M3U8_Parser
|
from .parser import M3U8_Parser, M3U8_Codec
|
||||||
from .url_fix import M3U8_UrlFix
|
from .url_fix import M3U8_UrlFix
|
@ -5,6 +5,7 @@ import os
|
|||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
import shutil
|
import shutil
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
# External libraries
|
# External libraries
|
||||||
@ -182,17 +183,19 @@ def add_subtitle(input_video_path: str, input_subtitle_path: str, output_video_p
|
|||||||
return output_video_path
|
return output_video_path
|
||||||
|
|
||||||
|
|
||||||
def concatenate_and_save(file_list_path: str, output_filename: str, video_decoding: str = None, audio_decoding: str = None, prefix: str = "segments", output_directory: str = None) -> str:
|
def concatenate_and_save(file_list_path: str, output_filename: str, v_codec: str = None, a_codec: str = None, bandwidth: int = None, prefix: str = "segments", output_directory: str = None) -> str:
|
||||||
"""
|
"""
|
||||||
Concatenate input files and save the output with specified decoding parameters.
|
Concatenate input files and save the output with specified decoding parameters.
|
||||||
|
|
||||||
Parameters:
|
Parameters:
|
||||||
- file_list_path (str): Path to the file list containing the segments.
|
- file_list_path (str): Path to the file list containing the segments.
|
||||||
- output_filename (str): Output filename for the concatenated video.
|
- output_filename (str): Output filename for the concatenated video.
|
||||||
- video_decoding (str): Video decoding parameter (optional).
|
- v_codec (str): Video decoding parameter (optional).
|
||||||
- audio_decoding (str): Audio decoding parameter (optional).
|
- a_codec (str): Audio decoding parameter (optional).
|
||||||
|
- bandwidth (int): Bitrate for the output video (optional).
|
||||||
- prefix (str): Prefix to add at the end of output file name (default is "segments").
|
- prefix (str): Prefix to add at the end of output file name (default is "segments").
|
||||||
- output_directory (str): Directory to save the output file. If not provided, defaults to the current directory.
|
- output_directory (str): Directory to save the output file. If not provided, defaults to the current directory.
|
||||||
|
- codecs (str): Codecs for video and audio (optional).
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
- output_file_path (str): Path to the saved output file.
|
- output_file_path (str): Path to the saved output file.
|
||||||
@ -208,9 +211,17 @@ def concatenate_and_save(file_list_path: str, output_filename: str, video_decodi
|
|||||||
output_args = {
|
output_args = {
|
||||||
'c': 'copy',
|
'c': 'copy',
|
||||||
'loglevel': DEBUG_FFMPEG,
|
'loglevel': DEBUG_FFMPEG,
|
||||||
'y': None
|
'y': None,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Add BANDWIDTH and CODECS if provided
|
||||||
|
if bandwidth is not None:
|
||||||
|
output_args['b:v'] = str(bandwidth)
|
||||||
|
"""if v_codec is not None:
|
||||||
|
output_args['vcodec'] = v_codec
|
||||||
|
if a_codec is not None:
|
||||||
|
output_args['acodec'] = a_codec"""
|
||||||
|
|
||||||
# Set up the output file name by modifying the video file name
|
# Set up the output file name by modifying the video file name
|
||||||
output_file_name = os.path.splitext(output_filename)[0] + f"_{prefix}.mp4"
|
output_file_name = os.path.splitext(output_filename)[0] + f"_{prefix}.mp4"
|
||||||
|
|
||||||
|
@ -12,6 +12,58 @@ import requests
|
|||||||
from m3u8 import M3U8
|
from m3u8 import M3U8
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class M3U8_Codec():
|
||||||
|
"""
|
||||||
|
Represents codec information for an M3U8 playlist.
|
||||||
|
|
||||||
|
Attributes:
|
||||||
|
- bandwidth (int): Bandwidth of the codec.
|
||||||
|
- resolution (str): Resolution of the codec.
|
||||||
|
- codecs (str): Codecs information in the format "avc1.xxxxxx,mp4a.xx".
|
||||||
|
- audio_codec (str): Audio codec extracted from the codecs information.
|
||||||
|
- video_codec (str): Video codec extracted from the codecs information.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, bandwidth, resolution, codecs):
|
||||||
|
"""
|
||||||
|
Initializes the M3U8Codec object with the provided parameters.
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
- bandwidth (int): Bandwidth of the codec.
|
||||||
|
- resolution (str): Resolution of the codec.
|
||||||
|
- codecs (str): Codecs information in the format "avc1.xxxxxx,mp4a.xx".
|
||||||
|
"""
|
||||||
|
self.bandwidth = bandwidth
|
||||||
|
self.resolution = resolution
|
||||||
|
self.codecs = codecs
|
||||||
|
self.audio_codec = None
|
||||||
|
self.video_codec = None
|
||||||
|
self.parse_codecs()
|
||||||
|
|
||||||
|
def parse_codecs(self):
|
||||||
|
"""
|
||||||
|
Parses the codecs information to extract audio and video codecs.
|
||||||
|
|
||||||
|
Extracted codecs are set as attributes: audio_codec and video_codec.
|
||||||
|
"""
|
||||||
|
# Split the codecs string by comma
|
||||||
|
codecs_list = self.codecs.split(',')
|
||||||
|
|
||||||
|
# Separate audio and video codecs
|
||||||
|
for codec in codecs_list:
|
||||||
|
if codec.startswith('avc'):
|
||||||
|
self.video_codec = codec
|
||||||
|
elif codec.startswith('mp4a'):
|
||||||
|
self.audio_codec = codec
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
"""
|
||||||
|
Returns a string representation of the M3U8Codec object.
|
||||||
|
"""
|
||||||
|
return f"BANDWIDTH={self.bandwidth},RESOLUTION={self.resolution},CODECS=\"{self.codecs}\""
|
||||||
|
|
||||||
|
|
||||||
class M3U8_Parser:
|
class M3U8_Parser:
|
||||||
def __init__(self, DOWNLOAD_SPECIFIC_SUBTITLE = None):
|
def __init__(self, DOWNLOAD_SPECIFIC_SUBTITLE = None):
|
||||||
"""
|
"""
|
||||||
@ -24,6 +76,7 @@ class M3U8_Parser:
|
|||||||
self.subtitle_playlist = [] # No vvt ma url a vvt
|
self.subtitle_playlist = [] # No vvt ma url a vvt
|
||||||
self.subtitle = [] # Url a vvt
|
self.subtitle = [] # Url a vvt
|
||||||
self.audio_ts = []
|
self.audio_ts = []
|
||||||
|
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):
|
||||||
@ -41,11 +94,19 @@ class M3U8_Parser:
|
|||||||
|
|
||||||
# Collect video info with url, resolution and codecs
|
# Collect video info with url, resolution and codecs
|
||||||
for playlist in m3u8_obj.playlists:
|
for playlist in m3u8_obj.playlists:
|
||||||
|
|
||||||
self.video_playlist.append({
|
self.video_playlist.append({
|
||||||
"uri": playlist.uri,
|
"uri": playlist.uri,
|
||||||
"width": playlist.stream_info.resolution,
|
"width": playlist.stream_info.resolution,
|
||||||
"codecs": playlist.stream_info.codecs
|
})
|
||||||
})
|
|
||||||
|
self.codec = M3U8_Codec(
|
||||||
|
playlist.stream_info.bandwidth,
|
||||||
|
playlist.stream_info.resolution,
|
||||||
|
playlist.stream_info.codecs
|
||||||
|
)
|
||||||
|
logging.info(f"Parse: {playlist.stream_info}")
|
||||||
|
logging.info(f"Coded test: {self.codec.bandwidth}")
|
||||||
|
|
||||||
# Collect info of encryption if present, method, uri and iv
|
# Collect info of encryption if present, method, uri and iv
|
||||||
for key in m3u8_obj.keys:
|
for key in m3u8_obj.keys:
|
||||||
@ -92,7 +153,7 @@ class M3U8_Parser:
|
|||||||
self.subtitle.append(segment.uri)
|
self.subtitle.append(segment.uri)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.error(f"[M3U8_Parser] Error parsing M3U8 content: {e}")
|
logging.error(f"Error parsing M3U8 content: {e}")
|
||||||
|
|
||||||
def get_resolution(self, uri: str) -> (int):
|
def get_resolution(self, uri: str) -> (int):
|
||||||
"""
|
"""
|
||||||
@ -134,8 +195,8 @@ class M3U8_Parser:
|
|||||||
return sorted_uris[0]
|
return sorted_uris[0]
|
||||||
|
|
||||||
except:
|
except:
|
||||||
logging.error("[M3U8_Parser] Error: Can't find M3U8 resolution by width...")
|
logging.error("Error: Can't find M3U8 resolution by width...")
|
||||||
logging.info("[M3U8_Parser] Try searching in URI")
|
logging.info("Try searching in URI")
|
||||||
|
|
||||||
# Sort the list of video playlist items based on the 'width' attribute if present,
|
# Sort the list of video playlist items based on the 'width' attribute if present,
|
||||||
# otherwise, use the resolution obtained from the 'uri' attribute as a fallback.
|
# otherwise, use the resolution obtained from the 'uri' attribute as a fallback.
|
||||||
@ -146,7 +207,7 @@ class M3U8_Parser:
|
|||||||
return sorted_uris[0]
|
return sorted_uris[0]
|
||||||
else:
|
else:
|
||||||
|
|
||||||
logging.info("[M3U8_Parser] No video playlists found.")
|
logging.info("No video playlists found.")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def get_subtitles(self):
|
def get_subtitles(self):
|
||||||
@ -168,7 +229,7 @@ class M3U8_Parser:
|
|||||||
|
|
||||||
# Get language name
|
# Get language name
|
||||||
name_language = sub_info.get("language")
|
name_language = sub_info.get("language")
|
||||||
logging.info(f"[M3U8_Parser] Find subtitle: {name_language}")
|
logging.info(f"Find subtitle: {name_language}")
|
||||||
|
|
||||||
# Check if there is custom subtitles to download
|
# Check if there is custom subtitles to download
|
||||||
if len(self.DOWNLOAD_SPECIFIC_SUBTITLE) > 0:
|
if len(self.DOWNLOAD_SPECIFIC_SUBTITLE) > 0:
|
||||||
@ -178,7 +239,7 @@ class M3U8_Parser:
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
# Make request to m3u8 subtitle to extract vtt
|
# Make request to m3u8 subtitle to extract vtt
|
||||||
logging.info(f"[M3U8_Parser] Download subtitle: {name_language}")
|
logging.info(f"Download subtitle: {name_language}")
|
||||||
req_sub_content = requests.get(sub_info.get("uri"), headers={'user-agent': get_headers()})
|
req_sub_content = requests.get(sub_info.get("uri"), headers={'user-agent': get_headers()})
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -196,13 +257,13 @@ class M3U8_Parser:
|
|||||||
})
|
})
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.error(f"[M3U8_Parser] Cant donwload: {name_language}, error: {e}")
|
logging.error(f"Cant donwload: {name_language}, error: {e}")
|
||||||
|
|
||||||
# Return
|
# Return
|
||||||
return output
|
return output
|
||||||
|
|
||||||
else:
|
else:
|
||||||
logging.info("[M3U8_Parser] No subtitle find")
|
logging.info("No subtitle find")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def get_track_audios(self) -> list:
|
def get_track_audios(self) -> list:
|
||||||
@ -213,10 +274,10 @@ class M3U8_Parser:
|
|||||||
list: A list of dictionaries containing language and URI information for audio tracks, or None if no audio tracks are found.
|
list: A list of dictionaries containing language and URI information for audio tracks, or None if no audio tracks are found.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
logging.info(f"[M3U8_Parser] Finding {len(self.audio_ts)} playlist(s) with audio.")
|
logging.info(f"Finding {len(self.audio_ts)} playlist(s) with audio.")
|
||||||
|
|
||||||
if self.audio_ts:
|
if self.audio_ts:
|
||||||
logging.info("[M3U8_Parser] Getting list of available audio names")
|
logging.info("Getting list of available audio names")
|
||||||
list_output = []
|
list_output = []
|
||||||
|
|
||||||
# For all languages present in m3u8
|
# For all languages present in m3u8
|
||||||
@ -232,7 +293,7 @@ class M3U8_Parser:
|
|||||||
return list_output
|
return list_output
|
||||||
|
|
||||||
else:
|
else:
|
||||||
logging.info("[M3U8_Parser] No audio tracks found")
|
logging.info("No audio tracks found")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def get_default_subtitle(self):
|
def get_default_subtitle(self):
|
||||||
@ -289,4 +350,5 @@ class M3U8_Parser:
|
|||||||
}
|
}
|
||||||
|
|
||||||
# Return the default audio track dictionary
|
# Return the default audio track dictionary
|
||||||
return dict_default_audio
|
return dict_default_audio
|
||||||
|
|
@ -1,6 +1,6 @@
|
|||||||
# 07.04.24
|
# 07.04.24
|
||||||
|
|
||||||
|
# to do
|
||||||
# run somehwere backup
|
# run somehwere backup
|
||||||
# add config to trace if ffmpeg is install, using config in local or temp
|
# add config to trace if ffmpeg is install, using config in local or temp
|
||||||
|
|
||||||
@ -11,6 +11,7 @@ import logging
|
|||||||
# Winreg only work for windows
|
# Winreg only work for windows
|
||||||
if platform.system() == "Windows":
|
if platform.system() == "Windows":
|
||||||
|
|
||||||
|
# Winreg only work for windows
|
||||||
import winreg
|
import winreg
|
||||||
|
|
||||||
# Define Windows registry key for user environment variables
|
# Define Windows registry key for user environment variables
|
||||||
|
Loading…
x
Reference in New Issue
Block a user