@echo off
SetLocal EnableDelayedExpansion
set title1=H.264 NVENC VBR
title %title1%

if "%~1"=="" ( echo ERROR: NO INPUT & echo  & pause & goto :eof ) else ( title %title1%^: "%~nx1")

:: you can override exe paths here. for example, set "ffmpeg=C:\ffmpeg\bin\ffmpeg.exe"
set "ffmpeg=ffmpeg.exe"
set "ffprobe=ffprobe.exe"

:: only these file extensions will be processed by the script
set supported_formats=avi,bik,flv,m2ts,m4p,m4v,mkv,mov,mp2,mp4,mpg,mpeg,mpe,mpv,mts,qt,swf,wmv,xmf,webm

:: whether to play a chime sound after completion
set playsound=true

:: the sound to play. you can change
set "chime=C:\Windows\Media\tada.wav"

:: whether to open the output folder after completion
set open_folder=true

:: whether to add suffix to output files. for example, set "suffix=_fixed"
set suffix=

:: optional default subfolder to output to. for example, set "subfolder=converted"
set subfolder=

set bitrate=5

if "%bitrate%"=="" echo ERROR^: bitrate value not defined & pause>nul & goto :eof
for /f "delims=1234567890" %%A in ('echo/%bitrate%') do ( echo ERROR^: bad bitrate value %bitrate% & pause>nul & goto :eof)

set title1=H.264 NVENC VBR %bitrate% Mbit/s
title %title1%

:: load override settings from optional settings.ini located in the same folder as this script
if exist "%~dp0settings.ini" ( for /f "tokens=* eol=;" %%L in ('type "%~dp0settings.ini"') do set "%%~L")

:CheckSubfolderVar
if not "%subfolder%"=="" (
	set subfolder=%subfolder: =%
	for %%A in ("!subfolder!") do ( set "subfolder=%%~A" & goto :CheckFFMPEG)
)
set subfolder=

:CheckFFMPEG
if not exist "%ffmpeg%" (
	if exist "%~dp0ffmpeg.exe" set "ffmpeg=%~dp0ffmpeg.exe" & goto :CheckFFPROBE
	ffmpeg.exe>nul 2>&1
	if !errorlevel!==9009 CALL :PrintMessage "ERROR: FFMPEG NOT FOUND / INSTALLED. EXITING." & echo  & pause & goto :eof
)

:CheckFFPROBE
if not exist "%ffprobe%" (
	if exist "%~dp0ffprobe.exe" set "ffprobe=%~dp0ffprobe.exe" & goto :CountFiles
	ffprobe.exe>nul 2>&1
	if !errorlevel!==9009 CALL :PrintMessage "ERROR: FFPROBE NOT FOUND / INSTALLED. EXITING." & echo  & pause & goto :eof
)

:CountFiles
:: replace bad characters for batch
set files=%*
set files=%files:,=-_comma_-%
set files=%files:(=-_opbr_-%
set files=%files:)=-_clbr_-%

:: count files
set total=0
for %%F in (%*) do ( if "%%~xF"=="" ( CALL :CountFolder "%%~F") else ( for %%A in (%supported_formats%) do ( if /i %%~xF==.%%A set /a total=!total!+1)))
if %total%==0 echo  & CALL :PrintMessage "NO FILES TO PROCESS" "EXITING" & pause & goto :eof
if %total% GTR 1 title %title1%^: %total% files

:CalcRates
set /a bufsize=%bitrate% * 2

:EnterPath
if "%subfolder%"=="" ( set "msg=output path = ") else ( set "msg=output path (default %subfolder%) ")
set p=
echo.
set /p p="%msg%"
if not "%p%"=="" (
	for %%F in ("!p!") do (
		set "outfolder=%%~F"
		goto :ConformPath
	)
)

:ConformPath
echo.
if not "!outfolder!"=="" (
	if not "!outfolder:~-1!"=="\" (
		if "!outfolder:~-1!"=="/" set "outfolder=!outfolder:~0,-1!"
		set "outfolder=!outfolder!\"
		for %%A in ("%outfolder%") do (
			echo "%%~dA"| find /i "%~d1" > nul 2>&1
			if not !ErrorLevel!==0 ( set "openfolder=true" & goto :BatchProcess)
		)
		for %%A in ("%outfolder%") do (
			echo "%%~dpA"| find /i "%~dp1" > nul 2>&1
			if not !ErrorLevel!==0 ( set "openfolder=true" & goto :BatchProcess)
		)
	)
)

