rework of multipart files with fixes in new sticker sets

This commit is contained in:
InsanusMokrassar 2023-03-11 21:17:59 +06:00
parent 6722ab5f50
commit e5a48e9684
18 changed files with 295 additions and 139 deletions

View File

@ -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-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-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-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-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-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" } microutils-fsm-common = { module = "dev.inmo:micro_utils.fsm.common", version.ref = "microutils" }

View File

@ -9,6 +9,7 @@ import dev.inmo.tgbotapi.types.files.TelegramMediaFile
import dev.inmo.tgbotapi.types.message.content.MediaContent import dev.inmo.tgbotapi.types.message.content.MediaContent
import io.ktor.util.cio.use import io.ktor.util.cio.use
import io.ktor.util.cio.writeChannel import io.ktor.util.cio.writeChannel
import io.ktor.utils.io.copyAndClose
import io.ktor.utils.io.copyTo import io.ktor.utils.io.copyTo
import kotlinx.coroutines.job import kotlinx.coroutines.job
import java.io.File import java.io.File
@ -25,7 +26,7 @@ suspend fun TelegramBot.downloadFile(
doOutsideOfCoroutine { destFile.createNewFile() } doOutsideOfCoroutine { destFile.createNewFile() }
destFile.writeChannel(coroutineContext.job).use { destFile.writeChannel(coroutineContext.job).use {
readChannel.copyTo(this) readChannel.copyAndClose(this)
} }
return destFile return destFile

View File

@ -30,11 +30,17 @@ suspend fun TelegramBot.downloadFileToTemp(
suspend fun TelegramBot.downloadFileToTemp( suspend fun TelegramBot.downloadFileToTemp(
pathedFile: PathedFile pathedFile: PathedFile
) = downloadFileToTemp( ): File = downloadFileToTemp(
pathedFile.filePath pathedFile.filePath
).apply { ).run {
runCatching { val newFile = File(parentFile, "$nameWithoutExtension.${pathedFile.fileName.fileExtension}")
renameTo(File(parentFile, "$nameWithoutExtension.${pathedFile.fileName.fileExtension}")) val success = runCatching {
renameTo(newFile)
}.getOrElse { false }
if (success) {
newFile
} else {
this@run
} }
} }

View File

@ -26,6 +26,7 @@ kotlin {
api libs.microutils.serialization.base64 api libs.microutils.serialization.base64
api libs.microutils.serialization.encapsulator api libs.microutils.serialization.encapsulator
api libs.microutils.serialization.typedSerializer api libs.microutils.serialization.typedSerializer
api libs.microutils.serialization.mapper
api libs.microutils.ktor.common api libs.microutils.ktor.common
api libs.microutils.languageCodes api libs.microutils.languageCodes

View File

@ -36,8 +36,10 @@ sealed class InputFile {
} }
} }
internal const val attachPrefix = "attach://"
internal inline val InputFile.attachFileId internal inline val InputFile.attachFileId
get() = "attach://$fileId" get() = "$attachPrefix$fileId"
internal inline val InputFile.fileIdToSend internal inline val InputFile.fileIdToSend
get() = when (this) { get() = when (this) {
is FileId -> fileId is FileId -> fileId
@ -60,8 +62,8 @@ fun String.toInputFile() = FileId(this)
@RiskFeature @RiskFeature
object InputFileSerializer : KSerializer<InputFile> { object InputFileSerializer : KSerializer<InputFile> {
override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor(FileId::class.toString(), PrimitiveKind.STRING) override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor(FileId::class.toString(), PrimitiveKind.STRING)
override fun serialize(encoder: Encoder, value: InputFile) = encoder.encodeString(value.fileId) override fun serialize(encoder: Encoder, value: InputFile) = encoder.encodeString(value.fileIdToSend)
override fun deserialize(decoder: Decoder): FileId = FileId(decoder.decodeString()) override fun deserialize(decoder: Decoder): FileId = FileId(decoder.decodeString().removePrefix(attachPrefix))
} }
// TODO:: add checks for files size // TODO:: add checks for files size

View File

@ -1,6 +1,7 @@
package dev.inmo.tgbotapi.requests.send.media package dev.inmo.tgbotapi.requests.send.media
import dev.inmo.tgbotapi.requests.abstracts.* 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.abstracts.*
import dev.inmo.tgbotapi.requests.send.media.base.* import dev.inmo.tgbotapi.requests.send.media.base.*
import dev.inmo.tgbotapi.types.* import dev.inmo.tgbotapi.types.*
@ -22,7 +23,7 @@ import kotlinx.serialization.*
fun SendAnimation( fun SendAnimation(
chatId: ChatIdentifier, chatId: ChatIdentifier,
animation: InputFile, animation: InputFile,
thumb: InputFile? = null, thumbnail: InputFile? = null,
text: String? = null, text: String? = null,
parseMode: ParseMode? = null, parseMode: ParseMode? = null,
spoilered: Boolean = false, spoilered: Boolean = false,
@ -36,15 +37,13 @@ fun SendAnimation(
allowSendingWithoutReply: Boolean? = null, allowSendingWithoutReply: Boolean? = null,
replyMarkup: KeyboardMarkup? = null replyMarkup: KeyboardMarkup? = null
): Request<ContentMessage<AnimationContent>> { ): Request<ContentMessage<AnimationContent>> {
val animationAsFileId = (animation as? FileId) ?.fileId
val animationAsFile = animation as? MultipartFile val animationAsFile = animation as? MultipartFile
val thumbAsFileId = (thumb as? FileId) ?.fileId val thumbAsFile = thumbnail as? MultipartFile
val thumbAsFile = thumb as? MultipartFile
val data = SendAnimationData( val data = SendAnimationData(
chatId, chatId,
animationAsFileId, animation,
thumbAsFileId, thumbnail ?.fileId,
text, text,
parseMode, parseMode,
null, null,
@ -63,9 +62,9 @@ fun SendAnimation(
return if (animationAsFile == null && thumbAsFile == null) { return if (animationAsFile == null && thumbAsFile == null) {
data data
} else { } else {
MultipartRequestImpl( CommonMultipartFileRequest(
data, data,
SendAnimationFiles(animationAsFile, thumbAsFile) listOfNotNull(animationAsFile, thumbAsFile).associateBy { it.fileId }
) )
} }
} }
@ -73,7 +72,7 @@ fun SendAnimation(
fun SendAnimation( fun SendAnimation(
chatId: ChatIdentifier, chatId: ChatIdentifier,
animation: InputFile, animation: InputFile,
thumb: InputFile? = null, thumbnail: InputFile? = null,
entities: TextSourcesList, entities: TextSourcesList,
spoilered: Boolean = false, spoilered: Boolean = false,
duration: Long? = null, duration: Long? = null,
@ -86,15 +85,13 @@ fun SendAnimation(
allowSendingWithoutReply: Boolean? = null, allowSendingWithoutReply: Boolean? = null,
replyMarkup: KeyboardMarkup? = null replyMarkup: KeyboardMarkup? = null
): Request<ContentMessage<AnimationContent>> { ): Request<ContentMessage<AnimationContent>> {
val animationAsFileId = (animation as? FileId) ?.fileId
val animationAsFile = animation as? MultipartFile val animationAsFile = animation as? MultipartFile
val thumbAsFileId = (thumb as? FileId) ?.fileId val thumbAsFile = thumbnail as? MultipartFile
val thumbAsFile = thumb as? MultipartFile
val data = SendAnimationData( val data = SendAnimationData(
chatId, chatId,
animationAsFileId, animation,
thumbAsFileId, thumbnail ?.fileId,
entities.makeString(), entities.makeString(),
null, null,
entities.toRawMessageEntities(), entities.toRawMessageEntities(),
@ -113,9 +110,9 @@ fun SendAnimation(
return if (animationAsFile == null && thumbAsFile == null) { return if (animationAsFile == null && thumbAsFile == null) {
data data
} else { } else {
MultipartRequestImpl( CommonMultipartFileRequest(
data, data,
SendAnimationFiles(animationAsFile, thumbAsFile) listOfNotNull(animationAsFile, thumbAsFile).associateBy { it.fileId }
) )
} }
} }
@ -128,7 +125,7 @@ data class SendAnimationData internal constructor(
@SerialName(chatIdField) @SerialName(chatIdField)
override val chatId: ChatIdentifier, override val chatId: ChatIdentifier,
@SerialName(animationField) @SerialName(animationField)
val animation: String? = null, val animation: InputFile,
@SerialName(thumbnailField) @SerialName(thumbnailField)
override val thumbnail: String? = null, override val thumbnail: String? = null,
@SerialName(captionField) @SerialName(captionField)

View File

@ -2,6 +2,7 @@ package dev.inmo.tgbotapi.requests.send.media
import dev.inmo.tgbotapi.abstracts.Performerable import dev.inmo.tgbotapi.abstracts.Performerable
import dev.inmo.tgbotapi.requests.abstracts.* 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.abstracts.*
import dev.inmo.tgbotapi.requests.send.media.base.* import dev.inmo.tgbotapi.requests.send.media.base.*
import dev.inmo.tgbotapi.types.* import dev.inmo.tgbotapi.types.*
@ -23,7 +24,7 @@ import kotlinx.serialization.*
fun SendAudio( fun SendAudio(
chatId: ChatIdentifier, chatId: ChatIdentifier,
audio: InputFile, audio: InputFile,
thumb: InputFile? = null, thumbnail: InputFile? = null,
text: String? = null, text: String? = null,
parseMode: ParseMode? = null, parseMode: ParseMode? = null,
duration: Long? = null, duration: Long? = null,
@ -36,15 +37,13 @@ fun SendAudio(
allowSendingWithoutReply: Boolean? = null, allowSendingWithoutReply: Boolean? = null,
replyMarkup: KeyboardMarkup? = null replyMarkup: KeyboardMarkup? = null
): Request<ContentMessage<AudioContent>> { ): Request<ContentMessage<AudioContent>> {
val audioAsFileId = (audio as? FileId) ?.fileId
val audioAsFile = audio as? MultipartFile val audioAsFile = audio as? MultipartFile
val thumbAsFileId = (thumb as? FileId) ?.fileId val thumbAsFile = thumbnail as? MultipartFile
val thumbAsFile = thumb as? MultipartFile
val data = SendAudioData( val data = SendAudioData(
chatId, chatId,
audioAsFileId, audio,
thumbAsFileId, thumbnail ?.fileId,
text, text,
parseMode, parseMode,
null, null,
@ -62,9 +61,9 @@ fun SendAudio(
return if (audioAsFile == null && thumbAsFile == null) { return if (audioAsFile == null && thumbAsFile == null) {
data data
} else { } else {
MultipartRequestImpl( CommonMultipartFileRequest(
data, data,
SendAudioFiles(audioAsFile, thumbAsFile) listOfNotNull(audioAsFile, thumbAsFile).associateBy { it.fileId }
) )
} }
} }
@ -72,7 +71,7 @@ fun SendAudio(
fun SendAudio( fun SendAudio(
chatId: ChatIdentifier, chatId: ChatIdentifier,
audio: InputFile, audio: InputFile,
thumb: InputFile? = null, thumbnail: InputFile? = null,
entities: List<TextSource>, entities: List<TextSource>,
duration: Long? = null, duration: Long? = null,
performer: String? = null, performer: String? = null,
@ -84,15 +83,13 @@ fun SendAudio(
allowSendingWithoutReply: Boolean? = null, allowSendingWithoutReply: Boolean? = null,
replyMarkup: KeyboardMarkup? = null replyMarkup: KeyboardMarkup? = null
): Request<ContentMessage<AudioContent>> { ): Request<ContentMessage<AudioContent>> {
val audioAsFileId = (audio as? FileId) ?.fileId
val audioAsFile = audio as? MultipartFile val audioAsFile = audio as? MultipartFile
val thumbAsFileId = (thumb as? FileId) ?.fileId val thumbAsFile = thumbnail as? MultipartFile
val thumbAsFile = thumb as? MultipartFile
val data = SendAudioData( val data = SendAudioData(
chatId, chatId,
audioAsFileId, audio,
thumbAsFileId, thumbnail ?.fileId,
entities.makeString(), entities.makeString(),
null, null,
entities.toRawMessageEntities(), entities.toRawMessageEntities(),
@ -110,9 +107,9 @@ fun SendAudio(
return if (audioAsFile == null && thumbAsFile == null) { return if (audioAsFile == null && thumbAsFile == null) {
data data
} else { } else {
MultipartRequestImpl( CommonMultipartFileRequest(
data, data,
SendAudioFiles(audioAsFile, thumbAsFile) listOfNotNull(audioAsFile, thumbAsFile).associateBy { it.fileId }
) )
} }
} }
@ -125,7 +122,7 @@ data class SendAudioData internal constructor(
@SerialName(chatIdField) @SerialName(chatIdField)
override val chatId: ChatIdentifier, override val chatId: ChatIdentifier,
@SerialName(audioField) @SerialName(audioField)
val audio: String? = null, val audio: InputFile,
@SerialName(thumbnailField) @SerialName(thumbnailField)
override val thumbnail: String? = null, override val thumbnail: String? = null,
@SerialName(captionField) @SerialName(captionField)

View File

@ -1,6 +1,7 @@
package dev.inmo.tgbotapi.requests.send.media package dev.inmo.tgbotapi.requests.send.media
import dev.inmo.tgbotapi.requests.abstracts.* 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.abstracts.*
import dev.inmo.tgbotapi.requests.send.media.base.* import dev.inmo.tgbotapi.requests.send.media.base.*
import dev.inmo.tgbotapi.types.* import dev.inmo.tgbotapi.types.*
@ -31,7 +32,7 @@ import kotlinx.serialization.*
fun SendDocument( fun SendDocument(
chatId: ChatIdentifier, chatId: ChatIdentifier,
document: InputFile, document: InputFile,
thumb: InputFile? = null, thumbnail: InputFile? = null,
text: String? = null, text: String? = null,
parseMode: ParseMode? = null, parseMode: ParseMode? = null,
threadId: MessageThreadId? = chatId.threadId, threadId: MessageThreadId? = chatId.threadId,
@ -42,15 +43,13 @@ fun SendDocument(
replyMarkup: KeyboardMarkup? = null, replyMarkup: KeyboardMarkup? = null,
disableContentTypeDetection: Boolean? = null disableContentTypeDetection: Boolean? = null
): Request<ContentMessage<DocumentContent>> { ): Request<ContentMessage<DocumentContent>> {
val documentAsFileId = (document as? FileId) ?.fileId
val documentAsFile = document as? MultipartFile val documentAsFile = document as? MultipartFile
val thumbAsFileId = (thumb as? FileId) ?.fileId val thumbAsFile = thumbnail as? MultipartFile
val thumbAsFile = thumb as? MultipartFile
val data = SendDocumentData( val data = SendDocumentData(
chatId, chatId,
documentAsFileId, document,
thumbAsFileId, thumbnail ?.fileId,
text, text,
parseMode, parseMode,
null, null,
@ -66,9 +65,9 @@ fun SendDocument(
return if (documentAsFile == null && thumbAsFile == null) { return if (documentAsFile == null && thumbAsFile == null) {
data data
} else { } else {
MultipartRequestImpl( CommonMultipartFileRequest(
data, data,
SendDocumentFiles(documentAsFile, thumbAsFile) listOfNotNull(documentAsFile, thumbAsFile).associateBy { it.fileId }
) )
} }
} }
@ -85,7 +84,7 @@ fun SendDocument(
fun SendDocument( fun SendDocument(
chatId: ChatIdentifier, chatId: ChatIdentifier,
document: InputFile, document: InputFile,
thumb: InputFile? = null, thumbnail: InputFile? = null,
entities: TextSourcesList, entities: TextSourcesList,
threadId: MessageThreadId? = chatId.threadId, threadId: MessageThreadId? = chatId.threadId,
disableNotification: Boolean = false, disableNotification: Boolean = false,
@ -95,15 +94,13 @@ fun SendDocument(
replyMarkup: KeyboardMarkup? = null, replyMarkup: KeyboardMarkup? = null,
disableContentTypeDetection: Boolean? = null disableContentTypeDetection: Boolean? = null
): Request<ContentMessage<DocumentContent>> { ): Request<ContentMessage<DocumentContent>> {
val documentAsFileId = (document as? FileId) ?.fileId
val documentAsFile = document as? MultipartFile val documentAsFile = document as? MultipartFile
val thumbAsFileId = (thumb as? FileId) ?.fileId val thumbAsFile = thumbnail as? MultipartFile
val thumbAsFile = thumb as? MultipartFile
val data = SendDocumentData( val data = SendDocumentData(
chatId, chatId,
documentAsFileId, document,
thumbAsFileId, thumbnail ?.fileId,
entities.makeString(), entities.makeString(),
null, null,
entities.toRawMessageEntities(), entities.toRawMessageEntities(),
@ -119,9 +116,9 @@ fun SendDocument(
return if (documentAsFile == null && thumbAsFile == null) { return if (documentAsFile == null && thumbAsFile == null) {
data data
} else { } else {
MultipartRequestImpl( CommonMultipartFileRequest(
data, data,
SendDocumentFiles(documentAsFile, thumbAsFile) listOfNotNull(documentAsFile, thumbAsFile).associateBy { it.fileId }
) )
} }
} }
@ -143,7 +140,7 @@ data class SendDocumentData internal constructor(
@SerialName(chatIdField) @SerialName(chatIdField)
override val chatId: ChatIdentifier, override val chatId: ChatIdentifier,
@SerialName(documentField) @SerialName(documentField)
val document: String? = null, val document: InputFile,
@SerialName(thumbnailField) @SerialName(thumbnailField)
override val thumbnail: String? = null, override val thumbnail: String? = null,
@SerialName(captionField) @SerialName(captionField)

View File

@ -2,10 +2,12 @@ package dev.inmo.tgbotapi.requests.send.media
import dev.inmo.tgbotapi.requests.abstracts.MultipartFile import dev.inmo.tgbotapi.requests.abstracts.MultipartFile
import dev.inmo.tgbotapi.requests.abstracts.Request 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.abstracts.SendMessageRequest
import dev.inmo.tgbotapi.requests.send.media.base.* import dev.inmo.tgbotapi.requests.send.media.base.*
import dev.inmo.tgbotapi.types.* import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.media.* 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.PossiblySentViaBotCommonMessage
import dev.inmo.tgbotapi.types.message.abstracts.TelegramBotAPIMessageDeserializeOnlySerializerClass import dev.inmo.tgbotapi.types.message.abstracts.TelegramBotAPIMessageDeserializeOnlySerializerClass
import dev.inmo.tgbotapi.types.message.content.MediaGroupPartContent import dev.inmo.tgbotapi.types.message.content.MediaGroupPartContent
@ -37,7 +39,7 @@ fun <T : MediaGroupPartContent> SendMediaGroup(
protectContent: Boolean = false, protectContent: Boolean = false,
replyToMessageId: MessageId? = null, replyToMessageId: MessageId? = null,
allowSendingWithoutReply: Boolean? = null allowSendingWithoutReply: Boolean? = null
): Request<PossiblySentViaBotCommonMessage<MediaGroupContent<T>>> { ): Request<ContentMessage<MediaGroupContent<T>>> {
if (media.size !in mediaCountInMediaGroup) { if (media.size !in mediaCountInMediaGroup) {
throwRangeError("Count of members in media group", mediaCountInMediaGroup, media.size) throwRangeError("Count of members in media group", mediaCountInMediaGroup, media.size)
} }
@ -66,11 +68,11 @@ fun <T : MediaGroupPartContent> SendMediaGroup(
return (if (files.isEmpty()) { return (if (files.isEmpty()) {
data data
} else { } else {
MultipartRequestImpl( CommonMultipartFileRequest(
data, data,
SendMediaGroupFiles(files) files.associateBy { it.fileId }
) )
}) as Request<PossiblySentViaBotCommonMessage<MediaGroupContent<T>>> }) as Request<ContentMessage<MediaGroupContent<T>>>
} }
/** /**

View File

@ -1,6 +1,7 @@
package dev.inmo.tgbotapi.requests.send.media package dev.inmo.tgbotapi.requests.send.media
import dev.inmo.tgbotapi.requests.abstracts.* 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.abstracts.*
import dev.inmo.tgbotapi.requests.send.media.base.* import dev.inmo.tgbotapi.requests.send.media.base.*
import dev.inmo.tgbotapi.types.* import dev.inmo.tgbotapi.types.*
@ -33,7 +34,7 @@ fun SendPhoto(
): Request<ContentMessage<PhotoContent>> { ): Request<ContentMessage<PhotoContent>> {
val data = SendPhotoData( val data = SendPhotoData(
chatId, chatId,
(photo as? FileId) ?.fileId, photo,
text, text,
parseMode, parseMode,
null, null,
@ -45,12 +46,14 @@ fun SendPhoto(
allowSendingWithoutReply, allowSendingWithoutReply,
replyMarkup replyMarkup
) )
return data.photo ?.let { return if (photo is MultipartFile) {
CommonMultipartFileRequest(
data,
listOf(photo).associateBy { it.fileId }
)
} else {
data data
} ?: MultipartRequestImpl( }
data,
SendPhotoFiles(photo as MultipartFile)
)
} }
fun SendPhoto( fun SendPhoto(
@ -67,7 +70,7 @@ fun SendPhoto(
): Request<ContentMessage<PhotoContent>> { ): Request<ContentMessage<PhotoContent>> {
val data = SendPhotoData( val data = SendPhotoData(
chatId, chatId,
(photo as? FileId)?.fileId, photo,
entities.makeString(), entities.makeString(),
null, null,
entities.toRawMessageEntities(), entities.toRawMessageEntities(),
@ -79,12 +82,15 @@ fun SendPhoto(
allowSendingWithoutReply, allowSendingWithoutReply,
replyMarkup replyMarkup
) )
return data.photo ?.let {
return if (photo is MultipartFile) {
CommonMultipartFileRequest(
data,
listOf(photo).associateBy { it.fileId }
)
} else {
data data
} ?: MultipartRequestImpl( }
data,
SendPhotoFiles(photo as MultipartFile)
)
} }
private val commonResultDeserializer: DeserializationStrategy<ContentMessage<PhotoContent>> private val commonResultDeserializer: DeserializationStrategy<ContentMessage<PhotoContent>>
@ -95,7 +101,7 @@ data class SendPhotoData internal constructor(
@SerialName(chatIdField) @SerialName(chatIdField)
override val chatId: ChatIdentifier, override val chatId: ChatIdentifier,
@SerialName(photoField) @SerialName(photoField)
val photo: String? = null, val photo: InputFile,
@SerialName(captionField) @SerialName(captionField)
override val text: String? = null, override val text: String? = null,
@SerialName(parseModeField) @SerialName(parseModeField)

View File

@ -1,6 +1,7 @@
package dev.inmo.tgbotapi.requests.send.media package dev.inmo.tgbotapi.requests.send.media
import dev.inmo.tgbotapi.requests.abstracts.* 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.ReplyingMarkupSendMessageRequest
import dev.inmo.tgbotapi.requests.send.abstracts.SendMessageRequest import dev.inmo.tgbotapi.requests.send.abstracts.SendMessageRequest
import dev.inmo.tgbotapi.types.* import dev.inmo.tgbotapi.types.*
@ -28,7 +29,7 @@ fun SendSticker(
replyMarkup: KeyboardMarkup? = null replyMarkup: KeyboardMarkup? = null
): Request<ContentMessage<StickerContent>> = SendStickerByFileId( ): Request<ContentMessage<StickerContent>> = SendStickerByFileId(
chatId, chatId,
sticker as? FileId, sticker,
threadId, threadId,
disableNotification, disableNotification,
protectContent, protectContent,
@ -37,7 +38,10 @@ fun SendSticker(
replyMarkup replyMarkup
).let { ).let {
when (sticker) { when (sticker) {
is MultipartFile -> SendStickerByFile(it, sticker, emoji) is MultipartFile -> CommonMultipartFileRequest(
it,
listOf(sticker).associateBy { it.fileId }
)
is FileId -> it is FileId -> it
} }
} }
@ -50,7 +54,7 @@ data class SendStickerByFileId internal constructor(
@SerialName(chatIdField) @SerialName(chatIdField)
override val chatId: ChatIdentifier, override val chatId: ChatIdentifier,
@SerialName(stickerField) @SerialName(stickerField)
val sticker: FileId? = null, val sticker: InputFile,
@SerialName(messageThreadIdField) @SerialName(messageThreadIdField)
override val threadId: MessageThreadId? = chatId.threadId, override val threadId: MessageThreadId? = chatId.threadId,
@SerialName(disableNotificationField) @SerialName(disableNotificationField)
@ -70,20 +74,3 @@ data class SendStickerByFileId internal constructor(
override val requestSerializer: SerializationStrategy<*> override val requestSerializer: SerializationStrategy<*>
get() = serializer() 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())
)
}
}

View File

@ -1,6 +1,7 @@
package dev.inmo.tgbotapi.requests.send.media package dev.inmo.tgbotapi.requests.send.media
import dev.inmo.tgbotapi.requests.abstracts.* 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.abstracts.*
import dev.inmo.tgbotapi.requests.send.media.base.* import dev.inmo.tgbotapi.requests.send.media.base.*
import dev.inmo.tgbotapi.types.* import dev.inmo.tgbotapi.types.*
@ -22,7 +23,7 @@ import kotlinx.serialization.*
fun SendVideo( fun SendVideo(
chatId: ChatIdentifier, chatId: ChatIdentifier,
video: InputFile, video: InputFile,
thumb: InputFile? = null, thumbnail: InputFile? = null,
text: String? = null, text: String? = null,
parseMode: ParseMode? = null, parseMode: ParseMode? = null,
spoilered: Boolean = false, spoilered: Boolean = false,
@ -37,15 +38,13 @@ fun SendVideo(
allowSendingWithoutReply: Boolean? = null, allowSendingWithoutReply: Boolean? = null,
replyMarkup: KeyboardMarkup? = null replyMarkup: KeyboardMarkup? = null
): Request<ContentMessage<VideoContent>> { ): Request<ContentMessage<VideoContent>> {
val videoAsFileId = (video as? FileId) ?.fileId
val videoAsFile = video as? MultipartFile val videoAsFile = video as? MultipartFile
val thumbAsFileId = (thumb as? FileId) ?.fileId val thumbAsFile = thumbnail as? MultipartFile
val thumbAsFile = thumb as? MultipartFile
val data = SendVideoData( val data = SendVideoData(
chatId, chatId,
videoAsFileId, video,
thumbAsFileId, thumbnail ?.fileId,
text, text,
parseMode, parseMode,
null, null,
@ -65,9 +64,9 @@ fun SendVideo(
return if (videoAsFile == null && thumbAsFile == null) { return if (videoAsFile == null && thumbAsFile == null) {
data data
} else { } else {
MultipartRequestImpl( CommonMultipartFileRequest(
data, data,
SendVideoFiles(videoAsFile, thumbAsFile) listOfNotNull(videoAsFile, thumbAsFile).associateBy { it.fileId }
) )
} }
} }
@ -75,7 +74,7 @@ fun SendVideo(
fun SendVideo( fun SendVideo(
chatId: ChatIdentifier, chatId: ChatIdentifier,
video: InputFile, video: InputFile,
thumb: InputFile? = null, thumbnail: InputFile? = null,
entities: TextSourcesList, entities: TextSourcesList,
spoilered: Boolean = false, spoilered: Boolean = false,
duration: Long? = null, duration: Long? = null,
@ -89,15 +88,13 @@ fun SendVideo(
allowSendingWithoutReply: Boolean? = null, allowSendingWithoutReply: Boolean? = null,
replyMarkup: KeyboardMarkup? = null replyMarkup: KeyboardMarkup? = null
): Request<ContentMessage<VideoContent>> { ): Request<ContentMessage<VideoContent>> {
val videoAsFileId = (video as? FileId) ?.fileId
val videoAsFile = video as? MultipartFile val videoAsFile = video as? MultipartFile
val thumbAsFileId = (thumb as? FileId) ?.fileId val thumbAsFile = thumbnail as? MultipartFile
val thumbAsFile = thumb as? MultipartFile
val data = SendVideoData( val data = SendVideoData(
chatId, chatId,
videoAsFileId, video,
thumbAsFileId, thumbnail ?.fileId,
entities.makeString(), entities.makeString(),
null, null,
entities.toRawMessageEntities(), entities.toRawMessageEntities(),
@ -117,9 +114,9 @@ fun SendVideo(
return if (videoAsFile == null && thumbAsFile == null) { return if (videoAsFile == null && thumbAsFile == null) {
data data
} else { } else {
MultipartRequestImpl( CommonMultipartFileRequest(
data, data,
SendVideoFiles(videoAsFile, thumbAsFile) listOfNotNull(videoAsFile, thumbAsFile).associateBy { it.fileId }
) )
} }
} }
@ -132,7 +129,7 @@ data class SendVideoData internal constructor(
@SerialName(chatIdField) @SerialName(chatIdField)
override val chatId: ChatIdentifier, override val chatId: ChatIdentifier,
@SerialName(videoField) @SerialName(videoField)
val video: String? = null, val video: InputFile,
@SerialName(thumbnailField) @SerialName(thumbnailField)
override val thumbnail: String? = null, override val thumbnail: String? = null,
@SerialName(captionField) @SerialName(captionField)

View File

@ -1,6 +1,7 @@
package dev.inmo.tgbotapi.requests.send.media package dev.inmo.tgbotapi.requests.send.media
import dev.inmo.tgbotapi.requests.abstracts.* 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.abstracts.*
import dev.inmo.tgbotapi.requests.send.media.base.* import dev.inmo.tgbotapi.requests.send.media.base.*
import dev.inmo.tgbotapi.types.* import dev.inmo.tgbotapi.types.*
@ -14,7 +15,7 @@ import kotlinx.serialization.*
fun SendVideoNote( fun SendVideoNote(
chatId: ChatIdentifier, chatId: ChatIdentifier,
videoNote: InputFile, videoNote: InputFile,
thumb: InputFile? = null, thumbnail: InputFile? = null,
duration: Long? = null, duration: Long? = null,
size: Int? = null, // in documentation - length (size of video side) size: Int? = null, // in documentation - length (size of video side)
threadId: MessageThreadId? = chatId.threadId, threadId: MessageThreadId? = chatId.threadId,
@ -24,15 +25,13 @@ fun SendVideoNote(
allowSendingWithoutReply: Boolean? = null, allowSendingWithoutReply: Boolean? = null,
replyMarkup: KeyboardMarkup? = null replyMarkup: KeyboardMarkup? = null
): Request<ContentMessage<VideoNoteContent>> { ): Request<ContentMessage<VideoNoteContent>> {
val videoNoteAsFileId = (videoNote as? FileId) ?.fileId
val videoNoteAsFile = videoNote as? MultipartFile val videoNoteAsFile = videoNote as? MultipartFile
val thumbAsFileId = (thumb as? FileId) ?.fileId val thumbAsFile = thumbnail as? MultipartFile
val thumbAsFile = thumb as? MultipartFile
val data = SendVideoNoteData( val data = SendVideoNoteData(
chatId, chatId,
videoNoteAsFileId, videoNote,
thumbAsFileId, thumbnail ?.fileId,
duration, duration,
size, size,
threadId, threadId,
@ -46,9 +45,9 @@ fun SendVideoNote(
return if (videoNoteAsFile == null && thumbAsFile == null) { return if (videoNoteAsFile == null && thumbAsFile == null) {
data data
} else { } else {
MultipartRequestImpl( CommonMultipartFileRequest(
data, data,
SendVideoNoteFiles(videoNoteAsFile, thumbAsFile) listOfNotNull(videoNoteAsFile, thumbAsFile).associateBy { it.fileId }
) )
} }
} }
@ -61,7 +60,7 @@ data class SendVideoNoteData internal constructor(
@SerialName(chatIdField) @SerialName(chatIdField)
override val chatId: ChatIdentifier, override val chatId: ChatIdentifier,
@SerialName(videoNoteField) @SerialName(videoNoteField)
val videoNote: String? = null, val videoNote: InputFile,
@SerialName(thumbnailField) @SerialName(thumbnailField)
override val thumbnail: String? = null, override val thumbnail: String? = null,
@SerialName(durationField) @SerialName(durationField)

View File

@ -1,6 +1,7 @@
package dev.inmo.tgbotapi.requests.send.media package dev.inmo.tgbotapi.requests.send.media
import dev.inmo.tgbotapi.requests.abstracts.* 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.abstracts.*
import dev.inmo.tgbotapi.requests.send.media.base.* import dev.inmo.tgbotapi.requests.send.media.base.*
import dev.inmo.tgbotapi.types.* import dev.inmo.tgbotapi.types.*
@ -32,12 +33,11 @@ fun SendVoice(
allowSendingWithoutReply: Boolean? = null, allowSendingWithoutReply: Boolean? = null,
replyMarkup: KeyboardMarkup? = null replyMarkup: KeyboardMarkup? = null
): Request<ContentMessage<VoiceContent>> { ): Request<ContentMessage<VoiceContent>> {
val voiceAsFileId = (voice as? FileId) ?.fileId
val voiceAsFile = voice as? MultipartFile val voiceAsFile = voice as? MultipartFile
val data = SendVoiceData( val data = SendVoiceData(
chatId, chatId,
voiceAsFileId, voice,
text, text,
parseMode, parseMode,
null, null,
@ -53,9 +53,9 @@ fun SendVoice(
return if (voiceAsFile == null) { return if (voiceAsFile == null) {
data data
} else { } else {
MultipartRequestImpl( CommonMultipartFileRequest(
data, data,
SendVoiceFiles(voiceAsFile) listOfNotNull(voiceAsFile).associateBy { it.fileId }
) )
} }
} }
@ -72,12 +72,11 @@ fun SendVoice(
allowSendingWithoutReply: Boolean? = null, allowSendingWithoutReply: Boolean? = null,
replyMarkup: KeyboardMarkup? = null replyMarkup: KeyboardMarkup? = null
): Request<ContentMessage<VoiceContent>> { ): Request<ContentMessage<VoiceContent>> {
val voiceAsFileId = (voice as? FileId) ?.fileId
val voiceAsFile = voice as? MultipartFile val voiceAsFile = voice as? MultipartFile
val data = SendVoiceData( val data = SendVoiceData(
chatId, chatId,
voiceAsFileId, voice,
entities.makeString(), entities.makeString(),
null, null,
entities.toRawMessageEntities(), entities.toRawMessageEntities(),
@ -93,9 +92,9 @@ fun SendVoice(
return if (voiceAsFile == null) { return if (voiceAsFile == null) {
data data
} else { } else {
MultipartRequestImpl( CommonMultipartFileRequest(
data, data,
SendVoiceFiles(voiceAsFile) listOfNotNull(voiceAsFile).associateBy { it.fileId }
) )
} }
} }
@ -108,7 +107,7 @@ data class SendVoiceData internal constructor(
@SerialName(chatIdField) @SerialName(chatIdField)
override val chatId: ChatIdentifier, override val chatId: ChatIdentifier,
@SerialName(voiceField) @SerialName(voiceField)
val voice: String? = null, val voice: InputFile,
@SerialName(captionField) @SerialName(captionField)
override val text: String? = null, override val text: String? = null,
@SerialName(parseModeField) @SerialName(parseModeField)

View File

@ -1,11 +1,15 @@
package dev.inmo.tgbotapi.requests.stickers 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.abstracts.*
import dev.inmo.tgbotapi.requests.common.CommonMultipartFileRequest import dev.inmo.tgbotapi.requests.common.CommonMultipartFileRequest
import dev.inmo.tgbotapi.requests.stickers.abstracts.CreateStickerSetAction import dev.inmo.tgbotapi.requests.stickers.abstracts.CreateStickerSetAction
import dev.inmo.tgbotapi.types.* import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.stickers.MaskPosition import dev.inmo.tgbotapi.types.stickers.MaskPosition
import kotlinx.serialization.* 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] * 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.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>()) 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()) { return if (multipartParts.isNotEmpty()) {
CommonMultipartFileRequest( when (data) { // cratch for exact determining of common multipart data type
data, is CreateNewStickerSet.CustomEmoji -> CommonMultipartFileRequest(
multipartParts.associateBy { it.fileId } data,
) multipartParts.associateBy { it.fileId }
)
is CreateNewStickerSet.Mask -> CommonMultipartFileRequest(
data,
multipartParts.associateBy { it.fileId }
)
is CreateNewStickerSet.Regular -> CommonMultipartFileRequest(
data,
multipartParts.associateBy { it.fileId }
)
}
} else { } else {
data data
} }
} }
@Serializable @Serializable(CreateNewStickerSetSerializer::class)
sealed interface CreateNewStickerSet : CreateStickerSetAction { sealed interface CreateNewStickerSet : CreateStickerSetAction {
val stickerType: StickerType val stickerType: StickerType
val stickers: List<InputSticker> val stickers: List<InputSticker>
@ -101,4 +117,70 @@ sealed interface CreateNewStickerSet : CreateStickerSetAction {
override val stickerType: StickerType override val stickerType: StickerType
get() = StickerType.CustomEmoji 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}")
}
}
)

View File

@ -1,17 +1,20 @@
package dev.inmo.tgbotapi.requests.stickers 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.requests.abstracts.InputFile
import dev.inmo.tgbotapi.types.StickerType
import dev.inmo.tgbotapi.types.emojiListField import dev.inmo.tgbotapi.types.emojiListField
import dev.inmo.tgbotapi.types.keywordsField import dev.inmo.tgbotapi.types.keywordsField
import dev.inmo.tgbotapi.types.maskPositionField import dev.inmo.tgbotapi.types.maskPositionField
import dev.inmo.tgbotapi.types.stickerField import dev.inmo.tgbotapi.types.stickerField
import dev.inmo.tgbotapi.types.stickers.MaskPosition import dev.inmo.tgbotapi.types.stickers.MaskPosition
import dev.inmo.tgbotapi.utils.internal.ClassCastsIncluded import dev.inmo.tgbotapi.utils.internal.ClassCastsIncluded
import kotlinx.serialization.KSerializer
import kotlinx.serialization.SerialName import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
@ClassCastsIncluded @ClassCastsIncluded
@Serializable @Serializable(InputStickerSerializer::class)
sealed interface InputSticker { sealed interface InputSticker {
val sticker: InputFile val sticker: InputFile
val emojisList: List<String> val emojisList: List<String>
@ -51,3 +54,69 @@ sealed interface InputSticker {
) : WithKeywords ) : 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()
)
}

View File

@ -118,6 +118,18 @@ sealed interface MediaCollectionContent<T: TelegramMediaFile>: MessageContent, M
sealed interface MediaContent: MessageContent { sealed interface MediaContent: MessageContent {
val media: TelegramMediaFile val media: TelegramMediaFile
fun asTelegramMedia(): TelegramMedia 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 sealed interface SpoilerableMediaContent : MediaContent, SpoilerableData

View File

@ -9,6 +9,7 @@ import dev.inmo.tgbotapi.types.MessageThreadId
import dev.inmo.tgbotapi.types.buttons.KeyboardMarkup import dev.inmo.tgbotapi.types.buttons.KeyboardMarkup
import dev.inmo.tgbotapi.types.files.TelegramMediaFile import dev.inmo.tgbotapi.types.files.TelegramMediaFile
import dev.inmo.tgbotapi.types.media.TelegramMedia 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.abstracts.Message
import dev.inmo.tgbotapi.types.message.textsources.TextSource import dev.inmo.tgbotapi.types.message.textsources.TextSource
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
@ -38,7 +39,7 @@ data class MediaGroupContent<T : MediaGroupPartContent>(
replyToMessageId: MessageId?, replyToMessageId: MessageId?,
allowSendingWithoutReply: Boolean?, allowSendingWithoutReply: Boolean?,
replyMarkup: KeyboardMarkup? replyMarkup: KeyboardMarkup?
): Request<out Message> = SendMediaGroup<MediaGroupPartContent>( ): Request<ContentMessage<MediaGroupContent<MediaGroupPartContent>>> = SendMediaGroup<MediaGroupPartContent>(
chatId, chatId,
group.map { it.content.toMediaGroupMemberTelegramMedia() }, group.map { it.content.toMediaGroupMemberTelegramMedia() },
threadId, threadId,