Connect capture speed function to pid and resolve problem with back command

This commit is contained in:
Lovi 2024-12-31 11:16:41 +01:00
parent 288976bfcb
commit a2ecdeb061
20 changed files with 109 additions and 66 deletions

View File

@ -27,7 +27,7 @@ def search(string_to_search: str = None, get_onylDatabase: bool = False):
""" """
if string_to_search is None: if string_to_search is None:
string_to_search = msg.ask(f"\n[purple]Insert word to search in [red]{SITE_NAME}").strip() string_to_search = msg.ask(f"\n[purple]Insert word to search in [green]{SITE_NAME}").strip()
# Search on database # Search on database
len_database = title_search(quote_plus(string_to_search)) len_database = title_search(quote_plus(string_to_search))

View File

@ -27,7 +27,7 @@ def search(string_to_search: str = None, get_onylDatabase: bool = False):
""" """
if string_to_search is None: if string_to_search is None:
string_to_search = msg.ask(f"\n[purple]Insert word to search in [red]{SITE_NAME}").strip() string_to_search = msg.ask(f"\n[purple]Insert word to search in [green]{SITE_NAME}").strip()
# Search on database # Search on database
len_database = title_search(quote_plus(string_to_search)) len_database = title_search(quote_plus(string_to_search))

View File

@ -24,7 +24,7 @@ from .costant import SITE_NAME
def search(string_to_search: str = None, get_onylDatabase: bool = False): def search(string_to_search: str = None, get_onylDatabase: bool = False):
if string_to_search is None: if string_to_search is None:
string_to_search = msg.ask(f"\n[purple]Insert word to search in [red]{SITE_NAME}").strip() string_to_search = msg.ask(f"\n[purple]Insert word to search in [green]{SITE_NAME}").strip()
# Search on database # Search on database
len_database = title_search(quote_plus(string_to_search)) len_database = title_search(quote_plus(string_to_search))

View File

@ -27,7 +27,7 @@ def search(string_to_search: str = None, get_onylDatabase: bool = False):
""" """
if string_to_search is None: if string_to_search is None:
string_to_search = msg.ask(f"\n[purple]Insert word to search in [red]{SITE_NAME}").strip() string_to_search = msg.ask(f"\n[purple]Insert word to search in [green]{SITE_NAME}").strip()
# Search on database # Search on database
len_database = title_search(quote_plus(string_to_search)) len_database = title_search(quote_plus(string_to_search))

View File

@ -28,9 +28,7 @@ def search(string_to_search: str = None, get_onylDatabase: bool = False):
""" """
if string_to_search is None: if string_to_search is None:
string_to_search = msg.ask(f"\n[purple]Insert word to search in [green]{SITE_NAME}").strip()
# Make request to site to get content that corrsisponde to that string
string_to_search = msg.ask(f"\n[purple]Insert word to search in [red]{SITE_NAME}").strip()
# Search on database # Search on database
len_database = title_search(quote_plus(string_to_search)) len_database = title_search(quote_plus(string_to_search))

View File

@ -25,7 +25,6 @@ from StreamingCommunity.Api.Player.ddl import VideoSource
# Variable # Variable
from .costant import ROOT_PATH, SERIES_FOLDER from .costant import ROOT_PATH, SERIES_FOLDER
table_show_manager = TVShowManager()
@ -120,6 +119,7 @@ def display_episodes_list(obj_episode_manager) -> str:
""" """
# Set up table for displaying episodes # Set up table for displaying episodes
table_show_manager = TVShowManager()
table_show_manager.set_slice_end(10) table_show_manager.set_slice_end(10)
# Add columns to the table # Add columns to the table

View File

@ -27,9 +27,7 @@ def search(string_to_search: str = None, get_onylDatabase: bool = False):
""" """
if string_to_search is None: if string_to_search is None:
string_to_search = msg.ask(f"\n[purple]Insert word to search in [green]{SITE_NAME}").strip()
# Make request to site to get content that corrsisponde to that string
string_to_search = msg.ask(f"\n[purple]Insert word to search in [red]{SITE_NAME}").strip()
# Search on database # Search on database
len_database = title_search(quote_plus(string_to_search)) len_database = title_search(quote_plus(string_to_search))

