├── 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 | Travis CI badge 17 | 18 | 19 | npm version badge 20 | 21 | 22 | CDNJS version badge 23 | 24 | 25 | dependencies Status badge 26 | 27 | 28 | devDependency Status badge 29 | 30 | 31 | Gitter badge 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 Found

Request 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 | --------------------------------------------------------------------------------