mirror of
https://github.com/mamoe/mirai.git
synced 2025-01-20 19:09:12 +08:00
LoginSolver swing (#257)
* LoginSolver, gui support * make `internal`,`object`, and rename.
This commit is contained in:
parent
03cffb897c
commit
0ede49896e
@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright 2020 Mamoe Technologies and contributors.
|
||||
*
|
||||
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
|
||||
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
|
||||
*
|
||||
* https://github.com/mamoe/mirai/blob/master/LICENSE
|
||||
*/
|
||||
|
||||
package net.mamoe.mirai.utils
|
||||
|
||||
/**
|
||||
* @author Karlatemp <karlatemp@vip.qq.com> <https://github.com/Karlatemp>
|
||||
*/
|
||||
|
||||
import kotlinx.coroutines.CompletableDeferred
|
||||
import java.awt.BorderLayout
|
||||
import java.awt.Desktop
|
||||
import java.awt.event.KeyEvent
|
||||
import java.awt.event.KeyListener
|
||||
import java.awt.event.WindowAdapter
|
||||
import java.awt.event.WindowEvent
|
||||
import javax.swing.JFrame
|
||||
import javax.swing.JTextField
|
||||
|
||||
internal class WindowInitialzier(private val initializer: WindowInitialzier.(JFrame) -> Unit) {
|
||||
private lateinit var frame0: JFrame
|
||||
val frame: JFrame get() = frame0
|
||||
fun java.awt.Component.append() {
|
||||
frame.add(this, BorderLayout.NORTH);
|
||||
}
|
||||
|
||||
fun java.awt.Component.last() {
|
||||
frame.add(this);
|
||||
}
|
||||
|
||||
internal fun init(frame: JFrame) {
|
||||
this.frame0 = frame;
|
||||
initializer(frame)
|
||||
}
|
||||
}
|
||||
|
||||
internal suspend fun openWindow(title: String = "", initializer: WindowInitialzier.(JFrame) -> Unit = {}): String {
|
||||
return openWindow(title, WindowInitialzier(initializer))
|
||||
}
|
||||
|
||||
internal suspend fun openWindow(title: String = "", initializer: WindowInitialzier = WindowInitialzier {}): String {
|
||||
val frame = JFrame()
|
||||
val value = JTextField()
|
||||
val def = CompletableDeferred<String>()
|
||||
value.addKeyListener(object : KeyListener {
|
||||
override fun keyTyped(e: KeyEvent?) {
|
||||
}
|
||||
|
||||
override fun keyPressed(e: KeyEvent?) {
|
||||
when (e!!.keyCode) {
|
||||
27, 10 -> {
|
||||
def.complete(value.text)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun keyReleased(e: KeyEvent?) {
|
||||
}
|
||||
})
|
||||
frame.layout = BorderLayout(10, 5)
|
||||
frame.add(value, BorderLayout.SOUTH)
|
||||
initializer.init(frame)
|
||||
|
||||
frame.pack()
|
||||
frame.defaultCloseOperation = JFrame.DISPOSE_ON_CLOSE
|
||||
frame.addWindowListener(object : WindowAdapter() {
|
||||
override fun windowClosing(e: WindowEvent?) {
|
||||
def.complete(value.text)
|
||||
}
|
||||
})
|
||||
frame.setLocationRelativeTo(null)
|
||||
frame.title = title
|
||||
frame.isVisible = true
|
||||
|
||||
val result = def.await()
|
||||
frame.dispose()
|
||||
return result
|
||||
}
|
@ -22,19 +22,46 @@ import kotlinx.coroutines.sync.withLock
|
||||
import kotlinx.coroutines.withContext
|
||||
import kotlinx.io.core.use
|
||||
import net.mamoe.mirai.Bot
|
||||
import net.mamoe.mirai.network.BotNetworkHandler
|
||||
import java.awt.Desktop
|
||||
import java.awt.Image
|
||||
import java.awt.image.BufferedImage
|
||||
import java.io.File
|
||||
import java.io.RandomAccessFile
|
||||
import javax.imageio.ImageIO
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
import kotlin.coroutines.EmptyCoroutineContext
|
||||
|
||||
actual typealias Throws = kotlin.jvm.Throws
|
||||
|
||||
@MiraiExperimentalAPI
|
||||
class DefaultLoginSolver(
|
||||
val input: suspend () -> String,
|
||||
val overrideLogger: MiraiLogger? = null
|
||||
) : LoginSolver() {
|
||||
private val degelate: LoginSolver
|
||||
|
||||
init {
|
||||
if (Desktop.isDesktopSupported()) {
|
||||
degelate = SwingSolver
|
||||
} else {
|
||||
degelate = DefaultLoginSolverImpl(input, overrideLogger)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun onSolvePicCaptcha(bot: Bot, data: ByteArray): String? {
|
||||
return degelate.onSolvePicCaptcha(bot, data)
|
||||
}
|
||||
|
||||
override suspend fun onSolveSliderCaptcha(bot: Bot, url: String): String? {
|
||||
return degelate.onSolveSliderCaptcha(bot, url)
|
||||
}
|
||||
|
||||
override suspend fun onSolveUnsafeDeviceLoginVerify(bot: Bot, url: String): String? {
|
||||
return degelate.onSolveUnsafeDeviceLoginVerify(bot, url)
|
||||
}
|
||||
}
|
||||
|
||||
@MiraiExperimentalAPI
|
||||
class DefaultLoginSolverImpl(
|
||||
private val input: suspend () -> String,
|
||||
private val overrideLogger: MiraiLogger? = null
|
||||
) : LoginSolver() {
|
||||
@ -106,7 +133,14 @@ actual abstract class LoginSolver {
|
||||
actual companion object {
|
||||
actual val Default: LoginSolver
|
||||
@OptIn(MiraiExperimentalAPI::class)
|
||||
get() = DefaultLoginSolver(input = { withContext(Dispatchers.IO) { readLine() } ?: error("No standard input") })
|
||||
get() {
|
||||
if (Desktop.isDesktopSupported()) {
|
||||
return SwingSolver
|
||||
}
|
||||
return DefaultLoginSolverImpl(input = {
|
||||
withContext(Dispatchers.IO) { readLine() } ?: error("No standard input")
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -149,7 +183,8 @@ private fun BufferedImage.createCharImg(outputWidth: Int = 100, ignoreRate: Doub
|
||||
return (r * 30 + g * 59 + b * 11 + 50) / 100
|
||||
}
|
||||
|
||||
fun grayCompare(g1: Int, g2: Int): Boolean = kotlin.math.min(g1, g2).toDouble() / kotlin.math.max(g1, g2) >= ignoreRate
|
||||
fun grayCompare(g1: Int, g2: Int): Boolean =
|
||||
kotlin.math.min(g1, g2).toDouble() / kotlin.math.max(g1, g2) >= ignoreRate
|
||||
|
||||
val background = gray(image.getRGB(0, 0))
|
||||
|
||||
|
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright 2020 Mamoe Technologies and contributors.
|
||||
*
|
||||
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
|
||||
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
|
||||
*
|
||||
* https://github.com/mamoe/mirai/blob/master/LICENSE
|
||||
*/
|
||||
|
||||
package net.mamoe.mirai.utils
|
||||
|
||||
import net.mamoe.mirai.Bot
|
||||
import java.awt.Desktop
|
||||
import java.net.URI
|
||||
import javax.imageio.ImageIO
|
||||
import javax.swing.ImageIcon
|
||||
import javax.swing.JLabel
|
||||
import javax.swing.JTextField
|
||||
|
||||
/**
|
||||
* @author Karlatemp <karlatemp@vip.qq.com> <https://github.com/Karlatemp>
|
||||
*/
|
||||
@MiraiExperimentalAPI
|
||||
object SwingSolver : LoginSolver() {
|
||||
override suspend fun onSolvePicCaptcha(bot: Bot, data: ByteArray): String? {
|
||||
return openWindow("Mirai PicCaptcha(${bot.id})") {
|
||||
val image = ImageIO.read(data.inputStream())
|
||||
JLabel(ImageIcon(image)).append()
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun onSolveSliderCaptcha(bot: Bot, url: String): String? {
|
||||
return openWindow("Mirai SliderCaptcha(${bot.id})") {
|
||||
JLabel("需要滑动验证码, 完成后请关闭该窗口").append()
|
||||
Desktop.getDesktop().browse(URI(url))
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun onSolveUnsafeDeviceLoginVerify(bot: Bot, url: String): String? {
|
||||
return openWindow("Mirai UnsafeDeviceLoginVerify(${bot.id})") {
|
||||
JLabel("需要进行账户安全认证").last()
|
||||
JLabel("该账户有[设备锁]/[不常用登录地点]/[不常用设备登录]的问题").last()
|
||||
JLabel("完成以下账号认证即可成功登录|理论本认证在mirai每个账户中最多出现1次").last()
|
||||
JTextField(url).append()
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user