feat: add jue command

This commit is contained in:
2024-09-21 16:03:28 +08:00
parent 60b41ead3b
commit 6d4cdff0a8
6 files changed
+129 -21

No files matched your search

@@ -27,6 +27,7 @@ import cn.rtast.fancybot.commands.misc.AntiRevokeCommand
import cn.rtast.fancybot.commands.misc.CompilerCommand import cn.rtast.fancybot.commands.misc.CompilerCommand
import cn.rtast.fancybot.commands.misc.FKXQSCommand import cn.rtast.fancybot.commands.misc.FKXQSCommand
import cn.rtast.fancybot.commands.misc.HitokotoCommand import cn.rtast.fancybot.commands.misc.HitokotoCommand
import cn.rtast.fancybot.commands.misc.JueCommand
import cn.rtast.fancybot.commands.misc.LikeMeCommand import cn.rtast.fancybot.commands.misc.LikeMeCommand
import cn.rtast.fancybot.commands.misc.RUACommand import cn.rtast.fancybot.commands.misc.RUACommand
import cn.rtast.fancybot.commands.misc.RemakeCommand import cn.rtast.fancybot.commands.misc.RemakeCommand
@@ -63,7 +64,6 @@ import cn.rtast.rob.entity.FileEvent
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.entity.GroupRevokeMessage import cn.rtast.rob.entity.GroupRevokeMessage
import cn.rtast.rob.entity.PrivateMessage
import cn.rtast.rob.enums.ArrayMessageType import cn.rtast.rob.enums.ArrayMessageType
import cn.rtast.rob.util.ob.MessageChain import cn.rtast.rob.util.ob.MessageChain
import cn.rtast.rob.util.ob.OneBotListener import cn.rtast.rob.util.ob.OneBotListener
@@ -86,8 +86,10 @@ class FancyBot : OneBotListener {
val messageId = message.messageId val messageId = message.messageId
println("$sender($senderId: $groupId >>> $messageId): $msg") println("$sender($senderId: $groupId >>> $messageId): $msg")
val calculateResult = CalculateCommand.parse(message.rawMessage) if (message.rawMessage.toList().any { it in arrayListOf<Char>('*', '-', '/', '+', '=') }) {
calculateResult?.let { message.reply(calculateResult) } val calculateResult = CalculateCommand.parse(message.rawMessage)
calculateResult?.let { message.reply(calculateResult) }
}
coroutineScope.launch { coroutineScope.launch {
message.message.forEach { message.message.forEach {
@@ -220,7 +222,8 @@ val commands = listOf(
MusicPlayUrlCommand(), DomainPriceCommand(), MusicPlayUrlCommand(), DomainPriceCommand(),
SendMailCommand(), ZiBiCommand(), SendMailCommand(), ZiBiCommand(),
UnsetZiBiCommand(), WikipediaCommand(), UnsetZiBiCommand(), WikipediaCommand(),
AsciiArtCommand(), StatusCommand() AsciiArtCommand(), StatusCommand(),
JueCommand()
) )
val START_UP_TIME = Instant.now().epochSecond val START_UP_TIME = Instant.now().epochSecond
@@ -0,0 +1,65 @@
/*
* Copyright © 2024 RTAkland
* Author: RTAkland
* Date: 2024/9/21
*/
package cn.rtast.fancybot.commands.misc
import cn.rtast.fancybot.util.Resources
import cn.rtast.fancybot.util.drawCircularImage
import cn.rtast.fancybot.util.makeGif
import cn.rtast.fancybot.util.str.encodeToBase64
import cn.rtast.fancybot.util.toBufferedImage
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
import com.madgag.gif.fmsware.GifDecoder
import java.awt.image.BufferedImage
import java.net.URI
class JueCommand : BaseCommand() {
override val commandNames = listOf("")
private val avatarUrl = "https://q1.qlogo.cn/g?b=qq&nk=#{}&s=640"
private fun createJueGIF(source: String, target: String): String {
val baseGIF = Resources.loadFromResources("misc/jue.gif")
val sourceAvatar = URI(avatarUrl.replace("#{}", source)).toURL().readBytes().toBufferedImage()
val targetAvatar = URI(avatarUrl.replace("#{}", target)).toURL().readBytes().toBufferedImage()
val decoder = GifDecoder()
decoder.read(baseGIF)
val frames = mutableListOf<BufferedImage>()
fun drawFrame(index: Int, sourceX: Int, sourceY: Int, targetX: Int, targetY: Int) {
val frame = decoder.getFrame(index)
val g2d = frame.createGraphics()
g2d.drawCircularImage(sourceAvatar, sourceX, sourceY, 126.0, 126.0)
g2d.drawCircularImage(targetAvatar, targetX, targetY, 126.0, 126.0)
g2d.dispose()
frames.add(frame)
}
(0 until decoder.frameCount).forEach {
when (it) {
0 -> drawFrame(it, 115, -12, 3, 175)
1 -> drawFrame(it, 109, 2, 10, 170)
2 -> drawFrame(it, 130, -13, 5, 154)
}
}
val gifBytes = decoder.makeGif(frames)
val gif = gifBytes.encodeToBase64()
return gif
}
override suspend fun executeGroup(listener: OneBotListener, message: GroupMessage, args: List<String>) {
val target = message.message.find { it.type == ArrayMessageType.at }?.data?.qq.toString()
val source = message.sender.userId.toString()
val gif = this.createJueGIF(source, target)
val msg = MessageChain.Builder().addImage(gif, true).build()
listener.sendGroupMessage(message.groupId, msg)
}
}
@@ -7,6 +7,7 @@
package cn.rtast.fancybot.commands.parse package cn.rtast.fancybot.commands.parse
import cn.rtast.fancybot.util.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.GetMessage
import cn.rtast.rob.enums.ArrayMessageType import cn.rtast.rob.enums.ArrayMessageType
@@ -24,16 +25,7 @@ object ReverseGIFCommand {
val decoder = GifDecoder() val decoder = GifDecoder()
decoder.read(gifStream) decoder.read(gifStream)
val frames = (0 until decoder.frameCount).map { decoder.getFrame(it) }.reversed() val frames = (0 until decoder.frameCount).map { decoder.getFrame(it) }.reversed()
val byteArrayOutputStream = ByteArrayOutputStream() val gifBytes = decoder.makeGif(frames)
val encoder = AnimatedGifEncoder()
encoder.start(byteArrayOutputStream)
encoder.setRepeat(0)
for (i in frames.indices) {
encoder.setDelay(decoder.getDelay(decoder.frameCount - i - 1))
encoder.addFrame(frames[i])
}
encoder.finish()
val gifBytes = byteArrayOutputStream.toByteArray()
return gifBytes.encodeToBase64() return gifBytes.encodeToBase64()
} }
@@ -0,0 +1,26 @@
/*
* Copyright © 2024 RTAkland
* Author: RTAkland
* Date: 2024/9/21
*/
package cn.rtast.fancybot.util
import com.madgag.gif.fmsware.AnimatedGifEncoder
import com.madgag.gif.fmsware.GifDecoder
import java.awt.image.BufferedImage
import java.io.ByteArrayOutputStream
fun GifDecoder.makeGif(frames: List<BufferedImage>): ByteArray {
val byteArrayOutputStream = ByteArrayOutputStream()
val encoder = AnimatedGifEncoder()
encoder.start(byteArrayOutputStream)
encoder.setRepeat(0)
for (i in frames.indices) {
encoder.setDelay(this.getDelay(this.frameCount - i - 1))
encoder.addFrame(frames[i])
}
encoder.finish()
return byteArrayOutputStream.toByteArray()
}
@@ -9,12 +9,25 @@ package cn.rtast.fancybot.util
import cn.rtast.fancybot.configManager import cn.rtast.fancybot.configManager
import java.awt.Graphics2D import java.awt.Graphics2D
import java.awt.geom.Ellipse2D
import java.awt.geom.RoundRectangle2D import java.awt.geom.RoundRectangle2D
import java.awt.image.BufferedImage import java.awt.image.BufferedImage
import java.io.ByteArrayInputStream import java.io.ByteArrayInputStream
import java.io.ByteArrayOutputStream import java.io.ByteArrayOutputStream
import javax.imageio.ImageIO import javax.imageio.ImageIO
private fun BufferedImage.getScaledWidth(maxWidth: Double, maxHeight: Double): Pair<Int, Int> {
val originalWidth = this.getWidth(null)
val originalHeight = this.getHeight(null)
val widthScale = maxWidth / originalWidth
val heightScale = maxHeight / originalHeight
val scale = minOf(widthScale, heightScale)
val targetWidth = (originalWidth * scale).toInt()
val targetHeight = (originalHeight * scale).toInt()
return targetWidth to targetHeight
}
fun Graphics2D.drawCustomImage( fun Graphics2D.drawCustomImage(
image: BufferedImage, image: BufferedImage,
x: Int, x: Int,
@@ -23,13 +36,7 @@ fun Graphics2D.drawCustomImage(
maxHeight: Double, maxHeight: Double,
clip: Boolean = false clip: Boolean = false
) { ) {
val originalWidth = image.getWidth(null) val (targetWidth, targetHeight) = image.getScaledWidth(maxWidth, maxHeight)
val originalHeight = image.getHeight(null)
val widthScale = maxWidth / originalWidth
val heightScale = maxHeight / originalHeight
val scale = minOf(widthScale, heightScale)
val targetWidth = (originalWidth * scale).toInt()
val targetHeight = (originalHeight * scale).toInt()
if (clip) { if (clip) {
this.clip = RoundRectangle2D.Float( this.clip = RoundRectangle2D.Float(
x.toFloat(), x.toFloat(),
@@ -41,6 +48,21 @@ fun Graphics2D.drawCustomImage(
) )
} }
this.drawImage(image, x, y, targetWidth, targetHeight, null) this.drawImage(image, x, y, targetWidth, targetHeight, null)
this.clip = null
}
fun Graphics2D.drawCircularImage(
image: BufferedImage,
x: Int,
y: Int,
maxWidth: Double,
maxHeight: Double,
) {
val (targetWidth, targetHeight) = image.getScaledWidth(maxWidth, maxHeight)
val circle = Ellipse2D.Double(x.toDouble(), y.toDouble(), targetWidth.toDouble(), targetHeight.toDouble());
this.clip = circle
this.drawImage(image, x, y, targetWidth, targetHeight, null)
this.clip = null
} }
fun BufferedImage.scaleImage(size: Pair<Int, Int>): BufferedImage { fun BufferedImage.scaleImage(size: Pair<Int, Int>): BufferedImage {
Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB