1

So, I want to create a Powershell or Batch file (whichever works best for the task), that I can paste in a folder and after executing it, will start to use FFmpeg to encode all videos

The part that works (in .bat):

for %%a in ("*.mkv") do(
  ffmpeg -i "%%a" -c:v libx265 -c:a copy -x265-params crf=25 "%%a [encoded].mkv"
   pause)

This works, but in some folders, I already have [encoded] files. I'd like for the script to skip these files. I asked in reddit and received the following script:

for %%a in ("*.mkv") do (
if not exist "%%a [encoded].mkv" ffmpeg -i "%%a" -c:v libx265 -c:a copy -x265-params crf=25 "%%a [encoded].mkv"
pause)

I tried the script, but every file got encoded, even if it had the [encoded] in it. After I pointed that out, they told me that I should probably switch to PowerShell and gave a link to a StackOverflow question:

You probably need to switch to PowerShell Find files which does not contains selected string Then do a foreach in what is returned to execute the ffmpeg command on it.

but I don't know how to code in PowerShell (never used it before) Would a .bat file even work? If yes, how could I write it? And if a PowerShell script would be the better option, how would I code it?

Any help and answers are appreciated.

WorldTeacher
  • 93
  • 1
  • 10
  • 3
    Your issue is probably that your code is using `"%%a [encoded].mkv"`, which would expand to `"SomeName.mkv [encoded].mkv"`, whereas you need, `"SomeName [encoded].mkv"`. The fix for that would be to change it to `"%%~na [encoded].mkv"`. For more information about for variable expansion, please open a Command Prompt window, type `for /?`, press the `[ENTER]` key, and read the output. From that you should see that `%~n` will expand the variable to its name without extension. I would suggest that pressing a key, between each iteration is unnecessary, so move the `pause`, outside of the for-loop. – Compo Sep 26 '20 at 21:42

2 Answers2

1

%%a already is the full filename (including [encoded]), so your if can't work.
I suggest another approach:

for %%a in ("*.mkv") do (
  echo %%a|findstr /iel "[encoded].mkv" >nul || ffmpeg -i "%%a" -c:v libx265 -c:a copy -x265-params crf=25 "%%~na [encoded].mkv"
  pause
)

(I didn't check if the ffmpeg syntax is ok - I trust you there)

Stephan
  • 53,940
  • 10
  • 58
  • 91
1

In PowerShell, you can use the following (you can paste this code as-is into a PowerShell console window):

Get-ChildItem *.mkv | where BaseName -notlike '*`[encoded]' | foreach {
  ffmpeg -i $_ -c:v libx265 -c:a copy -x265-params crf=25 "$($_.BaseName) [encoded].mkv"
  pause
}
  • Get-ChildItem *.mkv uses the Get-ChildItem to get information about all files with extension (.mkv) in the current directory (you could add -File to explicitly rule out directories, but directory names with extensions are are).

  • where BaseName -notlike '*`[encoded]' uses the Where-Object cmdlet (whose built-in alias is where) to weed out files whose base name (the name without the filename extensions) already ends in [encoded]. Note the ` before the opening [ in order to use it verbatim, because [ has special meaning in PowerShell's wildcard expressions, which the -like / -notlike operator operates on.

  • foreach { ... } uses the ForEach-Object cmdlet (whose built-in alias is foreach) to invoke ffmpeg for each file of interest:

    • Inside the script block ({ ... }), the automatic $_ variable refers to the pipeline (|) input object at hand, which in this case is a System.IO.FileInfo instance representing an input file.

    • "$($_.BaseName) [encoded].mkv" uses an expandable string (string interpolation) to derive the output file name via the input file's base name ($_.BaseName).

mklement0
  • 382,024
  • 64
  • 607
  • 775