test1
This commit is contained in:
parent
ebe1615e15
commit
24ca1a406f
@ -127,6 +127,11 @@
|
||||
<medium>448000</medium>
|
||||
<high>640000</high>
|
||||
</multi_channel>
|
||||
<surround_8ch>
|
||||
<low>640000</low>
|
||||
<medium>768000</medium>
|
||||
<high>1024000</high>
|
||||
</surround_8ch>
|
||||
</audio>
|
||||
|
||||
<!-- =============================
|
||||
|
||||
@ -3288,3 +3288,26 @@ anime,Chivalry of a Failed Knight (2015),Chivalry of a Failed Knight - S01E10 -
|
||||
anime,Chivalry of a Failed Knight (2015),Chivalry of a Failed Knight - S01E11 - Another One - The Uncrowned Sword King I h264 FLAC Bluray-1080p Remux CRUCiBLE - [EHX].mkv,3490.64,435.55,12.5,1920x1080,1920x1080,2,32,CQ
|
||||
anime,Chivalry of a Failed Knight (2015),Chivalry of a Failed Knight - S01E12 - Another One - The Uncrowned Sword King II h264 FLAC Bluray-1080p Remux CRUCiBLE - [EHX].mkv,3464.98,357.96,10.3,1920x1080,1920x1080,3,32,CQ
|
||||
tv,The Morning Show,The Morning Show - S01E01 - In the Dark Night of the Soul It's Always 3-30 in the Morning x265 EAC3 Atmos WEBDL-1080p t3nzin - [EHX].mkv,2042.56,914.35,44.8,1920x960,1920x960,1,28,CQ
|
||||
movie,N/A,output - [EHX].mkv,31649.13,2532.85,8.0,1920x1080,1920x804,2,32,CQ
|
||||
tv,The Morning Show,The Morning Show - S01E02 - A Seat at the Table x265 EAC3 Atmos WEBDL-1080p t3nzin - [EHX].mkv,1784.57,831.4,46.6,1920x960,1920x960,1,28,CQ
|
||||
tv,The Morning Show,The Morning Show - S01E03 - Chaos Is the New Cocaine x265 EAC3 Atmos WEBDL-1080p t3nzin - [EHX].mkv,1720.58,759.03,44.1,1920x960,1920x960,1,28,CQ
|
||||
tv,The Morning Show,The Morning Show - S01E04 - That Woman x265 EAC3 Atmos WEBDL-1080p t3nzin - [EHX].mkv,1606.77,689.17,42.9,1920x960,1920x960,1,28,CQ
|
||||
tv,The Morning Show,"The Morning Show - S01E05 - No One's Gonna Harm You, Not While I'm Around x265 EAC3 Atmos WEBDL-1080p t3nzin - [EHX].mkv",2069.83,864.23,41.8,1920x960,1920x960,1,28,CQ
|
||||
tv,The Morning Show,The Morning Show - S01E06 - The Pendulum Swings x265 EAC3 Atmos WEBDL-1080p t3nzin - [EHX].mkv,1800.73,795.15,44.2,1920x960,1920x960,1,28,CQ
|
||||
tv,The Morning Show,The Morning Show - S01E07 - Open Waters x265 EAC3 Atmos WEBDL-1080p t3nzin - [EHX].mkv,1823.72,729.46,40.0,1920x960,1920x960,1,28,CQ
|
||||
tv,The Morning Show,The Morning Show - S01E08 - Lonely at the Top x265 EAC3 Atmos WEBDL-1080p t3nzin - [EHX].mkv,1969.96,1051.15,53.4,1920x960,1920x960,1,28,CQ
|
||||
tv,The Morning Show,The Morning Show - S01E09 - Play the Queen x265 EAC3 Atmos WEBDL-1080p t3nzin - [EHX].mkv,1950.78,708.66,36.3,1920x960,1920x960,1,28,CQ
|
||||
tv,The Morning Show,The Morning Show - S01E10 - The Interview x265 EAC3 Atmos WEBDL-1080p t3nzin - [EHX].mkv,2131.99,919.32,43.1,1920x960,1920x960,1,28,CQ
|
||||
anime,Chaos Dragon (2015),Chaos Dragon - Sekiryuu Seneki 1 - [EHX].mkv,6773.93,360.9,5.3,1920x1080,1920x1080,3,32,CQ
|
||||
anime,Chaos Dragon (2015),Chaos Dragon - Sekiryuu Seneki 10 - [EHX].mkv,7592.28,364.65,4.8,1920x1080,1920x1080,3,32,CQ
|
||||
anime,Chaos Dragon (2015),Chaos Dragon - Sekiryuu Seneki 11 - [EHX].mkv,7593.23,374.88,4.9,1920x1080,1920x1080,3,32,CQ
|
||||
anime,Chaos Dragon (2015),Chaos Dragon - Sekiryuu Seneki 12 - [EHX].mkv,7548.73,385.42,5.1,1920x1080,1920x1080,3,32,CQ
|
||||
anime,Chaos Dragon (2015),Chaos Dragon - Sekiryuu Seneki 3 - [EHX].mkv,7574.79,330.86,4.4,1920x1080,1920x1080,3,32,CQ
|
||||
anime,Chaos Dragon (2015),Chaos Dragon - Sekiryuu Seneki 4 - [EHX].mkv,7563.95,337.94,4.5,1920x1080,1920x1080,3,32,CQ
|
||||
anime,Chaos Dragon (2015),Chaos Dragon - Sekiryuu Seneki 5 - [EHX].mkv,7592.28,330.86,4.4,1920x1080,1920x1080,3,32,CQ
|
||||
anime,Chaos Dragon (2015),Chaos Dragon - Sekiryuu Seneki 6 - [EHX].mkv,7604.28,331.41,4.4,1920x1080,1920x1080,3,32,CQ
|
||||
anime,Chaos Dragon (2015),Chaos Dragon - Sekiryuu Seneki 7 - [EHX].mkv,7607.11,372.48,4.9,1920x1080,1920x1080,3,32,CQ
|
||||
anime,Chaos Dragon (2015),Chaos Dragon - Sekiryuu Seneki 8 - [EHX].mkv,7538.8,313.37,4.2,1920x1080,1920x1080,3,32,CQ
|
||||
anime,Chaos Dragon (2015),Chaos Dragon - Sekiryuu Seneki 9 - [EHX].mkv,7570.84,364.14,4.8,1920x1080,1920x1080,3,32,CQ
|
||||
anime,Chaos Dragon (2015),Chaos Dragon - Sekiryuu Seneki 2 - [EHX].mkv,6744.61,396.4,5.9,1920x1080,1920x1080,3,32,CQ
|
||||
movie,N/A,The Mandalorian and Grogu (2026) h264 TrueHD Atmos 7.1 Remux-1080p BTM - [EHX].mkv,42712.99,1982.05,4.6,1920x1080,1920x1080,8,32,CQ
|
||||
|
||||
|
Can't render this file because it has a wrong number of fields in line 14.
|
@ -127,13 +127,20 @@ def calculate_stream_bitrate(input_file: Path, stream_index: int) -> int:
|
||||
logger.warning(f"Could not delete temporary file {temp_audio_path}: {e}")
|
||||
|
||||
|
||||
def get_audio_streams(input_file: Path):
|
||||
def get_audio_streams(input_file: Path, skip_audio_check: bool = False):
|
||||
"""
|
||||
Detect audio streams and calculate robust bitrates by extracting each stream.
|
||||
Returns list of (index, channels, calculated_bitrate_kbps, language, metadata_bitrate_kbps, title)
|
||||
|
||||
Args:
|
||||
input_file: Path to video file
|
||||
skip_audio_check: If True, skip bitrate calculation and use metadata instead (faster for testing)
|
||||
"""
|
||||
import re
|
||||
|
||||
print(f"[DEBUG] get_audio_streams called with skip_audio_check={skip_audio_check}") # DEBUG
|
||||
logger.debug(f"get_audio_streams: skip_audio_check={skip_audio_check}") # DEBUG
|
||||
|
||||
# First, get full ffprobe output to extract language codes and titles
|
||||
probe_cmd = ["ffprobe", "-v", "info", str(input_file)]
|
||||
probe_result = subprocess.run(probe_cmd, capture_output=True, text=True, encoding='utf-8', errors='ignore')
|
||||
@ -190,7 +197,12 @@ def get_audio_streams(input_file: Path):
|
||||
|
||||
bit_rate_meta = int(s.get("bit_rate", 0)) if s.get("bit_rate") else 0
|
||||
|
||||
# Calculate robust bitrate by extracting the audio stream
|
||||
# Calculate robust bitrate by extracting the audio stream (skip if --skip-audio-check flag is set)
|
||||
if skip_audio_check:
|
||||
# Use metadata bitrate only (faster for testing)
|
||||
calculated_bitrate_kbps = int(bit_rate_meta / 1000) if bit_rate_meta else 160
|
||||
logger.info(f"Stream {index}: Skipped audio bitrate check, using metadata bitrate {calculated_bitrate_kbps} kbps")
|
||||
else:
|
||||
calculated_bitrate_kbps = calculate_stream_bitrate(input_file, stream_num)
|
||||
|
||||
# If calculation failed, fall back to metadata
|
||||
@ -234,7 +246,7 @@ def find_nearest_bitrate(source_bitrate_kbps: int, candidate_bitrates: list, thr
|
||||
return 0 # No match within threshold
|
||||
|
||||
|
||||
def choose_audio_bitrate(channels: int, bitrate_kbps: int, audio_config: dict, is_1080_class: bool, is_commentary: bool = False, resolution: str = "1080") -> tuple:
|
||||
def choose_audio_bitrate(channels: int, bitrate_kbps: int, audio_config: dict, is_1080_class: bool, is_commentary: bool = False, resolution: str = "1080", codec_name: str = None) -> tuple:
|
||||
"""
|
||||
Choose audio codec and bitrate based on channel count, detected bitrate, and resolution.
|
||||
|
||||
@ -260,7 +272,7 @@ def choose_audio_bitrate(channels: int, bitrate_kbps: int, audio_config: dict, i
|
||||
- 4K with 6/8 channels: allow "high" bitrate
|
||||
- Below minimum threshold → preserve (copy)
|
||||
"""
|
||||
logger.debug(f"choose_audio_bitrate() called: channels={channels}, bitrate={bitrate_kbps}k, resolution={resolution}, is_commentary={is_commentary}, is_1080={is_1080_class}")
|
||||
logger.debug(f"choose_audio_bitrate() called: channels={channels}, bitrate={bitrate_kbps}k, resolution={resolution}, codec={codec_name}, is_commentary={is_commentary}, is_1080={is_1080_class}")
|
||||
|
||||
# Commentary tracks use low stereo bitrate, but copy if below threshold
|
||||
if is_commentary:
|
||||
@ -279,7 +291,7 @@ def choose_audio_bitrate(channels: int, bitrate_kbps: int, audio_config: dict, i
|
||||
|
||||
# Determine max channels based on resolution
|
||||
if resolution == "2160":
|
||||
max_channels = 6
|
||||
max_channels = 8
|
||||
elif resolution == "1080":
|
||||
max_channels = 6
|
||||
else: # 720, 480, etc.
|
||||
@ -326,13 +338,22 @@ def choose_audio_bitrate(channels: int, bitrate_kbps: int, audio_config: dict, i
|
||||
return ("copy", 0, 2)
|
||||
|
||||
else:
|
||||
# Multi-channel (6ch or 8ch) logic - use EAC3
|
||||
# Multi-channel (6ch or 8ch) logic - ALWAYS encode to EAC3
|
||||
# For 4K 8-channel, use surround_8ch tier; otherwise use multi_channel tier
|
||||
if resolution == "2160" and output_channels == 8:
|
||||
# 4K 7.1 surround: use dedicated high-bitrate tier
|
||||
low_br = audio_config["surround_8ch"]["low"]
|
||||
medium_br = audio_config["surround_8ch"]["medium"]
|
||||
high_br = audio_config["surround_8ch"]["high"]
|
||||
max_bitrate = high_br # 4K 8ch uses full range
|
||||
else:
|
||||
# Standard multi-channel (1080p 5.1 or lower resolutions)
|
||||
low_br = audio_config["multi_channel"]["low"]
|
||||
medium_br = audio_config["multi_channel"]["medium"]
|
||||
high_br = audio_config["multi_channel"]["high"]
|
||||
|
||||
# Apply resolution-based bitrate cap FIRST (before matching logic)
|
||||
# 4K can use all tiers; 1080p capped at medium; 720p capped at low
|
||||
# 4K 6ch capped at high; 1080p capped at medium; 720p capped at low
|
||||
if resolution == "2160":
|
||||
max_bitrate = high_br
|
||||
elif resolution == "1080":
|
||||
@ -349,23 +370,27 @@ def choose_audio_bitrate(channels: int, bitrate_kbps: int, audio_config: dict, i
|
||||
matched_br = find_nearest_bitrate(bitrate_kbps, multi_bitrates)
|
||||
if matched_br > 0:
|
||||
# Within threshold of a standard bitrate, use that one with EAC3
|
||||
logger.info(f"Multi-channel {output_channels}ch audio: matched bitrate {matched_br/1000:.0f}k → EAC3")
|
||||
return ("eac3", matched_br, output_channels)
|
||||
|
||||
# Not within threshold, check if bitrate is too low to encode this channel count
|
||||
# Not within threshold - force EAC3 encoding with appropriate bitrate
|
||||
# EXCEPT: for very low bitrate audio, copy original to avoid quality loss
|
||||
if bitrate_kbps < (low_br / 1000):
|
||||
# Source bitrate is below minimum for multi-channel encoding
|
||||
# Preserve the original multi-channel audio instead of downmixing to stereo
|
||||
# Preserve the original multi-channel audio to avoid quality loss
|
||||
logger.info(f"Multi-channel audio {bitrate_kbps}kbps < {low_br/1000:.0f}k minimum - copying original {output_channels}ch to avoid quality loss")
|
||||
logger.debug(f"COPY decision: codec=copy, br=0, channels={output_channels}")
|
||||
return ("copy", 0, output_channels)
|
||||
elif bitrate_kbps < (medium_br / 1000):
|
||||
# Below medium, use low with EAC3
|
||||
logger.info(f"Multi-channel {output_channels}ch audio {bitrate_kbps}kbps: forcing EAC3 at low {low_br/1000:.0f}k")
|
||||
return ("eac3", low_br, output_channels)
|
||||
elif bitrate_kbps >= (high_br / 1000) and resolution == "2160":
|
||||
# Only allow high bitrate for 4K
|
||||
# High bitrate on 4K - use high EAC3
|
||||
logger.info(f"Multi-channel {output_channels}ch audio {bitrate_kbps}kbps (4K): forcing EAC3 at high {high_br/1000:.0f}k")
|
||||
return ("eac3", high_br, output_channels)
|
||||
else:
|
||||
# Default to medium for 1080p and below, or when high is not allowed
|
||||
# Default to medium for 1080p and below
|
||||
logger.info(f"Multi-channel {output_channels}ch audio {bitrate_kbps}kbps: forcing EAC3 at medium {medium_br/1000:.0f}k")
|
||||
return ("eac3", medium_br, output_channels)
|
||||
|
||||
def filter_audio_streams(input_file: Path, streams: list) -> list:
|
||||
|
||||
@ -44,7 +44,7 @@ def check_encoder_available(encoder_codec: str) -> bool:
|
||||
def run_ffmpeg(input_file: Path, output_file: Path, cq: int, scale_width: int, scale_height: int,
|
||||
src_width: int, src_height: int, filter_flags: str, audio_config: dict,
|
||||
method: str, bitrate_config: dict, encoder: str = "nvenc", subtitle_files: list = None, audio_language: str = None,
|
||||
audio_filter_config: dict = None, test_mode: bool = False, strip_all_titles: bool = False, src_bit_depth: int = None, unforce_subs: bool = False, no_encode: bool = False, color_bit: int = None, crop_height: int = None, audio_titles: dict = None, audio_channels: dict = None, is_hdr: bool = False):
|
||||
audio_filter_config: dict = None, test_mode: bool = False, strip_all_titles: bool = False, src_bit_depth: int = None, unforce_subs: bool = False, no_encode: bool = False, color_bit: int = None, crop_height: int = None, audio_titles: dict = None, audio_channels: dict = None, is_hdr: bool = False, skip_audio_check: bool = False):
|
||||
"""
|
||||
Execute FFmpeg encoding/re-muxing with structured console output.
|
||||
|
||||
@ -72,11 +72,12 @@ def run_ffmpeg(input_file: Path, output_file: Path, cq: int, scale_width: int, s
|
||||
audio_titles: Dict mapping stream index to custom title. E.g., {1: "Commentary"} sets stream 1 title to "Commentary".
|
||||
audio_channels: Dict mapping stream index to channel count. E.g., {0: 2, 1: 6} forces track 0 to stereo, track 1 to 5.1. Only 2 or 6 allowed.
|
||||
is_hdr: If True, source is HDR content (applies HDR color profiles)
|
||||
skip_audio_check: If True, skip audio bitrate calculation (uses metadata instead, speeds up testing)
|
||||
|
||||
Returns:
|
||||
tuple: (orig_size_bytes, output_size_bytes, reduction_ratio)
|
||||
"""
|
||||
streams = get_audio_streams(input_file)
|
||||
streams = get_audio_streams(input_file, skip_audio_check=skip_audio_check)
|
||||
|
||||
# Apply audio filter if enabled
|
||||
if audio_filter_config and audio_filter_config.get("enabled", False):
|
||||
@ -215,7 +216,7 @@ def run_ffmpeg(input_file: Path, output_file: Path, cq: int, scale_width: int, s
|
||||
output_channels = 6 if is_1080_class and channels >= 6 else 2
|
||||
channels_override = False
|
||||
|
||||
codec, br, final_channels = choose_audio_bitrate(output_channels, avg_bitrate, audio_config, is_1080_class, is_commentary, resolution_str)
|
||||
codec, br, final_channels = choose_audio_bitrate(output_channels, avg_bitrate, audio_config, is_1080_class, is_commentary, resolution_str, codec_name)
|
||||
|
||||
if codec == "copy":
|
||||
action = "COPY"
|
||||
@ -335,6 +336,53 @@ def run_ffmpeg(input_file: Path, output_file: Path, cq: int, scale_width: int, s
|
||||
logger.warning("No audio streams detected, including all audio from source")
|
||||
cmd.extend(["-map", "0:a"])
|
||||
|
||||
# Build audio filters for streams that need re-encoding with channel layout conversion
|
||||
# This is needed when downmixing (e.g., 7.1 TrueHD to 5.1 EAC3) to ensure proper channel remixing
|
||||
audio_filters_list = []
|
||||
for i, (index, channels, avg_bitrate, src_lang, meta_bitrate, title, codec_name) in enumerate(streams):
|
||||
# Determine output channels
|
||||
final_title = audio_titles.get(index, title) if audio_titles else title
|
||||
is_commentary = final_title and "commentary" in final_title.lower()
|
||||
is_1080_class = scale_height >= 1080 or scale_width >= 1920
|
||||
|
||||
# Determine resolution string for audio bitrate selection
|
||||
if scale_width >= 3840 or scale_height >= 2160:
|
||||
resolution_str = "2160"
|
||||
elif scale_height >= 1080 or scale_width >= 1920:
|
||||
resolution_str = "1080"
|
||||
else:
|
||||
resolution_str = "720"
|
||||
|
||||
if audio_channels and index in audio_channels:
|
||||
output_channels = audio_channels[index]
|
||||
elif is_commentary:
|
||||
output_channels = 2
|
||||
else:
|
||||
output_channels = 6 if is_1080_class and channels >= 6 else 2
|
||||
|
||||
# Only add audio filter if re-encoding (not copying) and channels need to be remixed
|
||||
if not no_encode:
|
||||
codec, br, final_channels = choose_audio_bitrate(output_channels, avg_bitrate, audio_config, is_1080_class, is_commentary, resolution_str, codec_name)
|
||||
if codec != "copy" and channels != final_channels:
|
||||
# Need to downmix/remix channels
|
||||
if final_channels >= 6:
|
||||
audio_filters_list.append(f"[0:a:{i}]aformat=channel_layouts=5.1[a{i}]")
|
||||
else:
|
||||
audio_filters_list.append(f"[0:a:{i}]aformat=channel_layouts=stereo[a{i}]")
|
||||
|
||||
# Add audio filter chain if any filters are needed
|
||||
if audio_filters_list:
|
||||
# Build complex filter: mark inputs and concat outputs
|
||||
# For simple case with one audio stream, we can use -af instead of -filter_complex
|
||||
if len(audio_filters_list) == 1 and len(streams) == 1:
|
||||
# Single audio stream: use simple -af filter
|
||||
filter_spec = audio_filters_list[0]
|
||||
# Extract just the filter part (between brackets)
|
||||
if '[0:a:0]' in filter_spec and '[a0]' in filter_spec:
|
||||
filter_content = filter_spec.split(']')[0].replace('[0:a:0]', '')
|
||||
cmd.extend(["-af", filter_content])
|
||||
logger.info(f"Applied audio filter for stream 0: {filter_content}")
|
||||
|
||||
# Add subtitle mapping if present
|
||||
if subtitle_files:
|
||||
for i, _ in enumerate(subtitle_files):
|
||||
@ -411,7 +459,7 @@ def run_ffmpeg(input_file: Path, output_file: Path, cq: int, scale_width: int, s
|
||||
if no_encode:
|
||||
codec, br, final_channels = "copy", avg_bitrate, output_channels
|
||||
else:
|
||||
codec, br, final_channels = choose_audio_bitrate(output_channels, avg_bitrate, audio_config, is_1080_class, is_commentary, resolution_str)
|
||||
codec, br, final_channels = choose_audio_bitrate(output_channels, avg_bitrate, audio_config, is_1080_class, is_commentary, resolution_str, codec_name)
|
||||
|
||||
# Check if title should be stripped (for this stream or globally)
|
||||
# Preserve any stream with "commentary" or "descriptive" in the title, regardless of strip_all_titles
|
||||
@ -447,16 +495,14 @@ def run_ffmpeg(input_file: Path, output_file: Path, cq: int, scale_width: int, s
|
||||
cmd += [
|
||||
f"-c:a:{i}", "eac3",
|
||||
f"-b:a:{i}", str(br),
|
||||
f"-ac:{i}", str(final_channels),
|
||||
f"-channel_layout:a:{i}", "5.1" if final_channels >= 6 else "stereo"
|
||||
f"-ac:{i}", str(final_channels)
|
||||
]
|
||||
else:
|
||||
# AAC (stereo)
|
||||
cmd += [
|
||||
f"-c:a:{i}", "aac",
|
||||
f"-b:a:{i}", str(br),
|
||||
f"-ac:{i}", str(final_channels),
|
||||
f"-channel_layout:a:{i}", "stereo"
|
||||
f"-ac:{i}", str(final_channels)
|
||||
]
|
||||
# Only add language metadata if explicitly provided
|
||||
if audio_language:
|
||||
@ -544,7 +590,7 @@ def run_ffmpeg(input_file: Path, output_file: Path, cq: int, scale_width: int, s
|
||||
ffmpeg_cmd_str = " ".join(cmd)
|
||||
logger.info(f"FFmpeg command: {ffmpeg_cmd_str}")
|
||||
print(f"🔧 FFmpeg command (for debugging):")
|
||||
print(f" {' '.join(cmd[:10])}...") # Print first part of command
|
||||
print(f" {ffmpeg_cmd_str}")
|
||||
|
||||
# Initialize black frame detector
|
||||
black_detector = BlackFrameDetector(duration_seconds=300) # Monitor first 5 minutes
|
||||
|
||||
@ -99,7 +99,7 @@ def should_skip_file(file: Path, no_encode: bool, unforce_subs: bool, force_proc
|
||||
return False, None
|
||||
|
||||
|
||||
def process_folder(folder: Path, cq: int, transcode_mode: str, resolution: str, config: dict, tracker_file: Path, test_mode: bool = False, audio_language: str = None, filter_audio: bool = None, audio_select: str = None, encoder: str = "hevc", strip_all_titles: bool = False, travel_output_folder: Path = None, unforce_subs: bool = False, no_encode: bool = False, force_process: bool = False, replace_file: bool = False, wait_seconds: int = 0, color_bit: int = None, crop_height: int = None, audio_titles: dict = None, audio_channels: dict = None, title_suffix: str = None, default_language: str = None, no_replace_und: bool = False, move_mode: bool = False, keep_original: bool = False):
|
||||
def process_folder(folder: Path, cq: int, transcode_mode: str, resolution: str, config: dict, tracker_file: Path, test_mode: bool = False, audio_language: str = None, filter_audio: bool = None, audio_select: str = None, encoder: str = "hevc", strip_all_titles: bool = False, travel_output_folder: Path = None, unforce_subs: bool = False, no_encode: bool = False, force_process: bool = False, replace_file: bool = False, wait_seconds: int = 0, color_bit: int = None, crop_height: int = None, audio_titles: dict = None, audio_channels: dict = None, title_suffix: str = None, default_language: str = None, no_replace_und: bool = False, move_mode: bool = False, keep_original: bool = False, skip_audio_check: bool = False):
|
||||
"""
|
||||
Process all video files in folder with appropriate encoding settings.
|
||||
|
||||
@ -388,7 +388,7 @@ def process_folder(folder: Path, cq: int, transcode_mode: str, resolution: str,
|
||||
orig_size, out_size, reduction_ratio = run_ffmpeg(
|
||||
temp_input, temp_output, file_cq, res_width, res_height, src_width, src_height,
|
||||
filter_flags, audio_config, method, bitrate_config, actual_encoder, [subtitle_file] if subtitle_file else None, effective_audio_language,
|
||||
audio_filter_config, test_mode, strip_all_titles, src_bit_depth, unforce_subs, no_encode, color_bit, crop_height, audio_titles, audio_channels
|
||||
audio_filter_config, test_mode, strip_all_titles, src_bit_depth, unforce_subs, no_encode, color_bit, crop_height, audio_titles, audio_channels, False, skip_audio_check
|
||||
)
|
||||
|
||||
# Check if encode met size target
|
||||
@ -569,7 +569,7 @@ def process_folder(folder: Path, cq: int, transcode_mode: str, resolution: str,
|
||||
file_data['src_width'], file_data['src_height'],
|
||||
filter_flags, audio_config, "Bitrate", bitrate_config, file_data.get('encoder', encoder),
|
||||
[file_data.get('subtitle_file')] if file_data.get('subtitle_file') else None, file_data.get('effective_audio_language'), None, test_mode, strip_all_titles,
|
||||
file_data.get('src_bit_depth'), unforce_subs, no_encode, color_bit, crop_height, audio_titles, audio_channels
|
||||
file_data.get('src_bit_depth'), unforce_subs, no_encode, color_bit, crop_height, audio_titles, audio_channels, False, skip_audio_check
|
||||
)
|
||||
|
||||
# Check if bitrate also failed
|
||||
|
||||
12195
logs/conversion.log
12195
logs/conversion.log
File diff suppressed because it is too large
Load Diff
@ -179,3 +179,6 @@
|
||||
2026-08-19 22:58:57 | Colonel Miles Quaritch RDA Promos.mkv | CQ error: Command '['ffmpeg', '-y', '-i', 'C:\\Users\\Tyler\\Documents\\GitHub\\conversion_project\\processing
|
||||
2026-08-19 23:02:25 | Colonel Miles Quaritch RDA Promos.mkv | CQ error: Command '['ffmpeg', '-y', '-i', 'C:\\Users\\Tyler\\Documents\\GitHub\\conversion_project\\processing
|
||||
2026-08-19 23:04:20 | Colonel Miles Quaritch RDA Promos.mkv | CQ error: Command '['ffmpeg', '-y', '-i', 'C:\\Users\\Tyler\\Documents\\GitHub\\conversion_project\\processing
|
||||
2026-08-20 12:25:00 | The Morning Show - S02E01 - My Least Favorite Year x265 EAC3 Atmos WEBDL-1080p t3nzin.mkv | Unexpected error: 'charmap' codec can't decode byte 0x81 in position 79: character maps to <undefined>
|
||||
2026-08-20 12:25:34 | The Morning Show - S02E02 - It’s Like the Flu x265 EAC3 Atmos WEBDL-1080p t3nzin.mkv | Unexpected error: 'charmap' codec can't decode byte 0x81 in position 13: character maps to <undefined>
|
||||
2026-08-22 00:50:44 | Dungeons and Dragons - Honor Among Thieves_t00.mkv | Unexpected error: [WinError 32] The process cannot access the file because it is being used by another process: 'C:\\U
|
||||
|
||||
12
main.py
12
main.py
@ -472,6 +472,10 @@ Examples:
|
||||
"--retry-timeout", dest="retry_timeout", type=int, default=None,
|
||||
help="Queue mode: Total minutes to keep retrying before giving up (default: from config.xml). If source becomes reachable during retry, queue will immediately restart"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--skip-audio-check", dest="skip_audio_check", default=False, action="store_true",
|
||||
help="Skip audio bitrate calculation (speeds up testing). Uses metadata bitrate instead of extracting streams"
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
# Load configuration
|
||||
@ -640,7 +644,7 @@ Examples:
|
||||
merged_args.filter_audio, merged_args.audio_select, merged_args.encoder,
|
||||
merged_args.strip_all_titles, travel_output_folder, merged_args.unforce_subs,
|
||||
merged_args.no_encode, merged_args.ignore_tags, merged_args.force_encode, merged_args.replace_file,
|
||||
merged_args.wait_seconds, crop_height=merged_args.crop_height, audio_titles=audio_titles_dict, audio_channels=audio_channels_dict, title_suffix=merged_args.title_suffix, move_mode=merged_args.move_mode, keep_original=merged_args.keep_original
|
||||
merged_args.wait_seconds, crop_height=merged_args.crop_height, audio_titles=audio_titles_dict, audio_channels=audio_channels_dict, title_suffix=merged_args.title_suffix, move_mode=merged_args.move_mode, keep_original=merged_args.keep_original, skip_audio_check=merged_args.skip_audio_check
|
||||
)
|
||||
|
||||
print(f"✓ [BATCH {batch_num}] Completed: {folder.name}")
|
||||
@ -771,7 +775,7 @@ Examples:
|
||||
merged_args.filter_audio, merged_args.audio_select, merged_args.encoder,
|
||||
merged_args.strip_all_titles, travel_output_folder, merged_args.unforce_subs,
|
||||
merged_args.no_encode, merged_args.ignore_tags, merged_args.force_encode, merged_args.replace_file,
|
||||
merged_args.wait_seconds, crop_height=merged_args.crop_height, audio_titles=audio_titles_dict, audio_channels=audio_channels_dict, title_suffix=merged_args.title_suffix, move_mode=merged_args.move_mode, keep_original=merged_args.keep_original
|
||||
merged_args.wait_seconds, crop_height=merged_args.crop_height, audio_titles=audio_titles_dict, audio_channels=audio_channels_dict, title_suffix=merged_args.title_suffix, move_mode=merged_args.move_mode, keep_original=merged_args.keep_original, skip_audio_check=merged_args.skip_audio_check
|
||||
)
|
||||
|
||||
print(f"✓ [BATCH {batch_num}] Completed: {folder.name}")
|
||||
@ -972,7 +976,7 @@ Examples:
|
||||
merged_args.filter_audio, merged_args.audio_select, merged_args.encoder,
|
||||
merged_args.strip_all_titles, retry_travel_output_folder, merged_args.unforce_subs,
|
||||
merged_args.no_encode, merged_args.ignore_tags, merged_args.force_encode, merged_args.replace_file,
|
||||
merged_args.wait_seconds, crop_height=merged_args.crop_height, audio_titles=audio_titles_dict, audio_channels=audio_channels_dict, title_suffix=merged_args.title_suffix, move_mode=merged_args.move_mode, keep_original=merged_args.keep_original
|
||||
merged_args.wait_seconds, crop_height=merged_args.crop_height, audio_titles=audio_titles_dict, audio_channels=audio_channels_dict, title_suffix=merged_args.title_suffix, move_mode=merged_args.move_mode, keep_original=merged_args.keep_original, skip_audio_check=merged_args.skip_audio_check
|
||||
)
|
||||
|
||||
print(f"✓ [RETRY {batch_num}] Completed: {retry_folder.name}")
|
||||
@ -1102,7 +1106,7 @@ Examples:
|
||||
args.wait_seconds = 30 if args.no_encode else 0 # --wait used without value
|
||||
|
||||
# Process folder
|
||||
process_folder(folder, args.cq, args.transcode_mode, args.resolution, config, TRACKER_FILE, args.test_mode, args.audio_language, args.filter_audio, args.audio_select, args.encoder, args.strip_all_titles, travel_output_folder, args.unforce_subs, args.no_encode, args.ignore_tags, args.replace_file, args.wait_seconds, color_bit=getattr(args, 'color_bit', None), crop_height=args.crop_height, audio_titles=audio_titles_dict, audio_channels=audio_channels_dict, title_suffix=args.title_suffix, default_language=getattr(args, 'default_language', None), no_replace_und=getattr(args, 'no_replace_und', False), move_mode=args.move_mode, keep_original=args.keep_original)
|
||||
process_folder(folder, args.cq, args.transcode_mode, args.resolution, config, TRACKER_FILE, args.test_mode, args.audio_language, args.filter_audio, args.audio_select, args.encoder, args.strip_all_titles, travel_output_folder, args.unforce_subs, args.no_encode, args.ignore_tags, args.replace_file, args.wait_seconds, color_bit=getattr(args, 'color_bit', None), crop_height=args.crop_height, audio_titles=audio_titles_dict, audio_channels=audio_channels_dict, title_suffix=args.title_suffix, default_language=getattr(args, 'default_language', None), no_replace_und=getattr(args, 'no_replace_und', False), move_mode=args.move_mode, keep_original=args.keep_original, skip_audio_check=args.skip_audio_check)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
# "P:\anime\Witch Hat Atelier (2026)"
|
||||
"P:\tv\The Morning Show\Season 1"
|
||||
# "C:\Users\Tyler\Videos\Video Conversion\Input\test" --crop 804 --audio-select 2
|
||||
# "P:\tv\The Morning Show\Season 1"
|
||||
"P:\tv\The Morning Show\Season 2"
|
||||
"P:\tv\The Morning Show\Season 3"
|
||||
Loading…
x
Reference in New Issue
Block a user