diff --git a/README.md b/README.md index 867bb5f..84804a6 100644 --- a/README.md +++ b/README.md @@ -425,12 +425,25 @@ You can download VLC Media Player from the [official website](https://www.videol ```json { - "force_resolution": -1, + "force_resolution": "1080p", "get_only_link": false } ``` -- `force_resolution`: Force specific resolution (-1 for best available, or specify 1080, 720, 360) +- `force_resolution`: Choose the video resolution for downloading: + * `"Best"`: Highest available resolution + * `"Worst"`: Lowest available resolution + * `"720p"`: Force 720p resolution + * Or specify one of these resolutions: + - 1080p (1920x1080) + - 720p (1280x720) + - 480p (640x480) + - 360p (640x360) + - 320p (480x320) + - 240p (426x240) + - 240p (320x240) + - 144p (256x144) + - `get_only_link`: Return M3U8 playlist/index URL instead of downloading diff --git a/StreamingCommunity/Api/Site/animeunity/film_serie.py b/StreamingCommunity/Api/Site/animeunity/film_serie.py index 5c9eb68..b95f1f0 100644 --- a/StreamingCommunity/Api/Site/animeunity/film_serie.py +++ b/StreamingCommunity/Api/Site/animeunity/film_serie.py @@ -15,7 +15,7 @@ from StreamingCommunity.TelegramHelp.telegram_bot import TelegramSession, get_bo # Logic class from .util.ScrapeSerie import ScrapeSerieAnime -from StreamingCommunity.Api.Template.Util import manage_selection +from StreamingCommunity.Api.Template.Util import manage_selection, dynamic_format_number from StreamingCommunity.Api.Template.Class.SearchType import MediaItem @@ -64,8 +64,7 @@ def download_episode(index_select: int, scrape_serie: ScrapeSerieAnime, video_so video_source.get_embed(obj_episode.id) # Create output path - title_name = f"{obj_episode.number}.mp4" - title_name = f"{scrape_serie.series_name}_EP_{obj_episode.number}.mp4" + title_name = f"{scrape_serie.series_name}_EP_{dynamic_format_number(int(obj_episode.number))}.mp4" if scrape_serie.is_series: mp4_path = os_manager.get_sanitize_path(os.path.join(ANIME_FOLDER, scrape_serie.series_name)) diff --git a/StreamingCommunity/Lib/Downloader/HLS/downloader.py b/StreamingCommunity/Lib/Downloader/HLS/downloader.py index e8cba62..839729c 100644 --- a/StreamingCommunity/Lib/Downloader/HLS/downloader.py +++ b/StreamingCommunity/Lib/Downloader/HLS/downloader.py @@ -43,7 +43,7 @@ DOWNLOAD_SPECIFIC_SUBTITLE = config_manager.get_list('M3U8_DOWNLOAD', 'specific_ MERGE_AUDIO = config_manager.get_bool('M3U8_DOWNLOAD', 'merge_audio') MERGE_SUBTITLE = config_manager.get_bool('M3U8_DOWNLOAD', 'merge_subs') CLEANUP_TMP = config_manager.get_bool('M3U8_DOWNLOAD', 'cleanup_tmp_folder') -FILTER_CUSTOM_REOLUTION = config_manager.get_int('M3U8_PARSER', 'force_resolution') +FILTER_CUSTOM_REOLUTION = config_manager.get('M3U8_PARSER', 'force_resolution') GET_ONLY_LINK = config_manager.get_bool('M3U8_PARSER', 'get_only_link') RETRY_LIMIT = config_manager.get_int('REQUESTS', 'max_retry') MAX_TIMEOUT = config_manager.get_int("REQUESTS", "timeout") @@ -164,10 +164,12 @@ class M3U8Manager: self.sub_streams = [] else: - if FILTER_CUSTOM_REOLUTION != -1: - self.video_url, self.video_res = self.parser._video.get_custom_uri(y_resolution=FILTER_CUSTOM_REOLUTION) - else: + if str(FILTER_CUSTOM_REOLUTION).lower().strip() == "best": self.video_url, self.video_res = self.parser._video.get_best_uri() + elif str(FILTER_CUSTOM_REOLUTION).lower().strip() == "worst": + self.video_url, self.video_res = self.parser._video.get_worst_uri() + elif "p" in str(FILTER_CUSTOM_REOLUTION).lower().strip(): + self.video_url, self.video_res = self.parser._video.get_custom_uri(int(str(FILTER_CUSTOM_REOLUTION).strip().replace("p", ""))) self.audio_streams = [] if ENABLE_AUDIO: @@ -184,17 +186,12 @@ class M3U8Manager: ] def log_selection(self): - if FILTER_CUSTOM_REOLUTION == -1: - set_resolution = "Best" - else: - set_resolution = f"{FILTER_CUSTOM_REOLUTION}p" - tuple_available_resolution = self.parser._video.get_list_resolution() list_available_resolution = [f"{r[0]}x{r[1]}" for r in tuple_available_resolution] console.print( f"[cyan bold]Video →[/cyan bold] [green]Available:[/green] [purple]{', '.join(list_available_resolution)}[/purple] | " - f"[red]Set:[/red] [purple]{set_resolution}[/purple] | " + f"[red]Set:[/red] [purple]{FILTER_CUSTOM_REOLUTION}[/purple] | " f"[yellow]Downloadable:[/yellow] [purple]{self.video_res[0]}x{self.video_res[1]}[/purple]" ) diff --git a/StreamingCommunity/Lib/Downloader/HLS/segments.py b/StreamingCommunity/Lib/Downloader/HLS/segments.py index 35b2dcb..7974438 100644 --- a/StreamingCommunity/Lib/Downloader/HLS/segments.py +++ b/StreamingCommunity/Lib/Downloader/HLS/segments.py @@ -47,6 +47,7 @@ PROXY_START_MAX = config_manager.get_float('REQUESTS', 'proxy_start_max') DEFAULT_VIDEO_WORKERS = config_manager.get_int('M3U8_DOWNLOAD', 'default_video_workser') DEFAULT_AUDIO_WORKERS = config_manager.get_int('M3U8_DOWNLOAD', 'default_audio_workser') MAX_TIMEOOUT = config_manager.get_int("REQUESTS", "timeout") +MAX_INTERRUPT_COUNT = 3 SEGMENT_MAX_TIMEOUT = config_manager.get_int("M3U8_DOWNLOAD", "segment_timeout") @@ -83,6 +84,9 @@ class M3U8_Segments: # Stopping self.interrupt_flag = threading.Event() self.download_interrupted = False + self.interrupt_count = 0 + self.force_stop = False + self.interrupt_lock = threading.Lock() # OTHER INFO self.info_maxRetry = 0 @@ -157,12 +161,24 @@ class M3U8_Segments: Set up a signal handler for graceful interruption. """ def interrupt_handler(signum, frame): - if not self.interrupt_flag.is_set(): - console.print("\n[red]- Stopping download gracefully...") - #self.interrupt_flag.set() IN MODO DA NON TERMINARE SUBITO - self.download_interrupted = True - #self.stop_event.set() IN MODO DA NON TERMINARE SUBITO + with self.interrupt_lock: + self.interrupt_count += 1 + if self.interrupt_count >= MAX_INTERRUPT_COUNT: + self.force_stop = True + + if self.force_stop: + console.print("\n[red]Force stop triggered! Exiting immediately.") + else: + if not self.interrupt_flag.is_set(): + remaining = MAX_INTERRUPT_COUNT - self.interrupt_count + console.print(f"\n[red]- Stopping gracefully... (Ctrl+C {remaining}x to force)") + self.download_interrupted = True + + if remaining == 1: + self.interrupt_flag.set() + + if threading.current_thread() is threading.main_thread(): signal.signal(signal.SIGINT, interrupt_handler) else: @@ -430,8 +446,8 @@ class M3U8_Segments: writer_thread.join(timeout=30) progress_bar.close() - if self.download_interrupted: - console.print("\n[red]Download terminated by user") + #if self.download_interrupted: + # console.print("\n[red]Download terminated by user") if self.info_nFailed > 0: self._display_error_summary() diff --git a/StreamingCommunity/Lib/Downloader/MP4/downloader.py b/StreamingCommunity/Lib/Downloader/MP4/downloader.py index 60a690b..6f64f34 100644 --- a/StreamingCommunity/Lib/Downloader/MP4/downloader.py +++ b/StreamingCommunity/Lib/Downloader/MP4/downloader.py @@ -119,8 +119,8 @@ def MP4_downloader(url: str, path: str, referer: str = None, headers_: dict = No bar_format=f"{Colors.YELLOW}[MP4]{Colors.WHITE}: " f"{Colors.RED}{{percentage:.2f}}% {Colors.MAGENTA}{{bar}} {Colors.WHITE}[ " f"{Colors.YELLOW}{{n_fmt}}{Colors.WHITE} / {Colors.RED}{{total_fmt}} {Colors.WHITE}] " - f"{Colors.YELLOW}{{elapsed}} {Colors.WHITE}< {Colors.CYAN}{{remaining}} {Colors.WHITE}| " - f"{Colors.YELLOW}{{rate_fmt}}{{postfix}} {Colors.WHITE}]", + f"{Colors.YELLOW}{{elapsed}} {Colors.WHITE}< {Colors.CYAN}{{remaining}}{Colors.WHITE}, " + f"{Colors.YELLOW}{{rate_fmt}}{{postfix}} ", unit='iB', unit_scale=True, desc='Downloading', diff --git a/StreamingCommunity/Lib/M3U8/parser.py b/StreamingCommunity/Lib/M3U8/parser.py index d7dd472..07a6db3 100644 --- a/StreamingCommunity/Lib/M3U8/parser.py +++ b/StreamingCommunity/Lib/M3U8/parser.py @@ -39,12 +39,17 @@ CODEC_MAPPINGS = { } RESOLUTIONS = [ - (7680, 4320), - (3840, 2160), - (2560, 1440), - (1920, 1080), - (1280, 720), - (640, 480) + (7680, 4320), # 8K + (3840, 2160), # 4K + (2560, 1440), # 1440p + (1920, 1080), # 1080p + (1280, 720), # 720p + (640, 480), # VGA + (640, 360), # 360p + (480, 320), # HVGA + (426, 240), # 240p + (320, 240), # QVGA + (256, 144), # 144p ] diff --git a/config.json b/config.json index 70a729e..45017d6 100644 --- a/config.json +++ b/config.json @@ -54,7 +54,7 @@ "default_preset": "ultrafast" }, "M3U8_PARSER": { - "force_resolution": -1, + "force_resolution": "Best", "get_only_link": false }, "SITE": {