From 6ee610f4ccea6907817efd97a0fa9d6b3952919f Mon Sep 17 00:00:00 2001
From: zlzw <583819556@qq.com>
Date: Thu, 5 Dec 2024 10:36:15 +0800
Subject: [PATCH] =?UTF-8?q?=E5=8A=A0=E4=BA=86=E6=97=A5=E5=BF=97=E7=B3=BB?=
=?UTF-8?q?=E7=BB=9F?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.gitignore | 3 +-
pom.xml | 15 +++
.../java/com/yutou/BilibiliApplication.java | 27 ++--
.../yutou/biliapi/net/WebSocketServer.java | 26 ++--
.../yutou/bilibili/Tools/ApplicationInit.java | 10 +-
.../bilibili/services/SystemService.java | 4 +-
.../common/okhttp/HttpLoggingInterceptor.java | 5 +-
.../yutou/common/utils/DynamicLogFile.java | 123 ++++++++++++++++++
src/main/java/com/yutou/common/utils/Log.java | 9 ++
src/main/resources/application.properties | 1 +
src/main/resources/log4j2.xml | 37 ++++++
11 files changed, 227 insertions(+), 33 deletions(-)
create mode 100644 src/main/java/com/yutou/common/utils/DynamicLogFile.java
create mode 100644 src/main/resources/log4j2.xml
diff --git a/.gitignore b/.gitignore
index 39d4fa8..5d1a946 100644
--- a/.gitignore
+++ b/.gitignore
@@ -35,4 +35,5 @@ build/
### dir ###
/live/
/databases/
-/cache/
\ No newline at end of file
+/cache/
+/logs/
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 38ff572..7417af9 100644
--- a/pom.xml
+++ b/pom.xml
@@ -144,6 +144,21 @@
selenium-java
4.26.0
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ org.springframework.boot
+ spring-boot-starter-logging
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-log4j2
+
diff --git a/src/main/java/com/yutou/BilibiliApplication.java b/src/main/java/com/yutou/BilibiliApplication.java
index c4b977c..e298260 100644
--- a/src/main/java/com/yutou/BilibiliApplication.java
+++ b/src/main/java/com/yutou/BilibiliApplication.java
@@ -1,29 +1,32 @@
package com.yutou;
import com.yutou.common.okhttp.HttpLoggingInterceptor;
+import com.yutou.common.utils.ConfigTools;
+import com.yutou.common.utils.Log;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication()
public class BilibiliApplication {
- public static String version = "0.8.4";
+ public static String version = "0.9";
public static void main(String[] args) {
- HttpLoggingInterceptor.setLog(false);
+ Log.i("启动版本", version);
+ HttpLoggingInterceptor.setLog(ConfigTools.load(ConfigTools.CONFIG, "HttpLog", Boolean.class, false));
SpringApplication.run(BilibiliApplication.class, args);
}
//TODO 优化 1 手动中断录制后,没有时间戳问题需要解决,看是提示转码还是有什么其他解决方案 | 改成了通过q来退出
- //TODO 优化 2 创建nfo文件看看要不要改成录制后生成,或者触发打包指令再生成
- //TODO 优化 3 录制完成前应该也允许查看礼物信息和SC以及弹幕,未停止录制改成从开始时间到当前时间的弹幕和礼物信息,已停止录制则询问是否转码
- //TODO 优化 4 视频页面礼物的图标,有数据计算错误以及单项猛增的话导致其他项目无法查看的问题(可参考泛式死亡笔记录播) | 换成饼状图
- //TODO 修复 1 开播时有概率连续触发创建nfo和记录视频到数据宽度问题.
- //TODO 测试 1 需要测试网络中断下,弹幕重连机制
- //TODO 测试 2 在导出jar包后再测试完整的录制功能
- //TODO 测试 3 需要确认项目的内存占用情况
- //TODO 开发 1 完成用户列表的所有功能,包括移出用户和筛选ck和登陆扫码二维码的优化
+ //TODO 优化 2 创建nfo文件看看要不要改成录制后生成,或者触发打包指令再生成|改了
+ //TODO 优化 3 录制完成前应该也允许查看礼物信息和SC以及弹幕,未停止录制改成从开始时间到当前时间的弹幕和礼物信息,已停止录制则询问是否转码|改了
+ //TODO 优化 4 视频页面礼物的图标,有数据计算错误以及单项猛增的话导致其他项目无法查看的问题(可参考泛式死亡笔记录播) | 换成饼状图 | 改了
+ //TODO 修复 1 开播时有概率连续触发创建nfo和记录视频到数据宽度问题. | 改了
+ //TODO 测试 1 需要测试网络中断下,弹幕重连机制|好像没问题
+ //TODO 测试 2 在导出jar包后再测试完整的录制功能|没问题
+ //TODO 测试 3 需要确认项目的内存占用情况|好像还行
+ //TODO 开发 1 完成用户列表的所有功能,包括移出用户和筛选ck和登陆扫码二维码的优化|改了
//TODO 开发 2 数据中心
//TODO 开发 3 视频页面打包导出视频和弹幕
- //TODO 开发 4 弹幕随开播时间录制
- //TODO 开发 5 追加关键词检测
+ //TODO 开发 4 弹幕随开播时间录制|有了
+ //TODO 开发 5 追加关键词检测|加了
}
diff --git a/src/main/java/com/yutou/biliapi/net/WebSocketServer.java b/src/main/java/com/yutou/biliapi/net/WebSocketServer.java
index af32d2e..a2de8f3 100644
--- a/src/main/java/com/yutou/biliapi/net/WebSocketServer.java
+++ b/src/main/java/com/yutou/biliapi/net/WebSocketServer.java
@@ -15,7 +15,6 @@ import com.yutou.biliapi.bean.websocket.WebSocketBody;
import com.yutou.biliapi.bean.websocket.WebSocketHeader;
import com.yutou.biliapi.bean.websocket.live.WSData;
import com.yutou.biliapi.databases.BiliBiliLoginDatabase;
-import com.yutou.biliapi.databases.BiliLiveDatabase;
import com.yutou.biliapi.utils.BytesUtils;
import com.yutou.bilibili.services.LiveDatabasesService;
import com.yutou.bilibili.services.LiveService;
@@ -45,7 +44,6 @@ import java.util.concurrent.TimeUnit;
@Service
public class WebSocketServer {
ThreadPoolExecutor executor;
- private static WebSocketServer instance;
Map roomMap;
private final List userStopList = new ArrayList<>();//手动停止列表
@Resource
@@ -164,15 +162,17 @@ public class WebSocketServer {
private final LiveRoomConfig roomConfig;
private final HeartbeatTask heartbeatTask;
private final boolean isUser;
+ private final String logTag;
public WebSocketClientTh(URI serverUri, LiveRoomConfig roomId, boolean isUser) {
super(serverUri);
- Log.i("WebSocketClientTh.WebSocketClientTh : " + serverUri);
+ logTag = "WebSocket-" + roomId.getRoomId();
+ Log.getDynamicLogger(logTag).info("WebSocketClientTh.WebSocketClientTh = {}", serverUri);
this.isUser = isUser;
this.roomConfig = roomId;
Brotli4jLoader.ensureAvailability();
- heartbeatTask = new HeartbeatTask();
addHeader("User-Agent", ConfigTools.getUserAgent());
+ heartbeatTask = new HeartbeatTask();
connect();
}
@@ -182,7 +182,7 @@ public class WebSocketServer {
heartbeatTask.setSocket(this);
heartbeatTask.sendInitAuthData();
new Timer().schedule(heartbeatTask, 1000, 30000);
- Log.i("WebSocketClientTh.onOpen", roomConfig.getRoomId());
+ Log.getDynamicLogger(logTag).info("WebSocketClientTh.onOpen,{}", roomConfig.getRoomId());
}
@Override
@@ -199,7 +199,7 @@ public class WebSocketServer {
@Override
public void onClose(int i, String s, boolean b) {
- Log.e("WebSocketClientTh.onClose", "i = " + i + ", s = " + s + ", b = " + b, roomConfig.getRoomId(), heartbeatTask.socket.isOpen());
+ Log.getDynamicLogger(logTag).error("WebSocketClientTh.onClose. {},{},{}", "i = " + i + ", s = " + s + ", b = " + b, roomConfig.getRoomId(), heartbeatTask.socket.isOpen());
roomMap.remove(roomConfig);
heartbeatTask.cancel();
if (i == 1006) {
@@ -211,7 +211,7 @@ public class WebSocketServer {
@Override
public void onError(Exception e) {
- Log.i("WebSocketClientTh.onError", roomConfig.getRoomId());
+ Log.getDynamicLogger(logTag).info("WebSocketClientTh.onError,{}", roomConfig.getRoomId());
Log.e(e);
roomMap.remove(roomConfig);
heartbeatTask.cancel();
@@ -239,7 +239,7 @@ public class WebSocketServer {
}
private void danmu(byte[] bytes) {
- //Log.i("未压缩:" + new String(bytes));
+ Log.getDynamicLogger(logTag).info("未压缩:{}", new String(bytes));
}
private void unzipDanmu(byte[] bytes, boolean useHeader) {
@@ -248,16 +248,14 @@ public class WebSocketServer {
DirectDecompress directDecompress = Decoder.decompress(bytes);
if (directDecompress.getResultStatus() == DecoderJNI.Status.DONE) {
WebSocketBody body = new WebSocketBody(directDecompress.getDecompressedData());
-// Log.i("协议:" + useHeader + " 命令数:" + body.getBodyList().size());
+ Log.getDynamicLogger(logTag).info("协议:{},命令数:{}", useHeader, +body.getBodyList().size());
for (JSONObject json : body.getBodyList()) {
WSData parse = WSData.parse(json);
liveDatabasesService.getLiveDatabase(roomConfig.getRoomId()).addSource(parse);
- // Log.i("解压:" + parse);
+ Log.getDynamicLogger(logTag).info("解压:{}", parse);
}
- // Log.i();
- // Log.i();
} else {
- Log.e(new RuntimeException("解压失败"));
+ Log.getDynamicLogger(logTag).error(new RuntimeException("解压失败"));
}
} catch (Exception e) {
Log.e(e);
@@ -295,10 +293,10 @@ public class WebSocketServer {
json.put("uid", 0);
}
LoginCookieDatabaseBean cookie = BiliBiliLoginDatabase.getInstance().getCookie(roomConfig.getLoginUid());
- Log.d("cookie:", cookie, "RoomId:" + roomConfig);
try {
json.put("roomid", new BigInteger(roomConfig.getRoomId()));
json.put("protover", 3);
+// json.put("buvid3", BiliUserUtils.getBuvid(roomConfig.isLogin() ? BiliBiliLoginDatabase.getInstance().getCookie(roomConfig.getRoomId()) : null));
json.put("platform", "web");
json.put("type", 2);
json.put("key", roomConfig.getLiveInfo().getToken());
diff --git a/src/main/java/com/yutou/bilibili/Tools/ApplicationInit.java b/src/main/java/com/yutou/bilibili/Tools/ApplicationInit.java
index de4b3d9..5befe8a 100644
--- a/src/main/java/com/yutou/bilibili/Tools/ApplicationInit.java
+++ b/src/main/java/com/yutou/bilibili/Tools/ApplicationInit.java
@@ -1,13 +1,17 @@
package com.yutou.bilibili.Tools;
+import com.yutou.biliapi.bean.live.LiveRoomInfo;
import com.yutou.bilibili.services.SystemService;
+import com.yutou.common.utils.DynamicLogFile;
+import com.yutou.common.utils.Log;
import jakarta.annotation.Resource;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;
import java.util.logging.Level;
-import java.util.logging.Logger;
/**
* 服务启动后执行
@@ -16,11 +20,11 @@ import java.util.logging.Logger;
public class ApplicationInit implements ApplicationRunner {
@Resource
SystemService systemConfigService;
+ Logger logger = LogManager.getLogger(ApplicationInit.class);
@Override
public void run(ApplicationArguments args) throws Exception {
- Logger logger = Logger.getLogger("ApplicationInit");
- logger.log(Level.INFO, "服务启动后执行");
+ logger.info("服务启动后执行");
systemConfigService.start();
}
diff --git a/src/main/java/com/yutou/bilibili/services/SystemService.java b/src/main/java/com/yutou/bilibili/services/SystemService.java
index b4db522..59f59e4 100644
--- a/src/main/java/com/yutou/bilibili/services/SystemService.java
+++ b/src/main/java/com/yutou/bilibili/services/SystemService.java
@@ -81,7 +81,9 @@ public class SystemService {
}
public void stop() {
- scheduled.cancel(true);
+ if(scheduled!=null) {
+ scheduled.cancel(true);
+ }
videoService.stopAll();
}
diff --git a/src/main/java/com/yutou/common/okhttp/HttpLoggingInterceptor.java b/src/main/java/com/yutou/common/okhttp/HttpLoggingInterceptor.java
index ca0f922..edae618 100644
--- a/src/main/java/com/yutou/common/okhttp/HttpLoggingInterceptor.java
+++ b/src/main/java/com/yutou/common/okhttp/HttpLoggingInterceptor.java
@@ -8,13 +8,14 @@ import okio.Buffer;
import java.io.IOException;
import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;
public class HttpLoggingInterceptor implements Interceptor {
private static final String TAG = "HttpLogging";
- private static final Charset UTF8 = Charset.forName("UTF-8");
+ private static final Charset UTF8 = StandardCharsets.UTF_8;
private volatile Level printLevel = Level.BODY;
private java.util.logging.Level colorLevel;
@@ -51,7 +52,7 @@ public class HttpLoggingInterceptor implements Interceptor {
private void log(String message) {
//logger.log(colorLevel, message);
if (prLog) {
- Log.i(TAG, message);
+ Log.getDynamicLogger(TAG).info(message);
}
//Log.e(TAG,message);
}
diff --git a/src/main/java/com/yutou/common/utils/DynamicLogFile.java b/src/main/java/com/yutou/common/utils/DynamicLogFile.java
new file mode 100644
index 0000000..578dc17
--- /dev/null
+++ b/src/main/java/com/yutou/common/utils/DynamicLogFile.java
@@ -0,0 +1,123 @@
+package com.yutou.common.utils;
+
+import com.google.common.cache.Cache;
+import com.google.common.cache.CacheBuilder;
+import com.yutou.bilibili.Tools.DateFormatUtils;
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.core.Appender;
+import org.apache.logging.log4j.core.Layout;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.core.appender.rolling.*;
+import org.apache.logging.log4j.core.config.Configuration;
+import org.apache.logging.log4j.core.appender.RollingFileAppender;
+import org.apache.logging.log4j.core.layout.PatternLayout;
+
+import java.util.Date;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+
+public class DynamicLogFile {
+ // 创建一个缓存,用于存储Logger对象,最大容量为1000,过期时间为10分钟
+ static Cache cache = CacheBuilder.newBuilder()
+ .maximumSize(1000)
+ .expireAfterAccess(10, TimeUnit.MINUTES)
+ .removalListener(it -> {
+ if (it.wasEvicted()) {
+ if (it.getKey() != null) {
+ String loggerName = (String) it.getKey();
+ remove(loggerName, true);
+ }
+ }
+ })
+ .build();
+
+ // 根据loggerName获取Logger对象,如果缓存中不存在,则创建一个新的Logger对象并放入缓存
+ public static Logger getLogger(String loggerName) {
+ try {
+ return cache.get(loggerName, () -> {
+ configureLogger(loggerName);
+ return LogManager.getLogger(loggerName);
+ });
+ } catch (ExecutionException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ // 配置Logger对象
+ private static void configureLogger(String loggerName) {
+
+ LoggerContext context = (LoggerContext) LogManager.getContext(false);
+ Configuration config = context.getConfiguration();
+
+ // 创建日志格式
+ Layout layout = PatternLayout.newBuilder()
+ .withPattern("%d{yyyy-MM-dd'T'HH:mm:ss.SSSXXX} %-5p [%thread] (%F:%L) : %m%n")
+ .build();
+
+ // 创建时间触发策略
+ TimeBasedTriggeringPolicy timePolicy = TimeBasedTriggeringPolicy.newBuilder()
+ .build();
+
+ // 创建文件大小触发策略
+ SizeBasedTriggeringPolicy sizePolicy = SizeBasedTriggeringPolicy.createPolicy("100 MB");
+
+ // 创建组合触发策略
+ CompositeTriggeringPolicy triggeringPolicy = CompositeTriggeringPolicy.createPolicy(timePolicy, sizePolicy);
+
+
+ // 创建滚动文件Appender
+ RollingFileAppender appender = RollingFileAppender.newBuilder()
+ .setName(loggerName)
+ .withFileName("logs" + "/" + DateFormatUtils.getInstance().format(new Date(), "yyyy-MM-dd") + "/" + loggerName + ".log")
+ .withFilePattern("logs" + "/" + "%d{yyyy-MM-dd}" + "/" + loggerName + "-%i.log.gz")
+ .setLayout(layout)
+ .setImmediateFlush(true)
+ .withAppend(true)
+ .setIgnoreExceptions(false)
+ .withPolicy(triggeringPolicy)
+ .build();
+
+ appender.start();
+ config.addAppender(appender);
+
+ // 获取Logger对象
+ org.apache.logging.log4j.core.Logger coreLogger = context.getLogger(loggerName);
+ if (coreLogger == null) {
+ throw new IllegalStateException("Logger with name " + loggerName + " does not exist.");
+ }
+
+ // 将Appender添加到Logger对象中
+ coreLogger.addAppender(appender);
+ coreLogger.setLevel(Level.ALL);
+ coreLogger.setAdditive(false);
+
+ // 更新Logger对象
+ context.updateLoggers();
+
+ }
+
+ // 移除Logger对象
+ public static void remove(String loggerName) {
+ remove(loggerName, false);
+ }
+
+ // 私有方法,移除Logger对象,isAuto参数用于判断是否是自动移除
+ private static void remove(String loggerName, boolean isAuto) {
+ if (!isAuto) {
+ cache.invalidate(loggerName);
+ }
+ LoggerContext context = (LoggerContext) LogManager.getContext(false);
+ Configuration config = context.getConfiguration();
+ org.apache.logging.log4j.core.Logger coreLogger = context.getLogger(loggerName);
+ Appender appender = config.getAppender(loggerName);
+ if (appender != null) {
+ appender.stop();
+ coreLogger.removeAppender(appender);
+ }
+ config.getAppenders().remove(loggerName);
+ context.updateLoggers();
+ }
+
+}
diff --git a/src/main/java/com/yutou/common/utils/Log.java b/src/main/java/com/yutou/common/utils/Log.java
index dab9d16..ca2be38 100644
--- a/src/main/java/com/yutou/common/utils/Log.java
+++ b/src/main/java/com/yutou/common/utils/Log.java
@@ -2,6 +2,7 @@ package com.yutou.common.utils;
import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.util.StackLocatorUtil;
@@ -11,6 +12,14 @@ public class Log {
System.out.println();
}
+ public static Logger getDynamicLogger(String loggerName) {
+ return DynamicLogFile.getLogger(loggerName);
+ }
+
+ public static void removeDynamicLogger(String loggerName) {
+ DynamicLogFile.remove(loggerName);
+ }
+
public static void i(Object... log) {
if (!((boolean) ConfigTools.load(ConfigTools.CONFIG, "logcat"))) {
return;
diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties
index dc92337..80d9582 100644
--- a/src/main/resources/application.properties
+++ b/src/main/resources/application.properties
@@ -1,4 +1,5 @@
server.port=8880
+logging.config=classpath:log4j2.xml
logging.file.path=./logs
logging.level.com.log.controller = trace
# 启用Hibernate SQL日志
diff --git a/src/main/resources/log4j2.xml b/src/main/resources/log4j2.xml
new file mode 100644
index 0000000..08e385d
--- /dev/null
+++ b/src/main/resources/log4j2.xml
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ %d{yyyy-MM-dd'T'HH:mm:ss.SSSXXX} %-5p [%thread] (%F:%L) : %m%n%throwable
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+