View File

@ -25,7 +25,6 @@ from StreamingCommunity.Api.Player.supervideo import VideoSource
# Variable # Variable
from .costant import ROOT_PATH, SERIES_FOLDER from .costant import ROOT_PATH, SERIES_FOLDER
table_show_manager = TVShowManager()
@ -173,6 +172,7 @@ def display_episodes_list(obj_episode_manager) -> str:
""" """
# Set up table for displaying episodes # Set up table for displaying episodes
table_show_manager = TVShowManager()
table_show_manager.set_slice_end(10) table_show_manager.set_slice_end(10)
# Add columns to the table # Add columns to the table

View File

@ -28,7 +28,7 @@ def search(string_to_search: str = None, get_onylDatabase: bool = False):
""" """
if string_to_search is None: if string_to_search is None:
string_to_search = msg.ask(f"\n[purple]Insert word to search in [red]{SITE_NAME}").strip() string_to_search = msg.ask(f"\n[purple]Insert word to search in [green]{SITE_NAME}").strip()
# Search on database # Search on database
len_database = asyncio.run(title_search(quote_plus(string_to_search))) len_database = asyncio.run(title_search(quote_plus(string_to_search)))

View File

@ -27,7 +27,7 @@ def search(string_to_search: str = None, get_onylDatabase: bool = False):
""" """
if string_to_search is None: if string_to_search is None:
string_to_search = msg.ask(f"\n[purple]Insert word to search in [red]{SITE_NAME}").strip() string_to_search = msg.ask(f"\n[purple]Insert word to search in [green]{SITE_NAME}").strip()
# Not available for the moment # Not available for the moment
if get_onylDatabase: if get_onylDatabase:

View File

@ -28,7 +28,7 @@ def search(string_to_search: str = None, get_onylDatabase: bool = False):
""" """
if string_to_search is None: if string_to_search is None:
string_to_search = msg.ask(f"\n[purple]Insert word to search in [red]{SITE_NAME}").strip() string_to_search = msg.ask(f"\n[purple]Insert word to search in [green]{SITE_NAME}").strip()
# Get site domain and version and get result of the search # Get site domain and version and get result of the search
site_version, domain = get_version_and_domain() site_version, domain = get_version_and_domain()

View File

@ -25,7 +25,6 @@ from StreamingCommunity.Api.Player.vixcloud import VideoSource
# Variable # Variable
from .costant import ROOT_PATH, SITE_NAME, SERIES_FOLDER from .costant import ROOT_PATH, SITE_NAME, SERIES_FOLDER
table_show_manager = TVShowManager()
@ -178,6 +177,7 @@ def display_episodes_list(scrape_serie) -> str:
""" """
# Set up table for displaying episodes # Set up table for displaying episodes
table_show_manager = TVShowManager()
table_show_manager.set_slice_end(10) table_show_manager.set_slice_end(10)
# Add columns to the table # Add columns to the table

View File

