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_ERROR__=
|
||||||
@SET __MVNW_PSMODULEP_SAVE=%PSModulePath%
|
@SET __MVNW_PSMODULEP_SAVE=%PSModulePath%
|
||||||
@SET 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)
|
IF "%%A"=="MVN_CMD" (set __MVNW_CMD__=%%B) ELSE IF "%%B"=="" (echo %%A) ELSE (echo %%A=%%B)
|
||||||
)
|
)
|
||||||
@SET PSModulePath=%__MVNW_PSMODULEP_SAVE%
|
@SET PSModulePath=%__MVNW_PSMODULEP_SAVE%
|
||||||
@ -51,7 +51,7 @@ if ($env:MVNW_VERBOSE -eq "true") {
|
|||||||
}
|
}
|
||||||
|
|
||||||
# calculate distributionUrl, requires .mvn/wrapper/maven-wrapper.properties
|
# 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) {
|
if (!$distributionUrl) {
|
||||||
Write-Error "cannot read distributionUrl property in $scriptDir/.mvn/wrapper/maven-wrapper.properties"
|
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
|
$webclient.DownloadFile($distributionUrl, "$TMP_DOWNLOAD_DIR/$distributionUrlName") | Out-Null
|
||||||
|
|
||||||
# If specified, validate the SHA-256 sum of the Maven distribution zip file
|
# 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 ($distributionSha256Sum) {
|
||||||
if ($USE_MVND) {
|
if ($USE_MVND) {
|
||||||
Write-Error "Checksum validation is not supported for maven-mvnd. `nPlease disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties."
|
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>
|
<groupId>info.alinadace</groupId>
|
||||||
<artifactId>sakura-miki</artifactId>
|
<artifactId>sakura-miki</artifactId>
|
||||||
<version>0.0.1-SNAPSHOT</version>
|
<version>0.0.1-SNAPSHOT</version>
|
||||||
<name>sakuramiki</name>
|
<name>Sakura-Miki</name>
|
||||||
<description>sakuramiki</description>
|
<description>Sakura-Miki</description>
|
||||||
<url/>
|
<url/>
|
||||||
<licenses>
|
<licenses>
|
||||||
<license/>
|
<license/>
|
||||||
@ -127,6 +127,21 @@
|
|||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-actuator</artifactId>
|
<artifactId>spring-boot-starter-actuator</artifactId>
|
||||||
</dependency>
|
</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>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
@ -34,7 +34,7 @@ class ExampleService : Service<MessageV2Event> {
|
|||||||
return true
|
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
|
token: sq3CZjEpK7Z65s2xuyhwp8WVBqvx35XP
|
||||||
app-secret: Wgq0BMXit5HTfr3GTgt6JXlzDRgvAPet
|
app-secret: Wgq0BMXit5HTfr3GTgt6JXlzDRgvAPet
|
||||||
admin: 59EC2526FBCC1EC5F851187C0F4F8BA5
|
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