:BatchProcess
set current=
for %%F in (%files%) do (
	set "file=%%~F"
	set "file=!file:-_comma_-=,!"
	set "file=!file:-_clbr_-=)!"
	set "file=!file:-_opbr_-=(!"
	if "%%~xF"=="" (
		CALL :ProcessFolder "!file!"
	) else (
		for %%A in (%supported_formats%) do ( if /i %%~xF==.%%A CALL :ProcessFile "!file!")
	)
)
title Finished
if defined openfolder if %open_folder%==true explorer "%outfolder%"
if %playsound%==true if "%goterror%"=="" powershell -c (New-Object Media.SoundPlayer "%chime%").PlaySync();
goto :eof

:: SUBROUTINES
:CountFolder
set "f=%~1"
set "f=!f:-_comma_-=,!"
set "f=!f:-_clbr_-=)!"
set "f=!f:-_opbr_-=(!"
for /f "tokens=*" %%F in ('dir "!f!" /s /b /a:-d') do ( for %%A in (%supported_formats%) do ( if /i %%~xF==.%%A set /a total=!total!+1))
goto :eof

:ProcessFolder
for /f "tokens=*" %%F in ('dir "%~1" /b /s /a:-d /o:n') do (
	for %%A in (%supported_formats%) do (
		if /i %%~xF==.%%A (
			if not "%outfolder%"=="" ( set "foldertree=%%~dpF" & set "foldertree=!foldertree:%~dp1=!")
			CALL :ProcessFile "%%~F"
		)
	)
)
set foldertree=
goto :eof

:: MAIN ROUTINE
:ProcessFile
if "!current!"=="" ( set current=1) else ( set /a current=!current!+1)
if %total% GTR 1 set "ratio= !current!/!total!"
title %title1%^:!ratio! "%~nx1"
echo "%~1"|find "?" > nul 2>&1 && ( CALL :PrintMessage "ERROR: Unresolvable non-ASCII characters in" "%~1" "Either set your Windows locale setting accordingly," "or remove those characters from paths/names" & echo  & set "goterror=true" & pause & goto :eof)
echo "%~1"|find "(" > nul 2>&1 && ( CALL :PrintMessage "ERROR: Bad character ( in" "%~1" "Exiting." & echo  & set "goterror=true" & pause & goto :eof)
echo "%~1"|find ")" > nul 2>&1 && ( CALL :PrintMessage "ERROR: Bad character ) in" "%~1" "Exiting." & echo  & set "goterror=true" & pause & goto :eof)
echo "%~1"|find "," > nul 2>&1 && ( CALL :PrintMessage "ERROR: Bad character , in" "%~1" "Exiting." & echo  & set "goterror=true" & pause & goto :eof)
if not "%cd%\"=="%~dp1" cd /d "%~dp1"

:SetAudio
for /f "tokens=*" %%L in ('""%ffprobe%" -hide_banner -show_streams -select_streams a -show_entries stream^=codec_name "%~1""') do (
	echo "%%L"| find /i "codec_name" >nul 2>&1
	if !ErrorLevel!==0 for /f "tokens=2 delims==" %%C in ("%%L") do set "audiocodec=%%C"
)
if "!audiocodec!"=="aac" ( set "audiosettings=-c:a copy") else ( set "audiosettings=-c:a aac -b:a 320k")

:Checkoutfolder
if not "%outfolder%"=="" (
	set "outpath=%outfolder%!foldertree!"
) else (
	if "%subfolder%"=="" ( set "outpath=%~dp1") else ( set "outpath=%~dp1%subfolder%\")
)
if not exist "!outpath!" mkdir "!outpath!"

:Add_Postfix
if exist "!outpath!%~n1%suffix%.mp4" (
	for /L %%N in (1,1,1000) do (
		if not exist "!outpath!%~n1%suffix%_%%N.mp4" ( set "postfix=_%%N" & goto :FFmpeg)
	)
)

:FFmpeg
"%ffmpeg%" -hide_banner -hwaccel_output_format cuda -i "%~1" -map 0:v -map 0:a:? -c:v h264_nvenc -preset slow -profile:v high -bf 2 -g 30 -rc-lookahead 32 -rc vbr -b:v %bitrate%M -bufsize !bufsize!M !audiosettings! -movflags +faststart "!outpath!%~n1%suffix%!postfix!.mp4"
if not !errorlevel!==0 CALL :ErrorSubroutine "!outpath!%~n1%suffix%!postfix!.%ext%"
goto :eof

:: if output file is empty, deletes it. prints some messages. stores goterror var.
:ErrorSubroutine
if "%~z1"=="0" del %1 & ( echo  & echo ERROR: FILE OUTPUT FAILED & echo.)
set goterror=true
pause
goto :eof

:: UTILITIES

:PrintMessage
echo.
echo ---------------------------------------------------------------
echo  %~1
if not "%~2"=="" echo  %~2
if not "%~3"=="" echo  %~3
if not "%~4"=="" echo  %~4
echo ---------------------------------------------------------------
goto :eof