From c0e81b1d6dc26b7d0b652bddff7163514f657d2a Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Thu, 5 Nov 2020 16:53:26 +0600 Subject: [PATCH] partially complete rewriting of things according to #189 --- .../tgbotapi/CommonAbstracts/Explained.kt | 8 ++- .../tgbotapi/CommonAbstracts/TextSource.kt | 1 + .../inmo/tgbotapi/CommonAbstracts/Texted.kt | 32 +++++++++ .../edit/abstracts/EditTextChatMessage.kt | 7 +- .../edit/caption/EditChatMessageCaption.kt | 40 ++++++++++- .../edit/caption/EditInlineMessageCaption.kt | 37 +++++++++- .../requests/edit/text/EditChatMessageText.kt | 44 +++++++++++- .../edit/text/EditInlineMessageText.kt | 41 ++++++++++- .../tgbotapi/requests/send/SendMessage.kt | 49 ++++++++++++- .../abstracts/TextableSendMessageRequest.kt | 7 +- .../requests/send/media/SendAnimation.kt | 53 ++++++++++++++ .../tgbotapi/requests/send/media/SendAudio.kt | 54 +++++++++++++- .../requests/send/media/SendDocument.kt | 58 +++++++++++++++ .../tgbotapi/requests/send/media/SendPhoto.kt | 37 ++++++++++ .../tgbotapi/requests/send/media/SendVideo.kt | 55 +++++++++++++++ .../requests/send/media/SendVideoNote.kt | 17 ----- .../tgbotapi/requests/send/media/SendVoice.kt | 45 ++++++++++++ .../tgbotapi/requests/send/polls/SendPoll.kt | 70 ++++++++++++++++++- .../kotlin/dev/inmo/tgbotapi/types/Common.kt | 2 + .../types/InputMedia/InputMediaAnimation.kt | 42 +++++++++-- .../types/InputMedia/InputMediaAudio.kt | 43 ++++++++++-- .../types/InputMedia/InputMediaDocument.kt | 35 ++++++++-- .../types/InputMedia/InputMediaPhoto.kt | 29 ++++++-- .../types/InputMedia/InputMediaVideo.kt | 35 +++++++++- .../InputMedia/MediaGroupMemberInputMedia.kt | 6 +- .../types/MessageEntity/RawMessageEntity.kt | 17 ++++- 26 files changed, 800 insertions(+), 64 deletions(-) create mode 100644 tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/CommonAbstracts/Texted.kt diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/CommonAbstracts/Explained.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/CommonAbstracts/Explained.kt index ef79db3bb2..dd1e659658 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/CommonAbstracts/Explained.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/CommonAbstracts/Explained.kt @@ -7,10 +7,16 @@ interface Explained { val explanation: String? } -interface ExplainedOutput : Explained { +interface ParsableExplainedOutput : Explained { val parseMode: ParseMode? } +interface EntitiesExplainedOutput : Explained { + val entities: List? +} + +interface ExplainedOutput : ParsableExplainedOutput, EntitiesExplainedOutput + interface ExplainedInput : Explained { /** * Not full list of entities. This list WILL NOT contain [TextPart]s with [dev.inmo.tgbotapi.types.MessageEntity.textsources.RegularTextSource] diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/CommonAbstracts/TextSource.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/CommonAbstracts/TextSource.kt index 95bbd565b8..c652a3aac8 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/CommonAbstracts/TextSource.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/CommonAbstracts/TextSource.kt @@ -21,3 +21,4 @@ data class TextPart( ) fun List.justTextSources() = map { it.source } +fun List.makeString() = joinToString("") { it.source } diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/CommonAbstracts/Texted.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/CommonAbstracts/Texted.kt new file mode 100644 index 0000000000..b28b796591 --- /dev/null +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/CommonAbstracts/Texted.kt @@ -0,0 +1,32 @@ +package dev.inmo.tgbotapi.CommonAbstracts + +import dev.inmo.tgbotapi.types.ParseMode.ParseMode +import dev.inmo.tgbotapi.utils.fullListOfSubSource + +interface Texted { + val text: String? +} + +interface ParsableOutput : Texted { + val parseMode: ParseMode? +} + +interface EntitiesOutput : Texted { + val entities: List? +} + +interface TextedOutput : ParsableOutput, EntitiesOutput + +interface TextedInput : Texted { + /** + * Not full list of entities. This list WILL NOT contain [TextPart]s with [dev.inmo.tgbotapi.types.MessageEntity.textsources.RegularTextSource] + * @see [CaptionedInput.fullEntitiesList] + */ + val textEntities: List +} + +/** + * Convert its [TextedInput.textEntities] to list of [dev.inmo.tgbotapi.CommonAbstracts.TextSource] + * with [dev.inmo.tgbotapi.types.MessageEntity.textsources.RegularTextSource] + */ +fun TextedInput.fullEntitiesList(): FullTextSourcesList = text ?.fullListOfSubSource(textEntities) ?.map { it.source } ?: emptyList() diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/edit/abstracts/EditTextChatMessage.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/edit/abstracts/EditTextChatMessage.kt index 0c09216c1f..286695eaa3 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/edit/abstracts/EditTextChatMessage.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/edit/abstracts/EditTextChatMessage.kt @@ -1,8 +1,7 @@ package dev.inmo.tgbotapi.requests.edit.abstracts -import dev.inmo.tgbotapi.types.ParseMode.ParseMode +import dev.inmo.tgbotapi.CommonAbstracts.TextedOutput -interface EditTextChatMessage { - val text: String - val parseMode: ParseMode? +interface EditTextChatMessage : TextedOutput { + override val text: String } \ No newline at end of file diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/edit/caption/EditChatMessageCaption.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/edit/caption/EditChatMessageCaption.kt index ac53971139..9317cb1755 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/edit/caption/EditChatMessageCaption.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/edit/caption/EditChatMessageCaption.kt @@ -1,8 +1,12 @@ package dev.inmo.tgbotapi.requests.edit.caption +import dev.inmo.tgbotapi.CommonAbstracts.* import dev.inmo.tgbotapi.requests.edit.abstracts.* import dev.inmo.tgbotapi.requests.edit.media.MediaContentMessageResultDeserializer import dev.inmo.tgbotapi.types.* +import dev.inmo.tgbotapi.types.MessageEntity.* +import dev.inmo.tgbotapi.types.MessageEntity.RawMessageEntity +import dev.inmo.tgbotapi.types.MessageEntity.asTextParts import dev.inmo.tgbotapi.types.ParseMode.ParseMode import dev.inmo.tgbotapi.types.ParseMode.parseModeField import dev.inmo.tgbotapi.types.buttons.InlineKeyboardMarkup @@ -12,8 +16,37 @@ import kotlinx.serialization.* const val editMessageCaptionMethod = "editMessageCaption" +fun EditChatMessageCaption( + chatId: ChatIdentifier, + messageId: MessageIdentifier, + text: String, + parseMode: ParseMode? = null, + replyMarkup: InlineKeyboardMarkup? = null +) = EditChatMessageCaption( + chatId, + messageId, + text, + parseMode, + null, + replyMarkup +) + +fun EditChatMessageCaption( + chatId: ChatIdentifier, + messageId: MessageIdentifier, + entities: List, + replyMarkup: InlineKeyboardMarkup? = null +) = EditChatMessageCaption( + chatId, + messageId, + entities.makeString(), + null, + entities.toRawMessageEntities(), + replyMarkup +) + @Serializable -data class EditChatMessageCaption( +data class EditChatMessageCaption internal constructor( @SerialName(chatIdField) override val chatId: ChatIdentifier, @SerialName(messageIdField) @@ -22,9 +55,14 @@ data class EditChatMessageCaption( override val text: String, @SerialName(parseModeField) override val parseMode: ParseMode? = null, + @SerialName(captionEntitiesField) + private val rawEntities: List? = null, @SerialName(replyMarkupField) override val replyMarkup: InlineKeyboardMarkup? = null ) : EditChatMessage, EditTextChatMessage, EditReplyMessage { + override val entities: List? by lazy { + rawEntities ?.asTextParts(text) ?.justTextSources() + } override fun method(): String = editMessageCaptionMethod override val resultDeserializer: DeserializationStrategy> diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/edit/caption/EditInlineMessageCaption.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/edit/caption/EditInlineMessageCaption.kt index 4cd418ab54..4603e9a7a3 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/edit/caption/EditInlineMessageCaption.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/edit/caption/EditInlineMessageCaption.kt @@ -1,23 +1,58 @@ package dev.inmo.tgbotapi.requests.edit.caption +import dev.inmo.tgbotapi.CommonAbstracts.* import dev.inmo.tgbotapi.requests.edit.abstracts.* import dev.inmo.tgbotapi.types.* +import dev.inmo.tgbotapi.types.MessageEntity.* +import dev.inmo.tgbotapi.types.MessageEntity.RawMessageEntity +import dev.inmo.tgbotapi.types.MessageEntity.asTextParts import dev.inmo.tgbotapi.types.ParseMode.ParseMode import dev.inmo.tgbotapi.types.ParseMode.parseModeField import dev.inmo.tgbotapi.types.buttons.InlineKeyboardMarkup import kotlinx.serialization.* +fun EditInlineMessageCaption( + inlineMessageId: InlineMessageIdentifier, + text: String, + parseMode: ParseMode? = null, + replyMarkup: InlineKeyboardMarkup? = null +) = EditInlineMessageCaption( + inlineMessageId, + text, + parseMode, + null, + replyMarkup +) + +fun EditInlineMessageCaption( + inlineMessageId: InlineMessageIdentifier, + entities: List, + replyMarkup: InlineKeyboardMarkup? = null +) = EditInlineMessageCaption( + inlineMessageId, + entities.makeString(), + null, + entities.toRawMessageEntities(), + replyMarkup +) + @Serializable -data class EditInlineMessageCaption( +data class EditInlineMessageCaption internal constructor( @SerialName(inlineMessageIdField) override val inlineMessageId: InlineMessageIdentifier, @SerialName(captionField) override val text: String, @SerialName(parseModeField) override val parseMode: ParseMode? = null, + @SerialName(captionEntitiesField) + private val rawEntities: List? = null, @SerialName(replyMarkupField) override val replyMarkup: InlineKeyboardMarkup? = null ) : EditInlineMessage, EditTextChatMessage, EditReplyMessage { + override val entities: List? by lazy { + rawEntities ?.asTextParts(text) ?.justTextSources() + } + override fun method(): String = editMessageCaptionMethod override val requestSerializer: SerializationStrategy<*> get() = serializer() diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/edit/text/EditChatMessageText.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/edit/text/EditChatMessageText.kt index b327d18645..873fdc567c 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/edit/text/EditChatMessageText.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/edit/text/EditChatMessageText.kt @@ -1,8 +1,12 @@ package dev.inmo.tgbotapi.requests.edit.text +import dev.inmo.tgbotapi.CommonAbstracts.* import dev.inmo.tgbotapi.requests.edit.abstracts.* import dev.inmo.tgbotapi.requests.send.TextContentMessageResultDeserializer import dev.inmo.tgbotapi.types.* +import dev.inmo.tgbotapi.types.MessageEntity.* +import dev.inmo.tgbotapi.types.MessageEntity.RawMessageEntity +import dev.inmo.tgbotapi.types.MessageEntity.toRawMessageEntities import dev.inmo.tgbotapi.types.ParseMode.ParseMode import dev.inmo.tgbotapi.types.ParseMode.parseModeField import dev.inmo.tgbotapi.types.buttons.InlineKeyboardMarkup @@ -12,8 +16,41 @@ import kotlinx.serialization.* const val editMessageTextMethod = "editMessageText" +fun EditChatMessageText( + chatId: ChatIdentifier, + messageId: MessageIdentifier, + text: String, + parseMode: ParseMode? = null, + disableWebPagePreview: Boolean? = null, + replyMarkup: InlineKeyboardMarkup? = null +) = EditChatMessageText( + chatId, + messageId, + text, + parseMode, + null, + disableWebPagePreview, + replyMarkup +) + +fun EditChatMessageText( + chatId: ChatIdentifier, + messageId: MessageIdentifier, + entities: List, + disableWebPagePreview: Boolean? = null, + replyMarkup: InlineKeyboardMarkup? = null +) = EditChatMessageText( + chatId, + messageId, + entities.makeString(), + null, + entities.toRawMessageEntities(), + disableWebPagePreview, + replyMarkup +) + @Serializable -data class EditChatMessageText( +data class EditChatMessageText internal constructor( @SerialName(chatIdField) override val chatId: ChatIdentifier, @SerialName(messageIdField) @@ -22,11 +59,16 @@ data class EditChatMessageText( override val text: String, @SerialName(parseModeField) override val parseMode: ParseMode? = null, + @SerialName(entitiesField) + private val rawEntities: List? = null, @SerialName(disableWebPagePreviewField) override val disableWebPagePreview: Boolean? = null, @SerialName(replyMarkupField) override val replyMarkup: InlineKeyboardMarkup? = null ) : EditChatMessage, EditTextChatMessage, EditReplyMessage, EditDisableWebPagePreviewMessage { + override val entities: List? by lazy { + rawEntities ?.asTextParts(text) ?.justTextSources() + } override fun method(): String = editMessageTextMethod override val resultDeserializer: DeserializationStrategy> diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/edit/text/EditInlineMessageText.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/edit/text/EditInlineMessageText.kt index 00a714fa55..1b9ea92c95 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/edit/text/EditInlineMessageText.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/edit/text/EditInlineMessageText.kt @@ -1,26 +1,65 @@ package dev.inmo.tgbotapi.requests.edit.text +import dev.inmo.tgbotapi.CommonAbstracts.* import dev.inmo.tgbotapi.requests.edit.abstracts.* import dev.inmo.tgbotapi.requests.edit.media.editMessageMediaMethod import dev.inmo.tgbotapi.types.* +import dev.inmo.tgbotapi.types.MessageEntity.* +import dev.inmo.tgbotapi.types.MessageEntity.RawMessageEntity +import dev.inmo.tgbotapi.types.MessageEntity.toRawMessageEntities import dev.inmo.tgbotapi.types.ParseMode.ParseMode import dev.inmo.tgbotapi.types.ParseMode.parseModeField import dev.inmo.tgbotapi.types.buttons.InlineKeyboardMarkup import kotlinx.serialization.* +fun EditInlineMessageText( + inlineMessageId: InlineMessageIdentifier, + text: String, + parseMode: ParseMode? = null, + disableWebPagePreview: Boolean? = null, + replyMarkup: InlineKeyboardMarkup? = null +) = EditInlineMessageText( + inlineMessageId, + text, + parseMode, + null, + disableWebPagePreview, + replyMarkup +) + +fun EditInlineMessageText( + inlineMessageId: InlineMessageIdentifier, + entities: List, + disableWebPagePreview: Boolean? = null, + replyMarkup: InlineKeyboardMarkup? = null +) = EditInlineMessageText( + inlineMessageId, + entities.makeString(), + null, + entities.toRawMessageEntities(), + disableWebPagePreview, + replyMarkup +) + @Serializable -data class EditInlineMessageText( +data class EditInlineMessageText internal constructor( @SerialName(inlineMessageIdField) override val inlineMessageId: InlineMessageIdentifier, @SerialName(textField) override val text: String, @SerialName(parseModeField) override val parseMode: ParseMode? = null, + @SerialName(entitiesField) + private val rawEntities: List? = null, @SerialName(disableWebPagePreviewField) override val disableWebPagePreview: Boolean? = null, @SerialName(replyMarkupField) override val replyMarkup: InlineKeyboardMarkup? = null ) : EditInlineMessage, EditTextChatMessage, EditReplyMessage, EditDisableWebPagePreviewMessage { + override val entities: List? by lazy { + rawEntities ?.asTextParts(text ?: return@lazy null) ?.justTextSources() + } + override fun method(): String = editMessageMediaMethod override val requestSerializer: SerializationStrategy<*> get() = serializer() diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/send/SendMessage.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/send/SendMessage.kt index f6b8ef20e0..4a87e596c6 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/send/SendMessage.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/send/SendMessage.kt @@ -1,8 +1,12 @@ package dev.inmo.tgbotapi.requests.send +import dev.inmo.tgbotapi.CommonAbstracts.* import dev.inmo.tgbotapi.CommonAbstracts.types.DisableWebPagePreview import dev.inmo.tgbotapi.requests.send.abstracts.* import dev.inmo.tgbotapi.types.* +import dev.inmo.tgbotapi.types.MessageEntity.* +import dev.inmo.tgbotapi.types.MessageEntity.RawMessageEntity +import dev.inmo.tgbotapi.types.MessageEntity.asTextParts import dev.inmo.tgbotapi.types.ParseMode.ParseMode import dev.inmo.tgbotapi.types.ParseMode.parseModeField import dev.inmo.tgbotapi.types.buttons.KeyboardMarkup @@ -15,14 +19,53 @@ import kotlinx.serialization.* internal val TextContentMessageResultDeserializer: DeserializationStrategy> = TelegramBotAPIMessageDeserializationStrategyClass() +fun SendTextMessage( + chatId: ChatIdentifier, + text: String, + parseMode: ParseMode? = null, + disableWebPagePreview: Boolean? = null, + disableNotification: Boolean = false, + replyToMessageId: MessageIdentifier? = null, + replyMarkup: KeyboardMarkup? = null +) = SendTextMessage( + chatId, + text, + parseMode, + null, + disableWebPagePreview, + disableNotification, + replyToMessageId, + replyMarkup +) + +fun SendTextMessage( + chatId: ChatIdentifier, + entities: List, + disableWebPagePreview: Boolean? = null, + disableNotification: Boolean = false, + replyToMessageId: MessageIdentifier? = null, + replyMarkup: KeyboardMarkup? = null +) = SendTextMessage( + chatId, + entities.makeString(), + null, + entities.toRawMessageEntities(), + disableWebPagePreview, + disableNotification, + replyToMessageId, + replyMarkup +) + @Serializable -data class SendTextMessage( +data class SendTextMessage internal constructor( @SerialName(chatIdField) override val chatId: ChatIdentifier, @SerialName(textField) override val text: String, @SerialName(parseModeField) override val parseMode: ParseMode? = null, + @SerialName(entitiesField) + private val rawEntities: List? = null, @SerialName(disableWebPagePreviewField) override val disableWebPagePreview: Boolean? = null, @SerialName(disableNotificationField) @@ -36,6 +79,10 @@ data class SendTextMessage( TextableSendMessageRequest>, DisableWebPagePreview { + override val entities: List? by lazy { + rawEntities ?.asTextParts(text) ?.justTextSources() + } + init { if (text.length !in textLength) { throwRangeError("Text length", textLength, text.length) diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/send/abstracts/TextableSendMessageRequest.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/send/abstracts/TextableSendMessageRequest.kt index 078c94f326..e77f2d321d 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/send/abstracts/TextableSendMessageRequest.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/send/abstracts/TextableSendMessageRequest.kt @@ -1,8 +1,5 @@ package dev.inmo.tgbotapi.requests.send.abstracts -import dev.inmo.tgbotapi.types.ParseMode.ParseMode +import dev.inmo.tgbotapi.CommonAbstracts.TextedOutput -interface TextableSendMessageRequest: SendMessageRequest { - val text: String? - val parseMode: ParseMode? -} \ No newline at end of file +interface TextableSendMessageRequest: SendMessageRequest, TextedOutput diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/send/media/SendAnimation.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/send/media/SendAnimation.kt index de4578c8d0..012d556ec6 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/send/media/SendAnimation.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/send/media/SendAnimation.kt @@ -1,9 +1,13 @@ package dev.inmo.tgbotapi.requests.send.media +import dev.inmo.tgbotapi.CommonAbstracts.* import dev.inmo.tgbotapi.requests.abstracts.* import dev.inmo.tgbotapi.requests.send.abstracts.* import dev.inmo.tgbotapi.requests.send.media.base.* import dev.inmo.tgbotapi.types.* +import dev.inmo.tgbotapi.types.MessageEntity.* +import dev.inmo.tgbotapi.types.MessageEntity.RawMessageEntity +import dev.inmo.tgbotapi.types.MessageEntity.asTextParts import dev.inmo.tgbotapi.types.ParseMode.ParseMode import dev.inmo.tgbotapi.types.ParseMode.parseModeField import dev.inmo.tgbotapi.types.buttons.KeyboardMarkup @@ -38,6 +42,49 @@ fun SendAnimation( thumbAsFileId, caption, parseMode, + null, + duration, + width, + height, + disableNotification, + replyToMessageId, + replyMarkup + ) + + return if (animationAsFile == null && thumbAsFile == null) { + data + } else { + MultipartRequestImpl( + data, + SendAnimationFiles(animationAsFile, thumbAsFile) + ) + } +} + +fun SendAnimation( + chatId: ChatIdentifier, + animation: InputFile, + thumb: InputFile? = null, + entities: List, + duration: Long? = null, + width: Int? = null, + height: Int? = null, + disableNotification: Boolean = false, + replyToMessageId: MessageIdentifier? = null, + replyMarkup: KeyboardMarkup? = null +): Request> { + val animationAsFileId = (animation as? FileId) ?.fileId + val animationAsFile = animation as? MultipartFile + val thumbAsFileId = (thumb as? FileId) ?.fileId + val thumbAsFile = thumb as? MultipartFile + + val data = SendAnimationData( + chatId, + animationAsFileId, + thumbAsFileId, + entities.makeString(), + null, + entities.toRawMessageEntities(), duration, width, height, @@ -71,6 +118,8 @@ data class SendAnimationData internal constructor( override val text: String? = null, @SerialName(parseModeField) override val parseMode: ParseMode? = null, + @SerialName(captionEntitiesField) + private val rawEntities: List? = null, @SerialName(durationField) override val duration: Long? = null, @SerialName(widthField) @@ -91,6 +140,10 @@ data class SendAnimationData internal constructor( DuratedSendMessageRequest>, SizedSendMessageRequest> { + override val entities: List? by lazy { + rawEntities ?.asTextParts(text ?: return@lazy null) ?.justTextSources() + } + init { text ?.let { if (it.length !in captionLength) { diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/send/media/SendAudio.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/send/media/SendAudio.kt index dd06aa2faf..4dce2c6736 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/send/media/SendAudio.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/send/media/SendAudio.kt @@ -1,10 +1,13 @@ package dev.inmo.tgbotapi.requests.send.media -import dev.inmo.tgbotapi.CommonAbstracts.Performerable +import dev.inmo.tgbotapi.CommonAbstracts.* import dev.inmo.tgbotapi.requests.abstracts.* import dev.inmo.tgbotapi.requests.send.abstracts.* import dev.inmo.tgbotapi.requests.send.media.base.* import dev.inmo.tgbotapi.types.* +import dev.inmo.tgbotapi.types.MessageEntity.* +import dev.inmo.tgbotapi.types.MessageEntity.RawMessageEntity +import dev.inmo.tgbotapi.types.MessageEntity.toRawMessageEntities import dev.inmo.tgbotapi.types.ParseMode.ParseMode import dev.inmo.tgbotapi.types.ParseMode.parseModeField import dev.inmo.tgbotapi.types.buttons.KeyboardMarkup @@ -39,6 +42,49 @@ fun SendAudio( thumbAsFileId, caption, parseMode, + null, + duration, + performer, + title, + disableNotification, + replyToMessageId, + replyMarkup + ) + + return if (audioAsFile == null && thumbAsFile == null) { + data + } else { + MultipartRequestImpl( + data, + SendAudioFiles(audioAsFile, thumbAsFile) + ) + } +} + +fun SendAudio( + chatId: ChatIdentifier, + audio: InputFile, + thumb: InputFile? = null, + entities: List, + duration: Long? = null, + performer: String? = null, + title: String? = null, + disableNotification: Boolean = false, + replyToMessageId: MessageIdentifier? = null, + replyMarkup: KeyboardMarkup? = null +): Request> { + val audioAsFileId = (audio as? FileId) ?.fileId + val audioAsFile = audio as? MultipartFile + val thumbAsFileId = (thumb as? FileId) ?.fileId + val thumbAsFile = thumb as? MultipartFile + + val data = SendAudioData( + chatId, + audioAsFileId, + thumbAsFileId, + entities.makeString(), + null, + entities.toRawMessageEntities(), duration, performer, title, @@ -72,6 +118,8 @@ data class SendAudioData internal constructor( override val text: String? = null, @SerialName(parseModeField) override val parseMode: ParseMode? = null, + @SerialName(captionEntitiesField) + private val rawEntities: List? = null, @SerialName(durationField) override val duration: Long? = null, @SerialName(performerField) @@ -93,6 +141,10 @@ data class SendAudioData internal constructor( DuratedSendMessageRequest>, Performerable { + override val entities: List? by lazy { + rawEntities ?.asTextParts(text ?: return@lazy null) ?.justTextSources() + } + init { text ?.let { if (it.length !in captionLength) { diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/send/media/SendDocument.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/send/media/SendDocument.kt index 961d512dc6..72a0fed603 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/send/media/SendDocument.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/send/media/SendDocument.kt @@ -1,9 +1,13 @@ package dev.inmo.tgbotapi.requests.send.media +import dev.inmo.tgbotapi.CommonAbstracts.* import dev.inmo.tgbotapi.requests.abstracts.* import dev.inmo.tgbotapi.requests.send.abstracts.* import dev.inmo.tgbotapi.requests.send.media.base.* import dev.inmo.tgbotapi.types.* +import dev.inmo.tgbotapi.types.MessageEntity.* +import dev.inmo.tgbotapi.types.MessageEntity.RawMessageEntity +import dev.inmo.tgbotapi.types.MessageEntity.asTextParts import dev.inmo.tgbotapi.types.ParseMode.ParseMode import dev.inmo.tgbotapi.types.ParseMode.parseModeField import dev.inmo.tgbotapi.types.buttons.KeyboardMarkup @@ -45,6 +49,54 @@ fun SendDocument( thumbAsFileId, caption, parseMode, + null, + disableNotification, + replyToMessageId, + replyMarkup, + disableContentTypeDetection + ) + + return if (documentAsFile == null && thumbAsFile == null) { + data + } else { + MultipartRequestImpl( + data, + SendDocumentFiles(documentAsFile, thumbAsFile) + ) + } +} + +/** + * Use this method to send general files. On success, the sent [ContentMessage] with [DocumentContent] is returned. + * Bots can currently send files of any type of up to 50 MB in size, this limit may be changed in the future. + * + * @param disableContentTypeDetection Disables automatic server-side content type detection for [document] [MultipartFile] + * + * @see ContentMessage + * @see DocumentContent + */ +fun SendDocument( + chatId: ChatIdentifier, + document: InputFile, + thumb: InputFile? = null, + entities: List, + disableNotification: Boolean = false, + replyToMessageId: MessageIdentifier? = null, + replyMarkup: KeyboardMarkup? = null, + disableContentTypeDetection: Boolean? = null +): Request> { + val documentAsFileId = (document as? FileId) ?.fileId + val documentAsFile = document as? MultipartFile + val thumbAsFileId = (thumb as? FileId) ?.fileId + val thumbAsFile = thumb as? MultipartFile + + val data = SendDocumentData( + chatId, + documentAsFileId, + thumbAsFileId, + entities.makeString(), + null, + entities.toRawMessageEntities(), disableNotification, replyToMessageId, replyMarkup, @@ -85,6 +137,8 @@ data class SendDocumentData internal constructor( override val text: String? = null, @SerialName(parseModeField) override val parseMode: ParseMode? = null, + @SerialName(captionEntitiesField) + private val rawEntities: List? = null, @SerialName(disableNotificationField) override val disableNotification: Boolean = false, @SerialName(replyToMessageIdField) @@ -99,6 +153,10 @@ data class SendDocumentData internal constructor( TextableSendMessageRequest>, ThumbedSendMessageRequest> { + override val entities: List? by lazy { + rawEntities ?.asTextParts(text ?: return@lazy null) ?.justTextSources() + } + init { text ?.let { if (it.length !in captionLength) { diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/send/media/SendPhoto.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/send/media/SendPhoto.kt index 5ffd41caf2..a526b06704 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/send/media/SendPhoto.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/send/media/SendPhoto.kt @@ -1,9 +1,13 @@ package dev.inmo.tgbotapi.requests.send.media +import dev.inmo.tgbotapi.CommonAbstracts.* import dev.inmo.tgbotapi.requests.abstracts.* import dev.inmo.tgbotapi.requests.send.abstracts.* import dev.inmo.tgbotapi.requests.send.media.base.* import dev.inmo.tgbotapi.types.* +import dev.inmo.tgbotapi.types.MessageEntity.* +import dev.inmo.tgbotapi.types.MessageEntity.RawMessageEntity +import dev.inmo.tgbotapi.types.MessageEntity.toRawMessageEntities import dev.inmo.tgbotapi.types.ParseMode.ParseMode import dev.inmo.tgbotapi.types.ParseMode.parseModeField import dev.inmo.tgbotapi.types.buttons.KeyboardMarkup @@ -27,6 +31,33 @@ fun SendPhoto( (photo as? FileId) ?.fileId, caption, parseMode, + null, + disableNotification, + replyToMessageId, + replyMarkup + ) + return data.photo ?.let { + data + } ?: MultipartRequestImpl( + data, + SendPhotoFiles(photo as MultipartFile) + ) +} + +fun SendPhoto( + chatId: ChatIdentifier, + photo: InputFile, + entities: List, + disableNotification: Boolean = false, + replyToMessageId: MessageIdentifier? = null, + replyMarkup: KeyboardMarkup? = null +): Request> { + val data = SendPhotoData( + chatId, + (photo as? FileId) ?.fileId, + entities.makeString(), + null, + entities.toRawMessageEntities(), disableNotification, replyToMessageId, replyMarkup @@ -52,6 +83,8 @@ data class SendPhotoData internal constructor( override val text: String? = null, @SerialName(parseModeField) override val parseMode: ParseMode? = null, + @SerialName(captionEntitiesField) + private val rawEntities: List? = null, @SerialName(disableNotificationField) override val disableNotification: Boolean = false, @SerialName(replyToMessageIdField) @@ -63,6 +96,10 @@ data class SendPhotoData internal constructor( ReplyingMarkupSendMessageRequest>, TextableSendMessageRequest> { + override val entities: List? by lazy { + rawEntities ?.asTextParts(text ?: return@lazy null) ?.justTextSources() + } + init { text ?.let { if (it.length !in captionLength) { diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/send/media/SendVideo.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/send/media/SendVideo.kt index 3c2ba65bd3..3640d60adb 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/send/media/SendVideo.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/send/media/SendVideo.kt @@ -1,9 +1,13 @@ package dev.inmo.tgbotapi.requests.send.media +import dev.inmo.tgbotapi.CommonAbstracts.* import dev.inmo.tgbotapi.requests.abstracts.* import dev.inmo.tgbotapi.requests.send.abstracts.* import dev.inmo.tgbotapi.requests.send.media.base.* import dev.inmo.tgbotapi.types.* +import dev.inmo.tgbotapi.types.MessageEntity.* +import dev.inmo.tgbotapi.types.MessageEntity.RawMessageEntity +import dev.inmo.tgbotapi.types.MessageEntity.toRawMessageEntities import dev.inmo.tgbotapi.types.ParseMode.ParseMode import dev.inmo.tgbotapi.types.ParseMode.parseModeField import dev.inmo.tgbotapi.types.buttons.KeyboardMarkup @@ -39,6 +43,51 @@ fun SendVideo( thumbAsFileId, caption, parseMode, + null, + duration, + width, + height, + supportStreaming, + disableNotification, + replyToMessageId, + replyMarkup + ) + + return if (videoAsFile == null && thumbAsFile == null) { + data + } else { + MultipartRequestImpl( + data, + SendVideoFiles(videoAsFile, thumbAsFile) + ) + } +} + +fun SendVideo( + chatId: ChatIdentifier, + video: InputFile, + thumb: InputFile? = null, + entities: List, + duration: Long? = null, + width: Int? = null, + height: Int? = null, + supportStreaming: Boolean? = null, + disableNotification: Boolean = false, + replyToMessageId: MessageIdentifier? = null, + replyMarkup: KeyboardMarkup? = null +): Request> { + val videoAsFileId = (video as? FileId) ?.fileId + val videoAsFile = video as? MultipartFile + val thumbAsFileId = (thumb as? FileId) ?.fileId + val thumbAsFile = thumb as? MultipartFile + + val data = SendVideoData( + chatId, + videoAsFileId, + thumbAsFileId, + entities.makeString(), + null, + entities.toRawMessageEntities(), duration, width, height, @@ -73,6 +122,8 @@ data class SendVideoData internal constructor( override val text: String? = null, @SerialName(parseModeField) override val parseMode: ParseMode? = null, + @SerialName(captionEntitiesField) + private val rawEntities: List? = null, @SerialName(durationField) override val duration: Long? = null, @SerialName(widthField) @@ -95,6 +146,10 @@ data class SendVideoData internal constructor( DuratedSendMessageRequest>, SizedSendMessageRequest> { + override val entities: List? by lazy { + rawEntities ?.asTextParts(text ?: return@lazy null) ?.justTextSources() + } + init { text ?.let { if (it.length !in captionLength) { diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/send/media/SendVideoNote.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/send/media/SendVideoNote.kt index 66376e093b..9664f7ec61 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/send/media/SendVideoNote.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/send/media/SendVideoNote.kt @@ -18,8 +18,6 @@ fun SendVideoNote( chatId: ChatIdentifier, videoNote: InputFile, thumb: InputFile? = null, - caption: String? = null, - parseMode: ParseMode? = null, duration: Long? = null, size: Int? = null, // in documentation - length (size of video side) disableNotification: Boolean = false, @@ -35,8 +33,6 @@ fun SendVideoNote( chatId, videoNoteAsFileId, thumbAsFileId, - caption, - parseMode, duration, size, disableNotification, @@ -65,10 +61,6 @@ data class SendVideoNoteData internal constructor( val videoNote: String? = null, @SerialName(thumbField) override val thumb: String? = null, - @SerialName(captionField) - override val text: String? = null, - @SerialName(parseModeField) - override val parseMode: ParseMode? = null, @SerialName(durationField) override val duration: Long? = null, @SerialName(lengthField) @@ -82,7 +74,6 @@ data class SendVideoNoteData internal constructor( ) : DataRequest>, SendMessageRequest>, ReplyingMarkupSendMessageRequest>, - TextableSendMessageRequest>, ThumbedSendMessageRequest>, DuratedSendMessageRequest>, SizedSendMessageRequest> @@ -90,14 +81,6 @@ data class SendVideoNoteData internal constructor( override val height: Int? get() = width - init { - text ?.let { - if (it.length !in captionLength) { - throwRangeError("Caption length", captionLength, it.length) - } - } - } - override fun method(): String = "sendVideoNote" override val resultDeserializer: DeserializationStrategy> get() = commonResultDeserializer diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/send/media/SendVoice.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/send/media/SendVoice.kt index 1429239446..34962d6079 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/send/media/SendVoice.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/send/media/SendVoice.kt @@ -1,9 +1,13 @@ package dev.inmo.tgbotapi.requests.send.media +import dev.inmo.tgbotapi.CommonAbstracts.* import dev.inmo.tgbotapi.requests.abstracts.* import dev.inmo.tgbotapi.requests.send.abstracts.* import dev.inmo.tgbotapi.requests.send.media.base.* import dev.inmo.tgbotapi.types.* +import dev.inmo.tgbotapi.types.MessageEntity.* +import dev.inmo.tgbotapi.types.MessageEntity.RawMessageEntity +import dev.inmo.tgbotapi.types.MessageEntity.asTextParts import dev.inmo.tgbotapi.types.ParseMode.ParseMode import dev.inmo.tgbotapi.types.ParseMode.parseModeField import dev.inmo.tgbotapi.types.buttons.KeyboardMarkup @@ -32,6 +36,41 @@ fun SendVoice( voiceAsFileId, caption, parseMode, + null, + duration, + disableNotification, + replyToMessageId, + replyMarkup + ) + + return if (voiceAsFile == null) { + data + } else { + MultipartRequestImpl( + data, + SendVoiceFiles(voiceAsFile) + ) + } +} + +fun SendVoice( + chatId: ChatIdentifier, + voice: InputFile, + entities: List, + duration: Long? = null, + disableNotification: Boolean = false, + replyToMessageId: MessageIdentifier? = null, + replyMarkup: KeyboardMarkup? = null +): Request> { + val voiceAsFileId = (voice as? FileId) ?.fileId + val voiceAsFile = voice as? MultipartFile + + val data = SendVoiceData( + chatId, + voiceAsFileId, + entities.makeString(), + null, + entities.toRawMessageEntities(), duration, disableNotification, replyToMessageId, @@ -61,6 +100,8 @@ data class SendVoiceData internal constructor( override val text: String? = null, @SerialName(parseModeField) override val parseMode: ParseMode? = null, + @SerialName(captionEntitiesField) + private val rawEntities: List? = null, @SerialName(durationField) override val duration: Long? = null, @SerialName(disableNotificationField) @@ -75,6 +116,10 @@ data class SendVoiceData internal constructor( TextableSendMessageRequest>, DuratedSendMessageRequest> { + override val entities: List? by lazy { + rawEntities ?.asTextParts(text ?: return@lazy null) ?.justTextSources() + } + init { text ?.let { if (it.length !in captionLength) { diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/send/polls/SendPoll.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/send/polls/SendPoll.kt index 7ded492c21..9001b208e8 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/send/polls/SendPoll.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/requests/send/polls/SendPoll.kt @@ -14,6 +14,9 @@ import dev.inmo.tgbotapi.types.polls.* import dev.inmo.tgbotapi.utils.fullListOfSubSource import dev.inmo.tgbotapi.utils.toMarkdownV2Captions import com.soywiz.klock.DateTime +import dev.inmo.tgbotapi.types.MessageEntity.* +import dev.inmo.tgbotapi.types.MessageEntity.RawMessageEntity +import dev.inmo.tgbotapi.types.MessageEntity.asTextParts import kotlinx.serialization.* private val commonResultDeserializer: DeserializationStrategy> = TelegramBotAPIMessageDeserializationStrategyClass() @@ -85,8 +88,7 @@ fun Poll.createRequest( correctOptionId, isAnonymous, isClosed, - explanation ?.fullListOfSubSource(explanationEntities) ?.justTextSources() ?.toMarkdownV2Captions() ?.firstOrNull(), - MarkdownV2, + fullEntitiesList(), scheduledCloseInfo, disableNotification, replyToMessageId, @@ -186,8 +188,65 @@ data class SendRegularPoll( } } +fun SendQuizPoll( + chatId: ChatIdentifier, + question: String, + options: List, + correctOptionId: Int, + isAnonymous: Boolean = true, + isClosed: Boolean = false, + explanation: String? = null, + parseMode: ParseMode? = null, + closeInfo: ScheduledCloseInfo? = null, + disableNotification: Boolean = false, + replyToMessageId: MessageIdentifier? = null, + replyMarkup: KeyboardMarkup? = null +) = SendQuizPoll( + chatId, + question, + options, + correctOptionId, + isAnonymous, + isClosed, + explanation, + parseMode, + null, + closeInfo, + disableNotification, + replyToMessageId, + replyMarkup +) + +fun SendQuizPoll( + chatId: ChatIdentifier, + question: String, + options: List, + correctOptionId: Int, + isAnonymous: Boolean = true, + isClosed: Boolean = false, + entities: List, + closeInfo: ScheduledCloseInfo? = null, + disableNotification: Boolean = false, + replyToMessageId: MessageIdentifier? = null, + replyMarkup: KeyboardMarkup? = null +) = SendQuizPoll( + chatId, + question, + options, + correctOptionId, + isAnonymous, + isClosed, + entities.makeString(), + null, + entities.toRawMessageEntities(), + closeInfo, + disableNotification, + replyToMessageId, + replyMarkup +) + @Serializable -data class SendQuizPoll( +data class SendQuizPoll internal constructor( @SerialName(chatIdField) override val chatId: ChatIdentifier, @SerialName(questionField) @@ -204,6 +263,8 @@ data class SendQuizPoll( override val explanation: String? = null, @SerialName(explanationParseModeField) override val parseMode: ParseMode? = null, + @SerialName(explanationEntitiesField) + private val rawEntities: List? = null, @Transient override val closeInfo: ScheduledCloseInfo? = null, @SerialName(disableNotificationField) @@ -216,6 +277,9 @@ data class SendQuizPoll( override val type: String = quizPollType override val requestSerializer: SerializationStrategy<*> get() = serializer() + override val entities: List? by lazy { + rawEntities ?.asTextParts(explanation ?: return@lazy null) ?.justTextSources() + } @SerialName(openPeriodField) override val openPeriod: LongSeconds? diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/Common.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/Common.kt index fb2b899d5c..cdcbb62785 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/Common.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/Common.kt @@ -108,6 +108,7 @@ const val canJoinGroupsField = "can_join_groups" const val canReadAllGroupMessagesField = "can_read_all_group_messages" const val supportInlineQueriesField = "supports_inline_queries" const val textEntitiesField = "text_entities" +const val entitiesField = "entities" const val stickerSetNameField = "set_name" const val stickerSetNameFullField = "sticker_set_name" const val slowModeDelayField = "slow_mode_delay" @@ -147,6 +148,7 @@ const val totalVoterCountField = "total_voter_count" const val correctOptionIdField = "correct_option_id" const val allowsMultipleAnswersField = "allows_multiple_answers" const val isAnonymousField = "is_anonymous" +const val captionEntitiesField = "caption_entities" const val loginUrlField = "login_url" const val forwardTextField = "forward_text" const val botUsernameField = "bot_username" diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/InputMedia/InputMediaAnimation.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/InputMedia/InputMediaAnimation.kt index c56a9044f3..0f71ff5def 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/InputMedia/InputMediaAnimation.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/InputMedia/InputMediaAnimation.kt @@ -1,25 +1,57 @@ package dev.inmo.tgbotapi.types.InputMedia -import dev.inmo.tgbotapi.CommonAbstracts.CaptionedOutput +import dev.inmo.tgbotapi.CommonAbstracts.* import dev.inmo.tgbotapi.requests.abstracts.* +import dev.inmo.tgbotapi.types.* +import dev.inmo.tgbotapi.types.MessageEntity.* +import dev.inmo.tgbotapi.types.MessageEntity.RawMessageEntity +import dev.inmo.tgbotapi.types.MessageEntity.asTextParts import dev.inmo.tgbotapi.types.ParseMode.ParseMode import dev.inmo.tgbotapi.types.ParseMode.parseModeField -import dev.inmo.tgbotapi.types.mediaField import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable +fun InputMediaAnimation( + file: InputFile, + text: String? = null, + parseMode: ParseMode? = null, + width: Int? = null, + height: Int? = null, + duration: Long? = null, + thumb: InputFile? = null +) = InputMediaAnimation(file, text, parseMode, null, width, height, duration, thumb) + +fun InputMediaAnimation( + file: InputFile, + entities: List, + width: Int? = null, + height: Int? = null, + duration: Long? = null, + thumb: InputFile? = null +) = InputMediaAnimation(file, entities.makeString(), null, entities.toRawMessageEntities(), width, height, duration, thumb) + @Serializable -data class InputMediaAnimation( +data class InputMediaAnimation internal constructor( override val file: InputFile, - override val caption: String? = null, + @SerialName(captionField) + override val text: String? = null, @SerialName(parseModeField) override val parseMode: ParseMode? = null, + @SerialName(captionEntitiesField) + private val rawEntities: List? = null, override val width: Int? = null, override val height: Int? = null, override val duration: Long? = null, override val thumb: InputFile? = null -) : InputMedia, SizedInputMedia, DuratedInputMedia, ThumbedInputMedia, CaptionedOutput { +) : InputMedia, SizedInputMedia, DuratedInputMedia, ThumbedInputMedia, TextedOutput, CaptionedOutput { override val type: String = "animation" + override val entities: List? by lazy { + rawEntities ?.asTextParts(text ?: return@lazy null) ?.justTextSources() + } + + @Deprecated("Will be removed in next major release") + override val caption: String? + get() = text @SerialName(mediaField) override val media: String diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/InputMedia/InputMediaAudio.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/InputMedia/InputMediaAudio.kt index 1c3b547428..738da6a829 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/InputMedia/InputMediaAudio.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/InputMedia/InputMediaAudio.kt @@ -1,30 +1,61 @@ package dev.inmo.tgbotapi.types.InputMedia -import dev.inmo.tgbotapi.CommonAbstracts.CaptionedOutput -import dev.inmo.tgbotapi.CommonAbstracts.Performerable +import dev.inmo.tgbotapi.CommonAbstracts.* import dev.inmo.tgbotapi.requests.abstracts.* +import dev.inmo.tgbotapi.types.* +import dev.inmo.tgbotapi.types.MessageEntity.* +import dev.inmo.tgbotapi.types.MessageEntity.RawMessageEntity +import dev.inmo.tgbotapi.types.MessageEntity.asTextParts import dev.inmo.tgbotapi.types.ParseMode.ParseMode import dev.inmo.tgbotapi.types.ParseMode.parseModeField import dev.inmo.tgbotapi.types.files.AudioFile import dev.inmo.tgbotapi.types.files.PhotoSize -import dev.inmo.tgbotapi.types.mediaField import dev.inmo.tgbotapi.types.message.content.media.AudioContent import kotlinx.serialization.* internal const val audioInputMediaType = "audio" +fun InputMediaAudio( + file: InputFile, + entities: List, + duration: Long? = null, + performer: String? = null, + title: String? = null, + thumb: InputFile? = null +) = InputMediaAudio( + file, entities.makeString(), null, entities.toRawMessageEntities(), duration, performer, title, thumb +) + +fun InputMediaAudio( + file: InputFile, + text: String? = null, + parseMode: ParseMode? = null, + duration: Long? = null, + performer: String? = null, + title: String? = null, + thumb: InputFile? = null +) = InputMediaAudio( + file, text, parseMode, null, duration, performer, title, thumb +) + @Serializable -data class InputMediaAudio( +data class InputMediaAudio internal constructor( override val file: InputFile, - override val caption: String? = null, + @SerialName(captionField) + override val text: String? = null, @SerialName(parseModeField) override val parseMode: ParseMode? = null, + @SerialName(captionEntitiesField) + private val rawEntities: List? = null, override val duration: Long? = null, override val performer: String? = null, override val title: String? = null, override val thumb: InputFile? = null -) : InputMedia, AudioMediaGroupMemberInputMedia, DuratedInputMedia, ThumbedInputMedia, TitledInputMedia, CaptionedOutput, Performerable { +) : InputMedia, AudioMediaGroupMemberInputMedia, DuratedInputMedia, ThumbedInputMedia, TitledInputMedia, Performerable { override val type: String = audioInputMediaType + override val entities: List? by lazy { + rawEntities ?.asTextParts(text ?: return@lazy null) ?.justTextSources() + } override fun serialize(format: StringFormat): String = format.encodeToString(serializer(), this) diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/InputMedia/InputMediaDocument.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/InputMedia/InputMediaDocument.kt index a0fa37b7c0..81cc43a069 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/InputMedia/InputMediaDocument.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/InputMedia/InputMediaDocument.kt @@ -1,16 +1,33 @@ package dev.inmo.tgbotapi.types.InputMedia -import dev.inmo.tgbotapi.CommonAbstracts.CaptionedOutput +import dev.inmo.tgbotapi.CommonAbstracts.* import dev.inmo.tgbotapi.requests.abstracts.* +import dev.inmo.tgbotapi.types.* +import dev.inmo.tgbotapi.types.MessageEntity.* +import dev.inmo.tgbotapi.types.MessageEntity.RawMessageEntity +import dev.inmo.tgbotapi.types.MessageEntity.asTextParts import dev.inmo.tgbotapi.types.ParseMode.ParseMode import dev.inmo.tgbotapi.types.ParseMode.parseModeField -import dev.inmo.tgbotapi.types.disableContentTypeDetectionField import dev.inmo.tgbotapi.types.files.DocumentFile -import dev.inmo.tgbotapi.types.mediaField import kotlinx.serialization.* internal const val documentInputMediaType = "document" +fun InputMediaDocument( + file: InputFile, + caption: String? = null, + parseMode: ParseMode? = null, + thumb: InputFile? = null, + disableContentTypeDetection: Boolean? = null +) = InputMediaDocument(file, caption, parseMode, null, thumb, disableContentTypeDetection) + +fun InputMediaDocument( + file: InputFile, + entities: List, + thumb: InputFile? = null, + disableContentTypeDetection: Boolean? = null +) = InputMediaDocument(file, entities.makeString(), null, entities.toRawMessageEntities(), thumb, disableContentTypeDetection) + /** * Represents a general file to be sent. See https://core.telegram.org/bots/api#inputmediadocument * @@ -22,16 +39,22 @@ internal const val documentInputMediaType = "document" * @see FileId */ @Serializable -data class InputMediaDocument( +data class InputMediaDocument internal constructor( override val file: InputFile, - override val caption: String? = null, + @SerialName(captionField) + override val text: String? = null, @SerialName(parseModeField) override val parseMode: ParseMode? = null, + @SerialName(captionEntitiesField) + private val rawEntities: List? = null, override val thumb: InputFile? = null, @SerialName(disableContentTypeDetectionField) val disableContentTypeDetection: Boolean? = null -) : InputMedia, DocumentMediaGroupMemberInputMedia, ThumbedInputMedia, CaptionedOutput { +) : InputMedia, DocumentMediaGroupMemberInputMedia, ThumbedInputMedia { override val type: String = documentInputMediaType + override val entities: List? by lazy { + rawEntities ?.asTextParts(text ?: return@lazy null) ?.justTextSources() + } override fun serialize(format: StringFormat): String = format.encodeToString(serializer(), this) diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/InputMedia/InputMediaPhoto.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/InputMedia/InputMediaPhoto.kt index 32a5c1b482..e921b51508 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/InputMedia/InputMediaPhoto.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/InputMedia/InputMediaPhoto.kt @@ -1,24 +1,45 @@ package dev.inmo.tgbotapi.types.InputMedia +import dev.inmo.tgbotapi.CommonAbstracts.* import dev.inmo.tgbotapi.requests.abstracts.* +import dev.inmo.tgbotapi.types.* +import dev.inmo.tgbotapi.types.MessageEntity.* +import dev.inmo.tgbotapi.types.MessageEntity.RawMessageEntity +import dev.inmo.tgbotapi.types.MessageEntity.toRawMessageEntities import dev.inmo.tgbotapi.types.ParseMode.ParseMode import dev.inmo.tgbotapi.types.ParseMode.parseModeField import dev.inmo.tgbotapi.types.files.PhotoSize -import dev.inmo.tgbotapi.types.mediaField import kotlinx.serialization.* import kotlinx.serialization.json.JsonElement import kotlinx.serialization.json.JsonObject internal const val photoInputMediaType = "photo" +fun InputMediaPhoto( + file: InputFile, + text: String? = null, + parseMode: ParseMode? = null +) = InputMediaPhoto(file, text, parseMode, null) + +fun InputMediaPhoto( + file: InputFile, + entities: List +) = InputMediaPhoto(file, entities.makeString(), null, entities.toRawMessageEntities()) + @Serializable -data class InputMediaPhoto( +data class InputMediaPhoto internal constructor( override val file: InputFile, - override val caption: String? = null, + @SerialName(captionField) + override val text: String? = null, @SerialName(parseModeField) - override val parseMode: ParseMode? = null + override val parseMode: ParseMode? = null, + @SerialName(captionEntitiesField) + private val rawEntities: List? = null ) : InputMedia, VisualMediaGroupMemberInputMedia { override val type: String = photoInputMediaType + override val entities: List? by lazy { + rawEntities ?.asTextParts(text ?: return@lazy null) ?.justTextSources() + } override fun serialize(format: StringFormat): String = format.encodeToString(serializer(), this) diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/InputMedia/InputMediaVideo.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/InputMedia/InputMediaVideo.kt index 302a1579d3..d6a6c46bcd 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/InputMedia/InputMediaVideo.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/InputMedia/InputMediaVideo.kt @@ -1,26 +1,55 @@ package dev.inmo.tgbotapi.types.InputMedia +import dev.inmo.tgbotapi.CommonAbstracts.* import dev.inmo.tgbotapi.requests.abstracts.* +import dev.inmo.tgbotapi.types.* +import dev.inmo.tgbotapi.types.MessageEntity.* +import dev.inmo.tgbotapi.types.MessageEntity.RawMessageEntity +import dev.inmo.tgbotapi.types.MessageEntity.toRawMessageEntities import dev.inmo.tgbotapi.types.ParseMode.ParseMode import dev.inmo.tgbotapi.types.ParseMode.parseModeField -import dev.inmo.tgbotapi.types.mediaField import kotlinx.serialization.* import kotlinx.serialization.json.JsonElement internal const val videoInputMediaType = "video" +fun InputMediaVideo( + file: InputFile, + text: String? = null, + parseMode: ParseMode? = null, + width: Int? = null, + height: Int? = null, + duration: Long? = null, + thumb: InputFile? = null +) = InputMediaVideo(file, text, parseMode, null, width, height, duration, thumb) + +fun InputMediaVideo( + file: InputFile, + entities: List, + width: Int? = null, + height: Int? = null, + duration: Long? = null, + thumb: InputFile? = null +) = InputMediaVideo(file, entities.makeString(), null, entities.toRawMessageEntities(), width, height, duration, thumb) + @Serializable -data class InputMediaVideo( +data class InputMediaVideo internal constructor ( override val file: InputFile, - override val caption: String? = null, + @SerialName(captionField) + override val text: String? = null, @SerialName(parseModeField) override val parseMode: ParseMode? = null, + @SerialName(captionEntitiesField) + private val rawEntities: List? = null, override val width: Int? = null, override val height: Int? = null, override val duration: Long? = null, override val thumb: InputFile? = null ) : InputMedia, SizedInputMedia, DuratedInputMedia, ThumbedInputMedia, VisualMediaGroupMemberInputMedia { override val type: String = videoInputMediaType + override val entities: List? by lazy { + rawEntities ?.asTextParts(text ?: return@lazy null) ?.justTextSources() + } override fun serialize(format: StringFormat): String = format.encodeToString(serializer(), this) diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/InputMedia/MediaGroupMemberInputMedia.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/InputMedia/MediaGroupMemberInputMedia.kt index 83965179f8..ebb1b2291c 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/InputMedia/MediaGroupMemberInputMedia.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/InputMedia/MediaGroupMemberInputMedia.kt @@ -1,6 +1,7 @@ package dev.inmo.tgbotapi.types.InputMedia import dev.inmo.tgbotapi.CommonAbstracts.CaptionedOutput +import dev.inmo.tgbotapi.CommonAbstracts.TextedOutput import kotlinx.serialization.* import kotlinx.serialization.json.* @@ -15,7 +16,10 @@ internal fun T.buildArguments(withSerializer: SerializationStrategy) = ar ) @Serializable(MediaGroupMemberInputMediaSerializer::class) -interface MediaGroupMemberInputMedia : InputMedia, CaptionedOutput { +interface MediaGroupMemberInputMedia : InputMedia, CaptionedOutput, TextedOutput { + @Deprecated("Will be removed in next major release") + override val caption: String? + get() = text fun serialize(format: StringFormat): String } diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/MessageEntity/RawMessageEntity.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/MessageEntity/RawMessageEntity.kt index 942e6d1704..610a384682 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/MessageEntity/RawMessageEntity.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/MessageEntity/RawMessageEntity.kt @@ -1,7 +1,6 @@ package dev.inmo.tgbotapi.types.MessageEntity -import dev.inmo.tgbotapi.CommonAbstracts.MultilevelTextSource -import dev.inmo.tgbotapi.CommonAbstracts.TextPart +import dev.inmo.tgbotapi.CommonAbstracts.* import dev.inmo.tgbotapi.types.MessageEntity.textsources.* import dev.inmo.tgbotapi.types.User import dev.inmo.tgbotapi.utils.shiftSourcesToTheLeft @@ -83,7 +82,7 @@ internal fun createTextPart(from: String, entities: RawMessageEntities): List.asRawMessageEntities() = mapNotNull { +internal fun List.asRawMessageEntities(): List = mapNotNull { val source = it.source when (source) { is MentionTextSource -> RawMessageEntity("mention", it.range.first, it.range.last - it.range.first) @@ -105,6 +104,18 @@ internal fun List.asRawMessageEntities() = mapNotNull { } } +internal fun List.toRawMessageEntities(): List { + var i = 0 + return map { + TextPart( + i until it.source.length, + it + ).also { + i = it.range.last + 1 + } + }.asRawMessageEntities() +} + internal fun RawMessageEntities.asTextParts(sourceString: String): List = createTextPart(sourceString, this) internal typealias RawMessageEntities = List