Skip to content

Commit c7e91ac

Browse files
committed
feat: GtiHubReleasePluginUpdater
1 parent 6cf437e commit c7e91ac

2 files changed

Lines changed: 167 additions & 0 deletions

File tree

src/main/kotlin/io/github/gnuf0rce/mirai/github/GitHubHelperPlugin.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,10 @@ public object GitHubHelperPlugin : KotlinPlugin(
8787
regex findingReply replier
8888
}
8989
}
90+
val target = resolveConfigFile("update.dict.json")
91+
logger.info { "1.3.0 起提供从 github 更新<其他插件>的功能, 如有需要, 请编辑:\n $target" }
92+
GitHubReleasePluginUpdater.reload(target)
93+
GitHubReleasePluginUpdater.update()
9094
}
9195

9296
override fun onDisable() {
Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
/*
2+
* Copyright 2021-2023 dsstudio Technologies and contributors.
3+
*
4+
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
5+
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
6+
*
7+
* https://github.com/gnuf0rce/github-helper/blob/master/LICENSE
8+
*/
9+
10+
11+
package io.github.gnuf0rce.mirai.github
12+
13+
import io.github.gnuf0rce.github.*
14+
import io.ktor.client.request.*
15+
import io.ktor.client.statement.*
16+
import io.ktor.util.cio.*
17+
import io.ktor.utils.io.*
18+
import kotlinx.coroutines.*
19+
import kotlinx.serialization.*
20+
import net.mamoe.mirai.console.plugin.*
21+
import net.mamoe.mirai.console.plugin.jvm.*
22+
import net.mamoe.mirai.console.util.*
23+
import java.io.File
24+
25+
public object GitHubReleasePluginUpdater {
26+
27+
@JvmStatic
28+
public val dict: MutableMap<String, String> = hashMapOf(
29+
"cn.whitrayhb.grasspics" to "NLR-DevTeam/GrassPictures",
30+
31+
"com.evolvedghost.mirai.steamhelper.steamhelper" to "EvolvedGhost/Steamhelper",
32+
"com.evolvedghost.mutegames" to "EvolvedGhost/MuteGames",
33+
34+
"com.happysnaker.HRobot" to "happysnaker/mirai-plugin-HRobot",
35+
36+
"com.hcyacg.bilibili" to "Nekoer/mirai-plugins-bilibili",
37+
"com.hcyacg.github-notice" to "Nekoer/mirai-github-notice",
38+
"com.hcyacg.novelai" to "Nekoer/mirai-plugins-novelai",
39+
"com.hcyacg.pixiv" to "Nekoer/mirai-plugins-pixiv",
40+
41+
"com.hrs.kloping.AutoReply" to "Kloping/Mirai_Plugins_Auto_Reply",
42+
43+
"com.kasukusakura.mlss" to "KasukuSakura/mirai-login-solver-sakura",
44+
45+
"com.khjxiaogu.mirai.MiraiSongPlugin" to "khjxiaogu/MiraiSongPlugin",
46+
47+
"com.xtex.repeater" to "xtexChooser/mirai-repeater",
48+
49+
"io.github.samarium150.mirai.plugin.mirai-console-drift-bottle" to "Samarium150/mirai-console-drift-bottle",
50+
"io.github.samarium150.mirai.plugin.mirai-console-loafers-calendar" to "Samarium150/mirai-console-loafers-calendar",
51+
"io.github.samarium150.mirai.plugin.mirai-console-lolicon" to "Samarium150/mirai-console-lolicon",
52+
53+
"me.jie65535.mirai-console-jnr-plugin" to "jie65535/mirai-console-jnr-plugin",
54+
55+
"me.stageguard.obms.OsuMapSuggester" to "StageGuard/OsuMapSuggester",
56+
"me.stageguard.sctimetable" to "StageGuard/SuperCourseTimetableBot",
57+
58+
"org.laolittle.plugin.SkikoMirai" to "LaoLittle/SkikoMirai",
59+
"org.laolittle.plugin.draw.DrawMeme" to "LaoLittle/DrawMeme",
60+
61+
"top.colter.bilibili-dynamic-mirai-plugin" to "Colter23/bilibili-dynamic-mirai-plugin",
62+
"top.colter.genshin-sign" to "Colter23/genshin-sign-mirai-plugin",
63+
64+
"top.cutestar.antiRecall" to "Pmaru-top/AntiRecall",
65+
66+
"top.limbang.mcmod" to "limbang/mirai-console-mcmod-plugin",
67+
"top.limbang.mcsm" to "limbang/mirai-console-mcsm-plugin",
68+
"top.limbang.minecraft" to "limbang/mirai-console-minecraft-plugin",
69+
70+
"top.jie65535.mirai.grasscutter-command" to "jie65535/JGrasscutterCommand",
71+
"top.jie65535.mail-notify" to "jie65535/JMailNotify",
72+
"top.jie65535.mirai-console-jms-plugin" to "jie65535/mirai-console-jms-plugin",
73+
"top.jie65535.jcf" to "jie65535/mirai-console-jcf-plugin",
74+
"top.jie65535.mirai-console-jcr-plugin" to "jie65535/mirai-console-jcr-plugin",
75+
"top.jie65535.mirai-console-jhr-plugin" to "jie65535/mirai-console-jhr-plugin",
76+
"top.jie65535.mirai-console-jcab-arg-plugin" to "jie65535/mirai-console-jcab-arg-plugin",
77+
78+
"xmmt.dituon.petpet" to "Dituon/petpet",
79+
80+
"xyz.cssxsh.mirai.plugin.novelai-helper" to "cssxsh/novelai-helper",
81+
"xyz.cssxsh.mirai.plugin.pixiv-helper" to "cssxsh/pixiv-helper"
82+
)
83+
84+
public fun reload(file: File) {
85+
if (file.exists()) {
86+
dict.clear()
87+
dict.putAll(GitHubJson.decodeFromString(file.readText()))
88+
} else {
89+
file.writeText(GitHubJson.encodeToString(dict))
90+
val last = file.lastModified()
91+
runBlocking {
92+
ConsoleInput.requestInput(hint = "update.dict.json 已生成,你可以打开浏览一下 (输入回车结束等待)")
93+
}
94+
if (last < file.lastModified()) {
95+
dict.clear()
96+
dict.putAll(GitHubJson.decodeFromString(file.readText()))
97+
}
98+
}
99+
}
100+
101+
public fun update() {
102+
for (plugin in PluginManager.plugins) {
103+
if (plugin !is JvmPlugin) continue
104+
val id = dict[plugin.description.id]
105+
?: dict[plugin.description.name]
106+
?: continue
107+
val classLoader = plugin::class.java.classLoader as? java.net.URLClassLoader ?: continue
108+
val source = classLoader
109+
.urLs.singleOrNull()
110+
?.let { File(it.path) }
111+
?: continue
112+
var needUpdate = false
113+
var target = PluginManager.pluginsFolder.resolve(plugin.description.id)
114+
115+
plugin.launch {
116+
val latest = github.repo(id).releases.latest()
117+
val jar = latest.assets.find { it.name.endsWith(".mirai2.jar") }
118+
?: latest.assets.find { it.name.endsWith(".mirai.jar") }
119+
?: latest.assets.find { it.name.endsWith(".jar") }
120+
?: return@launch
121+
val updated = jar.updatedAt.toInstant().toEpochMilli()
122+
needUpdate = try {
123+
SemVersion(latest.tagName.removeSuffix("v")) > plugin.description.version
124+
} catch (_: IllegalArgumentException) {
125+
updated > source.lastModified()
126+
}
127+
128+
if (needUpdate.not()) return@launch
129+
130+
plugin.logger.info("${latest.htmlUrl} 尝试升级")
131+
target = PluginManager.pluginsFolder.resolve(jar.name)
132+
github.useHttpClient { http ->
133+
http.get(jar.browserDownloadUrl)
134+
.bodyAsChannel()
135+
.copyAndClose(target.writeChannel())
136+
}
137+
check(target.length() == jar.size) {
138+
target.delete()
139+
"${jar.browserDownloadUrl} 下载失败(文件大小校验失败 ${target.length()}!=${jar.size})"
140+
}
141+
target.setLastModified(updated)
142+
source.delete()
143+
plugin.logger.info("${latest.htmlUrl} 升级成功")
144+
145+
}.invokeOnCompletion { cause ->
146+
if (cause != null) {
147+
plugin.logger.warning("$id 升级失败")
148+
target.deleteOnExit()
149+
Runtime.getRuntime().addShutdownHook(Thread {
150+
target.delete()
151+
})
152+
} else if (needUpdate && source.exists()) {
153+
plugin.logger.warning("旧版插件 ${source.name} 删除失败,将尝试添加退出时删除,请在下次启动时手动检查")
154+
source.deleteOnExit()
155+
Runtime.getRuntime().addShutdownHook(Thread {
156+
classLoader.close()
157+
source.delete()
158+
})
159+
}
160+
}
161+
}
162+
}
163+
}

0 commit comments

Comments
 (0)