fixed
This commit is contained in:
parent
f32177e69a
commit
1fe0feef33
@ -3311,3 +3311,4 @@ anime,Chaos Dragon (2015),Chaos Dragon - Sekiryuu Seneki 8 - [EHX].mkv,7538.8,31
|
||||
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
|
||||
movie,N/A,Dungeons and Dragons - Honor Among Thieves_t00 - [EHX].mkv,31591.75,2174.97,6.9,1920x1080,1920x804,2,28,CQ
|
||||
|
||||
|
Can't render this file because it has a wrong number of fields in line 14.
|
@ -369,11 +369,12 @@ def choose_audio_bitrate(channels: int, bitrate_kbps: int, audio_config: dict, i
|
||||
# Check if source is within -10kbps of a standard bitrate
|
||||
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)
|
||||
# Within threshold of a standard bitrate, use that one with EAC3 (or Opus for 8ch)
|
||||
codec = "opus" if output_channels == 8 else "eac3"
|
||||
logger.info(f"Multi-channel {output_channels}ch audio: matched bitrate {matched_br/1000:.0f}k → {codec.upper()}")
|
||||
return (codec, matched_br, output_channels)
|
||||
|
||||
# Not within threshold - force EAC3 encoding with appropriate bitrate
|
||||
# Not within threshold - force EAC3/Opus 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
|
||||
@ -381,17 +382,22 @@ def choose_audio_bitrate(channels: int, bitrate_kbps: int, audio_config: dict, i
|
||||
logger.info(f"Multi-channel audio {bitrate_kbps}kbps < {low_br/1000:.0f}k minimum - copying original {output_channels}ch to avoid quality loss")
|
||||
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)
|
||||
# Below medium, use low bitrate
|
||||
codec = "opus" if output_channels == 8 else "eac3"
|
||||
logger.info(f"Multi-channel {output_channels}ch audio {bitrate_kbps}kbps: forcing {codec.upper()} at low {low_br/1000:.0f}k")
|
||||
return (codec, low_br, output_channels)
|
||||
elif bitrate_kbps >= (high_br / 1000) and resolution == "2160":
|
||||
# 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)
|
||||
# High bitrate on 4K - use high bitrate codec (but cap Opus at medium)
|
||||
codec = "opus" if output_channels == 8 else "eac3"
|
||||
target_br = medium_br if output_channels == 8 else high_br
|
||||
br_label = "medium" if output_channels == 8 else "high"
|
||||
logger.info(f"Multi-channel {output_channels}ch audio {bitrate_kbps}kbps (4K): forcing {codec.upper()} at {br_label} {target_br/1000:.0f}k")
|
||||
return (codec, target_br, output_channels)
|
||||
else:
|
||||
# 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)
|
||||
codec = "opus" if output_channels == 8 else "eac3"
|
||||
logger.info(f"Multi-channel {output_channels}ch audio {bitrate_kbps}kbps: forcing {codec.upper()} at medium {medium_br/1000:.0f}k")
|
||||
return (codec, 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, skip_audio_check: 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, use_remux_for_subs: bool = False):
|
||||
"""
|
||||
Execute FFmpeg encoding/re-muxing with structured console output.
|
||||
|
||||
@ -68,6 +68,7 @@ def run_ffmpeg(input_file: Path, output_file: Path, cq: int, scale_width: int, s
|
||||
unforce_subs: If True, remove forced flag from subtitle tracks
|
||||
no_encode: If True, copy video/audio (re-mux only, skip encoding)
|
||||
color_bit: If specified (8 or 10), forces HEVC color bit depth. 8-bit uses yuv420p, 10-bit uses p010le.
|
||||
use_remux_for_subs: If True, add subtitles in a separate remux pass (for PGS handling)
|
||||
crop_height: If specified, crop video to this height (centered). E.g., 816 for 1920x816 from 1920x1080 source.
|
||||
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.
|
||||
@ -133,8 +134,9 @@ def run_ffmpeg(input_file: Path, output_file: Path, cq: int, scale_width: int, s
|
||||
encoder_pix_fmt = "p010le"
|
||||
encoder_bit_depth = "10-bit"
|
||||
logger.info(f"Using --color-bit {color_bit}: HEVC NVENC 10-bit (p010le)")
|
||||
# Auto-select encoder based on detected source bit depth if provided (only if --color-bit not specified)
|
||||
elif src_bit_depth is not None and color_bit is None:
|
||||
# Auto-select encoder based on detected source bit depth only if user didn't explicitly specify one
|
||||
# (this only runs if encoder is None, otherwise user selection takes precedence)
|
||||
elif encoder is None and src_bit_depth is not None and color_bit is None:
|
||||
if src_bit_depth >= 10:
|
||||
# Source is 10-bit or higher - use HEVC NVENC
|
||||
encoder_name = "HEVC NVENC"
|
||||
@ -327,18 +329,10 @@ def run_ffmpeg(input_file: Path, output_file: Path, cq: int, scale_width: int, s
|
||||
|
||||
cmd.extend(["-map","0:v:0"]) # Map only first actual video stream (skips attached pictures)
|
||||
|
||||
# Map only selected audio streams
|
||||
if streams:
|
||||
for index, _, _, _, _, _, _ in streams:
|
||||
cmd.extend(["-map", f"0:{index}"])
|
||||
else:
|
||||
# Fallback: if no audio streams detected, include all audio from source
|
||||
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
|
||||
@ -365,30 +359,34 @@ def run_ffmpeg(input_file: Path, output_file: Path, cq: int, scale_width: int, s
|
||||
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
|
||||
# Use actual stream index, not enumeration index
|
||||
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}")
|
||||
# Map only selected audio streams
|
||||
if streams:
|
||||
for index, _, _, _, _, _, _ in streams:
|
||||
cmd.extend(["-map", f"0:{index}"])
|
||||
else:
|
||||
# Fallback: if no audio streams detected, include all audio from source
|
||||
logger.warning("No audio streams detected, including all audio from source")
|
||||
cmd.extend(["-map", "0:a"])
|
||||
|
||||
|
||||
|
||||
# Add subtitle mapping if present
|
||||
if subtitle_files:
|
||||
if not use_remux_for_subs:
|
||||
# Include subtitles in main encode (no PGS in source)
|
||||
for i, _ in enumerate(subtitle_files):
|
||||
cmd.extend(["-map", f"{i+1}:s"])
|
||||
else:
|
||||
cmd.extend(["-map", "0:s?"])
|
||||
# Skip subtitles in main encode (has PGS - will add via remux after)
|
||||
# This avoids conflicts with bitmap subtitle codecs
|
||||
pass
|
||||
|
||||
|
||||
# Video codec: copy if no_encode, otherwise use specified encoder
|
||||
if no_encode:
|
||||
@ -489,8 +487,15 @@ def run_ffmpeg(input_file: Path, output_file: Path, cq: int, scale_width: int, s
|
||||
cmd += [f"-metadata:s:a:{i}", "title="]
|
||||
else:
|
||||
# Re-encode with target bitrate
|
||||
# EAC3 for multichannel, AAC for stereo
|
||||
if codec == "eac3":
|
||||
# Opus for 8-channel, EAC3 for multichannel, AAC for stereo
|
||||
if codec == "opus":
|
||||
# Opus (supports 7.1/8-channel surround)
|
||||
cmd += [
|
||||
f"-c:a:{i}", "libopus",
|
||||
f"-b:a:{i}", str(br),
|
||||
f"-ac:{i}", str(final_channels)
|
||||
]
|
||||
elif codec == "eac3":
|
||||
# Enhanced AC-3 (5.1 surround)
|
||||
cmd += [
|
||||
f"-c:a:{i}", "eac3",
|
||||
@ -687,4 +692,56 @@ def run_ffmpeg(input_file: Path, output_file: Path, cq: int, scale_width: int, s
|
||||
test_preview_file.unlink()
|
||||
logger.info(f"Cleaned up test preview copy: {test_preview_file}")
|
||||
|
||||
# If using remux mode (PGS present), add subtitles (both embedded and external) via remux pass
|
||||
if use_remux_for_subs:
|
||||
logger.info(f"Adding subtitles via remux pass (PGS handling)...")
|
||||
temp_remux_file = output_file.parent / f"{output_file.stem}_remux.mkv"
|
||||
|
||||
# Build remux command: input is encoded file, add subtitles from original + external
|
||||
remux_cmd = [
|
||||
"ffmpeg", "-y",
|
||||
"-i", str(output_file), # Encoded video+audio
|
||||
"-i", str(input_file), # Original file for embedded subtitles
|
||||
]
|
||||
|
||||
# Add external subtitle files if present
|
||||
if subtitle_files:
|
||||
for sub_file in subtitle_files:
|
||||
remux_cmd.extend(["-i", str(sub_file)])
|
||||
|
||||
# Build mapping: all from encoded, subtitles from original, then external subs
|
||||
remux_cmd.extend([
|
||||
"-map", "0", # All streams from encoded file
|
||||
"-map", "1:s?", # All subtitle streams from original
|
||||
])
|
||||
|
||||
# Add external subtitle mappings
|
||||
if subtitle_files:
|
||||
for i in range(len(subtitle_files)):
|
||||
remux_cmd.extend(["-map", f"{i+2}:s"])
|
||||
|
||||
remux_cmd.extend([
|
||||
"-c", "copy", # Copy all streams (no re-encoding)
|
||||
str(temp_remux_file)
|
||||
])
|
||||
|
||||
try:
|
||||
logger.info(f"Remux command: {' '.join(remux_cmd)}")
|
||||
remux_result = subprocess.run(remux_cmd, capture_output=True, text=True, check=False)
|
||||
|
||||
if remux_result.returncode == 0:
|
||||
# Remux succeeded - replace output with remuxed version
|
||||
output_file.unlink()
|
||||
temp_remux_file.rename(output_file)
|
||||
logger.info(f"Successfully added subtitles via remux")
|
||||
else:
|
||||
# Remux failed - keep original encoded file (without subtitles)
|
||||
logger.warning(f"Remux failed, keeping encoded file without subtitles: {remux_result.stderr[:200]}")
|
||||
if temp_remux_file.exists():
|
||||
temp_remux_file.unlink()
|
||||
except Exception as e:
|
||||
logger.warning(f"Remux error: {e}")
|
||||
if temp_remux_file.exists():
|
||||
temp_remux_file.unlink()
|
||||
|
||||
return orig_size, out_size, reduction_ratio
|
||||
|
||||
@ -12,7 +12,7 @@ from core.audio_handler import get_audio_streams
|
||||
from core.encode_engine import run_ffmpeg
|
||||
from core.file_transfer import copy_with_progress
|
||||
from core.logger_helper import setup_logger, setup_failure_logger
|
||||
from core.video_handler import get_source_resolution, determine_target_resolution, get_source_bit_depth, has_forced_subtitles
|
||||
from core.video_handler import get_source_resolution, determine_target_resolution, get_source_bit_depth, has_forced_subtitles, has_pgs_subtitles
|
||||
|
||||
logger = setup_logger(Path(__file__).parent.parent / "logs")
|
||||
failure_logger = setup_failure_logger(Path(__file__).parent.parent / "logs")
|
||||
@ -304,6 +304,12 @@ def process_folder(folder: Path, cq: int, transcode_mode: str, resolution: str,
|
||||
# Width stays the same - cropping removes letterboxing vertically only
|
||||
logger.info(f"Adjusted target resolution for crop: {res_width}x{res_height} (width preserved)")
|
||||
|
||||
# Use user-specified encoder if provided, otherwise auto-select based on bit depth
|
||||
if encoder:
|
||||
# User explicitly specified encoder
|
||||
selected_encoder = encoder
|
||||
logger.info(f"Using user-specified encoder: {selected_encoder.upper()}")
|
||||
else:
|
||||
# Auto-select encoder based on detected source bit depth
|
||||
if src_bit_depth >= 10:
|
||||
# Source is 10-bit or higher - use HEVC NVENC
|
||||
@ -385,10 +391,16 @@ def process_folder(folder: Path, cq: int, transcode_mode: str, resolution: str,
|
||||
logger.info(f"First audio stream is 'und', replacing with default language: {effective_audio_language}")
|
||||
print(f"🔄 Audio stream detected as 'und', will tag as: {effective_audio_language}")
|
||||
|
||||
# Check if source has PGS subtitles (use remux workflow if yes)
|
||||
has_pgs = has_pgs_subtitles(file)
|
||||
use_remux = has_pgs
|
||||
if has_pgs:
|
||||
logger.info(f"Source has PGS subtitles - will use remux workflow for subtitle handling")
|
||||
|
||||
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, False, skip_audio_check
|
||||
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, use_remux
|
||||
)
|
||||
|
||||
# Check if encode met size target
|
||||
@ -430,7 +442,8 @@ def process_folder(folder: Path, cq: int, transcode_mode: str, resolution: str,
|
||||
'subtitle_file': subtitle_file,
|
||||
'src_bit_depth': src_bit_depth,
|
||||
'encoder': actual_encoder,
|
||||
'effective_audio_language': effective_audio_language
|
||||
'effective_audio_language': effective_audio_language,
|
||||
'use_remux': use_remux
|
||||
})
|
||||
consecutive_failures += 1
|
||||
if consecutive_failures >= max_consecutive:
|
||||
@ -483,7 +496,8 @@ def process_folder(folder: Path, cq: int, transcode_mode: str, resolution: str,
|
||||
'file_cq': file_cq,
|
||||
'is_tv': is_tv,
|
||||
'subtitle_file': subtitle_file,
|
||||
'effective_audio_language': effective_audio_language
|
||||
'effective_audio_language': effective_audio_language,
|
||||
'use_remux': use_remux
|
||||
})
|
||||
consecutive_failures += 1
|
||||
if consecutive_failures >= max_consecutive:
|
||||
@ -518,7 +532,7 @@ def process_folder(folder: Path, cq: int, transcode_mode: str, resolution: str,
|
||||
_save_successful_encoding(
|
||||
file, temp_input, temp_output, orig_size, out_size,
|
||||
reduction_ratio, method, src_width, src_height, res_width, res_height,
|
||||
file_cq, tracker_file, folder, is_tv, suffix, config, test_mode, subtitle_file, travel_output_folder, replace_file, wait_seconds, combined_suffix
|
||||
file_cq, tracker_file, folder, is_tv, suffix, config, test_mode, subtitle_file, travel_output_folder, replace_file, wait_seconds, combined_suffix, use_remux
|
||||
)
|
||||
|
||||
# In test mode, stop after first successful file
|
||||
@ -572,7 +586,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, False, skip_audio_check
|
||||
file_data.get('src_bit_depth'), unforce_subs, no_encode, color_bit, crop_height, audio_titles, audio_channels, False, skip_audio_check, file_data.get('use_remux', False)
|
||||
)
|
||||
|
||||
# Check if bitrate also failed
|
||||
@ -596,7 +610,7 @@ def process_folder(folder: Path, cq: int, transcode_mode: str, resolution: str,
|
||||
file_data['res_width'], file_data['res_height'],
|
||||
file_data['file_cq'], tracker_file,
|
||||
folder, file_data['is_tv'], suffix, config, False,
|
||||
file_data.get('subtitle_file'), travel_output_folder, replace_file, wait_seconds, combined_suffix
|
||||
file_data.get('subtitle_file'), travel_output_folder, replace_file, wait_seconds, combined_suffix, file_data.get('use_remux', False)
|
||||
)
|
||||
|
||||
except subprocess.CalledProcessError as e:
|
||||
@ -645,7 +659,7 @@ def process_folder(folder: Path, cq: int, transcode_mode: str, resolution: str,
|
||||
|
||||
def _save_successful_encoding(file, temp_input, temp_output, orig_size, out_size,
|
||||
reduction_ratio, method, src_width, src_height, res_width, res_height,
|
||||
file_cq, tracker_file, folder, is_tv, suffix, config=None, test_mode=False, subtitle_file=None, travel_output_folder=None, replace_file: bool = False, wait_seconds: int = 0, combined_suffix: str = None):
|
||||
file_cq, tracker_file, folder, is_tv, suffix, config=None, test_mode=False, subtitle_file=None, travel_output_folder=None, replace_file: bool = False, wait_seconds: int = 0, combined_suffix: str = None, use_remux: bool = False):
|
||||
"""Helper function to save successfully encoded files with [EHX] tag and clean up subtitle files."""
|
||||
|
||||
# In test mode, show ratio and skip file move/cleanup
|
||||
@ -756,12 +770,12 @@ def _save_successful_encoding(file, temp_input, temp_output, orig_size, out_size
|
||||
else:
|
||||
logger.info(f"Featurettes file preserved at origin: {file.name}")
|
||||
|
||||
# Clean up subtitle file if it was embedded
|
||||
# Clean up subtitle file after encoding (it's now embedded in the video)
|
||||
if subtitle_file and subtitle_file.exists():
|
||||
try:
|
||||
subtitle_file.unlink()
|
||||
print(f"🗑️ Removed embedded subtitle: {subtitle_file.name}")
|
||||
logger.info(f"Removed embedded subtitle: {subtitle_file.name}")
|
||||
print(f"🗑️ Removed subtitle file: {subtitle_file.name}")
|
||||
logger.info(f"Removed subtitle file: {subtitle_file.name}")
|
||||
except Exception as e:
|
||||
logger.warning(f"Could not delete subtitle file {subtitle_file.name}: {e}")
|
||||
except Exception as e:
|
||||
|
||||
@ -321,6 +321,23 @@ def get_subtitle_stream_codecs(input_file: Path) -> dict:
|
||||
logger.warning(f"Failed to get subtitle stream codecs for {input_file.name}: {e}")
|
||||
return {}
|
||||
|
||||
def has_pgs_subtitles(input_file: Path) -> bool:
|
||||
"""
|
||||
Check if the input file has PGS (presentation graphics) subtitles.
|
||||
PGS is the codec used for bitmap subtitles in Blu-ray discs.
|
||||
Returns True if at least one subtitle stream uses 'hdmv_pgs_subtitle' codec.
|
||||
"""
|
||||
try:
|
||||
subtitle_codecs = get_subtitle_stream_codecs(input_file)
|
||||
for codec_name in subtitle_codecs.values():
|
||||
if codec_name.lower() == "hdmv_pgs_subtitle":
|
||||
logger.debug(f"Found PGS subtitle stream in {input_file.name}")
|
||||
return True
|
||||
return False
|
||||
except Exception as e:
|
||||
logger.warning(f"Failed to check for PGS subtitles in {input_file.name}: {e}")
|
||||
return False
|
||||
|
||||
def has_forced_subtitles(input_file: Path) -> bool:
|
||||
"""
|
||||
Check if the input file has any subtitles with the forced flag set.
|
||||
|
||||
3224
logs/conversion.log
3224
logs/conversion.log
File diff suppressed because it is too large
Load Diff
@ -184,3 +184,6 @@
|
||||
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
|
||||
2026-08-22 01:04:47 | Dungeons and Dragons - Honor Among Thieves_t00.mkv | Unexpected error: Command '['ffmpeg', '-y', '-i', 'C:\\Users\\Tyler\\Documents\\GitHub\\conversion_project\\processing
|
||||
2026-08-22 01:11:39 | Dungeons and Dragons - Honor Among Thieves_t00.mkv | CQ error: Command '['ffmpeg', '-y', '-i', 'C:\\Users\\Tyler\\Documents\\GitHub\\conversion_project\\processing
|
||||
2026-08-22 02:21:31 | Dungeons and Dragons - Honor Among Thieves_t00.mkv | CQ error: Command '['ffmpeg', '-y', '-i', 'C:\\Users\\Tyler\\Documents\\GitHub\\conversion_project\\processing\\Dungeons and Dragons - Honor Among Thieves_t00.mkv', '-vf', 'crop=in_w:804:0:138,scale=1920:804:flags=lanczos,setsar=1:1', '-map', '0:v:0', '-map', '0:1', '-af', '[0:a:0', '-c:v', 'av1_nvenc', '-preset', 'p7', '-pix_fmt', 'yuv420p', '-cq', '32', '-c:a:0', 'eac3', '-b:a:0', '448000', '-ac:0', '6', '-metadata:s:a:0', 'title=', '-c:s', 'copy', 'C:\\Users\\Tyler\\Documents\\GitHub\\conversion_project\\processing\\Dungeons and Dragons - Honor Among Thieves_t00 - [EHX].mkv']' returned non-zero exit status 4294967274.
|
||||
2026-08-22 02:23:58 | Dungeons and Dragons - Honor Among Thieves_t00.mkv | CQ error: Command '['ffmpeg', '-y', '-i', 'C:\\Users\\Tyler\\Documents\\GitHub\\conversion_project\\processing\\Dungeons and Dragons - Honor Among Thieves_t00.mkv', '-i', 'C:\\Users\\Tyler\\Videos\\BluRay Rips\\4k DND\\Dungeons and Dragons - Honor Among Thieves_t00.en.srt', '-vf', 'crop=in_w:804:0:138,scale=1920:804:flags=lanczos,setsar=1:1', '-map', '0:v:0', '-map', '0:1', '-af', '[0:a:0', '-map', '1:s', '-c:v', 'av1_nvenc', '-preset', 'p7', '-pix_fmt', 'yuv420p', '-cq', '32', '-c:a:0', 'eac3', '-b:a:0', '448000', '-ac:0', '6', '-metadata:s:a:0', 'title=', '-c:s', 'srt', '-metadata:s:s:0', 'language=eng', 'C:\\Users\\Tyler\\Documents\\GitHub\\conversion_project\\processing\\Dungeons and Dragons - Honor Among Thieves_t00 - [EHX].mkv']' returned non-zero exit status 4294967274.
|
||||
2026-08-22 02:27:13 | Dungeons and Dragons - Honor Among Thieves_t00.mkv | CQ error: Command '['ffmpeg', '-y', '-i', 'C:\\Users\\Tyler\\Documents\\GitHub\\conversion_project\\processing\\Dungeons and Dragons - Honor Among Thieves_t00.mkv', '-i', 'C:\\Users\\Tyler\\Videos\\BluRay Rips\\4k DND\\Dungeons and Dragons - Honor Among Thieves_t00.en.srt', '-vf', 'crop=in_w:804:0:138,scale=1920:804:flags=lanczos,setsar=1:1', '-map', '0:v:0', '-map', '0:1', '-filter_complex', '[0:a:0]aformat=channel_layouts=5.1[a0]', '-map', '1:s', '-c:v', 'av1_nvenc', '-preset', 'p7', '-pix_fmt', 'yuv420p', '-cq', '32', '-c:a:0', 'eac3', '-b:a:0', '448000', '-ac:0', '6', '-metadata:s:a:0', 'title=', '-c:s', 'srt', '-metadata:s:s:0', 'language=eng', 'C:\\Users\\Tyler\\Documents\\GitHub\\conversion_project\\processing\\Dungeons and Dragons - Honor Among Thieves_t00 - [EHX].mkv']' returned non-zero exit status 4294967274.
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user