1 Star 2 Fork 3

无云无声 / java-learn-demo

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
BilibiliUtilVideoUWP.java 19.19 KB
一键复制 编辑 原始数据 按行查看 历史
无云无声 提交于 2024-03-23 22:47 . b站下载视频重命名(补充)
package Bilibili;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import util.PythonUtil;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.nio.file.Files;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
import static json.ParseJsonUtil.readFileContent;
/**
* 3分钟教你如何下载B站视频 https://www.bilibili.com/read/cv1422476/
* win10应用商店上下载客户端 bilibili UWP
* b站视频下载修改视频名称工具类(java) https://blog.csdn.net/jiarui_mama/article/details/113069238
* B站 bilibili 视频下载方法 批量重命名工具(Python) https://www.bilibili.com/read/cv6626120
* https://github.com/gooin/bilibili_video_rename_tool
*
* java实现音视频的合并 https://blog.csdn.net/maziaotong/article/details/127863727
*/
public class BilibiliUtilVideoUWP {
// 视频下载位置
private static final String videoDownloadPath = "D:\\bilibiliload\\967612226";
// ffmpeg exe路径,如果配置了环境变量,只写名称即可,如果没有配置,就写全路径
private static final String ffmpegExePath = "ffmpeg";
public static void main(String[] args) throws Exception {
// 根目录下 967612226.dvi cover.jpg desktop.ini
// 分p目录下
// 目前看到有3种格式
// 1.音画分开MP4
// D:\bilibiliload\967612226\290 967612226.info 967612226_290.xml audio1.mp4 video.mp4
// "Format": 2,
// "TotalParts": 2,
// "IsDash": true,
// "IsMerged": false,
// 2.分段flv
// D:\bilibiliload\17222411\1 17222411.info 17222411_1.xml 17222411_1_0.flv 17222411_1_1.flv
// "Format": 1,
// "TotalParts": 2,
// 3.完整合并的MP4
// D:\bilibiliload\333024338\1 333024338.info 333024338_1.xml 333024338_1_0.mp4
// "Format": 2,
// "TotalParts": 1,
// "IsMerged": true,
// String filepath = "D:\\bilibiliload\\333024338"; // 完整视频MP4
String filepath = videoDownloadPath; // 音画分开MP4
// String filepath = "D:\\bilibiliload\\17222411"; // 分段flv 一般6分钟一段
File file = new File(filepath);
if (!file.exists() || !file.isDirectory()) {
System.out.println("请指定正确的目录");
return;
}
File[] files = file.listFiles();
// 根目录下获取视频名称 .dvi
File[] dviFiles = file.listFiles((dir, name) -> name.endsWith(".dvi"));
if (dviFiles == null || dviFiles.length == 0) {
System.out.println("不存在指定后缀的文件");
return;
}
File dviFile = dviFiles[0];
if (!dviFile.isFile()) {
System.out.println("不存在指定后缀的文件");
return;
}
String jsonString = readFileContent(dviFile);
JSONObject jsonObject = JSON.parseObject(jsonString);
// {"SeasonId":null,"EpisodeId":null,"IsBangumi":false,"CoverWidth":192.0,
// "CoverHeight":120.0,"Title":"网易云课堂 - uni-app实战仿糗事百科app开发(上)",
// "IsSelected":false,"IsLastHit":false,"Aid":"71415770","Uploader":"_程序狗",
// "Mid":"232699246","Description":"https://study.163.com/\n#若有冒犯,请联系我删除\n网易云课堂 - uni-app实战仿糗事百科app开发\n课程资料:链接:https://pan.baidu.com/s/1FNG6R6wS1cYH3kxUPwZOGA \n提取码:j0hu \n复制这段内容后打开百度网盘手机App,操作更方便哦",
// "CoverURL":"http://i1.hdslb.com/bfs/archive/2da3ceb0dcac3a352d0f407c824375f12693bc03.jpg",
// "CoverImageSource":null,"Tag":null,"DownloadTimeRelative":161928671,"DownloadTime":null,
// "CreateDate":"2019-10-16 17:13","TotalTime":"00:00:00","Parts":null,"FontSize6":10.0,
// "FontSize8":12.0,"FontSize10":14.0,"FontSize12":16.0,"FontSize14":18.0,"FontSize16":20.0,
// "FontSize18":22.0,"FontSize20":24.0,"FontSize22":26.0,"FontSize24":28.0,"FontSize30":34.0,
// "FontSize34":38.0}
String title = jsonObject.getString("Title");
if (StringUtils.isBlank(title)) {
System.out.println("视频名称为null");
return;
}
// 复制到一个新的目录下
// File parentFile = file.getParentFile();
File targetFile = new File(file, title);
// 已存在同名目录处理,在文件夹名称后面+副本
while (true) {
if (!targetFile.exists() || !targetFile.isDirectory()) {
// 创建目录
// targetFile.mkdir(); // 只能创建一层目录
targetFile.mkdirs(); // 创建多层目录,包括创建必需但不存在的父目录
break;
}
title += "-副本";
targetFile = new File(file, title);
}
// stream流排序 https://blog.csdn.net/qq_36763236/article/details/111469653
List<File> fileList = Arrays.stream(files)
.filter(f -> isP(f))
.sorted(Comparator.comparing(f -> Integer.parseInt(f.getName())))
.collect(Collectors.toList());
if (CollectionUtils.isNotEmpty(fileList)) {
for (File dir : fileList) {
// 获取分P标题
// 333024338.info 333024338_1.xml 333024338_1_0.mp4
// {"Type":0,"Aid":"333024338","Bid":"BV17A411G7aL","Cid":"337618791","SeasonId":null,
// "EpisodeId":null,"Title":"【计算机-Java】Java避坑指南,致经常写bug的你","Uploader":"你的知识书架",
// "Description":"转自网络\r\n用于个人学习研究,如有侵权请联系删除\r\n看了这个指南,减少debug的时间",
// "CoverURL":"http://i2.hdslb.com/bfs/archive/ed96053469cda4829376e74ba4ea79c1bee2fe43.png",
// "Tag":null,"From":"vupload","PartNo":"1","PartName":"1-1 为什么做这门课","Format":2,"TotalParts":1,
// "DownloadTimeRelative":209659970,"CreateDate":"2021-05-13 22:49",
// "TotalTime":"00:05:19.3140000","PartTime":[319314],
// "TotalSizeByte":10571397,"TotalSizeString":null,"IsSinglePart":false,"IsDash":false,
// "IsMerged":true,"VideoInfo":{"MediaType":0,"CodecId":7,"CodecName":"avc1.640028","VideoWidth":1280,
// "VideoHeight":720,"Bandwidth":138950,"FrameRate":24.3902},"AudioInfo":[{"MediaType":1,"CodecId":0,
// "CodecName":"mp4a.40.2","VideoWidth":0,"VideoHeight":0,"Bandwidth":122829,"FrameRate":0.0}]}
File[] pFiles = dir.listFiles();
// 视频文件 mp4 flv
List<File> videoFileList = new ArrayList<>();
// 视频信息文件 .info
File partNameFile = null;
for (File pFile : pFiles) {
if (!pFile.isFile()) {
continue;
}
if (pFile.getName().endsWith(".info")) {
partNameFile = pFile;
}
if (pFile.getName().endsWith(".mp4") || pFile.getName().endsWith(".flv")) {
// audio1.mp4 video.mp4 音频和视频都是MP4
videoFileList.add(pFile);
}
}
if (partNameFile != null && CollectionUtils.isNotEmpty(videoFileList)) {
String partNameJsonString = readFileContent(partNameFile);
JSONObject partNameJsonObject = JSON.parseObject(partNameJsonString);
// 分p名称
String partName = partNameJsonObject.getString("PartName");
String PartNo = partNameJsonObject.getString("PartNo");
// 视频格式 1:flv 2:MP4
int format = partNameJsonObject.getIntValue("Format");
// 视频文件个数 flv:未合并 MP4:音频视频分离
int totalParts = partNameJsonObject.getIntValue("TotalParts");
// 是否合并
Boolean isMerged = partNameJsonObject.getBoolean("IsMerged");
if (format == 2 && isMerged != null && isMerged) {
// 完整视频 Mp4
if (StringUtils.isNotBlank(partName)) {
File videoFile = videoFileList.get(0);
// copy文件
// 4种Java文件复制的方法 https://blog.csdn.net/qq_30436011/article/details/127490081
File dest = new File(targetFile, partName + ".mp4");
Files.copy(videoFile.toPath(), dest.toPath());
// 测试时你,可以先只处理一个
// break;
}
}
if (format == 2 && isMerged != null && !isMerged) {
// 音频视频分离
if (StringUtils.isNotBlank(partName)) {
if (videoFileList.size() > 2) {
System.out.println("视频文件存在多个: " + dir.getAbsolutePath());
continue;
}
// audio1.mp4 video.mp4
String audioPath = null; // 音频文件路径
String videoPath = null; // 视频文件路径
File file1 = videoFileList.get(0);
File file2 = videoFileList.get(1);
if (file1.getName().startsWith("audio")) {
audioPath = file1.getAbsolutePath();
videoPath = file2.getAbsolutePath();
} else if (file1.getName().startsWith("video")) {
audioPath = file2.getAbsolutePath();
videoPath = file1.getAbsolutePath();
}
File dest = new File(targetFile, partName + ".mp4");
// 合并音视频
// 全网最强电商教程《谷粒商城》对标阿里P6/P7,40-60万年薪
// 文件名中有/,会创建2层文件夹
// 是Windows会给出提示:“\”符号是不能作为文件或者文件夹的名字的
// Windows文件名中不能有下列符号:“?”、“、”、“╲”、“/”、“*”、““”、“”“、“<”、“>”、“|”。
// https://blog.csdn.net/flf1234567898/article/details/108518043
ffmpegMerge(videoPath, audioPath, dest.getAbsolutePath());
// 测试时你,可以先只处理一个
// break;
}
}
// ffmpeg将多个flv文件合成为mp4
if (format == 1) {
// 分段flv
if (StringUtils.isNotBlank(partName)) {
// 17222411_2_0.flv 17222411_2_1.flv 17222411_2_2.flv
videoFileList = videoFileList.stream()
.sorted(Comparator.comparing(f ->
// java.lang.NumberFormatException: For input string: "17222411101" 超过intger最大值
// Integer.parseInt(f.getName().substring(0, f.getName().lastIndexOf(".")).replace("_", ""))))
Integer.parseInt(f.getName().substring(f.getName().indexOf("_") + 1, f.getName().lastIndexOf(".")).replace("_", ""))))
.collect(Collectors.toList());
if (videoFileList.size() == 1) {
// 单个文件将flv转换为MP4
// java 使用ffmpeg 处理视频 卡住问题 https://www.cnblogs.com/wangxiaomei/p/16573409.html
// 如果文件重名,就一直在等待 回执 加-y 可以覆盖
// File dest = new File(targetFile, partName + ".mp4");
File dest = new File(targetFile, "(" + PartNo + ")"+ partName + ".mp4");
if (dest.exists()) {
dest = new File(targetFile, "(" + PartNo + ")"+ partName + "-重名" + System.currentTimeMillis() + ".mp4");
}
boolean res = ffmpegFlv2Mp4(videoFileList.get(0).getAbsolutePath(), dest.getAbsolutePath());
if (!res) {
System.out.println("脚本文件执行失败,请手动处理");
break;
}
continue;
}
String str = "";
for (File flvFile : videoFileList) {
if (StringUtils.isNotBlank(str)) {
str += "\n";
}
str += "file '" + flvFile.getAbsolutePath() + "'";
}
System.out.println("flv个数:" + videoFileList.size());
// 保存文件名到目标文件 给ffmpeg调用
File listFile = new File(file, "list.txt");
String listFilePath = listFile.getAbsolutePath();
// 是覆盖,还是追加??? 是覆盖
writeFile(str, listFilePath);
File dest = new File(targetFile, partName + ".mp4");
boolean res = ffmpegMergeFlv(listFilePath, dest.getAbsolutePath());
if (!res) {
System.out.println("脚本文件执行失败,请手动处理");
break;
}
// 测试时你,可以先只处理一个
// break;
}
}
}
}
}
}
/**
* 是否为分P目录
*/
private static boolean isP(File file) {
if (file == null || !file.isDirectory()) {
return false;
}
String name = file.getName();
// java判断字符串是否为纯数字 https://jingyan.baidu.com/article/c74d6000d721f50f6b595d5e.html
return name.matches("[0-9]+");
}
/**
* 将内容写到目标文件
*/
private static void writeFile(String newContent, String targetFile) throws Exception {
File file = new File(targetFile);
FileOutputStream fos = new FileOutputStream(file);
OutputStreamWriter osw = new OutputStreamWriter(fos, "UTF-8");
osw.write(newContent);
osw.flush();
osw.close();
fos.close();
}
/**
* java实现音视频的合并
* https://blog.csdn.net/maziaotong/article/details/127863727
* 使用 ffmpeg 来合并音频和视频文件 https://www.cnblogs.com/dragona/p/17206097.html
*
* @param videoFilePath 原视频路径
* @param audioFilePath 原视频路径
* @param desFilePath 合并后视频存放路径+视频名称
*/
public static void ffmpegMerge(String videoFilePath, String audioFilePath, String desFilePath) {
// ffmpeg -i 原视频路径 -i 原音频路径 -codec copy 合并后视频存放路径+视频名称
// 解释器
String exe = ffmpegExePath;
// 组合成一个字符串数组
// 执行报错:Unrecognized option 'codec copy' https://www.jianshu.com/p/ea996d79a231
// String[] cmdArr = new String[]{exe, "-i", videoFilePath, "-i", audioFilePath, "-codec copy", desFilePath};
// 解决报错:"-codec copy" 要拆开,数组元素不带空格
String[] cmdArr = new String[]{exe, "-i", videoFilePath, "-i", audioFilePath, "-codec", "copy", desFilePath};
PythonUtil.executePythonScript(cmdArr);
String cmdStr = MessageFormat.format(exe + " -i {0} -i {1} -codec copy {2}", videoFilePath, audioFilePath, desFilePath);
System.out.println("cmdStr: " + cmdStr);
// PythonUtil.executeCmd(cmdStr);
}
/**
* 使用ffmpeg批量合并flv文件
* ffmpeg -f concat -i mylist.txt -c copy output.flv
* https://www.likecs.com/show-379618.html
* ffmpeg将多个flv文件合成为mp4(python版) https://www.jianshu.com/p/bfda71bad87d
* 通过ffmpeg将FLV文件转换为MP4 https://blog.csdn.net/CN_Sue/article/details/122290494
*
* @param desFilePath 合并后视频存放路径+视频名称
*/
public static boolean ffmpegMergeFlv(String listFilePath, String desFilePath) {
// 拼接完,只有第一个可以播放
// ffmpeg -i "concat:17222411_2_0.flv|17222411_2_1.flv|17222411_2_2.flv" -codec copy out_mp4.mp4
// 3个都可以播放
// ffmpeg -f concat -i list.txt -codec copy out_mp42.mp4
// PythonUtil.executePythonScript(cmdArr);
// 解决报错:-safe 0
// https://www.jianshu.com/p/ef54a7cdcb7f
// https://www.cnblogs.com/han-1034683568/p/11515459.html
// [concat @ 000001bbe578d3c0] Unsafe file name 'D:bilibiliload17222411117222411_1_0.flv'
// [in#0 @ 000001bbe5777500] Error opening input: Operation not permitted
// 解决报错:文件路径加单引号
// Impossible to open 'D:bilibiliload17222411117222411_1_0.flv'
// -loglevel quiet 如果报错可以删掉,放出日志
// ffmpeg设置终端不显示日志 https://www.cnblogs.com/chentiao/p/17174382.html
String cmdStr = MessageFormat.format(ffmpegExePath + " -loglevel quiet -f concat -safe 0 -i {0} -codec copy {1}", listFilePath, desFilePath);
System.out.println("cmdStr: " + cmdStr);
return PythonUtil.executeCmd(cmdStr);
}
/**
* 通过ffmpeg将FLV文件转换为MP4
* ffmpeg -i "input.flv" -c copy "output.mp4"
* https://blog.csdn.net/CN_Sue/article/details/122290494
* @param videoFilePath 要转换的flv视频
* @param desFilePath 合并后视频存放路径+视频名称
*/
public static boolean ffmpegFlv2Mp4(String videoFilePath, String desFilePath) {
// 文件名有空格 需要加引号
// String cmdStr = MessageFormat.format("ffmpeg -loglevel quiet -i \"{0}\" -codec copy \"{1}\"", videoFilePath, desFilePath);
String cmdStr = MessageFormat.format(ffmpegExePath + " -i \"{0}\" -codec copy \"{1}\"", videoFilePath, desFilePath);
System.out.println("cmdStr: " + cmdStr);
return PythonUtil.executeCmd(cmdStr);
}
}
Java
1
https://gitee.com/dingyinhui/java-learn-demo.git
git@gitee.com:dingyinhui/java-learn-demo.git
dingyinhui
java-learn-demo
java-learn-demo
master

搜索帮助