mirror of
https://github.com/Eyre-S/Coeur-Morny-Cono.git
synced 2024-11-26 04:57:41 +08:00
[[[release 0.8.0.11*putian]]]
## 📇功能 - 关闭了 tracker 功能(以及现在 morny 确实的没有任何文件 IO 了) - 添加 /encrypt 命令可以对文本使用加密算法处理 - 支持文本,图片,文件,但不支援复数个图片/文件,同时支援的大小受到 API 限制 - 支援 base64(enc/dec,url-format) md5, sha1/256/512 - md5 以及 sha1/256/512 支援 uppercase 选项 - 添加内联查询 twitter 分享链接 format 为 vxtwitter 链接的功能 - 添加内联查询 bilibili 分享链接或av/bv号 format 为 av/bv 视频链接的功能 - 目前仅支援 bilibili av/bv 视频链接不支援 b23 分享链接 - 添加 /info 命令 - 目前仅支援 stickers (以及stickers.ID) 选项输出 morny 使用的贴纸 - 添加了可以输出一个之前加进去但是没用到的贴纸的 /install 命令 ## 🔌系统接口 - 将所有之前在 sukazyo.cc:untitled-* 的工具类重新放回了 morny.utils 下 - CommonCommand 名称改为了 UniversalCommand - 也将之前的 TelegramUserInformation 和 TGToStringMessage 移动到了 utils.tgapi 的相应位置 - stringsConnect 添加进了 CommonConvert 当中 - 删除了 EncryptUtils,与之代替的是 CommonEncrypt - 之前放在 EncryptUtils 的 byte[] 转 hex string 的工具转移到了新的 CommonConvert 当中 - encryptByXXX 的命名改为了 hashXXX 的命名(虽然由于目前都是散列工具) - CommonEncrypt 也添加了可以用于规范化的 ENC_STD_CHARSET 字段,以及 sha1/256/512 一系列工具方法 - CommonFormatUtils 也跟随上文,类名改为了 CommonFormat(内容没有变) - 为这三个 utils.CommonXXX 都添加了 Test 类 ## 🔩技术修改/typo - CommonFormat.formatDate 中定义日期格式的字符串独立为了一个字段 - CommonConvert byte -> hex-char 的实现方式改为了 Integer.toHexString
This commit is contained in:
commit
3661cb1264
3
.gitignore
vendored
3
.gitignore
vendored
@ -4,7 +4,8 @@
|
||||
.vscode/
|
||||
.gradle/
|
||||
.settings/
|
||||
/src/test/*
|
||||
/src/test/java/test/*
|
||||
/src/test/resources/test/*
|
||||
|
||||
#build
|
||||
/build/
|
||||
|
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
[submodule "_book"]
|
||||
path = _book
|
||||
url = https://storage.sukazyo.cc/Eyre_S/morny-book.git
|
@ -2,7 +2,7 @@
|
||||
[tg-account]: https://t.me/morny_cono_annie_bot
|
||||
[issues]: https://github.com/Eyre-S/Coeur-Morny-Cono/issues
|
||||
[todo]: https://github.com/users/Eyre-S/projects/1
|
||||
[artifact]: https://mvn.sukazyo.cc/main/cc/sukazyo/morny-coeur
|
||||
[artifact]: https://mvn.sukazyo.cc/#/releases/cc/sukazyo/morny-coeur
|
||||
|
||||
[tg4j]: https://github.com/pengrad/java-telegram-bot-api
|
||||
[spotbugs]: https://spotbugs.github.io/
|
||||
|
1
_book
Submodule
1
_book
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit 3072bcee8e498e87ecdd36958185ad423e80bcf3
|
10
build.gradle
10
build.gradle
@ -17,24 +17,16 @@ repositories {
|
||||
maven { name '-ws'; url 'https://mvn.sukazyo.cc/releases' }
|
||||
}
|
||||
|
||||
String untitled (String lib, String upd = null) {
|
||||
int majorCode = Integer.parseInt(project.libUntitledVersionMajor)
|
||||
return "cc.sukazyo.untitled:$lib:[$majorCode${upd==null?"":".$upd"}, ${majorCode+1}["
|
||||
}
|
||||
dependencies {
|
||||
|
||||
compileOnlyApi "com.github.spotbugs:spotbugs-annotations:${libSpotbugsVersion}"
|
||||
|
||||
implementation untitled("util-command-parser","1.0")
|
||||
implementation untitled("util-string-commons", "1.0")
|
||||
implementation untitled("util-telegram-api", "2.1")
|
||||
implementation untitled("util-telegram-api-formatter", "3.3")
|
||||
implementation untitled("util-telegram-commons", "1.0")
|
||||
api "cc.sukazyo:messiva:${libMessivaVersion}"
|
||||
|
||||
implementation "com.github.pengrad:java-telegram-bot-api:${libJavaTelegramBotApiVersion}"
|
||||
|
||||
testImplementation "org.junit.jupiter:junit-jupiter-api:${libJunitVersion}"
|
||||
testImplementation "org.junit.jupiter:junit-jupiter-params:${libJunitVersion}"
|
||||
testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:${libJunitVersion}"
|
||||
|
||||
}
|
||||
|
@ -1,15 +1,13 @@
|
||||
## Core
|
||||
|
||||
VERSION = 0.7.2.1
|
||||
VERSION = 0.8.0.11
|
||||
|
||||
CODENAME = fuzhou
|
||||
CODENAME = putian
|
||||
|
||||
# dependencies
|
||||
|
||||
libSpotbugsVersion = 4.7.2
|
||||
|
||||
libUntitledVersionMajor = 1
|
||||
|
||||
libMessivaVersion = 0.1.0.1
|
||||
|
||||
libJavaTelegramBotApiVersion = 5.6.0
|
||||
|
@ -4,7 +4,7 @@ package cc.sukazyo.cono.morny;
|
||||
* the final field that will be updated by gradle automatically.
|
||||
*/
|
||||
public class GradleProjectConfigures {
|
||||
public static final String VERSION = "0.7.2.1";
|
||||
public static final String CODENAME = "fuzhou";
|
||||
public static final long COMPILE_TIMESTAMP = 1664590869773L;
|
||||
public static final String VERSION = "0.8.0.11";
|
||||
public static final String CODENAME = "putian";
|
||||
public static final long COMPILE_TIMESTAMP = 1667376095614L;
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ import cc.sukazyo.cono.morny.bot.event.EventListeners;
|
||||
import cc.sukazyo.cono.morny.bot.query.MornyQueries;
|
||||
import cc.sukazyo.cono.morny.daemon.MornyDaemons;
|
||||
import cc.sukazyo.cono.morny.daemon.TrackerDataManager;
|
||||
import cc.sukazyo.untitled.telegram.api.extra.ExtraAction;
|
||||
import cc.sukazyo.cono.morny.util.tgapi.ExtraAction;
|
||||
import com.pengrad.telegrambot.TelegramBot;
|
||||
import com.pengrad.telegrambot.impl.FileApi;
|
||||
import com.pengrad.telegrambot.model.User;
|
||||
@ -59,7 +59,7 @@ public class MornyCoeur {
|
||||
* {@link cc.sukazyo.cono.morny.bot.event.OnUpdateTimestampOffsetLock}
|
||||
* 会根据这里定义的时间戳取消掉比此时间更早的事件链
|
||||
*/
|
||||
public long latestEventTimestamp;
|
||||
public final long latestEventTimestamp;
|
||||
/**
|
||||
* morny 主程序启动时间<br>
|
||||
* 用于统计数据
|
||||
|
@ -1,6 +1,6 @@
|
||||
package cc.sukazyo.cono.morny;
|
||||
|
||||
import cc.sukazyo.cono.morny.util.CommonFormatUtils;
|
||||
import cc.sukazyo.cono.morny.util.CommonFormat;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
@ -205,7 +205,7 @@ public class ServerMain {
|
||||
MornySystem.VERSION, MornySystem.CODENAME.toUpperCase(),
|
||||
MornySystem.getJarMd5(),
|
||||
GradleProjectConfigures.COMPILE_TIMESTAMP,
|
||||
CommonFormatUtils.formatDate(GradleProjectConfigures.COMPILE_TIMESTAMP, 0)
|
||||
CommonFormat.formatDate(GradleProjectConfigures.COMPILE_TIMESTAMP, 0)
|
||||
));
|
||||
return;
|
||||
|
||||
|
@ -1,10 +1,9 @@
|
||||
package cc.sukazyo.cono.morny.bot.api;
|
||||
|
||||
import cc.sukazyo.cono.morny.util.tgapi.event.EventRuntimeException;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.pengrad.telegrambot.model.Update;
|
||||
|
||||
import cc.sukazyo.untitled.telegram.api.event.EventRuntimeException;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
|
@ -1,7 +1,7 @@
|
||||
package cc.sukazyo.cono.morny.bot.command;
|
||||
|
||||
import cc.sukazyo.cono.morny.MornyCoeur;
|
||||
import cc.sukazyo.untitled.util.telegram.object.InputCommand;
|
||||
import cc.sukazyo.cono.morny.util.tgapi.InputCommand;
|
||||
import com.pengrad.telegrambot.model.Chat;
|
||||
import com.pengrad.telegrambot.model.Update;
|
||||
import com.pengrad.telegrambot.request.DeleteMessage;
|
||||
|
205
src/main/java/cc/sukazyo/cono/morny/bot/command/Encryptor.java
Normal file
205
src/main/java/cc/sukazyo/cono/morny/bot/command/Encryptor.java
Normal file
@ -0,0 +1,205 @@
|
||||
package cc.sukazyo.cono.morny.bot.command;
|
||||
|
||||
import cc.sukazyo.cono.morny.MornyCoeur;
|
||||
import cc.sukazyo.cono.morny.data.TelegramStickers;
|
||||
import cc.sukazyo.cono.morny.util.CommonConvert;
|
||||
import cc.sukazyo.cono.morny.util.CommonEncrypt;
|
||||
import cc.sukazyo.cono.morny.util.tgapi.InputCommand;
|
||||
import cc.sukazyo.cono.morny.util.tgapi.formatting.MsgEscape;
|
||||
import com.pengrad.telegrambot.model.PhotoSize;
|
||||
import com.pengrad.telegrambot.model.Update;
|
||||
import com.pengrad.telegrambot.model.request.ParseMode;
|
||||
import com.pengrad.telegrambot.request.GetFile;
|
||||
import com.pengrad.telegrambot.request.SendDocument;
|
||||
import com.pengrad.telegrambot.request.SendMessage;
|
||||
import com.pengrad.telegrambot.request.SendSticker;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import java.io.IOException;
|
||||
import java.util.Base64;
|
||||
|
||||
import static cc.sukazyo.cono.morny.Log.logger;
|
||||
|
||||
public class Encryptor implements ITelegramCommand {
|
||||
|
||||
@Nonnull @Override public String getName () { return "encrypt"; }
|
||||
@Nullable @Override public String[] getAliases () { return new String[0]; }
|
||||
@Nonnull @Override public String getParamRule () { return "[algorithm|(l)] [(uppercase)]"; }
|
||||
@Nonnull @Override public String getDescription () { return "通过指定算法加密回复的内容 (目前只支持文本)"; }
|
||||
|
||||
@Override
|
||||
public void execute (@Nonnull InputCommand command, @Nonnull Update event) {
|
||||
|
||||
// show a simple help page
|
||||
// the first paragraph lists available encrypt algorithms, and its aliases.
|
||||
// with the separator "---",
|
||||
// the second paragraphs shows the mods available and its aliases.
|
||||
if (!command.hasArgs() || (command.getArgs()[0].equals("l") && command.getArgs().length==1)) {
|
||||
MornyCoeur.extra().exec(new SendMessage(
|
||||
event.message().chat().id(), """
|
||||
<b><u>base64</u></b>, b64
|
||||
<b><u>base64url</u></b>, base64u, b64u
|
||||
<b><u>base64decode</u></b>, base64d, b64d
|
||||
<b><u>base64url-decode</u></b>, base64ud, b64ud
|
||||
<b><u>sha1</u></b>
|
||||
<b><u>sha256</u></b>
|
||||
<b><u>sha512</u></b>
|
||||
<b><u>md5</u></b>
|
||||
---
|
||||
<b><i>uppercase</i></b>, upper, u <i>(sha1/sha256/sha512/md5 only)</i>
|
||||
"""
|
||||
).replyToMessageId(event.message().messageId()).parseMode(ParseMode.HTML));
|
||||
return;
|
||||
}
|
||||
|
||||
// param1 is the encrypting algorithm, it MUST EXIST.
|
||||
// so the mod will be set in param2.
|
||||
// and for now only support UPPERCASE mod, so it exists in param2, or there should no any params.
|
||||
boolean modUpperCase = false;
|
||||
if (command.getArgs().length > 1) {
|
||||
if (command.getArgs().length < 3 && (
|
||||
command.getArgs()[1].equalsIgnoreCase("uppercase") ||
|
||||
command.getArgs()[1].equalsIgnoreCase("u") ||
|
||||
command.getArgs()[1].equalsIgnoreCase("upper")
|
||||
)) {
|
||||
modUpperCase = true;
|
||||
} else {
|
||||
MornyCoeur.extra().exec(new SendSticker(
|
||||
event.message().chat().id(), TelegramStickers.ID_404
|
||||
).replyToMessageId(event.message().messageId()));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// for now, only support reply to A TEXT MESSAGE or ONE UNIVERSAL FILE
|
||||
// if the replied message contains a UNIVERSAL FILE, it will use the file and will not use the text with it
|
||||
// do not support TELEGRAM INLINE IMAGE/VIDEO/AUDIO yet
|
||||
// do not support MULTI_FILE yet
|
||||
// if there's no text message in reply, it will report null as result.
|
||||
boolean inputText;
|
||||
byte[] data;
|
||||
String dataName;
|
||||
if (event.message().replyToMessage() != null && event.message().replyToMessage().document() != null) {
|
||||
inputText = false;
|
||||
try {
|
||||
data = MornyCoeur.getAccount().getFileContent(MornyCoeur.extra().exec(new GetFile(
|
||||
event.message().replyToMessage().document().fileId()
|
||||
)).file());
|
||||
} catch (IOException e) {
|
||||
logger.warn("NetworkRequest error: TelegramFileAPI:\n\t" + e.getMessage());
|
||||
MornyCoeur.extra().exec(new SendSticker(
|
||||
event.message().chat().id(),
|
||||
TelegramStickers.ID_NETWORK_ERR
|
||||
).replyToMessageId(event.message().messageId()));
|
||||
return;
|
||||
}
|
||||
dataName = event.message().replyToMessage().document().fileName();
|
||||
} else if (event.message().replyToMessage() != null && event.message().replyToMessage().photo() != null) {
|
||||
inputText = false;
|
||||
try {
|
||||
PhotoSize originPhoto = null;
|
||||
long photoSize = 0;
|
||||
for (PhotoSize size : event.message().replyToMessage().photo()) if (photoSize < (long)size.width() *size.height()) {
|
||||
originPhoto = size;
|
||||
photoSize = (long)size.width() *size.height();
|
||||
} // found max size (original) image in available sizes
|
||||
if (originPhoto==null) throw new IOException("no photo object from api.");
|
||||
data = MornyCoeur.getAccount().getFileContent(MornyCoeur.extra().exec(new GetFile(
|
||||
originPhoto.fileId()
|
||||
)).file());
|
||||
} catch (IOException e) {
|
||||
logger.warn("NetworkRequest error: TelegramFileAPI:\n\t" + e.getMessage());
|
||||
MornyCoeur.extra().exec(new SendSticker(
|
||||
event.message().chat().id(),
|
||||
TelegramStickers.ID_NETWORK_ERR
|
||||
).replyToMessageId(event.message().messageId()));
|
||||
return;
|
||||
}
|
||||
dataName = "photo"+CommonConvert.byteArrayToHex(CommonEncrypt.hashMd5(String.valueOf(System.currentTimeMillis()))).substring(32-12).toUpperCase()+".png";
|
||||
} else if (event.message().replyToMessage() != null && event.message().replyToMessage().text() != null) {
|
||||
inputText = true;
|
||||
data = event.message().replyToMessage().text().getBytes(CommonEncrypt.ENCRYPT_STANDARD_CHARSET);
|
||||
dataName = null;
|
||||
} else {
|
||||
MornyCoeur.extra().exec(new SendMessage(
|
||||
event.message().chat().id(),
|
||||
"<i><u>null</u></i>"
|
||||
).replyToMessageId(event.message().messageId()).parseMode(ParseMode.HTML));
|
||||
return;
|
||||
}
|
||||
|
||||
boolean echoString = true;
|
||||
String resultString = null;
|
||||
byte[] result = null;
|
||||
String resultName = null;
|
||||
switch (command.getArgs()[0]) {
|
||||
case "base64", "b64", "base64url", "base64u", "b64u" -> {
|
||||
final Base64.Encoder b64tool = command.getArgs()[0].contains("u") ? Base64.getUrlEncoder() : Base64.getEncoder();
|
||||
result = b64tool.encode(data);
|
||||
if (!inputText) {
|
||||
echoString = false;
|
||||
resultName = dataName+".b64.txt";
|
||||
} else {
|
||||
resultString = new String(result, CommonEncrypt.ENCRYPT_STANDARD_CHARSET);
|
||||
}
|
||||
}
|
||||
case "base64decode", "base64d", "b64d", "base64url-decode", "base64ud", "b64ud" -> {
|
||||
final Base64.Decoder b64tool = command.getArgs()[0].contains("u") ? Base64.getUrlDecoder() : Base64.getDecoder();
|
||||
try { result = b64tool.decode(data); }
|
||||
catch (IllegalArgumentException e) {
|
||||
MornyCoeur.extra().exec(new SendSticker(
|
||||
event.message().chat().id(), TelegramStickers.ID_404
|
||||
).replyToMessageId(event.message().messageId()));
|
||||
return;
|
||||
}
|
||||
if (!inputText) {
|
||||
echoString = false;
|
||||
resultName = CommonEncrypt.base64FilenameLint(dataName);
|
||||
} else {
|
||||
resultString = new String(result, CommonEncrypt.ENCRYPT_STANDARD_CHARSET);
|
||||
}
|
||||
}
|
||||
case "md5" -> resultString = CommonConvert.byteArrayToHex(CommonEncrypt.hashMd5(data));
|
||||
case "sha1" -> resultString = CommonConvert.byteArrayToHex(CommonEncrypt.hashSha1(data));
|
||||
case "sha256" -> resultString = CommonConvert.byteArrayToHex(CommonEncrypt.hashSha256(data));
|
||||
case "sha512" -> resultString = CommonConvert.byteArrayToHex(CommonEncrypt.hashSha512(data));
|
||||
default -> {
|
||||
MornyCoeur.extra().exec(new SendSticker(
|
||||
event.message().chat().id(), TelegramStickers.ID_404
|
||||
).replyToMessageId(event.message().messageId()));
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (modUpperCase) {
|
||||
// modUpperCase support only algorithm that showed as HEX value.
|
||||
// it means md5, sha1, sha256, sha512 here.
|
||||
// other will report wrong param.
|
||||
switch (command.getArgs()[0]) {
|
||||
case "md5", "sha1", "sha256", "sha512" -> {
|
||||
assert resultString != null;
|
||||
resultString = resultString.toUpperCase();
|
||||
}
|
||||
default -> {
|
||||
MornyCoeur.extra().exec(new SendSticker(
|
||||
event.message().chat().id(), TelegramStickers.ID_404
|
||||
).replyToMessageId(event.message().messageId()));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (echoString) {
|
||||
MornyCoeur.extra().exec(new SendMessage(
|
||||
event.message().chat().id(),
|
||||
"<pre><code>" + MsgEscape.escapeHtml(resultString) + "</code></pre>"
|
||||
).replyToMessageId(event.message().messageId()).parseMode(ParseMode.HTML));
|
||||
} else {
|
||||
MornyCoeur.extra().exec(new SendDocument(
|
||||
event.message().chat().id(),
|
||||
result
|
||||
).fileName(resultName).replyToMessageId(event.message().messageId()));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -4,8 +4,8 @@ import cc.sukazyo.cono.morny.MornyCoeur;
|
||||
import cc.sukazyo.cono.morny.MornyTrusted;
|
||||
import cc.sukazyo.cono.morny.bot.event.OnEventHackHandle;
|
||||
import cc.sukazyo.cono.morny.data.TelegramStickers;
|
||||
import cc.sukazyo.untitled.util.telegram.object.InputCommand;
|
||||
|
||||
import cc.sukazyo.cono.morny.util.tgapi.InputCommand;
|
||||
import com.pengrad.telegrambot.model.Update;
|
||||
import com.pengrad.telegrambot.request.SendSticker;
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
package cc.sukazyo.cono.morny.bot.command;
|
||||
|
||||
import cc.sukazyo.cono.morny.MornyCoeur;
|
||||
import cc.sukazyo.cono.morny.util.TelegramUserInformation;
|
||||
import cc.sukazyo.untitled.util.telegram.object.InputCommand;
|
||||
import cc.sukazyo.cono.morny.util.tgapi.InputCommand;
|
||||
import cc.sukazyo.cono.morny.util.tgapi.formatting.TelegramUserInformation;
|
||||
import com.pengrad.telegrambot.model.Update;
|
||||
import com.pengrad.telegrambot.model.User;
|
||||
import com.pengrad.telegrambot.model.request.ParseMode;
|
||||
|
@ -1,6 +1,6 @@
|
||||
package cc.sukazyo.cono.morny.bot.command;
|
||||
|
||||
import cc.sukazyo.untitled.util.telegram.object.InputCommand;
|
||||
import cc.sukazyo.cono.morny.util.tgapi.InputCommand;
|
||||
import com.pengrad.telegrambot.model.Update;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
@ -2,8 +2,8 @@ package cc.sukazyo.cono.morny.bot.command;
|
||||
|
||||
import cc.sukazyo.cono.morny.MornyCoeur;
|
||||
import cc.sukazyo.cono.morny.data.ip186.IP186QueryResponse;
|
||||
import cc.sukazyo.untitled.util.telegram.object.InputCommand;
|
||||
import cc.sukazyo.cono.morny.data.ip186.IP186QueryHandler;
|
||||
import cc.sukazyo.cono.morny.util.tgapi.InputCommand;
|
||||
import com.pengrad.telegrambot.model.Update;
|
||||
import com.pengrad.telegrambot.model.request.ParseMode;
|
||||
import com.pengrad.telegrambot.request.SendMessage;
|
||||
@ -12,7 +12,8 @@ import org.jetbrains.annotations.NotNull;
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import static cc.sukazyo.untitled.util.telegram.formatting.MsgEscape.escapeHtml;
|
||||
import static cc.sukazyo.cono.morny.util.tgapi.formatting.MsgEscape.escapeHtml;
|
||||
|
||||
|
||||
/**
|
||||
* {@value IP186QueryHandler#SITE_URL} 查询的 telegram 命令前端
|
||||
|
@ -5,8 +5,8 @@ import cc.sukazyo.cono.morny.MornyCoeur;
|
||||
import cc.sukazyo.cono.morny.MornySystem;
|
||||
import cc.sukazyo.cono.morny.data.MornyJrrp;
|
||||
import cc.sukazyo.cono.morny.data.TelegramStickers;
|
||||
import cc.sukazyo.untitled.telegram.api.formatting.TGToString;
|
||||
import cc.sukazyo.untitled.util.telegram.object.InputCommand;
|
||||
import cc.sukazyo.cono.morny.util.tgapi.InputCommand;
|
||||
import cc.sukazyo.cono.morny.util.tgapi.formatting.TGToString;
|
||||
import com.pengrad.telegrambot.model.BotCommand;
|
||||
import com.pengrad.telegrambot.model.DeleteMyCommands;
|
||||
import com.pengrad.telegrambot.model.Update;
|
||||
@ -27,9 +27,9 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static cc.sukazyo.cono.morny.Log.logger;
|
||||
import static cc.sukazyo.cono.morny.util.CommonFormatUtils.formatDate;
|
||||
import static cc.sukazyo.cono.morny.util.CommonFormatUtils.formatDuration;
|
||||
import static cc.sukazyo.untitled.util.telegram.formatting.MsgEscape.escapeHtml;
|
||||
import static cc.sukazyo.cono.morny.util.CommonFormat.formatDate;
|
||||
import static cc.sukazyo.cono.morny.util.CommonFormat.formatDuration;
|
||||
import static cc.sukazyo.cono.morny.util.tgapi.formatting.MsgEscape.escapeHtml;
|
||||
|
||||
public class MornyCommands {
|
||||
|
||||
@ -57,6 +57,7 @@ public class MornyCommands {
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("NonAsciiCharacters")
|
||||
public MornyCommands () {
|
||||
|
||||
register(
|
||||
@ -67,7 +68,9 @@ public class MornyCommands {
|
||||
new Nbnhhsh(),
|
||||
new Ip186Query.Ip(),
|
||||
new Ip186Query.Whois(),
|
||||
new Encryptor(),
|
||||
new SaveData(),
|
||||
new MornyInformations(),
|
||||
new Version(),
|
||||
new MornyRuntime(),
|
||||
new Jrrp(),
|
||||
@ -76,6 +79,7 @@ public class MornyCommands {
|
||||
|
||||
// 特殊的命令
|
||||
register(
|
||||
new Testing(),
|
||||
new DirectMsgClear()
|
||||
);
|
||||
|
||||
@ -85,7 +89,8 @@ public class MornyCommands {
|
||||
new 喵呜.揉揉(),
|
||||
new 喵呜.蹭蹭(),
|
||||
new 喵呜.贴贴(),
|
||||
new 私わね()
|
||||
new 私わね(),
|
||||
new 喵呜.Progynova()
|
||||
);
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,46 @@
|
||||
package cc.sukazyo.cono.morny.bot.command;
|
||||
|
||||
import cc.sukazyo.cono.morny.MornyCoeur;
|
||||
import cc.sukazyo.cono.morny.data.TelegramStickers;
|
||||
import cc.sukazyo.cono.morny.util.tgapi.InputCommand;
|
||||
import com.pengrad.telegrambot.model.Update;
|
||||
import com.pengrad.telegrambot.request.SendSticker;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class MornyInformations implements ITelegramCommand {
|
||||
|
||||
private static final String ACT_STICKER = "stickers";
|
||||
|
||||
@Nonnull @Override public String getName () { return "info"; }
|
||||
@Nullable @Override public String[] getAliases () { return new String[0]; }
|
||||
@Nonnull @Override public String getParamRule () { return "[(stickers)|(stickers.)sticker_id]"; }
|
||||
@Nonnull @Override public String getDescription () { return "输出 Morny 当前版本的一些预定义信息"; }
|
||||
|
||||
@Override
|
||||
public void execute (@Nonnull InputCommand command, @Nonnull Update event) {
|
||||
|
||||
if (!command.hasArgs() || command.getArgs().length > 1) {
|
||||
MornyCoeur.extra().exec(new SendSticker(event.message().chat().id(), TelegramStickers.ID_404).replyToMessageId(event.message().messageId()));
|
||||
}
|
||||
|
||||
final String action = command.getArgs()[0];
|
||||
|
||||
if (action.startsWith("stickers")) {
|
||||
if (action.equals("stickers"))
|
||||
TelegramStickers.echoAllStickers(MornyCoeur.extra(), event.message().chat().id(), event.message().messageId());
|
||||
else {
|
||||
TelegramStickers.echoStickerByID(
|
||||
action.substring((ACT_STICKER+".").length()),
|
||||
MornyCoeur.extra(), event.message().chat().id(), event.message().messageId()
|
||||
);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
MornyCoeur.extra().exec(new SendSticker(event.message().chat().id(), TelegramStickers.ID_404).replyToMessageId(event.message().messageId()));
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -1,18 +1,18 @@
|
||||
package cc.sukazyo.cono.morny.bot.command;
|
||||
|
||||
import cc.sukazyo.cono.morny.util.tgapi.InputCommand;
|
||||
import com.pengrad.telegrambot.model.Update;
|
||||
import com.pengrad.telegrambot.model.request.ParseMode;
|
||||
import com.pengrad.telegrambot.request.SendMessage;
|
||||
|
||||
import cc.sukazyo.cono.morny.MornyCoeur;
|
||||
import cc.sukazyo.cono.morny.data.NbnhhshQuery;
|
||||
import cc.sukazyo.untitled.util.string.StringArrays;
|
||||
import cc.sukazyo.untitled.util.telegram.object.InputCommand;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import static cc.sukazyo.untitled.util.telegram.formatting.MsgEscape.escapeHtml;
|
||||
import static cc.sukazyo.cono.morny.util.CommonConvert.stringsConnecting;
|
||||
import static cc.sukazyo.cono.morny.util.tgapi.formatting.MsgEscape.escapeHtml;
|
||||
|
||||
public class Nbnhhsh implements ITelegramCommand {
|
||||
|
||||
@ -30,7 +30,7 @@ public class Nbnhhsh implements ITelegramCommand {
|
||||
if (event.message().replyToMessage() != null && event.message().replyToMessage().text() != null)
|
||||
queryTarget = event.message().replyToMessage().text();
|
||||
if (command.hasArgs())
|
||||
queryTarget = StringArrays.connectStringArray(command.getArgs(), " ", 0, command.getArgs().length-1);
|
||||
queryTarget = stringsConnecting(command.getArgs(), " ", 0, command.getArgs().length-1);
|
||||
|
||||
NbnhhshQuery.GuessResult response = NbnhhshQuery.sendGuess(queryTarget);
|
||||
|
||||
|
36
src/main/java/cc/sukazyo/cono/morny/bot/command/Testing.java
Normal file
36
src/main/java/cc/sukazyo/cono/morny/bot/command/Testing.java
Normal file
@ -0,0 +1,36 @@
|
||||
package cc.sukazyo.cono.morny.bot.command;
|
||||
|
||||
import cc.sukazyo.cono.morny.MornyCoeur;
|
||||
import cc.sukazyo.cono.morny.util.tgapi.InputCommand;
|
||||
import com.pengrad.telegrambot.model.Update;
|
||||
import com.pengrad.telegrambot.model.request.ParseMode;
|
||||
import com.pengrad.telegrambot.request.SendMessage;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class Testing implements ISimpleCommand {
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public String getName () {
|
||||
return "test";
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public String[] getAliases () {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute (@Nonnull InputCommand command, @Nonnull Update event) {
|
||||
|
||||
MornyCoeur.extra().exec(new SendMessage(
|
||||
event.message().chat().id(),
|
||||
"<b>Just<b/> a TEST command."
|
||||
).replyToMessageId(event.message().messageId()).parseMode(ParseMode.HTML));
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -1,10 +1,12 @@
|
||||
package cc.sukazyo.cono.morny.bot.command;
|
||||
|
||||
import cc.sukazyo.cono.morny.MornyCoeur;
|
||||
import cc.sukazyo.untitled.util.telegram.object.InputCommand;
|
||||
import cc.sukazyo.cono.morny.data.TelegramStickers;
|
||||
import cc.sukazyo.cono.morny.util.tgapi.InputCommand;
|
||||
import com.pengrad.telegrambot.model.Update;
|
||||
import com.pengrad.telegrambot.model.request.ParseMode;
|
||||
import com.pengrad.telegrambot.request.SendMessage;
|
||||
import com.pengrad.telegrambot.request.SendSticker;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
@ -56,4 +58,17 @@ public class 喵呜 {
|
||||
}
|
||||
}
|
||||
|
||||
public static class Progynova implements ITelegramCommand {
|
||||
@Nonnull @Override public String getName () { return "install"; }
|
||||
@Nullable @Override public String[] getAliases () { return new String[0]; }
|
||||
@Nonnull @Override public String getParamRule () { return ""; }
|
||||
@Nonnull @Override public String getDescription () { return "抽取一个神秘盒子"; }
|
||||
@Override public void execute (@Nonnull InputCommand command, @Nonnull Update event) {
|
||||
MornyCoeur.extra().exec(new SendSticker(
|
||||
event.message().chat().id(),
|
||||
TelegramStickers.ID_PROGYNOVA
|
||||
).replyToMessageId(event.message().messageId()));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
package cc.sukazyo.cono.morny.bot.command;
|
||||
|
||||
import cc.sukazyo.cono.morny.MornyCoeur;
|
||||
import cc.sukazyo.untitled.util.telegram.object.InputCommand;
|
||||
import cc.sukazyo.cono.morny.util.tgapi.InputCommand;
|
||||
import com.pengrad.telegrambot.model.Update;
|
||||
import com.pengrad.telegrambot.request.SendMessage;
|
||||
|
||||
|
@ -5,7 +5,7 @@ import cc.sukazyo.cono.morny.bot.api.EventListenerManager;
|
||||
public class EventListeners {
|
||||
|
||||
public static final OnTelegramCommand COMMANDS_LISTENER = new OnTelegramCommand();
|
||||
public static final OnActivityRecord ACTIVITY_RECORDER = new OnActivityRecord();
|
||||
@SuppressWarnings("unused") public static final OnActivityRecord ACTIVITY_RECORDER = new OnActivityRecord();
|
||||
public static final OnUserSlashAction USER_SLASH_ACTION = new OnUserSlashAction();
|
||||
public static final OnUpdateTimestampOffsetLock UPDATE_TIMESTAMP_OFFSET_LOCK = new OnUpdateTimestampOffsetLock();
|
||||
public static final OnInlineQueries INLINE_QUERY = new OnInlineQueries();
|
||||
@ -19,7 +19,7 @@ public class EventListeners {
|
||||
|
||||
public static void registerAllListeners () {
|
||||
EventListenerManager.addListener(
|
||||
ACTIVITY_RECORDER,
|
||||
// ACTIVITY_RECORDER,
|
||||
UPDATE_TIMESTAMP_OFFSET_LOCK,
|
||||
/* write functional event behind here */
|
||||
// KUOHUANHUAN_NEED_SLEEP,
|
||||
|
@ -4,9 +4,9 @@ import cc.sukazyo.cono.morny.MornyCoeur;
|
||||
import cc.sukazyo.cono.morny.MornyTrusted;
|
||||
import cc.sukazyo.cono.morny.bot.api.EventListener;
|
||||
import cc.sukazyo.cono.morny.data.TelegramStickers;
|
||||
import cc.sukazyo.cono.morny.util.CommonFormatUtils;
|
||||
import cc.sukazyo.untitled.telegram.api.formatting.TGToString;
|
||||
import cc.sukazyo.untitled.util.telegram.formatting.MsgEscape;
|
||||
import cc.sukazyo.cono.morny.util.CommonFormat;
|
||||
import cc.sukazyo.cono.morny.util.tgapi.formatting.MsgEscape;
|
||||
import cc.sukazyo.cono.morny.util.tgapi.formatting.TGToString;
|
||||
import com.pengrad.telegrambot.model.Chat;
|
||||
import com.pengrad.telegrambot.model.Message;
|
||||
import com.pengrad.telegrambot.model.Update;
|
||||
@ -122,9 +122,9 @@ public class OnCallMe extends EventListener {
|
||||
event.message().from().id(),
|
||||
String.format("<i>on</i> <code>%s [UTC+8]</code>\n- <code>%s</code> <i>before</i>",
|
||||
MsgEscape.escapeHtml(
|
||||
CommonFormatUtils.formatDate((long)lastDinnerData.forwardDate()*1000, 8)
|
||||
CommonFormat.formatDate((long)lastDinnerData.forwardDate()*1000, 8)
|
||||
), MsgEscape.escapeHtml(
|
||||
CommonFormatUtils.formatDuration(System.currentTimeMillis()-(long)lastDinnerData.forwardDate()*1000)
|
||||
CommonFormat.formatDuration(System.currentTimeMillis()-(long)lastDinnerData.forwardDate()*1000)
|
||||
)
|
||||
)
|
||||
).replyToMessageId(sendResp.message().messageId()).parseMode(ParseMode.HTML));
|
||||
|
@ -22,7 +22,8 @@ import cc.sukazyo.cono.morny.data.TelegramStickers;
|
||||
import com.pengrad.telegrambot.response.GetChatResponse;
|
||||
import com.pengrad.telegrambot.response.SendResponse;
|
||||
|
||||
import static cc.sukazyo.untitled.util.telegram.formatting.MsgEscape.escapeHtml;
|
||||
import static cc.sukazyo.cono.morny.util.tgapi.formatting.MsgEscape.escapeHtml;
|
||||
|
||||
|
||||
public class OnCallMsgSend extends EventListener {
|
||||
|
||||
|
@ -2,7 +2,7 @@ package cc.sukazyo.cono.morny.bot.event;
|
||||
|
||||
import cc.sukazyo.cono.morny.MornyCoeur;
|
||||
import cc.sukazyo.cono.morny.bot.api.EventListener;
|
||||
import cc.sukazyo.untitled.util.telegram.formatting.MsgEscape;
|
||||
import cc.sukazyo.cono.morny.util.tgapi.formatting.MsgEscape;
|
||||
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.pengrad.telegrambot.model.Update;
|
||||
|
@ -2,7 +2,7 @@ package cc.sukazyo.cono.morny.bot.event;
|
||||
|
||||
import cc.sukazyo.cono.morny.MornyCoeur;
|
||||
import cc.sukazyo.cono.morny.bot.api.EventListener;
|
||||
import cc.sukazyo.untitled.util.telegram.object.InputCommand;
|
||||
import cc.sukazyo.cono.morny.util.tgapi.InputCommand;
|
||||
|
||||
import com.pengrad.telegrambot.model.Update;
|
||||
|
||||
|
@ -2,7 +2,7 @@ package cc.sukazyo.cono.morny.bot.event;
|
||||
|
||||
import cc.sukazyo.cono.morny.MornyCoeur;
|
||||
import cc.sukazyo.cono.morny.bot.api.EventListener;
|
||||
import cc.sukazyo.untitled.util.command.CommonCommand;
|
||||
import cc.sukazyo.cono.morny.util.UniversalCommand;
|
||||
import com.pengrad.telegrambot.model.Update;
|
||||
import com.pengrad.telegrambot.request.SendMessage;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@ -22,7 +22,7 @@ public class OnUserRandoms extends EventListener {
|
||||
if (update.message().text() == null) return false;
|
||||
if (!update.message().text().startsWith("/")) return false;
|
||||
|
||||
final String[] preProcess = CommonCommand.format(update.message().text());
|
||||
final String[] preProcess = UniversalCommand.format(update.message().text());
|
||||
if (preProcess.length > 1) return false;
|
||||
final String query = preProcess[0];
|
||||
|
||||
|
@ -2,9 +2,8 @@ package cc.sukazyo.cono.morny.bot.event;
|
||||
|
||||
import cc.sukazyo.cono.morny.MornyCoeur;
|
||||
import cc.sukazyo.cono.morny.bot.api.EventListener;
|
||||
import cc.sukazyo.cono.morny.util.tgapi.TGToStringFromMessage;
|
||||
import cc.sukazyo.untitled.util.command.CommonCommand;
|
||||
import cc.sukazyo.untitled.util.string.StringArrays;
|
||||
import cc.sukazyo.cono.morny.util.UniversalCommand;
|
||||
import cc.sukazyo.cono.morny.util.tgapi.formatting.TGToString;
|
||||
|
||||
import com.pengrad.telegrambot.model.Message;
|
||||
import com.pengrad.telegrambot.model.Update;
|
||||
@ -13,7 +12,8 @@ import com.pengrad.telegrambot.request.SendMessage;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import static cc.sukazyo.untitled.util.telegram.formatting.MsgEscape.escapeHtml;
|
||||
import static cc.sukazyo.cono.morny.util.CommonConvert.stringsConnecting;
|
||||
import static cc.sukazyo.cono.morny.util.tgapi.formatting.MsgEscape.escapeHtml;
|
||||
|
||||
public class OnUserSlashAction extends EventListener {
|
||||
|
||||
@ -38,7 +38,7 @@ public class OnUserSlashAction extends EventListener {
|
||||
// return false;
|
||||
// }
|
||||
|
||||
final String[] action = CommonCommand.format(text);
|
||||
final String[] action = UniversalCommand.format(text);
|
||||
action[0] = action[0].substring(1);
|
||||
|
||||
if (action[0].matches("^\\w+(@\\w+)?$")) {
|
||||
@ -53,7 +53,7 @@ public class OnUserSlashAction extends EventListener {
|
||||
final boolean hasObject = action.length != (isHardParse?2:1);
|
||||
final String object =
|
||||
hasObject ?
|
||||
StringArrays.connectStringArray(action, " ", isHardParse?2:1, action.length-1) :
|
||||
stringsConnecting(action, " ", isHardParse?2:1, action.length-1) :
|
||||
"";
|
||||
final Message origin = event.message();
|
||||
final Message target = (event.message().replyToMessage() == null ? (
|
||||
@ -66,11 +66,11 @@ public class OnUserSlashAction extends EventListener {
|
||||
event.message().chat().id(),
|
||||
String.format(
|
||||
"%s %s%s %s %s!",
|
||||
TGToStringFromMessage.as(origin).getSenderFirstNameRefHtml(),
|
||||
TGToString.as(origin).getSenderFirstNameRefHtml(),
|
||||
escapeHtml(verb), escapeHtml((hasObject?"":"了")),
|
||||
origin==target ?
|
||||
"<a href='tg://user?id="+TGToStringFromMessage.as(target).getSenderId()+"'>自己</a>" :
|
||||
TGToStringFromMessage.as(target).getSenderFirstNameRefHtml(),
|
||||
"<a href='tg://user?id="+TGToString.as(target).getSenderId()+"'>自己</a>" :
|
||||
TGToString.as(target).getSenderFirstNameRefHtml(),
|
||||
escapeHtml(hasObject ? object+" " : "")
|
||||
)
|
||||
).parseMode(ParseMode.HTML).replyToMessageId(event.message().messageId()));
|
||||
|
@ -4,11 +4,12 @@ import javax.annotation.Nullable;
|
||||
|
||||
import cc.sukazyo.cono.morny.bot.api.InlineQueryUnit;
|
||||
import com.pengrad.telegrambot.model.Update;
|
||||
import com.pengrad.telegrambot.model.request.InlineQueryResult;
|
||||
|
||||
public interface ITelegramQuery <T extends InlineQueryResult<T>> {
|
||||
import java.util.List;
|
||||
|
||||
public interface ITelegramQuery {
|
||||
|
||||
@Nullable
|
||||
InlineQueryUnit<T> query (Update event);
|
||||
List<InlineQueryUnit<?>> query (Update event);
|
||||
|
||||
}
|
||||
|
@ -9,19 +9,21 @@ import java.util.List;
|
||||
|
||||
public class MornyQueries {
|
||||
|
||||
private final List<ITelegramQuery<?>> queryInstances = new ArrayList<>();
|
||||
private final List<ITelegramQuery> queryInstances = new ArrayList<>();
|
||||
|
||||
public MornyQueries () {
|
||||
queryInstances.add(new RawText());
|
||||
queryInstances.add(new MyInformation());
|
||||
queryInstances.add(new ShareToolTwitter());
|
||||
queryInstances.add(new ShareToolBilibili());
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public List<InlineQueryUnit<?>> query (@Nonnull Update event) {
|
||||
final List<InlineQueryUnit<?>> results = new ArrayList<>();
|
||||
for (ITelegramQuery<?> instance : queryInstances) {
|
||||
final InlineQueryUnit<?> r = instance.query(event);
|
||||
if (r!=null) results.add(r);
|
||||
for (ITelegramQuery instance : queryInstances) {
|
||||
final List<InlineQueryUnit<?>> r = instance.query(event);
|
||||
if (r!=null) results.addAll(r);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
@ -8,23 +8,28 @@ import com.pengrad.telegrambot.model.request.InlineQueryResultArticle;
|
||||
import com.pengrad.telegrambot.model.request.InputTextMessageContent;
|
||||
import com.pengrad.telegrambot.model.request.ParseMode;
|
||||
|
||||
import cc.sukazyo.cono.morny.util.TelegramUserInformation;
|
||||
import cc.sukazyo.cono.morny.util.tgapi.formatting.TelegramUserInformation;
|
||||
|
||||
public class MyInformation implements ITelegramQuery<InlineQueryResultArticle> {
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static cc.sukazyo.cono.morny.util.tgapi.formatting.NamedUtils.inlineIds;
|
||||
|
||||
public class MyInformation implements ITelegramQuery {
|
||||
|
||||
public static final String ID_PREFIX = "[morny/info/me]";
|
||||
public static final String TITLE = "My Account Information";
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public InlineQueryUnit<InlineQueryResultArticle> query(Update event) {
|
||||
public List<InlineQueryUnit<?>> query(Update event) {
|
||||
if (!(event.inlineQuery().query() == null || "".equals(event.inlineQuery().query()))) return null;
|
||||
return new InlineQueryUnit<>(new InlineQueryResultArticle(
|
||||
ID_PREFIX, TITLE,
|
||||
return Collections.singletonList(new InlineQueryUnit<>(new InlineQueryResultArticle(
|
||||
inlineIds(ID_PREFIX), TITLE,
|
||||
new InputTextMessageContent(
|
||||
TelegramUserInformation.informationOutputHTML(event.inlineQuery().from())
|
||||
).parseMode(ParseMode.HTML)
|
||||
)).isPersonal(true).cacheTime(10);
|
||||
)).isPersonal(true).cacheTime(10));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
package cc.sukazyo.cono.morny.bot.query;
|
||||
|
||||
import cc.sukazyo.cono.morny.bot.api.InlineQueryUnit;
|
||||
import cc.sukazyo.cono.morny.util.EncryptUtils;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
@ -9,20 +8,24 @@ import com.pengrad.telegrambot.model.Update;
|
||||
import com.pengrad.telegrambot.model.request.InlineQueryResultArticle;
|
||||
import com.pengrad.telegrambot.model.request.InputTextMessageContent;
|
||||
|
||||
public class RawText implements ITelegramQuery<InlineQueryResultArticle> {
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static cc.sukazyo.cono.morny.util.tgapi.formatting.NamedUtils.inlineIds;
|
||||
|
||||
public class RawText implements ITelegramQuery {
|
||||
|
||||
public static final String ID_PREFIX = "[morny/r/text]";
|
||||
public static final String TITLE = "Raw Text";
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public InlineQueryUnit<InlineQueryResultArticle> query (Update event) {
|
||||
public List<InlineQueryUnit<?>> query (Update event) {
|
||||
if (event.inlineQuery().query() == null || "".equals(event.inlineQuery().query())) return null;
|
||||
return new InlineQueryUnit<>(new InlineQueryResultArticle(
|
||||
ID_PREFIX + EncryptUtils.encryptByMD5(event.inlineQuery().query()),
|
||||
TITLE,
|
||||
return Collections.singletonList(new InlineQueryUnit<>(new InlineQueryResultArticle(
|
||||
inlineIds(ID_PREFIX, event.inlineQuery().query()), TITLE,
|
||||
new InputTextMessageContent(event.inlineQuery().query())
|
||||
));
|
||||
)));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,80 @@
|
||||
package cc.sukazyo.cono.morny.bot.query;
|
||||
|
||||
import cc.sukazyo.cono.morny.bot.api.InlineQueryUnit;
|
||||
import cc.sukazyo.cono.morny.util.BiliTool;
|
||||
import com.pengrad.telegrambot.model.Update;
|
||||
import com.pengrad.telegrambot.model.request.InlineQueryResultArticle;
|
||||
import com.pengrad.telegrambot.model.request.InputTextMessageContent;
|
||||
import com.pengrad.telegrambot.model.request.ParseMode;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
//import static cc.sukazyo.cono.morny.Log.logger;
|
||||
import static cc.sukazyo.cono.morny.util.tgapi.formatting.NamedUtils.inlineIds;
|
||||
|
||||
public class ShareToolBilibili implements ITelegramQuery {
|
||||
|
||||
public static final String TITLE_BILI_AV = "[bilibili] Share video / av";
|
||||
public static final String TITLE_BILI_BV = "[bilibili] Share video / BV";
|
||||
public static final String ID_PREFIX_BILI_AV = "[morny/share/bili/av]";
|
||||
public static final String ID_PREFIX_BILI_BV = "[morny/share/bili/bv]";
|
||||
public static final Pattern REGEX_BILI_VIDEO = Pattern.compile("^(?:(?:https?://)?(?:www\\.)?bilibili\\.com(?:/s)?/video/((?:av|AV)(\\d+)|(?:bv|BV)([A-HJ-NP-Za-km-z1-9]+))/?(\\?(?:p=(\\d+))?.*)?|(?:av|AV)(\\d+)|(?:bv|BV)([A-HJ-NP-Za-km-z1-9]+))$");
|
||||
|
||||
private static final String SHARE_FORMAT_HTML = "<a href='%s'>%s</a>";
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public List<InlineQueryUnit<?>> query (Update event) {
|
||||
if (event.inlineQuery().query() == null) return null;
|
||||
final Matcher regex = REGEX_BILI_VIDEO.matcher(event.inlineQuery().query());
|
||||
if (regex.matches()) {
|
||||
|
||||
// logger.debug(String.format(
|
||||
// "====== ok\n1: %s\n2: %s\n3: %s\n4: %s\n5: %s\n6: %s\n7: %s",
|
||||
// regex.group(1), regex.group(2), regex.group(3), regex.group(4),
|
||||
// regex.group(5), regex.group(6), regex.group(7)
|
||||
// ));
|
||||
|
||||
// get video id from input, also get video part id
|
||||
String av = regex.group(2)==null ? regex.group(6)==null ? null : regex.group(6) : regex.group(2);
|
||||
String bv = regex.group(3)==null ? regex.group(7)==null ? null : regex.group(7) : regex.group(3);
|
||||
// logger.trace(String.format("catch id av[%s] bv[%s]", av, bv));
|
||||
final int part = regex.group(5)==null ? -1 : Integer.parseInt(regex.group(5));
|
||||
// logger.trace(String.format("catch part [%s]", part));
|
||||
if (av == null) {
|
||||
assert bv != null;
|
||||
av = String.valueOf(BiliTool.toAv(bv));
|
||||
// logger.trace(String.format("converted bv[%s] to av[%s]", bv, av));
|
||||
} else {
|
||||
bv = BiliTool.toBv(Long.parseLong(av));
|
||||
// logger.trace(String.format("converted av[%s] to bv[%s]", av, bv));
|
||||
}
|
||||
// build standard share links
|
||||
final String linkPartParam = part==-1 ? "" : "?p="+part;
|
||||
final String linkAv = "https://www.bilibili.com/video/av"+av + linkPartParam;
|
||||
final String linkBv = "https://www.bilibili.com/video/BV"+bv + linkPartParam;
|
||||
final String idAv = "av"+av;
|
||||
final String idBv = "BV"+bv;
|
||||
// logger.trace("built all data.");
|
||||
|
||||
// build share message element
|
||||
List<InlineQueryUnit<?>> result = new ArrayList<>();
|
||||
result.add(new InlineQueryUnit<>(new InlineQueryResultArticle(
|
||||
inlineIds(ID_PREFIX_BILI_AV+av), TITLE_BILI_AV+av,
|
||||
new InputTextMessageContent(String.format(SHARE_FORMAT_HTML, linkAv, idAv)).parseMode(ParseMode.HTML)
|
||||
)));
|
||||
result.add(new InlineQueryUnit<>(new InlineQueryResultArticle(
|
||||
inlineIds(ID_PREFIX_BILI_BV+bv), TITLE_BILI_BV+bv,
|
||||
new InputTextMessageContent(String.format(SHARE_FORMAT_HTML, linkBv, idBv)).parseMode(ParseMode.HTML)
|
||||
)));
|
||||
return result;
|
||||
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
package cc.sukazyo.cono.morny.bot.query;
|
||||
|
||||
import cc.sukazyo.cono.morny.bot.api.InlineQueryUnit;
|
||||
import com.pengrad.telegrambot.model.Update;
|
||||
import com.pengrad.telegrambot.model.request.InlineQueryResultArticle;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static cc.sukazyo.cono.morny.util.tgapi.formatting.NamedUtils.inlineIds;
|
||||
|
||||
public class ShareToolTwitter implements ITelegramQuery {
|
||||
|
||||
public static final String TITLE_VX = "[tweet] Share as VxTwitter";
|
||||
public static final String TITLE_VX_COMBINED = "[tweet] Share as VxTwitter(combination)";
|
||||
public static final String ID_PREFIX_VX = "[morny/share/twitter/vxtwi]";
|
||||
public static final String ID_PREFIX_VX_COMBINED = "[morny/share/twitter/vxtwi_combine]";
|
||||
|
||||
public static final Pattern REGEX_TWEET_LINK = Pattern.compile(
|
||||
"^(?:https?://)?((?:(?:c\\.)?vx|fx|www\\.)?twitter\\.com)/((\\w+)/status/(\\d+)(?:/photo/(\\d+))?)/?(\\?[\\w&=-]+)?$");
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public List<InlineQueryUnit<?>> query (@Nonnull Update event) {
|
||||
if (event.inlineQuery().query() == null) return null;
|
||||
final Matcher regex = REGEX_TWEET_LINK.matcher(event.inlineQuery().query());
|
||||
if (regex.matches()) {
|
||||
|
||||
List<InlineQueryUnit<?>> result = new ArrayList<>();
|
||||
|
||||
result.add(new InlineQueryUnit<>(new InlineQueryResultArticle(
|
||||
inlineIds(ID_PREFIX_VX+event.inlineQuery().query()), TITLE_VX,
|
||||
String.format("https://vxtwitter.com/%s", regex.group(2))
|
||||
)));
|
||||
result.add(new InlineQueryUnit<>(new InlineQueryResultArticle(
|
||||
inlineIds(ID_PREFIX_VX_COMBINED+event.inlineQuery().query()), TITLE_VX_COMBINED,
|
||||
String.format("https://c.vxtwitter.com/%s", regex.group(2))
|
||||
)));
|
||||
|
||||
return result;
|
||||
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
package cc.sukazyo.cono.morny.daemon;
|
||||
|
||||
import cc.sukazyo.cono.morny.MornyCoeur;
|
||||
import cc.sukazyo.cono.morny.util.CommonFormatUtils;
|
||||
import cc.sukazyo.cono.morny.util.CommonFormat;
|
||||
import com.pengrad.telegrambot.model.Message;
|
||||
import com.pengrad.telegrambot.model.MessageEntity;
|
||||
import com.pengrad.telegrambot.model.request.ParseMode;
|
||||
@ -54,7 +54,7 @@ public class MedicationTimer extends Thread {
|
||||
|
||||
public void refreshNotificationWrite (Message edited) {
|
||||
if (edited.messageId() != lastNotify) return;
|
||||
final String editTime = CommonFormatUtils.formatDate(edited.editDate()*1000, 8);
|
||||
final String editTime = CommonFormat.formatDate(edited.editDate()*1000, 8);
|
||||
ArrayList<MessageEntity> entities = new ArrayList<>();
|
||||
if (edited.entities() != null) entities.addAll(List.of(edited.entities()));
|
||||
entities.add(new MessageEntity(MessageEntity.Type.italic, edited.text().length() + "\n-- ".length(), editTime.length()));
|
||||
|
@ -8,7 +8,7 @@ public class MornyDaemons {
|
||||
|
||||
public static void start () {
|
||||
logger.info("ALL Morny Daemons starting...");
|
||||
TrackerDataManager.init();
|
||||
// TrackerDataManager.init();
|
||||
medicationTimerInstance.start();
|
||||
logger.info("Morny Daemons started.");
|
||||
}
|
||||
@ -17,10 +17,10 @@ public class MornyDaemons {
|
||||
|
||||
logger.info("ALL Morny Daemons stopping...");
|
||||
|
||||
TrackerDataManager.DAEMON.interrupt();
|
||||
// TrackerDataManager.DAEMON.interrupt();
|
||||
medicationTimerInstance.interrupt();
|
||||
|
||||
TrackerDataManager.trackingLock.lock();
|
||||
// TrackerDataManager.trackingLock.lock();
|
||||
try { medicationTimerInstance.join(); } catch (InterruptedException e) { e.printStackTrace(System.out); }
|
||||
|
||||
logger.info("ALL Morny Daemons STOPPED.");
|
||||
|
@ -1,6 +1,7 @@
|
||||
package cc.sukazyo.cono.morny.data;
|
||||
|
||||
import cc.sukazyo.cono.morny.util.EncryptUtils;
|
||||
import cc.sukazyo.cono.morny.util.CommonConvert;
|
||||
import cc.sukazyo.cono.morny.util.CommonEncrypt;
|
||||
import com.pengrad.telegrambot.model.User;
|
||||
|
||||
/**
|
||||
@ -39,7 +40,7 @@ public class MornyJrrp {
|
||||
* @return 算法得到的 jrrp 值,取值为 {@code [0.00. 100.00]}
|
||||
*/
|
||||
public static double calcJrrpXmomi (long userId, long dayStamp) {
|
||||
return (double)Long.parseLong(EncryptUtils.encryptByMD5(userId + "@" + dayStamp).substring(0, 4), 16) / (double)0xffff;
|
||||
return (double)Long.parseLong(CommonConvert.byteArrayToHex(CommonEncrypt.hashMd5(userId + "@" + dayStamp)).substring(0, 4), 16) / (double)0xffff;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,5 +1,12 @@
|
||||
package cc.sukazyo.cono.morny.data;
|
||||
|
||||
import cc.sukazyo.cono.morny.util.tgapi.ExtraAction;
|
||||
import com.pengrad.telegrambot.request.SendMessage;
|
||||
import com.pengrad.telegrambot.request.SendSticker;
|
||||
import com.pengrad.telegrambot.response.SendResponse;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
/**
|
||||
* 存放 bot 使用到的贴纸
|
||||
* @since 0.4.2.0
|
||||
@ -15,5 +22,47 @@ public class TelegramStickers {
|
||||
public static final String ID_SENT = "CAACAgEAAx0CSQh32gABA--zYbiyU_wOijEitp-0tSl_k7W6l3gAAgMmAAJ4_MYF4GrompjXPx4jBA";
|
||||
public static final String ID_SAVED = "CAACAgEAAx0CSQh32gABBExuYdB_G0srfhQldRWkBYxWzCOv4-IAApooAAJ4_MYFcjuNZszfQcQjBA";
|
||||
public static final String ID_PROGYNOVA = "CAACAgUAAxkBAAICm2KEuL7UQqNP7vSPCg2DHJIND6UsAAKLAwACH4WSBszIo722aQ3jJAQ";
|
||||
public static final String ID_NETWORK_ERR = "CAACAgEAAxkBAAID0WNJgNEkD726KW4vZeFlw0FlVVyNAAIXJgACePzGBb50o7O1RbxoKgQ";
|
||||
|
||||
public static void echoAllStickers (ExtraAction actionObject, long sentChat, int replyToMessageId) {
|
||||
|
||||
for (Field object : TelegramStickers.class.getFields()) {
|
||||
if (object.getType()==String.class && object.getName().startsWith("ID_")) {
|
||||
try {
|
||||
|
||||
final String stickerId = (String)object.get("");
|
||||
SendSticker echo = new SendSticker(sentChat, stickerId);
|
||||
SendMessage echoName = new SendMessage(sentChat, object.getName());
|
||||
if (replyToMessageId!=-1) echo.replyToMessageId(replyToMessageId);
|
||||
SendResponse echoedName = actionObject.exec(echoName);
|
||||
actionObject.exec(echo.replyToMessageId(echoedName.message().messageId()));
|
||||
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static void echoStickerByID (String stickerFieldID, ExtraAction actionObject, long sentChat, int replyToMessageId) {
|
||||
try {
|
||||
// normally get the sticker and echo
|
||||
Field sticker = TelegramStickers.class.getField(stickerFieldID);
|
||||
SendMessage echoName = new SendMessage(sentChat, sticker.getName());
|
||||
SendSticker echo = new SendSticker(sentChat, (String)sticker.get(""));
|
||||
if (replyToMessageId!=-1) echo.replyToMessageId(replyToMessageId);
|
||||
SendResponse echoedName = actionObject.exec(echoName);
|
||||
actionObject.exec(echo.replyToMessageId(echoedName.message().messageId()));
|
||||
} catch (NoSuchFieldException e) {
|
||||
// no such sticker found
|
||||
SendSticker echo404 = new SendSticker(sentChat, TelegramStickers.ID_404);
|
||||
if (replyToMessageId!=-1) echo404.replyToMessageId(replyToMessageId);
|
||||
actionObject.exec(echo404);
|
||||
} catch (IllegalAccessException e) {
|
||||
// java-reflect get sticker FILE_ID failed
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
73
src/main/java/cc/sukazyo/cono/morny/util/BiliTool.java
Normal file
73
src/main/java/cc/sukazyo/cono/morny/util/BiliTool.java
Normal file
@ -0,0 +1,73 @@
|
||||
package cc.sukazyo.cono.morny.util;
|
||||
|
||||
import javax.annotation.Nonnegative;
|
||||
import javax.annotation.Nonnull;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class BiliTool {
|
||||
|
||||
private static final long V_CONV_XOR = 177451812L;
|
||||
private static final long V_CONV_ADD = 8728348608L;
|
||||
private static final char[] BV_TABLE = "fZodR9XQDSUm21yCkr6zBqiveYah8bt4xsWpHnJE7jL5VG3guMTKNPAwcF".toCharArray();
|
||||
private static final int TABLE_INT = BV_TABLE.length;
|
||||
private static final Map<Character, Integer> BV_TABLE_REVERSED = new HashMap<>();
|
||||
static { for (int i = 0; i < BV_TABLE.length; i++) BV_TABLE_REVERSED.put(BV_TABLE[i], i); }
|
||||
private static final char[] BV_TEMPLATE = "1 4 1 7 ".toCharArray();
|
||||
private static final int[] BV_TEMPLATE_FILTER = new int[]{9, 8, 1, 6, 2, 4};
|
||||
|
||||
/**
|
||||
* Convert a <a href="https://www.bilibili.com/">Bilibili</a> AV video id format to BV id format.
|
||||
* <p>
|
||||
* the AV id is a number; the BV id is a special base58 number, it shows as String in programming.<br>
|
||||
* eg:<br>
|
||||
* while the link <i>{@code https://www.bilibili.com/video/BV17x411w7KC/}</i>
|
||||
* shows the same with <i>{@code https://www.bilibili.com/video/av170001/}</i>,
|
||||
* the AV id is <u>{@code 170001}</u>, the BV id is <u>{@code 17x411w7KC}</u>
|
||||
* <p>
|
||||
* for now , the BV id has 10 digits.
|
||||
* the method <b>available while the <u>av-id < 2^27</u></b>, while it theoretically available when the av-id < 2^30.
|
||||
*
|
||||
* @see <a href="https://www.zhihu.com/question/381784377/answer/1099438784">mcfx的回复: 如何看待 2020 年 3 月 23 日哔哩哔哩将稿件的「av 号」变更为「BV 号」?</a>
|
||||
*
|
||||
* @param bv the BV id, a string in (a special) base58 number format, <b>without "BV" prefix</b>.
|
||||
* @return the AV id corresponding to this bv id in <a href="https://www.bilibili.com/">Bilibili</a>, formatted as a number.
|
||||
*/
|
||||
@Nonnegative
|
||||
public static long toAv (@Nonnull String bv) {
|
||||
long av = 0;
|
||||
for (int i = 0; i < BV_TEMPLATE_FILTER.length; i++) {
|
||||
av += BV_TABLE_REVERSED.get(bv.charAt(BV_TEMPLATE_FILTER[i])) * Math.pow(TABLE_INT,i);
|
||||
}
|
||||
return (av-V_CONV_ADD)^V_CONV_XOR;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a <a href="https://www.bilibili.com/">Bilibili</a> BV video id format to AV id format.
|
||||
* <p>
|
||||
* the AV id is a number; the BV id is a special base58 number, it shows as String in programming.<br>
|
||||
* eg:<br>
|
||||
* while the link <i>{@code https://www.bilibili.com/video/BV17x411w7KC/}</i>
|
||||
* shows the same with <i>{@code https://www.bilibili.com/video/av170001/}</i>,
|
||||
* the AV id is <u>{@code 170001}</u>, the BV id is <u>{@code 17x411w7KC}</u>
|
||||
* <p>
|
||||
* for now , the BV id has 10 digits.
|
||||
* the method <b>available while the <u>av-id < 2^27</u></b>, while it theoretically available when the av-id < 2^30.
|
||||
*
|
||||
* @see <a href="https://www.zhihu.com/question/381784377/answer/1099438784">mcfx的回复: 如何看待 2020 年 3 月 23 日哔哩哔哩将稿件的「av 号」变更为「BV 号」?</a>
|
||||
*
|
||||
* @param av the (base10) AV id.
|
||||
* @return the AV id corresponding to this bv id in <a href="https://www.bilibili.com/">Bilibili</a>,
|
||||
* as a (special) base 58 number format <b>without "BV" prefix</b>.
|
||||
*/
|
||||
@Nonnull
|
||||
public static String toBv (@Nonnegative long av) {
|
||||
av = (av^V_CONV_XOR)+V_CONV_ADD;
|
||||
final char[] bv = BV_TEMPLATE.clone();
|
||||
for (int i = 0; i < BV_TEMPLATE_FILTER.length; i++) {
|
||||
bv[BV_TEMPLATE_FILTER[i]] = BV_TABLE[(int)(Math.floor(av/(Math.pow(TABLE_INT, i)))%TABLE_INT)];
|
||||
}
|
||||
return String.copyValueOf(bv);
|
||||
}
|
||||
|
||||
}
|
61
src/main/java/cc/sukazyo/cono/morny/util/CommonConvert.java
Normal file
61
src/main/java/cc/sukazyo/cono/morny/util/CommonConvert.java
Normal file
@ -0,0 +1,61 @@
|
||||
package cc.sukazyo.cono.morny.util;
|
||||
|
||||
import javax.annotation.Nonnegative;
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
/**
|
||||
* 进行简单类型转换等工作的类.
|
||||
*/
|
||||
public class CommonConvert {
|
||||
|
||||
/**
|
||||
* 将字节数组转换成 hex 字符串.
|
||||
* @param b 字节数组
|
||||
* @return String 格式的字节数组的 hex 值(每个字节当中没有分隔符)
|
||||
* @see #byteToHex(byte)
|
||||
*/
|
||||
@Nonnull
|
||||
public static String byteArrayToHex(@Nonnull byte[] b){
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (byte value : b) {
|
||||
sb.append(byteToHex(value));
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 将一个字节转换成十六进制 hex 字符串.
|
||||
* @param b 字节值
|
||||
* @return String 格式的字节的 hex 值(小写)
|
||||
*/
|
||||
@Nonnull
|
||||
public static String byteToHex(byte b) {
|
||||
final String hex = Integer.toHexString(b & 0xff);
|
||||
return hex.length()<2?"0"+hex:hex;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将一个字符串数组按照一定规则连接.
|
||||
* <p>
|
||||
* 连接的方式类似于"数据1+分隔符+数据2+分隔符+...+数据n-1+分隔符+数据n"
|
||||
*
|
||||
* @param array 需要进行连接的字符串数组,数组中每一个元素会是一个数据
|
||||
* @param connector 在每两个传入数据中插入的分隔符
|
||||
* @param startIndex 从传入的数据组中的哪一个位置开始(第一个元素的位置是 {@code 0})
|
||||
* @param stopIndex 从传入的数据组中的哪一个位置停止(元素位置计算方式同上)
|
||||
* @return 连接好的字符串
|
||||
*/
|
||||
@Nonnull
|
||||
public static String stringsConnecting (
|
||||
@Nonnull String[] array, @Nonnull String connector, @Nonnegative int startIndex, @Nonnegative int stopIndex
|
||||
) {
|
||||
final StringBuilder builder = new StringBuilder();
|
||||
for (int i = startIndex; i < stopIndex; i++) {
|
||||
builder.append(array[i]);
|
||||
builder.append(connector);
|
||||
}
|
||||
builder.append(array[stopIndex]);
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
}
|
144
src/main/java/cc/sukazyo/cono/morny/util/CommonEncrypt.java
Normal file
144
src/main/java/cc/sukazyo/cono/morny/util/CommonEncrypt.java
Normal file
@ -0,0 +1,144 @@
|
||||
package cc.sukazyo.cono.morny.util;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.Base64;
|
||||
|
||||
/**
|
||||
* 用于数据加密或编解码的工具类.
|
||||
* <p>
|
||||
* 出于 java std 中 Base64 的 {@link Base64.Encoder encode}/{@link Base64.Decoder decode} 十分好用,在此不再进行包装。
|
||||
*/
|
||||
public class CommonEncrypt {
|
||||
|
||||
/**
|
||||
* 在使用加密算法处理字符串时默认会使用的字符串编码.
|
||||
* <p>
|
||||
* Morny 使用 UTF-8 编码因为这是一般而言加解密工具的默认行为
|
||||
*/
|
||||
public static final Charset ENCRYPT_STANDARD_CHARSET = StandardCharsets.UTF_8;
|
||||
|
||||
@Nonnull
|
||||
private static byte[] hashAsJavaMessageDigest(String algorithm, @Nonnull byte[] data) {
|
||||
try {
|
||||
return MessageDigest.getInstance(algorithm).digest(data);
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 取得数据的 md5 散列值.
|
||||
*
|
||||
* @param data byte 数组形式的数据体
|
||||
* @return 二进制(byte数组)格式的数据的 md5 散列值
|
||||
*/
|
||||
@Nonnull
|
||||
public static byte[] hashMd5 (@Nonnull byte[] data) {
|
||||
return hashAsJavaMessageDigest("md5", data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 取得一个字符串的 md5 散列值.
|
||||
* <p>
|
||||
* 输入的字符串将会以 {@link #ENCRYPT_STANDARD_CHARSET 默认的 UTF-8} 编码进行解析
|
||||
*
|
||||
* @param originString 要进行散列的字符串
|
||||
* @return 二进制(byte数组)格式的 md5 散列值
|
||||
*/
|
||||
@Nonnull
|
||||
public static byte[] hashMd5 (String originString) {
|
||||
return hashMd5(originString.getBytes(ENCRYPT_STANDARD_CHARSET));
|
||||
}
|
||||
|
||||
/**
|
||||
* 取得数据的 sha1 散列值.
|
||||
*
|
||||
* @param data byte 数组形式的数据体
|
||||
* @return 二进制(byte数组)格式的数据的 sha1 散列值
|
||||
*/
|
||||
@Nonnull
|
||||
public static byte[] hashSha1 (@Nonnull byte[] data) {
|
||||
return hashAsJavaMessageDigest("sha1", data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 取得一个字符串的 sha1 散列值.
|
||||
* <p>
|
||||
* 输入的字符串将会以 {@link #ENCRYPT_STANDARD_CHARSET 默认的 UTF-8} 编码进行解析
|
||||
*
|
||||
* @param originString 要进行散列的字符串
|
||||
* @return 二进制(byte数组)格式的 sha1 散列值
|
||||
*/
|
||||
@Nonnull
|
||||
public static byte[] hashSha1 (String originString) {
|
||||
return hashMd5(originString.getBytes(ENCRYPT_STANDARD_CHARSET));
|
||||
}
|
||||
|
||||
/**
|
||||
* 取得数据的 sha256 散列值.
|
||||
*
|
||||
* @param data byte 数组形式的数据体
|
||||
* @return 二进制(byte数组)格式的数据的 sha256 散列值
|
||||
*/
|
||||
@Nonnull
|
||||
public static byte[] hashSha256 (@Nonnull byte[] data) {
|
||||
return hashAsJavaMessageDigest("sha256", data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 取得一个字符串的 sha256 散列值.
|
||||
* <p>
|
||||
* 输入的字符串将会以 {@link #ENCRYPT_STANDARD_CHARSET 默认的 UTF-8} 编码进行解析
|
||||
*
|
||||
* @param originString 要进行散列的字符串
|
||||
* @return 二进制(byte数组)格式的 sha256 散列值
|
||||
*/
|
||||
@Nonnull
|
||||
public static byte[] hashSha256 (String originString) {
|
||||
return hashMd5(originString.getBytes(ENCRYPT_STANDARD_CHARSET));
|
||||
}
|
||||
|
||||
/**
|
||||
* 取得数据的 sha512 散列值.
|
||||
*
|
||||
* @param data byte 数组形式的数据体
|
||||
* @return 二进制(byte数组)格式的数据的 sha512 散列值
|
||||
*/
|
||||
@Nonnull
|
||||
public static byte[] hashSha512 (@Nonnull byte[] data) {
|
||||
return hashAsJavaMessageDigest("md5", data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 取得一个字符串的 sha512 散列值.
|
||||
* <p>
|
||||
* 输入的字符串将会以 {@link #ENCRYPT_STANDARD_CHARSET 默认的 UTF-8} 编码进行解析
|
||||
*
|
||||
* @param originString 要进行散列的字符串
|
||||
* @return 二进制(byte数组)格式的 sha512 散列值
|
||||
*/
|
||||
@Nonnull
|
||||
public static byte[] hashSha512 (String originString) {
|
||||
return hashMd5(originString.getBytes(ENCRYPT_STANDARD_CHARSET));
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public static String base64FilenameLint (String inputName) {
|
||||
if (inputName.endsWith(".b64")) {
|
||||
return inputName.substring(0, inputName.length()-".b64".length());
|
||||
} else if (inputName.endsWith(".b64.txt")) {
|
||||
return inputName.substring(0, inputName.length()-".b64.txt".length());
|
||||
} else if (inputName.endsWith(".base64")) {
|
||||
return inputName.substring(0, inputName.length()-".base64".length());
|
||||
} else if (inputName.endsWith(".base64.txt")) {
|
||||
return inputName.substring(0, inputName.length()-".base64.txt".length());
|
||||
} else {
|
||||
return inputName;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -6,10 +6,12 @@ import java.time.ZoneId;
|
||||
import java.time.ZoneOffset;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
|
||||
public class CommonFormatUtils {
|
||||
public class CommonFormat {
|
||||
|
||||
public static final String DATE_TIME_PATTERN_FULL_MILLIS = "yyyy-MM-dd HH:mm:ss:SSS";
|
||||
|
||||
public static String formatDate (long timestamp, int utcOffset) {
|
||||
return DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss:SSS").format(LocalDateTime.ofInstant(
|
||||
return DateTimeFormatter.ofPattern(DATE_TIME_PATTERN_FULL_MILLIS).format(LocalDateTime.ofInstant(
|
||||
Instant.ofEpochMilli(timestamp),
|
||||
ZoneId.ofOffset("UTC", ZoneOffset.ofHours(utcOffset))
|
||||
));
|
@ -1,62 +0,0 @@
|
||||
package cc.sukazyo.cono.morny.util;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
/**
|
||||
* 用于数据加密或编码的工具类<br>
|
||||
* <s>显然大部分代码是抄来的</s><br>
|
||||
* <ul>
|
||||
* <li><a href="https://blog.csdn.net/yu540135101/article/details/86765457">{@link #encryptByMD5} & {@link #byteToHex}
|
||||
* & {@link #byteArrayToHex} 来源</a></li>
|
||||
* </ul>
|
||||
*/
|
||||
public class EncryptUtils {
|
||||
|
||||
private final static String[] hexArray = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f"};
|
||||
|
||||
/***
|
||||
* 对指定的字符串进行MD5加密
|
||||
*/
|
||||
@Nonnull
|
||||
public static String encryptByMD5(String originString) {
|
||||
try {
|
||||
//创建具有MD5算法的信息摘要
|
||||
MessageDigest md = MessageDigest.getInstance("MD5");
|
||||
//使用指定的字节数组对摘要进行最后更新,然后完成摘要计算
|
||||
byte[] bytes = md.digest(originString.getBytes());
|
||||
//将得到的字节数组变成字符串返回
|
||||
String s = byteArrayToHex(bytes);
|
||||
return s.toUpperCase();
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将字节数组转换成十六进制,并以字符串的形式返回
|
||||
* 128位是指二进制位。二进制太长,所以一般都改写成16进制,
|
||||
* 每一位16进制数可以代替4位二进制数,所以128位二进制数写成16进制就变成了128/4=32位。
|
||||
*/
|
||||
private static String byteArrayToHex(byte[] b){
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (byte value : b) {
|
||||
sb.append(byteToHex(value));
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 将一个字节转换成十六进制,并以字符串的形式返回
|
||||
*/
|
||||
public static String byteToHex(byte b) {
|
||||
int n = b;
|
||||
if (n < 0)
|
||||
n = n + 256;
|
||||
int d1 = n / 16;
|
||||
int d2 = n % 16;
|
||||
return hexArray[d1]+hexArray[d2];
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
package cc.sukazyo.cono.morny.util;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class UniversalCommand {
|
||||
|
||||
@Nonnull
|
||||
public static String[] format (@Nonnull String com) {
|
||||
|
||||
final ArrayList<String> arr = new ArrayList<>();
|
||||
|
||||
final StringBuilder tmp = new StringBuilder();
|
||||
final char[] coma = com.toCharArray();
|
||||
for (int i = 0; i < coma.length; i++) {
|
||||
if (coma[i] == ' ') {
|
||||
if (!tmp.toString().equals("")) { arr.add(tmp.toString()); }
|
||||
tmp.setLength(0);
|
||||
} else if (coma[i] == '"') {
|
||||
while (true) {
|
||||
i++;
|
||||
if (coma[i] == '"') {
|
||||
break;
|
||||
} else if (coma[i] == '\\' && (coma[i+1] == '"' || coma[i+1] == '\\')) {
|
||||
i++;
|
||||
tmp.append(coma[i]);
|
||||
} else {
|
||||
tmp.append(coma[i]);
|
||||
}
|
||||
}
|
||||
} else if (coma[i] == '\\' && (coma[i+1] == ' ' || coma[i+1] == '"' || coma[i+1] == '\\')) {
|
||||
i++;
|
||||
tmp.append(coma[i]);
|
||||
} else {
|
||||
tmp.append(coma[i]);
|
||||
}
|
||||
}
|
||||
if (!tmp.toString().equals("")) { arr.add(tmp.toString()); }
|
||||
tmp.setLength(0);
|
||||
|
||||
final String[] out = new String[arr.size()];
|
||||
arr.toArray(out);
|
||||
return out;
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,88 @@
|
||||
package cc.sukazyo.cono.morny.util.tgapi;
|
||||
|
||||
import cc.sukazyo.cono.morny.util.tgapi.event.EventRuntimeException;
|
||||
import com.pengrad.telegrambot.TelegramBot;
|
||||
import com.pengrad.telegrambot.model.Chat;
|
||||
import com.pengrad.telegrambot.model.ChatMember;
|
||||
import com.pengrad.telegrambot.model.User;
|
||||
import com.pengrad.telegrambot.request.BaseRequest;
|
||||
import com.pengrad.telegrambot.request.GetChatMember;
|
||||
import com.pengrad.telegrambot.response.BaseResponse;
|
||||
|
||||
public class ExtraAction {
|
||||
|
||||
private final TelegramBot bot;
|
||||
|
||||
public ExtraAction (TelegramBot bot) {
|
||||
this.bot = bot;
|
||||
}
|
||||
|
||||
public static ExtraAction as (TelegramBot bot) {
|
||||
return new ExtraAction(bot);
|
||||
}
|
||||
|
||||
public boolean isUserInGroup (User user, Chat chat) {
|
||||
return isUserInGroup(user.id(), chat.id());
|
||||
}
|
||||
|
||||
public <T extends BaseRequest<T, R>, R extends BaseResponse> R exec (T req) {
|
||||
return exec(req, "");
|
||||
}
|
||||
|
||||
public <T extends BaseRequest<T, R>, R extends BaseResponse> R exec (T req, String errorMessage) {
|
||||
final R resp = bot.execute(req);
|
||||
if (!resp.isOk()) throw new EventRuntimeException.ActionFailed(
|
||||
(errorMessage.equals("") ? String.valueOf(resp.errorCode()) : errorMessage),
|
||||
resp
|
||||
);
|
||||
return resp;
|
||||
}
|
||||
|
||||
public boolean isUserInGroup (User user, Chat chat, ChatMember.Status permissionLevel) {
|
||||
return isUserInGroup(user.id(), chat.id(), permissionLevel);
|
||||
}
|
||||
|
||||
public boolean isUserInGroup (long userId, long chatId) {
|
||||
return isUserInGroup(userId, chatId, ChatMember.Status.restricted);
|
||||
}
|
||||
|
||||
public boolean isUserInGroup (long userId, long chatId, ChatMember.Status permissionLevel) {
|
||||
final ChatMember chatMember = exec(new GetChatMember(chatId, userId)).chatMember();
|
||||
return
|
||||
chatMember != null &&
|
||||
UserPermissionLevel.as(chatMember.status()).hasPermission(UserPermissionLevel.as(permissionLevel));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
enum UserPermissionLevel {
|
||||
|
||||
CREATOR(3),
|
||||
ADMINISTRATOR(2),
|
||||
MEMBER(1),
|
||||
RESTRICTED(0),
|
||||
LEFT(-1),
|
||||
KICKED(-2);
|
||||
|
||||
final int permissionLevel;
|
||||
|
||||
UserPermissionLevel (int permissionLevel) {
|
||||
this.permissionLevel = permissionLevel;
|
||||
}
|
||||
|
||||
static UserPermissionLevel as (ChatMember.Status status) {
|
||||
return switch (status) {
|
||||
case creator -> CREATOR;
|
||||
case administrator -> ADMINISTRATOR;
|
||||
case member -> MEMBER;
|
||||
case restricted -> RESTRICTED;
|
||||
case left -> LEFT;
|
||||
case kicked -> KICKED;
|
||||
};
|
||||
}
|
||||
|
||||
boolean hasPermission (UserPermissionLevel required) {
|
||||
return this.permissionLevel >= required.permissionLevel;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
package cc.sukazyo.cono.morny.util.tgapi;
|
||||
|
||||
import cc.sukazyo.cono.morny.util.UniversalCommand;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Arrays;
|
||||
|
||||
public class InputCommand {
|
||||
|
||||
|
||||
private final String target;
|
||||
private final String command;
|
||||
private final String[] args;
|
||||
|
||||
private InputCommand (@Nullable String target, @Nonnull String command, @Nonnull String[] args) {
|
||||
this.target = target;
|
||||
this.command = command;
|
||||
this.args = args;
|
||||
}
|
||||
|
||||
public InputCommand (@Nonnull String[] inputArray) {
|
||||
this(parseInputArray(inputArray));
|
||||
}
|
||||
|
||||
public InputCommand (@Nonnull String input) {
|
||||
this(UniversalCommand.format(input));
|
||||
}
|
||||
|
||||
public InputCommand (@Nonnull InputCommand source) {
|
||||
this(source.target, source.command, source.args);
|
||||
}
|
||||
|
||||
public static InputCommand parseInputArray (@Nonnull String[] inputArray) {
|
||||
final String[] cx = inputArray[0].split("@", 2);
|
||||
final String[] args = new String[inputArray.length-1];
|
||||
System.arraycopy(inputArray, 1, args, 0, inputArray.length - 1);
|
||||
return new InputCommand(cx.length == 1 ? null : cx[1], cx[0], args);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getTarget () {
|
||||
return target;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public String getCommand () {
|
||||
return command;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public String[] getArgs () {
|
||||
return args;
|
||||
}
|
||||
|
||||
public boolean hasArgs () {
|
||||
return args.length != 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nonnull
|
||||
public String toString() {
|
||||
return String.format("{{%s}@{%s}#{%s}}", command, target, Arrays.toString(args));
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
package cc.sukazyo.cono.morny.util.tgapi.event;
|
||||
|
||||
import com.pengrad.telegrambot.response.BaseResponse;
|
||||
|
||||
public class EventRuntimeException extends RuntimeException {
|
||||
|
||||
public EventRuntimeException () {
|
||||
super();
|
||||
}
|
||||
|
||||
public EventRuntimeException (String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public static class ActionFailed extends EventRuntimeException {
|
||||
|
||||
private final BaseResponse response;
|
||||
|
||||
public ActionFailed (BaseResponse response) {
|
||||
super();
|
||||
this.response = response;
|
||||
}
|
||||
|
||||
public ActionFailed (String message, BaseResponse response) {
|
||||
super(message);
|
||||
this.response = response;
|
||||
}
|
||||
|
||||
public BaseResponse getResponse() {
|
||||
return response;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
package cc.sukazyo.cono.morny.util.tgapi.formatting;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
public class MsgEscape {
|
||||
|
||||
@Nonnull
|
||||
public static String escapeHtml (@Nonnull String raw) {
|
||||
raw = raw.replaceAll("&", "&");
|
||||
raw = raw.replaceAll("<", "<");
|
||||
raw = raw.replaceAll(">", ">");
|
||||
return raw;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
package cc.sukazyo.cono.morny.util.tgapi.formatting;
|
||||
|
||||
import cc.sukazyo.cono.morny.util.CommonConvert;
|
||||
import cc.sukazyo.cono.morny.util.CommonEncrypt;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
public class NamedUtils {
|
||||
|
||||
public static String inlineIds (@Nonnull String tag) {
|
||||
return inlineIds(tag, "");
|
||||
}
|
||||
|
||||
public static String inlineIds (@Nonnull String tag, @Nonnull String taggedData) {
|
||||
return CommonConvert.byteArrayToHex(CommonEncrypt.hashMd5(tag+taggedData));
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
package cc.sukazyo.cono.morny.util.tgapi.formatting;
|
||||
|
||||
import com.pengrad.telegrambot.model.Chat;
|
||||
import com.pengrad.telegrambot.model.Message;
|
||||
import com.pengrad.telegrambot.model.User;
|
||||
|
||||
public class TGToString {
|
||||
|
||||
public static TGToStringFromChat as (Chat chat) {
|
||||
return new TGToStringFromChat(chat);
|
||||
}
|
||||
|
||||
public static TGToStringFromUser as (User user) {
|
||||
return new TGToStringFromUser(user);
|
||||
}
|
||||
|
||||
public static TGToStringFromMessage as (Message message) {
|
||||
return new TGToStringFromMessage(message);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
package cc.sukazyo.cono.morny.util.tgapi.formatting;
|
||||
|
||||
import com.pengrad.telegrambot.model.Chat;
|
||||
|
||||
public class TGToStringFromChat {
|
||||
|
||||
private final Chat data;
|
||||
|
||||
public TGToStringFromChat(Chat chat) {
|
||||
this.data = chat;
|
||||
}
|
||||
|
||||
public String toStringFullNameId() {
|
||||
if (data.title() == null) {
|
||||
throw new IllegalArgumentException("Cannot format private chat to group Name+Id format.");
|
||||
}
|
||||
return (data.username() == null) ?
|
||||
(String.format("%s [%d]", data.title(), data.id())) :
|
||||
(String.format("%s {%s}[%d]", data.title(), data.username(), data.id()));
|
||||
}
|
||||
|
||||
}
|
@ -1,7 +1,5 @@
|
||||
package cc.sukazyo.cono.morny.util.tgapi;
|
||||
package cc.sukazyo.cono.morny.util.tgapi.formatting;
|
||||
|
||||
import cc.sukazyo.untitled.telegram.api.formatting.TGToString;
|
||||
import cc.sukazyo.untitled.util.telegram.formatting.MsgEscape;
|
||||
import com.pengrad.telegrambot.model.Message;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
@ -12,7 +10,6 @@ public class TGToStringFromMessage extends TGToString {
|
||||
private final Message message;
|
||||
|
||||
public TGToStringFromMessage (@Nonnull Message message) { this.message = message; }
|
||||
public static TGToStringFromMessage as (@Nonnull Message message) { return new TGToStringFromMessage(message); }
|
||||
|
||||
@Nonnull
|
||||
public String getSenderFirstNameRefHtml () {
|
@ -0,0 +1,53 @@
|
||||
package cc.sukazyo.cono.morny.util.tgapi.formatting;
|
||||
|
||||
import com.pengrad.telegrambot.model.User;
|
||||
|
||||
public class TGToStringFromUser {
|
||||
|
||||
private final User data;
|
||||
|
||||
public TGToStringFromUser (User user) {
|
||||
this.data = user;
|
||||
}
|
||||
|
||||
public String fullname () {
|
||||
return data.firstName() + (data.lastName()==null ? "" : " "+data.lastName());
|
||||
}
|
||||
|
||||
public String fullnameRefHtml () {
|
||||
return String.format(
|
||||
"<a href='tg://user?id=%d'>%s</a>",
|
||||
data.id(),
|
||||
MsgEscape.escapeHtml(fullname())
|
||||
);
|
||||
}
|
||||
|
||||
public String fullnameRefMarkdown () {
|
||||
return String.format(
|
||||
"[%s](tg://user?id=%d)",
|
||||
fullname(),
|
||||
data.id()
|
||||
);
|
||||
}
|
||||
|
||||
public String firstnameRefHtml () {
|
||||
return String.format(
|
||||
"<a href='tg://user?id=%d'>%s</a>",
|
||||
data.id(),
|
||||
MsgEscape.escapeHtml(data.firstName())
|
||||
);
|
||||
}
|
||||
|
||||
public String firstnameRefMarkdown () {
|
||||
return String.format(
|
||||
"[%s](tg://user?id=%d)",
|
||||
data.firstName(),
|
||||
data.id()
|
||||
);
|
||||
}
|
||||
|
||||
public String toStringLogTag () {
|
||||
return (data.username()==null ? fullname()+" " : "@"+data.username()) + "[" + data.id() + "]";
|
||||
}
|
||||
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package cc.sukazyo.cono.morny.util;
|
||||
package cc.sukazyo.cono.morny.util.tgapi.formatting;
|
||||
|
||||
import com.pengrad.telegrambot.model.User;
|
||||
import okhttp3.OkHttpClient;
|
||||
@ -11,7 +11,7 @@ import java.io.IOException;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static cc.sukazyo.untitled.util.telegram.formatting.MsgEscape.escapeHtml;
|
||||
import static cc.sukazyo.cono.morny.util.tgapi.formatting.MsgEscape.escapeHtml;
|
||||
|
||||
public class TelegramUserInformation {
|
||||
|
18
src/test/java/cc/sukazyo/cono/morny/MornyCLI.java
Normal file
18
src/test/java/cc/sukazyo/cono/morny/MornyCLI.java
Normal file
@ -0,0 +1,18 @@
|
||||
package cc.sukazyo.cono.morny;
|
||||
|
||||
import cc.sukazyo.cono.morny.util.UniversalCommand;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class MornyCLI {
|
||||
|
||||
public static void main (String[] args) {
|
||||
|
||||
Scanner line = new Scanner(System.in);
|
||||
System.out.print("$ java -jar morny-coeur-"+GradleProjectConfigures.VERSION+".jar " );
|
||||
String x = line.nextLine();
|
||||
ServerMain.main(UniversalCommand.format(x));
|
||||
|
||||
}
|
||||
|
||||
}
|
30
src/test/java/cc/sukazyo/cono/morny/util/TestBiliTool.java
Normal file
30
src/test/java/cc/sukazyo/cono/morny/util/TestBiliTool.java
Normal file
@ -0,0 +1,30 @@
|
||||
package cc.sukazyo.cono.morny.util;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.CsvSource;
|
||||
|
||||
import static cc.sukazyo.cono.morny.util.BiliTool.*;
|
||||
|
||||
public class TestBiliTool {
|
||||
|
||||
private static final String AV_BV_DATA_CSV = """
|
||||
17x411w7KC, 170001
|
||||
1Q541167Qg, 455017605
|
||||
1mK4y1C7Bz, 882584971
|
||||
1T24y197V2, 688730800
|
||||
""";
|
||||
|
||||
@ParameterizedTest
|
||||
@CsvSource(textBlock = AV_BV_DATA_CSV)
|
||||
void testAvToBv (String bv, int av) {
|
||||
Assertions.assertEquals(bv, toBv(av));
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@CsvSource(textBlock = AV_BV_DATA_CSV)
|
||||
void testBvToAv (String bv, int av) {
|
||||
Assertions.assertEquals(av, toAv(bv));
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
package cc.sukazyo.cono.morny.util;
|
||||
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.CsvSource;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static cc.sukazyo.cono.morny.util.CommonConvert.byteArrayToHex;
|
||||
import static cc.sukazyo.cono.morny.util.CommonConvert.byteToHex;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.params.provider.Arguments.arguments;
|
||||
|
||||
public class TestCommonConvert {
|
||||
|
||||
@ParameterizedTest
|
||||
@CsvSource(textBlock = """
|
||||
0x00, 00
|
||||
0x01, 01
|
||||
0x20, 20
|
||||
0x77, 77
|
||||
-0x60, a0
|
||||
0x0a, 0a
|
||||
-0x01, ff
|
||||
-0x05, fb
|
||||
"""
|
||||
)
|
||||
void testByteToHex(byte source, String expected) {
|
||||
assertEquals(expected, byteToHex(source));
|
||||
}
|
||||
|
||||
public static Stream<Arguments> testByteArrayToHexProvider () {
|
||||
return Stream.of(
|
||||
arguments(new byte[]{0x00}, "00"),
|
||||
arguments(new byte[]{(byte)0xff}, "ff"),
|
||||
arguments(new byte[]{(byte)0xc3}, "c3"),
|
||||
arguments(new byte[]{}, ""),
|
||||
arguments(new byte[]{0x30,0x0a,0x00,0x04,(byte)0xb0,0x00}, "300a0004b000"),
|
||||
arguments(new byte[]{0x00,0x00,0x0a,(byte)0xff,(byte)0xfc,(byte)0xab,(byte)0x00,0x04}, "00000afffcab0004"),
|
||||
arguments(new byte[]{0x00,0x7c,0x11,0x28,(byte)0x88,(byte)0xa6,(byte)0xfc,0x30}, "007c112888a6fc30")
|
||||
);
|
||||
}
|
||||
@ParameterizedTest
|
||||
@MethodSource("testByteArrayToHexProvider")
|
||||
void testByteArrayToHex (byte[] raw, String expected) {
|
||||
assertEquals(expected, byteArrayToHex(raw));
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
package cc.sukazyo.cono.morny.util;
|
||||
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.CsvSource;
|
||||
|
||||
import static cc.sukazyo.cono.morny.util.CommonConvert.byteArrayToHex;
|
||||
import static cc.sukazyo.cono.morny.util.CommonEncrypt.*;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
public class TestCommonEncrypt {
|
||||
|
||||
@ParameterizedTest
|
||||
@SuppressWarnings("UnnecessaryStringEscape")
|
||||
@CsvSource(textBlock = """
|
||||
28be57d368b75051da76c068a6733284, '莲子'
|
||||
9644c5cbae223013228cd528817ba4f5, '莲子\n'
|
||||
d41d8cd98f00b204e9800998ecf8427e, ''
|
||||
""")
|
||||
void testHashMd5_String (String md5, String text) {
|
||||
assertEquals(md5, byteArrayToHex(hashMd5(text)));
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
package cc.sukazyo.cono.morny.util;
|
||||
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.CsvSource;
|
||||
|
||||
import static cc.sukazyo.cono.morny.util.CommonFormat.*;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
public class TestCommonFormat {
|
||||
|
||||
@ParameterizedTest
|
||||
@CsvSource(textBlock = """
|
||||
1664646870402, 8, 2022-10-02 01:54:30:402
|
||||
1, 8, 1970-01-01 08:00:00:001
|
||||
0, -1, 1969-12-31 23:00:00:000
|
||||
"""
|
||||
)
|
||||
void testFormatDate (long timestamp, int utfOffset, String expectedHumanReadableTime) {
|
||||
assertEquals(expectedHumanReadableTime, formatDate(timestamp, utfOffset));
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@CsvSource(textBlock = """
|
||||
100, '100ms'
|
||||
3000, '3s 0ms'
|
||||
326117522, '3d 18h 35min 17s 522ms'
|
||||
53373805, 14h 49min 33s 805ms
|
||||
""")
|
||||
// -1, '-1ms' // WARN: maybe sometime an unexpected usage
|
||||
// -194271974291, '-291ms' //
|
||||
// """) //
|
||||
void testFormatDuration (long durationMillis, String humanReadableDuration) {
|
||||
assertEquals(humanReadableDuration, formatDuration(durationMillis));
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user