feat(service): 添加随机照片服务- 新增 RandomPhotoService 类实现随机照片功能
- 添加 FileList 和 SingleFile 数据模型用于解析 JSON 响应 - 集成 AlistService 获取文件列表和文件信息 - 使用 OkHttpClient 下载图片 - 更新 application.yml 配置,添加 AList 相关设置 - 修改 ExampleService 中的 entrance 方法返回值
This commit is contained in:
parent
9755545639
commit
fbfb1c1a7f
6
mvnw.cmd
vendored
6
mvnw.cmd
vendored
@ -32,7 +32,7 @@
|
||||
@SET __MVNW_ERROR__=
|
||||
@SET __MVNW_PSMODULEP_SAVE=%PSModulePath%
|
||||
@SET PSModulePath=
|
||||
@FOR /F "usebackq tokens=1* delims==" %%A IN (`powershell -noprofile "& {$scriptDir='%~dp0'; $script='%__MVNW_ARG0_NAME__%'; icm -ScriptBlock ([Scriptblock]::Create((Get-Content -Raw '%~f0'))) -NoNewScope}"`) DO @(
|
||||
@FOR /F "usebackq tokens=1* delims==" %%A IN (`powershell -noprofile "& {$scriptDir='%~dp0'; $script='%__MVNW_ARG0_NAME__%'; icm -ScriptBlock ([Scriptblock]::Create((Get-info.alinadace.sakuramiki.service.randomphoto.domain.Content -Raw '%~f0'))) -NoNewScope}"`) DO @(
|
||||
IF "%%A"=="MVN_CMD" (set __MVNW_CMD__=%%B) ELSE IF "%%B"=="" (echo %%A) ELSE (echo %%A=%%B)
|
||||
)
|
||||
@SET PSModulePath=%__MVNW_PSMODULEP_SAVE%
|
||||
@ -51,7 +51,7 @@ if ($env:MVNW_VERBOSE -eq "true") {
|
||||
}
|
||||
|
||||
# calculate distributionUrl, requires .mvn/wrapper/maven-wrapper.properties
|
||||
$distributionUrl = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionUrl
|
||||
$distributionUrl = (Get-info.alinadace.sakuramiki.service.randomphoto.domain.Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionUrl
|
||||
if (!$distributionUrl) {
|
||||
Write-Error "cannot read distributionUrl property in $scriptDir/.mvn/wrapper/maven-wrapper.properties"
|
||||
}
|
||||
@ -121,7 +121,7 @@ if ($env:MVNW_USERNAME -and $env:MVNW_PASSWORD) {
|
||||
$webclient.DownloadFile($distributionUrl, "$TMP_DOWNLOAD_DIR/$distributionUrlName") | Out-Null
|
||||
|
||||
# If specified, validate the SHA-256 sum of the Maven distribution zip file
|
||||
$distributionSha256Sum = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionSha256Sum
|
||||
$distributionSha256Sum = (Get-info.alinadace.sakuramiki.service.randomphoto.domain.Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionSha256Sum
|
||||
if ($distributionSha256Sum) {
|
||||
if ($USE_MVND) {
|
||||
Write-Error "Checksum validation is not supported for maven-mvnd. `nPlease disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties."
|
||||
|
19
pom.xml
19
pom.xml
@ -11,8 +11,8 @@
|
||||
<groupId>info.alinadace</groupId>
|
||||
<artifactId>sakura-miki</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<name>sakuramiki</name>
|
||||
<description>sakuramiki</description>
|
||||
<name>Sakura-Miki</name>
|
||||
<description>Sakura-Miki</description>
|
||||
<url/>
|
||||
<licenses>
|
||||
<license/>
|
||||
@ -127,6 +127,21 @@
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-actuator</artifactId>
|
||||
</dependency>
|
||||
<!-- https://mvnrepository.com/artifact/com.beust/klaxon -->
|
||||
<dependency>
|
||||
<groupId>com.beust</groupId>
|
||||
<artifactId>klaxon</artifactId>
|
||||
<version>5.6</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.github.1530624156</groupId>
|
||||
<artifactId>AlistUtil</artifactId>
|
||||
<version>1.0.0-spring</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.squareup.okhttp3</groupId>
|
||||
<artifactId>okhttp</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
@ -34,7 +34,7 @@ class ExampleService : Service<MessageV2Event> {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return true
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -0,0 +1,69 @@
|
||||
package info.alinadace.sakuramiki.service.randomphoto
|
||||
|
||||
import com.mavis.service.AlistService
|
||||
import info.alinadace.sakuramiki.annotation.BotFunction
|
||||
import info.alinadace.sakuramiki.service.Service
|
||||
import info.alinadace.sakuramiki.service.randomphoto.domain.FileList
|
||||
import info.alinadace.sakuramiki.service.randomphoto.domain.SingleFile
|
||||
import info.alinadace.sakuramiki.util.okHttpClient
|
||||
import io.github.kloping.qqbot.api.v2.FriendMessageEvent
|
||||
import io.github.kloping.qqbot.api.v2.GroupMessageEvent
|
||||
import io.github.kloping.qqbot.api.v2.MessageV2Event
|
||||
import io.github.kloping.qqbot.entities.ex.Image
|
||||
import io.github.kloping.qqbot.entities.ex.PlainText
|
||||
import jakarta.annotation.Resource
|
||||
import okhttp3.Request
|
||||
|
||||
/**
|
||||
* @author Kane
|
||||
* @since 2024/11/11 19:26
|
||||
*/
|
||||
@BotFunction(FriendMessageEvent::class, GroupMessageEvent::class)
|
||||
class RandomPhotoService : Service<MessageV2Event> {
|
||||
|
||||
@Resource
|
||||
lateinit var alistService: AlistService
|
||||
|
||||
/**
|
||||
* 服务入口
|
||||
*/
|
||||
override fun entrance(event: MessageV2Event): Boolean {
|
||||
val chain = event.message
|
||||
if (chain.size == 1 && chain[0] is PlainText && chain[0].toString() == "#photo") {
|
||||
return true
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
* 服务行为
|
||||
*/
|
||||
override fun active(event: MessageV2Event) {
|
||||
val fileList = alistService.getAlistFileList("/VRChat-Photo")
|
||||
val files = FileList.fromJson(fileList)
|
||||
if (files.code != 200L) {
|
||||
event.send("文件列表获取失败")
|
||||
}
|
||||
val content = files.data.content.filter { x -> !x.isDir }
|
||||
if (content.isEmpty()) {
|
||||
event.send("暂无照片")
|
||||
return
|
||||
}
|
||||
val randomFile = content.random()
|
||||
val fileInfo = alistService.getAlistFileInfo("/VRChat-Photo/" + randomFile.name, "")
|
||||
val file = SingleFile.fromJson(fileInfo)
|
||||
if (file.code != 200L) {
|
||||
event.send("文件获取失败")
|
||||
return
|
||||
}
|
||||
event.send("图片下载中...")
|
||||
val request = Request.Builder().get().url(file.data.rawURL).build()
|
||||
val imageByte = okHttpClient.newCall(request).execute().body?.bytes();
|
||||
if (imageByte == null) {
|
||||
event.send("图片下载失败")
|
||||
return
|
||||
}
|
||||
val image = Image(imageByte)
|
||||
event.send(image)
|
||||
}
|
||||
}
|
@ -0,0 +1,128 @@
|
||||
package info.alinadace.sakuramiki.service.randomphoto.domain
|
||||
|
||||
// To parse the JSON, install jackson-module-kotlin and do:
|
||||
//
|
||||
// val response = FileList.fromJson(jsonString)
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude
|
||||
import com.fasterxml.jackson.annotation.JsonProperty
|
||||
import com.fasterxml.jackson.databind.PropertyNamingStrategies
|
||||
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
|
||||
import com.fasterxml.jackson.module.kotlin.readValue
|
||||
|
||||
|
||||
data class FileList(
|
||||
/**
|
||||
* 状态码
|
||||
*/
|
||||
@get:JsonProperty(required = true) @field:JsonProperty(required = true)
|
||||
val code: Long,
|
||||
|
||||
@get:JsonProperty(required = true) @field:JsonProperty(required = true)
|
||||
val data: Data,
|
||||
|
||||
/**
|
||||
* 信息
|
||||
*/
|
||||
@get:JsonProperty(required = true) @field:JsonProperty(required = true)
|
||||
val message: String
|
||||
) {
|
||||
|
||||
fun toJson() = mapper.writeValueAsString(this)
|
||||
|
||||
companion object {
|
||||
private var mapper = jacksonObjectMapper().apply {
|
||||
propertyNamingStrategy = PropertyNamingStrategies.LOWER_CAMEL_CASE
|
||||
setSerializationInclusion(JsonInclude.Include.NON_NULL)
|
||||
}
|
||||
|
||||
fun fromJson(json: String) = mapper.readValue<FileList>(json)
|
||||
}
|
||||
|
||||
data class Data(
|
||||
/**
|
||||
* 内容
|
||||
*/
|
||||
@get:JsonProperty(required = true) @field:JsonProperty(required = true)
|
||||
val content: List<Content>,
|
||||
|
||||
@get:JsonProperty(required = true) @field:JsonProperty(required = true)
|
||||
val header: String,
|
||||
|
||||
@get:JsonProperty(required = true) @field:JsonProperty(required = true)
|
||||
val provider: String,
|
||||
|
||||
/**
|
||||
* 说明
|
||||
*/
|
||||
@get:JsonProperty(required = true) @field:JsonProperty(required = true)
|
||||
val readme: String,
|
||||
|
||||
/**
|
||||
* 总数
|
||||
*/
|
||||
@get:JsonProperty(required = true) @field:JsonProperty(required = true)
|
||||
val total: Long,
|
||||
|
||||
/**
|
||||
* 是否可写入
|
||||
*/
|
||||
@get:JsonProperty(required = true) @field:JsonProperty(required = true)
|
||||
val write: Boolean
|
||||
) {
|
||||
data class Content(
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
val created: String? = null,
|
||||
|
||||
@get:JsonProperty("hash_info") @field:JsonProperty("hash_info")
|
||||
val hashInfo: Any? = null,
|
||||
|
||||
val hashinfo: String? = null,
|
||||
|
||||
/**
|
||||
* 是否是文件夹
|
||||
*/
|
||||
@get:JsonProperty("is_dir", required = true) @field:JsonProperty("is_dir", required = true)
|
||||
val isDir: Boolean,
|
||||
|
||||
/**
|
||||
* 修改时间
|
||||
*/
|
||||
@get:JsonProperty(required = true) @field:JsonProperty(required = true)
|
||||
val modified: String,
|
||||
|
||||
/**
|
||||
* 文件名
|
||||
*/
|
||||
@get:JsonProperty(required = true) @field:JsonProperty(required = true)
|
||||
val name: String,
|
||||
|
||||
/**
|
||||
* 签名
|
||||
*/
|
||||
@get:JsonProperty(required = true) @field:JsonProperty(required = true)
|
||||
val sign: String,
|
||||
|
||||
/**
|
||||
* 大小
|
||||
*/
|
||||
@get:JsonProperty(required = true) @field:JsonProperty(required = true)
|
||||
val size: Long,
|
||||
|
||||
/**
|
||||
* 缩略图
|
||||
*/
|
||||
@get:JsonProperty(required = true) @field:JsonProperty(required = true)
|
||||
val thumb: String,
|
||||
|
||||
/**
|
||||
* 类型
|
||||
*/
|
||||
@get:JsonProperty(required = true) @field:JsonProperty(required = true)
|
||||
val type: Long
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,117 @@
|
||||
package info.alinadace.sakuramiki.service.randomphoto.domain
|
||||
// To parse the JSON, install jackson-module-kotlin and do:
|
||||
//
|
||||
// val response = SingleFile.fromJson(jsonString)
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude
|
||||
import com.fasterxml.jackson.annotation.JsonProperty
|
||||
import com.fasterxml.jackson.databind.PropertyNamingStrategies
|
||||
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
|
||||
import com.fasterxml.jackson.module.kotlin.readValue
|
||||
|
||||
|
||||
data class SingleFile(
|
||||
/**
|
||||
* 状态码
|
||||
*/
|
||||
@get:JsonProperty(required = true) @field:JsonProperty(required = true)
|
||||
val code: Long,
|
||||
|
||||
@get:JsonProperty(required = true) @field:JsonProperty(required = true)
|
||||
val data: Data,
|
||||
|
||||
/**
|
||||
* 信息
|
||||
*/
|
||||
@get:JsonProperty(required = true) @field:JsonProperty(required = true)
|
||||
val message: String
|
||||
) {
|
||||
|
||||
fun toJson() = mapper.writeValueAsString(this)
|
||||
|
||||
companion object {
|
||||
private val mapper = jacksonObjectMapper().apply {
|
||||
propertyNamingStrategy = PropertyNamingStrategies.LOWER_CAMEL_CASE
|
||||
setSerializationInclusion(JsonInclude.Include.NON_NULL)
|
||||
}
|
||||
|
||||
fun fromJson(json: String) = mapper.readValue<SingleFile>(json)
|
||||
}
|
||||
|
||||
data class Data(
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@get:JsonProperty(required = true) @field:JsonProperty(required = true)
|
||||
val created: String,
|
||||
|
||||
@get:JsonProperty("hash_info") @field:JsonProperty("hash_info")
|
||||
val hashInfo: Any? = null,
|
||||
|
||||
@get:JsonProperty(required = true) @field:JsonProperty(required = true)
|
||||
val hashinfo: String,
|
||||
|
||||
@get:JsonProperty(required = true) @field:JsonProperty(required = true)
|
||||
val header: String,
|
||||
|
||||
/**
|
||||
* 是否是文件夹
|
||||
*/
|
||||
@get:JsonProperty("is_dir", required = true) @field:JsonProperty("is_dir", required = true)
|
||||
val isDir: Boolean,
|
||||
|
||||
/**
|
||||
* 修改时间
|
||||
*/
|
||||
@get:JsonProperty(required = true) @field:JsonProperty(required = true)
|
||||
val modified: String,
|
||||
|
||||
/**
|
||||
* 文件名
|
||||
*/
|
||||
@get:JsonProperty(required = true) @field:JsonProperty(required = true)
|
||||
val name: String,
|
||||
|
||||
@get:JsonProperty(required = true) @field:JsonProperty(required = true)
|
||||
val provider: String,
|
||||
|
||||
/**
|
||||
* 原始url
|
||||
*/
|
||||
@get:JsonProperty("raw_url", required = true) @field:JsonProperty("raw_url", required = true)
|
||||
val rawURL: String,
|
||||
|
||||
/**
|
||||
* 说明
|
||||
*/
|
||||
@get:JsonProperty(required = true) @field:JsonProperty(required = true)
|
||||
val readme: String,
|
||||
|
||||
val related: Any? = null,
|
||||
|
||||
/**
|
||||
* 签名
|
||||
*/
|
||||
@get:JsonProperty(required = true) @field:JsonProperty(required = true)
|
||||
val sign: String,
|
||||
|
||||
/**
|
||||
* 大小
|
||||
*/
|
||||
@get:JsonProperty(required = true) @field:JsonProperty(required = true)
|
||||
val size: Long,
|
||||
|
||||
/**
|
||||
* 缩略图
|
||||
*/
|
||||
@get:JsonProperty(required = true) @field:JsonProperty(required = true)
|
||||
val thumb: String,
|
||||
|
||||
/**
|
||||
* 类型
|
||||
*/
|
||||
@get:JsonProperty(required = true) @field:JsonProperty(required = true)
|
||||
val type: Long
|
||||
)
|
||||
}
|
||||
|
12
src/main/kotlin/info/alinadace/sakuramiki/util/OkHttp.kt
Normal file
12
src/main/kotlin/info/alinadace/sakuramiki/util/OkHttp.kt
Normal file
@ -0,0 +1,12 @@
|
||||
package info.alinadace.sakuramiki.util
|
||||
|
||||
import okhttp3.OkHttpClient
|
||||
|
||||
/**
|
||||
* @author Kane
|
||||
* @since 2024/11/11 20:39
|
||||
*/
|
||||
|
||||
// 创建 OkHttpClient 实例
|
||||
val okHttpClient = OkHttpClient.Builder()
|
||||
.build()
|
@ -12,3 +12,8 @@ bot:
|
||||
token: sq3CZjEpK7Z65s2xuyhwp8WVBqvx35XP
|
||||
app-secret: Wgq0BMXit5HTfr3GTgt6JXlzDRgvAPet
|
||||
admin: 59EC2526FBCC1EC5F851187C0F4F8BA5
|
||||
|
||||
alist:
|
||||
alist-base-url: https://alist.alina-dace.info
|
||||
alist-username: admin
|
||||
alist-password: vF7Wb2vo
|
||||
|
Loading…
Reference in New Issue
Block a user