问题
I'm trying to create a Batch whose purpose is to use MediaInfo.exe (CLI) to create a single text file (.nfo) containing all the "mediainfo" of the video files contained in a folder.
The Batch is executed from the context menu: right click on the folder containing the video files. To do so, the file will be placed in "shell:sendto".
The generated .nfo file containing all the mediainfo has to be "placed/saved or move" in the folder containing the video files.
A specificity is that i need to alter the final .nfo file, in order to delete all the path part of the lines "Complete name" :
Complete name : /Users/me/Downloads/Folder1/Folder2/RÉCENTS/[File] File Name - 185 (Encode Format 1080p).mkv
in this example : Do a search & replace to leave only :
Complete name : [File] File Name - 185 (Encode Format 1080p).mkv
For the moment, I've managed to create this batch (link below). This one has a few bugs, namely :
- File not found (x2)
- Powershell that bugs if there are special characters
To summarize process searched by the Batch :
1. Right click on the folder containing the files > send to > click on the Batch file.
2. Creation of all the Media info txt files of the files contained in the folder
3. Merge Media Info txt files by adding a separator between each content "----".
4. Search & Replace on the final file with a Regex to remove all path before filename, then save (.nfo) inside the folder.
5. Clean the old temporary files from step 2.
The actual Batch files I managed to create :
@echo off
:: Fullpath current folder : %cd%
:: Fullpath folder where the right click was made : %~f1
:: Name of the folder where the right click was made : for %%f in ("%~f1") do set Name=%%~nxf
for %%f in ("%~f1") do set Name=%%~nxf
:: Step 1: Creating a temporary folder
mkdir "%~f1-Temp"
:: Step 2: Creation of all nfo txt files in the temporary folder
FOR /F "tokens=*" %%G IN ('dir "%~f1" /b *.mkv') DO (
call "C:\Users\me\Desktop\MediaInfo\MediaInfo.exe" "%~f1\%%G" > "%~f1-Temp\%%~nG.txt"
)
:: Step 3: Filling in the final nfo
setlocal enabledelayedexpansion
set i=0
FOR /F "tokens=*" %%G IN ('dir "%~f1" /b *.mkv') DO (
IF !i! == 1 (
echo ------------------------------------------------------------------------------------------------------------------------------------ >> "%~f1-Temp\%Name%.txt"
echo. >> "%~f1-Temp\%Name%.txt"
echo. >> "%~f1-Temp\%Name%.txt"
)
cat "%~f1-Temp\%%~nG.txt" >> "%~f1-Temp\%Name%.txt"
set i=1
)
endlocal
:: Step 4: Removing the path
setlocal
set $source="%~f1-Temp\%Name%.txt"
set $dest="%~f1-Temp\%Name%1.txt"
set "search=%~f1\\"
for /f "delims=" %%a in ('powershell -c "(get-content '%$source%') | foreach-object {$_ -replace '(?<=Complete name\s+:\s+).+\\'} | set-content '%$dest%'"') do echo %%a
endlocal
:: Step 5: Renaming the nfo and moving to the right place
Ren "%~f1-Temp\%Name%1.txt" "%Name%.nfo"
move "%~f1-Temp\%Name%.nfo" "%~f1"
:: Step 6: Deleting temporary files
rmdir /s /q "%~f1-Temp"
pause
If you have suggestions for improvement or/and corrections of what is already coded, don't hesitate! Thank you in advance for your help!
回答1:
I think you've created an issue yourself, by providing MediaInfo with the full path as the argument. If you just provide it with the filename, the Complete name
will reflect just the filename.
In addition, unless I'm misunderstanding your intention, you're jumping through many hoops when I do not believe they are necessary.
The following example batch file should be created in your usual scripts directory, or even 'Documents' if you prefer.
Then you should create a shortcut to it in your 'SendTo' directory, giving it a name which you'll understand, perhaps MediaNFO
.
Now all you should need to do is right click on your directory and choose Send to
➡ MediaNFO
. This should create a file within the right clicked directory, with the same name as that directory, and containing the mediainfo
output for every supported file it contains. The Complete name
line should not include the path information, only the File name
.
@Echo Off
SetLocal EnableExtensions
Set "MIExe=%UserProfile%\Standalone\MediaInfo\MediaInfo.exe"
Set "OutExt=nfo"
Set "HR=------------------------------------------------------------------"
For %%G In ("%~1") Do If "%%~aG" Lss "d" (If "%%~aG" GEq "-" (
Echo Error! File arg.
GoTo EndIt) Else (Echo Error! Invalid directory arg.
GoTo EndIt)) Else If "%%~dG" == "" (
Echo Error! Full directory path required.
GoTo EndIt)
If Not Exist "%MIExe%" (Echo Error! MediaInfo not found.
GoTo EndIt)
PushD "%~1"
Set "ExtLst="
For %%G In (aac ac3 aifc aiff ape asf au avi avr dat dts flac iff ifo irca m1v
m2v mac mat mka mks mkv mov mp2 mp3 mp4 mpeg mpg mpgv mpv ogg ogm paf pvf qt
ra rm rmvb sd2 sds vob w64 wav wma wmv xi) Do If Not Defined ExtLst (
Set "ExtLst=".":"*.%%G"") Else Call Set "ExtLst=%%ExtLst%% ".":"*.%%G""
Set "}=%PATHEXT%" && Set "PATHEXT="
%SystemRoot%\System32\where.exe /Q %ExtLst%
If ErrorLevel 1 (Echo Error! Directory has no supported files.
GoTo EndIt)
Set "i="
(For /F "Delims=" %%G In ('%SystemRoot%\System32\where.exe %ExtLst% 2^> NUL'
) Do (If Defined i Echo %HR%
"%MIExe%" "%%~nxG"
Set "i=T")) 1> "%~nx1.%OutExt%"
:EndIt
%SystemRoot%\System32\timeout.exe /T 3 /NoBreak 1> NUL
GoTo :EOF
You can change the location of mediainfo.exe
on line 4
, and the output extension, on line 5
; but nothing else should be modified.
You should also note that I've added some input validation to this script. If your input directory is not a fully qualified directory path containing supported files for an existing mediainfo executable, it will report an error and close.
回答2:
1. Windows CMD versus PowerShell
The Windows command processor (cmd.exe
) is processing a batch file. Its successor is the much more powerful script interpreter PowerShell (powershell.exe
). The usage of PowerShell within a batch file does not really make sense as in this case it would be better to do the entire task with a PowerShell script using PowerShell syntax. For that reason I wrote a pure Windows command processor solution.
2. File/folder name not enclosed in double quotes
A file/folder name should be always referenced enclosed in "
as otherwise a batch file could fail to process file/folder names containing a space or one of these characters &()[]{}^=;!'+,`~
. Most argument strings referencing a file or folder name are enclosed in double quotes in code posted in question, but some are not.
See: Syntax error in one of two almost-identical batch scripts: “)” cannot be processed syntactically here
3. Wrong usage of command DIR
The first FOR loop is not working as it should:
FOR /F "tokens=*" %%G IN ('dir "%~f1" /b *.mkv') DO (
The command DIR is executed by one more command process started in background with %ComSpec% /c
and the command line within '
appended as additional arguments to output in bare format (just file/folder name without path) all files/folders in directory specified with %~f1
and all files/folders matching the pattern *.mkv
in current directory on batch file execution. That is not correct. Correct would be dir "%~f1\*.mkv" /A-D /B
to output just the names of all files with file extension .mkv
in the directory referenced with %~f1
.
The two file not found error messages are output most likely because of no *.mkv
file/folder is found in the current directory whatever is the current directory on execution of the batch file.
The file names are output by DIR without path, except option /S
is used for a recursive search. That must be taken into account on processing the file names output by DIR which is not done in batch code posted in the question.
4. Enabled delayed expansion not good on processing file names with a FOR loop
Enabling delayed expansion above a FOR loop processing file names, or lines in a text file, or lines captured from standard output of a command process executed in background, is not good because it results in parsing a command line within the command block executed by FOR for each file name a second time before execution. A file/folder name or line containing one or more exclamation mark is not correct processed in this case because of !
is interpreted by cmd.exe
on second parsing as start/end of a delayed expanded environment variable reference and not as literal character of file name or line.
See: How does the Windows Command Interpreter (CMD.EXE) parse scripts?
5. cat is not a Windows command
cat
is not a Windows command. That is a tool ported from Unix/Linux to Windows or executed on Windows 10 using Subsystem for Linux (WSL).
For that reason it is better to avoid the usage of cat
as not available by default on Windows depending on version of Windows and user´s configuration.
6. Command CALL is of no use on running an executable
The command CALL is of no use on running an executable from within a batch file. It is the default behavior of Windows command processor to run the executable and wait for self-termination before processing the next command line in batch file.
The command CALL is mainly needed for calling a batch file from within a batch file.
The usage of command CALL on a command line just running an executable makes the processing of the batch file just slower because of cmd.exe
processes in this case the command line a second time similar to usage of delayed expansion before executing the command line.
7. Batch file for collecting video information in one .nfo file
I don't have the tool MediaInfo installed nor do I have MKV files or other video files. It is perhaps enough to make the directory of which path is passed to the batch file the current directory and run MediaInfo.exe
with just name of a video file in that directory to get the Complete name
information written into the file without path. MediaInfo seems to be a tool ported also from Unix/Linux as it outputs the complete name of the video file without drive letter and colon and with /
instead of \
. The backslash is the directory separator on Windows as it can be read in the Microsoft documentation about Naming Files, Paths, and Namespaces.
Batch file code not using PowerShell or cat
:
@echo off
setlocal EnableExtensions DisableDelayedExpansion
set "MediaInfoTool=%UserProfile%\Desktop\MediaInfo\MediaInfo.exe"
rem Assign the folder path passed to batch file to environment variable FolderPath.
set "FolderPath=%~1"
rem Use the batch file path if started without a folder path argument.
if not defined FolderPath set "FolderPath=%~dp0"
rem Remove all double quotes from folder path.
set "FolderPath=%FolderPath:"=%"
if not defined FolderPath set "FolderPath=%~dp0"
rem Replace all slashes by backslashes in folder path.
set "FolderPath=%FolderPath:/=\%"
rem Make sure the folder path ends with a backslash.
if not "%FolderPath:~-1%" == "\" set "FolderPath=%FolderPath%\"
rem Check existence of folder and output an error message if not existing.
if not exist "%FolderPath%" echo ERROR: Could not find folder: "%FolderPath%"& goto EndBatch
rem Check existence of any video file in folder and output an error message if not existing.
if not exist "%FolderPath%*.avi" if not exist "%FolderPath%*.mp4" if not exist "%FolderPath%*.mpg" if not exist "%FolderPath%*.mkv" echo ERROR: There is no *.avi or *.mp4 or *.mpg or *.mkv file in folder: "%FolderPath%"& goto EndBatch
rem Check existence of MediaInfo executable and output an error message if not existing.
if not exist "%MediaInfoTool%" echo ERROR: Could not find file: "%MediaInfoTool%"& goto EndBatch
rem Get just the folder name without path and full qualified folder name.
for %%I in ("%FolderPath%.") do set "FolderName=%%~nxI" & set "FolderPath=%%~fI"
rem Make sure the following environment variable is not defined.
set "Separator="
(for /F "eol=| delims=" %%I in ('dir "%FolderPath%\*.avi" "%FolderPath%\*.mpg" "%FolderPath%\*.mp4" "%FolderPath%\*.mkv" /A-D /B') do (
if defined Separator (
echo ------------------------------------------------------------------------------------------------------------------------------------
echo(
echo(
)
set "Separator=1"
set "OutputLine="
for /F "delims=" %%J in ('^""%MediaInfoTool%" "%FolderPath%\%%I" ^| %SystemRoot%\System32\findstr.exe /N /R "^"^"') do (
set "InfoLine=%%J"
setlocal EnableDelayedExpansion
if defined OutputLine (
echo(!InfoLine:*:=!
endlocal
) else if "!InfoLine::Complete name=!" == "!InfoLine!" (
echo(!InfoLine:*:=!
endlocal
) else (
for /F "tokens=1* delims=/" %%K in ("!InfoLine:*:=!") do endlocal& echo %%K%%~nxL
set "OutputLine=1"
)
)
))>"%FolderPath%\%FolderName%.nfo"
if exist "%FolderPath%\%FolderName%.nfo" echo INFO: Video information written into file: "%FolderPath%\%FolderName%.nfo"
:EndBatch
endlocal
pause
ATTENTION: The Windows command processor cmd.exe
is not designed for processing file names with Unicode characters in name. So if a solution is needed to work really for all file names including those with Unicode characters in name, it is necessary to code a PowerShell script for the task and use powershell.exe
as script interpreter.
Most command lines are explained with remarks using command REM in the batch files itself.
Here is a description of the FOR loop for processing all AVI, MP4, MPG and MKV files in specified directory with an inner FOR loop to run the tool MediaInfo and process the output lines with modification of the line with Complete name
to remove the Unix/Linux path.
The most outer FOR starts in background one more command process with %ComSpec% /c
and the command line with DIR appended as additional arguments.
The command DIR
- searches in the directory referenced with
%FolderPath%
- just for files because of option
/A-D
(attribute not directory) - matching one of the four wildcard patterns
*.avi
,*.mp4
,*.mpg
or*.mkv
and - outputs just the file names without path in bare format because of option
/B
.
There should not be an error message output because of the IF condition used above to FOR loop to check the existence of any video file before running the FOR loop at all. The IF condition prevents the creation of an .nfo
file in the specified directory on not containing a video file at all.
The output of CMD internal command DIR to handle STDOUT of background command process is captured by for
respectively cmd.exe
processing the batch file and processed line by line after started cmd.exe
terminated itself.
FOR with option /F
ignores always empty lines which does not matter here on file names list. A line with a file name would be split up by default into substrings using normal space and horizontal tab as string delimiters. A file name can contain one or more spaces at beginning and also in the middle. For that reason option delims=
is used to specify an empty list of delimiters to prevent splitting up the file name into substrings (tokens). If the first substring (token) starts with a semicolon, the line is also ignored by FOR because of ;
is the default end of line character. A file name can have ;
at beginning although this is very unusual. Therefore option eol=|
is used to define a vertical bar as the end of line character which no file name can contain ever. "tokens=*"
is not useful as it results in removing first a leading spaces from file name and if the remaining file name starts with a semicolon, the file name is ignored by FOR.
So a file name without path is assigned to the specified loop variable I
, even on having the unusual name ;Video 100% & Test (1)!
.
A separator line and two empty lines are output if the currently processed file name is not the name of the first video file output by DIR (unsorted respectively as sorted by the file system). The environment variable Separator
is explicitly undefined above the FOR loop and is (re)defined on each iteration of the outer FOR loop. The value assigned to the environment variable Separator
does not matter.
See DosTips forum topic ECHO. FAILS to give text or blank line - Instead use ECHO/ for the reason using echo(
instead of echo.
to output empty lines.
The environment variable OutputLine
is explicitly undefined before running MediaInfo and is later defined on having found the line with Complete name
. It is used to speed up the processing of the information lines once the line Complete name
was processed as in this case all other lines can be simply output without any further special processing.
The tool MediaInfo is executed also by starting in background one more command process with %ComSpec% /c
and the command line within '
appended as additional argument. For that reason it is very important to know how cmd.exe
processes the argument string(s) after option /C
. That is tricky as the processing of the argument string(s) depends on several conditions explained by the help output on running in a command prompt window cmd /?
. In this case it is necessary to enclose the entire command line in "
to run background command process with correct command line as argument string.
But the batch file is processed also by cmd.exe
. So the FOR command line must contain the command line to execute by background command process in a manner being valid for both cmd.exe
. This is the reason why "
at beginning and at end of the entire command lines and also the redirection operator |
are escaped with ^
to be interpreted as literal characters by cmd.exe
processing the batch file. The command line enclosed in "
passed to started cmd.exe
does not contain the caret characters anymore.
The output of MediaInfo is redirected to FINDSTR which runs a regular expression find matching all lines and therefore outputs all lines with a line number and a colon according to option /N
. This is done to make sure no line captured finally by FOR is a completely empty line which should be finally also in the NFO file and not silently ignored by FOR.
The lines output by MediaInfo extended by FINSTR with a line number and a colon at beginning are captured by FOR respectively cmd.exe
processing the batch file and are processed line by line after started background command process terminated itself.
The current line is first assigned as is to the environment variable InfoLine
while delayed expansion is disabled to prevent interpretation of !
as start/end of a delayed expanded environment variable reference.
Delayed environment variable expansion is enabled next. Please read this answer for details about the commands SETLOCAL and ENDLOCAL as there happens more in the background than just enabling delayed expansion.
The current line is just output if the environment variable OutputLine
is defined already with removal of the line number and the colon at beginning of the line to output the line as output in background command process by MediaInfo.
Otherwise there is made a case-sensitive string comparison of the current line with all occurrences of :Complete name
(colon after line number and the string :Complete name
) removed case-insensitive with the line not modified at all. If line with string substitution is equal the line without string substitution, this line from MediaInfo does not contain at beginning the string Complete name
and is therefore also just output with removal of line number and colon.
Otherwise the line with Complete name
is found in captured output of MediaInfo. For that reason the line with line number and colon at beginning removed is split up into two substrings. The first substring is Complete name
with the whitespaces and the colon up to first /
in the line which is assigned to loop variable K
. The second substring is everything after first /
up to end of the line which is assigned to next but one loop variable according to the ASCII table which is the letter L
.
Delayed expansion is disabled first before the beginning of the line and the file name without path are output by the third FOR command line. Next the environment variable OutputLine
is defined now to just output all further lines of MediaInfo.
Everything output to standard output of command process processing the batch file during processing the video files is redirected into a file with folder name with file extension .nfo
in the specified folder.
The media information file was successful on file .nfo
finally existing (and the information file did not exist already on starting the batch file and was additionally write-protected by read-only attribute, NTFS permissions or file access permissions).
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 /?
cmd /?
dir /?
echo /?
endlocal /?
findstr /?
for /?
goto /?
if /?
pause /?
rem /?
set /?
setlocal /?
The batch file can be run also from within a Windows command prompt window or PowerShell console without or with a folder path which can be also a relative path.
来源:https://stackoverflow.com/questions/66190788/batch-files-inside-folder-to-create-mediainfo-nfo-file