update
This commit is contained in:
parent
23d4deb72e
commit
a466ddfb68
@ -250,7 +250,7 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
new Chart($('#giftChart').get(0), {
|
new Chart($('#giftChart').get(0), {
|
||||||
type: 'bar',
|
type: 'pie',
|
||||||
data: {
|
data: {
|
||||||
labels: lables,
|
labels: lables,
|
||||||
datasets: [{
|
datasets: [{
|
||||||
|
@ -59,7 +59,7 @@
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="layui-card-body">
|
<div class="layui-card-body">
|
||||||
<img src="#" onerror="showTmpImage('{{= item.cover}}',this)" onclick="toLive('{{= item.roomId}}')" style="width: 312px; height: 175px; object-fit: cover;"/><br>
|
<img src="#" onerror="showTmpImage('{{= item.cover}}',this)" onclick="toLive('{{= item.roomId}}')" style="width: 100%; height: 175px; object-fit: cover;"/><br>
|
||||||
<!-- <img src="#" onerror="showImage('{{= item.cover}}',this)" onclick="toLive('{{= item.roomId}}')" style="width: 100%; height: 100%;"/><br> -->
|
<!-- <img src="#" onerror="showImage('{{= item.cover}}',this)" onclick="toLive('{{= item.roomId}}')" style="width: 100%; height: 100%;"/><br> -->
|
||||||
{{= item.title}}<br>
|
{{= item.title}}<br>
|
||||||
<p>开播时长:{{= item.liveTime}}</p>
|
<p>开播时长:{{= item.liveTime}}</p>
|
||||||
@ -194,6 +194,13 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
|
// data.data.forEach(item =>{
|
||||||
|
// if(document.getElementById(item.data)!==null){
|
||||||
|
// document.getElementById(item.data).innerHTML=item.message;
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
// })
|
||||||
initFollowStatus(true)
|
initFollowStatus(true)
|
||||||
}, 1000);
|
}, 1000);
|
||||||
|
|
||||||
|
@ -13,10 +13,10 @@ public class BilibiliApplication {
|
|||||||
HttpLoggingInterceptor.setLog(false);
|
HttpLoggingInterceptor.setLog(false);
|
||||||
SpringApplication.run(BilibiliApplication.class, args);
|
SpringApplication.run(BilibiliApplication.class, args);
|
||||||
}
|
}
|
||||||
//TODO 优化 1 手动中断录制后,没有时间戳问题需要解决,看是提示转码还是有什么其他解决方案
|
//TODO 优化 1 手动中断录制后,没有时间戳问题需要解决,看是提示转码还是有什么其他解决方案 | 改成了通过q来退出
|
||||||
//TODO 优化 2 创建nfo文件看看要不要改成录制后生成,或者触发打包指令再生成
|
//TODO 优化 2 创建nfo文件看看要不要改成录制后生成,或者触发打包指令再生成
|
||||||
//TODO 优化 3 录制完成前应该也允许查看礼物信息和SC以及弹幕,未停止录制改成从开始时间到当前时间的弹幕和礼物信息,已停止录制则询问是否转码
|
//TODO 优化 3 录制完成前应该也允许查看礼物信息和SC以及弹幕,未停止录制改成从开始时间到当前时间的弹幕和礼物信息,已停止录制则询问是否转码
|
||||||
//TODO 优化 4 视频页面礼物的图标,有数据计算错误以及单项猛增的话导致其他项目无法查看的问题(可参考泛式死亡笔记录播)
|
//TODO 优化 4 视频页面礼物的图标,有数据计算错误以及单项猛增的话导致其他项目无法查看的问题(可参考泛式死亡笔记录播) | 换成饼状图
|
||||||
//TODO 修复 1 开播时有概率连续触发创建nfo和记录视频到数据宽度问题.
|
//TODO 修复 1 开播时有概率连续触发创建nfo和记录视频到数据宽度问题.
|
||||||
//TODO 测试 1 需要测试网络中断下,弹幕重连机制
|
//TODO 测试 1 需要测试网络中断下,弹幕重连机制
|
||||||
//TODO 测试 2 在导出jar包后再测试完整的录制功能
|
//TODO 测试 2 在导出jar包后再测试完整的录制功能
|
||||||
|
@ -18,7 +18,6 @@ import com.yutou.biliapi.databases.BiliBiliLoginDatabase;
|
|||||||
import com.yutou.biliapi.databases.BiliLiveDatabase;
|
import com.yutou.biliapi.databases.BiliLiveDatabase;
|
||||||
import com.yutou.biliapi.utils.BiliUserUtils;
|
import com.yutou.biliapi.utils.BiliUserUtils;
|
||||||
import com.yutou.biliapi.utils.BytesUtils;
|
import com.yutou.biliapi.utils.BytesUtils;
|
||||||
import com.yutou.bilibili.Tools.Tools;
|
|
||||||
import com.yutou.common.okhttp.HttpBody;
|
import com.yutou.common.okhttp.HttpBody;
|
||||||
import com.yutou.common.okhttp.HttpCallback;
|
import com.yutou.common.okhttp.HttpCallback;
|
||||||
import com.yutou.common.utils.ConfigTools;
|
import com.yutou.common.utils.ConfigTools;
|
||||||
@ -119,6 +118,7 @@ public class WebSocketManager {
|
|||||||
roomConfig.setRoomInfo(execute.body() != null ? execute.body().getData() : null);
|
roomConfig.setRoomInfo(execute.body() != null ? execute.body().getData() : null);
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
WebSocketManager.getInstance().roomMap.remove(roomConfig);
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
api.getLiveRoomDanmuInfo(String.valueOf(roomConfig.getRoomId())).enqueue(new HttpCallback<LiveDanmuInfo>() {
|
api.getLiveRoomDanmuInfo(String.valueOf(roomConfig.getRoomId())).enqueue(new HttpCallback<LiveDanmuInfo>() {
|
||||||
@ -132,6 +132,7 @@ public class WebSocketManager {
|
|||||||
roomConfig.setLiveInfo(response);
|
roomConfig.setLiveInfo(response);
|
||||||
client = new WebSocketClientTh(new URI(url), roomConfig);
|
client = new WebSocketClientTh(new URI(url), roomConfig);
|
||||||
} catch (URISyntaxException e) {
|
} catch (URISyntaxException e) {
|
||||||
|
WebSocketManager.getInstance().roomMap.remove(roomConfig);
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -139,6 +140,7 @@ public class WebSocketManager {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onFailure(Throwable throwable) {
|
public void onFailure(Throwable throwable) {
|
||||||
|
WebSocketManager.getInstance().roomMap.remove(roomConfig);
|
||||||
Log.e(throwable);
|
Log.e(throwable);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -1,76 +0,0 @@
|
|||||||
package com.yutou.bilibili.Tools;
|
|
||||||
|
|
||||||
import com.yutou.common.utils.AppTools;
|
|
||||||
import com.yutou.common.utils.Log;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class FFmpegUtils {
|
|
||||||
private static final List<File> nowFFmpegList = new ArrayList<>();
|
|
||||||
|
|
||||||
public static int add(String ffmpeg, File file, File out) {
|
|
||||||
if (nowFFmpegList.contains(file)) {
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
if (file.getName().contains("ffmpeg")) {
|
|
||||||
return 1;
|
|
||||||
} else {
|
|
||||||
startFFmpeg(ffmpeg, file, out);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
private synchronized static void startFFmpeg(String ffmpeg, File file, File out) {
|
|
||||||
if (nowFFmpegList.contains(file)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
nowFFmpegList.add(file);
|
|
||||||
new Thread(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
try {
|
|
||||||
if (!out.exists()) {
|
|
||||||
out.mkdirs();
|
|
||||||
}
|
|
||||||
String exec = String.format(
|
|
||||||
"%s -i \"%s\" -c:v copy -y \"%s\" ",
|
|
||||||
ffmpeg,
|
|
||||||
file.getAbsolutePath(),
|
|
||||||
out.getAbsolutePath() + File.separator + file.getName());
|
|
||||||
Log.i(exec);
|
|
||||||
Process process = ProcessUtils.exec(ffmpeg, "-i", file.getAbsolutePath(), "-c:v", "copy", "-y", out.getAbsolutePath() + File.separator + file.getName());
|
|
||||||
InputStream inputStream = process.getErrorStream();
|
|
||||||
byte[] bytes = new byte[1024];
|
|
||||||
while (inputStream.read(bytes) > -1) {
|
|
||||||
}
|
|
||||||
inputStream.close();
|
|
||||||
AppTools.copyFileToName(out.getAbsolutePath() + File.separator + file.getName(), file.getParent() + File.separator, file.getName().replace(".mp4", "_ffmpeg.mp4"), true);
|
|
||||||
file.delete();
|
|
||||||
new File(out.getAbsolutePath() + File.separator + file.getName()).delete();
|
|
||||||
} catch (Exception e) {
|
|
||||||
Log.e(e);
|
|
||||||
}
|
|
||||||
nowFFmpegList.remove(file);
|
|
||||||
}
|
|
||||||
}).start();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void main(String[] args) {
|
|
||||||
File file = new File("D:\\ieda\\bilibili\\live\\2021-03-20\\[2021-03-20 003537]1064046.mp4");
|
|
||||||
int i = -1;
|
|
||||||
while (i != 1) {
|
|
||||||
i = add("D:\\ffmpeg-4.3.1-2020-11-19-full_build\\bin\\ffmpeg.exe", file.getAbsoluteFile(), new File("ffmpeg_out"));
|
|
||||||
Log.i(i);
|
|
||||||
try {
|
|
||||||
Thread.sleep(300);
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
Log.e(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Log.i("转码完成");
|
|
||||||
}
|
|
||||||
}
|
|
@ -97,6 +97,10 @@ public class LiveDanmuService {
|
|||||||
long videoTime = FFmpegUtils.getVideoTime(videoFile);
|
long videoTime = FFmpegUtils.getVideoTime(videoFile);
|
||||||
long startTime = Long.parseLong(videoId);
|
long startTime = Long.parseLong(videoId);
|
||||||
long endTime = Long.parseLong(videoId) + videoTime;
|
long endTime = Long.parseLong(videoId) + videoTime;
|
||||||
|
// videoTime = 0;
|
||||||
|
if (videoTime == 0) {
|
||||||
|
endTime = System.currentTimeMillis();
|
||||||
|
}
|
||||||
List<LiveDanmuDatabaseBean> danmuList = liveDatabase.getOfTime(DateFormatUtils.getInstance().format(startTime), DateFormatUtils.getInstance().format(endTime), LiveDanmuDatabaseBean.class);
|
List<LiveDanmuDatabaseBean> danmuList = liveDatabase.getOfTime(DateFormatUtils.getInstance().format(startTime), DateFormatUtils.getInstance().format(endTime), LiveDanmuDatabaseBean.class);
|
||||||
List<LiveSuperChatDatabaseBean> superChatList = liveDatabase.getOfTime(DateFormatUtils.getInstance().format(startTime), DateFormatUtils.getInstance().format(endTime), LiveSuperChatDatabaseBean.class);
|
List<LiveSuperChatDatabaseBean> superChatList = liveDatabase.getOfTime(DateFormatUtils.getInstance().format(startTime), DateFormatUtils.getInstance().format(endTime), LiveSuperChatDatabaseBean.class);
|
||||||
for (LiveDanmuDatabaseBean bean : danmuList) {
|
for (LiveDanmuDatabaseBean bean : danmuList) {
|
||||||
@ -104,7 +108,7 @@ public class LiveDanmuService {
|
|||||||
danmus.getDanmu().add(danmu);
|
danmus.getDanmu().add(danmu);
|
||||||
}
|
}
|
||||||
for (LiveSuperChatDatabaseBean bean : superChatList) {
|
for (LiveSuperChatDatabaseBean bean : superChatList) {
|
||||||
LiveVideoDanmu.SuperChat superChat = new LiveVideoDanmu.SuperChat(startTime,bean);
|
LiveVideoDanmu.SuperChat superChat = new LiveVideoDanmu.SuperChat(startTime, bean);
|
||||||
danmus.getSuperChat().add(superChat);
|
danmus.getSuperChat().add(superChat);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -257,6 +257,7 @@ public class LiveVideoDownloadService {
|
|||||||
// .withNotSymbolParam("-progress", "-")
|
// .withNotSymbolParam("-progress", "-")
|
||||||
.withNotSymbolParam("-threads", "8")
|
.withNotSymbolParam("-threads", "8")
|
||||||
.withNotSymbolParam("-c:v", "copy")
|
.withNotSymbolParam("-c:v", "copy")
|
||||||
|
.withNotSymbolParam("-fflags","+genpts")
|
||||||
.withNotSymbolParam("-y", "");
|
.withNotSymbolParam("-y", "");
|
||||||
if (ck != null) {
|
if (ck != null) {
|
||||||
builder = builder.withParam("-cookies", cookie);
|
builder = builder.withParam("-cookies", cookie);
|
||||||
@ -299,7 +300,7 @@ public class LiveVideoDownloadService {
|
|||||||
videoDatabaseBean.setRoomInfoJson(JSONObject.toJSONString(roomInfo));
|
videoDatabaseBean.setRoomInfoJson(JSONObject.toJSONString(roomInfo));
|
||||||
videoDatabaseBean.setStartTime(new Date());
|
videoDatabaseBean.setStartTime(new Date());
|
||||||
database.addLiveInfo(videoDatabaseBean);
|
database.addLiveInfo(videoDatabaseBean);
|
||||||
LiveInfoNfoTools.saveLiveInfoNfo(roomInfo, rootPath.getAbsolutePath(), new File(savePath).getName().replace(".flv", ".nfo"));
|
// LiveInfoNfoTools.saveLiveInfoNfo(roomInfo, rootPath.getAbsolutePath(), new File(savePath).getName().replace(".flv", ".nfo"));
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,14 +12,12 @@ import java.nio.charset.StandardCharsets;
|
|||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
public class FFmpegUtils extends AbsVideoRecord {
|
public class FFmpegUtils extends AbsVideoRecord {
|
||||||
private static final Map<String, Long> pidMap = new HashMap<>();
|
private static final Map<String, Task> pidMap = new HashMap<>();
|
||||||
@Getter
|
@Getter
|
||||||
private String command;
|
private String command;
|
||||||
@Getter
|
@Getter
|
||||||
private String outputFilePath;
|
private String outputFilePath;
|
||||||
private String uid;
|
private String uid;
|
||||||
InputStream inputStream;
|
|
||||||
OutputStream outputStream;
|
|
||||||
|
|
||||||
public FFmpegUtils() {
|
public FFmpegUtils() {
|
||||||
}
|
}
|
||||||
@ -33,7 +31,10 @@ public class FFmpegUtils extends AbsVideoRecord {
|
|||||||
@Override
|
@Override
|
||||||
public boolean check(String roomId) {
|
public boolean check(String roomId) {
|
||||||
try {
|
try {
|
||||||
return ProcessUtils.isProcessRunning(pidMap.get(roomId));
|
if(!pidMap.containsKey(roomId)){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return ProcessUtils.isProcessRunning(pidMap.get(roomId).pid);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Log.e(e);
|
Log.e(e);
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
@ -43,8 +44,11 @@ public class FFmpegUtils extends AbsVideoRecord {
|
|||||||
@Override
|
@Override
|
||||||
public void kill(String roomId) {
|
public void kill(String roomId) {
|
||||||
try {
|
try {
|
||||||
ProcessUtils.killProcess(pidMap.get(roomId));
|
// ProcessUtils.killProcess(pidMap.get(roomId).pid);
|
||||||
pidMap.remove(roomId);
|
Task utils = pidMap.get(roomId);
|
||||||
|
if(utils != null) {
|
||||||
|
utils.kill();
|
||||||
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Log.e(e);
|
Log.e(e);
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
@ -53,9 +57,9 @@ public class FFmpegUtils extends AbsVideoRecord {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void killAll() {
|
public void killAll() {
|
||||||
for (Long pid : pidMap.values()) {
|
for (Task pid : pidMap.values()) {
|
||||||
try {
|
try {
|
||||||
ProcessUtils.killProcess(pid);
|
pid.kill();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Log.e(e);
|
Log.e(e);
|
||||||
}
|
}
|
||||||
@ -137,47 +141,12 @@ public class FFmpegUtils extends AbsVideoRecord {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void start(DownloadInterface downloadInterface) {
|
public void start(DownloadInterface downloadInterface) {
|
||||||
new Thread(() -> {
|
new Task(downloadInterface).start();
|
||||||
try {
|
|
||||||
if (check(uid)) {
|
|
||||||
kill(uid);
|
|
||||||
}
|
|
||||||
Process process = ProcessUtils.exec(command.split(" "));
|
|
||||||
long pid = process.toHandle().pid();
|
|
||||||
Log.i("进程id " + pid);
|
|
||||||
inputStream = process.getErrorStream();
|
|
||||||
outputStream = process.getOutputStream();
|
|
||||||
byte[] bytes = new byte[2048];
|
|
||||||
if (downloadInterface != null) {
|
|
||||||
downloadInterface.onDownloadStart();
|
|
||||||
}
|
|
||||||
pidMap.put(uid, pid);
|
|
||||||
while (inputStream.read(bytes) > -1) {
|
|
||||||
if (downloadInterface != null) {
|
|
||||||
downloadInterface.onDownloading(0, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pidMap.remove(uid);
|
|
||||||
//获取视频时长:ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 input.mp4
|
|
||||||
//获取到结果:5372.432000
|
|
||||||
if (downloadInterface != null) {
|
|
||||||
Log.i("触发下载完成",command);
|
|
||||||
downloadInterface.onDownload(null);
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}).start();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void stop() {
|
public void stop() {
|
||||||
try {
|
pidMap.get(uid).kill();
|
||||||
outputStream.write("q".getBytes());
|
|
||||||
outputStream.flush();
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -206,4 +175,63 @@ public class FFmpegUtils extends AbsVideoRecord {
|
|||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class Task extends Thread {
|
||||||
|
private long pid;
|
||||||
|
InputStream inputStream;
|
||||||
|
OutputStream outputStream;
|
||||||
|
DownloadInterface downloadInterface;
|
||||||
|
|
||||||
|
public Task(DownloadInterface downloadInterface) {
|
||||||
|
this.downloadInterface = downloadInterface;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
super.run();
|
||||||
|
try {
|
||||||
|
if (check(uid)) {
|
||||||
|
kill();
|
||||||
|
}
|
||||||
|
Process process = ProcessUtils.exec(command.split(" "));
|
||||||
|
pid = process.toHandle().pid();
|
||||||
|
Log.i("进程id " + pid);
|
||||||
|
inputStream = process.getErrorStream();
|
||||||
|
outputStream = process.getOutputStream();
|
||||||
|
byte[] bytes = new byte[2048];
|
||||||
|
if (downloadInterface != null) {
|
||||||
|
downloadInterface.onDownloadStart();
|
||||||
|
}
|
||||||
|
pidMap.put(uid, this);
|
||||||
|
while (inputStream.read(bytes) > -1) {
|
||||||
|
if (downloadInterface != null) {
|
||||||
|
downloadInterface.onDownloading(0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pidMap.remove(uid);
|
||||||
|
//获取视频时长:ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 input.mp4
|
||||||
|
//获取到结果:5372.432000
|
||||||
|
if (downloadInterface != null) {
|
||||||
|
Log.i("触发下载完成", command);
|
||||||
|
downloadInterface.onDownload(null);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void kill() {
|
||||||
|
try {
|
||||||
|
outputStream.write("q".getBytes());
|
||||||
|
outputStream.flush();
|
||||||
|
Thread.sleep(1000);
|
||||||
|
if (check(uid)) {
|
||||||
|
ProcessUtils.killProcess(pid);
|
||||||
|
}
|
||||||
|
pidMap.remove(uid);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user