新增FFmpeg录制方法,但如果意外中断会存储失败
This commit is contained in:
parent
e94033b3fd
commit
5666582641
@ -50,7 +50,7 @@
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div id="config" class="layui-card" style="margin-top: 5%;height: 100%;display: none">
|
||||
<div id="config" class="layui-card" style="margin-top: 5%;height: 120%;display: none">
|
||||
<div class="layui-card-header">系统设置</div>
|
||||
<div class="layui-card-body">
|
||||
<form class="layui-form" action="" style="margin-top: 2%;width: 80%">
|
||||
@ -68,6 +68,15 @@
|
||||
lay-text="开启|关闭">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">录制器</label>
|
||||
<div class="layui-input-block">
|
||||
<input id="savemodel" type="checkbox" lay-filter="saveLiveModel" lay-skin="switch"
|
||||
lay-text="FFMPEG| Java ">
|
||||
<i class="layui-icon" id="htitle"></i>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">FFmpeg</label>
|
||||
<div class="layui-input-block">
|
||||
@ -121,6 +130,15 @@
|
||||
form.render();
|
||||
}
|
||||
})
|
||||
$.post('/system/get/savelive.do',function (json){
|
||||
if (json.code === undefined || json.code !== 0) {
|
||||
return;
|
||||
}
|
||||
if (json.data.save_live_model) {
|
||||
$('#savemodel').prop('checked', true);
|
||||
}
|
||||
form.render();
|
||||
})
|
||||
form.on('switch(userReg)', function (data) {
|
||||
let flag = data.elem.checked ? '1' : '0';
|
||||
$.post("/system/set/config.do", {key: "userReg", value: flag}, function (json) {
|
||||
@ -137,6 +155,14 @@
|
||||
}
|
||||
})
|
||||
})
|
||||
form.on('switch(saveLiveModel)',function (data){
|
||||
let flag = data.elem.checked ? 'ffmpeg' : 'java';
|
||||
$.post("/system/set/savelive.do", {model: flag}, function (json) {
|
||||
if (json.code !== undefined) {
|
||||
layer.msg(json.msg)
|
||||
}
|
||||
})
|
||||
})
|
||||
});
|
||||
$.post('/bili/login/get/test.do', function (json) {
|
||||
if (json.code === undefined || json.code !== 0) {
|
||||
@ -153,6 +179,7 @@
|
||||
$('#ffmpeg').val(json.data.ffmpeg_path);
|
||||
|
||||
})
|
||||
|
||||
$('#login').click(function () {
|
||||
$.post('/bili/login/set/login.do', function (json) {
|
||||
if (json.code === undefined || json.code !== 0) {
|
||||
@ -184,7 +211,12 @@
|
||||
})
|
||||
$('#header').load("/html/header.html");
|
||||
$('#footer').load("/html/footer.html");
|
||||
|
||||
$('#htitle').on('click', function () {
|
||||
layer.open({
|
||||
title:"录制模式",
|
||||
content:'FFmpeg录制能保留视频信息,如时间戳之类的,但对性能要求比较高。<br>Java录制使用javaApi录制,性能要求较低,但无法记录视频信息,如没有时间戳,且有可能因为超时而断开录制。<br>建议性能足够的情况下使用FFmpeg。<br>需要设置FFmpeg的路径'
|
||||
})
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
<style>
|
||||
|
@ -0,0 +1,7 @@
|
||||
package com.yutou.bilibili.BiliBili.Datas;
|
||||
|
||||
public class AppData {
|
||||
public static String FFMPEG="";
|
||||
public static String BILIBILI_HEADERS = "User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.80 Safari/537.36 Referer:https://live.bilibili.com";
|
||||
public static boolean LIVE_SAVE_FFMPEG=false;
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
package com.yutou.bilibili.BiliBili.Tools;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.yutou.bilibili.BiliBili.Datas.AppData;
|
||||
import com.yutou.bilibili.BiliBili.Live;
|
||||
import com.yutou.bilibili.BiliBili.LiveUtils;
|
||||
import com.yutou.bilibili.QQBot.QQBotManager;
|
||||
@ -122,38 +123,11 @@ public class SaveLive {
|
||||
super.run();
|
||||
String url = getLiveUrl(roomId);
|
||||
try {
|
||||
com.yutou.bilibili.Tools.Log.i("开始录制:" + roomId);
|
||||
QQBotManager.getInstance().sendMessage(roomId + " 已启动录制");
|
||||
HttpURLConnection connection = LiveUtils.getBiliHttpGet(url, LiveUtils.getCookie());
|
||||
connection.setReadTimeout(5000);
|
||||
connection.setConnectTimeout(5000);
|
||||
heartbeat = new Timer();
|
||||
//Heartbeat beat = new Heartbeat();
|
||||
heartbeat.schedule(new Heartbeat(), 0, 30000);
|
||||
heartbeats.put(roomId, heartbeat);
|
||||
//heartbeats.add(beat);
|
||||
InputStream inputStream = connection.getInputStream();
|
||||
liveFile = new File(String.format("live%s%s%s[%s]%d.mp4",
|
||||
File.separator,
|
||||
AppTools.getToDayTime(),
|
||||
File.separator,
|
||||
AppTools.getToDayNowTimeToString().replace(":", ""),
|
||||
roomId));
|
||||
if (!liveFile.exists()) {
|
||||
liveFile.mkdirs();
|
||||
liveFile.delete();
|
||||
if(AppData.LIVE_SAVE_FFMPEG){
|
||||
ffmpegDownload(url);
|
||||
}else {
|
||||
httpDownload(url);
|
||||
}
|
||||
FileOutputStream outputStream = new FileOutputStream(liveFile);
|
||||
int len;
|
||||
byte[] bytes = new byte[1024];
|
||||
while ((len = inputStream.read(bytes)) != -1 && isSave) {
|
||||
outputStream.write(bytes, 0, len);
|
||||
outputStream.flush();
|
||||
}
|
||||
outputStream.close();
|
||||
inputStream.close();
|
||||
com.yutou.bilibili.Tools.Log.i("录制完成:" + roomId + " save = " + isSave + " len = " + len);
|
||||
QQBotManager.getInstance().sendMessage("录制完成:" + roomId + " save = " + isSave + " len = " + len);
|
||||
} catch (Exception e) {
|
||||
com.yutou.bilibili.Tools.Log.e(e);
|
||||
Log.i("录制发生意外:" + e.getMessage());
|
||||
@ -164,6 +138,74 @@ public class SaveLive {
|
||||
|
||||
}
|
||||
|
||||
private void ffmpegDownload(String url) throws Exception {
|
||||
liveFile = new File(String.format("live%s%s%s[%s]%d.mp4",
|
||||
File.separator,
|
||||
AppTools.getToDayTime(),
|
||||
File.separator,
|
||||
AppTools.getToDayNowTimeToString().replace(":", ""),
|
||||
roomId));
|
||||
if (!liveFile.exists()) {
|
||||
liveFile.mkdirs();
|
||||
liveFile.delete();
|
||||
}
|
||||
String exec = String.format("%s -user_agent \"%s\" -cookies \"%s\" -headers \"%s\" -i \"%s\" -threads 8 -c:v copy -y \"%s\" %s ",
|
||||
AppData.FFMPEG,
|
||||
AppData.BILIBILI_HEADERS,
|
||||
LiveUtils.getCookie(),
|
||||
"Referer:https://live.bilibili.com",
|
||||
url,
|
||||
liveFile.getAbsolutePath(),
|
||||
""
|
||||
);
|
||||
System.out.println(exec);
|
||||
Process process=AppTools.exec(exec);
|
||||
InputStream inputStream = process.getErrorStream();
|
||||
byte[] bytes = new byte[2048];
|
||||
while (inputStream.read(bytes) > -1) {
|
||||
System.out.println(new String(bytes,StandardCharsets.UTF_8));
|
||||
}
|
||||
System.out.println("----------------stop ffmpeg");
|
||||
inputStream.close();
|
||||
com.yutou.bilibili.Tools.Log.i("录制完成:" + roomId);
|
||||
QQBotManager.getInstance().sendMessage("录制完成:" + roomId);
|
||||
}
|
||||
|
||||
private void httpDownload(String url) throws Exception {
|
||||
com.yutou.bilibili.Tools.Log.i("开始录制:" + roomId);
|
||||
QQBotManager.getInstance().sendMessage(roomId + " 已启动录制");
|
||||
HttpURLConnection connection = LiveUtils.getBiliHttpGet(url, LiveUtils.getCookie());
|
||||
connection.setReadTimeout(5000);
|
||||
connection.setConnectTimeout(5000);
|
||||
heartbeat = new Timer();
|
||||
//Heartbeat beat = new Heartbeat();
|
||||
heartbeat.schedule(new Heartbeat(), 0, 30000);
|
||||
heartbeats.put(roomId, heartbeat);
|
||||
//heartbeats.add(beat);
|
||||
InputStream inputStream = connection.getInputStream();
|
||||
liveFile = new File(String.format("live%s%s%s[%s]%d.mp4",
|
||||
File.separator,
|
||||
AppTools.getToDayTime(),
|
||||
File.separator,
|
||||
AppTools.getToDayNowTimeToString().replace(":", ""),
|
||||
roomId));
|
||||
if (!liveFile.exists()) {
|
||||
liveFile.mkdirs();
|
||||
liveFile.delete();
|
||||
}
|
||||
FileOutputStream outputStream = new FileOutputStream(liveFile);
|
||||
int len;
|
||||
byte[] bytes = new byte[1024];
|
||||
while ((len = inputStream.read(bytes)) != -1 && isSave) {
|
||||
outputStream.write(bytes, 0, len);
|
||||
outputStream.flush();
|
||||
}
|
||||
outputStream.close();
|
||||
inputStream.close();
|
||||
com.yutou.bilibili.Tools.Log.i("录制完成:" + roomId + " save = " + isSave + " len = " + len);
|
||||
QQBotManager.getInstance().sendMessage("录制完成:" + roomId + " save = " + isSave + " len = " + len);
|
||||
}
|
||||
|
||||
private class Heartbeat extends TimerTask {
|
||||
int nextInterval = 1;
|
||||
|
||||
|
@ -1,10 +1,12 @@
|
||||
package com.yutou.bilibili.Controllers;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.yutou.bilibili.BiliBili.Datas.AppData;
|
||||
import com.yutou.bilibili.QQBot.QQBotManager;
|
||||
import com.yutou.bilibili.Services.ISystemConfigService;
|
||||
import com.yutou.bilibili.Tools.Config;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
@ -21,7 +23,7 @@ public class SystemConfigController {
|
||||
@ResponseBody
|
||||
public JSONObject getRegUser() {
|
||||
JSONObject json = new JSONObject();
|
||||
JSONObject data=new JSONObject();
|
||||
JSONObject data = new JSONObject();
|
||||
String reg = configService.getConfig(Config.USER_REG);
|
||||
String bLive = configService.getConfig(Config.BILI_LIVE_FLAG);
|
||||
if (reg == null) {
|
||||
@ -31,68 +33,103 @@ public class SystemConfigController {
|
||||
bLive = "0";
|
||||
}
|
||||
data.put(Config.USER_REG, reg);
|
||||
data.put(Config.BILI_LIVE_FLAG,bLive);
|
||||
json.put("code",0);
|
||||
json.put("data",data);
|
||||
data.put(Config.BILI_LIVE_FLAG, bLive);
|
||||
json.put("code", 0);
|
||||
json.put("data", data);
|
||||
return json;
|
||||
}
|
||||
|
||||
@RequestMapping("/system/set/config.do")
|
||||
@ResponseBody
|
||||
public JSONObject setConfig(String key,String value){
|
||||
public JSONObject setConfig(String key, String value) {
|
||||
configService.setConfig(key, value);
|
||||
JSONObject json=new JSONObject();
|
||||
json.put("code",0);
|
||||
json.put("msg","ok");
|
||||
JSONObject json = new JSONObject();
|
||||
json.put("code", 0);
|
||||
json.put("msg", "ok");
|
||||
return json;
|
||||
}
|
||||
|
||||
@RequestMapping("/system/public/reg.do")
|
||||
@ResponseBody
|
||||
public JSONObject getRegModel(){
|
||||
public JSONObject getRegModel() {
|
||||
JSONObject json = new JSONObject();
|
||||
JSONObject data=new JSONObject();
|
||||
JSONObject data = new JSONObject();
|
||||
String reg = configService.getConfig(Config.USER_REG);
|
||||
boolean model=false;
|
||||
boolean model = false;
|
||||
if (reg == null) {
|
||||
reg = "0";
|
||||
}
|
||||
if(reg.equals("1")){
|
||||
model=true;
|
||||
if (reg.equals("1")) {
|
||||
model = true;
|
||||
}
|
||||
data.put(Config.USER_REG, model);
|
||||
json.put("code",0);
|
||||
json.put("data",data);
|
||||
json.put("code", 0);
|
||||
json.put("data", data);
|
||||
return json;
|
||||
}
|
||||
|
||||
@ResponseBody
|
||||
@RequestMapping("/system/set/ffmpeg.do")
|
||||
public JSONObject setFFmpeg(String ffmpeg) throws UnsupportedEncodingException {
|
||||
ffmpeg= URLDecoder.decode(ffmpeg,"UTF-8");
|
||||
configService.setConfig(Config.SYSTEM_VIDEO_FFMPEG,ffmpeg);
|
||||
JSONObject json=new JSONObject();
|
||||
json.put("code",0);
|
||||
json.put("msg","ok");
|
||||
ffmpeg = URLDecoder.decode(ffmpeg, "UTF-8");
|
||||
configService.setConfig(Config.SYSTEM_VIDEO_FFMPEG, ffmpeg);
|
||||
AppData.FFMPEG = ffmpeg;
|
||||
JSONObject json = new JSONObject();
|
||||
json.put("code", 0);
|
||||
json.put("msg", "ok");
|
||||
return json;
|
||||
}
|
||||
|
||||
@ResponseBody
|
||||
@RequestMapping("/system/get/ffmpeg.do")
|
||||
public JSONObject getFFmpeg(){
|
||||
public JSONObject getFFmpeg() {
|
||||
JSONObject json = new JSONObject();
|
||||
JSONObject data=new JSONObject();
|
||||
JSONObject data = new JSONObject();
|
||||
String reg = configService.getConfig(Config.SYSTEM_VIDEO_FFMPEG);
|
||||
data.put(Config.SYSTEM_VIDEO_FFMPEG, reg);
|
||||
json.put("code",0);
|
||||
json.put("data",data);
|
||||
json.put("code", 0);
|
||||
json.put("data", data);
|
||||
return json;
|
||||
}
|
||||
|
||||
@ResponseBody
|
||||
@RequestMapping("/system/set/savelive.do")
|
||||
public JSONObject setSaveLive(String model) throws UnsupportedEncodingException {
|
||||
JSONObject json = new JSONObject();
|
||||
if (StringUtils.isEmpty(configService.getConfig(Config.SYSTEM_VIDEO_FFMPEG))) {
|
||||
json.put("code", 404);
|
||||
json.put("msg", "请先设置FFmpeg路径");
|
||||
return json;
|
||||
}
|
||||
model = URLDecoder.decode(model, "UTF-8");
|
||||
configService.setConfig(Config.SYSTEM_VIDEO_SAVE_MODEL, model);
|
||||
AppData.LIVE_SAVE_FFMPEG = model.equals("ffmpeg");
|
||||
json.put("code", 0);
|
||||
json.put("msg", "ok");
|
||||
return json;
|
||||
}
|
||||
|
||||
@ResponseBody
|
||||
@RequestMapping("/system/get/savelive.do")
|
||||
public JSONObject getSaveLiveModel() {
|
||||
JSONObject json = new JSONObject();
|
||||
JSONObject data = new JSONObject();
|
||||
String reg = configService.getConfig(Config.SYSTEM_VIDEO_SAVE_MODEL);
|
||||
System.out.println(reg);
|
||||
data.put(Config.SYSTEM_VIDEO_SAVE_MODEL, (!StringUtils.isEmpty(reg) && reg.equals("ffmpeg")));
|
||||
json.put("code", 0);
|
||||
json.put("data", data);
|
||||
return json;
|
||||
}
|
||||
|
||||
@ResponseBody
|
||||
@RequestMapping("/system/qq/login.do")
|
||||
public JSONObject loginQQ(){
|
||||
public JSONObject loginQQ() {
|
||||
QQBotManager.getInstance().stop();
|
||||
QQBotManager.getInstance().init();
|
||||
JSONObject json=new JSONObject();
|
||||
json.put("code",0);
|
||||
json.put("msg","ok");
|
||||
JSONObject json = new JSONObject();
|
||||
json.put("code", 0);
|
||||
json.put("msg", "ok");
|
||||
return json;
|
||||
}
|
||||
}
|
||||
|
@ -307,4 +307,26 @@ public class AppTools {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isRuntimeSystemOfWindow(){
|
||||
return System.getProperty ("os.name").contains("Windows");
|
||||
}
|
||||
|
||||
public static Process exec(String exec)throws Exception{
|
||||
if(AppTools.isRuntimeSystemOfWindow()) {
|
||||
return Runtime.getRuntime().exec(new String[]{
|
||||
"cmd",
|
||||
"/c",
|
||||
exec
|
||||
}
|
||||
);
|
||||
}else{
|
||||
return Runtime.getRuntime().exec(new String[]{
|
||||
"sh",
|
||||
"-c",
|
||||
exec
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
13
src/main/java/com/yutou/bilibili/Tools/ApplicationClose.java
Normal file
13
src/main/java/com/yutou/bilibili/Tools/ApplicationClose.java
Normal file
@ -0,0 +1,13 @@
|
||||
package com.yutou.bilibili.Tools;
|
||||
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.context.event.ContextClosedEvent;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class ApplicationClose implements ApplicationListener<ContextClosedEvent> {
|
||||
@Override
|
||||
public void onApplicationEvent(ContextClosedEvent contextClosedEvent) {
|
||||
Log.i("服务结束");
|
||||
}
|
||||
}
|
@ -1,9 +1,11 @@
|
||||
package com.yutou.bilibili.Tools;
|
||||
|
||||
import com.yutou.bilibili.BiliBili.Datas.AppData;
|
||||
import com.yutou.bilibili.BiliBili.Datas.LiveData;
|
||||
import com.yutou.bilibili.BiliBili.Live;
|
||||
import com.yutou.bilibili.BiliBili.LiveUtils;
|
||||
import com.yutou.bilibili.BiliBili.Services.IBiliBiliLiveService;
|
||||
import com.yutou.bilibili.Services.ISystemConfigService;
|
||||
import com.yutou.bilibili.mybatis.Bili.mybatis.model.BilibiliLiveInfo;
|
||||
import com.yutou.bilibili.mybatis.Bili.mybatis.model.BilibiliUpInfo;
|
||||
import org.springframework.boot.ApplicationArguments;
|
||||
@ -27,12 +29,16 @@ import java.util.TimerTask;
|
||||
public class ApplicationInit implements ApplicationRunner {
|
||||
@Resource
|
||||
IBiliBiliLiveService service;
|
||||
@Resource
|
||||
ISystemConfigService configService;
|
||||
private Timer timer;
|
||||
|
||||
|
||||
@Override
|
||||
public void run(ApplicationArguments args) throws Exception {
|
||||
LiveUtils.LiveGiftConfig.getInstance();
|
||||
AppData.FFMPEG=configService.getConfig(Config.SYSTEM_VIDEO_FFMPEG);
|
||||
AppData.LIVE_SAVE_FFMPEG= configService.getConfig(Config.SYSTEM_VIDEO_SAVE_MODEL) != null && configService.getConfig(Config.SYSTEM_VIDEO_SAVE_MODEL).equals("ffmpeg");
|
||||
startTimer();
|
||||
}
|
||||
|
||||
|
@ -4,4 +4,5 @@ public class Config {
|
||||
public static final String USER_REG="userReg";
|
||||
public static final String BILI_LIVE_FLAG="biliLive";
|
||||
public static final String SYSTEM_VIDEO_FFMPEG="ffmpeg_path";
|
||||
public static final String SYSTEM_VIDEO_SAVE_MODEL="save_live_model";
|
||||
}
|
||||
|
@ -39,12 +39,7 @@ public class FFmpegUtils {
|
||||
file.getAbsolutePath(),
|
||||
out.getAbsolutePath() + File.separator + file.getName());
|
||||
com.yutou.bilibili.Tools.Log.i(exec);
|
||||
Process process = Runtime.getRuntime().exec(new String[]{
|
||||
"cmd",
|
||||
"/c",
|
||||
exec
|
||||
}
|
||||
);
|
||||
Process process=AppTools.exec(exec);
|
||||
InputStream inputStream = process.getErrorStream();
|
||||
byte[] bytes = new byte[1024];
|
||||
while (inputStream.read(bytes) > -1) {
|
||||
|
Loading…
Reference in New Issue
Block a user