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){}; }