From bdc252803e35885f276fb1f9112c9b8172bbc113 Mon Sep 17 00:00:00 2001 From: Ghost <62809003+Ghost6446@users.noreply.github.com> Date: Tue, 2 Apr 2024 14:47:32 +0200 Subject: [PATCH] Fix range for options * in series --- README.md | 8 +++---- Src/Api/series.py | 39 ++++++++++++++++++-------------- Src/Lib/FFmpeg/my_m3u8.py | 28 ++++++++++++----------- Src/Lib/FFmpeg/util/__init__.py | 19 +++++++++++++++- Src/Lib/FFmpeg/util/helper.py | 2 +- Src/Lib/FFmpeg/util/math_calc.py | 2 +- Src/Util/os.py | 33 +++++++++++++++++++++------ config.json | 4 ++-- 8 files changed, 89 insertions(+), 46 deletions(-) diff --git a/README.md b/README.md index e82f022..97a0786 100644 --- a/README.md +++ b/README.md @@ -93,8 +93,8 @@ You can change some behaviors by tweaking the configuration file. "M3U8": { "tdqm_workers": 20, "tqdm_progress_timeout": 10, - "minium_ts_files_in_folder": 15, - "donwload_percentage": 1, + "minimum_ts_files_in_folder": 15, + "download_percentage": 1, "requests_timeout": 5, "enable_time_quit": false, "tqdm_show_progress": false, @@ -136,8 +136,8 @@ You can change some behaviors by tweaking the configuration file. | M3U8 | | Contains options specific to M3U8. | | | tdqm_workers | 20 | The number of workers that will cooperate to download .ts files.**A high value may slow down your PC** | 40 | | tqdm_progress_timeout | 10 | The timeout duration for progress display updates in seconds after quit download. | 5 | -| minium_ts_files_in_folder | 15 | The minimum number of .ts files expected in a folder. | 10 | -| donwload_percentage | 1 | The percentage of download completion required to consider the download complete. | 0.95 | +| minimum_ts_files_in_folder | 15 | The minimum number of .ts files expected in a folder. | 10 | +| download_percentage | 1 | The percentage of download completion required to consider the download complete. | 0.95 | | requests_timeout | 5 | The timeout duration for HTTP requests in seconds. | 10 | | enable_time_quit | false | Whether to enable quitting the download after a certain time period. | true | | tqdm_show_progress | false | Whether to show progress during downloads or not.**May slow down your PC** | true | diff --git a/Src/Api/series.py b/Src/Api/series.py index eec18a9..e069b29 100644 --- a/Src/Api/series.py +++ b/Src/Api/series.py @@ -5,6 +5,7 @@ from Src.Util.console import console, msg from Src.Util.config import config_manager from Src.Util.table import TVShowManager from Src.Util.message import start_message +from Src.Util.os import remove_special_characters from Src.Lib.FFmpeg.my_m3u8 import Downloader from .Class import VideoSource @@ -24,6 +25,7 @@ video_source.set_url_base_name(STREAM_SITE_NAME) table_show_manager = TVShowManager() +# --> LOGIC def manage_selection(cmd_insert: str, max_count: int) -> list[int]: """ Manage user selection for seasons to download. @@ -51,7 +53,7 @@ def manage_selection(cmd_insert: str, max_count: int) -> list[int]: elif cmd_insert == "*": list_season_select = list(range(1, max_count+1)) - # Return list of selected seasons + # Return list of selected seasons) return list_season_select def display_episodes_list() -> str: @@ -90,6 +92,8 @@ def display_episodes_list() -> str: return last_command + +# --> DOWNLOAD def donwload_video(tv_name: str, index_season_selected: int, index_episode_selected: int) -> None: """ Download a single episode video. @@ -106,8 +110,8 @@ def donwload_video(tv_name: str, index_season_selected: int, index_episode_selec episode_id = video_source.obj_episode_manager.episodes[index_episode_selected - 1].id # Define filename and path for the downloaded video - mp4_name = f"{index_episode_selected}.mp4" - mp4_path = os.path.join(ROOT_PATH, SERIES_FOLDER, tv_name, f"S{index_season_selected}", f"E{index_episode_selected}") + mp4_name = f"{index_episode_selected}_{remove_special_characters(video_source.obj_episode_manager.episodes[index_episode_selected - 1].name)}.mp4" + mp4_path = os.path.join(ROOT_PATH, SERIES_FOLDER, tv_name, f"S{index_season_selected}") os.makedirs(mp4_path, exist_ok=True) # Get iframe and content for the episode @@ -146,25 +150,26 @@ def donwload_episode(tv_name: str, index_season_selected: int, donwload_all: boo # Download all episodes wihtout ask if donwload_all: - for i_episode in range(0, episodes_count): + for i_episode in range(1, episodes_count+1): donwload_video(tv_name, index_season_selected, i_episode) - # Exit - console.print("\n[red]Done") - sys.exit(0) + console.print(f"\n[red]Download [yellow]season: [red]{index_season_selected}.") - # Display episodes list and manage user selection - last_command = display_episodes_list() - list_episode_select = manage_selection(last_command, episodes_count) + # If not download all episode but a single season + if not donwload_all: - # Download selected episodes - if len(list_episode_select) == 1 and last_command != "*": - donwload_video(tv_name, index_season_selected, list_episode_select[0]) + # Display episodes list and manage user selection + last_command = display_episodes_list() + list_episode_select = manage_selection(last_command, episodes_count) - # Download all other episodes selecter - else: - for i_episode in list_episode_select: - donwload_video(tv_name, index_season_selected, i_episode) + # Download selected episodes + if len(list_episode_select) == 1 and last_command != "*": + donwload_video(tv_name, index_season_selected, list_episode_select[0]) + + # Download all other episodes selecter + else: + for i_episode in list_episode_select: + donwload_video(tv_name, index_season_selected, i_episode) def download_series(tv_id: str, tv_name: str, version: str, domain: str) -> None: """ diff --git a/Src/Lib/FFmpeg/my_m3u8.py b/Src/Lib/FFmpeg/my_m3u8.py index 8289aee..88cfb8f 100644 --- a/Src/Lib/FFmpeg/my_m3u8.py +++ b/Src/Lib/FFmpeg/my_m3u8.py @@ -29,18 +29,20 @@ from Src.Util.os import ( compute_sha1_hash, convert_to_hex ) -from Src.Lib.FFmpeg.util.helper import ( - print_duration_table, - transcode_with_subtitles, - join_audios, - concatenate_and_save -) # Logic class -from .util.math_calc import TSFileSizeCalculator -from .util.url_fix import M3U8_UrlFix -from .util.decryption import M3U8_Decryption -from .util.parser import M3U8_Parser +from .util import ( + print_duration_table, + concatenate_and_save, + join_audios, + transcode_with_subtitles +) +from .util import ( + M3U8_Decryption, + M3U8_Ts_Files, + M3U8_Parser, + M3U8_UrlFix +) # Config Download_audio = config_manager.get_bool('M3U8_OPTIONS', 'download_audio') @@ -49,11 +51,11 @@ DOWNLOAD_SPECIFIC_AUDIO = config_manager.get_list('M3U8_OPTIONS', 'specific_list DOWNLOAD_SPECIFIC_SUBTITLE = config_manager.get_list('M3U8_OPTIONS', 'specific_list_subtitles') TQDM_MAX_WORKER = config_manager.get_int('M3U8', 'tdqm_workers') TQDM_PROGRESS_TIMEOUT = config_manager.get_int('M3U8', 'tqdm_progress_timeout') -COMPLETED_PERCENTAGE = config_manager.get_float('M3U8', 'donwload_percentage') +COMPLETED_PERCENTAGE = config_manager.get_float('M3U8', 'download_percentage') REQUESTS_TIMEOUT = config_manager.get_int('M3U8', 'requests_timeout') ENABLE_TIME_TIMEOUT = config_manager.get_bool('M3U8', 'enable_time_quit') TQDM_SHOW_PROGRESS = config_manager.get_bool('M3U8', 'tqdm_show_progress') -MIN_TS_FILES_IN_FOLDER = config_manager.get_int('M3U8', 'minium_ts_files_in_folder') +MIN_TS_FILES_IN_FOLDER = config_manager.get_int('M3U8', 'minimum_ts_files_in_folder') REMOVE_SEGMENTS_FOLDER = config_manager.get_bool('M3U8', 'cleanup_tmp_folder') # Variable @@ -88,7 +90,7 @@ class M3U8_Segments: # Config self.enable_timer = ENABLE_TIME_TIMEOUT self.progress_timeout = TQDM_PROGRESS_TIMEOUT - self.class_ts_files_size = TSFileSizeCalculator() + self.class_ts_files_size = M3U8_Ts_Files() def parse_data(self, m3u8_content: str) -> None: """ diff --git a/Src/Lib/FFmpeg/util/__init__.py b/Src/Lib/FFmpeg/util/__init__.py index 373a9eb..6419fd4 100644 --- a/Src/Lib/FFmpeg/util/__init__.py +++ b/Src/Lib/FFmpeg/util/__init__.py @@ -1 +1,18 @@ -# TO DO \ No newline at end of file +# 02.04.24 + +from .helper import ( + has_audio_stream, + get_video_duration, + format_duration, + print_duration_table, + compute_sha1_hash, + add_subtitle, + concatenate_and_save, + join_audios, + transcode_with_subtitles +) +from .decryption import M3U8_Decryption +from .installer import check_ffmpeg +from .math_calc import M3U8_Ts_Files +from .parser import M3U8_Parser +from .url_fix import M3U8_UrlFix \ No newline at end of file diff --git a/Src/Lib/FFmpeg/util/helper.py b/Src/Lib/FFmpeg/util/helper.py index 5867ed1..fe1348a 100644 --- a/Src/Lib/FFmpeg/util/helper.py +++ b/Src/Lib/FFmpeg/util/helper.py @@ -386,4 +386,4 @@ def transcode_with_subtitles(video: str, subtitles_list: list[dict[str, str]], o except ffmpeg.Error as ffmpeg_error: print(f"Error: {ffmpeg_error}") - return "" \ No newline at end of file + return "" diff --git a/Src/Lib/FFmpeg/util/math_calc.py b/Src/Lib/FFmpeg/util/math_calc.py index 1254275..bdb4056 100644 --- a/Src/Lib/FFmpeg/util/math_calc.py +++ b/Src/Lib/FFmpeg/util/math_calc.py @@ -2,7 +2,7 @@ from Src.Util.os import format_size -class TSFileSizeCalculator: +class M3U8_Ts_Files: def __init__(self): """ Initialize the TSFileSizeCalculator object. diff --git a/Src/Util/os.py b/Src/Util/os.py index 9442a81..d72a4b9 100644 --- a/Src/Util/os.py +++ b/Src/Util/os.py @@ -7,6 +7,7 @@ import time import json import hashlib import logging +import re def remove_folder(folder_path: str) -> None: """ @@ -39,14 +40,32 @@ def remove_file(file_path: str) -> None: print(f"Error removing file '{file_path}': {e}") #else: # print(f"File '{file_path}' does not exist.") + +def remove_special_characters(filename) -> str: + """ + Removes special characters from a filename to make it suitable for creating a filename in Windows. + + Args: + filename (str): The original filename containing special characters. + + Returns: + str: The cleaned filename without special characters. + """ -def move_file_one_folder_up(file_path): + # Define the regex pattern to match special characters + pattern = r'[^\w\-_\. ]' + + # Replace special characters with an empty string + cleaned_filename = re.sub(pattern, '', filename) + + return cleaned_filename + +def move_file_one_folder_up(file_path) -> None: """ Move a file one folder up from its current location. Args: file_path (str): Path to the file to be moved. - """ # Get the directory of the file @@ -79,7 +98,7 @@ def read_json(path: str): return config -def save_json(json_obj, path: str) -> (None): +def save_json(json_obj, path: str) -> None: """Saves JSON object to the specified file path. Args: @@ -90,7 +109,7 @@ def save_json(json_obj, path: str) -> (None): with open(path, 'w') as file: json.dump(json_obj, file, indent=4) # Adjust the indentation as needed -def clean_json(path: str) -> (None): +def clean_json(path: str) -> None: """Reads JSON data from the file, cleans it, and saves it back. Args: @@ -113,7 +132,7 @@ def clean_json(path: str) -> (None): # Save the modified JSON data back to the file save_json(modified_data, path) -def format_size(size_bytes: float): +def format_size(size_bytes: float) -> str: """ Format the size in bytes into a human-readable format. @@ -135,7 +154,7 @@ def format_size(size_bytes: float): # Round the size to two decimal places and return with the appropriate unit return f"{size_bytes:.2f} {units[unit_index]}" -def compute_sha1_hash(input_string: str) -> (str): +def compute_sha1_hash(input_string: str) -> str: """ Computes the SHA-1 hash of the input string. @@ -151,7 +170,7 @@ def compute_sha1_hash(input_string: str) -> (str): # Return the hashed string return hashed_string -def decode_bytes(bytes_data: bytes, encodings_to_try: list[str] = None) -> (str): +def decode_bytes(bytes_data: bytes, encodings_to_try: list[str] = None) -> str: """ Decode a byte sequence using a list of encodings and return the decoded string. diff --git a/config.json b/config.json index 2385545..b01cc74 100644 --- a/config.json +++ b/config.json @@ -23,8 +23,8 @@ "M3U8": { "tdqm_workers": 20, "tqdm_progress_timeout": 10, - "minium_ts_files_in_folder": 15, - "donwload_percentage": 1, + "minimum_ts_files_in_folder": 15, + "download_percentage": 1, "requests_timeout": 5, "enable_time_quit": false, "tqdm_show_progress": false,