批处理文件以递归方式混合来自不同文件夹的 .mp4 和 .srt

批处理文件以递归方式混合来自不同文件夹的 .mp4 和 .srt

现在,torrent 中出现了一种新趋势,即将电视和电影以 x265 .mp4 格式发布,并将 .srt 字幕放在单独的文件夹中,遵循以下文件夹结构:

Season1\title1.mp4
Season1\title2.mp4
Season1\title3.mp4
Season1\Subs\title1\subfile1.srt
Season1\Subs\title1\[subfile2.srt]
Season1\Subs\title1\[subfile3.srt]
Season1\Subs\title2\subfile1.srt
Season1\Subs\title2\[subfile2.srt]
Season1\Subs\title2\[subfile3.srt]
Season1\Subs\title3\subfile1.srt
Season1\Subs\title3\[subfile2.srt]
Season1\Subs\title3\[subfile3.srt]

我的目标是将每个 .mp4 多路复用到其 subs 文件夹中的第一个 .srt。我可以使用 MKVToolNix GUI 一次完成此操作,但我一直在寻找一种更简单/更快速的方法来使用批处理文件(或 PowerShell 脚本)执行此操作。以下两种解决方案接近:

将 MP4 和 SRT 文件批量合并/多路复用为 MKV

批量合并/多路复用 .srt 与 .mkv 文件

不过,只有当 .mp4 和 .srt 位于同一文件夹中且标题正确时,它们才有效。我的问题(也是许多其他人必须处理的问题)是在新发布标准下:

  • .mp4 和 .srt 位于不同的文件夹中。
  • 每个 .mp4 可能有一个或多个 .srt 文件。如果是这种情况,可以肯定地认为我想要第一个 .srt 文件,它通常是默认的英语字幕。
  • .srt 文件不遵循命名约定,即第一个文件始终使用相同的标题。换句话说,批处理文件必须使用第一个 .srt,无论其名称如何。

这是 2018 年的剧本苏杰·帕德克,是一个好的开始。

for %%f in (*.mkv) do (
    echo %%~nf
    'C:\Program Files\MKVToolNix\mkvmerge.exe' -o "%%~nf_New.mkv" "%%~nf.mkv" --language 0:eng "%%~nf.srt"
    move /Y "%%~nf_New.mkv"  "%%~nf.mkv"

只要所有文件(.mp4 和 .srt)都位于同一文件夹中且标题正确,它就会递归工作。不过,我正在寻找一个不涉及重命名或移动文件的批处理文件。它将使用 mkvmerge.exe 将每个 .mp4 复用到其子文件夹中的第一个 .srt,并将每个新的 .mkv 保存到与 .mp4 相同的文件夹中。

另外,由于我可以弄清楚,Mkvmerge.exe 应该将 .srt 设置为英语语言强制使用 DefaultTrack 标志

它适用于一个季节的所有 .mp4 文件。除非您很勤奋,否则无需让它逐季运行。然后,我将从与每个季节的 .mp4 文件相同的文件夹中运行每个季节的批处理文件。

抱歉解释得这么长,但这真的超出了我的理解范围,我需要你的帮助。我很感激任何建议。

答案1

@echo off 

setlocal && cd /d "%~dp0"
set "_mkv=C:\Program Files\MKVToolNix\mkvmerge.exe"
set "_flag_0=--default-language en --language 0:en"
set "_flag_1=--priority higher --flush-on-close --disable-track-statistics-tags -o"

for /f usebackq^delims^= %%G in (`dir /a:d /b ^|findstr Season.*[0-9] ^|find/v /i "\subs\"
   `)do if exist "%%G\*.mp4" for /f usebackq^delims^= %%i in (`2^>nul where "%%~G:*.mp4"
        `)do call %:^) "%%~G" "%%~ni" "%%~i" "%_mkv%" "%_flag_0%" "%_flag_1%" "*.srt"