@ -176,6 +176,8 @@ class ContentExtractor:
set_language = DOWNLOAD_SPECIFIC_AUDIO set_language = DOWNLOAD_SPECIFIC_AUDIO
downloadable_languages = list(set(available_languages) & set(set_language)) downloadable_languages = list(set(available_languages) & set(set_language))
# Only show if there is something available
if len(available_languages) > 0:
console.print(f"[cyan bold]Audio →[/cyan bold] [green]Available:[/green] [purple]{', '.join(available_languages)}[/purple] | " console.print(f"[cyan bold]Audio →[/cyan bold] [green]Available:[/green] [purple]{', '.join(available_languages)}[/purple] | "
f"[red]Set:[/red] [purple]{', '.join(set_language)}[/purple] | " f"[red]Set:[/red] [purple]{', '.join(set_language)}[/purple] | "
f"[yellow]Downloadable:[/yellow] [purple]{', '.join(downloadable_languages)}[/purple]") f"[yellow]Downloadable:[/yellow] [purple]{', '.join(downloadable_languages)}[/purple]")
@ -200,6 +202,8 @@ class ContentExtractor:
set_language = DOWNLOAD_SPECIFIC_SUBTITLE set_language = DOWNLOAD_SPECIFIC_SUBTITLE
downloadable_languages = list(set(available_languages) & set(set_language)) downloadable_languages = list(set(available_languages) & set(set_language))
# Only show if there is something available
if len(available_languages) > 0:
console.print(f"[cyan bold]Subtitle →[/cyan bold] [green]Available:[/green] [purple]{', '.join(available_languages)}[/purple] | " console.print(f"[cyan bold]Subtitle →[/cyan bold] [green]Available:[/green] [purple]{', '.join(available_languages)}[/purple] | "
f"[red]Set:[/red] [purple]{', '.join(set_language)}[/purple] | " f"[red]Set:[/red] [purple]{', '.join(set_language)}[/purple] | "
f"[yellow]Downloadable:[/yellow] [purple]{', '.join(downloadable_languages)}[/purple]") f"[yellow]Downloadable:[/yellow] [purple]{', '.join(downloadable_languages)}[/purple]")
@ -212,13 +216,18 @@ class ContentExtractor:
It identifies the best video quality and displays relevant information to the user. It identifies the best video quality and displays relevant information to the user.
""" """
logging.info(f"class 'ContentExtractor'; call _collect_video()") logging.info(f"class 'ContentExtractor'; call _collect_video()")
set_resolution = "Best"
# Collect custom quality video if a specific resolution is set # Collect custom quality video if a specific resolution is set
if FILTER_CUSTOM_REOLUTION != -1: if FILTER_CUSTOM_REOLUTION != -1:
self.m3u8_index, video_res = self.obj_parse._video.get_custom_uri(y_resolution=FILTER_CUSTOM_REOLUTION) self.m3u8_index, video_res = self.obj_parse._video.get_custom_uri(y_resolution=FILTER_CUSTOM_REOLUTION)
set_resolution = f"{FILTER_CUSTOM_REOLUTION}p"
else:
# Otherwise, get the best available video quality # Otherwise, get the best available video quality
self.m3u8_index, video_res = self.obj_parse._video.get_best_uri() self.m3u8_index, video_res = self.obj_parse._video.get_best_uri()
self.codec: M3U8_Codec = self.obj_parse.codec self.codec: M3U8_Codec = self.obj_parse.codec
# List all available resolutions # List all available resolutions
@ -227,19 +236,34 @@ class ContentExtractor:
logging.info(f"M3U8 index selected: {self.m3u8_index}, with resolution: {video_res}") logging.info(f"M3U8 index selected: {self.m3u8_index}, with resolution: {video_res}")
# Create a formatted table to display video info # Create a formatted table to display video info
console.print(f"[cyan bold]Video →[/cyan bold] [green]Available resolutions:[/green] [purple]{', '.join(list_available_resolution)}[/purple] | " console.print(f"[cyan bold]Video →[/cyan bold] [green]Available:[/green] [purple]{', '.join(list_available_resolution)}[/purple] | "
f"[red]Set:[/red] [purple]{set_resolution}[/purple] | "
f"[yellow]Downloadable:[/yellow] [purple]{video_res[0]}x{video_res[1]}[/purple]") f"[yellow]Downloadable:[/yellow] [purple]{video_res[0]}x{video_res[1]}[/purple]")
if self.codec is not None: if self.codec is not None:
if config_manager.get_bool("M3U8_CONVERSION", "use_codec"):
codec_info = (f"[green]v[/green]: [yellow]{self.codec.video_codec_name}[/yellow] " # Generate the string for available codec information
available_codec_info = (
f"[green]v[/green]: [yellow]{self.codec.video_codec_name}[/yellow] "
f"([green]b[/green]: [yellow]{self.codec.video_bitrate // 1000}k[/yellow]), " f"([green]b[/green]: [yellow]{self.codec.video_bitrate // 1000}k[/yellow]), "
f"[green]a[/green]: [yellow]{self.codec.audio_codec_name}[/yellow] " f"[green]a[/green]: [yellow]{self.codec.audio_codec_name}[/yellow] "
f"([green]b[/green]: [yellow]{self.codec.audio_bitrate // 1000}k[/yellow])") f"([green]b[/green]: [yellow]{self.codec.audio_bitrate // 1000}k[/yellow])"
else: )
codec_info = "[cyan]copy[/cyan]"
# Determine what to display for "Set"
# If the codec usage is enabled in the configuration, use the detailed codec info
# Otherwise, display "copy"
if config_manager.get_bool("M3U8_CONVERSION", "use_codec"):
set_codec_info = available_codec_info
else:
set_codec_info = "[purple]copy[/purple]"
# Print the formatted result with "Available" and "Set" information
console.print(
f"[bold cyan]Codec →[/bold cyan] [green]Available:[/green] {available_codec_info} | "
f"[red]Set:[/red] {set_codec_info}"
)
console.print(f"[bold cyan]Codec →[/bold cyan] {codec_info}")
# Fix the URL if it does not include the full protocol # Fix the URL if it does not include the full protocol
if "http" not in self.m3u8_index: if "http" not in self.m3u8_index:

