This commit is contained in:
Lovi 2024-12-10 11:14:09 +01:00
parent 0bedb1bf05
commit eb95a4e5ac
10 changed files with 85 additions and 60 deletions

View File

@ -120,8 +120,7 @@ class VideoSource:
response.raise_for_status()
except Exception as e:
print("\n")
console.print(Panel("[red bold]Coming soon", title="Notification", title_align="left", border_style="yellow"))
logging.error(f"Failed to get vixcloud contente with error: {e}")
sys.exit(0)
# Parse response with BeautifulSoup to get content

View File

@ -117,16 +117,29 @@ def validate_selection(list_season_select: List[int], seasons_count: int) -> Lis
Returns:
- List[int]: Adjusted list of valid season numbers.
"""
while True:
try:
# Remove any seasons greater than the available seasons
valid_seasons = [season for season in list_season_select if 1 <= season <= seasons_count]
# Remove any seasons greater than the available seasons
valid_seasons = [season for season in list_season_select if 1 <= season <= seasons_count]
# If the list is empty, the input was completely invalid
if not valid_seasons:
logging.error(f"Invalid selection: The selected seasons are outside the available range (1-{seasons_count}). Please try again.")
# If the list is empty, the input was completely invalid
if not valid_seasons:
print()
raise ValueError(f"Invalid selection: The selected seasons are outside the available range (1-{seasons_count}).")
# Re-prompt for valid input
input_seasons = input(f"Enter valid season numbers (1-{seasons_count}): ")
list_season_select = list(map(int, input_seasons.split(',')))
continue # Re-prompt the user if the selection is invalid
return valid_seasons # Return the valid seasons if the input is correct
except ValueError:
logging.error("Error: Please enter valid integers separated by commas.")
return valid_seasons
# Prompt the user for valid input again
input_seasons = input(f"Enter valid season numbers (1-{seasons_count}): ")
list_season_select = list(map(int, input_seasons.split(',')))
# --> for episode
@ -141,13 +154,26 @@ def validate_episode_selection(list_episode_select: List[int], episodes_count: i
Returns:
- List[int]: Adjusted list of valid episode numbers.
"""
while True:
try:
# Remove any episodes greater than the available episodes
valid_episodes = [episode for episode in list_episode_select if 1 <= episode <= episodes_count]
# Remove any episodes greater than the available episodes
valid_episodes = [episode for episode in list_episode_select if 1 <= episode <= episodes_count]
# If the list is empty, the input was completely invalid
if not valid_episodes:
print()
raise ValueError(f"Invalid selection: The selected episodes are outside the available range (1-{episodes_count}).")
# If the list is empty, the input was completely invalid
if not valid_episodes:
logging.error(f"Invalid selection: The selected episodes are outside the available range (1-{episodes_count}). Please try again.")
return valid_episodes
# Re-prompt for valid input
input_episodes = input(f"Enter valid episode numbers (1-{episodes_count}): ")
list_episode_select = list(map(int, input_episodes.split(',')))
continue # Re-prompt the user if the selection is invalid
return valid_episodes
except ValueError:
logging.error("Error: Please enter valid integers separated by commas.")
# Prompt the user for valid input again
input_episodes = input(f"Enter valid episode numbers (1-{episodes_count}): ")
list_episode_select = list(map(int, input_episodes.split(',')))

View File

