Use title metadata as output filename ffmpeg - batch-file

Is it possible to take the title metadata of input file, and just use that as the filename for the output file? I'm trying to encode a series of video files, and I'd like to automatically append the name of episodes to the filename, but I'm still very new to using ffmpeg and googling proved unsuccessful so far.
I'm trying to also write a batch script that'd encode the entire folder, and currently it looks like for %%a in ("*.mkv") do ffmpeg -i %%a -filter_complex "[0:v][0:s:1]overlay[subs];[subs]scale=960:720" -map 0:a:1 -acodec copy -sn test.mp4
What should i put in place of "test.mp4"?

So after being helped along by Ilogan, i managed to find an answer to what i want, even though it doesn't actually work properly yet, but i decided to write down here what i managed to find out so far, part for me, part for other poor souls.
So, following Ilogan's tip i managed to find out that ffprobe -v error -select_streams v:0 -show_entries stream_tags=title -of csv=p=0 "%%a" does indeed work and returns the metadata of title that's coded inside video stream.
Next was using that as a variable in a batchfile, which hs been answered several times, but I'll include it here as well:
You want to enclose the command in a for loop that has following look: FOR /F "delims=" %%g IN ('ffprobe -v error -select_streams v:0 -show_entries stream_tags^=title -of csv^=p^=0 "%%a"') do (SET title^=%%g) the important parts: some tutorials show "tokens=*" instead of "delims=" which might work, but i think delims will work better here. the most important part is that the command contains an equal sign, and you need to use a caret sign ^ to escape and have the command line properly parse those.
The remaining problem is that with my script looking currently like this:
for %%a in ("*.mkv") do (
FOR /F "tokens=*" %%g IN ('ffprobe -v error -select_streams v:0 -show_entries stream_tags^=title -of csv^=p^=0 "%%a"') do (SET title=%%g)
ffmpeg -i "%%a" -filter_complex "[0:v][0:s:1]overlay[subs];[subs]scale=960:720" -map 0:a:1 -acodec copy -sn "%title%.mp4"))
it seems that windows is running the first occurrence of the command in the file, and by then the title variable is still empty - as a result I'm getting files with name ".mp4" and still figuring out how to handle that
EDIT: OK, so i found out that what you need to do, is put setlocal enabledelayedexpansion at the start, and the title variable needs to be in exclamation marks, not percent marks, and it works! I tested it, and it properly creates the files, with the titles.

Related

cmd for loop error 'in was unexpected at this time'

I'm writing a cmd file that will loop through all the directories in a given directory and generate swagger code for each file in each directory. I cannot get the correct syntax for the 'for' loops.
cd C:\Users\Sora Teichman\Documents\APIJsonModels\models
for /D %%A in ("C:\Users\Sora Teichman\Documents\APIJsonModels\models\*") do (
set fileFolder=%cd%
echo %fileFolder%
for /F %%G in (fileFolder) do (
set filePath=%f
echo %filePath%
java -jar .\swagger-codegen-cli.jar generate -i filePath -l csharp-dotnet2 -o fileFolder
)
)
I'm getting 'in was unexpected at this time' at the outer for loop. I tried using a variable for the folder path, I tried with the asterisk and without, I tried ('dir "C:\Users\Sora Teichman\Documents\APIJsonModels\models"').
The ss64 does not provide enough detail for my scenario.
What is the correct syntax for this?
I know that I need double %% for the parameters because this is in a .cmd file, there are many question online for this issue :).
For context, I am running this command file from a .csproj file using an <Exec Command="codeGenerator.cmd"/> tag.
Edit: #Stephan pointed out that I needed to set my variables correctly, but now I need help with the inner loop. When I use the fileFolder variable, the error I get is 'The system cannot find the file C:\Users\Sora.' It is getting stuck on the space in the folder path.
I figured it out on my own thanks to #Stephan's comment. Here's the working code:
set jsonFoldersPath="C:\Users\Sora Teichman\Documents\APIJsonModels\models\*"
#echo off
setlocal enabledelayedexpansion
FOR /D %%f in (%jsonFoldersPath%) do (
set fileFolder=%%f
cd !fileFolder!
for %%a in (*) do (
set fileName=%%a
set filePath=!fileFolder!\!fileName!
cd C:\Users\Sora Teichman\Documents\AmazonAPIGenerator
java -jar .\swagger-codegen-cli.jar generate -i "!filePath!" -l csharp-dotnet2 -o "C:\Users\Sora Teichman\Documents\AmazonAPIGenerator\AmazonGeneratedModels" -c "C:\Users\Sora Teichman\Documents\AmazonAPIGenerator\config.json"
)
)
You need to enable delayed expansion for variables using setlocal enabledelayedexpansion so that they only evaluate at execution in the loop; read an explanation here: How do SETLOCAL and ENABLEDELAYEDEXPANSION work?
I did not end up using a variable for the -o output directory parameters for Swagger because Swagger organizes the code on its own; it generates API, Client and Model namespaces which I customized using a config.json file and the -c parameter.
I also plan to replace the hardcoded paths with relative ones.

