新增机器人指令控制
This commit is contained in:
parent
ef0d7e5850
commit
ab6bfbfd42
33
pom.xml
33
pom.xml
@ -15,6 +15,7 @@
|
||||
<description>Demo project for Spring Boot</description>
|
||||
<properties>
|
||||
<java.version>1.8</java.version>
|
||||
<kotlin.version>1.4.10</kotlin.version>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
@ -102,10 +103,42 @@
|
||||
<artifactId>poi-ooxml-schemas</artifactId>
|
||||
<version>3.17</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>net.mamoe</groupId>
|
||||
<artifactId>mirai-core-jvm</artifactId>
|
||||
<version>2.5.0</version> <!-- 替换版本为你需要的版本 -->
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jetbrains.kotlin</groupId>
|
||||
<artifactId>kotlin-stdlib</artifactId>
|
||||
<version>${kotlin.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.jetbrains.kotlin</groupId>
|
||||
<artifactId>kotlin-maven-plugin</artifactId>
|
||||
<version>${kotlin.version}</version>
|
||||
|
||||
<executions>
|
||||
<execution>
|
||||
<id>compile</id>
|
||||
<goals>
|
||||
<goal>compile</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
|
||||
<execution>
|
||||
<id>test-compile</id>
|
||||
<goals>
|
||||
<goal>test-compile</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
@ -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());
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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<String> saveList = new ArrayList<>();
|
||||
private Map<Integer,DownloadThread> downloads = new HashMap<>();
|
||||
private Map<Integer,Timer> heartbeats=new HashMap<>();
|
||||
private final List<String> saveList = new ArrayList<>();
|
||||
private final Map<Integer, DownloadThread> downloads = new HashMap<>();
|
||||
private final Map<Integer, Timer> 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();
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
404
src/main/java/com/yutou/bilibili/QQBot/QQBotManager.java
Normal file
404
src/main/java/com/yutou/bilibili/QQBot/QQBotManager.java
Normal file
@ -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> T getBean(Class<T> 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<File> 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<String> getImages(String str) {
|
||||
List<String> list = new ArrayList<>();
|
||||
String regex = "<img(.*?)/img>";
|
||||
Pattern pattern = Pattern.compile(regex);
|
||||
Matcher matcher = pattern.matcher(str);
|
||||
while (matcher.find()) {
|
||||
list.add(matcher.group().replace("<img", "")
|
||||
.replace("/img>", "")
|
||||
.trim());
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
getInstance();
|
||||
}
|
||||
|
||||
private static class MessageListener implements Consumer<GroupMessageEvent> {
|
||||
|
||||
|
||||
@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<File> files;
|
||||
private int index = 0;
|
||||
|
||||
private void sendImagesMsg(List<String> 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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
211
src/main/java/com/yutou/bilibili/Tools/Tools.java
Normal file
211
src/main/java/com/yutou/bilibili/Tools/Tools.java
Normal file
@ -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<FileSystemResource> 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());
|
||||
}
|
||||
}
|
@ -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){};
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user