%:^)
if "%~1" == "" (endlocal & goto :eof)else for /f ^usebackq^delims^= %%# in (`2^>nul ^
     where "%~1\Subs\%~2:%~7"`)do "%~4" %~6 "%~dpn3.mkv" "%~3" %~5 "%%~f#" & exit /b
     

1.将此 bat 保存在 base/root 下(SeasonX\文件夹上一级):

2.使用for /f循环获取每个文件夹的完整路径SeasonX\

3.如果该文件夹中有一个any/more.mp4,那么这次也会获取它们的路径

4.保存您需要的 mkv/flags以及 mkv 可执行文件的完整路径,并在函数内部使用 ( :label)

5.当找到第一个 subtitle\file.srt 时,调用一个已经组成要在其中使用的参数的函数来处理 mp4,并立即退出该函数。


观察:1.Findstr过滤子文件夹并允许其在所有符合您的文件夹名称布局的文件夹上运行,下面有一些选项可以检查哪一个最适合您的场景

dir /a:d /b | findstr /ei Season.[0-9]       |find/v /i "\subs\"
dir /a:d /b | findstr /ei Season.*[0-9]      |find/v /i "\subs\"
dir /a:d /b | findstr /ei Season[0-9][0-9]   |find/v /i "\subs\"
dir /a:d /b | findstr /ei Season.[0-9][0-9]  |find/v /i "\subs\"
dir /a:d /b | findstr /ei Season.*[0-9][0-9] |find/v /i "\subs\"

观察:2。在 bat 中调用函数时,需要传递变量/字符串(在参数中),以便可以使用它们:

::  call :label/function and passing all arguments
:: 
::  call %:^) "%%~G" "%%~ni" "%%~i" "%_mkv%" "%_flag_0%" "%_flag_1%" "* .srt"
::  call %:ˆ) "Season1" "title1" "C:\Users\Answer42\Videos\SU-2022\Season1\title1.mp4" "C:\Program Files\MKVToolNix\mkvmerge.exe" "--default-language en --language 0:en" "--priority higher --flush-on-close --disable-track-statistics-tags -o" "*.srt"
:: 
:: ------------------------------------------------------------------------------- ::
::
:: %1  ==      "%%~G" == folder where .mp4 files are
:: %2  ==     "%%~ni" == the name without extension for the current mp4
:: %3  ==      "%%~i" == the full path to the current mp4 file
:: %4  ==    "%_mkv%" == the full path to the mkvmerge executable
:: %5  == "%_flag_0%" == mkv flag for process the first subtitle :: input in loop
:: %6  == "%_flag_1%" == mkv flag to process and output file
:: %7  ==     "*.srt" == subtitle extension
:: 
:: ------------------------------------------------------------------------------- ::

观察:3。循环内的命令for /f(函数/标签内)以及使用参数在 for 循环中获得的结果:

for /f ... (`where "%~1\Subs\%~2:%~7"`)do...
for /f ... (`where "C:\Users\Answer42\Videos\SU-2022\Season1\Subs\title1:*.str`)do...

...)do "%~4" %~6 "%~dpn3.mkv" "%~3" %~5 "%%~f#"
...)do "C:\Program Files\MKVToolNix\mkvmerge.exe" --priority higher --flush-on-close --disable-track-statistics-tags -o "C:\Users\Answer42\Videos\SU-2022\Season1\title1.mkv" "C:\Users\Answer42\Videos\SU-2022\Season1\title1.mp4" --default-language en --language 0:en "C:\Users\Answer42\Videos\SU-2022\Season1\Subs\title1\subfile1.srt"


我的目标是将每个 .mp4 与其 subs 文件夹中的第一个 .srt 多路复用...

使用此代码最棘手的部分是调整返回正确字幕的命令......

  • 请理解,我们不知道如何才能使输出符合目标,我们甚至看不到文件、文件名、创建/更改日期甚至其内容。

  • 因此,很难定义什么使您有资格成为第一名(或 english.str),所以您可以进入此部分进行调整(如有必要),使用以下可能的命令之一替换函数中的当前命令:

%:^)
if "%~1" == "" (endlocal & goto :eof)else for /f ^usebackq^delims^= %%# in (`2^&>nul ^
     where "%~1\Subs\%~2:%~7"`)do "%~4" %~6 "%~dpn3.mkv" "%~3" %~5 "%%~f#" & exit /b

:: Possible adjustments/replacement/in command:
     where "%~1\Subs\%~2:%~7"`)do...

     where "%~1\Subs\%~2:%~7"^|sort`)do...
     where "%~1\Subs\%~2:%~7"^|sort /r`)do...

     dir /b /a:-d /on /s "%~1\Subs\%~2\%~7"`)do...
     dir /b /a:-d /o-n /s "%~1\Subs\%~2\%~7"`)do...

     dir /b /a:-d /od /tc /s "%~1\Subs\%~2\%~7"`)do...
     dir /b /a:-d /o-d /tc /s "%~1\Subs\%~2\%~7"`)do...

     dir /b /a:-d /on /s "%~1\Subs\%~2\%~7" ˆ|sort /r`)do...
     dir /b /a:-d /o-n /s "%~1\Subs\%~2\%~7" ˆ|sort /r`)do...

     dir /b /a:-d /od /tc /s "%~1\Subs\%~2\%~7" ^|sort`)do...
     dir /b /a:-d /o-d /tc /s "%~1\Subs\%~2\%~7" ^|sort /r`)do...

相关内容