Using FFMPEG to batch remove audio endings

I have over 1000 audio files, all of which end in a mouse click. I would like to remove the last half second from all of them. The audio files have different length (i.e. 15sec, 5 sec ...) But one thing in common with all of them is the last half second has a mouse click sound. How do I trim in bulk the ending of the mp3 files within a folder using windows 10 command line? I already have FFMPEG downloaded. Thank you!
This is two questions in one:
How to remove the last 0.5 seconds from inputs of arbitrary durations?
How to incorporate this into a Windows batch script?
I'll answer #1 because I'm not a Windows user. The batch scripting will be up to you.
Get duration using ffprobe:
ffprobe -v error -show_entries format=duration -of csv=p=0 input.mp3
Trim using ffmpeg:
ffmpeg -i input.mp3 -t <duration> -c copy output.mp3
Replace <duration> with the output from ffprobe minus 0.5 seconds.
How to incorporate this into a Windows batch script?
This should do:
FOR %%A IN (*.mp3) DO (
FOR /F %%B IN ('ffprobe.exe -v error -show_entries format^=duration -of csv^=p^=0 "%%~A" ^| xidel -s - -e ". - 0.5"') DO (
ffmpeg.exe -i "%%~A" -t %%B -c copy "%%~dpnA_trimmed.mp3"
)
)
First of all, doing floating point calculations in Batch is officially impossible and unofficially really hard to script. That's why I suggest to let Xidel do the math. It's first of all a command line tool to download and extract data from HTML/XML/JSON, but it can do A LOT more!
Loop over all mp3-files in the current directory.
The ffprobe command as suggested by llogan piped to Xidel to subtract the 0.5s. For example, 25.547755 now becomes 25.047755.
Don't forget to escape the necessary characters inside the for-loop! The = and | in this case.
The ffmpeg command as suggested by llogan, which opens "%%~A (the mp3-file), sets the duration to %%B and creates a new mp3-file (<filename>_trimmed.mp3).
This code assumes the mp3-files, ffprobe.exe, xidel.exe and ffmpeg.exe are all in the same directory.

How to filter on exact file extension?

I have .las and .lasx files which have the same file name in a DATA folder. I am trying to apply processes on the *.las files only. But it seems that the wildcard pattern *.las also includes *.lasx files:
for %%f in ("%DATA_PATH%\*.las") do
or
lasground -i "%DATA_PATH%\*.las" -merged
The parameter before -merged is supposed to be the list of my *.las files only, but during my tests it always includes the *.lasx files.
Any idea about how to get all my .las files without getting the .lasx ones?
After providing the documentation and the actual program you are using I would give these two examples a try.
Make a variable with all the file names.
#ECHO OFF
for %%G in ("%DATA_PATH%\*.las") do (
IF /I "%%~xG"==".las" call set list=%%list%% "%%G"
)
lasground -i %list% -merged
Make a list of files and use the -lof option.
#ECHO OFF
(for %%G in ("%DATA_PATH%\*.las") do (
IF /I "%%~xG"==".las" echo %%G
)
)>List.txt
lasground -lof List.txt -merged
The Where command is a simpler way to filter this directly, i.e. output only the extension specified:
#Where "%DATA_PATH%":*.las 2>Nul >"LasOnly.txt"
You can then use "LasOnly.txt" as input to lasground using the -lof option as already advised:
#lasground -lof "LasOnly.txt" -merged

