mirror of
https://github.com/Arrowar/StreamingCommunity.git
synced 2025-06-06 19:45:24 +00:00
Fix docker progress bar ffmpeg
This commit is contained in:
parent
20eae18cff
commit
cc9746b580
@ -23,6 +23,7 @@ Make sure you have the following prerequisites installed on your system:
|
||||
|
||||
* [python](https://www.python.org/downloads/) > 3.8
|
||||
* [ffmpeg](https://www.gyan.dev/ffmpeg/builds/)
|
||||
* [opnessl](https://www.openssl.org) or [pycryptodome](https://pypi.org/project/pycryptodome/)
|
||||
|
||||
## Installation
|
||||
|
||||
|
@ -7,12 +7,12 @@ import logging
|
||||
|
||||
# External libraries
|
||||
from bs4 import BeautifulSoup
|
||||
from unidecode import unidecode
|
||||
|
||||
|
||||
# Internal utilities
|
||||
from Src.Util.table import TVShowManager
|
||||
from Src.Lib.Request import requests
|
||||
from Src.Util.headers import get_headers
|
||||
from Src.Util.console import console
|
||||
from Src.Util._jsonConfig import config_manager
|
||||
|
||||
@ -44,7 +44,7 @@ def title_search(title_search: str) -> int:
|
||||
"""
|
||||
|
||||
# Send request to search for titles
|
||||
response = requests.get(f"https://{AD_SITE_NAME}.{AD_DOMAIN_NOW}/page/1/?story={title_search.replace(' ', '+')}&do=search&subaction=search&titleonly=3")
|
||||
response = requests.get(f"https://{AD_SITE_NAME}.{AD_DOMAIN_NOW}/page/1/?story={unidecode(title_search.replace(' ', '+'))}&do=search&subaction=search&titleonly=3")
|
||||
|
||||
# Create soup and find table
|
||||
soup = BeautifulSoup(response.text, "html.parser")
|
||||
|
@ -37,7 +37,7 @@ def download_episode(index_select: int):
|
||||
# Get information about the selected episode
|
||||
obj_episode = video_source.get_info_episode(index_select)
|
||||
|
||||
start_message(True)
|
||||
start_message()
|
||||
console.print(f"[yellow]Download: [red]EP_{obj_episode.number} \n")
|
||||
|
||||
# Get the embed URL for the episode
|
||||
|
@ -6,6 +6,7 @@ import logging
|
||||
|
||||
# External libraries
|
||||
from bs4 import BeautifulSoup
|
||||
from unidecode import unidecode
|
||||
|
||||
|
||||
# Internal utilities
|
||||
@ -160,7 +161,7 @@ def title_search(title: str) -> int:
|
||||
|
||||
# Prepare JSON data to be sent in the request
|
||||
json_data = {
|
||||
'title': title # Use the provided title for the search
|
||||
'title': unidecode(title) # Use the provided title for the search
|
||||
}
|
||||
|
||||
# Send a POST request to the API endpoint for live search
|
||||
|
@ -9,6 +9,7 @@ from typing import Tuple
|
||||
|
||||
# External libraries
|
||||
from bs4 import BeautifulSoup
|
||||
from unidecode import unidecode
|
||||
|
||||
|
||||
# Internal utilities
|
||||
@ -136,7 +137,7 @@ def title_search(title_search: str, domain: str) -> int:
|
||||
"""
|
||||
|
||||
# Send request to search for titles ( replace à to a and space to "+" )
|
||||
response = requests.get(f"https://{SC_SITE_NAME}.{domain}/api/search?q={title_search.replace(' ', '+')}", headers={'user-agent': get_headers()})
|
||||
response = requests.get(f"https://{SC_SITE_NAME}.{domain}/api/search?q={unidecode(title_search.replace(' ', '+'))}", headers={'user-agent': get_headers()})
|
||||
|
||||
# Add found titles to media search manager
|
||||
for dict_title in response.json()['data']:
|
||||
|
@ -32,45 +32,59 @@ def capture_output(process: subprocess.Popen, description: str) -> None:
|
||||
# Variable to store the length of the longest progress string
|
||||
max_length = 0
|
||||
|
||||
for line in iter(process.stdout.readline, b''):
|
||||
logging.info(f"FFMPEG: {line}")
|
||||
for line in iter(process.stdout.readline, ''):
|
||||
try:
|
||||
line = line.strip()
|
||||
if not line:
|
||||
continue
|
||||
|
||||
# Check if termination is requested
|
||||
if terminate_flag.is_set():
|
||||
break
|
||||
logging.info(f"FFMPEG line: {line}")
|
||||
|
||||
if line is not None and "size=" in str(line).strip():
|
||||
# Check if termination is requested
|
||||
if terminate_flag.is_set():
|
||||
break
|
||||
|
||||
# Parse the output line to extract relevant information
|
||||
data = parse_output_line(str(line).strip())
|
||||
if "size=" in line:
|
||||
try:
|
||||
|
||||
if 'q' in data:
|
||||
is_end = (float(data.get('q')) == -1.0)
|
||||
# Parse the output line to extract relevant information
|
||||
data = parse_output_line(line)
|
||||
|
||||
if not is_end:
|
||||
byte_size = int(re.findall(r'\d+', data.get('size'))[0]) * 1000
|
||||
else:
|
||||
byte_size = int(re.findall(r'\d+', data.get('Lsize'))[0]) * 1000
|
||||
else:
|
||||
byte_size = int(re.findall(r'\d+', data.get('size'))[0]) * 1000
|
||||
if 'q' in data:
|
||||
is_end = (float(data.get('q', -1.0)) == -1.0)
|
||||
size_key = 'Lsize' if is_end else 'size'
|
||||
byte_size = int(re.findall(r'\d+', data.get(size_key, '0'))[0]) * 1000
|
||||
else:
|
||||
byte_size = int(re.findall(r'\d+', data.get('size', '0'))[0]) * 1000
|
||||
|
||||
time_now = datetime.now().strftime('%H:%M:%S')
|
||||
time_now = datetime.now().strftime('%H:%M:%S')
|
||||
|
||||
# Construct the progress string with formatted output information
|
||||
progress_string = f"[blue][{time_now}][purple] FFmpeg [white][{description}[white]]: [white]([green]'speed': [yellow]{data.get('speed')}[white], [green]'size': [yellow]{format_size(byte_size)}[white])"
|
||||
max_length = max(max_length, len(progress_string))
|
||||
# Construct the progress string with formatted output information
|
||||
progress_string = (f"[blue][{time_now}][purple] FFmpeg [white][{description}]: "
|
||||
f"[white]([green]'speed': [yellow]{data.get('speed', 'N/A')}[white], "
|
||||
f"[green]'size': [yellow]{format_size(byte_size)}[white])")
|
||||
max_length = max(max_length, len(progress_string))
|
||||
|
||||
# Print the progress string to the console, overwriting the previous line
|
||||
console.print(progress_string.ljust(max_length), end="\r")
|
||||
# Print the progress string to the console, overwriting the previous line
|
||||
console.print(progress_string.ljust(max_length), end="\r")
|
||||
|
||||
except Exception as e:
|
||||
logging.error(f"Error parsing output line: {line} - {e}")
|
||||
|
||||
except Exception as e:
|
||||
logging.error(f"Error processing line from subprocess: {e}")
|
||||
|
||||
except Exception as e:
|
||||
logging.error(f"Error in capture_output: {e}")
|
||||
|
||||
finally:
|
||||
terminate_process(process)
|
||||
try:
|
||||
terminate_process(process)
|
||||
except Exception as e:
|
||||
logging.error(f"Error terminating process: {e}")
|
||||
|
||||
|
||||
def parse_output_line(line: str) -> Tuple[str, str]:
|
||||
def parse_output_line(line: str) -> dict:
|
||||
"""
|
||||
Function to parse the output line and extract relevant information.
|
||||
|
||||
@ -79,22 +93,27 @@ def parse_output_line(line: str) -> Tuple[str, str]:
|
||||
|
||||
Returns:
|
||||
dict: A dictionary containing parsed information.
|
||||
Ex. {'speed': '60.0x'}
|
||||
"""
|
||||
data = {}
|
||||
try:
|
||||
|
||||
# Split the line by whitespace and extract key-value pairs
|
||||
parts = line.replace(" ", "").replace("= ", "=").split()
|
||||
data = {}
|
||||
|
||||
for part in parts:
|
||||
key_value = part.split('=')
|
||||
# Split the line by whitespace and extract key-value pairs
|
||||
parts = line.replace(" ", "").replace("= ", "=").split()
|
||||
|
||||
if len(key_value) == 2:
|
||||
key = key_value[0]
|
||||
value = key_value[1]
|
||||
data[key] = value
|
||||
for part in parts:
|
||||
key_value = part.split('=')
|
||||
|
||||
return data
|
||||
if len(key_value) == 2:
|
||||
key = key_value[0]
|
||||
value = key_value[1]
|
||||
data[key] = value
|
||||
|
||||
return data
|
||||
|
||||
except Exception as e:
|
||||
logging.error(f"Error parsing line: {line} - {e}")
|
||||
return {}
|
||||
|
||||
|
||||
def terminate_process(process):
|
||||
@ -104,8 +123,11 @@ def terminate_process(process):
|
||||
Args:
|
||||
- process (subprocess.Popen): The subprocess to terminate.
|
||||
"""
|
||||
if process.poll() is None: # Check if the process is still running
|
||||
process.kill()
|
||||
try:
|
||||
if process.poll() is None: # Check if the process is still running
|
||||
process.kill()
|
||||
except Exception as e:
|
||||
logging.error(f"Failed to terminate process: {e}")
|
||||
|
||||
|
||||
def capture_ffmpeg_real_time(ffmpeg_command: list, description: str) -> None:
|
||||
@ -122,21 +144,28 @@ def capture_ffmpeg_real_time(ffmpeg_command: list, description: str) -> None:
|
||||
# Clear the terminate_flag before starting a new capture
|
||||
terminate_flag.clear()
|
||||
|
||||
# Start the ffmpeg process with subprocess.Popen
|
||||
process = subprocess.Popen(ffmpeg_command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True)
|
||||
|
||||
# Start a thread to capture and print output
|
||||
output_thread = threading.Thread(target=capture_output, args=(process,description))
|
||||
output_thread.start()
|
||||
|
||||
try:
|
||||
# Wait for ffmpeg process to complete
|
||||
process.wait()
|
||||
except KeyboardInterrupt:
|
||||
print("Terminating ffmpeg process...")
|
||||
except Exception as e:
|
||||
logging.error(f"Error in ffmpeg process: {e}")
|
||||
finally:
|
||||
terminate_flag.set() # Signal the output capture thread to terminate
|
||||
output_thread.join() # Wait for the output capture thread to complete
|
||||
|
||||
# Start the ffmpeg process with subprocess.Popen
|
||||
process = subprocess.Popen(ffmpeg_command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True)
|
||||
|
||||
# Start a thread to capture and print output
|
||||
output_thread = threading.Thread(target=capture_output, args=(process, description))
|
||||
output_thread.start()
|
||||
|
||||
try:
|
||||
# Wait for ffmpeg process to complete
|
||||
process.wait()
|
||||
|
||||
except KeyboardInterrupt:
|
||||
logging.error("Terminating ffmpeg process...")
|
||||
|
||||
except Exception as e:
|
||||
logging.error(f"Error in ffmpeg process: {e}")
|
||||
|
||||
finally:
|
||||
terminate_flag.set() # Signal the output capture thread to terminate
|
||||
output_thread.join() # Wait for the output capture thread to complete
|
||||
|
||||
except Exception as e:
|
||||
logging.error(f"Failed to start ffmpeg process: {e}")
|
||||
|
@ -19,6 +19,7 @@ except: pass
|
||||
# Internal utilities
|
||||
from Src.Util._jsonConfig import config_manager
|
||||
from Src.Util.os import check_file_existence
|
||||
from Src.Util.console import console
|
||||
from .util import has_audio_stream, need_to_force_to_ts, check_ffmpeg_input
|
||||
from .capture import capture_ffmpeg_real_time
|
||||
|
||||
@ -284,6 +285,7 @@ def join_video(video_path: str, out_path: str, vcodec: str = None, acodec: str =
|
||||
|
||||
# Add mpegts to force to detect input file as ts file
|
||||
if need_to_force_to_ts(video_path):
|
||||
console.log("[red]Force input file to 'mpegts'.")
|
||||
ffmpeg_cmd.extend(['-f', 'mpegts'])
|
||||
vcodec = "libx264"
|
||||
|
||||
@ -317,6 +319,7 @@ def join_video(video_path: str, out_path: str, vcodec: str = None, acodec: str =
|
||||
|
||||
# Check file
|
||||
if CHECK_OUTPUT_CONVERSION:
|
||||
console.log("[red]Check output ffmpeg")
|
||||
time.sleep(0.5)
|
||||
check_ffmpeg_input(out_path)
|
||||
|
||||
@ -369,6 +372,7 @@ def join_audios(video_path: str, audio_tracks: List[Dict[str, str]], out_path: s
|
||||
|
||||
# Check file
|
||||
if CHECK_OUTPUT_CONVERSION:
|
||||
console.log("[red]Check output ffmpeg")
|
||||
time.sleep(0.5)
|
||||
check_ffmpeg_input(out_path)
|
||||
|
||||
@ -426,5 +430,6 @@ def join_subtitle(video_path: str, subtitles_list: List[Dict[str, str]], out_pat
|
||||
|
||||
# Check file
|
||||
if CHECK_OUTPUT_CONVERSION:
|
||||
console.log("[red]Check output ffmpeg")
|
||||
time.sleep(0.5)
|
||||
check_ffmpeg_input(out_path)
|
||||
|
@ -7,6 +7,10 @@ from datetime import datetime
|
||||
from concurrent.futures import ThreadPoolExecutor
|
||||
|
||||
|
||||
# External library
|
||||
from unidecode import unidecode
|
||||
|
||||
|
||||
# Internal utilities
|
||||
from Src.Lib.Request.my_requests import requests
|
||||
from Src.Util.headers import get_headers
|
||||
@ -41,10 +45,6 @@ from .segments import M3U8_Segments
|
||||
from ..E_Table import report_table
|
||||
|
||||
|
||||
# External library
|
||||
from unidecode import unidecode as transliterate
|
||||
|
||||
|
||||
# Config
|
||||
DOWNLOAD_SPECIFIC_AUDIO = config_manager.get_list('M3U8_FILTER', 'specific_list_audio')
|
||||
DOWNLOAD_SPECIFIC_SUBTITLE = config_manager.get_list('M3U8_FILTER', 'specific_list_subtitles')
|
||||
@ -89,7 +89,7 @@ class Downloader():
|
||||
sys.exit(0)
|
||||
|
||||
self.output_filename = os.path.join(folder, base_name)
|
||||
self.output_filename = transliterate(self.output_filename)
|
||||
self.output_filename = unidecode(self.output_filename)
|
||||
|
||||
logging.info(f"Output filename: {self.output_filename}")
|
||||
|
||||
|
@ -3,8 +3,8 @@
|
||||
"debug": false,
|
||||
"log_file": "app.log",
|
||||
"log_to_file": true,
|
||||
"show_message": false,
|
||||
"clean_console": false,
|
||||
"show_message": true,
|
||||
"clean_console": true,
|
||||
"root_path": "Video",
|
||||
"map_episode_name": "%(tv_name)_S%(season)E%(episode)_%(episode_name)",
|
||||
"create_job_database": false,
|
||||
|
1
run.py
1
run.py
@ -18,6 +18,7 @@ from Src.Upload.update import update as git_update
|
||||
from Src.Lib.FFmpeg import check_ffmpeg
|
||||
from Src.Util.logger import Logger
|
||||
|
||||
|
||||
# Internal api
|
||||
from Src.Api.Streamingcommunity import main_film_series as streamingcommunity_film_serie
|
||||
from Src.Api.Animeunity import main_anime as streamingcommunity_anime
|
||||
|
Loading…
x
Reference in New Issue
Block a user