Add api costant

This commit is contained in:
Ghost 2024-05-26 18:45:37 +02:00
parent c8df23c0f7
commit 387ff64f4f
18 changed files with 229 additions and 97 deletions

View File

@ -73,9 +73,6 @@ You can change some behaviors by tweaking the configuration file.
* tqdm_show_progress: Whether to show progress during downloads or not.
- Default Value: true
* fake_proxy: Speed up download for streaming film and series. **Dont work for anime, need to set to FALSE, only streamingcommunity**
- Default Value: false
* create_report: When enabled, this option saves the name of the series or movie being downloaded along with the date and file size in a CSV file, providing a log of downloaded content.
- Default Value: false

View File

@ -0,0 +1,4 @@
# 26.05.24
STREAMING_FOLDER = "altadefinizione"
MOVIE_FOLDER = "Movie"

View File

@ -18,8 +18,7 @@ from .Core.Player.supervideo import VideoSource
# Config
ROOT_PATH = config_manager.get('DEFAULT', 'root_path')
STREAMING_FOLDER = "altadefinizione"
MOVIE_FOLDER = "Movie"
from .costant import STREAMING_FOLDER, MOVIE_FOLDER
# Variable

View File

@ -18,9 +18,7 @@ from .Core.Util import manage_selection
# Config
ROOT_PATH = config_manager.get('DEFAULT', 'root_path')
ANIME_FOLDER = "animeunity"
SERIES_FOLDER= "Serie"
MOVIE_FOLDER = "Movie"
from .costant import ANIME_FOLDER, SERIES_FOLDER, MOVIE_FOLDER
# Variable

View File

@ -0,0 +1,5 @@
# 26.05.24
ANIME_FOLDER = "animeunity"
SERIES_FOLDER= "Serie"
MOVIE_FOLDER = "Movie"

View File

@ -0,0 +1,7 @@
# 26.05.24
STREAMING_FOLDER = "streamingcommunity"
MOVIE_FOLDER = "Movie"
SERIES_FOLDER = "Serie"
SERVER_IP = ["57.129.7.85","57.129.7.188","57.129.7.174","57.129.4.77","57.129.16.196","57.129.16.156","57.129.16.139","57.129.16.135","57.129.13.175","51.38.112.237","51.195.107.7","51.195.107.230"]

View File

@ -18,8 +18,7 @@ from .Core.Vix_player.player import VideoSource
# Config
ROOT_PATH = config_manager.get('DEFAULT', 'root_path')
STREAMING_FOLDER = "streamingcommunity"
MOVIE_FOLDER = "Movie"
from .costant import STREAMING_FOLDER, MOVIE_FOLDER, SERVER_IP
# Variable
@ -60,4 +59,4 @@ def download_film(id_film: str, title_name: str, domain: str):
Downloader(
m3u8_playlist = master_playlist,
output_filename = os.path.join(mp4_path, mp4_format)
).start()
).start(SERVER_IP)

View File

@ -20,8 +20,7 @@ from .Core.Util import manage_selection, map_episode_title
# Config
ROOT_PATH = config_manager.get('DEFAULT', 'root_path')
STREAMING_FOLDER = "streamingcommunity"
SERIES_FOLDER = "Serie"
from .costant import STREAMING_FOLDER, SERIES_FOLDER, SERVER_IP
# Variable
@ -97,7 +96,7 @@ def donwload_video(tv_name: str, index_season_selected: int, index_episode_selec
Downloader(
m3u8_playlist = master_playlist,
output_filename = os.path.join(mp4_path, mp4_name)
).start()
).start(SERVER_IP)
def donwload_episode(tv_name: str, index_season_selected: int, donwload_all: bool = False) -> None:

View File

@ -3,7 +3,7 @@
from .command import (
join_video,
join_audios,
join_subtitle
join_subtitle,
)
from .util import print_duration_table
from .installer import check_ffmpeg

View File

