I need to batch convert all mkv files in a folder recursively to mp4.
If a filename exists and matches both extensions, ignore both files and process only filenames that contain mkv, without matching mp4.
Example: cat.mkv exists in folder with cat.mp4 = ignore both files
Example: cat.mkv exists in folder and cat.mp4 does not = process cat.mkv to cat.mp4
I have included a script that doesn't work well. It processes all mkv files and mp4 files. The mp4 files throw an error as FFmpeg will not encode the same format in this manner over itself.
As always thank you to anyone who might have a few ideas.
UPDATE: I may have gotten it to work. I changed a few things from the original. If anyone has success or an idea to improve I'm all ears. Thanks.
VERSION 2
#ECHO ON
SETLOCAL
PROMPT $G
COLOR 0A
REM Set FFmpeg.exe location if not in system PATH already
SET FF=C:\MAB\local64\bin-video\ffmpeg.exe
REM Set MKV files root folder to recursively search
SET "mkvPATH=C:\Encoding\1_Original\Test\"
REM Change into mkvPATH DIR
CD "C:\Encoding\1_Original\Test"
REM Set temp file name
SET TEMPFILE=convert_mkv.bat
REM Create empty convert file
COPY NUL "%TEMPFILE%" >NUL 2>&1
REM ADD #ECHO OFF to top of blank convert_mkv.bat script
ECHO #ECHO OFF >>"%TEMPFILE%"
REM Recursively search MKV root folder
FOR /R "%mkvPATH%" %%G IN (*.mkv *.mp4) DO (
SET "GPATH=%%~fG"
SET "GNAME=%%~nG"
SETLOCAL ENABLEDELAYEDEXPANSION
REM Ignore all files that have both
REM extensions ".mkv" and ".mp4" in the file name
IF "%%~nG.mkv"=="%%~nG.mkv" (
IF NOT EXIST "%%~nG.mp4" (
CALL :DO_FFmpeg "!GPATH!"
IF "%%~nG.mkv"=="%%~nG.mkv" (
IF EXIST "%%~nG.mp4" (
ECHO(>>"%TEMPFILE%"
) ELSE ENDLOCAL
)
)
)
)
GOTO END
REM CALL variables for use in FFmpeg's command line
:DO_FFmpeg
IF "%~1"=="" GOTO :END
FOR %%I IN ("%~1") DO (
SET "FOLDER=%%~dpI"
SET "NAME=%%~nxI"
)
REM Export info to "%TEMPFILE% and RUN ffmpeg.exe's command line in the cmd.exe window
ECHO %FF% -y -i "%~1" -ss 0 -t 300 -codec copy "%FOLDER%%~n1.mp4">>"%TEMPFILE%" && %FF% | %FF% -y -i "%~1" -ss 600 -t 30 -codec copy "%FOLDER%%~n1.mp4"
:END
PAUSE
EXIT /B
I'm using ffmpeg to concatenate (merge) multiple avi files to a single avi file.
I'm using the following command.
ffmpeg -f concat -i mylist.txt -c copy out.avi
The list of files to merge is given in mylist.txt
Ex 'mylist.txt':
file 'v01.avi'
file 'v02.avi'
file 'v03.avi'
...
file 'vxx.avi'
However, there is a problem when one of the file is corrupted (or empty).
In this case, the video only contains the files up to the corrupted file.
In this case, ffmpeg return the following errors:
[concat # 02b2ac80] Impossible to open 'v24.avi'
mylist.txt: Invalid data found when processing input
Q1) Is there a way to tell ffmpeg to continue merging even if it encounters an invalid file ?
Alternatively, I decided to write a batch file that check if my avi files are valid before doing the merging.
My second problem is that this operation takes more time that doing the merging itself.
Q2) Is there a fast way to check if multiple avi files are valid with ffmpeg ? (and delete, ignore or rename them if they are not valid).
Thanks in advance for your comments.
ssinfod.
For information, here is my current DOS batch file. (This batch is working but very slow because of the ffprobe to check if my avi are valids)
GO.bat
#ECHO OFF
echo.
echo == MERGING STARTED ==
echo.
set f=C:\myfolder
set outfile=output.avi
set listfile=mylist.txt
set count=1
if exist %listfile% call :deletelistfile
if exist %outfile% call :deleteoutfile
echo == Checking if avi is valid (with ffprobe) ==
for %%f in (*.avi) DO (
call ffprobe -v error %%f
if errorlevel 1 (
echo "ERROR:Corrupted file"
move %%f %%f.bad
del %%f
)
)
echo == List avi files to convert in listfile ==
for %%f in (*.avi) DO (
echo file '%%f' >> %listfile%
set /a count+=1
)
ffmpeg -v error -f concat -i mylist.txt -c copy %outfile%
echo.
echo == MERGING COMPLETED ==
echo.
GOTO :EOF
:deletelistfile
echo "Deleting mylist.txt"
del %listfile%
GOTO :EOF
:deleteoutfile
echo "Deleting output.avi"
del %outfile%
GOTO :EOF
:EOF
I suppose that ffmpeg terminates with an exit value greater 0 if any error occurred during operation. I don't have ffmpeg installed and therefore can't verify it.
So I would suppose that all AVI files in the list are valid on first run of ffmpeg for concatenation. Then check the return code assigned to errorlevel.
If the return code is 0, the concatenation of all AVI files was successful and batch can be exited.
Otherwise the more time consuming code is used to find out which AVI files are not valid, sort them out and concatenate the remaining AVI files.
So the batch file could be something like below (not tested):
#echo off
set "ListFile=%TEMP%\mylist.txt"
set "OutputFile=output.avi"
:PrepareMerge
if exist "%ListFile%" call :DeleteListFile
if exist "%OutputFile%" call :DeleteOutputFile
echo == List avi files to convert into list file ==
for %%F in (*.avi) do echo file '%%~fF'>>"%ListFile%"
if not exist "%ListFile%" goto CleanUp
echo == Merge the avi files to output file ==
ffmpeg.exe -v error -f concat -i "%ListFile%" -c copy "%OutputFile%"
if not errorlevel 1 goto Success
echo.
echo =================================================
echo ERROR: One or more avi files are corrupt.
echo =================================================
echo.
echo == Checking which avi are valid (with ffprobe) ==
for %%F in (*.avi) do (
ffprobe.exe -v error "%%~fF"
if errorlevel 1 (
echo Corrupt file: %%~nxF
ren "%%~fF" "%%~nF.bad"
)
)
goto PrepareMerge
:DeleteListFile
echo Deleting list file.
del "%ListFile%"
goto :EOF
:DeleteOutputFile
echo Deleting output file.
del "%OutputFile%"
goto :EOF
:Success
echo == MERGING COMPLETED ==
call :DeleteListFile
:CleanUp
set "ListFile="
set "OutputFile="
if not errorlevel 1 means if errorlevel is NOT greater or equal 1 which means is 0 (or negative).
In mylist.txt, you have to remove 'file' at the beginning of the line because the code you use echoing "file" yet before calling the line of your text file
I have a media server and I'm attempting to automate ripping my collection of movies and any future movies using MakeMKV. Ripping and moving is working without a hitch. The problem I'm running into is occasionally MakeMKV doesn't assign a title to the MKVs and I end up with title00.mkv which Media Center Master obviously cannot even begin to try to match to any metadata.
MakeMKV does offer the ability to get the information from the disc which I have print to info.txt which looks like this.
MSG:1005,0,1,"MakeMKV v1.8.10 win(x64-release) started","%1 started","MakeMKV v1.8.10 win(x64-release)"
DRV:0,2,999,1,"HD-DVD-ROM HL-DT-ST BD-RE GGW-H20L YL05","FARFROMHOME_16X9","\\Device\\CdRom0"
DRV:1,256,999,0,"","",""
DRV:2,256,999,0,"","",""
DRV:3,256,999,0,"","",""
DRV:4,256,999,0,"","",""
DRV:5,256,999,0,"","",""
DRV:6,256,999,0,"","",""
DRV:7,256,999,0,"","",""
DRV:8,256,999,0,"","",""
DRV:9,256,999,0,"","",""
DRV:10,256,999,0,"","",""
DRV:11,256,999,0,"","",""
DRV:12,256,999,0,"","",""
DRV:13,256,999,0,"","",""
DRV:14,256,999,0,"","",""
DRV:15,256,999,0,"","",""
FARFROMHOME_16X9 is the label for the disc.
How can I extract this and rename my .mkv when makemkv has finished?
Here is my BAT so far (my first attempt at a .bat):
makemkvcon64 -r info disc > info.txt
makemkvcon64 --minlength=3600 mkv disc:0 all C:\Users\HTPC\MakeMKV_Temp\
START /WAIT makemkvcon64.exe
cd "c:\Program Files (x86)\FreeEject\"
FreeEject d:
move C:\Users\HTPC\MakeMKV_Temp\*.mkv C:\Users\HTPC\Movies\
Renaming the file before the move would be ideal.
Although you posted an ample description of your problem and data, you have not explained what exactly you want as result, so I must guess a couple points. The lines below extract the sixth comma-separated token from the second line of info.txt file:
for /F "skip=1 tokens=6 delims=," %%a in (info.txt) do set "discLabel=%%~a" & goto continue
:continue
echo The label of the disk is: %discLabel%
This is the output of previous lines when they are executed on your example data:
The label of the disk is: FARFROMHOME_16X9
You also have not indicated the name of the file you want to rename (before move it). Below is a possible solution to your problem that should be adjusted when previous unclear points be defined:
makemkvcon64 -r info disc > info.txt
for /F "skip=1 tokens=6 delims=," %%a in (info.txt) do set "discLabel=%%~a" & goto continue
:continue
makemkvcon64 --minlength=3600 mkv disc:0 all C:\Users\HTPC1\MakeMKV_Temp\
START /WAIT makemkvcon64.exe
cd "c:\Program Files (x86)\FreeEject\"
FreeEject d:
ren C:\Users\HTPC1\MakeMKV_Temp\TheNameHere.mkv %discLabel%.mkv
move C:\Users\HTPC1\MakeMKV_Temp\*.mkv C:\Users\HTPC1\Movies\
I've been wrangling with the same thing and created something that works fairly well.
MakeMKV uses it's own output FileName like you indicated "title00.mkv" or something similar.
I've created two(2) batch files to perform my home movie automation.
The first is "RipWorkflow_DVD.bat", which handles all the heavy lifting to call MakeMKV first to rip the content to my drive. Also in this file is a call to Handbrake to convert the MKV to MP4 (my stupid "smart" tv won't play MKV, but likes MP4)
The second batch file "OneStepDVDRip.bat" calls the first, but with parameters I choose for
a) location of the MKV
b) the output name of my MP4
c) the minLength of a track to locate and rip to MKV
Here is the code for "OneStepDVDRip.bat"
call "C:\Users\Todd\Desktop\RipWorkflow_DVD.bat" "Z:\Video\TrueStory" "E:\My Videos\Movies\Drama\True Story (2015).mp4" 3600
Here is the code for "RipWorkflow_DVD.bat"
#echo off
cls
setlocal ENABLEDELAYEDEXPANSION
SET input=%1
SET output=%2
SET minlength=%3
echo
echo %input%
echo %output%
echo
if not exist %input% ( mkdir "%input%" )
call "C:\Program Files (x86)\MakeMKV\makemkvcon64.exe" --minlength=%minlength% --decrypt mkv disc:0 0 "%input%
timeout /t 5 /nobreak
for %%F in (%input%\*.mkv) do (
echo %%~dpnxF
echo %output%
call "C:\Program Files\Handbrake\HandbrakeCLI.exe" -v1 -i %%~dpnxF --main-feature -o %output% -f mp4 --markers -e x264 -b 2000 -a 1 -E faac -6 dpl2 -R 44.1 -B 128 -D 1.75 --subtitle-forced -x ref=2:bframes=2:subme=6:mixed-refs=0:weightb=0:8x8dct=0:trellis=0
timeout /t 5 /nobreak
DEL %%F /Q
)
endlocal
Working on a batch file from past 2 days but no luck :(
I am in need of a script (Bat) that will delete all projects (mostly vb) not mentioned in my build list (xml).
Eg: I have a folder named C:\123 which has around 15 files in it.
I have a build list (XML file) which has 10 filenames which are there in C:\123. Now I want a batch file script which will delete the rest 5 files from C:\123 which is not there in the xml file.
Any help will be greatly appreciated!
script tried to compare 2 folders and delete the identical files first (thought of tweaking it later according to my need but this didn't work)
#ECHO OFF
SET LOCALFOLDER=C:\123
SET OTHERFOLDER=D:\123
Pause
:LOCALKEYTEMP
SET FILE=DONE
:: THIS LINE SCANS THE LOCAL FOLDER FOR FILES,
:: WE CAN USE THIS TO SCAN SEPERATE FILES ONE AT A
TIME
FOR /F "TOKENS=*" %%G IN ('DIR/B ^"%LOCALFOLDER%
\*.*^"') DO SET FILE=%%G
Pause
ECHO %FILE%
pause
IF %FILE%==DONE GOTO END
pause
ECHO N|COMP "%LOCALFOLDER%\%FILE%"
"%OTHERFOLDER%\%FILE%" | FIND "FILES COMPARE OK" >
NUL
pause
IF ERRORLEVEL 1 GOTO DIFFERENTKEYS
IF ERRORLEVEL 0 GOTO DELETEBOTH
pause
DELETEBOTH
DEL /Q "%LOCALFOLDER%\%FILE%"
DEL /Q "%OTHERFOLDER%\%FILE%"
GOTO LOCALKEYTEMP
DIFFERENTKEYS
:: THIS LINE DELETES THE LOCAL FOLDERS FILES WHICH IS
NECCESSARY FOR THIS SCRIPT
DEL /Q "%LOCALFOLDER%\%FILE%"
GOTO LOCALKEYTEMP
:END
ECHO ALL FILES SHOULD BE DELETED FROM
%LOCALFOLDER%
pause
ECHO ALL DIFFERENT FILES SHOULD BE LEFT ON
%OTHERFOLDER%
PAUSE
EXIT
xml file looks like:
<ProjectsToBuild>
<Project>C:\123\Clients\Direct\App1.vbproj</Project>
<Project>C:\123\Clients\Direct\App2.vbproj</Project>
</ProjectsToBuild>
result of the Aacini's Batch Script:
Press any key to continue . . .
List of existent files:
fileName[D:\123\Subfolder1\a1.txt.txt]=1
fileName[D:\123\Subfolder1\a2.txt.txt]=1
fileName[D:\123\Subfolder1\a3.txt.txt]=1
fileName[D:\123\Subfolder1\a4.txt.txt]=1
fileName[D:\123\Subfolder1\buildList.xml]=1
fileName[D:\123\Subfolder2\a1.txt.txt]=1
fileName[D:\123\Subfolder2\a2.txt.txt]=1
fileName[D:\123\Subfolder2\a3.txt.txt]=1
fileName[D:\123\Subfolder2\a4.txt.txt]=1
fileName[D:\123\Subfolder2\buildList.xml]=1
Press any key to continue . . .
Keep these files:
Press any key to continue . . .
Remove these files:
Press any key to continue . . .
Press any key to continue . . .
This deletes all the files in the folder.
Excuse me. In your question you said "I have a folder named C:\123 which has around 15 files in it"; however, the build list just have two names that are in folders two levels down below C:\123. Indeed, C:\123 folder have no one file mentioned in build list. I assumed that you want to delete all files in C:\123 at any level that are not mentioned in the build list (because the build list mention files two levels down below C:\123). If this is not what you want, then the Batch file must be modified.
#echo off
setlocal
rem Create a list of existent file names in C:\123 *at any level*
for /R "C:\123" %%a in (*.*) do set "fileName[%%a]=1"
ECHO List of existent files:
SET fileName[
ECHO/
rem Process the build list and remove found names from existent files list
ECHO Keep these files:
for /F "tokens=2-4 delims=<>" %%a in (buildList.xml) do (
if "%%a" == "Project" if "%%c" == "/Project" (
ECHO fileName[%%b]
set "fileName[%%b]="
)
)
ECHO/
ECHO Remove these files:
rem Remove the remaining files
for /F "tokens=2 delims=[]" %%a in ('set fileName[') do (
ECHO del "%%a"
)
I'd like to write a batch file that logs data. Each time it runs, it should log data in a new, sequentially numbered directory.
If I were doing this in BASH I would simply do:
~/$ for i in {1..25}; do if [[ ! -d log-$i ]]; then mkdir log-$i; break; fi; done; echo "log-$i"
log-1
~/$ for i in {1..25}; do if [[ ! -d log-$i ]]; then mkdir log-$i; break; fi; done; echo "log-$i"
log-2
~/$ for i in {1..25}; do if [[ ! -d log-$i ]]; then mkdir log-$i; break; fi; done; echo "log-$i"
log-3
What would be the equivalent of this in Windows (XP or more recent) batch programming?
[EDIT]
This is what I implemented, and it doesn't do what I'd hoped:
set "UNIT_ID=00534"
echo Check Thermo-Cal
IF NOT EXIST "C:\Thermo-Cal\NUL" "md C:\Thermo-Cal"
echo Check Thermo-cal\%UNIT_ID%
IF NOT EXIST "C:\Thermo-Cal\%UNIT_ID%\NUL" "md C:\Thermo-Cal\%UNIT_ID%"
FOR /L %%F IN (1,1,99) DO (
IF NOT EXIST "C:\Thermo-Cal\%UNIT_ID%\log-%%F\NUL" (
"md C:\Thermo-Cal\%UNIT_ID%\log-%%F"
set "LOG_DIR=C:\Thermo-Cal\%UNIT_ID%\log-%%F"
goto dir_set
)
)
echo "Couldn't create a directory to save stuff."
goto :EOF
:dir_set
echo "Stuff will get saved in: %LOG_DIR%"
Running on Windows 7 (cmd) gives:
c:\batch\log-dir.bat
Check Thermo-Cal
The filename, directory name, or volume label syntax is incorrect.
Check Thermo-Cal\00534
The filename, directory name, or volume label syntax is incorrect.
The filename, directory name, or volume label syntax is incorrect.
"Stuff will get saved in: C:\Thermo-Cal\00534\log-1"
The first time the batch file runs, the log-1 is created.
Running the command a second time produces the exact same results, I would hope it create log-2.
Turning off the #echo off shows that the loop never breaks out early and runs (in this case) 99 times.
FOR /L %%F IN (1,1,25) DO (
IF "condition" "md C:\some\folder\log-%%F"
ECHO log-%%F
PAUSE
)
Inserted pause so you can see each output before it moves onto the next sequential number. Remove PAUSE when you finalize your script.
EDIT: Adding an IF NOT EXIST condition
FOR /L %%F IN (1,1,25) DO (
IF NOT EXIST "C:\some\folder\log-%%F\NUL" "md C:\some\folder\log-%%F"
ECHO log-%%F
PAUSE
)
When using IF [NOT] EXIST statements on directories, you must specify .\NUL as a file, as Windows normally only passes the condition on files and not folders. And in Windows, the NUL file ALWAYS exists in an existing directory.
EDIT2: Making log-%%F accessible outside of the loop
FOR /L %%F IN (1,1,25) DO (
IF NOT EXIST "C:\some\folder\log-%%F\NUL" ("md C:\some\folder\log-%%F" && SET dir%%F=C:\some\folder\log-%%F)
)
ECHO %dir1%
ECHO %dir2%
ECHO %dir3%
Plug that into a batch file and try it.
This worked on Windows 7:
set "UNIT_ID=00534"
echo Check Thermo-Cal
IF NOT EXIST C:\Thermo-Cal\NUL md C:\Thermo-Cal
echo Check Thermo-cal\%UNIT_ID%
IF NOT EXIST C:\Thermo-Cal\%UNIT_ID%\NUL md C:\Thermo-Cal\%UNIT_ID%
FOR /L %%F IN (1,1,99) DO (
IF NOT EXIST C:\Thermo-Cal\%UNIT_ID%\log-%%F\NUL (
md C:\Thermo-Cal\%UNIT_ID%\log-%%F
set "LOG_DIR=C:\Thermo-Cal\%UNIT_ID%\log-%%F"
goto dir_set
)
)
echo "Couldn't create a directory to save stuff."
goto :EOF
:dir_set
echo "Stuff will get saved in: %LOG_DIR%"
You have to be careful where you use quotes, as in batch scripting, quoted content can be seen as literal strings instead of code.
set "UNIT_ID=00534"
echo Check Thermo-Cal
IF NOT EXIST "C:\Thermo-Cal\NUL" (md C:\Thermo-Cal)
echo Check Thermo-cal\%UNIT_ID%
IF NOT EXIST "C:\Thermo-Cal\%UNIT_ID%\NUL" (md C:\Thermo-Cal\%UNIT_ID%)
FOR /L %%F IN (1,1,99) DO (
IF NOT EXIST "C:\Thermo-Cal\%UNIT_ID%\log-%%F\NUL" (
md C:\Thermo-Cal\%UNIT_ID%\log-%%F
set LOG_DIR=C:\Thermo-Cal\%UNIT_ID%\log-%%F
goto dir_set
)
)
echo "Couldn't create a directory to save stuff."
goto :EOF
:dir_set
echo Stuff will get saved in: %LOG_DIR%