整理Bilibili安卓客户端缓存的视频
March 16, 2017
Perl
昨天晚上无意中看到了B站竟然有TOUCH。。完全没想到。所以我决定这次要把这部动画片全部下载下来,B站的视频质量看起来还不错。所以最简单的方法就是用安卓客户端缓存,然后在电脑上处理了。
其实之前我做过这件事情。当初是为了整理「暖暖日记」这部番,因为它每集仅仅有5分钟左右。每个视频只有一个文件,所以只需要找到所有视频然后读json文件找到视频名称,重命名就好了。
不过这次好像有点不同:每集一般有25分钟,缓存的是高清的。奇怪的是:即使是同一集,最开始我缓存的时候某一集是仅仅有一个mp4文件,然后我又实验了一次,发现它就变成了多个flv文件。。真是迷。。
处理也不难,如果是单个mp4文件直接重命名就好了。如果是多个flv文件,那么就需要先合并,然后再命名。
然后看了一下之前写的Perl程序,竟然,看不太懂了。。。T_T,然而还好,最后还是搞定了:
#!/usr/bin/perl
# Date : 2017/03/16 19:14:35
# Finish: 2017/03/16 22:04:07
# NOTE: There MUST NOT be any non-ascii character in the path!!!!!!!!!!
use strict;
use warnings;
use 5.014;
use Cwd;
use JSON qw();
use open ':std', ':encoding(UTF-8)';
use File::Copy;
my $cur_dir = '/home/repl/Videos/Bilibili/Fanju/TOUCH/s_2425';
opendir(DIR, $cur_dir) or dir $!;
while (my $file = readdir(DIR)) {
next if ($file =~ /^\./);
# get index_title
my $json_file = $cur_dir . "/$file" . '/entry.json';
my $json_text = do {
open(my $json_fh, "<:encoding(UTF-8)", $json_file)
or die("Can not open $json_file\"$!\n\"");
local $/;
<$json_fh>
};
my $json = JSON->new;
my $data = $json->decode($json_text);
my $index = $data->{'ep'}{'index_title'};
# directories like 58116
my $subdir = "$cur_dir/$file";
opendir(SUBDIR, $subdir) or dir $!;
while (my $subfile = readdir(SUBDIR)) {
next if ($subfile =~ /^\./);
if (-d "$subdir/$subfile") {
if ($subfile =~ /hdmp4/) {
# only rename
opendir(DSTDIR, "$subdir/$subfile");
while (my $dstfile = readdir(DSTDIR)) {
next if ($dstfile =~ /^\./);
if ($dstfile =~ /mp4$/) {
$index =~ s/ /_/g;
rename("$subdir/$subfile/$dstfile", "$index.mp4") or die
"failed to copy file" . $index;
}
}
closedir(DSTDIR);
}
if ($subfile =~ /flv/) {
# concat flv files
opendir(DSTDIR, "$subdir/$subfile");
my @flv = ();
while (my $dstfile = readdir(DSTDIR)) {
next if ($dstfile =~ /^\./);
if ($dstfile =~ /flv$/) {
push @flv, $dstfile;
}
}
@flv = sort { $a cmp $b } @flv;
@flv = map { "file './$_'" } @flv;
my $mylist = "$subdir/$subfile/mylist.txt";
open (my $fh, ">", $mylist)
or dir $!;
for (@flv) { print $fh "$_\n"; }
close($fh);
say "$subdir/$subfile";
# output file is: output.flv. Chinese filename will crash. T_T
system("cd $subdir/$subfile && ffmpeg -f concat -safe 0 -i mylist.txt -c copy output.flv");
# rename the filename of the output.flv to Chinese filename.
$index =~ s/ /_/g;
rename("$subdir/$subfile/output.flv", "$index.flv") or die
"failed to copy file" . $index;
closedir(DSTDIR);
}
}
}
close(SUBDIR);
}
closedir(DIR);
exit 0;
遇到几个陷阱:ffmpeg命令的输出文件不能是中文文件名,这个调试很久。然后文件路径最好不要有中文,否则出现一些奇怪的问题,不知道怎么解决,都改成英文名就好了。
哦,还有一件事情:以前试过很多种从Android传数据到Linux的方法,最后还是发现,adb pull
最好用,速度最快。比如:
adb pull /storage/emulated/0/Android/data/tv.danmaku.bili/download/s_2425