This commit is contained in:
bnair
2026-01-03 14:59:59 +01:00
parent d5bcaf16ee
commit ef81365fce
4 changed files with 25 additions and 69 deletions

File diff suppressed because one or more lines are too long

View File

@@ -70,70 +70,13 @@ signal.signal(signal.SIGINT, handle_sigint)
# --- Hardware Detection ---
def detect_hardware_encoder():
"""Detects available hardware encoders via ffmpeg"""
try:
res = subprocess.run([FFMPEG_BIN, "-hide_banner", "-encoders"], capture_output=True, text=True)
out = res.stdout
av1_enc = None
hevc_enc = None
# Check AMD
if "av1_amf" in out: av1_enc = "av1_amf"
if "hevc_amf" in out: hevc_enc = "hevc_amf"
if av1_enc or hevc_enc: return av1_enc, hevc_enc, "amf"
# Check NVIDIA
if "av1_nvenc" in out: av1_enc = "av1_nvenc"
if "hevc_nvenc" in out: hevc_enc = "hevc_nvenc"
if av1_enc or hevc_enc: return av1_enc, hevc_enc, "nvenc"
# Check Intel
if "av1_qsv" in out: av1_enc = "av1_qsv"
if "hevc_qsv" in out: hevc_enc = "hevc_qsv"
if av1_enc or hevc_enc: return av1_enc, hevc_enc, "qsv"
# Check Apple
if "av1_videotoolbox" in out: av1_enc = "av1_videotoolbox"
if "hevc_videotoolbox" in out: hevc_enc = "hevc_videotoolbox"
if av1_enc or hevc_enc: return av1_enc, hevc_enc, "videotoolbox"
return None, None, "cpu"
except Exception as e:
print(f"[Warning] HW Detection failed: {e}")
return None, None, "cpu"
# Use common module detection
return common.detect_hardware_encoder()
def get_encoder_args(codec, encoder, qp):
"""Returns correct ffmpeg args for specific HW vendor"""
if not encoder: return []
# AMD AMF
if "amf" in encoder:
common_args = ["-rc", "cqp", "-qp_i", str(qp), "-qp_p", str(qp), "-qp_b", str(qp), "-quality", "quality"]
return ["-c:v", encoder, "-usage", "transcoding"] + common_args
# NVIDIA NVENC
if "nvenc" in encoder:
return ["-c:v", encoder, "-rc", "constqp", "-qp", str(qp), "-preset", "p6", "-spatial-aq", "1"]
# Intel QSV
if "qsv" in encoder:
return ["-c:v", encoder, "-global_quality", str(qp), "-look_ahead", "1"]
# Apple VideoToolbox
if "videotoolbox" in encoder:
q = int(100 - (qp * 2))
return ["-c:v", encoder, "-q:v", str(q)]
# Software Fallback
if encoder == "libsvtav1":
# CRF 20-35 range usually good
return ["-c:v", "libsvtav1", "-crf", str(qp), "-preset", "6", "-g", "240"]
if encoder == "libx265":
return ["-c:v", "libx265", "-crf", str(qp), "-preset", "medium"]
return []
# Use common module args
return common.get_encoder_args(codec, encoder, qp)
# --- Helpers ---
def run_process(cmd, description="", status_callback=None):
@@ -484,7 +427,7 @@ def main():
if tv_path.exists():
print(f"Scanning TV: {tv_path}")
files = list(tv_path.rglob("*.mkv")) + list(tv_path.rglob("*.mp4"))
files.sort(key=lambda x: x.stat().st_size, reverse=True)
files.sort() # Alphabetical order for consistency across platforms
for f in files:
if skipping:
if skip_until.lower() in str(f).lower():
@@ -499,7 +442,7 @@ def main():
if content_path.exists():
print(f"Scanning Content: {content_path}")
files = list(content_path.rglob("*.mkv")) + list(content_path.rglob("*.mp4"))
files.sort(key=lambda x: x.stat().st_size, reverse=True)
files.sort() # Alphabetical order for consistency across platforms
for f in files:
if skipping:
if skip_until.lower() in str(f).lower():

View File

@@ -76,7 +76,8 @@ def fast_scan(path):
files.append(entry.path)
except:
pass
return files
# Sort alphabetically for consistent ordering across platforms
return sorted(files)
# --- UI State ---
class Dashboard:
@@ -295,10 +296,14 @@ def main():
# Detect HW
encoders = common.detect_hardware_encoder(args)
av1_enc, hevc_enc, hw_type = encoders
# UI
dashboard = Dashboard(args.jobs, log_dir=log_dir)
dashboard.add_log(f"Locks: {lock_dir}")
dashboard.add_log(f"Logs: {log_dir}")
dashboard.add_log(f"Hardware: {hw_type.upper()}")
dashboard.add_log(f"AV1: {av1_enc or 'None'} | HEVC: {hevc_enc or 'None'}")
# Work Queue
work_queue = queue.Queue()

View File

@@ -231,8 +231,8 @@ def acquire_lock(lock_dir, filepath):
Simple file-based lock.
Returns lock_path if acquired, None if failed.
"""
# Use hash of filename to avoid long paths/invalid chars
fhash = hashlib.md5(str(filepath.name).encode()).hexdigest()
# Use hash of full path (not just filename) for uniqueness
fhash = hashlib.md5(str(filepath).encode()).hexdigest()
lock_file = lock_dir / f"{fhash}.lock"
if lock_file.exists():
@@ -241,14 +241,23 @@ def acquire_lock(lock_dir, filepath):
if time.time() - lock_file.stat().st_mtime > 86400:
lock_file.unlink()
else:
# Lock exists and is fresh - file is being processed elsewhere
return None
except:
return None
try:
lock_file.touch()
# Write hostname and timestamp for debugging
import socket
lock_info = {
"file": str(filepath),
"host": socket.gethostname(),
"timestamp": time.time()
}
lock_file.write_text(json.dumps(lock_info))
return lock_file
except:
except Exception as e:
print(f"[Warning] Failed to acquire lock for {filepath.name}: {e}")
return None
# --- Hardware Detection ---