diff --git a/README.md b/README.md index c181d5b..cb6b57d 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,7 @@ Make sure you have the following prerequisites installed on your system: * [python](https://www.python.org/downloads/) > 3.8 * [ffmpeg](https://www.gyan.dev/ffmpeg/builds/) +* [opnessl](https://www.openssl.org) or [pycryptodome](https://pypi.org/project/pycryptodome/) ## Installation diff --git a/Src/Api/Altadefinizione/site.py b/Src/Api/Altadefinizione/site.py index eba4160..02e6ec0 100644 --- a/Src/Api/Altadefinizione/site.py +++ b/Src/Api/Altadefinizione/site.py @@ -7,12 +7,12 @@ import logging # External libraries from bs4 import BeautifulSoup +from unidecode import unidecode # Internal utilities from Src.Util.table import TVShowManager from Src.Lib.Request import requests -from Src.Util.headers import get_headers from Src.Util.console import console from Src.Util._jsonConfig import config_manager @@ -44,7 +44,7 @@ def title_search(title_search: str) -> int: """ # Send request to search for titles - response = requests.get(f"https://{AD_SITE_NAME}.{AD_DOMAIN_NOW}/page/1/?story={title_search.replace(' ', '+')}&do=search&subaction=search&titleonly=3") + response = requests.get(f"https://{AD_SITE_NAME}.{AD_DOMAIN_NOW}/page/1/?story={unidecode(title_search.replace(' ', '+'))}&do=search&subaction=search&titleonly=3") # Create soup and find table soup = BeautifulSoup(response.text, "html.parser") diff --git a/Src/Api/Animeunity/anime.py b/Src/Api/Animeunity/anime.py index 75dcb73..ddb6417 100644 --- a/Src/Api/Animeunity/anime.py +++ b/Src/Api/Animeunity/anime.py @@ -37,7 +37,7 @@ def download_episode(index_select: int): # Get information about the selected episode obj_episode = video_source.get_info_episode(index_select) - start_message(True) + start_message() console.print(f"[yellow]Download: [red]EP_{obj_episode.number} \n") # Get the embed URL for the episode diff --git a/Src/Api/Animeunity/site.py b/Src/Api/Animeunity/site.py index cefbae1..4a90366 100644 --- a/Src/Api/Animeunity/site.py +++ b/Src/Api/Animeunity/site.py @@ -6,6 +6,7 @@ import logging # External libraries from bs4 import BeautifulSoup +from unidecode import unidecode # Internal utilities @@ -160,7 +161,7 @@ def title_search(title: str) -> int: # Prepare JSON data to be sent in the request json_data = { - 'title': title # Use the provided title for the search + 'title': unidecode(title) # Use the provided title for the search } # Send a POST request to the API endpoint for live search diff --git a/Src/Api/Streamingcommunity/site.py b/Src/Api/Streamingcommunity/site.py index b813811..95cf7e3 100644 --- a/Src/Api/Streamingcommunity/site.py +++ b/Src/Api/Streamingcommunity/site.py @@ -9,6 +9,7 @@ from typing import Tuple # External libraries from bs4 import BeautifulSoup +from unidecode import unidecode # Internal utilities @@ -136,7 +137,7 @@ def title_search(title_search: str, domain: str) -> int: """ # Send request to search for titles ( replace à to a and space to "+" ) - response = requests.get(f"https://{SC_SITE_NAME}.{domain}/api/search?q={title_search.replace(' ', '+')}", headers={'user-agent': get_headers()}) + response = requests.get(f"https://{SC_SITE_NAME}.{domain}/api/search?q={unidecode(title_search.replace(' ', '+'))}", headers={'user-agent': get_headers()}) # Add found titles to media search manager for dict_title in response.json()['data']: diff --git a/Src/Lib/FFmpeg/capture.py b/Src/Lib/FFmpeg/capture.py index a591fc6..b347b94 100644 --- a/Src/Lib/FFmpeg/capture.py +++ b/Src/Lib/FFmpeg/capture.py @@ -32,45 +32,59 @@ def capture_output(process: subprocess.Popen, description: str) -> None: # Variable to store the length of the longest progress string max_length = 0 - for line in iter(process.stdout.readline, b''): - logging.info(f"FFMPEG: {line}") + for line in iter(process.stdout.readline, ''): + try: + line = line.strip() + if not line: + continue - # Check if termination is requested - if terminate_flag.is_set(): - break + logging.info(f"FFMPEG line: {line}") - if line is not None and "size=" in str(line).strip(): + # Check if termination is requested + if terminate_flag.is_set(): + break - # Parse the output line to extract relevant information - data = parse_output_line(str(line).strip()) + if "size=" in line: + try: - if 'q' in data: - is_end = (float(data.get('q')) == -1.0) + # Parse the output line to extract relevant information + data = parse_output_line(line) - if not is_end: - byte_size = int(re.findall(r'\d+', data.get('size'))[0]) * 1000 - else: - byte_size = int(re.findall(r'\d+', data.get('Lsize'))[0]) * 1000 - else: - byte_size = int(re.findall(r'\d+', data.get('size'))[0]) * 1000 + if 'q' in data: + is_end = (float(data.get('q', -1.0)) == -1.0) + size_key = 'Lsize' if is_end else 'size' + byte_size = int(re.findall(r'\d+', data.get(size_key, '0'))[0]) * 1000 + else: + byte_size = int(re.findall(r'\d+', data.get('size', '0'))[0]) * 1000 - time_now = datetime.now().strftime('%H:%M:%S') + time_now = datetime.now().strftime('%H:%M:%S') - # Construct the progress string with formatted output information - progress_string = f"[blue][{time_now}][purple] FFmpeg [white][{description}[white]]: [white]([green]'speed': [yellow]{data.get('speed')}[white], [green]'size': [yellow]{format_size(byte_size)}[white])" - max_length = max(max_length, len(progress_string)) + # Construct the progress string with formatted output information + progress_string = (f"[blue][{time_now}][purple] FFmpeg [white][{description}]: " + f"[white]([green]'speed': [yellow]{data.get('speed', 'N/A')}[white], " + f"[green]'size': [yellow]{format_size(byte_size)}[white])") + max_length = max(max_length, len(progress_string)) - # Print the progress string to the console, overwriting the previous line - console.print(progress_string.ljust(max_length), end="\r") + # Print the progress string to the console, overwriting the previous line + console.print(progress_string.ljust(max_length), end="\r") + + except Exception as e: + logging.error(f"Error parsing output line: {line} - {e}") + + except Exception as e: + logging.error(f"Error processing line from subprocess: {e}") except Exception as e: logging.error(f"Error in capture_output: {e}") finally: - terminate_process(process) + try: + terminate_process(process) + except Exception as e: + logging.error(f"Error terminating process: {e}") -def parse_output_line(line: str) -> Tuple[str, str]: +def parse_output_line(line: str) -> dict: """ Function to parse the output line and extract relevant information. @@ -79,22 +93,27 @@ def parse_output_line(line: str) -> Tuple[str, str]: Returns: dict: A dictionary containing parsed information. - Ex. {'speed': '60.0x'} """ - data = {} + try: - # Split the line by whitespace and extract key-value pairs - parts = line.replace(" ", "").replace("= ", "=").split() + data = {} - for part in parts: - key_value = part.split('=') + # Split the line by whitespace and extract key-value pairs + parts = line.replace(" ", "").replace("= ", "=").split() - if len(key_value) == 2: - key = key_value[0] - value = key_value[1] - data[key] = value + for part in parts: + key_value = part.split('=') - return data + if len(key_value) == 2: + key = key_value[0] + value = key_value[1] + data[key] = value + + return data + + except Exception as e: + logging.error(f"Error parsing line: {line} - {e}") + return {} def terminate_process(process): @@ -104,8 +123,11 @@ def terminate_process(process): Args: - process (subprocess.Popen): The subprocess to terminate. """ - if process.poll() is None: # Check if the process is still running - process.kill() + try: + if process.poll() is None: # Check if the process is still running + process.kill() + except Exception as e: + logging.error(f"Failed to terminate process: {e}") def capture_ffmpeg_real_time(ffmpeg_command: list, description: str) -> None: @@ -122,21 +144,28 @@ def capture_ffmpeg_real_time(ffmpeg_command: list, description: str) -> None: # Clear the terminate_flag before starting a new capture terminate_flag.clear() - # Start the ffmpeg process with subprocess.Popen - process = subprocess.Popen(ffmpeg_command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True) - - # Start a thread to capture and print output - output_thread = threading.Thread(target=capture_output, args=(process,description)) - output_thread.start() - try: - # Wait for ffmpeg process to complete - process.wait() - except KeyboardInterrupt: - print("Terminating ffmpeg process...") - except Exception as e: - logging.error(f"Error in ffmpeg process: {e}") - finally: - terminate_flag.set() # Signal the output capture thread to terminate - output_thread.join() # Wait for the output capture thread to complete + # Start the ffmpeg process with subprocess.Popen + process = subprocess.Popen(ffmpeg_command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True) + + # Start a thread to capture and print output + output_thread = threading.Thread(target=capture_output, args=(process, description)) + output_thread.start() + + try: + # Wait for ffmpeg process to complete + process.wait() + + except KeyboardInterrupt: + logging.error("Terminating ffmpeg process...") + + except Exception as e: + logging.error(f"Error in ffmpeg process: {e}") + + finally: + terminate_flag.set() # Signal the output capture thread to terminate + output_thread.join() # Wait for the output capture thread to complete + + except Exception as e: + logging.error(f"Failed to start ffmpeg process: {e}") diff --git a/Src/Lib/FFmpeg/command.py b/Src/Lib/FFmpeg/command.py index fc3819a..d92a744 100644 --- a/Src/Lib/FFmpeg/command.py +++ b/Src/Lib/FFmpeg/command.py @@ -19,6 +19,7 @@ except: pass # Internal utilities from Src.Util._jsonConfig import config_manager from Src.Util.os import check_file_existence +from Src.Util.console import console from .util import has_audio_stream, need_to_force_to_ts, check_ffmpeg_input from .capture import capture_ffmpeg_real_time @@ -284,6 +285,7 @@ def join_video(video_path: str, out_path: str, vcodec: str = None, acodec: str = # Add mpegts to force to detect input file as ts file if need_to_force_to_ts(video_path): + console.log("[red]Force input file to 'mpegts'.") ffmpeg_cmd.extend(['-f', 'mpegts']) vcodec = "libx264" @@ -317,6 +319,7 @@ def join_video(video_path: str, out_path: str, vcodec: str = None, acodec: str = # Check file if CHECK_OUTPUT_CONVERSION: + console.log("[red]Check output ffmpeg") time.sleep(0.5) check_ffmpeg_input(out_path) @@ -369,6 +372,7 @@ def join_audios(video_path: str, audio_tracks: List[Dict[str, str]], out_path: s # Check file if CHECK_OUTPUT_CONVERSION: + console.log("[red]Check output ffmpeg") time.sleep(0.5) check_ffmpeg_input(out_path) @@ -426,5 +430,6 @@ def join_subtitle(video_path: str, subtitles_list: List[Dict[str, str]], out_pat # Check file if CHECK_OUTPUT_CONVERSION: + console.log("[red]Check output ffmpeg") time.sleep(0.5) check_ffmpeg_input(out_path) diff --git a/Src/Lib/Hls/downloader.py b/Src/Lib/Hls/downloader.py index 40b006e..2eb6005 100644 --- a/Src/Lib/Hls/downloader.py +++ b/Src/Lib/Hls/downloader.py @@ -7,6 +7,10 @@ from datetime import datetime from concurrent.futures import ThreadPoolExecutor +# External library +from unidecode import unidecode + + # Internal utilities from Src.Lib.Request.my_requests import requests from Src.Util.headers import get_headers @@ -41,10 +45,6 @@ from .segments import M3U8_Segments from ..E_Table import report_table -# External library -from unidecode import unidecode as transliterate - - # Config DOWNLOAD_SPECIFIC_AUDIO = config_manager.get_list('M3U8_FILTER', 'specific_list_audio') DOWNLOAD_SPECIFIC_SUBTITLE = config_manager.get_list('M3U8_FILTER', 'specific_list_subtitles') @@ -89,7 +89,7 @@ class Downloader(): sys.exit(0) self.output_filename = os.path.join(folder, base_name) - self.output_filename = transliterate(self.output_filename) + self.output_filename = unidecode(self.output_filename) logging.info(f"Output filename: {self.output_filename}") diff --git a/config.json b/config.json index b5eeaa8..8e23ec8 100644 --- a/config.json +++ b/config.json @@ -3,8 +3,8 @@ "debug": false, "log_file": "app.log", "log_to_file": true, - "show_message": false, - "clean_console": false, + "show_message": true, + "clean_console": true, "root_path": "Video", "map_episode_name": "%(tv_name)_S%(season)E%(episode)_%(episode_name)", "create_job_database": false, diff --git a/run.py b/run.py index cfb87aa..c78722c 100644 --- a/run.py +++ b/run.py @@ -18,6 +18,7 @@ from Src.Upload.update import update as git_update from Src.Lib.FFmpeg import check_ffmpeg from Src.Util.logger import Logger + # Internal api from Src.Api.Streamingcommunity import main_film_series as streamingcommunity_film_serie from Src.Api.Animeunity import main_anime as streamingcommunity_anime