diff --git a/Src/Api/Class/Video.py b/Src/Api/Class/Video.py index 74002c5..4eab48a 100644 --- a/Src/Api/Class/Video.py +++ b/Src/Api/Class/Video.py @@ -91,7 +91,7 @@ class VideoSource: # Make a request to collect information about seasons response = requests.get(f"https://{self.base_name}.{self.domain}/titles/{self.media_id}-{self.series_name}", headers=self.headers) - response.raise_for_status() # Raise exception for non-200 status codes + response.raise_for_status() if response.ok: @@ -152,7 +152,7 @@ class VideoSource: # Make a request to get iframe source response = requests.get(f"https://{self.base_name}.{self.domain}/iframe/{self.media_id}", params=params) - response.raise_for_status() # Raise exception for non-200 status codes + response.raise_for_status() if response.ok: @@ -228,9 +228,9 @@ class VideoSource: query = urlencode(list(self.window_parameter.data.items())) base_url = f'https://vixcloud.co/playlist/{self.window_video.id}' - full_url = urljoin(base_url, '?' + query) + #full_url = urljoin(base_url, '?' + query) - return full_url + return base_url except AttributeError as e: logging.error(f"Error getting playlist: {e}") @@ -245,15 +245,9 @@ class VideoSource: """ try: - # Fix title for latin-1 - title = quote(self.window_video.name) - - # Set referer header for the request - self.headers['referer'] = f'https://vixcloud.co/embed/{self.window_video.id}?token={self.window_parameter.token}&title={title}&referer=1&expires={self.window_parameter.expires}&canPlayFHD=1' - # Make a request to get key content response = requests.get('https://vixcloud.co/storage/enc.key', headers=self.headers) - response.raise_for_status() # Raise exception for non-200 status codes + response.raise_for_status() if response.ok: diff --git a/Src/Api/film.py b/Src/Api/film.py index a3ff674..d07e81f 100644 --- a/Src/Api/film.py +++ b/Src/Api/film.py @@ -1,6 +1,7 @@ # 3.12.23 -> 10.12.23 import os +import sys import logging @@ -8,6 +9,7 @@ import logging from Src.Util.console import console from Src.Util.config import config_manager from Src.Lib.FFmpeg.my_m3u8 import Downloader +from Src.Util.file_validation import can_create_file from Src.Util.message import start_message from .Class import VideoSource @@ -49,6 +51,10 @@ def download_film(id_film: str, title_name: str, domain: str): mp4_name = title_name.replace("-", "_") mp4_format = mp4_name + ".mp4" + if not can_create_file(mp4_format): + logging.error("Invalid mp4 name.") + sys.exit(0) + # Download the film using the m3u8 playlist, key, and output filename obj_download = Downloader( m3u8_playlist = video_source.get_playlist(), diff --git a/Src/Api/series.py b/Src/Api/series.py index f23fd47..2b6b1fe 100644 --- a/Src/Api/series.py +++ b/Src/Api/series.py @@ -13,6 +13,7 @@ from Src.Util.table import TVShowManager from Src.Util.message import start_message from Src.Util.os import remove_special_characters from Src.Lib.Unidecode import transliterate +from Src.Util.file_validation import can_create_file from Src.Lib.FFmpeg.my_m3u8 import Downloader from Src.Util.mapper import map_episode_title from .Class import VideoSource @@ -120,6 +121,10 @@ def donwload_video(tv_name: str, index_season_selected: int, index_episode_selec mp4_path = remove_special_characters(os.path.join(ROOT_PATH, SERIES_FOLDER, tv_name, f"S{index_season_selected}")) os.makedirs(mp4_path, exist_ok=True) + if not can_create_file(mp4_name): + logging.error("Invalid mp4 name.") + sys.exit(0) + # Get iframe and content for the episode video_source.get_iframe(episode_id) video_source.get_content() diff --git a/Src/Assets/win_7_install/explorer11.png b/Src/Assets/win_7_install/explorer11.png deleted file mode 100644 index 74cc758..0000000 Binary files a/Src/Assets/win_7_install/explorer11.png and /dev/null differ diff --git a/Src/Assets/win_7_install/internet_option.png b/Src/Assets/win_7_install/internet_option.png deleted file mode 100644 index 5e9b22c..0000000 Binary files a/Src/Assets/win_7_install/internet_option.png and /dev/null differ diff --git a/Src/Lib/Unidecode/x000.py b/Src/Lib/Unidecode/x000.py index 2c288a6..7ab4d76 100644 --- a/Src/Lib/Unidecode/x000.py +++ b/Src/Lib/Unidecode/x000.py @@ -1,15 +1,132 @@ data = ( -# Code points u+007f and below are equivalent to ASCII and are handled by a -# special case in the code. Hence they are not present in this table. -'', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', -'', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', -'', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', -'', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', -'', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', -'', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', -'', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', -'', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', - +'\x00', # 0x00 +'\x01', # 0x01 +'\x02', # 0x02 +'\x03', # 0x03 +'\x04', # 0x04 +'\x05', # 0x05 +'\x06', # 0x06 +'\x07', # 0x07 +'\x08', # 0x08 +'\x09', # 0x09 +'\x0a', # 0x0a +'\x0b', # 0x0b +'\x0c', # 0x0c +'\x0d', # 0x0d +'\x0e', # 0x0e +'\x0f', # 0x0f +'\x10', # 0x10 +'\x11', # 0x11 +'\x12', # 0x12 +'\x13', # 0x13 +'\x14', # 0x14 +'\x15', # 0x15 +'\x16', # 0x16 +'\x17', # 0x17 +'\x18', # 0x18 +'\x19', # 0x19 +'\x1a', # 0x1a +'\x1b', # 0x1b +'\x1c', # 0x1c +'\x1d', # 0x1d +'\x1e', # 0x1e +'\x1f', # 0x1f +' ', # 0x20 +'!', # 0x21 +'"', # 0x22 +'#', # 0x23 +'$', # 0x24 +'%', # 0x25 +'&', # 0x26 +'\'', # 0x27 +'(', # 0x28 +')', # 0x29 +'*', # 0x2a +'+', # 0x2b +',', # 0x2c +'-', # 0x2d +'.', # 0x2e +'/', # 0x2f +'0', # 0x30 +'1', # 0x31 +'2', # 0x32 +'3', # 0x33 +'4', # 0x34 +'5', # 0x35 +'6', # 0x36 +'7', # 0x37 +'8', # 0x38 +'9', # 0x39 +':', # 0x3a +';', # 0x3b +'<', # 0x3c +'=', # 0x3d +'>', # 0x3e +'?', # 0x3f +'@', # 0x40 +'A', # 0x41 +'B', # 0x42 +'C', # 0x43 +'D', # 0x44 +'E', # 0x45 +'F', # 0x46 +'G', # 0x47 +'H', # 0x48 +'I', # 0x49 +'J', # 0x4a +'K', # 0x4b +'L', # 0x4c +'M', # 0x4d +'N', # 0x4e +'O', # 0x4f +'P', # 0x50 +'Q', # 0x51 +'R', # 0x52 +'S', # 0x53 +'T', # 0x54 +'U', # 0x55 +'V', # 0x56 +'W', # 0x57 +'X', # 0x58 +'Y', # 0x59 +'Z', # 0x5a +']', # 0x5b +'\\', # 0x5c +']', # 0x5d +'^', # 0x5e +'_', # 0x5f +'`', # 0x60 +'a', # 0x61 +'b', # 0x62 +'c', # 0x63 +'d', # 0x64 +'e', # 0x65 +'f', # 0x66 +'g', # 0x67 +'h', # 0x68 +'i', # 0x69 +'j', # 0x6a +'k', # 0x6b +'l', # 0x6c +'m', # 0x6d +'n', # 0x6e +'o', # 0x6f +'p', # 0x70 +'q', # 0x71 +'r', # 0x72 +'s', # 0x73 +'t', # 0x74 +'u', # 0x75 +'v', # 0x76 +'w', # 0x77 +'x', # 0x78 +'y', # 0x79 +'z', # 0x7a +'{', # 0x7b +'|', # 0x7c +'}', # 0x7d +'~', # 0x7e +'', # 0x7f '', # 0x80 '', # 0x81 '', # 0x82 @@ -45,10 +162,7 @@ data = ( ' ', # 0xa0 '!', # 0xa1 'C/', # 0xa2 - -# Not "GBP" - Pound Sign is used for more than just British Pounds. 'PS', # 0xa3 - '$?', # 0xa4 'Y=', # 0xa5 '|', # 0xa6 @@ -63,11 +177,8 @@ data = ( '-', # 0xaf 'deg', # 0xb0 '+-', # 0xb1 - -# These might be combined with other superscript digits (u+2070 - u+2079) '2', # 0xb2 '3', # 0xb3 - '\'', # 0xb4 'u', # 0xb5 'P', # 0xb6 @@ -76,18 +187,15 @@ data = ( '1', # 0xb9 'o', # 0xba '>>', # 0xbb -' 1/4', # 0xbc -' 1/2', # 0xbd -' 3/4', # 0xbe +'1/4', # 0xbc +'1/2', # 0xbd +'3/4', # 0xbe '?', # 0xbf 'A', # 0xc0 'A', # 0xc1 'A', # 0xc2 'A', # 0xc3 - -# Not "AE" - used in languages other than German 'A', # 0xc4 - 'A', # 0xc5 'AE', # 0xc6 'C', # 0xc7 @@ -105,30 +213,21 @@ data = ( 'O', # 0xd3 'O', # 0xd4 'O', # 0xd5 - -# Not "OE" - used in languages other than German 'O', # 0xd6 - 'x', # 0xd7 'O', # 0xd8 'U', # 0xd9 'U', # 0xda 'U', # 0xdb - -# Not "UE" - used in languages other than German 'U', # 0xdc - -'Y', # 0xdd +'U', # 0xdd 'Th', # 0xde 'ss', # 0xdf 'a', # 0xe0 'a', # 0xe1 'a', # 0xe2 'a', # 0xe3 - -# Not "ae" - used in languages other than German 'a', # 0xe4 - 'a', # 0xe5 'ae', # 0xe6 'c', # 0xe7 @@ -146,20 +245,14 @@ data = ( 'o', # 0xf3 'o', # 0xf4 'o', # 0xf5 - -# Not "oe" - used in languages other than German 'o', # 0xf6 - '/', # 0xf7 'o', # 0xf8 'u', # 0xf9 'u', # 0xfa 'u', # 0xfb - -# Not "ue" - used in languages other than German 'u', # 0xfc - 'y', # 0xfd 'th', # 0xfe 'y', # 0xff -) +) \ No newline at end of file diff --git a/Src/Lib/Unidecode/x020.py b/Src/Lib/Unidecode/x020.py deleted file mode 100644 index 60ff961..0000000 --- a/Src/Lib/Unidecode/x020.py +++ /dev/null @@ -1,261 +0,0 @@ -data = ( -' ', # 0x00 -' ', # 0x01 -' ', # 0x02 -' ', # 0x03 -' ', # 0x04 -' ', # 0x05 -' ', # 0x06 -' ', # 0x07 -' ', # 0x08 -' ', # 0x09 -' ', # 0x0a -' ', # 0x0b -'', # 0x0c -'', # 0x0d -'', # 0x0e -'', # 0x0f -'-', # 0x10 -'-', # 0x11 -'-', # 0x12 -'-', # 0x13 -'--', # 0x14 -'--', # 0x15 -'||', # 0x16 -'_', # 0x17 -'\'', # 0x18 -'\'', # 0x19 -',', # 0x1a -'\'', # 0x1b -'"', # 0x1c -'"', # 0x1d -',,', # 0x1e -'"', # 0x1f -'+', # 0x20 -'++', # 0x21 -'*', # 0x22 -'*>', # 0x23 -'.', # 0x24 -'..', # 0x25 -'...', # 0x26 -'.', # 0x27 -'\x0a', # 0x28 -'\x0a\x0a', # 0x29 -'', # 0x2a -'', # 0x2b -'', # 0x2c -'', # 0x2d -'', # 0x2e -' ', # 0x2f -'%0', # 0x30 -'%00', # 0x31 -'\'', # 0x32 -'\'\'', # 0x33 -'\'\'\'', # 0x34 -'`', # 0x35 -'``', # 0x36 -'```', # 0x37 -'^', # 0x38 -'<', # 0x39 -'>', # 0x3a -'*', # 0x3b -'!!', # 0x3c -'!?', # 0x3d -'-', # 0x3e -'_', # 0x3f -'-', # 0x40 -'^', # 0x41 -'***', # 0x42 -'--', # 0x43 -'/', # 0x44 -'-[', # 0x45 -']-', # 0x46 -'??', # 0x47 -'?!', # 0x48 -'!?', # 0x49 - -# Tironian note standing for Latin "et". Still used as an ampersand -# in modern Irish. See https://github.com/avian2/unidecode/issues/57 -'&', # 0x4a - -'PP', # 0x4b -'(]', # 0x4c -'[)', # 0x4d -'*', # 0x4e -None, # 0x4f -None, # 0x50 -None, # 0x51 -'%', # 0x52 -'~', # 0x53 -None, # 0x54 -None, # 0x55 -None, # 0x56 -"''''", # 0x57 -None, # 0x58 -None, # 0x59 -None, # 0x5a -None, # 0x5b -None, # 0x5c -None, # 0x5d -None, # 0x5e -' ', # 0x5f -'', # 0x60 -None, # 0x61 -None, # 0x62 -None, # 0x63 -None, # 0x64 -None, # 0x65 -None, # 0x66 -None, # 0x67 -None, # 0x68 -None, # 0x69 -'', # 0x6a -'', # 0x6b -'', # 0x6c -'', # 0x6d -'', # 0x6e -'', # 0x6f -'0', # 0x70 -'i', # 0x71 -'', # 0x72 -'', # 0x73 -'4', # 0x74 -'5', # 0x75 -'6', # 0x76 -'7', # 0x77 -'8', # 0x78 -'9', # 0x79 -'+', # 0x7a -'-', # 0x7b -'=', # 0x7c -'(', # 0x7d -')', # 0x7e -'n', # 0x7f -'0', # 0x80 -'1', # 0x81 -'2', # 0x82 -'3', # 0x83 -'4', # 0x84 -'5', # 0x85 -'6', # 0x86 -'7', # 0x87 -'8', # 0x88 -'9', # 0x89 -'+', # 0x8a -'-', # 0x8b -'=', # 0x8c -'(', # 0x8d -')', # 0x8e -None, # 0x8f -'a', # 0x90 -'e', # 0x91 -'o', # 0x92 -'x', # 0x93 -None, # 0x94 -'h', # 0x95 -'k', # 0x96 -'l', # 0x97 -'m', # 0x98 -'n', # 0x99 -'p', # 0x9a -'s', # 0x9b -'t', # 0x9c -None, # 0x9d -None, # 0x9e -None, # 0x9f -'ECU', # 0xa0 -'CL', # 0xa1 -'Cr', # 0xa2 -'FF', # 0xa3 -'L', # 0xa4 -'mil', # 0xa5 -'N', # 0xa6 -'Pts', # 0xa7 -'Rs', # 0xa8 -'W', # 0xa9 -'NS', # 0xaa -'D', # 0xab -'EUR', # 0xac -'K', # 0xad -'T', # 0xae -'Dr', # 0xaf -'Pf', # 0xb0 -'P', # 0xb1 -'G', # 0xb2 -'A', # 0xb3 -'UAH', # 0xb4 -'C|', # 0xb5 -'L', # 0xb6 -'Sm', # 0xb7 -'T', # 0xb8 -'Rs', # 0xb9 -'L', # 0xba -'M', # 0xbb -'m', # 0xbc -'R', # 0xbd -'l', # 0xbe -'BTC', # 0xbf -None, # 0xc0 -None, # 0xc1 -None, # 0xc2 -None, # 0xc3 -None, # 0xc4 -None, # 0xc5 -None, # 0xc6 -None, # 0xc7 -None, # 0xc8 -None, # 0xc9 -None, # 0xca -None, # 0xcb -None, # 0xcc -None, # 0xcd -None, # 0xce -None, # 0xcf -'', # 0xd0 -'', # 0xd1 -'', # 0xd2 -'', # 0xd3 -'', # 0xd4 -'', # 0xd5 -'', # 0xd6 -'', # 0xd7 -'', # 0xd8 -'', # 0xd9 -'', # 0xda -'', # 0xdb -'', # 0xdc -'', # 0xdd -'', # 0xde -'', # 0xdf -'', # 0xe0 -'', # 0xe1 -'', # 0xe2 -'', # 0xe3 -None, # 0xe4 -'', # 0xe5 -None, # 0xe6 -None, # 0xe7 -None, # 0xe8 -None, # 0xe9 -None, # 0xea -None, # 0xeb -None, # 0xec -None, # 0xed -None, # 0xee -None, # 0xef -None, # 0xf0 -None, # 0xf1 -None, # 0xf2 -None, # 0xf3 -None, # 0xf4 -None, # 0xf5 -None, # 0xf6 -None, # 0xf7 -None, # 0xf8 -None, # 0xf9 -None, # 0xfa -None, # 0xfb -None, # 0xfc -None, # 0xfd -None, # 0xfe -) diff --git a/Src/Lib/Unidecode/x021.py b/Src/Lib/Unidecode/x021.py new file mode 100644 index 0000000..0c19908 --- /dev/null +++ b/Src/Lib/Unidecode/x021.py @@ -0,0 +1,42 @@ +data = ( +' ', # 0x00 +' ', # 0x01 +' ', # 0x02 +' ', # 0x03 +' ', # 0x04 +' ', # 0x05 +' ', # 0x06 +' ', # 0x07 +' ', # 0x08 +' ', # 0x09 +' ', # 0x0a +' ', # 0x0b +'', # 0x0c +'', # 0x0d +'', # 0x0e +'', # 0x0f +'-', # 0x10 +'-', # 0x11 +'-', # 0x12 +'-', # 0x13 +'--', # 0x14 +'--', # 0x15 +'||', # 0x16 +'_', # 0x17 +'\'', # 0x18 +'\'', # 0x19 +',', # 0x1a +'\'', # 0x1b +'"', # 0x1c +'"', # 0x1d +',,', # 0x1e +'"', # 0x1f +'+', # 0x20 +'++', # 0x21 +'*', # 0x22 +'*>', # 0x23 +'.', # 0x24 +'..', # 0x25 +'...', # 0x26 +'.', # 0x27 +) diff --git a/Src/Util/file_validation.py b/Src/Util/file_validation.py new file mode 100644 index 0000000..eef7844 --- /dev/null +++ b/Src/Util/file_validation.py @@ -0,0 +1,88 @@ +# 16.05.24 + +import os +import errno +import platform +import unicodedata + +# List of invalid characters for Windows filenames +WINDOWS_INVALID_CHARS = '<>:"/\\|?*' +WINDOWS_RESERVED_NAMES = [ + "CON", "PRN", "AUX", "NUL", + "COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9", + "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9" +] + +# Invalid characters for macOS filenames +MACOS_INVALID_CHARS = '/:' + +# Invalid characters for Linux/Android filenames +LINUX_INVALID_CHARS = '/\0' + +# Maximum path length for Windows +WINDOWS_MAX_PATH = 260 + +def is_valid_filename(filename, system): + """ + Validates if the given filename is valid for the specified system. + + Parameters: + filename (str): The filename to validate. + system (str): The operating system, e.g., 'Windows', 'Darwin' (macOS), or others for Linux/Android. + + Returns: + bool: True if the filename is valid, False otherwise. + """ + # Normalize Unicode + filename = unicodedata.normalize('NFC', filename) + + # Common checks across all systems + if filename.endswith(' ') or filename.endswith('.') or filename.endswith('/'): + return False + + if filename.startswith('.') and system == "Darwin": + return False + + # System-specific checks + if system == "Windows": + if len(filename) > WINDOWS_MAX_PATH: + return False + if any(char in filename for char in WINDOWS_INVALID_CHARS): + return False + name, ext = os.path.splitext(filename) + if name.upper() in WINDOWS_RESERVED_NAMES: + return False + elif system == "Darwin": # macOS + if any(char in filename for char in MACOS_INVALID_CHARS): + return False + else: # Linux and Android + if any(char in filename for char in LINUX_INVALID_CHARS): + return False + + return True + +def can_create_file(file_path): + """ + Checks if a file can be created at the given file path. + + Parameters: + file_path (str): The path where the file is to be created. + + Returns: + bool: True if the file can be created, False otherwise. + """ + current_system = platform.system() + + if not is_valid_filename(os.path.basename(file_path), current_system): + return False + + try: + with open(file_path, 'w') as file: + pass + os.remove(file_path) # Cleanup if the file was created + return True + except OSError as e: + if e.errno in (errno.EACCES, errno.ENOENT, errno.EEXIST, errno.ENOTDIR): + return False + raise +