├── src
├── main
│ ├── resources
│ │ ├── RELEASE
│ │ ├── HYWenHei.85W.ttf
│ │ ├── abyss_star.png
│ │ ├── background.jpg
│ │ ├── abyss_background.jpg
│ │ ├── genshin.score.example.png
│ │ └── default.configuration
│ └── java
│ │ └── glous
│ │ └── kleebot
│ │ ├── annonations
│ │ └── Copy.java
│ │ ├── async
│ │ ├── BaseFunction.java
│ │ ├── Task.java
│ │ ├── AsyncTask.java
│ │ ├── AsyncTaskQueue.java
│ │ └── Timer.java
│ │ ├── web
│ │ ├── WebService.java
│ │ ├── Set.java
│ │ ├── impl
│ │ │ └── HardwareInfoWebService.java
│ │ ├── HttpClient.java
│ │ └── HttpServer.java
│ │ ├── commands
│ │ ├── ICommandExecutor.java
│ │ ├── impl
│ │ │ ├── BroadcastCommand.java
│ │ │ └── StopCommand.java
│ │ └── CommandRegistry.java
│ │ ├── services
│ │ ├── FriendService.java
│ │ ├── api
│ │ │ └── ArtifactScore.java
│ │ ├── Service.java
│ │ ├── impl
│ │ │ ├── GenshinArtifactScoreService.java
│ │ │ ├── MCPingService.java
│ │ │ ├── SyncService.java
│ │ │ ├── HelpService.java
│ │ │ ├── MCWikiSearchService.java
│ │ │ ├── GenshinAbyssService.java
│ │ │ ├── CoreService.java
│ │ │ ├── GenshinPlayerService.java
│ │ │ ├── BilibiliService.java
│ │ │ ├── PixivService.java
│ │ │ └── AutoPostService.java
│ │ ├── builtin
│ │ │ └── BilibiliVideoInf.java
│ │ ├── GroupService.java
│ │ └── ServiceRegistry.java
│ │ ├── http
│ │ ├── IWebService.java
│ │ ├── services
│ │ │ ├── HardwareInfoService.java
│ │ │ ├── StoreWhisperService.java
│ │ │ └── GetWhisperService.java
│ │ ├── ChromeInstance.java
│ │ ├── HttpTaskQueue.java
│ │ ├── HttpClient.java
│ │ └── proxy
│ │ │ └── GeneralTCPProxy.java
│ │ ├── GlobalVars.java
│ │ ├── plugin
│ │ └── Plugin.java
│ │ ├── utils
│ │ ├── builtin
│ │ │ └── HttpResponse.java
│ │ ├── StringUtils.java
│ │ ├── DigestUtils.java
│ │ ├── RandomUtils.java
│ │ ├── ZipUtils.java
│ │ ├── HttpUtils.java
│ │ └── FileUtils.java
│ │ ├── features
│ │ ├── builtin
│ │ │ ├── AbyssFloor.java
│ │ │ ├── MCWikiElement.java
│ │ │ ├── World.java
│ │ │ ├── Role.java
│ │ │ ├── MCServerMOTD.java
│ │ │ ├── MCPacket.java
│ │ │ ├── VariableInt.java
│ │ │ ├── AbyssInfo.java
│ │ │ └── PlayerInfo.java
│ │ ├── minecraft
│ │ │ ├── WikiAPI.java
│ │ │ └── PingAPI.java
│ │ ├── bilibili
│ │ │ └── BilibiliAPI.java
│ │ └── pixiv
│ │ │ └── PixivAPI.java
│ │ ├── config
│ │ ├── SingleLineCommentNode.java
│ │ └── ConfigNode.java
│ │ ├── cache
│ │ ├── Cache.java
│ │ └── CacheFactory.java
│ │ ├── References.java
│ │ ├── BotConfig.java
│ │ └── log
│ │ └── Logger.java
└── test
│ └── java
│ └── shandiankulishe
│ └── kleebot
│ └── tests
│ ├── APITest.java
│ ├── WebServiceTest.java
│ ├── ProxyTest.java
│ ├── TaskQueueTest.java
│ └── ConfigTest.java
├── gradle.properties
├── scripts
├── run.sh
└── run.bat
├── resourcePacks
├── Base.zip
├── Whisper.zip
└── BotStatus.zip
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── settings.gradle
├── native
└── HardwareInfo
│ ├── CMakeLists.txt
│ ├── include
│ ├── windows
│ │ └── jni_md.h
│ ├── glous_kleebot_services_api_HardwareInfo.h
│ └── linux
│ │ └── jni_md.h
│ └── HardwareInfo.cc
├── web
├── Base
│ ├── 404.html
│ ├── Error.html
│ └── index.html
├── BotStatus
│ ├── index.css
│ └── materialize
│ │ ├── LICENSE
│ │ └── README.md
└── Whisper
│ └── cryptWorker.js
├── .gitignore
├── README.md
├── .github
└── workflows
│ └── build.yml
├── gradlew.bat
└── gradlew
/src/main/resources/RELEASE:
--------------------------------------------------------------------------------
1 | v0.0.1
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | kotlin.code.style=official
2 | NAME=KleeBot
3 | VERSION=0.1
--------------------------------------------------------------------------------
/scripts/run.sh:
--------------------------------------------------------------------------------
1 | java -cp .:KleeBot.jar:./dependencies/* glous.kleebot.KleeBot
--------------------------------------------------------------------------------
/resourcePacks/Base.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/youfantan/KleeBot/HEAD/resourcePacks/Base.zip
--------------------------------------------------------------------------------
/resourcePacks/Whisper.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/youfantan/KleeBot/HEAD/resourcePacks/Whisper.zip
--------------------------------------------------------------------------------
/resourcePacks/BotStatus.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/youfantan/KleeBot/HEAD/resourcePacks/BotStatus.zip
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/youfantan/KleeBot/HEAD/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/src/main/resources/HYWenHei.85W.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/youfantan/KleeBot/HEAD/src/main/resources/HYWenHei.85W.ttf
--------------------------------------------------------------------------------
/src/main/resources/abyss_star.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/youfantan/KleeBot/HEAD/src/main/resources/abyss_star.png
--------------------------------------------------------------------------------
/src/main/resources/background.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/youfantan/KleeBot/HEAD/src/main/resources/background.jpg
--------------------------------------------------------------------------------
/src/main/resources/abyss_background.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/youfantan/KleeBot/HEAD/src/main/resources/abyss_background.jpg
--------------------------------------------------------------------------------
/src/main/resources/genshin.score.example.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/youfantan/KleeBot/HEAD/src/main/resources/genshin.score.example.png
--------------------------------------------------------------------------------
/src/main/java/glous/kleebot/annonations/Copy.java:
--------------------------------------------------------------------------------
1 | package glous.kleebot.annonations;
2 |
3 | public @interface Copy {
4 | String url();
5 | }
6 |
--------------------------------------------------------------------------------
/src/main/java/glous/kleebot/async/BaseFunction.java:
--------------------------------------------------------------------------------
1 | package glous.kleebot.async;
2 | @FunctionalInterface
3 | public interface BaseFunction {
4 | void execute() throws Exception;
5 | }
6 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | pluginManagement {
2 | repositories {
3 | maven { url "https://plugins.gradle.org/m2/" }
4 | gradlePluginPortal()
5 | }
6 | }
7 | rootProject.name = 'KleeBot'
8 |
--------------------------------------------------------------------------------
/src/main/java/glous/kleebot/web/WebService.java:
--------------------------------------------------------------------------------
1 | package glous.kleebot.web;
2 |
3 | public interface WebService {
4 | void initialize();
5 | void response(HttpClient client);
6 | void shut();
7 | }
8 |
--------------------------------------------------------------------------------
/native/HardwareInfo/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.16.3)
2 | project(HardwareInfo)
3 |
4 | set(CMAKE_CXX_STANDARD 14)
5 | include_directories(include)
6 | add_library(HardwareInfo SHARED HardwareInfo.cc)
7 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.3-bin.zip
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 |
--------------------------------------------------------------------------------
/src/main/java/glous/kleebot/commands/ICommandExecutor.java:
--------------------------------------------------------------------------------
1 | package glous.kleebot.commands;
2 |
3 | public interface ICommandExecutor {
4 | boolean process(String command);
5 | boolean execute(String command);
6 | void init();
7 | void stop();
8 | }
9 |
--------------------------------------------------------------------------------
/scripts/run.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 | java --add-opens java.base/java.lang=ALL-UNNAMED --add-opens java.base/java.nio=ALL-UNNAMED --add-opens java.base/jdk.internal.misc=ALL-UNNAMED -Dio.netty.tryReflectionSetAccessible=true -Dmirai.no-desktop -cp .;KleeBot.jar;./dependencies/* glous.kleebot.KleeBot
3 | pause
--------------------------------------------------------------------------------
/src/main/java/glous/kleebot/services/FriendService.java:
--------------------------------------------------------------------------------
1 | package glous.kleebot.services;
2 |
3 | import net.mamoe.mirai.event.events.FriendMessageEvent;
4 |
5 | public interface FriendService {
6 | boolean process(FriendMessageEvent event);
7 | void execute(FriendMessageEvent event);
8 | }
9 |
--------------------------------------------------------------------------------
/web/Base/404.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 404 Not Found
6 |
7 |
8 | Request Resource Not Found
9 | KleeBot Http Services | Copyright 2021-2022 shandiankulishe@gmail.com
10 |
11 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | build/
2 | .idea/
3 | .gradle/
4 | native/TesseractForASOCR/
5 | native/ArtifactsScore/
6 | native/TestTesseract
7 | native/HardwareInfo/cmake-build-debug/
8 | native/HardwareInfo/cmake-build-release/
9 | native/HardwareInfo/.idea
10 | Base/.idea
11 | BotStatus/.idea
12 | Whisper/.idea
13 | src/test/
--------------------------------------------------------------------------------
/src/main/java/glous/kleebot/http/IWebService.java:
--------------------------------------------------------------------------------
1 | package glous.kleebot.http;
2 |
3 | import java.io.IOException;
4 |
5 | public interface IWebService {
6 | boolean doGET(HttpClient client) throws IOException;
7 | boolean doPOST(HttpClient client) throws IOException;
8 | void init();
9 | void stop();
10 | }
11 |
--------------------------------------------------------------------------------
/web/Base/Error.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Request Error
6 |
7 |
8 | Error Request Method or Server Occurred an Exception
9 | KleeBot Http Services | Copyright 2021-2022 shandiankulishe@gmail.com
10 |
11 |
--------------------------------------------------------------------------------
/src/main/java/glous/kleebot/GlobalVars.java:
--------------------------------------------------------------------------------
1 | package glous.kleebot;
2 |
3 | import glous.kleebot.async.AsyncTaskQueue;
4 |
5 | public class GlobalVars {
6 | private static AsyncTaskQueue queue;
7 | public static AsyncTaskQueue getQueue() {
8 | return queue;
9 | }
10 | public static void setQueue(AsyncTaskQueue queue) {
11 | GlobalVars.queue = queue;
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/main/java/glous/kleebot/services/api/ArtifactScore.java:
--------------------------------------------------------------------------------
1 | package glous.kleebot.services.api;
2 |
3 | public class ArtifactScore {
4 | public static String ScoreFactory(String fileName){
5 | ArtifactScore score=new ArtifactScore();
6 | return score.getArtifactScore(fileName);
7 | }
8 | private ArtifactScore(){}
9 | private native String getArtifactScore(String fileName);
10 | }
11 |
--------------------------------------------------------------------------------
/web/Base/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | KleeBot Http Services
6 |
7 |
8 | KleeBot Http Services
9 | KleeBot is a QQ bot running on mirai Platform and open-licensed under MIT License.For more information please visit our github repository.
10 | KleeBot Http Services | Copyright 2021-2022 shandiankulishe@gmail.com
11 |
12 |
--------------------------------------------------------------------------------
/src/main/java/glous/kleebot/web/Set.java:
--------------------------------------------------------------------------------
1 | package glous.kleebot.web;
2 |
3 | public class Set {
4 | private String K;
5 | private String V;
6 | public Set(String K,String V){
7 | this.K=K;
8 | this.V=V;
9 | }
10 |
11 | public String getK() {
12 | return K;
13 | }
14 |
15 | public String getV() {
16 | return V;
17 | }
18 |
19 | public void setK(String k) {
20 | K = k;
21 | }
22 |
23 | public void setV(String v) {
24 | V = v;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/main/resources/default.configuration:
--------------------------------------------------------------------------------
1 | # Copyright 2022 shandiankulishe@gmail.com
2 | # github.com/youfantan/KleeBot
3 | # Opensource Under AGPL License
4 | ProxyHost: 127.0.0.1 # 设置代理IP
5 | ProxyPort: 7890 # 设置代理端口
6 | QueueSize: 64 # 设置最大并行任务数
7 | BotAccount: 114514 # 设置Bot账号
8 | BotPassword: passwd #设置Bot密码
9 | CacheDir: cache #设置缓存文件夹
10 | ServicePort: 80 #设置Http服务开放端口
11 | CookieFile: cookie.dat #设置米游社Cookie文件
12 | ResourcePackDir: pages #设置Http静态服务资源包路径
13 | ResourcePackFileDir: resourcePacks #设置Http静态服务资源包释放路径
14 | SilentMode: true #设置是否输出群内消息
15 | EnableDebug : false #设置是否启用调试模式
--------------------------------------------------------------------------------
/src/main/java/glous/kleebot/plugin/Plugin.java:
--------------------------------------------------------------------------------
1 | package glous.kleebot.plugin;
2 |
3 | import glous.kleebot.BotConfig;
4 | import glous.kleebot.config.Configuration;
5 | import glous.kleebot.http.HttpServer;
6 | import glous.kleebot.log.Logger;
7 |
8 | public abstract class Plugin {
9 | protected final Logger logger=Logger.getLogger(this.getClass());
10 | protected String name=this.getClass().getName();
11 | public void onInit(Configuration configuration, BotConfig config, HttpServer server){
12 | }
13 | public void onStop(Configuration configuration, BotConfig config){
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/web/BotStatus/index.css:
--------------------------------------------------------------------------------
1 | html{
2 | background-color: #212121;
3 | }
4 | .ubuntu-font{
5 | font-family: 'Ubuntu', sans-serif;
6 | }
7 | .modal_scroll {
8 | max-height: 378px;
9 | height: 378px;
10 | overflow-y: auto;
11 | }
12 | .modal_scroll::-webkit-scrollbar {
13 | width: 5px;
14 | height: 1px;
15 | }
16 | .modal_scroll::-webkit-scrollbar-thumb {
17 | border-radius: 5px;
18 | background: #212121;
19 | }
20 | .modal_scroll::-webkit-scrollbar-track {
21 | border-radius: 10px;
22 | background: #bdbdbd;
23 | }
24 | .link{
25 | font-family: 'Ubuntu', sans-serif;
26 | font-size: 30px;
27 | color: #424242;
28 | }
--------------------------------------------------------------------------------
/src/main/java/glous/kleebot/utils/builtin/HttpResponse.java:
--------------------------------------------------------------------------------
1 | package glous.kleebot.utils.builtin;
2 |
3 | public class HttpResponse {
4 | public byte[] getBody() {
5 | return body;
6 | }
7 |
8 | public void setBody(byte[] body) {
9 | this.body = body;
10 | }
11 |
12 | public int getResponseCode() {
13 | return responseCode;
14 | }
15 |
16 | public void setResponseCode(int responseCode) {
17 | this.responseCode = responseCode;
18 | }
19 |
20 | public HttpResponse(byte[] body, int responseCode) {
21 | this.body = body;
22 | this.responseCode = responseCode;
23 | }
24 | public HttpResponse(){}
25 |
26 | private byte[] body;
27 | private int responseCode;
28 | }
29 |
--------------------------------------------------------------------------------
/src/main/java/glous/kleebot/services/Service.java:
--------------------------------------------------------------------------------
1 | package glous.kleebot.services;
2 |
3 | import glous.kleebot.log.Logger;
4 |
5 | public abstract class Service {
6 | private static final int RULE_START_WITH=0;
7 | private static final int RULE_CONTAINS=1;
8 | private static final int RULE_END_WITH=2;
9 | private static final int RULE_REGEXP=-1;
10 | protected Logger logger=Logger.getLogger(this.getClass());
11 | public String getServiceName(){
12 | return this.getClass().getName();
13 | }
14 | public void initialize(){
15 | logger.info(this.getClass().getName()+" initialized by default");
16 | }
17 | public void stop(){
18 | logger.info(this.getClass().getName()+" stopped by default");
19 | }
20 | private void registerTriggerRules(int RULE,String matchStr){
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/main/java/glous/kleebot/web/impl/HardwareInfoWebService.java:
--------------------------------------------------------------------------------
1 | package glous.kleebot.web.impl;
2 |
3 | import glous.kleebot.services.api.HardwareInfo;
4 | import glous.kleebot.web.HttpClient;
5 | import glous.kleebot.web.WebService;
6 |
7 | import java.io.IOException;
8 |
9 | public class HardwareInfoWebService implements WebService {
10 | @Override
11 | public void initialize() {
12 |
13 | }
14 |
15 | @Override
16 | public void response(HttpClient client) {
17 | client.setHeader("Content-Type","application/json");
18 | client.setHeader("Access-Control-Allow-Origin","*");
19 | client.setResponseCode("200 OK");
20 | try {
21 | client.write(HardwareInfo.getInstance().getJsonFormattedInfo());
22 | client.finish();
23 | } catch (IOException e) {
24 | e.printStackTrace();
25 | }
26 | }
27 |
28 | @Override
29 | public void shut() {
30 |
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/main/java/glous/kleebot/features/builtin/AbyssFloor.java:
--------------------------------------------------------------------------------
1 | package glous.kleebot.features.builtin;
2 |
3 | import java.io.Serializable;
4 |
5 | public class AbyssFloor implements Serializable {
6 | public AbyssFloor(int index, int star, int max_star) {
7 | this.index = index;
8 | this.star = star;
9 | this.max_star = max_star;
10 | }
11 |
12 | public int getIndex() {
13 | return index;
14 | }
15 |
16 | public void setIndex(int index) {
17 | this.index = index;
18 | }
19 |
20 | public int getStar() {
21 | return star;
22 | }
23 |
24 | public void setStar(int star) {
25 | this.star = star;
26 | }
27 |
28 | public int getMax_star() {
29 | return max_star;
30 | }
31 |
32 | public void setMax_star(int max_star) {
33 | this.max_star = max_star;
34 | }
35 |
36 | private int index;
37 | private int star;
38 | private int max_star;
39 | }
40 |
--------------------------------------------------------------------------------
/src/main/java/glous/kleebot/features/builtin/MCWikiElement.java:
--------------------------------------------------------------------------------
1 | package glous.kleebot.features.builtin;
2 |
3 | public class MCWikiElement {
4 | public MCWikiElement(String description, String image, String url) {
5 | this.description = description;
6 | this.image = image;
7 | this.url = url;
8 | }
9 |
10 | public String getDescription() {
11 | return description;
12 | }
13 |
14 | public void setDescription(String description) {
15 | this.description = description;
16 | }
17 |
18 | public String getImage() {
19 | return image;
20 | }
21 |
22 | public void setImage(String image) {
23 | this.image = image;
24 | }
25 |
26 | public String getUrl() {
27 | return url;
28 | }
29 |
30 | public void setUrl(String url) {
31 | this.url = url;
32 | }
33 |
34 | private String description;
35 | private String image;
36 | private String url;
37 | }
38 |
--------------------------------------------------------------------------------
/src/main/java/glous/kleebot/commands/impl/BroadcastCommand.java:
--------------------------------------------------------------------------------
1 | package glous.kleebot.commands.impl;
2 |
3 | import glous.kleebot.KleeBot;
4 | import glous.kleebot.commands.ICommandExecutor;
5 | import net.mamoe.mirai.contact.Group;
6 |
7 | public class BroadcastCommand implements ICommandExecutor {
8 | @Override
9 | public boolean process(String command) {
10 | return command.startsWith("broadcast ");
11 | }
12 |
13 | @Override
14 | public boolean execute(String command) {
15 | String[] args=command.split(" ");
16 | if (args.length==2){
17 | String msg=args[1];
18 | for (Group g :
19 | KleeBot.botInstance.getGroups()) {
20 | g.sendMessage(msg);
21 | }
22 | return true;
23 | }
24 | return false;
25 | }
26 |
27 | @Override
28 | public void init() {
29 |
30 | }
31 |
32 | @Override
33 | public void stop() {
34 |
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/main/java/glous/kleebot/async/Task.java:
--------------------------------------------------------------------------------
1 | package glous.kleebot.async;
2 |
3 | import java.util.Objects;
4 |
5 | public class Task {
6 | @Override
7 | public boolean equals(Object o) {
8 | if (o instanceof Task task){
9 | return (task.getName().equals(this.name)) && (task.getFullName().equals(this.getFullName())) && (task.getFunc() == this.func);
10 | }
11 | return false;
12 | }
13 |
14 | @Override
15 | public int hashCode() {
16 | return Objects.hash(func, name);
17 | }
18 |
19 | public Task(BaseFunction func, String name) {
20 | this.func = func;
21 | this.name = name;
22 | }
23 |
24 | public BaseFunction getFunc() {
25 | return func;
26 | }
27 |
28 | public String getName() {
29 | return name;
30 | }
31 |
32 | private BaseFunction func;
33 | private String name;
34 | public String getFullName(){
35 | return name+"@"+ func.hashCode();
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/main/java/glous/kleebot/config/SingleLineCommentNode.java:
--------------------------------------------------------------------------------
1 | package glous.kleebot.config;
2 |
3 | public class SingleLineCommentNode extends ConfigNode{
4 | public SingleLineCommentNode(String key, Object value, String comment) {
5 | super(key, value, comment);
6 | }
7 |
8 | @Override
9 | public String getKey() {
10 | return "__SINGLE_LINE_COMMENT";
11 | }
12 |
13 | @Override
14 | public void setKey(String key) {
15 | }
16 |
17 | @Override
18 | public Object getValue() {
19 | return "__SINGLE_LINE_COMMENT";
20 | }
21 |
22 | @Override
23 | public void setValue(Object value) {
24 | }
25 |
26 | @Override
27 | public String getComment() {
28 | return super.getComment();
29 | }
30 |
31 | @Override
32 | public void setComment(String comment) {
33 | super.setComment(comment);
34 | }
35 |
36 | @Override
37 | public String toString() {
38 | return "# "+getComment();
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/main/java/glous/kleebot/http/services/HardwareInfoService.java:
--------------------------------------------------------------------------------
1 | package glous.kleebot.http.services;
2 |
3 | import glous.kleebot.services.api.HardwareInfo;
4 | import glous.kleebot.http.HttpClient;
5 | import glous.kleebot.http.IWebService;
6 |
7 | import java.io.IOException;
8 |
9 | public class HardwareInfoService implements IWebService {
10 | @Override
11 | public boolean doGET(HttpClient client) throws IOException{
12 | client.setHeader("Content-Type","application/json");
13 | client.setHeader("Access-Control-Allow-Origin","*");
14 | client.setResponseCode("200 OK");
15 | client.writeResponseBody(HardwareInfo.getInstance().getJsonFormattedInfo());
16 | client.finish();
17 | return true;
18 | }
19 |
20 | @Override
21 | public boolean doPOST(HttpClient client) {
22 | return false;
23 | }
24 |
25 | @Override
26 | public void init() {
27 |
28 | }
29 |
30 | @Override
31 | public void stop() {
32 |
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/main/java/glous/kleebot/features/builtin/World.java:
--------------------------------------------------------------------------------
1 | package glous.kleebot.features.builtin;
2 |
3 | import java.io.Serializable;
4 |
5 | public class World implements Serializable {
6 | public String getName() {
7 | return name;
8 | }
9 |
10 | public void setName(String name) {
11 | this.name = name;
12 | }
13 |
14 | public int getExploration_percentage() {
15 | return exploration_percentage;
16 | }
17 |
18 | public void setExploration_percentage(int exploration_percentage) {
19 | this.exploration_percentage = exploration_percentage;
20 | }
21 |
22 | public World(String name, int exploration_percentage) {
23 | this.name = name;
24 | this.exploration_percentage = exploration_percentage;
25 | }
26 |
27 | private String name;
28 |
29 | public String getIcon() {
30 | return icon;
31 | }
32 |
33 | public void setIcon(String icon) {
34 | this.icon = icon;
35 | }
36 |
37 | private String icon;
38 | private int exploration_percentage;
39 | }
40 |
--------------------------------------------------------------------------------
/web/Whisper/cryptWorker.js:
--------------------------------------------------------------------------------
1 | importScripts('./crypto-4.1.1-forked.js')
2 | const key='e348da05aa56fe0a';
3 | const iv='ea412a61f9cd59a4'
4 | const AESKey=CryptoJS.enc.Utf8.parse(key);
5 | const AESIV=CryptoJS.enc.Utf8.parse(iv)
6 | function AESEncrypt(src) {
7 | let AESSrc=CryptoJS.enc.Utf8.parse(src)
8 | let AESEncrypted=CryptoJS.AES.encrypt(AESSrc,AESKey,{
9 | iv:AESIV,
10 | mode:CryptoJS.mode.CBC,
11 | padding:CryptoJS.pad.Pkcs7
12 | })
13 | return AESEncrypted.ciphertext.toString();
14 | }
15 | function AESDecrypt(src){
16 | let AESHex=CryptoJS.enc.Hex.parse(src);
17 | let AESSrc=CryptoJS.enc.Base64.stringify(AESHex);
18 | let AESDecrypted=CryptoJS.AES.decrypt(AESSrc,AESKey,{
19 | iv:AESIV,
20 | mode:CryptoJS.mode.CBC,
21 | padding:CryptoJS.pad.Pkcs7
22 | });
23 | let StrDecrypted=CryptoJS.enc.Utf8.stringify(AESDecrypted)
24 | return StrDecrypted.toString();
25 | }
26 | self.addEventListener('message',function (msg) {
27 | let decrypted=AESDecrypt(msg.data)
28 | postMessage(decrypted)
29 | })
--------------------------------------------------------------------------------
/src/main/java/glous/kleebot/async/AsyncTask.java:
--------------------------------------------------------------------------------
1 | package glous.kleebot.async;
2 | import glous.kleebot.log.Logger;
3 |
4 | public class AsyncTask implements Runnable{
5 | private Logger logger= Logger.getLogger(AsyncTask.class);
6 | private int state=0;
7 | private Task task;
8 | public AsyncTask(Task task){
9 | this.state=AsyncTaskQueue.TASK_PROCESSING;
10 | this.task=task;
11 | }
12 |
13 | public String getTaskName(){
14 | if (state==AsyncTaskQueue.TASK_PROCESSING){
15 | return task.getFullName();
16 | }
17 | return null;
18 | }
19 |
20 | public int getTaskState() {
21 | return state;
22 | }
23 |
24 | @Override
25 | public void run() {
26 | logger.trace("Start to execute Task: %s".formatted(task.getFullName()));
27 | try {
28 | task.getFunc().execute();
29 | } catch (Exception e){
30 | e.printStackTrace();
31 | }
32 | logger.trace("Task :%s executed done".formatted(task.getFullName()));
33 | this.state=AsyncTaskQueue.TASK_FINISHED;
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # KleeBot
2 | ## 简介
3 | KleeBot是一个使用Java及C++混合编写的,适用于QQ的机器人。
4 | 机器人提供了如下功能:
5 | + Pixiv榜单查询/IllustId查询
6 | + Bilibili视频链接提取与解析
7 | + 原神角色信息查询(使用miHoYo Takumi API)
8 | + 原神深渊信息查询(使用miHoYo Takumi API)
9 | + Minecraft Wiki查询
10 | + 游戏版本更新推送(现支持Minecraft,采用MojiraAPI与VersionManifest.json)
11 | 同时,机器人附加了许多如加密图片(Whisper)、Bot状态查询等功能。
12 | 即将支持的功能:
13 | + 原神圣遗物评分(采用OpenCV+TesseractOCR)
14 | + 支持加载插件/热更新插件
15 | 机器人以Apache2.0协议开源。
16 |
17 | ### 轻量
18 | 所有组件都采用插件式设计,拓展及更新更加方便。每一个功能都被封装成API类,服务与功能分离。
19 | ### 高效率
20 | 机器人采用多线程队列的方案来处理消息,不使用时队列休眠,根据分配线程数可以异步执行多个任务(默认32个线程,可在配置文件中更改)。即将面世的圣遗物评分功能将采用分布式设计。
21 | ### 稳定
22 | 所有的功能均已通过单元测试。自项目立项至今已测试60余天。所有服务均在JVM平台运行,C++部分非常少。
23 |
24 | ## 构建与下载
25 | KleeBot使用Github Action作为其CI。项目使用Gradle与CMake构建工具,在Windows平台使用OpenJDK与MingwW64编译,在Linux平台使用OpenJDK与GCC编译。
26 | 我们暂未开放下载通道,预计将在2022年6月末上传release。请前往[KleeBot交流群](https://jq.qq.com/?_wv=1027&k=IaAvtYDB)获取内测版本。
27 |
28 | ## 支持我们
29 | 点击[此链接](https://afdian.net/@shandiankulishe)前往爱发电捐助我(所有捐助费用将用作升级服务器)。
30 |
31 | ## 文档
32 | 文档未完成。
33 |
34 | ## 链接
35 | 点击[此链接](https://jq.qq.com/?_wv=1027&k=IaAvtYDB)前往KleeBot交流群。
36 | 点击[此链接](https://kleebot.glous.xyz)前往KleeBot简介。
--------------------------------------------------------------------------------
/src/main/java/glous/kleebot/config/ConfigNode.java:
--------------------------------------------------------------------------------
1 | package glous.kleebot.config;
2 |
3 | public class ConfigNode {
4 | public ConfigNode(String key, Object value, String comment) {
5 | this.key = key;
6 | this.value = value;
7 | this.comment = comment;
8 | }
9 |
10 | public String getKey() {
11 | return key;
12 | }
13 |
14 | public void setKey(String key) {
15 | this.key = key;
16 | }
17 |
18 | public Object getValue() {
19 | return value;
20 | }
21 |
22 | public void setValue(Object value) {
23 | this.value = value;
24 | }
25 |
26 | public String getComment() {
27 | if (comment==null){
28 | return "";
29 | }
30 | return comment;
31 | }
32 |
33 | public void setComment(String comment) {
34 | this.comment = comment;
35 | }
36 |
37 | @Override
38 | public String toString() {
39 | return "Key : %s Value : %s(Type: %s) Comment: %s".formatted(key,value,value.getClass().getName(),comment);
40 | }
41 |
42 | private String key;
43 | private Object value;
44 | private String comment;
45 | }
46 |
--------------------------------------------------------------------------------
/web/BotStatus/materialize/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2014-2018 Materialize
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/src/main/java/glous/kleebot/utils/StringUtils.java:
--------------------------------------------------------------------------------
1 | package glous.kleebot.utils;
2 |
3 | import java.util.Vector;
4 | import java.util.regex.Matcher;
5 | import java.util.regex.Pattern;
6 |
7 | public class StringUtils {
8 | public static boolean isDigit(String str){
9 | Pattern pattern=Pattern.compile("^-?\\d+(\\.\\d+)?$");
10 | Matcher isNum=pattern.matcher(str);
11 | return isNum.matches();
12 | }
13 | public static String findDigit(String str){
14 | if (str==null){
15 | return null;
16 | }
17 | boolean haveDigit=false;
18 | Vector charvct=new Vector<>();
19 | for (char c:str.toCharArray()){
20 | if (Character.isDigit(c)){
21 | haveDigit=true;
22 | charvct.add(c);
23 | } else{
24 | if (haveDigit){
25 | break;
26 | }
27 | }
28 | }
29 | Character[] outChars=charvct.toArray(new Character[charvct.size()]);
30 | String outStr ="";
31 | for (char c :
32 | outChars) {
33 | outStr+=c;
34 | }
35 | return outStr;
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/test/java/shandiankulishe/kleebot/tests/APITest.java:
--------------------------------------------------------------------------------
1 | package shandiankulishe.kleebot.tests;
2 |
3 | import com.google.gson.*;
4 | import glous.kleebot.features.builtin.MCPacket;
5 | import glous.kleebot.features.builtin.VariableInt;
6 | import glous.kleebot.features.genshin.GenshinAPI;
7 | import glous.kleebot.features.minecraft.PingAPI;
8 | import org.junit.jupiter.api.Test;
9 | import glous.kleebot.features.bilibili.BilibiliAPI;
10 |
11 | import java.io.*;
12 | import java.net.Socket;
13 | import java.nio.charset.StandardCharsets;
14 |
15 | public class APITest {
16 | @Test
17 | public void testPingAPI() throws IOException {
18 | PingAPI api=new PingAPI("mc.hypixel.net",25565);
19 | api.ping();
20 | }
21 | @Test
22 | public void testBilibiliAPI() throws IOException {
23 | BilibiliAPI api=new BilibiliAPI();
24 | System.out.println(api.getShortUrl("https://space.bilibili.com/36700106/video"));
25 | System.out.println(api.getShortUrl("https://www.bilibili.com/video/BV1e44y147nb"));
26 | System.out.println(api.getShortUrl("https://t.bilibili.com/599449444500820929"));
27 | System.out.println(api.getShortUrl("https://kleebot.glous.xyz"));
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/main/java/glous/kleebot/features/builtin/Role.java:
--------------------------------------------------------------------------------
1 | package glous.kleebot.features.builtin;
2 |
3 | import java.io.Serializable;
4 |
5 | public class Role implements Serializable {
6 | public String getName() {
7 | return name;
8 | }
9 |
10 | public void setName(String name) {
11 | this.name = name;
12 | }
13 |
14 | public int getLevel() {
15 | return level;
16 | }
17 |
18 | public void setLevel(int level) {
19 | this.level = level;
20 | }
21 |
22 | public String getAvatar_image() {
23 | return avatar_image;
24 | }
25 |
26 | public void setAvatar_image(String avatar_image) {
27 | this.avatar_image=avatar_image;
28 | }
29 |
30 | public int getFetter() {
31 | return fetter;
32 | }
33 |
34 | public void setFetter(int fetter) {
35 | this.fetter = fetter;
36 | }
37 |
38 | public Role(String name, int level, String avatar_image, int fetter) {
39 | this.name = name;
40 | this.level = level;
41 | this.avatar_image = avatar_image;
42 | this.fetter = fetter;
43 | }
44 |
45 | private String name;
46 | private int level;
47 | private String avatar_image;
48 | private int fetter;
49 | }
50 |
--------------------------------------------------------------------------------
/src/main/java/glous/kleebot/services/impl/GenshinArtifactScoreService.java:
--------------------------------------------------------------------------------
1 | package glous.kleebot.services.impl;
2 |
3 | import net.mamoe.mirai.event.events.GroupMessageEvent;
4 | import net.mamoe.mirai.message.data.At;
5 | import glous.kleebot.KleeBot;
6 | import glous.kleebot.services.GroupService;
7 |
8 | public class GenshinArtifactScoreService extends GroupService {
9 | @Override
10 | public boolean process(GroupMessageEvent event) {
11 | return event.getMessage().serializeToMiraiCode().startsWith(new At(KleeBot.config.getBotAccount()).serializeToMiraiCode() + " gscore");
12 | }
13 |
14 | @Override
15 | public boolean execute(GroupMessageEvent event) {
16 | // MessageChain chain=event.getMessage();
17 | // Image image = (Image) chain.stream().filter(Image.class::isInstance).findFirst().orElse(null);
18 | // byte[] imageBuffer= FileUtils.download(Image.queryUrl(image));
19 | // String cacheName=CacheFactory.getCacheName();
20 | // FileUtils.writeFile("cache"+ File.separatorChar+cacheName+".jpg",imageBuffer);
21 | // event.getGroup().sendMessage("正在解析图片,根据服务器性能需要1-5秒不等");
22 | // event.getGroup().sendMessage(ArtifactScore.ScoreFactory("cache/"+cacheName+".jpg"));
23 | return false;
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/main/java/glous/kleebot/services/builtin/BilibiliVideoInf.java:
--------------------------------------------------------------------------------
1 | package glous.kleebot.services.builtin;
2 |
3 | import java.util.Base64;
4 |
5 | public class BilibiliVideoInf {
6 | public BilibiliVideoInf(byte[] cover, String title, String author, String url) {
7 | this.cover = Base64.getEncoder().encodeToString(cover);
8 | this.title = title;
9 | this.author = author;
10 | this.url = url;
11 | }
12 |
13 | public byte[] getCover() {
14 | return Base64.getDecoder().decode(cover);
15 | }
16 |
17 | public void setCover(byte[] cover) {
18 | this.cover = Base64.getEncoder().encodeToString(cover);
19 | }
20 |
21 | public String getTitle() {
22 | return title;
23 | }
24 |
25 | public void setTitle(String title) {
26 | this.title = title;
27 | }
28 |
29 | public String getAuthor() {
30 | return author;
31 | }
32 |
33 | public void setAuthor(String author) {
34 | this.author = author;
35 | }
36 |
37 | public String getUrl() {
38 | return url;
39 | }
40 |
41 | public void setUrl(String url) {
42 | this.url = url;
43 | }
44 |
45 | private String cover;
46 | private String title;
47 | private String author;
48 | private String url;
49 | }
50 |
--------------------------------------------------------------------------------
/src/main/java/glous/kleebot/utils/DigestUtils.java:
--------------------------------------------------------------------------------
1 | package glous.kleebot.utils;
2 |
3 | import org.bouncycastle.jce.provider.BouncyCastleProvider;
4 | import glous.kleebot.References;
5 |
6 | import javax.crypto.*;
7 | import javax.crypto.spec.IvParameterSpec;
8 | import javax.crypto.spec.SecretKeySpec;
9 | import java.nio.charset.StandardCharsets;
10 | import java.security.*;
11 |
12 | public class DigestUtils {
13 | //encrypted data as AES128 algorithm with CBC/PKCS#7
14 | public static byte[] AES128CBCPKCS7Encrypt(byte[] src){
15 | try {
16 | Security.addProvider(new BouncyCastleProvider());
17 | Cipher cipher=Cipher.getInstance("AES/CBC/PKCS7Padding");
18 | IvParameterSpec iv=new IvParameterSpec(References.WHISPER_KEY_IV.getBytes(StandardCharsets.UTF_8));
19 | SecretKey key=new SecretKeySpec(References.WHISPER_KEY_PASSWD.getBytes(StandardCharsets.UTF_8),"AES/CBC/PKCS7Padding");
20 | cipher.init(Cipher.ENCRYPT_MODE,key,iv);
21 | byte[] data=cipher.doFinal(src);
22 | return data;
23 | } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | InvalidAlgorithmParameterException | IllegalBlockSizeException | BadPaddingException e) {
24 | e.printStackTrace();
25 | return null;
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/main/java/glous/kleebot/http/ChromeInstance.java:
--------------------------------------------------------------------------------
1 | package glous.kleebot.http;
2 |
3 | import org.openqa.selenium.OutputType;
4 | import org.openqa.selenium.chrome.ChromeDriver;
5 | import org.openqa.selenium.chrome.ChromeOptions;
6 |
7 | import java.io.File;
8 |
9 | public class ChromeInstance {
10 | private static ChromeDriver instance;
11 | public static void initialize(){
12 | ChromeOptions options=new ChromeOptions();
13 | options.addArguments("--headless");
14 | options.addArguments("--disable-gpu");
15 | options.addArguments("--no-sandbox");
16 | options.addArguments("--disable-dev-shm-usage");
17 | options.addArguments("--window-size=2160,1380");
18 | instance=new ChromeDriver(options);
19 | instance.manage().window().maximize();
20 | }
21 | public static void stop(){
22 | if (instance!=null){
23 | instance.close();
24 | instance.quit();
25 | }
26 | }
27 | public static synchronized byte[] getScreenShot(String _url,int delay,long scroll) throws InterruptedException {
28 | instance.get(_url);
29 | Thread.sleep(delay);
30 | instance.executeScript("window.scrollTo(0,%d)".formatted(scroll));
31 | byte[] bytes=instance.getScreenshotAs(OutputType.BYTES);
32 | instance.get("about:blank");
33 | return bytes;
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/main/java/glous/kleebot/commands/CommandRegistry.java:
--------------------------------------------------------------------------------
1 | package glous.kleebot.commands;
2 |
3 | import glous.kleebot.log.Logger;
4 |
5 | import java.util.HashMap;
6 | import java.util.Map;
7 | import java.util.Scanner;
8 |
9 | public class CommandRegistry {
10 | private static HashMap commandMap=new HashMap<>();
11 | private static Logger logger= Logger.getLogger(CommandRegistry.class);
12 | public static void register(String name,ICommandExecutor executor){
13 | commandMap.put(name,executor);
14 | }
15 | public static void start(){
16 | new Thread(()->{
17 | Scanner scanner=new Scanner(System.in);
18 | while (scanner.hasNext()){
19 | String command=scanner.nextLine();
20 | for (Map.Entry e:
21 | commandMap.entrySet()) {
22 | if (e.getValue().process(command)){
23 | if (!e.getValue().execute(command)){
24 | logger.error("Command Executed Error: %s/%s".formatted(e.getKey(),e.getValue().getClass().getName()));
25 | }
26 | }
27 | }
28 | }
29 | }).start();
30 | }
31 | public static void stop(){
32 | for (ICommandExecutor executor :
33 | commandMap.values()) {
34 | executor.stop();
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/main/java/glous/kleebot/features/builtin/MCServerMOTD.java:
--------------------------------------------------------------------------------
1 | package glous.kleebot.features.builtin;
2 |
3 | public class MCServerMOTD {
4 |
5 | public String getDescription() {
6 | return description;
7 | }
8 |
9 | public void setDescription(String description) {
10 | this.description = description;
11 | }
12 |
13 | public int getProtocol() {
14 | return protocol;
15 | }
16 |
17 | public void setProtocol(int protocol) {
18 | this.protocol = protocol;
19 | }
20 |
21 | public String getName() {
22 | return name;
23 | }
24 |
25 | public void setName(String name) {
26 | this.name = name;
27 | }
28 |
29 | public int getMaxPlayer() {
30 | return maxPlayer;
31 | }
32 |
33 | public void setMaxPlayer(int maxPlayer) {
34 | this.maxPlayer = maxPlayer;
35 | }
36 |
37 | public int getOnlinePlayer() {
38 | return onlinePlayer;
39 | }
40 |
41 | public void setOnlinePlayer(int onlinePlayer) {
42 | this.onlinePlayer = onlinePlayer;
43 | }
44 |
45 | private String description;
46 | private int protocol;
47 | private String name;
48 | private int maxPlayer;
49 | private int onlinePlayer;
50 | private int status;
51 |
52 | public String getFavicon() {
53 | return favicon;
54 | }
55 |
56 | public void setFavicon(String favicon) {
57 | this.favicon = favicon;
58 | }
59 |
60 | private String favicon;
61 |
62 | public int getStatus() {
63 | return status;
64 | }
65 |
66 | public void setStatus(int status) {
67 | this.status = status;
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/src/main/java/glous/kleebot/services/GroupService.java:
--------------------------------------------------------------------------------
1 | package glous.kleebot.services;
2 |
3 | import glous.kleebot.KleeBot;
4 | import net.mamoe.mirai.event.events.GroupMessageEvent;
5 | import net.mamoe.mirai.message.data.At;
6 | import net.mamoe.mirai.message.data.MessageChainBuilder;
7 |
8 | public abstract class GroupService extends Service{
9 | public boolean process(GroupMessageEvent event){
10 | return false;
11 | }
12 | public boolean execute(GroupMessageEvent event) throws Exception{ return true; }
13 | private boolean atTrigger(String raw,String cond){
14 | return raw.startsWith(new At(KleeBot.config.getBotAccount())+cond);
15 | }
16 | private boolean containsTrigger(String raw,String cond){
17 | return raw.contains(cond);
18 | }
19 | private boolean anyCondition(boolean ...args){
20 | boolean cond=false;
21 | for (boolean arg :
22 | args) {
23 | if (arg) {
24 | cond=true;
25 | }
26 | }
27 | return cond;
28 | }
29 | private boolean allCondition(boolean ...args){
30 | boolean cond=true;
31 | for (boolean arg:
32 | args) {
33 | if (!arg) {
34 | cond=false;
35 | }
36 | }
37 | return cond;
38 | }
39 | public static void sendMessage(String msg, GroupMessageEvent event){
40 | MessageChainBuilder builder=new MessageChainBuilder();
41 | builder.append(new At(event.getSender().getId()));
42 | builder.append(" ");
43 | builder.append(msg);
44 | event.getGroup().sendMessage(builder.build());
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/main/java/glous/kleebot/commands/impl/StopCommand.java:
--------------------------------------------------------------------------------
1 | package glous.kleebot.commands.impl;
2 |
3 | import glous.kleebot.GlobalVars;
4 | import glous.kleebot.KleeBot;
5 | import glous.kleebot.cache.CacheFactory;
6 | import glous.kleebot.commands.CommandRegistry;
7 | import glous.kleebot.commands.ICommandExecutor;
8 | import glous.kleebot.http.ChromeInstance;
9 | import glous.kleebot.log.Logger;
10 | import glous.kleebot.plugin.Plugin;
11 | import glous.kleebot.services.ServiceRegistry;
12 |
13 | import java.io.IOException;
14 |
15 | public class StopCommand implements ICommandExecutor {
16 | @Override
17 | public boolean process(String command) {
18 | return command.equals("stop");
19 | }
20 |
21 | @Override
22 | public boolean execute(String command) {
23 | try {
24 | ServiceRegistry.stop();
25 | KleeBot.plugins.forEach((Plugin plg)->{
26 | plg.onStop(KleeBot.configurationInstance,KleeBot.config);
27 | });
28 | KleeBot.getServerInstance().stop();
29 | KleeBot.botInstance.close();
30 | GlobalVars.getQueue().stop();
31 | KleeBot.stop();
32 | CommandRegistry.stop();
33 | CacheFactory.serializeCaches();
34 | ChromeInstance.stop();
35 | KleeBot.configurationInstance.mergeClass(KleeBot.config);
36 | KleeBot.configurationInstance.saveToFile();
37 | Logger.stop();
38 | } catch (IOException e) {
39 | e.printStackTrace();
40 | }
41 | System.exit(0);
42 | return true;
43 | }
44 |
45 | @Override
46 | public void init() {
47 |
48 | }
49 |
50 | @Override
51 | public void stop() {
52 |
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/native/HardwareInfo/include/windows/jni_md.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 1996, 2020, Oracle and/or its affiliates. All rights reserved.
3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 | *
5 | * This code is free software; you can redistribute it and/or modify it
6 | * under the terms of the GNU General Public License version 2 only, as
7 | * published by the Free Software Foundation. Oracle designates this
8 | * particular file as subject to the "Classpath" exception as provided
9 | * by Oracle in the LICENSE file that accompanied this code.
10 | *
11 | * This code is distributed in the hope that it will be useful, but WITHOUT
12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 | * version 2 for more details (a copy is included in the LICENSE file that
15 | * accompanied this code).
16 | *
17 | * You should have received a copy of the GNU General Public License version
18 | * 2 along with this work; if not, write to the Free Software Foundation,
19 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 | *
21 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 | * or visit www.oracle.com if you need additional information or have any
23 | * questions.
24 | */
25 |
26 | #ifndef _JAVASOFT_JNI_MD_H_
27 | #define _JAVASOFT_JNI_MD_H_
28 |
29 | #ifndef JNIEXPORT
30 | #define JNIEXPORT __declspec(dllexport)
31 | #endif
32 | #define JNIIMPORT __declspec(dllimport)
33 | #define JNICALL __stdcall
34 |
35 | // 'long' is always 32 bit on windows so this matches what jdk expects
36 | typedef long jint;
37 | typedef __int64 jlong;
38 | typedef signed char jbyte;
39 |
40 | #endif /* !_JAVASOFT_JNI_MD_H_ */
41 |
--------------------------------------------------------------------------------
/src/main/java/glous/kleebot/utils/RandomUtils.java:
--------------------------------------------------------------------------------
1 | package glous.kleebot.utils;
2 |
3 | import java.util.*;
4 |
5 | public class RandomUtils {
6 | private static final String RANDOM_CHAR_LIST="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
7 | private static final Random random=new Random();
8 | public static char newRandomUpperCaseString(){
9 | return (char)(random.nextInt(26)+'A');
10 | }
11 | public static char newRandomLowerCaseString(){
12 | return (char)(random.nextInt(26)+'a');
13 | }
14 | public static char newRandomNumber(){
15 | return (char)(random.nextInt(10)+'0');
16 | }
17 | public static String newRandomNumberSeries(int length){
18 | StringBuilder builder=new StringBuilder();
19 | for (int i = 0; i < length; i++) {
20 | builder.append(newRandomNumber());
21 | }
22 | return builder.toString();
23 | }
24 | public static String newRandomUpperCaseCharSeries(int length){
25 | StringBuilder builder=new StringBuilder();
26 | for (int i = 0; i < length; i++) {
27 | builder.append(newRandomUpperCaseString());
28 | }
29 | return builder.toString();
30 | }
31 | public static String newRandomLowerCaseCharSeries(int length){
32 | StringBuilder builder=new StringBuilder();
33 | for (int i = 0; i < length; i++) {
34 | builder.append(newRandomLowerCaseString());
35 | }
36 | return builder.toString();
37 | }
38 | public static String newRandomMixedString(int length){
39 | StringBuilder builder=new StringBuilder();
40 | for (int i = 0; i < length; i++) {
41 | builder.append(RANDOM_CHAR_LIST.charAt(random.nextInt(62)));
42 | }
43 | return builder.toString();
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/test/java/shandiankulishe/kleebot/tests/WebServiceTest.java:
--------------------------------------------------------------------------------
1 | package shandiankulishe.kleebot.tests;
2 |
3 | import com.google.gson.Gson;
4 | import glous.kleebot.utils.FileUtils;
5 | import org.junit.jupiter.api.Test;
6 | import glous.kleebot.BotConfig;
7 | import glous.kleebot.GlobalVars;
8 | import glous.kleebot.KleeBot;
9 | import glous.kleebot.async.AsyncTaskQueue;
10 | import glous.kleebot.async.Timer;
11 | import glous.kleebot.http.HttpServer;
12 | import glous.kleebot.http.services.HardwareInfoService;
13 | import glous.kleebot.services.api.HardwareInfo;
14 | import org.xbill.DNS.*;
15 |
16 | import java.io.*;
17 | import java.net.*;
18 | import java.util.Base64;
19 | import java.util.Scanner;
20 |
21 | public class WebServiceTest {
22 | @Test
23 | public void TestHttpServer() throws InterruptedException, FileNotFoundException {
24 | System.load(new File("bin\\libHardwareInfo.dll").getAbsolutePath());
25 | AsyncTaskQueue queue=new AsyncTaskQueue(32);
26 | GlobalVars.setQueue(queue);
27 | new Thread(queue::start).start();
28 | Timer.start();
29 | HardwareInfo.init();
30 | KleeBot.config=new Gson().fromJson(new FileReader("kleebot.json"), BotConfig.class);
31 | HttpServer server=new HttpServer(KleeBot.config.getServicePort());
32 | server.register("BotStatus.zip");
33 | server.register("Base.zip");
34 | server.register("/services/getHardwareInfo",new HardwareInfoService());
35 | new Thread(()->{
36 | server.start();
37 | }).start();
38 | Thread.sleep(10000);
39 | System.exit(0);
40 | }
41 |
42 | public static void main(String[] args) throws IOException {
43 | Scanner sc=new Scanner(System.in);
44 | while (sc.hasNext()){
45 | System.out.println(sc.nextLine());
46 | }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/src/main/java/glous/kleebot/features/builtin/MCPacket.java:
--------------------------------------------------------------------------------
1 | package glous.kleebot.features.builtin;
2 |
3 | import org.bouncycastle.util.Pack;
4 |
5 | import java.io.ByteArrayOutputStream;
6 | import java.io.DataOutputStream;
7 | import java.io.IOException;
8 |
9 | public class MCPacket {
10 | private ByteArrayOutputStream out=new ByteArrayOutputStream();
11 | private DataOutputStream dOut=new DataOutputStream(out);
12 | int PacketID;
13 | public void writeInt(int i) throws IOException {
14 | dOut.writeInt(i);
15 | dOut.flush();
16 | }
17 | public void writeByte(byte b) throws IOException {
18 | dOut.writeByte(b);
19 | dOut.flush();
20 | }
21 | public void writeVarInt(VariableInt i) throws IOException {
22 | dOut.write(i.getBytes());
23 | dOut.flush();
24 | }
25 | public void writeVarInt(int i) throws IOException {
26 | dOut.write(new VariableInt(i).getBytes());
27 | dOut.flush();
28 | }
29 | public void writeBytes(byte[] bytes) throws IOException {
30 | dOut.write(bytes);
31 | dOut.flush();
32 | }
33 | public void writeShort(short s) throws IOException {
34 | dOut.writeShort(s);
35 | dOut.flush();
36 | }
37 | public void setPacketID(int b){
38 | this.PacketID=b;
39 | }
40 | public byte[] getPacket() throws IOException {
41 | ByteArrayOutputStream o=new ByteArrayOutputStream();
42 | o.write(new VariableInt(1+out.size()).getBytes());
43 | o.write(PacketID);
44 | o.write(out.toByteArray());
45 | o.flush();
46 | o.close();
47 | dOut.flush();
48 | dOut.close();
49 | return o.toByteArray();
50 | }
51 | public static MCPacket getRequestPacket() throws IOException {
52 | MCPacket packet=new MCPacket();
53 | packet.setPacketID(0x00);
54 | return packet;
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/src/main/java/glous/kleebot/http/services/StoreWhisperService.java:
--------------------------------------------------------------------------------
1 | package glous.kleebot.http.services;
2 |
3 | import com.google.gson.stream.JsonWriter;
4 | import glous.kleebot.http.HttpClient;
5 | import glous.kleebot.http.IWebService;
6 |
7 | import java.io.IOException;
8 | import java.io.StringWriter;
9 | import java.util.HashMap;
10 | import java.util.UUID;
11 |
12 | public class StoreWhisperService implements IWebService {
13 | public static HashMap dataMap=new HashMap<>();
14 | @Override
15 | public boolean doGET(HttpClient client) throws IOException {
16 | return false;
17 | }
18 |
19 | @Override
20 | public boolean doPOST(HttpClient client) throws IOException {
21 | String key= UUID.randomUUID().toString();
22 | client.setHeader("Access-Control-Allow-Origin","*");
23 | String encryptedData=client.getBody();
24 | StringWriter out=new StringWriter();
25 | JsonWriter writer=new JsonWriter(out);
26 | writer.beginObject();
27 | if (encryptedData.length()>1024*1024*20){
28 | writer.name("status").value("error");
29 | writer.name("message").value("max size limit of 10MB");
30 | writer.endArray();
31 | writer.flush();
32 | writer.close();
33 | client.writeResponseBody(out.toString());
34 | client.finish();
35 | return true;
36 | }
37 | dataMap.put(key,encryptedData);
38 | writer.name("status").value("ok");
39 | writer.name("message").value("successfully stored");
40 | writer.name("uuid").value(key);
41 | writer.endObject();
42 | writer.flush();
43 | writer.close();
44 | client.writeResponseBody(out.toString());
45 | client.finish();
46 | return true;
47 | }
48 |
49 | @Override
50 | public void init() {
51 |
52 | }
53 |
54 | @Override
55 | public void stop() {
56 |
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/src/main/java/glous/kleebot/cache/Cache.java:
--------------------------------------------------------------------------------
1 | package glous.kleebot.cache;
2 |
3 | import glous.kleebot.KleeBot;
4 | import java.io.*;
5 | import java.util.UUID;
6 |
7 | public class Cache implements Serializable {
8 | private byte[] content;
9 | private long expired;
10 | private long saveTime;
11 | private String cacheName;
12 | private String cachePath;
13 | public Cache(byte[] content,long expired){
14 | this.content=content;
15 | this.expired=expired;
16 | this.cacheName=UUID.randomUUID().toString();
17 | this.saveTime=System.currentTimeMillis();
18 | this.cachePath= KleeBot.config.getCacheDir() +File.separatorChar+cacheName;
19 | }
20 | public void store(){
21 | try {
22 | File cache=new File(cachePath);
23 | if (!cache.exists()){
24 | cache.createNewFile();
25 | }
26 | ObjectOutputStream out=new ObjectOutputStream(new FileOutputStream(cache));
27 | out.writeObject(this);
28 | out.flush();
29 | out.close();
30 | } catch (IOException e) {
31 | e.printStackTrace();
32 | }
33 | }
34 | public String getCacheName() {
35 | return cacheName;
36 | }
37 |
38 | public long getExpired() {
39 | return expired;
40 | }
41 |
42 | public long getSaveTime() {
43 | return saveTime;
44 | }
45 |
46 | public byte[] getContent() {
47 | return content;
48 | }
49 |
50 | public String getCachePath() {
51 | return cachePath;
52 | }
53 |
54 | public static Cache restore(String name){
55 | File cache=new File(name);
56 | try {
57 | ObjectInputStream in=new ObjectInputStream(new FileInputStream(cache));
58 | return (Cache) in.readObject();
59 | } catch (IOException | ClassNotFoundException e) {
60 | e.printStackTrace();
61 | return null;
62 | }
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/src/test/java/shandiankulishe/kleebot/tests/ProxyTest.java:
--------------------------------------------------------------------------------
1 | package shandiankulishe.kleebot.tests;
2 |
3 | import com.google.gson.Gson;
4 | import glous.kleebot.BotConfig;
5 | import glous.kleebot.KleeBot;
6 | import glous.kleebot.config.Configuration;
7 | import glous.kleebot.features.builtin.VariableInt;
8 | import glous.kleebot.http.proxy.GeneralTCPProxy;
9 | import glous.kleebot.log.Logger;
10 | import org.junit.jupiter.api.Test;
11 |
12 | import java.io.ByteArrayOutputStream;
13 | import java.io.FileInputStream;
14 | import java.io.FileReader;
15 | import java.io.IOException;
16 | import java.nio.charset.StandardCharsets;
17 | import java.util.Scanner;
18 |
19 | public class ProxyTest {
20 |
21 | @Test
22 | public void testVarInt() throws IOException {
23 | VariableInt vi=new VariableInt(724125);
24 | byte[] vBytes1=vi.getBytes();
25 | int i=vi.readBytes(vBytes1);
26 | byte[] vBytes2=vi.getBytes();
27 | }
28 |
29 | public static void main(String[] args) throws IOException {
30 | Scanner scanner=new Scanner(System.in);
31 |
32 | Configuration configuration=ConfigTest.getTestConfig();
33 | KleeBot.config=configuration.serializeToClass(BotConfig.class);
34 | Logger.init();
35 | GeneralTCPProxy proxy=new GeneralTCPProxy(2333,25565);
36 | new Thread(()->{
37 | while (scanner.hasNext()){
38 | String line=scanner.nextLine();
39 | if (line.equals("stop")){
40 | System.out.println("stopped");
41 | try {
42 | proxy.stop();
43 | } catch (IOException e) {
44 | e.printStackTrace();
45 | }
46 | scanner.close();
47 | Logger.stop();
48 | System.exit(0);
49 | break;
50 | }
51 | }
52 | }).start();
53 | proxy.start();
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/src/main/java/glous/kleebot/References.java:
--------------------------------------------------------------------------------
1 | package glous.kleebot;
2 |
3 | public class References {
4 | public static final String PIXIV_RANKING_DAILY="https://www.pixiv.net/ranking.php?format=json&mode=daily&p=1";
5 | public static final String PIXIV_RANKING_WEEKLY="https://www.pixiv.net/ranking.php?format=json&mode=weekly&p=1";
6 | public static final String PIXIV_RANKING_MONTHLY="https://www.pixiv.net/ranking.php?format=json&mode=monthly&p=1";
7 | public static final String PIXIV_ILLUST_API="https://www.pixiv.net/ajax/illust/%d";
8 | public static final String BILBILI_PLAYER_LIST_URL="https://api.bilibili.com/x/player/pagelist?bvid=%s";
9 | public static final String BILBILI_WEB_INTERFACE_BVID_URL ="https://api.bilibili.com/x/web-interface/view?cid=%s&bvid=%s";
10 | public static final String BILBILI_WEB_INTERFACE_AID_URL ="https://api.bilibili.com/x/web-interface/view?aid=%s";
11 | public static final String BILIBILI_SHORT_URL="https://api.bilibili.com/x/share/click";
12 | public static final String MIHOYO_GAME_RECORD_URL="https://api-takumi.mihoyo.com/game_record/app/genshin/api/index?role_id=%s&server=%s";
13 | public static final String MIHOYO_ABYSS_URL="https://api-takumi-record.mihoyo.com/game_record/app/genshin/api/spiralAbyss?schedule_type=%s&server=%s&role_id=%s";
14 | public static final String MIHOYO_NOTES_URL="https://api-takumi.mihoyo.com/game_record/app/genshin/api/dailyNote?role_id=%s&server=%s";
15 | public static final String MCWIKI_CN_URL="https://minecraft.fandom.com/zh/wiki";
16 | public static final String MCWIKI_EN_URL="https://minecraft.fandom.com/wiki";
17 | public static final String WHISPER_KEY_IV="ea412a61f9cd59a4";
18 | public static final String WHISPER_KEY_PASSWD="e348da05aa56fe0a";
19 | public static final String IP_SEARCH_URL="https://pv.sohu.com/cityjson?ie=utf-8";
20 | public static final String GLOUS_REVERSE_PROXY_PIXIV_IMAGE_URL="https://proxy.glous.xyz/image/";
21 | public static final String GLOUS_REVERSE_PROXY_GITHUB_URL="https://proxy.glous.xyz/gh/";
22 | }
23 |
--------------------------------------------------------------------------------
/src/main/java/glous/kleebot/http/HttpTaskQueue.java:
--------------------------------------------------------------------------------
1 | package glous.kleebot.http;
2 |
3 | import glous.kleebot.async.BaseFunction;
4 |
5 | import java.util.LinkedList;
6 |
7 | public class HttpTaskQueue {
8 | private final LinkedList tasks=new LinkedList<>();
9 | private Thread[] threads;
10 | private HttpServer server;
11 | public HttpTaskQueue(int size,HttpServer server) {
12 | this.size = size;
13 | this.server=server;
14 | this.threads=new Thread[size];
15 | }
16 | public void start(){
17 | new Thread(()->{
18 | while (server.RUNNING_FLAG){
19 | while (!tasks.isEmpty()){
20 | for (int i = 0; i < size; i++) {
21 | Thread t=threads[i];
22 | if ((t==null||!t.isAlive())){
23 | BaseFunction function;
24 | if ((function=tasks.pollFirst())!=null){
25 | threads[i]=new Thread(()->{
26 | try {
27 | function.execute();
28 | } catch (Exception e) {
29 | e.printStackTrace();
30 | }
31 | });
32 | threads[i].start();
33 | }
34 | break;
35 | }
36 | }
37 | }
38 | synchronized (this){
39 | try {
40 | wait();
41 | } catch (InterruptedException e) {
42 | e.printStackTrace();
43 | }
44 | }
45 | }
46 | }).start();
47 | }
48 | public synchronized void addTask(BaseFunction function){
49 | tasks.addLast(function);
50 | synchronized (this){
51 | notify();
52 | }
53 | }
54 |
55 | private int size;
56 | }
57 |
--------------------------------------------------------------------------------
/src/main/java/glous/kleebot/http/HttpClient.java:
--------------------------------------------------------------------------------
1 | package glous.kleebot.http;
2 |
3 | import java.io.ByteArrayOutputStream;
4 | import java.io.IOException;
5 | import java.io.OutputStream;
6 | import java.nio.charset.StandardCharsets;
7 | import java.util.HashMap;
8 |
9 | public class HttpClient {
10 | public HttpClient(String requestPath, String body, OutputStream output) {
11 | this.requestPath = requestPath;
12 | this.body = body;
13 | this.output = output;
14 | }
15 |
16 | public String getRequestPath() {
17 | return requestPath;
18 | }
19 |
20 | public String getBody() {
21 | return body;
22 | }
23 |
24 | private final String requestPath;
25 | private final String body;
26 | private final OutputStream output;
27 | private final ByteArrayOutputStream responseBody=new ByteArrayOutputStream();
28 | private String responseCode="200 OK";
29 | private final HashMap responseHeader=new HashMap<>();
30 | public void setHeader(String k,String v){
31 | responseHeader.put(k,v);
32 | }
33 | public void setResponseCode(String responseCode){
34 | this.responseCode=responseCode;
35 | }
36 | public void writeResponseBody(byte[] body){
37 | try {
38 | responseBody.write(body);
39 | } catch (IOException e) {
40 | e.printStackTrace();
41 | }
42 | }
43 | public void writeResponseBody(String body){
44 | writeResponseBody(body.getBytes(StandardCharsets.UTF_8));
45 | }
46 | public void finish() throws IOException {
47 | output.write(("HTTP/1.1 "+responseCode+"\n").getBytes(StandardCharsets.UTF_8));
48 | responseHeader.put("Content-Length",String.valueOf(responseBody.size()));
49 | for (String s:responseHeader.keySet()){
50 | output.write((s+": "+responseHeader.get(s)+"\n").getBytes(StandardCharsets.UTF_8));
51 | }
52 | output.write("\n".getBytes(StandardCharsets.UTF_8));
53 | responseBody.close();
54 | output.write(responseBody.toByteArray());
55 | output.flush();
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/src/test/java/shandiankulishe/kleebot/tests/TaskQueueTest.java:
--------------------------------------------------------------------------------
1 | package shandiankulishe.kleebot.tests;
2 |
3 | import org.junit.jupiter.api.Test;
4 | import glous.kleebot.async.AsyncTaskQueue;
5 | import glous.kleebot.services.api.HardwareInfo;
6 | import java.util.List;
7 |
8 | public class TaskQueueTest {
9 | synchronized void add(){
10 | flag++;
11 | }
12 | int flag=0;
13 | @Test
14 | public void testAsyncTaskQueue() {
15 | AsyncTaskQueue queue=new AsyncTaskQueue(64);
16 | for (int i=0;i<100;i++){
17 | queue.addTask(()->{
18 | add();
19 | try {
20 | Thread.sleep(100);
21 | } catch (InterruptedException e) {
22 | e.printStackTrace();
23 | }
24 | },"taskTest");
25 | }
26 | try {
27 | Thread.sleep(100);
28 | } catch (InterruptedException e) {
29 | e.printStackTrace();
30 | }
31 | System.out.println(flag);
32 | System.out.println("Current running tasks:");
33 | List names=queue.getAllRunningTasksName();
34 | for (int i = 0; i < names.size(); i++) {
35 | System.out.println(" "+i+". "+names.get(i));
36 | }
37 | System.out.println("ready to interrupt");
38 | queue.stop();
39 | }
40 | public static void TestGetInfo(){
41 | String info=
42 | """
43 | CPU Model: %s
44 | CPU Clock Cycle: %d MHZ
45 | CPU Usage: %.2f %%
46 | CPU Cores: %d
47 | Memory Total: %d
48 | Memory Available: %d
49 | ProcessID: %d
50 | """.formatted(HardwareInfo.getInstance().getCpuModelInfo(),HardwareInfo.getInstance().getCpuClockCycleInfo(),HardwareInfo.getInstance().getCpuUsageInfo()*100,HardwareInfo.getInstance().getCpuAvailableCoresInfo(),HardwareInfo.getInstance().getTotalMemoryInfo(),HardwareInfo.getInstance().getAvailableMemoryInfo(),HardwareInfo.getInstance().getProcessIDInfo());
51 | System.out.println(info);
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/src/test/java/shandiankulishe/kleebot/tests/ConfigTest.java:
--------------------------------------------------------------------------------
1 | package shandiankulishe.kleebot.tests;
2 |
3 | import glous.kleebot.config.ConfigNode;
4 | import org.junit.jupiter.api.Test;
5 | import glous.kleebot.BotConfig;
6 | import glous.kleebot.config.Configuration;
7 |
8 | import java.io.IOException;
9 | import java.util.Map;
10 |
11 | public class ConfigTest {
12 | public static Configuration getTestConfig() throws IOException {
13 | String defaultConfig= """
14 | # Copyright 2022 shandiankulishe@gmail.com
15 | ProxyHost : 127.0.0.1 # 设置代理IP
16 | ProxyPort : 7890 # 设置代理端口
17 | QueueSize : 64 # 设置最大并行任务数
18 | BotAccount : 3479060093 # 设置Bot账号
19 | BotPassword : Andy20061108 #设置Bot密码
20 | CacheDir : cache #设置缓存文件夹
21 | ServicePort : 80 #设置Http服务开放端口
22 | CookieFile : cookie.dat #设置米游社Cookie文件
23 | ResourcePackDir : pages #设置Http静态服务资源包路径
24 | ResourcePackFileDir : resourcePacks #设置Http静态服务资源包释放路径
25 | SilentMode : true #设置是否输出群内消息
26 | EnableDebug : true #设置是否启用调试
27 | """;
28 | Configuration configuration=new Configuration();
29 | configuration.load(defaultConfig);
30 | return configuration;
31 | }
32 | @Test
33 | public void testConfig() throws IOException {
34 |
35 | Configuration configuration=getTestConfig();
36 | Map map=configuration.getConfigNodes();
37 | for (Map.Entry entry :
38 | map.entrySet()) {
39 | System.out.printf("Key: %s Value: %s ValueType: %s Comment: %s\n",entry.getValue().getKey(),entry.getValue().getValue(),entry.getValue().getValue().getClass().getName(),entry.getValue().getComment());
40 | }
41 | System.out.println((String) configuration.get("ProxyHost"));
42 | System.out.println(configuration.getString("ProxyHost"));
43 | BotConfig config=configuration.serializeToClass(BotConfig.class);
44 | config.setQueueSize(128);
45 | configuration.mergeClass(config);
46 | System.out.println(configuration.save());
47 | System.out.println(configuration.getBoolean("SilentMode"));
48 | System.out.println(config.isSilentMode());
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/.github/workflows/build.yml:
--------------------------------------------------------------------------------
1 | name: build
2 | on:
3 | push:
4 | branches: [ master ]
5 | jobs:
6 | build_linux64:
7 | runs-on: ubuntu-latest
8 | steps:
9 | - uses: actions/checkout@v3
10 | - uses: lukka/get-cmake@v3.23.0
11 | - uses: actions/setup-java@v3.1.0
12 | with:
13 | java-version: 17
14 | distribution: temurin
15 | - uses: DamianReeves/write-file-action@v1.0
16 | with:
17 | path: src/main/resources/SIGN
18 | contents: ${{ github.sha }}
19 | - name: Build Native
20 | run: |
21 | cd native/HardwareInfo
22 | mkdir build
23 | cd build
24 | cmake ..
25 | make
26 | cp libHardwareInfo.so ../../../src/main/resources/libHardwareInfo.so
27 | - name: Build Java
28 | run: |
29 | chmod +x gradlew
30 | ./gradlew build -x test
31 | ./gradlew makeReleaseJar
32 | ./gradlew exportAll
33 | - uses: actions/upload-artifact@v3.0.0
34 | with:
35 | name: kleebot_build_linux64
36 | path: build/all
37 | build_win64:
38 | runs-on: windows-latest
39 | steps:
40 | - uses: actions/checkout@v3
41 | - uses: lukka/get-cmake@v3.23.0
42 | - uses: actions/setup-java@v3.1.0
43 | with:
44 | java-version: 17
45 | distribution: temurin
46 | - uses: DamianReeves/write-file-action@v1.0
47 | with:
48 | path: src/main/resources/SIGN
49 | contents: ${{ github.sha }}
50 | - uses: egor-tensin/setup-mingw@v2
51 | - name: Build Native
52 | run: |
53 | cd .\native\HardwareInfo\
54 | mkdir build
55 | cd build
56 | cmake -G"MinGW Makefiles" ..
57 | mingw32-make
58 | copy libHardwareInfo.dll ../../../src/main/resources/libHardwareInfo.dll
59 | - name: Build Java
60 | run: |
61 | ./gradlew build -x test
62 | ./gradlew makeReleaseJar
63 | ./gradlew exportAll
64 | - uses: actions/upload-artifact@v3.0.0
65 | with:
66 | name: kleebot_build_win64
67 | path: build/all
68 |
--------------------------------------------------------------------------------
/native/HardwareInfo/include/glous_kleebot_services_api_HardwareInfo.h:
--------------------------------------------------------------------------------
1 | /* DO NOT EDIT THIS FILE - it is machine generated */
2 | #include "jni.h"
3 | /* Header for class glous_kleebot_services_api_HardwareInfo */
4 |
5 | #ifndef _Included_glous_kleebot_services_api_HardwareInfo
6 | #define _Included_glous_kleebot_services_api_HardwareInfo
7 | #ifdef __cplusplus
8 | extern "C" {
9 | #endif
10 | /*
11 | * Class: glous_kleebot_services_api_HardwareInfo
12 | * Method: getCpuModel
13 | * Signature: ()Ljava/lang/String;
14 | */
15 | JNIEXPORT jstring JNICALL Java_glous_kleebot_services_api_HardwareInfo_getCpuModel
16 | (JNIEnv *, jobject);
17 |
18 | /*
19 | * Class: glous_kleebot_services_api_HardwareInfo
20 | * Method: getCpuUsage
21 | * Signature: ()D
22 | */
23 | JNIEXPORT jdouble JNICALL Java_glous_kleebot_services_api_HardwareInfo_getCpuUsage
24 | (JNIEnv *, jobject);
25 |
26 | /*
27 | * Class: glous_kleebot_services_api_HardwareInfo
28 | * Method: getCpuClockCycle
29 | * Signature: ()J
30 | */
31 | JNIEXPORT jlong JNICALL Java_glous_kleebot_services_api_HardwareInfo_getCpuClockCycle
32 | (JNIEnv *, jobject);
33 |
34 | /*
35 | * Class: glous_kleebot_services_api_HardwareInfo
36 | * Method: getCpuAvailableCores
37 | * Signature: ()I
38 | */
39 | JNIEXPORT jint JNICALL Java_glous_kleebot_services_api_HardwareInfo_getCpuAvailableCores
40 | (JNIEnv *, jobject);
41 |
42 | /*
43 | * Class: glous_kleebot_services_api_HardwareInfo
44 | * Method: getTotalMemory
45 | * Signature: ()J
46 | */
47 | JNIEXPORT jlong JNICALL Java_glous_kleebot_services_api_HardwareInfo_getTotalMemory
48 | (JNIEnv *, jobject);
49 |
50 | /*
51 | * Class: glous_kleebot_services_api_HardwareInfo
52 | * Method: getAvailableMemory
53 | * Signature: ()J
54 | */
55 | JNIEXPORT jlong JNICALL Java_glous_kleebot_services_api_HardwareInfo_getAvailableMemory
56 | (JNIEnv *, jobject);
57 |
58 | /*
59 | * Class: glous_kleebot_services_api_HardwareInfo
60 | * Method: getProcessID
61 | * Signature: ()J
62 | */
63 | JNIEXPORT jlong JNICALL Java_glous_kleebot_services_api_HardwareInfo_getProcessID
64 | (JNIEnv *, jobject);
65 |
66 | #ifdef __cplusplus
67 | }
68 | #endif
69 | #endif
70 |
--------------------------------------------------------------------------------
/src/main/java/glous/kleebot/utils/ZipUtils.java:
--------------------------------------------------------------------------------
1 | package glous.kleebot.utils;
2 |
3 | import org.apache.commons.compress.archivers.ArchiveEntry;
4 | import org.apache.commons.compress.archivers.zip.ZipArchiveInputStream;
5 | import org.apache.commons.compress.archivers.zip.ZipFile;
6 |
7 | import java.io.*;
8 |
9 | public class ZipUtils {
10 | public static void extractZipFile(String filePath,String extractPath){
11 | if (!extractPath.endsWith(String.valueOf(File.separatorChar))){
12 | extractPath+=File.separatorChar;
13 | }
14 | File destDir=new File(extractPath);
15 | if (!destDir.exists()){
16 | destDir.mkdirs();
17 | }
18 | try {
19 | File file=new File(filePath);
20 | ZipArchiveInputStream zipStream=new ZipArchiveInputStream(new FileInputStream(file));
21 | ArchiveEntry entry;
22 | while ((entry=zipStream.getNextEntry())!=null) {
23 | String entryName = entry.getName();
24 | entryName = extractPath+ entryName;
25 | if (entry.isDirectory()) {
26 | File dir = new File(entryName);
27 | if (!dir.exists()) {
28 | dir.mkdirs();
29 | }
30 | } else {
31 | File destFile = new File(entryName);
32 | if (!destFile.getParentFile().exists()) {
33 | destFile.getParentFile().mkdirs();
34 | }
35 | if (!destFile.exists()) {
36 | destFile.createNewFile();
37 | }
38 | BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(destFile));
39 | byte[] buffer = new byte[1024];
40 | int len;
41 | while ((len = zipStream.read(buffer)) != -1) {
42 | out.write(buffer, 0, len);
43 | out.flush();
44 | }
45 | out.close();
46 | }
47 | }
48 | zipStream.close();
49 | } catch (IOException e) {
50 | e.printStackTrace();
51 | }
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/src/main/java/glous/kleebot/async/AsyncTaskQueue.java:
--------------------------------------------------------------------------------
1 | package glous.kleebot.async;
2 |
3 | import glous.kleebot.KleeBot;
4 |
5 | import java.util.*;
6 |
7 | public class AsyncTaskQueue {
8 | public static final int TASK_FINISHED =0;
9 | public static final int TASK_PROCESSING=1;
10 | boolean flag=true;
11 | final Vector taskQueue=new Vector<>();
12 | private AsyncTask[] threads;
13 | synchronized Task pollFirst(){
14 | if (taskQueue.size()>0){
15 | Task task=taskQueue.get(0);
16 | taskQueue.remove(0);
17 | return task;
18 | }
19 | return null;
20 | }
21 | public AsyncTaskQueue(int size){
22 | //init all working processes
23 | threads=new AsyncTask[size];
24 | }
25 | public synchronized void start(){
26 | while (KleeBot.getRunningFlag()&&flag){
27 | Task task;
28 | if ((task=pollFirst())!=null){
29 | //dispatch task
30 | for (int i = 0; i < threads.length; i++) {
31 | if (threads[i]==null||threads[i].getTaskState()==TASK_FINISHED){
32 | threads[i]=new AsyncTask(task);
33 | new Thread(threads[i]).start();
34 | break;
35 | }
36 | }
37 | }
38 | try {
39 | this.wait();
40 | } catch (InterruptedException e) {
41 | e.printStackTrace();
42 | }
43 | }
44 | }
45 | public synchronized void asyncStart(){
46 | new Thread(this::start).start();
47 | }
48 | public List getAllRunningTasksName(){
49 | List taskNames=new ArrayList<>();
50 | for (AsyncTask task:threads){
51 | if (task!=null){
52 | if (task.getTaskState()==TASK_PROCESSING) {
53 | taskNames.add(task.getTaskName());
54 | }
55 | }
56 |
57 | }
58 | return taskNames;
59 | }
60 | public synchronized void addTask(BaseFunction func,String funcName){
61 | taskQueue.add(new Task(func,funcName));
62 | this.notify();
63 | }
64 | public void stop(){
65 | flag=false;
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/src/main/java/glous/kleebot/features/builtin/VariableInt.java:
--------------------------------------------------------------------------------
1 | package glous.kleebot.features.builtin;
2 |
3 | import glous.kleebot.annonations.Copy;
4 |
5 | import java.io.*;
6 | import java.nio.ByteBuffer;
7 | import java.util.Vector;
8 |
9 | public class VariableInt {
10 | private static final int SEGMENT_BITS = 0x7F;
11 | private static final int CONTINUE_BIT = 0x80;
12 | int i;
13 | public VariableInt(int i){
14 | this.i=i;
15 | }
16 | public VariableInt(){
17 | }
18 |
19 | @Copy(url = "https://wiki.vg/Protocol")
20 | public byte[] getBytes() {
21 | ByteArrayOutputStream o=new ByteArrayOutputStream();
22 | while (true) {
23 | if ((i & ~SEGMENT_BITS) == 0) {
24 | o.write((byte) i);
25 | return o.toByteArray();
26 | }
27 | o.write((byte) (i & SEGMENT_BITS) | CONTINUE_BIT);
28 | i >>>= 7;
29 | }
30 | }
31 |
32 | public void writeBytes(OutputStream out) throws IOException {
33 | out.write(getBytes());
34 | }
35 |
36 | @Copy(url = "https://wiki.vg/Protocol")
37 | public int readBytes(byte[] bytes) throws IOException {
38 | ByteArrayInputStream in=new ByteArrayInputStream(bytes);
39 | int value = 0;
40 | int position = 0;
41 | byte currentByte;
42 | while (true) {
43 | currentByte =(byte) in.read();
44 | value |= (currentByte & SEGMENT_BITS) << position;
45 | if ((currentByte & CONTINUE_BIT) == 0) break;
46 | position += 7;
47 | if (position >= 32) throw new RuntimeException("VarInt is too big");
48 | }
49 | this.i=value;
50 | return i;
51 | }
52 |
53 | @Copy(url = "https://wiki.vg/Protocol")
54 | public int readBytes(InputStream in) throws IOException {
55 | int value = 0;
56 | int position = 0;
57 | byte currentByte;
58 | while (true) {
59 | currentByte =(byte) in.read();
60 | value |= (currentByte & SEGMENT_BITS) << position;
61 | if ((currentByte & CONTINUE_BIT) == 0) break;
62 | position += 7;
63 | if (position >= 32) throw new RuntimeException("VarInt is too big");
64 | }
65 | this.i=value;
66 | return i;
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/src/main/java/glous/kleebot/http/services/GetWhisperService.java:
--------------------------------------------------------------------------------
1 | package glous.kleebot.http.services;
2 |
3 | import com.google.gson.stream.JsonWriter;
4 | import glous.kleebot.http.HttpClient;
5 | import glous.kleebot.http.IWebService;
6 |
7 | import java.io.IOException;
8 | import java.io.StringWriter;
9 |
10 | public class GetWhisperService implements IWebService {
11 | @Override
12 | public boolean doGET(HttpClient client) throws IOException {
13 | client.setHeader("Access-Control-Allow-Origin","*");
14 | String requestKey=client.getRequestPath();
15 | StringWriter out=new StringWriter();
16 | JsonWriter writer=new JsonWriter(out);
17 | writer.beginObject();
18 | if (!requestKey.contains(":")){
19 | writer.name("status").value("error");
20 | writer.name("message").value("request method not right");
21 | writer.endObject();
22 | writer.flush();
23 | writer.close();
24 | client.writeResponseBody(out.toString());
25 | client.finish();
26 | return true;
27 | }
28 | requestKey=requestKey.substring(requestKey.indexOf(":")+1);
29 | if (!StoreWhisperService.dataMap.containsKey(requestKey)){
30 | writer.name("status").value("error");
31 | writer.name("message").value("whisper not found");
32 | writer.endObject();
33 | writer.flush();
34 | writer.close();
35 | client.writeResponseBody(out.toString());
36 | client.finish();
37 | return true;
38 | }
39 | writer.name("status").value("ok");
40 | writer.name("message").value("successfully got data");
41 | writer.name("body").value(StoreWhisperService.dataMap.get(requestKey));
42 | StoreWhisperService.dataMap.remove(requestKey);
43 | writer.endObject();
44 | writer.flush();
45 | writer.close();
46 | client.writeResponseBody(out.toString());
47 | client.finish();
48 | return true;
49 | }
50 |
51 | @Override
52 | public boolean doPOST(HttpClient client) throws IOException {
53 | return false;
54 | }
55 |
56 | @Override
57 | public void init() {
58 |
59 | }
60 |
61 | @Override
62 | public void stop() {
63 |
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/src/main/java/glous/kleebot/utils/HttpUtils.java:
--------------------------------------------------------------------------------
1 | package glous.kleebot.utils;
2 |
3 | import glous.kleebot.utils.builtin.HttpResponse;
4 | import org.jetbrains.annotations.NotNull;
5 | import org.jetbrains.annotations.Nullable;
6 |
7 | import java.io.BufferedInputStream;
8 | import java.io.BufferedOutputStream;
9 | import java.io.ByteArrayOutputStream;
10 | import java.io.IOException;
11 | import java.net.HttpURLConnection;
12 | import java.net.Proxy;
13 | import java.net.URL;
14 | import java.util.Map;
15 |
16 | public class HttpUtils {
17 | public static final String CONTENT_TYPE_JSON="application/json";
18 | public static final String CONTENT_TYPE_TEXT="text/plain";
19 | public HttpResponse post(@NotNull String _url, @Nullable Proxy proxy, @Nullable Map headers, @Nullable byte[] body) throws IOException {
20 | HttpResponse response=new HttpResponse();
21 | HttpURLConnection connection;
22 | URL url=new URL(_url);
23 | if (proxy!=null){
24 | connection=(HttpURLConnection) url.openConnection(proxy);
25 | } else{
26 | connection=(HttpURLConnection) url.openConnection();
27 | }
28 | if (headers!=null){
29 | for (Map.Entry header :
30 | headers.entrySet()) {
31 | connection.setRequestProperty(header.getKey(), header.getValue());
32 | }
33 | }
34 | connection.setRequestMethod("POST");
35 | connection.setDoInput(true);
36 | connection.setDoOutput(true);
37 | BufferedOutputStream out = null;
38 | if (body!=null){
39 | out=new BufferedOutputStream(connection.getOutputStream());
40 | out.write(body);
41 | out.flush();
42 | }
43 | response.setResponseCode(connection.getResponseCode());
44 | BufferedInputStream in=new BufferedInputStream(connection.getInputStream());
45 | byte[] bytes=new byte[1024];
46 | int bytesRead;
47 | ByteArrayOutputStream bOut=new ByteArrayOutputStream();
48 | while ((bytesRead=in.read(bytes))!=-1){
49 | bOut.write(bytes,0,bytesRead);
50 | }
51 | response.setBody(bOut.toByteArray());
52 | in.close();
53 | bOut.close();
54 | if (out!=null){
55 | out.close();
56 | }
57 | return response;
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/native/HardwareInfo/include/linux/jni_md.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 1996, 2020, Oracle and/or its affiliates. All rights reserved.
3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 | *
5 | * This code is free software; you can redistribute it and/or modify it
6 | * under the terms of the GNU General Public License version 2 only, as
7 | * published by the Free Software Foundation. Oracle designates this
8 | * particular file as subject to the "Classpath" exception as provided
9 | * by Oracle in the LICENSE file that accompanied this code.
10 | *
11 | * This code is distributed in the hope that it will be useful, but WITHOUT
12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 | * version 2 for more details (a copy is included in the LICENSE file that
15 | * accompanied this code).
16 | *
17 | * You should have received a copy of the GNU General Public License version
18 | * 2 along with this work; if not, write to the Free Software Foundation,
19 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 | *
21 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 | * or visit www.oracle.com if you need additional information or have any
23 | * questions.
24 | */
25 |
26 | #ifndef _JAVASOFT_JNI_MD_H_
27 | #define _JAVASOFT_JNI_MD_H_
28 |
29 | #ifndef __has_attribute
30 | #define __has_attribute(x) 0
31 | #endif
32 |
33 | #ifndef JNIEXPORT
34 | #if (defined(__GNUC__) && ((__GNUC__ > 4) || (__GNUC__ == 4) && (__GNUC_MINOR__ > 2))) || __has_attribute(visibility)
35 | #ifdef ARM
36 | #define JNIEXPORT __attribute__((externally_visible,visibility("default")))
37 | #else
38 | #define JNIEXPORT __attribute__((visibility("default")))
39 | #endif
40 | #else
41 | #define JNIEXPORT
42 | #endif
43 | #endif
44 |
45 | #if (defined(__GNUC__) && ((__GNUC__ > 4) || (__GNUC__ == 4) && (__GNUC_MINOR__ > 2))) || __has_attribute(visibility)
46 | #ifdef ARM
47 | #define JNIIMPORT __attribute__((externally_visible,visibility("default")))
48 | #else
49 | #define JNIIMPORT __attribute__((visibility("default")))
50 | #endif
51 | #else
52 | #define JNIIMPORT
53 | #endif
54 |
55 | #define JNICALL
56 |
57 | typedef int jint;
58 | #ifdef _LP64
59 | typedef long jlong;
60 | #else
61 | typedef long long jlong;
62 | #endif
63 |
64 | typedef signed char jbyte;
65 |
66 | #endif /* !_JAVASOFT_JNI_MD_H_ */
67 |
--------------------------------------------------------------------------------
/src/main/java/glous/kleebot/async/Timer.java:
--------------------------------------------------------------------------------
1 | package glous.kleebot.async;
2 |
3 | import glous.kleebot.KleeBot;
4 | import glous.kleebot.log.Logger;
5 |
6 | import java.util.ArrayList;
7 | import java.util.HashMap;
8 | import java.util.List;
9 |
10 | public class Timer {
11 | private static final HashMap setInterval = new HashMap<>();
12 | private static final HashMap runningInterval=new HashMap<>();
13 | private static final List tasks=new ArrayList<>();
14 | private static final Logger logger=Logger.getLogger(Timer.class);
15 | public static final long SECOND=1000L;
16 | public static final long MINUTE=60000L;
17 | public static final long HOUR=3600000L;
18 | public static final long DAY=86400000L;
19 | public static final long NO_LIMIT =-1L;
20 | public static void registerScheduledTask(Task task,long interval){
21 | setInterval.put(task,interval);
22 | runningInterval.put(task,0L);
23 | tasks.add(task);
24 | }
25 | public static void init() throws Exception {
26 | //init start run timer
27 | logger.info("开始运行初始化任务");
28 | for (Task value : tasks) {
29 | logger.info("任务: %s 开始执行".formatted(value.getFullName()));
30 | value.getFunc().execute();
31 | }
32 | }
33 | public static void start(){
34 | new Thread(()->{
35 | long start;
36 | long last=System.currentTimeMillis();
37 | while (KleeBot.getRunningFlag()){
38 | start=System.currentTimeMillis();
39 | for (Task task :
40 | setInterval.keySet()) {
41 | long set=setInterval.get(task);
42 | long running=runningInterval.get(task);
43 | if (running>set){
44 | try {
45 | task.getFunc().execute();
46 | } catch (Exception e) {
47 | e.printStackTrace();
48 | }
49 | runningInterval.put(task,0L);
50 | } else {
51 | runningInterval.put(task,running+(start-last));
52 | }
53 | }
54 | last=System.currentTimeMillis();
55 | try {
56 | Thread.sleep(100);
57 | } catch (InterruptedException e) {
58 | e.printStackTrace();
59 | }
60 | }
61 | }).start();
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/src/main/java/glous/kleebot/web/HttpClient.java:
--------------------------------------------------------------------------------
1 | package glous.kleebot.web;
2 |
3 | import java.io.ByteArrayOutputStream;
4 | import java.io.IOException;
5 | import java.io.InputStream;
6 | import java.io.OutputStream;
7 | import java.nio.charset.StandardCharsets;
8 | import java.util.HashMap;
9 |
10 | public class HttpClient {
11 | public HttpClient(InputStream in,HashMap headers,String requestMethod,OutputStream out){
12 | this.in=in;
13 | this.headers=headers;
14 | this.requestMethod=requestMethod;
15 | this.out=out;
16 | }
17 | //Set
18 | private OutputStream out;
19 | private String responseCode;
20 | private ByteArrayOutputStream finalOut=new ByteArrayOutputStream();
21 | private StringBuffer finalHeader=new StringBuffer();
22 | public void write(byte[] bytes) throws IOException {
23 | finalOut.write(bytes);
24 | }
25 | public void write(String str) throws IOException {
26 | finalOut.write((str+"\n").getBytes(StandardCharsets.UTF_8));
27 | }
28 | public void setHeader(String K,String V){
29 | finalHeader.append(K).append(": ").append(V).append("\n");
30 | }
31 | public void setResponseCode(String code){
32 | responseCode=code+"\n";
33 | }
34 | public void finish(){
35 | try {
36 | if (responseCode==null){
37 | setResponseCode("200 OK");
38 | }
39 | setHeader("Server","KleeBot Http Services");
40 | if (finalOut.size()>0){
41 | setHeader("Content-Length",String.valueOf(finalOut.size()));
42 | }
43 | ByteArrayOutputStream bytesOut=new ByteArrayOutputStream();
44 | bytesOut.write("HTTP/1.1 ".getBytes(StandardCharsets.UTF_8));
45 | bytesOut.write(responseCode.getBytes(StandardCharsets.UTF_8));
46 | bytesOut.write(finalHeader.toString().getBytes(StandardCharsets.UTF_8));
47 | bytesOut.write("\n".getBytes(StandardCharsets.UTF_8));
48 | bytesOut.write(finalOut.toByteArray());
49 | bytesOut.close();
50 | String s= bytesOut.toString(StandardCharsets.UTF_8);
51 | out.write(bytesOut.toByteArray());
52 | out.flush();
53 | out.close();
54 | } catch (IOException e) {
55 | e.printStackTrace();
56 | }
57 | }
58 | public InputStream getIn() {
59 | return in;
60 | }
61 |
62 | public HashMap getHeaders() {
63 | return headers;
64 | }
65 |
66 | public String getRequestMethod() {
67 | return requestMethod;
68 | }
69 |
70 | //Get
71 | private InputStream in;
72 | private HashMap headers;
73 | private String requestMethod;
74 | }
75 |
--------------------------------------------------------------------------------
/src/main/java/glous/kleebot/BotConfig.java:
--------------------------------------------------------------------------------
1 | package glous.kleebot;
2 |
3 |
4 | public class BotConfig {
5 | public String getProxyHost() {
6 | return ProxyHost;
7 | }
8 |
9 | public void setProxyHost(String proxyHost) {
10 | ProxyHost = proxyHost;
11 | }
12 |
13 | public int getProxyPort() {
14 | return ProxyPort;
15 | }
16 |
17 | public void setProxyPort(int proxyPort) {
18 | ProxyPort = proxyPort;
19 | }
20 |
21 | public int getQueueSize() {
22 | return QueueSize;
23 | }
24 |
25 | public void setQueueSize(int queueSize) {
26 | QueueSize = queueSize;
27 | }
28 |
29 | public long getBotAccount() {
30 | return BotAccount;
31 | }
32 |
33 | public void setBotAccount(long botAccount) {
34 | BotAccount = botAccount;
35 | }
36 |
37 | public String getBotPassword() {
38 | return BotPassword;
39 | }
40 |
41 | public void setBotPassword(String botPassword) {
42 | BotPassword = botPassword;
43 | }
44 |
45 | public String getCacheDir() {
46 | return CacheDir;
47 | }
48 |
49 | public void setCacheDir(String cacheDir) {
50 | CacheDir = cacheDir;
51 | }
52 |
53 | public int getServicePort() {
54 | return ServicePort;
55 | }
56 |
57 | public void setServicePort(int servicePort) {
58 | ServicePort = servicePort;
59 | }
60 |
61 | public String getCookieFile() {
62 | return CookieFile;
63 | }
64 |
65 | public void setCookieFile(String cookieFile) {
66 | CookieFile = cookieFile;
67 | }
68 |
69 | public String getResourcePackDir() {
70 | return ResourcePackDir;
71 | }
72 |
73 | public void setResourcePackDir(String resourcePackDir) {
74 | ResourcePackDir = resourcePackDir;
75 | }
76 |
77 | public String getResourcePackFileDir() {
78 | return ResourcePackFileDir;
79 | }
80 |
81 | public void setResourcePackFileDir(String resourcePackFileDir) {
82 | ResourcePackFileDir = resourcePackFileDir;
83 | }
84 |
85 | private String ProxyHost;
86 | private int ProxyPort;
87 | private int QueueSize;
88 | private long BotAccount;
89 | private String BotPassword;
90 | private String CacheDir;
91 | private int ServicePort;
92 | private String CookieFile;
93 | private String ResourcePackDir;
94 | private String ResourcePackFileDir;
95 | private boolean SilentMode;
96 |
97 | public boolean isSilentMode() {
98 | return SilentMode;
99 | }
100 |
101 | public void setSilentMode(boolean silentMode) {
102 | SilentMode = silentMode;
103 | }
104 | }
105 |
--------------------------------------------------------------------------------
/src/main/java/glous/kleebot/services/impl/MCPingService.java:
--------------------------------------------------------------------------------
1 | package glous.kleebot.services.impl;
2 |
3 | import glous.kleebot.KleeBot;
4 | import glous.kleebot.features.builtin.MCServerMOTD;
5 | import glous.kleebot.features.minecraft.PingAPI;
6 | import glous.kleebot.services.GroupService;
7 | import net.mamoe.mirai.event.events.GroupMessageEvent;
8 | import net.mamoe.mirai.message.data.At;
9 | import net.mamoe.mirai.message.data.Image;
10 | import net.mamoe.mirai.message.data.MessageChainBuilder;
11 | import net.mamoe.mirai.utils.ExternalResource;
12 |
13 | import java.util.Base64;
14 |
15 | public class MCPingService extends GroupService {
16 | @Override
17 | public boolean process(GroupMessageEvent event) {
18 | return event.getMessage().serializeToMiraiCode().startsWith(new At(KleeBot.config.getBotAccount())+" mcp ");
19 | }
20 |
21 | @Override
22 | public boolean execute(GroupMessageEvent event) throws Exception {
23 | String message=event.getMessage().serializeToMiraiCode();
24 | String[] args=message.split(" ");
25 | if (args.length==3){
26 | String rawHost=args[2].replace("\\","");//¿
27 | String host=rawHost;
28 | int port=25565;
29 | if (rawHost.contains(":")){
30 | host=rawHost.substring(0,rawHost.indexOf(":"));
31 | port=Integer.parseInt(rawHost.substring(rawHost.indexOf(":")+1));
32 | }
33 | PingAPI api=new PingAPI(host,port);
34 | MCServerMOTD motd=api.ping();
35 | if (motd.getStatus()==-1){
36 | sendMessage("错误的主机名或端口号",event);
37 | } else{
38 | String ret=
39 | """
40 | %s 的 服务器信息
41 | 服务器版本名: %s
42 | 服务器版本协议: %d
43 | 最大在线人数: %d
44 | 当前在线人数: %d
45 | 描述: %s
46 | """.formatted(host+":"+port,motd.getName(),motd.getProtocol(),motd.getMaxPlayer(),motd.getOnlinePlayer(),motd.getDescription());
47 | MessageChainBuilder builder=new MessageChainBuilder();
48 | builder.append(new At(event.getSender().getId()));
49 | builder.append("\n").append(ret);
50 | ExternalResource res=ExternalResource.create(Base64.getDecoder().decode(motd.getFavicon().substring(motd.getFavicon().indexOf(",")+1)));
51 | Image image=event.getSubject().uploadImage(res);
52 | builder.append(image);
53 | res.close();
54 | event.getGroup().sendMessage(builder.build());
55 | return true;
56 | }
57 | }
58 | return false;
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/src/main/java/glous/kleebot/features/minecraft/WikiAPI.java:
--------------------------------------------------------------------------------
1 | package glous.kleebot.features.minecraft;
2 |
3 | import org.jsoup.Jsoup;
4 | import org.jsoup.nodes.Document;
5 | import org.jsoup.nodes.Element;
6 | import org.jsoup.select.Elements;
7 | import glous.kleebot.References;
8 | import glous.kleebot.features.builtin.MCWikiElement;
9 | import glous.kleebot.http.ChromeInstance;
10 | import glous.kleebot.utils.FileUtils;
11 |
12 | import java.io.IOException;
13 | import java.net.InetSocketAddress;
14 | import java.net.Proxy;
15 | import java.net.URLEncoder;
16 | import java.nio.charset.StandardCharsets;
17 | import java.util.Base64;
18 |
19 | public class WikiAPI {
20 | private Proxy proxy;
21 | public WikiAPI(String proxyHost,int proxyPort){
22 | this.proxy=new Proxy(Proxy.Type.HTTP,new InetSocketAddress(proxyHost,proxyPort));
23 | }
24 | public static final int WIKI_CN=0;
25 | public static final int WIKI_EN=1;
26 | public MCWikiElement getElement(String item , int type) throws IOException {
27 | String _url;
28 | if (type==WIKI_CN){
29 | _url=References.MCWIKI_CN_URL+"/"+ URLEncoder.encode(item,StandardCharsets.UTF_8);
30 | } else{
31 | _url=References.MCWIKI_EN_URL+"/"+ URLEncoder.encode(item,StandardCharsets.UTF_8);
32 | }
33 | byte[] bytes=FileUtils.download(_url,proxy);
34 | if (bytes==null){
35 | return null;
36 | }
37 | String document_content= new String(bytes,StandardCharsets.UTF_8);
38 | Document document= Jsoup.parse(document_content);
39 | Elements metaOgDescription=document.select("meta[name=description]");
40 | Element ogDescription=metaOgDescription.get(0);
41 | String description_content=ogDescription.attr("content");
42 | if (description_content.equals("")){
43 | return null;
44 | }
45 | Elements metaOgImage=document.select("meta[property=og:image]");
46 | Element ogImage=metaOgImage.get(0);
47 | Elements metaOgUrl=document.select("meta[property=og:url]");
48 | Element ogUrl=metaOgUrl.get(0);
49 | String ogImage_content=ogImage.attr("content");
50 | String ogImage_Base64= Base64.getEncoder().encodeToString(FileUtils.download(ogImage_content,proxy));
51 | String ogUrl_content=ogUrl.attr("content");
52 | return new MCWikiElement(description_content,ogImage_Base64,ogUrl_content);
53 | }
54 | public byte[] getElementImage(String item, int type) throws InterruptedException {
55 | String _url;
56 | if (type==WIKI_CN){
57 | _url=References.MCWIKI_CN_URL+"/"+ URLEncoder.encode(item,StandardCharsets.UTF_8);
58 | } else{
59 | _url=References.MCWIKI_EN_URL+"/"+ URLEncoder.encode(item,StandardCharsets.UTF_8);
60 | }
61 | byte[] image= ChromeInstance.getScreenShot(_url,0,500L);
62 | return image;
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%" == "" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%" == "" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34 |
35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
37 |
38 | @rem Find java.exe
39 | if defined JAVA_HOME goto findJavaFromJavaHome
40 |
41 | set JAVA_EXE=java.exe
42 | %JAVA_EXE% -version >NUL 2>&1
43 | if "%ERRORLEVEL%" == "0" goto execute
44 |
45 | echo.
46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47 | echo.
48 | echo Please set the JAVA_HOME variable in your environment to match the
49 | echo location of your Java installation.
50 |
51 | goto fail
52 |
53 | :findJavaFromJavaHome
54 | set JAVA_HOME=%JAVA_HOME:"=%
55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
56 |
57 | if exist "%JAVA_EXE%" goto execute
58 |
59 | echo.
60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61 | echo.
62 | echo Please set the JAVA_HOME variable in your environment to match the
63 | echo location of your Java installation.
64 |
65 | goto fail
66 |
67 | :execute
68 | @rem Setup the command line
69 |
70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
71 |
72 |
73 | @rem Execute Gradle
74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
75 |
76 | :end
77 | @rem End local scope for the variables with windows NT shell
78 | if "%ERRORLEVEL%"=="0" goto mainEnd
79 |
80 | :fail
81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
82 | rem the _cmd.exe /c_ return code!
83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
84 | exit /b 1
85 |
86 | :mainEnd
87 | if "%OS%"=="Windows_NT" endlocal
88 |
89 | :omega
90 |
--------------------------------------------------------------------------------
/src/main/java/glous/kleebot/services/impl/SyncService.java:
--------------------------------------------------------------------------------
1 | package glous.kleebot.services.impl;
2 |
3 | import glous.kleebot.KleeBot;
4 | import glous.kleebot.cache.CacheFactory;
5 | import glous.kleebot.features.pixiv.PixivAPI;
6 | import glous.kleebot.services.GroupService;
7 | import net.mamoe.mirai.event.events.GroupMessageEvent;
8 | import net.mamoe.mirai.message.data.At;
9 |
10 | import java.util.Arrays;
11 | import java.util.HashMap;
12 |
13 | public class SyncService extends GroupService {
14 | @Override
15 | public boolean process(GroupMessageEvent event) {
16 | return event.getMessage().serializeToMiraiCode().startsWith(new At(KleeBot.config.getBotAccount())+" sync ");
17 | }
18 |
19 | @Override
20 | public boolean execute(GroupMessageEvent event) throws Exception {
21 | String message=event.getMessage().serializeToMiraiCode();
22 | String[] args=message.substring(message.indexOf("sync")+5).split(" ");
23 | if (args[0].equals("info")){
24 | //pixiv rank sync info
25 | PixivAPI api=new PixivAPI(KleeBot.config.getProxyHost(),KleeBot.config.getProxyPort());
26 | HashMap> daily=api.getDailyRanking(false);
27 | HashMap> weekly=api.getWeeklyRanking(false);
28 | HashMap> monthly=api.getMonthlyRanking(false);
29 | StringBuilder builder=new StringBuilder();
30 | builder.append("Pixiv Synchronization Info:\n");
31 | for (HashMap artwork :
32 | daily.values()) {
33 | String syncInfo=
34 | """
35 | %s\040""".formatted(artwork.get("title"));
36 | builder.append(syncInfo);
37 | if (CacheFactory.getCache(artwork.get("imageUrl"))==null)
38 | builder.append("\uD83D\uDD34\n");
39 | else
40 | builder.append("\uD83D\uDFE2\n");
41 | }
42 | for (HashMap artwork :
43 | weekly.values()) {
44 | String syncInfo=
45 | """
46 | %s\040""".formatted(artwork.get("title"));
47 | builder.append(syncInfo);
48 | if (CacheFactory.getCache(artwork.get("imageUrl"))==null)
49 | builder.append("\uD83D\uDD34\n");
50 | else
51 | builder.append("\uD83D\uDFE2\n");
52 | }
53 | for (HashMap artwork :
54 | monthly.values()) {
55 | String syncInfo=
56 | """
57 | %s\040""".formatted(artwork.get("title"));
58 | builder.append(syncInfo);
59 | if (CacheFactory.getCache(artwork.get("imageUrl"))==null)
60 | builder.append("\uD83D\uDD34\n");
61 | else
62 | builder.append("\uD83D\uDFE2\n");
63 | }
64 | builder.append("END");
65 | System.out.println(builder.toString());
66 | sendMessage(builder.toString(),event);
67 | return true ;
68 | }
69 | return false;
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/src/main/java/glous/kleebot/services/impl/HelpService.java:
--------------------------------------------------------------------------------
1 | package glous.kleebot.services.impl;
2 |
3 | import net.mamoe.mirai.event.events.GroupMessageEvent;
4 | import net.mamoe.mirai.message.data.At;
5 | import net.mamoe.mirai.message.data.Image;
6 | import net.mamoe.mirai.message.data.MessageChainBuilder;
7 | import net.mamoe.mirai.utils.ExternalResource;
8 | import glous.kleebot.KleeBot;
9 | import glous.kleebot.services.GroupService;
10 |
11 | import java.io.IOException;
12 | import java.util.Objects;
13 |
14 | public class HelpService extends GroupService {
15 | @Override
16 | public boolean process(GroupMessageEvent event) {
17 | return event.getMessage().serializeToMiraiCode().equals(new At(KleeBot.config.getBotAccount()).serializeToMiraiCode() + " help");
18 | }
19 |
20 | @Override
21 | public boolean execute(GroupMessageEvent event) throws IOException {
22 | MessageChainBuilder builder=new MessageChainBuilder();
23 | builder.append(
24 | """
25 | Copyright 2022 shandiankulishe@gmail.com
26 | 官方仓库:www.github.com/youfantan/KleeBot
27 | 有疑问请提交ISSUES,作者七月前不接收QQ消息
28 | (正在填坑,前有!符号代表正在开发)
29 | @[bot] help/? --显示帮助 例: @KleeBot help
30 | @[bot] status --获取Bot当前状态
31 | pixiv(注:r18作品会返回一个url,可以点击url后在本地浏览器执行javascript解密图片):
32 | @[bot] pixiv rank daily #[num] --获取pixiv日榜作品 例: @KleeBot rank daily #1
33 | @[bot] pixiv rank weekly #[num] --获取pixiv周榜作品 例: @KleeBot rank weekly #1
34 | @[bot] pixiv rank monthly #[num] --获取pixiv月榜作品 例: @KleeBot rank monthly #1
35 | @[bot] pixiv [artworkId] --根据artworkId获取作品 例: @KleeBot 96311355
36 | bilibili:
37 | @[bot] [bilibili稿件url] 获取稿件标题、封面、作者 例: @KleeBot https://www.bilibili.com/video/BV1GJ411x7h7
38 | *https://www.bilibili.com/* 直接从消息中检测稿件,返回同上 例: You got rick rolled lol https://www.bilibili.com/video/BV1GJ411x7h7
39 | 原神(仅支持天空岛(官服)&世界树(b服)):
40 | !@[bot] gscore [图片] --根据图片获取圣遗物评分 例: @KleeBot gscore
41 | """
42 | );
43 | ExternalResource gscoreexpimg=ExternalResource.create(Objects.requireNonNull(this.getClass().getResourceAsStream("/genshin.score.example.png")));
44 | Image gscoreexp=event.getSubject().uploadImage(gscoreexpimg);
45 | builder.append(gscoreexp);
46 | builder.append("\n");
47 | builder.append(
48 | """
49 | @[bot] gsearch [uid] [server] --根据玩家UID获取详细信息(角色/武器/圣遗物/蒙德、璃月、稻妻、渊下宫探索度) 国服/B服(暂不支持海外服务器(Oversea Server)) CN为官服 CN_B为b服 例: @KleeBot gsearch 128035175 CN
50 | !@[bot] gabyss [uid] --根据玩家UID获取深渊战绩 例: @KleeBot gabyss 128035715
51 | Minecraft:
52 | @[bot] mcws [条目] --获取minecraft wiki中条目的简介
53 | Github:
54 | @[bot] ghr [url] --获取github release的加速url
55 | 自动推送:
56 | @[bot] enable-mcv --启用自动推送服务(Release&Snapshot) 例: @KleeBot enable mcv
57 | 可选推送内容:
58 | - mcv: minecraft新版本(Release&Snapshot)(version_manifest.json及mojira,不会重复推送)
59 | """
60 | );
61 | event.getGroup().sendMessage(builder.build());
62 | gscoreexpimg.close();
63 | return true;
64 | }
65 |
66 | @Override
67 | public void initialize() {
68 |
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/src/main/java/glous/kleebot/http/proxy/GeneralTCPProxy.java:
--------------------------------------------------------------------------------
1 | package glous.kleebot.http.proxy;
2 |
3 | import glous.kleebot.async.AsyncTaskQueue;
4 | import glous.kleebot.async.BaseFunction;
5 | import glous.kleebot.async.Task;
6 | import glous.kleebot.features.genshin.GenshinAPI;
7 | import glous.kleebot.log.Logger;
8 | import glous.kleebot.utils.FileUtils;
9 | import org.bouncycastle.util.encoders.Hex;
10 |
11 | import java.io.BufferedInputStream;
12 | import java.io.BufferedOutputStream;
13 | import java.io.ByteArrayOutputStream;
14 | import java.io.IOException;
15 | import java.net.ServerSocket;
16 | import java.net.Socket;
17 | import java.util.ArrayList;
18 | import java.util.List;
19 |
20 | public class GeneralTCPProxy {
21 | private static final Logger logger=Logger.getLogger(GeneralTCPProxy.class);
22 | private boolean stop=false;
23 | private AsyncTaskQueue queue=new AsyncTaskQueue(64);
24 | public GeneralTCPProxy(int openPort, int forwardPort) {
25 | this.openPort = openPort;
26 | this.forwardPort = forwardPort;
27 | }
28 | private int openPort;
29 | private int forwardPort;
30 | public void start() throws IOException {
31 | queue.asyncStart();
32 | ServerSocket socket=new ServerSocket(openPort);
33 | while (!stop){
34 | Socket from=socket.accept();
35 | Socket to=new Socket("127.0.0.1",forwardPort);
36 | System.out.printf("Connected from %s to %s\n",from.getInetAddress().getHostAddress(),to.getInetAddress().getHostAddress());
37 | BufferedInputStream fromIn=new BufferedInputStream(from.getInputStream());
38 | BufferedOutputStream fromOut=new BufferedOutputStream(from.getOutputStream());
39 | BufferedInputStream toIn=new BufferedInputStream(to.getInputStream());
40 | BufferedOutputStream toOut=new BufferedOutputStream(to.getOutputStream());
41 | ByteArrayOutputStream fromRecorder=new ByteArrayOutputStream();
42 | ByteArrayOutputStream toRecorder=new ByteArrayOutputStream();
43 | queue.addTask(()->{
44 | logger.info("proxy start");
45 | byte[] buffer=new byte[1024];
46 | int bytesRead;
47 | while ((bytesRead=fromIn.read(buffer))!=-1){
48 | logger.info("%s".formatted(GenshinAPI.byteArrayToHex(buffer)));
49 | toOut.write(buffer,0,bytesRead);
50 | toOut.flush();
51 | toRecorder.write(buffer,0,bytesRead);
52 | toRecorder.flush();
53 | }
54 | toIn.close();
55 | fromOut.close();
56 | fromRecorder.close();
57 | FileUtils.writeFile(String.valueOf(from.hashCode()),fromRecorder.toByteArray());
58 | },"TCP-PROXY-CLIENT-POSTER"+from.hashCode());
59 | queue.addTask(()->{
60 | logger.info("proxy start");
61 | byte[] buffer=new byte[1024];
62 | int bytesRead;
63 | while ((bytesRead=toIn.read(buffer))!=-1){
64 | logger.info("%s".formatted(GenshinAPI.byteArrayToHex(buffer)));
65 | fromOut.write(buffer,0,bytesRead);
66 | fromOut.flush();
67 | fromRecorder.write(buffer,0,bytesRead);
68 | fromRecorder.flush();
69 | }
70 | fromIn.close();
71 | toOut.close();
72 | fromRecorder.close();
73 | FileUtils.writeFile(String.valueOf(to.hashCode()),toRecorder.toByteArray());
74 | },"TCP-PROXY-SERVER-POSTER"+to.hashCode());
75 | }
76 | }
77 | public void stop() throws IOException {
78 | this.stop=true;
79 | queue.stop();
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/src/main/java/glous/kleebot/services/impl/MCWikiSearchService.java:
--------------------------------------------------------------------------------
1 | package glous.kleebot.services.impl;
2 |
3 | import net.mamoe.mirai.event.events.GroupMessageEvent;
4 | import net.mamoe.mirai.message.data.At;
5 | import net.mamoe.mirai.message.data.Image;
6 | import net.mamoe.mirai.message.data.MessageChainBuilder;
7 | import net.mamoe.mirai.utils.ExternalResource;
8 | import glous.kleebot.KleeBot;
9 | import glous.kleebot.features.builtin.MCWikiElement;
10 | import glous.kleebot.features.minecraft.WikiAPI;
11 | import glous.kleebot.services.GroupService;
12 |
13 | import java.io.IOException;
14 | import java.util.Base64;
15 |
16 | public class MCWikiSearchService extends GroupService {
17 | @Override
18 | public boolean process(GroupMessageEvent event) {
19 | return event.getMessage().serializeToMiraiCode().startsWith(new At(KleeBot.config.getBotAccount())+" mcws ");
20 | }
21 |
22 | @Override
23 | public boolean execute(GroupMessageEvent event) throws Exception {
24 | String message=event.getMessage().serializeToMiraiCode();
25 | String item=message.substring(message.indexOf("mcws")+5);
26 | if (item.isEmpty()){
27 | return false;
28 | } else{
29 | WikiAPI api=new WikiAPI(KleeBot.config.getProxyHost(),KleeBot.config.getProxyPort());
30 | if (item.contains("CN")){
31 | if (item.contains("img")){
32 | item=item.substring(0,item.indexOf(" "));
33 | byte[] img=api.getElementImage(item,WikiAPI.WIKI_CN);
34 | sendElementImage(event,img);
35 | return true;
36 | } else{
37 | if (item.contains(" ")){
38 | item=item.substring(0,item.indexOf(" "));
39 | }
40 | MCWikiElement element=api.getElement(item,WikiAPI.WIKI_CN);
41 | if (element==null){
42 | sendMessage("未在minecraft wiki中找到 %s 条目".formatted(item),event);
43 | return false;
44 | }
45 | sendElement(event, element);
46 | return true;
47 | }
48 | } else{
49 | if (item.contains("img")){
50 | item=item.substring(0,item.indexOf(" "));
51 | byte[] img=api.getElementImage(item,WikiAPI.WIKI_EN);
52 | sendElementImage(event,img);
53 | return true;
54 | } else{
55 | if (item.contains(" ")){
56 | item=item.substring(0,item.indexOf(" "));
57 | }
58 | MCWikiElement element=api.getElement(item,WikiAPI.WIKI_EN);
59 | if (element==null){
60 | sendMessage("element %s not found in minecraft wiki".formatted(item),event);
61 | return false;
62 | }
63 | sendElement(event, element);
64 | return true;
65 | }
66 | }
67 | }
68 | }
69 | private void sendElementImage(GroupMessageEvent event, byte[] element) throws IOException {
70 | MessageChainBuilder builder=new MessageChainBuilder();
71 | builder.append(new At(event.getSender().getId()));
72 | builder.append(" ");
73 | ExternalResource resource=ExternalResource.create(element);
74 | Image image=event.getSubject().uploadImage(resource);
75 | builder.append(image);
76 | event.getGroup().sendMessage(builder.build());
77 | resource.close();
78 |
79 | }
80 | private void sendElement(GroupMessageEvent event, MCWikiElement element) throws IOException {
81 | MessageChainBuilder builder=new MessageChainBuilder();
82 | builder.append(new At(event.getSender().getId()));
83 | builder.append("\n").append(element.getDescription());
84 | builder.append("\n").append(element.getUrl());
85 | ExternalResource resource=ExternalResource.create(Base64.getDecoder().decode(element.getImage()));
86 | Image image=event.getSubject().uploadImage(resource);
87 | builder.append(image);
88 | event.getGroup().sendMessage(builder.build());
89 | resource.close();
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/src/main/java/glous/kleebot/features/builtin/AbyssInfo.java:
--------------------------------------------------------------------------------
1 | package glous.kleebot.features.builtin;
2 |
3 | import java.io.Serializable;
4 |
5 | public class AbyssInfo implements Serializable {
6 |
7 | public int getTotal_battle_times() {
8 | return total_battle_times;
9 | }
10 |
11 | public void setTotal_battle_times(int total_battle_times) {
12 | this.total_battle_times = total_battle_times;
13 | }
14 |
15 | public int getTotal_win_times() {
16 | return total_win_times;
17 | }
18 |
19 | public void setTotal_win_times(int total_win_times) {
20 | this.total_win_times = total_win_times;
21 | }
22 |
23 | public String getMax_floor() {
24 | return max_floor;
25 | }
26 |
27 | public void setMax_floor(String max_floor) {
28 | this.max_floor = max_floor;
29 | }
30 |
31 | public int getTotal_star() {
32 | return total_star;
33 | }
34 |
35 | public void setTotal_star(int total_star) {
36 | this.total_star = total_star;
37 | }
38 |
39 | public boolean isIs_unlock() {
40 | return is_unlock;
41 | }
42 |
43 | public void setIs_unlock(boolean is_unlock) {
44 | this.is_unlock = is_unlock;
45 | }
46 |
47 | public long getMax_damaged() {
48 | return max_damaged;
49 | }
50 |
51 | public void setMax_damaged(long max_damaged) {
52 | this.max_damaged = max_damaged;
53 | }
54 |
55 | public String getMax_damaged_avatar() {
56 | return max_damaged_avatar;
57 | }
58 |
59 | public void setMax_damaged_avatar(String max_damaged_avatar) {
60 | this.max_damaged_avatar = max_damaged_avatar;
61 | }
62 |
63 | public int getMax_defeat() {
64 | return max_defeat;
65 | }
66 |
67 | public void setMax_defeat(int max_defeat) {
68 | this.max_defeat = max_defeat;
69 | }
70 |
71 | public String getMax_defeat_avatar() {
72 | return max_defeat_avatar;
73 | }
74 |
75 | public void setMax_defeat_avatar(String max_defeat_avatar) {
76 | this.max_defeat_avatar = max_defeat_avatar;
77 | }
78 |
79 | public int getMax_skill() {
80 | return max_skill;
81 | }
82 |
83 | public void setMax_skill(int max_skill) {
84 | this.max_skill = max_skill;
85 | }
86 |
87 | public String getMax_skill_avatar() {
88 | return max_skill_avatar;
89 | }
90 |
91 | public void setMax_skill_avatar(String max_skill_avatar) {
92 | this.max_skill_avatar = max_skill_avatar;
93 | }
94 |
95 | public int getMax_energy_skill() {
96 | return max_energy_skill;
97 | }
98 |
99 | public void setMax_energy_skill(int max_energy_skill) {
100 | this.max_energy_skill = max_energy_skill;
101 | }
102 |
103 | public String getMax_energy_skill_avatar() {
104 | return max_energy_skill_avatar;
105 | }
106 |
107 | public void setMax_energy_skill_avatar(String max_energy_skill_avatar) {
108 | this.max_energy_skill_avatar = max_energy_skill_avatar;
109 | }
110 |
111 | public int getStatus() {
112 | return status;
113 | }
114 |
115 | public void setStatus(int status) {
116 | this.status = status;
117 | }
118 |
119 | public String getErrorMsg() {
120 | return errorMsg;
121 | }
122 |
123 | public void setErrorMsg(String errorMsg) {
124 | this.errorMsg = errorMsg;
125 | }
126 |
127 | private int total_battle_times;
128 | private int total_win_times;
129 | private String max_floor;
130 | private int total_star;
131 | private boolean is_unlock;
132 | private long max_damaged;
133 | private String max_damaged_avatar;
134 | private int max_defeat;
135 | private String max_defeat_avatar;
136 | private int max_skill;
137 | private String max_skill_avatar;
138 | private int max_energy_skill;
139 | private String max_energy_skill_avatar;
140 | private int status;
141 | private String errorMsg;
142 | private AbyssFloor[] floors;
143 |
144 | public AbyssFloor[] getFloors() {
145 | return floors;
146 | }
147 |
148 | public void setFloors(AbyssFloor[] floors) {
149 | this.floors = floors;
150 | }
151 | }
152 |
--------------------------------------------------------------------------------
/src/main/java/glous/kleebot/services/ServiceRegistry.java:
--------------------------------------------------------------------------------
1 | package glous.kleebot.services;
2 |
3 | import net.mamoe.mirai.event.events.GroupMessageEvent;
4 | import net.mamoe.mirai.message.data.At;
5 | import net.mamoe.mirai.message.data.MessageChainBuilder;
6 | import glous.kleebot.KleeBot;
7 | import glous.kleebot.log.Logger;
8 |
9 | import java.io.IOException;
10 | import java.io.PrintWriter;
11 | import java.io.StringWriter;
12 | import java.lang.reflect.InvocationTargetException;
13 | import java.util.HashMap;
14 |
15 | public class ServiceRegistry {
16 | private static final HashMap serviceMap=new HashMap<>();
17 | private static final HashMap enabledServiceMap=new HashMap<>();
18 | private static final Logger logger=Logger.getLogger(ServiceRegistry.class);
19 | @SuppressWarnings("unchecked")
20 | public static void register(Class service) throws InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException, IOException {
21 | serviceMap.put(service.getName(),(Service)service.getDeclaredConstructor().newInstance());
22 | }
23 | public static void init() throws IOException {
24 | for (Service service:serviceMap.values()){
25 | if (KleeBot.configurationInstance.contains(service.getClass().getName())&&KleeBot.configurationInstance.getBoolean(service.getClass().getName())){
26 | enabledServiceMap.put(service.getClass().getName(),service);
27 | }
28 | service.initialize();
29 | }
30 | }
31 | public static String[] getAllEnabledService(){
32 | return enabledServiceMap.keySet().toArray(new String[enabledServiceMap.size()]);
33 | }
34 | public static String[] getAllRegisteredServices(){
35 | return serviceMap.keySet().toArray(new String[0]);
36 | }
37 |
38 | public static HashMap getEnabledServiceMap() {
39 | return enabledServiceMap;
40 | }
41 |
42 | public static HashMap getServiceMap() {
43 | return serviceMap;
44 | }
45 |
46 | public static void processGroupMessage(GroupMessageEvent rawMessage){
47 | for (Service service:enabledServiceMap.values()){
48 | if (service instanceof GroupService){
49 | if (((GroupService) service).process(rawMessage)){
50 | KleeBot.queue.addTask(()->{
51 | logger.trace("Post task %s to execute".formatted(service.getServiceName()));
52 | try {
53 | boolean success=((GroupService) service).execute(rawMessage);
54 | if (!success){
55 | MessageChainBuilder builder=new MessageChainBuilder();
56 | builder.append(new At(rawMessage.getSender().getId()));
57 | builder.append(" 未定义用法。请发送KleeBot Help以获取详细信息");
58 | rawMessage.getGroup().sendMessage(builder.build());
59 | }
60 | } catch (Exception e) {
61 | StringWriter writer=new StringWriter();
62 | PrintWriter pw=new PrintWriter(writer);
63 | e.printStackTrace(pw);
64 | MessageChainBuilder builder=new MessageChainBuilder();
65 | builder.append(new At(rawMessage.getSender().getId()));
66 | builder.append(" 运行异常。错误信息:");
67 | builder.append(writer.toString());
68 | builder.append("\n若非用法错误,请上报ISSUES到https://www.github.com/youfantan/KleeBot/issues");
69 | rawMessage.getGroup().sendMessage(builder.build());
70 | try {
71 | writer.close();
72 | } catch (IOException ioException) {
73 | ioException.printStackTrace();
74 | }
75 | pw.close();
76 | }
77 | },service.getServiceName());
78 | }
79 | }
80 | }
81 | }
82 | public static void stop(){
83 | for (Service service:serviceMap.values()){
84 | service.stop();
85 | }
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/src/main/java/glous/kleebot/log/Logger.java:
--------------------------------------------------------------------------------
1 | package glous.kleebot.log;
2 |
3 | import glous.kleebot.KleeBot;
4 |
5 | import java.io.*;
6 | import java.nio.charset.StandardCharsets;
7 | import java.text.SimpleDateFormat;
8 | import java.util.Date;
9 | import java.util.zip.GZIPOutputStream;
10 |
11 | public class Logger {
12 | private static final StringWriter strOut=new StringWriter();
13 | private static File logFile;
14 | public static void init(){
15 | Date date=new Date();
16 | String fileTimeFormat="yyyy-MM-dd-HH.mm.ss";
17 | SimpleDateFormat formatter=new SimpleDateFormat(fileTimeFormat);
18 | String fileTime=formatter.format(date);
19 | File logDir=new File("logs");
20 | if (!logDir.exists()){
21 | boolean ret=logDir.mkdir();
22 | if (!ret){
23 | System.out.println("logs目录创建失败,请检查权限。");
24 | System.exit(-1);
25 | }
26 | }
27 | logFile=new File("logs"+File.separatorChar+fileTime+".log.gz");
28 | if (!logFile.exists()){
29 | try {
30 | boolean ret=logFile.createNewFile();
31 | if (!ret){
32 | System.out.println("log文件创建失败,请检查权限。");
33 | System.exit(-1);
34 | }
35 | } catch (IOException e) {
36 | e.printStackTrace();
37 | }
38 | }
39 | writer=new BufferedWriter(strOut);
40 | }
41 | public static Logger getLogger(Class clz){
42 | return new Logger(clz);
43 | }
44 | private Class clz;
45 | private static BufferedWriter writer;
46 | private Logger(Class clz) {
47 | this.clz=clz;
48 | }
49 | private String getFormattedMessage(String level,String message){
50 | String consoleTimeFormat="yyyy-MM-dd-HH:mm:ss";
51 | Date date=new Date();
52 | SimpleDateFormat formatter=new SimpleDateFormat(consoleTimeFormat);
53 | String consoleTime=formatter.format(date);
54 | String threadName=Thread.currentThread().getName();
55 | String className=clz.getSimpleName();
56 | return """
57 | %s [%s/%s/%s]: %s
58 | """.formatted(consoleTime,level,className,threadName,message);
59 | }
60 | public void info(String message){
61 | String formattedMessage=getFormattedMessage("INFO",message);
62 | System.out.print(formattedMessage);
63 | try {
64 | writer.write(formattedMessage);
65 | } catch (IOException e) {
66 | e.printStackTrace();
67 | }
68 | }
69 | public void trace(String message){
70 | String formattedMessage=getFormattedMessage("TRACE",message);
71 | try {
72 | writer.write(formattedMessage);
73 | } catch (IOException e) {
74 | e.printStackTrace();
75 | }
76 | }
77 | public void debug(String message){
78 | if (KleeBot.ENBALE_DEBUG){
79 | String formattedMessage=getFormattedMessage("DEBUG",message);
80 | System.out.print(formattedMessage);
81 | try {
82 | writer.write(formattedMessage);
83 | } catch (IOException e) {
84 | e.printStackTrace();
85 | }
86 | }
87 | }
88 | public void error(String message){
89 | String formattedMessage=getFormattedMessage("ERROR",message);
90 | System.out.print(formattedMessage);
91 | try {
92 | writer.write(formattedMessage);
93 | } catch (IOException e) {
94 | e.printStackTrace();
95 | }
96 | }
97 | public void fatal(String message){
98 | String formattedMessage=getFormattedMessage("FATAL",message);
99 | System.out.print(formattedMessage);
100 | try {
101 | writer.write(formattedMessage);
102 | } catch (IOException e) {
103 | e.printStackTrace();
104 | }
105 | }
106 | public static void stop(){
107 | try {
108 | writer.flush();
109 | writer.close();
110 | strOut.flush();
111 | strOut.close();
112 | GZIPOutputStream gout=new GZIPOutputStream(new FileOutputStream(logFile));
113 | gout.write(strOut.toString().getBytes(StandardCharsets.UTF_8));
114 | gout.close();
115 | } catch (IOException e) {
116 | e.printStackTrace();
117 | }
118 | }
119 | }
120 |
--------------------------------------------------------------------------------
/web/BotStatus/materialize/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | MaterializeCSS
8 |
9 |
10 | Materialize, a CSS Framework based on material design.
11 |
12 | -- Browse the docs --
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 | ## Table of Contents
36 | - [Quickstart](#quickstart)
37 | - [Documentation](#documentation)
38 | - [Supported Browsers](#supported-browsers)
39 | - [Changelog](#changelog)
40 | - [Testing](#testing)
41 | - [Contributing](#contributing)
42 | - [Copyright and license](#copyright-and-license)
43 |
44 | ## Quickstart:
45 | Read the [getting started guide](http://materializecss.com/getting-started.html) for more information on how to use materialize.
46 |
47 | - [Download the latest release](https://github.com/Dogfalo/materialize/releases/latest) of materialize directly from GitHub. ([Beta](https://github.com/Dogfalo/materialize/releases/))
48 | - Clone the repo: `git clone https://github.com/Dogfalo/materialize.git` (Beta: `git clone -b v1-dev https://github.com/Dogfalo/materialize.git`)
49 | - Include the files via [cdnjs](https://cdnjs.com/libraries/materialize). More [here](http://materializecss.com/getting-started.html). ([Beta](https://cdnjs.com/libraries/materialize/1.0.0-beta))
50 | - Install with [npm](https://www.npmjs.com): `npm install materialize-css` (Beta: `npm install materialize-css@next`)
51 | - Install with [Bower](https://bower.io): `bower install materialize` ([DEPRECATED](https://bower.io/blog/2017/how-to-migrate-away-from-bower/))
52 | - Install with [Atmosphere](https://atmospherejs.com): `meteor add materialize:materialize` (Beta: `meteor add materialize:materialize@=1.0.0-beta`)
53 |
54 | ## Documentation
55 | The documentation can be found at . To run the documentation locally on your machine, you need [Node.js](https://nodejs.org/en/) installed on your computer.
56 |
57 | ### Running documentation locally
58 | Run these commands to set up the documentation:
59 |
60 | ```bash
61 | git clone https://github.com/Dogfalo/materialize
62 | cd materialize
63 | npm install
64 | ```
65 |
66 | Then run `grunt monitor` to compile the documentation. When it finishes, open a new browser window and navigate to `localhost:8000`. We use [BrowserSync](https://www.browsersync.io/) to display the documentation.
67 |
68 | ### Documentation for previous releases
69 | Previous releases and their documentation are available for [download](https://github.com/Dogfalo/materialize/releases).
70 |
71 | ## Supported Browsers:
72 | Materialize is compatible with:
73 |
74 | - Chrome 35+
75 | - Firefox 31+
76 | - Safari 9+
77 | - Opera
78 | - Edge
79 | - IE 11+
80 |
81 | ## Changelog
82 | For changelogs, check out [the Releases section of materialize](https://github.com/Dogfalo/materialize/releases) or the [CHANGELOG.md](CHANGELOG.md).
83 |
84 | ## Testing
85 | We use Jasmine as our testing framework and we're trying to write a robust test suite for our components. If you want to help, [here's a starting guide on how to write tests in Jasmine](CONTRIBUTING.md#jasmine-testing-guide).
86 |
87 | ## Contributing
88 | Check out the [CONTRIBUTING document](CONTRIBUTING.md) in the root of the repository to learn how you can contribute. You can also browse the [help-wanted](https://github.com/Dogfalo/materialize/labels/help-wanted) tag in our issue tracker to find things to do.
89 |
90 | ## Copyright and license
91 | Code Copyright 2018 Materialize. Code released under the MIT license.
92 |
--------------------------------------------------------------------------------
/src/main/java/glous/kleebot/services/impl/GenshinAbyssService.java:
--------------------------------------------------------------------------------
1 | package glous.kleebot.services.impl;
2 |
3 | import glous.kleebot.features.builtin.AbyssFloor;
4 | import glous.kleebot.features.builtin.AbyssInfo;
5 | import net.mamoe.mirai.event.events.GroupMessageEvent;
6 | import net.mamoe.mirai.message.data.At;
7 | import net.mamoe.mirai.message.data.Image;
8 | import net.mamoe.mirai.message.data.MessageChainBuilder;
9 | import net.mamoe.mirai.utils.ExternalResource;
10 | import glous.kleebot.KleeBot;
11 | import glous.kleebot.features.genshin.GenshinAPI;
12 | import glous.kleebot.services.GroupService;
13 | import glous.kleebot.utils.FileUtils;
14 | import glous.kleebot.utils.StringUtils;
15 |
16 | import java.nio.charset.StandardCharsets;
17 | import java.util.Base64;
18 |
19 | public class GenshinAbyssService extends GroupService {
20 | @Override
21 | public boolean process(GroupMessageEvent event) {
22 | return event.getMessage().serializeToMiraiCode().startsWith(new At(KleeBot.config.getBotAccount())+" gabyss ");
23 | }
24 |
25 | @Override
26 | public boolean execute(GroupMessageEvent event) throws Exception {
27 | String rawMessage=event.getMessage().serializeToMiraiCode();
28 | String uid=rawMessage.substring(rawMessage.indexOf("gabyss")+7);
29 | if ((uid= StringUtils.findDigit(uid))!=null){
30 | String cookie= FileUtils.readFile(KleeBot.config.getCookieFile(), StandardCharsets.UTF_8);
31 | if (cookie==null){
32 | sendErrorMessage(event,"米游社cookie文件不存在,请联系bot管理员修复。");
33 | return false;
34 | }
35 | GenshinAPI api=new GenshinAPI(cookie);
36 | AbyssInfo info;
37 | if (rawMessage.endsWith("CN")){
38 | info=api.getSpiralAbyssInfo(GenshinAPI.GENSHIN_CHINA,uid);
39 | } else if (rawMessage.endsWith("CN_B")){
40 | info=api.getSpiralAbyssInfo(GenshinAPI.GENSHIN_CHINA_BILIBILI,uid);
41 | } else{
42 | info=api.getSpiralAbyssInfo(GenshinAPI.GENSHIN_CHINA,uid);
43 | }
44 | if (info.getStatus()==0) {
45 | if (rawMessage.contains("img")){
46 | String encodedImg=api.generateAbyssInfoImage(info);
47 | ExternalResource resource=ExternalResource.create(Base64.getDecoder().decode(encodedImg));
48 | Image image=event.getSubject().uploadImage(resource);
49 | MessageChainBuilder builder=new MessageChainBuilder();
50 | builder.append(new At(event.getSender().getId()));
51 | builder.append(image);
52 | event.getGroup().sendMessage(builder.build());
53 | resource.close();
54 | } else {
55 | MessageChainBuilder builder=new MessageChainBuilder();
56 | builder.append(new At(event.getSender().getId()));
57 | builder.append("\n%s 的深渊信息:\n".formatted(uid));
58 | builder.append(
59 | """
60 | 最深抵达: %s
61 | 总渊星数: %d
62 | 出战次数: %d
63 | 最多击败数: %d
64 | 最大伤害数: %d
65 | 最大元素爆发数 %d
66 | 最大元素战技数: %d
67 | """.formatted(info.getMax_floor(),info.getTotal_star(),info.getTotal_battle_times(),info.getMax_defeat(),info.getMax_damaged(),info.getMax_energy_skill(),info.getMax_skill())
68 | );
69 | builder.append("单层数据:\n");
70 | for (AbyssFloor floor:info.getFloors()){
71 | int total=floor.getMax_star();
72 | int get=floor.getStar();
73 | float progress=(float) get/total;
74 | builder.append("\t层数: %d 获取渊星数: %d/%d 进度: %.2f\n".formatted(floor.getIndex(),get,total,progress*100));
75 | }
76 | event.getGroup().sendMessage(builder.build());
77 | }
78 | } else{
79 | sendErrorMessage(event,"发生错误,错误信息:%s".formatted(info.getErrorMsg()));
80 | return false;
81 | }
82 | }
83 | return true;
84 | }
85 | private void sendErrorMessage(GroupMessageEvent event,String errorMessage){
86 | MessageChainBuilder builder=new MessageChainBuilder();
87 | builder.append(new At(event.getSender().getId()));
88 | builder.append(" 无法通过UID获取玩家信息。错误信息:\n%s".formatted(errorMessage));
89 | event.getGroup().sendMessage(builder.build());
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/native/HardwareInfo/HardwareInfo.cc:
--------------------------------------------------------------------------------
1 | #include "include/glous_kleebot_services_api_HardwareInfo.h"
2 | #ifdef WIN32
3 | #include
4 | #include
5 | #endif
6 | #ifdef __linux__
7 | #include
8 | #endif
9 | JNIEXPORT jstring JNICALL Java_glous_kleebot_services_api_HardwareInfo_getCpuModel
10 | (JNIEnv * env, jobject){
11 | #ifdef WIN32
12 | int cpuInfo[4] = {-1};
13 | char cpu_type[32]={0};
14 | char cpu_name[32]={0};
15 | char cpu_freq[32]={0};
16 | char cpu_full_name[64]={0};
17 | __cpuid(cpuInfo, 0x80000003);
18 | memcpy(cpu_type, cpuInfo, sizeof(cpuInfo));
19 | __cpuid(cpuInfo, 0x80000002);
20 | memcpy(cpu_name, cpuInfo, sizeof(cpuInfo));
21 | __cpuid(cpuInfo, 0x80000004);
22 | memcpy(cpu_freq, cpuInfo, sizeof(cpuInfo));
23 | strcat(cpu_full_name,cpu_name);
24 | strcat(cpu_full_name,cpu_type);
25 | strcat(cpu_full_name,cpu_freq);
26 | return env->NewStringUTF(cpu_full_name);
27 | #endif
28 | }
29 |
30 | /*
31 | * Class: shandiankulishe_kleebot_services_api_HardwareInfo
32 | * Method: getCpuClockCycle
33 | * Signature: ()J
34 | */
35 | JNIEXPORT jlong JNICALL Java_glous_kleebot_services_api_HardwareInfo_getCpuClockCycle
36 | (JNIEnv *, jobject){
37 | #ifdef WIN32
38 | unsigned __int64 t1,t2;
39 | t1 = __rdtsc();
40 | Sleep(1000);
41 | t2 = __rdtsc();
42 | unsigned __int64 freq=(t2 - t1) / 1000000;
43 | return freq;
44 | #endif
45 | #ifdef __linux__
46 | unsigned long long t1;
47 | __asm__ __volatile__ ("rdtsc" : "=A" (t1));
48 | sleep(1);
49 | unsigned long long t2;
50 | __asm__ __volatile__ ("rdtsc" : "=A" (t2));
51 | return (long long)(t2-t1)/1000000;
52 | #endif
53 | }
54 |
55 | /*
56 | * Class: shandiankulishe_kleebot_services_api_HardwareInfo
57 | * Method: getCpuUsage
58 | * Signature: ()D
59 | */
60 |
61 | #ifdef WIN32
62 | __int64 Filetime2Int64(const FILETIME &ftime)
63 | {
64 | LARGE_INTEGER li;
65 | li.LowPart = ftime.dwLowDateTime;
66 | li.HighPart = ftime.dwHighDateTime;
67 | return li.QuadPart;
68 | }
69 | __int64 CompareFileTime2(const FILETIME &preTime, const FILETIME &nowTime)
70 | {
71 | return Filetime2Int64(nowTime) - Filetime2Int64(preTime);
72 | }
73 | #endif
74 |
75 |
76 | JNIEXPORT jdouble JNICALL Java_glous_kleebot_services_api_HardwareInfo_getCpuUsage
77 | (JNIEnv *, jobject){
78 | #ifdef WIN32
79 | FILETIME preIdleTime;
80 | FILETIME preKernelTime;
81 | FILETIME preUserTime;
82 | GetSystemTimes(&preIdleTime, &preKernelTime, &preUserTime);
83 | Sleep(1000);
84 | FILETIME idleTime;
85 | FILETIME kernelTime;
86 | FILETIME userTime;
87 | GetSystemTimes(&idleTime, &kernelTime, &userTime);
88 | auto idle = CompareFileTime2(preIdleTime, idleTime);
89 | auto kernel = CompareFileTime2(preKernelTime, kernelTime);
90 | auto user = CompareFileTime2(preUserTime, userTime);
91 | if (kernel + user == 0)
92 | return 0;
93 | return 1.0 * (kernel + user - idle) / (kernel + user);
94 | #endif
95 | }
96 |
97 | /*
98 | * Class: shandiankulishe_kleebot_services_api_HardwareInfo
99 | * Method: getCpuAvailableCores
100 | * Signature: ()Ljava/lang/String;
101 | */
102 | JNIEXPORT jint JNICALL Java_glous_kleebot_services_api_HardwareInfo_getCpuAvailableCores
103 | (JNIEnv *, jobject){
104 | #ifdef WIN32
105 | SYSTEM_INFO info;
106 | GetSystemInfo(&info);
107 | return info.dwNumberOfProcessors;
108 | #endif
109 | }
110 |
111 | /*
112 | * Class: shandiankulishe_kleebot_services_api_HardwareInfo
113 | * Method: getTotalMemory
114 | * Signature: ()Ljava/lang/String;
115 | */
116 | JNIEXPORT jlong JNICALL Java_glous_kleebot_services_api_HardwareInfo_getTotalMemory
117 | (JNIEnv *, jobject){
118 | #ifdef WIN32
119 | MEMORYSTATUS ms;
120 | GlobalMemoryStatus(&ms);
121 | return ms.dwTotalPhys;
122 | #endif
123 | }
124 |
125 | /*
126 | * Class: shandiankulishe_kleebot_services_api_HardwareInfo
127 | * Method: getAvailableMemory
128 | * Signature: ()Ljava/lang/String;
129 | */
130 | JNIEXPORT jlong JNICALL Java_glous_kleebot_services_api_HardwareInfo_getAvailableMemory
131 | (JNIEnv *, jobject){
132 | #ifdef WIN32
133 | MEMORYSTATUS ms;
134 | GlobalMemoryStatus(&ms);
135 | return ms.dwAvailPhys;
136 | #endif
137 | }
138 |
139 | /*
140 | * Class: shandiankulishe_kleebot_services_api_HardwareInfo
141 | * Method: getProcessID
142 | * Signature: ()J
143 | */
144 | JNIEXPORT jlong JNICALL Java_glous_kleebot_services_api_HardwareInfo_getProcessID
145 | (JNIEnv *, jobject){
146 | #ifdef WIN32
147 | return GetCurrentProcessId();
148 | #endif
149 | #ifdef __linux__
150 | return getpid();
151 | #endif
152 | }
--------------------------------------------------------------------------------
/src/main/java/glous/kleebot/cache/CacheFactory.java:
--------------------------------------------------------------------------------
1 | package glous.kleebot.cache;
2 |
3 | import glous.kleebot.KleeBot;
4 | import glous.kleebot.utils.FileUtils;
5 |
6 | import java.io.ByteArrayInputStream;
7 | import java.io.ByteArrayOutputStream;
8 | import java.io.File;
9 | import java.io.IOException;
10 | import java.lang.reflect.Field;
11 | import java.nio.charset.StandardCharsets;
12 | import java.util.*;
13 | import java.util.zip.CRC32;
14 |
15 | public class CacheFactory {
16 | public static byte[] long2byte(long res) {
17 | byte[] buffer = new byte[8];
18 | for (int i = 0; i < 8; i++) {
19 | int offset = 64 - (i + 1) * 8;
20 | buffer[i] = (byte) ((res >> offset) & 0xff);
21 | }
22 | return buffer;
23 | }
24 | public static String getCacheName(){
25 | CRC32 code=new CRC32();
26 | code.reset();
27 | long cTime=System.currentTimeMillis();
28 | byte[] time=long2byte(cTime);
29 | code.update(time);
30 | return Long.toHexString(code.getValue());
31 | }
32 | private static HashMap cacheMap=new HashMap<>();
33 | public static void storeCache(String name, byte[] content, long expired){
34 | String cachePath;
35 | Cache cache;
36 | if ((cachePath=cacheMap.get(name))!=null){
37 | cache=Cache.restore(cachePath);
38 | try {
39 | Field fContent=cache.getClass().getDeclaredField("content");
40 | Field fExpired=cache.getClass().getDeclaredField("expired");
41 | fContent.setAccessible(true);
42 | fExpired.setAccessible(true);
43 | fContent.set(cache,content);
44 | fExpired.set(cache,expired);
45 | cache.store();
46 | } catch (NoSuchFieldException | IllegalAccessException e) {
47 | e.printStackTrace();
48 | }
49 | } else{
50 | cache=new Cache(content,expired);
51 | cache.store();
52 | cacheMap.put(name,cache.getCachePath());
53 | }
54 | }
55 | public static byte[] getCache(String cacheName){ ;
56 | if (cacheMap.containsKey(cacheName)){
57 | Cache cache=Cache.restore(cacheMap.get(cacheName));
58 | long saved=System.currentTimeMillis()-cache.getSaveTime();
59 | if (cache.getExpired()==-1||saved s:
68 | cacheMap.entrySet()) {
69 | bout.write(s.getKey().getBytes(StandardCharsets.UTF_8));
70 | bout.write(0x01);
71 | bout.write(s.getValue().getBytes(StandardCharsets.UTF_8));
72 | bout.write(0x02);
73 | }
74 | bout.flush();
75 | bout.close();
76 | FileUtils.writeFile(KleeBot.config.getCacheDir()+File.separatorChar+"cache.map",bout.toByteArray());
77 | }
78 | public static void deserializeCaches() throws IOException {
79 | if (new File(KleeBot.config.getCacheDir()+File.separatorChar+"cache.map").exists()){
80 | ByteArrayInputStream bin=new ByteArrayInputStream(Objects.requireNonNull(FileUtils.readFile(KleeBot.config.getCacheDir() + File.separatorChar + "cache.map")));
81 | byte[] total=bin.readAllBytes();
82 | ByteArrayOutputStream key=new ByteArrayOutputStream();
83 | ByteArrayOutputStream value=new ByteArrayOutputStream();
84 | boolean status=true;
85 | for (byte b :
86 | total) {
87 | if (status){
88 | if (b==0x01){
89 | status=false;
90 | } else{
91 | key.write(b);
92 | }
93 | } else{
94 | if (b!=0x02){
95 | value.write(b);
96 | } else{
97 | String sKey= key.toString(StandardCharsets.UTF_8);
98 | String sValue=value.toString(StandardCharsets.UTF_8);
99 | cacheMap.put(sKey,sValue);
100 | key.close();
101 | value.close();
102 | key=new ByteArrayOutputStream();
103 | value=new ByteArrayOutputStream();
104 | status=true;
105 | }
106 | }
107 | }
108 | key.close();
109 | value.close();
110 | }
111 | }
112 | }
113 |
--------------------------------------------------------------------------------
/src/main/java/glous/kleebot/features/builtin/PlayerInfo.java:
--------------------------------------------------------------------------------
1 | package glous.kleebot.features.builtin;
2 |
3 | import java.io.Serializable;
4 |
5 | public class PlayerInfo implements Serializable {
6 | public PlayerInfo(){};
7 |
8 | public Role[] getRoles() {
9 | return roles;
10 | }
11 |
12 | public void setRoles(Role[] roles) {
13 | this.roles = roles;
14 | }
15 |
16 | public World[] getWorlds() {
17 | return worlds;
18 | }
19 |
20 | public void setWorlds(World[] worlds) {
21 | this.worlds = worlds;
22 | }
23 |
24 | public int getElectroculus_number() {
25 | return electroculus_number;
26 | }
27 |
28 | public void setElectroculus_number(int electroculus_number) {
29 | this.electroculus_number = electroculus_number;
30 | }
31 |
32 | public int getGeoculus_number() {
33 | return geoculus_number;
34 | }
35 |
36 | public void setGeoculus_number(int geoculus_number) {
37 | this.geoculus_number = geoculus_number;
38 | }
39 |
40 | public int getAnemoculus_number() {
41 | return anemoculus_number;
42 | }
43 |
44 | public void setAnemoculus_number(int anemoculus_number) {
45 | this.anemoculus_number = anemoculus_number;
46 | }
47 |
48 | public int getAvatar_number() {
49 | return avatar_number;
50 | }
51 |
52 | public void setAvatar_number(int avatar_number) {
53 | this.avatar_number = avatar_number;
54 | }
55 |
56 | public int getDomain_number() {
57 | return domain_number;
58 | }
59 |
60 | public void setDomain_number(int domain_number) {
61 | this.domain_number = domain_number;
62 | }
63 |
64 | public int getCommon_chest_number() {
65 | return common_chest_number;
66 | }
67 |
68 | public void setCommon_chest_number(int common_chest_number) {
69 | this.common_chest_number = common_chest_number;
70 | }
71 |
72 | public int getExquisite_chest_number() {
73 | return exquisite_chest_number;
74 | }
75 |
76 | public void setExquisite_chest_number(int exquisite_chest_number) {
77 | this.exquisite_chest_number = exquisite_chest_number;
78 | }
79 |
80 | public int getPrecious_chest_number() {
81 | return precious_chest_number;
82 | }
83 |
84 | public void setPrecious_chest_number(int precious_chest_number) {
85 | this.precious_chest_number = precious_chest_number;
86 | }
87 |
88 | public int getLuxurious_chest_number() {
89 | return luxurious_chest_number;
90 | }
91 |
92 | public void setLuxurious_chest_number(int luxurious_chest_number) {
93 | this.luxurious_chest_number = luxurious_chest_number;
94 | }
95 |
96 | public int getMagic_chest_number() {
97 | return magic_chest_number;
98 | }
99 |
100 | public void setMagic_chest_number(int magic_chest_number) {
101 | this.magic_chest_number = magic_chest_number;
102 | }
103 |
104 | public int getActive_day_number() {
105 | return active_day_number;
106 | }
107 |
108 | public void setActive_day_number(int active_day_number) {
109 | this.active_day_number = active_day_number;
110 | }
111 |
112 | public int getAchievement_number() {
113 | return achievement_number;
114 | }
115 |
116 | public void setAchievement_number(int achievement_number) {
117 | this.achievement_number = achievement_number;
118 | }
119 |
120 | public String getSpiral_abyss() {
121 | return spiral_abyss;
122 | }
123 |
124 | public void setSpiral_abyss(String spiral_abyss) {
125 | this.spiral_abyss = spiral_abyss;
126 | }
127 |
128 | public String getErrorMsg() {
129 | return errorMsg;
130 | }
131 |
132 | public void setErrorMsg(String errorMsg) {
133 | this.errorMsg = errorMsg;
134 | }
135 |
136 | private String errorMsg;
137 |
138 | public int getStatus() {
139 | return status;
140 | }
141 |
142 | public void setStatus(int status) {
143 | this.status = status;
144 | }
145 |
146 | private int status;
147 | private Role[] roles;
148 | private World[] worlds;
149 | private int electroculus_number;
150 | private int geoculus_number;
151 | private int anemoculus_number;
152 | private int avatar_number;
153 | private int domain_number;
154 | private int common_chest_number;
155 | private int exquisite_chest_number;
156 | private int precious_chest_number;
157 | private int luxurious_chest_number;
158 | private int magic_chest_number;
159 | private int active_day_number;
160 | private int achievement_number;
161 | private String spiral_abyss;
162 |
163 | public String getUid() {
164 | return uid;
165 | }
166 |
167 | public void setUid(String uid) {
168 | this.uid = uid;
169 | }
170 |
171 | private String uid;
172 | }
173 |
--------------------------------------------------------------------------------
/src/main/java/glous/kleebot/features/bilibili/BilibiliAPI.java:
--------------------------------------------------------------------------------
1 | package glous.kleebot.features.bilibili;
2 |
3 | import com.google.gson.Gson;
4 | import com.google.gson.JsonObject;
5 | import com.google.gson.JsonParser;
6 | import com.google.gson.stream.JsonWriter;
7 | import glous.kleebot.services.builtin.BilibiliVideoInf;
8 | import glous.kleebot.References;
9 | import glous.kleebot.async.Timer;
10 | import glous.kleebot.cache.CacheFactory;
11 | import glous.kleebot.utils.FileUtils;
12 | import glous.kleebot.utils.HttpUtils;
13 | import glous.kleebot.utils.RandomUtils;
14 | import glous.kleebot.utils.builtin.HttpResponse;
15 |
16 | import java.io.IOException;
17 | import java.io.StringWriter;
18 | import java.net.HttpURLConnection;
19 | import java.net.URL;
20 | import java.nio.charset.StandardCharsets;
21 | import java.util.Map;
22 |
23 | public class BilibiliAPI {
24 | public String getShortUrl(String originUrl) throws IOException {
25 | StringWriter writer=new StringWriter();
26 | JsonWriter json=new JsonWriter(writer);
27 | json.beginObject();
28 | json.name("build").value(6500300);
29 | json.name("buvid").value(RandomUtils.newRandomMixedString(32)+"infoc");
30 | json.name("oid").value(originUrl);
31 | json.name("platform").value("android");
32 | json.name("share_channel").value("COPY");
33 | json.name("share_id").value("public.webview.0.0.pv");
34 | json.name("share_mode").value(3);
35 | json.endObject();
36 | json.close();
37 | writer.close();
38 | HttpUtils httpUtils=new HttpUtils();
39 | HttpResponse resp=httpUtils.post(References.BILIBILI_SHORT_URL,null,Map.of("Content-Type","application/json"),writer.toString().getBytes(StandardCharsets.UTF_8));
40 | if (resp.getResponseCode()!=200){
41 | return "error return value: "+resp.getResponseCode();
42 | }
43 | JsonObject object= JsonParser.parseString(new String(resp.getBody(),StandardCharsets.UTF_8)).getAsJsonObject();
44 | if (!object.has("data")){
45 | return object.get("message").getAsString();
46 | }
47 | JsonObject data=object.get("data").getAsJsonObject();
48 | if (!data.has("content")){
49 | return "not a url like [bilibili/hdslb]";
50 | }
51 | return data.get("content").getAsString();
52 | }
53 | public String getBVid(String rawUrl){
54 | if (rawUrl.length() headers=new HashMap<>();
25 | headers.put("referer","http://www.pixiv.net");
26 | headers.put("user-agent","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.102 Safari/537.36");
27 | byte[] cache;
28 | if ((cache=CacheFactory.getCache(url))!=null){
29 | return cache;
30 | } else {
31 | byte[] content=FileUtils.download(url,proxy,headers);
32 | CacheFactory.storeCache(url,content, Timer.NO_LIMIT);
33 | return content;
34 | }
35 | }
36 | public HashMap getArtwork(int illustid) {
37 | HashMap artwork = new LinkedHashMap<>();
38 | String url = References.PIXIV_ILLUST_API.formatted(illustid);
39 | HashMap headers = new HashMap<>();
40 | headers.put("referer", "http://www.pixiv.net");
41 | headers.put("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.102 Safari/537.36");
42 | String retApi;
43 | byte[] cache;
44 | if ((cache = CacheFactory.getCache("illust:" + illustid)) != null) {
45 | retApi = new String(cache, StandardCharsets.UTF_8);
46 | } else {
47 | byte[] api=FileUtils.download(url, proxy, headers);
48 | if (api==null){
49 | return null;
50 | }
51 | retApi=new String(api,StandardCharsets.UTF_8);
52 | CacheFactory.storeCache("illust:"+illustid,retApi.getBytes(StandardCharsets.UTF_8),Timer.NO_LIMIT);
53 | }
54 | JsonObject object=JsonParser.parseString(retApi).getAsJsonObject();
55 | JsonObject body=object.get("body").getAsJsonObject();
56 | artwork.put("title",body.get("illustTitle").getAsString());
57 | artwork.put("author",body.get("userName").getAsString());
58 | if (body.get("xRestrict").getAsInt()==0){
59 | artwork.put("sexual","false");
60 | } else{
61 | artwork.put("sexual","true");
62 | }
63 | artwork.put("imageUrl",body.get("urls").getAsJsonObject().get("original").getAsString());
64 | artwork.put("date",body.get("uploadDate").getAsString());
65 | return artwork;
66 | }
67 | public HashMap> getDailyRanking() throws IOException {
68 | return getRanking(References.PIXIV_RANKING_DAILY,true);
69 | }
70 | public HashMap> getWeeklyRanking() throws IOException {
71 | return getRanking(References.PIXIV_RANKING_WEEKLY,true);
72 | }
73 | public HashMap> getMonthlyRanking() throws IOException {
74 | return getRanking(References.PIXIV_RANKING_MONTHLY,true);
75 | }
76 | public HashMap> getDailyRanking(boolean useCache) throws IOException {
77 | return getRanking(References.PIXIV_RANKING_DAILY,useCache);
78 | }
79 | public HashMap> getWeeklyRanking(boolean useCache) throws IOException {
80 | return getRanking(References.PIXIV_RANKING_WEEKLY,useCache);
81 | }
82 | public HashMap> getMonthlyRanking(boolean useCache) throws IOException {
83 | return getRanking(References.PIXIV_RANKING_MONTHLY,useCache);
84 | }
85 | public HashMap> getRanking(String url,boolean useCache) throws IOException {
86 | HashMap> result=new HashMap<>();
87 | String retApi;
88 | byte[] cacheContent;
89 | if ((cacheContent=CacheFactory.getCache(url))!=null&&useCache){
90 | retApi=new String(cacheContent,StandardCharsets.UTF_8);
91 | } else{
92 | retApi= new String(FileUtils.download(url,proxy), StandardCharsets.UTF_8);
93 | CacheFactory.storeCache(url,retApi.getBytes(StandardCharsets.UTF_8), Timer.HOUR);
94 | }
95 | JsonObject object=JsonParser.parseString(retApi).getAsJsonObject();
96 | JsonArray array=object.get("contents").getAsJsonArray();
97 | for (int i=0;i artwork=getArtwork(Integer.parseInt(content.get("illust_id").getAsString()));
100 | result.put(i,artwork);
101 | }
102 | return result;
103 | }
104 | }
105 |
--------------------------------------------------------------------------------
/src/main/java/glous/kleebot/features/minecraft/PingAPI.java:
--------------------------------------------------------------------------------
1 | package glous.kleebot.features.minecraft;
2 |
3 | import com.google.gson.*;
4 | import glous.kleebot.features.builtin.MCPacket;
5 | import glous.kleebot.features.builtin.MCServerMOTD;
6 | import glous.kleebot.features.builtin.VariableInt;
7 |
8 | import java.io.*;
9 | import java.net.Socket;
10 | import java.nio.charset.StandardCharsets;
11 |
12 | public class PingAPI {
13 | String host;
14 | int port;
15 | public PingAPI(String host,int port){
16 | this.host=host;
17 | this.port=port;
18 | }
19 | public MCServerMOTD ping() throws IOException {
20 | MCServerMOTD motd=new MCServerMOTD();
21 | try(Socket socket=new Socket(host,port)){
22 | motd.setStatus(0);
23 | DataInputStream in=new DataInputStream(socket.getInputStream());
24 | DataOutputStream out=new DataOutputStream(socket.getOutputStream());
25 | MCPacket packet=new MCPacket();
26 | packet.setPacketID(0x00);
27 | packet.writeVarInt(755);
28 | packet.writeVarInt(host.length());
29 | packet.writeBytes(host.getBytes(StandardCharsets.UTF_8));
30 | packet.writeShort((short) port);
31 | packet.writeVarInt(1);
32 | out.write(packet.getPacket());
33 | out.write(MCPacket.getRequestPacket().getPacket());
34 | VariableInt vi1=new VariableInt();
35 | int i1=vi1.readBytes(in);
36 | VariableInt vi2=new VariableInt();
37 | int i2=vi2.readBytes(in);
38 | //i1,i2 may be used in the future
39 | VariableInt vi3=new VariableInt();
40 | int i3=vi3.readBytes(in);
41 | byte[] resp=new byte[i3];
42 | in.readFully(resp);
43 | String response=new String(resp,StandardCharsets.UTF_8);
44 | JsonObject object= JsonParser.parseString(response).getAsJsonObject();
45 | String desText;
46 | if (object.get("description").isJsonObject()){
47 | JsonObject description=object.get("description").getAsJsonObject();
48 | if (description.has("extra")){
49 | JsonArray array=description.get("extra").getAsJsonArray();
50 | desText=traverseGetMotd(new StringWriter(),array);
51 | } else{
52 | desText=reformatMOTD(description.get("text").getAsString());
53 | }
54 | } else{
55 | desText=reformatMOTD(object.get("description").getAsString());
56 | }
57 | JsonObject version=object.get("version").getAsJsonObject();
58 | String name=version.get("name").getAsString();
59 | int protocol=version.get("protocol").getAsInt();
60 | String favicon=object.get("favicon").getAsString();
61 | JsonObject players=object.get("players").getAsJsonObject();
62 | int max=players.get("max").getAsInt();
63 | int online=players.get("online").getAsInt();
64 | motd.setDescription(desText);
65 | motd.setOnlinePlayer(online);
66 | motd.setMaxPlayer(max);
67 | motd.setName(name);
68 | motd.setProtocol(protocol);
69 | motd.setFavicon(favicon);
70 | in.close();
71 | out.close();
72 | } catch (IOException e){
73 | motd.setStatus(-1);
74 | e.printStackTrace();
75 | }
76 | return motd;
77 | }
78 | public String traverseGetMotd(StringWriter writer,JsonArray array){
79 | for (int i = 0; i < array.size(); i++) {
80 | JsonObject obj=array.get(i).getAsJsonObject();
81 | if (obj.has("extra")){
82 | traverseGetMotd(writer,obj.get("extra").getAsJsonArray());
83 | } else{
84 | String text=obj.get("text").getAsString();
85 | writer.write(text);
86 | }
87 | }
88 | return writer.toString();
89 | }
90 | public String reformatMOTD(String raw){
91 | CharArrayWriter writer=new CharArrayWriter();
92 | int status=0;
93 | /*
94 | * 0 > normal
95 | * 1 > §*
96 | * 2 > \
97 | * 3 > u
98 | * 4 > [\\u]*
99 | * 5 > [\\u]**
100 | * 6 > [\\u]***
101 | * */
102 | for (char c :
103 | raw.toCharArray()) {
104 | switch (status){
105 | case 0:
106 | if (c=='§'){
107 | status=1;
108 | } else if (c=='\\'){
109 | status=2;
110 | } else{
111 | writer.write(c);
112 | }
113 | break;
114 | case 1:
115 | status=0;
116 | break;
117 | case 2:
118 | if (c=='u')
119 | status++;
120 | break;
121 | case 3:
122 | case 5:
123 | status++;
124 | break;
125 | case 4:
126 | status++;
127 | break;
128 | case 6:
129 | status=0;
130 | break;
131 | }
132 | }
133 | return writer.toString();
134 | }
135 | }
136 |
--------------------------------------------------------------------------------
/src/main/java/glous/kleebot/services/impl/CoreService.java:
--------------------------------------------------------------------------------
1 | package glous.kleebot.services.impl;
2 |
3 | import glous.kleebot.http.ChromeInstance;
4 | import net.mamoe.mirai.event.events.GroupMessageEvent;
5 | import net.mamoe.mirai.message.data.At;
6 | import net.mamoe.mirai.message.data.Image;
7 | import net.mamoe.mirai.message.data.MessageChainBuilder;
8 | import net.mamoe.mirai.utils.ExternalResource;
9 | import glous.kleebot.KleeBot;
10 | import glous.kleebot.async.Task;
11 | import glous.kleebot.async.Timer;
12 | import glous.kleebot.services.GroupService;
13 | import glous.kleebot.services.Service;
14 | import glous.kleebot.services.ServiceRegistry;
15 | import glous.kleebot.services.api.HardwareInfo;
16 |
17 | import java.io.IOException;
18 | import java.net.*;
19 | import java.text.SimpleDateFormat;
20 | import java.util.Date;
21 | import java.util.HashMap;
22 | import java.util.List;
23 |
24 | public class CoreService extends GroupService {
25 | @Override
26 | public void initialize(){
27 | getDelay();
28 | Timer.registerScheduledTask(new Task(CoreService::getDelay,CoreService.class.getName()),Timer.SECOND*10);
29 | }
30 | @Override
31 | public boolean process(GroupMessageEvent event) {
32 | return event.getMessage().serializeToMiraiCode().startsWith(new At(KleeBot.config.getBotAccount()).serializeToMiraiCode() + " status");
33 | }
34 | private static long pixiv_delay=0;
35 | private static long bilibili_delay=0;
36 |
37 | public static long getBilibili_delay() {
38 | return bilibili_delay;
39 | }
40 |
41 | public static long getPixiv_delay() {
42 | return pixiv_delay;
43 | }
44 |
45 | private static void getDelay(){
46 | Proxy proxy=new Proxy(Proxy.Type.HTTP,new InetSocketAddress(KleeBot.config.getProxyHost(),KleeBot.config.getProxyPort()));
47 | try {
48 | Socket skt=new Socket(proxy);
49 | long start=System.currentTimeMillis();
50 | skt.connect(new InetSocketAddress("www.pixiv.net",80));
51 | long end=System.currentTimeMillis();
52 | skt.close();
53 | pixiv_delay=end-start;
54 | skt=new Socket();
55 | start=System.currentTimeMillis();
56 | skt.connect(new InetSocketAddress("www.bilibili.com",80));
57 | end=System.currentTimeMillis();
58 | skt.close();
59 | bilibili_delay=end-start;
60 | } catch (IOException e) {
61 | e.printStackTrace();
62 | }
63 |
64 | }
65 | @Override
66 | public boolean execute(GroupMessageEvent event) throws IOException, InterruptedException {
67 | if (event.getMessage().serializeToMiraiCode().equals(new At(KleeBot.config.getBotAccount())+" status img")){
68 | byte[] bytes=ChromeInstance.getScreenShot("http://localhost:%s/BotStatus/".formatted(KleeBot.config.getServicePort()),1000,0);
69 | MessageChainBuilder builder=new MessageChainBuilder();
70 | builder.append(new At(event.getSender().getId()));
71 | ExternalResource resource=ExternalResource.create(bytes);
72 | Image image=event.getSubject().uploadImage(resource);
73 | builder.append(image);
74 | event.getGroup().sendMessage(builder.build());
75 | resource.close();
76 | } else if (event.getMessage().serializeToMiraiCode().equals(new At(KleeBot.config.getBotAccount())+" status")){
77 | MessageChainBuilder builder=new MessageChainBuilder();
78 | //get current time
79 | long currentTime=System.currentTimeMillis();
80 | long running=currentTime-KleeBot.startTime;
81 | running=running/1000;
82 | Date date=new Date();
83 | SimpleDateFormat formatter=new SimpleDateFormat("yyyy-MM-dd-HH:mm:ss");
84 | List names=KleeBot.queue.getAllRunningTasksName();
85 | builder.append(
86 | """
87 | KleeBot %s
88 | Web页面: http://%s/BotStatus/
89 | Github仓库: https://www.github.com/youfantan/Kleebot
90 | KleeBot主页: https://kleebot.glous.xyz
91 | OpenCV版本: %s
92 | Tesseract-OCR版本: %s
93 | Java版本: %s
94 | 运行系统: %s
95 | 任务队列: %d 个任务正在运行
96 | """.formatted(KleeBot.GET_VERSION(),KleeBot.ip,"4.5.5","4.1",System.getProperty("java.version"),System.getProperty("os.name"),names.size())
97 | );
98 | for (int i = 0; i < names.size(); i++) {
99 | builder.append("\t"+i+": "+names.get(i)+"\n");
100 | }
101 | double memUse= (double) (HardwareInfo.getInstance().getTotalMemoryInfo()-HardwareInfo.getInstance().getAvailableMemoryInfo())/HardwareInfo.getInstance().getTotalMemoryInfo();
102 | builder.append(
103 | """
104 | CPU: %s
105 | CPU时钟频率: %d Mhz
106 | CPU占用率: %.2f %%
107 | 内存占用率: %.2f %%
108 | 校准延迟时间: %s
109 | 已经运行: %d 秒
110 | 与pixiv的延迟: %d 毫秒
111 | 与bilbili的延迟: %d 毫秒
112 | 进程ID: %d
113 | 已安装服务:
114 | """.formatted(HardwareInfo.getInstance().getCpuModelInfo(), HardwareInfo.getInstance().getCpuClockCycleInfo(), HardwareInfo.getInstance().getCpuUsageInfo() * 100, memUse * 100, formatter.format(date), running, pixiv_delay, bilibili_delay, HardwareInfo.getInstance().getProcessIDInfo())
115 | );
116 | String[] services= ServiceRegistry.getAllRegisteredServices();
117 | HashMap enabledServiceMap=ServiceRegistry.getEnabledServiceMap();
118 | for (String service:services){
119 | builder.append("\t").append(service).append(enabledServiceMap.containsKey(service)?"(启用)":"(未启用)").append("\n");
120 | }
121 | event.getGroup().sendMessage(builder.build());
122 | } else {
123 | return false;
124 | }
125 | return true;
126 | }
127 | }
128 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | #
4 | # Copyright 2015 the original author or authors.
5 | #
6 | # Licensed under the Apache License, Version 2.0 (the "License");
7 | # you may not use this file except in compliance with the License.
8 | # You may obtain a copy of the License at
9 | #
10 | # https://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing, software
13 | # distributed under the License is distributed on an "AS IS" BASIS,
14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | # See the License for the specific language governing permissions and
16 | # limitations under the License.
17 | #
18 |
19 | ##############################################################################
20 | ##
21 | ## Gradle start up script for UN*X
22 | ##
23 | ##############################################################################
24 |
25 | # Attempt to set APP_HOME
26 | # Resolve links: $0 may be a link
27 | PRG="$0"
28 | # Need this for relative symlinks.
29 | while [ -h "$PRG" ] ; do
30 | ls=`ls -ld "$PRG"`
31 | link=`expr "$ls" : '.*-> \(.*\)$'`
32 | if expr "$link" : '/.*' > /dev/null; then
33 | PRG="$link"
34 | else
35 | PRG=`dirname "$PRG"`"/$link"
36 | fi
37 | done
38 | SAVED="`pwd`"
39 | cd "`dirname \"$PRG\"`/" >/dev/null
40 | APP_HOME="`pwd -P`"
41 | cd "$SAVED" >/dev/null
42 |
43 | APP_NAME="Gradle"
44 | APP_BASE_NAME=`basename "$0"`
45 |
46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
48 |
49 | # Use the maximum available, or set MAX_FD != -1 to use that value.
50 | MAX_FD="maximum"
51 |
52 | warn () {
53 | echo "$*"
54 | }
55 |
56 | die () {
57 | echo
58 | echo "$*"
59 | echo
60 | exit 1
61 | }
62 |
63 | # OS specific support (must be 'true' or 'false').
64 | cygwin=false
65 | msys=false
66 | darwin=false
67 | nonstop=false
68 | case "`uname`" in
69 | CYGWIN* )
70 | cygwin=true
71 | ;;
72 | Darwin* )
73 | darwin=true
74 | ;;
75 | MINGW* )
76 | msys=true
77 | ;;
78 | NONSTOP* )
79 | nonstop=true
80 | ;;
81 | esac
82 |
83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
84 |
85 |
86 | # Determine the Java command to use to start the JVM.
87 | if [ -n "$JAVA_HOME" ] ; then
88 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
89 | # IBM's JDK on AIX uses strange locations for the executables
90 | JAVACMD="$JAVA_HOME/jre/sh/java"
91 | else
92 | JAVACMD="$JAVA_HOME/bin/java"
93 | fi
94 | if [ ! -x "$JAVACMD" ] ; then
95 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
96 |
97 | Please set the JAVA_HOME variable in your environment to match the
98 | location of your Java installation."
99 | fi
100 | else
101 | JAVACMD="java"
102 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
103 |
104 | Please set the JAVA_HOME variable in your environment to match the
105 | location of your Java installation."
106 | fi
107 |
108 | # Increase the maximum file descriptors if we can.
109 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
110 | MAX_FD_LIMIT=`ulimit -H -n`
111 | if [ $? -eq 0 ] ; then
112 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
113 | MAX_FD="$MAX_FD_LIMIT"
114 | fi
115 | ulimit -n $MAX_FD
116 | if [ $? -ne 0 ] ; then
117 | warn "Could not set maximum file descriptor limit: $MAX_FD"
118 | fi
119 | else
120 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
121 | fi
122 | fi
123 |
124 | # For Darwin, add options to specify how the application appears in the dock
125 | if $darwin; then
126 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
127 | fi
128 |
129 | # For Cygwin or MSYS, switch paths to Windows format before running java
130 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
131 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
132 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
133 |
134 | JAVACMD=`cygpath --unix "$JAVACMD"`
135 |
136 | # We build the pattern for arguments to be converted via cygpath
137 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
138 | SEP=""
139 | for dir in $ROOTDIRSRAW ; do
140 | ROOTDIRS="$ROOTDIRS$SEP$dir"
141 | SEP="|"
142 | done
143 | OURCYGPATTERN="(^($ROOTDIRS))"
144 | # Add a user-defined pattern to the cygpath arguments
145 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
146 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
147 | fi
148 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
149 | i=0
150 | for arg in "$@" ; do
151 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
152 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
153 |
154 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
155 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
156 | else
157 | eval `echo args$i`="\"$arg\""
158 | fi
159 | i=`expr $i + 1`
160 | done
161 | case $i in
162 | 0) set -- ;;
163 | 1) set -- "$args0" ;;
164 | 2) set -- "$args0" "$args1" ;;
165 | 3) set -- "$args0" "$args1" "$args2" ;;
166 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
167 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
168 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
169 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
170 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
171 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
172 | esac
173 | fi
174 |
175 | # Escape application args
176 | save () {
177 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
178 | echo " "
179 | }
180 | APP_ARGS=`save "$@"`
181 |
182 | # Collect all arguments for the java command, following the shell quoting and substitution rules
183 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
184 |
185 | exec "$JAVACMD" "$@"
186 |
--------------------------------------------------------------------------------
/src/main/java/glous/kleebot/utils/FileUtils.java:
--------------------------------------------------------------------------------
1 | package glous.kleebot.utils;
2 |
3 |
4 | import glous.kleebot.log.Logger;
5 |
6 | import javax.net.ssl.HttpsURLConnection;
7 | import javax.net.ssl.SSLContext;
8 | import javax.net.ssl.TrustManager;
9 | import javax.net.ssl.X509TrustManager;
10 | import java.io.*;
11 | import java.net.*;
12 | import java.nio.charset.Charset;
13 | import java.nio.charset.StandardCharsets;
14 | import java.security.cert.CertificateException;
15 | import java.security.cert.X509Certificate;
16 | import java.util.Map;
17 | import java.util.Objects;
18 |
19 | public class FileUtils {
20 | private static int DEBUG_PORT;
21 | public static void enableDebug(int port){
22 | DEBUG_PORT=port;
23 | }
24 | private static final Logger logger=Logger.getLogger(FileUtils.class);
25 | public static byte[] readFile(String fileName) throws IOException {
26 | BufferedInputStream in = new BufferedInputStream(new FileInputStream(fileName));
27 | ByteArrayOutputStream out = new ByteArrayOutputStream();
28 | int bytesRead;
29 | byte[] buffer = new byte[1024];
30 | while ((bytesRead = in.read(buffer)) != -1) {
31 | out.write(buffer, 0, bytesRead);
32 | }
33 | out.close();
34 | in.close();
35 | return out.toByteArray();
36 | }
37 | public static byte[] readBytesStream(InputStream stream){
38 | try {
39 | BufferedInputStream in=new BufferedInputStream(stream);
40 | byte[] buff=new byte[1024];
41 | int bytesRead;
42 | ByteArrayOutputStream out=new ByteArrayOutputStream();
43 | while ((bytesRead=in.read(buff))!=-1) {
44 | out.write(buff, 0, bytesRead);
45 | }
46 | in.close();
47 | out.close();
48 | return out.toByteArray();
49 | } catch (IOException e) {
50 | e.printStackTrace();
51 | return null;
52 | }
53 | }
54 | public static String readStreamString(InputStream stream){
55 | return new String(Objects.requireNonNull(readStreamBytes(stream)),StandardCharsets.UTF_8);
56 | }
57 | public static byte[] readStreamBytes(InputStream stream){
58 | try {
59 | BufferedInputStream in=new BufferedInputStream(stream);
60 | byte[] bytes=new byte[1024];
61 | int bytesRead;
62 | ByteArrayOutputStream out=new ByteArrayOutputStream();
63 | while ((bytesRead=in.read(bytes))!=-1){
64 | out.write(bytes,0,bytesRead);
65 | }
66 | in.close();
67 | out.close();
68 | return out.toByteArray();
69 | } catch (IOException e) {
70 | e.printStackTrace();
71 | return null;
72 | }
73 | }
74 | public static String readFile(String fileName, Charset charset) throws IOException {
75 | byte[] bytes = readFile(fileName);
76 | if (bytes == null) {
77 | return null;
78 | }
79 | return new String(bytes, charset);
80 | }
81 |
82 | public static void writeFile(String fileName, byte[] content) throws IOException {
83 | BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(fileName));
84 | out.write(content);
85 | out.flush();
86 | out.close();
87 | }
88 |
89 | public static void writeFile(String fileName, String content) throws IOException {
90 | writeFile(fileName, content.getBytes(StandardCharsets.UTF_8));
91 | }
92 | public static byte[] download(String _url, Proxy proxy, Map extraHeaders) {
93 | long start=System.currentTimeMillis();
94 | try {
95 | URL url = new URL(_url);
96 | HttpURLConnection conn;
97 | if (proxy != null) {
98 | conn = (HttpURLConnection) url.openConnection(proxy);
99 | } else if (DEBUG_PORT!=0){
100 | trustAllHosts();
101 | conn = (HttpURLConnection) url.openConnection(new Proxy(Proxy.Type.HTTP,new InetSocketAddress("localhost",DEBUG_PORT)));
102 | }
103 | else {
104 | conn = (HttpURLConnection) url.openConnection();
105 | }
106 | if (extraHeaders!=null){
107 | for (String k :
108 | extraHeaders.keySet()) {
109 | conn.setRequestProperty(k, extraHeaders.get(k));
110 | }
111 | }
112 | BufferedInputStream in = new BufferedInputStream(conn.getInputStream());
113 | int bytesRead;
114 | ByteArrayOutputStream out = new ByteArrayOutputStream();
115 | byte[] buffer = new byte[1024];
116 | while ((bytesRead = in.read(buffer)) != -1) {
117 | out.write(buffer, 0, bytesRead);
118 | }
119 | in.close();
120 | out.close();
121 | long end=System.currentTimeMillis();
122 | logger.debug("Total: %d ms".formatted(end-start));
123 | return out.toByteArray();
124 | } catch (Exception e){
125 | e.printStackTrace();
126 | return null;
127 | }
128 |
129 | }
130 |
131 | public static byte[] download(String _url) throws IOException {
132 | return download(_url, null,null);
133 | }
134 | public static byte[] download(String _url,Proxy proxy) throws IOException {
135 | return download(_url,proxy,null);
136 | }
137 | private static void trustAllHosts() {
138 | final String TAG = "trustAllHosts";
139 | // Create a trust manager that does not validate certificate chains
140 | TrustManager[] trustAllCerts = new TrustManager[]{new X509TrustManager() {
141 | public X509Certificate[] getAcceptedIssuers() {
142 | return new X509Certificate[]{};
143 | }
144 |
145 | public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
146 | }
147 |
148 | public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
149 | }
150 | }};
151 | // Install the all-trusting trust manager
152 | try {
153 | SSLContext sc = SSLContext.getInstance("TLS");
154 | sc.init(null, trustAllCerts, new java.security.SecureRandom());
155 | HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
156 | } catch (Exception e) {
157 | e.printStackTrace();
158 | }
159 | }
160 | }
161 |
--------------------------------------------------------------------------------
/src/main/java/glous/kleebot/services/impl/GenshinPlayerService.java:
--------------------------------------------------------------------------------
1 | package glous.kleebot.services.impl;
2 |
3 | import net.mamoe.mirai.event.events.GroupMessageEvent;
4 | import net.mamoe.mirai.message.data.At;
5 | import net.mamoe.mirai.message.data.Image;
6 | import net.mamoe.mirai.message.data.MessageChainBuilder;
7 | import net.mamoe.mirai.utils.ExternalResource;
8 | import glous.kleebot.KleeBot;
9 | import glous.kleebot.features.builtin.PlayerInfo;
10 | import glous.kleebot.features.builtin.Role;
11 | import glous.kleebot.features.builtin.World;
12 | import glous.kleebot.features.genshin.GenshinAPI;
13 | import glous.kleebot.services.GroupService;
14 | import glous.kleebot.utils.FileUtils;
15 | import glous.kleebot.utils.StringUtils;
16 |
17 | import java.awt.*;
18 | import java.io.IOException;
19 | import java.math.BigDecimal;
20 | import java.math.RoundingMode;
21 | import java.nio.charset.StandardCharsets;
22 | import java.security.NoSuchAlgorithmException;
23 | import java.util.Base64;
24 |
25 | public class GenshinPlayerService extends GroupService {
26 | @Override
27 | public boolean process(GroupMessageEvent event) {
28 | return event.getMessage().serializeToMiraiCode().startsWith(new At(KleeBot.config.getBotAccount())+" gsearch ");
29 | }
30 |
31 | @Override
32 | public boolean execute(GroupMessageEvent event) throws IOException, FontFormatException, NoSuchAlgorithmException {
33 | String rawMessage=event.getMessage().serializeToMiraiCode();
34 | String uid=rawMessage.substring(rawMessage.indexOf("gsearch")+8);
35 | if ((uid=StringUtils.findDigit(uid))!=null){
36 | String cookie= FileUtils.readFile(KleeBot.config.getCookieFile(), StandardCharsets.UTF_8);
37 | if (cookie==null){
38 | sendErrorMessage(event,"米游社cookie文件不存在,请联系bot管理员修复。");
39 | return false;
40 | }
41 | GenshinAPI api=new GenshinAPI(cookie);
42 | PlayerInfo info;
43 | if (rawMessage.endsWith("CN")){
44 | info=api.getPlayerInfo(GenshinAPI.GENSHIN_CHINA,uid);
45 | } else if (rawMessage.endsWith("CN_B")){
46 | info=api.getPlayerInfo(GenshinAPI.GENSHIN_CHINA_BILIBILI,uid);
47 | } else{
48 | info=api.getPlayerInfo(GenshinAPI.GENSHIN_CHINA,uid);
49 | }
50 | if (info.getStatus()==0) {
51 | if (rawMessage.contains("img")){
52 | String encodedImg=api.generatePlayerInfoImage(info);
53 | ExternalResource resource=ExternalResource.create(Base64.getDecoder().decode(encodedImg));
54 | Image image=event.getSubject().uploadImage(resource);
55 | MessageChainBuilder builder=new MessageChainBuilder();
56 | builder.append(new At(event.getSender().getId()));
57 | builder.append(image);
58 | event.getGroup().sendMessage(builder.build());
59 | resource.close();
60 | } else {
61 | MessageChainBuilder builder=new MessageChainBuilder();
62 | builder.append(new At(event.getSender().getId()));
63 | builder.append("\n%s 的玩家信息:\n".formatted(uid));
64 | builder.append(" 角色:\n");
65 | Role[] roles=info.getRoles();
66 | for (Role r:roles){
67 | builder.append("""
68 | %s 等级: %s 好感度: %s
69 | """.formatted(r.getName(),r.getLevel(),r.getFetter()));
70 | }
71 | builder.append(" 大世界:\n");
72 | World[] worlds=info.getWorlds();
73 | for (World w:worlds){
74 | int percentage=w.getExploration_percentage();
75 | BigDecimal decimal=BigDecimal.valueOf(percentage);
76 | decimal=decimal.divide(BigDecimal.valueOf(10),1, RoundingMode.HALF_UP);
77 | builder.append("""
78 | %s 探索度: %f
79 | """.formatted(w.getName(),decimal.doubleValue()));
80 | }
81 | builder.append(" 统计:");
82 | builder.append(
83 | """
84 |
85 | 风神瞳收集: %d
86 | 岩神瞳收集: %d
87 | 雷神瞳收集: %d
88 | 普通宝箱收集: %d
89 | 稀有宝箱收集: %d
90 | 珍贵宝箱收集: %d
91 | 华丽宝箱收集: %d
92 | 奇馈宝箱收集: %d
93 | 拥有角色数: %d
94 | 成就数: %d
95 | 活跃天数: %d
96 | 深渊进度: %s
97 | """
98 | .formatted(
99 | info.getAnemoculus_number(),
100 | info.getGeoculus_number(),
101 | info.getElectroculus_number(),
102 | info.getCommon_chest_number(),
103 | info.getExquisite_chest_number(),
104 | info.getPrecious_chest_number(),
105 | info.getLuxurious_chest_number(),
106 | info.getMagic_chest_number(),
107 | info.getAvatar_number(),
108 | info.getAchievement_number(),
109 | info.getActive_day_number(),
110 | info.getSpiral_abyss()
111 | )
112 | );
113 | event.getGroup().sendMessage(builder.build());
114 | }
115 | } else{
116 | sendErrorMessage(event,"发生错误,错误信息:%s".formatted(info.getErrorMsg()));
117 | return false;
118 | }
119 | }
120 | return true;
121 | }
122 | private void sendErrorMessage(GroupMessageEvent event,String errorMessage){
123 | MessageChainBuilder builder=new MessageChainBuilder();
124 | builder.append(new At(event.getSender().getId()));
125 | builder.append(" 无法通过UID获取玩家信息。错误信息:\n%s".formatted(errorMessage));
126 | event.getGroup().sendMessage(builder.build());
127 | }
128 | }
129 |
--------------------------------------------------------------------------------
/src/main/java/glous/kleebot/services/impl/BilibiliService.java:
--------------------------------------------------------------------------------
1 | package glous.kleebot.services.impl;
2 |
3 | import glous.kleebot.features.bilibili.BilibiliAPI;
4 | import glous.kleebot.services.builtin.BilibiliVideoInf;
5 | import net.mamoe.mirai.event.events.GroupMessageEvent;
6 | import net.mamoe.mirai.message.data.At;
7 | import net.mamoe.mirai.message.data.Image;
8 | import net.mamoe.mirai.message.data.MessageChainBuilder;
9 | import net.mamoe.mirai.utils.ExternalResource;
10 | import glous.kleebot.KleeBot;
11 | import glous.kleebot.services.GroupService;
12 | import glous.kleebot.utils.StringUtils;
13 |
14 | import java.io.IOException;
15 |
16 | public class BilibiliService extends GroupService {
17 | @Override
18 | public boolean process(GroupMessageEvent event) {
19 | return event.getMessage().serializeToMiraiCode().contains("bilibili")||event.getMessage().serializeToMiraiCode().contains("b23.tv");
20 | }
21 |
22 | @Override
23 | public boolean execute(GroupMessageEvent event) throws IOException {
24 | String rawMessage=event.getMessage().serializeToMiraiCode();
25 | BilibiliAPI api=new BilibiliAPI();
26 | if (rawMessage.startsWith(new At(KleeBot.config.getBotAccount())+" bilibili ")){
27 | if (rawMessage.startsWith(new At(KleeBot.config.getBotAccount())+" bilibili shorturl ")){
28 | String rawUrl=rawMessage.substring(rawMessage.indexOf("bilibili.com"));
29 | if (rawUrl.contains("BV")){
30 | String bvid=api.getBVid(rawUrl);
31 | if (bvid!=null){
32 | sendMessage("解析后的链接: "+api.getShortUrl("https://www.bilibili.com/video/"+bvid),event);
33 | return true;
34 | }
35 | } else if (rawUrl.contains("av")){
36 | String aid= StringUtils.findDigit(rawUrl);
37 | if (aid!=null){
38 | sendMessage("解析后的链接: "+api.getShortUrl("https://www.bilibili.com/video/av"+aid),event);
39 | return true;
40 | }
41 | }
42 | } else{
43 | if (rawMessage.contains("bilibili.com")){
44 | String rawUrl=rawMessage.substring(rawMessage.indexOf("bilibili.com"));
45 | if (rawUrl.contains("BV")){
46 | String bvid=api.getBVid(rawUrl);
47 | if (bvid!=null){
48 | String cid=api.getCid(bvid);
49 | String aid=api.getAid(cid,bvid);
50 | sendVideoInformation(event,api.getVideoInformation(aid));
51 | return true;
52 | }
53 | } else if (rawUrl.contains("av")){
54 | String aid= StringUtils.findDigit(rawUrl);
55 | if (aid!=null){
56 | sendVideoInformation(event,api.getVideoInformation(aid));
57 | return true;
58 | }
59 | }
60 | } else if (rawMessage.contains("b23.tv")){
61 | String rawUrl=rawMessage.substring(rawMessage.indexOf("b23.tv"));
62 | if (rawUrl.contains("av")){
63 | String aid=StringUtils.findDigit(rawUrl);
64 | if (aid!=null){
65 | sendVideoInformation(event, api.getVideoInformation(aid));
66 | return true;
67 | }
68 | } else{
69 | String b23ShortUrl=rawUrl.substring(rawUrl.indexOf("b23.tv/"+8),rawUrl.indexOf("b23.tv/"+8)+7);
70 | System.out.println(b23ShortUrl);
71 | String url=api.getB23RedirectUrl(b23ShortUrl);
72 | if (url.startsWith("https://")){
73 | String bvid=api.getBVid(url);
74 | if (bvid!=null){
75 | String cid=api.getCid(bvid);
76 | String aid=api.getAid(cid,bvid);
77 | sendVideoInformation(event,api.getVideoInformation(aid));
78 | return true;
79 | }
80 | }
81 | }
82 | }
83 | }
84 | return false;
85 | } else if (rawMessage.contains("bilibili.com")){
86 | String rawUrl=rawMessage.substring(rawMessage.indexOf("bilibili.com"));
87 | executeVideo(event, api, rawUrl);
88 | return true;
89 | } else if (rawMessage.contains("b23.tv")){
90 | String rawUrl=rawMessage.substring(rawMessage.indexOf("b23.tv")+7);
91 | if (rawUrl.contains("av")){
92 | String aid=StringUtils.findDigit(rawUrl);
93 | if (aid!=null){
94 | sendVideoInformation(event, api.getVideoInformation(aid));
95 | }
96 | } else{
97 | String b23ShortUrl=rawUrl.substring(0,7);
98 | String url=api.getB23RedirectUrl("https://b23.tv/"+b23ShortUrl);
99 | if (url.startsWith("https://")){
100 | executeVideo(event, api, url);
101 | }
102 | }
103 | }
104 | return true;
105 | }
106 |
107 | private void executeVideo(GroupMessageEvent event, BilibiliAPI api, String url) throws IOException {
108 | if (url.contains("BV")){
109 | String bvid=api.getBVid(url);
110 | if (bvid!=null){
111 | String cid=api.getCid(bvid);
112 | String aid=api.getAid(cid,bvid);
113 | sendVideoInformation(event,api.getVideoInformation(aid));
114 | }
115 | } else if (url.contains("av")){
116 | String aid= StringUtils.findDigit(url);
117 | if (aid!=null){
118 | sendVideoInformation(event,api.getVideoInformation(aid));
119 | }
120 | }
121 | }
122 |
123 | private void sendVideoInformation(GroupMessageEvent event, BilibiliVideoInf inf){
124 | MessageChainBuilder builder=new MessageChainBuilder();
125 | builder.append(new At(event.getSender().getId()));
126 | builder.append("\n视频封面:");
127 | ExternalResource res=ExternalResource.create(inf.getCover());
128 | Image image=event.getSubject().uploadImage(res);
129 | builder.append(image);
130 | builder.append(
131 | """
132 |
133 | 标题: %s
134 | 作者: %s
135 | 源URL: %s
136 | """
137 | .formatted(inf.getTitle(),inf.getAuthor(),inf.getUrl()));
138 | event.getGroup().sendMessage(builder.build());
139 | }
140 | }
141 |
142 |
--------------------------------------------------------------------------------
/src/main/java/glous/kleebot/services/impl/PixivService.java:
--------------------------------------------------------------------------------
1 | package glous.kleebot.services.impl;
2 |
3 | import net.mamoe.mirai.event.events.GroupMessageEvent;
4 | import net.mamoe.mirai.message.data.*;
5 | import net.mamoe.mirai.utils.ExternalResource;
6 |
7 | import org.bouncycastle.util.encoders.Hex;
8 | import glous.kleebot.KleeBot;
9 | import glous.kleebot.async.Task;
10 | import glous.kleebot.async.Timer;
11 | import glous.kleebot.features.pixiv.PixivAPI;
12 | import glous.kleebot.http.services.StoreWhisperService;
13 | import glous.kleebot.log.Logger;
14 | import glous.kleebot.services.GroupService;
15 | import glous.kleebot.utils.DigestUtils;
16 |
17 | import java.io.IOException;
18 | import java.nio.charset.StandardCharsets;
19 | import java.util.Base64;
20 | import java.util.HashMap;
21 | import java.util.Objects;
22 | import java.util.UUID;
23 |
24 | import static glous.kleebot.utils.StringUtils.isDigit;
25 |
26 | public class PixivService extends GroupService {
27 | private static final PixivAPI api=new PixivAPI(KleeBot.config.getProxyHost(),KleeBot.config.getProxyPort());
28 | private static final Logger logger=Logger.getLogger(PixivService.class);
29 | private static void syncRanks(){
30 | try {
31 |
32 | HashMap> daily=api.getDailyRanking(false);
33 | HashMap> weekly=api.getWeeklyRanking(false);
34 | HashMap> monthly=api.getMonthlyRanking(false);
35 | logger.info("开始同步日榜");
36 | for (HashMap artwork :
37 | daily.values()) {
38 | logger.info(
39 | """
40 | 正在同步: 标题: %s/作者: %s/日期: %s/URL: %s
41 | """.formatted(artwork.get("title"),artwork.get("author"),artwork.get("date"),artwork.get("imageUrl")));
42 | PixivService.api.getImage(artwork.get("imageUrl"));
43 | }
44 | logger.info("开始同步周榜");
45 | for (HashMap artwork :
46 | weekly.values()) {
47 | logger.info(
48 | """
49 | 正在同步: 标题: %s/作者: %s/日期: %s/URL: %s
50 | """.formatted(artwork.get("title"),artwork.get("author"),artwork.get("date"),artwork.get("imageUrl")));
51 | PixivService.api.getImage(artwork.get("imageUrl"));
52 | }
53 | logger.info("开始同步月榜");
54 | for (HashMap artwork :
55 | monthly.values()) {
56 | logger.info(
57 | """
58 | 正在同步: 标题: %s/作者: %s/日期: %s/URL: %s
59 | """.formatted(artwork.get("title"),artwork.get("author"),artwork.get("date"),artwork.get("imageUrl")));
60 | PixivService.api.getImage(artwork.get("imageUrl"));
61 | }
62 | } catch (IOException e) {
63 | e.printStackTrace();
64 | }
65 | }
66 | @Override
67 | public void initialize() {
68 | Timer.registerScheduledTask(new Task(PixivService::syncRanks,this.getServiceName()+"#syncRanks"),Timer.HOUR);
69 | logger.info(getServiceName()+" initialized successfully");
70 | }
71 |
72 | @Override
73 | public boolean process(GroupMessageEvent event) {
74 | return event.getMessage().serializeToMiraiCode().startsWith(new At(KleeBot.config.getBotAccount()).serializeToMiraiCode() + " pixiv ");
75 | }
76 | @Override
77 | public boolean execute(GroupMessageEvent event) throws IOException {
78 | String msg=event.getMessage().serializeToMiraiCode();
79 | String method=msg.substring(msg.indexOf("pixiv")+6);
80 | if (method.startsWith("rank")){//get rank information
81 | //get ranking serial
82 | if (!method.contains("#")||(!method.contains("daily")&&!method.contains("weekly")&&!method.contains("monthly"))){
83 | return false;
84 | }
85 | String type=method.substring(method.indexOf("rank")+5,method.indexOf("#")-1);
86 | String serial=method.substring(method.indexOf("#")+1);
87 | if (!isDigit(serial)){
88 | return false;
89 | }
90 | int serialNum=Integer.parseInt(serial);
91 | HashMap> ranking;
92 | if (type.equals("daily"))
93 | ranking= api.getDailyRanking();
94 | else if (type.equals("weekly"))
95 | ranking= api.getWeeklyRanking();
96 | else if (type.equals("monthly"))
97 | ranking= api.getMonthlyRanking();
98 | else {
99 | return false;
100 | }
101 | if (serialNum>ranking.size()+1||serialNum<1){
102 | return false;
103 | }
104 | HashMap artwork=ranking.get(serialNum-1);
105 | sendRankMessage(event, artwork);
106 | } else{
107 | String illustid=method;
108 | if (!isDigit(illustid)){
109 | return false;
110 | }
111 | HashMap artwork= api.getArtwork(Integer.parseInt(illustid));
112 | if (artwork==null){
113 | return false;
114 | }
115 | sendRankMessage(event, artwork);
116 | }
117 | return true;
118 | }
119 |
120 | private void sendRankMessage(GroupMessageEvent event, HashMap artwork) throws IOException {
121 | if (artwork.get("sexual").equals("true")){
122 | String uuid=UUID.randomUUID().toString();
123 | StoreWhisperService.dataMap.put(uuid, Hex.toHexString(Objects.requireNonNull(DigestUtils.AES128CBCPKCS7Encrypt(("image;data:image/jpg;base64," + Base64.getEncoder().encodeToString(PixivService.api.getImage(artwork.get("imageUrl")))).getBytes(StandardCharsets.UTF_8)))));
124 | sendMessage("富强民主文明和谐自由平等公正法制爱国敬业诚信友善。\n图片编号为: %s\n访问地址: http://%s/Whisper/".formatted(uuid,KleeBot.ip),event);
125 | } else{
126 | ExternalResource resource=ExternalResource.create(PixivService.api.getImage(artwork.get("imageUrl")));
127 | MessageChainBuilder builder=new MessageChainBuilder();
128 | Image image=event.getSubject().uploadImage(resource);
129 | builder.append(new At(event.getSender().getId()));
130 | builder.append(image);
131 | builder.append(
132 | """
133 | 标题: %s
134 | 画师: %s
135 | 上传时间: %s
136 | 原图URL: %s
137 | """.formatted(artwork.get("title"),artwork.get("author"),artwork.get("date"),artwork.get("imageUrl"))
138 | );
139 | event.getGroup().sendMessage(builder.build());
140 | resource.close();
141 | }
142 | }
143 | }
144 |
--------------------------------------------------------------------------------
/src/main/java/glous/kleebot/services/impl/AutoPostService.java:
--------------------------------------------------------------------------------
1 | package glous.kleebot.services.impl;
2 |
3 | import com.google.gson.JsonArray;
4 | import com.google.gson.JsonElement;
5 | import com.google.gson.JsonObject;
6 | import com.google.gson.JsonParser;
7 | import net.mamoe.mirai.event.events.GroupMessageEvent;
8 | import net.mamoe.mirai.message.data.At;
9 | import glous.kleebot.KleeBot;
10 | import glous.kleebot.async.Task;
11 | import glous.kleebot.async.Timer;
12 | import glous.kleebot.cache.CacheFactory;
13 | import glous.kleebot.services.GroupService;
14 | import glous.kleebot.utils.FileUtils;
15 |
16 | import java.io.*;
17 | import java.net.InetSocketAddress;
18 | import java.net.Proxy;
19 | import java.nio.charset.StandardCharsets;
20 | import java.util.ArrayList;
21 | import java.util.HashMap;
22 | import java.util.List;
23 |
24 | public class AutoPostService extends GroupService {
25 | private static HashMap> enableList=new HashMap<>();
26 | private static final List availableFeatures=List.of("mcv");
27 | @Override
28 | public boolean process(GroupMessageEvent event) {
29 | return event.getMessage().serializeToMiraiCode().startsWith(new At(KleeBot.config.getBotAccount())+" enable ");
30 | }
31 |
32 | @Override
33 | public boolean execute(GroupMessageEvent event) throws Exception {
34 | logger.trace("test");
35 | String message=event.getMessage().serializeToMiraiCode();
36 | String feature=message.substring(message.indexOf("enable")+7);
37 | System.out.println(feature);
38 | List features;
39 | enableList.computeIfAbsent(event.getGroup().getId(), k -> new ArrayList());
40 | features=enableList.get(event.getGroup().getId());
41 | if (availableFeatures.contains(feature)) {
42 | if (features.contains(feature)) {
43 | sendMessage("%s 功能重复启用".formatted(feature),event);
44 | } else{
45 | features.add(feature);
46 | enableList.put(event.getGroup().getId(),features);
47 | sendMessage("已成功启用 %s 功能".formatted(feature),event);
48 | }
49 | return true;
50 | } else{
51 | return false;
52 | }
53 | }
54 |
55 | @Override
56 | public String getServiceName() {
57 | return super.getServiceName();
58 | }
59 |
60 | @SuppressWarnings("unchecked")
61 | @Override
62 | public void initialize() {
63 | byte[] bytes;
64 | if ((bytes=CacheFactory.getCache("AutoPostServiceConfig"))!=null){
65 | ByteArrayInputStream in=new ByteArrayInputStream(bytes);
66 | try {
67 | ObjectInputStream ois=new ObjectInputStream(in);
68 | enableList=(HashMap>) ois.readObject();
69 | } catch (IOException | ClassNotFoundException e) {
70 | e.printStackTrace();
71 | }
72 | }
73 | Timer.registerScheduledTask(new Task(()->{
74 | //update version
75 | try {
76 | byte[] manifest_bytes=FileUtils.download("https://launchermeta.mojang.com/mc/game/version_manifest.json",new Proxy(Proxy.Type.HTTP,new InetSocketAddress(KleeBot.config.getProxyHost(),KleeBot.config.getProxyPort())));
77 | String manifest=new String(manifest_bytes, StandardCharsets.UTF_8);
78 | JsonElement ele=JsonParser.parseString(manifest);
79 | JsonObject object=ele.getAsJsonObject();
80 | JsonObject latest=object.get("latest").getAsJsonObject();
81 | String latestRelease=latest.get("release").getAsString();
82 | String latestSnapshot=latest.get("snapshot").getAsString();
83 | byte[] bytes1;
84 | byte[] bytes2;
85 | boolean haveHigherVersion=false;
86 | if ((bytes1=CacheFactory.getCache("mcv_latest_release"))!=null){
87 | String behindRelease=new String(bytes1);
88 | if (!behindRelease.equals(latestRelease)){
89 | haveHigherVersion=true;
90 | }
91 | }
92 | if ((bytes2=CacheFactory.getCache("mcv_latest_snapshot"))!=null){
93 | String behindSnapshot=new String(bytes2);
94 | if (!behindSnapshot.equals(latestSnapshot)){
95 | haveHigherVersion=true;
96 | }
97 | }
98 | String snapshotDetails="RELEASE_DETAILS";
99 | String releaseDetails="SNAPSHOT_DETAILS";
100 | if (haveHigherVersion){
101 | JsonArray versions=object.get("versions").getAsJsonArray();
102 | for (int i = 0; i < versions.size(); i++) {
103 | JsonObject obj=versions.get(i).getAsJsonObject();
104 | if (obj.get("id").getAsString().equals(latestSnapshot)){
105 | snapshotDetails="发布时间: %s 类型: %s 清单文件URL: %s".formatted(obj.get("releaseTime").getAsString(),obj.get("type").getAsString(),obj.get("url").getAsString());
106 | }
107 | if (obj.get("id").getAsString().equals(latestRelease)){
108 | releaseDetails="发布时间: %s 类型: %s 清单文件URL: %s".formatted(obj.get("releaseTime").getAsString(),obj.get("type").getAsString(),obj.get("url").getAsString());
109 | }
110 | }
111 | }
112 | CacheFactory.storeCache("mcv_latest_snapshot",latestSnapshot.getBytes(StandardCharsets.UTF_8),Timer.NO_LIMIT);
113 | CacheFactory.storeCache("mcv_latest_release",latestRelease.getBytes(StandardCharsets.UTF_8),Timer.NO_LIMIT);
114 | for (long key :
115 | enableList.keySet()) {
116 | if (enableList.get(key).contains("mcv")){
117 | if (haveHigherVersion){
118 | KleeBot.botInstance.getGroup(key).sendMessage("检测到Minecraft新版本: \n正式版: %s(%s)\n快照版: %s(%s)".formatted(latestRelease,releaseDetails,latestSnapshot,snapshotDetails));
119 | }
120 | }
121 | }
122 | } catch (IOException e) {
123 | e.printStackTrace();
124 | }
125 | },this.getClass().getName()+"#MCV"),Timer.MINUTE*10);
126 | logger.info(getServiceName()+" initialized successfully");
127 | }
128 |
129 | @Override
130 | public void stop() {
131 | ByteArrayOutputStream out=new ByteArrayOutputStream();
132 | try {
133 | ObjectOutputStream oos=new ObjectOutputStream(out);
134 | oos.writeObject(enableList);
135 | oos.flush();
136 | oos.close();
137 | out.close();
138 | CacheFactory.storeCache("AutoPostServiceConfig",out.toByteArray(), Timer.NO_LIMIT);
139 | } catch (IOException e) {
140 | e.printStackTrace();
141 | }
142 | }
143 | }
144 |
--------------------------------------------------------------------------------
/src/main/java/glous/kleebot/web/HttpServer.java:
--------------------------------------------------------------------------------
1 | package glous.kleebot.web;
2 |
3 | import glous.kleebot.async.AsyncTaskQueue;
4 | import glous.kleebot.utils.FileUtils;
5 | import glous.kleebot.utils.ZipUtils;
6 | import glous.kleebot.KleeBot;
7 | import glous.kleebot.log.Logger;
8 |
9 | import java.io.*;
10 | import java.net.ServerSocket;
11 | import java.net.Socket;
12 | import java.nio.charset.StandardCharsets;
13 | import java.util.HashMap;
14 |
15 | public class HttpServer {
16 | private int port;
17 | private boolean flag=true;
18 | private AsyncTaskQueue queue;
19 | private String resourcePackName;
20 | private Logger logger= Logger.getLogger(HttpServer.class);
21 | public HttpServer(AsyncTaskQueue queue,int port){
22 | this.port=port;
23 | this.queue=queue;
24 | }
25 | private HashMap services=new HashMap<>();
26 | public void registerService(String name,WebService service){
27 | services.put(name,service);
28 | }
29 | public void setResourcePack(String path){
30 | this.resourcePackName=path.substring(0,path.length()-4);
31 | ZipUtils.extractZipFile(path,"web"+File.separatorChar+resourcePackName);
32 | }
33 | public Set makeHeader(String buffer){
34 | StringBuilder left= new StringBuilder();
35 | StringBuilder right= new StringBuilder();
36 | boolean in_left=true;
37 | boolean have_word=false;
38 | for (char c:buffer.toCharArray()){
39 | if (in_left){
40 | if (c==':'){
41 | in_left=false;
42 | } else{
43 | left.append(c);
44 | }
45 | } else{
46 | if (c!=' '&&!have_word){
47 | have_word=true;
48 | right.append(c);
49 | } else{
50 | if (have_word){
51 | right.append(c);
52 | }
53 | }
54 | }
55 | }
56 | return new Set(left.toString(),right.toString());
57 | }
58 | public void start(){
59 | try {
60 | ServerSocket server=new ServerSocket(port);
61 | while (KleeBot.getRunningFlag()&&flag){
62 | Socket clientSocket=server.accept();
63 | InputStream in=clientSocket.getInputStream();
64 | OutputStream out=clientSocket.getOutputStream();
65 | BufferedReader reader=new BufferedReader(new InputStreamReader(in));
66 | BufferedWriter writer=new BufferedWriter(new OutputStreamWriter(out));
67 | String buffer;
68 | HashMap requestHeaders=new HashMap<>();
69 | String service=null;
70 | String method=null;
71 | while ((buffer=reader.readLine())!=null&&!buffer.isEmpty()){
72 | if (buffer.startsWith("GET")){
73 | method="GET";
74 | service=buffer.substring(buffer.indexOf("/"),buffer.indexOf("HTTP")-1);
75 | logger.info("Request Method: GET.Request Service: %s".formatted(service));
76 | } else{
77 | Set header=makeHeader(buffer);
78 | requestHeaders.put(header.getK(),header.getV());
79 | }
80 | }
81 | if (method != null&&method.equals("GET")){
82 | if (!services.containsKey(service)){
83 | if (resourcePackName != null){
84 | if (service.endsWith("/")) {
85 | service+="index.html";
86 | }
87 | File staticFile=new File("web"+File.separatorChar+service);
88 | if (staticFile.exists()&&staticFile.isFile()){
89 | ByteArrayOutputStream bOut=new ByteArrayOutputStream();
90 | byte[] content= FileUtils.readFile(staticFile.getAbsolutePath());
91 | bOut.write("HTTP/1.1 200 OK\n".getBytes(StandardCharsets.UTF_8));
92 | if (service.endsWith(".html")){
93 | bOut.write("Content-Type: text/html".getBytes(StandardCharsets.UTF_8));
94 | } else if (service.endsWith(".css")) {
95 | bOut.write("Content-Type: text/css".getBytes(StandardCharsets.UTF_8));
96 | } else if (service.endsWith(".js")){
97 | bOut.write("Content-Type: application/javascript".getBytes(StandardCharsets.UTF_8));
98 | } else if (service.endsWith(".jpg")||service.endsWith(".png")||service.endsWith(".gif")){
99 | bOut.write(("Content-Type: image/"+service.substring(0,service.length()-3)).getBytes(StandardCharsets.UTF_8));
100 | } else if (service.endsWith(".json")){
101 | bOut.write("Content-Type: application/json".getBytes(StandardCharsets.UTF_8));
102 | } else if (service.endsWith(".xml")){
103 | bOut.write("Content-Type: application/xml".getBytes(StandardCharsets.UTF_8));
104 | } else {
105 | bOut.write("Content-Type: octet-stream".getBytes(StandardCharsets.UTF_8));
106 | }
107 | bOut.write(("\nAccess-Control-Allow-Origin: *\n\n").getBytes(StandardCharsets.UTF_8));
108 | bOut.write(content);
109 | bOut.flush();
110 | bOut.close();
111 | out.write(bOut.toByteArray());
112 | out.flush();
113 | out.close();
114 | in.close();
115 | clientSocket.close();
116 | continue;
117 | }
118 | }
119 | String resp =
120 | """
121 | HTTP/1.1 404 Not Found
122 | Server: KleeBot Http Services
123 | Content-Type: text/html
124 |
125 | 404 Not FoundRequest Resource Not Found
KleeBot Http Services(%s@%s)
126 | """.formatted("dev", "@dev-000000 build at 2022-2-27");
127 | writer.write(resp);
128 | writer.flush();
129 | in.close();
130 | out.close();
131 | clientSocket.close();
132 | } else{
133 | HttpClient client=new HttpClient(in, requestHeaders, method, out);
134 | WebService webService=services.get(service);
135 | queue.addTask(()->{ webService.response(client); },this.getClass().getName());
136 | }
137 | }
138 | }
139 | } catch (Exception e){
140 | e.printStackTrace();
141 | }
142 |
143 | }
144 | public void stop(){
145 | flag=false;
146 | }
147 | }
148 |
--------------------------------------------------------------------------------