Add options [4-*]

This commit is contained in:
Lovi-0 2024-07-11 21:11:44 +02:00
parent 8c1baf929a
commit 49a8826142
13 changed files with 145 additions and 68 deletions

View File

@ -1,5 +1,6 @@
# 19.06.24
import sys
import logging
from typing import List
@ -55,9 +56,29 @@ def manage_selection(cmd_insert: str, max_count: int) -> List[int]:
# For a range (e.g., '[5-12]')
elif "[" in cmd_insert:
start, end = map(int, cmd_insert[1:-1].split('-'))
list_season_select = list(range(start, end + 1))
# Extract the start and end parts
start, end = map(str.strip, cmd_insert[1:-1].split('-'))
start = int(start)
# If end is an integer, convert it
try:
end = int(end)
except ValueError:
# end remains a string if conversion fails
pass
# Generate the list_season_select based on the type of end
if isinstance(end, int):
list_season_select = list(range(start, end + 1))
elif end == "*":
list_season_select = list(range(start, max_count + 1))
else:
raise ValueError("Invalid end value")
# For all seasons
elif cmd_insert == "*":
list_season_select = list(range(1, max_count+1))

View File

@ -6,7 +6,7 @@ from Src.Util.console import console, msg
# Logic class
from .site import title_search, run_get_select_title
from .anime import donwload_film, donwload_series
from .anime import download_film, download_series
# Variable
@ -25,10 +25,10 @@ def search():
select_title = run_get_select_title()
if select_title.type == 'TV':
donwload_series(select_title)
download_series(select_title)
else:
donwload_film(select_title)
download_film(select_title)
else:
console.print(f"\n[red]Nothing matching was found for[white]: [purple]{string_to_search}")

View File

@ -62,7 +62,7 @@ def download_episode(index_select: int):
logging.error(f"Skip index: {index_select} cant find info with api.")
def donwload_series(select_title: MediaItem):
def download_series(select_title: MediaItem):
"""
Function to download episodes of a TV series.
@ -79,7 +79,7 @@ def donwload_series(select_title: MediaItem):
console.log(f"[cyan]Episodes find: [red]{episoded_count}")
# Prompt user to select an episode index
last_command = msg.ask("\n[cyan]Insert media [red]index [yellow]or [red](*) [cyan]to download all media [yellow]or [red][1-2] [cyan]for a range of media")
last_command = msg.ask("\n[cyan]Insert media [red]index [yellow]or [red](*) [cyan]to download all media [yellow]or [red][1-2] [cyan]or [red][3-*] [cyan]for a range of media")
# Manage user selection
list_episode_select = manage_selection(last_command, episoded_count)
@ -94,7 +94,7 @@ def donwload_series(select_title: MediaItem):
download_episode(i_episode-1)
def donwload_film(select_title: MediaItem):
def download_film(select_title: MediaItem):
"""
Function to download a film.

View File

