diff --git a/Web/index.html b/Web/index.html
index f1d0a86..ee52381 100644
--- a/Web/index.html
+++ b/Web/index.html
@@ -1,6 +1,5 @@
-
-
+
@@ -9,51 +8,31 @@
-
-
-
-
- 本站点采用限时注册模式,仅登陆用户可使用。当前注册状态: 关闭
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
\ No newline at end of file
diff --git a/src/main/java/com/yutou/bilibili/Controllers/LiveConfigController.java b/src/main/java/com/yutou/bilibili/Controllers/LiveConfigController.java
index da6d4c5..a5bcd56 100644
--- a/src/main/java/com/yutou/bilibili/Controllers/LiveConfigController.java
+++ b/src/main/java/com/yutou/bilibili/Controllers/LiveConfigController.java
@@ -3,10 +3,13 @@ package com.yutou.bilibili.Controllers;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.yutou.biliapi.bean.live.database.LiveConfigDatabaseBean;
+import com.yutou.bilibili.Tools.Tools;
import com.yutou.bilibili.datas.ResultData;
import com.yutou.bilibili.datas.ReturnCode;
import com.yutou.bilibili.services.LiveConfigService;
import jakarta.annotation.Resource;
+import org.springframework.core.io.FileSystemResource;
+import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
@@ -60,7 +63,7 @@ public class LiveConfigController {
public JSONObject getAllConfig() {
List config = configService.getAllConfig();
if (config != null) {
- return ResultData.success(JSONArray.parseArray(JSONArray.toJSONString(config)));
+ return ResultData.success(config);
}
return ResultData.fail(ReturnCode.RC999);
}
@@ -77,4 +80,9 @@ public class LiveConfigController {
}
return ResultData.fail(ReturnCode.RC999);
}
+
+ @RequestMapping(value = "face", method = RequestMethod.GET)
+ public ResponseEntity getFace(String roomId) {
+ return Tools.getFile(configService.getFace(roomId));
+ }
}
diff --git a/src/main/java/com/yutou/bilibili/Controllers/TestControllers.java b/src/main/java/com/yutou/bilibili/Controllers/TestControllers.java
index 60791ce..76f29cb 100644
--- a/src/main/java/com/yutou/bilibili/Controllers/TestControllers.java
+++ b/src/main/java/com/yutou/bilibili/Controllers/TestControllers.java
@@ -7,16 +7,9 @@ import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class TestControllers {
- @RequestMapping("/root/test")
+ @RequestMapping("/root/all")
@ResponseBody
public String test(){
- FFmpegUtils.killAll();
return "hello world";
}
- @RequestMapping("/root/kill")
- @ResponseBody
- public String kill(String roomId){
- FFmpegUtils.kill(roomId);
- return FFmpegUtils.check(roomId)+"";
- }
}
diff --git a/src/main/java/com/yutou/bilibili/Tools/ApplicationClose.java b/src/main/java/com/yutou/bilibili/Tools/ApplicationClose.java
index 269b85a..09edecf 100644
--- a/src/main/java/com/yutou/bilibili/Tools/ApplicationClose.java
+++ b/src/main/java/com/yutou/bilibili/Tools/ApplicationClose.java
@@ -1,5 +1,6 @@
package com.yutou.bilibili.Tools;
+import com.yutou.bilibili.services.LiveVideoService;
import com.yutou.bilibili.services.SystemService;
import com.yutou.common.utils.FFmpegUtils;
import com.yutou.common.utils.Log;
@@ -7,15 +8,18 @@ import jakarta.annotation.Resource;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextClosedEvent;
import org.springframework.stereotype.Component;
+import org.springframework.stereotype.Service;
@Component
public class ApplicationClose implements ApplicationListener {
@Resource
SystemService systemConfigService;
+ @Resource
+ LiveVideoService videoService;
@Override
public void onApplicationEvent(ContextClosedEvent contextClosedEvent) {
Log.i("服务结束");
systemConfigService.stop();
- FFmpegUtils.killAll();
+ videoService.stopAll();
}
}
diff --git a/src/main/java/com/yutou/bilibili/Tools/FFmpegUtils.java b/src/main/java/com/yutou/bilibili/Tools/FFmpegUtils.java
index 831f99f..e64a0a2 100644
--- a/src/main/java/com/yutou/bilibili/Tools/FFmpegUtils.java
+++ b/src/main/java/com/yutou/bilibili/Tools/FFmpegUtils.java
@@ -42,15 +42,15 @@ public class FFmpegUtils {
file.getAbsolutePath(),
out.getAbsolutePath() + File.separator + file.getName());
Log.i(exec);
- Process process= ProcessUtils.exec(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);
+ 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();
+ new File(out.getAbsolutePath() + File.separator + file.getName()).delete();
} catch (Exception e) {
Log.e(e);
}
diff --git a/src/main/java/com/yutou/bilibili/Tools/ProcessUtils.java b/src/main/java/com/yutou/bilibili/Tools/ProcessUtils.java
index 6bef7be..0843265 100644
--- a/src/main/java/com/yutou/bilibili/Tools/ProcessUtils.java
+++ b/src/main/java/com/yutou/bilibili/Tools/ProcessUtils.java
@@ -7,11 +7,12 @@ import java.io.InputStreamReader;
public class ProcessUtils {
- public static boolean isRuntimeSystemOfWindow(){
- return System.getProperty ("os.name").contains("Windows");
+ public static boolean isRuntimeSystemOfWindow() {
+ return System.getProperty("os.name").contains("Windows");
}
+
public static void killProcess(Long pid) throws Exception {
- if(pid==null) {
+ if (pid == null) {
return;
}
if (isRuntimeSystemOfWindow()) {
@@ -25,8 +26,9 @@ public class ProcessUtils {
}
}
+
public static boolean isProcessRunning(Long pid) throws Exception {
- if(pid==null) {
+ if (pid == null) {
return false;
}
String command;
@@ -48,24 +50,19 @@ public class ProcessUtils {
}
return false;
}
- public static Process exec(String exec)throws Exception{
- if(isRuntimeSystemOfWindow()) {
- return Runtime.getRuntime().exec(new String[]{
- "cmd",
- "/c",
- exec
- }
- );
+ public static Process exec(String exec) throws Exception {
+ if(isRuntimeSystemOfWindow()){
+ return exec("cmd.exe","/c",exec);
}else{
- return Runtime.getRuntime().exec(new String[]{
- "sh",
- "-c",
- exec
- }
- );
+ return exec("sh","-c",exec);
}
}
+ public static Process exec(String... command) throws Exception {
+ ProcessBuilder pb;
+ pb = new ProcessBuilder(command);
+ return pb.start();
+ }
public static void main(String[] args) throws Exception {
- }
+ }
}
diff --git a/src/main/java/com/yutou/bilibili/datas/ResultData.java b/src/main/java/com/yutou/bilibili/datas/ResultData.java
index f48af0c..747e16c 100644
--- a/src/main/java/com/yutou/bilibili/datas/ResultData.java
+++ b/src/main/java/com/yutou/bilibili/datas/ResultData.java
@@ -1,14 +1,19 @@
package com.yutou.bilibili.datas;
+import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import lombok.Data;
+import java.util.Collection;
+import java.util.List;
+
@Data
public class ResultData {
private int status;
private String message;
private T data;
- private long timestamp ;
+ private int count;
+ private long timestamp;
public ResultData() {
this.timestamp = System.currentTimeMillis();
@@ -20,6 +25,9 @@ public class ResultData {
resultData.setStatus(ReturnCode.RC100.getCode());
resultData.setMessage(ReturnCode.RC100.getMessage());
resultData.setData(data);
+ if (data instanceof Collection>) {
+ resultData.count = ((Collection>) data).size();
+ }
return JSONObject.parseObject(JSONObject.toJSONString(resultData));
}
@@ -29,9 +37,11 @@ public class ResultData {
resultData.setMessage(message);
return JSONObject.parseObject(JSONObject.toJSONString(resultData));
}
+
public static JSONObject success(ReturnCode code) {
return fail(code);
}
+
public static JSONObject fail(ReturnCode code) {
ResultData resultData = new ResultData<>();
resultData.setStatus(code.getCode());
diff --git a/src/main/java/com/yutou/bilibili/services/LiveConfigService.java b/src/main/java/com/yutou/bilibili/services/LiveConfigService.java
index 4324728..1f63de8 100644
--- a/src/main/java/com/yutou/bilibili/services/LiveConfigService.java
+++ b/src/main/java/com/yutou/bilibili/services/LiveConfigService.java
@@ -5,10 +5,12 @@ import com.yutou.biliapi.bean.live.MasterInfoBean;
import com.yutou.biliapi.bean.live.database.LiveConfigDatabaseBean;
import com.yutou.biliapi.databases.BiliLiveConfigDatabase;
import com.yutou.biliapi.net.BiliLiveNetApiManager;
+import com.yutou.common.okhttp.HttpDownloadUtils;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
+import java.io.File;
import java.io.IOException;
import java.math.BigInteger;
import java.util.List;
@@ -34,6 +36,7 @@ public class LiveConfigService {
bean.setAnchorFace(infoBean.getInfo().getFace());
bean.setAnchorName(infoBean.getInfo().getUname());
database.setConfig(bean);
+ downloadFace(bean);
return bean;
} catch (IOException e) {
throw new RuntimeException(e);
@@ -48,6 +51,7 @@ public class LiveConfigService {
bean.setRoomId(roomId);
bean.setSql_time(config.getSql_time());
database.setConfig(bean);
+ downloadFace(bean);
return bean;
}
@@ -67,4 +71,22 @@ public class LiveConfigService {
public LiveConfigDatabaseBean getConfig(BigInteger roomId) {
return database.getConfig(roomId);
}
+
+ public File getFace(String roomId){
+ LiveConfigDatabaseBean config = database.getConfig(new BigInteger(roomId));
+ if (config == null) {
+ return null;
+ }
+ return new File(config.getRecordPath() + File.separator + config.getAnchorName() + File.separator + config.getAnchorFace());
+ }
+
+ private void downloadFace(LiveConfigDatabaseBean bean) {
+ HttpDownloadUtils.download(
+ new HttpDownloadUtils.Builder()
+ .setPath(bean.getRecordPath() + File.separator + bean.getAnchorName())
+ .setUrl(bean.getAnchorFace())
+ .setFileName("face.jpg")
+ );
+ bean.setAnchorFace(bean.getRecordPath() + File.separator + bean.getAnchorName() + File.separator + "face.jpg");
+ }
}
diff --git a/src/main/java/com/yutou/bilibili/services/LiveVideoService.java b/src/main/java/com/yutou/bilibili/services/LiveVideoService.java
index c62d57b..1112bbd 100644
--- a/src/main/java/com/yutou/bilibili/services/LiveVideoService.java
+++ b/src/main/java/com/yutou/bilibili/services/LiveVideoService.java
@@ -27,6 +27,7 @@ import com.yutou.bilibili.datas.VideoFilePath;
import com.yutou.bilibili.interfaces.DownloadInterface;
import com.yutou.common.okhttp.HttpCallback;
import com.yutou.common.okhttp.HttpDownloadUtils;
+import com.yutou.common.record.AbsVideoRecord;
import com.yutou.common.utils.ConfigTools;
import com.yutou.common.utils.FFmpegUtils;
import com.yutou.common.utils.Log;
@@ -47,12 +48,12 @@ import static com.alibaba.fastjson2.util.DateUtils.DateTimeFormatPattern.DATE_FO
@Service
public class LiveVideoService {
ThreadPoolExecutor executor;
- private final Map liveVideoMap = new HashMap<>();
private final List userStopList = new ArrayList<>();//手动停止列表
-
+ AbsVideoRecord videoRecord;
public LiveVideoService() {
Log.i("初始化下载服务");
+ videoRecord=new FFmpegUtils();
executor = new ThreadPoolExecutor(2, 4, Long.MAX_VALUE, TimeUnit.SECONDS, new ArrayBlockingQueue(100));
}
@@ -63,27 +64,22 @@ public class LiveVideoService {
if (isUser) {
userStopList.remove(bean.getRoomId().toString());
}
- if (liveVideoMap.containsKey(bean)) {
+ if (videoRecord.check(bean.getRoomId().toString())) {
return;
}
- Log.i("添加下载任务:" + liveVideoMap.keySet().size());
- liveVideoMap.put(bean, null);
BiliLiveNetApiManager.getInstance().getApi(bean.getRecordUid()).getRoomInfo(bean.getRoomId().toString()).enqueue(new HttpCallback() {
@Override
public void onResponse(Headers headers, int code, String status, LiveRoomInfo response, String rawResponse) {
if (response.getLiveStatus() == 1) {
VideoTask task = new VideoTask(bean, response);
executor.execute(task);
- liveVideoMap.put(bean, task);
} else {
- liveVideoMap.remove(bean);
Log.i("移除下载");
}
}
@Override
public void onFailure(Throwable throwable) {
- liveVideoMap.remove(bean);
Log.i("移除下载");
}
});
@@ -95,36 +91,18 @@ public class LiveVideoService {
if (isUser) {
userStopList.add(roomId);
}
- for (Map.Entry entry : liveVideoMap.entrySet()) {
- if (entry.getKey().getRoomId().toString().equals(roomId)) {
- entry.getValue().isDownload = false;
- liveVideoMap.remove(entry.getKey());
- Log.i("移除下载");
- break;
- }
- }
+ videoRecord.kill(roomId);
}
- public boolean check(String roomId) {
- for (LiveConfigDatabaseBean bean : liveVideoMap.keySet()) {
- if (bean.getRoomId().toString().equals(roomId)) {
- return true;
- }
- }
- return false;
- }
public JSONArray getDownloadTasks() {
JSONArray array = new JSONArray();
- array.addAll(liveVideoMap.keySet());
+ array.addAll(videoRecord.getRoomIds());
return array;
}
public void stopAll() {
- for (VideoTask task : liveVideoMap.values()) {
- task.isDownload = false;
- }
- liveVideoMap.clear();
+ videoRecord.killAll();
}
private class VideoTask implements Runnable {
@@ -163,7 +141,7 @@ public class LiveVideoService {
}
private void stop() {
- liveVideoMap.remove(bean);
+ videoRecord.kill(bean.getRoomId().toString());
api.getRoomInfo(config.getRoomId().toString()).enqueue(new HttpCallback() {
@Override
public void onResponse(Headers headers, int code, String status, LiveRoomInfo response, String rawResponse) {
@@ -196,7 +174,7 @@ public class LiveVideoService {
HttpDownloadUtils.download(new HttpDownloadUtils.Builder().setUrl(roomInfo.getKeyframe())
.setPath(rootPath.getAbsolutePath())
.setFileName("poster.jpg"));
- LiveInfoNfoTools.saveLiveInfoNfo(roomInfo,rootPath.getAbsolutePath(),new File(savePath).getName().replace(".flv",".nfo"));
+ LiveInfoNfoTools.saveLiveInfoNfo(roomInfo, rootPath.getAbsolutePath(), new File(savePath).getName().replace(".flv", ".nfo"));
saveLiveInfo(roomInfo);
api.getLiveRoomPlayInfo(
bean.getRoomId().toString(),
@@ -270,7 +248,7 @@ public class LiveVideoService {
.withNotSymbolParam("-threads", "8")
.withNotSymbolParam("-c:v", "copy")
.withNotSymbolParam("-y", "")
- .build(config.getRoomId().toString(),ffmpegPath, url, savePath);
+ .build(config.getRoomId().toString(), ffmpegPath, url, savePath);
Log.i(command.getCommand());
try {
command.start(new DownloadInterface() {
diff --git a/src/main/java/com/yutou/common/record/AbsVideoRecord.java b/src/main/java/com/yutou/common/record/AbsVideoRecord.java
new file mode 100644
index 0000000..35db229
--- /dev/null
+++ b/src/main/java/com/yutou/common/record/AbsVideoRecord.java
@@ -0,0 +1,14 @@
+package com.yutou.common.record;
+
+import com.yutou.bilibili.interfaces.DownloadInterface;
+
+import java.util.List;
+
+public abstract class AbsVideoRecord {
+ public abstract List getRoomIds();
+ public abstract boolean check(String roomId);
+ public abstract void kill(String roomId);
+ public abstract void killAll();
+ public abstract void start(DownloadInterface downloadInterface);
+ public abstract void stop();
+}
diff --git a/src/main/java/com/yutou/common/utils/FFmpegUtils.java b/src/main/java/com/yutou/common/utils/FFmpegUtils.java
index 8864ec7..5b40322 100644
--- a/src/main/java/com/yutou/common/utils/FFmpegUtils.java
+++ b/src/main/java/com/yutou/common/utils/FFmpegUtils.java
@@ -2,13 +2,14 @@ package com.yutou.common.utils;
import com.yutou.bilibili.Tools.ProcessUtils;
import com.yutou.bilibili.interfaces.DownloadInterface;
+import com.yutou.common.record.AbsVideoRecord;
import lombok.Getter;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.*;
-public class FFmpegUtils {
+public class FFmpegUtils extends AbsVideoRecord {
private static final Map pidMap = new HashMap<>();
@Getter
private String command;
@@ -16,28 +17,38 @@ public class FFmpegUtils {
InputStream inputStream;
OutputStream outputStream;
- private FFmpegUtils() {
+ public FFmpegUtils() {
}
- public static boolean check(String anchorUid) {
+ @Override
+ public List getRoomIds() {
+ pidMap.keySet().removeIf(key -> !check(key));
+ return pidMap.keySet().stream().toList();
+ }
+
+ @Override
+ public boolean check(String roomId) {
try {
- return ProcessUtils.isProcessRunning(pidMap.get(anchorUid));
+ return ProcessUtils.isProcessRunning(pidMap.get(roomId));
} catch (Exception e) {
Log.e(e);
throw new RuntimeException(e);
}
}
- public static void kill(String anchorUid) {
+ @Override
+ public void kill(String roomId) {
try {
- ProcessUtils.killProcess(pidMap.get(anchorUid));
+ ProcessUtils.killProcess(pidMap.get(roomId));
+ pidMap.remove(roomId);
} catch (Exception e) {
Log.e(e);
throw new RuntimeException(e);
}
}
- public static void killAll() {
+ @Override
+ public void killAll() {
for (Long pid : pidMap.values()) {
try {
ProcessUtils.killProcess(pid);
@@ -45,6 +56,7 @@ public class FFmpegUtils {
Log.e(e);
}
}
+ pidMap.clear();
}
public static class Builder {
@@ -96,15 +108,16 @@ public class FFmpegUtils {
}
}
+ @Override
public void start(DownloadInterface downloadInterface) {
new Thread(() -> {
try {
if (check(uid)) {
kill(uid);
}
- Process process = ProcessUtils.exec(command);
+ Process process = ProcessUtils.exec(command.split(" "));
long pid = process.toHandle().pid();
- Log.i("进程id "+pid);
+ Log.i("进程id " + pid);
inputStream = process.getErrorStream();
outputStream = process.getOutputStream();
byte[] bytes = new byte[2048];
@@ -130,6 +143,7 @@ public class FFmpegUtils {
}).start();
}
+ @Override
public void stop() {
try {
outputStream.write("q".getBytes());