@ -16,9 +16,9 @@ except: pass
# Internal utilities
from Src.Util.os import check_file_existence
from Src.Util._jsonConfig import config_manager
from .util import has_audio_stream
from Src.Util.os import check_file_existence
from .util import has_audio_stream, need_to_force_to_ts
from .capture import capture_ffmpeg_real_time
@ -257,7 +257,7 @@ def __transcode_with_subtitles(video: str, subtitles_list: List[Dict[str, str]],
# --> v 1.1 (new)
def join_video(video_path: str, out_path: str, vcodec: str = None, acodec: str = None, bitrate: str = None, force_ts = False):
def join_video(video_path: str, out_path: str, vcodec: str = None, acodec: str = None, bitrate: str = None):
"""
Joins single ts video file to mp4
@ -281,8 +281,9 @@ def join_video(video_path: str, out_path: str, vcodec: str = None, acodec: str =
ffmpeg_cmd.extend(['-hwaccel', 'cuda', '-hwaccel_output_format', 'cuda'])
# Add mpegts to force to detect input file as ts file
if force_ts:
if need_to_force_to_ts(video_path):
ffmpeg_cmd.extend(['-f', 'mpegts'])
vcodec = "libx264"
# Insert input video path
ffmpeg_cmd.extend(['-i', video_path])

View File

@ -105,3 +105,66 @@ def print_duration_table(file_path: str) -> None:
if video_duration is not None:
hours, minutes, seconds = format_duration(video_duration)
console.log(f"[cyan]Duration for [white]([green]{os.path.basename(file_path)}[white]): [yellow]{int(hours)}[red]h [yellow]{int(minutes)}[red]m [yellow]{int(seconds)}[red]s")
def get_ffprobe_info(file_path):
"""
Get format and codec information for a media file using ffprobe.
Args:
file_path (str): Path to the media file.
Returns:
dict: A dictionary containing the format name and a list of codec names.
"""
try:
result = subprocess.run(
['ffprobe', '-v', 'error', '-show_format', '-show_streams', '-print_format', 'json', file_path],
stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, check=True
)
output = result.stdout
info = json.loads(output)
format_name = info['format']['format_name'] if 'format' in info else None
codec_names = [stream['codec_name'] for stream in info['streams']] if 'streams' in info else []
return {
'format_name': format_name,
'codec_names': codec_names
}
except subprocess.CalledProcessError as e:
logging.error(f"ffprobe failed for file {file_path}: {e}")
return None
except json.JSONDecodeError as e:
logging.error(f"Failed to parse JSON output from ffprobe for file {file_path}: {e}")
return None
def is_png_format_or_codec(file_info):
"""
Check if the format is 'png_pipe' or if any codec is 'png'.
Args:
file_info (dict): The dictionary containing file information.
Returns:
bool: True if the format is 'png_pipe' or any codec is 'png', otherwise False.
"""
if not file_info:
return False
return file_info['format_name'] == 'png_pipe' or 'png' in file_info['codec_names']
def need_to_force_to_ts(file_path):
"""
Get if a file to TS format if it is in PNG format or contains a PNG codec.
Args:
file_path (str): Path to the input media file.
"""
logging.info(f"Processing file: {file_path}")
file_info = get_ffprobe_info(file_path)
if is_png_format_or_codec(file_info):
return True
return False

View File

@ -46,7 +46,6 @@ from ..E_Table import report_table
DOWNLOAD_SPECIFIC_AUDIO = config_manager.get_list('M3U8_FILTER', 'specific_list_audio')
DOWNLOAD_SPECIFIC_SUBTITLE = config_manager.get_list('M3U8_FILTER', 'specific_list_subtitles')
REMOVE_SEGMENTS_FOLDER = config_manager.get_bool('M3U8_FILTER', 'cleanup_tmp_folder')
FORCE_TS = config_manager.get_dict('M3U8_FILTER', 'force_ts')
FILTER_CUSTOM_REOLUTION = config_manager.get_int('M3U8_PARSER', 'force_resolution')
CREATE_REPORT = config_manager.get_bool('M3U8_DOWNLOAD', 'create_report')
@ -80,13 +79,14 @@ class Downloader():
else:
folder, base_name = os.path.split(self.output_filename) # Split file_folder output
base_name = reduce_base_name(remove_special_characters(transliterate(base_name))) # Remove special char
base_name = reduce_base_name(remove_special_characters(base_name)) # Remove special char
create_folder(folder) # Create folder and check if exist
if not can_create_file(base_name): # Check if folder file name can be create
logging.error("Invalid mp4 name.")
sys.exit(0)
self.output_filename = os.path.join(folder, base_name)
self.output_filename = transliterate(self.output_filename)
logging.info(f"Output filename: {self.output_filename}")
@ -222,12 +222,15 @@ class Downloader():
if self.codec is not None:
console.log(f"[cyan]Find codec [white]=> ([green]'v'[white]: [yellow]{self.codec.video_codec_name}[white], [green]'a'[white]: [yellow]{self.codec.audio_codec_name}[white], [green]'b'[white]: [yellow]{self.codec.bandwidth})")
def __donwload_video__(self):
def __donwload_video__(self, server_ip: list = None):
"""
Downloads and manages video segments.
This method downloads video segments if necessary and updates
the list of downloaded video segments.
Args:
- server_ip (list): A list of IP addresses to use in requests.
"""
# Construct full path for the video segment directory
@ -243,6 +246,7 @@ class Downloader():
# Create an instance of M3U8_Segments to handle video segments
video_m3u8 = M3U8_Segments(self.m3u8_index, full_path_video)
video_m3u8.add_server_ip(server_ip)
# Get information about the video segments
video_m3u8.get_info()
@ -253,12 +257,15 @@ class Downloader():
else:
console.log("[cyan]Video [red]already exists.")
def __donwload_audio__(self):
def __donwload_audio__(self, server_ip: list = None):
"""
Downloads and manages audio segments.
This method iterates over available audio tracks, downloads them if necessary, and updates
the list of downloaded audio tracks.
Args:
- server_ip (list): A list of IP addresses to use in requests.
"""
# Iterate over each available audio track
@ -285,6 +292,7 @@ class Downloader():
# If the audio segment directory doesn't exist, download audio segments
audio_m3u8 = M3U8_Segments(obj_audio.get('uri'), full_path_audio)
audio_m3u8.add_server_ip(server_ip)
# Get information about the audio segments
audio_m3u8.get_info()
@ -361,7 +369,7 @@ class Downloader():
for future in futures:
future.result()
def __join_video__(self, force_ts = False, vcodec = 'copy') -> str:
def __join_video__(self, vcodec = 'copy') -> str:
"""
Join downloaded video segments into a single video file.
@ -378,7 +386,6 @@ class Downloader():
join_video(
video_path = self.downloaded_video[0].get('path'),
out_path = path_join_video,
force_ts = force_ts,
vcodec = vcodec
)
@ -459,9 +466,12 @@ class Downloader():
else:
logging.info("Video file converted already exist.")
def start(self) -> None:
def start(self, server_ip: list = None) -> None:
"""
Start the process of fetching, downloading, joining, and cleaning up the video.
Args:
- server_ip (list): A list of IP addresses to use in requests.
"""
# Check if file already exist
@ -492,8 +502,8 @@ class Downloader():
self.__manage_playlist__(m3u8_playlist_text)
# Start all download ...
self.__donwload_video__()
self.__donwload_audio__()
self.__donwload_video__(server_ip)
self.__donwload_audio__(server_ip)
self.__download_subtitle__()
# Check file to convert
@ -529,10 +539,7 @@ class Downloader():
self.__donwload_video__()
# Convert video
if FORCE_TS:
converted_out_path = self.__join_video__(force_ts=True, vcodec="libx264")
else:
converted_out_path = self.__join_video__()
converted_out_path = self.__join_video__()
# Clean all tmp file
self.__clean__(converted_out_path)

View File

@ -35,8 +35,6 @@ from ..M3U8 import (
# Config
TQDM_MAX_WORKER = config_manager.get_int('M3U8_DOWNLOAD', 'tdqm_workers')
TQDM_SHOW_PROGRESS = config_manager.get_int('M3U8_DOWNLOAD', 'tqdm_show_progress')
FAKE_PROXY = config_manager.get_float('M3U8_DOWNLOAD', 'fake_proxy')
FAKE_PROXY_IP = config_manager.get_list('M3U8_DOWNLOAD', 'fake_proxy_ip')
REQUEST_TIMEOUT = config_manager.get_int('M3U8_REQUESTS', 'timeout')
REQUEST_VERIFY_SSL = config_manager.get_bool('M3U8_REQUESTS', 'verify_ssl')
REQUEST_DISABLE_ERROR = config_manager.get_bool('M3U8_REQUESTS', 'disable_error')
@ -67,8 +65,20 @@ class M3U8_Segments:
self.ctrl_c_detected = False # Global variable to track Ctrl+C detection
os.makedirs(self.tmp_folder, exist_ok=True) # Create the temporary folder if it does not exist
self.class_ts_estimator = M3U8_Ts_Estimator(TQDM_MAX_WORKER)
self.class_ts_estimator = M3U8_Ts_Estimator(TQDM_MAX_WORKER, 0)
self.class_url_fixer = M3U8_UrlFix(url)
self.fake_proxy = False
def add_server_ip(self, list_ip):
"""
Add server IP addresses
Args:
list_ip (list): A list of IP addresses to be added.
"""
if list_ip is not None:
self.fake_proxy = True
self.fake_proxy_ip = list_ip
def __get_key__(self, m3u8_parser: M3U8_Parser) -> bytes:
"""
@ -143,7 +153,7 @@ class M3U8_Segments:
logging.info(f"Generated new URL: {self.segments[i]}, from: {segment_url}")
# Change IP address of server
if FAKE_PROXY:
if self.fake_proxy:
for i in range(len(self.segments)):
segment_url = self.segments[i]
@ -155,6 +165,9 @@ class M3U8_Segments:
for item in self.segments:
file.write(f"{item}\n")
# Update segments for estimator
self.class_ts_estimator.total_segments = len(self.segments)
def get_info(self) -> None:
"""
Makes a request to the index M3U8 file to get information about segments.
@ -183,42 +196,13 @@ class M3U8_Segments:
Returns:
str: The modified URL with the new IP address.
"""
new_ip_address = FAKE_PROXY_IP[url_index % len(FAKE_PROXY_IP)]
new_ip_address = self.fake_proxy_ip[url_index % len(self.fake_proxy_ip)]
# Parse the original URL and replace the hostname with the new IP address
parsed_url = urlparse(url)._replace(netloc=new_ip_address)
return urlunparse(parsed_url)
def update_progress_bar(self, segment_content: bytes, duration: float, progress_counter: tqdm) -> None:
"""
Updates the progress bar with information about the TS segment download.
Args:
segment_content (bytes): The content of the downloaded TS segment.
duration (float): The duration of the segment download in seconds.
progress_counter (tqdm): The tqdm object representing the progress bar.
"""
if TQDM_SHOW_PROGRESS:
total_downloaded = len(segment_content)
# Add the size of the downloaded segment to the estimator
self.class_ts_estimator.add_ts_file(total_downloaded * len(self.segments), total_downloaded, duration)
# Get downloaded size and total estimated size
downloaded_file_size_str = self.class_ts_estimator.get_downloaded_size().split(' ')[0]
file_total_size = self.class_ts_estimator.calculate_total_size()
number_file_total_size = file_total_size.split(' ')[0]
units_file_total_size = file_total_size.split(' ')[1]
average_internet_speed = self.class_ts_estimator.get_average_speed()
# Update the progress bar's postfix
progress_counter.set_postfix_str(
f"{Colors.WHITE}[ {Colors.GREEN}{downloaded_file_size_str} {Colors.WHITE}< {Colors.GREEN}{number_file_total_size} {Colors.RED}{units_file_total_size} "
f"{Colors.WHITE}| {Colors.CYAN}{average_internet_speed:.2f} {Colors.RED}MB/s"
)
def make_requests_stream(self, ts_url: str, index: int, stop_event: threading.Event, progress_bar: tqdm) -> None:
"""
Downloads a TS segment and adds it to the segment queue.
@ -248,7 +232,8 @@ class M3U8_Segments:
# Get the content of the segment
segment_content = response.content
self.update_progress_bar(segment_content, duration, progress_bar)
if TQDM_SHOW_PROGRESS:
self.class_ts_estimator.update_progress_bar(segment_content, duration, progress_bar)
# Decrypt the segment content if decryption is needed
if self.decryption is not None:
@ -315,8 +300,9 @@ class M3U8_Segments:
total=len(self.segments),
unit='s',
ascii=' #',
bar_format=f"{Colors.YELLOW}Downloading {Colors.WHITE}({add_desc}{Colors.WHITE}): {Colors.RED}{{percentage:.0f}}% {Colors.MAGENTA}{{bar}} {Colors.YELLOW}{{elapsed}} {Colors.WHITE}< {Colors.CYAN}{{remaining}}{{postfix}} {Colors.WHITE}]",
dynamic_ncols=True
bar_format=f"{Colors.YELLOW}Downloading {Colors.WHITE}({add_desc}{Colors.WHITE}): {Colors.RED}{{percentage:.2f}}% {Colors.MAGENTA}{{bar}} {Colors.YELLOW}{{elapsed}} {Colors.WHITE}< {Colors.CYAN}{{remaining}}{{postfix}} {Colors.WHITE}]",
dynamic_ncols=True,
mininterval=0.01
)
def signal_handler(sig, frame):
@ -342,7 +328,7 @@ class M3U8_Segments:
time.sleep(0.025)
if self.ctrl_c_detected:
console.log("[red]1. Ctrl+C detected. Stopping further downloads.")
console.log("[red]Ctrl+C detected. Stopping further downloads.")
stop_event.set()
with self.condition:

View File

@ -2,17 +2,24 @@
from collections import deque
# External libraries
from tqdm import tqdm
# Internal utilities
from Src.Util.color import Colors
from Src.Util.os import format_size
class M3U8_Ts_Estimator:
def __init__(self, workers: int):
def __init__(self, workers: int, total_segments: int):
"""
Initialize the TSFileSizeCalculator object.
Args:
- workers (int): The number of workers using with ThreadPool.
- total_segments (int): Len of total segments to download
"""
self.ts_file_sizes = []
self.now_downloaded_size = 0
@ -20,6 +27,7 @@ class M3U8_Ts_Estimator:
self.list_speeds = deque(maxlen=self.average_over)
self.smoothed_speeds = []
self.tqdm_workers = workers
self.total_segments = total_segments
def add_ts_file(self, size: int, size_download: int, duration: float):
"""
@ -33,6 +41,10 @@ class M3U8_Ts_Estimator:
self.ts_file_sizes.append(size)
self.now_downloaded_size += size_download
# Only for the start
if len(self.smoothed_speeds) <= 3:
size_download = size_download / self.tqdm_workers
# Calculate mbps
speed_mbps = (size_download * 8) / (duration * 1_000_000) * self.tqdm_workers
self.list_speeds.append(speed_mbps)
@ -78,4 +90,33 @@ class M3U8_Ts_Estimator:
Returns:
str: The total downloaded size as a human-readable string.
"""
return format_size(self.now_downloaded_size)
return format_size(self.now_downloaded_size)
def update_progress_bar(self, segment_content: bytes, duration: float, progress_counter: tqdm) -> None:
"""
Updates the progress bar with information about the TS segment download.
Args:
segment_content (bytes): The content of the downloaded TS segment.
duration (float): The duration of the segment download in seconds.
progress_counter (tqdm): The tqdm object representing the progress bar.
"""
total_downloaded = len(segment_content)
# Add the size of the downloaded segment to the estimator
self.add_ts_file(total_downloaded * self.total_segments, total_downloaded, duration)
# Get downloaded size and total estimated size
downloaded_file_size_str = self.get_downloaded_size().split(' ')[0]
file_total_size = self.calculate_total_size()
# Fix parameter for prefix
number_file_total_size = file_total_size.split(' ')[0]
units_file_total_size = file_total_size.split(' ')[1]
average_internet_speed = self.get_average_speed()
# Update the progress bar's postfix
progress_counter.set_postfix_str(
f"{Colors.WHITE}[ {Colors.GREEN}{downloaded_file_size_str} {Colors.WHITE}< {Colors.GREEN}{number_file_total_size} {Colors.RED}{units_file_total_size} "
f"{Colors.WHITE}| {Colors.CYAN}{average_internet_speed:.2f} {Colors.RED}MB/s"
)

View File

@ -1,5 +1,7 @@
# 16.05.24
from unidecode import unidecode
# Internal utilities
from .alphabet import alpha_mappings
@ -31,5 +33,5 @@ all_mappings = {
def transliterate(text):
translated_text = ''.join(all_mappings.get(c, c) for c in text)
return translated_text
transliterated_text = unidecode(translated_text)
return transliterated_text

View File

@ -4,26 +4,49 @@ alpha_mappings = {
# Latin Alphabet
'À': 'A', 'Á': 'A', 'Â': 'A', 'Ã': 'A', 'Ä': 'A', 'Å': 'A', 'Æ': 'AE',
'Ç': 'C', 'È': 'E', 'É': 'E', 'Ê': 'E', 'Ë': 'E', 'Ì': 'I', 'Í': 'I', 'Î': 'I', 'Ï': 'I',
'Ð': 'D', 'Ñ': 'N', 'Ò': 'O', 'Ó': 'O', 'Ô': 'O', 'Õ': 'O', 'Ö': 'O', 'Ø': 'O',
'Ù': 'U', 'Ú': 'U', 'Û': 'U', 'Ü': 'U', 'Ý': 'Y', 'Þ': 'Th', 'ß': 'ss',
'Ç': 'C', 'È': 'E', 'É': 'E', 'Ê': 'E', 'Ë': 'E',
'Ì': 'I', 'Í': 'I', 'Î': 'I', 'Ï': 'I',
'Ð': 'D', 'Ñ': 'N',
'Ò': 'O', 'Ó': 'O', 'Ô': 'O', 'Õ': 'O', 'Ö': 'O', 'Ø': 'O',
'Ù': 'U', 'Ú': 'U', 'Û': 'U', 'Ü': 'U',
'Ý': 'Y',
'Þ': 'TH',
'ß': 'ss',
'à': 'a', 'á': 'a', 'â': 'a', 'ã': 'a', 'ä': 'a', 'å': 'a', 'æ': 'ae',
'ç': 'c', 'è': 'e', 'é': 'e', 'ê': 'e', 'ë': 'e', 'ì': 'i', 'í': 'i', 'î': 'i', 'ï': 'i',
'ð': 'd', 'ñ': 'n', 'ò': 'o', 'ó': 'o', 'ô': 'o', 'õ': 'o', 'ö': 'o', 'ø': 'o',
'ù': 'u', 'ú': 'u', 'û': 'u', 'ü': 'u', 'ý': 'y', 'þ': 'th', 'ÿ': 'y',
'Ā': 'A', 'ā': 'a', 'Ă': 'A', 'ă': 'a', 'Ą': 'A', 'ą': 'a', 'Ć': 'C', 'ć': 'c',
'Ĉ': 'C', 'ĉ': 'c', 'Ċ': 'C', 'ċ': 'c', 'Č': 'C', 'č': 'c', 'Ď': 'D', 'ď': 'd', 'Đ': 'D', 'đ': 'd',
'ç': 'c', 'è': 'e', 'é': 'e', 'ê': 'e', 'ë': 'e',
'ì': 'i', 'í': 'i', 'î': 'i', 'ï': 'i',
'ð': 'd', 'ñ': 'n',
'ò': 'o', 'ó': 'o', 'ô': 'o', 'õ': 'o', 'ö': 'o', 'ø': 'o',
'ù': 'u', 'ú': 'u', 'û': 'u', 'ü': 'u',
'ý': 'y', 'þ': 'th', 'ÿ': 'y',
'Ā': 'A', 'ā': 'a', 'Ă': 'A', 'ă': 'a', 'Ą': 'A', 'ą': 'a',
'Ć': 'C', 'ć': 'c', 'Ĉ': 'C', 'ĉ': 'c', 'Ċ': 'C', 'ċ': 'c', 'Č': 'C', 'č': 'c',
'Ď': 'D', 'ď': 'd', 'Đ': 'D', 'đ': 'd',
'Ē': 'E', 'ē': 'e', 'Ĕ': 'E', 'ĕ': 'e', 'Ė': 'E', 'ė': 'e', 'Ę': 'E', 'ę': 'e', 'Ě': 'E', 'ě': 'e',
'Ĝ': 'G', 'ĝ': 'g', 'Ğ': 'G', 'ğ': 'g', 'Ġ': 'G', 'ġ': 'g', 'Ģ': 'G', 'ģ': 'g', 'Ĥ': 'H', 'ĥ': 'h',
'Ħ': 'H', 'ħ': 'h', 'Ĩ': 'I', 'ĩ': 'i', 'Ī': 'I', 'ī': 'i', 'Ĭ': 'I', 'ĭ': 'i', 'Į': 'I', 'į': 'i',
'İ': 'I', 'ı': 'i', 'IJ': 'IJ', 'ij': 'ij', 'Ĵ': 'J', 'ĵ': 'j', 'Ķ': 'K', 'ķ': 'k', 'ĸ': 'k', 'Ĺ': 'L',
'ĺ': 'l', 'Ļ': 'L', 'ļ': 'l', 'Ľ': 'L', 'ľ': 'l', 'Ŀ': 'L', 'ŀ': 'l', 'Ł': 'L', 'ł': 'l', 'Ń': 'N',
'ń': 'n', 'Ņ': 'N', 'ņ': 'n', 'Ň': 'N', 'ň': 'n', 'ʼn': 'n', 'Ō': 'O', 'ō': 'o', 'Ŏ': 'O', 'ŏ': 'o',
'Ő': 'O', 'ő': 'o', 'Ŕ': 'R', 'ŕ': 'r', 'Ŗ': 'R', 'ŗ': 'r', 'Ř': 'R', 'ř': 'r', 'Ś': 'S', 'ś': 's',
'Ŝ': 'S', 'ŝ': 's', 'Ş': 'S', 'ş': 's', 'Š': 'S', 'š': 's', 'Ţ': 'T', 'ţ': 't', 'Ť': 'T', 'ť': 't',
'Ŧ': 'T', 'ŧ': 't', 'Ũ': 'U', 'ũ': 'u', 'Ū': 'U', 'ū': 'u', 'Ŭ': 'U', 'ŭ': 'u', 'Ů': 'U', 'ů': 'u',
'Ű': 'U', 'ű': 'u', 'Ų': 'U', 'ų': 'u', 'Ŵ': 'W', 'ŵ': 'w', 'Ŷ': 'Y', 'ŷ': 'y', 'Ÿ': 'Y', 'Ź': 'Z',
'ź': 'z', 'Ż': 'Z', 'ż': 'z', 'Ž': 'Z', 'ž': 'z',
'Ĝ': 'G', 'ĝ': 'g', 'Ğ': 'G', 'ğ': 'g', 'Ġ': 'G', 'ġ': 'g', 'Ģ': 'G', 'ģ': 'g',
'Ĥ': 'H', 'ĥ': 'h', 'Ħ': 'H', 'ħ': 'h',
'Ĩ': 'I', 'ĩ': 'i', 'Ī': 'I', 'ī': 'i', 'Ĭ': 'I', 'ĭ': 'i', 'Į': 'I', 'į': 'i',
'İ': 'I', 'ı': 'i',
'IJ': 'IJ', 'ij': 'ij',
'Ĵ': 'J', 'ĵ': 'j',
'Ķ': 'K', 'ķ': 'k', 'ĸ': 'k',
'Ĺ': 'L', 'ĺ': 'l', 'Ļ': 'L', 'ļ': 'l', 'Ľ': 'L', 'ľ': 'l', 'Ŀ': 'L', 'ŀ': 'l', 'Ł': 'L', 'ł': 'l',
'Ń': 'N', 'ń': 'n', 'Ņ': 'N', 'ņ': 'n', 'Ň': 'N', 'ň': 'n', 'ʼn': 'n', 'Ŋ': 'N', 'ŋ': 'n',
'Ō': 'O', 'ō': 'o', 'Ŏ': 'O', 'ŏ': 'o', 'Ő': 'O', 'ő': 'o',
'Œ': 'OE', 'œ': 'oe',
'Ŕ': 'R', 'ŕ': 'r', 'Ŗ': 'R', 'ŗ': 'r', 'Ř': 'R', 'ř': 'r',
'Ś': 'S', 'ś': 's', 'Ŝ': 'S', 'ŝ': 's', 'Ş': 'S', 'ş': 's', 'Š': 'S', 'š': 's',
'Ţ': 'T', 'ţ': 't', 'Ť': 'T', 'ť': 't', 'Ŧ': 'T', 'ŧ': 't',
'Ũ': 'U', 'ũ': 'u', 'Ū': 'U', 'ū': 'u', 'Ŭ': 'U', 'ŭ': 'u', 'Ů': 'U', 'ů': 'u',
'Ű': 'U', 'ű': 'u', 'Ų': 'U', 'ų': 'u',
'Ŵ': 'W', 'ŵ': 'w',
'Ŷ': 'Y', 'ŷ': 'y', 'Ÿ': 'Y',
'Ź': 'Z', 'ź': 'z', 'Ż': 'Z', 'ż': 'z', 'Ž': 'Z', 'ž': 'z',
'ƒ': 'f',
'Ơ': 'O', 'ơ': 'o', 'Ư': 'U', 'ư': 'u',
'Ǎ': 'A', 'ǎ': 'a', 'Ǐ': 'I', 'ǐ': 'i', 'Ǒ': 'O', 'ǒ': 'o', 'Ǔ': 'U', 'ǔ': 'u',
'Ǖ': 'U', 'ǖ': 'u', 'Ǘ': 'U', 'ǘ': 'u', 'Ǚ': 'U', 'ǚ': 'u', 'Ǜ': 'U', 'ǜ': 'u',
'Ǻ': 'A', 'ǻ': 'a', 'Ǽ': 'AE', 'ǽ': 'ae', 'Ǿ': 'O', 'ǿ': 'o',
# Cyrillic Alphabet
'А': 'A', 'Б': 'B', 'В': 'V', 'Г': 'G', 'Д': 'D', 'Е': 'E', 'Ё': 'E', 'Ж': 'Zh', 'З': 'Z', 'И': 'I',
@ -109,4 +132,10 @@ alpha_mappings = {
'ù': 'u', 'ú': 'u', 'ũ': 'u', '': 'u',
'': 'u', '': 'u', '': 'u', '': 'u', '': 'u', '': 'u',
'': 'y', 'ý': 'y', '': 'y', '': 'y', '': 'y',
# Devanagari
'': 'a', '': 'aa', '': 'i', '': 'ii', '': 'u', '': 'uu', '': 'e', '': 'ai', '': 'o', '': 'au', '': 'ka', '': 'kha', '': 'ga', '': 'gha', '': 'nga', '': 'cha',
'': 'chha', '': 'ja', '': 'jha', '': 'nya', '': 'ta', '': 'tha', '': 'da', '': 'dha', '': 'na', '': 'ta', '': 'tha', '': 'da', '': 'dha', '': 'na', '': 'pa',
'': 'pha', '': 'ba', '': 'bha', '': 'ma', '': 'ya', '': 'ra', '': 'la', '': 'va', '': 'sha', '': 'ssha', '': 'sa', '': 'ha', '': 'a',
}

View File

@ -13,6 +13,4 @@ units_of_measurement_mapping = {
'mm³': 'cubic millimeters',
'km²': 'square kilometers',
'km³': 'cubic kilometers',
'ha': 'hectares',
'ha': 'hectares',
}

View File

@ -18,14 +18,11 @@
"M3U8_DOWNLOAD": {
"tdqm_workers": 30,
"tqdm_show_progress": true,
"fake_proxy": false,
"fake_proxy_ip": ["57.129.7.85","57.129.7.188","57.129.7.174","57.129.4.77","57.129.16.196","57.129.16.156","57.129.16.139","57.129.16.135","57.129.13.175","57.129.13.157","51.38.112.237","51.195.107.7","51.195.107.230"],
"create_report": false
},
"M3U8_FILTER": {
"use_codec": false,
"use_gpu": false,
"force_ts": false,
"default_preset": "ultrafast",
"cleanup_tmp_folder": true,
"specific_list_audio": ["ita"],