Skip to content

Commit 32c0350

Browse files
authored
Merge pull request #189 from simple-robot/dev/image-b64-188
对图片、视频、语音文件进行base64编码时,默认使用 Base64.Default 进行编码
2 parents df5f6f9 + 15dab0c commit 32c0350

File tree

10 files changed

+342
-37
lines changed

10 files changed

+342
-37
lines changed

simbot-component-onebot-v11/simbot-component-onebot-v11-message/api/simbot-component-onebot-v11-message.api

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,14 @@
1+
public abstract interface class love/forte/simbot/component/onebot/v11/message/Base64Encoder {
2+
public static final field Companion Llove/forte/simbot/component/onebot/v11/message/Base64Encoder$Companion;
3+
public static final field Default Llove/forte/simbot/component/onebot/v11/message/Base64Encoder;
4+
public static final field Mime Llove/forte/simbot/component/onebot/v11/message/Base64Encoder;
5+
public static final field UrlSafe Llove/forte/simbot/component/onebot/v11/message/Base64Encoder;
6+
public abstract fun encodeToAppendable ([BLjava/lang/Appendable;)Ljava/lang/Appendable;
7+
}
8+
9+
public final class love/forte/simbot/component/onebot/v11/message/Base64Encoder$Companion {
10+
}
11+
112
public abstract interface class love/forte/simbot/component/onebot/v11/message/OneBotMessageContent : love/forte/simbot/message/MessageContent {
213
public abstract synthetic fun delete ([Llove/forte/simbot/ability/DeleteOption;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
314
public abstract fun getId ()Llove/forte/simbot/common/id/ID;
@@ -427,7 +438,7 @@ public final class love/forte/simbot/component/onebot/v11/message/segment/OneBot
427438
public final class love/forte/simbot/component/onebot/v11/message/segment/OneBotImage : love/forte/simbot/component/onebot/v11/message/segment/OneBotMessageSegment, love/forte/simbot/component/onebot/v11/message/segment/OneBotMessageSegmentElementResolver {
428439
public static final field Factory Llove/forte/simbot/component/onebot/v11/message/segment/OneBotImage$Factory;
429440
public static final field TYPE Ljava/lang/String;
430-
public synthetic fun <init> (Llove/forte/simbot/component/onebot/v11/message/segment/OneBotImage$Data;Llove/forte/simbot/resource/Resource;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
441+
public synthetic fun <init> (Llove/forte/simbot/component/onebot/v11/message/segment/OneBotImage$Data;Llove/forte/simbot/resource/Resource;Ljava/lang/String;Llove/forte/simbot/component/onebot/v11/message/Base64Encoder;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
431442
public static final fun create (Ljava/lang/String;)Llove/forte/simbot/component/onebot/v11/message/segment/OneBotImage;
432443
public static final fun create (Llove/forte/simbot/component/onebot/v11/message/segment/OneBotImage$Data;)Llove/forte/simbot/component/onebot/v11/message/segment/OneBotImage;
433444
public static final fun create (Llove/forte/simbot/component/onebot/v11/message/segment/OneBotImage$Data;Llove/forte/simbot/resource/Resource;)Llove/forte/simbot/component/onebot/v11/message/segment/OneBotImage;
@@ -455,11 +466,13 @@ public synthetic class love/forte/simbot/component/onebot/v11/message/segment/On
455466

456467
public final class love/forte/simbot/component/onebot/v11/message/segment/OneBotImage$AdditionalParams {
457468
public fun <init> ()V
469+
public final fun getBase64Encoder ()Llove/forte/simbot/component/onebot/v11/message/Base64Encoder;
458470
public final fun getCache ()Ljava/lang/Boolean;
459471
public final fun getLocalFileToBase64 ()Z
460472
public final fun getProxy ()Ljava/lang/Boolean;
461473
public final fun getTimeout ()Ljava/lang/Integer;
462474
public final fun getType ()Ljava/lang/String;
475+
public final fun setBase64Encoder (Llove/forte/simbot/component/onebot/v11/message/Base64Encoder;)V
463476
public final fun setCache (Ljava/lang/Boolean;)V
464477
public final fun setLocalFileToBase64 (Z)V
465478
public final fun setProxy (Ljava/lang/Boolean;)V
@@ -836,7 +849,7 @@ public final class love/forte/simbot/component/onebot/v11/message/segment/OneBot
836849
public final class love/forte/simbot/component/onebot/v11/message/segment/OneBotRecord : love/forte/simbot/component/onebot/v11/message/segment/OneBotMessageSegment {
837850
public static final field Factory Llove/forte/simbot/component/onebot/v11/message/segment/OneBotRecord$Factory;
838851
public static final field TYPE Ljava/lang/String;
839-
public synthetic fun <init> (Llove/forte/simbot/component/onebot/v11/message/segment/OneBotRecord$Data;Llove/forte/simbot/resource/Resource;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
852+
public synthetic fun <init> (Llove/forte/simbot/component/onebot/v11/message/segment/OneBotRecord$Data;Llove/forte/simbot/resource/Resource;Ljava/lang/String;Llove/forte/simbot/component/onebot/v11/message/Base64Encoder;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
840853
public static final fun create (Ljava/lang/String;)Llove/forte/simbot/component/onebot/v11/message/segment/OneBotRecord;
841854
public static final fun create (Llove/forte/simbot/component/onebot/v11/message/segment/OneBotRecord$Data;)Llove/forte/simbot/component/onebot/v11/message/segment/OneBotRecord;
842855
public static final fun create (Llove/forte/simbot/component/onebot/v11/message/segment/OneBotRecord$Data;Llove/forte/simbot/resource/Resource;)Llove/forte/simbot/component/onebot/v11/message/segment/OneBotRecord;
@@ -863,11 +876,13 @@ public synthetic class love/forte/simbot/component/onebot/v11/message/segment/On
863876

864877
public final class love/forte/simbot/component/onebot/v11/message/segment/OneBotRecord$AdditionalParams {
865878
public fun <init> ()V
879+
public final fun getBase64Encoder ()Llove/forte/simbot/component/onebot/v11/message/Base64Encoder;
866880
public final fun getCache ()Ljava/lang/Boolean;
867881
public final fun getLocalFileToBase64 ()Z
868882
public final fun getMagic ()Ljava/lang/String;
869883
public final fun getProxy ()Ljava/lang/Boolean;
870884
public final fun getTimeout ()Ljava/lang/Integer;
885+
public final fun setBase64Encoder (Llove/forte/simbot/component/onebot/v11/message/Base64Encoder;)V
871886
public final fun setCache (Ljava/lang/Boolean;)V
872887
public final fun setLocalFileToBase64 (Z)V
873888
public final fun setMagic (Ljava/lang/String;)V
@@ -1143,7 +1158,7 @@ public final class love/forte/simbot/component/onebot/v11/message/segment/OneBot
11431158
public final class love/forte/simbot/component/onebot/v11/message/segment/OneBotVideo : love/forte/simbot/component/onebot/v11/message/segment/OneBotMessageSegment {
11441159
public static final field Factory Llove/forte/simbot/component/onebot/v11/message/segment/OneBotVideo$Factory;
11451160
public static final field TYPE Ljava/lang/String;
1146-
public synthetic fun <init> (Llove/forte/simbot/component/onebot/v11/message/segment/OneBotVideo$Data;Llove/forte/simbot/resource/Resource;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
1161+
public synthetic fun <init> (Llove/forte/simbot/component/onebot/v11/message/segment/OneBotVideo$Data;Llove/forte/simbot/resource/Resource;Ljava/lang/String;Llove/forte/simbot/component/onebot/v11/message/Base64Encoder;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
11471162
public static final fun create (Ljava/lang/String;)Llove/forte/simbot/component/onebot/v11/message/segment/OneBotVideo;
11481163
public static final fun create (Llove/forte/simbot/component/onebot/v11/message/segment/OneBotVideo$Data;)Llove/forte/simbot/component/onebot/v11/message/segment/OneBotVideo;
11491164
public static final fun create (Llove/forte/simbot/component/onebot/v11/message/segment/OneBotVideo$Data;Llove/forte/simbot/resource/Resource;)Llove/forte/simbot/component/onebot/v11/message/segment/OneBotVideo;
@@ -1170,10 +1185,12 @@ public synthetic class love/forte/simbot/component/onebot/v11/message/segment/On
11701185

11711186
public final class love/forte/simbot/component/onebot/v11/message/segment/OneBotVideo$AdditionalParams {
11721187
public fun <init> ()V
1188+
public final fun getBase64Encoder ()Llove/forte/simbot/component/onebot/v11/message/Base64Encoder;
11731189
public final fun getCache ()Ljava/lang/Boolean;
11741190
public final fun getLocalFileToBase64 ()Z
11751191
public final fun getProxy ()Ljava/lang/Boolean;
11761192
public final fun getTimeout ()Ljava/lang/Integer;
1193+
public final fun setBase64Encoder (Llove/forte/simbot/component/onebot/v11/message/Base64Encoder;)V
11771194
public final fun setCache (Ljava/lang/Boolean;)V
11781195
public final fun setLocalFileToBase64 (Z)V
11791196
public final fun setProxy (Ljava/lang/Boolean;)V
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
/*
2+
* Copyright (c) 2025. ForteScarlet.
3+
*
4+
* This file is part of simbot-component-onebot.
5+
*
6+
* simbot-component-onebot is free software: you can redistribute it and/or modify it under the terms
7+
* of the GNU Lesser General Public License as published by the Free Software Foundation,
8+
* either version 3 of the License, or (at your option) any later version.
9+
*
10+
* simbot-component-onebot is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
11+
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12+
* See the GNU Lesser General Public License for more details.
13+
*
14+
* You should have received a copy of the GNU Lesser General Public License along with simbot-component-onebot.
15+
* If not, see <https://www.gnu.org/licenses/>.
16+
*/
17+
18+
package love.forte.simbot.component.onebot.v11.message
19+
20+
import kotlin.io.encoding.Base64
21+
import kotlin.io.encoding.ExperimentalEncodingApi
22+
import kotlin.jvm.JvmField
23+
24+
25+
/**
26+
* A base64 encoder.
27+
*
28+
* @since 1.6.1
29+
*
30+
* @author ForteScarlet
31+
*/
32+
public interface Base64Encoder {
33+
/**
34+
* Encodes [source] ByteArray to a Base64 encoded ByteArray.
35+
*/
36+
public fun <A : Appendable> encodeToAppendable(source: ByteArray, destination: A): A
37+
38+
public companion object {
39+
/**
40+
* Get a [Base64Encoder] instance based on [kotlin.io.encoding.Base64.Default].
41+
*/
42+
@ExperimentalEncodingApi
43+
@JvmField
44+
public val Default: Base64Encoder = KotlinBase64Encoder(Base64.Default)
45+
46+
/**
47+
* Get a [Base64Encoder] instance based on [kotlin.io.encoding.Base64.Mime].
48+
*/
49+
@ExperimentalEncodingApi
50+
@JvmField
51+
public val Mime: Base64Encoder = KotlinBase64Encoder(Base64.Mime)
52+
53+
/**
54+
* Get a [Base64Encoder] instance based on [kotlin.io.encoding.Base64.UrlSafe].
55+
*/
56+
@ExperimentalEncodingApi
57+
@JvmField
58+
public val UrlSafe: Base64Encoder = KotlinBase64Encoder(Base64.UrlSafe)
59+
}
60+
}
61+
62+
@ExperimentalEncodingApi
63+
private class KotlinBase64Encoder(val base64: Base64) : Base64Encoder {
64+
override fun <A : Appendable> encodeToAppendable(source: ByteArray, destination: A): A {
65+
base64.encodeToAppendable(source, destination)
66+
return destination
67+
}
68+
}
69+
70+
@OptIn(ExperimentalEncodingApi::class)
71+
internal fun standardEncoderByName(name: String): Base64Encoder? {
72+
return when {
73+
name.equals("Default", true) -> Base64Encoder.Default
74+
name.equals("Mime", true) -> Base64Encoder.Mime
75+
name.equals("UrlSafe", true) || name.equals("url_safe", true)
76+
-> Base64Encoder.UrlSafe
77+
78+
else -> null
79+
}
80+
}
81+
82+
@OptIn(ExperimentalEncodingApi::class)
83+
internal fun Base64Encoder.standardName(): String? {
84+
return when (this) {
85+
Base64Encoder.Default -> "Default"
86+
Base64Encoder.Mime -> "Mime"
87+
Base64Encoder.UrlSafe -> "UrlSafe"
88+
else -> null
89+
}
90+
}
91+
92+
@OptIn(ExperimentalEncodingApi::class)
93+
internal val Base64Encoder.base64: Base64? get() = (this as? KotlinBase64Encoder)?.base64

simbot-component-onebot-v11/simbot-component-onebot-v11-message/src/commonMain/kotlin/love/forte/simbot/component/onebot/v11/message/segment/OneBotImage.kt

Lines changed: 48 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2024. ForteScarlet.
2+
* Copyright (c) 2024-2025. ForteScarlet.
33
*
44
* This file is part of simbot-component-onebot.
55
*
@@ -17,13 +17,19 @@
1717

1818
package love.forte.simbot.component.onebot.v11.message.segment
1919

20+
import kotlinx.serialization.ExperimentalSerializationApi
2021
import kotlinx.serialization.SerialName
2122
import kotlinx.serialization.Serializable
2223
import kotlinx.serialization.Transient
24+
import love.forte.simbot.component.onebot.v11.message.Base64Encoder
25+
import love.forte.simbot.component.onebot.v11.message.segment.OneBotImage.Factory.create
26+
import love.forte.simbot.component.onebot.v11.message.standardEncoderByName
27+
import love.forte.simbot.component.onebot.v11.message.standardName
2328
import love.forte.simbot.message.Image
2429
import love.forte.simbot.message.UrlAwareImage
2530
import love.forte.simbot.resource.ByteArrayResource
2631
import love.forte.simbot.resource.Resource
32+
import kotlin.io.encoding.ExperimentalEncodingApi
2733
import kotlin.jvm.JvmOverloads
2834
import kotlin.jvm.JvmStatic
2935
import kotlin.jvm.JvmSynthetic
@@ -33,14 +39,25 @@ import kotlin.jvm.JvmSynthetic
3339
*
3440
* 可用于发送。
3541
*
42+
* ## 序列化
43+
* ### Base64 encoder
44+
* 在序列化并反序列化后,之前通过 [AdditionalParams.base64Encoder] 指定的 [Base64Encoder] **可能会丢失**。
45+
* 如果丢失后再次需要使用 [Base64Encoder] 时,会选择使用 [Base64Encoder.Default]。
46+
*
3647
* @author ForteScarlet
3748
*/
49+
@OptIn(ExperimentalSerializationApi::class)
3850
@Serializable
3951
@SerialName(OneBotImage.TYPE)
4052
public class OneBotImage private constructor(
4153
override val data: Data,
4254
@Transient
4355
private val resource0: Resource? = null,
56+
private val base64Encoder: String? = null,
57+
@Transient
58+
@OptIn(ExperimentalEncodingApi::class)
59+
private val base64EncoderValue: Base64Encoder =
60+
base64Encoder?.let { standardEncoderByName(it) } ?: Base64Encoder.Default
4461
) : OneBotMessageSegment, OneBotMessageSegmentElementResolver {
4562
/**
4663
* 当前 [OneBotImage] 中的资源信息。
@@ -49,14 +66,14 @@ public class OneBotImage private constructor(
4966
* [Data.file] 的资源信息。
5067
*/
5168
public val resource: Resource by lazy {
52-
resource0 ?: data.resolveToResource()
69+
resource0 ?: data.resolveToResource(base64EncoderValue)
5370
}
5471

5572
public companion object Factory {
5673
public const val TYPE: String = "image"
5774

58-
private fun Data.resolveToResource(): Resource {
59-
return resolveUrlOrFileToResource(url, file)
75+
private fun Data.resolveToResource(encoder: Base64Encoder): Resource {
76+
return resolveUrlOrFileToResource(url, file, encoder)
6077
}
6178

6279
/**
@@ -67,6 +84,9 @@ public class OneBotImage private constructor(
6784
* - 如果 [Data.file] 是链接或者文件路径,
6885
* 解析为 `URIResource` 或 `PathResource` (仅支持 JVM 平台)
6986
*
87+
* 如果需要指定 [Base64Encoder] (since 1.6.1),
88+
* 选择使用 [create] 的另一个可以提供 [AdditionalParams] 的重载。
89+
*
7090
* @throws UnsupportedOperationException 如果解析 [resource] 时平台不支持
7191
*/
7292
@JvmStatic
@@ -97,12 +117,16 @@ public class OneBotImage private constructor(
97117
*
98118
* @throws UnsupportedOperationException 如果解析 [resource] 时平台不支持
99119
*/
120+
@OptIn(ExperimentalEncodingApi::class)
100121
@JvmStatic
101122
@JvmOverloads
102123
public fun create(resource: Resource, additional: AdditionalParams? = null): OneBotImage {
124+
val base64Encoder = additional.base64EncoderOrDefault
125+
103126
val file = resolveResourceToFileValue(
104127
resource,
105-
additional?.localFileToBase64 == true
128+
additional?.localFileToBase64 == true,
129+
base64Encoder
106130
)
107131

108132
val data = Data(
@@ -113,7 +137,12 @@ public class OneBotImage private constructor(
113137
timeout = additional?.timeout,
114138
)
115139

116-
return OneBotImage(data, resource)
140+
return OneBotImage(
141+
data,
142+
resource,
143+
base64Encoder.standardName(),
144+
base64Encoder
145+
)
117146
}
118147
}
119148

@@ -152,10 +181,18 @@ public class OneBotImage private constructor(
152181

153182
/**
154183
* 用于 [OneBotImage] 提供的部分工厂函数中,
155-
* 指定 [Data] 中部分属性
184+
* 指定 [Data] 中部分属性或一些有用的额外参数
156185
*/
157186
public class AdditionalParams {
158187
public var localFileToBase64: Boolean = false
188+
189+
/**
190+
* 当需要对资源进行 base64 编码时使用的编码器。
191+
* 如果未配置则默认为 [Base64Encoder.Default]。
192+
* @since 1.6.1
193+
*/
194+
public var base64Encoder: Base64Encoder? = null
195+
159196
public var type: String? = null
160197
public var cache: Boolean? = null
161198
public var proxy: Boolean? = null
@@ -196,3 +233,7 @@ public inline fun OneBotImage.Factory.create(
196233
): OneBotImage {
197234
return create(resource, OneBotImage.AdditionalParams().also(block))
198235
}
236+
237+
@OptIn(ExperimentalEncodingApi::class)
238+
private inline val OneBotImage.AdditionalParams?.base64EncoderOrDefault: Base64Encoder
239+
get() = this?.base64Encoder ?: Base64Encoder.Default

0 commit comments

Comments
 (0)