@ -22,7 +22,6 @@ from StreamingCommunity.Util.os import (
# Logic class
from ...FFmpeg import (
print_duration_table,
get_video_duration_s,
join_video,
join_audios,
join_subtitle
@ -52,6 +51,7 @@ GET_ONLY_LINK = config_manager.get_bool('M3U8_PARSER', 'get_only_link')
max_timeout = config_manager.get_int("REQUESTS", "timeout")
headers_index = config_manager.get_dict('REQUESTS', 'user-agent')
m3u8_url_fixer = M3U8_UrlFix()
list_MissingTs = []
@ -397,7 +397,8 @@ class ContentDownloader:
self.expected_real_time = video_m3u8.expected_real_time
# Download the video streams and print status
video_m3u8.download_streams(f"{Colors.MAGENTA}video", "video")
info_dw = video_m3u8.download_streams(f"{Colors.MAGENTA}video", "video")
list_MissingTs.append(info_dw)
# Print duration information of the downloaded video
#print_duration_table(downloaded_video[0].get('path'))
@ -427,7 +428,8 @@ class ContentDownloader:
audio_m3u8.get_info()
# Download the audio segments and print status
audio_m3u8.download_streams(f"{Colors.MAGENTA}audio {Colors.RED}{obj_audio.get('language')}", "audio")
info_dw = audio_m3u8.download_streams(f"{Colors.MAGENTA}audio {Colors.RED}{obj_audio.get('language')}", f"audio_{obj_audio.get('language')}")
list_MissingTs.append(info_dw)
# Print duration information of the downloaded audio
#print_duration_table(obj_audio.get('path'))
@ -838,40 +840,33 @@ class HLS_Downloader:
# Rename the output file to the desired output filename if it does not already exist
if not os.path.exists(self.output_filename):
missing_ts = False
missing_info = ""
# Rename the converted file to the specified output filename
os.rename(out_path, self.output_filename)
# Get duration information for the output file
end_output_time = print_duration_table(self.output_filename, description=False, return_string=False)
# Calculate file size and duration for reporting
formatted_size = internet_manager.format_file_size(os.path.getsize(self.output_filename))
formatted_duration = print_duration_table(self.output_filename, description=False, return_string=True)
expected_real_seconds = dict_to_seconds(self.content_downloader.expected_real_time)
end_output_seconds = dict_to_seconds(end_output_time)
# Check if the downloaded content is complete based on expected duration
if expected_real_seconds is not None:
missing_ts = not (expected_real_seconds - 3 <= end_output_seconds <= expected_real_seconds + 3)
else:
missing_ts = "Undefined"
# Second check for missing segments
if not missing_ts:
if get_video_duration_s(self.output_filename) < int(expected_real_seconds) - 5:
# Collect info about type missing
for item in list_MissingTs:
if int(item['nFailed']) >= 1:
missing_ts = True
missing_info += f"[red]TS Failed: {item['nFailed']} {item['type']} tracks[/red]\n"
# Prepare the report panel content
print("")
panel_content = (
f"[bold green]Download completed![/bold green]\n"
f"[cyan]File size: [bold red]{formatted_size}[/bold red]\n"
f"[cyan]Duration: [bold]{formatted_duration}[/bold]\n"
f"[cyan]Missing TS: [bold red]{missing_ts}[/bold red]"
f"[cyan]Duration: [bold]{formatted_duration}[/bold]"
)
if missing_ts:
panel_content += f"\n{missing_info}"
# Display the download completion message
console.print(Panel(
panel_content,

View File

@ -35,7 +35,7 @@ from ...M3U8 import (
M3U8_Parser,
M3U8_UrlFix
)
from ...FFmpeg.util import print_duration_table
from ...FFmpeg.util import print_duration_table, format_duration
from .proxyes import main_test_proxy
# Config
@ -98,6 +98,7 @@ class M3U8_Segments:
# OTHER INFO
self.info_maxRetry = 0
self.info_nRetry = 0
self.info_nFailed = 0
def __get_key__(self, m3u8_parser: M3U8_Parser) -> bytes:
"""
@ -133,6 +134,7 @@ class M3U8_Segments:
hex_content = binascii.hexlify(response.content).decode('utf-8')
byte_content = bytes.fromhex(hex_content)
#console.print(f"[cyan]Find key: [red]{hex_content}")
return byte_content
def parse_data(self, m3u8_content: str) -> None:
@ -332,6 +334,8 @@ class M3U8_Segments:
console.log(f"[red]Final retry failed for segment: {index}")
self.queue.put((index, None)) # Marker for failed segment
progress_bar.update(1)
self.info_nFailed += 1
#break
sleep_time = backoff_factor * (2 ** attempt)
@ -426,10 +430,10 @@ class M3U8_Segments:
AUDIO_WORKERS = DEFAULT_AUDIO_WORKERS
# Differnt workers for audio and video
if "video" == str(type):
if "video" in str(type):
TQDM_MAX_WORKER = VIDEO_WORKERS
if "audio" == str(type):
if "audio" in str(type):
TQDM_MAX_WORKER = AUDIO_WORKERS
console.print(f"[cyan]Video workers[white]: [green]{VIDEO_WORKERS} [white]| [cyan]Audio workers[white]: [green]{AUDIO_WORKERS}")
@ -526,11 +530,6 @@ class M3U8_Segments:
if self.download_interrupted:
console.log("[red] Download was manually stopped.")
# Optional: Delete partial download
if os.path.exists(self.tmp_file_path):
os.remove(self.tmp_file_path)
sys.exit(0)
# Clean up
self.stop_event.set()
writer_thread.join(timeout=30)
@ -549,12 +548,18 @@ class M3U8_Segments:
file_size = os.path.getsize(self.tmp_file_path)
if file_size == 0:
raise Exception("Output file is empty")
console.print(f"[cyan]Max retry per URL[white]: [green]{self.info_maxRetry}[green] [white]| [cyan]Total retry done[white]: [green]{self.info_nRetry}[green] [white]| [cyan]Duration: {print_duration_table(self.tmp_file_path, None, True)} \n")
# Get expected time
ex_hours, ex_minutes, ex_seconds = format_duration(self.expected_real_time_s)
ex_formatted_duration = f"[yellow]{int(ex_hours)}[red]h [yellow]{int(ex_minutes)}[red]m [yellow]{int(ex_seconds)}[red]s"
console.print(f"[cyan]Max retry per URL[white]: [green]{self.info_maxRetry}[green] [white]| [cyan]Total retry done[white]: [green]{self.info_nRetry}[green] [white]| [cyan]Missing TS: [red]{self.info_nFailed} [white]| [cyan]Duration: {print_duration_table(self.tmp_file_path, None, True)} [white]| [cyan]Expected duation: {ex_formatted_duration} \n")
if self.info_nRetry >= len(self.segments) * (1/3.33):
console.print(
"[yellow]⚠ Warning:[/yellow] Too many retries detected! "
"Consider reducing the number of [cyan]workers[/cyan] in the [magenta]config.json[/magenta] file. "
"This will impact [bold]performance[/bold]."
)
)
# Info to return
return {'type': type, 'nFailed': self.info_nFailed}

View File

@ -1,4 +1,4 @@
# 18.04.24
from .command import join_video, join_audios, join_subtitle
from .util import print_duration_table, get_video_duration_s
from .util import print_duration_table, get_video_duration

View File

@ -79,7 +79,7 @@ def get_video_duration(file_path: str) -> float:
return 1
except Exception as e:
logging.error(f"Error get video duration: {e}")
logging.error(f"Get video duration error: {e}")
sys.exit(0)
@ -144,7 +144,6 @@ def print_duration_table(file_path: str, description: str = "Duration", return_s
- str: The formatted duration string if return_string is True.
- dict: A dictionary with keys 'h', 'm', 's' representing hours, minutes, and seconds if return_string is False.
"""
video_duration = get_video_duration(file_path)
if video_duration is not None:

View File

@ -1,5 +1,5 @@
__title__ = 'StreamingCommunity'
__version__ = '1.9.0'
__version__ = '1.9.2'
__author__ = 'Lovi-0'
__description__ = 'A command-line program to download film'
__copyright__ = 'Copyright 2024'

View File

@ -309,9 +309,8 @@ class InternManager():
class OsSummary:
def __init__(self):
ffmpeg_path, ffprobe_path = check_ffmpeg()
self.ffmpeg_path = ffmpeg_path
self.ffprobe_path = ffprobe_path
self.ffmpeg_path = None
self.ffprobe_path = None
def get_executable_version(self, command: list):
"""
@ -454,13 +453,17 @@ class OsSummary:
else:
command = 'which'
# Locate ffmpeg and ffprobe
# Locate ffmpeg and ffprobe from path enviroment
if self.ffmpeg_path != None and "binary" not in self.ffmpeg_path:
self.ffmpeg_path = self.check_ffmpeg_location([command, 'ffmpeg'])
if self.ffprobe_path != None and "binary" not in self.ffprobe_path:
self.ffprobe_path = self.check_ffmpeg_location([command, 'ffprobe'])
# Locate ffmpeg from bin installation
if self.ffmpeg_path is None or self.ffprobe_path is None:
self.ffmpeg_path, self.ffprobe_path = check_ffmpeg()
if self.ffmpeg_path is None or self.ffprobe_path is None:
console.log("[red]Cant locate ffmpeg or ffprobe")
sys.exit(0)
@ -501,7 +504,6 @@ class OsSummary:
logging.info(f"Libraries: {', '.join([self.get_library_version(lib) for lib in optional_libraries])}")
# OTHER
os_manager = OsManager()
internet_manager = InternManager()

View File

@ -16,7 +16,7 @@ from StreamingCommunity.Util.message import start_message
from StreamingCommunity.Util.console import console, msg
from StreamingCommunity.Util._jsonConfig import config_manager
from StreamingCommunity.Upload.update import update as git_update
from StreamingCommunity.Util.os import OsSummary
from StreamingCommunity.Util.os import os_summary
from StreamingCommunity.Lib.TMBD import tmdb
from StreamingCommunity.Util.logger import Logger
@ -108,7 +108,6 @@ def initialize():
start_message()
# Get system info
os_summary = OsSummary()
os_summary.get_system_summary()
# Set terminal size for win 7
@ -133,7 +132,7 @@ def initialize():
print()
tmdb.display_trending_tv_shows()
print()
def main():

View File

@ -11,7 +11,7 @@ with open("requirements.txt", "r", encoding="utf-8-sig") as f:
setup(
name="StreamingCommunity",
version="1.9.1",
version="1.9.2",
long_description=read_readme(),
long_description_content_type="text/markdown",
author="Lovi-0",