mirror of
https://github.com/InsanusMokrassar/TelegramBotAPI.git
synced 2024-11-22 08:13:47 +00:00
rework of multipart files with fixes in new sticker sets
This commit is contained in:
parent
6722ab5f50
commit
e5a48e9684
@ -45,6 +45,7 @@ microutils-coroutines = { module = "dev.inmo:micro_utils.coroutines", version.re
|
||||
microutils-serialization-base64 = { module = "dev.inmo:micro_utils.serialization.base64", version.ref = "microutils" }
|
||||
microutils-serialization-encapsulator = { module = "dev.inmo:micro_utils.serialization.encapsulator", version.ref = "microutils" }
|
||||
microutils-serialization-typedSerializer = { module = "dev.inmo:micro_utils.serialization.typed_serializer", version.ref = "microutils" }
|
||||
microutils-serialization-mapper = { module = "dev.inmo:micro_utils.serialization.mapper", version.ref = "microutils" }
|
||||
microutils-languageCodes = { module = "dev.inmo:micro_utils.language_codes", version.ref = "microutils" }
|
||||
microutils-ktor-common = { module = "dev.inmo:micro_utils.ktor.common", version.ref = "microutils" }
|
||||
microutils-fsm-common = { module = "dev.inmo:micro_utils.fsm.common", version.ref = "microutils" }
|
||||
|
@ -9,6 +9,7 @@ import dev.inmo.tgbotapi.types.files.TelegramMediaFile
|
||||
import dev.inmo.tgbotapi.types.message.content.MediaContent
|
||||
import io.ktor.util.cio.use
|
||||
import io.ktor.util.cio.writeChannel
|
||||
import io.ktor.utils.io.copyAndClose
|
||||
import io.ktor.utils.io.copyTo
|
||||
import kotlinx.coroutines.job
|
||||
import java.io.File
|
||||
@ -25,7 +26,7 @@ suspend fun TelegramBot.downloadFile(
|
||||
doOutsideOfCoroutine { destFile.createNewFile() }
|
||||
|
||||
destFile.writeChannel(coroutineContext.job).use {
|
||||
readChannel.copyTo(this)
|
||||
readChannel.copyAndClose(this)
|
||||
}
|
||||
|
||||
return destFile
|
||||
|
@ -30,11 +30,17 @@ suspend fun TelegramBot.downloadFileToTemp(
|
||||
|
||||
suspend fun TelegramBot.downloadFileToTemp(
|
||||
pathedFile: PathedFile
|
||||
) = downloadFileToTemp(
|
||||
): File = downloadFileToTemp(
|
||||
pathedFile.filePath
|
||||
).apply {
|
||||
runCatching {
|
||||
renameTo(File(parentFile, "$nameWithoutExtension.${pathedFile.fileName.fileExtension}"))
|
||||
).run {
|
||||
val newFile = File(parentFile, "$nameWithoutExtension.${pathedFile.fileName.fileExtension}")
|
||||
val success = runCatching {
|
||||
renameTo(newFile)
|
||||
}.getOrElse { false }
|
||||
if (success) {
|
||||
newFile
|
||||
} else {
|
||||
this@run
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -26,6 +26,7 @@ kotlin {
|
||||
api libs.microutils.serialization.base64
|
||||
api libs.microutils.serialization.encapsulator
|
||||
api libs.microutils.serialization.typedSerializer
|
||||
api libs.microutils.serialization.mapper
|
||||
api libs.microutils.ktor.common
|
||||
api libs.microutils.languageCodes
|
||||
|
||||
|
@ -36,8 +36,10 @@ sealed class InputFile {
|
||||
}
|
||||
}
|
||||
|
||||
internal const val attachPrefix = "attach://"
|
||||
|
||||
internal inline val InputFile.attachFileId
|
||||
get() = "attach://$fileId"
|
||||
get() = "$attachPrefix$fileId"
|
||||
internal inline val InputFile.fileIdToSend
|
||||
get() = when (this) {
|
||||
is FileId -> fileId
|
||||
@ -60,8 +62,8 @@ fun String.toInputFile() = FileId(this)
|
||||
@RiskFeature
|
||||
object InputFileSerializer : KSerializer<InputFile> {
|
||||
override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor(FileId::class.toString(), PrimitiveKind.STRING)
|
||||
override fun serialize(encoder: Encoder, value: InputFile) = encoder.encodeString(value.fileId)
|
||||
override fun deserialize(decoder: Decoder): FileId = FileId(decoder.decodeString())
|
||||
override fun serialize(encoder: Encoder, value: InputFile) = encoder.encodeString(value.fileIdToSend)
|
||||
override fun deserialize(decoder: Decoder): FileId = FileId(decoder.decodeString().removePrefix(attachPrefix))
|
||||
}
|
||||
|
||||
// TODO:: add checks for files size
|
||||
|
@ -1,6 +1,7 @@
|
||||
package dev.inmo.tgbotapi.requests.send.media
|
||||
|
||||
import dev.inmo.tgbotapi.requests.abstracts.*
|
||||
import dev.inmo.tgbotapi.requests.common.CommonMultipartFileRequest
|
||||
import dev.inmo.tgbotapi.requests.send.abstracts.*
|
||||
import dev.inmo.tgbotapi.requests.send.media.base.*
|
||||
import dev.inmo.tgbotapi.types.*
|
||||
@ -22,7 +23,7 @@ import kotlinx.serialization.*
|
||||
fun SendAnimation(
|
||||
chatId: ChatIdentifier,
|
||||
animation: InputFile,
|
||||
thumb: InputFile? = null,
|
||||
thumbnail: InputFile? = null,
|
||||
text: String? = null,
|
||||
parseMode: ParseMode? = null,
|
||||
spoilered: Boolean = false,
|
||||
@ -36,15 +37,13 @@ fun SendAnimation(
|
||||
allowSendingWithoutReply: Boolean? = null,
|
||||
replyMarkup: KeyboardMarkup? = null
|
||||
): Request<ContentMessage<AnimationContent>> {
|
||||
val animationAsFileId = (animation as? FileId) ?.fileId
|
||||
val animationAsFile = animation as? MultipartFile
|
||||
val thumbAsFileId = (thumb as? FileId) ?.fileId
|
||||
val thumbAsFile = thumb as? MultipartFile
|
||||
val thumbAsFile = thumbnail as? MultipartFile
|
||||
|
||||
val data = SendAnimationData(
|
||||
chatId,
|
||||
animationAsFileId,
|
||||
thumbAsFileId,
|
||||
animation,
|
||||
thumbnail ?.fileId,
|
||||
text,
|
||||
parseMode,
|
||||
null,
|
||||
@ -63,9 +62,9 @@ fun SendAnimation(
|
||||
return if (animationAsFile == null && thumbAsFile == null) {
|
||||
data
|
||||
} else {
|
||||
MultipartRequestImpl(
|
||||
CommonMultipartFileRequest(
|
||||
data,
|
||||
SendAnimationFiles(animationAsFile, thumbAsFile)
|
||||
listOfNotNull(animationAsFile, thumbAsFile).associateBy { it.fileId }
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -73,7 +72,7 @@ fun SendAnimation(
|
||||
fun SendAnimation(
|
||||
chatId: ChatIdentifier,
|
||||
animation: InputFile,
|
||||
thumb: InputFile? = null,
|
||||
thumbnail: InputFile? = null,
|
||||
entities: TextSourcesList,
|
||||
spoilered: Boolean = false,
|
||||
duration: Long? = null,
|
||||
@ -86,15 +85,13 @@ fun SendAnimation(
|
||||
allowSendingWithoutReply: Boolean? = null,
|
||||
replyMarkup: KeyboardMarkup? = null
|
||||
): Request<ContentMessage<AnimationContent>> {
|
||||
val animationAsFileId = (animation as? FileId) ?.fileId
|
||||
val animationAsFile = animation as? MultipartFile
|
||||
val thumbAsFileId = (thumb as? FileId) ?.fileId
|
||||
val thumbAsFile = thumb as? MultipartFile
|
||||
val thumbAsFile = thumbnail as? MultipartFile
|
||||
|
||||
val data = SendAnimationData(
|
||||
chatId,
|
||||
animationAsFileId,
|
||||
thumbAsFileId,
|
||||
animation,
|
||||
thumbnail ?.fileId,
|
||||
entities.makeString(),
|
||||
null,
|
||||
entities.toRawMessageEntities(),
|
||||
@ -113,9 +110,9 @@ fun SendAnimation(
|
||||
return if (animationAsFile == null && thumbAsFile == null) {
|
||||
data
|
||||
} else {
|
||||
MultipartRequestImpl(
|
||||
CommonMultipartFileRequest(
|
||||
data,
|
||||
SendAnimationFiles(animationAsFile, thumbAsFile)
|
||||
listOfNotNull(animationAsFile, thumbAsFile).associateBy { it.fileId }
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -128,7 +125,7 @@ data class SendAnimationData internal constructor(
|
||||
@SerialName(chatIdField)
|
||||
override val chatId: ChatIdentifier,
|
||||
@SerialName(animationField)
|
||||
val animation: String? = null,
|
||||
val animation: InputFile,
|
||||
@SerialName(thumbnailField)
|
||||
override val thumbnail: String? = null,
|
||||
@SerialName(captionField)
|
||||
|
@ -2,6 +2,7 @@ package dev.inmo.tgbotapi.requests.send.media
|
||||
|
||||
import dev.inmo.tgbotapi.abstracts.Performerable
|
||||
import dev.inmo.tgbotapi.requests.abstracts.*
|
||||
import dev.inmo.tgbotapi.requests.common.CommonMultipartFileRequest
|
||||
import dev.inmo.tgbotapi.requests.send.abstracts.*
|
||||
import dev.inmo.tgbotapi.requests.send.media.base.*
|
||||
import dev.inmo.tgbotapi.types.*
|
||||
@ -23,7 +24,7 @@ import kotlinx.serialization.*
|
||||
fun SendAudio(
|
||||
chatId: ChatIdentifier,
|
||||
audio: InputFile,
|
||||
thumb: InputFile? = null,
|
||||
thumbnail: InputFile? = null,
|
||||
text: String? = null,
|
||||
parseMode: ParseMode? = null,
|
||||
duration: Long? = null,
|
||||
@ -36,15 +37,13 @@ fun SendAudio(
|
||||
allowSendingWithoutReply: Boolean? = null,
|
||||
replyMarkup: KeyboardMarkup? = null
|
||||
): Request<ContentMessage<AudioContent>> {
|
||||
val audioAsFileId = (audio as? FileId) ?.fileId
|
||||
val audioAsFile = audio as? MultipartFile
|
||||
val thumbAsFileId = (thumb as? FileId) ?.fileId
|
||||
val thumbAsFile = thumb as? MultipartFile
|
||||
val thumbAsFile = thumbnail as? MultipartFile
|
||||
|
||||
val data = SendAudioData(
|
||||
chatId,
|
||||
audioAsFileId,
|
||||
thumbAsFileId,
|
||||
audio,
|
||||
thumbnail ?.fileId,
|
||||
text,
|
||||
parseMode,
|
||||
null,
|
||||
@ -62,9 +61,9 @@ fun SendAudio(
|
||||
return if (audioAsFile == null && thumbAsFile == null) {
|
||||
data
|
||||
} else {
|
||||
MultipartRequestImpl(
|
||||
CommonMultipartFileRequest(
|
||||
data,
|
||||
SendAudioFiles(audioAsFile, thumbAsFile)
|
||||
listOfNotNull(audioAsFile, thumbAsFile).associateBy { it.fileId }
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -72,7 +71,7 @@ fun SendAudio(
|
||||
fun SendAudio(
|
||||
chatId: ChatIdentifier,
|
||||
audio: InputFile,
|
||||
thumb: InputFile? = null,
|
||||
thumbnail: InputFile? = null,
|
||||
entities: List<TextSource>,
|
||||
duration: Long? = null,
|
||||
performer: String? = null,
|
||||
@ -84,15 +83,13 @@ fun SendAudio(
|
||||
allowSendingWithoutReply: Boolean? = null,
|
||||
replyMarkup: KeyboardMarkup? = null
|
||||
): Request<ContentMessage<AudioContent>> {
|
||||
val audioAsFileId = (audio as? FileId) ?.fileId
|
||||
val audioAsFile = audio as? MultipartFile
|
||||
val thumbAsFileId = (thumb as? FileId) ?.fileId
|
||||
val thumbAsFile = thumb as? MultipartFile
|
||||
val thumbAsFile = thumbnail as? MultipartFile
|
||||
|
||||
val data = SendAudioData(
|
||||
chatId,
|
||||
audioAsFileId,
|
||||
thumbAsFileId,
|
||||
audio,
|
||||
thumbnail ?.fileId,
|
||||
entities.makeString(),
|
||||
null,
|
||||
entities.toRawMessageEntities(),
|
||||
@ -110,9 +107,9 @@ fun SendAudio(
|
||||
return if (audioAsFile == null && thumbAsFile == null) {
|
||||
data
|
||||
} else {
|
||||
MultipartRequestImpl(
|
||||
CommonMultipartFileRequest(
|
||||
data,
|
||||
SendAudioFiles(audioAsFile, thumbAsFile)
|
||||
listOfNotNull(audioAsFile, thumbAsFile).associateBy { it.fileId }
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -125,7 +122,7 @@ data class SendAudioData internal constructor(
|
||||
@SerialName(chatIdField)
|
||||
override val chatId: ChatIdentifier,
|
||||
@SerialName(audioField)
|
||||
val audio: String? = null,
|
||||
val audio: InputFile,
|
||||
@SerialName(thumbnailField)
|
||||
override val thumbnail: String? = null,
|
||||
@SerialName(captionField)
|
||||
|
@ -1,6 +1,7 @@
|
||||
package dev.inmo.tgbotapi.requests.send.media
|
||||
|
||||
import dev.inmo.tgbotapi.requests.abstracts.*
|
||||
import dev.inmo.tgbotapi.requests.common.CommonMultipartFileRequest
|
||||
import dev.inmo.tgbotapi.requests.send.abstracts.*
|
||||
import dev.inmo.tgbotapi.requests.send.media.base.*
|
||||
import dev.inmo.tgbotapi.types.*
|
||||
@ -31,7 +32,7 @@ import kotlinx.serialization.*
|
||||
fun SendDocument(
|
||||
chatId: ChatIdentifier,
|
||||
document: InputFile,
|
||||
thumb: InputFile? = null,
|
||||
thumbnail: InputFile? = null,
|
||||
text: String? = null,
|
||||
parseMode: ParseMode? = null,
|
||||
threadId: MessageThreadId? = chatId.threadId,
|
||||
@ -42,15 +43,13 @@ fun SendDocument(
|
||||
replyMarkup: KeyboardMarkup? = null,
|
||||
disableContentTypeDetection: Boolean? = null
|
||||
): Request<ContentMessage<DocumentContent>> {
|
||||
val documentAsFileId = (document as? FileId) ?.fileId
|
||||
val documentAsFile = document as? MultipartFile
|
||||
val thumbAsFileId = (thumb as? FileId) ?.fileId
|
||||
val thumbAsFile = thumb as? MultipartFile
|
||||
val thumbAsFile = thumbnail as? MultipartFile
|
||||
|
||||
val data = SendDocumentData(
|
||||
chatId,
|
||||
documentAsFileId,
|
||||
thumbAsFileId,
|
||||
document,
|
||||
thumbnail ?.fileId,
|
||||
text,
|
||||
parseMode,
|
||||
null,
|
||||
@ -66,9 +65,9 @@ fun SendDocument(
|
||||
return if (documentAsFile == null && thumbAsFile == null) {
|
||||
data
|
||||
} else {
|
||||
MultipartRequestImpl(
|
||||
CommonMultipartFileRequest(
|
||||
data,
|
||||
SendDocumentFiles(documentAsFile, thumbAsFile)
|
||||
listOfNotNull(documentAsFile, thumbAsFile).associateBy { it.fileId }
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -85,7 +84,7 @@ fun SendDocument(
|
||||
fun SendDocument(
|
||||
chatId: ChatIdentifier,
|
||||
document: InputFile,
|
||||
thumb: InputFile? = null,
|
||||
thumbnail: InputFile? = null,
|
||||
entities: TextSourcesList,
|
||||
threadId: MessageThreadId? = chatId.threadId,
|
||||
disableNotification: Boolean = false,
|
||||
@ -95,15 +94,13 @@ fun SendDocument(
|
||||
replyMarkup: KeyboardMarkup? = null,
|
||||
disableContentTypeDetection: Boolean? = null
|
||||
): Request<ContentMessage<DocumentContent>> {
|
||||
val documentAsFileId = (document as? FileId) ?.fileId
|
||||
val documentAsFile = document as? MultipartFile
|
||||
val thumbAsFileId = (thumb as? FileId) ?.fileId
|
||||
val thumbAsFile = thumb as? MultipartFile
|
||||
val thumbAsFile = thumbnail as? MultipartFile
|
||||
|
||||
val data = SendDocumentData(
|
||||
chatId,
|
||||
documentAsFileId,
|
||||
thumbAsFileId,
|
||||
document,
|
||||
thumbnail ?.fileId,
|
||||
entities.makeString(),
|
||||
null,
|
||||
entities.toRawMessageEntities(),
|
||||
@ -119,9 +116,9 @@ fun SendDocument(
|
||||
return if (documentAsFile == null && thumbAsFile == null) {
|
||||
data
|
||||
} else {
|
||||
MultipartRequestImpl(
|
||||
CommonMultipartFileRequest(
|
||||
data,
|
||||
SendDocumentFiles(documentAsFile, thumbAsFile)
|
||||
listOfNotNull(documentAsFile, thumbAsFile).associateBy { it.fileId }
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -143,7 +140,7 @@ data class SendDocumentData internal constructor(
|
||||
@SerialName(chatIdField)
|
||||
override val chatId: ChatIdentifier,
|
||||
@SerialName(documentField)
|
||||
val document: String? = null,
|
||||
val document: InputFile,
|
||||
@SerialName(thumbnailField)
|
||||
override val thumbnail: String? = null,
|
||||
@SerialName(captionField)
|
||||
|
@ -2,10 +2,12 @@ package dev.inmo.tgbotapi.requests.send.media
|
||||
|
||||
import dev.inmo.tgbotapi.requests.abstracts.MultipartFile
|
||||
import dev.inmo.tgbotapi.requests.abstracts.Request
|
||||
import dev.inmo.tgbotapi.requests.common.CommonMultipartFileRequest
|
||||
import dev.inmo.tgbotapi.requests.send.abstracts.SendMessageRequest
|
||||
import dev.inmo.tgbotapi.requests.send.media.base.*
|
||||
import dev.inmo.tgbotapi.types.*
|
||||
import dev.inmo.tgbotapi.types.media.*
|
||||
import dev.inmo.tgbotapi.types.message.abstracts.ContentMessage
|
||||
import dev.inmo.tgbotapi.types.message.abstracts.PossiblySentViaBotCommonMessage
|
||||
import dev.inmo.tgbotapi.types.message.abstracts.TelegramBotAPIMessageDeserializeOnlySerializerClass
|
||||
import dev.inmo.tgbotapi.types.message.content.MediaGroupPartContent
|
||||
@ -37,7 +39,7 @@ fun <T : MediaGroupPartContent> SendMediaGroup(
|
||||
protectContent: Boolean = false,
|
||||
replyToMessageId: MessageId? = null,
|
||||
allowSendingWithoutReply: Boolean? = null
|
||||
): Request<PossiblySentViaBotCommonMessage<MediaGroupContent<T>>> {
|
||||
): Request<ContentMessage<MediaGroupContent<T>>> {
|
||||
if (media.size !in mediaCountInMediaGroup) {
|
||||
throwRangeError("Count of members in media group", mediaCountInMediaGroup, media.size)
|
||||
}
|
||||
@ -66,11 +68,11 @@ fun <T : MediaGroupPartContent> SendMediaGroup(
|
||||
return (if (files.isEmpty()) {
|
||||
data
|
||||
} else {
|
||||
MultipartRequestImpl(
|
||||
CommonMultipartFileRequest(
|
||||
data,
|
||||
SendMediaGroupFiles(files)
|
||||
files.associateBy { it.fileId }
|
||||
)
|
||||
}) as Request<PossiblySentViaBotCommonMessage<MediaGroupContent<T>>>
|
||||
}) as Request<ContentMessage<MediaGroupContent<T>>>
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,6 +1,7 @@
|
||||
package dev.inmo.tgbotapi.requests.send.media
|
||||
|
||||
import dev.inmo.tgbotapi.requests.abstracts.*
|
||||
import dev.inmo.tgbotapi.requests.common.CommonMultipartFileRequest
|
||||
import dev.inmo.tgbotapi.requests.send.abstracts.*
|
||||
import dev.inmo.tgbotapi.requests.send.media.base.*
|
||||
import dev.inmo.tgbotapi.types.*
|
||||
@ -33,7 +34,7 @@ fun SendPhoto(
|
||||
): Request<ContentMessage<PhotoContent>> {
|
||||
val data = SendPhotoData(
|
||||
chatId,
|
||||
(photo as? FileId) ?.fileId,
|
||||
photo,
|
||||
text,
|
||||
parseMode,
|
||||
null,
|
||||
@ -45,12 +46,14 @@ fun SendPhoto(
|
||||
allowSendingWithoutReply,
|
||||
replyMarkup
|
||||
)
|
||||
return data.photo ?.let {
|
||||
return if (photo is MultipartFile) {
|
||||
CommonMultipartFileRequest(
|
||||
data,
|
||||
listOf(photo).associateBy { it.fileId }
|
||||
)
|
||||
} else {
|
||||
data
|
||||
} ?: MultipartRequestImpl(
|
||||
data,
|
||||
SendPhotoFiles(photo as MultipartFile)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun SendPhoto(
|
||||
@ -67,7 +70,7 @@ fun SendPhoto(
|
||||
): Request<ContentMessage<PhotoContent>> {
|
||||
val data = SendPhotoData(
|
||||
chatId,
|
||||
(photo as? FileId)?.fileId,
|
||||
photo,
|
||||
entities.makeString(),
|
||||
null,
|
||||
entities.toRawMessageEntities(),
|
||||
@ -79,12 +82,15 @@ fun SendPhoto(
|
||||
allowSendingWithoutReply,
|
||||
replyMarkup
|
||||
)
|
||||
return data.photo ?.let {
|
||||
|
||||
return if (photo is MultipartFile) {
|
||||
CommonMultipartFileRequest(
|
||||
data,
|
||||
listOf(photo).associateBy { it.fileId }
|
||||
)
|
||||
} else {
|
||||
data
|
||||
} ?: MultipartRequestImpl(
|
||||
data,
|
||||
SendPhotoFiles(photo as MultipartFile)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private val commonResultDeserializer: DeserializationStrategy<ContentMessage<PhotoContent>>
|
||||
@ -95,7 +101,7 @@ data class SendPhotoData internal constructor(
|
||||
@SerialName(chatIdField)
|
||||
override val chatId: ChatIdentifier,
|
||||
@SerialName(photoField)
|
||||
val photo: String? = null,
|
||||
val photo: InputFile,
|
||||
@SerialName(captionField)
|
||||
override val text: String? = null,
|
||||
@SerialName(parseModeField)
|
||||
|
@ -1,6 +1,7 @@
|
||||
package dev.inmo.tgbotapi.requests.send.media
|
||||
|
||||
import dev.inmo.tgbotapi.requests.abstracts.*
|
||||
import dev.inmo.tgbotapi.requests.common.CommonMultipartFileRequest
|
||||
import dev.inmo.tgbotapi.requests.send.abstracts.ReplyingMarkupSendMessageRequest
|
||||
import dev.inmo.tgbotapi.requests.send.abstracts.SendMessageRequest
|
||||
import dev.inmo.tgbotapi.types.*
|
||||
@ -28,7 +29,7 @@ fun SendSticker(
|
||||
replyMarkup: KeyboardMarkup? = null
|
||||
): Request<ContentMessage<StickerContent>> = SendStickerByFileId(
|
||||
chatId,
|
||||
sticker as? FileId,
|
||||
sticker,
|
||||
threadId,
|
||||
disableNotification,
|
||||
protectContent,
|
||||
@ -37,7 +38,10 @@ fun SendSticker(
|
||||
replyMarkup
|
||||
).let {
|
||||
when (sticker) {
|
||||
is MultipartFile -> SendStickerByFile(it, sticker, emoji)
|
||||
is MultipartFile -> CommonMultipartFileRequest(
|
||||
it,
|
||||
listOf(sticker).associateBy { it.fileId }
|
||||
)
|
||||
is FileId -> it
|
||||
}
|
||||
}
|
||||
@ -50,7 +54,7 @@ data class SendStickerByFileId internal constructor(
|
||||
@SerialName(chatIdField)
|
||||
override val chatId: ChatIdentifier,
|
||||
@SerialName(stickerField)
|
||||
val sticker: FileId? = null,
|
||||
val sticker: InputFile,
|
||||
@SerialName(messageThreadIdField)
|
||||
override val threadId: MessageThreadId? = chatId.threadId,
|
||||
@SerialName(disableNotificationField)
|
||||
@ -70,20 +74,3 @@ data class SendStickerByFileId internal constructor(
|
||||
override val requestSerializer: SerializationStrategy<*>
|
||||
get() = serializer()
|
||||
}
|
||||
|
||||
data class SendStickerByFile internal constructor(
|
||||
@Transient
|
||||
private val sendStickerByFileId: SendStickerByFileId,
|
||||
val sticker: MultipartFile,
|
||||
val emoji: String?
|
||||
) : MultipartRequest<ContentMessage<StickerContent>>, Request<ContentMessage<StickerContent>> by sendStickerByFileId {
|
||||
override val mediaMap: Map<String, MultipartFile> = mapOf(stickerField to sticker)
|
||||
override val paramsJson: JsonObject
|
||||
get() {
|
||||
return JsonObject(
|
||||
mapOfNotNull(
|
||||
emojiField to emoji ?.let { JsonPrimitive(it) }
|
||||
) + sendStickerByFileId.toJsonWithoutNulls(SendStickerByFileId.serializer())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package dev.inmo.tgbotapi.requests.send.media
|
||||
|
||||
import dev.inmo.tgbotapi.requests.abstracts.*
|
||||
import dev.inmo.tgbotapi.requests.common.CommonMultipartFileRequest
|
||||
import dev.inmo.tgbotapi.requests.send.abstracts.*
|
||||
import dev.inmo.tgbotapi.requests.send.media.base.*
|
||||
import dev.inmo.tgbotapi.types.*
|
||||
@ -22,7 +23,7 @@ import kotlinx.serialization.*
|
||||
fun SendVideo(
|
||||
chatId: ChatIdentifier,
|
||||
video: InputFile,
|
||||
thumb: InputFile? = null,
|
||||
thumbnail: InputFile? = null,
|
||||
text: String? = null,
|
||||
parseMode: ParseMode? = null,
|
||||
spoilered: Boolean = false,
|
||||
@ -37,15 +38,13 @@ fun SendVideo(
|
||||
allowSendingWithoutReply: Boolean? = null,
|
||||
replyMarkup: KeyboardMarkup? = null
|
||||
): Request<ContentMessage<VideoContent>> {
|
||||
val videoAsFileId = (video as? FileId) ?.fileId
|
||||
val videoAsFile = video as? MultipartFile
|
||||
val thumbAsFileId = (thumb as? FileId) ?.fileId
|
||||
val thumbAsFile = thumb as? MultipartFile
|
||||
val thumbAsFile = thumbnail as? MultipartFile
|
||||
|
||||
val data = SendVideoData(
|
||||
chatId,
|
||||
videoAsFileId,
|
||||
thumbAsFileId,
|
||||
video,
|
||||
thumbnail ?.fileId,
|
||||
text,
|
||||
parseMode,
|
||||
null,
|
||||
@ -65,9 +64,9 @@ fun SendVideo(
|
||||
return if (videoAsFile == null && thumbAsFile == null) {
|
||||
data
|
||||
} else {
|
||||
MultipartRequestImpl(
|
||||
CommonMultipartFileRequest(
|
||||
data,
|
||||
SendVideoFiles(videoAsFile, thumbAsFile)
|
||||
listOfNotNull(videoAsFile, thumbAsFile).associateBy { it.fileId }
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -75,7 +74,7 @@ fun SendVideo(
|
||||
fun SendVideo(
|
||||
chatId: ChatIdentifier,
|
||||
video: InputFile,
|
||||
thumb: InputFile? = null,
|
||||
thumbnail: InputFile? = null,
|
||||
entities: TextSourcesList,
|
||||
spoilered: Boolean = false,
|
||||
duration: Long? = null,
|
||||
@ -89,15 +88,13 @@ fun SendVideo(
|
||||
allowSendingWithoutReply: Boolean? = null,
|
||||
replyMarkup: KeyboardMarkup? = null
|
||||
): Request<ContentMessage<VideoContent>> {
|
||||
val videoAsFileId = (video as? FileId) ?.fileId
|
||||
val videoAsFile = video as? MultipartFile
|
||||
val thumbAsFileId = (thumb as? FileId) ?.fileId
|
||||
val thumbAsFile = thumb as? MultipartFile
|
||||
val thumbAsFile = thumbnail as? MultipartFile
|
||||
|
||||
val data = SendVideoData(
|
||||
chatId,
|
||||
videoAsFileId,
|
||||
thumbAsFileId,
|
||||
video,
|
||||
thumbnail ?.fileId,
|
||||
entities.makeString(),
|
||||
null,
|
||||
entities.toRawMessageEntities(),
|
||||
@ -117,9 +114,9 @@ fun SendVideo(
|
||||
return if (videoAsFile == null && thumbAsFile == null) {
|
||||
data
|
||||
} else {
|
||||
MultipartRequestImpl(
|
||||
CommonMultipartFileRequest(
|
||||
data,
|
||||
SendVideoFiles(videoAsFile, thumbAsFile)
|
||||
listOfNotNull(videoAsFile, thumbAsFile).associateBy { it.fileId }
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -132,7 +129,7 @@ data class SendVideoData internal constructor(
|
||||
@SerialName(chatIdField)
|
||||
override val chatId: ChatIdentifier,
|
||||
@SerialName(videoField)
|
||||
val video: String? = null,
|
||||
val video: InputFile,
|
||||
@SerialName(thumbnailField)
|
||||
override val thumbnail: String? = null,
|
||||
@SerialName(captionField)
|
||||
|
@ -1,6 +1,7 @@
|
||||
package dev.inmo.tgbotapi.requests.send.media
|
||||
|
||||
import dev.inmo.tgbotapi.requests.abstracts.*
|
||||
import dev.inmo.tgbotapi.requests.common.CommonMultipartFileRequest
|
||||
import dev.inmo.tgbotapi.requests.send.abstracts.*
|
||||
import dev.inmo.tgbotapi.requests.send.media.base.*
|
||||
import dev.inmo.tgbotapi.types.*
|
||||
@ -14,7 +15,7 @@ import kotlinx.serialization.*
|
||||
fun SendVideoNote(
|
||||
chatId: ChatIdentifier,
|
||||
videoNote: InputFile,
|
||||
thumb: InputFile? = null,
|
||||
thumbnail: InputFile? = null,
|
||||
duration: Long? = null,
|
||||
size: Int? = null, // in documentation - length (size of video side)
|
||||
threadId: MessageThreadId? = chatId.threadId,
|
||||
@ -24,15 +25,13 @@ fun SendVideoNote(
|
||||
allowSendingWithoutReply: Boolean? = null,
|
||||
replyMarkup: KeyboardMarkup? = null
|
||||
): Request<ContentMessage<VideoNoteContent>> {
|
||||
val videoNoteAsFileId = (videoNote as? FileId) ?.fileId
|
||||
val videoNoteAsFile = videoNote as? MultipartFile
|
||||
val thumbAsFileId = (thumb as? FileId) ?.fileId
|
||||
val thumbAsFile = thumb as? MultipartFile
|
||||
val thumbAsFile = thumbnail as? MultipartFile
|
||||
|
||||
val data = SendVideoNoteData(
|
||||
chatId,
|
||||
videoNoteAsFileId,
|
||||
thumbAsFileId,
|
||||
videoNote,
|
||||
thumbnail ?.fileId,
|
||||
duration,
|
||||
size,
|
||||
threadId,
|
||||
@ -46,9 +45,9 @@ fun SendVideoNote(
|
||||
return if (videoNoteAsFile == null && thumbAsFile == null) {
|
||||
data
|
||||
} else {
|
||||
MultipartRequestImpl(
|
||||
CommonMultipartFileRequest(
|
||||
data,
|
||||
SendVideoNoteFiles(videoNoteAsFile, thumbAsFile)
|
||||
listOfNotNull(videoNoteAsFile, thumbAsFile).associateBy { it.fileId }
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -61,7 +60,7 @@ data class SendVideoNoteData internal constructor(
|
||||
@SerialName(chatIdField)
|
||||
override val chatId: ChatIdentifier,
|
||||
@SerialName(videoNoteField)
|
||||
val videoNote: String? = null,
|
||||
val videoNote: InputFile,
|
||||
@SerialName(thumbnailField)
|
||||
override val thumbnail: String? = null,
|
||||
@SerialName(durationField)
|
||||
|
@ -1,6 +1,7 @@
|
||||
package dev.inmo.tgbotapi.requests.send.media
|
||||
|
||||
import dev.inmo.tgbotapi.requests.abstracts.*
|
||||
import dev.inmo.tgbotapi.requests.common.CommonMultipartFileRequest
|
||||
import dev.inmo.tgbotapi.requests.send.abstracts.*
|
||||
import dev.inmo.tgbotapi.requests.send.media.base.*
|
||||
import dev.inmo.tgbotapi.types.*
|
||||
@ -32,12 +33,11 @@ fun SendVoice(
|
||||
allowSendingWithoutReply: Boolean? = null,
|
||||
replyMarkup: KeyboardMarkup? = null
|
||||
): Request<ContentMessage<VoiceContent>> {
|
||||
val voiceAsFileId = (voice as? FileId) ?.fileId
|
||||
val voiceAsFile = voice as? MultipartFile
|
||||
|
||||
val data = SendVoiceData(
|
||||
chatId,
|
||||
voiceAsFileId,
|
||||
voice,
|
||||
text,
|
||||
parseMode,
|
||||
null,
|
||||
@ -53,9 +53,9 @@ fun SendVoice(
|
||||
return if (voiceAsFile == null) {
|
||||
data
|
||||
} else {
|
||||
MultipartRequestImpl(
|
||||
CommonMultipartFileRequest(
|
||||
data,
|
||||
SendVoiceFiles(voiceAsFile)
|
||||
listOfNotNull(voiceAsFile).associateBy { it.fileId }
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -72,12 +72,11 @@ fun SendVoice(
|
||||
allowSendingWithoutReply: Boolean? = null,
|
||||
replyMarkup: KeyboardMarkup? = null
|
||||
): Request<ContentMessage<VoiceContent>> {
|
||||
val voiceAsFileId = (voice as? FileId) ?.fileId
|
||||
val voiceAsFile = voice as? MultipartFile
|
||||
|
||||
val data = SendVoiceData(
|
||||
chatId,
|
||||
voiceAsFileId,
|
||||
voice,
|
||||
entities.makeString(),
|
||||
null,
|
||||
entities.toRawMessageEntities(),
|
||||
@ -93,9 +92,9 @@ fun SendVoice(
|
||||
return if (voiceAsFile == null) {
|
||||
data
|
||||
} else {
|
||||
MultipartRequestImpl(
|
||||
CommonMultipartFileRequest(
|
||||
data,
|
||||
SendVoiceFiles(voiceAsFile)
|
||||
listOfNotNull(voiceAsFile).associateBy { it.fileId }
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -108,7 +107,7 @@ data class SendVoiceData internal constructor(
|
||||
@SerialName(chatIdField)
|
||||
override val chatId: ChatIdentifier,
|
||||
@SerialName(voiceField)
|
||||
val voice: String? = null,
|
||||
val voice: InputFile,
|
||||
@SerialName(captionField)
|
||||
override val text: String? = null,
|
||||
@SerialName(parseModeField)
|
||||
|
@ -1,11 +1,15 @@
|
||||
package dev.inmo.tgbotapi.requests.stickers
|
||||
|
||||
import dev.inmo.micro_utils.serialization.mapper.MapperSerializer
|
||||
import dev.inmo.tgbotapi.requests.abstracts.*
|
||||
import dev.inmo.tgbotapi.requests.common.CommonMultipartFileRequest
|
||||
import dev.inmo.tgbotapi.requests.stickers.abstracts.CreateStickerSetAction
|
||||
import dev.inmo.tgbotapi.types.*
|
||||
import dev.inmo.tgbotapi.types.stickers.MaskPosition
|
||||
import kotlinx.serialization.*
|
||||
import kotlinx.serialization.descriptors.SerialDescriptor
|
||||
import kotlinx.serialization.encoding.Decoder
|
||||
import kotlinx.serialization.encoding.Encoder
|
||||
|
||||
/**
|
||||
* Will create one of [CreateNewStickerSet] types based on the first element of [stickers]
|
||||
@ -26,18 +30,30 @@ fun CreateNewStickerSet(
|
||||
is InputSticker.WithKeywords.CustomEmoji -> CreateNewStickerSet.CustomEmoji(userId, name, title, stickersFormat, stickers.filterIsInstance<InputSticker.WithKeywords.CustomEmoji>(), needsRepainting)
|
||||
is InputSticker.WithKeywords.Regular -> CreateNewStickerSet.Regular(userId, name, title, stickersFormat, stickers.filterIsInstance<InputSticker.WithKeywords.Regular>())
|
||||
}
|
||||
val multipartParts = stickers.mapNotNull { (it.sticker as? MultipartFile) }
|
||||
val multipartParts = stickers.mapNotNull {
|
||||
(it.sticker as? MultipartFile)
|
||||
}
|
||||
return if (multipartParts.isNotEmpty()) {
|
||||
CommonMultipartFileRequest(
|
||||
data,
|
||||
multipartParts.associateBy { it.fileId }
|
||||
)
|
||||
when (data) { // cratch for exact determining of common multipart data type
|
||||
is CreateNewStickerSet.CustomEmoji -> CommonMultipartFileRequest(
|
||||
data,
|
||||
multipartParts.associateBy { it.fileId }
|
||||
)
|
||||
is CreateNewStickerSet.Mask -> CommonMultipartFileRequest(
|
||||
data,
|
||||
multipartParts.associateBy { it.fileId }
|
||||
)
|
||||
is CreateNewStickerSet.Regular -> CommonMultipartFileRequest(
|
||||
data,
|
||||
multipartParts.associateBy { it.fileId }
|
||||
)
|
||||
}
|
||||
} else {
|
||||
data
|
||||
}
|
||||
}
|
||||
|
||||
@Serializable
|
||||
@Serializable(CreateNewStickerSetSerializer::class)
|
||||
sealed interface CreateNewStickerSet : CreateStickerSetAction {
|
||||
val stickerType: StickerType
|
||||
val stickers: List<InputSticker>
|
||||
@ -101,4 +117,70 @@ sealed interface CreateNewStickerSet : CreateStickerSetAction {
|
||||
override val stickerType: StickerType
|
||||
get() = StickerType.CustomEmoji
|
||||
}
|
||||
|
||||
@Serializable
|
||||
data class SurrogateCreateNewSticker internal constructor(
|
||||
@SerialName(userIdField)
|
||||
override val userId: UserId,
|
||||
@SerialName(nameField)
|
||||
override val name: String,
|
||||
@SerialName(titleField)
|
||||
override val title: String,
|
||||
@SerialName(stickerFormatField)
|
||||
val stickersFormat: StickerFormat,
|
||||
@SerialName(stickersField)
|
||||
val stickers: List<InputSticker>,
|
||||
@SerialName(stickerTypeField)
|
||||
val stickerType: StickerType,
|
||||
@SerialName(needsRepaintingField)
|
||||
val needsRepainting: Boolean? = null
|
||||
) : CreateStickerSetAction {
|
||||
override val requestSerializer: SerializationStrategy<*>
|
||||
get() = CreateNewStickerSet.serializer()
|
||||
|
||||
override fun method(): String = "createNewStickerSet"
|
||||
}
|
||||
}
|
||||
|
||||
object CreateNewStickerSetSerializer : KSerializer<CreateNewStickerSet>,
|
||||
MapperSerializer<CreateNewStickerSet.SurrogateCreateNewSticker, CreateNewStickerSet>(
|
||||
CreateNewStickerSet.SurrogateCreateNewSticker.serializer(),
|
||||
{
|
||||
CreateNewStickerSet.SurrogateCreateNewSticker(
|
||||
it.userId,
|
||||
it.name,
|
||||
it.title,
|
||||
it.stickersFormat,
|
||||
it.stickers,
|
||||
it.stickerType,
|
||||
(it as? CreateNewStickerSet.CustomEmoji)?.needsRepainting
|
||||
)
|
||||
},
|
||||
{
|
||||
when (it.stickerType) {
|
||||
StickerType.CustomEmoji -> CreateNewStickerSet.CustomEmoji(
|
||||
it.userId,
|
||||
it.name,
|
||||
it.title,
|
||||
it.stickersFormat,
|
||||
it.stickers.filterIsInstance<InputSticker.WithKeywords.CustomEmoji>(),
|
||||
it.needsRepainting
|
||||
)
|
||||
StickerType.Mask -> CreateNewStickerSet.Mask(
|
||||
it.userId,
|
||||
it.name,
|
||||
it.title,
|
||||
it.stickersFormat,
|
||||
it.stickers.filterIsInstance<InputSticker.Mask>(),
|
||||
)
|
||||
StickerType.Regular -> CreateNewStickerSet.Regular(
|
||||
it.userId,
|
||||
it.name,
|
||||
it.title,
|
||||
it.stickersFormat,
|
||||
it.stickers.filterIsInstance<InputSticker.WithKeywords.Regular>(),
|
||||
)
|
||||
is StickerType.Unknown -> error("Unable to create new sticker set due to error in type format: ${it.stickerType}")
|
||||
}
|
||||
}
|
||||
)
|
||||
|
@ -1,17 +1,20 @@
|
||||
package dev.inmo.tgbotapi.requests.stickers
|
||||
|
||||
import dev.inmo.micro_utils.serialization.mapper.MapperSerializer
|
||||
import dev.inmo.tgbotapi.requests.abstracts.InputFile
|
||||
import dev.inmo.tgbotapi.types.StickerType
|
||||
import dev.inmo.tgbotapi.types.emojiListField
|
||||
import dev.inmo.tgbotapi.types.keywordsField
|
||||
import dev.inmo.tgbotapi.types.maskPositionField
|
||||
import dev.inmo.tgbotapi.types.stickerField
|
||||
import dev.inmo.tgbotapi.types.stickers.MaskPosition
|
||||
import dev.inmo.tgbotapi.utils.internal.ClassCastsIncluded
|
||||
import kotlinx.serialization.KSerializer
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@ClassCastsIncluded
|
||||
@Serializable
|
||||
@Serializable(InputStickerSerializer::class)
|
||||
sealed interface InputSticker {
|
||||
val sticker: InputFile
|
||||
val emojisList: List<String>
|
||||
@ -51,3 +54,69 @@ sealed interface InputSticker {
|
||||
) : WithKeywords
|
||||
}
|
||||
}
|
||||
|
||||
object InputStickerSerializer : KSerializer<InputSticker>, MapperSerializer<InputStickerSerializer.SurrogateInputSticker, InputSticker>(
|
||||
SurrogateInputSticker.serializer(),
|
||||
{
|
||||
when (it) {
|
||||
is InputSticker.Mask -> SurrogateInputSticker(
|
||||
it.sticker,
|
||||
it.emojisList,
|
||||
emptyList(),
|
||||
it.maskPosition,
|
||||
StickerType.Mask
|
||||
)
|
||||
is InputSticker.WithKeywords.CustomEmoji -> SurrogateInputSticker(
|
||||
it.sticker,
|
||||
it.emojisList,
|
||||
it.keywords,
|
||||
null,
|
||||
StickerType.CustomEmoji
|
||||
)
|
||||
is InputSticker.WithKeywords.Regular -> SurrogateInputSticker(
|
||||
it.sticker,
|
||||
it.emojisList,
|
||||
it.keywords,
|
||||
null,
|
||||
StickerType.Regular
|
||||
)
|
||||
}
|
||||
},
|
||||
{
|
||||
when (it.internalType) {
|
||||
StickerType.CustomEmoji -> InputSticker.WithKeywords.CustomEmoji(
|
||||
it.sticker,
|
||||
it.emojisList,
|
||||
it.keywords
|
||||
)
|
||||
StickerType.Mask -> InputSticker.Mask(
|
||||
it.sticker,
|
||||
it.emojisList,
|
||||
it.maskPosition
|
||||
)
|
||||
StickerType.Regular -> InputSticker.WithKeywords.Regular(
|
||||
it.sticker,
|
||||
it.emojisList,
|
||||
it.keywords
|
||||
)
|
||||
is StickerType.Unknown -> InputSticker.WithKeywords.Regular(
|
||||
it.sticker,
|
||||
it.emojisList,
|
||||
it.keywords
|
||||
)
|
||||
}
|
||||
},
|
||||
) {
|
||||
@Serializable
|
||||
data class SurrogateInputSticker internal constructor(
|
||||
@SerialName(stickerField)
|
||||
val sticker: InputFile,
|
||||
@SerialName(emojiListField)
|
||||
val emojisList: List<String>,
|
||||
@SerialName(keywordsField)
|
||||
val keywords: List<String> = emptyList(),
|
||||
@SerialName(maskPositionField)
|
||||
val maskPosition: MaskPosition? = null,
|
||||
internal val internalType: StickerType = StickerType.Unknown()
|
||||
)
|
||||
}
|
||||
|
@ -118,6 +118,18 @@ sealed interface MediaCollectionContent<T: TelegramMediaFile>: MessageContent, M
|
||||
sealed interface MediaContent: MessageContent {
|
||||
val media: TelegramMediaFile
|
||||
fun asTelegramMedia(): TelegramMedia
|
||||
|
||||
override fun createResend(
|
||||
chatId: ChatIdentifier,
|
||||
messageThreadId: MessageThreadId?,
|
||||
disableNotification: Boolean,
|
||||
protectContent: Boolean,
|
||||
replyToMessageId: MessageId?,
|
||||
allowSendingWithoutReply: Boolean?,
|
||||
replyMarkup: KeyboardMarkup?
|
||||
): Request<out ContentMessage<MediaContent>> {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
}
|
||||
|
||||
sealed interface SpoilerableMediaContent : MediaContent, SpoilerableData
|
||||
|
@ -9,6 +9,7 @@ import dev.inmo.tgbotapi.types.MessageThreadId
|
||||
import dev.inmo.tgbotapi.types.buttons.KeyboardMarkup
|
||||
import dev.inmo.tgbotapi.types.files.TelegramMediaFile
|
||||
import dev.inmo.tgbotapi.types.media.TelegramMedia
|
||||
import dev.inmo.tgbotapi.types.message.abstracts.ContentMessage
|
||||
import dev.inmo.tgbotapi.types.message.abstracts.Message
|
||||
import dev.inmo.tgbotapi.types.message.textsources.TextSource
|
||||
import kotlinx.serialization.Serializable
|
||||
@ -38,7 +39,7 @@ data class MediaGroupContent<T : MediaGroupPartContent>(
|
||||
replyToMessageId: MessageId?,
|
||||
allowSendingWithoutReply: Boolean?,
|
||||
replyMarkup: KeyboardMarkup?
|
||||
): Request<out Message> = SendMediaGroup<MediaGroupPartContent>(
|
||||
): Request<ContentMessage<MediaGroupContent<MediaGroupPartContent>>> = SendMediaGroup<MediaGroupPartContent>(
|
||||
chatId,
|
||||
group.map { it.content.toMediaGroupMemberTelegramMedia() },
|
||||
threadId,
|
||||
|
Loading…
Reference in New Issue
Block a user