这里介绍一个Windows批处理脚本(Windows Batch Script),主要用于处理 .m3u8 ts 视频文件的下载和合并功能。
以下是程序的主要功能和逻辑流程:
功能概述
-
参数检查与路径处理:
-
检查是否传递了文件或文件夹路径作为参数。
-
判断传递的路径是文件还是文件夹,并根据路径切换到相应的目录。
-
-
文件处理逻辑:
-
如果目标目录中存在
.m3u8
文件(如index.m3u8
或以当前目录名命名的.m3u8
文件),程序会解析该文件。 -
根据
.m3u8
文件中的内容,提取有效的文件链接(如.ts
文件的 URL)。
-
-
文件下载:
-
使用
aria2c
工具批量下载.m3u8
文件中列出的文件(如.ts
文件)。 -
下载的文件会保存到当前目录。
-
-
文件合并:
- 使用
ffmpeg
将下载的文件片段(如.ts
文件)合并为一个完整的视频文件(如.mp4
文件)。
- 使用
-
清理操作:
-
提供选项删除下载的片段文件、临时文件(如
newindex.m3u8
、links.list
等)。 -
根据用户选择,保留或删除这些文件。
-
-
错误处理与用户交互:
-
检查目标文件是否已存在,并提示用户是否需要重新生成。
-
如果
.m3u8
文件或目标文件已存在,程序会询问用户是否覆盖。 -
如果下载或合并过程中出现错误,程序会提示用户。
-
详细逻辑流程
-
参数检查:
-
如果未传递参数,程序提示用户并退出。
-
如果传递了参数,程序会判断路径是文件还是文件夹。
-
-
目录切换:
-
如果路径是文件夹,程序切换到该文件夹。
-
如果路径是文件,程序切换到文件所在的目录。
-
-
解析
.m3u8
文件:-
程序会尝试解析
index.m3u8
或以当前目录名命名的.m3u8
文件。 -
提取文件链接(如
.ts
文件的 URL)并保存到links.list
文件中。 -
如果
.m3u8
文件中包含加密信息(如 AES-128 密钥链接),程序会提取并处理这些链接。
-
-
文件下载:
-
使用
aria2c
根据links.list
文件中的链接批量下载文件。 -
下载的文件会保存到当前目录。
-
-
文件合并:
-
使用
ffmpeg
将下载的文件片段(如.ts
文件)合并为一个.mp4
文件。 -
提供多种
ffmpeg
命令选项,用户可以根据需要选择合适的命令。
-
-
清理操作:
-
提供选项删除下载的片段文件、临时文件(如
newindex.m3u8
、links.list
等)。 -
用户可以选择保留或删除这些文件。
-
-
错误处理与用户交互:
-
如果目标文件已存在,程序会提示用户是否重新生成。
-
如果
.m3u8
文件或目标文件已存在,程序会询问用户是否覆盖。 -
如果下载或合并过程中出现错误,程序会提示用户。
-
应用场景
-
该脚本主要用于处理视频片段的下载和合并,通常用于处理
.m3u8
格式的视频文件(如在线视频、直播回放等)。 -
用户可以通过传递文件或文件夹路径作为参数,让脚本自动完成下载和合并操作。
-
脚本提供了用户交互功能,允许用户根据需要选择是否覆盖文件或删除临时文件。
注意事项
-
程序依赖于外部工具
aria2c
和ffmpeg
,需要确保这些工具已安装并配置在系统路径中。 -
程序的逻辑较为复杂,涉及文件路径处理、文件下载、文件合并等多个步骤,需要谨慎使用。
-
用户在运行脚本时需要确保传递的参数正确,否则可能导致程序无法正常运行。
完整的程序代码
@echo off
echo 正在处理文件:%~1
rem ~可以确保获取到的参数不包含多余的引号
rem 判断是否传递了参数
if "%~1"=="" (
echo 未传递任何参数,请提供文件或文件夹路径。
exit /b 1
)
rem 获取参数的属性
set "attribute=%~a1"
set "fpath=%~1"
rem 判断是否为文件夹
if "%attribute:~0,1%"=="d" (
echo "%~1 是一个文件夹目录。"
rem 这里可以添加处理文件夹的逻辑
rem set "fpath=%~1"
) else if "%attribute:~0,1%"=="-" (
echo "%~1 是一个文件路径。"
rem 这里可以添加处理文件的逻辑
set "fpath=%~dp1"
) else (
echo "无法识别 %~1 是文件还是文件夹。"
exit /b 1
)
echo 切换目录到 "%fpath%"
pushd "%fpath%"
if errorlevel 1 (
echo "Error: Directory %~1 not found."
pause
exit /b
)
for %%i in (.) do set "curr=%%~ni"
echo "使用最后一级目录 %curr% 作为文件名"
rem 判断文件是否存在,如果存在询问用户是否删除重新生成
setlocal enableextensions enabledelayedexpansion
rem 检查 index.m3u8 文件是否存在
rem set "m3u8=index.m3u8"
set "m3u8=%curr%.m3u8"
if not exist "!m3u8!" (
set "m3u8=index.m3u8"
)
echo "!m3u8!"
rem if exist "%curr%.mp4" (del /f "%curr%.mp4")
rem 定义目标文件路径,你可以根据实际情况修改
set "target_file=%curr%.mp4"
rem 检查目标文件是否存在
if exist "%target_file%" (
:ask_user
set /p "choice=目标文件 %target_file% 已存在,是否重新生成?(Y/N)(回车=是): "
:: 检测用户输入
if /i "!choice!"=="" (
set "choice=Y" :: 如果用户直接回车,则设置默认值为 Y
)
if /i "!choice!"=="Y" (
rem 用户选择重新生成,删除原有文件
del /f "%target_file%"
echo "已删除原有文件 %target_file%。"
) else if /i "!choice!"=="N" (
echo 你选择不重新生成,程序将退出。
goto ask_user3
pause
exit /b
) else (
echo 无效的输入,请输入 Y 或 N。
goto ask_user
)
)
rem 如果 newindex.m3u8 文件存在则直接合并文件
if exist "newindex.m3u8" (
:ask_user2
set /p "choice=目标文件 newindex.m3u8 已存在,是否重新生成?(Y/N)(回车=是): "
echo !choice!
:: 检测用户输入
if /i "!choice!"=="" (
set "choice=Y" :: 如果用户直接回车,则设置默认值为 Y
)
if /i "!choice!"=="Y" (
rem 用户选择重新生成,删除原有文件
del /f newindex.m3u8
del /f links.list
echo 已删除原有文件 newindex.m3u8。
) else if /i "!choice!"=="N" (
echo 你选择不重新生成,直接跳转到合并过程。
goto ffmpeg_merge
) else (
echo 无效的输入,请输入 Y 或 N。
goto ask_user2
)
)
set /a b=0
set /a fn=0
rem 遍历 index.m3u8 文件的每一行
for /f "usebackq delims=" %%a in ("!m3u8!") do (
rem 去除可能的引号
set "url=%%a"
set "url=!url:"=!"
rem 判断 url 是否为有效的文件链接(简单判断是否以 http 或 https 开头)
if "!url:~0,4!"=="http" (
rem 提取文件名
for %%f in ("!url!") do set "filename=%%~nxf"
if exist "!filename!" (
rem 判断文件大小 for /f %%i in ('dir /b %%a') do if 0 lss %%~zi (echo file %%a >> newindex.m3u8)
echo !filename! 文件已存在!
) else (
echo !url! >> links.list
)
echo !filename! >> newindex.m3u8
) else (
if "!b!"=="0" (
if "!url:~0,30!"=="#EXT-X-KEY:METHOD=AES-128,URI=" (
echo "!url!"
set "uri=!url:~30!"
set "uri=!uri:"=!"
echo "uri=!uri!"
if "!uri:~0,4!"=="http" (
if not exist "!uri!" (
echo !uri! >> links.list
)
set /a b+=1
echo #EXT-X-KEY:METHOD=AES-128,URI=key.key >> newindex.m3u8
rem 输出提取到的 URI
echo 提取到的 URI 是: !uri!
)
)
if "!b!"=="0" (
rem echo !url! 不是有效的文件链接,跳过
echo !url! >> newindex.m3u8
)
) else (
rem echo !url! 不是有效的文件链接,跳过
echo .
echo !url! >> newindex.m3u8
)
)
set /a fn+=1
)
rem 设置包含下载链接的文本文件路径
set "links_file=links.list"
rem 设置下载文件保存的目录
set "download_dir=%cd%"
if exist "%links_file%" (
rem 调用 aria2c 批量下载文件
aria2c -i "%links_file%" -d "%download_dir%" -x 16 -s 8 -j 10 -c
echo 调用 aria2c 批量下载完成!
)
:ffmpeg_merge
rem 如果 key.key 文件不存在,ffmpeg 不会报错,会继续执行
echo ffmpeg merge begin
ffmpeg -protocol_whitelist "file,crypto" -allowed_extensions ALL -threads auto -i "newindex.m3u8" -c copy -bsf:a aac_adtstoasc "%curr%.mp4"
rem ffmpeg -protocol_whitelist "file,crypto" -allowed_extensions ALL -i "newindex.m3u8" -c copy -bsf:a aac_adtstoasc "output.mp4"
rem ffmpeg -protocol_whitelist "file,crypto" -allowed_extensions ALL -threads auto -i "newindex.m3u8" -c copy "%curr%.mp4"
rem ffmpeg -protocol_whitelist "file,crypto" -allowed_extensions ALL -i "newindex.m3u8" -c:v libx264 -c:a aac "%curr%.mp4"
rem ffmpeg -f concat -safe 0 -protocol_whitelist "file,concat" -i newindex.m3u8 -c copy %curr%.mp4
if errorlevel 1 (
echo Error: ffmpeg failed to merge files.
) else (
echo "%curr%.mp4 合并成功!"
:ask_user3
set /p "choice=是否删除下载的切片文件?(Y/N)(回车=Y): "
echo "!choice!"
:: 检测用户输入
if /i "!choice!"=="" (
set "choice=Y" :: 如果用户直接回车,则设置默认值为 Y
)
if /i "!choice!"=="Y" (
rem 用户选择重新生成,删除原有文件
echo "!m3u8!"
del /f *.ts
rem 遍历 index.m3u8 文件的每一行
for /f "usebackq delims=" %%a in ("!m3u8!") do (
rem 去除可能的引号
set "url=%%a"
set "url=!url:"=!"
rem 判断 url 是否为有效的文件链接(简单判断是否以 http 或 https 开头)
if "!url:~0,4!"=="http" (
rem 提取文件名
for %%f in ("!url!") do set "filename=%%~nxf"
echo !filename!
if exist "!filename!" (
del /f "!filename!"
)
)
)
if exist "newindex.m3u8" (
del /f newindex.m3u8
)
if exist "links.list" (
del /f links.list
)
if exist "index.html" (
del /f index.html
)
if exist "index.m3u8" (
del /f index.m3u8
)
if exist "index.1.html" (
del /f index.1.html
)
if exist "url.txt" (
del /f url.txt
)
if exist "!m3u8!" (
del /f "!m3u8!"
)
) else if /i "!choice!"=="N" (
echo 你选择不删除,程序即将退出!
exit /b 0
) else (
echo 无效的输入,请输入 Y 或 N。
goto ask_user3
)
)
endlocal
pause
如何使用呢?
将以上内容保存为 "ts2mp4.bat",放在系统目录下,比如:C:\Windows,这样你就可以在任何一个目录调用它了;
首先你得知道如何拿到视频的 .m3u8 文件的URL地址 ,下载到本地;
然后就可以使用上面的bat下载ts切片并合并为 mp4视频文件了,例如: ts2mp4 index.m3u8
你也可以将以下内容导入注册表:
Windows Registry Editor Version 5.00
[HKEY_CLASSES_ROOT\VLC.m3u8\shell\ts2mp4\command]
@="ts2mp4.bat \"%1\""
这样在 .m3u8 文件上点击鼠标右键时,就可以通过右键菜单的形成调用 ts2mp4 了;
该程序目前还存在一个问题 :如果 .m3u8 文件中的ts切片url地址是相对的,不是完整的url的话,无法实现下载;
编写该bat文件遇到的坑:
echo 后面输出的内容中有变量(并且变量中包含特殊字符,比如小括号)的情况必须使用双引号将输出内容括起来,否则即使程序没有执行到那一行,而是执行到那个程序块的话也是会报错停止执行,这给查找问题发生的位置带来不小的麻烦
bat的字符查找功能比较弱,要要找字符串的话实现起来比较麻烦;