Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
M
Mirai
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Locked Files
Issues
0
Issues
0
List
Boards
Labels
Service Desk
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Security & Compliance
Security & Compliance
Dependency List
License Compliance
Packages
Packages
List
Container Registry
Analytics
Analytics
CI / CD
Code Review
Insights
Issues
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
MyCard
Mirai
Commits
a9502957
Commit
a9502957
authored
Feb 05, 2020
by
jiahua.liu
Browse files
Options
Browse Files
Download
Plain Diff
Merge remote-tracking branch 'origin/master'
parents
6f67edfd
28cdb759
Changes
17
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
17 changed files
with
545 additions
and
215 deletions
+545
-215
README.md
README.md
+0
-1
mirai-api-http/README_CH.md
mirai-api-http/README_CH.md
+274
-19
mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/MiraiHttpAPIServer.kt
...ain/kotlin/net/mamoe/mirai/api/http/MiraiHttpAPIServer.kt
+3
-8
mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/Session.kt
...-http/src/main/kotlin/net/mamoe/mirai/api/http/Session.kt
+14
-17
mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/dto/ContactDTO.kt
...rc/main/kotlin/net/mamoe/mirai/api/http/dto/ContactDTO.kt
+2
-1
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/ContactImpl.kt
...ommonMain/kotlin/net/mamoe/mirai/qqandroid/ContactImpl.kt
+10
-0
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/data/proto/OIDB.kt
...mamoe/mirai/qqandroid/network/protocol/data/proto/OIDB.kt
+123
-123
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/OnlinePush.kt
...ndroid/network/protocol/packet/chat/receive/OnlinePush.kt
+0
-0
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Contact.kt
.../src/commonMain/kotlin/net.mamoe.mirai/contact/Contact.kt
+19
-3
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Group.kt
...re/src/commonMain/kotlin/net.mamoe.mirai/contact/Group.kt
+17
-17
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Member.kt
...e/src/commonMain/kotlin/net.mamoe.mirai/contact/Member.kt
+9
-5
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/MessagePacket.kt
...ommonMain/kotlin/net.mamoe.mirai/message/MessagePacket.kt
+41
-7
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/MessageChain.kt
...nMain/kotlin/net.mamoe.mirai/message/data/MessageChain.kt
+2
-0
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/io/DebugUtil.kt
...c/commonMain/kotlin/net.mamoe.mirai/utils/io/DebugUtil.kt
+1
-0
mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/message/MessagePacket.kt
...c/jvmMain/kotlin/net/mamoe/mirai/message/MessagePacket.kt
+17
-1
mirai-demos/mirai-demo-gentleman/src/main/kotlin/demo/gentleman/GentleImage.kt
...o-gentleman/src/main/kotlin/demo/gentleman/GentleImage.kt
+9
-7
mirai-demos/mirai-demo-gentleman/src/main/kotlin/demo/gentleman/Gentleman.kt
...emo-gentleman/src/main/kotlin/demo/gentleman/Gentleman.kt
+4
-6
No files found.
README.md
View file @
a9502957
# Mirai
# Mirai
[

](https://www.codacy.com/manual/Him188/mirai?utm_source=github.com
&
utm_medium=referral
&
utm_content=mamoe/mirai
&
utm_campaign=Badge_Grade)
[

](https://gitter.im/mamoe/mirai?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
[

](https://gitter.im/mamoe/mirai?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
[

](https://github.com/mamoe/mirai/actions)
[

](https://github.com/mamoe/mirai/actions)
[

](https://bintray.com/him188moe/mirai/mirai-core/)
[

](https://bintray.com/him188moe/mirai/mirai-core/)
...
...
mirai-api-http/README_CH.md
View file @
a9502957
# mirai-api-http
# mirai-api-http
<b>
<b>
Mirai-API-http 提供HTTP API供所有语言使用mirai
</b>
Mirai-API-http 提供HTTP API供所有语言使用mirai
<br>
</b>
### 快速开始
```
kotlin
fun
main
()
{
val
bot
=
Bot
(
123456789
,
"password"
)
bot
.
login
()
MiraiHttpAPIServer
.
start
()
bot
.
network
.
awaitDisconnection
()
}
```
### 开始会话-认证(Authorize)
### 开始会话-认证(Authorize)
```
```
[POST] /auth
[POST] /auth
```
```
使用此方法验证你的会话连接, 并将这个会话绑定一个BOT
<br>
使用此方法验证你的身份,并返回一个会话
注意: 每个会话只能绑定一个BOT.
#### 请求:<br>
#### 请求:
```
json5
{
"authKey": "U9HSaDXl39ksd918273hU"
}
```
| 名字 | 类型 | 可选 | 举例 | 说明 |
| 名字 | 类型 | 可选 | 举例 | 说明 |
| --- | --- | --- | --- | --- |
| --- | --- | --- | --- | --- |
| key | String |false|U9HSaDXl39ksd918273hU|MIRAI API HTTP key, HTTP API的核心key|
| authKey | String |false|"U9HSaDXl39ksd918273hU"|创建Mirai-Http-Server时生成的key,可在启动时指定或随机生成|
| qq | String |false|1040400290|需要绑定的BOT QQ号|
#### 响应: 返回(成功):
#### 返回(成功):<br>
```
json5
{
"code": 0,
"session": "UnVerifiedSession"
}
```
| 名字 | 类型 | 举例 | 说明|
| 名字 | 类型 | 举例 | 说明|
| --- | --- | --- | --- |
| --- | --- | --- | --- |
| code |Int |0|返回状态|
| code |Int |0|返回状态
码
|
| session |String |
UANSHDKSLAOISN
|你的session key|
| session |String |
"UnVerifiedSession"
|你的session key|
#### 状态码:
<br>
#### 状态码:
| 代码 | 原因|
| 代码 | 原因|
| --- | --- |
| --- | --- |
| 0 | 正常 |
| 0 | 正常 |
| 1 | 错误的MIRAI API HTTP key|
| 1 | 错误的MIRAI API HTTP auth key|
| 2 | 试图绑定不存在的bot|
session key 是使用以下方法必须携带的
</br>
session key 是使用以下方法必须携带的
</br>
session key
需要被以cookie的形式上报
<b>
cookies
</b>
:
session key
使用前必须进行校验和绑定指定的Bot,
**每个Session只能绑定一个Bot,但一个Bot可有多个Session**
| 名字 | 值 |
| --- | --- |
| session |your session key here |
如果出现HTTP 403错误码,代表session key已过期, 需要重新获取
### 校验Session
```
[post] /verify
```
使用此方法校验并激活你的Session,同时将Session与一个
**已登录**
的Bot绑定
#### 请求:
```
json5
{
"sessionKey": "UnVerifiedSession",
"qq": 123456789
}
```
| 名字 | 类型 | 可选 | 举例 | 说明 |
| ---------- | ------ | ----- | ------------------- | -------------------------- |
| sessionKey | String | false | "UnVerifiedSession" | 你的session key |
| qq | Long | false | 123456789 | Session将要绑定的Bot的qq号 |
#### 响应: 返回统一状态码(后续不再赘述)
```
json5
{
"code": 0,
"msg": "success"
}
```
| 状态码 | 原因 |
| ------ | ---------------------------------- |
| 0 | 正常 |
| 1 | 错误的auth key |
| 2 | 绑定的Bot不存在 |
| 3 | Session失效或不存在 |
| 4 | Session未认证(未激活) |
| 5 | 发送消息目标不存在(指定对象不存在) |
| 400 | 错误的访问,如参数错误等 |
### 发送好友消息
### 发送好友消息
...
@@ -50,3 +110,198 @@ Mirai-API-http 提供HTTP API供所有语言使用mirai<br>
...
@@ -50,3 +110,198 @@ Mirai-API-http 提供HTTP API供所有语言使用mirai<br>
[POST] /sendFriendMessage
[POST] /sendFriendMessage
```
```
使用此方法向指定好友发送消息
#### 请求
```
json5
{
"sessionKey": "YourSession",
"target": 987654321,
"messageChain": [
{ "type": "Plain", "text":"hello\n" },
{ "type": "Plain", "text":"world" }
]
}
```
| 名字 | 类型 | 可选 | 举例 | 说明 |
| ------------ | ------ | ----- | ----------- | -------------------------------- |
| sessionKey | String | false | YourSession | 已经激活的Session |
| target | Long | false | 987654321 | 发送消息目标好友的QQ号 |
| messageChain | Array | false | [] | 消息链,是一个消息对象构成的数组 |
#### 响应: 返回统一状态码
```
json5
{
"code": 0,
"msg": "success"
}
```
### 发送群消息
```
[POST] /sendGroupMessage
```
使用此方法向指定群发送消息
#### 请求
```
json5
{
"sessionKey": "YourSession",
"target": 987654321,
"messageChain": [
{ "type": "Plain", "text":"hello\n" },
{ "type": "Plain", "text":"world" }
]
}
```
| 名字 | 类型 | 可选 | 举例 | 说明 |
| ------------ | ------ | ----- | ----------- | -------------------------------- |
| sessionKey | String | false | YourSession | 已经激活的Session |
| target | Long | false | 987654321 | 发送消息目标群的群号 |
| messageChain | Array | false | [] | 消息链,是一个消息对象构成的数组 |
#### 响应: 返回统一状态码
```
json5
{
"code": 0,
"msg": "success"
}
```
### 获取Bot收到的消息
```
[GET] /fetchMessage?sessionKey=YourSessionKey&count=10
```
#### 请求:
| 名字 | 可选 | 举例 | 说明 |
| ---------- | ----- | -------------- | --------------- |
| sessionKey | false | YourSessionKey | 你的session key |
| count | false | 10 | 获取消息的数量 |
#### 响应: 返回JSON对象
```
json5
[{
"type": "GroupMessage", // 消息类型:GroupMessage或FriendMessage
"messageChain": [{ // 消息链,是一个消息对象构成的数组
"type": "Plain",
"text": "Miral牛逼"
}],
"sender": { // 发送者信息
"id": 123456789, // 发送者的QQ号码
"memberName": "化腾", // 发送者的群名片
"permission": "MEMBER", // 发送者的群限权:OWNER、ADMINISTRATOR或MEMBER
"group": { // 消息发送群的信息
"id": 1234567890, // 发送群的群号
"name": "Miral Technology" // 发送群的群名称
}
}
},
{
"type": "FriendMessage", // 消息类型:GroupMessage或FriendMessage
"messageChain": [{ // 消息链,是一个消息对象构成的数组
"type": "Plain",
"text": "Miral牛逼"
}],
"sender": { // 发送者信息
"id": 1234567890, // 发送者的QQ号码
"nickName": "", // 发送者的昵称
"remark": "" // 发送者的备注
}
}]
```
### 消息类型一览
#### 消息是构成消息链的基本对象,目前支持的消息类型有
+
[x] At,@消息
+
[x] Face,表情消息
+
[x] Plain,文字消息
+
[ ] Image,图片消息
+
[ ] Xml,Xml卡片消息
+
[ ] 敬请期待
#### At
```
json5
{
"type": "At",
"target": 123456,
"display": "@Mirai"
}
```
| 名字 | 类型 | 说明 |
| ------- | ------ | ------------------------- |
| target | Long | 群员QQ号 |
| display | String | @时显示的文本如:"@Mirai" |
#### Face
```
json5
{
"type": "Face",
"faceID": 123
}
```
| 名字 | 类型 | 说明 |
| ------ | ---- | ---------- |
| faceID | Int | QQ表情编号 |
#### Plain
```
json5
{
"type": "Plain",
"text": "Mirai牛逼"
}
```
| 名字 | 类型 | 说明 |
| ---- | ------ | -------- |
| text | String | 文字消息 |
#### Image
```
json5
{
"type": "Image"
// 暂时不支持Image
}
```
| 名字 | 类型 | 说明 |
| ---- | ---- | ---- |
| | | |
#### Xml
```
json5
{
"type": "Xml",
"xml": "XML"
}
```
| 名字 | 类型 | 说明 |
| ---- | ------ | ------- |
| xml | String | XML文本 |
\ No newline at end of file
mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/MiraiHttpAPIServer.kt
View file @
a9502957
...
@@ -18,16 +18,11 @@ object MiraiHttpAPIServer {
...
@@ -18,16 +18,11 @@ object MiraiHttpAPIServer {
@UseExperimental
(
KtorExperimentalAPI
::
class
)
@UseExperimental
(
KtorExperimentalAPI
::
class
)
fun
start
(
fun
start
(
port
:
Int
=
8080
,
port
:
Int
=
8080
,
authKey
:
String
?
=
null
,
authKey
:
String
,
callback
:
(()
->
Unit
)?
=
null
callback
:
(()
->
Unit
)?
=
null
)
{
)
{
authKey
?.
apply
{
require
(
authKey
.
length
in
8
..
128
)
{
"Expected authKey length is between 8 to 128"
}
if
(
authKey
.
length
in
8
..
128
)
{
SessionManager
.
authKey
=
authKey
SessionManager
.
authKey
=
authKey
}
else
{
logger
.
error
(
"Expected authKey length is between 8 to 128"
)
}
}
// TODO: start是无阻塞的,理应获取启动状态后再执行后续代码
// TODO: start是无阻塞的,理应获取启动状态后再执行后续代码
try
{
try
{
...
...
mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/Session.kt
View file @
a9502957
...
@@ -9,7 +9,7 @@ import net.mamoe.mirai.message.MessagePacket
...
@@ -9,7 +9,7 @@ import net.mamoe.mirai.message.MessagePacket
import
kotlin.coroutines.CoroutineContext
import
kotlin.coroutines.CoroutineContext
import
kotlin.coroutines.EmptyCoroutineContext
import
kotlin.coroutines.EmptyCoroutineContext
tailrec
fun
generateSessionKey
():
String
{
tailrec
fun
generateSessionKey
():
String
{
fun
generateRandomSessionKey
():
String
{
fun
generateRandomSessionKey
():
String
{
val
all
=
"QWERTYUIOPASDFGHJKLZXCVBNM1234567890qwertyuiopasdfghjklzxcvbnm"
val
all
=
"QWERTYUIOPASDFGHJKLZXCVBNM1234567890qwertyuiopasdfghjklzxcvbnm"
return
buildString
(
capacity
=
8
)
{
return
buildString
(
capacity
=
8
)
{
...
@@ -20,27 +20,27 @@ tailrec fun generateSessionKey():String{
...
@@ -20,27 +20,27 @@ tailrec fun generateSessionKey():String{
}
}
val
key
=
generateRandomSessionKey
()
val
key
=
generateRandomSessionKey
()
if
(!
SessionManager
.
allSession
.
containsKey
(
key
))
{
if
(!
SessionManager
.
allSession
.
containsKey
(
key
))
{
return
key
return
key
}
}
return
generateSessionKey
()
return
generateSessionKey
()
}
}
object
SessionManager
{
internal
object
SessionManager
{
val
allSession
:
MutableMap
<
String
,
Session
>
=
mutableMapOf
()
val
allSession
:
MutableMap
<
String
,
Session
>
=
mutableMapOf
()
lateinit
var
authKey
:
String
lateinit
var
authKey
:
String
fun
createTempSession
():
TempSession
=
TempSession
(
EmptyCoroutineContext
).
also
{
newTempSession
->
fun
createTempSession
():
TempSession
=
TempSession
(
EmptyCoroutineContext
).
also
{
newTempSession
->
allSession
[
newTempSession
.
key
]
=
newTempSession
allSession
[
newTempSession
.
key
]
=
newTempSession
//设置180000ms后检测并回收
//设置180000ms后检测并回收
newTempSession
.
launch
{
newTempSession
.
launch
{
delay
(
180000
)
delay
(
180000
)
allSession
[
newTempSession
.
key
]
?.
run
{
allSession
[
newTempSession
.
key
]
?.
run
{
if
(
this
is
TempSession
)
if
(
this
is
TempSession
)
closeSession
(
newTempSession
.
key
)
closeSession
(
newTempSession
.
key
)
}
}
}
}
...
@@ -50,15 +50,13 @@ object SessionManager {
...
@@ -50,15 +50,13 @@ object SessionManager {
fun
containSession
(
sessionKey
:
String
):
Boolean
=
allSession
.
containsKey
(
sessionKey
)
fun
containSession
(
sessionKey
:
String
):
Boolean
=
allSession
.
containsKey
(
sessionKey
)
fun
closeSession
(
sessionKey
:
String
)
=
allSession
.
remove
(
sessionKey
)
?.
also
{
it
.
close
()
}
fun
closeSession
(
sessionKey
:
String
)
=
allSession
.
remove
(
sessionKey
)
?.
also
{
it
.
close
()
}
fun
closeSession
(
session
:
Session
)
=
closeSession
(
session
.
key
)
fun
closeSession
(
session
:
Session
)
=
closeSession
(
session
.
key
)
}
}
/**
/**
* @author NaturalHG
* @author NaturalHG
* 这个用于管理不同Client与Mirai HTTP的会话
* 这个用于管理不同Client与Mirai HTTP的会话
...
@@ -68,20 +66,19 @@ object SessionManager {
...
@@ -68,20 +66,19 @@ object SessionManager {
*/
*/
abstract
class
Session
internal
constructor
(
abstract
class
Session
internal
constructor
(
coroutineContext
:
CoroutineContext
coroutineContext
:
CoroutineContext
):
CoroutineScope
{
)
:
CoroutineScope
{
val
supervisorJob
=
SupervisorJob
(
coroutineContext
[
Job
])
val
supervisorJob
=
SupervisorJob
(
coroutineContext
[
Job
])
final
override
val
coroutineContext
:
CoroutineContext
=
supervisorJob
+
coroutineContext
final
override
val
coroutineContext
:
CoroutineContext
=
supervisorJob
+
coroutineContext
val
key
:
String
=
generateSessionKey
()
val
key
:
String
=
generateSessionKey
()
internal
open
fun
close
(){
internal
open
fun
close
()
{
supervisorJob
.
complete
()
supervisorJob
.
complete
()
}
}
}
}
/**
/**
* 任何新链接建立后分配一个[TempSession]
* 任何新链接建立后分配一个[TempSession]
*
*
...
@@ -93,10 +90,10 @@ class TempSession internal constructor(coroutineContext: CoroutineContext) : Ses
...
@@ -93,10 +90,10 @@ class TempSession internal constructor(coroutineContext: CoroutineContext) : Ses
* 任何[TempSession]认证后转化为一个[AuthedSession]
* 任何[TempSession]认证后转化为一个[AuthedSession]
* 在这一步[AuthedSession]应该已经有assigned的bot
* 在这一步[AuthedSession]应该已经有assigned的bot
*/
*/
class
AuthedSession
internal
constructor
(
val
bot
:
Bot
,
coroutineContext
:
CoroutineContext
)
:
Session
(
coroutineContext
)
{
class
AuthedSession
internal
constructor
(
val
bot
:
Bot
,
coroutineContext
:
CoroutineContext
)
:
Session
(
coroutineContext
)
{
val
messageQueue
=
MessageQueue
()
val
messageQueue
=
MessageQueue
()
private
val
_listener
:
Listener
<
MessagePacket
<
*
,
*
>>
private
val
_listener
:
Listener
<
MessagePacket
<
*
,
*
>>
init
{
init
{
bot
.
subscribeMessages
{
bot
.
subscribeMessages
{
...
...
mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/dto/ContactDTO.kt
View file @
a9502957
...
@@ -18,7 +18,8 @@ data class QQDTO(
...
@@ -18,7 +18,8 @@ data class QQDTO(
val
remark
:
String
val
remark
:
String
)
:
ContactDTO
()
)
:
ContactDTO
()
suspend
fun
QQDTO
(
qq
:
QQ
):
QQDTO
=
QQDTO
(
qq
.
id
,
qq
.
queryProfile
().
nickname
,
qq
.
queryRemark
().
value
)
// TODO: queryProfile.nickname & queryRemark.value not support now
suspend
fun
QQDTO
(
qq
:
QQ
):
QQDTO
=
QQDTO
(
qq
.
id
,
""
,
""
)
@Serializable
@Serializable
data class
MemberDTO
(
data class
MemberDTO
(
...
...
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/ContactImpl.kt
View file @
a9502957
...
@@ -59,6 +59,9 @@ internal class QQImpl(bot: QQAndroidBot, override val coroutineContext: Coroutin
...
@@ -59,6 +59,9 @@ internal class QQImpl(bot: QQAndroidBot, override val coroutineContext: Coroutin
TODO
(
"not implemented"
)
TODO
(
"not implemented"
)
}
}
override
fun
equals
(
other
:
Any
?):
Boolean
{
return
other
is
QQ
&&
other
.
id
==
this
.
id
}
}
}
...
@@ -107,6 +110,9 @@ internal class MemberImpl(
...
@@ -107,6 +110,9 @@ internal class MemberImpl(
return
mute
(
0
)
return
mute
(
0
)
}
}
override
fun
equals
(
other
:
Any
?):
Boolean
{
return
other
is
Member
&&
other
.
id
==
this
.
id
}
}
}
...
@@ -324,4 +330,8 @@ internal class GroupImpl(
...
@@ -324,4 +330,8 @@ internal class GroupImpl(
}
}
}
}
}
}
override
fun
equals
(
other
:
Any
?):
Boolean
{
return
other
is
Group
&&
other
.
id
==
this
.
id
}
}
}
\ No newline at end of file
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/data/proto/OIDB.kt
View file @
a9502957
This diff is collapsed.
Click to expand it.
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/OnlinePush.
PbPushGroupMsg.
kt
→
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/OnlinePush.kt
View file @
a9502957
File moved
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Contact.kt
View file @
a9502957
...
@@ -19,24 +19,40 @@ import kotlin.contracts.contract
...
@@ -19,24 +19,40 @@ import kotlin.contracts.contract
*/
*/
interface
Contact
:
CoroutineScope
{
interface
Contact
:
CoroutineScope
{
/**
/**
* 这个联系人所属 [Bot]
* 这个联系人所属 [Bot]
.
*/
*/
@WeakRefProperty
@WeakRefProperty
val
bot
:
Bot
// weak ref
val
bot
:
Bot
// weak ref
/**
/**
* 可以是 QQ 号码或者群号码.
* 可以是 QQ 号码或者群号码.
*
* 对于 QQ, `uin` 与 `id` 是相同的意思.
* 对于 Group, `groupCode` 与 `id` 是相同的意思.
*/
*/
val
id
:
Long
val
id
:
Long
/**
/**
* 向这个对象发送消息.
* 向这个对象发送消息.
*
* 速度太快会被服务器屏蔽(无响应). 在测试中不延迟地发送 6 条消息就会被屏蔽之后的数据包 1 秒左右.
*/
*/
suspend
fun
sendMessage
(
message
:
MessageChain
)
suspend
fun
sendMessage
(
message
:
MessageChain
)
/**
* 上传一个图片以备发送.
* TODO: 群图片与好友图片之间是否通用还不确定.
* TODO: 好友之间图片是否通用还不确定.
*/
suspend
fun
uploadImage
(
image
:
ExternalImage
):
Image
suspend
fun
uploadImage
(
image
:
ExternalImage
):
Image
/**
* 判断 `this` 和 [other] 是否是相同的类型, 并且 [id] 相同.
*
* 注:
* [id] 相同的 [Member] 和 [QQ], 他们并不 [equals].
* 因为, [Member] 含义为群员, 必属于一个群.
* 而 [QQ] 含义为一个独立的人, 可以是好友, 也可以是陌生人.
*/
override
fun
equals
(
other
:
Any
?):
Boolean
}
}
suspend
inline
fun
Contact
.
sendMessage
(
message
:
Message
)
=
sendMessage
(
message
.
toChain
())
suspend
inline
fun
Contact
.
sendMessage
(
message
:
Message
)
=
sendMessage
(
message
.
toChain
())
...
...
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Group.kt
View file @
a9502957
...
@@ -9,38 +9,38 @@ import kotlinx.coroutines.CoroutineScope
...
@@ -9,38 +9,38 @@ import kotlinx.coroutines.CoroutineScope
* 群. 在 QQ Android 中叫做 "Troop"
* 群. 在 QQ Android 中叫做 "Troop"
*/
*/
interface
Group
:
Contact
,
CoroutineScope
{
interface
Group
:
Contact
,
CoroutineScope
{
/**
* ====以下字段在更新值的时候会自动异步上报服务器更改群信息====
*/
/**
/**
* 群名称
* 群名称.
* [可查可改已完成]
*
* 在修改时将会异步上传至服务器.
*
* 注: 频繁修改可能会被服务器拒绝
*/
*/
var
name
:
String
var
name
:
String
/**
/**
* 入群公告, 没有时为空字符串
* 入群公告, 没有时为空字符串.
* [可查可改已完成]
*
* 在修改时将会异步上传至服务器.
*/
*/
var
announcement
:
String
var
announcement
:
String
/**
/**
* 全体禁言状态
* 全体禁言状态. `true` 为开启.
* [可改已完成]
*
*/
* 当前仅能修改状态.
*/
// TODO: 2020/2/5 实现 muteAll 的查询
var
muteAll
:
Boolean
var
muteAll
:
Boolean
/**
/**
* 坦白说状态
* 坦白说状态. `true` 为允许.
* [可查可改已完成]
*
* 在修改时将会异步上传至服务器.
*/
*/
var
confessTalk
:
Boolean
var
confessTalk
:
Boolean
/**
/**
* 允许群员拉人状态
* 允许群员邀请好友入群的状态. `true` 为允许
* [可查可改已完成]
*/
*/
var
allowMemberInvite
:
Boolean
var
allowMemberInvite
:
Boolean
/**
/**
* QQ中的自动加群审批
* 自动加群审批
* [可查已完成]
*/
*/
val
autoApprove
:
Boolean
val
autoApprove
:
Boolean
/**
/**
...
...
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Member.kt
View file @
a9502957
...
@@ -11,18 +11,18 @@ import kotlin.time.ExperimentalTime
...
@@ -11,18 +11,18 @@ import kotlin.time.ExperimentalTime
*/
*/
interface
Member
:
QQ
,
Contact
{
interface
Member
:
QQ
,
Contact
{
/**
/**
* 所在的群
* 所在的群
.
*/
*/
@WeakRefProperty
@WeakRefProperty
val
group
:
Group
val
group
:
Group
/**
/**
*
权限
*
成员的权限, 动态更新.
*/
*/
val
permission
:
MemberPermission
val
permission
:
MemberPermission
/**
/**
*
*
群名片 (如果有) 或个人昵称. 动态更新.
*/
*/
var
groupCard
:
String
var
groupCard
:
String
...
@@ -30,7 +30,7 @@ interface Member : QQ, Contact {
...
@@ -30,7 +30,7 @@ interface Member : QQ, Contact {
* 禁言
* 禁言
*
*
* @param durationSeconds 持续时间. 精确到秒. 范围区间表示为 `(0s, 30days]`. 超过范围则会抛出异常.
* @param durationSeconds 持续时间. 精确到秒. 范围区间表示为 `(0s, 30days]`. 超过范围则会抛出异常.
* @return
若机器人无权限禁言这个群成员,
返回 `false`
* @return
仅当机器人无权限禁言这个群成员时
返回 `false`
*
*
* @see Int.minutesToSeconds
* @see Int.minutesToSeconds
* @see Int.hoursToSeconds
* @see Int.hoursToSeconds
...
@@ -39,10 +39,14 @@ interface Member : QQ, Contact {
...
@@ -39,10 +39,14 @@ interface Member : QQ, Contact {
suspend
fun
mute
(
durationSeconds
:
Int
):
Boolean
suspend
fun
mute
(
durationSeconds
:
Int
):
Boolean
/**
/**
* 解除禁言
* 解除禁言
. 在没有权限时会返回 `false`. 否则均返回 `true`.
*/
*/
suspend
fun
unmute
():
Boolean
suspend
fun
unmute
():
Boolean
/**
* 当且仅当 `[other] is [Member] && [other].id == this.id && [other].group == this.group` 时为 true
*/
override
fun
equals
(
other
:
Any
?):
Boolean
}
}
@ExperimentalTime
@ExperimentalTime
...
...
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/MessagePacket.kt
View file @
a9502957
...
@@ -3,6 +3,7 @@
...
@@ -3,6 +3,7 @@
package
net.mamoe.mirai.message
package
net.mamoe.mirai.message
import
kotlinx.io.core.ByteReadPacket
import
kotlinx.io.core.ByteReadPacket
import
kotlinx.io.core.IoBuffer
import
net.mamoe.mirai.Bot
import
net.mamoe.mirai.Bot
import
net.mamoe.mirai.contact.Contact
import
net.mamoe.mirai.contact.Contact
import
net.mamoe.mirai.contact.Group
import
net.mamoe.mirai.contact.Group
...
@@ -15,35 +16,47 @@ import net.mamoe.mirai.utils.*
...
@@ -15,35 +16,47 @@ import net.mamoe.mirai.utils.*
import
kotlin.jvm.JvmName
import
kotlin.jvm.JvmName
/**
/**
* 平台相关扩展
* 一条从服务器接收到的消息事件.
* 请查看各平台的 `actual` 实现的说明.
*/
*/
@UseExperimental
(
MiraiInternalAPI
::
class
)
@UseExperimental
(
MiraiInternalAPI
::
class
)
expect
abstract
class
MessagePacket
<
TSender
:
QQ
,
TSubject
:
Contact
>(
bot
:
Bot
)
:
MessagePacketBase
<
TSender
,
TSubject
>
expect
abstract
class
MessagePacket
<
TSender
:
QQ
,
TSubject
:
Contact
>(
bot
:
Bot
)
:
MessagePacketBase
<
TSender
,
TSubject
>
/**
* 仅内部使用, 请使用 [MessagePacket]
*/
// Tips: 在 IntelliJ 中 (左侧边栏) 打开 `Structure`, 可查看类结构
@Suppress
(
"NOTHING_TO_INLINE"
)
@Suppress
(
"NOTHING_TO_INLINE"
)
@MiraiInternalAPI
@MiraiInternalAPI
abstract
class
MessagePacketBase
<
TSender
:
QQ
,
TSubject
:
Contact
>(
_bot
:
Bot
)
:
EventPacket
,
BotEvent
()
{
abstract
class
MessagePacketBase
<
TSender
:
QQ
,
TSubject
:
Contact
>(
_bot
:
Bot
)
:
EventPacket
,
BotEvent
()
{
/**
* 接受到这条消息的
*/
override
val
bot
:
Bot
by
_bot
.
unsafeWeakRef
()
override
val
bot
:
Bot
by
_bot
.
unsafeWeakRef
()
/**
/**
* 消息事件主体.
* 消息事件主体.
*
*
* 对于好友消息, 这个属性为 [QQ] 的实例;
* 对于好友消息, 这个属性为 [QQ] 的实例
, 与 [sender] 引用相同
;
* 对于群消息, 这个属性为 [Group] 的实例
* 对于群消息, 这个属性为 [Group] 的实例
, 与 [GroupMessage.group] 引用相同
*
*
* 在回复消息时, 可通过 [subject] 作为回复对象
* 在回复消息时, 可通过 [subject] 作为回复对象
*/
*/
abstract
val
subject
:
TSubject
abstract
val
subject
:
TSubject
/**
/**
* 发送人
* 发送人.
*
* 在好友消息时为 [QQ] 的实例, 在群消息时为 [Member] 的实例
*/
*/
abstract
val
sender
:
TSender
abstract
val
sender
:
TSender
/**
* 消息内容
*/
abstract
val
message
:
MessageChain
abstract
val
message
:
MessageChain
// region
Send to subject
// region
发送 Message
/**
/**
* 给这个消息事件的主体发送消息
* 给这个消息事件的主体发送消息
...
@@ -64,20 +77,41 @@ abstract class MessagePacketBase<TSender : QQ, TSubject : Contact>(_bot: Bot) :
...
@@ -64,20 +77,41 @@ abstract class MessagePacketBase<TSender : QQ, TSubject : Contact>(_bot: Bot) :
@JvmName
(
"reply1"
)
@JvmName
(
"reply1"
)
suspend
inline
fun
MessageChain
.
reply
()
=
reply
(
this
)
suspend
inline
fun
MessageChain
.
reply
()
=
reply
(
this
)
suspend
inline
fun
ExternalImage
.
send
()
=
this
.
sendTo
(
subject
)
// endregion
// region 上传图片
suspend
inline
fun
ExternalImage
.
upload
():
Image
=
this
.
upload
(
subject
)
suspend
inline
fun
ExternalImage
.
upload
():
Image
=
this
.
upload
(
subject
)
// endregion
// region 发送图片
suspend
inline
fun
ExternalImage
.
send
()
=
this
.
sendTo
(
subject
)
suspend
inline
fun
Image
.
send
()
=
this
.
sendTo
(
subject
)
suspend
inline
fun
Image
.
send
()
=
this
.
sendTo
(
subject
)
suspend
inline
fun
Message
.
send
()
=
this
.
sendTo
(
subject
)
suspend
inline
fun
Message
.
send
()
=
this
.
sendTo
(
subject
)
suspend
inline
fun
String
.
send
()
=
this
.
toMessage
().
sendTo
(
subject
)
suspend
inline
fun
String
.
send
()
=
this
.
toMessage
().
sendTo
(
subject
)
// endregion
inline
fun
QQ
.
at
():
At
=
At
(
this
as
Member
)
/**
* 创建 @ 这个账号的消息. 当且仅当消息为群消息时可用. 否则将会抛出 [IllegalArgumentException]
*/
inline
fun
QQ
.
at
():
At
=
At
(
this
as
?
Member
?:
error
(
"`QQ.at` can only be used in GroupMessage"
))
// endregion
// endregion
// region Image download
// region Image download
/**
* 将图片下载到内存.
*
* 非常不推荐这样做.
*/
@Deprecated
(
"内存使用效率十分低下"
,
ReplaceWith
(
"this.download()"
),
DeprecationLevel
.
WARNING
)
suspend
inline
fun
Image
.
downloadAsByteArray
():
ByteArray
=
bot
.
run
{
downloadAsByteArray
()
}
suspend
inline
fun
Image
.
downloadAsByteArray
():
ByteArray
=
bot
.
run
{
downloadAsByteArray
()
}
// TODO: 2020/2/5 为下载图片添加文件系统的存储方式
/**
* 将图片下载到内存缓存中 (使用 [IoBuffer.Pool])
*/
suspend
inline
fun
Image
.
download
():
ByteReadPacket
=
bot
.
run
{
download
()
}
suspend
inline
fun
Image
.
download
():
ByteReadPacket
=
bot
.
run
{
download
()
}
// endregion
// endregion
...
...
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/MessageChain.kt
View file @
a9502957
...
@@ -17,6 +17,8 @@ import kotlin.reflect.KProperty
...
@@ -17,6 +17,8 @@ import kotlin.reflect.KProperty
* - 若两个 [MessageChain] 连接, 后一个将会被合并到第一个内.
* - 若两个 [MessageChain] 连接, 后一个将会被合并到第一个内.
* - 若一个 [MessageChain] 与一个其他 [Message] 连接, [Message] 将会被添加入 [MessageChain].
* - 若一个 [MessageChain] 与一个其他 [Message] 连接, [Message] 将会被添加入 [MessageChain].
* - 若一个 [Message] 与一个 [MessageChain] 连接, [Message] 将会被添加入 [MessageChain].
* - 若一个 [Message] 与一个 [MessageChain] 连接, [Message] 将会被添加入 [MessageChain].
*
* 要获取更多信息, 请查看 [Message]
*/
*/
interface
MessageChain
:
Message
,
MutableList
<
Message
>
{
interface
MessageChain
:
Message
,
MutableList
<
Message
>
{
// region Message override
// region Message override
...
...
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/io/DebugUtil.kt
View file @
a9502957
...
@@ -70,6 +70,7 @@ fun ByteReadPacket.debugPrintThis(name: String = ""): ByteReadPacket {
...
@@ -70,6 +70,7 @@ fun ByteReadPacket.debugPrintThis(name: String = ""): ByteReadPacket {
@MiraiDebugAPI
(
"Low efficiency"
)
@MiraiDebugAPI
(
"Low efficiency"
)
@UseExperimental
(
ExperimentalContracts
::
class
)
@UseExperimental
(
ExperimentalContracts
::
class
)
inline
fun
<
R
>
Input
.
debugIfFail
(
name
:
String
=
""
,
onFail
:
(
ByteArray
)
->
ByteReadPacket
=
{
it
.
toReadPacket
()
},
block
:
ByteReadPacket
.()
->
R
):
R
{
inline
fun
<
R
>
Input
.
debugIfFail
(
name
:
String
=
""
,
onFail
:
(
ByteArray
)
->
ByteReadPacket
=
{
it
.
toReadPacket
()
},
block
:
ByteReadPacket
.()
->
R
):
R
{
contract
{
contract
{
callsInPlace
(
block
,
InvocationKind
.
EXACTLY_ONCE
)
callsInPlace
(
block
,
InvocationKind
.
EXACTLY_ONCE
)
callsInPlace
(
onFail
,
InvocationKind
.
UNKNOWN
)
callsInPlace
(
onFail
,
InvocationKind
.
UNKNOWN
)
...
...
mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/message/MessagePacket.kt
View file @
a9502957
...
@@ -22,37 +22,52 @@ import java.net.URL
...
@@ -22,37 +22,52 @@ import java.net.URL
import
javax.imageio.ImageIO
import
javax.imageio.ImageIO
/**
/**
* 一条从服务器接收到的消息事件.
* JVM 平台相关扩展
* JVM 平台相关扩展
*/
*/
@UseExperimental
(
MiraiInternalAPI
::
class
)
@UseExperimental
(
MiraiInternalAPI
::
class
)
actual
abstract
class
MessagePacket
<
TSender
:
QQ
,
TSubject
:
Contact
>
actual
constructor
(
bot
:
Bot
)
:
MessagePacketBase
<
TSender
,
TSubject
>(
bot
)
{
actual
abstract
class
MessagePacket
<
TSender
:
QQ
,
TSubject
:
Contact
>
actual
constructor
(
bot
:
Bot
)
:
MessagePacketBase
<
TSender
,
TSubject
>(
bot
)
{
// region 上传图片
suspend
inline
fun
uploadImage
(
image
:
BufferedImage
):
Image
=
subject
.
uploadImage
(
image
)
suspend
inline
fun
uploadImage
(
image
:
BufferedImage
):
Image
=
subject
.
uploadImage
(
image
)
suspend
inline
fun
uploadImage
(
image
:
URL
):
Image
=
subject
.
uploadImage
(
image
)
suspend
inline
fun
uploadImage
(
image
:
URL
):
Image
=
subject
.
uploadImage
(
image
)
suspend
inline
fun
uploadImage
(
image
:
Input
):
Image
=
subject
.
uploadImage
(
image
)
suspend
inline
fun
uploadImage
(
image
:
Input
):
Image
=
subject
.
uploadImage
(
image
)
suspend
inline
fun
uploadImage
(
image
:
InputStream
):
Image
=
subject
.
uploadImage
(
image
)
suspend
inline
fun
uploadImage
(
image
:
InputStream
):
Image
=
subject
.
uploadImage
(
image
)
suspend
inline
fun
uploadImage
(
image
:
File
):
Image
=
subject
.
uploadImage
(
image
)
suspend
inline
fun
uploadImage
(
image
:
File
):
Image
=
subject
.
uploadImage
(
image
)
// endregion
// region 发送图片
suspend
inline
fun
sendImage
(
image
:
BufferedImage
)
=
subject
.
sendImage
(
image
)
suspend
inline
fun
sendImage
(
image
:
BufferedImage
)
=
subject
.
sendImage
(
image
)
suspend
inline
fun
sendImage
(
image
:
URL
)
=
subject
.
sendImage
(
image
)
suspend
inline
fun
sendImage
(
image
:
URL
)
=
subject
.
sendImage
(
image
)
suspend
inline
fun
sendImage
(
image
:
Input
)
=
subject
.
sendImage
(
image
)
suspend
inline
fun
sendImage
(
image
:
Input
)
=
subject
.
sendImage
(
image
)
suspend
inline
fun
sendImage
(
image
:
InputStream
)
=
subject
.
sendImage
(
image
)
suspend
inline
fun
sendImage
(
image
:
InputStream
)
=
subject
.
sendImage
(
image
)
suspend
inline
fun
sendImage
(
image
:
File
)
=
subject
.
sendImage
(
image
)
suspend
inline
fun
sendImage
(
image
:
File
)
=
subject
.
sendImage
(
image
)
// endregion
// region 上传图片 (扩展)
suspend
inline
fun
BufferedImage
.
upload
():
Image
=
upload
(
subject
)
suspend
inline
fun
BufferedImage
.
upload
():
Image
=
upload
(
subject
)
suspend
inline
fun
URL
.
uploadAsImage
():
Image
=
uploadAsImage
(
subject
)
suspend
inline
fun
URL
.
uploadAsImage
():
Image
=
uploadAsImage
(
subject
)
suspend
inline
fun
Input
.
uploadAsImage
():
Image
=
uploadAsImage
(
subject
)
suspend
inline
fun
Input
.
uploadAsImage
():
Image
=
uploadAsImage
(
subject
)
suspend
inline
fun
InputStream
.
uploadAsImage
():
Image
=
uploadAsImage
(
subject
)
suspend
inline
fun
InputStream
.
uploadAsImage
():
Image
=
uploadAsImage
(
subject
)
suspend
inline
fun
File
.
uploadAsImage
():
Image
=
uploadAsImage
(
subject
)
suspend
inline
fun
File
.
uploadAsImage
():
Image
=
uploadAsImage
(
subject
)
// endregion 上传图片 (扩展)
// region 发送图片 (扩展)
suspend
inline
fun
BufferedImage
.
send
()
=
sendTo
(
subject
)
suspend
inline
fun
BufferedImage
.
send
()
=
sendTo
(
subject
)
suspend
inline
fun
URL
.
sendAsImage
()
=
sendAsImageTo
(
subject
)
suspend
inline
fun
URL
.
sendAsImage
()
=
sendAsImageTo
(
subject
)
suspend
inline
fun
Input
.
sendAsImage
()
=
sendAsImageTo
(
subject
)
suspend
inline
fun
Input
.
sendAsImage
()
=
sendAsImageTo
(
subject
)
suspend
inline
fun
InputStream
.
sendAsImage
()
=
sendAsImageTo
(
subject
)
suspend
inline
fun
InputStream
.
sendAsImage
()
=
sendAsImageTo
(
subject
)
suspend
inline
fun
File
.
sendAsImage
()
=
sendAsImageTo
(
subject
)
suspend
inline
fun
File
.
sendAsImage
()
=
sendAsImageTo
(
subject
)
// endregion 发送图片 (扩展)
// region 下载图片 (扩展)
suspend
inline
fun
Image
.
downloadTo
(
file
:
File
):
Long
=
file
.
outputStream
().
use
{
downloadTo
(
it
)
}
suspend
inline
fun
Image
.
downloadTo
(
file
:
File
):
Long
=
file
.
outputStream
().
use
{
downloadTo
(
it
)
}
/**
/**
* 这个函数结束后不会关闭 [output]
* 这个函数结束后不会关闭 [output]
. 请务必解决好 [OutputStream.close]
*/
*/
suspend
inline
fun
Image
.
downloadTo
(
output
:
OutputStream
):
Long
=
suspend
inline
fun
Image
.
downloadTo
(
output
:
OutputStream
):
Long
=
download
().
inputStream
().
use
{
input
->
withContext
(
Dispatchers
.
IO
)
{
input
.
copyTo
(
output
)
}
}
download
().
inputStream
().
use
{
input
->
withContext
(
Dispatchers
.
IO
)
{
input
.
copyTo
(
output
)
}
}
...
@@ -60,4 +75,5 @@ actual abstract class MessagePacket<TSender : QQ, TSubject : Contact> actual con
...
@@ -60,4 +75,5 @@ actual abstract class MessagePacket<TSender : QQ, TSubject : Contact> actual con
suspend
inline
fun
Image
.
downloadAsStream
():
InputStream
=
download
().
inputStream
()
suspend
inline
fun
Image
.
downloadAsStream
():
InputStream
=
download
().
inputStream
()
suspend
inline
fun
Image
.
downloadAsExternalImage
():
ExternalImage
=
withContext
(
Dispatchers
.
IO
)
{
download
().
toExternalImage
()
}
suspend
inline
fun
Image
.
downloadAsExternalImage
():
ExternalImage
=
withContext
(
Dispatchers
.
IO
)
{
download
().
toExternalImage
()
}
suspend
inline
fun
Image
.
downloadAsBufferedImage
():
BufferedImage
=
withContext
(
Dispatchers
.
IO
)
{
ImageIO
.
read
(
downloadAsStream
())
}
suspend
inline
fun
Image
.
downloadAsBufferedImage
():
BufferedImage
=
withContext
(
Dispatchers
.
IO
)
{
ImageIO
.
read
(
downloadAsStream
())
}
// endregion
}
}
\ No newline at end of file
mirai-demos/mirai-demo-gentleman/src/main/kotlin/demo/gentleman/GentleImage.kt
View file @
a9502957
package
demo.gentleman
package
demo.gentleman
import
com.alibaba.fastjson.JSON
import
com.alibaba.fastjson.JSON
import
com.alibaba.fastjson.JSONObject
import
kotlinx.coroutines.*
import
kotlinx.coroutines.*
import
net.mamoe.mirai.contact.Contact
import
net.mamoe.mirai.contact.Contact
import
net.mamoe.mirai.message.data.Image
import
net.mamoe.mirai.message.data.Image
import
net.mamoe.mirai.message.uploadAsImage
import
net.mamoe.mirai.message.uploadAsImage
import
org.jsoup.Jsoup
import
org.jsoup.Jsoup
import
kotlin.random.Random
class
GentleImage
{
class
GentleImage
(
val
contact
:
Contact
,
val
keyword
:
String
)
{
lateinit
var
contact
:
Contact
// `Deferred<Image?>` causes a runtime ClassCastException
val
image
:
Deferred
<
Image
>
by
lazy
{
getImage
(
0
)
}
val
image
:
Deferred
<
Image
>
by
lazy
{
getImage
(
0
)
}
...
@@ -18,18 +17,21 @@ class GentleImage {
...
@@ -18,18 +17,21 @@ class GentleImage {
fun
getImage
(
r18
:
Int
):
Deferred
<
Image
>
{
fun
getImage
(
r18
:
Int
):
Deferred
<
Image
>
{
return
GlobalScope
.
async
{
return
GlobalScope
.
async
{
withTimeoutOrNull
(
5
*
1000
)
{
withTimeoutOrNull
(
10
*
1000
)
{
withContext
(
Dispatchers
.
IO
)
{
withContext
(
Dispatchers
.
IO
)
{
val
result
=
val
result
=
JSON
.
parseObject
(
JSON
.
parseObject
(
Jsoup
.
connect
(
"https://api.lolicon.app/setu/?r18=$r18"
).
ignoreContentType
(
true
).
timeout
(
Jsoup
.
connect
(
"https://api.lolicon.app/setu/?r18=$r18"
+
if
(
keyword
.
isNotBlank
())
"&keyword=$keyword&num=100"
else
""
).
ignoreContentType
(
true
).
timeout
(
10
_0000
10
_0000
).
get
().
body
().
text
()
).
get
().
body
().
text
()
)
)
val
url
:
String
val
url
:
String
val
pid
:
String
val
pid
:
String
with
(
result
.
getJSONArray
(
"data"
).
getJSONObject
(
0
))
{
val
data
=
result
.
getJSONArray
(
"data"
)
with
(
JSONObject
(
data
.
getJSONObject
(
Random
.
nextInt
(
0
,
data
.
size
))))
{
url
=
this
.
getString
(
"url"
)
url
=
this
.
getString
(
"url"
)
pid
=
this
.
getString
(
"pid"
)
pid
=
this
.
getString
(
"pid"
)
}
}
...
...
mirai-demos/mirai-demo-gentleman/src/main/kotlin/demo/gentleman/Gentleman.kt
View file @
a9502957
...
@@ -18,22 +18,20 @@ private const val IMAGE_BUFFER_CAPACITY: Int = 5
...
@@ -18,22 +18,20 @@ private const val IMAGE_BUFFER_CAPACITY: Int = 5
@ExperimentalUnsignedTypes
@ExperimentalUnsignedTypes
@ExperimentalCoroutinesApi
@ExperimentalCoroutinesApi
object
Gentlemen
:
MutableMap
<
Long
,
Gentleman
>
by
mutableMapOf
()
{
object
Gentlemen
:
MutableMap
<
Long
,
Gentleman
>
by
mutableMapOf
()
{
fun
provide
(
key
:
Contact
):
Gentleman
=
this
.
getOrPut
(
key
.
id
)
{
Gentleman
(
key
)
}
fun
provide
(
key
:
Contact
,
keyword
:
String
=
""
):
Gentleman
=
this
.
getOrPut
(
key
.
id
)
{
Gentleman
(
key
,
keyword
)
}
}
}
/**
/**
* 工作是缓存图片
* 工作是缓存图片
*/
*/
@ExperimentalCoroutinesApi
@ExperimentalCoroutinesApi
class
Gentleman
(
private
val
contact
:
Contact
)
:
Channel
<
GentleImage
>
by
Channel
(
IMAGE_BUFFER_CAPACITY
)
{
class
Gentleman
(
private
val
contact
:
Contact
,
private
val
keyword
:
String
)
:
Channel
<
GentleImage
>
by
Channel
(
IMAGE_BUFFER_CAPACITY
)
{
init
{
init
{
GlobalScope
.
launch
{
GlobalScope
.
launch
{
while
(!
isClosedForSend
)
{
while
(!
isClosedForSend
)
{
send
(
GentleImage
().
apply
{
send
(
GentleImage
(
contact
,
keyword
).
apply
{
contact
=
this
@Gentleman
.
contact
seImage
// start downloading
image
// start downloading
})
})
}
}
}
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment