新增FFmpeg录制方法,但如果意外中断会存储失败
This commit is contained in:
parent
e94033b3fd
commit
5666582641
@ -50,7 +50,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</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-header">系统设置</div>
|
||||||
<div class="layui-card-body">
|
<div class="layui-card-body">
|
||||||
<form class="layui-form" action="" style="margin-top: 2%;width: 80%">
|
<form class="layui-form" action="" style="margin-top: 2%;width: 80%">
|
||||||
@ -68,6 +68,15 @@
|
|||||||
lay-text="开启|关闭">
|
lay-text="开启|关闭">
|
||||||
</div>
|
</div>
|
||||||
</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">
|
<div class="layui-form-item">
|
||||||
<label class="layui-form-label">FFmpeg</label>
|
<label class="layui-form-label">FFmpeg</label>
|
||||||
<div class="layui-input-block">
|
<div class="layui-input-block">
|
||||||
@ -121,6 +130,15 @@
|
|||||||
form.render();
|
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) {
|
form.on('switch(userReg)', function (data) {
|
||||||
let flag = data.elem.checked ? '1' : '0';
|
let flag = data.elem.checked ? '1' : '0';
|
||||||
$.post("/system/set/config.do", {key: "userReg", value: flag}, function (json) {
|
$.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) {
|
$.post('/bili/login/get/test.do', function (json) {
|
||||||
if (json.code === undefined || json.code !== 0) {
|
if (json.code === undefined || json.code !== 0) {
|
||||||
@ -153,6 +179,7 @@
|
|||||||
$('#ffmpeg').val(json.data.ffmpeg_path);
|
$('#ffmpeg').val(json.data.ffmpeg_path);
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
$('#login').click(function () {
|
$('#login').click(function () {
|
||||||
$.post('/bili/login/set/login.do', function (json) {
|
$.post('/bili/login/set/login.do', function (json) {
|
||||||
if (json.code === undefined || json.code !== 0) {
|
if (json.code === undefined || json.code !== 0) {
|
||||||
@ -184,7 +211,12 @@
|
|||||||
})
|
})
|
||||||
$('#header').load("/html/header.html");
|
$('#header').load("/html/header.html");
|
||||||
$('#footer').load("/html/footer.html");
|
$('#footer').load("/html/footer.html");
|
||||||
|
$('#htitle').on('click', function () {
|
||||||
|
layer.open({
|
||||||
|
title:"录制模式",
|
||||||
|
content:'FFmpeg录制能保留视频信息,如时间戳之类的,但对性能要求比较高。<br>Java录制使用javaApi录制,性能要求较低,但无法记录视频信息,如没有时间戳,且有可能因为超时而断开录制。<br>建议性能足够的情况下使用FFmpeg。<br>需要设置FFmpeg的路径'
|
||||||
|
})
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
<style>
|
<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;
|
package com.yutou.bilibili.BiliBili.Tools;
|
||||||
|
|
||||||
import com.alibaba.fastjson.JSONObject;
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
import com.yutou.bilibili.BiliBili.Datas.AppData;
|
||||||
import com.yutou.bilibili.BiliBili.Live;
|
import com.yutou.bilibili.BiliBili.Live;
|
||||||
import com.yutou.bilibili.BiliBili.LiveUtils;
|
import com.yutou.bilibili.BiliBili.LiveUtils;
|
||||||
import com.yutou.bilibili.QQBot.QQBotManager;
|
import com.yutou.bilibili.QQBot.QQBotManager;
|
||||||
@ -122,6 +123,55 @@ public class SaveLive {
|
|||||||
super.run();
|
super.run();
|
||||||
String url = getLiveUrl(roomId);
|
String url = getLiveUrl(roomId);
|
||||||
try {
|
try {
|
||||||
|
if(AppData.LIVE_SAVE_FFMPEG){
|
||||||
|
ffmpegDownload(url);
|
||||||
|
}else {
|
||||||
|
httpDownload(url);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
com.yutou.bilibili.Tools.Log.e(e);
|
||||||
|
Log.i("录制发生意外:" + e.getMessage());
|
||||||
|
QQBotManager.getInstance().sendMessage("录制发生意外:" + e.getLocalizedMessage());
|
||||||
|
LiveUtils.LiveInfoManager.getInstance().check(roomId);
|
||||||
|
}
|
||||||
|
SaveLive.this.stop(roomId);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
com.yutou.bilibili.Tools.Log.i("开始录制:" + roomId);
|
||||||
QQBotManager.getInstance().sendMessage(roomId + " 已启动录制");
|
QQBotManager.getInstance().sendMessage(roomId + " 已启动录制");
|
||||||
HttpURLConnection connection = LiveUtils.getBiliHttpGet(url, LiveUtils.getCookie());
|
HttpURLConnection connection = LiveUtils.getBiliHttpGet(url, LiveUtils.getCookie());
|
||||||
@ -154,14 +204,6 @@ public class SaveLive {
|
|||||||
inputStream.close();
|
inputStream.close();
|
||||||
com.yutou.bilibili.Tools.Log.i("录制完成:" + roomId + " save = " + isSave + " len = " + len);
|
com.yutou.bilibili.Tools.Log.i("录制完成:" + roomId + " save = " + isSave + " len = " + len);
|
||||||
QQBotManager.getInstance().sendMessage("录制完成:" + 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());
|
|
||||||
QQBotManager.getInstance().sendMessage("录制发生意外:" + e.getLocalizedMessage());
|
|
||||||
LiveUtils.LiveInfoManager.getInstance().check(roomId);
|
|
||||||
}
|
|
||||||
SaveLive.this.stop(roomId);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private class Heartbeat extends TimerTask {
|
private class Heartbeat extends TimerTask {
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
package com.yutou.bilibili.Controllers;
|
package com.yutou.bilibili.Controllers;
|
||||||
|
|
||||||
import com.alibaba.fastjson.JSONObject;
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
import com.yutou.bilibili.BiliBili.Datas.AppData;
|
||||||
import com.yutou.bilibili.QQBot.QQBotManager;
|
import com.yutou.bilibili.QQBot.QQBotManager;
|
||||||
import com.yutou.bilibili.Services.ISystemConfigService;
|
import com.yutou.bilibili.Services.ISystemConfigService;
|
||||||
import com.yutou.bilibili.Tools.Config;
|
import com.yutou.bilibili.Tools.Config;
|
||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.ResponseBody;
|
import org.springframework.web.bind.annotation.ResponseBody;
|
||||||
|
|
||||||
@ -46,6 +48,7 @@ public class SystemConfigController {
|
|||||||
json.put("msg", "ok");
|
json.put("msg", "ok");
|
||||||
return json;
|
return json;
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequestMapping("/system/public/reg.do")
|
@RequestMapping("/system/public/reg.do")
|
||||||
@ResponseBody
|
@ResponseBody
|
||||||
public JSONObject getRegModel() {
|
public JSONObject getRegModel() {
|
||||||
@ -64,16 +67,19 @@ public class SystemConfigController {
|
|||||||
json.put("data", data);
|
json.put("data", data);
|
||||||
return json;
|
return json;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ResponseBody
|
@ResponseBody
|
||||||
@RequestMapping("/system/set/ffmpeg.do")
|
@RequestMapping("/system/set/ffmpeg.do")
|
||||||
public JSONObject setFFmpeg(String ffmpeg) throws UnsupportedEncodingException {
|
public JSONObject setFFmpeg(String ffmpeg) throws UnsupportedEncodingException {
|
||||||
ffmpeg = URLDecoder.decode(ffmpeg, "UTF-8");
|
ffmpeg = URLDecoder.decode(ffmpeg, "UTF-8");
|
||||||
configService.setConfig(Config.SYSTEM_VIDEO_FFMPEG, ffmpeg);
|
configService.setConfig(Config.SYSTEM_VIDEO_FFMPEG, ffmpeg);
|
||||||
|
AppData.FFMPEG = ffmpeg;
|
||||||
JSONObject json = new JSONObject();
|
JSONObject json = new JSONObject();
|
||||||
json.put("code", 0);
|
json.put("code", 0);
|
||||||
json.put("msg", "ok");
|
json.put("msg", "ok");
|
||||||
return json;
|
return json;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ResponseBody
|
@ResponseBody
|
||||||
@RequestMapping("/system/get/ffmpeg.do")
|
@RequestMapping("/system/get/ffmpeg.do")
|
||||||
public JSONObject getFFmpeg() {
|
public JSONObject getFFmpeg() {
|
||||||
@ -85,6 +91,37 @@ public class SystemConfigController {
|
|||||||
json.put("data", data);
|
json.put("data", data);
|
||||||
return json;
|
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
|
@ResponseBody
|
||||||
@RequestMapping("/system/qq/login.do")
|
@RequestMapping("/system/qq/login.do")
|
||||||
public JSONObject loginQQ() {
|
public JSONObject loginQQ() {
|
||||||
|
@ -307,4 +307,26 @@ public class AppTools {
|
|||||||
return false;
|
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;
|
package com.yutou.bilibili.Tools;
|
||||||
|
|
||||||
|
import com.yutou.bilibili.BiliBili.Datas.AppData;
|
||||||
import com.yutou.bilibili.BiliBili.Datas.LiveData;
|
import com.yutou.bilibili.BiliBili.Datas.LiveData;
|
||||||
import com.yutou.bilibili.BiliBili.Live;
|
import com.yutou.bilibili.BiliBili.Live;
|
||||||
import com.yutou.bilibili.BiliBili.LiveUtils;
|
import com.yutou.bilibili.BiliBili.LiveUtils;
|
||||||
import com.yutou.bilibili.BiliBili.Services.IBiliBiliLiveService;
|
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.BilibiliLiveInfo;
|
||||||
import com.yutou.bilibili.mybatis.Bili.mybatis.model.BilibiliUpInfo;
|
import com.yutou.bilibili.mybatis.Bili.mybatis.model.BilibiliUpInfo;
|
||||||
import org.springframework.boot.ApplicationArguments;
|
import org.springframework.boot.ApplicationArguments;
|
||||||
@ -27,12 +29,16 @@ import java.util.TimerTask;
|
|||||||
public class ApplicationInit implements ApplicationRunner {
|
public class ApplicationInit implements ApplicationRunner {
|
||||||
@Resource
|
@Resource
|
||||||
IBiliBiliLiveService service;
|
IBiliBiliLiveService service;
|
||||||
|
@Resource
|
||||||
|
ISystemConfigService configService;
|
||||||
private Timer timer;
|
private Timer timer;
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run(ApplicationArguments args) throws Exception {
|
public void run(ApplicationArguments args) throws Exception {
|
||||||
LiveUtils.LiveGiftConfig.getInstance();
|
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();
|
startTimer();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,4 +4,5 @@ public class Config {
|
|||||||
public static final String USER_REG="userReg";
|
public static final String USER_REG="userReg";
|
||||||
public static final String BILI_LIVE_FLAG="biliLive";
|
public static final String BILI_LIVE_FLAG="biliLive";
|
||||||
public static final String SYSTEM_VIDEO_FFMPEG="ffmpeg_path";
|
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(),
|
file.getAbsolutePath(),
|
||||||
out.getAbsolutePath() + File.separator + file.getName());
|
out.getAbsolutePath() + File.separator + file.getName());
|
||||||
com.yutou.bilibili.Tools.Log.i(exec);
|
com.yutou.bilibili.Tools.Log.i(exec);
|
||||||
Process process = Runtime.getRuntime().exec(new String[]{
|
Process process=AppTools.exec(exec);
|
||||||
"cmd",
|
|
||||||
"/c",
|
|
||||||
exec
|
|
||||||
}
|
|
||||||
);
|
|
||||||
InputStream inputStream = process.getErrorStream();
|
InputStream inputStream = process.getErrorStream();
|
||||||
byte[] bytes = new byte[1024];
|
byte[] bytes = new byte[1024];
|
||||||
while (inputStream.read(bytes) > -1) {
|
while (inputStream.read(bytes) > -1) {
|
||||||
|
Loading…
Reference in New Issue
Block a user