View File

@ -545,6 +545,9 @@ class M3U8_Segments:
if file_size == 0: if file_size == 0:
raise Exception("Output file is empty") raise Exception("Output file is empty")
# Display additional info only if there is failed segments
if self.info_nFailed > 0:
# Get expected time # Get expected time
ex_hours, ex_minutes, ex_seconds = format_duration(self.expected_real_time_s) ex_hours, ex_minutes, ex_seconds = format_duration(self.expected_real_time_s)
ex_formatted_duration = f"[yellow]{int(ex_hours)}[red]h [yellow]{int(ex_minutes)}[red]m [yellow]{int(ex_seconds)}[red]s" ex_formatted_duration = f"[yellow]{int(ex_hours)}[red]h [yellow]{int(ex_minutes)}[red]m [yellow]{int(ex_seconds)}[red]s"

View File

@ -17,7 +17,7 @@ crypto_installed = crypto_spec is not None
if crypto_installed: if crypto_installed:
console.print("[cyan]Decrypy use: Cryptodomex") logging.info("[cyan]Decrypy use: Cryptodomex")
from Cryptodome.Cipher import AES from Cryptodome.Cipher import AES
from Cryptodome.Util.Padding import unpad from Cryptodome.Util.Padding import unpad
@ -93,7 +93,7 @@ else:
# Check if openssl command is available # Check if openssl command is available
try: try:
openssl_available = subprocess.run(["openssl", "version"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL).returncode == 0 openssl_available = subprocess.run(["openssl", "version"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL).returncode == 0
console.print("[cyan]Decrypy use: OPENSSL") logging.info("[cyan]Decrypy use: OPENSSL")
except: except:
openssl_available = False openssl_available = False

View File

@ -56,35 +56,60 @@ class M3U8_Ts_Estimator:
self.ts_file_sizes.append(size) self.ts_file_sizes.append(size)
self.now_downloaded_size += size_download self.now_downloaded_size += size_download
def capture_speed(self, interval: float = 1): def capture_speed(self, interval: float = 1, pid: int = None):
""" """
Capture the internet speed periodically and store the values. Capture the internet speed periodically for a specific process (identified by PID)
or the entire system if no PID is provided.
"""
def get_network_io(process=None):
"""
Get network I/O counters for a specific process or system-wide if no process is specified.
""" """
def get_network_io():
"""Get network I/O counters, handle missing psutil gracefully."""
try: try:
if process:
io_counters = process.io_counters()
return io_counters
else:
io_counters = psutil.net_io_counters() io_counters = psutil.net_io_counters()
return io_counters return io_counters
except Exception as e: except Exception as e:
logging.warning(f"Unable to access network I/O counters: {e}") logging.warning(f"Unable to access network I/O counters: {e}")
return None return None
while True: # If a PID is provided, attempt to attach to the corresponding process
old_value = get_network_io() process = None
if pid is not None:
try:
process = psutil.Process(pid)
except psutil.NoSuchProcess:
logging.error(f"Process with PID {pid} does not exist.")
return
except Exception as e:
logging.error(f"Failed to attach to process with PID {pid}: {e}")
return
if old_value is None: # If psutil is not available, continue with default values while True:
old_value = get_network_io(process)
if old_value is None: # If psutil fails, continue with the next interval
time.sleep(interval) time.sleep(interval)
continue continue
time.sleep(interval) time.sleep(interval)
new_value = get_network_io() new_value = get_network_io(process)
if new_value is None: # Handle again if psutil fails in the next call if new_value is None: # Handle again if psutil fails in the next call
time.sleep(interval) time.sleep(interval)
continue continue
with self.lock: with self.lock:
# Calculate speed based on process-specific counters if process is specified
if process:
upload_speed = (new_value.write_bytes - old_value.write_bytes) / interval
download_speed = (new_value.read_bytes - old_value.read_bytes) / interval
else:
# System-wide counters
upload_speed = (new_value.bytes_sent - old_value.bytes_sent) / interval upload_speed = (new_value.bytes_sent - old_value.bytes_sent) / interval
download_speed = (new_value.bytes_recv - old_value.bytes_recv) / interval download_speed = (new_value.bytes_recv - old_value.bytes_recv) / interval
@ -93,6 +118,7 @@ class M3U8_Ts_Estimator:
"download": internet_manager.format_transfer_speed(download_speed) "download": internet_manager.format_transfer_speed(download_speed)
} }
def get_average_speed(self) -> float: def get_average_speed(self) -> float:
""" """
Calculate the average internet speed. Calculate the average internet speed.

