Search code examples
batch-fileffmpegschedule

How to run ffmpeg in a scheduled batch file with a file exclusion list?


I have the following batch file created to run as a schedule task. It auto encodes the audio to AAC in my main media folder. Everything is working, but now I need to do 2 more things:

  1. Delete the original upon completion.
  2. Set it so that the next time it runs, it does not try to convert the already converted files.

Is that possible? How would that look? Is there a way to "disregard" file names with CONVERTED in them?

for /r "C:\Users\USER\Desktop\TEST" %%a in ("*.mkv") do ffmpeg -i "%%a" -vcodec copy -acodec aac -ac 2 -ab 256K %%~dpnaCONVERTED.mkv

Solution

  • This could be done with following batch file:

    @echo off
    for /F "eol=| delims=" %%I in ('dir "%UserProfile%\Desktop\TEST\*.mkv" /A-D-H /B /S 2^>nul ^| %SystemRoot%\System32\findstr.exe /E /I /L /V /C:CONVERTED.mkv 2^>nul') do (
        ffmpeg.exe -i "%%I" -vcodec copy -acodec aac -ac 2 -ab 256K "%%~dpnICONVERTED.mkv"
        if not errorlevel 1 del "%%I"
    )
    

    The command FOR executes in a separate command process started with cmd.exe /C in background (= not visible) the command line:

    dir "C:\Users\USER\Desktop\TEST\*.mkv" /A-D-H /B /S 2>nul | C:\Windows\System32\findstr.exe /E /I /L /V /C:CONVERTED.mkv 2>nul
    

    So the command process in background with no console window is first running command DIR which outputs

    • all non hidden files because of /A-D-H (attribute not directory and not hidden)
    • matching the wildcard pattern *.mkv
    • in bare format because of /B which means file name only
    • in specified directory and all its subdirectories because of /S
    • with full path also because of /S
    • to handle STDOUT.

    DIR outputs an error message if it can't find any *.mkv file. This error message written to handle STDERR is suppressed by redirecting it to device NUL with 2>nul.

    The file names with full path output by DIR line by line to handle STDOUT are redirected with | to handle STDIN of next command FINDSTR.

    FINDSTR searches in the list of file names for

    • comparison string CONVERTED.mkv
    • at end of a line because of /E
    • case-insensitive because of /I
    • and literally because of /L
    • and outputs the inverted result because of /V.

    That means FINDSTR outputs the lines not ending with case-insensitive, literally interpreted comparison string CONVERTED.mkv to ignore the *.mkv file converted already in a previous execution of the batch file.

    It is possible that FINDSTR can't find any line matching the search criteria and therefore outputs an error message to handle STDERR which is suppressed by redirecting it with 2>nul to device NUL.

    The command FOR captures the output written to handle STDOUT of the background command process which is the output of DIR filtered with FINDSTR and then processes this output line by line.

    Empty lines are ignored by FOR. But that does not matter here as the list of file names with full path does not contain empty lines.

    Lines starting with a semicolon would be also ignored by FOR, but this behavior is modified with eol=| to ignore just lines starting with a vertical bar. A vertical bar is impossible here as no directory or file can contain a vertical bar in name. Well, it is also practically impossible that a file name with full path starts with a semicolon. So eol=| would not be really needed here.

    FOR with parameter /F splits by default a line up into substrings using space and horizontal tab as string delimiters and assign only the first space/tab delimited string to specified loop variable I. This split behavior is not wanted here as needed in body command block of FOR is always the full qualified name of an MKV file even on path or file name contains a space character. For that reason delims= is specified to define an empty list of delimiters which disables splitting up the lines into substrings.

    ffmpeg.exe is executed which I don't have installed and so I can only assume that it exits with 0 on success and with any value greater 0 on an error.

    The exit code of an executed application or command is assigned by Windows command interpreter to environment variable ERRORLEVEL.

    The IF condition checks if ffmpeg.exe exited not with a value greater or equal 1, i.e. with 0 (or a negative value) for success. In this case the input file is deleted as wanted to prevent a conversion of same file once again on next run of this batch file.

    For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.

    • dir /?
    • echo /?
    • findstr /?
    • for /?
    • if /?

    Read also the Microsoft article about Using Command Redirection Operators for an explanation of 2>nul and |. The redirection operators > and | must be escaped with caret character ^ on FOR command line to be interpreted as literal character when Windows command interpreter processes this command line before executing command FOR which executes the embedded command line with using a separate command process started in background.