diff --git a/pom.xml b/pom.xml
index 02c58ed..35fc14e 100644
--- a/pom.xml
+++ b/pom.xml
@@ -15,6 +15,7 @@
Demo project for Spring Boot
1.8
+ 1.4.10
@@ -102,10 +103,42 @@
poi-ooxml-schemas
3.17
+
+
+ net.mamoe
+ mirai-core-jvm
+ 2.5.0
+
+
+ org.jetbrains.kotlin
+ kotlin-stdlib
+ ${kotlin.version}
+
+
+ org.jetbrains.kotlin
+ kotlin-maven-plugin
+ ${kotlin.version}
+
+
+
+ compile
+
+ compile
+
+
+
+
+ test-compile
+
+ test-compile
+
+
+
+
org.springframework.boot
spring-boot-maven-plugin
diff --git a/src/main/java/com/yutou/bilibili/BiliBili/Controllers/RealTimeDataController.java b/src/main/java/com/yutou/bilibili/BiliBili/Controllers/RealTimeDataController.java
index 9239b0a..bc41183 100644
--- a/src/main/java/com/yutou/bilibili/BiliBili/Controllers/RealTimeDataController.java
+++ b/src/main/java/com/yutou/bilibili/BiliBili/Controllers/RealTimeDataController.java
@@ -30,7 +30,8 @@ public class RealTimeDataController {
@RequestMapping("get/query.do")
public JSONObject queryToDayLiveData(int roomid,Date startTime,Date endTime) throws ParseException {
JSONObject json = new JSONObject();
- BilibiliUpInfo info = service.queryUpToRoomId(roomid);
+ BilibiliUpInfo info = new BilibiliUpInfo();
+ info.setRoomid(roomid);
Live live = LiveUtils.liveContains(info);
if(startTime==null){
startTime=AppTools.getToDayStartTime();
diff --git a/src/main/java/com/yutou/bilibili/BiliBili/Controllers/UpInfoController.java b/src/main/java/com/yutou/bilibili/BiliBili/Controllers/UpInfoController.java
index b76e345..2cb2bf4 100644
--- a/src/main/java/com/yutou/bilibili/BiliBili/Controllers/UpInfoController.java
+++ b/src/main/java/com/yutou/bilibili/BiliBili/Controllers/UpInfoController.java
@@ -10,7 +10,6 @@ import com.yutou.bilibili.BiliBili.Services.IBiliBiliLiveService;
import com.yutou.bilibili.BiliBili.Tools.BiliTools;
import com.yutou.bilibili.Services.IUserService;
import com.yutou.bilibili.Tools.AppTools;
-import com.yutou.bilibili.Tools.Log;
import com.yutou.bilibili.mybatis.Bili.mybatis.model.BilibiliUpInfo;
import com.yutou.bilibili.mybatis.model.UUser;
import org.springframework.stereotype.Controller;
@@ -19,7 +18,6 @@ import org.springframework.web.bind.annotation.ResponseBody;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
import java.util.List;
@Controller
diff --git a/src/main/java/com/yutou/bilibili/BiliBili/Live.java b/src/main/java/com/yutou/bilibili/BiliBili/Live.java
index 181b238..608b3ab 100644
--- a/src/main/java/com/yutou/bilibili/BiliBili/Live.java
+++ b/src/main/java/com/yutou/bilibili/BiliBili/Live.java
@@ -7,8 +7,11 @@ import com.yutou.bilibili.BiliBili.Datas.LiveData;
import com.alibaba.fastjson.JSONObject;
import com.yutou.bilibili.BiliBili.Services.IBiliBiliLiveService;
import com.yutou.bilibili.BiliBili.Tools.SaveLive;
+import com.yutou.bilibili.QQBot.QQBotManager;
import com.yutou.bilibili.Tools.AppTools;
import com.yutou.bilibili.Tools.Log;
+import com.yutou.bilibili.Tools.Tools;
+import com.yutou.bilibili.interfaces.DownloadInterface;
import com.yutou.bilibili.mybatis.Bili.mybatis.model.BilibiliLiveData;
import com.yutou.bilibili.mybatis.Bili.mybatis.model.BilibiliLiveInfo;
import com.yutou.bilibili.mybatis.Bili.mybatis.model.BilibiliUpInfo;
@@ -81,13 +84,13 @@ public class Live implements ApplicationContextAware {
Live.lives.add(this);
updateUpInfo();
com.yutou.bilibili.Tools.Log.i("roomId = " + roomId + ", isLogin = " + isLogin);
- checkLiveTimer=new Timer();
+ checkLiveTimer = new Timer();
checkLiveTimer.schedule(new TimerTask() {
@Override
public void run() {
checkLive();
}
- },0,1000);
+ }, 0, 1000);
}
private void updateUpInfo() {
@@ -104,7 +107,7 @@ public class Live implements ApplicationContextAware {
}
}
} catch (Exception e) {
- e.printStackTrace();
+ Log.e(e);
}
}
@@ -147,7 +150,7 @@ public class Live implements ApplicationContextAware {
try {
likeLive();
} catch (Exception e) {
- e.printStackTrace();
+ Log.e(e);
}
}
@@ -179,7 +182,7 @@ public class Live implements ApplicationContextAware {
client.close();
start();
} catch (Exception e) {
- e.printStackTrace();
+ Log.e(e);
}
return;
}
@@ -197,7 +200,7 @@ public class Live implements ApplicationContextAware {
@Override
public void onError(Exception e) {
- e.printStackTrace();
+ Log.e(e);
run = false;
client.close();
}
@@ -216,7 +219,7 @@ public class Live implements ApplicationContextAware {
}
Live.lives.remove(this);
com.yutou.bilibili.Tools.Log.i("退出" + roomId + "直播间");
- if(checkLiveTimer!=null){
+ if (checkLiveTimer != null) {
checkLiveTimer.cancel();
}
}
@@ -281,13 +284,13 @@ public class Live implements ApplicationContextAware {
JSONObject json = JSONObject.parseObject(new String(bytes, StandardCharsets.UTF_8));
com.yutou.bilibili.Tools.Log.i(json.toJSONString());
} catch (Exception e) {
+ checkLive();
int popular = LiveUtils.bytesToInt2(bytes, 0);
info.setPopular(popular);
- checkLive();
}
}
} catch (Exception e) {
- e.printStackTrace();
+ Log.e(e);
com.yutou.bilibili.Tools.Log.i("----------ERROR----------");
com.yutou.bilibili.Tools.Log.i(new String(data, StandardCharsets.UTF_8));
LiveUtils.printHex(LiveUtils.dec(data));
@@ -467,6 +470,18 @@ public class Live implements ApplicationContextAware {
case "WIDGET_BANNER"://鬼知道是啥
case "HOT_RANK_SETTLEMENT":
case "LIVE"://开始直播,不过有在心跳包上做检测了,所以也无所谓?
+ JSONObject liveInfo = LiveUtils.getLiveInfo(roomId);
+ StringBuilder builder = new StringBuilder();
+ builder.append(upData.getName()).append("开播了!").append("\n");
+ builder.append(liveInfo.getJSONObject("data").getJSONObject("room_info").getString("title"));
+ Tools.download(liveInfo.getJSONObject("data").getJSONObject("room_info").getString("keyframe"), new DownloadInterface() {
+ @Override
+ public void onDownload(File file) {
+ super.onDownload(file);
+ QQBotManager.getInstance().sendMessage(file, builder.toString());
+ }
+ });
+ break;
case "PK_BATTLE_SETTLE_V2":
case "PK_BATTLE_END":
case "PK_BATTLE_SETTLE":
@@ -487,12 +502,12 @@ public class Live implements ApplicationContextAware {
service.addLiveData(liveData);
}
} catch (Exception e) {
- e.printStackTrace();
+ Log.e(e);
try {
JSONObject.parseObject(new String(bytes, StandardCharsets.UTF_8));
processData(new String(bytes, StandardCharsets.UTF_8), null);
} catch (Exception e2) {
- e2.printStackTrace();
+ Log.e(e2);
com.yutou.bilibili.Tools.Log.i(msg);
com.yutou.bilibili.Tools.Log.i("---------ERROR !!-----");
LiveUtils.printHex(bytes);
@@ -558,7 +573,7 @@ public class Live implements ApplicationContextAware {
outputStream.flush();
client.send(outputStream.toByteArray());
} catch (Exception e) {
- e.printStackTrace();
+ Log.e(e);
com.yutou.bilibili.Tools.Log.i(client.isClosed());
com.yutou.bilibili.Tools.Log.i(client.isOpen());
diff --git a/src/main/java/com/yutou/bilibili/BiliBili/LiveUtils.java b/src/main/java/com/yutou/bilibili/BiliBili/LiveUtils.java
index db87438..f9d587f 100644
--- a/src/main/java/com/yutou/bilibili/BiliBili/LiveUtils.java
+++ b/src/main/java/com/yutou/bilibili/BiliBili/LiveUtils.java
@@ -43,11 +43,10 @@ public class LiveUtils {
com.yutou.bilibili.Tools.Log.i("\n");
}
if (str.length() - i > 4) {
- System.out.print(str.substring(i, i + 4));
+ com.yutou.bilibili.Tools.Log.i(str.substring(i, i + 4));
} else {
com.yutou.bilibili.Tools.Log.i(str.substring(i));
}
- System.out.print(" ");
}
}
@@ -211,7 +210,8 @@ public class LiveUtils {
}
} catch (IOException e) {
- e.printStackTrace();
+ //e.printStackTrace();
+ Log.i("412 in "+url);
}
return null;
}
@@ -340,9 +340,19 @@ public class LiveUtils {
}
return null;
}
+ public static JSONObject getLiveInfo(int roomId){
+ return http_get("https://api.live.bilibili.com/xlive/web-room/v1/index/getInfoByRoom?room_id=" + roomId);
+ }
+ public static String getLiveTitle(int roomId){
+ JSONObject json=getLiveInfo(roomId);
+ if(json!=null){
+ return json.getJSONObject("data").getJSONObject("room_info").getString("title");
+ }
+ return null;
+ }
public static boolean isLivePlayer(int roomId) {
- JSONObject json = http_get("https://api.live.bilibili.com/xlive/web-room/v1/index/getInfoByRoom?room_id=" + roomId);
+ JSONObject json =getLiveInfo(roomId);
if (json == null)
return false;
BilibiliUpInfo upData = new BilibiliUpInfo();
diff --git a/src/main/java/com/yutou/bilibili/BiliBili/Tools/SaveLive.java b/src/main/java/com/yutou/bilibili/BiliBili/Tools/SaveLive.java
index b04b5eb..8054fdf 100644
--- a/src/main/java/com/yutou/bilibili/BiliBili/Tools/SaveLive.java
+++ b/src/main/java/com/yutou/bilibili/BiliBili/Tools/SaveLive.java
@@ -3,6 +3,7 @@ package com.yutou.bilibili.BiliBili.Tools;
import com.alibaba.fastjson.JSONObject;
import com.yutou.bilibili.BiliBili.Live;
import com.yutou.bilibili.BiliBili.LiveUtils;
+import com.yutou.bilibili.QQBot.QQBotManager;
import com.yutou.bilibili.Tools.AppTools;
import com.yutou.bilibili.Tools.HttpTools;
@@ -14,9 +15,9 @@ import java.util.*;
public class SaveLive {
private static SaveLive live;
- private List saveList = new ArrayList<>();
- private Map downloads = new HashMap<>();
- private Map heartbeats=new HashMap<>();
+ private final List saveList = new ArrayList<>();
+ private final Map downloads = new HashMap<>();
+ private final Map heartbeats = new HashMap<>();
public static void main(String[] args) {
SaveLive.getInstance().addLive(3715397);
@@ -35,7 +36,11 @@ public class SaveLive {
public void addLive(Live live) {
addLive(live.geData().getRoomid());
}
-
+ public void startLive(int roomId){
+ saveList.add(roomId + "");
+ start(roomId);
+ QQBotManager.getInstance().sendMessage(roomId+" 已启动录制");
+ }
public void addLive(int roomId) {
if (saveList.contains(roomId + "")) {
return;
@@ -45,11 +50,15 @@ public class SaveLive {
}
saveList.add(roomId + "");
start(roomId);
+ QQBotManager.getInstance().sendMessage(roomId+" 已启动录制");
}
public boolean checkLive(int roomId) {
return saveList.contains(roomId + "");
}
+ public File getLiveFile(int roomId){
+ return downloads.get(roomId).liveFile;
+ }
private long timer = 0;
@@ -57,12 +66,12 @@ public class SaveLive {
com.yutou.bilibili.Tools.Log.i("t停止录播:" + roomId + " time=" + (System.currentTimeMillis() - timer));
saveList.remove(roomId + "");
- if(downloads.containsKey(roomId)){
- downloads.get(roomId).isSave=false;
+ if (downloads.containsKey(roomId)) {
+ downloads.get(roomId).isSave = false;
downloads.remove(roomId);
}
- if(heartbeats.containsKey(roomId)){
+ if (heartbeats.containsKey(roomId)) {
heartbeats.get(roomId).cancel();
heartbeats.remove(roomId);
}
@@ -72,7 +81,7 @@ public class SaveLive {
private void start(int roomId) {
timer = System.currentTimeMillis();
DownloadThread thread = new DownloadThread(roomId);
- downloads.put(roomId,thread);
+ downloads.put(roomId, thread);
}
@@ -84,6 +93,7 @@ public class SaveLive {
int roomId = 0;
boolean isSave = true;
Timer heartbeat;
+ File liveFile;
public DownloadThread(int roomId) {
this.roomId = roomId;
@@ -112,20 +122,20 @@ public class SaveLive {
heartbeat = new Timer();
//Heartbeat beat = new Heartbeat();
heartbeat.schedule(new Heartbeat(), 0, 30000);
- heartbeats.put(roomId,heartbeat);
+ heartbeats.put(roomId, heartbeat);
//heartbeats.add(beat);
InputStream inputStream = connection.getInputStream();
- File file = new File(String.format("live%s%s%s[%s]%d.mp4",
+ liveFile = new File(String.format("live%s%s%s[%s]%d.mp4",
File.separator,
AppTools.getToDayTime(),
File.separator,
AppTools.getToDayNowTimeToString().replace(":", ""),
roomId));
- if (!file.exists()) {
- file.mkdirs();
- file.delete();
+ if (!liveFile.exists()) {
+ liveFile.mkdirs();
+ liveFile.delete();
}
- FileOutputStream outputStream = new FileOutputStream(file);
+ FileOutputStream outputStream = new FileOutputStream(liveFile);
int len;
byte[] bytes = new byte[1024];
while ((len = inputStream.read(bytes)) != -1 && isSave) {
@@ -134,16 +144,17 @@ public class SaveLive {
}
outputStream.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);
} catch (Exception e) {
e.printStackTrace();
- } finally {
- SaveLive.this.stop(roomId);
}
+ SaveLive.this.stop(roomId);
}
+
private class Heartbeat extends TimerTask {
- int nextInterval=1;
+ int nextInterval = 1;
+
@Override
public void run() {
try {
@@ -151,16 +162,16 @@ public class SaveLive {
JSONObject userHear = new JSONObject();
JSONObject cookie = JSONObject.parseObject(LiveUtils.getFile("cookies.json"));
hearBeat = LiveUtils.http_get("https://api.live.bilibili.com/relation/v1/Feed/heartBeat");
- com.yutou.bilibili.Tools.Log.i(hearBeat+" \t");
- hearBeat = LiveUtils.http_get(String.format("https://live-trace.bilibili.com/xlive/rdata-interface/v1/heartbeat/webHeartBeat?hb=%s&pf=web", URLEncoder.encode(new String(Base64.getEncoder().encode(String.format("%d|%d|1|0",nextInterval, roomId).getBytes(StandardCharsets.UTF_8))), "UTF-8")));
- com.yutou.bilibili.Tools.Log.i(hearBeat+"\t");
- nextInterval=hearBeat.getJSONObject("data").getInteger("next_interval");
- com.yutou.bilibili.Tools.Log.i("next = "+nextInterval);
- userHear.put("csrf_token",cookie.getString("bili_jct"));
- userHear.put("csrf",cookie.getString("bili_jct"));
- userHear.put("visit_id","");
- hearBeat=LiveUtils.http_post("https://api.live.bilibili.com/User/userOnlineHeart", HttpTools.toUrlParams(userHear));
- com.yutou.bilibili.Tools.Log.i("["+AppTools.getToDayNowTimeToString()+"]"+hearBeat);
+ com.yutou.bilibili.Tools.Log.i(hearBeat + " \t");
+ hearBeat = LiveUtils.http_get(String.format("https://live-trace.bilibili.com/xlive/rdata-interface/v1/heartbeat/webHeartBeat?hb=%s&pf=web", URLEncoder.encode(new String(Base64.getEncoder().encode(String.format("%d|%d|1|0", nextInterval, roomId).getBytes(StandardCharsets.UTF_8))), "UTF-8")));
+ com.yutou.bilibili.Tools.Log.i(hearBeat + "\t");
+ nextInterval = hearBeat.getJSONObject("data").getInteger("next_interval");
+ com.yutou.bilibili.Tools.Log.i("next = " + nextInterval);
+ userHear.put("csrf_token", cookie.getString("bili_jct"));
+ userHear.put("csrf", cookie.getString("bili_jct"));
+ userHear.put("visit_id", "");
+ hearBeat = LiveUtils.http_post("https://api.live.bilibili.com/User/userOnlineHeart", HttpTools.toUrlParams(userHear));
+ com.yutou.bilibili.Tools.Log.i("[" + AppTools.getToDayNowTimeToString() + "]" + hearBeat);
} catch (Exception e) {
e.printStackTrace();
}
diff --git a/src/main/java/com/yutou/bilibili/BilibiliApplication.java b/src/main/java/com/yutou/bilibili/BilibiliApplication.java
index d8d6587..639fd3f 100644
--- a/src/main/java/com/yutou/bilibili/BilibiliApplication.java
+++ b/src/main/java/com/yutou/bilibili/BilibiliApplication.java
@@ -2,18 +2,22 @@ package com.yutou.bilibili;
import com.yutou.bilibili.BiliBili.Live;
import com.yutou.bilibili.BiliBili.Tools.LiveT;
+import com.yutou.bilibili.QQBot.QQBotManager;
import com.yutou.bilibili.Tools.ExcelUtils;
import com.yutou.bilibili.Tools.ServiceTools;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Import;
-@Import({Live.class,ServiceTools.class, ExcelUtils.class})
+@Import({Live.class,ServiceTools.class, ExcelUtils.class, QQBotManager.class})
@SpringBootApplication
public class BilibiliApplication {
+ public static String version="0.6";
+
public static void main(String[] args) {
SpringApplication.run(BilibiliApplication.class, args);
+ QQBotManager.getInstance().init();
}
}
diff --git a/src/main/java/com/yutou/bilibili/QQBot/QQBotManager.java b/src/main/java/com/yutou/bilibili/QQBot/QQBotManager.java
new file mode 100644
index 0000000..ca1d9b7
--- /dev/null
+++ b/src/main/java/com/yutou/bilibili/QQBot/QQBotManager.java
@@ -0,0 +1,404 @@
+package com.yutou.bilibili.QQBot;
+
+import com.alibaba.fastjson.JSONObject;
+import com.yutou.bilibili.BiliBili.Controllers.RealTimeDataController;
+import com.yutou.bilibili.BiliBili.Live;
+import com.yutou.bilibili.BiliBili.LiveUtils;
+import com.yutou.bilibili.BiliBili.Tools.SaveLive;
+import com.yutou.bilibili.BilibiliApplication;
+import com.yutou.bilibili.Tools.AppTools;
+import com.yutou.bilibili.Tools.HttpTools;
+import com.yutou.bilibili.Tools.Log;
+import com.yutou.bilibili.Tools.Tools;
+import com.yutou.bilibili.interfaces.DownloadInterface;
+import com.yutou.bilibili.mybatis.Bili.mybatis.model.BilibiliUpInfo;
+import net.mamoe.mirai.Bot;
+import net.mamoe.mirai.BotFactory;
+import net.mamoe.mirai.event.GlobalEventChannel;
+import net.mamoe.mirai.event.events.GroupMessageEvent;
+import net.mamoe.mirai.message.data.Image;
+import net.mamoe.mirai.message.data.MessageChainBuilder;
+import net.mamoe.mirai.utils.BotConfiguration;
+import net.mamoe.mirai.utils.ExternalResource;
+import org.springframework.beans.BeansException;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+
+import javax.annotation.Resource;
+import java.io.File;
+import java.lang.reflect.Field;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Objects;
+import java.util.function.Consumer;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class QQBotManager implements ApplicationContextAware {
+ private static ApplicationContext applicationContext;
+
+ @Override
+ public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
+ if (QQBotManager.applicationContext == null)
+ QQBotManager.applicationContext = applicationContext;
+ }
+
+ private T getBean(Class tClass) {
+ return applicationContext.getBean(tClass);
+ }
+
+ private static class QQCommands {
+ private final static String QQ_HELP = "!help";
+ private final static String QQ_GET_IP = "!ip";
+ private final static String QQ_GET_VERSION = "!version";
+ private final static String QQ_LIVE_LIST = "!直播列表";
+ private final static String QQ_LIVE_SAVE = "!录播列表";
+ private final static String QQ_LIVE_TO_DAY_DATE = "!今日数据";
+ private final static String QQ_LIVE_DATE = "!数据";
+ private final static String QQ_LIVE_USE_SAVE = "!启动录播";
+ }
+
+ private static QQBotManager botManager = null;
+ private Bot bot;
+ private static final long qqGroup = 891655174L;
+ private boolean isLogin = false;
+ private static boolean isInit = false;
+ private static final boolean debug = true;
+
+ @Resource
+ RealTimeDataController realTimeDataController;
+
+
+ private QQBotManager() {
+
+ }
+
+ public void init() {
+ new Thread(new Runnable() {
+ @Override
+ public void run() {
+ long qq = 3620756944L;
+ String password = "UAs6YBYMyxJU";
+ System.out.println("调用机器人");
+ bot = BotFactory.INSTANCE.newBot(qq, password, new BotConfiguration() {
+ {
+ setProtocol(MiraiProtocol.ANDROID_PAD);
+ fileBasedDeviceInfo("qq_bot_devices_info.json");
+ if (debug) {
+ noBotLog();
+ noNetworkLog();
+ }
+ }
+ });
+ //Events.registerEvents(bot, new MessageListener());
+ GlobalEventChannel.INSTANCE.subscribeAlways(GroupMessageEvent.class, new MessageListener());
+ System.out.println("准备登陆");
+ bot.login();
+ System.out.println("登陆成功");
+ isLogin = true;
+ isInit = true;
+ new Thread(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ String str = sendMessage("姬妻酱上线拉~");
+ Log.i(str);
+
+ }
+ }).start();
+ bot.join();
+
+ }
+ }).start();
+
+ }
+
+ public static QQBotManager getInstance() {
+ if (botManager == null && !isInit) {
+ botManager = new QQBotManager();
+ }
+ return botManager;
+ }
+
+ public boolean isLogin() {
+ return isLogin;
+ }
+
+ private Image getImage(File file) {
+ if (bot != null) {
+ return Objects.requireNonNull(bot.getGroup(qqGroup)).uploadImage(ExternalResource.create(file));
+ }
+ return null;
+ }
+
+ private String getNotLoginQQ() {
+ return "没有登录QQ";
+ }
+
+
+ public String sendMessage(String text) {
+ if (bot != null) {
+ try {
+ return Objects.requireNonNull(bot.getGroup(qqGroup)).sendMessage(text).toString();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ return getNotLoginQQ();
+ }
+
+ public String sendMessage(Long group, String text) {
+ if (bot != null) {
+ try {
+ return Objects.requireNonNull(bot.getGroup(group)).sendMessage(text).toString();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ return getNotLoginQQ();
+ }
+
+ public void sendMessage(Long group, MessageChainBuilder builder) {
+ if (bot != null) {
+ Objects.requireNonNull(bot.getGroup(group)).sendMessage(builder.asMessageChain());
+ }
+ }
+
+
+ public String sendMessage(File imageFile, String text) {
+ try {
+ if (bot != null) {
+ Image image = getImage(imageFile);
+ MessageChainBuilder builder = new MessageChainBuilder();
+ if (image != null) {
+ builder.append(image);
+ }
+ builder.append(text);
+ return Objects.requireNonNull(bot.getGroup(qqGroup)).sendMessage(builder.asMessageChain()).toString();
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ return getNotLoginQQ();
+ }
+
+ public String sendMessage(List imgs, String text) {
+ if (bot != null) {
+ MessageChainBuilder builder = new MessageChainBuilder();
+ for (File img : imgs) {
+ builder.append(Objects.requireNonNull(getImage(img)));
+ }
+ builder.append(text);
+ return Objects.requireNonNull(bot.getGroup(qqGroup)).sendMessage(builder.asMessageChain()).toString();
+ }
+ return getNotLoginQQ();
+ }
+
+ private static List getImages(String str) {
+ List list = new ArrayList<>();
+ String regex = "
";
+ Pattern pattern = Pattern.compile(regex);
+ Matcher matcher = pattern.matcher(str);
+ while (matcher.find()) {
+ list.add(matcher.group().replace("
", "")
+ .trim());
+ }
+ return list;
+ }
+
+ public static void main(String[] args) {
+ getInstance();
+ }
+
+ private static class MessageListener implements Consumer {
+
+
+ @Override
+ public void accept(GroupMessageEvent event) {
+ String msg = event.getMessage().contentToString();
+ switch (event.getGroup().getId() + "") {
+ case qqGroup + "":
+ myGroup(msg);
+
+ }
+ }
+
+ private void myGroup(String msg) {
+ msg = msg.replace("!", "!").toLowerCase();
+ StringBuilder builder = new StringBuilder();
+ JSONObject json;
+ String[] cmd = new String[0];
+ int _roomId = 0;
+ switch (msg) {
+ case QQCommands.QQ_GET_IP:
+ json = JSONObject.parseObject(HttpTools.get("https://api.asilu.com/ip/"));
+ String ip = json.getString("ip");
+ getInstance().sendMessage("服务器IP:" + ip);
+ break;
+ case QQCommands.QQ_GET_VERSION:
+ sendVersion();
+ break;
+ case QQCommands.QQ_LIVE_LIST:
+ builder.append("当前正在记录数据的直播间:");
+ builder.append("\n");
+ for (Live live : Live.lives) {
+ JSONObject liveJson = LiveUtils.getLiveInfo(live.getInfo().getRoomid());
+ builder
+ .append("名字:").append(live.geData().getName()).append(" ")
+ .append(" roomId:").append(live.geData().getRoomid()).append(" ");
+ if (liveJson != null) {
+ builder.append("标题:").append(liveJson.getJSONObject("data").getJSONObject("room_info").getString("title")).append("\n");
+ } else {
+ builder.append("\n");
+ }
+ }
+ getInstance().sendMessage(builder.toString());
+ break;
+ case QQCommands.QQ_LIVE_SAVE:
+ builder.append("当前正在录制的直播间:");
+ builder.append("\n");
+ for (String roomId : SaveLive.getInstance().getLiveList()) {
+ BilibiliUpInfo data = new BilibiliUpInfo();
+ data.setRoomid(Integer.parseInt(roomId));
+ Live live = LiveUtils.liveContains(data);
+ if (live != null) {
+ File file = SaveLive.getInstance().getLiveFile(_roomId);
+ builder
+ .append("名字:").append(live.geData().getName()).append(" ")
+ .append("文件大小(字节):").append(file.length()).append(" ")
+ .append("roomId:").append(live.geData().getRoomid()).append("\n");
+ }
+
+ }
+ getInstance().sendMessage(builder.toString());
+ break;
+ case QQCommands.QQ_HELP:
+ for (Field field : QQCommands.class.getDeclaredFields()) {
+ try {
+ field.setAccessible(true);
+ builder.append(field.get(null)).append("\n");
+ } catch (IllegalAccessException e) {
+ e.printStackTrace();
+ }
+ }
+ getInstance().sendMessage(builder.toString());
+ break;
+ default:
+ if(msg.startsWith(QQCommands.QQ_LIVE_TO_DAY_DATE)){
+ try {
+ cmd = msg.split(" ");
+ _roomId = Integer.parseInt(cmd[1]);
+ QQBotManager.getInstance().sendMessage("请稍等,正在查询...");
+ sendGiftData(_roomId, null, null);
+ } catch (Exception e) {
+ getInstance().sendMessage("参数错误。\n使用方式: " + QQCommands.QQ_LIVE_TO_DAY_DATE + "+空格+roomId");
+ }
+ }else if(msg.startsWith(QQCommands.QQ_LIVE_DATE)){
+ try {
+ cmd = msg.split(" ");
+ _roomId = Integer.parseInt(cmd[1]);
+ Date startTime = new SimpleDateFormat("yyyy-MM-dd_HH:mm:ss").parse(cmd[2]);
+ Date endTime = new SimpleDateFormat("yyyy-MM-dd_HH:mm:ss").parse(cmd[3]);
+ QQBotManager.getInstance().sendMessage("请稍等,正在查询...");
+ sendGiftData(_roomId, startTime, endTime);
+ } catch (Exception e) {
+ getInstance().sendMessage("参数错误。" +
+ "\n使用方式: " + QQCommands.QQ_LIVE_DATE + "+空格+roomId+起始时间+空格+结束时间" +
+ "\n时间格式:年-月-日_时:分:秒 例:2021-4-1_12:00:00" +
+ "\n时分秒不可省略");
+ }
+ }else if(msg.startsWith(QQCommands.QQ_LIVE_USE_SAVE)){
+ try {
+ cmd = msg.split(" ");
+ _roomId = Integer.parseInt(cmd[1]);
+ if (SaveLive.getInstance().checkLive(_roomId)) {
+ SaveLive.getInstance().stop(_roomId);
+ }
+ SaveLive.getInstance().startLive(_roomId);
+ getInstance().sendMessage("已启动" + _roomId + "的录播");
+ } catch (Exception e) {
+ getInstance().sendMessage("参数错误。\n使用方式: " + QQCommands.QQ_LIVE_USE_SAVE + "+空格+roomId");
+ }
+ }
+ }
+ }
+
+ public void sendGiftData(int roomId, Date startTime, Date endTime) throws ParseException {
+ StringBuilder builder = new StringBuilder();
+ if (startTime == null) {
+ startTime = AppTools.getToDayStartTime();
+ }
+ if (endTime == null) {
+ endTime = AppTools.getToDayNowTime();
+ }
+ if (getInstance().realTimeDataController == null)
+ getInstance().realTimeDataController = getInstance().getBean(RealTimeDataController.class);
+ JSONObject json = getInstance().realTimeDataController.queryToDayLiveData(roomId, startTime, endTime);
+ System.out.println(json);
+ builder.append("当前人气:").append(json.getJSONObject("data").getInteger("popular")).append("\n");
+ builder.append("普通观众入场:").append(json.getJSONObject("data").getInteger("userLength")).append("\n");
+ builder.append("舰长入场:").append(json.getJSONObject("data").getInteger("vipLength")).append("\n");
+ int price = 0;
+ for (Object o : json.getJSONObject("data").getJSONArray("price")) {
+ price += ((JSONObject) o).getInteger("price");
+ }
+ builder.append("金瓜子:").append(price).append(" 抽成后:").append((price / 2) / 1000).append("¥").append("\n");
+ builder.append("礼物收益情况:").append("\n");
+ for (Object o : json.getJSONObject("data").getJSONArray("gift")) {
+ builder.append(((JSONObject) o).getString("giftName")).append(":").append(((JSONObject) o).getInteger("size")).append("\n");
+ }
+ getInstance().sendMessage(builder.toString());
+ }
+
+ private List files;
+ private int index = 0;
+
+ private void sendImagesMsg(List imgs, String text) {
+ files = new ArrayList<>();
+ index = 0;
+ if (imgs.size() == 0) {
+ getInstance().sendMessage(text);
+ return;
+ }
+ for (String img : imgs) {
+ Tools.download(img, new DownloadInterface() {
+ @Override
+ public void onDownload(File file) {
+ super.onDownload(file);
+ files.add(file);
+ send(imgs.size(), text);
+ }
+
+ @Override
+ public void onError(Exception e) {
+ super.onError(e);
+ index++;
+ send(imgs.size(), text);
+ }
+ });
+ }
+ }
+
+ private void send(int size, String text) {
+ if ((files.size() + index) == size) {
+ String str = getInstance().sendMessage(files, text);
+ Log.i("str = " + str);
+ }
+ }
+
+ private void sendVersion() {
+ String msg = "软件版本:" + BilibiliApplication.version;
+ QQBotManager.getInstance().sendMessage(msg);
+ }
+
+ }
+}
diff --git a/src/main/java/com/yutou/bilibili/Tools/Log.java b/src/main/java/com/yutou/bilibili/Tools/Log.java
index d1176c4..c838f49 100644
--- a/src/main/java/com/yutou/bilibili/Tools/Log.java
+++ b/src/main/java/com/yutou/bilibili/Tools/Log.java
@@ -2,10 +2,17 @@ package com.yutou.bilibili.Tools;
public class Log {
public static void i(Object log){
+ if(true)
+ return;
System.out.printf("[%s]%s%n",
AppTools.getToDayNowTimeToString(),
log
);
}
+ public static void e(Exception e){
+ if(true)
+ return;
+ e.printStackTrace();
+ }
}
diff --git a/src/main/java/com/yutou/bilibili/Tools/Tools.java b/src/main/java/com/yutou/bilibili/Tools/Tools.java
new file mode 100644
index 0000000..16eb299
--- /dev/null
+++ b/src/main/java/com/yutou/bilibili/Tools/Tools.java
@@ -0,0 +1,211 @@
+package com.yutou.bilibili.Tools;
+
+import com.alibaba.fastjson.JSONArray;
+import com.yutou.bilibili.interfaces.DownloadInterface;
+import org.springframework.core.io.FileSystemResource;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.util.StringUtils;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.*;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.net.URLDecoder;
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
+import java.security.MessageDigest;
+import java.text.SimpleDateFormat;
+import java.util.Base64;
+import java.util.Date;
+import java.util.Random;
+
+public class Tools {
+
+
+ /**
+ * 获取项目路径
+ *
+ * @param request
+ * @return
+ */
+ public static String getPath(HttpServletRequest request) {
+ return request.getServletContext().getRealPath("/") + "/";
+ }
+
+ /**
+ * 获取客户端IP
+ *
+ * @param request
+ * @return
+ */
+ public static String getRemoteAddress(HttpServletRequest request) {
+ String ip = request.getHeader("x-forwarded-for");
+ if (ip == null || ip.length() == 0 || ip.equalsIgnoreCase("unknown")) {
+ ip = request.getHeader("Proxy-Client-IP");
+ }
+ if (ip == null || ip.length() == 0 || ip.equalsIgnoreCase("unknown")) {
+ ip = request.getHeader("WL-Proxy-Client-IP");
+ }
+ if (ip == null || ip.length() == 0 || ip.equalsIgnoreCase("unknown")) {
+ ip = request.getRemoteAddr();
+ }
+ return ip;
+ }
+
+ /**
+ * N以内的不重复随机数
+ *
+ * @param min 最小值
+ * @param max 最大值
+ * @param n
+ * @return
+ */
+ public static int[] randomCommon(int min, int max, int n) {
+ int len = max - min + 1;
+ if (max < min || n > len) {
+ return new int[0];
+ }
+ // 初始化给定范围的待选数组
+ int[] source = new int[len];
+ for (int i = min; i < min + len; i++) {
+ source[i - min] = i;
+ }
+ int[] result = new int[n];
+ Random rd = new Random();
+ int index = 0;
+ for (int i = 0; i < result.length; i++) {
+ // 待选数组0到(len-2)随机一个下标
+ index = Math.abs(rd.nextInt() % len--);
+ // 将随机到的数放入结果集
+ result[i] = source[index];
+ // 将待选数组中被随机到的数,用待选数组(len-1)下标对应的数替换
+ source[index] = source[len];
+ }
+ return result;
+ }
+
+ public static void download(String url, DownloadInterface downloadInterface) {
+ try {
+ HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
+ connection.addRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.97 Safari/537.36");
+ connection.disconnect();
+ new File("tmp").mkdirs();
+ File file = new File("tmp" + File.separator + url.trim().split("/")[url.trim().split("/").length - 1]);
+ if (file.exists()) {
+ file.delete();
+ }
+ FileOutputStream outputStream = new FileOutputStream(file);
+ InputStream inputStream = connection.getInputStream();
+ byte[] bytes = new byte[4096];
+ int len;
+ while ((len = inputStream.read(bytes)) != -1) {
+ outputStream.write(bytes, 0, len);
+ outputStream.flush();
+ }
+ outputStream.close();
+ inputStream.close();
+ downloadInterface.onDownload(file);
+ } catch (IOException e) {
+ e.printStackTrace();
+ downloadInterface.onError(e);
+ }
+ }
+
+ /**
+ * 构造给前端的文件
+ *
+ * @param file 文件路径
+ * @return 前端获取的文件
+ */
+ public static ResponseEntity getFile(File file) {
+ HttpHeaders headers = new HttpHeaders();
+ headers.add("Cache-Control", "no-cache, no-store, must-revalidate");
+ try {
+ headers.add("Content-Disposition", "attachment; filename=" + URLEncoder.encode(file.getName(), "UTF-8"));
+ } catch (UnsupportedEncodingException e) {
+ headers.add("Content-Disposition", "attachment; filename=" + file.getName());
+ }
+ headers.add("Pragma", "no-cache");
+ headers.add("Expires", "0");
+ headers.add("Last-Modified", new Date().toString());
+ headers.add("ETag", String.valueOf(System.currentTimeMillis()));
+ return ResponseEntity.ok().headers(headers).contentLength(file.length()).contentType(MediaType.parseMediaType("application/octet-stream")).body(new FileSystemResource(file));
+ }
+
+ public static String getFileMD5(File file) {
+ if (!file.isFile()) {
+ return null;
+ }
+ MessageDigest digest = null;
+ FileInputStream in = null;
+ byte buffer[] = new byte[1024];
+ int len;
+ try {
+ digest = MessageDigest.getInstance("MD5");
+ in = new FileInputStream(file);
+ while ((len = in.read(buffer, 0, 1024)) != -1) {
+ digest.update(buffer, 0, len);
+ }
+ in.close();
+ } catch (Exception e) {
+ e.printStackTrace();
+ return null;
+ }
+ return bytesToHexString(digest.digest());
+ }
+
+ private static String bytesToHexString(byte[] src) {
+ StringBuilder stringBuilder = new StringBuilder("");
+ if (src == null || src.length <= 0) {
+ return null;
+ }
+ for (byte aSrc : src) {
+ int v = aSrc & 0xFF;
+ String hv = Integer.toHexString(v);
+ if (hv.length() < 2) {
+ stringBuilder.append(0);
+ }
+ stringBuilder.append(hv);
+ }
+ return stringBuilder.toString();
+ }
+
+ public static String base64ToString(String base) {
+ base = base.replace(" ", "+");
+ try {
+ base = new String(Base64.getDecoder().decode(base.replace("\r\n", "").getBytes()));
+ } catch (Exception e) {
+ try {
+ base = URLDecoder.decode(base, "UTF-8");
+ base = base.replace(" ", "+");
+ base = new String(Base64.getDecoder().decode(base.replace("\r\n", "").getBytes()));
+ } catch (Exception e1) {
+ e1.printStackTrace();
+ }
+ }
+ return base;
+ }
+
+ /**
+ * 异常输出
+ *
+ * @param e 异常
+ * @return
+ */
+ public static String getExceptionString(Exception e) {
+ StringWriter writer = new StringWriter();
+ PrintWriter printWriter = new PrintWriter(writer);
+ e.printStackTrace(printWriter);
+ printWriter.close();
+ return writer.toString();
+ }
+
+ public static String getToDayTime() {
+ return new SimpleDateFormat("yyyy-MM-dd").format(new Date());
+ }
+}
diff --git a/src/main/java/com/yutou/bilibili/interfaces/DownloadInterface.java b/src/main/java/com/yutou/bilibili/interfaces/DownloadInterface.java
index 0f65763..3cee5af 100644
--- a/src/main/java/com/yutou/bilibili/interfaces/DownloadInterface.java
+++ b/src/main/java/com/yutou/bilibili/interfaces/DownloadInterface.java
@@ -1,6 +1,9 @@
package com.yutou.bilibili.interfaces;
+import java.io.File;
+
public abstract class DownloadInterface {
- public void onDownload(String file){};
+ public void onDownloading(double soFarBytes, double totalBytes){};
+ public void onDownload(File file){};
public void onError(Exception e){};
}