View File

@ -57,11 +57,10 @@ def update():
# Check installed version # Check installed version
if str(__version__).replace('v', '') != str(last_version).replace('v', '') : if str(__version__).replace('v', '') != str(last_version).replace('v', '') :
console.print(f"[red]New version available: [yellow]{last_version}") console.print(f"[red]New version available: [yellow]{last_version} \n")
else: else:
console.print(f"[red]Everything is up to date") console.print(f" [yellow]Everything is up to date \n")
console.print("\n")
console.print(f"[red]{__title__} has been downloaded [yellow]{total_download_count} [red]times, but only [yellow]{percentual_stars}% [red]of users have starred it.\n\ console.print(f"[red]{__title__} has been downloaded [yellow]{total_download_count} [red]times, but only [yellow]{percentual_stars}% [red]of users have starred it.\n\
[cyan]Help the repository grow today by leaving a [yellow]star [cyan]and [yellow]sharing [cyan]it with others online!") [cyan]Help the repository grow today by leaving a [yellow]star [cyan]and [yellow]sharing [cyan]it with others online!")

View File

@ -317,16 +317,13 @@ class InternManager():
def check_internet(): def check_internet():
while True: while True:
try: try:
httpx.get("https://www.google.com") httpx.get("https://www.google.com", timeout=15)
#console.log("[bold green]Internet is available![/bold green]")
break break
except urllib.error.URLError: except urllib.error.URLError:
console.log("[bold red]Internet is not available. Waiting...[/bold red]") console.log("[bold red]Internet is not available. Waiting...[/bold red]")
time.sleep(5) time.sleep(5)
print()
class OsSummary: class OsSummary:

View File

@ -118,11 +118,10 @@ def initialize():
sys.exit(0) sys.exit(0)
# Attempting GitHub update # Attempting GitHub update
try: """try:
git_update() git_update()
print()
except: except:
console.log("[red]Error with loading github.") console.log("[red]Error with loading github.")"""
def main(): def main():

View File

@ -1,5 +1,4 @@
httpx httpx
cffi
bs4 bs4
rich rich
tqdm tqdm