分段是个好东西,然而等想要完整缓存的时候就非常要命了...
缘起
昨天在 B 站上花 5 B 币买了《你的名字。》,然后就试图把它搞到本地。客户端是没法下载的,提示版权受限,原因都知道。然后就要用某些特殊的方式抓 URL 了,蠢蠢地一段段下载(
update @2017.8.29: 现在手机客户端可以正常缓存了...
1080P 版君名总共有 18 个分段,所以肯定要合并啊。
分段命名大概长这样:
需求
- 合并分段的 flv 文件到一个文件;
- 操作方便;
- 速度尽可能地快。
解决方案
第一时间只想到了 ffmpeg
,然后折腾了半天写了个 PHP Script 自动写列表,用别的怕是都合完两遍了...感觉自己好蠢
ffmpeg
使用还是相当方便的,只需要一个文件列表(e.g. ff.txt
),长这样:
file '1.flv'
file '2.flv'
file '3.flv'
file '4.flv'
file '5.flv'
然后一行命令
ffmpeg -f concat -i ff.txt -c copy output.mp4
然而像我这么懒的人怎么可能去手动打个文件列表出来...
写个脚本
当然是选择全世界最好的语言 PHP 啊,因为其他都不会(
然而 PHP 直接 scandir
的排序会不正确,因为分段数大于 10,最后结果会这样:
22500529-1-hd.flv
22500529-10-hd.flv
22500529-11-hd.flv
22500529-12-hd.flv
22500529-13-hd.flv
22500529-14-hd.flv
22500529-15-hd.flv
22500529-16-hd.flv
22500529-17-hd.flv
22500529-18-hd.flv
22500529-2-hd.flv
22500529-3-hd.flv
22500529-4-hd.flv
22500529-5-hd.flv
22500529-6-hd.flv
22500529-7-hd.flv
22500529-8-hd.flv
22500529-9-hd.flv
于是决定用正则去匹配分段 ID(e.g. 22500529-13-hd.flv
中的 13
),存进一个数组,然后按顺序去遍历这个数组,顺序就正确了,还不用动原文件名(主要是强迫症)
<?php
echo "Making a list..." . "\n";
foreach(scandir("./") as $name) {
if (preg_match_all("/[0-9]+-(.*)-hd.flv/", $name, $id)) {
$file[$id[1][0]] = $name;
}
}
if (empty($file)) {
echo "Can't find any video.\nExit.";
exit;
}
$list = "";
for ($i = 1; true; $i++) {
if (!isset($file[$i+1])) {
$list .= "file '" . $file[$i] . "'";
break;
}
$list .= "file '" . $file[$i] . "'\n";
}
file_put_contents("./ff.txt", $list);
echo "Using ffmpeg to merge..." . "\n";
passthru("ffmpeg -f concat -i ./ff.txt -c copy output.mp4");
echo "Done.";