文件夹内的批处理文件以创建 MediaInfo.nfo 文件

Batch files inside folder to create MediaInfo.nfo file

我正在尝试创建一个批处理,其目的是使用 MediaInfo.exe (CLI) 创建一个包含文件夹中视频文件的所有“媒体信息”的文本文件 (.nfo) .

从上下文菜单执行批处理:右键单击包含视频文件的文件夹。 为此,文件将被放置在“shell:sendto”中。

生成的包含所有媒体信息的 .nfo 文件必须“placed/saved 或移动”到包含视频文件的文件夹中。

具体情况是我需要更改最终的 .nfo 文件,以便删除“完整名称”行的所有路径部分:

Complete name                            : /Users/me/Downloads/Folder1/Folder2/RÉCENTS/[File] File Name - 185  (Encode Format 1080p).mkv

在此示例中:执行搜索和替换以仅保留:

Complete name                            : [File] File Name - 185  (Encode Format 1080p).mkv

目前,我已经成功创建了这个批次(link 下面)。 这个有一些错误,即:

总结Batch搜索的进程:

1. 右键单击​​包含文件的文件夹 > 发送到 > 单击批处理文件。

2. 创建文件夹中包含的文件的所有媒体信息 txt 文件

3. 通过在每个内容“----”之间添加分隔符来合并媒体信息 txt 文件。

4. 使用正则表达式搜索并替换最终文件以删除文件名之前的所有路径,然后将 (.nfo) 保存在文件夹中。

5. 清除步骤 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

如果您有改进建议or/and 更正已编码的内容,请不要犹豫! 预先感谢您的帮助!

1。 Windows CMD 与 PowerShell

Windows 命令处理器 (cmd.exe) 正在处理一个批处理文件。它的继任者是功能更强大的脚本解释器 PowerShell (powershell.exe)。在批处理文件中使用 PowerShell 并没有真正意义,因为在这种情况下,最好使用 PowerShell 语法使用 PowerShell 脚本来完成整个任务。出于这个原因,我写了一个纯粹的 Windows 命令处理器解决方案。

2。 File/folder 名称未用双引号引起来

A file/folder 名称应始终引用在 " 中,否则批处理文件可能无法处理包含 space 或这些字符之一的 file/folder 名称&()[]{}^=;!'+,`~。大多数引用文件或文件夹名称的参数字符串在有问题的代码中用双引号括起来,但有些不是。

参见:

3。命令 DIR

的错误用法

第一个 FOR 循环没有正常工作:

