mirror of
https://github.com/Arrowar/StreamingCommunity.git
synced 2025-06-06 19:45:24 +00:00
Fix signal handler mp4
This commit is contained in:
parent
2f8d706b59
commit
8ce68479ae
@ -3,6 +3,7 @@
|
|||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
|
import time
|
||||||
import signal
|
import signal
|
||||||
import logging
|
import logging
|
||||||
from functools import partial
|
from functools import partial
|
||||||
@ -39,21 +40,38 @@ TELEGRAM_BOT = config_manager.get_bool('DEFAULT', 'telegram_bot')
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
def signal_handler(signum, frame, kill_handler):
|
class InterruptHandler:
|
||||||
"""Signal handler for graceful interruption"""
|
def __init__(self):
|
||||||
kill_handler[0] = True
|
self.interrupt_count = 0
|
||||||
print("\nReceived interrupt signal. Completing current download...")
|
self.last_interrupt_time = 0
|
||||||
|
self.kill_download = False
|
||||||
|
self.force_quit = False
|
||||||
|
|
||||||
|
def signal_handler(signum, frame, interrupt_handler, original_handler):
|
||||||
|
"""Enhanced signal handler for multiple interrupt scenarios"""
|
||||||
|
current_time = time.time()
|
||||||
|
|
||||||
|
# Reset counter if more than 2 seconds have passed since last interrupt
|
||||||
|
if current_time - interrupt_handler.last_interrupt_time > 2:
|
||||||
|
interrupt_handler.interrupt_count = 0
|
||||||
|
|
||||||
|
interrupt_handler.interrupt_count += 1
|
||||||
|
interrupt_handler.last_interrupt_time = current_time
|
||||||
|
|
||||||
|
if interrupt_handler.interrupt_count == 1:
|
||||||
|
interrupt_handler.kill_download = True
|
||||||
|
console.print("\n[bold yellow]First interrupt received. Download will complete and save. Press Ctrl+C three times quickly to force quit.[/bold yellow]")
|
||||||
|
|
||||||
|
elif interrupt_handler.interrupt_count >= 3:
|
||||||
|
interrupt_handler.force_quit = True
|
||||||
|
console.print("\n[bold red]Force quit activated. Saving partial download...[/bold red]")
|
||||||
|
signal.signal(signum, original_handler)
|
||||||
|
|
||||||
def MP4_downloader(url: str, path: str, referer: str = None, headers_: dict = None):
|
def MP4_downloader(url: str, path: str, referer: str = None, headers_: dict = None):
|
||||||
"""
|
"""
|
||||||
Downloads an MP4 video from a given URL with robust error handling and SSL bypass.
|
Downloads an MP4 video with enhanced interrupt handling.
|
||||||
|
- Single Ctrl+C: Completes download gracefully
|
||||||
Parameters:
|
- Triple Ctrl+C: Saves partial download and exits
|
||||||
- url (str): The URL of the MP4 video to download.
|
|
||||||
- path (str): The local path where the downloaded MP4 file will be saved.
|
|
||||||
- referer (str, optional): The referer header value.
|
|
||||||
- headers_ (dict, optional): Custom headers for the request.
|
|
||||||
"""
|
"""
|
||||||
if TELEGRAM_BOT:
|
if TELEGRAM_BOT:
|
||||||
bot = get_bot_instance()
|
bot = get_bot_instance()
|
||||||
@ -65,23 +83,19 @@ def MP4_downloader(url: str, path: str, referer: str = None, headers_: dict = No
|
|||||||
bot.send_message(f"Contenuto già scaricato!", None)
|
bot.send_message(f"Contenuto già scaricato!", None)
|
||||||
return 400
|
return 400
|
||||||
|
|
||||||
# Early return for link-only mode
|
|
||||||
if GET_ONLY_LINK:
|
if GET_ONLY_LINK:
|
||||||
return {'path': path, 'url': url}
|
return {'path': path, 'url': url}
|
||||||
|
|
||||||
# Validate URL
|
|
||||||
if not (url.lower().startswith('http://') or url.lower().startswith('https://')):
|
if not (url.lower().startswith('http://') or url.lower().startswith('https://')):
|
||||||
logging.error(f"Invalid URL: {url}")
|
logging.error(f"Invalid URL: {url}")
|
||||||
console.print(f"[bold red]Invalid URL: {url}[/bold red]")
|
console.print(f"[bold red]Invalid URL: {url}[/bold red]")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
# Prepare headers
|
|
||||||
try:
|
try:
|
||||||
headers = {}
|
headers = {}
|
||||||
if referer:
|
if referer:
|
||||||
headers['Referer'] = referer
|
headers['Referer'] = referer
|
||||||
|
|
||||||
# Use custom headers if provided, otherwise use default user agent
|
|
||||||
if headers_:
|
if headers_:
|
||||||
headers.update(headers_)
|
headers.update(headers_)
|
||||||
else:
|
else:
|
||||||
@ -93,17 +107,12 @@ def MP4_downloader(url: str, path: str, referer: str = None, headers_: dict = No
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
temp_path = f"{path}.temp"
|
temp_path = f"{path}.temp"
|
||||||
kill_handler = [False] # Using list for mutable state
|
interrupt_handler = InterruptHandler()
|
||||||
original_handler = signal.signal(signal.SIGINT, partial(signal_handler, kill_handler=kill_handler))
|
original_handler = signal.signal(signal.SIGINT, partial(signal_handler, interrupt_handler=interrupt_handler, original_handler=signal.getsignal(signal.SIGINT)))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Create a custom transport that bypasses SSL verification
|
transport = httpx.HTTPTransport(verify=False, http2=True)
|
||||||
transport = httpx.HTTPTransport(
|
|
||||||
verify=False,
|
|
||||||
http2=True
|
|
||||||
)
|
|
||||||
|
|
||||||
# Download with streaming and progress tracking
|
|
||||||
with httpx.Client(transport=transport, timeout=httpx.Timeout(60)) as client:
|
with httpx.Client(transport=transport, timeout=httpx.Timeout(60)) as client:
|
||||||
with client.stream("GET", url, headers=headers, timeout=REQUEST_TIMEOUT) as response:
|
with client.stream("GET", url, headers=headers, timeout=REQUEST_TIMEOUT) as response:
|
||||||
response.raise_for_status()
|
response.raise_for_status()
|
||||||
@ -125,16 +134,16 @@ def MP4_downloader(url: str, path: str, referer: str = None, headers_: dict = No
|
|||||||
unit_scale=True,
|
unit_scale=True,
|
||||||
desc='Downloading',
|
desc='Downloading',
|
||||||
mininterval=0.05,
|
mininterval=0.05,
|
||||||
file=sys.stdout, # Using file=sys.stdout to force in-place updates because sys.stderr may not support carriage returns in this environment.
|
file=sys.stdout # Using file=sys.stdout to force in-place updates because sys.stderr may not support carriage returns in this environment.
|
||||||
)
|
)
|
||||||
|
|
||||||
downloaded = 0
|
downloaded = 0
|
||||||
with open(temp_path, 'wb') as file, progress_bar as bar:
|
with open(temp_path, 'wb') as file, progress_bar as bar:
|
||||||
try:
|
try:
|
||||||
for chunk in response.iter_bytes(chunk_size=1024):
|
for chunk in response.iter_bytes(chunk_size=1024):
|
||||||
if kill_handler[0]:
|
if interrupt_handler.force_quit:
|
||||||
console.print("\n[bold yellow]Interrupting download...[/bold yellow]")
|
console.print("\n[bold red]Force quitting... Saving partial download.[/bold red]")
|
||||||
return None, True
|
break
|
||||||
|
|
||||||
if chunk:
|
if chunk:
|
||||||
size = file.write(chunk)
|
size = file.write(chunk)
|
||||||
@ -142,18 +151,15 @@ def MP4_downloader(url: str, path: str, referer: str = None, headers_: dict = No
|
|||||||
bar.update(size)
|
bar.update(size)
|
||||||
|
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
console.print("\n[bold red]Download interrupted by user.[/bold red]")
|
if not interrupt_handler.force_quit:
|
||||||
if os.path.exists(temp_path):
|
interrupt_handler.kill_download = True
|
||||||
os.remove(temp_path)
|
|
||||||
return None, True
|
|
||||||
|
|
||||||
# Rename temp file to final file
|
|
||||||
if os.path.exists(temp_path):
|
if os.path.exists(temp_path):
|
||||||
os.rename(temp_path, path)
|
os.rename(temp_path, path)
|
||||||
|
|
||||||
if os.path.exists(path):
|
if os.path.exists(path):
|
||||||
console.print(Panel(
|
console.print(Panel(
|
||||||
f"[bold green]Download completed![/bold green]\n"
|
f"[bold green]Download completed{' (Partial)' if interrupt_handler.force_quit else ''}![/bold green]\n"
|
||||||
f"[cyan]File size: [bold red]{internet_manager.format_file_size(os.path.getsize(path))}[/bold red]\n"
|
f"[cyan]File size: [bold red]{internet_manager.format_file_size(os.path.getsize(path))}[/bold red]\n"
|
||||||
f"[cyan]Duration: [bold]{print_duration_table(path, description=False, return_string=True)}[/bold]",
|
f"[cyan]Duration: [bold]{print_duration_table(path, description=False, return_string=True)}[/bold]",
|
||||||
title=f"{os.path.basename(path.replace('.mp4', ''))}",
|
title=f"{os.path.basename(path.replace('.mp4', ''))}",
|
||||||
@ -161,22 +167,22 @@ def MP4_downloader(url: str, path: str, referer: str = None, headers_: dict = No
|
|||||||
))
|
))
|
||||||
|
|
||||||
if TELEGRAM_BOT:
|
if TELEGRAM_BOT:
|
||||||
message = f"Download completato\nDimensione: {internet_manager.format_file_size(os.path.getsize(path))}\nDurata: {print_duration_table(path, description=False, return_string=True)}\nTitolo: {os.path.basename(path.replace('.mp4', ''))}"
|
message = f"Download completato{'(Parziale)' if interrupt_handler.force_quit else ''}\nDimensione: {internet_manager.format_file_size(os.path.getsize(path))}\nDurata: {print_duration_table(path, description=False, return_string=True)}\nTitolo: {os.path.basename(path.replace('.mp4', ''))}"
|
||||||
clean_message = re.sub(r'\[[a-zA-Z]+\]', '', message)
|
clean_message = re.sub(r'\[[a-zA-Z]+\]', '', message)
|
||||||
bot.send_message(clean_message, None)
|
bot.send_message(clean_message, None)
|
||||||
|
|
||||||
return path, kill_handler[0]
|
return path, interrupt_handler.kill_download
|
||||||
|
|
||||||
else:
|
else:
|
||||||
console.print("[bold red]Download failed or file is empty.[/bold red]")
|
console.print("[bold red]Download failed or file is empty.[/bold red]")
|
||||||
return None, kill_handler[0]
|
return None, interrupt_handler.kill_download
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.error(f"Unexpected error: {e}")
|
logging.error(f"Unexpected error: {e}")
|
||||||
console.print(f"[bold red]Unexpected Error: {e}[/bold red]")
|
console.print(f"[bold red]Unexpected Error: {e}[/bold red]")
|
||||||
if os.path.exists(temp_path):
|
if os.path.exists(temp_path):
|
||||||
os.remove(temp_path)
|
os.remove(temp_path)
|
||||||
return None, kill_handler[0]
|
return None, interrupt_handler.kill_download
|
||||||
|
|
||||||
finally:
|
finally:
|
||||||
# Restore original signal handler
|
|
||||||
signal.signal(signal.SIGINT, original_handler)
|
signal.signal(signal.SIGINT, original_handler)
|
2
setup.py
2
setup.py
@ -10,7 +10,7 @@ with open("requirements.txt", "r", encoding="utf-8-sig") as f:
|
|||||||
|
|
||||||
setup(
|
setup(
|
||||||
name="StreamingCommunity",
|
name="StreamingCommunity",
|
||||||
version="2.5.7",
|
version="2.5.8",
|
||||||
long_description=read_readme(),
|
long_description=read_readme(),
|
||||||
long_description_content_type="text/markdown",
|
long_description_content_type="text/markdown",
|
||||||
author="Lovi-0",
|
author="Lovi-0",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user