Compare commits
295
Commits
feature/dm
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a134406764 | ||
|
|
93a2bf949a | ||
|
|
11e65d99ba | ||
|
|
c049fb1d8a | ||
|
|
bfbba46d0a | ||
|
|
f6f83e2454 | ||
|
|
cb5b989b38 | ||
|
|
586714d704 | ||
|
|
510fdc0c60 | ||
|
|
d68753df98 | ||
|
|
5852ceb5ba | ||
|
|
b7db3b3e98 | ||
|
|
6bce847a0f | ||
|
|
24c8ef0cb7 | ||
|
|
411b468e5e | ||
|
|
5060afd43e | ||
|
|
5e4d4e4bfc | ||
|
|
d406e74659 | ||
|
|
a6b8698a68 | ||
|
|
4be2791c92 | ||
|
|
cc0c0f4022 | ||
|
|
8589951cc4 | ||
|
|
7f199959f1 | ||
|
|
5584b18f2f | ||
|
|
64f256fb25 | ||
|
|
8107117e5f | ||
|
|
59105331fb | ||
|
|
c1172b8867 | ||
|
|
f925a77cdb | ||
|
|
c376612d77 | ||
|
|
8b90790395 | ||
|
|
ca304874dc | ||
|
|
56270771b0 | ||
|
|
12064dfe10 | ||
|
|
6b5ca9c38b | ||
|
|
5b8de20430 | ||
|
|
a2bdcc5232 | ||
|
|
9838d90855 | ||
|
|
43b3e96881 | ||
|
|
be03a90d72 | ||
|
|
159f83a89f | ||
|
|
760aeeca82 | ||
|
|
42c215420a | ||
|
|
5320836d26 | ||
|
|
4117c3d253 | ||
|
|
9a018c0bdd | ||
|
|
8dee66d022 | ||
|
|
b3410e6d07 | ||
|
|
7935597a05 | ||
|
|
217e465d62 | ||
|
|
1cd2242c6f | ||
|
|
229c73b6ac | ||
|
|
4be023282e | ||
|
|
8541358348 | ||
|
|
81e2169c1e | ||
|
|
fac2d5491a | ||
|
|
2c0ca2f739 | ||
|
|
b85b0bf33a | ||
|
|
321a82e599 | ||
|
|
8c7227c77d | ||
|
|
82c1f4f89d | ||
|
|
9af2916dfc | ||
|
|
40d4661e1b | ||
|
|
b1405ad3e8 | ||
|
|
edfbb820a0 | ||
|
|
c139c09b1a | ||
|
|
9ee543b1e1 | ||
|
|
d45ab4e286 | ||
|
|
ad12ff5ce8 | ||
|
|
f9b52c8c4b | ||
|
|
a99f636158 | ||
|
|
c0fa5c3a49 | ||
|
|
c3dc3fa4e5 | ||
|
|
7e851e831a | ||
|
|
b238ec5f30 | ||
|
|
b0446d9baf | ||
|
|
7994861348 | ||
|
|
64c4fd04b1 | ||
|
|
2115f3d63a | ||
|
|
c1ba1cd5b1 | ||
|
|
b1f13b6754 | ||
|
|
41463b8b18 | ||
|
|
bc28a4fefc | ||
|
|
f0d92d8fe7 | ||
|
|
184378c907 | ||
|
|
fc864529b5 | ||
|
|
4e0cb17f4e | ||
|
|
2ce9d3dc8f | ||
|
|
f48b2ea8b3 | ||
|
|
57d0737f21 | ||
|
|
0d73a29d34 | ||
|
|
7511dfd37f | ||
|
|
3eabe254af | ||
|
|
97cd846b53 | ||
|
|
d8b4f5003b | ||
|
|
ac96431552 | ||
|
|
8fd92b8fed | ||
|
|
9381ef8637 | ||
|
|
b64f3580d0 | ||
|
|
3fba603b17 | ||
|
|
492f36d6a5 | ||
|
|
10a61fbee7 | ||
|
|
b0d295d97f | ||
|
|
f5d6a3acb7 | ||
|
|
f5cc673836 | ||
|
|
838d95391e | ||
|
|
8999e8912a | ||
|
|
5d3a31dd28 | ||
|
|
28cf80c271 | ||
|
|
b3c3e230bf | ||
|
|
1b7f09732f | ||
|
|
e5b8b42d7a | ||
|
|
f22934c325 | ||
|
|
9a7d3af844 | ||
|
|
bbb552dc14 | ||
|
|
2ac27d29e7 | ||
|
|
087d55ba28 | ||
|
|
fbcdbe301a | ||
|
|
6b4ef38443 | ||
|
|
c4e6f9e348 | ||
|
|
a59a544792 | ||
|
|
c2e1ec91b5 | ||
|
|
88fd259712 | ||
|
|
ae3eae4e71 | ||
|
|
ac88dcc296 | ||
|
|
7f3b1fd1b5 | ||
|
|
e375f20e9c | ||
|
|
bfbeee2880 | ||
|
|
c4d8c0eaf0 | ||
|
|
f96f7b7055 | ||
|
|
6f32323fec | ||
|
|
73b417775a | ||
|
|
c9d2ddeff7 | ||
|
|
f0e6f31faf | ||
|
|
a78a365ebd | ||
|
|
d036c2bdba | ||
|
|
c831a76850 | ||
|
|
ec6e186284 | ||
|
|
95355d92fe | ||
|
|
ff65333a8f | ||
|
|
499eab9549 | ||
|
|
242ce3e60e | ||
|
|
83e3404665 | ||
|
|
6bc77fb4ac | ||
|
|
217364ffb8 | ||
|
|
2ac7d3b20b | ||
|
|
5ac05f052a | ||
|
|
1b1a579f23 | ||
|
|
1aab83ae51 | ||
|
|
c428b84e10 | ||
|
|
e01a98d254 | ||
|
|
f783f8b4ec | ||
|
|
1c3f582c86 | ||
|
|
a0b74d3df4 | ||
|
|
ccb72a7277 | ||
|
|
7fda4dc333 | ||
|
|
68b7c60a4d | ||
|
|
e0e89d1ecb | ||
|
|
6da5553d1f | ||
|
|
90225ae147 | ||
|
|
1c00093560 | ||
|
|
7b8120dbc5 | ||
|
|
af6f580583 | ||
|
|
ac7910d20c | ||
|
|
b8568c00e7 | ||
|
|
52c791d3ed | ||
|
|
f34e12b3d2 | ||
|
|
c280c02a4e | ||
|
|
829f858840 | ||
|
|
fdad0054ef | ||
|
|
cd69d9a18e | ||
|
|
44c622190d | ||
|
|
f9e6bac23d | ||
|
|
06a385db1a | ||
|
|
b660b504fd | ||
|
|
8504533659 | ||
|
|
92bf62347c | ||
|
|
8ae4ce7870 | ||
|
|
54354e0a52 | ||
|
|
a80cbdcb1a | ||
|
|
9ff4f03b24 | ||
|
|
95a6abbfb3 | ||
|
|
f62055d2ac | ||
|
|
9e198c0084 | ||
|
|
7dda9ad4bc | ||
|
|
80557e9ccc | ||
|
|
e4d6e683d3 | ||
|
|
97e62d5422 | ||
|
|
a850ab9152 | ||
|
|
33f4014bae | ||
|
|
327426988b | ||
|
|
938ef0792a | ||
|
|
af9a117561 | ||
|
|
0ad3314ddb | ||
|
|
b0ae938722 | ||
|
|
91906d9711 | ||
|
|
b7f82446f9 | ||
|
|
69743ca42b | ||
|
|
35fd368cb6 | ||
|
|
63c1de608d | ||
|
|
c6f1bf9629 | ||
|
|
ed85575e14 | ||
|
|
2b725ab71e | ||
|
|
0a5c9b63c2 | ||
|
|
262cfa532c | ||
|
|
956b29d076 | ||
|
|
8f7a5e5f0e | ||
|
|
04b6823d7e | ||
|
|
6bb6979467 | ||
|
|
d42fd55228 | ||
|
|
88a513864a | ||
|
|
98a6ebb3d4 | ||
|
|
4078af7c29 | ||
|
|
05efdaebff | ||
|
|
9abbf2830a | ||
|
|
c9c0f8e360 | ||
|
|
b82a895d99 | ||
|
|
5f0921410d | ||
|
|
45fafd4a4d | ||
|
|
d7d7e237e6 | ||
|
|
a349687e4f | ||
|
|
385dcb4328 | ||
|
|
02ab1e816f | ||
|
|
93338a9d64 | ||
|
|
3a033d2694 | ||
|
|
57885473bd | ||
|
|
767bd7c0f3 | ||
|
|
4ac5d6603b | ||
|
|
9ba1c135d8 | ||
|
|
a07560fa37 | ||
|
|
2eb8a3e387 | ||
|
|
805c6d56c2 | ||
|
|
bf9e6dd311 | ||
|
|
7372724274 | ||
|
|
44e3e093d1 | ||
|
|
e2b6ffff38 | ||
|
|
042cef3340 | ||
|
|
32c822c3a1 | ||
|
|
9aab28334e | ||
|
|
120fc38084 | ||
|
|
bc04c53517 | ||
|
|
e040819e61 | ||
|
|
9762d8d566 | ||
|
|
cc30d8e1c0 | ||
|
|
8a31dce4d4 | ||
|
|
4a2575e1c5 | ||
|
|
1953897642 | ||
|
|
a51be7292f | ||
|
|
0016fa578d | ||
|
|
a6537628d5 | ||
|
|
ef7e3bf1ad | ||
|
|
45a6cbece3 | ||
|
|
3c147c9ad6 | ||
|
|
8110ed6cd4 | ||
|
|
862670183a | ||
|
|
53a1807d9d | ||
|
|
2d7d81c825 | ||
|
|
478c0ce4fd | ||
|
|
e832b1cb3b | ||
|
|
a3058780be | ||
|
|
f332031961 | ||
|
|
04021a8fff | ||
|
|
06d0aeb529 | ||
|
|
917d4f0d26 | ||
|
|
1b5a6c627d | ||
|
|
6e38ff1b04 | ||
|
|
7a6e00d4d2 | ||
|
|
cbfaf0d8aa | ||
|
|
9f0133de8a | ||
|
|
0442c0ef6a | ||
|
|
660e5bcbe8 | ||
|
|
8dc311fb90 | ||
|
|
0a28d05bfe | ||
|
|
9a9c767e17 | ||
|
|
1c89d54636 | ||
|
|
ecd50ffea6 | ||
|
|
19e980be86 | ||
|
|
4d2be92081 | ||
|
|
3e65d6ef3e | ||
|
|
a2117f04a4 | ||
|
|
a91a5f475d | ||
|
|
4a9483bf12 | ||
|
|
ae5f60df41 | ||
|
|
ddad36b28d | ||
|
|
7e2d2d7cdb | ||
|
|
82f4b3c542 | ||
|
|
98f4f5d10f | ||
|
|
7688f538fb | ||
|
|
765a1a60e6 | ||
|
|
e51c7ecf04 | ||
|
|
57b454e7d0 | ||
|
|
8fc6dd6443 | ||
|
|
02578a8901 | ||
|
|
0c19984e60 | ||
|
|
e8b847a7ac |
No files matched your search
@@ -15,13 +15,14 @@
|
|||||||
|
|
||||||
# 概述
|
# 概述
|
||||||
|
|
||||||
> 这是一个使用了 `ROneBot` 框架的QQ机器人, 包含了20多种命令, 例如: 点歌, 今日人品, 签到...
|
> 这是一个使用了 `ROneBot` 框架的QQ机器人, 包含了超多命令, 例如: 点歌, 今日人品, 签到...
|
||||||
> 你可以在[这里](src/main/kotlin/cn/rtast/fancybot/commands/)来查看所有的命令
|
> 你可以在[这里](src/main/kotlin/cn/rtast/fancybot/commands/)来查看所有的命令
|
||||||
|
|
||||||
> ROneBot项目地址: [Gitlab](https://repo.rtast.cn/RTAkland/ronebot) [Github](https://github.com/RTAkland/ROneBot)
|
> ROneBot项目地址: [Gitlab](https://repo.rtast.cn/RTAkland/ronebot) [Github](https://github.com/RTAkland/ROneBot)
|
||||||
|
|
||||||
# 构建
|
# 构建
|
||||||
由于项目使用的依赖过多项目构建出的产物在28Mb左右并且项目开启了
|
|
||||||
|
由于项目使用的依赖过多项目构建出的产物在40+Mb左右并且项目开启了
|
||||||
Github Action来自动化部署机器人, github Action的作用仅用作判断
|
Github Action来自动化部署机器人, github Action的作用仅用作判断
|
||||||
构建是否成功以及自动部署机器人, 并不带有上传构建产物的功能(占用的空间太多)
|
构建是否成功以及自动部署机器人, 并不带有上传构建产物的功能(占用的空间太多)
|
||||||
所以你需要自行构建出机器人的jar包来运行
|
所以你需要自行构建出机器人的jar包来运行
|
||||||
@@ -33,10 +34,23 @@ $ ./gradlew build clean
|
|||||||
|
|
||||||
> 产物在`build/libs/`目录下你可以找到`-all`结尾的jar包
|
> 产物在`build/libs/`目录下你可以找到`-all`结尾的jar包
|
||||||
|
|
||||||
# 一些想说的话
|
# 部署
|
||||||
|
|
||||||
OneBot协议本身并不是一个很好的协议, 在Kritor、Laana等新型协议完善后机器人会全面迁移到上述协议中
|
> 部署并不是一件很难的事, 只是需要准备的前期工作有点多
|
||||||
并且将OneBot版本的分支放置到另外一个分支中不再更新, 后续将主要更新Kritor/Laana的分支
|
|
||||||
|
1. 申请一个Github Classic Token (需要`repo`的所有权限)(如果你想使用github作为图床)
|
||||||
|
2. 申请一个Cloudflare Token (需要`R2`的编辑权限)(如果你想使用cf作为图床)
|
||||||
|
3. 获取Cloudflare的Account Id以及R2的ID
|
||||||
|
4. 一个天聚数行API(TianAPI),并开通历史上的今天API权限
|
||||||
|
5. 一个openai平台的密钥和模型以及镜像地址
|
||||||
|
6. 和风天气的API key(免费订阅)
|
||||||
|
7. smtp服务器和端口
|
||||||
|
8. 网易云音乐API
|
||||||
|
9. QQ音乐API
|
||||||
|
10. 一个Azure APP (用于获取MC AccessToken)
|
||||||
|
11. 一个RTAST api token (用于生短链接, 你可以自行搭建但是源代码不公开)
|
||||||
|
12. 一个APISpace key
|
||||||
|
13. llama的api地址
|
||||||
|
|
||||||
# 开源
|
# 开源
|
||||||
|
|
||||||
|
|||||||
+21
-17
@@ -4,6 +4,7 @@ import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
|||||||
plugins {
|
plugins {
|
||||||
alias(libs.plugins.kotlin)
|
alias(libs.plugins.kotlin)
|
||||||
alias(libs.plugins.shadow)
|
alias(libs.plugins.shadow)
|
||||||
|
id("application")
|
||||||
}
|
}
|
||||||
|
|
||||||
val fancyBotVersion: String by project
|
val fancyBotVersion: String by project
|
||||||
@@ -14,8 +15,10 @@ version = fancyBotVersion
|
|||||||
repositories {
|
repositories {
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
mavenLocal()
|
mavenLocal()
|
||||||
maven("https://repo.rtast.cn/api/v4/projects/33/packages/maven")
|
maven("https://repo.opencollab.dev/main/")
|
||||||
maven("https://repo.rtast.cn/api/v4/projects/19/packages/maven")
|
maven("https://oss.sonatype.org/content/repositories/snapshots")
|
||||||
|
maven("https://repo.maven.rtast.cn/releases/")
|
||||||
|
maven("https://libraries.minecraft.net")
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.compileKotlin {
|
tasks.compileKotlin {
|
||||||
@@ -27,18 +30,23 @@ tasks.compileJava {
|
|||||||
targetCompatibility = "17"
|
targetCompatibility = "17"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation(libs.rOneBot)
|
implementation(libs.ronebot)
|
||||||
implementation(libs.okhttp)
|
implementation(libs.okhttp)
|
||||||
implementation(libs.exposedCore)
|
implementation(libs.exposed.core)
|
||||||
implementation(libs.exposedJDBC)
|
implementation(libs.exposed.jdbc)
|
||||||
implementation(libs.sqliteJDBC)
|
implementation(libs.exposed.dao)
|
||||||
implementation(libs.motdPinger)
|
implementation(libs.h2.jdbc)
|
||||||
|
implementation(libs.motd.pinger)
|
||||||
implementation(libs.animated.gif.lib)
|
implementation(libs.animated.gif.lib)
|
||||||
implementation(libs.simple.java.mail)
|
implementation(libs.simple.java.mail)
|
||||||
implementation(libs.jsoup)
|
implementation(libs.jsoup)
|
||||||
implementation(libs.nashorn.core)
|
implementation(libs.nashorn.core)
|
||||||
|
implementation(libs.zxing.core)
|
||||||
|
implementation(libs.zxing.javase)
|
||||||
|
implementation(libs.aws.s3.sdk)
|
||||||
|
implementation(libs.rconlib)
|
||||||
|
implementation(libs.mcprotocollib)
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.build {
|
tasks.build {
|
||||||
@@ -49,15 +57,6 @@ tasks.jar {
|
|||||||
enabled = false
|
enabled = false
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.shadowJar {
|
|
||||||
manifest {
|
|
||||||
attributes(
|
|
||||||
"Main-Class" to "cn.rtast.fancybot.FancyBotKt",
|
|
||||||
"Manifest-Version" to "1.0"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tasks.register("deployBot") {
|
tasks.register("deployBot") {
|
||||||
val apiKey = System.getenv("MCSM_API_KEY")
|
val apiKey = System.getenv("MCSM_API_KEY")
|
||||||
val apiUrl = System.getenv("MCSM_API_URL")
|
val apiUrl = System.getenv("MCSM_API_URL")
|
||||||
@@ -65,3 +64,8 @@ tasks.register("deployBot") {
|
|||||||
val instanceId = System.getenv("MCSM_INSTANCE_ID")
|
val instanceId = System.getenv("MCSM_INSTANCE_ID")
|
||||||
MCSMDeploy(apiUrl, apiKey, daemonId, instanceId).deploy(file("build/libs/FancyBot-1.0.0-all.jar"))
|
MCSMDeploy(apiUrl, apiKey, daemonId, instanceId).deploy(file("build/libs/FancyBot-1.0.0-all.jar"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
application {
|
||||||
|
mainClass = "cn.rtast.fancybot.FancyBotKt"
|
||||||
|
applicationName = "FancyBot"
|
||||||
|
}
|
||||||
@@ -1,2 +1,7 @@
|
|||||||
kotlin.code.style=official
|
kotlin.code.style=official
|
||||||
fancyBotVersion=1.0.0
|
fancyBotVersion=1.0.0
|
||||||
|
|
||||||
|
#systemProp.http.proxyHost=127.0.0.1
|
||||||
|
#systemProp.http.proxyPort=12334
|
||||||
|
#systemProp.https.proxyHost=127.0.0.1
|
||||||
|
#systemProp.https.proxyPort=12334
|
||||||
+20
-10
@@ -1,27 +1,37 @@
|
|||||||
[versions]
|
[versions]
|
||||||
kotlinVersion = "2.0.10"
|
kotlinVersion = "2.0.20"
|
||||||
ronebotVersion = "1.10.0"
|
ronebotVersion = "2.7.4"
|
||||||
shadowVersion = "8.3.0"
|
shadowVersion = "8.3.0"
|
||||||
okhttpVersion = "5.0.0-alpha.14"
|
okhttpVersion = "5.0.0-alpha.14"
|
||||||
exposedVersion = "0.53.0"
|
exposedVersion = "0.53.0"
|
||||||
sqliteJDBCVersion = "3.46.1.0"
|
motdPingerVersion = "1.1.4"
|
||||||
motdPingerVersion = "1.0.1"
|
|
||||||
animatedGifLibVersion = "1.4"
|
animatedGifLibVersion = "1.4"
|
||||||
simpleJavaMailVersion = "8.11.3"
|
simpleJavaMailVersion = "8.12.2"
|
||||||
jsoupVersion = "1.18.1"
|
jsoupVersion = "1.18.1"
|
||||||
nashornVersion = "15.4"
|
nashornVersion = "15.4"
|
||||||
|
zxingVersion = "3.5.3"
|
||||||
|
awsS3SDKVersion = "2.28.18"
|
||||||
|
rconLibVersion = "1.1.1"
|
||||||
|
mcprotolobVersion = "1.21-SNAPSHOT"
|
||||||
|
h2Version = "2.3.232"
|
||||||
|
|
||||||
[libraries]
|
[libraries]
|
||||||
rOneBot = { group = "cn.rtast", name = "ROneBot", version.ref = "ronebotVersion" }
|
ronebot = { group = "cn.rtast.rob", name = "ronebot-onebot-v11", version.ref = "ronebotVersion" }
|
||||||
motdPinger = { group = "cn.rtast", name = "MotdPinger", version.ref = "motdPingerVersion" }
|
motd-pinger = { group = "cn.rtast", name = "motd-pinger", version.ref = "motdPingerVersion" }
|
||||||
okhttp = { group = "com.squareup.okhttp3", name = "okhttp", version.ref = "okhttpVersion" }
|
okhttp = { group = "com.squareup.okhttp3", name = "okhttp", version.ref = "okhttpVersion" }
|
||||||
exposedCore = { group = "org.jetbrains.exposed", name = "exposed-core", version.ref = "exposedVersion" }
|
exposed-core = { group = "org.jetbrains.exposed", name = "exposed-core", version.ref = "exposedVersion" }
|
||||||
exposedJDBC = { group = "org.jetbrains.exposed", name = "exposed-jdbc", version.ref = "exposedVersion" }
|
exposed-jdbc = { group = "org.jetbrains.exposed", name = "exposed-jdbc", version.ref = "exposedVersion" }
|
||||||
sqliteJDBC = { group = "org.xerial", name = "sqlite-jdbc", version.ref = "sqliteJDBCVersion" }
|
exposed-dao = { group = "org.jetbrains.exposed", name = "exposed-dao", version.ref = "exposedVersion" }
|
||||||
animated-gif-lib = { group = "com.madgag", name = "animated-gif-lib", version.ref = "animatedGifLibVersion" }
|
animated-gif-lib = { group = "com.madgag", name = "animated-gif-lib", version.ref = "animatedGifLibVersion" }
|
||||||
simple-java-mail = { group = "org.simplejavamail", name = "simple-java-mail", version.ref = "simpleJavaMailVersion" }
|
simple-java-mail = { group = "org.simplejavamail", name = "simple-java-mail", version.ref = "simpleJavaMailVersion" }
|
||||||
jsoup = { group = "org.jsoup", name = "jsoup", version.ref = "jsoupVersion" }
|
jsoup = { group = "org.jsoup", name = "jsoup", version.ref = "jsoupVersion" }
|
||||||
nashorn-core = { group = "org.openjdk.nashorn", name = "nashorn-core", version.ref = "nashornVersion" }
|
nashorn-core = { group = "org.openjdk.nashorn", name = "nashorn-core", version.ref = "nashornVersion" }
|
||||||
|
zxing-core = { group = "com.google.zxing", name = "core", version.ref = "zxingVersion" }
|
||||||
|
zxing-javase = { group = "com.google.zxing", name = "javase", version.ref = "zxingVersion" }
|
||||||
|
aws-s3-sdk = { group = "software.amazon.awssdk", name = "s3", version.ref = "awsS3SDKVersion" }
|
||||||
|
rconlib = { group = "cn.rtast", name = "rconlib", version.ref = "rconLibVersion" }
|
||||||
|
mcprotocollib = { group = "org.geysermc.mcprotocollib", name = "protocol", version.ref = "mcprotolobVersion" }
|
||||||
|
h2-jdbc = { group = "com.h2database", name = "h2", version.ref = "h2Version" }
|
||||||
|
|
||||||
[bundles]
|
[bundles]
|
||||||
|
|
||||||
|
|||||||
Vendored
BIN
Binary file not shown.
+3
-2
@@ -1,6 +1,7 @@
|
|||||||
#Mon Aug 26 20:47:33 CST 2024
|
|
||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip
|
||||||
|
networkTimeout=10000
|
||||||
|
validateDistributionUrl=true
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
@@ -15,6 +15,8 @@
|
|||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
#
|
#
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
#
|
||||||
|
|
||||||
##############################################################################
|
##############################################################################
|
||||||
#
|
#
|
||||||
@@ -55,7 +57,7 @@
|
|||||||
# Darwin, MinGW, and NonStop.
|
# Darwin, MinGW, and NonStop.
|
||||||
#
|
#
|
||||||
# (3) This script is generated from the Groovy template
|
# (3) This script is generated from the Groovy template
|
||||||
# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||||
# within the Gradle project.
|
# within the Gradle project.
|
||||||
#
|
#
|
||||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||||
@@ -80,13 +82,12 @@ do
|
|||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
|
|
||||||
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
|
# This is normally unused
|
||||||
|
# shellcheck disable=SC2034
|
||||||
APP_NAME="Gradle"
|
|
||||||
APP_BASE_NAME=${0##*/}
|
APP_BASE_NAME=${0##*/}
|
||||||
|
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
|
||||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s
|
||||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
' "$PWD" ) || exit
|
||||||
|
|
||||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||||
MAX_FD=maximum
|
MAX_FD=maximum
|
||||||
@@ -133,22 +134,29 @@ location of your Java installation."
|
|||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
JAVACMD=java
|
JAVACMD=java
|
||||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
if ! command -v java >/dev/null 2>&1
|
||||||
|
then
|
||||||
|
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||||
|
|
||||||
Please set the JAVA_HOME variable in your environment to match the
|
Please set the JAVA_HOME variable in your environment to match the
|
||||||
location of your Java installation."
|
location of your Java installation."
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Increase the maximum file descriptors if we can.
|
# Increase the maximum file descriptors if we can.
|
||||||
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||||
case $MAX_FD in #(
|
case $MAX_FD in #(
|
||||||
max*)
|
max*)
|
||||||
|
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
|
||||||
|
# shellcheck disable=SC2039,SC3045
|
||||||
MAX_FD=$( ulimit -H -n ) ||
|
MAX_FD=$( ulimit -H -n ) ||
|
||||||
warn "Could not query maximum file descriptor limit"
|
warn "Could not query maximum file descriptor limit"
|
||||||
esac
|
esac
|
||||||
case $MAX_FD in #(
|
case $MAX_FD in #(
|
||||||
'' | soft) :;; #(
|
'' | soft) :;; #(
|
||||||
*)
|
*)
|
||||||
|
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
|
||||||
|
# shellcheck disable=SC2039,SC3045
|
||||||
ulimit -n "$MAX_FD" ||
|
ulimit -n "$MAX_FD" ||
|
||||||
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||||
esac
|
esac
|
||||||
@@ -193,11 +201,15 @@ if "$cygwin" || "$msys" ; then
|
|||||||
done
|
done
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Collect all arguments for the java command;
|
|
||||||
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
|
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||||
# shell script including quotes and variable substitutions, so put them in
|
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||||
# double quotes to make sure that they get re-expanded; and
|
|
||||||
# * put everything else in single quotes, so that it's not re-expanded.
|
# Collect all arguments for the java command:
|
||||||
|
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
||||||
|
# and any embedded shellness will be escaped.
|
||||||
|
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
|
||||||
|
# treated as '${Hostname}' itself on the command line.
|
||||||
|
|
||||||
set -- \
|
set -- \
|
||||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||||
@@ -205,6 +217,12 @@ set -- \
|
|||||||
org.gradle.wrapper.GradleWrapperMain \
|
org.gradle.wrapper.GradleWrapperMain \
|
||||||
"$@"
|
"$@"
|
||||||
|
|
||||||
|
# Stop when "xargs" is not available.
|
||||||
|
if ! command -v xargs >/dev/null 2>&1
|
||||||
|
then
|
||||||
|
die "xargs is not available"
|
||||||
|
fi
|
||||||
|
|
||||||
# Use "xargs" to parse quoted args.
|
# Use "xargs" to parse quoted args.
|
||||||
#
|
#
|
||||||
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
|
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
|
||||||
|
|||||||
Vendored
+21
-16
@@ -13,8 +13,10 @@
|
|||||||
@rem See the License for the specific language governing permissions and
|
@rem See the License for the specific language governing permissions and
|
||||||
@rem limitations under the License.
|
@rem limitations under the License.
|
||||||
@rem
|
@rem
|
||||||
|
@rem SPDX-License-Identifier: Apache-2.0
|
||||||
|
@rem
|
||||||
|
|
||||||
@if "%DEBUG%" == "" @echo off
|
@if "%DEBUG%"=="" @echo off
|
||||||
@rem ##########################################################################
|
@rem ##########################################################################
|
||||||
@rem
|
@rem
|
||||||
@rem Gradle startup script for Windows
|
@rem Gradle startup script for Windows
|
||||||
@@ -25,7 +27,8 @@
|
|||||||
if "%OS%"=="Windows_NT" setlocal
|
if "%OS%"=="Windows_NT" setlocal
|
||||||
|
|
||||||
set DIRNAME=%~dp0
|
set DIRNAME=%~dp0
|
||||||
if "%DIRNAME%" == "" set DIRNAME=.
|
if "%DIRNAME%"=="" set DIRNAME=.
|
||||||
|
@rem This is normally unused
|
||||||
set APP_BASE_NAME=%~n0
|
set APP_BASE_NAME=%~n0
|
||||||
set APP_HOME=%DIRNAME%
|
set APP_HOME=%DIRNAME%
|
||||||
|
|
||||||
@@ -40,13 +43,13 @@ if defined JAVA_HOME goto findJavaFromJavaHome
|
|||||||
|
|
||||||
set JAVA_EXE=java.exe
|
set JAVA_EXE=java.exe
|
||||||
%JAVA_EXE% -version >NUL 2>&1
|
%JAVA_EXE% -version >NUL 2>&1
|
||||||
if "%ERRORLEVEL%" == "0" goto execute
|
if %ERRORLEVEL% equ 0 goto execute
|
||||||
|
|
||||||
echo.
|
echo. 1>&2
|
||||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
|
||||||
echo.
|
echo. 1>&2
|
||||||
echo Please set the JAVA_HOME variable in your environment to match the
|
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||||
echo location of your Java installation.
|
echo location of your Java installation. 1>&2
|
||||||
|
|
||||||
goto fail
|
goto fail
|
||||||
|
|
||||||
@@ -56,11 +59,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
|||||||
|
|
||||||
if exist "%JAVA_EXE%" goto execute
|
if exist "%JAVA_EXE%" goto execute
|
||||||
|
|
||||||
echo.
|
echo. 1>&2
|
||||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
|
||||||
echo.
|
echo. 1>&2
|
||||||
echo Please set the JAVA_HOME variable in your environment to match the
|
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||||
echo location of your Java installation.
|
echo location of your Java installation. 1>&2
|
||||||
|
|
||||||
goto fail
|
goto fail
|
||||||
|
|
||||||
@@ -75,13 +78,15 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
|||||||
|
|
||||||
:end
|
:end
|
||||||
@rem End local scope for the variables with windows NT shell
|
@rem End local scope for the variables with windows NT shell
|
||||||
if "%ERRORLEVEL%"=="0" goto mainEnd
|
if %ERRORLEVEL% equ 0 goto mainEnd
|
||||||
|
|
||||||
:fail
|
:fail
|
||||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||||
rem the _cmd.exe /c_ return code!
|
rem the _cmd.exe /c_ return code!
|
||||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
set EXIT_CODE=%ERRORLEVEL%
|
||||||
exit /b 1
|
if %EXIT_CODE% equ 0 set EXIT_CODE=1
|
||||||
|
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
|
||||||
|
exit /b %EXIT_CODE%
|
||||||
|
|
||||||
:mainEnd
|
:mainEnd
|
||||||
if "%OS%"=="Windows_NT" endlocal
|
if "%OS%"=="Windows_NT" endlocal
|
||||||
|
|||||||
+31
@@ -0,0 +1,31 @@
|
|||||||
|
#-------------------------------------------------------------------------------#
|
||||||
|
# Qodana analysis is configured by qodana.yaml file #
|
||||||
|
# https://www.jetbrains.com/help/qodana/qodana-yaml.html #
|
||||||
|
#-------------------------------------------------------------------------------#
|
||||||
|
version: "1.0"
|
||||||
|
|
||||||
|
#Specify inspection profile for code analysis
|
||||||
|
profile:
|
||||||
|
name: qodana.starter
|
||||||
|
|
||||||
|
#Enable inspections
|
||||||
|
#include:
|
||||||
|
# - name: <SomeEnabledInspectionId>
|
||||||
|
|
||||||
|
#Disable inspections
|
||||||
|
#exclude:
|
||||||
|
# - name: <SomeDisabledInspectionId>
|
||||||
|
# paths:
|
||||||
|
# - <path/where/not/run/inspection>
|
||||||
|
|
||||||
|
projectJDK: 17 #(Applied in CI/CD pipeline)
|
||||||
|
|
||||||
|
#Execute shell command before Qodana execution (Applied in CI/CD pipeline)
|
||||||
|
#bootstrap: sh ./prepare-qodana.sh
|
||||||
|
|
||||||
|
#Install IDE plugins before Qodana execution (Applied in CI/CD pipeline)
|
||||||
|
#plugins:
|
||||||
|
# - id: <plugin.id> #(plugin id can be found at https://plugins.jetbrains.com)
|
||||||
|
|
||||||
|
#Specify Qodana linter for analysis (Applied in CI/CD pipeline)
|
||||||
|
linter: jetbrains/qodana-jvm:latest
|
||||||
@@ -4,14 +4,27 @@
|
|||||||
* Date: 2024/8/27
|
* Date: 2024/8/27
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@file:Suppress("DEPRECATION")
|
||||||
|
|
||||||
package cn.rtast.fancybot
|
package cn.rtast.fancybot
|
||||||
|
|
||||||
|
import cn.rtast.fancybot.commands.*
|
||||||
|
import cn.rtast.fancybot.commands.lookup.*
|
||||||
|
import cn.rtast.fancybot.commands.misc.*
|
||||||
|
import cn.rtast.fancybot.commands.niuzi.*
|
||||||
|
import cn.rtast.fancybot.commands.parse.AsciiArtCommand
|
||||||
|
import cn.rtast.fancybot.commands.parse.ReverseGIFCommand
|
||||||
import cn.rtast.fancybot.entity.Config
|
import cn.rtast.fancybot.entity.Config
|
||||||
import cn.rtast.fancybot.entity.enums.ImageType
|
import cn.rtast.fancybot.enums.ImageBedType
|
||||||
import cn.rtast.fancybot.entity.enums.WSType
|
import cn.rtast.fancybot.enums.ImageType
|
||||||
|
import cn.rtast.fancybot.enums.WSType
|
||||||
|
import cn.rtast.fancybot.items.*
|
||||||
|
import cn.rtast.fancybot.util.file.*
|
||||||
|
import cn.rtast.fancybot.util.item.ItemManager
|
||||||
import com.google.gson.Gson
|
import com.google.gson.Gson
|
||||||
import com.google.gson.GsonBuilder
|
import com.google.gson.GsonBuilder
|
||||||
|
import java.io.File
|
||||||
|
import java.time.Instant
|
||||||
|
|
||||||
val gson: Gson = GsonBuilder()
|
val gson: Gson = GsonBuilder()
|
||||||
.setPrettyPrinting()
|
.setPrettyPrinting()
|
||||||
@@ -19,6 +32,10 @@ val gson: Gson = GsonBuilder()
|
|||||||
.create()
|
.create()
|
||||||
|
|
||||||
const val ROOT_PATH = "./data"
|
const val ROOT_PATH = "./data"
|
||||||
|
val ROOT_PATH_ = File(ROOT_PATH).apply { mkdirs() }
|
||||||
|
const val ASSETS_BASE_URL = "https://static.rtast.cn"
|
||||||
|
const val API_RTAST_URL = "https://api.rtast.cn"
|
||||||
|
const val PBI_API_URL = "https://pbi.us.kg"
|
||||||
|
|
||||||
val DEFAULT_CONFIG = Config(
|
val DEFAULT_CONFIG = Config(
|
||||||
ncmAPI = "https://ncm.rtast.cn",
|
ncmAPI = "https://ncm.rtast.cn",
|
||||||
@@ -32,11 +49,73 @@ val DEFAULT_CONFIG = Config(
|
|||||||
imageType = ImageType.PNG,
|
imageType = ImageType.PNG,
|
||||||
openAIAPIHost = "https://api.moonshot.cn",
|
openAIAPIHost = "https://api.moonshot.cn",
|
||||||
openAIAPIKey = "114514",
|
openAIAPIKey = "114514",
|
||||||
|
openAIModel = "moonshot-v1-8k",
|
||||||
smtpHost = "127.0.0.1",
|
smtpHost = "127.0.0.1",
|
||||||
smtpPort = 25,
|
smtpPort = 25,
|
||||||
smtpUser = "114514",
|
smtpUser = "114514",
|
||||||
smtpPassword = "1919810",
|
smtpPassword = "1919810",
|
||||||
smtpFromAddress = "fancybot@repo.rtast.cn",
|
smtpFromAddress = "fancybot@repo.rtast.cn",
|
||||||
admins = listOf(3458671395L),
|
admins = listOf(3458671395L),
|
||||||
enableAntiRevoke = true
|
enableAntiRevoke = true,
|
||||||
|
llamaUrl = "http://127.0.0.1",
|
||||||
|
llamaModel = "llama3.1",
|
||||||
|
qqMusicApiUrl = "http://127.0.0.1:3200",
|
||||||
|
noticeUser = 114514L,
|
||||||
|
selfId = 114514L,
|
||||||
|
tianXingApiKey = "1145141919810",
|
||||||
|
githubUser = "RTAkland",
|
||||||
|
githubImageRepo = "Static-Images",
|
||||||
|
imageBedType = ImageBedType.Github,
|
||||||
|
cloudflareAccountId = "111",
|
||||||
|
cloudflareR2AccessKeyId = "11111",
|
||||||
|
cloudflareR2SecretKey = "222",
|
||||||
|
cloudflareR2BucketName = "fancybot",
|
||||||
|
cloudflareR2PublicUrl = "https://114514.com",
|
||||||
|
apiSpaceKey = "114514",
|
||||||
|
apiRtastKey = "114514",
|
||||||
|
azureAppClientId = "114514",
|
||||||
|
youtubeDataApiKey = "114514",
|
||||||
|
naiLongApiUrl = "http://127.0.0.1:5000/nailong",
|
||||||
|
osuClientId = 111,
|
||||||
|
osuClientSecret = "222"
|
||||||
|
)
|
||||||
|
|
||||||
|
val configManager = ConfigManager()
|
||||||
|
val itemManager = ItemManager()
|
||||||
|
val niuziManager = NiuziManager()
|
||||||
|
val niuziBankManager = NiuziBankManager()
|
||||||
|
val blackListManager = BlackListManager()
|
||||||
|
val rconManager = RCONManager()
|
||||||
|
|
||||||
|
val START_UP_TIME = Instant.now().epochSecond
|
||||||
|
|
||||||
|
val items = listOf(
|
||||||
|
HeisiItem(), BaisiItem(),
|
||||||
|
SetuItem(), NiuziItem(),
|
||||||
|
TenSetuItem(), TenSetuR18Item()
|
||||||
|
)
|
||||||
|
|
||||||
|
val commands = listOf(
|
||||||
|
EchoCommand(), JrrpCommand(), NiuziRedeemCommand(), HitokotoCommand(),
|
||||||
|
KFCCommand(), GenerateQRCodeCommand(), AntiRevokeCommand(), MCPingCommand(),
|
||||||
|
WeatherCommand(), CigaretteCommand(), RemakeCommand(), PixivCommand(),
|
||||||
|
RUACommand(), CompilerCommand(), AICommand(),
|
||||||
|
GithubUserCommand(), AboutCommand(), MusicPlayUrlCommand(), DomainPriceCommand(),
|
||||||
|
SendMailCommand(), ZiBiCommand(), UnsetZiBiCommand(), WikipediaCommand(),
|
||||||
|
AsciiArtCommand(), StatusCommand(), JueCommand(), ShortLinkCommand(),
|
||||||
|
ShotOtherCommand(), ReverseGIFCommand(), HelpCommand(), MusicCommand(),
|
||||||
|
SendLikeCommand(), NiuziTransferCommand(), NiuziSignCommand(), NiuziJiJianCommand(),
|
||||||
|
NiuziQueryCommand(), MyNiuziCommand(), NiuziBankCommand(), WithdrawCommand(),
|
||||||
|
BankTransferCommand(), CreateBankAccountCommand(), BankBalanceCommand(), DepositCommand(),
|
||||||
|
AnimeSearchCommand(), LlamaCommand(), QQMusicCommand(), BullShitGenerateCommand(),
|
||||||
|
NiuziRankCommand(), NiuziBankRankCommand(), ShotSelfCommand(), TenSetuCommand(),
|
||||||
|
ReactionCommand(), MCSkinCommand(), GithubLatestCommitCommand(), RandomMusicCommand(),
|
||||||
|
ZDJDCommand(), ScanQRCodeCommand(), TTSCommand(), SlimeChunkHelperCommand(),
|
||||||
|
SupportMeCommand(), TheCatCommand(), TheHistoryOfTodayCommand(), MCVersionCommand(),
|
||||||
|
MinecraftWikiCommand(), GaoKaoDaysRemainCommand(), IdiomExplainCommand(), NiuziManagerCommand(),
|
||||||
|
TodayEatCommand(), TodayDrinkCommand(), MCLoginCommand(), RCONCommand(),
|
||||||
|
GravatarCommand(), PastebinCommand(), ShuffleEchoCommand(), TodayDontEatCommand(),
|
||||||
|
TodayDontDrinkCommand(), MCBotCommand(), HTTPCatCommand(), HTTPDogCommand(),
|
||||||
|
AITTSCommand(), NWWNCommand(), TJBGXLCommand(), XNMCommand(), SJCommand(),
|
||||||
|
OSUCommand(), TodaySmokeCommand(), GoodNewsCommand(), MRRHRCommand()
|
||||||
)
|
)
|
||||||
@@ -7,59 +7,54 @@
|
|||||||
|
|
||||||
package cn.rtast.fancybot
|
package cn.rtast.fancybot
|
||||||
|
|
||||||
import cn.rtast.fancybot.commands.AboutCommand
|
import cn.rtast.fancybot.commands.misc.JueCommand
|
||||||
import cn.rtast.fancybot.commands.EchoCommand
|
import cn.rtast.fancybot.commands.misc.PastebinCommand
|
||||||
import cn.rtast.fancybot.commands.HelpCommand
|
import cn.rtast.fancybot.commands.misc.ReactionCommand
|
||||||
import cn.rtast.fancybot.commands.StatusCommand
|
import cn.rtast.fancybot.commands.misc.ScanQRCodeCommand
|
||||||
import cn.rtast.fancybot.commands.lookup.*
|
import cn.rtast.fancybot.commands.misc.ShortLinkCommand.Companion.makeShortLink
|
||||||
import cn.rtast.fancybot.commands.misc.*
|
import cn.rtast.fancybot.commands.parse.*
|
||||||
import cn.rtast.fancybot.commands.parse.AsciiArtCommand
|
import cn.rtast.fancybot.commands.reply.ImageBedCommand
|
||||||
import cn.rtast.fancybot.commands.parse.BVParseCommand
|
import cn.rtast.fancybot.commands.reply.InvertImageCommand
|
||||||
import cn.rtast.fancybot.commands.parse.CalculateCommand
|
import cn.rtast.fancybot.commands.reply.RandomRGBCommand
|
||||||
import cn.rtast.fancybot.commands.parse.GitHubParseCommand
|
import cn.rtast.fancybot.commands.reply.SpeedUpGIFCommand
|
||||||
import cn.rtast.fancybot.commands.parse.ImageURLCommand
|
import cn.rtast.fancybot.enums.WSType
|
||||||
import cn.rtast.fancybot.commands.parse.ReverseGIFCommand
|
import cn.rtast.fancybot.util.Logger
|
||||||
import cn.rtast.fancybot.commands.record.JiJianCommand
|
|
||||||
import cn.rtast.fancybot.commands.record.JrrpCommand
|
|
||||||
import cn.rtast.fancybot.commands.record.MyNiuziCommand
|
|
||||||
import cn.rtast.fancybot.commands.record.MyPointCommand
|
|
||||||
import cn.rtast.fancybot.commands.record.NiuziSignCommand
|
|
||||||
import cn.rtast.fancybot.commands.record.RedeemCommand
|
|
||||||
import cn.rtast.fancybot.commands.record.ShortLinkCommand
|
|
||||||
import cn.rtast.fancybot.commands.record.SignCommand
|
|
||||||
import cn.rtast.fancybot.entity.bili.CardShare
|
|
||||||
import cn.rtast.fancybot.entity.enums.WSType
|
|
||||||
import cn.rtast.fancybot.items.BaisiItem
|
|
||||||
import cn.rtast.fancybot.items.HeisiItem
|
|
||||||
import cn.rtast.fancybot.items.SetuItem
|
|
||||||
import cn.rtast.fancybot.util.file.ConfigManager
|
|
||||||
import cn.rtast.fancybot.util.file.NiuziManager
|
|
||||||
import cn.rtast.fancybot.util.file.SignManager
|
|
||||||
import cn.rtast.fancybot.util.initDatabase
|
import cn.rtast.fancybot.util.initDatabase
|
||||||
import cn.rtast.fancybot.util.item.ItemManager
|
import cn.rtast.fancybot.util.misc.*
|
||||||
import cn.rtast.fancybot.util.str.fromJson
|
import cn.rtast.fancybot.util.str.encodeToBase64
|
||||||
import cn.rtast.rob.ROneBotFactory
|
import cn.rtast.rob.ROneBotFactory
|
||||||
import cn.rtast.rob.entity.AddFriendRequest
|
import cn.rtast.rob.entity.*
|
||||||
import cn.rtast.rob.entity.FileEvent
|
import cn.rtast.rob.entity.custom.BeKickEvent
|
||||||
import cn.rtast.rob.entity.GetMessage
|
import cn.rtast.rob.entity.custom.ErrorEvent
|
||||||
import cn.rtast.rob.entity.GroupMessage
|
import cn.rtast.rob.entity.custom.MemberKickEvent
|
||||||
import cn.rtast.rob.entity.GroupRevokeMessage
|
import cn.rtast.rob.entity.custom.MemberLeaveEvent
|
||||||
|
import cn.rtast.rob.entity.lagrange.FileEvent
|
||||||
|
import cn.rtast.rob.entity.lagrange.PokeEvent
|
||||||
import cn.rtast.rob.enums.ArrayMessageType
|
import cn.rtast.rob.enums.ArrayMessageType
|
||||||
import cn.rtast.rob.util.ob.MessageChain
|
import cn.rtast.rob.onebot.MessageChain
|
||||||
import cn.rtast.rob.util.ob.OneBotListener
|
import cn.rtast.rob.onebot.OneBotAction
|
||||||
|
import cn.rtast.rob.onebot.OneBotListener
|
||||||
|
import cn.rtast.rob.segment.NewLine
|
||||||
|
import cn.rtast.rob.segment.Text
|
||||||
|
import com.madgag.gif.fmsware.GifDecoder
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
import java.io.ByteArrayOutputStream
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.net.URI
|
import java.net.URI
|
||||||
import java.time.Instant
|
import java.util.zip.ZipEntry
|
||||||
|
import java.util.zip.ZipOutputStream
|
||||||
|
import javax.imageio.ImageIO
|
||||||
|
|
||||||
class FancyBot : OneBotListener {
|
class FancyBot : OneBotListener {
|
||||||
|
|
||||||
|
private val logger = Logger.getLogger<FancyBot>()
|
||||||
private val coroutineScope = CoroutineScope(Dispatchers.IO)
|
private val coroutineScope = CoroutineScope(Dispatchers.IO)
|
||||||
|
|
||||||
override suspend fun onWebsocketOpenEvent() {
|
override suspend fun onWebsocketOpenEvent(action: OneBotAction) {
|
||||||
this.broadcastMessage("FancyBot启动成功了呢~")
|
action.sendPrivateMessage(configManager.noticeUser, "FancyBot启动完成~")
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun onGroupMessage(message: GroupMessage, json: String) {
|
override suspend fun onGroupMessage(message: GroupMessage, json: String) {
|
||||||
@@ -68,70 +63,152 @@ class FancyBot : OneBotListener {
|
|||||||
val msg = message.rawMessage
|
val msg = message.rawMessage
|
||||||
val groupId = message.groupId
|
val groupId = message.groupId
|
||||||
val messageId = message.messageId
|
val messageId = message.messageId
|
||||||
println("$sender($senderId: $groupId >>> $messageId): $msg")
|
logger.info("$sender($senderId: $groupId >>> $messageId): $msg")
|
||||||
|
logger.trace("$sender($senderId: $groupId >>> $messageId: $json")
|
||||||
|
|
||||||
if (message.rawMessage.toList().any { it in arrayListOf('*', '-', '/', '+', '=') }) {
|
// if (message.message.any { it.type == ArrayMessageType.face && it.data.id.toString() == "419" }) {
|
||||||
|
// message.reply("你发牛魔的火车呢, 我直接就是打断")
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if (message.text.contains("原神")) {
|
||||||
|
// (0..10).forEach { _ -> message.reaction(QQFace.entries.random()) }
|
||||||
|
// message.reply("你原神牛魔呢")
|
||||||
|
// delay(1500L)
|
||||||
|
// message.reply("但是话又说回来.....启动!!")
|
||||||
|
// }
|
||||||
|
|
||||||
|
GitHubParseCommand.parse(message)
|
||||||
|
ReverseGIFCommand.callback(message)
|
||||||
|
AsciiArtCommand.callback(message)
|
||||||
|
ScanQRCodeCommand.callback(message)
|
||||||
|
BiliVideoParseCommand.parse(message)
|
||||||
|
BiliUserParseCommand.parse(message)
|
||||||
|
DouyinVideoParseCommand.parse(message)
|
||||||
|
YoutubeVideoParseCommand.parse(message)
|
||||||
|
|
||||||
|
if (message.text.toList().any { it in arrayListOf('*', '-', '/', '+', '=') }) {
|
||||||
val calculateResult = CalculateCommand.parse(message.rawMessage)
|
val calculateResult = CalculateCommand.parse(message.rawMessage)
|
||||||
calculateResult?.let { message.reply(calculateResult) }
|
calculateResult?.let { message.reply(calculateResult) }
|
||||||
}
|
}
|
||||||
|
|
||||||
ReverseGIFCommand.callback(message)
|
if (message.message.any { it.type == ArrayMessageType.at }) {
|
||||||
AsciiArtCommand.callback(message)
|
if (message.text.contains("/取头像")) {
|
||||||
if (message.message.any { it.type == ArrayMessageType.reply }) { // Image url parse
|
val target = message.message.find { it.type == ArrayMessageType.at }?.data?.qq!!
|
||||||
val command = message.message.reversed().find { it.type == ArrayMessageType.text }!!.data.text!!
|
val avatar = JueCommand.AVATAR_REPLACE_URL.replace("#{}", target)
|
||||||
|
val msg = MessageChain.Builder()
|
||||||
|
if (message.text.contains("黑白")) {
|
||||||
|
val greyscale = avatar.toURL()
|
||||||
|
.readBytes().toBufferedImage()
|
||||||
|
.toGrayscale().toByteArray()
|
||||||
|
val greyscaleShortLink = ImageBed.upload(greyscale).makeShortLink()
|
||||||
|
msg.addImage(greyscale.encodeToBase64(), true)
|
||||||
|
.addText(greyscaleShortLink)
|
||||||
|
} else {
|
||||||
|
val shortLink = avatar.makeShortLink()
|
||||||
|
msg.addImage(avatar).addText(shortLink)
|
||||||
|
}
|
||||||
|
message.reply(msg.build())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (message.message.any { it.type == ArrayMessageType.reply }) {
|
||||||
|
val command = message.text.trim()
|
||||||
val replyId = message.message.find { it.type == ArrayMessageType.reply }!!.data.id!!
|
val replyId = message.message.find { it.type == ArrayMessageType.reply }!!.data.id!!
|
||||||
if (command.contains("图来") || command.contains("图链")) {
|
val getMsg = message.action.getMessage(replyId.toString().toLong())
|
||||||
val getMsg = this.getMessage(replyId.toString().toLong())
|
val plainTextContent = getMsg.text
|
||||||
ImageURLCommand.callback(message, getMsg)
|
when (command) {
|
||||||
|
"/倒放", "/df" -> ReverseGIFCommand.reverse(message, getMsg)
|
||||||
|
"/图来", "/图链" -> ImageURLCommand.callback(message, getMsg)
|
||||||
|
"/图床" -> ImageBedCommand.execute(getMsg, message)
|
||||||
|
"/reaction" -> ReactionCommand.reaction(message.action, message.groupId, getMsg.messageId)
|
||||||
|
"/sl", "/short" -> message.reply(plainTextContent.trim().makeShortLink())
|
||||||
|
"/rc", "/随机颜色" -> RandomRGBCommand.random(message, getMsg)
|
||||||
|
"/颜色反转", "/iv" -> InvertImageCommand.invert(message, getMsg)
|
||||||
|
"/ascii", "/asc" -> {
|
||||||
|
val url = AsciiArtCommand.getImageUrl(getMsg)
|
||||||
|
val image = AsciiArtCommand.generateAsciiArt(url)
|
||||||
|
message.reply(image)
|
||||||
|
}
|
||||||
|
|
||||||
|
"/pb", "/pastebin" -> {
|
||||||
|
val pastebinUrl = PastebinCommand.createPastebin(plainTextContent)
|
||||||
|
message.reply(pastebinUrl)
|
||||||
|
}
|
||||||
|
|
||||||
|
"/加速" -> {
|
||||||
|
val multiply = command.split("加速").last().toFloat()
|
||||||
|
SpeedUpGIFCommand.speedUp(message, getMsg, multiply)
|
||||||
|
}
|
||||||
|
|
||||||
|
"/黑白", "/灰度" -> {
|
||||||
|
val msg = MessageChain.Builder()
|
||||||
|
getMsg.message.filter { it.type == ArrayMessageType.image || it.type == ArrayMessageType.mface }
|
||||||
|
.forEach {
|
||||||
|
val imgUrl = it.data.file!!
|
||||||
|
val decoder = GifDecoder()
|
||||||
|
val imageStream = withContext(Dispatchers.IO) { imgUrl.toURL().openStream() }
|
||||||
|
decoder.read(imageStream)
|
||||||
|
if (decoder.frameCount == 0) {
|
||||||
|
msg.addImage(
|
||||||
|
imageStream.readBytes().toBufferedImage().toByteArray().encodeToBase64(), true
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
val frames = (0 until decoder.frameCount).map { decoder.getFrame(it).toGrayscale() }
|
||||||
|
val base64 = decoder.makeGif(frames).encodeToBase64()
|
||||||
|
msg.addImage(base64, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
message.reply(msg.build())
|
||||||
|
}
|
||||||
|
|
||||||
|
"/拆帧", "/cj" -> {
|
||||||
|
val gifStream = getMsg.images.first().file.toURL().openStream()
|
||||||
|
val decoder = GifDecoder()
|
||||||
|
decoder.read(gifStream)
|
||||||
|
val frames = (0 until decoder.frameCount).map { decoder.getFrame(it) }
|
||||||
|
val byteArrayOutputStream = ByteArrayOutputStream()
|
||||||
|
ZipOutputStream(byteArrayOutputStream).use { zipOut ->
|
||||||
|
for ((index, image) in frames.withIndex()) {
|
||||||
|
val imageOutputStream = ByteArrayOutputStream()
|
||||||
|
ImageIO.write(image, "png", imageOutputStream)
|
||||||
|
val entry = ZipEntry("frame_$index.png")
|
||||||
|
zipOut.putNextEntry(entry)
|
||||||
|
zipOut.write(imageOutputStream.toByteArray())
|
||||||
|
zipOut.closeEntry()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val zipBytes = byteArrayOutputStream.toByteArray()
|
||||||
|
logger.info("Split frame size: ${zipBytes.size / 1024 / 1024}MB")
|
||||||
|
val imgBedUrl = ImageBed.upload(zipBytes, "zip")
|
||||||
|
val shortLink = imgBedUrl.makeShortLink()
|
||||||
|
val msg = Text(imgBedUrl) + NewLine() + Text(shortLink)
|
||||||
|
message.reply(msg)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
coroutineScope.launch {
|
coroutineScope.launch {
|
||||||
|
// if (message.images.isNotEmpty()) {
|
||||||
|
// message.images.forEach {
|
||||||
|
// val payload = NaiLongDetectPayload(it.file).toJson()
|
||||||
|
// val result = Http.post<NaiLongDetectResponse>(configManager.naiLongApiUrl, payload)
|
||||||
|
// logger.info("奶龙识别结果: ${result.result}")
|
||||||
|
// if (result.result) {
|
||||||
|
// message.reply("本群禁止发奶龙!")
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
message.message.forEach {
|
message.message.forEach {
|
||||||
if (it.type == ArrayMessageType.image) {
|
if (it.type == ArrayMessageType.image) {
|
||||||
val filename = it.data.file!!.split("=").last() + ".png"
|
val filename = it.data.file!!.split("=").last() + ".png"
|
||||||
URI(it.data.file!!).toURL().openConnection().inputStream.use { input ->
|
URI(it.data.file!!).toURL().openConnection().inputStream.use { input ->
|
||||||
File("./files/images/$filename").outputStream().use { output ->
|
File("$ROOT_PATH/caches/images/$filename").outputStream().use { output ->
|
||||||
output.write(input.readBytes())
|
output.write(input.readBytes())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (message.rawMessage.startsWith("https://github.com/") || message.rawMessage.startsWith("git@github.com:")) {
|
|
||||||
GitHubParseCommand.parse(this, message)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (message.rawMessage.startsWith("BV") ||
|
|
||||||
message.rawMessage.startsWith("https://www.bilibili.com") ||
|
|
||||||
message.rawMessage.contains("https://b23.tv/") ||
|
|
||||||
message.message.find { it.type == ArrayMessageType.json } != null
|
|
||||||
) {
|
|
||||||
// parse bilibili video with a link, bvid or b23.tv link
|
|
||||||
val bvid = if (message.rawMessage.startsWith("BV")) {
|
|
||||||
message.rawMessage
|
|
||||||
} else if (message.rawMessage.split(" ").last().startsWith("https://b23.tv/")) {
|
|
||||||
val shortUrl = message.rawMessage.split(" ").last()
|
|
||||||
BVParseCommand.getShortUrlBVID(shortUrl)
|
|
||||||
} else if (message.message.find { it.type == ArrayMessageType.json } != null) {
|
|
||||||
val card = message.message.find { it.type == ArrayMessageType.json }!!
|
|
||||||
.data.data!!.toString().fromJson<CardShare>()
|
|
||||||
val shortUrl = if (card.meta.detail == null) {
|
|
||||||
if (!card.meta.news?.tag!!.contains("哔哩哔哩")) return
|
|
||||||
card.meta.news.jumpUrl
|
|
||||||
} else {
|
|
||||||
if (!card.meta.detail.title.contains("哔哩哔哩")) return
|
|
||||||
card.meta.detail.qqDocUrl
|
|
||||||
}
|
|
||||||
BVParseCommand.getShortUrlBVID(shortUrl)
|
|
||||||
} else {
|
|
||||||
message.rawMessage.split("?").first()
|
|
||||||
.split("/")
|
|
||||||
.last { it.isNotEmpty() && it.isNotBlank() }
|
|
||||||
}
|
|
||||||
BVParseCommand.parse(this, bvid, message)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun onGroupMessageRevoke(message: GroupRevokeMessage) {
|
override suspend fun onGroupMessageRevoke(message: GroupRevokeMessage) {
|
||||||
@@ -141,89 +218,77 @@ class FancyBot : OneBotListener {
|
|||||||
.addNewLine()
|
.addNewLine()
|
||||||
.addText("使用/revoke ${message.messageId} 来获取被撤回的消息")
|
.addText("使用/revoke ${message.messageId} 来获取被撤回的消息")
|
||||||
.build()
|
.build()
|
||||||
this.sendGroupMessage(message.groupId, msg)
|
message.action.sendGroupMessage(message.groupId, msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun onWebsocketErrorEvent(ex: Exception) {
|
override suspend fun onWebsocketErrorEvent(event: ErrorEvent) {
|
||||||
ex.printStackTrace()
|
event.exception.printStackTrace()
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun onAddFriendRequest(event: AddFriendRequest) {
|
override suspend fun onAddFriendRequest(event: AddFriendRequestEvent) {
|
||||||
event.approve()
|
event.approve()
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun onGroupFileUpload(event: FileEvent) {
|
override suspend fun onGroupFileUpload(event: FileEvent) {
|
||||||
event.saveTo("./files")
|
event.saveTo("$ROOT_PATH/caches/")
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun onLeaveEvent(groupId: Long, userId: Long, operator: Long, time: Long) {
|
override suspend fun onLeaveEvent(event: MemberLeaveEvent) {
|
||||||
|
val nickname = event.action.getGroupMemberInfo(event.groupId, event.userId).nickname
|
||||||
val msg = MessageChain.Builder()
|
val msg = MessageChain.Builder()
|
||||||
.addText("有人退群了")
|
.addText("有人坐飞船离开了本星系~(主动退出)")
|
||||||
.addNewLine()
|
.addNewLine()
|
||||||
.addText("QQ: $userId | 操作者: ${if (operator == 0L) "主动退出" else operator}")
|
.addText("QQ: $nickname(${event.userId})")
|
||||||
.addNewLine()
|
.addNewLine()
|
||||||
.addText("下次再见吧~~~")
|
.addText("下次再见吧~~~")
|
||||||
.build()
|
.build()
|
||||||
this.sendGroupMessage(groupId, msg)
|
event.action.sendGroupMessage(event.groupId, msg)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
val configManager = ConfigManager()
|
override suspend fun onMemberKick(event: MemberKickEvent) {
|
||||||
val itemManager = ItemManager()
|
val nickname = event.action.getGroupMemberInfo(event.groupId, event.userId).nickname
|
||||||
val signManager = SignManager()
|
val msg = MessageChain.Builder()
|
||||||
val niuziManager = NiuziManager()
|
.addText("有人坐飞船离开了本星系~(管理员踢出)")
|
||||||
|
.addNewLine()
|
||||||
|
.addText("QQ: $nickname(${event.userId})")
|
||||||
|
.addNewLine()
|
||||||
|
.addText("下次再见吧~~~")
|
||||||
|
.build()
|
||||||
|
event.action.sendGroupMessage(event.groupId, msg)
|
||||||
|
}
|
||||||
|
|
||||||
val items = listOf(
|
override suspend fun onGroupPoke(event: PokeEvent) {
|
||||||
HeisiItem(),
|
if (event.targetId == configManager.selfId) {
|
||||||
BaisiItem(),
|
val msg = MessageChain.Builder()
|
||||||
SetuItem()
|
.addAt(event.userId)
|
||||||
)
|
.addText("你${event.pokeAction.first()}牛魔呢")
|
||||||
|
.build()
|
||||||
|
event.action.sendGroupMessage(event.groupId!!, msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val commands = listOf(
|
override suspend fun onBeKicked(event: BeKickEvent) {
|
||||||
EchoCommand(), JrrpCommand(),
|
blackListManager.insertGroup(event.groupId, event.operator, event.time)
|
||||||
MusicCommand(), SignCommand(),
|
event.action.sendPrivateMessage(
|
||||||
RedeemCommand(), MyPointCommand(),
|
configManager.noticeUser,
|
||||||
HitokotoCommand(), FKXQSCommand(),
|
"被: ${event.groupId}踢出! 操作人: ${event.operator} 时间: ${event.time.convertToDate()} 已将其拉入黑名单!"
|
||||||
QRCodeCommand(), AntiRevokeCommand(),
|
)
|
||||||
MCPingCommand(), HelpCommand(),
|
}
|
||||||
WeatherCommand(), CigaretteCommand(),
|
|
||||||
RemakeCommand(), PixivCommand(),
|
|
||||||
RUACommand(), NslookupCommand(),
|
|
||||||
NiuziSignCommand(), MyNiuziCommand(),
|
|
||||||
JiJianCommand(), LikeMeCommand(),
|
|
||||||
CompilerCommand(), AICommand(),
|
|
||||||
GithubUserCommand(), AboutCommand(),
|
|
||||||
MusicPlayUrlCommand(), DomainPriceCommand(),
|
|
||||||
SendMailCommand(), ZiBiCommand(),
|
|
||||||
UnsetZiBiCommand(), WikipediaCommand(),
|
|
||||||
AsciiArtCommand(), StatusCommand(),
|
|
||||||
JueCommand(), ShortLinkCommand(),
|
|
||||||
TenSetuCommand(), ShotSelfCommand(),
|
|
||||||
ShotOtherCommand(), ReverseGIFCommand()
|
|
||||||
)
|
|
||||||
|
|
||||||
val START_UP_TIME = Instant.now().epochSecond
|
|
||||||
|
|
||||||
fun initFilesDir() {
|
|
||||||
File("./files/images").also { it.mkdirs() }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun main() {
|
suspend fun main() {
|
||||||
val fancyBot = FancyBot()
|
val fancyBot = FancyBot()
|
||||||
val workType = configManager.wsType
|
val workType = configManager.wsType
|
||||||
val accessToken = configManager.accessToken
|
val accessToken = configManager.accessToken
|
||||||
val rob = if (workType == WSType.Client) {
|
val instance = when (workType) {
|
||||||
val address = configManager.wsAddress
|
WSType.Client -> ROneBotFactory.createClient(configManager.wsAddress, accessToken, fancyBot)
|
||||||
ROneBotFactory.createClient(address, accessToken, fancyBot)
|
WSType.Server -> ROneBotFactory.createServer(configManager.wsPort, accessToken, fancyBot)
|
||||||
.also { it.addListeningGroups(*configManager.listeningGroups.toLongArray()) }
|
|
||||||
} else {
|
|
||||||
val port = configManager.wsPort
|
|
||||||
ROneBotFactory.createServer(port, accessToken, fancyBot)
|
|
||||||
.also { it.addListeningGroups(*configManager.listeningGroups.toLongArray()) }
|
|
||||||
}
|
}
|
||||||
|
instance.addListeningGroups(*configManager.listeningGroups.toLongArray())
|
||||||
initDatabase()
|
initDatabase()
|
||||||
initFilesDir()
|
initFilesDir()
|
||||||
val commandManager = rob.commandManager
|
initCommand()
|
||||||
commands.forEach { commandManager.register(it) }
|
initSetuIndex()
|
||||||
items.forEach { itemManager.register(it) }
|
initItems()
|
||||||
|
initBackgroundTasks(instance)
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2024 RTAkland
|
||||||
|
* Author: RTAkland
|
||||||
|
* Date: 2024/9/26
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
package cn.rtast.fancybot.annotations
|
||||||
|
|
||||||
|
@Target(AnnotationTarget.CLASS)
|
||||||
|
@Retention(AnnotationRetention.RUNTIME)
|
||||||
|
annotation class CommandDescription(val description: String)
|
||||||
@@ -7,18 +7,17 @@
|
|||||||
|
|
||||||
package cn.rtast.fancybot.commands
|
package cn.rtast.fancybot.commands
|
||||||
|
|
||||||
|
import cn.rtast.fancybot.annotations.CommandDescription
|
||||||
import cn.rtast.rob.entity.GroupMessage
|
import cn.rtast.rob.entity.GroupMessage
|
||||||
|
import cn.rtast.rob.onebot.MessageChain
|
||||||
import cn.rtast.rob.util.BaseCommand
|
import cn.rtast.rob.util.BaseCommand
|
||||||
import cn.rtast.rob.util.ob.MessageChain
|
|
||||||
import cn.rtast.rob.util.ob.OneBotListener
|
|
||||||
|
|
||||||
|
@CommandDescription("关于")
|
||||||
class AboutCommand : BaseCommand() {
|
class AboutCommand : BaseCommand() {
|
||||||
override val commandNames = listOf("/about", "/关于")
|
override val commandNames = listOf("/about", "/关于")
|
||||||
|
|
||||||
override suspend fun executeGroup(listener: OneBotListener, message: GroupMessage, args: List<String>) {
|
override suspend fun executeGroup(message: GroupMessage, args: List<String>) {
|
||||||
val msg = MessageChain.Builder()
|
val msg = MessageChain.Builder()
|
||||||
.addAt(message.sender.userId)
|
|
||||||
.addNewLine()
|
|
||||||
.addText("Bot名称: FancyBot")
|
.addText("Bot名称: FancyBot")
|
||||||
.addNewLine()
|
.addNewLine()
|
||||||
.addText("作者: RTAkland")
|
.addText("作者: RTAkland")
|
||||||
@@ -27,6 +26,6 @@ class AboutCommand : BaseCommand() {
|
|||||||
.addNewLine()
|
.addNewLine()
|
||||||
.addText("项目地址: https://repo.rtast.cn/RTAkland/FancyBot")
|
.addText("项目地址: https://repo.rtast.cn/RTAkland/FancyBot")
|
||||||
.build()
|
.build()
|
||||||
listener.sendGroupMessage(message.groupId, msg)
|
message.reply(msg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -7,14 +7,36 @@
|
|||||||
|
|
||||||
package cn.rtast.fancybot.commands
|
package cn.rtast.fancybot.commands
|
||||||
|
|
||||||
|
import cn.rtast.fancybot.annotations.CommandDescription
|
||||||
|
import cn.rtast.fancybot.enums.CommandAction
|
||||||
|
import cn.rtast.fancybot.util.file.insertActionRecord
|
||||||
import cn.rtast.rob.entity.GroupMessage
|
import cn.rtast.rob.entity.GroupMessage
|
||||||
import cn.rtast.rob.util.BaseCommand
|
import cn.rtast.rob.util.BaseCommand
|
||||||
import cn.rtast.rob.util.ob.OneBotListener
|
|
||||||
|
|
||||||
|
@CommandDescription("Echo")
|
||||||
class EchoCommand : BaseCommand() {
|
class EchoCommand : BaseCommand() {
|
||||||
override val commandNames = listOf("/echo")
|
override val commandNames = listOf("/echo")
|
||||||
|
|
||||||
override suspend fun executeGroup(listener: OneBotListener, message: GroupMessage, args: List<String>) {
|
override suspend fun executeGroup(message: GroupMessage, args: List<String>) {
|
||||||
listener.sendGroupMessage(message.groupId, args.joinToString(" "))
|
if (message.sender.isAdmin || message.sender.isOwner) {
|
||||||
|
message.reply(args.joinToString(" "))
|
||||||
|
insertActionRecord(CommandAction.Echo, message.sender.userId)
|
||||||
|
} else {
|
||||||
|
message.reply("你不许用echo")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@CommandDescription("精神错乱(×), 胡言乱语(√)")
|
||||||
|
class ShuffleEchoCommand : BaseCommand() {
|
||||||
|
override val commandNames = listOf("/secho", "/se")
|
||||||
|
|
||||||
|
override suspend fun executeGroup(message: GroupMessage, args: List<String>) {
|
||||||
|
if (message.sender.isAdmin || message.sender.isOwner) {
|
||||||
|
message.reply(message.rawMessage.toList().shuffled().joinToString(""))
|
||||||
|
insertActionRecord(CommandAction.Echo, message.sender.userId)
|
||||||
|
} else {
|
||||||
|
message.reply("你不许用echo")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -7,24 +7,56 @@
|
|||||||
|
|
||||||
package cn.rtast.fancybot.commands
|
package cn.rtast.fancybot.commands
|
||||||
|
|
||||||
|
import cn.rtast.fancybot.annotations.CommandDescription
|
||||||
import cn.rtast.fancybot.commands
|
import cn.rtast.fancybot.commands
|
||||||
|
import cn.rtast.fancybot.configManager
|
||||||
import cn.rtast.rob.entity.GroupMessage
|
import cn.rtast.rob.entity.GroupMessage
|
||||||
|
import cn.rtast.rob.onebot.MessageChain
|
||||||
|
import cn.rtast.rob.onebot.NodeMessageChain
|
||||||
import cn.rtast.rob.util.BaseCommand
|
import cn.rtast.rob.util.BaseCommand
|
||||||
import cn.rtast.rob.util.ob.MessageChain
|
import kotlin.reflect.full.findAnnotation
|
||||||
import cn.rtast.rob.util.ob.OneBotListener
|
import kotlin.reflect.full.hasAnnotation
|
||||||
|
|
||||||
|
@CommandDescription("帮助")
|
||||||
class HelpCommand : BaseCommand() {
|
class HelpCommand : BaseCommand() {
|
||||||
override val commandNames = listOf("/help", "/帮助")
|
override val commandNames = listOf("/help", "/帮助")
|
||||||
|
|
||||||
override suspend fun executeGroup(listener: OneBotListener, message: GroupMessage, args: List<String>) {
|
override suspend fun executeGroup(message: GroupMessage, args: List<String>) {
|
||||||
val allCommands = commands.joinToString("\n") {
|
if (args.isEmpty()) {
|
||||||
"[${it.javaClass.name.split(".").last().replace("Command", "")}] 命令:${it.commandNames.joinToString(",")}"
|
val node = NodeMessageChain.Builder()
|
||||||
}
|
|
||||||
val msg = MessageChain.Builder()
|
val msg = MessageChain.Builder()
|
||||||
.addAt(message.sender.userId)
|
commands.sortedBy { it::class.simpleName }.toMutableList().forEach {
|
||||||
|
val description = if (!it::class.hasAnnotation<CommandDescription>()) "暂无描述"
|
||||||
|
else it::class.findAnnotation<CommandDescription>()?.description!!
|
||||||
|
val commandName = it::class.simpleName?.replace("Command", "")!!
|
||||||
|
val commandNames = it.commandNames.joinToString(",")
|
||||||
|
msg.addText("[$commandName] [$description] 命令: $commandNames").addNewLine()
|
||||||
|
}
|
||||||
|
msg.addText("共计${commands.size}条命令")
|
||||||
|
node.addMessageChain(
|
||||||
|
MessageChain.Builder().addText("你可以使用`/help <指令>`来获取这个指令的帮助信息").build(),
|
||||||
|
configManager.selfId
|
||||||
|
)
|
||||||
|
node.addMessageChain(msg.build(), configManager.selfId)
|
||||||
|
message.reply(node.build())
|
||||||
|
} else {
|
||||||
|
val commandName = args.first().replace("/", "")
|
||||||
|
val matchedCommand = commands.find {
|
||||||
|
it.commandNames.map { map -> map.replace("/", "").lowercase() }.contains(commandName)
|
||||||
|
}
|
||||||
|
if (matchedCommand == null) {
|
||||||
|
message.reply("未查询到该命令")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val description = matchedCommand::class.findAnnotation<CommandDescription>()?.description ?: "暂无描述"
|
||||||
|
val msg = MessageChain.Builder()
|
||||||
|
.addText("类名: ${matchedCommand::class.simpleName}")
|
||||||
.addNewLine()
|
.addNewLine()
|
||||||
.addText(allCommands)
|
.addText("指令: ${matchedCommand.commandNames.joinToString(",")}")
|
||||||
|
.addNewLine()
|
||||||
|
.addText("描述: $description")
|
||||||
.build()
|
.build()
|
||||||
listener.sendGroupMessage(message.groupId, msg)
|
message.reply(msg)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -8,16 +8,19 @@
|
|||||||
package cn.rtast.fancybot.commands
|
package cn.rtast.fancybot.commands
|
||||||
|
|
||||||
import cn.rtast.fancybot.START_UP_TIME
|
import cn.rtast.fancybot.START_UP_TIME
|
||||||
|
import cn.rtast.fancybot.annotations.CommandDescription
|
||||||
|
import cn.rtast.fancybot.enums.CommandAction
|
||||||
|
import cn.rtast.fancybot.util.file.insertActionRecord
|
||||||
import cn.rtast.rob.entity.GroupMessage
|
import cn.rtast.rob.entity.GroupMessage
|
||||||
|
import cn.rtast.rob.onebot.MessageChain
|
||||||
import cn.rtast.rob.util.BaseCommand
|
import cn.rtast.rob.util.BaseCommand
|
||||||
import cn.rtast.rob.util.ob.MessageChain
|
|
||||||
import cn.rtast.rob.util.ob.OneBotListener
|
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
|
|
||||||
|
@CommandDescription("状态")
|
||||||
class StatusCommand : BaseCommand() {
|
class StatusCommand : BaseCommand() {
|
||||||
override val commandNames = listOf("/status")
|
override val commandNames = listOf("/status")
|
||||||
|
|
||||||
override suspend fun executeGroup(listener: OneBotListener, message: GroupMessage, args: List<String>) {
|
override suspend fun executeGroup(message: GroupMessage, args: List<String>) {
|
||||||
val runtime = Runtime.getRuntime()
|
val runtime = Runtime.getRuntime()
|
||||||
val maxMemory = runtime.maxMemory() / (1024 * 1024)
|
val maxMemory = runtime.maxMemory() / (1024 * 1024)
|
||||||
val allocatedMemory = runtime.totalMemory() / (1024 * 1024)
|
val allocatedMemory = runtime.totalMemory() / (1024 * 1024)
|
||||||
@@ -42,5 +45,6 @@ class StatusCommand : BaseCommand() {
|
|||||||
.addText("Java版本: $javaVersion / Kotlin版本: $kotlinVersion")
|
.addText("Java版本: $javaVersion / Kotlin版本: $kotlinVersion")
|
||||||
.build()
|
.build()
|
||||||
message.reply(msg)
|
message.reply(msg)
|
||||||
|
insertActionRecord(CommandAction.Status, message.sender.userId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2024 RTAkland
|
||||||
|
* Author: RTAkland
|
||||||
|
* Date: 2024/10/7
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
package cn.rtast.fancybot.commands
|
||||||
|
|
||||||
|
import cn.rtast.fancybot.ASSETS_BASE_URL
|
||||||
|
import cn.rtast.fancybot.annotations.CommandDescription
|
||||||
|
import cn.rtast.fancybot.util.str.encodeToBase64
|
||||||
|
import cn.rtast.rob.entity.GroupMessage
|
||||||
|
import cn.rtast.rob.onebot.MessageChain
|
||||||
|
import cn.rtast.rob.util.BaseCommand
|
||||||
|
import java.net.URI
|
||||||
|
|
||||||
|
@CommandDescription("给我打钱!")
|
||||||
|
class SupportMeCommand : BaseCommand() {
|
||||||
|
override val commandNames = listOf("打钱", "给我打钱", "给满子打钱")
|
||||||
|
|
||||||
|
override suspend fun executeGroup(message: GroupMessage, args: List<String>, matchedCommand: String) {
|
||||||
|
if (matchedCommand == "给满子打钱") {
|
||||||
|
message.reply("你打牛魔呢?")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val image = URI("$ASSETS_BASE_URL/images/048cc8af57f19850ca176f29e50b6215.png")
|
||||||
|
.toURL().readBytes().encodeToBase64()
|
||||||
|
val msg = MessageChain.Builder()
|
||||||
|
.addImage(image, true)
|
||||||
|
.build()
|
||||||
|
message.reply(msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,31 +7,37 @@
|
|||||||
|
|
||||||
package cn.rtast.fancybot.commands.lookup
|
package cn.rtast.fancybot.commands.lookup
|
||||||
|
|
||||||
|
import cn.rtast.fancybot.annotations.CommandDescription
|
||||||
import cn.rtast.fancybot.configManager
|
import cn.rtast.fancybot.configManager
|
||||||
import cn.rtast.fancybot.entity.gpt.ChatCompletionsPayload
|
import cn.rtast.fancybot.entity.gpt.ChatCompletionsPayload
|
||||||
import cn.rtast.fancybot.entity.gpt.ChatCompletionsResponse
|
import cn.rtast.fancybot.entity.gpt.ChatCompletionsResponse
|
||||||
|
import cn.rtast.fancybot.entity.gpt.LlamaResponse
|
||||||
import cn.rtast.fancybot.entity.gpt.ModelList
|
import cn.rtast.fancybot.entity.gpt.ModelList
|
||||||
|
import cn.rtast.fancybot.enums.CommandAction
|
||||||
import cn.rtast.fancybot.util.Http
|
import cn.rtast.fancybot.util.Http
|
||||||
|
import cn.rtast.fancybot.util.file.insertActionRecord
|
||||||
import cn.rtast.fancybot.util.str.toJson
|
import cn.rtast.fancybot.util.str.toJson
|
||||||
import cn.rtast.rob.entity.GroupMessage
|
import cn.rtast.rob.entity.GroupMessage
|
||||||
|
import cn.rtast.rob.onebot.MessageChain
|
||||||
|
import cn.rtast.rob.onebot.NodeMessageChain
|
||||||
import cn.rtast.rob.util.BaseCommand
|
import cn.rtast.rob.util.BaseCommand
|
||||||
import cn.rtast.rob.util.ob.MessageChain
|
|
||||||
import cn.rtast.rob.util.ob.OneBotListener
|
|
||||||
|
|
||||||
|
@CommandDescription("问AI(GPT)")
|
||||||
class AICommand : BaseCommand() {
|
class AICommand : BaseCommand() {
|
||||||
override val commandNames = listOf("/ai", "问AI")
|
override val commandNames = listOf("/ai")
|
||||||
|
|
||||||
override suspend fun executeGroup(listener: OneBotListener, message: GroupMessage, args: List<String>) {
|
private val openAIModel = configManager.openAIModel
|
||||||
|
|
||||||
|
override suspend fun executeGroup(message: GroupMessage, args: List<String>) {
|
||||||
if (args.isEmpty()) {
|
if (args.isEmpty()) {
|
||||||
val msg = MessageChain.Builder()
|
val msg = MessageChain.Builder()
|
||||||
.addAt(message.sender.userId)
|
|
||||||
.addText("发送`/ai [模型] <问题>`即可询问AI哦~")
|
.addText("发送`/ai [模型] <问题>`即可询问AI哦~")
|
||||||
.addNewLine()
|
.addNewLine()
|
||||||
.addText("不指定模型默认为`moonshot-v1-8k`")
|
.addText("不指定模型默认为从配置文件中读取 >>>${openAIModel}")
|
||||||
.addNewLine()
|
.addNewLine()
|
||||||
.addText("发送`/ai list`可以获取可用的模型列表~")
|
.addText("发送`/ai list`可以获取可用的模型列表~")
|
||||||
.build()
|
.build()
|
||||||
listener.sendGroupMessage(message.groupId, msg)
|
message.reply(msg)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -42,27 +48,54 @@ class AICommand : BaseCommand() {
|
|||||||
)
|
)
|
||||||
val modelsString = models.data.joinToString(", ") { it.id }
|
val modelsString = models.data.joinToString(", ") { it.id }
|
||||||
val msg = MessageChain.Builder()
|
val msg = MessageChain.Builder()
|
||||||
.addReply(message.messageId)
|
|
||||||
.addText("可用的模型列表如下: ")
|
.addText("可用的模型列表如下: ")
|
||||||
.addNewLine()
|
.addNewLine()
|
||||||
.addText(modelsString)
|
.addText(modelsString)
|
||||||
.build()
|
.build()
|
||||||
listener.sendGroupMessage(message.groupId, msg)
|
message.reply(msg)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
val model = if (args.size == 1) "moonshot-v1-8k" else args.first()
|
val model = if (args.size == 1) openAIModel else args.first()
|
||||||
val content = if (args.size == 1) args.joinToString(" ") else args.drop(1).joinToString(" ")
|
val content = if (args.size == 1) args.joinToString(" ") else args.drop(1).joinToString(" ")
|
||||||
val messages = ChatCompletionsPayload(model, listOf(ChatCompletionsPayload.Message(content)))
|
val messages = ChatCompletionsPayload(model, listOf(ChatCompletionsPayload.Message(content)))
|
||||||
val response = Http.post<ChatCompletionsResponse>(
|
val response = Http.post<ChatCompletionsResponse>(
|
||||||
"${configManager.openAIAPIHost}/v1/chat/completions",
|
"${configManager.openAIAPIHost}/v1/chat/completions", messages.toJson(),
|
||||||
messages.toJson(),
|
|
||||||
mapOf("Authorization" to "Bearer ${configManager.openAIAPIKey}")
|
mapOf("Authorization" to "Bearer ${configManager.openAIAPIKey}")
|
||||||
)
|
)
|
||||||
|
val nodeMsg = NodeMessageChain.Builder()
|
||||||
val msg = MessageChain.Builder()
|
val msg = MessageChain.Builder()
|
||||||
.addReply(message.messageId)
|
|
||||||
.addText(response.choices.first().message.content)
|
.addText(response.choices.first().message.content)
|
||||||
.build()
|
.build()
|
||||||
listener.sendGroupMessage(message.groupId, msg)
|
nodeMsg.addMessageChain(msg, configManager.selfId)
|
||||||
|
message.action.sendGroupForwardMsg(message.groupId, nodeMsg.build())
|
||||||
|
insertActionRecord(CommandAction.AI, message.sender.userId, "$content-$model-GPT")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@CommandDescription("问AI(LLAMA)")
|
||||||
|
class LlamaCommand : BaseCommand() {
|
||||||
|
override val commandNames = listOf("/llama")
|
||||||
|
|
||||||
|
private val llamaURL = configManager.llamaUrl
|
||||||
|
private val llamaModel = configManager.llamaModel
|
||||||
|
|
||||||
|
override suspend fun executeGroup(message: GroupMessage, args: List<String>) {
|
||||||
|
if (args.isEmpty()) {
|
||||||
|
message.reply("发送`/llama <问题>`即可使用llama模型来回复")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val prompt = args.joinToString(" ")
|
||||||
|
val payload = ChatCompletionsPayload(llamaModel, listOf(ChatCompletionsPayload.Message(prompt)))
|
||||||
|
val response = Http.post<LlamaResponse>("$llamaURL/api/chat", payload.toJson())
|
||||||
|
val nodeMsg = NodeMessageChain.Builder()
|
||||||
|
val msg = MessageChain.Builder()
|
||||||
|
.addText("AI回复如下:")
|
||||||
|
.addNewLine()
|
||||||
|
.addText(response.message.content)
|
||||||
|
.build()
|
||||||
|
nodeMsg.addMessageChain(msg, configManager.selfId)
|
||||||
|
message.action.sendGroupForwardMsg(message.groupId, nodeMsg.build())
|
||||||
|
insertActionRecord(CommandAction.AI, message.sender.userId, "$prompt-LLAMA")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2024 RTAkland
|
||||||
|
* Author: RTAkland
|
||||||
|
* Date: 2024/9/24
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
package cn.rtast.fancybot.commands.lookup
|
||||||
|
|
||||||
|
import cn.rtast.fancybot.annotations.CommandDescription
|
||||||
|
import cn.rtast.fancybot.configManager
|
||||||
|
import cn.rtast.fancybot.entity.bgm.BGMSearch
|
||||||
|
import cn.rtast.fancybot.util.Http
|
||||||
|
import cn.rtast.fancybot.util.str.encodeToBase64
|
||||||
|
import cn.rtast.rob.entity.GroupMessage
|
||||||
|
import cn.rtast.rob.onebot.MessageChain
|
||||||
|
import cn.rtast.rob.onebot.NodeMessageChain
|
||||||
|
import cn.rtast.rob.util.BaseCommand
|
||||||
|
import okhttp3.OkHttpClient
|
||||||
|
import okhttp3.Request
|
||||||
|
|
||||||
|
@CommandDescription("搜索动漫(Bangumi.tv)")
|
||||||
|
class AnimeSearchCommand : BaseCommand() {
|
||||||
|
override val commandNames = listOf("/dm", "动漫")
|
||||||
|
|
||||||
|
private val client = OkHttpClient()
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val API_URL = "https://api.bgm.tv/search/subject/#{}?type=2&responseGroup=small"
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun followRedirect(url: String): ByteArray {
|
||||||
|
val request = Request.Builder().url(url).build()
|
||||||
|
client.newCall(request).execute().use { response ->
|
||||||
|
return response.body.bytes()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun executeGroup(message: GroupMessage, args: List<String>) {
|
||||||
|
if (args.isEmpty()) {
|
||||||
|
message.reply("发送`/dm <关键词>`即可搜索番剧啦~")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
val keyword = args.joinToString(" ")
|
||||||
|
val response = Http.get<BGMSearch>(API_URL.replace("#{}", keyword)).list
|
||||||
|
val nodeMsg = NodeMessageChain.Builder()
|
||||||
|
response.asSequence().take(5).forEach {
|
||||||
|
val imageBase64 = this.followRedirect(it.images.large).encodeToBase64()
|
||||||
|
val tempMsg = MessageChain.Builder()
|
||||||
|
.addImage(imageBase64, true)
|
||||||
|
.addText("${it.name} | ${it.nameCN}")
|
||||||
|
.addNewLine()
|
||||||
|
.addText(it.url)
|
||||||
|
.build()
|
||||||
|
nodeMsg.addMessageChain(tempMsg, configManager.selfId)
|
||||||
|
}
|
||||||
|
val footerNode = MessageChain.Builder().addText("数据来源: Bangumi").build()
|
||||||
|
nodeMsg.addMessageChain(footerNode, configManager.selfId)
|
||||||
|
message.action.sendGroupForwardMsg(message.groupId, nodeMsg.build())
|
||||||
|
} catch (_: Exception) {
|
||||||
|
message.reply("没有搜索到结果呢~")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,32 +7,31 @@
|
|||||||
|
|
||||||
package cn.rtast.fancybot.commands.lookup
|
package cn.rtast.fancybot.commands.lookup
|
||||||
|
|
||||||
|
import cn.rtast.fancybot.annotations.CommandDescription
|
||||||
|
import cn.rtast.fancybot.configManager
|
||||||
import cn.rtast.fancybot.entity.cigarette.Cigarette
|
import cn.rtast.fancybot.entity.cigarette.Cigarette
|
||||||
import cn.rtast.fancybot.util.Http
|
import cn.rtast.fancybot.util.Http
|
||||||
import cn.rtast.fancybot.util.str.encodeToBase64
|
import cn.rtast.fancybot.util.str.encodeToBase64
|
||||||
import cn.rtast.rob.entity.GroupMessage
|
import cn.rtast.rob.entity.GroupMessage
|
||||||
import cn.rtast.rob.segment.Node
|
import cn.rtast.rob.onebot.MessageChain
|
||||||
|
import cn.rtast.rob.onebot.NodeMessageChain
|
||||||
import cn.rtast.rob.util.BaseCommand
|
import cn.rtast.rob.util.BaseCommand
|
||||||
import cn.rtast.rob.util.ob.MessageChain
|
|
||||||
import cn.rtast.rob.util.ob.NodeMessageChain
|
|
||||||
import cn.rtast.rob.util.ob.OneBotListener
|
|
||||||
import java.net.URI
|
import java.net.URI
|
||||||
|
|
||||||
|
@CommandDescription("查询香烟价格")
|
||||||
class CigaretteCommand : BaseCommand() {
|
class CigaretteCommand : BaseCommand() {
|
||||||
override val commandNames = listOf("/香烟", "/tobacco", "/cigarette")
|
override val commandNames = listOf("/tobacco")
|
||||||
|
|
||||||
private val apiUrl = "https://www.yanyue.cn/api/rc/product/yanlist"
|
private val apiUrl = "https://www.yanyue.cn/api/rc/product/yanlist"
|
||||||
|
|
||||||
override suspend fun executeGroup(listener: OneBotListener, message: GroupMessage, args: List<String>) {
|
override suspend fun executeGroup(message: GroupMessage, args: List<String>) {
|
||||||
if (args.isEmpty()) {
|
if (args.isEmpty()) {
|
||||||
val msg = MessageChain.Builder()
|
val msg = MessageChain.Builder()
|
||||||
.addAt(message.sender.userId)
|
|
||||||
.addNewLine()
|
|
||||||
.addText("发送/tobacco <名称> [数量] 来搜索结果哦~")
|
.addText("发送/tobacco <名称> [数量] 来搜索结果哦~")
|
||||||
.addNewLine()
|
.addNewLine()
|
||||||
.addText("最多只能显示出10条结果哦, 不指定数量的话默认是3条~")
|
.addText("最多只能显示出10条结果哦, 不指定数量的话默认是3条~")
|
||||||
.build()
|
.build()
|
||||||
listener.sendGroupMessage(message.groupId, msg)
|
message.reply(msg)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
val limit = if (args.size == 1) 3 else if (args.last().toInt() > 10) 3 else args.last().toInt()
|
val limit = if (args.size == 1) 3 else if (args.last().toInt() > 10) 3 else args.last().toInt()
|
||||||
@@ -42,8 +41,7 @@ class CigaretteCommand : BaseCommand() {
|
|||||||
val headerMsg = MessageChain.Builder()
|
val headerMsg = MessageChain.Builder()
|
||||||
.addText("搜索到${result.totalCount}条结果, 仅展示前 $limit 条结果哦~")
|
.addText("搜索到${result.totalCount}条结果, 仅展示前 $limit 条结果哦~")
|
||||||
.build()
|
.build()
|
||||||
val headerNode = Node(Node.Data("", message.userId.toString(), headerMsg.finalArrayMsgList))
|
nodeMsg.addMessageChain(headerMsg, message.sender.userId)
|
||||||
nodeMsg.addNode(headerNode)
|
|
||||||
result.productList.asSequence().take(limit).forEach {
|
result.productList.asSequence().take(limit).forEach {
|
||||||
val imageBase64 = URI(it.cover).toURL().readBytes().encodeToBase64()
|
val imageBase64 = URI(it.cover).toURL().readBytes().encodeToBase64()
|
||||||
val tempMsg = MessageChain.Builder()
|
val tempMsg = MessageChain.Builder()
|
||||||
@@ -55,14 +53,13 @@ class CigaretteCommand : BaseCommand() {
|
|||||||
.addText("参考价: 单盒: ${it.packPrice}元 | 整条: ${it.barPrice}元")
|
.addText("参考价: 单盒: ${it.packPrice}元 | 整条: ${it.barPrice}元")
|
||||||
.addNewLine()
|
.addNewLine()
|
||||||
.build()
|
.build()
|
||||||
val tempNode = Node(Node.Data("", message.userId.toString(), tempMsg.finalArrayMsgList))
|
nodeMsg.addMessageChain(tempMsg, configManager.selfId)
|
||||||
nodeMsg.addNode(tempNode)
|
|
||||||
}
|
}
|
||||||
val footerMsg = MessageChain.Builder()
|
val footerMsg = MessageChain.Builder()
|
||||||
.addText("吸烟有害健康, 尽早戒烟有益健康。")
|
.addText("吸烟有害健康, 尽早戒烟有益健康。")
|
||||||
.build()
|
.build()
|
||||||
val footerNode = Node(Node.Data("", message.userId.toString(), footerMsg.finalArrayMsgList))
|
nodeMsg.addMessageChain(footerMsg, configManager.selfId)
|
||||||
nodeMsg.addNode(footerNode)
|
message.reply(nodeMsg.build())
|
||||||
listener.sendGroupForwardMsg(message.groupId, nodeMsg.build())
|
message.sender.poke()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -7,22 +7,23 @@
|
|||||||
|
|
||||||
package cn.rtast.fancybot.commands.lookup
|
package cn.rtast.fancybot.commands.lookup
|
||||||
|
|
||||||
|
import cn.rtast.fancybot.annotations.CommandDescription
|
||||||
import cn.rtast.fancybot.entity.domain.PricePayload
|
import cn.rtast.fancybot.entity.domain.PricePayload
|
||||||
import cn.rtast.fancybot.entity.domain.PriceResponse
|
import cn.rtast.fancybot.entity.domain.PriceResponse
|
||||||
import cn.rtast.fancybot.util.Http
|
import cn.rtast.fancybot.util.Http
|
||||||
|
import cn.rtast.fancybot.util.misc.toByteArray
|
||||||
import cn.rtast.fancybot.util.str.encodeToBase64
|
import cn.rtast.fancybot.util.str.encodeToBase64
|
||||||
import cn.rtast.fancybot.util.str.toJson
|
import cn.rtast.fancybot.util.str.toJson
|
||||||
import cn.rtast.fancybot.util.toByteArray
|
|
||||||
import cn.rtast.rob.entity.GroupMessage
|
import cn.rtast.rob.entity.GroupMessage
|
||||||
|
import cn.rtast.rob.onebot.MessageChain
|
||||||
import cn.rtast.rob.util.BaseCommand
|
import cn.rtast.rob.util.BaseCommand
|
||||||
import cn.rtast.rob.util.ob.MessageChain
|
|
||||||
import cn.rtast.rob.util.ob.OneBotListener
|
|
||||||
import java.awt.Color
|
import java.awt.Color
|
||||||
import java.awt.Font
|
import java.awt.Font
|
||||||
import java.awt.image.BufferedImage
|
import java.awt.image.BufferedImage
|
||||||
|
|
||||||
|
@CommandDescription("查询域名价格")
|
||||||
class DomainPriceCommand : BaseCommand() {
|
class DomainPriceCommand : BaseCommand() {
|
||||||
override val commandNames = listOf("/domain")
|
override val commandNames = listOf("/domain", "/dp")
|
||||||
|
|
||||||
private val canvasWidth = 400
|
private val canvasWidth = 400
|
||||||
private val canvasHeight = 300
|
private val canvasHeight = 300
|
||||||
@@ -59,7 +60,7 @@ class DomainPriceCommand : BaseCommand() {
|
|||||||
domain: String,
|
domain: String,
|
||||||
available: Boolean,
|
available: Boolean,
|
||||||
premium: Boolean,
|
premium: Boolean,
|
||||||
domainPrice: Pair<Int, Int>
|
domainPrice: Pair<Int, Int>,
|
||||||
): String {
|
): String {
|
||||||
val canvas = this.createCommonCanvas()
|
val canvas = this.createCommonCanvas()
|
||||||
val g2d = canvas.createGraphics()
|
val g2d = canvas.createGraphics()
|
||||||
@@ -67,7 +68,7 @@ class DomainPriceCommand : BaseCommand() {
|
|||||||
g2d.color = textColor
|
g2d.color = textColor
|
||||||
g2d.drawString("域名$domain${if (available) "可以注册" else "已被注册"}", 50, 110)
|
g2d.drawString("域名$domain${if (available) "可以注册" else "已被注册"}", 50, 110)
|
||||||
g2d.drawString("${if (premium) "是" else "不是"}白金域名", 50, 140)
|
g2d.drawString("${if (premium) "是" else "不是"}白金域名", 50, 140)
|
||||||
g2d.drawString("首年年注册价格: ${domainPrice.first}元", 50, 170)
|
g2d.drawString("首年注册价格: ${domainPrice.first}元", 50, 170)
|
||||||
g2d.drawString("续费价格: ${domainPrice.second}元", 50, 200)
|
g2d.drawString("续费价格: ${domainPrice.second}元", 50, 200)
|
||||||
g2d.drawString("数据来源: 腾讯云", 50, 230)
|
g2d.drawString("数据来源: 腾讯云", 50, 230)
|
||||||
g2d.dispose()
|
g2d.dispose()
|
||||||
@@ -75,13 +76,12 @@ class DomainPriceCommand : BaseCommand() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
override suspend fun executeGroup(listener: OneBotListener, message: GroupMessage, args: List<String>) {
|
override suspend fun executeGroup(message: GroupMessage, args: List<String>) {
|
||||||
if (args.isEmpty()) {
|
if (args.isEmpty()) {
|
||||||
val msg = MessageChain.Builder()
|
val msg = MessageChain.Builder()
|
||||||
.addAt(message.sender.userId)
|
|
||||||
.addText("发送`/domain <域名>`即可查询对应的注册和续费价格~")
|
.addText("发送`/domain <域名>`即可查询对应的注册和续费价格~")
|
||||||
.build()
|
.build()
|
||||||
listener.sendGroupMessage(message.groupId, msg)
|
message.reply(msg)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
val suffix = args.first()
|
val suffix = args.first()
|
||||||
@@ -101,10 +101,7 @@ class DomainPriceCommand : BaseCommand() {
|
|||||||
} else {
|
} else {
|
||||||
this.createDomainPriceCard(suffix, response.realPrice to response.price)
|
this.createDomainPriceCard(suffix, response.realPrice to response.price)
|
||||||
}
|
}
|
||||||
val msg = MessageChain.Builder()
|
val msg = MessageChain.Builder().addImage(cardImage, true).build()
|
||||||
.addAt(message.sender.userId)
|
message.reply(msg)
|
||||||
.addImage(cardImage, true)
|
|
||||||
.build()
|
|
||||||
listener.sendGroupMessage(message.groupId, msg)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2024 RTAkland
|
||||||
|
* Author: RTAkland
|
||||||
|
* Date: 2024/10/3
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
package cn.rtast.fancybot.commands.lookup
|
||||||
|
|
||||||
|
import cn.rtast.fancybot.annotations.CommandDescription
|
||||||
|
import cn.rtast.fancybot.commands.parse.GitHubParseCommand
|
||||||
|
import cn.rtast.fancybot.configManager
|
||||||
|
import cn.rtast.fancybot.entity.github.LatestCommit
|
||||||
|
import cn.rtast.fancybot.util.Http
|
||||||
|
import cn.rtast.fancybot.util.str.fromArrayJson
|
||||||
|
import cn.rtast.rob.entity.GroupMessage
|
||||||
|
import cn.rtast.rob.onebot.MessageChain
|
||||||
|
import cn.rtast.rob.util.BaseCommand
|
||||||
|
|
||||||
|
@CommandDescription("查询Github上的仓库的最新一次的提交信息")
|
||||||
|
class GithubLatestCommitCommand : BaseCommand() {
|
||||||
|
override val commandNames = listOf(".commit")
|
||||||
|
|
||||||
|
private val userInfoUrl = "https://api.github.com/repos"
|
||||||
|
|
||||||
|
override suspend fun executeGroup(message: GroupMessage, args: List<String>) {
|
||||||
|
if (args.isEmpty()) {
|
||||||
|
message.reply("发送`.commit <用户名/仓库名>`即可查询仓库最新一次的提交信息")
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
val (user, repo) = if (args.size == 1) {
|
||||||
|
args.first().split("/").first() to args.first().split("/").last()
|
||||||
|
} else {
|
||||||
|
args.first() to args.last()
|
||||||
|
}
|
||||||
|
val response = Http.get(
|
||||||
|
"$userInfoUrl/$user/$repo/commits",
|
||||||
|
headers = mapOf("Authorization" to configManager.githubKey)
|
||||||
|
).fromArrayJson<List<LatestCommit>>().first()
|
||||||
|
val image = GitHubParseCommand.creatRepoImage(user, repo)
|
||||||
|
val msg = MessageChain.Builder()
|
||||||
|
.addImage(image, true)
|
||||||
|
.addText("最新提交ID: ${response.sha.substring(0, 7)}")
|
||||||
|
.addNewLine()
|
||||||
|
.addText("提交者: ${response.commit.committer.name}(${response.commit.committer.email})")
|
||||||
|
.addNewLine()
|
||||||
|
.addText("提交日期: ${response.commit.committer.date}")
|
||||||
|
.addNewLine()
|
||||||
|
.addText("https://github.com/$user/$repo")
|
||||||
|
.build()
|
||||||
|
message.reply(msg)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
message.reply("查询失败~")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,25 +7,26 @@
|
|||||||
|
|
||||||
package cn.rtast.fancybot.commands.lookup
|
package cn.rtast.fancybot.commands.lookup
|
||||||
|
|
||||||
|
import cn.rtast.fancybot.annotations.CommandDescription
|
||||||
import cn.rtast.fancybot.configManager
|
import cn.rtast.fancybot.configManager
|
||||||
import cn.rtast.fancybot.entity.github.UserInfo
|
import cn.rtast.fancybot.entity.github.UserInfo
|
||||||
import cn.rtast.fancybot.util.Http
|
import cn.rtast.fancybot.util.Http
|
||||||
import cn.rtast.fancybot.util.drawCustomImage
|
import cn.rtast.fancybot.util.misc.drawCustomImage
|
||||||
import cn.rtast.fancybot.util.drawString
|
import cn.rtast.fancybot.util.misc.drawString
|
||||||
|
import cn.rtast.fancybot.util.misc.toBufferedImage
|
||||||
|
import cn.rtast.fancybot.util.misc.toByteArray
|
||||||
import cn.rtast.fancybot.util.str.encodeToBase64
|
import cn.rtast.fancybot.util.str.encodeToBase64
|
||||||
import cn.rtast.fancybot.util.toBufferedImage
|
|
||||||
import cn.rtast.fancybot.util.toByteArray
|
|
||||||
import cn.rtast.rob.entity.GroupMessage
|
import cn.rtast.rob.entity.GroupMessage
|
||||||
|
import cn.rtast.rob.onebot.MessageChain
|
||||||
import cn.rtast.rob.util.BaseCommand
|
import cn.rtast.rob.util.BaseCommand
|
||||||
import cn.rtast.rob.util.ob.MessageChain
|
|
||||||
import cn.rtast.rob.util.ob.OneBotListener
|
|
||||||
import java.awt.Color
|
import java.awt.Color
|
||||||
import java.awt.Font
|
import java.awt.Font
|
||||||
import java.awt.image.BufferedImage
|
import java.awt.image.BufferedImage
|
||||||
import java.net.URI
|
import java.net.URI
|
||||||
|
|
||||||
|
@CommandDescription("获取Github用户信息")
|
||||||
class GithubUserCommand : BaseCommand() {
|
class GithubUserCommand : BaseCommand() {
|
||||||
override val commandNames = listOf("/gh", "/github", "gh")
|
override val commandNames = listOf("/gh")
|
||||||
|
|
||||||
private val userInfoUrl = "https://api.github.com/users"
|
private val userInfoUrl = "https://api.github.com/users"
|
||||||
private val backgroundColor = Color(255, 255, 240)
|
private val backgroundColor = Color(255, 255, 240)
|
||||||
@@ -65,13 +66,10 @@ class GithubUserCommand : BaseCommand() {
|
|||||||
return canvas.toByteArray().encodeToBase64()
|
return canvas.toByteArray().encodeToBase64()
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun executeGroup(listener: OneBotListener, message: GroupMessage, args: List<String>) {
|
override suspend fun executeGroup(message: GroupMessage, args: List<String>) {
|
||||||
if (args.isEmpty()) {
|
if (args.isEmpty()) {
|
||||||
val msg = MessageChain.Builder()
|
val msg = MessageChain.Builder().addText("发送`gh <用户名>`即可查询用户的信息~").build()
|
||||||
.addAt(message.sender.userId)
|
message.reply(msg)
|
||||||
.addText("发送`gh <用户名>`即可查询用户的信息~")
|
|
||||||
.build()
|
|
||||||
listener.sendGroupMessage(message.groupId, msg)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
val username = args.first()
|
val username = args.first()
|
||||||
@@ -80,10 +78,7 @@ class GithubUserCommand : BaseCommand() {
|
|||||||
headers = mapOf("Authorization" to configManager.githubKey)
|
headers = mapOf("Authorization" to configManager.githubKey)
|
||||||
)
|
)
|
||||||
val image = this.createUserInfoCard(userInfo)
|
val image = this.createUserInfoCard(userInfo)
|
||||||
val msg = MessageChain.Builder()
|
val msg = MessageChain.Builder().addImage(image, true).build()
|
||||||
.addReply(message.messageId)
|
message.reply(msg)
|
||||||
.addImage(image, true)
|
|
||||||
.build()
|
|
||||||
listener.sendGroupMessage(message.groupId, msg)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2024 RTAkland
|
||||||
|
* Author: RTAkland
|
||||||
|
* Date: 2024/10/14
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
package cn.rtast.fancybot.commands.lookup
|
||||||
|
|
||||||
|
import cn.rtast.fancybot.annotations.CommandDescription
|
||||||
|
import cn.rtast.fancybot.util.misc.toURL
|
||||||
|
import cn.rtast.fancybot.util.str.encodeToBase64
|
||||||
|
import cn.rtast.fancybot.util.str.getMD5
|
||||||
|
import cn.rtast.rob.entity.GroupMessage
|
||||||
|
import cn.rtast.rob.onebot.MessageChain
|
||||||
|
import cn.rtast.rob.util.BaseCommand
|
||||||
|
|
||||||
|
@CommandDescription("查询用户的Gravatar头像")
|
||||||
|
class GravatarCommand : BaseCommand() {
|
||||||
|
override val commandNames = listOf("/g", "/gravatar")
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val GRAVATAR_URL = "https://gravatar.rtast.cn/avatar"
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun executeGroup(message: GroupMessage, args: List<String>) {
|
||||||
|
val emailMD5 = if (args.first().trim().lowercase().contains("@")) args.first().trim().lowercase().getMD5()
|
||||||
|
else args.first().trim().lowercase()
|
||||||
|
val avatarImage = "$GRAVATAR_URL/$emailMD5?size=256".toURL().readBytes().encodeToBase64()
|
||||||
|
val msg = MessageChain.Builder().addImage(avatarImage, true).build()
|
||||||
|
message.reply(msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2024 RTAkland
|
||||||
|
* Author: RTAkland
|
||||||
|
* Date: 2024/10/10
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
package cn.rtast.fancybot.commands.lookup
|
||||||
|
|
||||||
|
import cn.rtast.fancybot.annotations.CommandDescription
|
||||||
|
import cn.rtast.fancybot.configManager
|
||||||
|
import cn.rtast.fancybot.entity.apispace.IdiomExplainResponse
|
||||||
|
import cn.rtast.fancybot.util.Http
|
||||||
|
import cn.rtast.rob.entity.GroupMessage
|
||||||
|
import cn.rtast.rob.onebot.MessageChain
|
||||||
|
import cn.rtast.rob.util.BaseCommand
|
||||||
|
|
||||||
|
@CommandDescription("解释一个成语")
|
||||||
|
class IdiomExplainCommand : BaseCommand() {
|
||||||
|
override val commandNames = listOf("成语解释")
|
||||||
|
|
||||||
|
private val apiSpaceUrl = "https://eolink.o.apispace.com/cyudac/api/v1/idioms/SearchIdiomsByPinyin/search"
|
||||||
|
|
||||||
|
override suspend fun executeGroup(message: GroupMessage, args: List<String>) {
|
||||||
|
if (args.isEmpty()) {
|
||||||
|
message.reply("发送`成语解释 <成语>`就能解释这个成语的意思了")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
val idiom = args.joinToString(" ").trim()
|
||||||
|
val response = Http.get<IdiomExplainResponse>(
|
||||||
|
apiSpaceUrl,
|
||||||
|
mapOf("name" to idiom, "search_type" to "name"),
|
||||||
|
mapOf("X-APISpace-Token" to configManager.apiSpaceKey)
|
||||||
|
).data.first()
|
||||||
|
val msg = MessageChain.Builder()
|
||||||
|
.addText("成语: ${response.name} 的解释如下")
|
||||||
|
.addNewLine()
|
||||||
|
.addText(response.explanation)
|
||||||
|
.addNewLine(2)
|
||||||
|
.addText(response.provenance)
|
||||||
|
.addNewLine(2)
|
||||||
|
.addText(response.sound)
|
||||||
|
.build()
|
||||||
|
message.reply(msg)
|
||||||
|
} catch (_: Exception) {
|
||||||
|
message.reply("这个词似乎不是一个成语呢~~")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,66 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright © 2024 RTAkland
|
|
||||||
* Author: RTAkland
|
|
||||||
* Date: 2024/9/3
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
package cn.rtast.fancybot.commands.lookup
|
|
||||||
|
|
||||||
import cn.rtast.fancybot.entity.MCPing
|
|
||||||
import cn.rtast.fancybot.util.str.fromJson
|
|
||||||
import cn.rtast.motdpinger.MotdPinger
|
|
||||||
import cn.rtast.rob.entity.GroupMessage
|
|
||||||
import cn.rtast.rob.util.BaseCommand
|
|
||||||
import cn.rtast.rob.util.ob.MessageChain
|
|
||||||
import cn.rtast.rob.util.ob.OneBotListener
|
|
||||||
|
|
||||||
class MCPingCommand : BaseCommand() {
|
|
||||||
override val commandNames = listOf("/mcping", "/mcPing")
|
|
||||||
|
|
||||||
private val pingInstance = MotdPinger()
|
|
||||||
|
|
||||||
override suspend fun executeGroup(listener: OneBotListener, message: GroupMessage, args: List<String>) {
|
|
||||||
if (args.isEmpty()) {
|
|
||||||
val msg = MessageChain.Builder()
|
|
||||||
.addAt(message.sender.userId)
|
|
||||||
.addNewLine()
|
|
||||||
.addText("使用方法: /mcping <host>:[port]")
|
|
||||||
.addNewLine()
|
|
||||||
.addText("仅限Java版服务器哦~")
|
|
||||||
.build()
|
|
||||||
listener.sendGroupMessage(message.groupId, msg)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
val parts = args.first().split(":")
|
|
||||||
val host: String
|
|
||||||
val port: Int
|
|
||||||
if (parts.size == 2) {
|
|
||||||
host = parts[0]
|
|
||||||
port = parts[1].toIntOrNull() ?: 25565
|
|
||||||
} else {
|
|
||||||
host = args.first()
|
|
||||||
port = 25565
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
val rawResponse = pingInstance.pingServer(host, port)
|
|
||||||
val jsonResponse = rawResponse?.fromJson<MCPing>()!!
|
|
||||||
val msg = MessageChain.Builder().addAt(message.sender.userId).addNewLine()
|
|
||||||
if (jsonResponse.favicon != null) msg.addImage(jsonResponse.favicon, true)
|
|
||||||
msg.addText("服务器地址: $host:$port")
|
|
||||||
msg.addNewLine()
|
|
||||||
msg.addText("协议版本号: ${jsonResponse.version.protocol}/${jsonResponse.version.name}")
|
|
||||||
msg.addNewLine()
|
|
||||||
msg.addText("玩家: ${jsonResponse.players.online}/${jsonResponse.players.max}")
|
|
||||||
listener.sendGroupMessage(message.groupId, msg.build())
|
|
||||||
} catch (_: Exception) {
|
|
||||||
val msg = MessageChain.Builder()
|
|
||||||
.addAt(message.sender.userId)
|
|
||||||
.addText("ping失败~")
|
|
||||||
.addNewLine()
|
|
||||||
.addText("检查一下地址或者端口是否正确吧~")
|
|
||||||
.build()
|
|
||||||
listener.sendGroupMessage(message.groupId, msg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -7,39 +7,39 @@
|
|||||||
|
|
||||||
package cn.rtast.fancybot.commands.lookup
|
package cn.rtast.fancybot.commands.lookup
|
||||||
|
|
||||||
|
import cn.rtast.fancybot.annotations.CommandDescription
|
||||||
import cn.rtast.fancybot.configManager
|
import cn.rtast.fancybot.configManager
|
||||||
import cn.rtast.fancybot.entity.music.Search
|
import cn.rtast.fancybot.entity.music.Search
|
||||||
import cn.rtast.fancybot.entity.music.SearchedResult
|
import cn.rtast.fancybot.entity.music.SearchedResult
|
||||||
import cn.rtast.fancybot.entity.music.SongUrl
|
import cn.rtast.fancybot.entity.music.SongUrl
|
||||||
|
import cn.rtast.fancybot.entity.music.qq.QQMSearch
|
||||||
import cn.rtast.fancybot.util.Http
|
import cn.rtast.fancybot.util.Http
|
||||||
import cn.rtast.rob.entity.GroupMessage
|
import cn.rtast.rob.entity.GroupMessage
|
||||||
import cn.rtast.rob.enums.MusicShareType
|
import cn.rtast.rob.enums.MusicShareType
|
||||||
|
import cn.rtast.rob.onebot.MessageChain
|
||||||
import cn.rtast.rob.util.BaseCommand
|
import cn.rtast.rob.util.BaseCommand
|
||||||
import cn.rtast.rob.util.ob.MessageChain
|
|
||||||
import cn.rtast.rob.util.ob.OneBotListener
|
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
|
|
||||||
|
@CommandDescription("网易云音乐点歌")
|
||||||
class MusicCommand : BaseCommand() {
|
class MusicCommand : BaseCommand() {
|
||||||
override val commandNames = listOf("/music", "/点歌", "点歌")
|
override val commandNames = listOf("点歌", "music")
|
||||||
|
|
||||||
private val searchedResult = mutableMapOf<Long, List<SearchedResult>>()
|
private val searchedResult = mutableMapOf<Long, List<SearchedResult>>()
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
private val MUSIC_API_URL = configManager.ncmAPI
|
||||||
|
|
||||||
fun searchSong(keyword: String): Search {
|
fun searchSong(keyword: String): Search {
|
||||||
return Http.get<Search>(
|
return Http.get<Search>(
|
||||||
"${configManager.ncmAPI}/search",
|
"$MUSIC_API_URL/search",
|
||||||
mapOf("keywords" to keyword),
|
mapOf("keywords" to keyword),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun legacyMusicCommand(listener: OneBotListener, message: GroupMessage, args: List<String>) {
|
private suspend fun legacyMusicCommand(message: GroupMessage, args: List<String>) {
|
||||||
if (args.isEmpty()) {
|
if (args.isEmpty()) {
|
||||||
val msg = MessageChain.Builder()
|
message.reply("发送`/点歌` <关键词> 来搜索音乐~")
|
||||||
.addAt(message.sender.userId)
|
|
||||||
.addText("发送`/点歌`或者`/music` <关键词> 来搜索音乐~")
|
|
||||||
.build()
|
|
||||||
listener.sendGroupMessage(message.groupId, msg)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
searchedResult.forEach { (key, results) ->
|
searchedResult.forEach { (key, results) ->
|
||||||
@@ -62,13 +62,9 @@ class MusicCommand : BaseCommand() {
|
|||||||
val msg = MessageChain.Builder()
|
val msg = MessageChain.Builder()
|
||||||
.addMusicShare(MusicShareType.Netease, finalResult.id.toString())
|
.addMusicShare(MusicShareType.Netease, finalResult.id.toString())
|
||||||
.build()
|
.build()
|
||||||
listener.sendGroupMessage(message.groupId, msg)
|
message.reply(msg)
|
||||||
} catch (_: Exception) {
|
} catch (_: Exception) {
|
||||||
val msg = MessageChain.Builder()
|
message.reply("输入有误请重新搜索本次搜索结果已清除")
|
||||||
.addAt(message.sender.userId)
|
|
||||||
.addText("输入有误请重新搜索本次搜索结果已清除")
|
|
||||||
.build()
|
|
||||||
listener.sendGroupMessage(message.groupId, msg)
|
|
||||||
}
|
}
|
||||||
searchedResult.remove(message.sender.userId)
|
searchedResult.remove(message.sender.userId)
|
||||||
}
|
}
|
||||||
@@ -76,11 +72,7 @@ class MusicCommand : BaseCommand() {
|
|||||||
else -> {
|
else -> {
|
||||||
if (searchedResult.containsKey(message.sender.userId)) {
|
if (searchedResult.containsKey(message.sender.userId)) {
|
||||||
searchedResult.remove(message.sender.userId)
|
searchedResult.remove(message.sender.userId)
|
||||||
val msg = MessageChain.Builder()
|
message.reply("你上次的搜索结果还没用呢, 已经帮你把上次的搜索结果清除掉啦~")
|
||||||
.addAt(message.sender.userId)
|
|
||||||
.addText("你上次的搜索结果还没用呢, 已经帮你把上次的搜索结果清除掉啦~")
|
|
||||||
.build()
|
|
||||||
listener.sendGroupMessage(message.groupId, msg)
|
|
||||||
}
|
}
|
||||||
val keyword = args.joinToString(" ")
|
val keyword = args.joinToString(" ")
|
||||||
val result = searchSong(keyword)
|
val result = searchSong(keyword)
|
||||||
@@ -95,48 +87,47 @@ class MusicCommand : BaseCommand() {
|
|||||||
stringResult.append("| $index | 《${searchedResult.name}》-- ${searchedResult.artists}\n")
|
stringResult.append("| $index | 《${searchedResult.name}》-- ${searchedResult.artists}\n")
|
||||||
}
|
}
|
||||||
stringResult.append("输入/music p <序号> 播放\n你有30秒的时间进行操作")
|
stringResult.append("输入/music p <序号> 播放\n你有30秒的时间进行操作")
|
||||||
val msg = MessageChain.Builder()
|
message.reply(stringResult.toString())
|
||||||
.addAt(message.sender.userId)
|
|
||||||
.addText(stringResult.toString())
|
|
||||||
.build()
|
|
||||||
listener.sendGroupMessage(message.groupId, msg)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun executeGroup(listener: OneBotListener, message: GroupMessage, args: List<String>) {
|
override suspend fun executeGroup(message: GroupMessage, args: List<String>) {
|
||||||
if (args.last() == "legacy" || args.last() == "l" || args.last() in "0".."4") {
|
if (args.last() == "legacy" || args.last() == "l" || args.last() in "0".."4") {
|
||||||
this.legacyMusicCommand(listener, message, args)
|
this.legacyMusicCommand(message, args)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (args.isEmpty()) {
|
if (args.isEmpty()) {
|
||||||
val msg = MessageChain.Builder()
|
val msg = MessageChain.Builder()
|
||||||
.addAt(message.sender.userId)
|
.addReply(message.messageId)
|
||||||
.addText("发送`点歌 <歌名>`即可点第一首搜索到的歌曲~")
|
.addText("发送`点歌 <歌名>`即可点第一首搜索到的歌曲~")
|
||||||
.addNewLine()
|
.addNewLine()
|
||||||
.addText("发送`点歌 <歌名> [l|legacy]`即可使用旧版点歌系统")
|
.addText("发送`点歌 <歌名> [l|legacy]`即可使用旧版点歌系统")
|
||||||
.build()
|
.build()
|
||||||
listener.sendGroupMessage(message.groupId, msg)
|
message.reply(msg)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
val keyword = args.joinToString(" ")
|
val keyword = args.joinToString(" ")
|
||||||
val result = searchSong(keyword).result.songs.asSequence().first().id
|
val result = searchSong(keyword).result.songs.first().id
|
||||||
val msg = MessageChain.Builder()
|
val msg = MessageChain.Builder()
|
||||||
.addMusicShare(MusicShareType.Netease, result.toString())
|
.addMusicShare(MusicShareType.Netease, result.toString())
|
||||||
.build()
|
.build()
|
||||||
listener.sendGroupMessage(message.groupId, msg)
|
message.action.sendGroupMessage(message.groupId, msg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@CommandDescription("获取网易云音乐链接")
|
||||||
class MusicPlayUrlCommand : BaseCommand() {
|
class MusicPlayUrlCommand : BaseCommand() {
|
||||||
override val commandNames = listOf("/lj", "lj", "song", "/song")
|
override val commandNames = listOf("lj")
|
||||||
|
|
||||||
|
private val musicApiUrl = configManager.ncmAPI
|
||||||
|
|
||||||
private fun getPlayUrl(id: String): String {
|
private fun getPlayUrl(id: String): String {
|
||||||
return Http.get<SongUrl>("${configManager.ncmAPI}/song/url", mapOf("id" to id)).data.first().url
|
return Http.get<SongUrl>("$musicApiUrl/song/url", mapOf("id" to id)).data.first().url
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun executeGroup(listener: OneBotListener, message: GroupMessage, args: List<String>) {
|
override suspend fun executeGroup(message: GroupMessage, args: List<String>) {
|
||||||
val url = if (args.last() == "id" || args.last() == "i") {
|
val url = if (args.last() == "id" || args.last() == "i") {
|
||||||
val id = args.first()
|
val id = args.first()
|
||||||
this.getPlayUrl(id)
|
this.getPlayUrl(id)
|
||||||
@@ -149,6 +140,27 @@ class MusicPlayUrlCommand : BaseCommand() {
|
|||||||
.addReply(message.messageId)
|
.addReply(message.messageId)
|
||||||
.addText(url)
|
.addText(url)
|
||||||
.build()
|
.build()
|
||||||
listener.sendGroupMessage(message.groupId, msg)
|
message.reply(msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@CommandDescription("QQ音乐点歌")
|
||||||
|
class QQMusicCommand : BaseCommand() {
|
||||||
|
override val commandNames = listOf("qm", "/qm")
|
||||||
|
|
||||||
|
private val qqMusicApiUrl = configManager.qqMusicApiUrl
|
||||||
|
|
||||||
|
override suspend fun executeGroup(message: GroupMessage, args: List<String>) {
|
||||||
|
if (args.isEmpty()) {
|
||||||
|
message.reply("发送`/qm <关键词>`即可搜索qq音乐的音乐哦")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val keyword = args.joinToString(" ")
|
||||||
|
val response = Http.get<QQMSearch>(
|
||||||
|
"$qqMusicApiUrl/getSearchByKey",
|
||||||
|
mapOf("key" to keyword)
|
||||||
|
).response.data.song.list.first().songId
|
||||||
|
val msg = MessageChain.Builder().addMusicShare(MusicShareType.QQ, response.toString()).build()
|
||||||
|
message.action.sendGroupMessage(message.groupId, msg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright © 2024 RTAkland
|
|
||||||
* Author: RTAkland
|
|
||||||
* Date: 2024/9/6
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
package cn.rtast.fancybot.commands.lookup
|
|
||||||
|
|
||||||
import cn.rtast.rob.entity.GroupMessage
|
|
||||||
import cn.rtast.rob.util.BaseCommand
|
|
||||||
import cn.rtast.rob.util.ob.MessageChain
|
|
||||||
import cn.rtast.rob.util.ob.OneBotListener
|
|
||||||
import java.net.InetAddress
|
|
||||||
|
|
||||||
class NslookupCommand : BaseCommand() {
|
|
||||||
override val commandNames = listOf("/nslookup", "/ns")
|
|
||||||
|
|
||||||
override suspend fun executeGroup(listener: OneBotListener, message: GroupMessage, args: List<String>) {
|
|
||||||
val msg = MessageChain.Builder()
|
|
||||||
.addReply(message.messageId)
|
|
||||||
.addText("域名: ${args.first()}解析后的IP地址为: ")
|
|
||||||
.addText(InetAddress.getByName(args.first()).hostAddress)
|
|
||||||
.build()
|
|
||||||
listener.sendGroupMessage(message.groupId, msg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,87 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2025 RTAkland
|
||||||
|
* Author: RTAkland
|
||||||
|
* Date: 2025/2/4
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
package cn.rtast.fancybot.commands.lookup
|
||||||
|
|
||||||
|
import cn.rtast.fancybot.annotations.CommandDescription
|
||||||
|
import cn.rtast.fancybot.configManager
|
||||||
|
import cn.rtast.fancybot.entity.osu.OSUAccessToken
|
||||||
|
import cn.rtast.fancybot.entity.osu.OSUUserData
|
||||||
|
import cn.rtast.fancybot.util.Http
|
||||||
|
import cn.rtast.rob.entity.GroupMessage
|
||||||
|
import cn.rtast.rob.onebot.MessageChain
|
||||||
|
import cn.rtast.rob.util.BaseCommand
|
||||||
|
import java.awt.Color
|
||||||
|
import java.awt.RenderingHints
|
||||||
|
import java.awt.image.BufferedImage
|
||||||
|
|
||||||
|
@CommandDescription("osu!")
|
||||||
|
class OSUCommand : BaseCommand() {
|
||||||
|
override val commandNames = listOf("/osu")
|
||||||
|
|
||||||
|
private val clientSecret = configManager.osuClientSecret
|
||||||
|
private val clientId = configManager.osuClientId
|
||||||
|
|
||||||
|
private fun getAccessToken(): String {
|
||||||
|
return Http.post<OSUAccessToken>(
|
||||||
|
"https://osu.ppy.sh/oauth/token",
|
||||||
|
formBody = mapOf(
|
||||||
|
"client_id" to clientId, "client_secret" to clientSecret,
|
||||||
|
"grant_type" to "client_credentials", "scope" to "public"
|
||||||
|
),
|
||||||
|
headers = mapOf("Content-Type" to "application/x-www-form-urlencoded", "Accept" to "application/json")
|
||||||
|
).accessToken
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getUser(username: String): OSUUserData {
|
||||||
|
val token = this.getAccessToken()
|
||||||
|
val resp = Http.get<OSUUserData>(
|
||||||
|
"https://osu.ppy.sh/api/v2/users/$username/osu",
|
||||||
|
headers = mapOf("Authorization" to "Bearer $token"),
|
||||||
|
)
|
||||||
|
return resp
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun generateProgressBar(percent: Int, length: Int = 10): String {
|
||||||
|
val completedLength = (percent * length) / 100
|
||||||
|
val remainingLength = length - completedLength
|
||||||
|
val progressBar = "█".repeat(completedLength) + "=".repeat(remainingLength)
|
||||||
|
return "[$progressBar] $percent%"
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun formatDuration(seconds: Long): String {
|
||||||
|
val days = seconds / (24 * 3600)
|
||||||
|
val hours = (seconds % (24 * 3600)) / 3600
|
||||||
|
val minutes = (seconds % 3600) / 60
|
||||||
|
val parts = mutableListOf<String>()
|
||||||
|
if (days > 0) parts.add("${days}d")
|
||||||
|
if (hours > 0) parts.add("${hours}h")
|
||||||
|
if (minutes > 0) parts.add("${minutes}m")
|
||||||
|
return parts.joinToString(" ")
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun executeGroup(message: GroupMessage, args: List<String>) {
|
||||||
|
val username = args.first()
|
||||||
|
val userData = getUser(username)
|
||||||
|
val msg = MessageChain.Builder()
|
||||||
|
.addText(userData.username)
|
||||||
|
.addNewLine()
|
||||||
|
.addText("等级 | Lv.${userData.statistics.level.current} ${generateProgressBar(userData.statistics.level.progress)}")
|
||||||
|
.addNewLine()
|
||||||
|
.addText("排名 | #${userData.statistics.globalRank} / ${userData.countryCode} #${userData.statistics.countryRank}")
|
||||||
|
.addNewLine()
|
||||||
|
.addText("准确率 | ${userData.statistics.hitAccuracy}%")
|
||||||
|
.addNewLine()
|
||||||
|
.addText("游玩时间 | ${formatDuration(userData.statistics.playTime)}")
|
||||||
|
.addNewLine()
|
||||||
|
.addText("游玩次数 | ${userData.statistics.playCount}")
|
||||||
|
.addNewLine()
|
||||||
|
.addText("表现分/PP | ${userData.statistics.pp.toInt()}")
|
||||||
|
.build()
|
||||||
|
message.reply(msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,48 +7,60 @@
|
|||||||
|
|
||||||
package cn.rtast.fancybot.commands.lookup
|
package cn.rtast.fancybot.commands.lookup
|
||||||
|
|
||||||
|
import cn.rtast.fancybot.annotations.CommandDescription
|
||||||
|
import cn.rtast.fancybot.configManager
|
||||||
import cn.rtast.fancybot.entity.pixiv.Ranking
|
import cn.rtast.fancybot.entity.pixiv.Ranking
|
||||||
import cn.rtast.fancybot.util.Http
|
import cn.rtast.fancybot.util.Http
|
||||||
import cn.rtast.fancybot.util.str.encodeToBase64
|
import cn.rtast.fancybot.util.str.encodeToBase64
|
||||||
import cn.rtast.rob.entity.GroupMessage
|
import cn.rtast.rob.entity.GroupMessage
|
||||||
|
import cn.rtast.rob.onebot.MessageChain
|
||||||
|
import cn.rtast.rob.onebot.NodeMessageChain
|
||||||
import cn.rtast.rob.util.BaseCommand
|
import cn.rtast.rob.util.BaseCommand
|
||||||
import cn.rtast.rob.util.ob.MessageChain
|
|
||||||
import cn.rtast.rob.util.ob.OneBotListener
|
|
||||||
import java.net.URI
|
import java.net.URI
|
||||||
|
|
||||||
|
@CommandDescription("获取Pixiv上的图片")
|
||||||
class PixivCommand : BaseCommand() {
|
class PixivCommand : BaseCommand() {
|
||||||
override val commandNames = listOf("/pixiv", "/p")
|
override val commandNames = listOf("/p")
|
||||||
|
|
||||||
private val pixivRankingURL = "https://proxy.rtast.cn/https/www.pixiv.net/ranking.php?format=json&mode=daily&p=1"
|
private val pixivRankingURL = "https://proxy.rtast.cn/https/www.pixiv.net/ranking.php?format=json&mode=daily&p=1"
|
||||||
private val imageProxyURL = "https://pixiv.re"
|
private val imageProxyURL = "https://pixiv.re"
|
||||||
|
|
||||||
override suspend fun executeGroup(listener: OneBotListener, message: GroupMessage, args: List<String>) {
|
override suspend fun executeGroup(message: GroupMessage, args: List<String>) {
|
||||||
if (args.isEmpty()) {
|
if (args.isEmpty()) {
|
||||||
val msg = MessageChain.Builder()
|
val msg = MessageChain.Builder()
|
||||||
.addAt(message.sender.userId)
|
.addText("发送`/pixiv <id> | rank` 来进行操作哦~")
|
||||||
.addText("发送/pixiv <id> | rank 来进行操作哦~")
|
|
||||||
.build()
|
.build()
|
||||||
listener.sendGroupMessage(message.groupId, msg)
|
message.reply(msg)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
when (val keyword = args.first()) {
|
when (val keyword = args.first()) {
|
||||||
"rank", "排名", "r" -> {
|
"rank", "排名", "r" -> {
|
||||||
val msg = MessageChain.Builder()
|
val node = NodeMessageChain.Builder()
|
||||||
.addAt(message.sender.userId)
|
.addMessageChain(
|
||||||
.addText("今日Pixiv Ranking~")
|
MessageChain.Builder().addText("今日Pixiv Ranking~").build(),
|
||||||
.addNewLine()
|
message.sender.userId
|
||||||
|
)
|
||||||
val result = Http.get<Ranking>(pixivRankingURL)
|
val result = Http.get<Ranking>(pixivRankingURL)
|
||||||
result.contents.asSequence().take(5).forEach {
|
result.contents.asSequence().take(5).forEach {
|
||||||
try {
|
try {
|
||||||
|
val msg = MessageChain.Builder()
|
||||||
val imageBase64 = URI(it.getOriginUrl()).toURL().readBytes().encodeToBase64()
|
val imageBase64 = URI(it.getOriginUrl()).toURL().readBytes().encodeToBase64()
|
||||||
msg.addText(it.title)
|
msg.addImage(imageBase64, true)
|
||||||
.addImage(imageBase64, true)
|
.addText("标题: ${it.title}")
|
||||||
.addNewLine()
|
.addNewLine()
|
||||||
|
.addText("用户: ${it.userName}(${it.userId}) | 作品ID: ${it.illustId}")
|
||||||
|
.addNewLine()
|
||||||
|
.addText("日期: ${it.date}")
|
||||||
|
node.addMessageChain(msg.build(), configManager.selfId)
|
||||||
} catch (_: Exception) {
|
} catch (_: Exception) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
listener.sendGroupMessage(message.groupId, msg.build())
|
node.addMessageChain(
|
||||||
|
MessageChain.Builder()
|
||||||
|
.addText("图片来源: Pixiv")
|
||||||
|
.build(), configManager.selfId
|
||||||
|
)
|
||||||
|
message.reply(node.build())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -56,19 +68,14 @@ class PixivCommand : BaseCommand() {
|
|||||||
try {
|
try {
|
||||||
val id = keyword.toLong()
|
val id = keyword.toLong()
|
||||||
val imageBase64 = URI("$imageProxyURL/$id.png").toURL().readBytes().encodeToBase64()
|
val imageBase64 = URI("$imageProxyURL/$id.png").toURL().readBytes().encodeToBase64()
|
||||||
println(imageBase64)
|
|
||||||
val msg = MessageChain.Builder()
|
val msg = MessageChain.Builder()
|
||||||
.addAt(message.sender.userId)
|
|
||||||
.addText("来咯~ 你要的图片~~~")
|
|
||||||
.addImage(imageBase64, true)
|
.addImage(imageBase64, true)
|
||||||
|
.addText("图片来源: Pixiv")
|
||||||
.build()
|
.build()
|
||||||
listener.sendGroupMessage(message.groupId, msg)
|
message.reply(msg)
|
||||||
} catch (_: Exception) {
|
} catch (_: Exception) {
|
||||||
val msg = MessageChain.Builder()
|
val msg = MessageChain.Builder().addText("输入错误~检查一下有没有输错吧~").build()
|
||||||
.addAt(message.sender.userId)
|
message.reply(msg)
|
||||||
.addText("输入错误~检查一下有没有输错吧~")
|
|
||||||
.build()
|
|
||||||
listener.sendGroupMessage(message.groupId, msg)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,26 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright © 2024 RTAkland
|
|
||||||
* Author: RTAkland
|
|
||||||
* Date: 2024/8/30
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
package cn.rtast.fancybot.commands.lookup
|
|
||||||
|
|
||||||
import cn.rtast.rob.entity.GroupMessage
|
|
||||||
import cn.rtast.rob.util.BaseCommand
|
|
||||||
import cn.rtast.rob.util.ob.MessageChain
|
|
||||||
import cn.rtast.rob.util.ob.OneBotListener
|
|
||||||
|
|
||||||
class QRCodeCommand : BaseCommand() {
|
|
||||||
override val commandNames = listOf("/qrcode", "/qr", "/二维码")
|
|
||||||
|
|
||||||
override suspend fun executeGroup(listener: OneBotListener, message: GroupMessage, args: List<String>) {
|
|
||||||
val content = args.joinToString(" ")
|
|
||||||
val msg = MessageChain.Builder()
|
|
||||||
.addAt(message.sender.userId)
|
|
||||||
.addImage("https://api.rtast.cn/api/generate_qr?data=$content")
|
|
||||||
.build()
|
|
||||||
listener.sendGroupMessage(message.groupId, msg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -7,52 +7,46 @@
|
|||||||
|
|
||||||
package cn.rtast.fancybot.commands.lookup
|
package cn.rtast.fancybot.commands.lookup
|
||||||
|
|
||||||
|
import cn.rtast.fancybot.annotations.CommandDescription
|
||||||
import cn.rtast.rob.entity.GroupMessage
|
import cn.rtast.rob.entity.GroupMessage
|
||||||
import cn.rtast.rob.enums.ArrayMessageType
|
import cn.rtast.rob.enums.ArrayMessageType
|
||||||
import cn.rtast.rob.segment.Node
|
import cn.rtast.rob.onebot.MessageChain
|
||||||
import cn.rtast.rob.segment.PlainText
|
import cn.rtast.rob.onebot.NodeMessageChain
|
||||||
import cn.rtast.rob.util.BaseCommand
|
import cn.rtast.rob.util.BaseCommand
|
||||||
import cn.rtast.rob.util.ob.NodeMessageChain
|
|
||||||
import cn.rtast.rob.util.ob.OneBotListener
|
|
||||||
|
|
||||||
|
|
||||||
private fun generateNodeMessage(targetName: String, targetId: String, times: Int = 10): NodeMessageChain {
|
private fun generateNodeMessage(targetId: String, times: Int = 10): NodeMessageChain {
|
||||||
val nodeMsg = NodeMessageChain.Builder()
|
val nodeMsg = NodeMessageChain.Builder()
|
||||||
repeat(times) {
|
repeat(times) {
|
||||||
val node = Node(
|
val msg = MessageChain.Builder().addText("我是傻逼").build()
|
||||||
Node.Data(
|
nodeMsg.addMessageChain(msg, targetId.toLong())
|
||||||
targetName,
|
|
||||||
targetId,
|
|
||||||
listOf(PlainText(PlainText.Data("我是傻逼")))
|
|
||||||
)
|
|
||||||
)
|
|
||||||
nodeMsg.addNode(node)
|
|
||||||
}
|
}
|
||||||
return nodeMsg.build()
|
return nodeMsg.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@CommandDescription("骂自己(好爽)")
|
||||||
class ShotSelfCommand : BaseCommand() {
|
class ShotSelfCommand : BaseCommand() {
|
||||||
override val commandNames = listOf("骂我")
|
override val commandNames = listOf("骂我")
|
||||||
|
|
||||||
override suspend fun executeGroup(listener: OneBotListener, message: GroupMessage, args: List<String>) {
|
override suspend fun executeGroup(message: GroupMessage, args: List<String>) {
|
||||||
listener.sendGroupForwardMsg(
|
message.action.sendGroupForwardMsg(message.groupId, generateNodeMessage(message.sender.userId.toString()))
|
||||||
message.groupId,
|
|
||||||
generateNodeMessage(message.sender.nickname, message.sender.userId.toString())
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@CommandDescription("骂别人(更爽了")
|
||||||
class ShotOtherCommand : BaseCommand() {
|
class ShotOtherCommand : BaseCommand() {
|
||||||
override val commandNames = listOf("骂")
|
override val commandNames = listOf("骂")
|
||||||
|
|
||||||
override suspend fun executeGroup(listener: OneBotListener, message: GroupMessage, args: List<String>) {
|
override suspend fun executeGroup(message: GroupMessage, args: List<String>) {
|
||||||
if (args.isEmpty()) {
|
if (args.isEmpty()) {
|
||||||
message.reply("发送`骂 @某人`可以骂他~")
|
message.action.sendGroupForwardMsg(
|
||||||
|
message.groupId, generateNodeMessage(message.sender.userId.toString(), 20)
|
||||||
|
)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
var times = if (args.size == 1) 10 else if (args.last() == "") 10 else args.last().toInt()
|
var times = if (args.size == 1) 10 else if (args.last() == "") 10 else args.last().toInt()
|
||||||
if (times >= 200) times = 10
|
if (times >= 200) times = 10
|
||||||
val target = message.message.find { it.type == ArrayMessageType.at }?.data!!
|
val target = message.message.find { it.type == ArrayMessageType.at }?.data!!
|
||||||
listener.sendGroupForwardMsg(message.groupId, generateNodeMessage(target.name!!, target.qq!!, times))
|
message.action.sendGroupForwardMsg(message.groupId, generateNodeMessage(target.qq!!, times))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2024 RTAkland
|
||||||
|
* Author: RTAkland
|
||||||
|
* Date: 2024/10/8
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
package cn.rtast.fancybot.commands.lookup
|
||||||
|
|
||||||
|
import cn.rtast.fancybot.annotations.CommandDescription
|
||||||
|
import cn.rtast.fancybot.entity.thecat.Cat
|
||||||
|
import cn.rtast.fancybot.util.Http
|
||||||
|
import cn.rtast.fancybot.util.misc.toURL
|
||||||
|
import cn.rtast.fancybot.util.str.encodeToBase64
|
||||||
|
import cn.rtast.fancybot.util.str.fromArrayJson
|
||||||
|
import cn.rtast.fancybot.util.str.proxy
|
||||||
|
import cn.rtast.rob.entity.GroupMessage
|
||||||
|
import cn.rtast.rob.onebot.MessageChain
|
||||||
|
import cn.rtast.rob.util.BaseCommand
|
||||||
|
|
||||||
|
@CommandDescription("随机猫猫图")
|
||||||
|
class TheCatCommand : BaseCommand() {
|
||||||
|
override val commandNames = listOf("随机猫咪", "随机猫猫")
|
||||||
|
|
||||||
|
private val theCatApiUrl = "https://api.thecatapi.com/v1/images/search"
|
||||||
|
|
||||||
|
override suspend fun executeGroup(message: GroupMessage, args: List<String>) {
|
||||||
|
val imageBase64 = Http.get(theCatApiUrl)
|
||||||
|
.fromArrayJson<List<Cat>>().first().url
|
||||||
|
.proxy.toURL().readBytes().encodeToBase64()
|
||||||
|
val msg = MessageChain.Builder().addImage(imageBase64, true).build()
|
||||||
|
message.reply(msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2024 RTAkland
|
||||||
|
* Author: RTAkland
|
||||||
|
* Date: 2024/10/8
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
package cn.rtast.fancybot.commands.lookup
|
||||||
|
|
||||||
|
import cn.rtast.fancybot.annotations.CommandDescription
|
||||||
|
import cn.rtast.fancybot.configManager
|
||||||
|
import cn.rtast.fancybot.entity.tianxing.HistoryOfToday
|
||||||
|
import cn.rtast.fancybot.util.Http
|
||||||
|
import cn.rtast.rob.entity.GroupMessage
|
||||||
|
import cn.rtast.rob.onebot.MessageChain
|
||||||
|
import cn.rtast.rob.onebot.toNode
|
||||||
|
import cn.rtast.rob.util.BaseCommand
|
||||||
|
import java.time.LocalDateTime
|
||||||
|
import java.time.ZoneId
|
||||||
|
import java.time.format.DateTimeFormatter
|
||||||
|
|
||||||
|
@CommandDescription("历史上的今天~~~")
|
||||||
|
class TheHistoryOfTodayCommand : BaseCommand() {
|
||||||
|
override val commandNames = listOf("历史上的今天")
|
||||||
|
|
||||||
|
private val tianXingApiUrl = "https://apis.tianapi.com/lishi/index"
|
||||||
|
private val tianXingApiKey = configManager.tianXingApiKey
|
||||||
|
|
||||||
|
override suspend fun executeGroup(message: GroupMessage, args: List<String>) {
|
||||||
|
val currentDateTime = LocalDateTime.now(ZoneId.of("Asia/Shanghai"))
|
||||||
|
val formatter = DateTimeFormatter.ofPattern("MMdd")
|
||||||
|
val currentDate = currentDateTime.format(formatter)
|
||||||
|
val messages = mutableListOf<MessageChain>()
|
||||||
|
Http.get<HistoryOfToday>(
|
||||||
|
tianXingApiUrl,
|
||||||
|
mapOf(
|
||||||
|
"key" to tianXingApiKey,
|
||||||
|
"date" to currentDate,
|
||||||
|
)
|
||||||
|
).result.list.forEach {
|
||||||
|
messages.add(
|
||||||
|
MessageChain.Builder()
|
||||||
|
.addText("事件: ${it.title}")
|
||||||
|
.addNewLine()
|
||||||
|
.addText("发生日期: ${it.lsDate}")
|
||||||
|
.build()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
message.reply(messages.toNode(configManager.selfId))
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,26 +7,27 @@
|
|||||||
|
|
||||||
package cn.rtast.fancybot.commands.lookup
|
package cn.rtast.fancybot.commands.lookup
|
||||||
|
|
||||||
|
import cn.rtast.fancybot.annotations.CommandDescription
|
||||||
import cn.rtast.fancybot.configManager
|
import cn.rtast.fancybot.configManager
|
||||||
import cn.rtast.fancybot.entity.weather.Geo
|
import cn.rtast.fancybot.entity.weather.Geo
|
||||||
import cn.rtast.fancybot.entity.weather.Weather
|
import cn.rtast.fancybot.entity.weather.Weather
|
||||||
import cn.rtast.fancybot.util.Http
|
import cn.rtast.fancybot.util.Http
|
||||||
import cn.rtast.fancybot.util.Resources
|
import cn.rtast.fancybot.util.misc.Resources
|
||||||
import cn.rtast.fancybot.util.drawCenteredText
|
import cn.rtast.fancybot.util.misc.drawCenteredText
|
||||||
import cn.rtast.fancybot.util.drawCustomImage
|
import cn.rtast.fancybot.util.misc.drawCustomImage
|
||||||
|
import cn.rtast.fancybot.util.misc.toBufferedImage
|
||||||
|
import cn.rtast.fancybot.util.misc.toByteArray
|
||||||
import cn.rtast.fancybot.util.str.encodeToBase64
|
import cn.rtast.fancybot.util.str.encodeToBase64
|
||||||
import cn.rtast.fancybot.util.toBufferedImage
|
|
||||||
import cn.rtast.fancybot.util.toByteArray
|
|
||||||
import cn.rtast.rob.entity.GroupMessage
|
import cn.rtast.rob.entity.GroupMessage
|
||||||
|
import cn.rtast.rob.onebot.MessageChain
|
||||||
import cn.rtast.rob.util.BaseCommand
|
import cn.rtast.rob.util.BaseCommand
|
||||||
import cn.rtast.rob.util.ob.MessageChain
|
|
||||||
import cn.rtast.rob.util.ob.OneBotListener
|
|
||||||
import java.awt.Color
|
import java.awt.Color
|
||||||
import java.awt.Font
|
import java.awt.Font
|
||||||
import java.awt.image.BufferedImage
|
import java.awt.image.BufferedImage
|
||||||
|
|
||||||
|
@CommandDescription("查询天气")
|
||||||
class WeatherCommand : BaseCommand() {
|
class WeatherCommand : BaseCommand() {
|
||||||
override val commandNames = listOf("/weather", "/天气", "天气")
|
override val commandNames = listOf("天气")
|
||||||
|
|
||||||
private val canvasWidth = 800
|
private val canvasWidth = 800
|
||||||
private val canvasHeight = 600
|
private val canvasHeight = 600
|
||||||
@@ -56,13 +57,13 @@ class WeatherCommand : BaseCommand() {
|
|||||||
return emptyImage.toByteArray().encodeToBase64()
|
return emptyImage.toByteArray().encodeToBase64()
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun executeGroup(listener: OneBotListener, message: GroupMessage, args: List<String>) {
|
override suspend fun executeGroup(message: GroupMessage, args: List<String>) {
|
||||||
if (args.isEmpty()) {
|
if (args.isEmpty()) {
|
||||||
val msg = MessageChain.Builder()
|
val msg = MessageChain.Builder()
|
||||||
.addAt(message.sender.userId)
|
.addAt(message.sender.userId)
|
||||||
.addText("发送/weather <地区名>即可查看实时天气哦~")
|
.addText("发送/weather <地区名>即可查看实时天气哦~")
|
||||||
.build()
|
.build()
|
||||||
listener.sendGroupMessage(message.groupId, msg)
|
message.reply(msg)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
@@ -79,13 +80,13 @@ class WeatherCommand : BaseCommand() {
|
|||||||
.addReply(message.messageId)
|
.addReply(message.messageId)
|
||||||
.addImage(this.createWeatherCard(weather, lookupLocation), true)
|
.addImage(this.createWeatherCard(weather, lookupLocation), true)
|
||||||
.build()
|
.build()
|
||||||
listener.sendGroupMessage(message.groupId, msg)
|
message.reply(msg)
|
||||||
} catch (_: NullPointerException) {
|
} catch (_: NullPointerException) {
|
||||||
val msg = MessageChain.Builder()
|
val msg = MessageChain.Builder()
|
||||||
.addAt(message.sender.userId)
|
.addAt(message.sender.userId)
|
||||||
.addText("没有查询到该城市的天气信息哦~")
|
.addText("没有查询到该城市的天气信息哦~")
|
||||||
.build()
|
.build()
|
||||||
listener.sendGroupMessage(message.groupId, msg)
|
message.reply(msg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -7,26 +7,31 @@
|
|||||||
|
|
||||||
package cn.rtast.fancybot.commands.lookup
|
package cn.rtast.fancybot.commands.lookup
|
||||||
|
|
||||||
|
import cn.rtast.fancybot.annotations.CommandDescription
|
||||||
import cn.rtast.fancybot.entity.wiki.PageInfoResponse
|
import cn.rtast.fancybot.entity.wiki.PageInfoResponse
|
||||||
import cn.rtast.fancybot.entity.wiki.WikipediaResponse
|
import cn.rtast.fancybot.entity.wiki.WikipediaResponse
|
||||||
|
import cn.rtast.fancybot.enums.CommandAction
|
||||||
import cn.rtast.fancybot.util.Http
|
import cn.rtast.fancybot.util.Http
|
||||||
|
import cn.rtast.fancybot.util.file.insertActionRecord
|
||||||
import cn.rtast.rob.entity.GroupMessage
|
import cn.rtast.rob.entity.GroupMessage
|
||||||
|
import cn.rtast.rob.onebot.MessageChain
|
||||||
import cn.rtast.rob.util.BaseCommand
|
import cn.rtast.rob.util.BaseCommand
|
||||||
import cn.rtast.rob.util.ob.MessageChain
|
|
||||||
import cn.rtast.rob.util.ob.OneBotListener
|
|
||||||
import org.jsoup.Jsoup
|
import org.jsoup.Jsoup
|
||||||
|
|
||||||
|
@CommandDescription("查询wiki百科")
|
||||||
class WikipediaCommand : BaseCommand() {
|
class WikipediaCommand : BaseCommand() {
|
||||||
override val commandNames = listOf("/wiki", "/wk")
|
override val commandNames = listOf("/wiki", "/wk")
|
||||||
|
|
||||||
private val wikipediaAPI = "https://proxy.rtast.cn/https/zh.wikipedia.org/w/api.php"
|
private val wikipediaAPI = "https://proxy.rtast.cn/https/zh.wikipedia.org/w/api.php"
|
||||||
|
|
||||||
private fun String.extractPlainTextFromHtml(): String {
|
companion object {
|
||||||
|
fun String.extractPlainTextFromHtml(): String {
|
||||||
val doc = Jsoup.parse(this)
|
val doc = Jsoup.parse(this)
|
||||||
return doc.text()
|
return doc.text()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override suspend fun executeGroup(listener: OneBotListener, message: GroupMessage, args: List<String>) {
|
override suspend fun executeGroup(message: GroupMessage, args: List<String>) {
|
||||||
if (args.isEmpty()) {
|
if (args.isEmpty()) {
|
||||||
val msg = MessageChain.Builder()
|
val msg = MessageChain.Builder()
|
||||||
.addText("发送`/wiki <关键字>`即可查询出最匹配的wiki页面~")
|
.addText("发送`/wiki <关键字>`即可查询出最匹配的wiki页面~")
|
||||||
@@ -67,6 +72,8 @@ class WikipediaCommand : BaseCommand() {
|
|||||||
.addText("没有查询到指定的wiki页面呢 >>> $title")
|
.addText("没有查询到指定的wiki页面呢 >>> $title")
|
||||||
.build()
|
.build()
|
||||||
message.reply(msg)
|
message.reply(msg)
|
||||||
|
} finally {
|
||||||
|
insertActionRecord(CommandAction.Wiki, message.sender.userId, title)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -7,24 +7,30 @@
|
|||||||
|
|
||||||
package cn.rtast.fancybot.commands.misc
|
package cn.rtast.fancybot.commands.misc
|
||||||
|
|
||||||
import cn.rtast.fancybot.configManager
|
import cn.rtast.fancybot.annotations.CommandDescription
|
||||||
|
import cn.rtast.fancybot.enums.CommandAction
|
||||||
|
import cn.rtast.fancybot.util.file.insertActionRecord
|
||||||
import cn.rtast.rob.entity.ArrayMessage
|
import cn.rtast.rob.entity.ArrayMessage
|
||||||
import cn.rtast.rob.entity.GroupMessage
|
import cn.rtast.rob.entity.GroupMessage
|
||||||
import cn.rtast.rob.enums.ArrayMessageType
|
import cn.rtast.rob.enums.ArrayMessageType
|
||||||
import cn.rtast.rob.util.BaseCommand
|
import cn.rtast.rob.util.BaseCommand
|
||||||
import cn.rtast.rob.util.ob.OneBotListener
|
|
||||||
|
|
||||||
|
@CommandDescription("防撤回(获取消息)")
|
||||||
class AntiRevokeCommand : BaseCommand() {
|
class AntiRevokeCommand : BaseCommand() {
|
||||||
override val commandNames = listOf("/revoke", "/rv", "/防撤回")
|
override val commandNames = listOf("/revoke", "/rv")
|
||||||
|
|
||||||
override suspend fun executeGroup(listener: OneBotListener, message: GroupMessage, args: List<String>) {
|
override suspend fun executeGroup(message: GroupMessage, args: List<String>) {
|
||||||
if (message.sender.userId !in configManager.admins) message.reply("你不许用防撤回")
|
if (message.sender.isAdmin || message.sender.isOwner) {
|
||||||
val messageId = args.first().toLong()
|
val messageId = args.first().toLong()
|
||||||
val getMsg = listener.getMessage(messageId)
|
val getMsg = message.action.getMessage(messageId)
|
||||||
val msgList = mutableListOf<ArrayMessage>()
|
val msgList = mutableListOf<ArrayMessage>()
|
||||||
msgList.add(ArrayMessage(ArrayMessageType.at, ArrayMessage.Data(qq = getMsg.sender.userId.toString())))
|
msgList.add(ArrayMessage(ArrayMessageType.at, ArrayMessage.Data(qq = message.sender.userId.toString())))
|
||||||
msgList.add(ArrayMessage(ArrayMessageType.text, ArrayMessage.Data(text = "\n被撤回的消息如下: \n")))
|
msgList.add(ArrayMessage(ArrayMessageType.text, ArrayMessage.Data(text = "\n被撤回的消息如下: \n")))
|
||||||
msgList.addAll(getMsg.message)
|
msgList.addAll(getMsg.message)
|
||||||
listener.sendGroupMessage(message.groupId, msgList)
|
message.action.sendGroupMessage(message.groupId, msgList)
|
||||||
|
insertActionRecord(CommandAction.AntiRevoke, message.sender.userId, getMsg.messageId.toString())
|
||||||
|
} else {
|
||||||
|
message.reply("你不许用防撤回")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2024 RTAkland
|
||||||
|
* Author: RTAkland
|
||||||
|
* Date: 2024/9/26
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
package cn.rtast.fancybot.commands.misc
|
||||||
|
|
||||||
|
import cn.rtast.fancybot.annotations.CommandDescription
|
||||||
|
import cn.rtast.fancybot.configManager
|
||||||
|
import cn.rtast.fancybot.entity.bullshit.BullShit
|
||||||
|
import cn.rtast.fancybot.util.misc.Resources
|
||||||
|
import cn.rtast.fancybot.util.str.fromJson
|
||||||
|
import cn.rtast.rob.entity.GroupMessage
|
||||||
|
import cn.rtast.rob.onebot.MessageChain
|
||||||
|
import cn.rtast.rob.onebot.NodeMessageChain
|
||||||
|
import cn.rtast.rob.util.BaseCommand
|
||||||
|
import kotlin.random.Random
|
||||||
|
|
||||||
|
@CommandDescription("狗屁不通文章生成器")
|
||||||
|
class BullShitGenerateCommand : BaseCommand() {
|
||||||
|
override val commandNames = listOf("/gpbt", "狗屁不通")
|
||||||
|
|
||||||
|
private val bullShitData = String(Resources.loadFromResourcesAsBytes("misc/bull_shit.json")!!)
|
||||||
|
.fromJson<BullShit>()
|
||||||
|
|
||||||
|
|
||||||
|
private fun <T> shuffleList(list: List<T>): Iterator<T> {
|
||||||
|
val pool = mutableListOf<T>().apply { addAll(list) }.toMutableList()
|
||||||
|
repeat(1) { pool.addAll(list) }
|
||||||
|
return generateSequence {
|
||||||
|
pool.shuffle()
|
||||||
|
pool
|
||||||
|
}.flatten().iterator()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getFamousQuote(nextQuote: Iterator<String>, beforeList: List<String>, afterList: List<String>): String {
|
||||||
|
var quote = nextQuote.next()
|
||||||
|
quote = quote.replace("a", beforeList.random())
|
||||||
|
quote = quote.replace("b", afterList.random())
|
||||||
|
return quote
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun newParagraph(): String {
|
||||||
|
return ".\n\n "
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun executeGroup(message: GroupMessage, args: List<String>) {
|
||||||
|
val topic = args.joinToString(" ")
|
||||||
|
val nextFamousQuote = shuffleList(bullShitData.famous)
|
||||||
|
val nextBosh = shuffleList(bullShitData.bosh)
|
||||||
|
val output = StringBuilder()
|
||||||
|
while (output.length < 6000) {
|
||||||
|
val branch = Random.nextInt(100)
|
||||||
|
if (branch < 5) {
|
||||||
|
output.append(newParagraph())
|
||||||
|
} else if (branch < 20) {
|
||||||
|
output.append(getFamousQuote(nextFamousQuote, bullShitData.before, bullShitData.after))
|
||||||
|
} else {
|
||||||
|
output.append(nextBosh.next())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val finalText = output.toString().replace("x", topic)
|
||||||
|
val node = NodeMessageChain.Builder()
|
||||||
|
.addMessageChain(MessageChain.Builder().addText(finalText).build(), configManager.selfId)
|
||||||
|
.build()
|
||||||
|
message.reply(node)
|
||||||
|
message.sender.poke()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,42 +7,47 @@
|
|||||||
|
|
||||||
package cn.rtast.fancybot.commands.misc
|
package cn.rtast.fancybot.commands.misc
|
||||||
|
|
||||||
|
import cn.rtast.fancybot.annotations.CommandDescription
|
||||||
import cn.rtast.fancybot.entity.compiler.GLOTPayload
|
import cn.rtast.fancybot.entity.compiler.GLOTPayload
|
||||||
import cn.rtast.fancybot.entity.compiler.GLOTResponse
|
import cn.rtast.fancybot.entity.compiler.GLOTResponse
|
||||||
import cn.rtast.fancybot.entity.compiler.KCSPayload
|
import cn.rtast.fancybot.entity.compiler.KCSPayload
|
||||||
import cn.rtast.fancybot.entity.compiler.KCSResponse
|
import cn.rtast.fancybot.entity.compiler.KCSResponse
|
||||||
|
import cn.rtast.fancybot.enums.CommandAction
|
||||||
import cn.rtast.fancybot.util.Http
|
import cn.rtast.fancybot.util.Http
|
||||||
|
import cn.rtast.fancybot.util.file.insertActionRecord
|
||||||
import cn.rtast.fancybot.util.str.toJson
|
import cn.rtast.fancybot.util.str.toJson
|
||||||
import cn.rtast.rob.entity.GroupMessage
|
import cn.rtast.rob.entity.GroupMessage
|
||||||
|
import cn.rtast.rob.onebot.MessageChain
|
||||||
import cn.rtast.rob.util.BaseCommand
|
import cn.rtast.rob.util.BaseCommand
|
||||||
import cn.rtast.rob.util.ob.MessageChain
|
|
||||||
import cn.rtast.rob.util.ob.OneBotListener
|
|
||||||
|
|
||||||
|
@CommandDescription("执行不同语言的代码")
|
||||||
class CompilerCommand : BaseCommand() {
|
class CompilerCommand : BaseCommand() {
|
||||||
override val commandNames = listOf("/compiler", "/exec")
|
override val commandNames = listOf("/compiler", "/exec", "/e")
|
||||||
|
|
||||||
private val kotlinCompilerServer = "https://api.kotlinlang.org/api/2.0.20/compiler/run"
|
private val kotlinCompilerServer = "https://api.kotlinlang.org/api/2.0.20/compiler/run"
|
||||||
private val glotCompilerServer = "https://glot.io/run"
|
private val glotCompilerServer = "https://glot.io/run"
|
||||||
|
|
||||||
override suspend fun executeGroup(listener: OneBotListener, message: GroupMessage, args: List<String>) {
|
override suspend fun executeGroup(message: GroupMessage, args: List<String>) {
|
||||||
if (args.isEmpty()) {
|
if (args.isEmpty()) {
|
||||||
val msg = MessageChain.Builder()
|
message.reply("使用`/exec` <语言> <代码> 即可执行~")
|
||||||
.addAt(message.sender.userId)
|
|
||||||
.addText("使用`/exec` <语言> <代码> 即可执行~")
|
|
||||||
.build()
|
|
||||||
listener.sendGroupMessage(message.groupId, msg)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
val language = args.first()
|
var language = args.first().lowercase()
|
||||||
val code = args.drop(1).joinToString(" ")
|
val code = args.drop(1).joinToString(" ")
|
||||||
val response = when (language) {
|
val response = when (language) {
|
||||||
"kotlin", "Kotlin", "kt", "Kt", "KT" -> {
|
"kotlin", "kt" -> {
|
||||||
Http.post<KCSResponse>(
|
Http.post<KCSResponse>(
|
||||||
kotlinCompilerServer, jsonBody = KCSPayload(listOf(KCSPayload.File(code))).toJson()
|
kotlinCompilerServer,
|
||||||
|
jsonBody = KCSPayload(listOf(KCSPayload.File(code))).toJson()
|
||||||
).text
|
).text
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
|
if (language == "js") language = "javascript"
|
||||||
|
if (language == "cs") language = "csharp"
|
||||||
|
if (language == "sh") language = "bash"
|
||||||
|
if (language == "asm") language = "assembly"
|
||||||
|
if (language == "py") language = "python"
|
||||||
Http.post<GLOTResponse>(
|
Http.post<GLOTResponse>(
|
||||||
"$glotCompilerServer/$language",
|
"$glotCompilerServer/$language",
|
||||||
params = mapOf("version" to "latest"),
|
params = mapOf("version" to "latest"),
|
||||||
@@ -50,12 +55,18 @@ class CompilerCommand : BaseCommand() {
|
|||||||
).stdout
|
).stdout
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
try {
|
||||||
val msg = MessageChain.Builder()
|
val msg = MessageChain.Builder()
|
||||||
.addAt(message.sender.userId)
|
.addReply(message.messageId)
|
||||||
.addText("执行结果如下:")
|
.addText("执行结果如下:")
|
||||||
.addNewLine()
|
.addNewLine()
|
||||||
.addText(response.replace("<outStream>", "").replace("</outStream>", ""))
|
.addText(response.replace("<outStream>", "").replace("</outStream>", ""))
|
||||||
.build()
|
.build()
|
||||||
listener.sendGroupMessage(message.groupId, msg)
|
message.reply(msg)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
message.reply("执行错误: ${e.message}")
|
||||||
|
} finally {
|
||||||
|
insertActionRecord(CommandAction.Compiler, message.sender.userId)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright © 2024 RTAkland
|
|
||||||
* Author: RTAkland
|
|
||||||
* Date: 2024/8/30
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
package cn.rtast.fancybot.commands.misc
|
|
||||||
|
|
||||||
import cn.rtast.fancybot.entity.FKXQS
|
|
||||||
import cn.rtast.fancybot.util.Http
|
|
||||||
import cn.rtast.rob.entity.GroupMessage
|
|
||||||
import cn.rtast.rob.util.BaseCommand
|
|
||||||
import cn.rtast.rob.util.ob.MessageChain
|
|
||||||
import cn.rtast.rob.util.ob.OneBotListener
|
|
||||||
|
|
||||||
class FKXQSCommand : BaseCommand() {
|
|
||||||
override val commandNames = listOf("/fkxqs", "/fk", "/疯狂星期四")
|
|
||||||
|
|
||||||
override suspend fun executeGroup(listener: OneBotListener, message: GroupMessage, args: List<String>) {
|
|
||||||
val response = Http.get<FKXQS>("https://api.shadiao.pro/kfc").data.text
|
|
||||||
val msg = MessageChain.Builder()
|
|
||||||
.addAt(message.sender.userId)
|
|
||||||
.addText(response)
|
|
||||||
.build()
|
|
||||||
listener.sendGroupMessage(message.groupId, msg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2024 RTAkland
|
||||||
|
* Author: RTAkland
|
||||||
|
* Date: 2024/10/9
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
package cn.rtast.fancybot.commands.misc
|
||||||
|
|
||||||
|
import cn.rtast.fancybot.annotations.CommandDescription
|
||||||
|
import cn.rtast.rob.entity.GroupMessage
|
||||||
|
import cn.rtast.rob.util.BaseCommand
|
||||||
|
import java.time.LocalDate
|
||||||
|
import java.time.temporal.ChronoUnit
|
||||||
|
|
||||||
|
@CommandDescription("高考倒计时")
|
||||||
|
class GaoKaoDaysRemainCommand : BaseCommand() {
|
||||||
|
override val commandNames = listOf("高考倒计时")
|
||||||
|
|
||||||
|
override suspend fun executeGroup(message: GroupMessage, args: List<String>) {
|
||||||
|
val gaoKaoDate = LocalDate.of(LocalDate.now().year, 6, 7)
|
||||||
|
val currentDate = LocalDate.now()
|
||||||
|
val adjustedGaoKaoDate = if (currentDate.isAfter(gaoKaoDate)) gaoKaoDate.plusYears(1) else gaoKaoDate
|
||||||
|
val daysBetween = ChronoUnit.DAYS.between(currentDate, adjustedGaoKaoDate)
|
||||||
|
message.reply("高考倒计时: ${daysBetween}天")
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2025 RTAkland
|
||||||
|
* Author: RTAkland
|
||||||
|
* Date: 2025/2/20
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
package cn.rtast.fancybot.commands.misc
|
||||||
|
|
||||||
|
import cn.rtast.fancybot.util.misc.Resources
|
||||||
|
import cn.rtast.fancybot.util.misc.drawCenteredText
|
||||||
|
import cn.rtast.fancybot.util.misc.toByteArray
|
||||||
|
import cn.rtast.fancybot.util.str.encodeToBase64
|
||||||
|
import cn.rtast.rob.entity.GroupMessage
|
||||||
|
import cn.rtast.rob.segment.Image
|
||||||
|
import cn.rtast.rob.util.BaseCommand
|
||||||
|
import java.awt.Color
|
||||||
|
import java.awt.Font
|
||||||
|
import java.awt.RenderingHints
|
||||||
|
import javax.imageio.ImageIO
|
||||||
|
|
||||||
|
class GoodNewsCommand: BaseCommand() {
|
||||||
|
override val commandNames = listOf("xb", "喜报")
|
||||||
|
|
||||||
|
private val goodNewsImageBytes = Resources.loadFromResourcesAsBytes("misc/good_news.png")
|
||||||
|
private val font = Font("SimSun", Font.BOLD, 130)
|
||||||
|
|
||||||
|
private fun generateImage(content: String): String {
|
||||||
|
val img = ImageIO.read(goodNewsImageBytes!!.inputStream())
|
||||||
|
val g2d = img.createGraphics()
|
||||||
|
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON)
|
||||||
|
g2d.color = Color.RED
|
||||||
|
g2d.font = font
|
||||||
|
g2d.drawCenteredText(content, 650, 500)
|
||||||
|
g2d.dispose()
|
||||||
|
val imgBase64 = img.toByteArray().encodeToBase64()
|
||||||
|
return imgBase64
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun executeGroup(message: GroupMessage, args: List<String>) {
|
||||||
|
val content = args.joinToString(" ")
|
||||||
|
val imgBase64 = generateImage(content)
|
||||||
|
message.reply(Image(imgBase64, true))
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2024 RTAkland
|
||||||
|
* Author: RTAkland
|
||||||
|
* Date: 2024/10/23
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
package cn.rtast.fancybot.commands.misc
|
||||||
|
|
||||||
|
import cn.rtast.fancybot.annotations.CommandDescription
|
||||||
|
import cn.rtast.fancybot.enums.HttpStatusCode
|
||||||
|
import cn.rtast.fancybot.util.misc.Resources
|
||||||
|
import cn.rtast.fancybot.util.str.encodeToBase64
|
||||||
|
import cn.rtast.rob.entity.GroupMessage
|
||||||
|
import cn.rtast.rob.onebot.MessageChain
|
||||||
|
import cn.rtast.rob.util.BaseCommand
|
||||||
|
|
||||||
|
@CommandDescription("随机HTTP猫猫")
|
||||||
|
class HTTPCatCommand : BaseCommand() {
|
||||||
|
override val commandNames = listOf("http猫猫", "HTTP猫猫")
|
||||||
|
|
||||||
|
private val notFoundCatBase64 = Resources.loadFromResourcesAsBytes("httpcat/0.jpg")!!.encodeToBase64()
|
||||||
|
|
||||||
|
private fun loadHTTPCat(code: String): String {
|
||||||
|
return Resources.loadFromResourcesAsBytes("httpcat/${code}.jpg")?.encodeToBase64() ?: notFoundCatBase64
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun executeGroup(message: GroupMessage, args: List<String>) {
|
||||||
|
val statusCode = if (args.isEmpty()) HttpStatusCode.entries.random().code.toString() else args.first()
|
||||||
|
val image = loadHTTPCat(statusCode)
|
||||||
|
val msg = MessageChain.Builder().addImage(image, true).build()
|
||||||
|
message.reply(msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2024 RTAkland
|
||||||
|
* Author: RTAkland
|
||||||
|
* Date: 2024/10/23
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
package cn.rtast.fancybot.commands.misc
|
||||||
|
|
||||||
|
import cn.rtast.fancybot.annotations.CommandDescription
|
||||||
|
import cn.rtast.fancybot.enums.HttpStatusCode
|
||||||
|
import cn.rtast.fancybot.util.misc.Resources
|
||||||
|
import cn.rtast.fancybot.util.str.encodeToBase64
|
||||||
|
import cn.rtast.rob.entity.GroupMessage
|
||||||
|
import cn.rtast.rob.onebot.MessageChain
|
||||||
|
import cn.rtast.rob.util.BaseCommand
|
||||||
|
|
||||||
|
@CommandDescription("随机HTTP狗狗")
|
||||||
|
class HTTPDogCommand : BaseCommand() {
|
||||||
|
override val commandNames = listOf("http狗狗", "HTTP狗狗")
|
||||||
|
|
||||||
|
private val notFoundCatBase64 = Resources.loadFromResourcesAsBytes("httpdog/999.jpg")!!.encodeToBase64()
|
||||||
|
|
||||||
|
private fun loadHTTPDog(code: String): String {
|
||||||
|
return Resources.loadFromResourcesAsBytes("httpdog/${code}.jpg")?.encodeToBase64() ?: notFoundCatBase64
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun executeGroup(message: GroupMessage, args: List<String>) {
|
||||||
|
val statusCode = if (args.isEmpty()) HttpStatusCode.entries.random().code.toString() else args.first()
|
||||||
|
val image = loadHTTPDog(statusCode)
|
||||||
|
val msg = MessageChain.Builder().addImage(image, true).build()
|
||||||
|
message.reply(msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,17 +7,18 @@
|
|||||||
|
|
||||||
package cn.rtast.fancybot.commands.misc
|
package cn.rtast.fancybot.commands.misc
|
||||||
|
|
||||||
|
import cn.rtast.fancybot.annotations.CommandDescription
|
||||||
import cn.rtast.fancybot.entity.Hitokoto
|
import cn.rtast.fancybot.entity.Hitokoto
|
||||||
import cn.rtast.fancybot.util.Http
|
import cn.rtast.fancybot.util.Http
|
||||||
import cn.rtast.rob.entity.GroupMessage
|
import cn.rtast.rob.entity.GroupMessage
|
||||||
|
import cn.rtast.rob.onebot.MessageChain
|
||||||
import cn.rtast.rob.util.BaseCommand
|
import cn.rtast.rob.util.BaseCommand
|
||||||
import cn.rtast.rob.util.ob.MessageChain
|
|
||||||
import cn.rtast.rob.util.ob.OneBotListener
|
|
||||||
|
|
||||||
|
@CommandDescription("一言")
|
||||||
class HitokotoCommand : BaseCommand() {
|
class HitokotoCommand : BaseCommand() {
|
||||||
override val commandNames = listOf("/hitokoto", "/1", "一言", "1")
|
override val commandNames = listOf("/1")
|
||||||
|
|
||||||
override suspend fun executeGroup(listener: OneBotListener, message: GroupMessage, args: List<String>) {
|
override suspend fun executeGroup(message: GroupMessage, args: List<String>) {
|
||||||
val response = Http.get<Hitokoto>("https://v1.hitokoto.cn/?c=b")
|
val response = Http.get<Hitokoto>("https://v1.hitokoto.cn/?c=b")
|
||||||
val msg = MessageChain.Builder()
|
val msg = MessageChain.Builder()
|
||||||
.addText("⌊${response.sentence}⌉ ---《${response.from}》")
|
.addText("⌊${response.sentence}⌉ ---《${response.from}》")
|
||||||
|
|||||||
+7
-6
@@ -5,26 +5,27 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
package cn.rtast.fancybot.commands.record
|
package cn.rtast.fancybot.commands.misc
|
||||||
|
|
||||||
|
import cn.rtast.fancybot.annotations.CommandDescription
|
||||||
import cn.rtast.fancybot.util.file.JrrpManager
|
import cn.rtast.fancybot.util.file.JrrpManager
|
||||||
import cn.rtast.rob.entity.GroupMessage
|
import cn.rtast.rob.entity.GroupMessage
|
||||||
|
import cn.rtast.rob.onebot.MessageChain
|
||||||
import cn.rtast.rob.util.BaseCommand
|
import cn.rtast.rob.util.BaseCommand
|
||||||
import cn.rtast.rob.util.ob.MessageChain
|
|
||||||
import cn.rtast.rob.util.ob.OneBotListener
|
|
||||||
|
|
||||||
|
@CommandDescription("今日人品~")
|
||||||
class JrrpCommand : BaseCommand() {
|
class JrrpCommand : BaseCommand() {
|
||||||
override val commandNames = listOf("/jrrp", "/今日人品")
|
override val commandNames = listOf("/jrrp", "/今日人品")
|
||||||
|
|
||||||
private val jrrpManager = JrrpManager()
|
private val jrrpManager = JrrpManager()
|
||||||
|
|
||||||
override suspend fun executeGroup(listener: OneBotListener, message: GroupMessage, args: List<String>) {
|
override suspend fun executeGroup(message: GroupMessage, args: List<String>) {
|
||||||
if (jrrpManager.isJrrped(message.sender.userId)) {
|
if (jrrpManager.isJrrped(message.sender.userId)) {
|
||||||
val msg = MessageChain.Builder()
|
val msg = MessageChain.Builder()
|
||||||
.addAt(message.sender.userId)
|
.addAt(message.sender.userId)
|
||||||
.addText("你今天已经今日人品过啦, 明天再来吧~")
|
.addText("你今天已经今日人品过啦, 明天再来吧~")
|
||||||
.build()
|
.build()
|
||||||
listener.sendGroupMessage(message.groupId, msg)
|
message.reply(msg)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
val randomPoint = jrrpManager.jrrp(message.sender.userId)
|
val randomPoint = jrrpManager.jrrp(message.sender.userId)
|
||||||
@@ -39,6 +40,6 @@ class JrrpCommand : BaseCommand() {
|
|||||||
.addAt(message.sender.userId)
|
.addAt(message.sender.userId)
|
||||||
.addText("$scoreDesc($randomPoint)")
|
.addText("$scoreDesc($randomPoint)")
|
||||||
.build()
|
.build()
|
||||||
listener.sendGroupMessage(message.groupId, msg)
|
message.reply(msg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -7,29 +7,32 @@
|
|||||||
|
|
||||||
package cn.rtast.fancybot.commands.misc
|
package cn.rtast.fancybot.commands.misc
|
||||||
|
|
||||||
import cn.rtast.fancybot.util.Resources
|
import cn.rtast.fancybot.annotations.CommandDescription
|
||||||
import cn.rtast.fancybot.util.drawCircularImage
|
import cn.rtast.fancybot.util.misc.Resources
|
||||||
import cn.rtast.fancybot.util.makeGif
|
import cn.rtast.fancybot.util.misc.drawCircularImage
|
||||||
|
import cn.rtast.fancybot.util.misc.makeGif
|
||||||
|
import cn.rtast.fancybot.util.misc.toBufferedImage
|
||||||
import cn.rtast.fancybot.util.str.encodeToBase64
|
import cn.rtast.fancybot.util.str.encodeToBase64
|
||||||
import cn.rtast.fancybot.util.toBufferedImage
|
|
||||||
import cn.rtast.rob.entity.GroupMessage
|
import cn.rtast.rob.entity.GroupMessage
|
||||||
import cn.rtast.rob.enums.ArrayMessageType
|
import cn.rtast.rob.enums.ArrayMessageType
|
||||||
|
import cn.rtast.rob.onebot.MessageChain
|
||||||
import cn.rtast.rob.util.BaseCommand
|
import cn.rtast.rob.util.BaseCommand
|
||||||
import cn.rtast.rob.util.ob.MessageChain
|
|
||||||
import cn.rtast.rob.util.ob.OneBotListener
|
|
||||||
import com.madgag.gif.fmsware.GifDecoder
|
import com.madgag.gif.fmsware.GifDecoder
|
||||||
import java.awt.image.BufferedImage
|
import java.awt.image.BufferedImage
|
||||||
import java.net.URI
|
import java.net.URI
|
||||||
|
|
||||||
|
@CommandDescription("撅撅你")
|
||||||
class JueCommand : BaseCommand() {
|
class JueCommand : BaseCommand() {
|
||||||
override val commandNames = listOf("撅")
|
override val commandNames = listOf("撅")
|
||||||
|
|
||||||
private val avatarUrl = "https://q1.qlogo.cn/g?b=qq&nk=#{}&s=640"
|
companion object {
|
||||||
|
const val AVATAR_REPLACE_URL = "https://q1.qlogo.cn/g?b=qq&nk=#{}&s=640"
|
||||||
|
}
|
||||||
|
|
||||||
private fun createJueGIF(source: String, target: String): String {
|
private fun createJueGIF(source: String, target: String): String {
|
||||||
val baseGIF = Resources.loadFromResources("misc/jue.gif")
|
val baseGIF = Resources.loadFromResources("misc/jue.gif")
|
||||||
val sourceAvatar = URI(avatarUrl.replace("#{}", source)).toURL().readBytes().toBufferedImage()
|
val sourceAvatar = URI(AVATAR_REPLACE_URL.replace("#{}", source)).toURL().readBytes().toBufferedImage()
|
||||||
val targetAvatar = URI(avatarUrl.replace("#{}", target)).toURL().readBytes().toBufferedImage()
|
val targetAvatar = URI(AVATAR_REPLACE_URL.replace("#{}", target)).toURL().readBytes().toBufferedImage()
|
||||||
val decoder = GifDecoder()
|
val decoder = GifDecoder()
|
||||||
decoder.read(baseGIF)
|
decoder.read(baseGIF)
|
||||||
val frames = mutableListOf<BufferedImage>()
|
val frames = mutableListOf<BufferedImage>()
|
||||||
@@ -55,11 +58,11 @@ class JueCommand : BaseCommand() {
|
|||||||
return gif
|
return gif
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun executeGroup(listener: OneBotListener, message: GroupMessage, args: List<String>) {
|
override suspend fun executeGroup(message: GroupMessage, args: List<String>) {
|
||||||
val target = message.message.find { it.type == ArrayMessageType.at }?.data?.qq.toString()
|
val target = message.message.find { it.type == ArrayMessageType.at }?.data?.qq.toString()
|
||||||
val source = message.sender.userId.toString()
|
val source = message.sender.userId.toString()
|
||||||
val gif = this.createJueGIF(source, target)
|
val gif = this.createJueGIF(source, target)
|
||||||
val msg = MessageChain.Builder().addImage(gif, true).build()
|
val msg = MessageChain.Builder().addImage(gif, true).build()
|
||||||
listener.sendGroupMessage(message.groupId, msg)
|
message.reply(msg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2024 RTAkland
|
||||||
|
* Author: RTAkland
|
||||||
|
* Date: 2024/8/30
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
package cn.rtast.fancybot.commands.misc
|
||||||
|
|
||||||
|
import cn.rtast.fancybot.annotations.CommandDescription
|
||||||
|
import cn.rtast.fancybot.entity.KFC
|
||||||
|
import cn.rtast.fancybot.util.Http
|
||||||
|
import cn.rtast.rob.entity.GroupMessage
|
||||||
|
import cn.rtast.rob.util.BaseCommand
|
||||||
|
import java.time.DayOfWeek
|
||||||
|
import java.time.Instant
|
||||||
|
import java.time.LocalDateTime
|
||||||
|
import java.time.ZoneId
|
||||||
|
|
||||||
|
@CommandDescription("今天是疯狂星期四!")
|
||||||
|
class KFCCommand : BaseCommand() {
|
||||||
|
override val commandNames = listOf("/fkxqs", "/kfc")
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun isThursday(): Boolean {
|
||||||
|
val dateTime = LocalDateTime.ofInstant(
|
||||||
|
Instant.now(),
|
||||||
|
ZoneId.of("Asia/Shanghai")
|
||||||
|
)
|
||||||
|
return dateTime.dayOfWeek == DayOfWeek.THURSDAY
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun executeGroup(message: GroupMessage, args: List<String>) {
|
||||||
|
if (!isThursday()) {
|
||||||
|
message.reply("很可惜今天并不是星期四~")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
message.reply(Http.get<KFC>("https://api.shadiao.pro/kfc").data.text)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright © 2024 RTAkland
|
|
||||||
* Author: RTAkland
|
|
||||||
* Date: 2024/9/8
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
package cn.rtast.fancybot.commands.misc
|
|
||||||
|
|
||||||
import cn.rtast.rob.entity.GroupMessage
|
|
||||||
import cn.rtast.rob.util.BaseCommand
|
|
||||||
import cn.rtast.rob.util.ob.MessageChain
|
|
||||||
import cn.rtast.rob.util.ob.OneBotListener
|
|
||||||
|
|
||||||
class LikeMeCommand : BaseCommand() {
|
|
||||||
override val commandNames = listOf("赞我")
|
|
||||||
|
|
||||||
override suspend fun executeGroup(listener: OneBotListener, message: GroupMessage, args: List<String>) {
|
|
||||||
listener.sendLike(message.sender.userId, 10)
|
|
||||||
val msg = MessageChain.Builder()
|
|
||||||
.addReply(message.messageId)
|
|
||||||
.addText("👍了你十下~~😁")
|
|
||||||
.build()
|
|
||||||
listener.sendGroupMessage(message.groupId, msg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2025 RTAkland
|
||||||
|
* Author: RTAkland
|
||||||
|
* Date: 2025/2/21
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
package cn.rtast.fancybot.commands.misc
|
||||||
|
|
||||||
|
import cn.rtast.fancybot.annotations.CommandDescription
|
||||||
|
import cn.rtast.fancybot.util.misc.Resources
|
||||||
|
import cn.rtast.fancybot.util.misc.drawCenteredText
|
||||||
|
import cn.rtast.fancybot.util.misc.toByteArray
|
||||||
|
import cn.rtast.fancybot.util.str.encodeToBase64
|
||||||
|
import cn.rtast.rob.entity.GroupMessage
|
||||||
|
import cn.rtast.rob.segment.Image
|
||||||
|
import cn.rtast.rob.util.BaseCommand
|
||||||
|
import java.awt.Color
|
||||||
|
import java.awt.Font
|
||||||
|
import java.awt.RenderingHints
|
||||||
|
import javax.imageio.ImageIO
|
||||||
|
|
||||||
|
@CommandDescription("没惹任何人")
|
||||||
|
class MRRHRCommand : BaseCommand() {
|
||||||
|
override val commandNames = listOf("/mr")
|
||||||
|
|
||||||
|
private val mrrhrImageBytes = Resources.loadFromResourcesAsBytes("misc/mrrhr.png")
|
||||||
|
private val font = Font("SimSun", Font.BOLD, 60)
|
||||||
|
|
||||||
|
private fun generateImage(content: String): String {
|
||||||
|
val img = ImageIO.read(mrrhrImageBytes!!.inputStream())
|
||||||
|
val g2d = img.createGraphics()
|
||||||
|
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON)
|
||||||
|
g2d.color = Color.BLACK
|
||||||
|
g2d.font = font
|
||||||
|
g2d.drawCenteredText(content, 315, 466)
|
||||||
|
g2d.dispose()
|
||||||
|
val imgBase64 = img.toByteArray().encodeToBase64()
|
||||||
|
return imgBase64
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun executeGroup(message: GroupMessage, args: List<String>) {
|
||||||
|
val content = args.joinToString(" ")
|
||||||
|
val image = generateImage(content)
|
||||||
|
message.reply(Image(image, true))
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,669 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2024 RTAkland
|
||||||
|
* Author: RTAkland
|
||||||
|
* Date: 2024/10/9
|
||||||
|
*/
|
||||||
|
|
||||||
|
@file:Suppress("KDocUnresolvedReference", "unused")
|
||||||
|
|
||||||
|
package cn.rtast.fancybot.commands.misc
|
||||||
|
|
||||||
|
import cn.rtast.fancybot.annotations.CommandDescription
|
||||||
|
import cn.rtast.fancybot.commands.lookup.NslookupCommand
|
||||||
|
import cn.rtast.fancybot.commands.lookup.WikipediaCommand.Companion.extractPlainTextFromHtml
|
||||||
|
import cn.rtast.fancybot.configManager
|
||||||
|
import cn.rtast.fancybot.db.deleteAccessTokenById
|
||||||
|
import cn.rtast.fancybot.db.getAccessTokenById
|
||||||
|
import cn.rtast.fancybot.db.insertNewAccessToken
|
||||||
|
import cn.rtast.fancybot.entity.mc.DecodedSkin
|
||||||
|
import cn.rtast.fancybot.entity.mc.MCVersion
|
||||||
|
import cn.rtast.fancybot.entity.mc.MCWikiPageResponse
|
||||||
|
import cn.rtast.fancybot.entity.mc.MCWikiSearchResponse
|
||||||
|
import cn.rtast.fancybot.entity.mc.Skin
|
||||||
|
import cn.rtast.fancybot.entity.mc.Username
|
||||||
|
import cn.rtast.fancybot.entity.mc.oauth.DeviceCodeResponse
|
||||||
|
import cn.rtast.fancybot.entity.mc.oauth.LoginXboxLivePayload
|
||||||
|
import cn.rtast.fancybot.entity.mc.oauth.LoginXboxLiveResponse
|
||||||
|
import cn.rtast.fancybot.entity.mc.oauth.ObtainXSTSPayload
|
||||||
|
import cn.rtast.fancybot.entity.mc.oauth.ObtainXSTSResponse
|
||||||
|
import cn.rtast.fancybot.entity.mc.oauth.RedeemCodeResponse
|
||||||
|
import cn.rtast.fancybot.enums.mc.MCVersionType
|
||||||
|
import cn.rtast.fancybot.rconManager
|
||||||
|
import cn.rtast.fancybot.util.Http
|
||||||
|
import cn.rtast.fancybot.util.Logger
|
||||||
|
import cn.rtast.fancybot.util.mcbot.MCClient
|
||||||
|
import cn.rtast.fancybot.util.misc.isFullyTransparent
|
||||||
|
import cn.rtast.fancybot.util.misc.scaleImage
|
||||||
|
import cn.rtast.fancybot.util.misc.toByteArray
|
||||||
|
import cn.rtast.fancybot.util.misc.toURL
|
||||||
|
import cn.rtast.fancybot.util.str.convertToHTML
|
||||||
|
import cn.rtast.fancybot.util.str.decodeToString
|
||||||
|
import cn.rtast.fancybot.util.str.encodeToBase64
|
||||||
|
import cn.rtast.fancybot.util.str.fromJson
|
||||||
|
import cn.rtast.fancybot.util.str.generateRandomString
|
||||||
|
import cn.rtast.fancybot.util.str.toJson
|
||||||
|
import cn.rtast.fancybot.util.str.uriEncode
|
||||||
|
import cn.rtast.motdpinger.BedrockPing
|
||||||
|
import cn.rtast.motdpinger.JavaPing
|
||||||
|
import cn.rtast.rcon.exceptions.AuthFailedException
|
||||||
|
import cn.rtast.rob.entity.GroupMessage
|
||||||
|
import cn.rtast.rob.entity.PrivateMessage
|
||||||
|
import cn.rtast.rob.onebot.MessageChain
|
||||||
|
import cn.rtast.rob.onebot.toNode
|
||||||
|
import cn.rtast.rob.segment.NewLine
|
||||||
|
import cn.rtast.rob.segment.Text
|
||||||
|
import cn.rtast.rob.segment.toMessageChain
|
||||||
|
import cn.rtast.rob.util.BaseCommand
|
||||||
|
import okhttp3.FormBody
|
||||||
|
import java.awt.AlphaComposite
|
||||||
|
import java.awt.Color
|
||||||
|
import java.awt.image.BufferedImage
|
||||||
|
import java.net.SocketException
|
||||||
|
import java.net.URI
|
||||||
|
import java.util.concurrent.Executors
|
||||||
|
import javax.imageio.ImageIO
|
||||||
|
import kotlin.random.Random
|
||||||
|
import kotlin.text.split
|
||||||
|
|
||||||
|
@CommandDescription("获取MC最新的版本!")
|
||||||
|
class MCVersionCommand : BaseCommand() {
|
||||||
|
override val commandNames = listOf("mc版本")
|
||||||
|
|
||||||
|
private val javaEditionAPI = "https://launchermeta.mojang.com/mc/game/version_manifest.json"
|
||||||
|
|
||||||
|
override suspend fun executeGroup(message: GroupMessage, args: List<String>) {
|
||||||
|
val mcVersion = Http.get<MCVersion>(javaEditionAPI)
|
||||||
|
val msg = MessageChain.Builder()
|
||||||
|
.addText("最新正式版: ${mcVersion.latest.release}")
|
||||||
|
.addNewLine()
|
||||||
|
.addText("发布时间: ${mcVersion.versions.find { it.type == MCVersionType.release }?.releaseTime}")
|
||||||
|
.addNewLine()
|
||||||
|
.addText("最新测试版: ${mcVersion.latest.snapshot}")
|
||||||
|
.addNewLine()
|
||||||
|
.addText("测试版发布时间: ${mcVersion.versions.find { it.type == MCVersionType.snapshot }?.releaseTime}")
|
||||||
|
.build()
|
||||||
|
message.reply(msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@CommandDescription("查询来自minecraft.wiki中的wiki页面")
|
||||||
|
class MinecraftWikiCommand : BaseCommand() {
|
||||||
|
override val commandNames = listOf("/mcwiki")
|
||||||
|
|
||||||
|
private val baseApiUrl = "https://zh.minecraft.wiki/rest.php/v1"
|
||||||
|
private val logger = Logger.getLogger<MinecraftWikiCommand>()
|
||||||
|
|
||||||
|
override suspend fun executeGroup(message: GroupMessage, args: List<String>) {
|
||||||
|
val action = args.first()
|
||||||
|
when (action) {
|
||||||
|
"s", "搜索" -> {
|
||||||
|
val searchKeyword = args.drop(1).joinToString(" ").trim()
|
||||||
|
val messages = mutableListOf<MessageChain>()
|
||||||
|
val headerMessage = MessageChain.Builder().addText("结果如下:").build()
|
||||||
|
messages.add(headerMessage)
|
||||||
|
Http.get<MCWikiSearchResponse>(
|
||||||
|
"$baseApiUrl/search/title",
|
||||||
|
mapOf("q" to searchKeyword, "limit" to 10)
|
||||||
|
).pages.forEach {
|
||||||
|
val msg = MessageChain.Builder()
|
||||||
|
val imageUrl = it.thumbnail
|
||||||
|
if (imageUrl != null) {
|
||||||
|
val imageBase64 = imageUrl.url.toURL().readBytes().encodeToBase64()
|
||||||
|
msg.addImage(imageBase64, true)
|
||||||
|
}
|
||||||
|
msg.addText("标题: ${it.title}")
|
||||||
|
.addNewLine()
|
||||||
|
.addText("ID: ${it.id}")
|
||||||
|
.addNewLine()
|
||||||
|
.addText("https://zh.minecraft.wiki/w/${it.title.uriEncode}")
|
||||||
|
messages.add(msg.build())
|
||||||
|
}
|
||||||
|
message.reply(messages.toNode(configManager.selfId))
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> {
|
||||||
|
val title = args.joinToString(" ").trim()
|
||||||
|
var response = Http.get<MCWikiPageResponse>("$baseApiUrl/page/$title")
|
||||||
|
if (response.httpCode != null) {
|
||||||
|
logger.info("页面($title)不存在")
|
||||||
|
message.reply("页面($title)不存在")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (response.redirectTarget != null) {
|
||||||
|
logger.info("重定向Wiki页面到: ${response.redirectTarget}")
|
||||||
|
response = Http.get<MCWikiPageResponse>(response.redirectTarget)
|
||||||
|
}
|
||||||
|
val messages = mutableListOf<MessageChain>()
|
||||||
|
val headerMsg = MessageChain.Builder().addText("标题${response.title}的内容如下").build()
|
||||||
|
val footerMsg = listOf(
|
||||||
|
Text("数据来源: https://zh.minecraft.wiki"),
|
||||||
|
NewLine(),
|
||||||
|
Text("协议: ${response.license.title}(${response.license.url})")
|
||||||
|
).toMessageChain()
|
||||||
|
val bodyMsg = MessageChain.Builder()
|
||||||
|
.addText(response.source.convertToHTML().extractPlainTextFromHtml())
|
||||||
|
.build()
|
||||||
|
messages.add(headerMsg)
|
||||||
|
messages.add(bodyMsg)
|
||||||
|
messages.add(footerMsg)
|
||||||
|
message.reply(messages.toNode(configManager.selfId))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@CommandDescription("帮助你寻找指定空置域大小并且在某个区块范围内的最多史莱姆区块范围")
|
||||||
|
class SlimeChunkHelperCommand : BaseCommand() {
|
||||||
|
override val commandNames = listOf("/slime")
|
||||||
|
|
||||||
|
private fun isSlimeChunk(worldSeed: Long, chunkX: Int, chunkZ: Int): Boolean {
|
||||||
|
val rng = Random(
|
||||||
|
worldSeed + (chunkX * chunkX) * 0x4C1906 +
|
||||||
|
(chunkX * 0x5AC0DB) + (chunkZ * chunkZ) * 0x4307A7L +
|
||||||
|
(chunkZ * 0x5F24F) xor 0x3AD8025FL
|
||||||
|
)
|
||||||
|
return rng.nextInt(10) == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun countSlimeChunksInRegion(xStart: Int, zStart: Int, chunkSize: Int, worldSeed: Long): Int {
|
||||||
|
var count = 0
|
||||||
|
for (x in xStart until xStart + chunkSize) {
|
||||||
|
for (z in zStart until zStart + chunkSize) {
|
||||||
|
if (isSlimeChunk(worldSeed, x, z)) {
|
||||||
|
count++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun findMaxSlimeChunks(
|
||||||
|
worldSeed: Long,
|
||||||
|
searchRange: Int,
|
||||||
|
chunkSize: Int,
|
||||||
|
): Pair<Pair<Pair<Int, Int>, Pair<Int, Int>>, Int> {
|
||||||
|
var maxCount = 0
|
||||||
|
var bestStartLocation = Pair(0, 0)
|
||||||
|
var bestEndLocation = Pair(0, 0)
|
||||||
|
for (x in -searchRange until searchRange - chunkSize + 1) {
|
||||||
|
for (z in -searchRange until searchRange - chunkSize + 1) {
|
||||||
|
val count = countSlimeChunksInRegion(x, z, chunkSize, worldSeed)
|
||||||
|
if (count > maxCount) {
|
||||||
|
maxCount = count
|
||||||
|
bestStartLocation = Pair(x, z)
|
||||||
|
bestEndLocation = Pair(x + chunkSize - 1, z + chunkSize - 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Pair(Pair(bestStartLocation, bestEndLocation), maxCount)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun generateSlimeChunkImage(startX: Int, startZ: Int, endX: Int, endZ: Int, worldSeed: Long): String {
|
||||||
|
val width = endX - startX + 1
|
||||||
|
val height = endZ - startZ + 1
|
||||||
|
val pixelSize = 15
|
||||||
|
val imageWidth = width * pixelSize
|
||||||
|
val imageHeight = height * pixelSize
|
||||||
|
val image = BufferedImage(imageWidth, imageHeight, BufferedImage.TYPE_INT_RGB)
|
||||||
|
val graphics = image.graphics
|
||||||
|
val borderColor = Color.LIGHT_GRAY
|
||||||
|
for (x in startX..endX) {
|
||||||
|
for (z in startZ..endZ) {
|
||||||
|
val isSlime = isSlimeChunk(worldSeed, x, z)
|
||||||
|
val fillColor = if (isSlime) Color.PINK else Color.WHITE
|
||||||
|
val px = (x - startX) * pixelSize
|
||||||
|
val pz = (z - startZ) * pixelSize
|
||||||
|
graphics.color = fillColor
|
||||||
|
graphics.fillRect(px, pz, pixelSize, pixelSize)
|
||||||
|
graphics.color = borderColor
|
||||||
|
graphics.drawRect(px, pz, pixelSize, pixelSize)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
graphics.dispose()
|
||||||
|
return image.toByteArray().encodeToBase64()
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun executeGroup(message: GroupMessage, args: List<String>) {
|
||||||
|
if (args.isEmpty()) {
|
||||||
|
val msg = MessageChain.Builder()
|
||||||
|
.addText("此指令可以借助一个种子来帮助查找最适合史莱姆农场的位置")
|
||||||
|
.addNewLine()
|
||||||
|
.addText("如果不指定史莱姆农场的宽度的话默认为17x17区块大小")
|
||||||
|
.addNewLine()
|
||||||
|
.addText("不指定搜索区块范围默认为X: 500~-500, Y: 500~-500, 共计搜索100万个区块")
|
||||||
|
.addNewLine()
|
||||||
|
.addText("还可以指定空置域的大小, 不指定默认为17x17")
|
||||||
|
.addNewLine()
|
||||||
|
.addText("你可以使用`/slime <种子> [范围(例如600)] [空置域大小]`")
|
||||||
|
.build()
|
||||||
|
message.reply(msg)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val seed = args.first().toLong()
|
||||||
|
val slimeFarmSize = if (args.size == 1) 17 else args[1].toInt()
|
||||||
|
val range = if (args.size == 1) 500 else args[2].toInt()
|
||||||
|
val (location, slimeCount) = findMaxSlimeChunks(seed, range, slimeFarmSize)
|
||||||
|
val startX = location.first.first
|
||||||
|
val startZ = location.first.second
|
||||||
|
val endX = location.second.first
|
||||||
|
val endZ = location.second.second
|
||||||
|
val image = generateSlimeChunkImage(startX, startZ, endX, endZ, seed)
|
||||||
|
val msg = MessageChain.Builder()
|
||||||
|
.addText("起始区块坐标X:$startX Y:$startZ")
|
||||||
|
.addNewLine()
|
||||||
|
.addText("结束区块坐标X:$endX Y:$endZ")
|
||||||
|
.addNewLine()
|
||||||
|
.addText("共计史莱姆区块数量: $slimeCount")
|
||||||
|
.addImage(image, true)
|
||||||
|
.build()
|
||||||
|
message.reply(msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@CommandDescription("通过游戏名称或UUID来获取他的皮肤")
|
||||||
|
class MCSkinCommand : BaseCommand() {
|
||||||
|
override val commandNames = listOf("/skin")
|
||||||
|
|
||||||
|
private val uuidQueryUrl = "https://api.mojang.com/users/profiles/minecraft"
|
||||||
|
private val skinUrl = "https://sessionserver.mojang.com/session/minecraft/profile"
|
||||||
|
|
||||||
|
private fun String.isUsername(): Boolean {
|
||||||
|
val usernamePattern = Regex("^[a-zA-Z][a-zA-Z0-9_]{2,15}$")
|
||||||
|
return usernamePattern.matches(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 截取整张皮肤中的头部部分, 如果是单层皮肤则直接截取脸部
|
||||||
|
* 如果是双层皮肤也就将脸部作为背景图层, 将头发绘制在脸部上
|
||||||
|
* 代码来自
|
||||||
|
* `[YeeeesMOTD]
|
||||||
|
* (https://github.com/RTAkland/YeeeesMOTD/blob/main/core/src/main/kotlin/cn/rtast/yeeeesmotd/utils/SkinHeadUtil.kt)`
|
||||||
|
*/
|
||||||
|
private fun getSkinHead(skinUrl: String): String {
|
||||||
|
val url = URI(skinUrl).toURL()
|
||||||
|
val image = ImageIO.read(url)
|
||||||
|
var subImage = image.getSubimage(8, 8, 8, 8)
|
||||||
|
|
||||||
|
if (subImage.isFullyTransparent()) {
|
||||||
|
subImage = image.getSubimage(40, 8, 8, 8)
|
||||||
|
} else {
|
||||||
|
val hairLayer = image.getSubimage(40, 8, 8, 8)
|
||||||
|
val combined = BufferedImage(subImage.width, subImage.height, BufferedImage.TYPE_INT_ARGB)
|
||||||
|
val g2d = combined.createGraphics()
|
||||||
|
g2d.drawImage(subImage, 0, 0, null)
|
||||||
|
g2d.composite = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1.0f)
|
||||||
|
g2d.drawImage(hairLayer, 0, 0, null)
|
||||||
|
g2d.dispose()
|
||||||
|
subImage = combined
|
||||||
|
}
|
||||||
|
val zoom = subImage.scaleImage(128 to 128)
|
||||||
|
return zoom.toByteArray().encodeToBase64()
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun executeGroup(message: GroupMessage, args: List<String>) {
|
||||||
|
if (args.isEmpty()) {
|
||||||
|
message.reply("发送`/skin <uuid/游戏名称>`即可查询他的皮肤~ (仅限Java版)")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
val nameOrUUID = args.first().trim()
|
||||||
|
val uuid = if (nameOrUUID.isUsername()) Http.get<Username>("$uuidQueryUrl/$nameOrUUID").id
|
||||||
|
else nameOrUUID
|
||||||
|
val skinUrl = Http.get<Skin>("$skinUrl/$uuid")
|
||||||
|
.properties.first().value.decodeToString().fromJson<DecodedSkin>()
|
||||||
|
.textures.skin.url
|
||||||
|
val headBase64 = this.getSkinHead(skinUrl)
|
||||||
|
val msg = MessageChain.Builder()
|
||||||
|
.addImage(headBase64, true)
|
||||||
|
.addText(skinUrl)
|
||||||
|
.build()
|
||||||
|
message.reply(msg)
|
||||||
|
} catch (_: Exception) {
|
||||||
|
message.reply("输入错误, 检查一下是否输入正确吧~")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@CommandDescription("PingMC服务器")
|
||||||
|
class MCPingCommand : BaseCommand() {
|
||||||
|
override val commandNames = listOf("/mcping")
|
||||||
|
|
||||||
|
private fun String.removeColorCodes(): String {
|
||||||
|
return this.replace(Regex("§."), "")
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun executeGroup(message: GroupMessage, args: List<String>) {
|
||||||
|
if (args.isEmpty()) {
|
||||||
|
val msg = MessageChain.Builder()
|
||||||
|
.addText("使用方法: /mcping <host>:[port] [java|be]")
|
||||||
|
.addNewLine()
|
||||||
|
.addText("不添加平台默认Java版~")
|
||||||
|
.build()
|
||||||
|
message.reply(msg)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val platform = if (args.size == 2) args.last() else "java"
|
||||||
|
when (platform) {
|
||||||
|
"java", "je", "Java", "JAVA" -> {
|
||||||
|
val parts = args.first().split(":")
|
||||||
|
var port = if (parts.size == 1) 25565 else parts.last().toInt()
|
||||||
|
var host = parts.first()
|
||||||
|
val srv = NslookupCommand.srv(host)
|
||||||
|
if (srv.isNotEmpty()) {
|
||||||
|
val srv = srv.first().split(" ")
|
||||||
|
port = srv[2].toInt()
|
||||||
|
host = srv.last()
|
||||||
|
}
|
||||||
|
val response = JavaPing().ping(host, port, 10000)
|
||||||
|
if (response == null) {
|
||||||
|
message.reply("无法获取服务器的消息请检查输入是否正确 >>> $host:$port")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val msg = MessageChain.Builder()
|
||||||
|
response.favicon?.let { msg.addImage(response.favicon!!.replace("data:image/png;base64,", ""), true) }
|
||||||
|
msg.addText("服务器地址: $host:$port")
|
||||||
|
.addNewLine()
|
||||||
|
.addText("服务器类型: Java | 延迟: ${response.latency}ms")
|
||||||
|
.addNewLine()
|
||||||
|
.addText("服务器版本: ${response.version.name}/${response.version.protocol}")
|
||||||
|
.addNewLine()
|
||||||
|
.addText("在线玩家数: ${response.players.online}/${response.players.max}")
|
||||||
|
message.reply(msg.build())
|
||||||
|
}
|
||||||
|
|
||||||
|
"be", "bedrock", "BE", "Bedrock" -> {
|
||||||
|
val parts = args.first().split(":")
|
||||||
|
val port = if (parts.size == 1) 19132 else parts.last().toInt()
|
||||||
|
val host = parts.first()
|
||||||
|
try {
|
||||||
|
val response = BedrockPing().ping(host, port, 10000)
|
||||||
|
val msg = MessageChain.Builder()
|
||||||
|
.addText("服务器地址: $host:$port")
|
||||||
|
.addNewLine()
|
||||||
|
.addText("服务器类型: Bedrock(基岩版) | 延迟: ${response.latency}ms")
|
||||||
|
.addNewLine()
|
||||||
|
.addText("服务器版本: ${response.version}/${response.protocolVersion}")
|
||||||
|
.addNewLine()
|
||||||
|
.addText("在线玩家: ${response.onlinePlayers}/${response.maxPlayers}")
|
||||||
|
.addNewLine()
|
||||||
|
.addText("MOTD: ${response.motd.removeColorCodes()}")
|
||||||
|
.addNewLine()
|
||||||
|
.addText(response.subTitle.removeColorCodes())
|
||||||
|
message.reply(msg.build())
|
||||||
|
} catch (_: SocketException) {
|
||||||
|
message.reply("无法从服务器接收Ping结果请检查服务器地址是否正确 >>> $host:$port")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> {
|
||||||
|
message.reply("输入错误请在 `java` 和 `be`中选择 >>> $platform")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@CommandDescription("获取MC账号的AccessToken")
|
||||||
|
class MCLoginCommand : BaseCommand() {
|
||||||
|
override val commandNames = listOf("/mclogin")
|
||||||
|
|
||||||
|
private val deviceCodeUrl = "https://login.microsoftonline.com/consumers/oauth2/v2.0/devicecode"
|
||||||
|
private val redeemCodeUrl = "https://login.microsoftonline.com/consumers/oauth2/v2.0/token"
|
||||||
|
private val xboxLiveAuthUrl = "https://user.auth.xboxlive.com/user/authenticate"
|
||||||
|
private val obtainXSTSUrl = "https://xsts.auth.xboxlive.com/xsts/authorize"
|
||||||
|
private val clientId = configManager.azureAppClientId
|
||||||
|
private val waitingList = mutableListOf<Long>()
|
||||||
|
private val deviceCodeMap = mutableMapOf<Long, String>()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取user code 和device code 和验证url
|
||||||
|
*/
|
||||||
|
private fun getDeviceCode(): Triple<String, String, String> {
|
||||||
|
val form = FormBody.Builder()
|
||||||
|
.add("client_id", clientId)
|
||||||
|
.add("scope", "XboxLive.signin")
|
||||||
|
.build()
|
||||||
|
val response = Http.post<DeviceCodeResponse>(deviceCodeUrl, form)
|
||||||
|
return Triple(response.userCode, response.deviceCode, response.verificationUri)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将这个code兑换成一个access token
|
||||||
|
*/
|
||||||
|
private fun redeemCode(deviceCode: String): String {
|
||||||
|
val form = FormBody.Builder()
|
||||||
|
.add("client_id", clientId)
|
||||||
|
.add("grant_type", "urn:ietf:params:oauth:grant-type:device_code")
|
||||||
|
.add("device_code", deviceCode)
|
||||||
|
.build()
|
||||||
|
val response = Http.post<RedeemCodeResponse>(redeemCodeUrl, form)
|
||||||
|
return response.accessToken
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 登录Xbox
|
||||||
|
*/
|
||||||
|
private fun loginXboxLive(accessToken: String): Pair<String, String> {
|
||||||
|
val payload = LoginXboxLivePayload(properties = LoginXboxLivePayload.Properties("d=$accessToken"))
|
||||||
|
val response = Http.post<LoginXboxLiveResponse>(xboxLiveAuthUrl, payload.toJson())
|
||||||
|
val token = response.token
|
||||||
|
val uhs = response.displayClaims.xui.first().uhs
|
||||||
|
return token to uhs
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取最后的mc access token, 这个access token可以直接用于登录游戏
|
||||||
|
*/
|
||||||
|
private fun obtainXSTSToken(token: String, uhs: String): String {
|
||||||
|
val payload = ObtainXSTSPayload(properties = ObtainXSTSPayload.Properties(listOf(token)))
|
||||||
|
val response = Http.post<ObtainXSTSResponse>(obtainXSTSUrl, payload.toJson())
|
||||||
|
return response.token
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun executeGroup(message: GroupMessage, args: List<String>) {
|
||||||
|
if (args.isEmpty()) {
|
||||||
|
message.reply("这个命令可以获取你的MC登录Token发送 `/mclogin login`进行操作吧")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
deleteAccessTokenById(message.sender.userId)
|
||||||
|
val action = args.first()
|
||||||
|
if (action == "确认" || action == "confirm") {
|
||||||
|
if (message.sender.userId !in waitingList) {
|
||||||
|
message.reply("你还没开始登陆呢")
|
||||||
|
} else {
|
||||||
|
waitingList.removeIf { it == message.sender.userId }
|
||||||
|
val deviceCode = deviceCodeMap[message.sender.userId]!!
|
||||||
|
deviceCodeMap.remove(message.sender.userId)
|
||||||
|
val accessToken = this.redeemCode(deviceCode)
|
||||||
|
val (token, uhs) = this.loginXboxLive(accessToken)
|
||||||
|
val minecraftAccessToken = this.obtainXSTSToken(token, uhs)
|
||||||
|
insertNewAccessToken(minecraftAccessToken, message.sender.userId)
|
||||||
|
message.reply("你的账号token已经被保存到了数据库中, 请加机器人好友然后发送`/mclogin`来获取这个Token, Token会在你获取之后从数据库中删除")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (message.sender.userId !in waitingList) {
|
||||||
|
waitingList.add(message.sender.userId)
|
||||||
|
val deviceInfo = getDeviceCode()
|
||||||
|
val msg = MessageChain.Builder()
|
||||||
|
.addText("你的用户代码是: ${deviceInfo.first}")
|
||||||
|
.addNewLine()
|
||||||
|
.addText("请前往: ${deviceInfo.third}进行验证")
|
||||||
|
.addNewLine()
|
||||||
|
.addText("登陆完成后发送`/mclogin confirm` 或 `/mclogin 确认`")
|
||||||
|
.build()
|
||||||
|
deviceCodeMap[message.sender.userId] = deviceInfo.second
|
||||||
|
message.reply(msg)
|
||||||
|
} else {
|
||||||
|
waitingList.removeIf { it == message.sender.userId }
|
||||||
|
deviceCodeMap.remove(message.sender.userId)
|
||||||
|
message.reply("回复错误已结束本次登录流程")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun executePrivate(message: PrivateMessage, args: List<String>) {
|
||||||
|
val token = getAccessTokenById(message.sender.userId)
|
||||||
|
if (token == null) {
|
||||||
|
message.reply("你还没登录呢!")
|
||||||
|
} else {
|
||||||
|
val msg = MessageChain.Builder()
|
||||||
|
.addText("你的AccessToken如下: ")
|
||||||
|
.addNewLine()
|
||||||
|
.addText(token.token)
|
||||||
|
.addNewLine()
|
||||||
|
.addText("这个Token是敏感信息请妥善保管")
|
||||||
|
.build()
|
||||||
|
deleteAccessTokenById(message.sender.userId)
|
||||||
|
message.reply(msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@CommandDescription("通过RCON来控制MC服务器(仅限私聊执行)")
|
||||||
|
class RCONCommand : BaseCommand() {
|
||||||
|
override val commandNames = listOf("/rcon", "/r")
|
||||||
|
|
||||||
|
override suspend fun executeGroup(message: GroupMessage, args: List<String>) {
|
||||||
|
message.reply("请在私聊中使用此命令")
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun executePrivate(message: PrivateMessage, args: List<String>) {
|
||||||
|
if (args.isEmpty()) {
|
||||||
|
val msg = MessageChain.Builder()
|
||||||
|
.addText("这条指令用于在群内操作mc服务器")
|
||||||
|
.addNewLine()
|
||||||
|
.addText("使用`/r add <name> <host> <port> <password>` 可以创建一条配置")
|
||||||
|
.addNewLine()
|
||||||
|
.addText("使用`/r <name> <command>`可以执行命令")
|
||||||
|
.addNewLine()
|
||||||
|
.addText("使用`/r remove <name>`可以移除这条RCON配置")
|
||||||
|
.build()
|
||||||
|
message.reply(msg)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val action = args.first()
|
||||||
|
when (action) {
|
||||||
|
"get" -> {
|
||||||
|
val allRcons = rconManager.getAllRconsById(message.sender.userId)
|
||||||
|
if (allRcons.isEmpty()) {
|
||||||
|
message.reply("你还没有RCON配置呢, 发送`/r add <name> <host> <port> <password>`来创建一个配置吧")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val messages = mutableListOf<MessageChain>()
|
||||||
|
.also { it.add(MessageChain.Builder().addText("所有配置如下").build()) }
|
||||||
|
allRcons.forEach {
|
||||||
|
val msg = MessageChain.Builder()
|
||||||
|
.addText("名称: ${it.name}")
|
||||||
|
.addNewLine()
|
||||||
|
.addText("地址: ${it.host}:${it.port}")
|
||||||
|
.addNewLine()
|
||||||
|
.addText("密码: *********")
|
||||||
|
.build()
|
||||||
|
messages.add(msg)
|
||||||
|
}
|
||||||
|
message.reply(messages.toNode(configManager.selfId))
|
||||||
|
}
|
||||||
|
|
||||||
|
"add" -> {
|
||||||
|
val name = args[1]
|
||||||
|
val host = args[2]
|
||||||
|
val port = args[3].toInt()
|
||||||
|
val password = args[4]
|
||||||
|
rconManager.insertConfig(message.sender.userId, name, host, port, password)
|
||||||
|
message.reply("成功增加一条记录: $name")
|
||||||
|
}
|
||||||
|
|
||||||
|
"remove" -> {
|
||||||
|
val name = args.last()
|
||||||
|
val count = rconManager.removeRRCON(message.sender.userId, name)
|
||||||
|
if (count == 0) {
|
||||||
|
message.reply("RCON($name)不存在")
|
||||||
|
} else {
|
||||||
|
message.reply("成功移除了$name")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> {
|
||||||
|
val name = args.first().trim()
|
||||||
|
val command = args.drop(1).joinToString(" ").trim()
|
||||||
|
val rconData = rconManager.getRcon(message.sender.userId, name)
|
||||||
|
if (rconData == null) {
|
||||||
|
message.reply("RCON($name)配置不存在")
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
val result = rconManager.executeCommand(message.sender.userId, name, command)
|
||||||
|
val messages = mutableListOf<MessageChain>()
|
||||||
|
.also { it.add(MessageChain.Builder().addText("执行结果如下").build()) }
|
||||||
|
.also { it.add(MessageChain.Builder().addText(result).build()) }
|
||||||
|
.toNode(configManager.selfId)
|
||||||
|
message.reply(messages)
|
||||||
|
} catch (_: AuthFailedException) {
|
||||||
|
message.reply("执行失败, 密码不正确")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@CommandDescription("Java版服务器假人压测")
|
||||||
|
class MCBotCommand : BaseCommand() {
|
||||||
|
override val commandNames = listOf("/mcbot")
|
||||||
|
|
||||||
|
private val userClientMap = mutableMapOf<Long, MutableList<MCClient>>()
|
||||||
|
|
||||||
|
private fun getPlayerList(host: String, port: Int): Pair<Int, Int> {
|
||||||
|
val response = JavaPing().ping(host, port, 8000)!!
|
||||||
|
return response.players.max to response.players.online
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun executeGroup(message: GroupMessage, args: List<String>) {
|
||||||
|
val clients = mutableListOf<MCClient>()
|
||||||
|
val action = args.first()
|
||||||
|
when (action) {
|
||||||
|
"start" -> {
|
||||||
|
if (userClientMap.containsKey(message.sender.userId)) {
|
||||||
|
message.reply("你有一个正在进行的任务不能开启另外一个任务请先使用`/mcbot cancel`取消任务")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val address = args[1]
|
||||||
|
val host = address.split(":").first()
|
||||||
|
val port = address.split(":").last().toInt()
|
||||||
|
val count = args[2].toInt()
|
||||||
|
val executor = Executors.newFixedThreadPool(count)
|
||||||
|
val (maxPlayer, onlinePlayer) = this.getPlayerList(host, port)
|
||||||
|
val availableSit = maxPlayer - onlinePlayer
|
||||||
|
if (count > availableSit) {
|
||||||
|
message.replyAsync("当前服务器仅剩余${availableSit}个玩家可进入!!")
|
||||||
|
}
|
||||||
|
(1..count).forEach {
|
||||||
|
val client = MCClient(host, port, generateRandomString())
|
||||||
|
.also { it.createClient() }
|
||||||
|
executor.execute { clients.add(client.runBot()) }
|
||||||
|
}
|
||||||
|
userClientMap[message.sender.userId] = clients
|
||||||
|
message.reply("成功开启任务: $address, $count")
|
||||||
|
}
|
||||||
|
|
||||||
|
"cancel" -> {
|
||||||
|
if (userClientMap.containsKey(message.sender.userId)) {
|
||||||
|
userClientMap.entries.forEach {
|
||||||
|
if (it.key == message.sender.userId) {
|
||||||
|
it.value.forEach { it.disconnect() }
|
||||||
|
userClientMap.remove(it.key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
message.reply("成功取消任务")
|
||||||
|
} else {
|
||||||
|
message.reply("你还没开启任务呢")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
"message" -> {
|
||||||
|
val content = args.drop(1).joinToString(" ").trim()
|
||||||
|
userClientMap[message.sender.userId]!!.forEach { it.sendChat(content) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,126 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2025 RTAkland
|
||||||
|
* Author: RTAkland
|
||||||
|
* Date: 2025/1/15
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
package cn.rtast.fancybot.commands.misc
|
||||||
|
|
||||||
|
import cn.rtast.fancybot.annotations.CommandDescription
|
||||||
|
import cn.rtast.fancybot.util.misc.Resources
|
||||||
|
import cn.rtast.fancybot.util.misc.drawCenteredText
|
||||||
|
import cn.rtast.fancybot.util.misc.toByteArray
|
||||||
|
import cn.rtast.fancybot.util.str.encodeToBase64
|
||||||
|
import cn.rtast.rob.entity.GroupMessage
|
||||||
|
import cn.rtast.rob.segment.Image
|
||||||
|
import cn.rtast.rob.util.BaseCommand
|
||||||
|
import java.awt.Color
|
||||||
|
import java.awt.Font
|
||||||
|
import java.awt.RenderingHints
|
||||||
|
import javax.imageio.ImageIO
|
||||||
|
|
||||||
|
@CommandDescription("那我问你")
|
||||||
|
class NWWNCommand : BaseCommand() {
|
||||||
|
override val commandNames = listOf("nwwn", "那我问你")
|
||||||
|
private val originNWWNImage = Resources.loadFromResourcesAsBytes("misc/nwwn.png")
|
||||||
|
private val font = Font("SimSun", Font.BOLD, 55)
|
||||||
|
|
||||||
|
override suspend fun executeGroup(message: GroupMessage, args: List<String>) {
|
||||||
|
try {
|
||||||
|
val keyword = args.joinToString(" ")
|
||||||
|
val img = ImageIO.read(originNWWNImage!!.inputStream())
|
||||||
|
val g2d = img.createGraphics()
|
||||||
|
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON)
|
||||||
|
g2d.color = Color.BLACK
|
||||||
|
g2d.font = font
|
||||||
|
g2d.drawString(keyword, 290, 70)
|
||||||
|
g2d.dispose()
|
||||||
|
val imgBase64 = img.toByteArray().encodeToBase64()
|
||||||
|
val msg = Image(imgBase64, true)
|
||||||
|
message.reply(msg)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
message.reply("生成失败: ${e.message}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@CommandDescription("太几把搞笑了")
|
||||||
|
class TJBGXLCommand: BaseCommand() {
|
||||||
|
override val commandNames = listOf("太几把搞笑了", "tjbgxl", "jb")
|
||||||
|
|
||||||
|
private val originImage = Resources.loadFromResourcesAsBytes("misc/tjbgxl.png")
|
||||||
|
private val font = Font("SimSun", Font.BOLD, 45)
|
||||||
|
|
||||||
|
override suspend fun executeGroup(message: GroupMessage, args: List<String>) {
|
||||||
|
try {
|
||||||
|
val keyword = args.joinToString(" ")
|
||||||
|
val img = ImageIO.read(originImage!!.inputStream())
|
||||||
|
val g2d = img.createGraphics()
|
||||||
|
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON)
|
||||||
|
g2d.color = Color.BLACK
|
||||||
|
g2d.font = font
|
||||||
|
g2d.drawCenteredText(keyword, 380, 620)
|
||||||
|
g2d.dispose()
|
||||||
|
val imgBase64 = img.toByteArray().encodeToBase64()
|
||||||
|
val msg = Image(imgBase64, true)
|
||||||
|
message.reply(msg)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
message.reply("生成失败: ${e.message}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@CommandDescription("香奈美语句生成")
|
||||||
|
class XNMCommand: BaseCommand() {
|
||||||
|
override val commandNames = listOf("xnm", "香奈美")
|
||||||
|
|
||||||
|
private val font = Font("SimSun", Font.BOLD, 55)
|
||||||
|
private val originImage = Resources.loadFromResourcesAsBytes("misc/xnm.png")
|
||||||
|
|
||||||
|
override suspend fun executeGroup(message: GroupMessage, args: List<String>) {
|
||||||
|
try {
|
||||||
|
val keyword = args.first()
|
||||||
|
val keyword2 = args.last()
|
||||||
|
val img = ImageIO.read(originImage!!.inputStream())
|
||||||
|
val g2d = img.createGraphics()
|
||||||
|
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON)
|
||||||
|
g2d.color = Color.BLACK
|
||||||
|
g2d.font = font
|
||||||
|
g2d.drawCenteredText(keyword, 510, 55)
|
||||||
|
g2d.drawCenteredText(keyword2, 510, 140)
|
||||||
|
g2d.dispose()
|
||||||
|
val imgBase64 = img.toByteArray().encodeToBase64()
|
||||||
|
val msg = Image(imgBase64, true)
|
||||||
|
message.reply(msg)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
message.reply("生成失败: ${e.message}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@CommandDescription("设静")
|
||||||
|
class SJCommand: BaseCommand() {
|
||||||
|
override val commandNames = listOf("sj")
|
||||||
|
|
||||||
|
private val font = Font("SimSun", Font.BOLD, 20)
|
||||||
|
private val originImage = Resources.loadFromResourcesAsBytes("misc/sj.png")
|
||||||
|
|
||||||
|
override suspend fun executeGroup(message: GroupMessage, args: List<String>) {
|
||||||
|
try {
|
||||||
|
val keyword = args.joinToString(" ")
|
||||||
|
val img = ImageIO.read(originImage!!.inputStream())
|
||||||
|
val g2d = img.createGraphics()
|
||||||
|
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON)
|
||||||
|
g2d.color = Color.BLACK
|
||||||
|
g2d.font = font
|
||||||
|
g2d.drawCenteredText(keyword, 126, 210)
|
||||||
|
g2d.dispose()
|
||||||
|
val imgBase64 = img.toByteArray().encodeToBase64()
|
||||||
|
val msg = Image(imgBase64, true)
|
||||||
|
message.reply(msg)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
message.reply("生成失败: ${e.message}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2024 RTAkland
|
||||||
|
* Author: RTAkland
|
||||||
|
* Date: 2024/10/14
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
package cn.rtast.fancybot.commands.misc
|
||||||
|
|
||||||
|
import cn.rtast.fancybot.API_RTAST_URL
|
||||||
|
import cn.rtast.fancybot.PBI_API_URL
|
||||||
|
import cn.rtast.fancybot.annotations.CommandDescription
|
||||||
|
import cn.rtast.fancybot.configManager
|
||||||
|
import cn.rtast.fancybot.entity.pastebin.PastebinPayload
|
||||||
|
import cn.rtast.fancybot.entity.pastebin.PastebinResponse
|
||||||
|
import cn.rtast.fancybot.enums.CommandAction
|
||||||
|
import cn.rtast.fancybot.util.Http
|
||||||
|
import cn.rtast.fancybot.util.file.insertActionRecord
|
||||||
|
import cn.rtast.fancybot.util.str.toJson
|
||||||
|
import cn.rtast.rob.entity.GroupMessage
|
||||||
|
import cn.rtast.rob.util.BaseCommand
|
||||||
|
|
||||||
|
@CommandDescription("Pastebin!")
|
||||||
|
class PastebinCommand : BaseCommand() {
|
||||||
|
override val commandNames = listOf("/pastebin", "/pb")
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun createPastebin(content: String): String {
|
||||||
|
val pastebinPayload = PastebinPayload(content)
|
||||||
|
val response = Http.post<PastebinResponse>(
|
||||||
|
"$API_RTAST_URL/api/pastebin", pastebinPayload.toJson(),
|
||||||
|
params = mapOf("key" to configManager.apiRtastKey)
|
||||||
|
)
|
||||||
|
return "https://api.rtast.cn/-/${response.id}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun executeGroup(message: GroupMessage, args: List<String>) {
|
||||||
|
if (args.isEmpty()) {
|
||||||
|
message.reply("使用`/pb <内容>`或者回复一个消息`/pb`可以快速创建一个pastebin")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val content = args.joinToString(" ")
|
||||||
|
message.reply(createPastebin(content))
|
||||||
|
insertActionRecord(CommandAction.Pastebin, message.sender.userId, content)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,95 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2024 RTAkland
|
||||||
|
* Author: RTAkland
|
||||||
|
* Date: 2024/8/30
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
package cn.rtast.fancybot.commands.misc
|
||||||
|
|
||||||
|
import cn.rtast.fancybot.annotations.CommandDescription
|
||||||
|
import cn.rtast.fancybot.enums.CommandAction
|
||||||
|
import cn.rtast.fancybot.util.file.insertActionRecord
|
||||||
|
import cn.rtast.fancybot.util.misc.toBufferedImage
|
||||||
|
import cn.rtast.fancybot.util.misc.toByteArray
|
||||||
|
import cn.rtast.fancybot.util.str.encodeToBase64
|
||||||
|
import cn.rtast.rob.entity.GroupMessage
|
||||||
|
import cn.rtast.rob.enums.ArrayMessageType
|
||||||
|
import cn.rtast.rob.onebot.MessageChain
|
||||||
|
import cn.rtast.rob.util.BaseCommand
|
||||||
|
import com.google.zxing.BarcodeFormat
|
||||||
|
import com.google.zxing.BinaryBitmap
|
||||||
|
import com.google.zxing.EncodeHintType
|
||||||
|
import com.google.zxing.MultiFormatReader
|
||||||
|
import com.google.zxing.client.j2se.BufferedImageLuminanceSource
|
||||||
|
import com.google.zxing.client.j2se.MatrixToImageWriter
|
||||||
|
import com.google.zxing.common.HybridBinarizer
|
||||||
|
import com.google.zxing.qrcode.QRCodeWriter
|
||||||
|
import java.awt.image.BufferedImage
|
||||||
|
import java.net.URI
|
||||||
|
|
||||||
|
@CommandDescription("生成二维码")
|
||||||
|
class GenerateQRCodeCommand : BaseCommand() {
|
||||||
|
override val commandNames = listOf("/qr")
|
||||||
|
|
||||||
|
private fun generateQRCode(content: String): String {
|
||||||
|
val qrCodeWriter = QRCodeWriter()
|
||||||
|
val hints = mapOf(EncodeHintType.CHARACTER_SET to "UTF-8")
|
||||||
|
val bitMatrix = qrCodeWriter.encode(content, BarcodeFormat.QR_CODE, 300, 300, hints)
|
||||||
|
return MatrixToImageWriter.toBufferedImage(bitMatrix).toByteArray().encodeToBase64()
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun executeGroup(message: GroupMessage, args: List<String>) {
|
||||||
|
if (args.isEmpty()) {
|
||||||
|
message.reply("发送`/qr <内容>`即可生成一张二维码的图片")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val content = args.joinToString(" ")
|
||||||
|
val image = this.generateQRCode(content)
|
||||||
|
val msg = MessageChain.Builder()
|
||||||
|
.addImage(image, true)
|
||||||
|
.build()
|
||||||
|
message.reply(msg)
|
||||||
|
insertActionRecord(CommandAction.GenQRCode, message.sender.userId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@CommandDescription("解析二维码中的内容!")
|
||||||
|
class ScanQRCodeCommand : BaseCommand() {
|
||||||
|
override val commandNames = listOf("/scan")
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
private val waitingList = mutableListOf<Long>()
|
||||||
|
|
||||||
|
private fun scanQRCode(image: BufferedImage): String {
|
||||||
|
val luminanceSource = BufferedImageLuminanceSource(image)
|
||||||
|
val binaryBitmap = BinaryBitmap(HybridBinarizer(luminanceSource))
|
||||||
|
val result = MultiFormatReader().decode(binaryBitmap)
|
||||||
|
return result.text
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun callback(message: GroupMessage) {
|
||||||
|
if (message.sender() in waitingList) {
|
||||||
|
waitingList.remove(message.sender())
|
||||||
|
if (!message.message.any { it.type == ArrayMessageType.image }) {
|
||||||
|
message.reply("回复错误已取消本次操作")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val image = message.message.find { it.type == ArrayMessageType.image }?.data?.file!!
|
||||||
|
val bufferedImage = URI(image).toURL().readBytes().toBufferedImage()
|
||||||
|
val result = this.scanQRCode(bufferedImage)
|
||||||
|
message.reply("二维码扫描结果: $result")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun executeGroup(message: GroupMessage, args: List<String>) {
|
||||||
|
if (message.sender() !in waitingList) {
|
||||||
|
waitingList.add(message.sender())
|
||||||
|
message.reply("继续发送一张二维码图片")
|
||||||
|
} else {
|
||||||
|
message.reply("回复错误已经取消本次操作")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,23 +7,24 @@
|
|||||||
|
|
||||||
package cn.rtast.fancybot.commands.misc
|
package cn.rtast.fancybot.commands.misc
|
||||||
|
|
||||||
|
import cn.rtast.fancybot.annotations.CommandDescription
|
||||||
import cn.rtast.rob.entity.GroupMessage
|
import cn.rtast.rob.entity.GroupMessage
|
||||||
import cn.rtast.rob.enums.ArrayMessageType
|
import cn.rtast.rob.enums.ArrayMessageType
|
||||||
|
import cn.rtast.rob.onebot.MessageChain
|
||||||
import cn.rtast.rob.util.BaseCommand
|
import cn.rtast.rob.util.BaseCommand
|
||||||
import cn.rtast.rob.util.ob.MessageChain
|
|
||||||
import cn.rtast.rob.util.ob.OneBotListener
|
|
||||||
|
|
||||||
|
@CommandDescription("RUA!")
|
||||||
class RUACommand : BaseCommand() {
|
class RUACommand : BaseCommand() {
|
||||||
override val commandNames = listOf("/rua", "rua")
|
override val commandNames = listOf("/rua", "rua")
|
||||||
|
|
||||||
override suspend fun executeGroup(listener: OneBotListener, message: GroupMessage, args: List<String>) {
|
override suspend fun executeGroup(message: GroupMessage, args: List<String>) {
|
||||||
if (args.isEmpty()) {
|
if (args.isEmpty()) {
|
||||||
val msg = MessageChain.Builder()
|
val msg = MessageChain.Builder()
|
||||||
.addAt(message.sender.userId)
|
.addAt(message.sender.userId)
|
||||||
.addText("使用rua @xxxx")
|
.addText("使用rua @xxxx")
|
||||||
.addText("即可rua某人啦~")
|
.addText("即可rua某人啦~")
|
||||||
.build()
|
.build()
|
||||||
listener.sendGroupMessage(message.groupId, msg)
|
message.reply(msg)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
@@ -36,13 +37,13 @@ class RUACommand : BaseCommand() {
|
|||||||
.addText(" ")
|
.addText(" ")
|
||||||
.addText("rua了你~")
|
.addText("rua了你~")
|
||||||
.build()
|
.build()
|
||||||
listener.sendGroupMessage(message.groupId, msg)
|
message.reply(msg)
|
||||||
} catch (_: NullPointerException) {
|
} catch (_: NullPointerException) {
|
||||||
val msg = MessageChain.Builder()
|
val msg = MessageChain.Builder()
|
||||||
.addAt(message.sender.userId)
|
.addAt(message.sender.userId)
|
||||||
.addText("要@才有用哦~")
|
.addText("要@才有用哦~")
|
||||||
.build()
|
.build()
|
||||||
listener.sendGroupMessage(message.groupId, msg)
|
message.reply(msg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2024 RTAkland
|
||||||
|
* Author: RTAkland
|
||||||
|
* Date: 2024/10/3
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
package cn.rtast.fancybot.commands.misc
|
||||||
|
|
||||||
|
import cn.rtast.fancybot.annotations.CommandDescription
|
||||||
|
import cn.rtast.fancybot.configManager
|
||||||
|
import cn.rtast.fancybot.entity.music.TopSong
|
||||||
|
import cn.rtast.fancybot.util.Http
|
||||||
|
import cn.rtast.rob.entity.GroupMessage
|
||||||
|
import cn.rtast.rob.enums.MusicShareType
|
||||||
|
import cn.rtast.rob.onebot.MessageChain
|
||||||
|
import cn.rtast.rob.util.BaseCommand
|
||||||
|
|
||||||
|
@CommandDescription("获取随机热榜音乐(网易云)")
|
||||||
|
class RandomMusicCommand : BaseCommand() {
|
||||||
|
override val commandNames = listOf("随机音乐", "随机歌曲")
|
||||||
|
|
||||||
|
private val ncmApiUrl = "${configManager.ncmAPI}/top/song"
|
||||||
|
|
||||||
|
override suspend fun executeGroup(message: GroupMessage, args: List<String>) {
|
||||||
|
val id = Http.get<TopSong>(ncmApiUrl).data.random().privilege.id
|
||||||
|
val msg = MessageChain.Builder()
|
||||||
|
.addMusicShare(MusicShareType.Netease, id.toString())
|
||||||
|
.build()
|
||||||
|
message.reply(msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2024 RTAkland
|
||||||
|
* Author: RTAkland
|
||||||
|
* Date: 2024/10/1
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
package cn.rtast.fancybot.commands.misc
|
||||||
|
|
||||||
|
import cn.rtast.fancybot.annotations.CommandDescription
|
||||||
|
import cn.rtast.rob.entity.GroupMessage
|
||||||
|
import cn.rtast.rob.enums.QQFace
|
||||||
|
import cn.rtast.rob.onebot.OneBotAction
|
||||||
|
import cn.rtast.rob.util.BaseCommand
|
||||||
|
|
||||||
|
@CommandDescription("让你的消息得到回应(reaction)!")
|
||||||
|
class ReactionCommand : BaseCommand() {
|
||||||
|
override val commandNames = listOf("reaction", "回应")
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
suspend fun reaction(action: OneBotAction, groupId: Long, messageId: Long, limit: Int = 30) {
|
||||||
|
(0..limit - 1).forEach { action.reaction(groupId, messageId, QQFace.entries.random().id.toString()) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun executeGroup(message: GroupMessage, args: List<String>) =
|
||||||
|
reaction(message.action, message.groupId, message.messageId)
|
||||||
|
}
|
||||||
@@ -7,15 +7,16 @@
|
|||||||
|
|
||||||
package cn.rtast.fancybot.commands.misc
|
package cn.rtast.fancybot.commands.misc
|
||||||
|
|
||||||
import cn.rtast.fancybot.entity.enums.CountryList
|
import cn.rtast.fancybot.annotations.CommandDescription
|
||||||
import cn.rtast.fancybot.util.randomBooleanWithProbability
|
import cn.rtast.fancybot.enums.CountryList
|
||||||
|
import cn.rtast.fancybot.util.misc.randomBooleanWithProbability
|
||||||
import cn.rtast.rob.entity.GroupMessage
|
import cn.rtast.rob.entity.GroupMessage
|
||||||
|
import cn.rtast.rob.onebot.MessageChain
|
||||||
import cn.rtast.rob.util.BaseCommand
|
import cn.rtast.rob.util.BaseCommand
|
||||||
import cn.rtast.rob.util.ob.MessageChain
|
|
||||||
import cn.rtast.rob.util.ob.OneBotListener
|
|
||||||
|
|
||||||
|
@CommandDescription("人生重开模拟器")
|
||||||
class RemakeCommand : BaseCommand() {
|
class RemakeCommand : BaseCommand() {
|
||||||
override val commandNames = listOf("/remake", "/重开", "remake", "重开")
|
override val commandNames = listOf("remake")
|
||||||
|
|
||||||
private val locations = listOf(
|
private val locations = listOf(
|
||||||
"厕所", "首都", "农村", "市区",
|
"厕所", "首都", "农村", "市区",
|
||||||
@@ -28,7 +29,7 @@ class RemakeCommand : BaseCommand() {
|
|||||||
"鸽子", "鼠鼠", "化石", "狗狗"
|
"鸽子", "鼠鼠", "化石", "狗狗"
|
||||||
)
|
)
|
||||||
|
|
||||||
override suspend fun executeGroup(listener: OneBotListener, message: GroupMessage, args: List<String>) {
|
override suspend fun executeGroup(message: GroupMessage, args: List<String>) {
|
||||||
val isSuccess = randomBooleanWithProbability(0.7)
|
val isSuccess = randomBooleanWithProbability(0.7)
|
||||||
val msg = MessageChain.Builder().addReply(message.messageId)
|
val msg = MessageChain.Builder().addReply(message.messageId)
|
||||||
if (isSuccess) {
|
if (isSuccess) {
|
||||||
@@ -38,6 +39,6 @@ class RemakeCommand : BaseCommand() {
|
|||||||
msg.addText("重开成功! 你转生在${country.chineseName}的$location, 是一个$role")
|
msg.addText("重开成功! 你转生在${country.chineseName}的$location, 是一个$role")
|
||||||
} else
|
} else
|
||||||
msg.addText("转生失败~")
|
msg.addText("转生失败~")
|
||||||
listener.sendGroupMessage(message.groupId, msg.build())
|
message.reply(msg.build())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2024 RTAkland
|
||||||
|
* Author: RTAkland
|
||||||
|
* Date: 2024/9/8
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
package cn.rtast.fancybot.commands.misc
|
||||||
|
|
||||||
|
import cn.rtast.fancybot.annotations.CommandDescription
|
||||||
|
import cn.rtast.rob.entity.GroupMessage
|
||||||
|
import cn.rtast.rob.onebot.MessageChain
|
||||||
|
import cn.rtast.rob.util.BaseCommand
|
||||||
|
|
||||||
|
@CommandDescription("资料卡点赞")
|
||||||
|
class SendLikeCommand : BaseCommand() {
|
||||||
|
override val commandNames = listOf("赞我")
|
||||||
|
|
||||||
|
override suspend fun executeGroup(message: GroupMessage, args: List<String>) {
|
||||||
|
message.action.sendLike(message.sender.userId, 10)
|
||||||
|
val msg = MessageChain.Builder()
|
||||||
|
.addText("👍了你十下~~😁")
|
||||||
|
.build()
|
||||||
|
message.reply(msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,15 +7,17 @@
|
|||||||
|
|
||||||
package cn.rtast.fancybot.commands.misc
|
package cn.rtast.fancybot.commands.misc
|
||||||
|
|
||||||
|
import cn.rtast.fancybot.annotations.CommandDescription
|
||||||
import cn.rtast.fancybot.configManager
|
import cn.rtast.fancybot.configManager
|
||||||
|
import cn.rtast.fancybot.enums.CommandAction
|
||||||
|
import cn.rtast.fancybot.util.file.insertActionRecord
|
||||||
import cn.rtast.rob.entity.GroupMessage
|
import cn.rtast.rob.entity.GroupMessage
|
||||||
import cn.rtast.rob.util.BaseCommand
|
import cn.rtast.rob.util.BaseCommand
|
||||||
import cn.rtast.rob.util.ob.MessageChain
|
|
||||||
import cn.rtast.rob.util.ob.OneBotListener
|
|
||||||
import org.simplejavamail.api.mailer.config.TransportStrategy
|
import org.simplejavamail.api.mailer.config.TransportStrategy
|
||||||
import org.simplejavamail.email.EmailBuilder
|
import org.simplejavamail.email.EmailBuilder
|
||||||
import org.simplejavamail.mailer.MailerBuilder
|
import org.simplejavamail.mailer.MailerBuilder
|
||||||
|
|
||||||
|
@CommandDescription("发送邮件!")
|
||||||
class SendMailCommand : BaseCommand() {
|
class SendMailCommand : BaseCommand() {
|
||||||
override val commandNames = listOf("/mail")
|
override val commandNames = listOf("/mail")
|
||||||
|
|
||||||
@@ -40,29 +42,18 @@ class SendMailCommand : BaseCommand() {
|
|||||||
this.mailer.sendMail(email)
|
this.mailer.sendMail(email)
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun executeGroup(listener: OneBotListener, message: GroupMessage, args: List<String>) {
|
override suspend fun executeGroup(message: GroupMessage, args: List<String>) {
|
||||||
if (args.isEmpty()) {
|
if (args.isEmpty()) {
|
||||||
val msg = MessageChain.Builder()
|
message.reply("发送`/mail <收件人地址>`即可发送测试邮件~")
|
||||||
.addAt(message.sender.userId)
|
|
||||||
.addText("发送`/mail <收件人地址>`即可发送测试邮件~")
|
|
||||||
.build()
|
|
||||||
listener.sendGroupMessage(message.groupId, msg)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (message.sender.userId !in configManager.admins) {
|
|
||||||
val msg = MessageChain.Builder()
|
|
||||||
.addReply(message.messageId)
|
|
||||||
.addText("你不许发邮件")
|
|
||||||
.build()
|
|
||||||
listener.sendGroupMessage(message.groupId, msg)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if (message.sender.isAdmin || message.sender.isOwner) {
|
||||||
val target = args.first()
|
val target = args.first()
|
||||||
this.sendMail(target)
|
this.sendMail(target)
|
||||||
val msg = MessageChain.Builder()
|
message.reply("正在发送邮件, 请查收~(可能会出现在垃圾桶中~)")
|
||||||
.addAt(message.sender.userId)
|
insertActionRecord(CommandAction.SendMail, message.sender.userId, target)
|
||||||
.addText("正在发送邮件, 请查收~(可能会出现在垃圾桶中~)")
|
} else {
|
||||||
.build()
|
message.reply("你不许发邮件")
|
||||||
listener.sendGroupMessage(message.groupId, msg)
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2024 RTAkland
|
||||||
|
* Author: RTAkland
|
||||||
|
* Date: 2024/9/22
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
package cn.rtast.fancybot.commands.misc
|
||||||
|
|
||||||
|
import cn.rtast.fancybot.API_RTAST_URL
|
||||||
|
import cn.rtast.fancybot.annotations.CommandDescription
|
||||||
|
import cn.rtast.fancybot.configManager
|
||||||
|
import cn.rtast.fancybot.entity.shortlink.ShortLinkPayload
|
||||||
|
import cn.rtast.fancybot.entity.shortlink.ShortLinkResponse
|
||||||
|
import cn.rtast.fancybot.util.Http
|
||||||
|
import cn.rtast.fancybot.util.str.toJson
|
||||||
|
import cn.rtast.rob.entity.GroupMessage
|
||||||
|
import cn.rtast.rob.util.BaseCommand
|
||||||
|
|
||||||
|
@CommandDescription("生成短链接")
|
||||||
|
class ShortLinkCommand : BaseCommand() {
|
||||||
|
override val commandNames = listOf("/s")
|
||||||
|
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun String.makeShortLink(): String {
|
||||||
|
val shortLink = Http.post<ShortLinkResponse>(
|
||||||
|
"$API_RTAST_URL/api/sl",
|
||||||
|
ShortLinkPayload(this).toJson(),
|
||||||
|
params = mapOf("key" to configManager.apiRtastKey)
|
||||||
|
)
|
||||||
|
return "$API_RTAST_URL/${shortLink.id}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun executeGroup(message: GroupMessage, args: List<String>) {
|
||||||
|
if (args.isEmpty()) {
|
||||||
|
message.reply("发送`/s <url>`来生成短链接`不要放入一些奇怪的链接哦~")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val target = args.first()
|
||||||
|
val shortLink = target.makeShortLink()
|
||||||
|
message.reply(shortLink)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2024 RTAkland
|
||||||
|
* Author: RTAkland
|
||||||
|
* Date: 2024/10/7
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
package cn.rtast.fancybot.commands.misc
|
||||||
|
|
||||||
|
import cn.rtast.fancybot.annotations.CommandDescription
|
||||||
|
import cn.rtast.fancybot.entity.tts.TTSResponse
|
||||||
|
import cn.rtast.fancybot.util.Http
|
||||||
|
import cn.rtast.fancybot.util.str.proxy
|
||||||
|
import cn.rtast.rob.entity.GroupMessage
|
||||||
|
import cn.rtast.rob.enums.AIRecordCharacter
|
||||||
|
import cn.rtast.rob.onebot.MessageChain
|
||||||
|
import cn.rtast.rob.util.BaseCommand
|
||||||
|
import okhttp3.FormBody
|
||||||
|
|
||||||
|
@CommandDescription("将文字转换成语音(TTS)!")
|
||||||
|
class TTSCommand : BaseCommand() {
|
||||||
|
override val commandNames = listOf("/tts")
|
||||||
|
|
||||||
|
private val ttsApiUrl = "https://ttsmp3.com/makemp3_new.php"
|
||||||
|
|
||||||
|
override suspend fun executeGroup(message: GroupMessage, args: List<String>) {
|
||||||
|
if (args.isEmpty()) {
|
||||||
|
message.reply("发送`/tts <文字>`就可以生成语音啦~")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val content = args.joinToString(" ").trim()
|
||||||
|
val form = FormBody.Builder()
|
||||||
|
.add("msg", content)
|
||||||
|
.add("lang", "Zhiyu")
|
||||||
|
.add("source", "ttsmp3")
|
||||||
|
.build()
|
||||||
|
val response = Http.post<TTSResponse>(ttsApiUrl, form)
|
||||||
|
val msg = MessageChain.Builder()
|
||||||
|
.addRecord(response.url.proxy)
|
||||||
|
.build()
|
||||||
|
message.reply(msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class AITTSCommand : BaseCommand() {
|
||||||
|
override val commandNames = listOf("/aitts")
|
||||||
|
|
||||||
|
override suspend fun executeGroup(message: GroupMessage, args: List<String>) {
|
||||||
|
val content = args.joinToString(" ").trim()
|
||||||
|
val character = if (args.size == 1) AIRecordCharacter.XiaoXin
|
||||||
|
else AIRecordCharacter.forName(args.last()) ?: AIRecordCharacter.XiaoXin
|
||||||
|
message.action.sendGroupAIRecord(message.groupId, character, content)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,48 +1,32 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright © 2024 RTAkland
|
* Copyright © 2024 RTAkland
|
||||||
* Author: RTAkland
|
* Author: RTAkland
|
||||||
* Date: 2024/9/23
|
* Date: 2024/9/29
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
package cn.rtast.fancybot.commands.misc
|
package cn.rtast.fancybot.commands.misc
|
||||||
|
|
||||||
import cn.rtast.fancybot.entity.Setu
|
import cn.rtast.fancybot.annotations.CommandDescription
|
||||||
import cn.rtast.fancybot.util.Http
|
|
||||||
import cn.rtast.fancybot.util.str.encodeToBase64
|
|
||||||
import cn.rtast.fancybot.util.str.fromArrayJson
|
|
||||||
import cn.rtast.rob.entity.GroupMessage
|
import cn.rtast.rob.entity.GroupMessage
|
||||||
import cn.rtast.rob.segment.Node
|
import cn.rtast.rob.onebot.MessageChain
|
||||||
import cn.rtast.rob.util.BaseCommand
|
import cn.rtast.rob.util.BaseCommand
|
||||||
import cn.rtast.rob.util.ob.MessageChain
|
|
||||||
import cn.rtast.rob.util.ob.NodeMessageChain
|
|
||||||
import cn.rtast.rob.util.ob.OneBotListener
|
|
||||||
import java.net.URI
|
|
||||||
|
|
||||||
|
@Deprecated("已迁移到兑换列表中")
|
||||||
|
@CommandDescription("获得十张色图!")
|
||||||
class TenSetuCommand : BaseCommand() {
|
class TenSetuCommand : BaseCommand() {
|
||||||
override val commandNames = listOf("十张色图")
|
override val commandNames = listOf("十张色图")
|
||||||
|
|
||||||
override suspend fun executeGroup(listener: OneBotListener, message: GroupMessage, args: List<String>) {
|
override suspend fun executeGroup(message: GroupMessage, args: List<String>) {
|
||||||
val nodeMsg = NodeMessageChain.Builder()
|
val msg = MessageChain.Builder()
|
||||||
val response = Http.get("https://api.rtast.cn/api/setu?size=10").fromArrayJson<List<Setu>>()
|
.addText("指令已经迁移到兑换列表中")
|
||||||
response.forEach {
|
|
||||||
if (it.r18) {
|
|
||||||
try {
|
|
||||||
val imageBase64 = URI(it.urls.large).toURL().readBytes().encodeToBase64()
|
|
||||||
val tempMsg = MessageChain.Builder().addImage(imageBase64, true).build()
|
|
||||||
val tempNode = Node(Node.Data("", message.userId.toString(), tempMsg.finalArrayMsgList))
|
|
||||||
nodeMsg.addNode(tempNode)
|
|
||||||
} catch (_: Exception) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
val footerMsg = MessageChain.Builder()
|
|
||||||
.addText("图片数量可能不足10张~")
|
|
||||||
.addNewLine()
|
.addNewLine()
|
||||||
.addText("因为过滤了R18的图片~")
|
.addText("使用`/rdm 十张色图`来兑换吧~")
|
||||||
|
.addNewLine()
|
||||||
|
.addText("(需要20cm的牛子长度来兑换)")
|
||||||
|
.addNewLine()
|
||||||
|
.addText("此指令已废弃")
|
||||||
.build()
|
.build()
|
||||||
val footerNode = Node(Node.Data("", message.userId.toString(), footerMsg.finalArrayMsgList))
|
message.reply(msg)
|
||||||
nodeMsg.addNode(footerNode)
|
|
||||||
listener.sendGroupForwardMsg(message.groupId, nodeMsg.build())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,89 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2024 RTAkland
|
||||||
|
* Author: RTAkland
|
||||||
|
* Date: 2024/10/11
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
package cn.rtast.fancybot.commands.misc
|
||||||
|
|
||||||
|
import cn.rtast.fancybot.annotations.CommandDescription
|
||||||
|
import cn.rtast.rob.entity.GroupMessage
|
||||||
|
import cn.rtast.rob.util.BaseCommand
|
||||||
|
import kotlin.random.Random
|
||||||
|
|
||||||
|
@CommandDescription("今天吃什么")
|
||||||
|
class TodayEatCommand : BaseCommand() {
|
||||||
|
override val commandNames = listOf("今天吃什么")
|
||||||
|
|
||||||
|
private val foodList = listOf(
|
||||||
|
"炒饭", "火锅", "汉堡", "披萨", "寿司", "拉面", "炸鸡", "米粉",
|
||||||
|
"牛排", "烤串", "沙拉", "饺子", "意大利面", "烤鸭", "豆腐脑",
|
||||||
|
"蛋糕", "烧烤", "咖喱饭", "麻辣烫", "烤鱼", "牛肉面", "凉皮",
|
||||||
|
"西餐", "日式便当", "韩式拌饭", "生煎包", "炸酱面", "煎饼果子",
|
||||||
|
"酸辣粉", "煲仔饭", "⑩", "史"
|
||||||
|
)
|
||||||
|
|
||||||
|
override suspend fun executeGroup(message: GroupMessage, args: List<String>) {
|
||||||
|
if (KFCCommand.isThursday() && Random.nextBoolean()) {
|
||||||
|
message.reply("今天是疯! 狂! 星! 期! 四!, 所以吃肯德基!")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
message.reply("今天吃${foodList.random()}吧~")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@CommandDescription("今天不吃什么")
|
||||||
|
class TodayDontEatCommand : BaseCommand() {
|
||||||
|
override val commandNames = listOf("今天不吃什么")
|
||||||
|
|
||||||
|
override suspend fun executeGroup(message: GroupMessage, args: List<String>) {
|
||||||
|
message.reply("你吃个结巴, 是吧")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@CommandDescription("今天喝什么")
|
||||||
|
class TodayDrinkCommand : BaseCommand() {
|
||||||
|
override val commandNames = listOf("今天喝什么")
|
||||||
|
|
||||||
|
private val drinkList = listOf(
|
||||||
|
"咖啡", "绿茶", "奶茶", "橙汁", "苹果汁", "可乐", "啤酒", "矿泉水",
|
||||||
|
"苏打水", "红茶", "酸梅汤", "豆浆", "椰子水", "冰沙", "葡萄汁",
|
||||||
|
"柠檬水", "奶昔", "热巧克力", "果茶", "乌龙茶", "茉莉花茶", "白开水",
|
||||||
|
"气泡水", "奶盖茶", "冰可乐", "草莓汁", "芒果汁", "蓝莓汁", "热奶茶", "蜂蜜柚子茶"
|
||||||
|
)
|
||||||
|
|
||||||
|
override suspend fun executeGroup(message: GroupMessage, args: List<String>) {
|
||||||
|
message.reply("今天喝${drinkList.random()}吧~")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@CommandDescription("今天不吃什么")
|
||||||
|
class TodayDontDrinkCommand : BaseCommand() {
|
||||||
|
override val commandNames = listOf("今天不喝什么")
|
||||||
|
|
||||||
|
override suspend fun executeGroup(message: GroupMessage, args: List<String>) {
|
||||||
|
message.reply("你喝个结巴, 是吧")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@CommandDescription("今天抽什么")
|
||||||
|
class TodaySmokeCommand : BaseCommand() {
|
||||||
|
override val commandNames = listOf("今天抽什么")
|
||||||
|
|
||||||
|
private val smokeList = listOf(
|
||||||
|
"黑利", "蓝利", "白利", "普皖", "金皖",
|
||||||
|
"宽窄", "煊赫门", "骆驼", "百乐(红酒)",
|
||||||
|
"手卷烟", "烟斗", "万宝路", "白沙3代",
|
||||||
|
"白沙2代", "中华", "南京-大观园", "金钗",
|
||||||
|
"银钗", "玉溪", "芒果", "南京-雨花石",
|
||||||
|
"金圣", "南京95", "红塔山", "轿子",
|
||||||
|
"钻石荷花", "黄金叶(天叶)", "芙蓉王",
|
||||||
|
"黄鹤楼", "红河", "长白山", "长丰",
|
||||||
|
"中南海(蓝莓爆珠)", "云烟", "真龙", "红利"
|
||||||
|
)
|
||||||
|
|
||||||
|
override suspend fun executeGroup(message: GroupMessage, args: List<String>) {
|
||||||
|
message.reply("今天抽${smokeList.random()}吧~")
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2024 RTAkland
|
||||||
|
* Author: RTAkland
|
||||||
|
* Date: 2024/10/5
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
package cn.rtast.fancybot.commands.misc
|
||||||
|
|
||||||
|
import cn.rtast.fancybot.annotations.CommandDescription
|
||||||
|
import cn.rtast.fancybot.util.str.decodeToString
|
||||||
|
import cn.rtast.fancybot.util.str.encodeToBase64
|
||||||
|
import cn.rtast.rob.entity.GroupMessage
|
||||||
|
import cn.rtast.rob.enums.ArrayMessageType
|
||||||
|
import cn.rtast.rob.util.BaseCommand
|
||||||
|
|
||||||
|
@CommandDescription("将人类的语言翻译成尊嘟假嘟语还能将尊嘟假嘟语翻译成人类的语言!")
|
||||||
|
class ZDJDCommand : BaseCommand() {
|
||||||
|
override val commandNames = listOf("尊嘟假嘟", "zdjd")
|
||||||
|
|
||||||
|
private val b64 = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ+/="
|
||||||
|
private val leftEye = listOf("o", "0", "O", "Ö")
|
||||||
|
private val mouse = listOf("w", "v", ".", "_")
|
||||||
|
private val rightEye = listOf("o", "0", "O", "Ö")
|
||||||
|
private val table = mutableListOf<String>()
|
||||||
|
private val separator = " "
|
||||||
|
|
||||||
|
init {
|
||||||
|
makeTable()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun makeTable() {
|
||||||
|
for (i in leftEye.indices) {
|
||||||
|
for (j in mouse.indices) {
|
||||||
|
for (k in rightEye.indices) {
|
||||||
|
table.add(leftEye[i] + mouse[j] + rightEye[k])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun human2zdjd(text: String): String {
|
||||||
|
val encoded = text.encodeToBase64()
|
||||||
|
val arr = mutableListOf<String>()
|
||||||
|
for (c in encoded) {
|
||||||
|
if (c != '=') {
|
||||||
|
val n = b64.indexOf(c)
|
||||||
|
arr.add(table[n])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return arr.joinToString(separator)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun zdjd2human(t: String): String {
|
||||||
|
val arr = t.split(separator)
|
||||||
|
val resultArr = mutableListOf<String>()
|
||||||
|
for (c in arr) {
|
||||||
|
if (c.isEmpty()) continue
|
||||||
|
val n = table.indexOf(c)
|
||||||
|
if (n < 0) throw IllegalArgumentException("Invalid zdjd code")
|
||||||
|
resultArr.add(b64[n].toString())
|
||||||
|
}
|
||||||
|
var base64String = resultArr.joinToString("")
|
||||||
|
val padding = resultArr.size % 4
|
||||||
|
if (padding > 0) {
|
||||||
|
base64String += "=".repeat(4 - padding)
|
||||||
|
}
|
||||||
|
return base64String.decodeToString()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun String.isZdjd(): Boolean {
|
||||||
|
return try {
|
||||||
|
zdjd2human(this)
|
||||||
|
true
|
||||||
|
} catch (_: Exception) {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun executeGroup(message: GroupMessage, args: List<String>) {
|
||||||
|
val text = if (message.message.any { it.type == ArrayMessageType.image }) {
|
||||||
|
message.message.find { it.type == ArrayMessageType.image }!!.data.file!!
|
||||||
|
} else args.joinToString(" ")
|
||||||
|
if (text.isZdjd()) {
|
||||||
|
message.reply(zdjd2human(text))
|
||||||
|
} else {
|
||||||
|
message.reply(human2zdjd(text))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,18 +7,19 @@
|
|||||||
|
|
||||||
package cn.rtast.fancybot.commands.misc
|
package cn.rtast.fancybot.commands.misc
|
||||||
|
|
||||||
|
import cn.rtast.fancybot.annotations.CommandDescription
|
||||||
import cn.rtast.rob.entity.GroupMessage
|
import cn.rtast.rob.entity.GroupMessage
|
||||||
import cn.rtast.rob.entity.PrivateMessage
|
import cn.rtast.rob.entity.PrivateMessage
|
||||||
|
import cn.rtast.rob.onebot.MessageChain
|
||||||
import cn.rtast.rob.util.BaseCommand
|
import cn.rtast.rob.util.BaseCommand
|
||||||
import cn.rtast.rob.util.ob.MessageChain
|
|
||||||
import cn.rtast.rob.util.ob.OneBotListener
|
|
||||||
|
|
||||||
val users = mutableMapOf<Long, Long>()
|
val users = mutableMapOf<Long, Long>()
|
||||||
|
|
||||||
|
@CommandDescription("自闭去吧你")
|
||||||
class ZiBiCommand : BaseCommand() {
|
class ZiBiCommand : BaseCommand() {
|
||||||
override val commandNames = listOf("/自闭", "自闭")
|
override val commandNames = listOf("/自闭", "自闭")
|
||||||
|
|
||||||
override suspend fun executeGroup(listener: OneBotListener, message: GroupMessage, args: List<String>) {
|
override suspend fun executeGroup(message: GroupMessage, args: List<String>) {
|
||||||
try {
|
try {
|
||||||
users.remove(message.sender.userId)
|
users.remove(message.sender.userId)
|
||||||
val duration = if (args.isEmpty()) 1 else args.first().toInt()
|
val duration = if (args.isEmpty()) 1 else args.first().toInt()
|
||||||
@@ -29,21 +30,23 @@ class ZiBiCommand : BaseCommand() {
|
|||||||
.addText("私聊发送`我想开了`即可取消禁言~")
|
.addText("私聊发送`我想开了`即可取消禁言~")
|
||||||
.build()
|
.build()
|
||||||
message.reply(msg)
|
message.reply(msg)
|
||||||
users[message.sender.userId] = message.groupId
|
|
||||||
} catch (_: Exception) {
|
} catch (_: Exception) {
|
||||||
val msg = MessageChain.Builder()
|
val msg = MessageChain.Builder()
|
||||||
.addText("你输入有误所以我决定让你自闭1天~")
|
.addText("你输入有误所以我决定让你自闭1天~")
|
||||||
.build()
|
.build()
|
||||||
message.reply(msg)
|
message.reply(msg)
|
||||||
message.sender.ban(86400)
|
message.sender.ban(86400)
|
||||||
|
} finally {
|
||||||
|
users[message.sender.userId] = message.groupId
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@CommandDescription("我好像突然想开了")
|
||||||
class UnsetZiBiCommand : BaseCommand() {
|
class UnsetZiBiCommand : BaseCommand() {
|
||||||
override val commandNames = listOf("我想开了")
|
override val commandNames = listOf("我想开了")
|
||||||
|
|
||||||
override suspend fun executePrivate(listener: OneBotListener, message: PrivateMessage, args: List<String>) {
|
override suspend fun executePrivate(message: PrivateMessage, args: List<String>) {
|
||||||
if (!users.any { it.key == message.sender.userId }) {
|
if (!users.any { it.key == message.sender.userId }) {
|
||||||
val msg = MessageChain.Builder()
|
val msg = MessageChain.Builder()
|
||||||
.addText("你没有在自闭列表中~")
|
.addText("你没有在自闭列表中~")
|
||||||
@@ -51,7 +54,7 @@ class UnsetZiBiCommand : BaseCommand() {
|
|||||||
message.reply(msg)
|
message.reply(msg)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
listener.setGroupBan(users.getValue(message.sender.userId), message.sender.userId, 0)
|
message.action.setGroupBan(users.getValue(message.sender.userId), message.sender.userId, 0)
|
||||||
val msg = MessageChain.Builder()
|
val msg = MessageChain.Builder()
|
||||||
.addText("祝你天天开心不要自闭~~")
|
.addText("祝你天天开心不要自闭~~")
|
||||||
.build()
|
.build()
|
||||||
|
|||||||
@@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2024 RTAkland
|
||||||
|
* Author: RTAkland
|
||||||
|
* Date: 2024/9/24
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
package cn.rtast.fancybot.commands.niuzi
|
||||||
|
|
||||||
|
import cn.rtast.fancybot.annotations.CommandDescription
|
||||||
|
import cn.rtast.fancybot.niuziManager
|
||||||
|
import cn.rtast.rob.entity.GroupMessage
|
||||||
|
import cn.rtast.rob.onebot.MessageChain
|
||||||
|
import cn.rtast.rob.util.BaseCommand
|
||||||
|
|
||||||
|
|
||||||
|
@CommandDescription("查询自己牛子的长度")
|
||||||
|
class MyNiuziCommand : BaseCommand() {
|
||||||
|
override val commandNames = listOf("我的牛子", "mp")
|
||||||
|
|
||||||
|
override suspend fun executeGroup(message: GroupMessage, args: List<String>) {
|
||||||
|
val niuzi = niuziManager.getUser(message.sender.userId)
|
||||||
|
if (niuzi == null) {
|
||||||
|
message.reply("你还没有牛子呢, 发送`牛子签到`来领取一根专属于你的牛子吧~")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val msg = MessageChain.Builder()
|
||||||
|
.addAt(message.sender.userId)
|
||||||
|
.addText("你的牛子长度为: ${niuzi.length}cm")
|
||||||
|
|
||||||
|
val niuziString = when (niuzi.length) {
|
||||||
|
in -999.0..0.0 -> "你的牛子已经凹进去了!!!!"
|
||||||
|
in 0.1..6.0 -> "小小的也很可爱呢~"
|
||||||
|
in 6.1..15.0 -> "好长的牛子!"
|
||||||
|
in 15.1..30.0 -> "你的牛子已经快突破天际了!!!"
|
||||||
|
else -> "牛子也太长啦把天捅穿啦!!!!!!"
|
||||||
|
}
|
||||||
|
msg.addText(niuziString)
|
||||||
|
message.reply(msg.build())
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,162 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2024 RTAkland
|
||||||
|
* Author: RTAkland
|
||||||
|
* Date: 2024/9/24
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
package cn.rtast.fancybot.commands.niuzi
|
||||||
|
|
||||||
|
import cn.rtast.fancybot.annotations.CommandDescription
|
||||||
|
import cn.rtast.fancybot.commands
|
||||||
|
import cn.rtast.fancybot.niuziBankManager
|
||||||
|
import cn.rtast.fancybot.niuziManager
|
||||||
|
import cn.rtast.fancybot.util.misc.getUserName
|
||||||
|
import cn.rtast.rob.entity.GroupMessage
|
||||||
|
import cn.rtast.rob.enums.ArrayMessageType
|
||||||
|
import cn.rtast.rob.onebot.MessageChain
|
||||||
|
import cn.rtast.rob.util.BaseCommand
|
||||||
|
|
||||||
|
private suspend fun noAccount(message: GroupMessage) {
|
||||||
|
message.reply("你还没有银行账户呢, 发送`创建账户`来创建一个账户吧~")
|
||||||
|
}
|
||||||
|
|
||||||
|
private const val INTEREST_RATE = 0.0054
|
||||||
|
|
||||||
|
@CommandDescription("牛子银行根命令")
|
||||||
|
class NiuziBankCommand : BaseCommand() {
|
||||||
|
override val commandNames = listOf("牛子银行")
|
||||||
|
|
||||||
|
override suspend fun executeGroup(message: GroupMessage, args: List<String>) {
|
||||||
|
val niuziCommands = commands.filter {
|
||||||
|
it::class.simpleName?.startsWith("Niuzi")!! && !it::class.simpleName?.lowercase()?.contains("redeem")!!
|
||||||
|
}.joinToString("\n") { it.commandNames.joinToString(",") { join -> "`$join`" } }
|
||||||
|
val msg = MessageChain.Builder()
|
||||||
|
.addText("发送")
|
||||||
|
.addNewLine()
|
||||||
|
.addText(niuziCommands)
|
||||||
|
.addNewLine()
|
||||||
|
.addText("即可做出对应的操作")
|
||||||
|
.addNewLine()
|
||||||
|
.addText("银行利率是0.54%")
|
||||||
|
.build()
|
||||||
|
message.reply(msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@CommandDescription("查询牛子银行的余额")
|
||||||
|
class BankBalanceCommand : BaseCommand() {
|
||||||
|
override val commandNames = listOf("余额查询")
|
||||||
|
|
||||||
|
override suspend fun executeGroup(message: GroupMessage, args: List<String>) {
|
||||||
|
val balanceData = niuziBankManager.getUser(message.sender.userId)
|
||||||
|
if (balanceData == null) {
|
||||||
|
noAccount(message)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
message.reply("你的账户余额还有: ${balanceData.balance}cm")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@CommandDescription("创建一个空的牛子银行账户")
|
||||||
|
class CreateBankAccountCommand : BaseCommand() {
|
||||||
|
override val commandNames = listOf("创建账户")
|
||||||
|
|
||||||
|
override suspend fun executeGroup(message: GroupMessage, args: List<String>) {
|
||||||
|
if (niuziBankManager.getUser(message.sender.userId) != null) {
|
||||||
|
message.reply("你已经有账户了!")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val userInfo = message.action.getGroupMemberInfo(message.groupId, message.sender.userId)
|
||||||
|
niuziBankManager.createBlankAccount(message.sender.userId, userInfo.card ?: userInfo.nickname)
|
||||||
|
message.reply("成功创建了一个账户!")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@CommandDescription("用于牛子银行之间转账")
|
||||||
|
class BankTransferCommand : BaseCommand() {
|
||||||
|
override val commandNames = listOf("银行转账")
|
||||||
|
|
||||||
|
override suspend fun executeGroup(message: GroupMessage, args: List<String>) {
|
||||||
|
val currentUserBalance = niuziBankManager.getUser(message.sender.userId)
|
||||||
|
if (currentUserBalance == null) {
|
||||||
|
noAccount(message)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val target = message.message.find { it.type == ArrayMessageType.at }?.data?.qq!!.toLong()
|
||||||
|
if (niuziBankManager.getUser(target) == null) {
|
||||||
|
message.reply("他还没有银行账户呢, 提醒他创建一个账户吧~(发送`创建账户`)")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val amount = args.last().toDouble()
|
||||||
|
if (amount > currentUserBalance.balance) {
|
||||||
|
message.reply("你的牛子长度不够转账!")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val username = message.action.getUserName(message.groupId, message.sender.userId)
|
||||||
|
val result = niuziBankManager.transfer(message.sender.userId, target, amount, username)
|
||||||
|
message.reply("转账成功! 你在银行内剩余的牛子长度为: ${result?.balance}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@CommandDescription("牛子银行提现")
|
||||||
|
class WithdrawCommand : BaseCommand() {
|
||||||
|
override val commandNames = listOf("取牛子")
|
||||||
|
|
||||||
|
override suspend fun executeGroup(message: GroupMessage, args: List<String>) {
|
||||||
|
val amount = args.last().toDouble()
|
||||||
|
val currentBalance = niuziBankManager.getUser(message.sender.userId)
|
||||||
|
val niuzi = niuziManager.getUser(message.sender.userId)
|
||||||
|
if (currentBalance == null) {
|
||||||
|
noAccount(message)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (niuzi == null) {
|
||||||
|
message.reply("你还没有认领牛子呢, 发送`牛子签到`来领取一根吧")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (amount > currentBalance.balance) {
|
||||||
|
message.reply("你的牛子长度不足无法取出 >>> $amount")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (amount <= 0) {
|
||||||
|
message.reply("取出的长度必须大于0!")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val username = message.action.getUserName(message.groupId, message.sender.userId)
|
||||||
|
val result = niuziBankManager.withdraw(message.sender.userId, amount, username)
|
||||||
|
niuziManager.updateLength(message.sender.userId, amount + amount * INTEREST_RATE)
|
||||||
|
message.reply("取牛子成功, 你现在还剩${result.balance}cm的牛子在银行内")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@CommandDescription("牛子银行存入")
|
||||||
|
class DepositCommand : BaseCommand() {
|
||||||
|
override val commandNames = listOf("存牛子")
|
||||||
|
|
||||||
|
override suspend fun executeGroup(message: GroupMessage, args: List<String>) {
|
||||||
|
val currentBalance = niuziBankManager.getUser(message.sender.userId)
|
||||||
|
val niuzi = niuziManager.getUser(message.sender.userId)
|
||||||
|
val amount = args.last().toDouble()
|
||||||
|
if (amount <= 0) {
|
||||||
|
message.reply("存款必须大于0!")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (currentBalance == null) {
|
||||||
|
noAccount(message)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (niuzi == null) {
|
||||||
|
message.reply("你还没有认领牛子呢, 发送`牛子签到`来领取一根吧")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (amount > niuzi.length) {
|
||||||
|
message.reply("你身上的牛子不够用啦, 没办法存进银行! >>> ${niuzi.length}")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val username = message.action.getUserName(message.groupId, message.sender.userId)
|
||||||
|
val self = niuziManager.updateLength(message.sender.userId, -amount)
|
||||||
|
val result = niuziBankManager.deposit(message.sender.userId, amount, username)
|
||||||
|
message.reply("存入成功你身上的牛子还有${self?.length}cm 银行账户内还有: ${result.balance}cm")
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2024 RTAkland
|
||||||
|
* Author: RTAkland
|
||||||
|
* Date: 2024/9/24
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
package cn.rtast.fancybot.commands.niuzi
|
||||||
|
|
||||||
|
import cn.rtast.fancybot.annotations.CommandDescription
|
||||||
|
import cn.rtast.fancybot.niuziManager
|
||||||
|
import cn.rtast.rob.entity.GroupMessage
|
||||||
|
import cn.rtast.rob.enums.ArrayMessageType
|
||||||
|
import cn.rtast.rob.onebot.MessageChain
|
||||||
|
import cn.rtast.rob.util.BaseCommand
|
||||||
|
|
||||||
|
@CommandDescription("来一起激情击剑吧!")
|
||||||
|
class NiuziJiJianCommand : BaseCommand() {
|
||||||
|
override val commandNames = listOf("击剑", "jj")
|
||||||
|
|
||||||
|
override suspend fun executeGroup(message: GroupMessage, args: List<String>) {
|
||||||
|
if (args.isEmpty()) {
|
||||||
|
message.reply("发送`击剑 @xxx`即可对某人进行击剑")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
val target = message.message.find { it.type == ArrayMessageType.at }!!.data
|
||||||
|
val targetId = target.qq!!.toLong()
|
||||||
|
if (targetId == 0L) {
|
||||||
|
val msg = MessageChain.Builder()
|
||||||
|
.addReply(message.messageId)
|
||||||
|
.addText("你的只有一根牛子,他们牛子太多啦你战胜不了他们的~")
|
||||||
|
.addNewLine()
|
||||||
|
.addText("所以你不能和他们击剑~")
|
||||||
|
.build()
|
||||||
|
message.reply(msg)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (message.sender.userId == targetId) {
|
||||||
|
message.reply("你不能和自己击剑啊")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (!niuziManager.exists(message.sender.userId)) {
|
||||||
|
message.reply("你还没有牛子呢, 发送`牛子签到`领取你的牛子吧~")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (!niuziManager.exists(targetId)) {
|
||||||
|
message.reply("对方还没有牛子呢, 提醒他领取一根牛子吧~")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (niuziManager.getUser(message.sender.userId)?.length!! < 0.0) {
|
||||||
|
message.reply("你的牛子已经凹进去了没办法进行击剑~发送`牛子签到`来增加你的牛子长度吧~")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (niuziManager.getUser(targetId)?.length!! < 0.0) {
|
||||||
|
message.reply("他已经没有牛子啦!(他的牛子已经凹进去了!!)你不能和他击剑")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val result = niuziManager.jijian(message.sender.userId, targetId)
|
||||||
|
if (result.first) {
|
||||||
|
message.reply("你以已绝对的长度在这场击剑中获胜了~, 你的牛子增加了${result.second}cm")
|
||||||
|
} else {
|
||||||
|
val msg = MessageChain.Builder()
|
||||||
|
.addAt(message.sender.userId)
|
||||||
|
.addText("很不幸你的牛子没能战胜${target.name}, 你的牛子缩短了${result.second}cm")
|
||||||
|
.addNewLine()
|
||||||
|
.addText("对方的牛子增加了${result.second}cm~")
|
||||||
|
.build()
|
||||||
|
message.reply(msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2024 RTAkland
|
||||||
|
* Author: RTAkland
|
||||||
|
* Date: 2024/10/11
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
package cn.rtast.fancybot.commands.niuzi
|
||||||
|
|
||||||
|
import cn.rtast.fancybot.annotations.CommandDescription
|
||||||
|
import cn.rtast.fancybot.niuziBankManager
|
||||||
|
import cn.rtast.fancybot.niuziManager
|
||||||
|
import cn.rtast.fancybot.util.misc.getUserName
|
||||||
|
import cn.rtast.rob.entity.GroupMessage
|
||||||
|
import cn.rtast.rob.enums.ArrayMessageType
|
||||||
|
import cn.rtast.rob.onebot.MessageChain
|
||||||
|
import cn.rtast.rob.util.BaseCommand
|
||||||
|
|
||||||
|
@CommandDescription("在群内设置某个成员的牛子银行余额或者现金牛子长度")
|
||||||
|
class NiuziManagerCommand : BaseCommand() {
|
||||||
|
override val commandNames = listOf("管理牛子")
|
||||||
|
|
||||||
|
override suspend fun executeGroup(message: GroupMessage, args: List<String>) {
|
||||||
|
if (args.isEmpty()) {
|
||||||
|
message.reply("此命令可以管理成员的牛子或者银行账户")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
println(args)
|
||||||
|
if (message.sender.isAdmin || message.sender.isOwner) {
|
||||||
|
val target = message.message.find { it.type == ArrayMessageType.at }!!.data.qq!!.toLong()
|
||||||
|
val method = args[0]
|
||||||
|
val amount = args[1].toDouble()
|
||||||
|
when (method) {
|
||||||
|
"set", "s", "设置" -> {
|
||||||
|
val type = args[2]
|
||||||
|
when (type) {
|
||||||
|
"yh", "银行" -> {
|
||||||
|
val before = niuziBankManager.getUser(target)
|
||||||
|
niuziBankManager.deposit(
|
||||||
|
target, amount, message.action.getUserName(message.groupId, target)
|
||||||
|
)
|
||||||
|
val after = niuziBankManager.getUser(target)
|
||||||
|
val msg = MessageChain.Builder()
|
||||||
|
.addText("设置成功! 金额: $amount")
|
||||||
|
.addNewLine()
|
||||||
|
.addText("设置前余额: ${before?.balance?.toFloat()} | 设置后余额: ${after?.balance?.toFloat()}")
|
||||||
|
.build()
|
||||||
|
message.reply(msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> {
|
||||||
|
val before = niuziManager.getUser(target)
|
||||||
|
niuziManager.updateLength(target, amount)
|
||||||
|
val after = niuziManager.getUser(target)
|
||||||
|
val msg = MessageChain.Builder()
|
||||||
|
.addText("设置成功! 金额: $amount")
|
||||||
|
.addNewLine()
|
||||||
|
.addText("设置前长度: ${before?.length?.toFloat()} | 设置后长度: ${after?.length?.toFloat()}")
|
||||||
|
.build()
|
||||||
|
message.reply(msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
message.reply("你没权限呢!")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2024 RTAkland
|
||||||
|
* Author: RTAkland
|
||||||
|
* Date: 2024/9/24
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
package cn.rtast.fancybot.commands.niuzi
|
||||||
|
|
||||||
|
import cn.rtast.fancybot.annotations.CommandDescription
|
||||||
|
import cn.rtast.fancybot.niuziManager
|
||||||
|
import cn.rtast.rob.entity.GroupMessage
|
||||||
|
import cn.rtast.rob.enums.ArrayMessageType
|
||||||
|
import cn.rtast.rob.util.BaseCommand
|
||||||
|
|
||||||
|
@CommandDescription("查询别人的牛子长度")
|
||||||
|
class NiuziQueryCommand : BaseCommand() {
|
||||||
|
override val commandNames = listOf("牛子查询")
|
||||||
|
|
||||||
|
override suspend fun executeGroup(message: GroupMessage, args: List<String>) {
|
||||||
|
if (args.isEmpty()) {
|
||||||
|
message.reply("输入`牛子查询 @某人`即可查询他的牛子长度")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val target = message.message.find { it.type == ArrayMessageType.at }?.data?.qq!!.toLong()
|
||||||
|
val targetNiuzi = niuziManager.getUser(target)
|
||||||
|
if (targetNiuzi == null) {
|
||||||
|
message.reply("他还没有牛子")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
message.reply("他的牛子长度为: ${targetNiuzi.length}cm")
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2024 RTAkland
|
||||||
|
* Author: RTAkland
|
||||||
|
* Date: 2024/9/26
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
package cn.rtast.fancybot.commands.niuzi
|
||||||
|
|
||||||
|
import cn.rtast.fancybot.annotations.CommandDescription
|
||||||
|
import cn.rtast.fancybot.niuziBankManager
|
||||||
|
import cn.rtast.fancybot.niuziManager
|
||||||
|
import cn.rtast.rob.entity.GroupMessage
|
||||||
|
import cn.rtast.rob.onebot.MessageChain
|
||||||
|
import cn.rtast.rob.util.BaseCommand
|
||||||
|
|
||||||
|
@CommandDescription("查询所有人的牛子的排行榜")
|
||||||
|
class NiuziRankCommand : BaseCommand() {
|
||||||
|
override val commandNames = listOf("牛子排行榜", "牛子排行")
|
||||||
|
|
||||||
|
override suspend fun executeGroup(message: GroupMessage, args: List<String>) {
|
||||||
|
val allNiuzi = niuziManager.getAllNiuzi().sortedBy { it.length }.reversed()
|
||||||
|
val msg = MessageChain.Builder().addText("牛子长度排行榜如下").addNewLine()
|
||||||
|
allNiuzi.forEach {
|
||||||
|
msg.addText("[${it.nickname}] | ${it.length}cm").addNewLine()
|
||||||
|
}
|
||||||
|
message.reply(msg.build())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@CommandDescription("查询所有人的银行账户余额排行榜")
|
||||||
|
class NiuziBankRankCommand : BaseCommand() {
|
||||||
|
override val commandNames = listOf("牛子富豪榜", "富豪榜")
|
||||||
|
|
||||||
|
override suspend fun executeGroup(message: GroupMessage, args: List<String>) {
|
||||||
|
val allNiuziBankAccounts = niuziBankManager.getAllAccount()
|
||||||
|
.sortedBy { it.balance }.reversed()
|
||||||
|
val msg = MessageChain.Builder().addText("牛子银行富豪榜排行如下").addNewLine()
|
||||||
|
allNiuziBankAccounts.forEach {
|
||||||
|
msg.addText("[${it.nickname}] | ${it.balance}cm").addNewLine()
|
||||||
|
}
|
||||||
|
message.reply(msg.build())
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2024 RTAkland
|
||||||
|
* Author: RTAkland
|
||||||
|
* Date: 2024/9/3
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
package cn.rtast.fancybot.commands.niuzi
|
||||||
|
|
||||||
|
import cn.rtast.fancybot.annotations.CommandDescription
|
||||||
|
import cn.rtast.fancybot.itemManager
|
||||||
|
import cn.rtast.fancybot.niuziManager
|
||||||
|
import cn.rtast.rob.entity.GroupMessage
|
||||||
|
import cn.rtast.rob.onebot.MessageChain
|
||||||
|
import cn.rtast.rob.util.BaseCommand
|
||||||
|
|
||||||
|
@CommandDescription("使用牛子长度兑换物品")
|
||||||
|
class NiuziRedeemCommand : BaseCommand() {
|
||||||
|
override val commandNames = listOf("/rdm")
|
||||||
|
|
||||||
|
override suspend fun executeGroup(message: GroupMessage, args: List<String>) {
|
||||||
|
if (args.isEmpty()) {
|
||||||
|
val msg = MessageChain.Builder()
|
||||||
|
.addText("发送 /rdm <物品名称> 即可兑换哦!")
|
||||||
|
.addNewLine()
|
||||||
|
.addText("发送 /rdm list 即可查看所有可兑换的物品~")
|
||||||
|
.addNewLine()
|
||||||
|
.addText("发送 `我的牛子` 可以查看自己的牛子长度~")
|
||||||
|
.build()
|
||||||
|
message.reply(msg)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val status = niuziManager.getUser(message.sender.userId)
|
||||||
|
if (status == null) {
|
||||||
|
message.reply("你还没有签到过呢要签到一次才能兑换哦~")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val item = args.first()
|
||||||
|
if (item == "list" || item == "列表") {
|
||||||
|
val priceTable = itemManager.items.joinToString("\n")
|
||||||
|
{ "[${it.itemNames.joinToString("|")}]:${it.itemPrice}cm" }
|
||||||
|
message.reply(priceTable)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val selectedItem = itemManager.items.find { it.itemNames.any { any -> any == item } }
|
||||||
|
if (selectedItem == null) {
|
||||||
|
val msg = MessageChain.Builder()
|
||||||
|
.addText("没有找到你想兑换的东西呢")
|
||||||
|
.addNewLine()
|
||||||
|
.addText("你可以发送 /rdm list来查看所有可兑换的物品")
|
||||||
|
.build()
|
||||||
|
message.reply(msg)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val selectedItemPrice = selectedItem.itemPrice
|
||||||
|
if (selectedItemPrice > status.length) {
|
||||||
|
val msg = MessageChain.Builder()
|
||||||
|
.addText("你的牛子长度不够兑换这个物品呢~")
|
||||||
|
.addNewLine()
|
||||||
|
.addText("你有: ${status.length}cm, 兑换需要: $selectedItemPrice cm~\"")
|
||||||
|
.build()
|
||||||
|
message.reply(msg)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val afterStatus = niuziManager.redeemItem(message.sender.userId, selectedItemPrice)?.length!!
|
||||||
|
val action = selectedItem.redeemInGroup(message, afterStatus)
|
||||||
|
val msg = MessageChain.Builder()
|
||||||
|
.addText("兑换成功! 你花费了${selectedItemPrice}cm来兑换奖品, 还剩${afterStatus}cm")
|
||||||
|
.addNewLine()
|
||||||
|
.addText("-------------------")
|
||||||
|
.addNewLine()
|
||||||
|
.addMessageChain(action)
|
||||||
|
.build()
|
||||||
|
message.reply(msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2024 RTAkland
|
||||||
|
* Author: RTAkland
|
||||||
|
* Date: 2024/9/24
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
package cn.rtast.fancybot.commands.niuzi
|
||||||
|
|
||||||
|
import cn.rtast.fancybot.annotations.CommandDescription
|
||||||
|
import cn.rtast.fancybot.niuziManager
|
||||||
|
import cn.rtast.fancybot.util.misc.getUserName
|
||||||
|
import cn.rtast.rob.entity.GroupMessage
|
||||||
|
import cn.rtast.rob.onebot.MessageChain
|
||||||
|
import cn.rtast.rob.util.BaseCommand
|
||||||
|
|
||||||
|
@CommandDescription("牛子签到~")
|
||||||
|
class NiuziSignCommand : BaseCommand() {
|
||||||
|
override val commandNames = listOf("牛子签到", "签到")
|
||||||
|
|
||||||
|
override suspend fun executeGroup(message: GroupMessage, args: List<String>) {
|
||||||
|
if (niuziManager.isSigned(message.sender.userId)) {
|
||||||
|
message.reply("你今天已经对你的牛子使用了签到啦,明天再来吧~")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val username = message.action.getUserName(message.groupId, message.sender.userId)
|
||||||
|
val afterStatus = niuziManager.sign(message.sender.userId, username)
|
||||||
|
val msg = MessageChain.Builder()
|
||||||
|
.addReply(message.messageId)
|
||||||
|
.addText("签到成功~")
|
||||||
|
.addNewLine()
|
||||||
|
.addText("你的牛子增加了${afterStatus.first}cm~ 总长度为: ${afterStatus.second?.length}")
|
||||||
|
.build()
|
||||||
|
message.reply(msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2024 RTAkland
|
||||||
|
* Author: RTAkland
|
||||||
|
* Date: 2024/9/24
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
package cn.rtast.fancybot.commands.niuzi
|
||||||
|
|
||||||
|
import cn.rtast.fancybot.annotations.CommandDescription
|
||||||
|
import cn.rtast.fancybot.niuziManager
|
||||||
|
import cn.rtast.rob.entity.GroupMessage
|
||||||
|
import cn.rtast.rob.enums.ArrayMessageType
|
||||||
|
import cn.rtast.rob.util.BaseCommand
|
||||||
|
|
||||||
|
@CommandDescription("将自己的牛子长度转账给别人")
|
||||||
|
class NiuziTransferCommand : BaseCommand() {
|
||||||
|
override val commandNames = listOf("牛子转账", "zz")
|
||||||
|
|
||||||
|
override suspend fun executeGroup(message: GroupMessage, args: List<String>) {
|
||||||
|
if (args.isEmpty()) {
|
||||||
|
message.reply("发送`牛子转账 @某人 <长度>` 即可把自己的牛子长度转账给TA")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val target = message.message.find { it.type == ArrayMessageType.at }!!.data.qq!!.toLong()
|
||||||
|
val targetNiuzi = niuziManager.getUser(target)
|
||||||
|
if (targetNiuzi == null) niuziManager.createBlankUser(target)
|
||||||
|
val transferLength = args.last().toDouble()
|
||||||
|
val currentNiuzi = niuziManager.getUser(message.sender.userId)
|
||||||
|
if (currentNiuzi == null) {
|
||||||
|
message.reply("你没有牛子没办法转账")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (currentNiuzi.length <= 0.0) {
|
||||||
|
message.reply("你已经没有牛子可以转账了")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (currentNiuzi.length < transferLength) {
|
||||||
|
message.reply("你的牛子长度不够转账这么多 >>>${transferLength}cm")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (transferLength <= 0) {
|
||||||
|
message.reply("长度必须大于0!")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
niuziManager.updateLength(message.sender.userId, -transferLength)
|
||||||
|
niuziManager.updateLength(target, transferLength)
|
||||||
|
message.reply("转账成功, 你的长度减少了: ${transferLength}cm, 对方的长度增加了 ${transferLength}cm")
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,13 +7,22 @@
|
|||||||
|
|
||||||
package cn.rtast.fancybot.commands.parse
|
package cn.rtast.fancybot.commands.parse
|
||||||
|
|
||||||
|
import cn.rtast.fancybot.annotations.CommandDescription
|
||||||
|
import cn.rtast.fancybot.commands.misc.ShortLinkCommand.Companion.makeShortLink
|
||||||
|
import cn.rtast.fancybot.util.Logger
|
||||||
|
import cn.rtast.fancybot.util.file.getFileType
|
||||||
|
import cn.rtast.fancybot.util.misc.ImageBed
|
||||||
|
import cn.rtast.fancybot.util.misc.makeGif
|
||||||
|
import cn.rtast.fancybot.util.misc.toByteArray
|
||||||
import cn.rtast.fancybot.util.str.encodeToBase64
|
import cn.rtast.fancybot.util.str.encodeToBase64
|
||||||
import cn.rtast.fancybot.util.toByteArray
|
import cn.rtast.rob.entity.GetMessage
|
||||||
import cn.rtast.rob.entity.GroupMessage
|
import cn.rtast.rob.entity.GroupMessage
|
||||||
import cn.rtast.rob.enums.ArrayMessageType
|
import cn.rtast.rob.enums.ArrayMessageType
|
||||||
|
import cn.rtast.rob.onebot.MessageChain
|
||||||
import cn.rtast.rob.util.BaseCommand
|
import cn.rtast.rob.util.BaseCommand
|
||||||
import cn.rtast.rob.util.ob.MessageChain
|
import com.madgag.gif.fmsware.GifDecoder
|
||||||
import cn.rtast.rob.util.ob.OneBotListener
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
import java.awt.Color
|
import java.awt.Color
|
||||||
import java.awt.Font
|
import java.awt.Font
|
||||||
import java.awt.image.BufferedImage
|
import java.awt.image.BufferedImage
|
||||||
@@ -21,12 +30,14 @@ import java.net.URI
|
|||||||
import javax.imageio.ImageIO
|
import javax.imageio.ImageIO
|
||||||
import kotlin.math.roundToInt
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
|
@CommandDescription("将图片转换成ASCII字符画!")
|
||||||
class AsciiArtCommand : BaseCommand() {
|
class AsciiArtCommand : BaseCommand() {
|
||||||
override val commandNames = listOf("/ascii", "/asc")
|
override val commandNames = listOf("/ascii", "/asc")
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val FONT_SIZE = 12
|
private const val FONT_SIZE = 12
|
||||||
private val font = Font("Monospaced", Font.PLAIN, FONT_SIZE)
|
private val font = Font("Monospaced", Font.PLAIN, FONT_SIZE)
|
||||||
|
private val logger = Logger.getLogger<AsciiArtCommand>()
|
||||||
val waitingList = mutableListOf<Long>()
|
val waitingList = mutableListOf<Long>()
|
||||||
|
|
||||||
private fun BufferedImage.convertToAscii(): String {
|
private fun BufferedImage.convertToAscii(): String {
|
||||||
@@ -63,7 +74,7 @@ class AsciiArtCommand : BaseCommand() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private fun String.saveAsciiArtToImage(width: Int, height: Int): String {
|
private fun String.saveAsciiArtToImage(width: Int, height: Int): BufferedImage {
|
||||||
val imgWidth = width * FONT_SIZE / 2
|
val imgWidth = width * FONT_SIZE / 2
|
||||||
val imgHeight = height * FONT_SIZE / 2
|
val imgHeight = height * FONT_SIZE / 2
|
||||||
val img = BufferedImage(imgWidth, imgHeight, BufferedImage.TYPE_INT_RGB)
|
val img = BufferedImage(imgWidth, imgHeight, BufferedImage.TYPE_INT_RGB)
|
||||||
@@ -77,29 +88,97 @@ class AsciiArtCommand : BaseCommand() {
|
|||||||
g2d.drawString(line, 0, (index + 1) * FONT_SIZE)
|
g2d.drawString(line, 0, (index + 1) * FONT_SIZE)
|
||||||
}
|
}
|
||||||
g2d.dispose()
|
g2d.dispose()
|
||||||
return img.toByteArray().encodeToBase64()
|
return img
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun generateAsciiArt(url: String): MessageChain {
|
||||||
|
val gifStream = withContext(Dispatchers.IO) { URI(url).toURL().openStream() }
|
||||||
|
val decoder = GifDecoder()
|
||||||
|
try {
|
||||||
|
decoder.read(gifStream)
|
||||||
|
if (decoder.frameCount == 0) {
|
||||||
|
val bufferedImage = withContext(Dispatchers.IO) { ImageIO.read(gifStream) }
|
||||||
|
val imageBytes = bufferedImage.convertToAscii()
|
||||||
|
.saveAsciiArtToImage(bufferedImage.width, bufferedImage.height)
|
||||||
|
.toByteArray()
|
||||||
|
val imageBedUrl = ImageBed.upload(imageBytes, imageBytes.getFileType()).makeShortLink()
|
||||||
|
val msg = MessageChain.Builder()
|
||||||
|
.addImage(imageBytes.encodeToBase64(), true)
|
||||||
|
.addText(imageBedUrl)
|
||||||
|
.build()
|
||||||
|
return msg
|
||||||
|
} else {
|
||||||
|
logger.info("制作GIF Ascii art中, 总帧数: ${decoder.frameCount}")
|
||||||
|
val frames = (0 until decoder.frameCount).map { decoder.getFrame(it) }
|
||||||
|
val asciiFrames = mutableListOf<BufferedImage>()
|
||||||
|
val width = frames.first().width
|
||||||
|
val height = frames.first().height
|
||||||
|
frames.forEachIndexed { index, item ->
|
||||||
|
asciiFrames.add(item.convertToAscii().saveAsciiArtToImage(width, height))
|
||||||
|
logger.info("帧:${index}处理完成")
|
||||||
|
}
|
||||||
|
logger.info("合成GIF中...")
|
||||||
|
val gifBytes = decoder.makeGif(asciiFrames)
|
||||||
|
val imageBedUrl = ImageBed.upload(gifBytes, gifBytes.getFileType()).makeShortLink()
|
||||||
|
logger.info("合并完成")
|
||||||
|
val gifBase64 = gifBytes.encodeToBase64()
|
||||||
|
logger.info("处理后的图片大小: ${(gifBytes.size / 1024 / 1024).toInt()}MB")
|
||||||
|
val msg = MessageChain.Builder()
|
||||||
|
.addImage(gifBase64, true)
|
||||||
|
.addText(imageBedUrl)
|
||||||
|
.build()
|
||||||
|
return msg
|
||||||
|
}
|
||||||
|
} catch (_: OutOfMemoryError) {
|
||||||
|
return MessageChain.Builder().addText("GIF处理失败: 内存溢出").build()
|
||||||
|
logger.info("GIF处理失败: 内存溢出")
|
||||||
|
} catch (e: Exception) {
|
||||||
|
return MessageChain.Builder().addText("处理GIF失败: ${e.message}").build()
|
||||||
|
logger.info("gif处理失败: ${e.message}")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun callback(message: GroupMessage) {
|
suspend fun callback(message: GroupMessage) {
|
||||||
if (message.sender.userId in waitingList) {
|
if (message.sender.userId !in waitingList) return
|
||||||
if (message.message.any { it.type == ArrayMessageType.image }) {
|
waitingList.removeIf { it == message.sender.userId }
|
||||||
val url = message.message.find { it.type == ArrayMessageType.image }!!.data.file!!
|
if (message.message.any { it.type == ArrayMessageType.image }
|
||||||
val bufferedImage = ImageIO.read(URI(url).toURL())
|
|| message.message.any { it.type == ArrayMessageType.mface }) {
|
||||||
val imageBase64 =
|
val url = this.getImageUrl(message)
|
||||||
bufferedImage.convertToAscii().saveAsciiArtToImage(bufferedImage.width, bufferedImage.height)
|
val msg = this.generateAsciiArt(url)
|
||||||
val msg = MessageChain.Builder().addImage(imageBase64, true).build()
|
|
||||||
message.reply(msg)
|
message.reply(msg)
|
||||||
} else {
|
} else {
|
||||||
message.reply("回复错误已取消本次操作")
|
message.reply("回复错误已取消本次操作")
|
||||||
}
|
}
|
||||||
waitingList.removeIf { it == message.sender.userId }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun executeGroup(listener: OneBotListener, message: GroupMessage, args: List<String>) {
|
fun getImageUrl(groupMessage: GroupMessage): String {
|
||||||
|
return getImageUrlFromUnified(toUnifiedMessage(groupMessage))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getImageUrl(getMessageData: GetMessage.Message): String {
|
||||||
|
return getImageUrlFromUnified(toUnifiedMessage(getMessageData))
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getImageUrlFromUnified(messages: List<UnifiedMessage>): String {
|
||||||
|
return if (messages.any { it.type == ArrayMessageType.image })
|
||||||
|
messages.find { it.type == ArrayMessageType.image }!!.file!!
|
||||||
|
else messages.find { it.type == ArrayMessageType.mface }!!.url!!
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun toUnifiedMessage(groupMessage: GroupMessage): List<UnifiedMessage> {
|
||||||
|
return groupMessage.message.map { UnifiedMessage(it.type, it.data.file, it.data.url) }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun toUnifiedMessage(getMessageData: GetMessage.Message): List<UnifiedMessage> {
|
||||||
|
return getMessageData.message.map { UnifiedMessage(it.type, it.data.file, it.data.url) }
|
||||||
|
}
|
||||||
|
|
||||||
|
private data class UnifiedMessage(val type: ArrayMessageType, val file: String?, val url: String?)
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun executeGroup(message: GroupMessage, args: List<String>) {
|
||||||
if (message.sender.userId !in waitingList) {
|
if (message.sender.userId !in waitingList) {
|
||||||
message.reply("请继续发送一张图片,如果输入错误则取消本次操作")
|
message.reply("请继续发送一张图片, 如果输入错误则取消本次操作, 如果GIF帧数过多可能会需要很长时间(也可能处理失败)")
|
||||||
waitingList.add(message.sender.userId)
|
waitingList.add(message.sender.userId)
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -1,180 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright © 2024 RTAkland
|
|
||||||
* Author: RTAkland
|
|
||||||
* Date: 2024/9/6
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
package cn.rtast.fancybot.commands.parse
|
|
||||||
|
|
||||||
import cn.rtast.fancybot.entity.bili.ShortUrl
|
|
||||||
import cn.rtast.fancybot.entity.bili.UserStat
|
|
||||||
import cn.rtast.fancybot.entity.bili.VideoStat
|
|
||||||
import cn.rtast.fancybot.entity.bili.ViewCount
|
|
||||||
import cn.rtast.fancybot.util.Http
|
|
||||||
import cn.rtast.fancybot.util.Resources
|
|
||||||
import cn.rtast.fancybot.util.drawCustomImage
|
|
||||||
import cn.rtast.fancybot.util.str.encodeToBase64
|
|
||||||
import cn.rtast.fancybot.util.str.formatNumber
|
|
||||||
import cn.rtast.fancybot.util.str.setTruncat
|
|
||||||
import cn.rtast.fancybot.util.toByteArray
|
|
||||||
import cn.rtast.rob.entity.GroupMessage
|
|
||||||
import cn.rtast.rob.util.ob.MessageChain
|
|
||||||
import cn.rtast.rob.util.ob.OneBotListener
|
|
||||||
import okhttp3.OkHttpClient
|
|
||||||
import okhttp3.Request
|
|
||||||
import java.awt.Color
|
|
||||||
import java.awt.Font
|
|
||||||
import java.awt.RenderingHints
|
|
||||||
import java.awt.image.BufferedImage
|
|
||||||
import java.net.URI
|
|
||||||
import javax.imageio.ImageIO
|
|
||||||
|
|
||||||
object BVParseCommand {
|
|
||||||
|
|
||||||
private const val VIDEO_STAT_URL = "https://api.bilibili.com/x/web-interface/view"
|
|
||||||
private const val USER_STAT_URL = "https://api.bilibili.com/x/relation/stat"
|
|
||||||
private const val SHORT_URL_API_URL = "https://api.bilibili.com/x/share/click"
|
|
||||||
private const val VIEW_COUNT_URL = "https://api.bilibili.com/x/player/online/total"
|
|
||||||
private const val CANVAS_WIDTH = 1000
|
|
||||||
private const val CANVAS_HEIGHT = 600
|
|
||||||
private val backgroundColor = Color(43, 43, 43)
|
|
||||||
private val upBarColor = Color(102, 102, 102)
|
|
||||||
private val textColor = Color.WHITE
|
|
||||||
private val titleFont = Font("Serif", Font.ITALIC, 40)
|
|
||||||
private val numberFont = Font("Serif", Font.ITALIC, 25)
|
|
||||||
private val twoTwoLogo = ImageIO.read(Resources.loadFromResources("bili/22-coin.png"))
|
|
||||||
private val likeIcon = ImageIO.read(Resources.loadFromResources("bili/like.png"))
|
|
||||||
private val coinIcon = ImageIO.read(Resources.loadFromResources("bili/coin.png"))
|
|
||||||
private val viewIcon = ImageIO.read(Resources.loadFromResources("bili/view.png"))
|
|
||||||
private val shareIcon = ImageIO.read(Resources.loadFromResources("bili/share.png"))
|
|
||||||
private val favoriteIcon = ImageIO.read(Resources.loadFromResources("bili/favorite.png"))
|
|
||||||
private val replyIcon = ImageIO.read(Resources.loadFromResources("bili/reply.png"))
|
|
||||||
|
|
||||||
private val tempOkHttpClient = OkHttpClient()
|
|
||||||
|
|
||||||
private fun generateShortUrl(bvid: String, oid: Long): String {
|
|
||||||
val result = Http.post<ShortUrl>(
|
|
||||||
SHORT_URL_API_URL, mapOf(
|
|
||||||
"buvid" to bvid,
|
|
||||||
"build" to 6114514,
|
|
||||||
"platform" to "unix",
|
|
||||||
"share_channel" to "COPY",
|
|
||||||
"share_mode" to 2,
|
|
||||||
"share_id" to "main.ugc-video-detail.0.0.pv",
|
|
||||||
"oid" to oid
|
|
||||||
)
|
|
||||||
)
|
|
||||||
return result.data.content.split(" ").last()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getViewCount(bvid: String, cid: Long): String {
|
|
||||||
return Http.get<ViewCount>(
|
|
||||||
VIEW_COUNT_URL, mapOf(
|
|
||||||
"bvid" to bvid,
|
|
||||||
"cid" to cid
|
|
||||||
)
|
|
||||||
).data.total
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getVideoStat(bvid: String): VideoStat {
|
|
||||||
return Http.get<VideoStat>(VIDEO_STAT_URL, mapOf("bvid" to bvid))
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun createResponseImage(
|
|
||||||
title: String,
|
|
||||||
author: String,
|
|
||||||
authorFace: String,
|
|
||||||
picUrl: String,
|
|
||||||
reply: String,
|
|
||||||
view: String,
|
|
||||||
coin: String,
|
|
||||||
share: String,
|
|
||||||
like: String,
|
|
||||||
favorite: String,
|
|
||||||
fans: Int,
|
|
||||||
viewCount: String,
|
|
||||||
): String {
|
|
||||||
val coverImage = ImageIO.read(URI(picUrl).toURL())
|
|
||||||
val faceImage = ImageIO.read(URI(authorFace).toURL())
|
|
||||||
val canvas = BufferedImage(CANVAS_WIDTH, CANVAS_HEIGHT, BufferedImage.TYPE_INT_RGB)
|
|
||||||
val g2d = canvas.createGraphics()
|
|
||||||
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON)
|
|
||||||
g2d.color = backgroundColor
|
|
||||||
g2d.fillRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT)
|
|
||||||
// draw rect
|
|
||||||
g2d.color = upBarColor
|
|
||||||
g2d.fillRect(0, 0, CANVAS_WIDTH, 120)
|
|
||||||
g2d.color = textColor
|
|
||||||
// draw numbers
|
|
||||||
g2d.font = numberFont
|
|
||||||
g2d.drawString(like, 110, 200)
|
|
||||||
g2d.drawString(coin, 110, 290)
|
|
||||||
g2d.drawString(view, 110, 380)
|
|
||||||
g2d.drawString(favorite, 300, 380)
|
|
||||||
g2d.drawString(reply, 300, 290)
|
|
||||||
g2d.drawString(share, 300, 200)
|
|
||||||
// draw video title
|
|
||||||
val truncatedText = setTruncat(title, g2d)
|
|
||||||
g2d.font = titleFont
|
|
||||||
g2d.drawString(truncatedText, 20, 70)
|
|
||||||
// draw author name
|
|
||||||
g2d.drawString(author, 40, 580)
|
|
||||||
// draw icons
|
|
||||||
g2d.drawCustomImage(favoriteIcon, 230, 340, 50.0, 50.0, false)
|
|
||||||
g2d.drawCustomImage(replyIcon, 230, 250, 50.0, 50.0, false)
|
|
||||||
g2d.drawCustomImage(shareIcon, 230, 160, 50.0, 50.0, false)
|
|
||||||
g2d.drawCustomImage(viewIcon, 40, 340, 50.0, 50.0, false)
|
|
||||||
g2d.drawCustomImage(coinIcon, 40, 250, 50.0, 50.0, false)
|
|
||||||
g2d.drawCustomImage(likeIcon, 40, 160, 50.0, 50.0, false)
|
|
||||||
// draw 22 logo
|
|
||||||
g2d.drawCustomImage(twoTwoLogo, 800, 450, 90.0, 160.0, false)
|
|
||||||
// draw fans count
|
|
||||||
g2d.font = numberFont
|
|
||||||
g2d.drawString(fans.formatNumber() + "粉丝", 120, 520)
|
|
||||||
// draw viewing count
|
|
||||||
g2d.drawString("${viewCount}人正在观看", 40, 460)
|
|
||||||
// draw author face
|
|
||||||
g2d.drawCustomImage(faceImage, 40, 480, 60.0, 60.0, true)
|
|
||||||
// draw cover image
|
|
||||||
g2d.drawCustomImage(coverImage, 430, 140, 600.0, 300.0, true)
|
|
||||||
g2d.dispose()
|
|
||||||
return canvas.toByteArray().encodeToBase64()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getShortUrlBVID(shortUrl: String): String {
|
|
||||||
val request = Request.Builder().url(shortUrl.split(" ").last()).build()
|
|
||||||
val redirectedUrl = tempOkHttpClient.newCall(request).execute()
|
|
||||||
redirectedUrl.use {
|
|
||||||
return it.request.url.toString().split("/")[4].split("?").first()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun parse(listener: OneBotListener, bvid: String, message: GroupMessage) {
|
|
||||||
val videoInfo = this.getVideoStat(bvid)
|
|
||||||
val viewCount = this.getViewCount(bvid, videoInfo.data.cid)
|
|
||||||
val shortUrl = this.generateShortUrl(bvid, videoInfo.data.aid)
|
|
||||||
val fans = Http.get<UserStat>(USER_STAT_URL, mapOf("vmid" to videoInfo.data.owner.mid)).data.follower
|
|
||||||
val authorFace = videoInfo.data.owner.face
|
|
||||||
val title = videoInfo.data.title
|
|
||||||
val author = videoInfo.data.owner.name
|
|
||||||
val coverPicUrl = videoInfo.data.pic
|
|
||||||
val view = videoInfo.data.stat.view.formatNumber()
|
|
||||||
val share = videoInfo.data.stat.share.formatNumber()
|
|
||||||
val like = videoInfo.data.stat.like.formatNumber()
|
|
||||||
val favorite = videoInfo.data.stat.favorite.formatNumber()
|
|
||||||
val coin = videoInfo.data.stat.coin.formatNumber()
|
|
||||||
val reply = videoInfo.data.stat.reply.formatNumber()
|
|
||||||
val image = this.createResponseImage(
|
|
||||||
title, author, authorFace,
|
|
||||||
coverPicUrl, reply, view, coin,
|
|
||||||
share, like, favorite, fans, viewCount
|
|
||||||
)
|
|
||||||
val msg = MessageChain.Builder()
|
|
||||||
.addReply(message.messageId)
|
|
||||||
.addImage(image, true)
|
|
||||||
.addText(shortUrl)
|
|
||||||
.build()
|
|
||||||
listener.sendGroupMessage(message.groupId, msg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,291 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2024 RTAkland
|
||||||
|
* Author: RTAkland
|
||||||
|
* Date: 2024/9/6
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
package cn.rtast.fancybot.commands.parse
|
||||||
|
|
||||||
|
import cn.rtast.fancybot.entity.bili.*
|
||||||
|
import cn.rtast.fancybot.util.Http
|
||||||
|
import cn.rtast.fancybot.util.misc.Resources
|
||||||
|
import cn.rtast.fancybot.util.misc.drawCustomImage
|
||||||
|
import cn.rtast.fancybot.util.misc.drawString
|
||||||
|
import cn.rtast.fancybot.util.misc.toBufferedImage
|
||||||
|
import cn.rtast.fancybot.util.misc.toByteArray
|
||||||
|
import cn.rtast.fancybot.util.misc.toURL
|
||||||
|
import cn.rtast.fancybot.util.str.encodeToBase64
|
||||||
|
import cn.rtast.fancybot.util.str.formatNumber
|
||||||
|
import cn.rtast.fancybot.util.str.fromJson
|
||||||
|
import cn.rtast.fancybot.util.str.setTruncate
|
||||||
|
import cn.rtast.rob.entity.GroupMessage
|
||||||
|
import cn.rtast.rob.entity.text
|
||||||
|
import cn.rtast.rob.enums.ArrayMessageType
|
||||||
|
import cn.rtast.rob.onebot.MessageChain
|
||||||
|
import okhttp3.OkHttpClient
|
||||||
|
import okhttp3.Request
|
||||||
|
import java.awt.Color
|
||||||
|
import java.awt.Font
|
||||||
|
import java.awt.Image
|
||||||
|
import java.awt.RenderingHints
|
||||||
|
import java.awt.image.BufferedImage
|
||||||
|
import java.math.BigInteger
|
||||||
|
import java.net.URI
|
||||||
|
import javax.imageio.ImageIO
|
||||||
|
|
||||||
|
|
||||||
|
object BiliVideoParseCommand {
|
||||||
|
private val avRegex = Regex("av(\\d+)", RegexOption.IGNORE_CASE)
|
||||||
|
private val bvRegex = Regex("BV[\\dA-Za-z]{10}")
|
||||||
|
private val shortUrlRegex = Regex("https://b23\\.tv/\\w{6,8}")
|
||||||
|
private val backgroundColor = Color(43, 43, 43)
|
||||||
|
private val upBarColor = Color(102, 102, 102)
|
||||||
|
private val textColor = Color.WHITE
|
||||||
|
private val titleFont = Font("Serif", Font.ITALIC, 40)
|
||||||
|
private val numberFont = Font("Serif", Font.ITALIC, 25)
|
||||||
|
private val twoTwoLogo = ImageIO.read(Resources.loadFromResources("bili/22-coin.png"))
|
||||||
|
private val likeIcon = ImageIO.read(Resources.loadFromResources("bili/like.png"))
|
||||||
|
private val coinIcon = ImageIO.read(Resources.loadFromResources("bili/coin.png"))
|
||||||
|
private val viewIcon = ImageIO.read(Resources.loadFromResources("bili/view.png"))
|
||||||
|
private val shareIcon = ImageIO.read(Resources.loadFromResources("bili/share.png"))
|
||||||
|
private val favoriteIcon = ImageIO.read(Resources.loadFromResources("bili/favorite.png"))
|
||||||
|
private val replyIcon = ImageIO.read(Resources.loadFromResources("bili/reply.png"))
|
||||||
|
private const val VIDEO_STAT_URL = "https://api.bilibili.com/x/web-interface/view"
|
||||||
|
private const val USER_STAT_URL = "https://api.bilibili.com/x/relation/stat"
|
||||||
|
private const val SHORT_URL_API_URL = "https://api.bilibili.com/x/share/click"
|
||||||
|
private const val VIEW_COUNT_URL = "https://api.bilibili.com/x/player/online/total"
|
||||||
|
private const val CANVAS_WIDTH = 1000
|
||||||
|
private const val CANVAS_HEIGHT = 600
|
||||||
|
private const val BASE = 58
|
||||||
|
private const val DATA = "FcwAPNKTMug3GV5Lj7EJnHpWsx4tb8haYeviqBz6rkCy12mUSDQX9RdoZf"
|
||||||
|
private val XOR_CODE = BigInteger.valueOf(23442827791579L)
|
||||||
|
private val MAX_AID = BigInteger.ONE.shiftLeft(51)
|
||||||
|
private val tempOkHttpClient = OkHttpClient()
|
||||||
|
|
||||||
|
private fun generateShortUrl(bvid: String, oid: Long): String {
|
||||||
|
val result = Http.post<ShortUrl>(
|
||||||
|
SHORT_URL_API_URL, mapOf(
|
||||||
|
"buvid" to bvid,
|
||||||
|
"build" to 6114514,
|
||||||
|
"platform" to "unix",
|
||||||
|
"share_channel" to "COPY",
|
||||||
|
"share_mode" to 2,
|
||||||
|
"share_id" to "main.ugc-video-detail.0.0.pv",
|
||||||
|
"oid" to oid
|
||||||
|
)
|
||||||
|
)
|
||||||
|
return result.data.content.split(" ").last()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getViewCount(bvid: String, cid: Long): String {
|
||||||
|
return Http.get<ViewCount>(
|
||||||
|
VIEW_COUNT_URL, mapOf(
|
||||||
|
"bvid" to bvid,
|
||||||
|
"cid" to cid
|
||||||
|
)
|
||||||
|
).data.total
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getVideoStat(bvid: String): VideoStat {
|
||||||
|
return Http.get<VideoStat>(VIDEO_STAT_URL, mapOf("bvid" to bvid))
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createResponseImage(
|
||||||
|
title: String,
|
||||||
|
author: String,
|
||||||
|
authorFace: String,
|
||||||
|
picUrl: String,
|
||||||
|
reply: String,
|
||||||
|
view: String,
|
||||||
|
coin: String,
|
||||||
|
share: String,
|
||||||
|
like: String,
|
||||||
|
favorite: String,
|
||||||
|
fans: Int,
|
||||||
|
viewCount: String,
|
||||||
|
): String {
|
||||||
|
val coverImage = ImageIO.read(URI(picUrl).toURL())
|
||||||
|
val faceImage = ImageIO.read(URI(authorFace).toURL())
|
||||||
|
val canvas = BufferedImage(CANVAS_WIDTH, CANVAS_HEIGHT, BufferedImage.TYPE_INT_RGB)
|
||||||
|
val g2d = canvas.createGraphics()
|
||||||
|
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON)
|
||||||
|
g2d.color = backgroundColor
|
||||||
|
g2d.fillRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT)
|
||||||
|
// draw rect
|
||||||
|
g2d.color = upBarColor
|
||||||
|
g2d.fillRect(0, 0, CANVAS_WIDTH, 120)
|
||||||
|
g2d.color = textColor
|
||||||
|
// draw numbers
|
||||||
|
g2d.font = numberFont
|
||||||
|
g2d.drawString(like, 110, 200)
|
||||||
|
g2d.drawString(coin, 110, 290)
|
||||||
|
g2d.drawString(view, 110, 380)
|
||||||
|
g2d.drawString(favorite, 300, 380)
|
||||||
|
g2d.drawString(reply, 300, 290)
|
||||||
|
g2d.drawString(share, 300, 200)
|
||||||
|
// draw video title
|
||||||
|
val truncatedText = setTruncate(title, g2d)
|
||||||
|
g2d.font = titleFont
|
||||||
|
g2d.drawString(truncatedText, 20, 70)
|
||||||
|
// draw author name
|
||||||
|
g2d.drawString(author, 40, 580)
|
||||||
|
// draw icons
|
||||||
|
g2d.drawCustomImage(favoriteIcon, 230, 340, 50.0, 50.0, false)
|
||||||
|
g2d.drawCustomImage(replyIcon, 230, 250, 50.0, 50.0, false)
|
||||||
|
g2d.drawCustomImage(shareIcon, 230, 160, 50.0, 50.0, false)
|
||||||
|
g2d.drawCustomImage(viewIcon, 40, 340, 50.0, 50.0, false)
|
||||||
|
g2d.drawCustomImage(coinIcon, 40, 250, 50.0, 50.0, false)
|
||||||
|
g2d.drawCustomImage(likeIcon, 40, 160, 50.0, 50.0, false)
|
||||||
|
// draw 22 logo
|
||||||
|
g2d.drawCustomImage(twoTwoLogo, 800, 450, 90.0, 160.0, false)
|
||||||
|
// draw fans count
|
||||||
|
g2d.font = numberFont
|
||||||
|
g2d.drawString(fans.formatNumber() + "粉丝", 120, 520)
|
||||||
|
// draw viewing count
|
||||||
|
g2d.drawString("${viewCount}人正在观看", 40, 460)
|
||||||
|
// draw author face
|
||||||
|
g2d.drawCustomImage(faceImage, 40, 480, 60.0, 60.0, true)
|
||||||
|
// draw cover image
|
||||||
|
g2d.drawCustomImage(coverImage, 430, 140, 600.0, 300.0, true)
|
||||||
|
g2d.dispose()
|
||||||
|
return canvas.toByteArray().encodeToBase64()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getShortUrlBVID(shortUrl: String): String {
|
||||||
|
val request = Request.Builder().url(shortUrl.split(" ").last()).build()
|
||||||
|
val redirectedUrl = tempOkHttpClient.newCall(request).execute()
|
||||||
|
redirectedUrl.use {
|
||||||
|
return it.request.url.toString().split("/")[4].split("?").first()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun String.extractAv(): Long = avRegex.find(this)!!.groupValues[1].toLong()
|
||||||
|
private fun String.extractBv(): String = bvRegex.find(this)!!.value
|
||||||
|
|
||||||
|
private fun swap(array: CharArray, i: Int, j: Int) {
|
||||||
|
val temp = array[i]
|
||||||
|
array[i] = array[j]
|
||||||
|
array[j] = temp
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun Long.avToBv(): String {
|
||||||
|
val aid = BigInteger.valueOf(this)
|
||||||
|
val bytes = charArrayOf('B', 'V', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0')
|
||||||
|
var bvIndex = bytes.size - 1
|
||||||
|
var tmp = MAX_AID.or(aid).xor(XOR_CODE)
|
||||||
|
while (tmp > BigInteger.ZERO) {
|
||||||
|
bytes[bvIndex] = DATA[tmp.mod(BigInteger.valueOf(BASE.toLong())).toInt()]
|
||||||
|
tmp = tmp.divide(BigInteger.valueOf(BASE.toLong()))
|
||||||
|
bvIndex--
|
||||||
|
}
|
||||||
|
swap(bytes, 3, 9)
|
||||||
|
swap(bytes, 4, 7)
|
||||||
|
return String(bytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun parse(message: GroupMessage) {
|
||||||
|
if (!message.text.contains("bilibili.com") && !message.text.contains("b23.tv")) return
|
||||||
|
try {
|
||||||
|
val bvid = if (bvRegex.containsMatchIn(message.rawMessage)) {
|
||||||
|
message.rawMessage.extractBv()
|
||||||
|
} else if (avRegex.containsMatchIn(message.rawMessage)) {
|
||||||
|
message.rawMessage.extractAv().avToBv()
|
||||||
|
} else if (shortUrlRegex.containsMatchIn(message.rawMessage)) {
|
||||||
|
val shortUrl = shortUrlRegex.find(message.rawMessage)!!.value
|
||||||
|
getShortUrlBVID(shortUrl)
|
||||||
|
} else if (bvRegex.containsMatchIn(message.rawMessage)) {
|
||||||
|
bvRegex.find(message.rawMessage)!!.value
|
||||||
|
} else if (message.message.find { it.type == ArrayMessageType.json } != null) {
|
||||||
|
val card = message.message.find { it.type == ArrayMessageType.json }!!
|
||||||
|
.data.data!!.toString().fromJson<CardShare>()
|
||||||
|
val shortUrl = if (card.meta.detail == null) {
|
||||||
|
if (!card.meta.news?.tag!!.contains("哔哩哔哩")) return
|
||||||
|
card.meta.news.jumpUrl
|
||||||
|
} else {
|
||||||
|
if (!card.meta.detail.title.contains("哔哩哔哩")) return
|
||||||
|
card.meta.detail.qqDocUrl
|
||||||
|
}
|
||||||
|
getShortUrlBVID(shortUrl)
|
||||||
|
} else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val videoInfo = this.getVideoStat(bvid)
|
||||||
|
val viewCount = this.getViewCount(bvid, videoInfo.data.cid)
|
||||||
|
val shortUrl = this.generateShortUrl(bvid, videoInfo.data.aid)
|
||||||
|
val fans = Http.get<UserStat>(USER_STAT_URL, mapOf("vmid" to videoInfo.data.owner.mid)).data.follower
|
||||||
|
val authorFace = videoInfo.data.owner.face
|
||||||
|
val title = videoInfo.data.title
|
||||||
|
val author = videoInfo.data.owner.name
|
||||||
|
val coverPicUrl = videoInfo.data.pic
|
||||||
|
val view = videoInfo.data.stat.view.formatNumber()
|
||||||
|
val share = videoInfo.data.stat.share.formatNumber()
|
||||||
|
val like = videoInfo.data.stat.like.formatNumber()
|
||||||
|
val favorite = videoInfo.data.stat.favorite.formatNumber()
|
||||||
|
val coin = videoInfo.data.stat.coin.formatNumber()
|
||||||
|
val reply = videoInfo.data.stat.reply.formatNumber()
|
||||||
|
val image = this.createResponseImage(
|
||||||
|
title, author, authorFace,
|
||||||
|
coverPicUrl, reply, view, coin,
|
||||||
|
share, like, favorite, fans, viewCount
|
||||||
|
)
|
||||||
|
val msg = MessageChain.Builder()
|
||||||
|
.addImage(image, true)
|
||||||
|
.addText(shortUrl)
|
||||||
|
.build()
|
||||||
|
message.reply(msg)
|
||||||
|
} catch (_: Exception) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object BiliUserParseCommand {
|
||||||
|
|
||||||
|
private val idRegex = Regex("https://space\\.bilibili\\.com/(\\d+)")
|
||||||
|
private const val USER_INFO_API_URL = "https://api.bilibili.com/x/web-interface/card"
|
||||||
|
private val font = Font("Serif", Font.BOLD, 24)
|
||||||
|
private val signFont = Font("Serif", Font.BOLD, 18)
|
||||||
|
private const val IMAGE_WIDTH = 500
|
||||||
|
private const val IMAGE_HEIGHT = 300
|
||||||
|
|
||||||
|
|
||||||
|
private fun getUserInfo(userId: String): BiliUserInfo {
|
||||||
|
val result = Http.get<UserInfo>(USER_INFO_API_URL, mapOf("mid" to userId)).data.card
|
||||||
|
return BiliUserInfo(result.name, result.levelInfo.currentLevel, result.face, result.fans, result.sign)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getUserFace(url: String) = url.toURL().readBytes().toBufferedImage()
|
||||||
|
|
||||||
|
private fun createUserImage(userInfo: BiliUserInfo): String {
|
||||||
|
val image = BufferedImage(IMAGE_WIDTH, IMAGE_HEIGHT, BufferedImage.TYPE_INT_ARGB)
|
||||||
|
val g2d = image.createGraphics()
|
||||||
|
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON)
|
||||||
|
g2d.color = Color.WHITE
|
||||||
|
g2d.fillRect(0, 0, IMAGE_WIDTH, IMAGE_HEIGHT)
|
||||||
|
g2d.font = font
|
||||||
|
g2d.color = Color.BLACK
|
||||||
|
g2d.drawString("用户名: ${userInfo.name}", 150, 50)
|
||||||
|
g2d.drawString("粉丝数: ${userInfo.fans}", 150, 100)
|
||||||
|
g2d.drawString("等级: ${userInfo.level}", 150, 150)
|
||||||
|
g2d.font = signFont
|
||||||
|
g2d.drawString(setTruncate("签名: ${userInfo.sign}", g2d), 40, 180, 100)
|
||||||
|
val faceImage = getUserFace(userInfo.avatar)
|
||||||
|
val resizedFaceImage = faceImage.getScaledInstance(100, 100, Image.SCALE_SMOOTH)
|
||||||
|
g2d.drawImage(resizedFaceImage, 20, 20, null)
|
||||||
|
g2d.dispose()
|
||||||
|
return image.toByteArray().encodeToBase64()
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun parse(message: GroupMessage) {
|
||||||
|
val match = idRegex.find(message.rawMessage)
|
||||||
|
if (match != null) {
|
||||||
|
val userId = match.groupValues[1]
|
||||||
|
val userInfo = this.getUserInfo(userId)
|
||||||
|
val userCardImage = this.createUserImage(userInfo)
|
||||||
|
val msg = MessageChain.Builder()
|
||||||
|
.addImage(userCardImage, true)
|
||||||
|
.build()
|
||||||
|
message.reply(msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -18,7 +18,6 @@ object CalculateCommand {
|
|||||||
return try {
|
return try {
|
||||||
engine.eval(input)
|
engine.eval(input)
|
||||||
} catch (_: ScriptException) {
|
} catch (_: ScriptException) {
|
||||||
"Invalid expression"
|
|
||||||
return null
|
return null
|
||||||
}.toString()
|
}.toString()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,107 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2024 RTAkland
|
||||||
|
* Author: RTAkland
|
||||||
|
* Date: 2024/10/13
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
package cn.rtast.fancybot.commands.parse
|
||||||
|
|
||||||
|
import cn.rtast.fancybot.commands.misc.ShortLinkCommand.Companion.makeShortLink
|
||||||
|
import cn.rtast.fancybot.entity.douyin.DouyinVideo
|
||||||
|
import cn.rtast.fancybot.util.Http
|
||||||
|
import cn.rtast.fancybot.util.Logger
|
||||||
|
import cn.rtast.fancybot.util.misc.drawCustomImage
|
||||||
|
import cn.rtast.fancybot.util.misc.toBufferedImage
|
||||||
|
import cn.rtast.fancybot.util.misc.toByteArray
|
||||||
|
import cn.rtast.fancybot.util.misc.toURL
|
||||||
|
import cn.rtast.fancybot.util.str.encodeToBase64
|
||||||
|
import cn.rtast.fancybot.util.str.formatNumber
|
||||||
|
import cn.rtast.fancybot.util.str.proxy
|
||||||
|
import cn.rtast.rob.entity.GroupMessage
|
||||||
|
import cn.rtast.rob.onebot.MessageChain
|
||||||
|
import okhttp3.OkHttpClient
|
||||||
|
import okhttp3.Request
|
||||||
|
import java.awt.Color
|
||||||
|
import java.awt.Font
|
||||||
|
import java.awt.RenderingHints
|
||||||
|
import java.awt.geom.RoundRectangle2D
|
||||||
|
import java.awt.image.BufferedImage
|
||||||
|
|
||||||
|
object DouyinVideoParseCommand {
|
||||||
|
|
||||||
|
private val tempHttpClient = OkHttpClient.Builder().followRedirects(true).followSslRedirects(true).build()
|
||||||
|
private val shortLinkRegex = Regex("https://v\\.douyin\\.com/[a-zA-Z0-9]+/")
|
||||||
|
private val singleVideoRegex = Regex("https://www\\.douyin\\.com/video/([0-9]+)")
|
||||||
|
private val douyinApiUrl = "https://douyin.wtf/api/douyin/web/fetch_one_video".proxy
|
||||||
|
private val logger = Logger.getLogger<DouyinVideoParseCommand>()
|
||||||
|
private const val IMAGE_WIDTH = 1200
|
||||||
|
private const val IMAGE_HEIGHT = 800
|
||||||
|
|
||||||
|
private fun extractVideoId(origin: String) = singleVideoRegex.find(origin)?.groupValues?.get(1)!!
|
||||||
|
private fun createDouyinVideoCard(video: DouyinVideo): String {
|
||||||
|
val card = BufferedImage(IMAGE_WIDTH, IMAGE_HEIGHT, BufferedImage.TYPE_INT_RGB)
|
||||||
|
val g2d = card.createGraphics()
|
||||||
|
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON)
|
||||||
|
g2d.color = Color(245, 245, 245)
|
||||||
|
g2d.fillRect(0, 0, IMAGE_WIDTH, IMAGE_HEIGHT)
|
||||||
|
g2d.color = Color(230, 230, 230)
|
||||||
|
g2d.fill(
|
||||||
|
RoundRectangle2D.Float(20f, 20f, (IMAGE_WIDTH - 40).toFloat(), (IMAGE_HEIGHT - 40).toFloat(), 50f, 50f)
|
||||||
|
)
|
||||||
|
g2d.color = Color.BLACK
|
||||||
|
g2d.font = Font("Serif", Font.BOLD, 48)
|
||||||
|
g2d.drawString(video.data.awemeDetail.author.nickname, 60, 100)
|
||||||
|
g2d.font = Font("Serif", Font.PLAIN, 32)
|
||||||
|
g2d.drawString(video.data.awemeDetail.desc, 60, 160)
|
||||||
|
val avatarImage = video.data.awemeDetail.author.avatarThumb.urlList
|
||||||
|
.first().toURL().readBytes().toBufferedImage()
|
||||||
|
g2d.drawImage(avatarImage, 60, 180, 160, 160, null)
|
||||||
|
val cover = video.data.awemeDetail.video.coverOriginalScale
|
||||||
|
|
||||||
|
g2d.drawCustomImage(
|
||||||
|
cover.urlList.first().toURL().readBytes().toBufferedImage(),
|
||||||
|
450, 170, cover.width.toDouble(), cover.height.toDouble()
|
||||||
|
)
|
||||||
|
g2d.color = Color.DARK_GRAY
|
||||||
|
g2d.font = Font("Serif", Font.PLAIN, 28)
|
||||||
|
g2d.drawString("粉丝: ${video.data.awemeDetail.author.followerCount.formatNumber()}", 60, 400)
|
||||||
|
g2d.drawString("点赞: ${video.data.awemeDetail.statistics.diggCount.formatNumber()}", 60, 440)
|
||||||
|
g2d.drawString("播放: ${video.data.awemeDetail.statistics.playCount.formatNumber()}", 60, 480)
|
||||||
|
g2d.drawString("评论: ${video.data.awemeDetail.statistics.commentCount.formatNumber()}", 60, 520)
|
||||||
|
g2d.drawString("收藏: ${video.data.awemeDetail.statistics.collectCount.formatNumber()}", 60, 560)
|
||||||
|
g2d.drawString("分享: ${video.data.awemeDetail.statistics.shareCount.formatNumber()}", 60, 600)
|
||||||
|
g2d.dispose()
|
||||||
|
return card.toByteArray().encodeToBase64()
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun parse(message: GroupMessage) {
|
||||||
|
try {
|
||||||
|
val id = if (shortLinkRegex.find(message.rawMessage) != null) {
|
||||||
|
val shortUrl = shortLinkRegex.find(message.rawMessage)?.value ?: ""
|
||||||
|
val request = Request.Builder().url(shortUrl).build()
|
||||||
|
val finalUrl = tempHttpClient.newCall(request).execute().also { it.close() }
|
||||||
|
extractVideoId(finalUrl.request.url.toString())
|
||||||
|
} else if (singleVideoRegex.find(message.rawMessage) != null) extractVideoId(message.rawMessage) else ""
|
||||||
|
if (id.isNotBlank()) {
|
||||||
|
val response = Http.get<DouyinVideo>(
|
||||||
|
douyinApiUrl,
|
||||||
|
mapOf("aweme_id" to id)
|
||||||
|
)
|
||||||
|
val videoPlayUrlShortUrl = response.data.awemeDetail.video.bitRate
|
||||||
|
.first().playAddr.urlList.first().makeShortLink()
|
||||||
|
val shareUrlShortUrl = response.data.awemeDetail.shareUrl.makeShortLink()
|
||||||
|
val image = this.createDouyinVideoCard(response)
|
||||||
|
val msg = MessageChain.Builder()
|
||||||
|
.addImage(image, true)
|
||||||
|
.addText("视频地址: $shareUrlShortUrl")
|
||||||
|
.addNewLine()
|
||||||
|
.addText("下载地址: $videoPlayUrlShortUrl")
|
||||||
|
.build()
|
||||||
|
message.reply(msg)
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
logger.warn("抖音视频解析失败: ${e.message}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -10,16 +10,15 @@ package cn.rtast.fancybot.commands.parse
|
|||||||
import cn.rtast.fancybot.configManager
|
import cn.rtast.fancybot.configManager
|
||||||
import cn.rtast.fancybot.entity.github.RepoInfo
|
import cn.rtast.fancybot.entity.github.RepoInfo
|
||||||
import cn.rtast.fancybot.util.Http
|
import cn.rtast.fancybot.util.Http
|
||||||
import cn.rtast.fancybot.util.Resources
|
import cn.rtast.fancybot.util.misc.Resources
|
||||||
import cn.rtast.fancybot.util.drawCustomImage
|
import cn.rtast.fancybot.util.misc.drawCustomImage
|
||||||
import cn.rtast.fancybot.util.drawString
|
import cn.rtast.fancybot.util.misc.drawString
|
||||||
|
import cn.rtast.fancybot.util.misc.toByteArray
|
||||||
import cn.rtast.fancybot.util.str.encodeToBase64
|
import cn.rtast.fancybot.util.str.encodeToBase64
|
||||||
import cn.rtast.fancybot.util.str.formatNumberEnglish
|
import cn.rtast.fancybot.util.str.formatNumberEnglish
|
||||||
import cn.rtast.fancybot.util.str.setTruncat
|
import cn.rtast.fancybot.util.str.setTruncate
|
||||||
import cn.rtast.fancybot.util.toByteArray
|
|
||||||
import cn.rtast.rob.entity.GroupMessage
|
import cn.rtast.rob.entity.GroupMessage
|
||||||
import cn.rtast.rob.util.ob.MessageChain
|
import cn.rtast.rob.onebot.MessageChain
|
||||||
import cn.rtast.rob.util.ob.OneBotListener
|
|
||||||
import java.awt.Color
|
import java.awt.Color
|
||||||
import java.awt.Font
|
import java.awt.Font
|
||||||
import java.awt.RenderingHints
|
import java.awt.RenderingHints
|
||||||
@@ -42,6 +41,7 @@ object GitHubParseCommand {
|
|||||||
private val descriptionCustomFont = Font("Serif", Font.PLAIN, 40).deriveFont(Font.BOLD or Font.ITALIC)
|
private val descriptionCustomFont = Font("Serif", Font.PLAIN, 40).deriveFont(Font.BOLD or Font.ITALIC)
|
||||||
private val backgroundColor = Color.WHITE
|
private val backgroundColor = Color.WHITE
|
||||||
private val textColor = Color(60, 60, 60)
|
private val textColor = Color(60, 60, 60)
|
||||||
|
private val githubRegex = Regex("""github\.com/([^/]+)/([^/]+)""")
|
||||||
|
|
||||||
private val languageColors = mapOf(
|
private val languageColors = mapOf(
|
||||||
"Kotlin" to Color(169, 123, 255),
|
"Kotlin" to Color(169, 123, 255),
|
||||||
@@ -52,7 +52,7 @@ object GitHubParseCommand {
|
|||||||
"Go" to Color(0, 173, 216),
|
"Go" to Color(0, 173, 216),
|
||||||
"Ruby" to Color(112, 21, 22),
|
"Ruby" to Color(112, 21, 22),
|
||||||
"PHP" to Color(79, 93, 149),
|
"PHP" to Color(79, 93, 149),
|
||||||
"TypeScript" to Color(43, 116, 137),
|
"TypeScript" to Color(0x3178c6),
|
||||||
"Swift" to Color(240, 81, 56),
|
"Swift" to Color(240, 81, 56),
|
||||||
"SCSS" to Color(198, 83, 140),
|
"SCSS" to Color(198, 83, 140),
|
||||||
"Visual Basic 6.0" to Color(44, 99, 83),
|
"Visual Basic 6.0" to Color(44, 99, 83),
|
||||||
@@ -63,17 +63,72 @@ object GitHubParseCommand {
|
|||||||
"Shell" to Color(137, 224, 81),
|
"Shell" to Color(137, 224, 81),
|
||||||
"CMake" to Color(218, 52, 52),
|
"CMake" to Color(218, 52, 52),
|
||||||
"HTML" to Color(227, 76, 38),
|
"HTML" to Color(227, 76, 38),
|
||||||
|
"C#" to Color(23, 134, 0),
|
||||||
|
"F#" to Color(184, 69, 252),
|
||||||
|
"Scala" to Color(194, 45, 64),
|
||||||
|
"CSS" to Color(86, 61, 124),
|
||||||
|
"XML" to Color(0, 96, 172),
|
||||||
|
"Dart" to Color(0, 180, 171),
|
||||||
|
"Objective-C" to Color(67, 142, 255),
|
||||||
|
"OCaml" to Color(239, 122, 8),
|
||||||
|
"Jupyter Notebook" to Color(218, 91, 11),
|
||||||
|
"Haskell" to Color(239, 122, 8),
|
||||||
|
"GDScript" to Color(0x355570),
|
||||||
|
"Elm" to Color(0x60b5cc),
|
||||||
|
"Dockerfile" to Color(0x384d54),
|
||||||
|
"C" to Color(0x555555),
|
||||||
|
"Batchfile" to Color(0xC1, 0xF7, 0x65),
|
||||||
|
"AngelScript" to Color(0xC7d7dc),
|
||||||
|
"Vue" to Color(0x41b883),
|
||||||
|
"SQF" to Color(0x3f3f3f),
|
||||||
|
"R" to Color(0x198ce7),
|
||||||
|
"Assembly" to Color(0x6e4c13),
|
||||||
|
"M" to Color(0x9a6700),
|
||||||
|
"HCL" to Color(0x844fba),
|
||||||
|
"Scilab" to Color(0xca0f21),
|
||||||
|
"TeX" to Color(0x3d6117),
|
||||||
|
"Makefile" to Color(0x427819),
|
||||||
|
"Svelte" to Color(0xff3e00),
|
||||||
|
"Stylus" to Color(0xff6347),
|
||||||
|
"EJS" to Color(0xa91e50),
|
||||||
|
"PLpgSQL" to Color(0x336790),
|
||||||
|
"Markdown" to Color(0x083fa1),
|
||||||
|
"Lua" to Color(0x000080),
|
||||||
|
"JSON" to Color(0x292929),
|
||||||
|
"YAML" to Color(0xcb171e),
|
||||||
|
"HLSL" to Color(0xaace60),
|
||||||
|
"GLSL" to Color(0x5686a5),
|
||||||
|
"Jinja" to Color(0xa52a22),
|
||||||
|
"Zig" to Color(0xec915c),
|
||||||
|
"Perl" to Color(0x0298c3),
|
||||||
|
"Vim Script" to Color(0x199f4b),
|
||||||
|
"Tcl" to Color(0xe4cc98),
|
||||||
|
"Roff" to Color(0xecdebe),
|
||||||
|
"CoffeeScript" to Color(0x244776),
|
||||||
|
"Matlab" to Color(0xe16737),
|
||||||
|
"Pascal" to Color(0xE3F171),
|
||||||
|
"Fortran" to Color(0x4d41b1),
|
||||||
|
"Prolog" to Color(0x74283c),
|
||||||
|
"Erlang" to Color(0xB83998),
|
||||||
|
"D" to Color(0xba595e),
|
||||||
|
"ActionScript" to Color(0x882B0F),
|
||||||
|
"Mathematica" to Color(0xdd1100),
|
||||||
|
"Nim" to Color(0xffc200),
|
||||||
|
"COBOL" to Color(0x9a6700),
|
||||||
|
"Cuda" to Color(0x3a4e3a),
|
||||||
|
"SAS" to Color(0xb34936),
|
||||||
|
"Visual Basic .NET" to Color(0x945db7),
|
||||||
|
"Less" to Color(0x1d365d),
|
||||||
"Unknown" to Color(211, 211, 211)
|
"Unknown" to Color(211, 211, 211)
|
||||||
)
|
)
|
||||||
|
|
||||||
private fun getLanguageColor(language: String): Color {
|
private fun getLanguageColor(language: String?): Color {
|
||||||
return languageColors[language] ?: languageColors["Unknown"]!!
|
return languageColors[language] ?: languageColors["Unknown"]!!
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getRepoStat(username: String, repo: String): RepoInfo {
|
private fun getRepoStat(username: String, repo: String): RepoInfo {
|
||||||
return Http.get<RepoInfo>(
|
return Http.get<RepoInfo>(
|
||||||
"$REPO_INFO_API/$username/$repo",
|
"$REPO_INFO_API/$username/$repo", headers = mapOf("Authorization" to "Bearer ${configManager.githubKey}")
|
||||||
headers = mapOf("Authorization" to "Bearer ${configManager.githubKey}")
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,34 +155,36 @@ object GitHubParseCommand {
|
|||||||
if (repoStat.fork) {
|
if (repoStat.fork) {
|
||||||
g2d.font = forkParentFont
|
g2d.font = forkParentFont
|
||||||
val parentName = repoStat.parent?.fullName!!
|
val parentName = repoStat.parent?.fullName!!
|
||||||
val truncatedParentFullName = setTruncat("复刻自 $parentName", g2d, 1000)
|
val truncatedParentFullName = setTruncate("复刻自 $parentName", g2d, 1000)
|
||||||
g2d.drawString(truncatedParentFullName, 80, 335)
|
g2d.drawString(truncatedParentFullName, 80, 335)
|
||||||
}
|
}
|
||||||
g2d.font = titleCustomFont
|
g2d.font = titleCustomFont
|
||||||
val truncatedFullNameText = setTruncat(repoStat.fullName, g2d, 1000)
|
val truncatedFullNameText = setTruncate(repoStat.fullName, g2d, 1000)
|
||||||
g2d.drawString(truncatedFullNameText, 80, 280)
|
g2d.drawString(truncatedFullNameText, 80, 280)
|
||||||
g2d.font = descriptionCustomFont
|
g2d.font = descriptionCustomFont
|
||||||
g2d.drawString(repoStat.description ?: "暂无描述~", 80, 400, 800)
|
g2d.drawString(repoStat.description ?: "暂无描述~", 80, 400, 800)
|
||||||
val avatarImage = ImageIO.read(URI(repoStat.owner.avatarUrl).toURL())
|
val avatarImage = ImageIO.read(URI(repoStat.owner.avatarUrl).toURL())
|
||||||
g2d.drawCustomImage(avatarImage, 1200, 160, 300.0, 300.0, true)
|
g2d.drawCustomImage(avatarImage, 1200, 160, 300.0, 300.0, true)
|
||||||
|
g2d.color = this.getLanguageColor(repoStat.language)
|
||||||
|
g2d.drawString(repoStat.language ?: "[无语言]", 30, CANVAS_HEIGHT - 50)
|
||||||
g2d.dispose()
|
g2d.dispose()
|
||||||
return canvas.toByteArray().encodeToBase64()
|
return canvas.toByteArray().encodeToBase64()
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun parse(listener: OneBotListener, message: GroupMessage) {
|
suspend fun parse(message: GroupMessage) {
|
||||||
val path = message.rawMessage
|
val matchedResult = githubRegex.find(message.rawMessage)
|
||||||
.replace(".git", "")
|
if (message.rawMessage.contains("github.com") && matchedResult != null) {
|
||||||
.replace("https://github.com/", "")
|
val (user, repo) = matchedResult.destructured
|
||||||
.replace("git@github.com:", "")
|
|
||||||
.split("/")
|
|
||||||
val user = path.first()
|
|
||||||
val repo = path.last()
|
|
||||||
val repoStat = this.getRepoStat(user, repo)
|
val repoStat = this.getRepoStat(user, repo)
|
||||||
val image = this.createImage(repoStat)
|
val image = this.createImage(repoStat)
|
||||||
val msg = MessageChain.Builder()
|
val msg = MessageChain.Builder().addImage(image, true).build()
|
||||||
.addReply(message.messageId)
|
message.reply(msg)
|
||||||
.addImage(image, true)
|
}
|
||||||
.build()
|
}
|
||||||
listener.sendGroupMessage(message.groupId, msg)
|
|
||||||
|
fun creatRepoImage(user: String, repo: String): String {
|
||||||
|
val repoStat = this.getRepoStat(user, repo)
|
||||||
|
val image = this.createImage(repoStat)
|
||||||
|
return image
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -7,24 +7,52 @@
|
|||||||
|
|
||||||
package cn.rtast.fancybot.commands.parse
|
package cn.rtast.fancybot.commands.parse
|
||||||
|
|
||||||
|
import cn.rtast.fancybot.commands.misc.ShortLinkCommand.Companion.makeShortLink
|
||||||
|
import cn.rtast.fancybot.configManager
|
||||||
import cn.rtast.rob.entity.GetMessage
|
import cn.rtast.rob.entity.GetMessage
|
||||||
import cn.rtast.rob.entity.GroupMessage
|
import cn.rtast.rob.entity.GroupMessage
|
||||||
import cn.rtast.rob.enums.ArrayMessageType
|
import cn.rtast.rob.enums.ArrayMessageType
|
||||||
import cn.rtast.rob.util.ob.MessageChain
|
import cn.rtast.rob.onebot.MessageChain
|
||||||
|
import cn.rtast.rob.onebot.toNode
|
||||||
|
|
||||||
object ImageURLCommand {
|
object ImageURLCommand {
|
||||||
suspend fun callback(groupMessage: GroupMessage, message: GetMessage.Data) {
|
|
||||||
val msg = MessageChain.Builder()
|
fun getImageUrl(message: GetMessage.Message): List<String> {
|
||||||
.addReply(message.messageId)
|
try {
|
||||||
.addText("哈哈哈哈图片来咯~")
|
val images = mutableListOf<String>()
|
||||||
.addNewLine()
|
message.message.forEach {
|
||||||
val image = message.message.find { it.type == ArrayMessageType.image }
|
if (it.type == ArrayMessageType.image) images.add(it.data.file!!)
|
||||||
if (image == null) {
|
if (it.type == ArrayMessageType.mface) images.add(it.data.url!!)
|
||||||
val gif = message.message.find { it.type == ArrayMessageType.mface }!!
|
}
|
||||||
msg.addText(gif.data.url!!)
|
return images
|
||||||
} else {
|
} catch (_: NullPointerException) {
|
||||||
msg.addText(image.data.file!!)
|
return emptyList()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun callback(groupMessage: GroupMessage, message: GetMessage.Message) {
|
||||||
|
val images = getImageUrl(message)
|
||||||
|
if (images.isEmpty()) {
|
||||||
|
groupMessage.reply("这个消息里没有图片呢!")
|
||||||
|
} else {
|
||||||
|
if (images.size == 1) {
|
||||||
|
val msg = MessageChain.Builder()
|
||||||
|
.addText(images.first().makeShortLink())
|
||||||
|
.addNewLine(2)
|
||||||
|
.addText(images.first())
|
||||||
|
.build()
|
||||||
|
groupMessage.reply(msg)
|
||||||
|
} else {
|
||||||
|
val messages = mutableListOf<MessageChain>()
|
||||||
|
images.forEach {
|
||||||
|
val msg = MessageChain.Builder()
|
||||||
|
.addText(it)
|
||||||
|
.addNewLine(2)
|
||||||
|
.build()
|
||||||
|
messages.add(msg)
|
||||||
|
}
|
||||||
|
groupMessage.reply(messages.toNode(configManager.selfId))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
groupMessage.reply(msg.build())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -7,16 +7,18 @@
|
|||||||
|
|
||||||
package cn.rtast.fancybot.commands.parse
|
package cn.rtast.fancybot.commands.parse
|
||||||
|
|
||||||
import cn.rtast.fancybot.util.makeGif
|
import cn.rtast.fancybot.annotations.CommandDescription
|
||||||
|
import cn.rtast.fancybot.util.misc.makeGif
|
||||||
import cn.rtast.fancybot.util.str.encodeToBase64
|
import cn.rtast.fancybot.util.str.encodeToBase64
|
||||||
|
import cn.rtast.rob.entity.GetMessage
|
||||||
import cn.rtast.rob.entity.GroupMessage
|
import cn.rtast.rob.entity.GroupMessage
|
||||||
import cn.rtast.rob.enums.ArrayMessageType
|
import cn.rtast.rob.enums.ArrayMessageType
|
||||||
|
import cn.rtast.rob.onebot.MessageChain
|
||||||
import cn.rtast.rob.util.BaseCommand
|
import cn.rtast.rob.util.BaseCommand
|
||||||
import cn.rtast.rob.util.ob.MessageChain
|
|
||||||
import cn.rtast.rob.util.ob.OneBotListener
|
|
||||||
import com.madgag.gif.fmsware.GifDecoder
|
import com.madgag.gif.fmsware.GifDecoder
|
||||||
import java.net.URI
|
import java.net.URI
|
||||||
|
|
||||||
|
@CommandDescription("倒放GIF")
|
||||||
class ReverseGIFCommand : BaseCommand() {
|
class ReverseGIFCommand : BaseCommand() {
|
||||||
override val commandNames = listOf("倒放")
|
override val commandNames = listOf("倒放")
|
||||||
|
|
||||||
@@ -32,8 +34,23 @@ class ReverseGIFCommand : BaseCommand() {
|
|||||||
return gifBytes.encodeToBase64()
|
return gifBytes.encodeToBase64()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suspend fun reverse(message: GroupMessage, getMsg: GetMessage.Message) {
|
||||||
|
val imageObject = getMsg.message.find { it.type == ArrayMessageType.image }
|
||||||
|
if (imageObject == null) {
|
||||||
|
message.reply("这个消息中没有图片呢")
|
||||||
|
} else {
|
||||||
|
val url = imageObject.data.file!!
|
||||||
|
val image = this.reverseGif(url)
|
||||||
|
val msg = MessageChain.Builder()
|
||||||
|
.addImage(image, true)
|
||||||
|
.build()
|
||||||
|
message.reply(msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
suspend fun callback(message: GroupMessage) {
|
suspend fun callback(message: GroupMessage) {
|
||||||
if (message.sender.userId !in waitingList) return
|
if (message.sender.userId !in waitingList) return
|
||||||
|
waitingList.removeIf { it == message.sender.userId }
|
||||||
val gifUrl = if (message.message.find { it.type == ArrayMessageType.mface } == null) {
|
val gifUrl = if (message.message.find { it.type == ArrayMessageType.mface } == null) {
|
||||||
message.message.find { it.type == ArrayMessageType.image }!!.data.file!!
|
message.message.find { it.type == ArrayMessageType.image }!!.data.file!!
|
||||||
} else {
|
} else {
|
||||||
@@ -42,14 +59,13 @@ class ReverseGIFCommand : BaseCommand() {
|
|||||||
val base64String = this.reverseGif(gifUrl)
|
val base64String = this.reverseGif(gifUrl)
|
||||||
val msg = MessageChain.Builder().addImage(base64String, true).build()
|
val msg = MessageChain.Builder().addImage(base64String, true).build()
|
||||||
message.reply(msg)
|
message.reply(msg)
|
||||||
waitingList.removeIf { it == message.sender.userId }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun executeGroup(listener: OneBotListener, message: GroupMessage, args: List<String>) {
|
override suspend fun executeGroup(message: GroupMessage, args: List<String>) {
|
||||||
if (message.sender.userId !in waitingList) {
|
if (message.sender.userId !in waitingList) {
|
||||||
waitingList.add(message.sender.userId)
|
|
||||||
message.reply("发送一张动图来继续操作")
|
message.reply("发送一张动图来继续操作")
|
||||||
|
waitingList.add(message.sender.userId)
|
||||||
} else {
|
} else {
|
||||||
message.reply("发送错误本次操作已取消")
|
message.reply("发送错误本次操作已取消")
|
||||||
waitingList.removeIf { it == message.sender.userId }
|
waitingList.removeIf { it == message.sender.userId }
|
||||||
|
|||||||
@@ -0,0 +1,85 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2024 RTAkland
|
||||||
|
* Author: RTAkland
|
||||||
|
* Date: 2024/10/15
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
package cn.rtast.fancybot.commands.parse
|
||||||
|
|
||||||
|
import cn.rtast.fancybot.configManager
|
||||||
|
import cn.rtast.fancybot.entity.yt.YoutubeVideoResponse
|
||||||
|
import cn.rtast.fancybot.util.Http
|
||||||
|
import cn.rtast.fancybot.util.misc.toBufferedImage
|
||||||
|
import cn.rtast.fancybot.util.misc.toByteArray
|
||||||
|
import cn.rtast.fancybot.util.misc.toURL
|
||||||
|
import cn.rtast.fancybot.util.str.encodeToBase64
|
||||||
|
import cn.rtast.fancybot.util.str.formatNumber
|
||||||
|
import cn.rtast.fancybot.util.str.proxy
|
||||||
|
import cn.rtast.rob.entity.GroupMessage
|
||||||
|
import cn.rtast.rob.onebot.MessageChain
|
||||||
|
import java.awt.Color
|
||||||
|
import java.awt.Font
|
||||||
|
import java.awt.RenderingHints
|
||||||
|
import java.awt.image.BufferedImage
|
||||||
|
|
||||||
|
object YoutubeVideoParseCommand {
|
||||||
|
private const val YOUTUBE_API_URL = "https://proxy.rtast.cn/https/www.googleapis.com/youtube/v3/videos"
|
||||||
|
private const val IMAGE_WIDTH = 800
|
||||||
|
private const val IMAGE_HEIGHT = 450
|
||||||
|
private val dataApiKey = configManager.youtubeDataApiKey
|
||||||
|
private val youtubeVideoIdRegex =
|
||||||
|
Regex("(?:https?://)?(?:www\\.)?(?:youtube\\.com/(?:watch\\?v=|embed/|v/|.+\\?v=)|youtu\\.be/)([\\w\\-]{11})")
|
||||||
|
|
||||||
|
private fun createVideoCard(videoInfo: YoutubeVideoResponse): String {
|
||||||
|
val image = BufferedImage(IMAGE_WIDTH, IMAGE_HEIGHT, BufferedImage.TYPE_INT_ARGB)
|
||||||
|
val g2d = image.createGraphics()
|
||||||
|
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON)
|
||||||
|
g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON)
|
||||||
|
g2d.color = Color(48, 48, 48)
|
||||||
|
g2d.fillRect(0, 0, IMAGE_WIDTH, IMAGE_HEIGHT)
|
||||||
|
g2d.color = Color(255, 255, 255)
|
||||||
|
g2d.font = Font("Serif", Font.BOLD, 24)
|
||||||
|
val title = videoInfo.items.first().snippet.title
|
||||||
|
g2d.drawString(title, 20, 40)
|
||||||
|
g2d.font = Font("Serif", Font.PLAIN, 18)
|
||||||
|
val channelTitle = videoInfo.items.first().snippet.channelTitle
|
||||||
|
g2d.drawString(channelTitle, 20, 70)
|
||||||
|
val thumbnailImage = videoInfo.items.first().snippet.thumbnails.standard.url
|
||||||
|
.proxy.toURL().readBytes().toBufferedImage()
|
||||||
|
val scaledWidth = 300
|
||||||
|
val scaledHeight = (thumbnailImage.height * (scaledWidth / thumbnailImage.width.toDouble())).toInt()
|
||||||
|
g2d.drawImage(thumbnailImage, 20, 100, scaledWidth, scaledHeight, null)
|
||||||
|
g2d.color = Color(200, 200, 200)
|
||||||
|
g2d.font = Font("Serif", Font.PLAIN, 16)
|
||||||
|
g2d.drawString("观看次数: ${videoInfo.items.first().statistics.viewCount.toInt().formatNumber()}", 340, 120)
|
||||||
|
g2d.drawString("点赞次数: ${videoInfo.items.first().statistics.likeCount.toInt().formatNumber()}", 340, 150)
|
||||||
|
g2d.drawString("收藏次数: ${videoInfo.items.first().statistics.favoriteCount.toInt().formatNumber()}", 340, 180)
|
||||||
|
g2d.drawString("评论数: ${videoInfo.items.first().statistics.commentCount.toInt().formatNumber()}", 340, 210)
|
||||||
|
g2d.dispose()
|
||||||
|
return image.toByteArray().encodeToBase64()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getVideoInfo(videoId: String): YoutubeVideoResponse {
|
||||||
|
val response = Http.get<YoutubeVideoResponse>(
|
||||||
|
YOUTUBE_API_URL,
|
||||||
|
mapOf(
|
||||||
|
"id" to videoId,
|
||||||
|
"key" to dataApiKey,
|
||||||
|
"part" to "snippet,statistics"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
return response
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun parse(message: GroupMessage) {
|
||||||
|
val matchResult = youtubeVideoIdRegex.find(message.rawMessage)
|
||||||
|
if (matchResult != null) {
|
||||||
|
val videoId = matchResult.groupValues[1]
|
||||||
|
val videoInfo = this.getVideoInfo(videoId)
|
||||||
|
val image = createVideoCard(videoInfo)
|
||||||
|
val msg = MessageChain.Builder().addImage(image, true).build()
|
||||||
|
message.reply(msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright © 2024 RTAkland
|
|
||||||
* Author: RTAkland
|
|
||||||
* Date: 2024/9/4
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
package cn.rtast.fancybot.commands.record
|
|
||||||
|
|
||||||
import cn.rtast.fancybot.configManager
|
|
||||||
import cn.rtast.fancybot.signManager
|
|
||||||
import cn.rtast.rob.entity.GroupMessage
|
|
||||||
import cn.rtast.rob.enums.UserRole
|
|
||||||
import cn.rtast.rob.util.BaseCommand
|
|
||||||
import cn.rtast.rob.util.ob.MessageChain
|
|
||||||
import cn.rtast.rob.util.ob.OneBotListener
|
|
||||||
|
|
||||||
class MyPointCommand : BaseCommand() {
|
|
||||||
override val commandNames = listOf("/我的点数", "/mp")
|
|
||||||
|
|
||||||
override suspend fun executeGroup(listener: OneBotListener, message: GroupMessage, args: List<String>) {
|
|
||||||
// query target's point
|
|
||||||
if (args.isNotEmpty() && (message.sender.role == UserRole.admin || message.sender.userId in configManager.admins)) {
|
|
||||||
val targetId = args.first().toLong()
|
|
||||||
val targetData = signManager.getStatus(targetId)
|
|
||||||
val msg = MessageChain.Builder().addAt(message.sender.userId)
|
|
||||||
|
|
||||||
if (targetData == null) {
|
|
||||||
msg.addText("用户不存在, 需要先签到一次才能查询点数呢~")
|
|
||||||
} else {
|
|
||||||
msg.addText("用户: ${targetData.id} 的点数有: ${targetData.points}")
|
|
||||||
}
|
|
||||||
listener.sendGroupMessage(message.groupId, msg.build())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// query self point
|
|
||||||
val status = signManager.getStatus(message.sender.userId)
|
|
||||||
if (status == null) {
|
|
||||||
val msg = MessageChain.Builder()
|
|
||||||
.addAt(message.sender.userId)
|
|
||||||
.addText("你还没有签到过呢! 先发送‘/签到’再来查询吧~")
|
|
||||||
.build()
|
|
||||||
listener.sendGroupMessage(message.groupId, msg)
|
|
||||||
return
|
|
||||||
} else {
|
|
||||||
val msg = MessageChain.Builder()
|
|
||||||
.addAt(message.sender.userId)
|
|
||||||
.addText("你当前的点数为: ${status.points}")
|
|
||||||
.build()
|
|
||||||
listener.sendGroupMessage(message.groupId, msg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,153 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright © 2024 RTAkland
|
|
||||||
* Author: RTAkland
|
|
||||||
* Date: 2024/9/8
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
package cn.rtast.fancybot.commands.record
|
|
||||||
|
|
||||||
import cn.rtast.fancybot.niuziManager
|
|
||||||
import cn.rtast.rob.entity.GroupMessage
|
|
||||||
import cn.rtast.rob.enums.ArrayMessageType
|
|
||||||
import cn.rtast.rob.util.BaseCommand
|
|
||||||
import cn.rtast.rob.util.ob.MessageChain
|
|
||||||
import cn.rtast.rob.util.ob.OneBotListener
|
|
||||||
|
|
||||||
class NiuziSignCommand : BaseCommand() {
|
|
||||||
override val commandNames = listOf("牛子签到")
|
|
||||||
|
|
||||||
override suspend fun executeGroup(listener: OneBotListener, message: GroupMessage, args: List<String>) {
|
|
||||||
if (niuziManager.isSigned(message.sender.userId)) {
|
|
||||||
val msg = MessageChain.Builder()
|
|
||||||
.addAt(message.sender.userId)
|
|
||||||
.addText("你今天已经对你的牛子使用了签到啦,明天再来吧~")
|
|
||||||
.build()
|
|
||||||
listener.sendGroupMessage(message.groupId, msg)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
val afterStatus = niuziManager.sign(message.sender.userId)
|
|
||||||
val msg = MessageChain.Builder()
|
|
||||||
.addAt(message.sender.userId)
|
|
||||||
.addText("签到成功~")
|
|
||||||
.addNewLine()
|
|
||||||
.addText("你的牛子增加了${afterStatus.first}cm~ 总长度为: ${afterStatus.second?.length}")
|
|
||||||
.build()
|
|
||||||
listener.sendGroupMessage(message.groupId, msg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class JiJianCommand : BaseCommand() {
|
|
||||||
override val commandNames = listOf("击剑", "jj")
|
|
||||||
|
|
||||||
override suspend fun executeGroup(listener: OneBotListener, message: GroupMessage, args: List<String>) {
|
|
||||||
if (args.isEmpty()) {
|
|
||||||
val msg = MessageChain.Builder()
|
|
||||||
.addAt(message.sender.userId)
|
|
||||||
.addText("发送`击剑 @xxx`即可对某人进行击剑")
|
|
||||||
.build()
|
|
||||||
listener.sendGroupMessage(message.groupId, msg)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
val target = message.message.find { it.type == ArrayMessageType.at }!!.data
|
|
||||||
val targetId = target.qq!!.toLong()
|
|
||||||
if (targetId == 0L) {
|
|
||||||
val msg = MessageChain.Builder()
|
|
||||||
.addAt(message.sender.userId)
|
|
||||||
.addText("你的只有一根牛子,他们牛子太多啦你战胜不了他们的~")
|
|
||||||
.addNewLine()
|
|
||||||
.addText("所以你不能和他们击剑~")
|
|
||||||
.build()
|
|
||||||
listener.sendGroupMessage(message.groupId, msg)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (message.sender.userId == targetId) {
|
|
||||||
val msg = MessageChain.Builder()
|
|
||||||
.addAt(message.sender.userId)
|
|
||||||
.addText("你不能和自己击剑啊")
|
|
||||||
.build()
|
|
||||||
listener.sendGroupMessage(message.groupId, msg)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (!niuziManager.exists(message.sender.userId)) {
|
|
||||||
val msg = MessageChain.Builder()
|
|
||||||
.addAt(message.sender.userId)
|
|
||||||
.addText("你还没有牛子呢, 发送`牛子签到`领取你的牛子吧~")
|
|
||||||
.build()
|
|
||||||
listener.sendGroupMessage(message.groupId, msg)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (!niuziManager.exists(targetId)) {
|
|
||||||
val msg = MessageChain.Builder()
|
|
||||||
.addAt(targetId)
|
|
||||||
.addText("对方还没有牛子呢, 提醒他领取一根牛子吧~")
|
|
||||||
.build()
|
|
||||||
listener.sendGroupMessage(message.groupId, msg)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (niuziManager.getUser(message.sender.userId)?.length!! < 0.0) {
|
|
||||||
val msg = MessageChain.Builder()
|
|
||||||
.addAt(message.sender.userId)
|
|
||||||
.addText("你的牛子已经凹进去了没办法进行击剑~发送`牛子签到来增加你的牛子长度吧~`")
|
|
||||||
.build()
|
|
||||||
listener.sendGroupMessage(message.groupId, msg)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (niuziManager.getUser(targetId)?.length!! < 0.0) {
|
|
||||||
val msg = MessageChain.Builder()
|
|
||||||
.addAt(message.sender.userId)
|
|
||||||
.addText("他已经没有牛子啦!(他的牛子已经凹进去了!!)你不能和他击剑")
|
|
||||||
.build()
|
|
||||||
listener.sendGroupMessage(message.groupId, msg)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
val result = niuziManager.jijian(message.sender.userId, targetId)
|
|
||||||
if (result.first) {
|
|
||||||
val msg = MessageChain.Builder()
|
|
||||||
.addAt(message.sender.userId)
|
|
||||||
.addText("你以已绝对的长度在这场击剑中获胜了~, 你的牛子增加了${result.second}cm")
|
|
||||||
.build()
|
|
||||||
listener.sendGroupMessage(message.groupId, msg)
|
|
||||||
} else {
|
|
||||||
val msg = MessageChain.Builder()
|
|
||||||
.addAt(message.sender.userId)
|
|
||||||
.addText("很不幸你的牛子没能战胜${target.name}, 你的牛子缩短了${result.second}cm")
|
|
||||||
.addNewLine()
|
|
||||||
.addText("对方的牛子增加了${result.second}cm~")
|
|
||||||
.build()
|
|
||||||
listener.sendGroupMessage(message.groupId, msg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class MyNiuziCommand : BaseCommand() {
|
|
||||||
override val commandNames = listOf("我的牛子")
|
|
||||||
|
|
||||||
override suspend fun executeGroup(listener: OneBotListener, message: GroupMessage, args: List<String>) {
|
|
||||||
val niuzi = niuziManager.getUser(message.sender.userId)
|
|
||||||
if (niuzi == null) {
|
|
||||||
val msg = MessageChain.Builder()
|
|
||||||
.addAt(message.sender.userId)
|
|
||||||
.addText("你还没有牛子呢, 发送`牛子签到`来领取一根专属于你的牛子吧~")
|
|
||||||
.build()
|
|
||||||
listener.sendGroupMessage(message.groupId, msg)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
val msg = MessageChain.Builder()
|
|
||||||
.addAt(message.sender.userId)
|
|
||||||
.addText("你的牛子长度为: ${niuzi.length}cm")
|
|
||||||
|
|
||||||
val niuziString = when (niuzi.length) {
|
|
||||||
in -999.0..0.0 -> "你的牛子已经凹进去了!!!!"
|
|
||||||
in 0.1..6.0 -> "小小的也很可爱呢~"
|
|
||||||
in 6.1..15.0 -> "好长的牛子!"
|
|
||||||
in 15.1..30.0 -> "你的牛子已经快突破天际了!!!"
|
|
||||||
else -> "牛子也太长啦把天捅穿啦!!!!!!"
|
|
||||||
}
|
|
||||||
msg.addText(niuziString)
|
|
||||||
listener.sendGroupMessage(message.groupId, msg.build())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,86 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright © 2024 RTAkland
|
|
||||||
* Author: RTAkland
|
|
||||||
* Date: 2024/9/3
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
package cn.rtast.fancybot.commands.record
|
|
||||||
|
|
||||||
import cn.rtast.fancybot.itemManager
|
|
||||||
import cn.rtast.fancybot.signManager
|
|
||||||
import cn.rtast.rob.entity.GroupMessage
|
|
||||||
import cn.rtast.rob.util.BaseCommand
|
|
||||||
import cn.rtast.rob.util.ob.MessageChain
|
|
||||||
import cn.rtast.rob.util.ob.OneBotListener
|
|
||||||
|
|
||||||
class RedeemCommand : BaseCommand() {
|
|
||||||
override val commandNames = listOf("/redeem", "/兑换", "/rdm")
|
|
||||||
|
|
||||||
override suspend fun executeGroup(listener: OneBotListener, message: GroupMessage, args: List<String>) {
|
|
||||||
if (args.isEmpty()) {
|
|
||||||
val msg = MessageChain.Builder()
|
|
||||||
.addAt(message.sender.userId)
|
|
||||||
.addText("发送 /rdm <物品名称> 即可兑换哦!")
|
|
||||||
.addNewLine()
|
|
||||||
.addText("发送 /rdm list 即可查看所有可兑换的物品~")
|
|
||||||
.addNewLine()
|
|
||||||
.addText("发送 /mp 可以查看自己拥有的点数~")
|
|
||||||
.build()
|
|
||||||
listener.sendGroupMessage(message.groupId, msg)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
val status = signManager.getStatus(message.sender.userId)
|
|
||||||
if (status == null) {
|
|
||||||
val msg = MessageChain.Builder()
|
|
||||||
.addAt(message.sender.userId)
|
|
||||||
.addText("你还没有签到过呢要签到一次才能兑换哦~")
|
|
||||||
.build()
|
|
||||||
listener.sendGroupMessage(message.groupId, msg)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
val item = args.first()
|
|
||||||
if (item == "list" || item == "列表") {
|
|
||||||
val priceTable =
|
|
||||||
itemManager.items.joinToString("\n") { "[${it.itemNames.joinToString("|")}]:${it.itemPrice}积分" }
|
|
||||||
val msg = MessageChain.Builder()
|
|
||||||
.addAt(message.sender.userId)
|
|
||||||
.addNewLine()
|
|
||||||
.addText(priceTable)
|
|
||||||
.build()
|
|
||||||
listener.sendGroupMessage(message.groupId, msg)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
val selectedItem = itemManager.items.find { it.itemNames.any { any -> any == item } }
|
|
||||||
if (selectedItem == null) {
|
|
||||||
val msg = MessageChain.Builder()
|
|
||||||
.addAt(message.sender.userId)
|
|
||||||
.addText("没有找到你想兑换的东西呢")
|
|
||||||
.addNewLine()
|
|
||||||
.addText("你可以发送 /rdm list来查看所有可兑换的物品")
|
|
||||||
.build()
|
|
||||||
listener.sendGroupMessage(message.groupId, msg)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
val selectedItemPrice = selectedItem.itemPrice
|
|
||||||
if (selectedItemPrice > status.points) {
|
|
||||||
val msg = MessageChain.Builder()
|
|
||||||
.addAt(message.sender.userId)
|
|
||||||
.addText("你的积分不够兑换这个物品呢~")
|
|
||||||
.addNewLine()
|
|
||||||
.addText("你有: ${status.points}个积分, 兑换需要: $selectedItemPrice 个积分~\"")
|
|
||||||
.build()
|
|
||||||
listener.sendGroupMessage(message.groupId, msg)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
val afterStatus = signManager.redeemItem(message.sender.userId, selectedItemPrice)?.points!!
|
|
||||||
val msg = MessageChain.Builder()
|
|
||||||
.addAt(message.sender.userId)
|
|
||||||
.addText("兑换成功正在发送奖品中~")
|
|
||||||
.addNewLine()
|
|
||||||
.addText("你花费了 $selectedItemPrice 点积分来兑换奖品, 还剩 $afterStatus 点积分")
|
|
||||||
.build()
|
|
||||||
listener.sendGroupMessage(message.groupId, msg)
|
|
||||||
selectedItem.redeemGroup(listener, message, afterStatus)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright © 2024 RTAkland
|
|
||||||
* Author: RTAkland
|
|
||||||
* Date: 2024/9/22
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
package cn.rtast.fancybot.commands.record
|
|
||||||
|
|
||||||
import cn.rtast.fancybot.entity.ShortLink
|
|
||||||
import cn.rtast.fancybot.util.Http
|
|
||||||
import cn.rtast.fancybot.util.str.encodeToBase64
|
|
||||||
import cn.rtast.rob.entity.GroupMessage
|
|
||||||
import cn.rtast.rob.util.BaseCommand
|
|
||||||
import cn.rtast.rob.util.ob.OneBotListener
|
|
||||||
|
|
||||||
class ShortLinkCommand : BaseCommand() {
|
|
||||||
override val commandNames = listOf("/s", "/sl", "/shortlink", "/short")
|
|
||||||
|
|
||||||
private val shortLinkApi = "https://api.rtast.cn"
|
|
||||||
|
|
||||||
override suspend fun executeGroup(listener: OneBotListener, message: GroupMessage, args: List<String>) {
|
|
||||||
if (args.isEmpty()) {
|
|
||||||
message.reply("发送`/s <url>`来生成短链接`不要放入一些奇怪的链接哦~")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
val target = args.first().encodeToBase64()
|
|
||||||
val shortLink = Http.post<ShortLink>(
|
|
||||||
"$shortLinkApi/short_link",
|
|
||||||
params = mapOf("target" to target)
|
|
||||||
)
|
|
||||||
message.reply("$shortLinkApi/s?rnd_id=${shortLink.id}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright © 2024 RTAkland
|
|
||||||
* Author: RTAkland
|
|
||||||
* Date: 2024/8/30
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
package cn.rtast.fancybot.commands.record
|
|
||||||
|
|
||||||
import cn.rtast.fancybot.signManager
|
|
||||||
import cn.rtast.rob.entity.GroupMessage
|
|
||||||
import cn.rtast.rob.util.BaseCommand
|
|
||||||
import cn.rtast.rob.util.ob.MessageChain
|
|
||||||
import cn.rtast.rob.util.ob.OneBotListener
|
|
||||||
|
|
||||||
|
|
||||||
class SignCommand : BaseCommand() {
|
|
||||||
override val commandNames = listOf("/签到", "/sign")
|
|
||||||
|
|
||||||
override suspend fun executeGroup(listener: OneBotListener, message: GroupMessage, args: List<String>) {
|
|
||||||
if (signManager.isSigned(message.sender.userId)) {
|
|
||||||
val msg = MessageChain.Builder()
|
|
||||||
.addAt(message.sender.userId)
|
|
||||||
.addText("你今天已经签到过啦, 明天再来吧~")
|
|
||||||
.build()
|
|
||||||
listener.sendGroupMessage(message.groupId, msg)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
val randomPoint = signManager.sign(message.sender.userId)
|
|
||||||
val msg = MessageChain.Builder()
|
|
||||||
.addAt(message.sender.userId)
|
|
||||||
.addText("你获得了 $randomPoint 点分数!")
|
|
||||||
.addNewLine()
|
|
||||||
.addText("发送‘/我的点数’ 或者 ‘/mp’ 即可查看当前的点数")
|
|
||||||
.build()
|
|
||||||
listener.sendGroupMessage(message.groupId, msg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2024 RTAkland
|
||||||
|
* Author: RTAkland
|
||||||
|
* Date: 2024/10/13
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
package cn.rtast.fancybot.commands.reply
|
||||||
|
|
||||||
|
import cn.rtast.fancybot.commands.misc.ShortLinkCommand.Companion.makeShortLink
|
||||||
|
import cn.rtast.fancybot.commands.parse.ImageURLCommand
|
||||||
|
import cn.rtast.fancybot.configManager
|
||||||
|
import cn.rtast.fancybot.util.file.getFileType
|
||||||
|
import cn.rtast.fancybot.util.misc.ImageBed
|
||||||
|
import cn.rtast.fancybot.util.misc.toURL
|
||||||
|
import cn.rtast.rob.entity.GetMessage
|
||||||
|
import cn.rtast.rob.entity.GroupMessage
|
||||||
|
import cn.rtast.rob.onebot.MessageChain
|
||||||
|
import cn.rtast.rob.onebot.toNode
|
||||||
|
import okio.IOException
|
||||||
|
|
||||||
|
object ImageBedCommand {
|
||||||
|
suspend fun execute(getMsg: GetMessage.Message, message: GroupMessage) {
|
||||||
|
val imagesUrl = ImageURLCommand.getImageUrl(getMsg)
|
||||||
|
if (imagesUrl.isEmpty()) {
|
||||||
|
message.reply("这个消息里没有图片呢!")
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
if (imagesUrl.size == 1) {
|
||||||
|
val imageByteArray = imagesUrl.first().toURL().readBytes()
|
||||||
|
val imageFileType = imageByteArray.getFileType()
|
||||||
|
val imageBedUrl = ImageBed.upload(imageByteArray, imageFileType)
|
||||||
|
val msg = MessageChain.Builder()
|
||||||
|
.addText(imageBedUrl.makeShortLink())
|
||||||
|
.addNewLine(2)
|
||||||
|
.addText(imageBedUrl)
|
||||||
|
.build()
|
||||||
|
message.reply(msg)
|
||||||
|
} else {
|
||||||
|
val messages = mutableListOf<MessageChain>()
|
||||||
|
imagesUrl.forEach {
|
||||||
|
val imageByteArray = it.toURL().readBytes()
|
||||||
|
val imageFileType = imageByteArray.getFileType()
|
||||||
|
val imageBedUrl = ImageBed.upload(imageByteArray, imageFileType)
|
||||||
|
val msg = MessageChain.Builder()
|
||||||
|
.addText(imageBedUrl.makeShortLink())
|
||||||
|
.addNewLine(2)
|
||||||
|
.addText(imageBedUrl)
|
||||||
|
.build()
|
||||||
|
messages.add(msg)
|
||||||
|
}
|
||||||
|
message.reply(messages.toNode(configManager.selfId))
|
||||||
|
}
|
||||||
|
} catch (_: IOException) {
|
||||||
|
message.reply("上传失败: 图片已过期")
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
message.reply("上传失败: ${e.message}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2024 RTAkland
|
||||||
|
* Author: RTAkland
|
||||||
|
* Date: 2024/10/31
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
package cn.rtast.fancybot.commands.reply
|
||||||
|
|
||||||
|
import cn.rtast.fancybot.util.misc.invertColor
|
||||||
|
import cn.rtast.fancybot.util.misc.toBufferedImage
|
||||||
|
import cn.rtast.fancybot.util.misc.toByteArray
|
||||||
|
import cn.rtast.fancybot.util.misc.toURL
|
||||||
|
import cn.rtast.fancybot.util.str.encodeToBase64
|
||||||
|
import cn.rtast.rob.entity.GetMessage
|
||||||
|
import cn.rtast.rob.entity.GroupMessage
|
||||||
|
import cn.rtast.rob.entity.images
|
||||||
|
import cn.rtast.rob.onebot.MessageChain
|
||||||
|
|
||||||
|
object InvertImageCommand {
|
||||||
|
|
||||||
|
suspend fun invert(message: GroupMessage, getMsg: GetMessage.Message) {
|
||||||
|
val msg = MessageChain.Builder()
|
||||||
|
getMsg.images.forEach {
|
||||||
|
val img = it.file.toURL().readBytes().toBufferedImage()
|
||||||
|
.invertColor().toByteArray().encodeToBase64()
|
||||||
|
msg.addImage(img, true)
|
||||||
|
}
|
||||||
|
message.reply(msg.build())
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2024 RTAkland
|
||||||
|
* Author: RTAkland
|
||||||
|
* Date: 2024/10/31
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
package cn.rtast.fancybot.commands.reply
|
||||||
|
|
||||||
|
import cn.rtast.fancybot.util.misc.randomColor
|
||||||
|
import cn.rtast.fancybot.util.misc.toBufferedImage
|
||||||
|
import cn.rtast.fancybot.util.misc.toByteArray
|
||||||
|
import cn.rtast.fancybot.util.misc.toURL
|
||||||
|
import cn.rtast.fancybot.util.str.encodeToBase64
|
||||||
|
import cn.rtast.rob.entity.GetMessage
|
||||||
|
import cn.rtast.rob.entity.GroupMessage
|
||||||
|
import cn.rtast.rob.entity.images
|
||||||
|
import cn.rtast.rob.onebot.MessageChain
|
||||||
|
|
||||||
|
object RandomRGBCommand {
|
||||||
|
|
||||||
|
suspend fun random(message: GroupMessage, getMsg: GetMessage.Message) {
|
||||||
|
val msg = MessageChain.Builder()
|
||||||
|
getMsg.images.forEach {
|
||||||
|
msg.addImage(
|
||||||
|
it.file.toURL().readBytes().toBufferedImage()
|
||||||
|
.randomColor().toByteArray().encodeToBase64(),
|
||||||
|
true
|
||||||
|
)
|
||||||
|
}
|
||||||
|
message.reply(msg.build())
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2024 RTAkland
|
||||||
|
* Author: RTAkland
|
||||||
|
* Date: 2024/10/27
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
package cn.rtast.fancybot.commands.reply
|
||||||
|
|
||||||
|
import cn.rtast.fancybot.commands.misc.ShortLinkCommand.Companion.makeShortLink
|
||||||
|
import cn.rtast.fancybot.commands.parse.AsciiArtCommand
|
||||||
|
import cn.rtast.fancybot.util.misc.ImageBed
|
||||||
|
import cn.rtast.fancybot.util.misc.makeGif
|
||||||
|
import cn.rtast.fancybot.util.misc.toURL
|
||||||
|
import cn.rtast.fancybot.util.str.encodeToBase64
|
||||||
|
import cn.rtast.rob.entity.GetMessage
|
||||||
|
import cn.rtast.rob.entity.GroupMessage
|
||||||
|
import cn.rtast.rob.onebot.MessageChain
|
||||||
|
import com.madgag.gif.fmsware.GifDecoder
|
||||||
|
|
||||||
|
object SpeedUpGIFCommand {
|
||||||
|
suspend fun speedUp(message: GroupMessage, getMsg: GetMessage.Message, multiply: Float) {
|
||||||
|
val gifUrl = AsciiArtCommand.getImageUrl(getMsg)
|
||||||
|
val gifStream = gifUrl.toURL().openStream()
|
||||||
|
val decoder = GifDecoder()
|
||||||
|
decoder.read(gifStream)
|
||||||
|
val frames = (0 until decoder.frameCount).map { decoder.getFrame(it) }
|
||||||
|
val gifBase64 = decoder.makeGif(frames, multiply)
|
||||||
|
val imgBedUrl = ImageBed.upload(gifBase64)
|
||||||
|
val shortLink = imgBedUrl.makeShortLink()
|
||||||
|
val msg = MessageChain.Builder()
|
||||||
|
.addImage(gifBase64.encodeToBase64(), true)
|
||||||
|
.addText(shortLink)
|
||||||
|
.build()
|
||||||
|
message.reply(msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
+6
-6
@@ -1,19 +1,19 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright © 2024 RTAkland
|
* Copyright © 2024 RTAkland
|
||||||
* Author: RTAkland
|
* Author: RTAkland
|
||||||
* Date: 2024/8/30
|
* Date: 2024/10/2
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
package cn.rtast.fancybot.entity.db
|
package cn.rtast.fancybot.db
|
||||||
|
|
||||||
import org.jetbrains.exposed.sql.Table
|
import org.jetbrains.exposed.sql.Table
|
||||||
|
|
||||||
object SignTable : Table("sign") {
|
object ActionTable : Table("action") {
|
||||||
val id = integer("id").autoIncrement()
|
val id = integer("id").autoIncrement()
|
||||||
val userId = long("userId").uniqueIndex()
|
val action = varchar("action", 255)
|
||||||
val timestamp = long("timestamp")
|
val timestamp = long("timestamp")
|
||||||
val point = long("point")
|
val triggerId = long("trigger_id")
|
||||||
|
val result = text("result")
|
||||||
override val primaryKey = PrimaryKey(id)
|
override val primaryKey = PrimaryKey(id)
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2024 RTAkland
|
||||||
|
* Author: RTAkland
|
||||||
|
* Date: 2024/10/11
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
package cn.rtast.fancybot.db
|
||||||
|
|
||||||
|
import org.jetbrains.exposed.sql.Table
|
||||||
|
|
||||||
|
object BlackListTable : Table("blacklist") {
|
||||||
|
val id = integer("id").autoIncrement()
|
||||||
|
val groupId = long("group_id")
|
||||||
|
val operator = long("operator")
|
||||||
|
val timestamp = long("timestamp")
|
||||||
|
override val primaryKey = PrimaryKey(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
data class BlackListEntity(
|
||||||
|
val groupId: Long,
|
||||||
|
val operator: Long,
|
||||||
|
val timestamp: Long,
|
||||||
|
)
|
||||||
+1
-1
@@ -5,7 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
package cn.rtast.fancybot.entity.db
|
package cn.rtast.fancybot.db
|
||||||
|
|
||||||
import org.jetbrains.exposed.sql.Table
|
import org.jetbrains.exposed.sql.Table
|
||||||
|
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2024 RTAkland
|
||||||
|
* Author: RTAkland
|
||||||
|
* Date: 2024/10/11
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
package cn.rtast.fancybot.db
|
||||||
|
|
||||||
|
import cn.rtast.fancybot.db.MinecraftAccessTokenTable.timestamp
|
||||||
|
import cn.rtast.fancybot.db.MinecraftAccessTokenTable.token
|
||||||
|
import cn.rtast.fancybot.db.MinecraftAccessTokenTable.userId
|
||||||
|
import cn.rtast.fancybot.util.suspendedTransaction
|
||||||
|
import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
|
||||||
|
import org.jetbrains.exposed.sql.Table
|
||||||
|
import org.jetbrains.exposed.sql.deleteWhere
|
||||||
|
import org.jetbrains.exposed.sql.insert
|
||||||
|
import org.jetbrains.exposed.sql.selectAll
|
||||||
|
import java.time.Instant
|
||||||
|
|
||||||
|
object MinecraftAccessTokenTable : Table("mc_access_token") {
|
||||||
|
val id = integer("id").autoIncrement()
|
||||||
|
val token = text("token")
|
||||||
|
val userId = long("user_id")
|
||||||
|
val timestamp = long("timestamp")
|
||||||
|
override val primaryKey = PrimaryKey(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
data class MCAccessTokenEntity(
|
||||||
|
val token: String,
|
||||||
|
val userId: Long,
|
||||||
|
val timestamp: Long,
|
||||||
|
)
|
||||||
|
|
||||||
|
suspend fun insertNewAccessToken(accessToken: String, id: Long) {
|
||||||
|
suspendedTransaction {
|
||||||
|
MinecraftAccessTokenTable.insert {
|
||||||
|
it[token] = accessToken
|
||||||
|
it[userId] = id
|
||||||
|
it[timestamp] = Instant.now().epochSecond
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun getAccessTokenById(id: Long): MCAccessTokenEntity? {
|
||||||
|
return suspendedTransaction {
|
||||||
|
MinecraftAccessTokenTable.selectAll()
|
||||||
|
.where { userId eq id }
|
||||||
|
.map {
|
||||||
|
MCAccessTokenEntity(
|
||||||
|
it[token],
|
||||||
|
it[userId],
|
||||||
|
it[timestamp]
|
||||||
|
)
|
||||||
|
}.singleOrNull()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun deleteAccessTokenById(id: Long) {
|
||||||
|
suspendedTransaction {
|
||||||
|
MinecraftAccessTokenTable.deleteWhere { userId eq id }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2024 RTAkland
|
||||||
|
* Author: RTAkland
|
||||||
|
* Date: 2024/9/24
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
package cn.rtast.fancybot.db
|
||||||
|
|
||||||
|
import org.jetbrains.exposed.sql.Table
|
||||||
|
|
||||||
|
object NiuziBankTable : Table("niuzi_bank") {
|
||||||
|
val id = long("id").autoIncrement()
|
||||||
|
val userId = long("userId").uniqueIndex()
|
||||||
|
val timestamp = long("timestamp")
|
||||||
|
val balance = double("balance")
|
||||||
|
val interestRate = double("interest_rate")
|
||||||
|
val nickname = varchar("nickname", 255)
|
||||||
|
override val primaryKey = PrimaryKey(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
data class NiuziBankAccount(
|
||||||
|
val userId: Long,
|
||||||
|
val balance: Double,
|
||||||
|
val interestRate: Double,
|
||||||
|
val timestamp: Long,
|
||||||
|
val nickname: String,
|
||||||
|
)
|
||||||
+5
-3
@@ -5,20 +5,22 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
package cn.rtast.fancybot.entity.db
|
package cn.rtast.fancybot.db
|
||||||
|
|
||||||
import org.jetbrains.exposed.sql.Table
|
import org.jetbrains.exposed.sql.Table
|
||||||
|
|
||||||
object NiuziTable : Table("niuzu") {
|
object NiuziTable : Table("niuzi") {
|
||||||
val length = double("length")
|
val length = double("length")
|
||||||
val id = long("id").autoIncrement()
|
val id = long("id").autoIncrement()
|
||||||
val userId = long("userId").uniqueIndex()
|
val userId = long("userId").uniqueIndex()
|
||||||
val timestamp = long("timestamp")
|
val timestamp = long("timestamp")
|
||||||
|
val nickname = varchar("nickname", 255)
|
||||||
override val primaryKey = PrimaryKey(id)
|
override val primaryKey = PrimaryKey(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
data class Niuzi(
|
data class Niuzi(
|
||||||
val userId: Long,
|
val userId: Long,
|
||||||
val length: Double,
|
val length: Double,
|
||||||
val timestamp: Long
|
val timestamp: Long,
|
||||||
|
val nickname: String,
|
||||||
)
|
)
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2024 RTAkland
|
||||||
|
* Author: RTAkland
|
||||||
|
* Date: 2024/10/13
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
package cn.rtast.fancybot.db
|
||||||
|
|
||||||
|
import org.jetbrains.exposed.sql.Table
|
||||||
|
|
||||||
|
object RCONTable : Table("rcon") {
|
||||||
|
val id = integer("id").autoIncrement()
|
||||||
|
val host = varchar("host", 50)
|
||||||
|
val port = integer("port")
|
||||||
|
val userId = long("user_id")
|
||||||
|
val password = varchar("password", 128)
|
||||||
|
val name = varchar("name", 50)
|
||||||
|
override val primaryKey = PrimaryKey(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
data class RCONEntity(
|
||||||
|
val host: String,
|
||||||
|
val port: Int,
|
||||||
|
val userId: Long,
|
||||||
|
val name: String,
|
||||||
|
val password: String,
|
||||||
|
)
|
||||||
|
|
||||||
Loaded 100 of 338 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in New Issue
Block a user