FOR /F "tokens=*" %%G IN ('dir "%~f1" /b *.mkv') DO (

命令 DIR 由另一个在后台启动的命令进程执行,其中 %ComSpec% /c' 中的命令行作为附加参数附加到输出以裸格式(只有 file/folder 没有路径的名称)所有 files/folders 在 %~f1 指定的目录中和所有 files/folders 匹配批处理文件当前目录中的模式 *.mkv执行。那是不正确的。正确的做法是 dir "%~f1\*.mkv" /A-D /B 仅输出 %~f1.

引用的目录中所有文件扩展名为 .mkv 的文件的名称

这两条文件未找到的错误消息很可能是因为没有*.mkv file/folder is found in the current directory whatever is the current directory on the execution of the batch file.

文件名由 DIR 输出,没有路径,除了选项 /S 用于递归搜索。在处理 DIR 输出的文件名时必须考虑到这一点,这在问题中发布的批处理代码中没有完成。

4。启用延迟扩展不利于使用 FOR 循环处理文件名

启用 delayed expansion 以上 FOR 循环处理文件名,或文本文件中的行,或从后台执行的命令进程的标准输出捕获的行,不好,因为它会导致在 FOR 执行的命令块中为每个文件名在执行前第二次解析命令行。在这种情况下,包含一个或多个感叹号的 file/folder 名称或行未正确处理,因为 ! 在第二次解析时被 cmd.exe 解释为延迟扩展的 start/end环境变量引用而不是文件名或行的文字字符。

参见:How does the Windows Command Interpreter (CMD.EXE) parse scripts?

5。 cat 不是 Windows 命令

cat 不是 Windows command. That is a tool ported from Unix/Linux to Windows or executed on Windows 10 using Subsystem for Linux (WSL).

因此,最好避免使用 cat,因为 Windows 默认不可用,具体取决于 Windows 的版本和用户的配置。

6.命令 CALL 在 运行 可执行文件

上没有用

命令 CALL 对从批处理文件中 运行ning 可执行文件没有用。这是 Windows 命令处理器对 运行 可执行文件的默认行为,并在处理批处理文件中的下一个命令行之前等待 self-termination。

命令CALL主要用于从批处理文件中调用批处理文件。

在命令行上使用命令 CALL 只是 运行 一个可执行文件使得批处理文件的处理速度变慢,因为 cmd.exe 个进程在这种情况下,命令行第二次类似于在执行命令行之前延迟扩展的用法。

7。将视频信息采集到一个.nfo文件中的批处理文件

我没有安装 MediaInfo 工具,也没有 MKV 文件或其他视频文件。将路径传递给批处理文件的目录设为当前目录,然后 运行 MediaInfo.exe 仅使用该目录中视频文件的名称即可获取 Complete name 信息写入没有路径的文件。 MediaInfo 似乎也是从 Unix/Linux 移植的工具,因为它输出视频文件的完整名称,不带驱动器号和冒号,并且使用 / 而不是 \。反斜杠是 Windows 上的目录分隔符,因为它可以在有关 Naming Files, Paths, and Namespaces.

的 Microsoft 文档中阅读

不使用 PowerShell 或 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

注意: Windows 命令处理器 cmd.exe 不是为处理名称中包含 Unicode 字符的文件名而设计的。因此,如果需要一个解决方案真正适用于所有文件名,包括名称中带有 Unicode 字符的文件名,则有必要为该任务编写一个 PowerShell 脚本,并使用 powershell.exe 作为脚本解释器。

大多数命令行都用command的注释来解释REM 在批处理文件中。

这里是 FOR 循环的描述,用于处理指定目录中的所有 AVI、MP4、MPG 和 MKV 文件,内部 FOR 循环到 运行 工具 MediaInfo 并处理输出行,修改带有 Complete name 的行以删除 Unix/Linux 路径。

最外层的FOR在后台启动了一个命令进程%ComSpec% /c和命令行DIR附加为附加参数。

命令DIR

  • %FolderPath%
  • 引用的目录中搜索
  • 由于选项 /A-D(属性而非目录)仅适用于文件
  • 匹配四种通配符模式之一 *.avi*.mp4*.mpg*.mkv
  • 由于选项 /B.
  • ,仅以裸格式输出没有路径的文件名

不应该有错误消息输出,因为上面使用 IF 条件到 FOR 循环来检查任何视频的存在在 运行 宁 FOR 循环之前的文件。 IF 条件阻止在指定目录中创建根本不包含视频文件的 .nfo 文件。

CMD内部命令DIR处理后台命令进程STDOUT的输出是for 分别捕获 cmd.exe 处理批处理文件并在启动后逐行处理 cmd.exe 自行终止。

FOR 选项 /F 总是忽略空行,这在文件名列表中无关紧要。默认情况下,带有文件名的行将使用普通 space 和水平制表符作为字符串分隔符拆分为子字符串。文件名可以在开头和中间包含一个或多个 space。出于这个原因,选项 delims= 用于指定一个空的分隔符列表,以防止将文件名拆分为子字符串(标记)。如果第一个子字符串(标记)以分号开头,则该行也会被 FOR 忽略,因为 ; 是默认的行尾字符。文件名可以以 ; 开头,尽管这很不常见。因此,选项 eol=| 用于将竖线定义为任何文件名都不能包含的行尾字符。 "tokens=*" 没有用,因为它会首先从文件名中删除前导 space,如果剩余的文件名以分号开头,则文件名将被 FOR[= 忽略284=].

所以一个没有路径的文件名被分配给指定的循环变量I,即使有不寻常的名字  ;Video 100% & Test (1)!

如果当前处理的文件名不是DIR输出的第一个视频文件名(未排序分别为按文件排序系统)。环境变量 SeparatorFOR 循环之上明确未定义,并在外部 FOR 循环的每次迭代中(重新)定义。赋给环境变量的值Separator无所谓。

有关使用 echo( 而不是 echo. 输出空行的原因,请参阅 DosTips 论坛主题 ECHO. FAILS to give text or blank line - Instead use ECHO/

环境变量 OutputLine 在 运行ning MediaInfo 之前明确未定义,后来在找到带有 Complete name 的行时定义。它用于在处理行 Complete name 后加快信息行的处理,因为在这种情况下,所有其他行都可以简单地输出而无需任何进一步的特殊处理。

工具 MediaInfo 也通过在后台启动另一个带有 %ComSpec% /c 的命令进程和 ' 中的命令行作为附加参数来执行。因此,了解 cmd.exe 如何处理选项 /C 之后的参数字符串非常重要。这很棘手,因为参数字符串的处理取决于 运行ning 在命令提示符 window cmd /? 上的帮助输出所解释的几个条件。在这种情况下,有必要将整个命令行包含在 " 到 运行 后台命令进程中,并将正确的命令行作为参数字符串。

但是批处理文件也由cmd.exe处理。因此 FOR 命令行必须包含由后台命令进程以对两者都有效的方式执行的命令行 cmd.exe。这就是为什么 " 在整个命令行的开头和结尾以及重定向运算符 |^ 转义以被 cmd.exe 解释为文字字符的原因处理批处理文件。传递给 started cmd.exe" 中包含的命令行不再包含脱字符。

MediaInfo 的输出被重定向到 FINDSTR,其中 运行 是一个匹配所有行的正则表达式因此,nd 根据选项 /N 输出所有带有行号和冒号的行。这样做是为了确保 FOR 最终捕获的行不是一个完全空的行,它最终也应该在 NFO 文件中并且不会被 FOR[=284 静默忽略=].

MediaInfo 输出的行由 FINSTR 扩展,开头有行号和冒号,被 捕获FOR分别cmd.exe处理批处理文件,并在启动后台命令进程自行终止后逐行处理。

当前行首先按原样分配给环境变量 InfoLine,同时禁用延迟扩展以防止将 ! 解释为延迟扩展环境变量引用的 start/end。

接下来启用延迟环境变量扩展。请阅读 以了解有关命令 SETLOCALENDLOCAL 的详细信息,因为后台发生的不仅仅是启用延迟扩展。

如果已经定义了环境变量OutputLine并删除了行号和行首的冒号,则仅输出当前行以通过[=输出该行作为后台命令进程的输出216=]MediaInfo.

否则会对当前行进行 case-sensitive 字符串比较,所有出现的 :Complete name(行号后的冒号和字符串 :Complete name)已删除 case-insensitive该行根本没有修改。如果带有字符串替换的行与没有字符串替换的行相同,则来自 MediaInfo 的这一行在开头不包含字符串 Complete name,因此也只是在删除行号的情况下输出和冒号。

否则在 MediaInfo 的捕获输出中找到带有 Complete name 的行。出于这个原因,行号和开头的冒号被删除的行被分成两个子字符串。第一个子字符串是 Complete name,其中白色 space 和冒号一直到分配给循环变量 K 的行中的第一个 /。第二个子字符串是第一个 / 之后的所有内容,直到分配给下一个的行尾,但根据 ASCII table 的一个循环变量是字母 L.

在行首之前首先禁用延迟扩展,第三个FOR命令行输出不带路径的文件名。接下来,现在定义环境变量 OutputLine 以仅输出 MediaInfo.

的所有其他行

在处理视频文件期间,处理批处理文件的命令进程标准输出的所有输出都被重定向到指定文件夹中的文件夹名称和文件扩展名 .nfo 的文件中。

媒体信息文件在文件 .nfo 上成功,最终存在(信息文件在启动批处理文件时不存在,另外 write-protected 通过 read-only 属性, NTFS 权限或文件访问权限)。

为了了解使用的命令及其工作原理,请打开 command prompt window,在那里执行以下命令,并仔细阅读每个命令显示的所有帮助页面。

  • call /?
  • cmd /?
  • dir /?
  • echo /?
  • endlocal /?
  • findstr /?
  • for /?
  • goto /?
  • if /?
  • pause /?
  • rem /?
  • set /?
  • setlocal /?

批处理文件可以是 运行,也可以来自 Windows 命令提示符 window 或 PowerShell 控制台,没有或有文件夹路径,也可以是相对路径。

我认为您通过向 MediaInfo 提供完整路径作为参数,自己制造了一个问题。如果您只提供文件名,Complete name 将只反映文件名。

此外,除非我误解了你的意图,否则当我认为没有必要时,你正在跳过许多障碍。

应在您常用的脚本目录中创建以下示例批处理文件,如果您愿意,甚至可以 'Documents'。

然后你应该在你的 'SendTo' 目录中创建一个快捷方式,给它一个你会理解的名字,也许 MediaNFO.

现在您需要做的就是右键单击您的目录并选择Send toMediaNFO。这应该在右键单击的目录中创建一个文件,与该目录同名,并包含它包含的每个受支持文件的 mediainfo 输出。 Complete name 行不应该包含路径信息,只有 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

您可以在行 4 上更改 mediainfo.exe 的位置,在行 5 上更改输出扩展名;但其他任何东西都不应修改。

您还应该注意到,我已经向该脚本添加了一些输入验证。如果您的输入目录不是包含现有 mediainfo 可执行文件支持文件的完全限定目录路径,它将报告错误并关闭。