Final(ish) bat and start of python
This commit is contained in:
parent
094aa3a447
commit
20a8e3dca2
@ -57,7 +57,7 @@ if not errorlevel 1 (
|
||||
if "%RES_CHOICE%"=="1080" (
|
||||
set "CQ_DEFAULT=28"
|
||||
) else (
|
||||
set "CQ_DEFAULT=30"
|
||||
set "CQ_DEFAULT=32"
|
||||
)
|
||||
) else (
|
||||
REM Defaults for anime
|
||||
@ -119,17 +119,29 @@ for /R "%ORIGINATION_FOLDER%" %%F in (*.mkv *.mp4) do (
|
||||
REM Wait briefly to ensure copy finishes
|
||||
timeout /t 1 /nobreak >nul
|
||||
|
||||
REM =========================
|
||||
REM Determine audio bitrate based on channel count
|
||||
REM =========================
|
||||
set "AUDIO_BITRATE="
|
||||
set "AUDIO_CHANNELS="
|
||||
for /f "tokens=1,2 delims=," %%A in ('ffprobe -v error -select_streams a -show_entries stream=index,channels -of csv=p=0 "%INPUT_FILE%"') do (
|
||||
rem =========================
|
||||
rem Detect audio bitrate & bucket to safe values
|
||||
rem =========================
|
||||
for /f "tokens=1,2,3 delims=," %%A in ('ffprobe -v error -select_streams a:0 -show_entries stream=index,channels,bit_rate -of csv=p=0 "%INPUT_FILE%"') do (
|
||||
set "STREAM_INDEX=%%A"
|
||||
set "STREAM_CHANNELS=%%B"
|
||||
set /a "STREAM_BR=%%C/1000" rem kbps approx
|
||||
|
||||
if %%B==2 (
|
||||
set "AUDIO_BITRATE=128k"
|
||||
if !STREAM_BR! lss 80 (
|
||||
set "AUDIO_BITRATE=64000"
|
||||
) else if !STREAM_BR! lss 112 (
|
||||
set "AUDIO_BITRATE=96000"
|
||||
) else (
|
||||
set "AUDIO_BITRATE=128000"
|
||||
)
|
||||
set "AUDIO_CHANNELS=2"
|
||||
) else (
|
||||
set "AUDIO_BITRATE=192k"
|
||||
if !STREAM_BR! lss 176 (
|
||||
set "AUDIO_BITRATE=160000"
|
||||
) else (
|
||||
set "AUDIO_BITRATE=192000"
|
||||
)
|
||||
set "AUDIO_CHANNELS=6"
|
||||
)
|
||||
)
|
||||
@ -143,9 +155,20 @@ for /R "%ORIGINATION_FOLDER%" %%F in (*.mkv *.mp4) do (
|
||||
)
|
||||
|
||||
REM Default to 128k / 2 channels if detection failed
|
||||
if "!AUDIO_BITRATE!"=="" set "AUDIO_BITRATE=128k"
|
||||
if "!AUDIO_BITRATE!"=="" set "AUDIO_BITRATE=128000"
|
||||
if "!AUDIO_CHANNELS!"=="" set "AUDIO_CHANNELS=2"
|
||||
|
||||
set "LANGUAGE_TAG="
|
||||
for /f "tokens=1,* delims==" %%A in ('ffprobe -v error -select_streams a:0 -show_entries stream_tags=language -of default=nokey=1:noprint_wrappers=1 "!INPUT_FILE!"') do (
|
||||
set "LANGUAGE_TAG=%%A"
|
||||
)
|
||||
|
||||
if "!LANGUAGE_TAG!"=="" (
|
||||
set "LANGUAGE_METADATA=-metadata:s:a:0 language=eng"
|
||||
) else (
|
||||
set "LANGUAGE_METADATA="
|
||||
)
|
||||
|
||||
REM =========================
|
||||
REM Run conversion with AV1 NVENC, 10-bit, auto aspect ratio
|
||||
REM =========================
|
||||
@ -153,7 +176,7 @@ for /R "%ORIGINATION_FOLDER%" %%F in (*.mkv *.mp4) do (
|
||||
-vf "scale=!SCALE_WIDTH!:!SCALE_HEIGHT!:flags=!FILTER_FLAGS!:force_original_aspect_ratio=decrease" ^
|
||||
-map 0:v -map 0:a -map 0:s? ^
|
||||
-c:v av1_nvenc -preset p1 -cq %CQ% -pix_fmt p010le ^
|
||||
-c:a aac -b:a !AUDIO_BITRATE! -ac !AUDIO_CHANNELS! ^
|
||||
-c:a aac -b:a !AUDIO_BITRATE! -ac !AUDIO_CHANNELS! !LANGUAGE_METADATA! -metadata:s:a:0 bit_rate=!AUDIO_BITRATE! ^
|
||||
-c:s copy ^
|
||||
"%PROCESSING_FOLDER%\%%~nF%SUFFIX%.mkv"
|
||||
|
||||
@ -177,7 +200,6 @@ for /R "%ORIGINATION_FOLDER%" %%F in (*.mkv *.mp4) do (
|
||||
) else (
|
||||
echo ERROR: Converted file not found. Skipping deletion of originals.
|
||||
)
|
||||
echo =====================================================
|
||||
) else (
|
||||
echo Skipping: %%~nxF (contains 'EHX' or 'MeGusta')
|
||||
)
|
||||
|
||||
145
main.py
Normal file
145
main.py
Normal file
@ -0,0 +1,145 @@
|
||||
import os
|
||||
import shutil
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
import argparse
|
||||
|
||||
def get_audio_info(filepath):
|
||||
"""Return (stream_index, channels, bitrate_in_bits)."""
|
||||
cmd = [
|
||||
"ffprobe", "-v", "error", "-select_streams", "a:0",
|
||||
"-show_entries", "stream=index,channels,bit_rate",
|
||||
"-of", "csv=p=0", filepath
|
||||
]
|
||||
result = subprocess.run(cmd, capture_output=True, text=True)
|
||||
if not result.stdout:
|
||||
return None, 2, 128000
|
||||
parts = result.stdout.strip().split(',')
|
||||
if len(parts) < 3:
|
||||
return None, 2, 128000
|
||||
_, channels, bitrate = parts
|
||||
channels = int(channels)
|
||||
bitrate = int(bitrate) // 1000 # kbps approx
|
||||
|
||||
# Bucket logic
|
||||
if channels == 2:
|
||||
if bitrate < 80:
|
||||
br = 64000
|
||||
elif bitrate < 112:
|
||||
br = 96000
|
||||
else:
|
||||
br = 128000
|
||||
else:
|
||||
if bitrate < 176:
|
||||
br = 160000
|
||||
else:
|
||||
br = 192000
|
||||
return 0, channels, br
|
||||
|
||||
def get_language_tag(filepath):
|
||||
cmd = [
|
||||
"ffprobe", "-v", "error", "-select_streams", "a:0",
|
||||
"-show_entries", "stream_tags=language",
|
||||
"-of", "default=nokey=1:noprint_wrappers=1", filepath
|
||||
]
|
||||
result = subprocess.run(cmd, capture_output=True, text=True)
|
||||
return result.stdout.strip() or None
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Batch AV1 transcoder (FFmpeg-based) for anime/TV folders."
|
||||
)
|
||||
parser.add_argument("origination", help="Path to origination folder (e.g., P:\\Anime\\Show)")
|
||||
parser.add_argument("-p", "--processing", default=r"C:\Users\Tyler\Videos\Video Conversion\temp",
|
||||
help="Temporary processing folder (default: %(default)s)")
|
||||
parser.add_argument("-c", "--completed", default=None,
|
||||
help="Completed output folder (default: back to original)")
|
||||
parser.add_argument("-r", "--resolution", type=int, choices=[720, 1080], default=1080,
|
||||
help="Output resolution height (default: %(default)s)")
|
||||
parser.add_argument("-cq", type=int, default=None,
|
||||
help="Constant quality value for AV1_NVENC (auto if not specified)")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
orig = args.origination
|
||||
processing = args.processing
|
||||
completed = args.completed
|
||||
res_choice = str(args.resolution)
|
||||
|
||||
# Auto-detect filter & default CQ
|
||||
filter_flags = "lanczos"
|
||||
if "\\tv\\" in orig.lower() or "/tv/" in orig.lower():
|
||||
filter_flags = "bicubic"
|
||||
cq_default = 28 if res_choice == "1080" else 32
|
||||
else:
|
||||
cq_default = 32 if res_choice == "1080" else 34
|
||||
|
||||
cq = args.cq if args.cq is not None else cq_default
|
||||
|
||||
print("\n=== Using These Settings ===")
|
||||
print(f"Origination: {orig}")
|
||||
print(f"Processing: {processing}")
|
||||
print(f"Completed: {completed if completed else '[Return to original folder]'}")
|
||||
print(f"Resolution: {res_choice}")
|
||||
print(f"Filter: {filter_flags}")
|
||||
print(f"CQ: {cq}")
|
||||
print("=============================\n")
|
||||
|
||||
os.makedirs(processing, exist_ok=True)
|
||||
if completed:
|
||||
os.makedirs(completed, exist_ok=True)
|
||||
|
||||
suffix = " -EHX"
|
||||
|
||||
for root, dirs, files in os.walk(orig):
|
||||
for f in files:
|
||||
if not f.lower().endswith((".mkv", ".mp4")):
|
||||
continue
|
||||
if "ehx" in f.lower() or "megusta" in f.lower():
|
||||
print(f"Skipping {f} (contains 'EHX' or 'MeGusta')")
|
||||
continue
|
||||
|
||||
print("=" * 60)
|
||||
print(f"Processing: {f}")
|
||||
src = Path(root) / f
|
||||
tmp = Path(processing) / f
|
||||
shutil.copy2(src, tmp)
|
||||
|
||||
# Detect audio info
|
||||
_, channels, abr = get_audio_info(str(tmp))
|
||||
lang = get_language_tag(str(tmp))
|
||||
lang_metadata = []
|
||||
if not lang:
|
||||
lang_metadata = ["-metadata:s:a:0", "language=eng"]
|
||||
|
||||
width, height = ("1920", "1080") if res_choice == "1080" else ("1280", "720")
|
||||
out_file = Path(processing) / f"{Path(f).stem}{suffix}.mkv"
|
||||
|
||||
ffmpeg_cmd = [
|
||||
"ffmpeg", "-y", "-i", str(tmp),
|
||||
"-vf", f"scale={width}:{height}:flags={filter_flags}:force_original_aspect_ratio=decrease",
|
||||
"-map", "0:v", "-map", "0:a", "-map", "0:s?",
|
||||
"-c:v", "av1_nvenc", "-preset", "p1", "-cq", str(cq), "-pix_fmt", "p010le",
|
||||
"-c:a", "aac", "-b:a", str(abr), "-ac", str(channels),
|
||||
*lang_metadata,
|
||||
"-metadata:s:a:0", f"bit_rate={abr}",
|
||||
"-c:s", "copy",
|
||||
str(out_file)
|
||||
]
|
||||
|
||||
subprocess.run(ffmpeg_cmd)
|
||||
|
||||
target = Path(completed) / out_file.name if completed else Path(root) / out_file.name
|
||||
shutil.move(out_file, target)
|
||||
print(f"Moved file to {target}")
|
||||
|
||||
if target.exists():
|
||||
print("Conversion confirmed. Deleting originals...")
|
||||
os.remove(src)
|
||||
os.remove(tmp)
|
||||
else:
|
||||
print("ERROR: Converted file not found. Skipping deletion of originals.")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Loading…
x
Reference in New Issue
Block a user