@ -27,7 +27,7 @@ table_show_manager = TVShowManager()
video_source = VideoSource()
def donwload_video(scape_info_serie: GetSerieInfo, index_episode_selected: int) -> None:
def download_video(scape_info_serie: GetSerieInfo, index_episode_selected: int) -> None:
"""
Download a single episode video.
@ -91,12 +91,12 @@ def download_thread(dict_serie: MediaItem):
# Download selected episodes
if len(list_episode_select) == 1 and last_command != "*":
donwload_video(scape_info_serie, list_episode_select[0])
download_video(scape_info_serie, list_episode_select[0])
# Download all other episodes selecter
else:
for i_episode in list_episode_select:
donwload_video(scape_info_serie, i_episode)
download_video(scape_info_serie, i_episode)
def display_episodes_list(obj_episode_manager) -> str:

View File

@ -26,7 +26,7 @@ table_show_manager = TVShowManager()
video_source = VideoSource()
def donwload_video(scape_info_serie: GetSerieInfo, index_season_selected: int, index_episode_selected: int) -> None:
def download_video(scape_info_serie: GetSerieInfo, index_season_selected: int, index_episode_selected: int) -> None:
"""
Download a single episode video.
@ -67,14 +67,14 @@ def donwload_video(scape_info_serie: GetSerieInfo, index_season_selected: int, i
).start()
def donwload_episode(scape_info_serie: GetSerieInfo, index_season_selected: int, donwload_all: bool = False) -> None:
def download_episode(scape_info_serie: GetSerieInfo, index_season_selected: int, download_all: bool = False) -> None:
"""
Download all episodes of a season.
Parameters:
- tv_name (str): Name of the TV series.
- index_season_selected (int): Index of the selected season.
- donwload_all (bool): Donwload all seasons episodes
- download_all (bool): Download all seasons episodes
"""
# Start message and collect information about episodes
@ -83,14 +83,14 @@ def donwload_episode(scape_info_serie: GetSerieInfo, index_season_selected: int,
episodes_count = len(list_dict_episode)
# Download all episodes wihtout ask
if donwload_all:
if download_all:
for i_episode in range(1, episodes_count+1):
donwload_video(scape_info_serie, index_season_selected, i_episode)
download_video(scape_info_serie, index_season_selected, i_episode)
console.print(f"\n[red]Download [yellow]season: [red]{index_season_selected}.")
# If not download all episode but a single season
if not donwload_all:
if not download_all:
# Display episodes list and manage user selection
last_command = display_episodes_list(scape_info_serie.list_episodes)
@ -98,12 +98,12 @@ def donwload_episode(scape_info_serie: GetSerieInfo, index_season_selected: int,
# Download selected episodes
if len(list_episode_select) == 1 and last_command != "*":
donwload_video(scape_info_serie, index_season_selected, list_episode_select[0])
download_video(scape_info_serie, index_season_selected, list_episode_select[0])
# Download all other episodes selecter
else:
for i_episode in list_episode_select:
donwload_video(scape_info_serie, index_season_selected, i_episode)
download_video(scape_info_serie, index_season_selected, i_episode)
def download_series(dict_serie: MediaItem) -> None:
@ -125,23 +125,23 @@ def download_series(dict_serie: MediaItem) -> None:
# Prompt user for season selection and download episodes
console.print(f"\n[green]Season find: [red]{seasons_count}")
index_season_selected = str(msg.ask("\n[cyan]Insert media [red]index [yellow]or [red](*) [cyan]to download all media [yellow]or [red][1-2] [cyan]for a range of media"))
index_season_selected = msg.ask("\n[cyan]Insert media [red]index [yellow]or [red](*) [cyan]to download all media [yellow]or [red][1-2] [cyan]or [red][3-*] [cyan]for a range of media")
list_season_select = manage_selection(index_season_selected, seasons_count)
# Download selected episodes
if len(list_season_select) == 1 and index_season_selected != "*":
if 1 <= int(index_season_selected) <= seasons_count:
donwload_episode(scape_info_serie, list_season_select[0])
download_episode(scape_info_serie, list_season_select[0])
# Dowload all seasons and episodes
elif index_season_selected == "*":
for i_season in list_season_select:
donwload_episode(scape_info_serie, i_season, True)
download_episode(scape_info_serie, i_season, True)
# Download all other season selecter
else:
for i_season in list_season_select:
donwload_episode(scape_info_serie, i_season)
download_episode(scape_info_serie, i_season)
def display_episodes_list(obj_episode_manager) -> str:

View File

@ -23,8 +23,8 @@ from .costant import ROOT_PATH, SITE_NAME, SERIES_FOLDER
video_source = VideoSource()
table_show_manager = TVShowManager()
def donwload_video(tv_name: str, index_season_selected: int, index_episode_selected: int) -> None:
# download_video
def download_video(tv_name: str, index_season_selected: int, index_episode_selected: int) -> None:
"""
Download a single episode video.
@ -57,14 +57,14 @@ def donwload_video(tv_name: str, index_season_selected: int, index_episode_selec
).start()
def donwload_episode(tv_name: str, index_season_selected: int, donwload_all: bool = False) -> None:
def download_episode(tv_name: str, index_season_selected: int, download_all: bool = False) -> None:
"""
Download all episodes of a season.
Parameters:
- tv_name (str): Name of the TV series.
- index_season_selected (int): Index of the selected season.
- donwload_all (bool): Donwload all seasons episodes
- download_all (bool): Download all seasons episodes
"""
# Clean memory of all episodes and get the number of the season (some dont follow rule of [1,2,3,4,5] but [1,2,3,145,5,6,7]).
@ -77,14 +77,14 @@ def donwload_episode(tv_name: str, index_season_selected: int, donwload_all: boo
episodes_count = video_source.obj_episode_manager.get_length()
# Download all episodes wihtout ask
if donwload_all:
if download_all:
for i_episode in range(1, episodes_count+1):
donwload_video(tv_name, index_season_selected, i_episode)
download_video(tv_name, index_season_selected, i_episode)
console.print(f"\n[red]Download [yellow]season: [red]{index_season_selected}.")
# If not download all episode but a single season
if not donwload_all:
if not download_all:
# Display episodes list and manage user selection
last_command = display_episodes_list()
@ -92,12 +92,12 @@ def donwload_episode(tv_name: str, index_season_selected: int, donwload_all: boo
# Download selected episodes
if len(list_episode_select) == 1 and last_command != "*":
donwload_video(tv_name, index_season_selected, list_episode_select[0])
download_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)
download_video(tv_name, index_season_selected, i_episode)
def download_series(select_title: MediaItem, domain: str, version: str) -> None:
@ -121,23 +121,23 @@ def download_series(select_title: MediaItem, domain: str, version: str) -> None:
# Prompt user for season selection and download episodes
console.print(f"\n[green]Season find: [red]{seasons_count}")
index_season_selected = str(msg.ask("\n[cyan]Insert media [red]index [yellow]or [red](*) [cyan]to download all media [yellow]or [red][1-2] [cyan]for a range of media"))
index_season_selected = msg.ask("\n[cyan]Insert media [red]index [yellow]or [red](*) [cyan]to download all media [yellow]or [red][1-2] [cyan]or [red][3-*] [cyan]for a range of media")
list_season_select = manage_selection(index_season_selected, seasons_count)
# Download selected episodes
if len(list_season_select) == 1 and index_season_selected != "*":
if 1 <= int(index_season_selected) <= seasons_count:
donwload_episode(select_title.slug, list_season_select[0])
download_episode(select_title.slug, list_season_select[0])
# Dowload all seasons and episodes
elif index_season_selected == "*":
for i_season in list_season_select:
donwload_episode(select_title.slug, i_season, True)
download_episode(select_title.slug, i_season, True)
# Download all other season selecter
else:
for i_season in list_season_select:
donwload_episode(select_title.slug, i_season)
download_episode(select_title.slug, i_season)
def display_episodes_list() -> str:

View File

@ -6,7 +6,7 @@ from Src.Util.console import console, msg
# Logic class
from .site import title_search, run_get_select_title
from .serie import donwload_serie
from .serie import download_serie
@ -30,7 +30,7 @@ def search():
select_title = run_get_select_title()
# Download only TV
donwload_serie(select_title)
download_serie(select_title)
else:
console.print(f"\n[red]Nothing matching was found for[white]: [purple]{string_to_search}")

View File

@ -26,7 +26,7 @@ from .costant import ROOT_PATH, SITE_NAME, SERIES_FOLDER
table_show_manager = TVShowManager()
def donwload_video(api_manager: ApiManager, index_season_selected: int, index_episode_selected: int) -> None:
def download_video(api_manager: ApiManager, index_season_selected: int, index_episode_selected: int) -> None:
"""
Download a single episode video.
@ -71,14 +71,14 @@ def donwload_video(api_manager: ApiManager, index_season_selected: int, index_ep
)
def donwload_episode(api_manager: ApiManager, index_season_selected: int, donwload_all: bool = False) -> None:
def download_episode(api_manager: ApiManager, index_season_selected: int, download_all: bool = False) -> None:
"""
Download all episodes of a season.
Parameters:
- tv_name (str): Name of the TV series.
- index_season_selected (int): Index of the selected season.
- donwload_all (bool): Donwload all seasons episodes
- download_all (bool): Download all seasons episodes
"""
# Clean memory of all episodes and get the number of the season (some dont follow rule of [1,2,3,4,5] but [1,2,3,145,5,6,7]).
@ -93,14 +93,14 @@ def donwload_episode(api_manager: ApiManager, index_season_selected: int, donwlo
start_message()
# Download all episodes wihtout ask
if donwload_all:
if download_all:
for i_episode in range(1, episodes_count+1):
donwload_video(api_manager, index_season_selected, i_episode)
download_video(api_manager, index_season_selected, i_episode)
console.print(f"\n[red]Download [yellow]season: [red]{index_season_selected}.")
# If not download all episode but a single season
if not donwload_all:
if not download_all:
# Display episodes list and manage user selection
last_command = display_episodes_list(api_manager)
@ -108,15 +108,15 @@ def donwload_episode(api_manager: ApiManager, index_season_selected: int, donwlo
# Download selected episodes
if len(list_episode_select) == 1 and last_command != "*":
donwload_video(api_manager, index_season_selected, list_episode_select[0])
download_video(api_manager, index_season_selected, list_episode_select[0])
# Download all other episodes selecter
else:
for i_episode in list_episode_select:
donwload_video(api_manager, index_season_selected, i_episode)
download_video(api_manager, index_season_selected, i_episode)
def donwload_serie(media: MediaItem):
def download_serie(media: MediaItem):
"""
Downloads a media title using its API manager and WebAutomation driver.
@ -135,23 +135,23 @@ def donwload_serie(media: MediaItem):
# Prompt user for season selection and download episodes
console.print(f"\n[green]Season find: [red]{seasons_count}")
index_season_selected = str(msg.ask("\n[cyan]Insert media [red]index [yellow]or [red](*) [cyan]to download all media [yellow]or [red][1-2] [cyan]for a range of media"))
index_season_selected = msg.ask("\n[cyan]Insert media [red]index [yellow]or [red](*) [cyan]to download all media [yellow]or [red][1-2] [cyan]or [red][3-*] [cyan]for a range of media")
list_season_select = manage_selection(index_season_selected, seasons_count)
# Download selected episodes
if len(list_season_select) == 1 and index_season_selected != "*":
if 1 <= int(index_season_selected) <= seasons_count:
donwload_episode(api_manager, list_season_select[0])
download_episode(api_manager, list_season_select[0])
# Dowload all seasons and episodes
elif index_season_selected == "*":
for i_season in list_season_select:
donwload_episode(api_manager, i_season, True)
download_episode(api_manager, i_season, True)
# Download all other season selecter
else:
for i_season in list_season_select:
donwload_episode(api_manager, i_season)
download_episode(api_manager, i_season)
def display_episodes_list(api_manager: ApiManager) -> str:

View File

@ -12,7 +12,6 @@ from unidecode import unidecode
# Internal utilities
from Src.Util.headers import get_headers
from Src.Util._jsonConfig import config_manager
from Src.Util.console import console, Panel
from Src.Util.color import Colors
@ -116,7 +115,7 @@ class HLS_Downloader():
os.makedirs(self.audio_segments_path, exist_ok=True)
os.makedirs(self.subtitle_segments_path, exist_ok=True)
# Track subtitle, audio donwload
# Track subtitle, audio download
self.downloaded_audio = []
self.downloaded_subtitle = []
self.downloaded_video = []
@ -235,12 +234,15 @@ class HLS_Downloader():
if self.codec is not None:
console.print(f"[cyan]Codec [white]=> ([green]'v'[white]: [yellow]{self.codec.video_codec_name}[white] ([green]b[white]: [yellow]{self.codec.video_bitrate // 1000}k[white]), [green]'a'[white]: [yellow]{self.codec.audio_codec_name}[white] ([green]b[white]: [yellow]{self.codec.audio_bitrate // 1000}k[white]))")
def __donwload_video__(self):
def download_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
@ -258,6 +260,7 @@ class HLS_Downloader():
if self.is_index_url:
logging.info("Parse index by url.")
video_m3u8 = M3U8_Segments(self.m3u8_index, full_path_video, True)
video_m3u8.add_server_ip(server_ip)
else:
logging.info("Parse index by text input.")
@ -279,12 +282,15 @@ class HLS_Downloader():
else:
console.log("[cyan]Video [red]already exists.")
def __donwload_audio__(self):
def download_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
@ -311,6 +317,7 @@ class HLS_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()
@ -540,9 +547,12 @@ class HLS_Downloader():
else:
logging.info("Video file converted already exist.")
def start(self) -> None:
def start(self, server_ip: list = 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
@ -581,9 +591,9 @@ class HLS_Downloader():
# Start all download ...
if DOWNLOAD_VIDEO:
self.__donwload_video__()
self.download_video(server_ip)
if DOWNLOAD_AUDIO:
self.__donwload_audio__()
self.download_audio(server_ip)
if DOWNLOAD_SUBTITLE:
self.__download_subtitle__()
@ -673,7 +683,7 @@ class HLS_Downloader():
self.m3u8_url_fixer.set_playlist(self.m3u8_index)
# Start all download ...
self.__donwload_video__()
self.download_video()
# Convert video
converted_out_path = self.__join_video__()

View File

@ -8,7 +8,7 @@ import logging
import binascii
import threading
from queue import PriorityQueue
from urllib.parse import urljoin, urlparse
from urllib.parse import urljoin, urlparse, urlunparse
from concurrent.futures import ThreadPoolExecutor
@ -84,7 +84,21 @@ class M3U8_Segments:
# Sync
self.queue = PriorityQueue()
self.stop_event = threading.Event()
# Server ip
self.fake_proxy = False
def add_server_ip(self, list_ip: list):
"""
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:
"""
Retrieves the encryption key from the M3U8 playlist.
@ -117,6 +131,24 @@ class M3U8_Segments:
logging.info(f"Key: ('hex': {hex_content}, 'byte': {byte_content})")
return byte_content
def __gen_proxy__(self, url: str, url_index: int) -> str:
"""
Change the IP address of the provided URL based on the given index.
Args:
- url (str): The original URL that needs its IP address replaced.
- url_index (int): The index used to select a new IP address from the list of FAKE_PROXY_IP.
Returns:
str: The modified URL with the new IP address.
"""
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 parse_data(self, m3u8_content: str) -> None:
"""
@ -160,7 +192,7 @@ class M3U8_Segments:
# Update segments for estimator
self.class_ts_estimator.total_segments = len(self.segments)
logging.info(f"Segmnets to donwload: [{len(self.segments)}]")
logging.info(f"Segmnets to download: [{len(self.segments)}]")
# Proxy
if THERE_IS_PROXY_LIST:
@ -171,6 +203,12 @@ class M3U8_Segments:
if len(self.valid_proxy) == 0:
sys.exit(0)
# Server ip
if self.fake_proxy:
for i in range(len(self.segments)):
segment_url = self.segments[i]
self.segments[i] = self.__gen_proxy__(segment_url, self.segments.index(segment_url))
def get_info(self) -> None:
"""
Makes a request to the index M3U8 file to get information about segments.
@ -205,6 +243,12 @@ class M3U8_Segments:
- index (int): The index of the segment.
- progress_bar (tqdm): Progress counter for tracking download progress.
"""
need_verify = REQUEST_VERIFY
# Set to false for only fake proxy that use real ip of server
if self.fake_proxy:
need_verify = False
try:
start_time = time.time()
@ -215,14 +259,14 @@ class M3U8_Segments:
proxy = self.valid_proxy[index % len(self.valid_proxy)]
logging.info(f"Use proxy: {proxy}")
with httpx.Client(proxies=proxy, verify=True) as client:
with httpx.Client(proxies=proxy, verify=need_verify) as client:
if 'key_base_url' in self.__dict__:
response = client.get(ts_url, headers=random_headers(self.key_base_url), timeout=REQUEST_TIMEOUT, follow_redirects=True)
else:
response = client.get(ts_url, headers={'user-agent': get_headers()}, timeout=REQUEST_TIMEOUT, follow_redirects=True)
else:
with httpx.Client(verify=True) as client_2:
with httpx.Client(verify=need_verify) as client_2:
if 'key_base_url' in self.__dict__:
response = client_2.get(ts_url, headers=random_headers(self.key_base_url), timeout=REQUEST_TIMEOUT, follow_redirects=True)
else:

View File

@ -407,7 +407,7 @@ class M3U8_Subtitle:
})
except Exception as e:
logging.error(f"Cant donwload: {obj_subtitle.get('name')}, error: {e}")
logging.error(f"Cant download: {obj_subtitle.get('name')}, error: {e}")
return output

View File

@ -105,7 +105,8 @@ class TVShowManager:
self.console.print(f"\n\n[yellow][INFO] [green]Press [red]Enter [green]to restart, or [red]'q' [green]to quit.")
if not force_int_input:
key = Prompt.ask("[cyan]Insert media [red]index [yellow]or [red](*) [cyan]to download all media [yellow]or [red][1-2] [cyan]for a range of media")
key = Prompt.ask("\n[cyan]Insert media [red]index [yellow]or [red](*) [cyan]to download all media [yellow]or [red][1-2] [cyan]or [red][3-*] [cyan]for a range of media")
else:
choices = [str(i) for i in range(0, max_int_input)]
choices.extend(["q", ""])
@ -128,7 +129,8 @@ class TVShowManager:
else:
self.console.print(f"\n\n[yellow][INFO] [red]You've reached the end. [green]Press [red]Enter [green]to restart, or [red]'q' [green]to quit.")
if not force_int_input:
key = Prompt.ask("[cyan]Insert media [red]index [yellow]or [red](*) [cyan]to download all media [yellow]or [red][1-2] [cyan]for a range of media")
key = Prompt.ask("\n[cyan]Insert media [red]index [yellow]or [red](*) [cyan]to download all media [yellow]or [red][1-2] [cyan]or [red][3-*] [cyan]for a range of media")
else:
choices = [str(i) for i in range(0, max_int_input)]
choices.extend(["q", ""])

2
run.py
View File

@ -125,7 +125,7 @@ def initialize():
# Attempting GitHub update
try:
#git_update()
git_update()
print()
except:
console.log("[red]Error with loading github.")