feat(service): 添加随机照片服务- 新增 RandomPhotoService 类实现随机照片功能

- 添加 FileList 和 SingleFile 数据模型用于解析 JSON 响应
- 集成 AlistService 获取文件列表和文件信息
- 使用 OkHttpClient 下载图片
- 更新 application.yml 配置,添加 AList 相关设置
- 修改 ExampleService 中的 entrance 方法返回值
This commit is contained in:
Grand-cocoa 2024-11-11 20:48:56 +08:00
parent 9755545639
commit fbfb1c1a7f
8 changed files with 352 additions and 6 deletions

6
mvnw.cmd vendored
View File

@ -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
View File

@ -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>

View File

@ -34,7 +34,7 @@ class ExampleService : Service<MessageV2Event> {
return true
}
}
return true
return false
}
/**

View File

@ -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)
}
}

View File

@ -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
)
}
}

View File

@ -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
)
}

View 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()

View File

@ -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