Merge remote-tracking branch 'origin/master'

This commit is contained in:
Him188 2020-02-23 18:14:44 +08:00
commit a8e7fa85a7
12 changed files with 6311 additions and 102 deletions

View File

@ -13,10 +13,7 @@ import net.mamoe.mirai.console.graphical.model.VerificationCodeModel
import net.mamoe.mirai.console.graphical.view.VerificationCodeFragment
import net.mamoe.mirai.console.utils.MiraiConsoleUI
import net.mamoe.mirai.utils.LoginSolver
import tornadofx.Controller
import tornadofx.Scope
import tornadofx.find
import tornadofx.observableListOf
import tornadofx.*
class MiraiGraphicalUIController : Controller(), MiraiConsoleUI {
@ -28,8 +25,6 @@ class MiraiGraphicalUIController : Controller(), MiraiConsoleUI {
val botList = observableListOf<BotModel>()
val pluginList: ObservableList<PluginModel> by lazy(::getPluginsFromConsole)
// val consoleConfig : Map<String, Any> by lazy(::getConfigFromConsole)
val consoleInfo = ConsoleInfo()
fun login(qq: String, psd: String) {
@ -79,10 +74,9 @@ class MiraiGraphicalUIController : Controller(), MiraiConsoleUI {
override fun createLoginSolver(): LoginSolver = loginSolver
private fun getPluginsFromConsole(): ObservableList<PluginModel> {
// TODO
return observableListOf<PluginModel>()
}
private fun getPluginsFromConsole(): ObservableList<PluginModel> =
MiraiConsole.pluginManager.getAllPluginDescriptions().map(::PluginModel).toObservable()
}
class GraphicalLoginSolver : LoginSolver() {

View File

@ -3,16 +3,17 @@ package net.mamoe.mirai.console.graphical.model
import com.jfoenix.controls.datamodels.treetable.RecursiveTreeObject
import javafx.beans.property.SimpleBooleanProperty
import javafx.beans.property.SimpleStringProperty
import net.mamoe.mirai.console.plugins.PluginDescription
import tornadofx.getValue
import tornadofx.setValue
class PluginModel : RecursiveTreeObject<PluginModel>() {
val nameProperty = SimpleStringProperty(this, "nameProperty")
val name by nameProperty
val descriptionProperty = SimpleStringProperty(this, "descriptionProperty")
val description by descriptionProperty
class PluginModel(
val name: String,
val version: String,
val author: String,
val description: String
) : RecursiveTreeObject<PluginModel>() {
constructor(plugin: PluginDescription):this(plugin.name, plugin.version, plugin.author, plugin.info)
val enabledProperty = SimpleBooleanProperty(this, "enabledProperty")
var enabled by enabledProperty

View File

@ -13,10 +13,21 @@ class PluginsView : View() {
override val root = jfxTreeTableView(plugins) {
columns.addAll(
JFXTreeTableColumn<PluginModel, String>("插件名").apply { },
JFXTreeTableColumn<PluginModel, String>("版本").apply { },
JFXTreeTableColumn<PluginModel, String>("作者").apply { },
JFXTreeTableColumn<PluginModel, String>("介绍").apply { }
JFXTreeTableColumn<PluginModel, String>("插件名").apply {
prefWidthProperty().bind(this@jfxTreeTableView.widthProperty().multiply(0.1))
},
JFXTreeTableColumn<PluginModel, String>("版本").apply {
prefWidthProperty().bind(this@jfxTreeTableView.widthProperty().multiply(0.1))
},
JFXTreeTableColumn<PluginModel, String>("作者").apply {
prefWidthProperty().bind(this@jfxTreeTableView.widthProperty().multiply(0.1))
},
JFXTreeTableColumn<PluginModel, String>("介绍").apply {
prefWidthProperty().bind(this@jfxTreeTableView.widthProperty().multiply(0.6))
},
JFXTreeTableColumn<PluginModel, String>("操作").apply {
prefWidthProperty().bind(this@jfxTreeTableView.widthProperty().multiply(0.08))
}
)
}
}

View File

@ -1,23 +1,36 @@
package net.mamoe.mirai.console.graphical.view
import net.mamoe.mirai.console.graphical.controller.MiraiGraphicalUIController
import net.mamoe.mirai.console.graphical.util.jfxButton
import net.mamoe.mirai.console.graphical.util.jfxTextfield
import tornadofx.View
import tornadofx.field
import tornadofx.fieldset
import tornadofx.form
import tornadofx.*
class SettingsView : View() {
private val controller = find<MiraiGraphicalUIController>()
override val root = form {
// controller.consoleConfig.forEach {
// fieldset {
// field(it.key) {
// jfxTextfield(it.value.toString()) { isEditable = false }
// }
// }
// }
fieldset {
field {
jfxButton("撤掉") { }
jfxButton("保存") { }
}
}
fieldset("插件目录") {
field {
jfxTextfield("...") { isEditable = false }
jfxButton("打开目录")
}
}
fieldset("最大日志容量") {
field {
jfxTextfield("...") {
}
}
}
}
}

View File

@ -0,0 +1,2 @@
package net.mamoe.mirai.console

View File

@ -131,13 +131,6 @@ object DefaultCommands {
}
bot.login()
bot.subscribeMessages {
contains("test") {
if (this is GroupMessage) {
quoteReply("Hello $senderName")
} else {
reply("Hello!")
}
}
this.startsWith("/") {
if (bot.checkManager(this.sender.id)) {
val sender = ContactCommandSender(this.subject)
@ -149,7 +142,6 @@ object DefaultCommands {
}
sendMessage("$qqNumber login successes")
MiraiConsole.frontEnd.pushBot(bot)
} catch (e: Exception) {
sendMessage("$qqNumber login failed -> " + e.message)
}

View File

@ -48,6 +48,7 @@ interface Config {
fun getFloatList(key: String): List<Float>
fun getDoubleList(key: String): List<Double>
fun getLongList(key: String): List<Long>
fun getConfigSectionList(key: String): List<ConfigSection>
operator fun set(key: String, value: Any)
operator fun get(key: String): Any?
operator fun contains(key: String): Boolean
@ -196,8 +197,14 @@ fun <T : Any> Config._smartCast(propertyName: String, _class: KClass<T>): T {
Float::class -> getFloatList(propertyName)
Double::class -> getDoubleList(propertyName)
Long::class -> getLongList(propertyName)
//不去支持getConfigSectionList(propertyName)
// LinkedHashMap::class -> getConfigSectionList(propertyName)//faster approach
else -> {
error("unsupported type")
//if(list[0]!! is ConfigSection || list[0]!! is Map<*,*>){
// getConfigSectionList(propertyName)
//}else {
error("unsupported type" + list[0]!!::class)
//}
}
}
} as T
@ -271,6 +278,20 @@ interface ConfigSection : Config, MutableMap<String, Any> {
return ((get(key) ?: error("ConfigSection does not contain $key ")) as List<*>).map { it.toString().toLong() }
}
override fun getConfigSectionList(key: String): List<ConfigSection> {
return ((get(key) ?: error("ConfigSection does not contain $key ")) as List<*>).map {
if (it is ConfigSection) {
it
} else {
ConfigSectionDelegation(
Collections.synchronizedMap(
it as MutableMap<String, Any>
)
)
}
}
}
override fun exist(key: String): Boolean {
return get(key) != null
}

View File

@ -1,48 +0,0 @@
/*
* 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.imageplugin
import com.alibaba.fastjson.JSON
import kotlinx.coroutines.*
import net.mamoe.mirai.contact.Contact
import net.mamoe.mirai.message.data.Image
import net.mamoe.mirai.message.uploadAsImage
import org.jsoup.Jsoup
class ImageProvider {
lateinit var contact: Contact
// `Deferred<Image?>` causes a runtime ClassCastException
val image: Deferred<Image> by lazy {
GlobalScope.async {
withTimeoutOrNull(5 * 1000) {
withContext(Dispatchers.IO) {
val result = JSON.parseArray(
Jsoup.connect("https://yande.re/post.json?limit=1&page=${(Math.random() * 10000).toInt()}").ignoreContentType(
true
).timeout(
10_0000
).get().body().text()
)
Jsoup.connect(result.getJSONObject(0).getString("jpeg_url"))
.userAgent("Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_7; ja-jp) AppleWebKit/533.20.25 (KHTML, like Gecko) Version/5.0.4 Safari/533.20.27")
.timeout(10_0000)
.ignoreContentType(true)
.maxBodySize(Int.MAX_VALUE)
.execute()
.bodyStream()
}
}?.uploadAsImage(contact) ?: error("Unable to download image|连接这个图站需要你的网络在外网")
}
}
}

View File

@ -9,15 +9,27 @@
package net.mamoe.mirai.imageplugin
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.*
import net.mamoe.mirai.console.plugins.Config
import net.mamoe.mirai.console.plugins.ConfigSection
import net.mamoe.mirai.event.events.BotOnlineEvent
import net.mamoe.mirai.event.subscribeAlways
import net.mamoe.mirai.event.subscribeMessages
import net.mamoe.mirai.console.plugins.PluginBase
import net.mamoe.mirai.contact.Contact
import net.mamoe.mirai.message.data.Image
import net.mamoe.mirai.message.uploadAsImage
import net.mamoe.mirai.utils.MiraiExperimentalAPI
import org.jsoup.Jsoup
import java.io.File
import kotlin.random.Random
class ImageSenderMain : PluginBase() {
lateinit var images: Config
lateinit var normal: List<ConfigSection>
lateinit var r18: List<ConfigSection>
@ExperimentalCoroutinesApi
@MiraiExperimentalAPI
override fun onEnable() {
@ -25,24 +37,61 @@ class ImageSenderMain : PluginBase() {
GlobalScope.subscribeAlways<BotOnlineEvent> {
logger.info("${this.bot.uin} login succeed, it will be controlled by Image Sender Plugin")
this.bot.subscribeMessages {
case("at me") {
reply(sender.at() + " ? ")
(contains("色图")) {
try {
with(normal.random()) {
getImage(
subject, this.getString("url"), this.getString("pid")
).plus(this.getString("tags")).send()
}
} catch (e: Exception) {
reply(e.message ?: "unknown error")
}
}
(contains("image") or contains("")) {
"图片发送中".reply()
ImageProvider().apply {
this.contact = sender
}.image.await().reply()
(contains("不够色")) {
try {
with(r18.random()) {
getImage(
subject, this.getString("url"), this.getString("pid")
).plus(this.getString("tags")).send()
}
} catch (e: Exception) {
reply(e.message ?: "unknown error")
}
}
}
}
}
suspend fun getImage(contact: Contact, url: String, pid: String): Image {
return withTimeoutOrNull(20 * 1000) {
withContext(Dispatchers.IO) {
Jsoup
.connect(url)
.followRedirects(true)
.timeout(180_000)
.ignoreContentType(true)
.userAgent("Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_7; ja-jp) AppleWebKit/533.20.25 (KHTML, like Gecko) Version/5.0.4 Safari/533.20.27")
.referrer("https://www.pixiv.net/member_illust.php?mode=medium&illust_id=$pid")
.ignoreHttpErrors(true)
.maxBodySize(100000000)
.execute().also { check(it.statusCode() == 200) { "Failed to download image" } }
}
}?.bodyStream()?.uploadAsImage(contact) ?: error("Unable to download image")
}
override fun onLoad() {
logger.info("loading...")
logger.info("loading local image data")
try {
images = Config.load(this.javaClass.classLoader.getResource("data.yml")!!.path!!)
} catch (e: Exception) {
logger.info("无法加载本地图片")
}
logger.info("本地图片版本" + images.getString("version"))
logger.info("Normal * " + images.getList("normal").size)
logger.info("R18 * " + images.getList("R18").size)
}
override fun onDisable() {

View File

@ -0,0 +1,144 @@
import com.alibaba.fastjson.JSONObject
import com.google.gson.JsonObject
import net.mamoe.mirai.console.plugins.*
import net.mamoe.mirai.utils.cryptor.contentToString
import org.jsoup.Connection
import org.jsoup.Jsoup
import java.io.File
import kotlin.concurrent.thread
object Data {
val section = (File(System.getProperty("user.dir") + "/setu.yml")).loadAsConfig()
val abstract = section.getStringList("abstract").toMutableList()
val R18 = section.getConfigSectionList("R18").toMutableList()
val normal = section.getConfigSectionList("normal").toMutableList()
fun init() {
section.setIfAbsent("abstract", mutableListOf<String>())
section.setIfAbsent("R18", mutableListOf<ConfigSection>())
section.setIfAbsent("Normal", mutableListOf<ConfigSection>())
}
fun save() {
section["abstract"] = abstract
section["R18"] = R18
section["normal"] = normal
section.save()
}
}
fun main() {
val abstract_file = (File(System.getProperty("user.dir") + "/abstractSetu.yml")).loadAsConfig()
abstract_file.setIfAbsent("R18", mutableListOf<ConfigSection>())
abstract_file.setIfAbsent("normal", mutableListOf<ConfigSection>())
val r18 = abstract_file.getConfigSectionList("R18").toMutableList()
val normal = abstract_file.getConfigSectionList("normal").toMutableList()
Data.R18.forEach {
val forbid = with(it.getString("tags")) {
this.contains("初音ミク") || this.contains("VOCALOID") || this.contains("Miku")
||
this.contains("东方") || this.contains("東方")
}
if (forbid) {
println("过滤掉了一张图")
} else {
r18.add(
ConfigSectionImpl().apply {
this["pid"] = it["pid"]!!
this["author"] = it["author"]!!
this["uid"] = it["uid"]!!
this["tags"] = it["tags"]!!
this["url"] = it["url"]!!
}
)
}
}
Data.normal.forEach {
val forbid = with(it.getString("tags")) {
this.contains("初音ミク") || this.contains("VOCALOID") || this.contains("Miku")
||
this.contains("东方") || this.contains("東方")
}
if (forbid) {
println("过滤掉了一张图")
} else {
normal.add(
ConfigSectionImpl().apply {
this["pid"] = it["pid"]!!
this["author"] = it["author"]!!
this["uid"] = it["uid"]!!
this["tags"] = it["tags"]!!
this["url"] = it["url"]!!
}
)
}
}
abstract_file.set("R18", r18)
abstract_file.set("normal", normal)
abstract_file.save()
/**
Data.init()
Runtime.getRuntime().addShutdownHook(thread(start = false) {
Data.save()
})
while (true){
try {
val val0 = JSONObject.parseObject(Jsoup
.connect("https://api.lolicon.app/setu/")
.ignoreContentType(true)
.method(Connection.Method.GET)
.data("r18","1")
.data("num","10")
.execute().body())
val val1 = val0.getJSONArray("data")
for(index in 0 until val1.size - 1){
val content = val1.getJSONObject(index)
val pid = content.getString("pid")
if(Data.abstract.contains(pid)){
println("获取到了一张重复图$pid")
continue
}
val configSection = ConfigSectionImpl()
val isR18 = content.getBoolean("r18")
configSection["author"] = content.getString("author")
configSection["pid"] = pid
configSection["uid"] = content.getInteger("uid")
configSection["width"] = content.getInteger("width")
configSection["height"] = content.getInteger("height")
configSection["tags"] = content.getJSONArray("tags").map {
it.toString()
}.joinToString(",")
configSection["url"] = content.getString("url")
if(isR18){
Data.R18.add(configSection)
print("获取到了一张R18")
}else{
Data.normal.add(configSection)
print("获取到了一张Normal")
}
Data.abstract.add(pid)
println(configSection.contentToString())
}
}catch (e:Exception){
println(e.message)
}
Data.save()
println("SAVED")
Thread.sleep(1000)
}
*/
}

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
name: ImageSender
main: net.mamoe.mirai.imageplugin.ImageSenderMain
version: 1.0.0
author: mamoe
info: a demo plugin of mirai
author: 不想写代码
info: a demo[hso] plugin of mirai