()
75 | val url = "$DOMAIN/s?key=$key&filter=${filer.ordinal}&page=$page"
76 | val elements = documentElementSelect(getDocument(url), RESULT)
77 | elements.forEach {
78 | searchResultsList.add(SearchResult(it.text(), it.attr("href"), filer))
79 | }
80 | return searchResultsList
81 | }
82 |
83 | private fun parseMod(url: String): Mod {
84 | val document = getDocument(url)
85 | return Mod(
86 | document.select(ICON_URL).attr("src").run {
87 | if (this.contains("https")) this
88 | else "https:$this"
89 | },
90 | document.select(SHORT_NAME).text(),
91 | document.select(CN_NAME).text(),
92 | document.select(EN_NAME).text(),
93 | labelReplacement(document.select(INTRODUCTION_TEXT))
94 | )
95 | }
96 |
97 | private fun parseItem(url: String): Item {
98 | val document = getDocument(url)
99 | return Item(
100 | document.select("td > img").attr("src").run {
101 | if (this.isNotEmpty()) "https:$this"
102 | else document.select("td > a > img").attr("src")
103 | },
104 | document.select(NAME).text(),
105 | labelReplacement(document.select(INTRODUCTION_ITEM)),
106 | DOMAIN + document.select(TAB_URL).attr("href")
107 | )
108 | }
109 |
110 | private fun parseTutorial(url: String): Tutorial {
111 | val document = getDocument(url)
112 | return Tutorial(
113 | document.select(NAME).text(),
114 | labelReplacement(document.select(INTRODUCTION_POST))
115 | )
116 | }
117 |
118 | private fun labelReplacement(elements: Elements): String {
119 | val whitelist = Whitelist()
120 | whitelist.addTags("p")
121 | whitelist.addAttributes("img", "data-src")
122 | var body = Jsoup.clean(elements.html(), whitelist)
123 | body = body.replace("".toRegex(), "")
124 | body = body.replace("
".toRegex(), "")
125 | body = body.replace(" ".toRegex(), " ")
126 | return body
127 | }
128 |
129 | class MCMODProvider {
130 |
131 | private val searchResultsList = mutableListOf()
132 | private var page: Int = 1
133 | private var nextPage: Boolean = false
134 |
135 | private fun search(key: String, filer: Filter) {
136 | searchResultsList.addAll(search(key, filer, page))
137 | nextPage = searchResultsList.size == 30
138 | }
139 |
140 | private fun getSearchList(key: String, filer: Filter, entry: Int): List {
141 | if (page == 1) {
142 | search(key, filer)
143 | page++
144 | }
145 | val subList = if (entry <= searchResultsList.size) {
146 | searchResultsList.subList(0, entry)
147 | } else {
148 | if (nextPage) {
149 | search(key, filer)
150 | return getSearchList(key, filer, entry)
151 | } else {
152 | page = 1
153 | searchResultsList.subList(0, searchResultsList.size)
154 | }
155 | }
156 | val toList = subList.toList()
157 | subList.clear()
158 | return toList
159 | }
160 |
161 | fun searchListToString(list: List, group: Group, sender: Member): Message {
162 | if (list.isEmpty()) return PlainText("未查询到此内容...\n")
163 | val builder = ForwardMessageBuilder(group)
164 |
165 | builder.add(sender, PlainText("30秒内回复编号查看"))
166 |
167 | for (i in list.indices) {
168 | val title = list[i].title
169 | .replace(Regex("\\([^()]*\\)"), "")
170 | .replace(Regex("\\[[^\\[\\]]*]"), "")
171 | .replace(Regex("\\s*-\\s*"), "-")
172 | builder.add(sender.id, i.toString(), PlainText(title))
173 | }
174 | if (searchResultsList.size > 0) builder.add(sender, PlainText("回复[P]下一页"))
175 | return builder.build()
176 | }
177 |
178 | fun getNextPage() = nextPage
179 |
180 | fun getSearchResultsListSize() = searchResultsList.size
181 |
182 | fun clear() {
183 | searchResultsList.clear()
184 | page = 1
185 | nextPage = false
186 | }
187 |
188 | }
189 |
190 |
191 | private suspend fun getSearchResults(serialNumber: Int, list: List, event: GroupMessageEvent): Any {
192 | if (serialNumber >= list.size) return "输入序号大于可查询数据,此 次查询已取消, 请重新查询。"
193 |
194 | val searchResults = list[serialNumber]
195 | return when (searchResults.filter) {
196 | Filter.MOD -> modMessageHandler(searchResults.url, event)
197 | Filter.DATA -> dataMessageHandler(searchResults.url, event)
198 | Filter.TUTORIAL -> tutorialMessageHandler(searchResults.url, event)
199 | else -> Unit
200 | }
201 | }
202 |
203 | private suspend fun modMessageHandler(url: String, event: GroupMessageEvent) {
204 | val mod = parseMod(url)
205 | val forwardMessageBuilder = ForwardMessageBuilder(event.group)
206 | forwardMessageBuilder.add(event.bot, event.group.uploadImage(readImage(mod.iconUrl)))
207 |
208 | var name = ""
209 | if (mod.shortName.isNotEmpty()) name += "缩写:${mod.shortName}\n"
210 | if (mod.cnName.isNotEmpty()) name += "中文:${mod.cnName}\n"
211 | if (mod.enName.isNotEmpty()) name += "英文:${mod.enName}"
212 | forwardMessageBuilder.add(event.bot, PlainText(name))
213 | forwardMessageBuilder.add(event.bot, PlainText(url))
214 | introductionMessage(forwardMessageBuilder, mod.introduction, event)
215 | event.group.sendMessage(forwardMessageBuilder.build())
216 | }
217 |
218 | private suspend fun dataMessageHandler(url: String, event: GroupMessageEvent) {
219 | val item = parseItem(url)
220 |
221 | val forwardMessageBuilder = ForwardMessageBuilder(event.group)
222 | forwardMessageBuilder.add(event.bot, event.group.uploadImage(readImage(item.iconUrl)))
223 | forwardMessageBuilder.add(event.bot, PlainText(item.name))
224 | forwardMessageBuilder.add(event.bot, PlainText(url))
225 | introductionMessage(forwardMessageBuilder, item.introduction, event)
226 | forwardMessageBuilder.add(event.bot, PlainText("合成表:${item.tabUrl}"))
227 |
228 | event.group.sendMessage(forwardMessageBuilder.build())
229 | }
230 |
231 | private suspend fun tutorialMessageHandler(url: String, event: GroupMessageEvent) {
232 | val tutorial = parseTutorial(url)
233 |
234 | val forwardMessageBuilder = ForwardMessageBuilder(event.group)
235 | forwardMessageBuilder.add(event.bot, PlainText(tutorial.name))
236 | forwardMessageBuilder.add(event.bot, PlainText(url))
237 | introductionMessage(forwardMessageBuilder, tutorial.introduction, event)
238 |
239 | event.group.sendMessage(forwardMessageBuilder.build())
240 | }
241 |
242 | private suspend fun introductionMessage(
243 | forwardMessageBuilder: ForwardMessageBuilder,
244 | introductionHtml: String,
245 | event: GroupMessageEvent
246 | ) {
247 | var introduction = introductionHtml
248 | val strList: MutableList = ArrayList()
249 | val imgList: MutableList = ArrayList()
250 | var start: Int
251 | while (introduction.indexOf("
")
255 | imgList.add(event.group.uploadImage(readImage(imgUrl)))
256 | introduction = introduction.substring(imgUrl.length + 17)
257 | }
258 | strList.add(introduction)
259 | var i = 0
260 | while (strList.size > i) {
261 | strList[i].split("\n\n").forEach {
262 | val maxLength = 1500
263 | val n = it.length / maxLength + if (it.length % maxLength != 0) 1 else 0
264 | for (j in 0 until n)
265 | forwardMessageBuilder.add(
266 | event.bot,
267 | PlainText(it.substring(j * maxLength, Integer.min((j + 1) * maxLength, it.length)))
268 | )
269 | }
270 | if (i < imgList.size) {
271 | forwardMessageBuilder.add(event.bot, imgList[i])
272 | }
273 | i++
274 | }
275 | }
276 |
--------------------------------------------------------------------------------
/src/main/resources/commands.json:
--------------------------------------------------------------------------------
1 | {
2 | "commands": [
3 | {
4 | "name": "ping",
5 | "info": "Bot存活测试",
6 | "messages": [
7 | "Pong!"
8 | ]
9 | },
10 | {
11 | "name": "info",
12 | "info": "显示Bot资料"
13 | },
14 | {
15 | "name": "help",
16 | "info": "显示Bot帮助信息"
17 | },
18 | {
19 | "name": "jrrp",
20 | "info": "获取今日随机人品值[roll 0~100]"
21 | },
22 | {
23 | "name": "ask",
24 | "info": "教你提问",
25 | "messages": [
26 | "提问的正确方式:",
27 | "简明清晰地描述你的游戏版本&遇到的问题",
28 | "魔改问题请将[crafttweaker.log]和log中提到/你认为可能出错的代码使用pastebin发送到群内",
29 | "(详见/pastebin)"
30 | ]
31 | },
32 | {
33 | "name": "pastebin",
34 | "info": "pastebin 使用方法",
35 | "messages": [
36 | "Ubuntu Pastebin使用介绍:",
37 | "1.打开https://paste.ubuntu.com.cn/",
38 | "2.填写Poster(随便写)",
39 | "3.将信息复制到Content框内",
40 | "4.点击Paste!",
41 | "5.复制网址栏网址发送至群内"
42 | ]
43 | },
44 | {
45 | "name": "log",
46 | "info": "log相关",
47 | "messages": [
48 | "关于log:",
49 | "首先在[.minecraft]文件夹找到[crafttweaker.log]和[.minecraft/logs]文件夹下的[debug.log]文件",
50 | "如果自己百度/Bing/Google无果实在无法解决,请使用 pastebin 将文件内容发送到群内等待群友/管理解答(详见 &ask 和 &pastebin)"
51 | ]
52 | },
53 | {
54 | "name": "rules",
55 | "info": "显示群规",
56 | "messages": [
57 | "《Minecraft魔改交流群 群规》请熟读并背诵()",
58 | "1.不允许多次加群,超过[3次]将被加入本群黑名单;",
59 | "2.禁止以任何形式发布有关 [键政/商业广告/非私人服务器宣传] 的消息;",
60 | "3.禁止以任何形式发布R18等[限制级]内容,擦边球也不行;",
61 | "4.禁止以任何形式发布付费资源;",
62 | "5.看Wiki(真的有很多问题看Wiki就能解决);",
63 | "6.看Wiki(第一次警告,第二次十分钟,第三次飞机票);",
64 | "7.看Wiki(重要的事情说三遍);",
65 | "8.群内大佬不是神,拒绝伸手党和随意@;",
66 | "更多群规详见群公告..."
67 | ]
68 | },
69 | {
70 | "name": "crtcmds",
71 | "info": "CraftTweaker 部分常用指令使用方法",
72 | "messages": [
73 | "CraftTweaker 可用的部分实用指令:",
74 | "/ct hand 输出玩家手上物品的 ID / 矿辞 (1.12-) / 标签 (1.14+) 等信息,你可以点击有关信息将其复制到剪贴板里。",
75 | "/ct syntax 检查脚本的语法是否准确。注意语法正确也不代表一定能运行的符合预期,此指令仅能检查语法问题,无法检查逻辑问题。",
76 | "/ct log 打开 CrT 日志文件,请配合 &pastebin 发送。",
77 | "/ct inventory 输出玩家物品栏的所有物品的 ID。",
78 | "/ct conflict 打印所有冲突配方和其总数。 (仅限工作台和熔炉)",
79 | "/reload (1.14+ 可用) 重载脚本。但 CoT 脚本不可重载。"
80 | ]
81 | },
82 | {
83 | "name": "mtcmds",
84 | "info": "MineTweaker 部分常用指令使用方法",
85 | "messages": [
86 | "MineTweaker 可用的部分实用指令: ",
87 | "/mt hand 输出玩家手上物品的 ID 等信息,你可以点击有关信息将其复制到剪贴板里。",
88 | "/mt inventory 输出玩家物品栏的所有物品的 ID。",
89 | "/mt oredict 打印所有游戏内存在的矿辞。",
90 | "/mt liquids 输出游戏内所有流体的注册 ID。",
91 | "/mt blocks 可以输出游戏内所有方块的注册ID。",
92 | "/mt blockinfo 开启时左右键可查看方块数据,再次输入指令以关闭。",
93 | "/mt reload 重载脚本。"
94 | ]
95 | },
96 | {
97 | "name": "whyvsc",
98 | "info": "为什么要使用 VisualStudio Code ?",
99 | "messages": [
100 | "VisualStudio Code(以下简称VSCode) 是当下编写 ZenScript 代码的最佳选择之一, 也是本群极力推荐的 文本编辑工具。",
101 | "为什么? 请花半分钟阅读以下理由:",
102 | "VSCode 是一款由微软维护的, 功能十分丰富, 用户社区和插件社区极其发达的文本编辑器。",
103 | "对于 ZenScript 这种脚本语言, 是最佳的编写工具之一, 安装了插件后, 可以提供代码高亮和语法纠错, NBT 预览和编辑, Language 文件高亮等等功能。",
104 | "就算对于其他脚本语言, 甚至程序设计语言, 其都是一个值得考虑的选择。",
105 | "想要下载并安装 VSCode, 前往 https://code.visualstudio.com/download, 下载适合自己系统的安装包安装即可。",
106 | "如果需要安装 ZenScript 高亮插件, 请参考 https://github.com/GBLodb/GBLodb/blob/master/personalModpackDevExperience.md。"
107 | ]
108 | },
109 | {
110 | "name": "links",
111 | "info": "实用链接",
112 | "messages": [
113 | "实用链接:",
114 | "CraftTweaker *官方英文文档*: https://docs.blamejared.com/",
115 | "MineTweaker 官方 Wiki: http://minetweaker3.powerofbytes.com/wiki/Main_Page/",
116 | "TweakerGroup Discord: https://discord.gg/4XsUtUfDFt/",
117 | "BlameJared Discord: https://discord.blamejared.com/",
118 | "Ubuntu Pastebin: https://paste.ubuntu.com.cn/",
119 | "Hastebin (DimDev): http://paste.dimdev.org/",
120 | "CurseForge Minecraft Mods: https://www.curseforge.com/minecraft/mc-mods/"
121 | ]
122 | }
123 | ]
124 | }
125 |
--------------------------------------------------------------------------------
/src/main/resources/permissions.json:
--------------------------------------------------------------------------------
1 | {
2 | "op": [
3 | 2082152212
4 | ],
5 | "banned": [
6 | 114514810
7 | ]
8 | }
--------------------------------------------------------------------------------