mirror of
https://github.com/Arrowar/StreamingCommunity.git
synced 2025-06-06 11:35:29 +00:00
Add api costant
This commit is contained in:
parent
c8df23c0f7
commit
387ff64f4f
@ -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
|
||||
|
||||
|
4
Src/Api/Altadefinizione/costant.py
Normal file
4
Src/Api/Altadefinizione/costant.py
Normal file
@ -0,0 +1,4 @@
|
||||
# 26.05.24
|
||||
|
||||
STREAMING_FOLDER = "altadefinizione"
|
||||
MOVIE_FOLDER = "Movie"
|
@ -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
|
||||
|
@ -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
|
||||
|
5
Src/Api/Animeunity/costant.py
Normal file
5
Src/Api/Animeunity/costant.py
Normal file
@ -0,0 +1,5 @@
|
||||
# 26.05.24
|
||||
|
||||
ANIME_FOLDER = "animeunity"
|
||||
SERIES_FOLDER= "Serie"
|
||||
MOVIE_FOLDER = "Movie"
|
7
Src/Api/Streamingcommunity/costant.py
Normal file
7
Src/Api/Streamingcommunity/costant.py
Normal 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"]
|
@ -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)
|
@ -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:
|
||||
|
@ -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
|
||||
|
@ -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])
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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:
|
||||
|
@ -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"
|
||||
)
|
@ -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
|
@ -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',
|
||||
|
||||
}
|
||||
|
@ -13,6 +13,4 @@ units_of_measurement_mapping = {
|
||||
'mm³': 'cubic millimeters',
|
||||
'km²': 'square kilometers',
|
||||
'km³': 'cubic kilometers',
|
||||
'ha': 'hectares',
|
||||
'ha': 'hectares',
|
||||
}
|
@ -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"],
|
||||
|
Loading…
x
Reference in New Issue
Block a user