Certutil with Batch Script

Trying to encode all my *.pdf and *docx within a folder and its subdirectories, to base64. So far, since the certutil specifies "from source" "to destination" or an overwrite with -f switch, am clueless on how to get this working, even with a FOR loop. Thanks for your help.
Thanks putu. Corrections taken. Well, am trying to overwrite the existing documents to its base64 encoding which I've been successful in doing one document at a time. The challenge is in automating the process into all documents in folders and sub-folders. I've tried using the the "for" statement:
for /R %%a in (*.docx, *.pdf) do certutil -f -encode %%a %%a.
This was just a test as certutil don't have any syntax for encoding multiple files at once.
The /R function of the for loop returns the full file spec including the drive and path. I suspect either the path or file name contains one or more spaces so they need to be quoted. Use the following:
for /R %%a in (*.docx, *.pdf) do certutil -f -encode "%%a" "%%a"

Removing multiple extensions while executing batch

This is the first time I actually use batch.
I have multiple files I want to merge with ffmpeg:
3 - Making Your First Pickup Class.f303.webm
3 - Making Your First Pickup Class.f251.webm
I am trying to do it using the following script:
for %%g in (*.webm) do (
ffmpeg -y -i %%~ng.f251.webm -i %%~ng.f303.webm -c copy -map 0:v:0 -map 1:a:0 -shortest %%~ng.mp4
)
cmd /k
The problem is that I need to remove the last TWO extensions for this to work correctly.
E.g.: I am getting 3 - Making Your First Pickup Class.f303.f251.webm:
In short, I need what will look like %%~n(%~ng)
Here is one solution:
#echo off
setlocal EnableDelayedExpansion
for %%G in (*.f303.webm) do (
set "FileName=%%~nG"
set "FileName=!FileName:~0,-5!"
ffmpeg.exe -y -i "!FileName!.f251.webm" -i "!FileName!.f303.webm" -c copy -map 0:v:0 -map 1:a:0 -shortest "!FileName!.mp4"
)
endlocal
The FOR loop does not search anymore for any file with extension .webm, but instead just for one of the two files to merge. This avoids the double merge.
The string .f303 is removed by assigning file name without .webm to an environment variable which is copied to same variable without the last 5 characters.
It is necessary to use delayed expansion because the environment variable FileName is modified within a block defined with (...).
Another method would be using a subroutine as demonstrated below:
#echo off
for %%G in (*.f303.webm) do call :Merge "%%~nG"
goto :EOF
:Merge
ffmpeg.exe -y -i "%~n1.f251.webm" -i "%~n1.f303.webm" -c copy -map 0:v:0 -map 1:a:0 -shortest "%~n1.mp4"
exit /B
Double quotes are necessary around all file names because of the spaces in the *.webm file names.
%~n1 is replaced by file name of first argument without file extension which means the substring of first argument from first character after last backslash (if present at all) to last character before last dot in string being interpreted as separator between file name and file extension.
For the command processor it does not matter in most cases if first argument is really the name of an existing file or an existing folder on determining "file/folder" name (%~n1), "file" extension (%~x1) and "file/folder" path with drive (%~dp1).
The file or folder must be found only if the string of first argument is incomplete to determine the string. For example if just name of a file with file extension but without drive and path is passed as first argument and %~dp1 is used somewhere, the command processor must find the file or folder to determine drive and path for this file/folder.
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.
call /? explains briefly usage of a subroutine as well as %~n1.
echo /?
endlocal /?
exit /?
for /?
goto /?
set /?
setlocal /?

Resources