mirror of
https://github.com/Arrowar/StreamingCommunity.git
synced 2025-06-06 19:45:24 +00:00
Fix build pyinstaller
This commit is contained in:
parent
077b935b75
commit
c1d3e1f809
61
.github/workflows/build.yml
vendored
61
.github/workflows/build.yml
vendored
@ -82,16 +82,26 @@ jobs:
|
|||||||
shell: pwsh
|
shell: pwsh
|
||||||
run: |
|
run: |
|
||||||
pyinstaller --onefile --hidden-import=pycryptodomex --hidden-import=ua_generator `
|
pyinstaller --onefile --hidden-import=pycryptodomex --hidden-import=ua_generator `
|
||||||
--hidden-import=qbittorrentapi --hidden-import=qbittorrent `
|
--hidden-import=qbittorrentapi --hidden-import=qbittorrent `
|
||||||
--hidden-import=bs4 --hidden-import=httpx --hidden-import=rich --hidden-import=tqdm `
|
--hidden-import=bs4 --hidden-import=httpx --hidden-import=rich --hidden-import=tqdm `
|
||||||
--hidden-import=m3u8 --hidden-import=psutil --hidden-import=unidecode `
|
--hidden-import=m3u8 --hidden-import=psutil --hidden-import=unidecode `
|
||||||
--hidden-import=jsbeautifier --hidden-import=six --hidden-import=pathvalidate `
|
--hidden-import=jsbeautifier --hidden-import=jsbeautifier.core `
|
||||||
--hidden-import=Cryptodome.Cipher --hidden-import=Cryptodome.Cipher.AES `
|
--hidden-import=jsbeautifier.javascript --hidden-import=jsbeautifier.javascript.beautifier `
|
||||||
--hidden-import=Cryptodome.Util --hidden-import=Cryptodome.Util.Padding `
|
--hidden-import=jsbeautifier.unpackers --hidden-import=jsbeautifier.unpackers.packer `
|
||||||
--hidden-import=Cryptodome.Random --hidden-import=Pillow `
|
--hidden-import=jsbeautifier.unpackers.javascriptobfuscator `
|
||||||
--hidden-import=pyTelegramBotAPI --additional-hooks-dir=pyinstaller/hooks `
|
--hidden-import=jsbeautifier.unpackers.myobfuscate `
|
||||||
--add-data "StreamingCommunity;StreamingCommunity" `
|
--hidden-import=jsbeautifier.unpackers.urlencode `
|
||||||
--name=StreamingCommunity_win --icon=".github/media/logo.ico" test_run.py
|
--hidden-import=jsbeautifier.unpackers.meshim `
|
||||||
|
--hidden-import=editorconfig --hidden-import=editorconfig.handlers `
|
||||||
|
--hidden-import=six --hidden-import=pathvalidate `
|
||||||
|
--hidden-import=Cryptodome.Cipher --hidden-import=Cryptodome.Cipher.AES `
|
||||||
|
--hidden-import=Cryptodome.Util --hidden-import=Cryptodome.Util.Padding `
|
||||||
|
--hidden-import=Cryptodome.Random `
|
||||||
|
--hidden-import=telebot `
|
||||||
|
--additional-hooks-dir=pyinstaller/hooks `
|
||||||
|
--add-data "StreamingCommunity;StreamingCommunity" `
|
||||||
|
--name=StreamingCommunity_win --icon=".github/media/logo.ico" test_run.py
|
||||||
|
|
||||||
- name: Build executable with PyInstaller (Linux)
|
- name: Build executable with PyInstaller (Linux)
|
||||||
if: matrix.os == 'ubuntu-latest'
|
if: matrix.os == 'ubuntu-latest'
|
||||||
run: |
|
run: |
|
||||||
@ -99,13 +109,23 @@ jobs:
|
|||||||
--hidden-import=qbittorrentapi --hidden-import=qbittorrent \
|
--hidden-import=qbittorrentapi --hidden-import=qbittorrent \
|
||||||
--hidden-import=bs4 --hidden-import=httpx --hidden-import=rich --hidden-import=tqdm \
|
--hidden-import=bs4 --hidden-import=httpx --hidden-import=rich --hidden-import=tqdm \
|
||||||
--hidden-import=m3u8 --hidden-import=psutil --hidden-import=unidecode \
|
--hidden-import=m3u8 --hidden-import=psutil --hidden-import=unidecode \
|
||||||
--hidden-import=jsbeautifier --hidden-import=six --hidden-import=pathvalidate \
|
--hidden-import=jsbeautifier --hidden-import=jsbeautifier.core \
|
||||||
|
--hidden-import=jsbeautifier.javascript --hidden-import=jsbeautifier.javascript.beautifier \
|
||||||
|
--hidden-import=jsbeautifier.unpackers --hidden-import=jsbeautifier.unpackers.packer \
|
||||||
|
--hidden-import=jsbeautifier.unpackers.javascriptobfuscator \
|
||||||
|
--hidden-import=jsbeautifier.unpackers.myobfuscate \
|
||||||
|
--hidden-import=jsbeautifier.unpackers.urlencode \
|
||||||
|
--hidden-import=jsbeautifier.unpackers.meshim \
|
||||||
|
--hidden-import=editorconfig --hidden-import=editorconfig.handlers \
|
||||||
|
--hidden-import=six --hidden-import=pathvalidate \
|
||||||
--hidden-import=Cryptodome.Cipher --hidden-import=Cryptodome.Cipher.AES \
|
--hidden-import=Cryptodome.Cipher --hidden-import=Cryptodome.Cipher.AES \
|
||||||
--hidden-import=Cryptodome.Util --hidden-import=Cryptodome.Util.Padding \
|
--hidden-import=Cryptodome.Util --hidden-import=Cryptodome.Util.Padding \
|
||||||
--hidden-import=Cryptodome.Random --hidden-import=Pillow \
|
--hidden-import=Cryptodome.Random \
|
||||||
--hidden-import=pyTelegramBotAPI --additional-hooks-dir=pyinstaller/hooks \
|
--hidden-import=telebot \
|
||||||
|
--additional-hooks-dir=pyinstaller/hooks \
|
||||||
--add-data "StreamingCommunity:StreamingCommunity" \
|
--add-data "StreamingCommunity:StreamingCommunity" \
|
||||||
--name=StreamingCommunity_linux test_run.py
|
--name=StreamingCommunity_linux test_run.py
|
||||||
|
|
||||||
- name: Build executable with PyInstaller (macOS)
|
- name: Build executable with PyInstaller (macOS)
|
||||||
if: matrix.os == 'macos-latest'
|
if: matrix.os == 'macos-latest'
|
||||||
run: |
|
run: |
|
||||||
@ -113,11 +133,20 @@ jobs:
|
|||||||
--hidden-import=qbittorrentapi --hidden-import=qbittorrent \
|
--hidden-import=qbittorrentapi --hidden-import=qbittorrent \
|
||||||
--hidden-import=bs4 --hidden-import=httpx --hidden-import=rich --hidden-import=tqdm \
|
--hidden-import=bs4 --hidden-import=httpx --hidden-import=rich --hidden-import=tqdm \
|
||||||
--hidden-import=m3u8 --hidden-import=psutil --hidden-import=unidecode \
|
--hidden-import=m3u8 --hidden-import=psutil --hidden-import=unidecode \
|
||||||
--hidden-import=jsbeautifier --hidden-import=six --hidden-import=pathvalidate \
|
--hidden-import=jsbeautifier --hidden-import=jsbeautifier.core \
|
||||||
|
--hidden-import=jsbeautifier.javascript --hidden-import=jsbeautifier.javascript.beautifier \
|
||||||
|
--hidden-import=jsbeautifier.unpackers --hidden-import=jsbeautifier.unpackers.packer \
|
||||||
|
--hidden-import=jsbeautifier.unpackers.javascriptobfuscator \
|
||||||
|
--hidden-import=jsbeautifier.unpackers.myobfuscate \
|
||||||
|
--hidden-import=jsbeautifier.unpackers.urlencode \
|
||||||
|
--hidden-import=jsbeautifier.unpackers.meshim \
|
||||||
|
--hidden-import=editorconfig --hidden-import=editorconfig.handlers \
|
||||||
|
--hidden-import=six --hidden-import=pathvalidate \
|
||||||
--hidden-import=Cryptodome.Cipher --hidden-import=Cryptodome.Cipher.AES \
|
--hidden-import=Cryptodome.Cipher --hidden-import=Cryptodome.Cipher.AES \
|
||||||
--hidden-import=Cryptodome.Util --hidden-import=Cryptodome.Util.Padding \
|
--hidden-import=Cryptodome.Util --hidden-import=Cryptodome.Util.Padding \
|
||||||
--hidden-import=Cryptodome.Random --hidden-import=Pillow \
|
--hidden-import=Cryptodome.Random \
|
||||||
--hidden-import=pyTelegramBotAPI --additional-hooks-dir=pyinstaller/hooks \
|
--hidden-import=telebot \
|
||||||
|
--additional-hooks-dir=pyinstaller/hooks \
|
||||||
--add-data "StreamingCommunity:StreamingCommunity" \
|
--add-data "StreamingCommunity:StreamingCommunity" \
|
||||||
--name=StreamingCommunity_mac test_run.py
|
--name=StreamingCommunity_mac test_run.py
|
||||||
|
|
||||||
|
@ -46,6 +46,7 @@
|
|||||||
- 🔍 [Parser](#m3u8_parser-settings)
|
- 🔍 [Parser](#m3u8_parser-settings)
|
||||||
- 📝 [Command](#command)
|
- 📝 [Command](#command)
|
||||||
- 💻 [Examples of terminal](#examples-of-terminal-usage)
|
- 💻 [Examples of terminal](#examples-of-terminal-usage)
|
||||||
|
- 🔧 [Manual domain configuration](#update-domains)
|
||||||
- 🐳 [Docker](#docker)
|
- 🐳 [Docker](#docker)
|
||||||
- 📝 [Telegram Usage](#telegram-usage)
|
- 📝 [Telegram Usage](#telegram-usage)
|
||||||
- 🎓 [Tutorial](#tutorials)
|
- 🎓 [Tutorial](#tutorials)
|
||||||
|
@ -130,6 +130,9 @@ class VideoSource:
|
|||||||
logging.info(f"M3U8 URL: {self.m3u8_url}")
|
logging.info(f"M3U8 URL: {self.m3u8_url}")
|
||||||
break
|
break
|
||||||
|
|
||||||
|
else:
|
||||||
|
logging.error("Failed to find M3U8 URL: No match found")
|
||||||
|
|
||||||
return self.m3u8_url
|
return self.m3u8_url
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
@ -119,6 +119,8 @@ class VideoSource:
|
|||||||
|
|
||||||
if match:
|
if match:
|
||||||
return match.group(1)
|
return match.group(1)
|
||||||
|
else:
|
||||||
|
logging.error("Failed to find M3U8 URL: No match found")
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
|
||||||
@ -151,6 +153,8 @@ class VideoSource:
|
|||||||
|
|
||||||
if match:
|
if match:
|
||||||
return match.group(1)
|
return match.group(1)
|
||||||
|
else:
|
||||||
|
logging.error("Failed to find M3U8 URL: No match found")
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
@ -436,6 +436,18 @@ class HLS_Downloader:
|
|||||||
if TELEGRAM_BOT:
|
if TELEGRAM_BOT:
|
||||||
bot.send_message(f"Contenuto già scaricato!", None)
|
bot.send_message(f"Contenuto già scaricato!", None)
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
if GET_ONLY_LINK:
|
||||||
|
console.print(f"URL: {self.m3u8_url}[/bold red]")
|
||||||
|
return {
|
||||||
|
'path': None,
|
||||||
|
'url': self.m3u8_url,
|
||||||
|
'is_master': getattr(self.m3u8_manager, 'is_master', None),
|
||||||
|
'msg': None,
|
||||||
|
'error': error_msg,
|
||||||
|
'stopped': True
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
self.path_manager.setup_directories()
|
self.path_manager.setup_directories()
|
||||||
|
|
||||||
@ -466,9 +478,8 @@ class HLS_Downloader:
|
|||||||
|
|
||||||
final_file = self.merge_manager.merge()
|
final_file = self.merge_manager.merge()
|
||||||
self.path_manager.move_final_file(final_file)
|
self.path_manager.move_final_file(final_file)
|
||||||
self.path_manager.cleanup()
|
|
||||||
|
|
||||||
self._print_summary()
|
self._print_summary()
|
||||||
|
self.path_manager.cleanup()
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'path': self.path_manager.output_path,
|
'path': self.path_manager.output_path,
|
||||||
|
@ -74,6 +74,9 @@ class M3U8_Segments:
|
|||||||
|
|
||||||
# Sync
|
# Sync
|
||||||
self.queue = PriorityQueue()
|
self.queue = PriorityQueue()
|
||||||
|
self.buffer = {}
|
||||||
|
self.expected_index = 0
|
||||||
|
|
||||||
self.stop_event = threading.Event()
|
self.stop_event = threading.Event()
|
||||||
self.downloaded_segments = set()
|
self.downloaded_segments = set()
|
||||||
self.base_timeout = 0.5
|
self.base_timeout = 0.5
|
||||||
@ -94,6 +97,15 @@ class M3U8_Segments:
|
|||||||
self.active_retries_lock = threading.Lock()
|
self.active_retries_lock = threading.Lock()
|
||||||
|
|
||||||
def __get_key__(self, m3u8_parser: M3U8_Parser) -> bytes:
|
def __get_key__(self, m3u8_parser: M3U8_Parser) -> bytes:
|
||||||
|
"""
|
||||||
|
Fetches the encryption key from the M3U8 playlist.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
m3u8_parser (M3U8_Parser): An instance of M3U8_Parser containing parsed M3U8 data.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bytes: The decryption key in byte format.
|
||||||
|
"""
|
||||||
key_uri = urljoin(self.url, m3u8_parser.keys.get('uri'))
|
key_uri = urljoin(self.url, m3u8_parser.keys.get('uri'))
|
||||||
parsed_url = urlparse(key_uri)
|
parsed_url = urlparse(key_uri)
|
||||||
self.key_base_url = f"{parsed_url.scheme}://{parsed_url.netloc}/"
|
self.key_base_url = f"{parsed_url.scheme}://{parsed_url.netloc}/"
|
||||||
@ -110,6 +122,12 @@ class M3U8_Segments:
|
|||||||
raise Exception(f"Failed to fetch key: {e}")
|
raise Exception(f"Failed to fetch key: {e}")
|
||||||
|
|
||||||
def parse_data(self, m3u8_content: str) -> None:
|
def parse_data(self, m3u8_content: str) -> None:
|
||||||
|
"""
|
||||||
|
Parses the M3U8 content and extracts necessary data.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
m3u8_content (str): The raw M3U8 playlist content.
|
||||||
|
"""
|
||||||
m3u8_parser = M3U8_Parser()
|
m3u8_parser = M3U8_Parser()
|
||||||
m3u8_parser.parse_data(uri=self.url, raw_content=m3u8_content)
|
m3u8_parser.parse_data(uri=self.url, raw_content=m3u8_content)
|
||||||
|
|
||||||
@ -131,6 +149,14 @@ class M3U8_Segments:
|
|||||||
self.class_ts_estimator.total_segments = len(self.segments)
|
self.class_ts_estimator.total_segments = len(self.segments)
|
||||||
|
|
||||||
def get_info(self) -> None:
|
def get_info(self) -> None:
|
||||||
|
"""
|
||||||
|
Retrieves M3U8 playlist information from the given URL.
|
||||||
|
|
||||||
|
If the URL is an index URL, this method:
|
||||||
|
- Sends an HTTP GET request to fetch the M3U8 playlist.
|
||||||
|
- Parses the M3U8 content using `parse_data`.
|
||||||
|
- Saves the playlist to a temporary folder.
|
||||||
|
"""
|
||||||
if self.is_index_url:
|
if self.is_index_url:
|
||||||
try:
|
try:
|
||||||
client_params = {'headers': {'User-Agent': get_userAgent()}, 'timeout': MAX_TIMEOOUT}
|
client_params = {'headers': {'User-Agent': get_userAgent()}, 'timeout': MAX_TIMEOOUT}
|
||||||
@ -251,9 +277,6 @@ class M3U8_Segments:
|
|||||||
"""
|
"""
|
||||||
Writes segments to file with additional verification.
|
Writes segments to file with additional verification.
|
||||||
"""
|
"""
|
||||||
buffer = {}
|
|
||||||
expected_index = 0
|
|
||||||
|
|
||||||
with open(self.tmp_file_path, 'wb') as f:
|
with open(self.tmp_file_path, 'wb') as f:
|
||||||
while not self.stop_event.is_set() or not self.queue.empty():
|
while not self.stop_event.is_set() or not self.queue.empty():
|
||||||
if self.interrupt_flag.is_set():
|
if self.interrupt_flag.is_set():
|
||||||
@ -267,28 +290,28 @@ class M3U8_Segments:
|
|||||||
|
|
||||||
# Handle failed segments
|
# Handle failed segments
|
||||||
if segment_content is None:
|
if segment_content is None:
|
||||||
if index == expected_index:
|
if index == self.expected_index:
|
||||||
expected_index += 1
|
self.expected_index += 1
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# Write segment if it's the next expected one
|
# Write segment if it's the next expected one
|
||||||
if index == expected_index:
|
if index == self.expected_index:
|
||||||
f.write(segment_content)
|
f.write(segment_content)
|
||||||
f.flush()
|
f.flush()
|
||||||
expected_index += 1
|
self.expected_index += 1
|
||||||
|
|
||||||
# Write any buffered segments that are now in order
|
# Write any buffered segments that are now in order
|
||||||
while expected_index in buffer:
|
while self.expected_index in self.buffer:
|
||||||
next_segment = buffer.pop(expected_index)
|
next_segment = self.buffer.pop(self.expected_index)
|
||||||
|
|
||||||
if next_segment is not None:
|
if next_segment is not None:
|
||||||
f.write(next_segment)
|
f.write(next_segment)
|
||||||
f.flush()
|
f.flush()
|
||||||
|
|
||||||
expected_index += 1
|
self.expected_index += 1
|
||||||
|
|
||||||
else:
|
else:
|
||||||
buffer[index] = segment_content
|
self.buffer[index] = segment_content
|
||||||
|
|
||||||
except queue.Empty:
|
except queue.Empty:
|
||||||
self.current_timeout = min(MAX_TIMEOOUT, self.current_timeout * 1.1)
|
self.current_timeout = min(MAX_TIMEOOUT, self.current_timeout * 1.1)
|
||||||
@ -440,6 +463,9 @@ class M3U8_Segments:
|
|||||||
if self.info_nFailed > 0:
|
if self.info_nFailed > 0:
|
||||||
self._display_error_summary()
|
self._display_error_summary()
|
||||||
|
|
||||||
|
self.buffer = {}
|
||||||
|
self.expected_index = 0
|
||||||
|
|
||||||
def _display_error_summary(self) -> None:
|
def _display_error_summary(self) -> None:
|
||||||
"""Generate final error report."""
|
"""Generate final error report."""
|
||||||
console.print(f"\n[cyan]Retry Summary: "
|
console.print(f"\n[cyan]Retry Summary: "
|
||||||
|
@ -87,7 +87,8 @@ def MP4_downloader(url: str, path: str, referer: str = None, headers_: dict = No
|
|||||||
return None, False
|
return None, False
|
||||||
|
|
||||||
if GET_ONLY_LINK:
|
if GET_ONLY_LINK:
|
||||||
return {'path': path, 'url': url}
|
console.print(f"URL: {url}[/bold red]")
|
||||||
|
return path, True
|
||||||
|
|
||||||
if not (url.lower().startswith('http://') or url.lower().startswith('https://')):
|
if not (url.lower().startswith('http://') or url.lower().startswith('https://')):
|
||||||
logging.error(f"Invalid URL: {url}")
|
logging.error(f"Invalid URL: {url}")
|
||||||
|
@ -180,7 +180,7 @@ def join_audios(video_path: str, audio_tracks: List[Dict[str, str]], out_path: s
|
|||||||
Each dictionary should contain the 'path' key with the path to the audio file.
|
Each dictionary should contain the 'path' key with the path to the audio file.
|
||||||
- out_path (str): The path to save the output file.
|
- out_path (str): The path to save the output file.
|
||||||
"""
|
"""
|
||||||
video_audio_same_duration = check_duration_v_a(video_path, audio_tracks[0].get('path'))
|
video_audio_same_duration, duration_diff = check_duration_v_a(video_path, audio_tracks[0].get('path'))
|
||||||
|
|
||||||
# Start command with locate ffmpeg
|
# Start command with locate ffmpeg
|
||||||
ffmpeg_cmd = [get_ffmpeg_path()]
|
ffmpeg_cmd = [get_ffmpeg_path()]
|
||||||
@ -242,7 +242,7 @@ def join_audios(video_path: str, audio_tracks: List[Dict[str, str]], out_path: s
|
|||||||
|
|
||||||
# Use shortest input path for video and audios
|
# Use shortest input path for video and audios
|
||||||
if not video_audio_same_duration:
|
if not video_audio_same_duration:
|
||||||
console.log("[red]Use shortest input ...")
|
console.log(f"[red]Use shortest input (Duration difference: {duration_diff:.2f} seconds)...")
|
||||||
ffmpeg_cmd.extend(['-shortest', '-strict', 'experimental'])
|
ffmpeg_cmd.extend(['-shortest', '-strict', 'experimental'])
|
||||||
|
|
||||||
# Overwrite
|
# Overwrite
|
||||||
|
@ -57,7 +57,6 @@ def get_video_duration(file_path: str) -> float:
|
|||||||
Returns:
|
Returns:
|
||||||
(float): The duration of the video in seconds if successful, None if there's an error.
|
(float): The duration of the video in seconds if successful, None if there's an error.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
try:
|
try:
|
||||||
ffprobe_cmd = [get_ffprobe_path(), '-v', 'error', '-show_format', '-print_format', 'json', file_path]
|
ffprobe_cmd = [get_ffprobe_path(), '-v', 'error', '-show_format', '-print_format', 'json', file_path]
|
||||||
logging.info(f"FFmpeg command: {ffprobe_cmd}")
|
logging.info(f"FFmpeg command: {ffprobe_cmd}")
|
||||||
@ -95,7 +94,6 @@ def format_duration(seconds: float) -> Tuple[int, int, int]:
|
|||||||
Returns:
|
Returns:
|
||||||
list[int, int, int]: List containing hours, minutes, and seconds.
|
list[int, int, int]: List containing hours, minutes, and seconds.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
hours, remainder = divmod(seconds, 3600)
|
hours, remainder = divmod(seconds, 3600)
|
||||||
minutes, seconds = divmod(remainder, 60)
|
minutes, seconds = divmod(remainder, 60)
|
||||||
|
|
||||||
@ -157,11 +155,7 @@ def get_ffprobe_info(file_path):
|
|||||||
'codec_names': codec_names
|
'codec_names': codec_names
|
||||||
}
|
}
|
||||||
|
|
||||||
except subprocess.CalledProcessError as e:
|
except Exception as e:
|
||||||
logging.error(f"ffprobe failed for file {file_path}: {e}")
|
|
||||||
return None
|
|
||||||
|
|
||||||
except json.JSONDecodeError as e:
|
|
||||||
logging.error(f"Failed to parse JSON output from ffprobe for file {file_path}: {e}")
|
logging.error(f"Failed to parse JSON output from ffprobe for file {file_path}: {e}")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@ -198,23 +192,25 @@ def need_to_force_to_ts(file_path):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def check_duration_v_a(video_path, audio_path):
|
def check_duration_v_a(video_path, audio_path, tolerance=1.0):
|
||||||
"""
|
"""
|
||||||
Check if the duration of the video and audio matches.
|
Check if the duration of the video and audio matches.
|
||||||
|
|
||||||
Parameters:
|
Parameters:
|
||||||
- video_path (str): Path to the video file.
|
- video_path (str): Path to the video file.
|
||||||
- audio_path (str): Path to the audio file.
|
- audio_path (str): Path to the audio file.
|
||||||
|
- tolerance (float): Allowed tolerance for the duration difference (in seconds).
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
- bool: True if the duration of the video and audio matches, False otherwise.
|
- tuple: (bool, float) -> True if the duration of the video and audio matches, False otherwise, along with the difference in duration.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Ottieni la durata del video
|
|
||||||
video_duration = get_video_duration(video_path)
|
video_duration = get_video_duration(video_path)
|
||||||
|
|
||||||
# Ottieni la durata dell'audio
|
|
||||||
audio_duration = get_video_duration(audio_path)
|
audio_duration = get_video_duration(audio_path)
|
||||||
|
|
||||||
# Verifica se le durate corrispondono
|
duration_difference = abs(video_duration - audio_duration)
|
||||||
return video_duration == audio_duration
|
|
||||||
|
# Check if the duration difference is within the tolerance
|
||||||
|
if duration_difference <= tolerance:
|
||||||
|
return True, duration_difference
|
||||||
|
else:
|
||||||
|
return False, duration_difference
|
@ -52,7 +52,7 @@ class M3U8_Ts_Estimator:
|
|||||||
self.now_downloaded_size += size_download
|
self.now_downloaded_size += size_download
|
||||||
logging.debug(f"Current total downloaded size: {self.now_downloaded_size}")
|
logging.debug(f"Current total downloaded size: {self.now_downloaded_size}")
|
||||||
|
|
||||||
def capture_speed(self, interval: float = 1):
|
def capture_speed(self, interval: float = 1.5):
|
||||||
"""Capture the internet speed periodically."""
|
"""Capture the internet speed periodically."""
|
||||||
last_upload, last_download = 0, 0
|
last_upload, last_download = 0, 0
|
||||||
speed_buffer = deque(maxlen=3)
|
speed_buffer = deque(maxlen=3)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user