1
0
mirror of https://github.com/InsanusMokrassar/TelegramBotAPI.git synced 2025-11-30 11:25:44 +00:00

Compare commits

..

39 Commits

Author SHA1 Message Date
241545c0cb fix in updates unique calculation and update dependencies 2023-04-19 20:29:40 +06:00
3b2310ece1 fixes in unique updates handling 2023-04-19 19:36:43 +06:00
e1adde0978 Update libs.versions.toml 2023-04-18 14:15:45 +06:00
3b17bce71a fix changelog and readme 2023-04-18 12:55:06 +06:00
999efc64eb complete native integration 2023-04-18 12:40:45 +06:00
05c99642cb update packages publishing to install openssl 2023-04-18 03:26:58 +06:00
cd6f4831ae MultipleClientKtorRequestsExecutor, DefaultKtorRequestsExecutor, KtorRequestsExecutor as expect class 2023-04-18 03:13:41 +06:00
2778315aed add support of fallback handlers in behaviour builder with fsm 2023-04-17 15:50:04 +06:00
ff8d67a780 potential fix in native 2023-04-13 19:26:58 +06:00
2a5f9a629d fixes in TextSourceSerializer 2023-04-13 13:58:20 +06:00
75b27858dd update dependencies 2023-04-13 12:28:51 +06:00
034e2d7ff3 Update libs.versions.toml 2023-04-04 01:43:53 +06:00
1f69c16f2a fix of build 2023-04-04 00:21:59 +06:00
8d24512413 experimentally add support of natives 2023-04-03 23:33:54 +06:00
09009003e3 start 7.0.2 2023-04-03 23:07:10 +06:00
048486146c Merge pull request #738 from InsanusMokrassar/7.0.1
7.0.1
2023-03-16 20:14:57 +06:00
b688fa570a ChatMemberUpdated now inherits WithChat and fill changes related to WithChat 2023-03-16 19:32:43 +06:00
0eba0c4e15 improvements in same-notations 2023-03-16 19:29:35 +06:00
f8bbfa2b1e Merge pull request #737 from Tolsi/more-same-flow-filters
more "same" flow filters were added
2023-03-16 18:52:13 +06:00
fec2715dc1 start 7.0.1 2023-03-16 18:48:36 +06:00
Sergey Tolmachev
941a25b116 more "same" flow filters were added 2023-03-16 16:53:39 +05:30
741d808db2 Merge pull request #736 from InsanusMokrassar/7.0.0
7.0.0
2023-03-11 22:38:33 +06:00
69683a4e6a upfill changelog 2023-03-11 22:38:09 +06:00
e5a48e9684 rework of multipart files with fixes in new sticker sets 2023-03-11 21:17:59 +06:00
6722ab5f50 add several extensions for addStickerToSet 2023-03-11 17:58:48 +06:00
810b2ab5a1 add Sticker#asInputSticker 2023-03-11 17:39:12 +06:00
5992fdd456 Update Sticker.kt 2023-03-11 01:30:12 +06:00
3c4f8787a6 mask position is nullable in mask stickers and sticker sets 2023-03-11 01:18:39 +06:00
0c24aa1270 add sticker format to stickerset 2023-03-11 00:53:36 +06:00
988d9995c5 add sticker format to sticker object 2023-03-11 00:46:20 +06:00
f75df0a425 Update microutils 2023-03-10 22:34:48 +06:00
9f14eb2ca3 update microutils 2023-03-10 15:08:44 +06:00
6f9f880b79 deprecations removing 2023-03-10 14:59:59 +06:00
2d2310daca fixes in build 2023-03-10 14:43:34 +06:00
dff04d26ca add support of setCustomEmojiStickerSetThumbnail 2023-03-10 14:29:55 +06:00
4390c12180 update uploadStickerFile 2023-03-10 14:24:42 +06:00
1b4d13e452 rework of addStickerToSet 2023-03-10 14:20:34 +06:00
afda5e0e7f rework of create new sticker set 2023-03-10 14:00:57 +06:00
cd354e9456 upgrade version up to 7.0.0 2023-03-10 13:40:15 +06:00
118 changed files with 1685 additions and 2559 deletions

View File

@@ -8,12 +8,16 @@ jobs:
- uses: actions/setup-java@v1 - uses: actions/setup-java@v1
with: with:
java-version: 11 java-version: 11
- name: Setup LibCurl
run: sudo apt install -y libcurl4-openssl-dev
- name: Rewrite version - name: Rewrite version
run: | run: |
branch="`echo "${{ github.ref }}" | grep -o "[^/]*$"`" branch="`echo "${{ github.ref }}" | grep -o "[^/]*$"`"
cat gradle.properties | sed -e "s/^library_version=\([0-9\.]*\)/library_version=\1-branch_$branch-build${{ github.run_number }}/" > gradle.properties.tmp cat gradle.properties | sed -e "s/^library_version=\([0-9\.]*\)/library_version=\1-branch_$branch-build${{ github.run_number }}/" > gradle.properties.tmp
rm gradle.properties rm gradle.properties
mv gradle.properties.tmp gradle.properties mv gradle.properties.tmp gradle.properties
- name: KotlinSymbolProcessing execution
run: ./gradlew ksp
- name: Build - name: Build
run: ./gradlew build run: ./gradlew build
- name: Publish to Gitea - name: Publish to Gitea

View File

@@ -1,6 +1,45 @@
# TelegramBotAPI changelog # TelegramBotAPI changelog
## 6.2.0 ## 7.0.2
_This update brings experimental support of `linuxX64` and `mingwX64` platforms_
* `Versions`:
* `Kotlin`: `1.8.10` -> `1.8.20`
* `MicroUtils`: `0.17.5` -> `0.17.8`
* `Ktor`: `2.2.4` -> `2.3.0`
* `Core`:
* New `RequestsExecutor` - `MultipleClientKtorRequestsExecutor`
* Old `KtorRequestsExecutor` has been renamed to `DefaultKtorRequestsExecutor`
* `KtorRequestsExecutor` now is `expect class`
* On `JS`, `JVM` and `MinGWX64` platforms it is `DefaultKtorRequestsExecutor`
* On `LinuxX64` platform it is `MultipleClientKtorRequestsExecutor`
## 7.0.1
* `Core`:
* New interface `WithChat` which contains `chat` field
* `Message` now inherits `WithChat`
* `ChatMemberUpdated` now inherits `WithChat`
* `Utils`:
* Improvements in `same`-notations
## 7.0.0
This update contains support of [Telegram Bot API 6.6](https://core.telegram.org/bots/api-changelog#march-9-2023)
**THIS VERSION CONTAINS BREAKING CHANGES**:
* All previous deprecations have been removed
* Fully reworked mechanism of stickers creating and adding
* All separations of stickers types like `Animeted` have been replaces with type `StickerFormat`
* New `InputSticker` type (and all subtypes) as replacements for old raw fields in methods
* Reworked mechanism of files uploading
Other changes
* `Versions`:
* `MicroUtils`: `0.17.3` -> `0.17.5`
## 6.1.0 ## 6.1.0

View File

@@ -1,9 +1,11 @@
# TelegramBotAPI [![Maven Central](https://maven-badges.herokuapp.com/maven-central/dev.inmo/tgbotapi/badge.svg)](https://maven-badges.herokuapp.com/maven-central/dev.inmo/tgbotapi) [![Supported version](https://img.shields.io/badge/Telegram%20Bot%20API-6.5-blue)](https://core.telegram.org/bots/api-changelog#february-3-2023) # TelegramBotAPI [![Maven Central](https://maven-badges.herokuapp.com/maven-central/dev.inmo/tgbotapi/badge.svg)](https://maven-badges.herokuapp.com/maven-central/dev.inmo/tgbotapi) [![Supported version](https://img.shields.io/badge/Telegram%20Bot%20API-6.6-blue)](https://core.telegram.org/bots/api-changelog#march-9-2023)
| Docs | [![KDocs](https://img.shields.io/static/v1?label=Dokka&message=KDocs&color=blue&logo=kotlin)](https://tgbotapi.inmo.dev/index.html) [![Mini tutorial](https://img.shields.io/static/v1?label=Bookstack&message=Tutorial&color=blue&logo=bookstack)](https://bookstack.inmo.dev/books/telegrambotapi/chapter/introduction-tutorial) | | Docs | [![KDocs](https://img.shields.io/static/v1?label=Dokka&message=KDocs&color=blue&logo=kotlin)](https://tgbotapi.inmo.dev/index.html) [![Mini tutorial](https://img.shields.io/static/v1?label=Bookstack&message=Tutorial&color=blue&logo=bookstack)](https://bookstack.inmo.dev/books/telegrambotapi/chapter/introduction-tutorial) |
|:---:|:---:| |:----------------------:|:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------:|
| Useful repos | [![Create bot](https://img.shields.io/static/v1?label=Github&message=Template&color=blue&logo=github)](https://github.com/InsanusMokrassar/TelegramBotAPI-bot_template/generate) [![Examples](https://img.shields.io/static/v1?label=Github&message=Examples&color=blue&logo=github)](https://github.com/InsanusMokrassar/TelegramBotAPI-examples/) | | Useful repos | [![Create bot](https://img.shields.io/static/v1?label=Github&message=Template&color=blue&logo=github)](https://github.com/InsanusMokrassar/TelegramBotAPI-bot_template/generate) [![Examples](https://img.shields.io/static/v1?label=Github&message=Examples&color=blue&logo=github)](https://github.com/InsanusMokrassar/TelegramBotAPI-examples/) |
| Misc | [![Awesome Kotlin Badge](https://kotlin.link/awesome-kotlin.svg)](https://github.com/KotlinBy/awesome-kotlin) [![Small survey](https://img.shields.io/static/v1?label=Google&message=Survey&color=blue&logo=google-sheets)](https://docs.google.com/forms/d/e/1FAIpQLSctdJHT_aEniyYT0-IUAEfo1hsIlezX2owlkEAYX4KPl2V2_A/viewform?usp=sf_link) | | Misc | [![Awesome Kotlin Badge](https://kotlin.link/awesome-kotlin.svg)](https://github.com/KotlinBy/awesome-kotlin) [![Small survey](https://img.shields.io/static/v1?label=Google&message=Survey&color=blue&logo=google-sheets)](https://docs.google.com/forms/d/e/1FAIpQLSctdJHT_aEniyYT0-IUAEfo1hsIlezX2owlkEAYX4KPl2V2_A/viewform?usp=sf_link) |
| Platforms | ![JVM](https://img.shields.io/badge/JVM-red?style=plastic&logo=openjdk&logoColor=white) ![Js](https://img.shields.io/badge/JavaScript-323330?style=plastic&logo=javascript&logoColor=F7DF1E) |
| Experimental Platforms | ![Linux x64](https://img.shields.io/badge/LinuxX64-FCC624?style=plastic&logo=linux&logoColor=black) ![MinGW x64](https://img.shields.io/badge/MinGWX64-black?style=plastic&logo=windows&logoColor=green) |
<!--- [![Telegram Channel](./resources/tg_channel_qr.jpg)](https://t.me/ktgbotapi) ---> <!--- [![Telegram Channel](./resources/tg_channel_qr.jpg)](https://t.me/ktgbotapi) --->

View File

@@ -6,4 +6,4 @@ kotlin.incremental=true
kotlin.incremental.js=true kotlin.incremental.js=true
library_group=dev.inmo library_group=dev.inmo
library_version=6.2.0 library_version=7.0.2

View File

@@ -1,6 +1,6 @@
[versions] [versions]
kotlin = "1.8.10" kotlin = "1.8.20"
kotlin-serialization = "1.5.0" kotlin-serialization = "1.5.0"
kotlin-coroutines = "1.6.4" kotlin-coroutines = "1.6.4"
@@ -8,12 +8,12 @@ javax-activation = "1.1.1"
korlibs = "3.4.0" korlibs = "3.4.0"
uuid = "0.7.0" uuid = "0.7.0"
ktor = "2.2.4" ktor = "2.3.0"
ksp = "1.8.10-1.0.9" ksp = "1.8.20-1.0.11"
kotlin-poet = "1.12.0" kotlin-poet = "1.13.0"
microutils = "0.17.3" microutils = "0.17.8"
github-release-plugin = "2.4.1" github-release-plugin = "2.4.1"
dokka = "1.8.10" dokka = "1.8.10"
@@ -31,6 +31,8 @@ kotlin-test-js = { module = "org.jetbrains.kotlin:kotlin-test-js", version.ref =
ktor-client-core = { module = "io.ktor:ktor-client-core", version.ref = "ktor" } ktor-client-core = { module = "io.ktor:ktor-client-core", version.ref = "ktor" }
ktor-client-cio = { module = "io.ktor:ktor-client-cio", version.ref = "ktor" } ktor-client-cio = { module = "io.ktor:ktor-client-cio", version.ref = "ktor" }
ktor-client-curl = { module = "io.ktor:ktor-client-curl", version.ref = "ktor" }
ktor-client-winhttp = { module = "io.ktor:ktor-client-winhttp", version.ref = "ktor" }
ktor-server = { module = "io.ktor:ktor-server", version.ref = "ktor" } ktor-server = { module = "io.ktor:ktor-server", version.ref = "ktor" }
ktor-server-host-common = { module = "io.ktor:ktor-server-host-common", version.ref = "ktor" } ktor-server-host-common = { module = "io.ktor:ktor-server-host-common", version.ref = "ktor" }
@@ -45,6 +47,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

@@ -13,6 +13,8 @@ kotlin {
browser() browser()
nodejs() nodejs()
} }
linuxX64()
mingwX64()
sourceSets { sourceSets {
commonMain { commonMain {

View File

@@ -10,13 +10,6 @@ suspend fun TelegramBot.getStickerSet(
GetStickerSet(name) GetStickerSet(name)
) )
@Deprecated("Renamed", ReplaceWith("getStickerSetOrThrow(sticker)", "dev.inmo.tgbotapi.extensions.api.get.getStickerSetOrThrow"))
suspend fun TelegramBot.getStickerSet(
sticker: Sticker
) = getStickerSet(
sticker.stickerSetName ?: error("Sticker must contains stickerSetName to be correctly used in getStickerSet method")
)
suspend fun TelegramBot.getStickerSetOrNull( suspend fun TelegramBot.getStickerSetOrNull(
sticker: Sticker sticker: Sticker
) = sticker.stickerSetName ?.let { ) = sticker.stickerSetName ?.let {

View File

@@ -685,20 +685,22 @@ suspend inline fun TelegramBot.reply(
suspend inline fun TelegramBot.replyWithSticker( suspend inline fun TelegramBot.replyWithSticker(
to: Message, to: Message,
sticker: InputFile, sticker: InputFile,
emoji: String? = null,
disableNotification: Boolean = false, disableNotification: Boolean = false,
protectContent: Boolean = false, protectContent: Boolean = false,
allowSendingWithoutReply: Boolean? = null, allowSendingWithoutReply: Boolean? = null,
replyMarkup: KeyboardMarkup? = null replyMarkup: KeyboardMarkup? = null
) = sendSticker(to.chat, sticker, to.threadIdOrNull, disableNotification, protectContent, to.messageId, allowSendingWithoutReply, replyMarkup) ) = sendSticker(to.chat, sticker, to.threadIdOrNull, emoji, disableNotification, protectContent, to.messageId, allowSendingWithoutReply, replyMarkup)
suspend inline fun TelegramBot.reply( suspend inline fun TelegramBot.reply(
to: Message, to: Message,
sticker: Sticker, sticker: Sticker,
emoji: String? = null,
disableNotification: Boolean = false, disableNotification: Boolean = false,
protectContent: Boolean = false, protectContent: Boolean = false,
allowSendingWithoutReply: Boolean? = null, allowSendingWithoutReply: Boolean? = null,
replyMarkup: KeyboardMarkup? = null replyMarkup: KeyboardMarkup? = null
) = sendSticker(to.chat, sticker, to.threadIdOrNull, disableNotification, protectContent, to.messageId, allowSendingWithoutReply, replyMarkup) ) = sendSticker(to.chat, sticker, to.threadIdOrNull, emoji, disableNotification, protectContent, to.messageId, allowSendingWithoutReply, replyMarkup)
// Videos // Videos

View File

@@ -761,22 +761,24 @@ suspend inline fun TelegramBot.replyWithSticker(
toMessageId: MessageId, toMessageId: MessageId,
sticker: InputFile, sticker: InputFile,
threadId: MessageThreadId? = toChatId.threadId, threadId: MessageThreadId? = toChatId.threadId,
emoji: String? = null,
disableNotification: Boolean = false, disableNotification: Boolean = false,
protectContent: Boolean = false, protectContent: Boolean = false,
allowSendingWithoutReply: Boolean? = null, allowSendingWithoutReply: Boolean? = null,
replyMarkup: KeyboardMarkup? = null replyMarkup: KeyboardMarkup? = null
) = sendSticker(toChatId, sticker, threadId, disableNotification, protectContent, toMessageId, allowSendingWithoutReply, replyMarkup) ) = sendSticker(toChatId, sticker, threadId, emoji, disableNotification, protectContent, toMessageId, allowSendingWithoutReply, replyMarkup)
suspend inline fun TelegramBot.reply( suspend inline fun TelegramBot.reply(
toChatId: IdChatIdentifier, toChatId: IdChatIdentifier,
toMessageId: MessageId, toMessageId: MessageId,
sticker: Sticker, sticker: Sticker,
threadId: MessageThreadId? = toChatId.threadId, threadId: MessageThreadId? = toChatId.threadId,
emoji: String? = null,
disableNotification: Boolean = false, disableNotification: Boolean = false,
protectContent: Boolean = false, protectContent: Boolean = false,
allowSendingWithoutReply: Boolean? = null, allowSendingWithoutReply: Boolean? = null,
replyMarkup: KeyboardMarkup? = null replyMarkup: KeyboardMarkup? = null
) = sendSticker(toChatId, sticker, threadId, disableNotification, protectContent, toMessageId, allowSendingWithoutReply, replyMarkup) ) = sendSticker(toChatId, sticker, threadId, emoji, disableNotification, protectContent, toMessageId, allowSendingWithoutReply, replyMarkup)
// Videos // Videos

View File

@@ -1111,12 +1111,13 @@ suspend fun TelegramBot.send(
chatId: ChatIdentifier, chatId: ChatIdentifier,
sticker: Sticker, sticker: Sticker,
threadId: MessageThreadId? = chatId.threadId, threadId: MessageThreadId? = chatId.threadId,
emoji: String? = null,
disableNotification: Boolean = false, disableNotification: Boolean = false,
protectContent: Boolean = false, protectContent: Boolean = false,
replyToMessageId: MessageId? = null, replyToMessageId: MessageId? = null,
allowSendingWithoutReply: Boolean? = null, allowSendingWithoutReply: Boolean? = null,
replyMarkup: KeyboardMarkup? = null replyMarkup: KeyboardMarkup? = null
) = sendSticker(chatId, sticker, threadId, disableNotification, protectContent, replyToMessageId, allowSendingWithoutReply, replyMarkup) ) = sendSticker(chatId, sticker, threadId, emoji, disableNotification, protectContent, replyToMessageId, allowSendingWithoutReply, replyMarkup)
/** /**
* Will execute [sendSticker] request * Will execute [sendSticker] request
@@ -1127,12 +1128,13 @@ suspend fun TelegramBot.send(
chat: Chat, chat: Chat,
sticker: Sticker, sticker: Sticker,
threadId: MessageThreadId? = chat.id.threadId, threadId: MessageThreadId? = chat.id.threadId,
emoji: String? = null,
disableNotification: Boolean = false, disableNotification: Boolean = false,
protectContent: Boolean = false, protectContent: Boolean = false,
replyToMessageId: MessageId? = null, replyToMessageId: MessageId? = null,
allowSendingWithoutReply: Boolean? = null, allowSendingWithoutReply: Boolean? = null,
replyMarkup: KeyboardMarkup? = null replyMarkup: KeyboardMarkup? = null
) = sendSticker(chat, sticker, threadId, disableNotification, protectContent, replyToMessageId, allowSendingWithoutReply, replyMarkup) ) = sendSticker(chat, sticker, threadId, emoji, disableNotification, protectContent, replyToMessageId, allowSendingWithoutReply, replyMarkup)
/** /**

View File

@@ -19,13 +19,14 @@ suspend fun TelegramBot.sendSticker(
chatId: ChatIdentifier, chatId: ChatIdentifier,
sticker: InputFile, sticker: InputFile,
threadId: MessageThreadId? = chatId.threadId, threadId: MessageThreadId? = chatId.threadId,
emoji: String? = null,
disableNotification: Boolean = false, disableNotification: Boolean = false,
protectContent: Boolean = false, protectContent: Boolean = false,
replyToMessageId: MessageId? = null, replyToMessageId: MessageId? = null,
allowSendingWithoutReply: Boolean? = null, allowSendingWithoutReply: Boolean? = null,
replyMarkup: KeyboardMarkup? = null replyMarkup: KeyboardMarkup? = null
) = execute( ) = execute(
SendSticker(chatId, sticker, threadId, disableNotification, protectContent, replyToMessageId, allowSendingWithoutReply, replyMarkup) SendSticker(chatId, sticker, threadId, emoji, disableNotification, protectContent, replyToMessageId, allowSendingWithoutReply, replyMarkup)
) )
/** /**
@@ -36,12 +37,13 @@ suspend fun TelegramBot.sendSticker(
chat: Chat, chat: Chat,
sticker: InputFile, sticker: InputFile,
threadId: MessageThreadId? = chat.id.threadId, threadId: MessageThreadId? = chat.id.threadId,
emoji: String? = null,
disableNotification: Boolean = false, disableNotification: Boolean = false,
protectContent: Boolean = false, protectContent: Boolean = false,
replyToMessageId: MessageId? = null, replyToMessageId: MessageId? = null,
allowSendingWithoutReply: Boolean? = null, allowSendingWithoutReply: Boolean? = null,
replyMarkup: KeyboardMarkup? = null replyMarkup: KeyboardMarkup? = null
) = sendSticker(chat.id, sticker, threadId, disableNotification, protectContent, replyToMessageId, allowSendingWithoutReply, replyMarkup) ) = sendSticker(chat.id, sticker, threadId, emoji, disableNotification, protectContent, replyToMessageId, allowSendingWithoutReply, replyMarkup)
/** /**
* @param replyMarkup Some of [KeyboardMarkup]. See [dev.inmo.tgbotapi.extensions.utils.types.buttons.replyKeyboard] or * @param replyMarkup Some of [KeyboardMarkup]. See [dev.inmo.tgbotapi.extensions.utils.types.buttons.replyKeyboard] or
@@ -51,12 +53,13 @@ suspend fun TelegramBot.sendSticker(
chatId: ChatIdentifier, chatId: ChatIdentifier,
sticker: Sticker, sticker: Sticker,
threadId: MessageThreadId? = chatId.threadId, threadId: MessageThreadId? = chatId.threadId,
emoji: String? = null,
disableNotification: Boolean = false, disableNotification: Boolean = false,
protectContent: Boolean = false, protectContent: Boolean = false,
replyToMessageId: MessageId? = null, replyToMessageId: MessageId? = null,
allowSendingWithoutReply: Boolean? = null, allowSendingWithoutReply: Boolean? = null,
replyMarkup: KeyboardMarkup? = null replyMarkup: KeyboardMarkup? = null
) = sendSticker(chatId, sticker.fileId, threadId, disableNotification, protectContent, replyToMessageId, allowSendingWithoutReply, replyMarkup) ) = sendSticker(chatId, sticker.fileId, threadId, emoji, disableNotification, protectContent, replyToMessageId, allowSendingWithoutReply, replyMarkup)
/** /**
* @param replyMarkup Some of [KeyboardMarkup]. See [dev.inmo.tgbotapi.extensions.utils.types.buttons.replyKeyboard] or * @param replyMarkup Some of [KeyboardMarkup]. See [dev.inmo.tgbotapi.extensions.utils.types.buttons.replyKeyboard] or
@@ -66,9 +69,10 @@ suspend fun TelegramBot.sendSticker(
chat: Chat, chat: Chat,
sticker: Sticker, sticker: Sticker,
threadId: MessageThreadId? = chat.id.threadId, threadId: MessageThreadId? = chat.id.threadId,
emoji: String? = null,
disableNotification: Boolean = false, disableNotification: Boolean = false,
protectContent: Boolean = false, protectContent: Boolean = false,
replyToMessageId: MessageId? = null, replyToMessageId: MessageId? = null,
allowSendingWithoutReply: Boolean? = null, allowSendingWithoutReply: Boolean? = null,
replyMarkup: KeyboardMarkup? = null replyMarkup: KeyboardMarkup? = null
) = sendSticker(chat, sticker.fileId, threadId, disableNotification, protectContent, replyToMessageId, allowSendingWithoutReply, replyMarkup) ) = sendSticker(chat, sticker.fileId, threadId, emoji, disableNotification, protectContent, replyToMessageId, allowSendingWithoutReply, replyMarkup)

View File

@@ -1,90 +0,0 @@
package dev.inmo.tgbotapi.extensions.api.stickers
import dev.inmo.tgbotapi.bot.TelegramBot
import dev.inmo.tgbotapi.requests.abstracts.FileId
import dev.inmo.tgbotapi.requests.abstracts.MultipartFile
import dev.inmo.tgbotapi.requests.stickers.AddAnimatedStickerToSet
import dev.inmo.tgbotapi.types.chat.CommonUser
import dev.inmo.tgbotapi.types.UserId
import dev.inmo.tgbotapi.types.stickers.MaskPosition
import dev.inmo.tgbotapi.types.stickers.StickerSet
suspend fun TelegramBot.addAnimatedStickerToSet(
userId: UserId,
stickerSetName: String,
sticker: FileId,
emojis: String,
maskPosition: MaskPosition? = null
) = execute(
AddAnimatedStickerToSet(userId, stickerSetName, sticker, emojis, maskPosition)
)
suspend fun TelegramBot.addAnimatedStickerToSet(
userId: UserId,
stickerSetName: String,
sticker: MultipartFile,
emojis: String,
maskPosition: MaskPosition? = null
) = execute(
AddAnimatedStickerToSet(userId, stickerSetName, sticker, emojis, maskPosition)
)
suspend fun TelegramBot.addAnimatedStickerToSet(
user: CommonUser,
stickerSetName: String,
sticker: FileId,
emojis: String,
maskPosition: MaskPosition? = null
) = addAnimatedStickerToSet(
user.id, stickerSetName, sticker, emojis, maskPosition
)
suspend fun TelegramBot.addAnimatedStickerToSet(
user: CommonUser,
stickerSetName: String,
sticker: MultipartFile,
emojis: String,
maskPosition: MaskPosition? = null
) = addAnimatedStickerToSet(
user.id, stickerSetName, sticker, emojis, maskPosition
)
suspend fun TelegramBot.addAnimatedStickerToSet(
userId: UserId,
stickerSet: StickerSet,
sticker: FileId,
emojis: String,
maskPosition: MaskPosition? = null
) = addAnimatedStickerToSet(
userId, stickerSet.name, sticker, emojis, maskPosition
)
suspend fun TelegramBot.addAnimatedStickerToSet(
userId: UserId,
stickerSet: StickerSet,
sticker: MultipartFile,
emojis: String,
maskPosition: MaskPosition? = null
) = addAnimatedStickerToSet(
userId, stickerSet.name, sticker, emojis, maskPosition
)
suspend fun TelegramBot.addAnimatedStickerToSet(
user: CommonUser,
stickerSet: StickerSet,
sticker: FileId,
emojis: String,
maskPosition: MaskPosition? = null
) = addAnimatedStickerToSet(
user.id, stickerSet.name, sticker, emojis, maskPosition
)
suspend fun TelegramBot.addAnimatedStickerToSet(
user: CommonUser,
stickerSet: StickerSet,
sticker: MultipartFile,
emojis: String,
maskPosition: MaskPosition? = null
) = addAnimatedStickerToSet(
user.id, stickerSet.name, sticker, emojis, maskPosition
)

View File

@@ -1,90 +0,0 @@
package dev.inmo.tgbotapi.extensions.api.stickers
import dev.inmo.tgbotapi.bot.TelegramBot
import dev.inmo.tgbotapi.requests.abstracts.FileId
import dev.inmo.tgbotapi.requests.abstracts.MultipartFile
import dev.inmo.tgbotapi.requests.stickers.AddStaticStickerToSet
import dev.inmo.tgbotapi.types.chat.CommonUser
import dev.inmo.tgbotapi.types.UserId
import dev.inmo.tgbotapi.types.stickers.MaskPosition
import dev.inmo.tgbotapi.types.stickers.StickerSet
suspend fun TelegramBot.addStaticStickerToSet(
userId: UserId,
stickerSetName: String,
sticker: FileId,
emojis: String,
maskPosition: MaskPosition? = null
) = execute(
AddStaticStickerToSet(userId, stickerSetName, sticker, emojis, maskPosition)
)
suspend fun TelegramBot.addStaticStickerToSet(
userId: UserId,
stickerSetName: String,
sticker: MultipartFile,
emojis: String,
maskPosition: MaskPosition? = null
) = execute(
AddStaticStickerToSet(userId, stickerSetName, sticker, emojis, maskPosition)
)
suspend fun TelegramBot.addStaticStickerToSet(
user: CommonUser,
stickerSetName: String,
sticker: FileId,
emojis: String,
maskPosition: MaskPosition? = null
) = addStaticStickerToSet(
user.id, stickerSetName, sticker, emojis, maskPosition
)
suspend fun TelegramBot.addStaticStickerToSet(
user: CommonUser,
stickerSetName: String,
sticker: MultipartFile,
emojis: String,
maskPosition: MaskPosition? = null
) = addStaticStickerToSet(
user.id, stickerSetName, sticker, emojis, maskPosition
)
suspend fun TelegramBot.addStaticStickerToSet(
userId: UserId,
stickerSet: StickerSet,
sticker: FileId,
emojis: String,
maskPosition: MaskPosition? = null
) = addStaticStickerToSet(
userId, stickerSet.name, sticker, emojis, maskPosition
)
suspend fun TelegramBot.addStaticStickerToSet(
userId: UserId,
stickerSet: StickerSet,
sticker: MultipartFile,
emojis: String,
maskPosition: MaskPosition? = null
) = addStaticStickerToSet(
userId, stickerSet.name, sticker, emojis, maskPosition
)
suspend fun TelegramBot.addStaticStickerToSet(
user: CommonUser,
stickerSet: StickerSet,
sticker: FileId,
emojis: String,
maskPosition: MaskPosition? = null
) = addStaticStickerToSet(
user.id, stickerSet.name, sticker, emojis, maskPosition
)
suspend fun TelegramBot.addStaticStickerToSet(
user: CommonUser,
stickerSet: StickerSet,
sticker: MultipartFile,
emojis: String,
maskPosition: MaskPosition? = null
) = addStaticStickerToSet(
user.id, stickerSet.name, sticker, emojis, maskPosition
)

View File

@@ -0,0 +1,116 @@
package dev.inmo.tgbotapi.extensions.api.stickers
import dev.inmo.tgbotapi.bot.TelegramBot
import dev.inmo.tgbotapi.requests.abstracts.InputFile
import dev.inmo.tgbotapi.requests.stickers.AddStickerToSet
import dev.inmo.tgbotapi.requests.stickers.InputSticker
import dev.inmo.tgbotapi.types.StickerType
import dev.inmo.tgbotapi.types.chat.CommonUser
import dev.inmo.tgbotapi.types.UserId
import dev.inmo.tgbotapi.types.stickers.MaskPosition
import dev.inmo.tgbotapi.types.stickers.StickerSet
suspend fun TelegramBot.addStickerToSet(
userId: UserId,
stickerSetName: String,
inputSticker: InputSticker
) = execute(
AddStickerToSet(userId, stickerSetName, inputSticker)
)
suspend fun TelegramBot.addStickerToSet(
userId: UserId,
stickerSet: StickerSet,
sticker: InputSticker
) = addStickerToSet(
userId,
stickerSet.name,
sticker
)
suspend fun TelegramBot.addStickerToSet(
userId: UserId,
stickerSet: StickerSet,
sticker: InputFile,
emojis: List<String>,
keywords: List<String> = emptyList()
) = addStickerToSet(
userId,
stickerSet,
when (stickerSet.stickerType) {
StickerType.CustomEmoji -> InputSticker.WithKeywords.CustomEmoji(
sticker,
emojis,
keywords
)
StickerType.Mask -> InputSticker.Mask(
sticker,
emojis
)
StickerType.Regular -> InputSticker.WithKeywords.Regular(
sticker,
emojis,
keywords
)
is StickerType.Unknown -> error("Unable to create sticker to the set with type ${stickerSet.stickerType}")
}
)
suspend fun TelegramBot.addStickerToSet(
userId: UserId,
stickerSet: StickerSet,
sticker: InputFile,
emojis: List<String>,
maskPosition: MaskPosition? = null
) = addStickerToSet(
userId,
stickerSet.name,
when (stickerSet.stickerType) {
StickerType.CustomEmoji -> InputSticker.WithKeywords.CustomEmoji(
sticker,
emojis,
emptyList()
)
StickerType.Mask -> InputSticker.Mask(
sticker,
emojis,
maskPosition
)
StickerType.Regular -> InputSticker.WithKeywords.Regular(
sticker,
emojis,
emptyList()
)
is StickerType.Unknown -> error("Unable to create sticker to the set with type ${stickerSet.stickerType}")
}
)
suspend fun TelegramBot.addStickerToSet(
user: CommonUser,
stickerSet: StickerSet,
sticker: InputSticker
) = addStickerToSet(
user.id,
stickerSet.name,
sticker
)
suspend fun TelegramBot.addStickerToSet(
user: CommonUser,
stickerSet: StickerSet,
sticker: InputFile,
emojis: List<String>,
keywords: List<String> = emptyList()
) = addStickerToSet(
user.id, stickerSet, sticker, emojis, keywords
)
suspend fun TelegramBot.addStickerToSet(
user: CommonUser,
stickerSet: StickerSet,
sticker: InputFile,
emojis: List<String>,
maskPosition: MaskPosition? = null
) = addStickerToSet(
user.id, stickerSet, sticker, emojis, maskPosition
)

View File

@@ -1,90 +0,0 @@
package dev.inmo.tgbotapi.extensions.api.stickers
import dev.inmo.tgbotapi.bot.TelegramBot
import dev.inmo.tgbotapi.requests.abstracts.FileId
import dev.inmo.tgbotapi.requests.abstracts.MultipartFile
import dev.inmo.tgbotapi.requests.stickers.AddVideoStickerToSet
import dev.inmo.tgbotapi.types.chat.CommonUser
import dev.inmo.tgbotapi.types.UserId
import dev.inmo.tgbotapi.types.stickers.MaskPosition
import dev.inmo.tgbotapi.types.stickers.StickerSet
suspend fun TelegramBot.addVideoStickerToSet(
userId: UserId,
stickerSetName: String,
sticker: FileId,
emojis: String,
maskPosition: MaskPosition? = null
) = execute(
AddVideoStickerToSet(userId, stickerSetName, sticker, emojis, maskPosition)
)
suspend fun TelegramBot.addVideoStickerToSet(
userId: UserId,
stickerSetName: String,
sticker: MultipartFile,
emojis: String,
maskPosition: MaskPosition? = null
) = execute(
AddVideoStickerToSet(userId, stickerSetName, sticker, emojis, maskPosition)
)
suspend fun TelegramBot.addVideoStickerToSet(
user: CommonUser,
stickerSetName: String,
sticker: FileId,
emojis: String,
maskPosition: MaskPosition? = null
) = addVideoStickerToSet(
user.id, stickerSetName, sticker, emojis, maskPosition
)
suspend fun TelegramBot.addVideoStickerToSet(
user: CommonUser,
stickerSetName: String,
sticker: MultipartFile,
emojis: String,
maskPosition: MaskPosition? = null
) = addVideoStickerToSet(
user.id, stickerSetName, sticker, emojis, maskPosition
)
suspend fun TelegramBot.addVideoStickerToSet(
userId: UserId,
stickerSet: StickerSet,
sticker: FileId,
emojis: String,
maskPosition: MaskPosition? = null
) = addVideoStickerToSet(
userId, stickerSet.name, sticker, emojis, maskPosition
)
suspend fun TelegramBot.addVideoStickerToSet(
userId: UserId,
stickerSet: StickerSet,
sticker: MultipartFile,
emojis: String,
maskPosition: MaskPosition? = null
) = addVideoStickerToSet(
userId, stickerSet.name, sticker, emojis, maskPosition
)
suspend fun TelegramBot.addVideoStickerToSet(
user: CommonUser,
stickerSet: StickerSet,
sticker: FileId,
emojis: String,
maskPosition: MaskPosition? = null
) = addVideoStickerToSet(
user.id, stickerSet.name, sticker, emojis, maskPosition
)
suspend fun TelegramBot.addVideoStickerToSet(
user: CommonUser,
stickerSet: StickerSet,
sticker: MultipartFile,
emojis: String,
maskPosition: MaskPosition? = null
) = addVideoStickerToSet(
user.id, stickerSet.name, sticker, emojis, maskPosition
)

View File

@@ -1,58 +0,0 @@
package dev.inmo.tgbotapi.extensions.api.stickers
import dev.inmo.tgbotapi.bot.TelegramBot
import dev.inmo.tgbotapi.requests.abstracts.FileId
import dev.inmo.tgbotapi.requests.abstracts.MultipartFile
import dev.inmo.tgbotapi.requests.stickers.CreateNewAnimatedStickerSet
import dev.inmo.tgbotapi.types.chat.CommonUser
import dev.inmo.tgbotapi.types.UserId
import dev.inmo.tgbotapi.types.stickers.MaskPosition
suspend fun TelegramBot.createNewAnimatedStickerSet(
userId: UserId,
name: String,
title: String,
sticker: FileId,
emojis: String,
containsMasks: Boolean? = null,
maskPosition: MaskPosition? = null
) = execute(
CreateNewAnimatedStickerSet(userId, name, title, sticker, emojis, containsMasks, maskPosition)
)
suspend fun TelegramBot.createNewAnimatedStickerSet(
userId: UserId,
name: String,
title: String,
sticker: MultipartFile,
emojis: String,
containsMasks: Boolean? = null,
maskPosition: MaskPosition? = null
) = execute(
CreateNewAnimatedStickerSet(userId, name, title, sticker, emojis, containsMasks, maskPosition)
)
suspend fun TelegramBot.createNewAnimatedStickerSet(
user: CommonUser,
name: String,
title: String,
sticker: FileId,
emojis: String,
containsMasks: Boolean? = null,
maskPosition: MaskPosition? = null
) = createNewAnimatedStickerSet(
user.id, name, title, sticker, emojis, containsMasks, maskPosition
)
suspend fun TelegramBot.createNewAnimatedStickerSet(
user: CommonUser,
name: String,
title: String,
sticker: MultipartFile,
emojis: String,
containsMasks: Boolean? = null,
maskPosition: MaskPosition? = null
) = createNewAnimatedStickerSet(
user.id, name, title, sticker, emojis, containsMasks, maskPosition
)

View File

@@ -1,54 +0,0 @@
package dev.inmo.tgbotapi.extensions.api.stickers
import dev.inmo.tgbotapi.bot.TelegramBot
import dev.inmo.tgbotapi.requests.abstracts.FileId
import dev.inmo.tgbotapi.requests.abstracts.MultipartFile
import dev.inmo.tgbotapi.requests.stickers.*
import dev.inmo.tgbotapi.types.chat.CommonUser
import dev.inmo.tgbotapi.types.UserId
import dev.inmo.tgbotapi.types.stickers.MaskPosition
suspend fun TelegramBot.createNewMaskAnimatedStickerSet(
userId: UserId,
name: String,
title: String,
sticker: FileId,
emojis: String,
maskPosition: MaskPosition
) = execute(
CreateNewMaskAnimatedStickerSet(userId, name, title, sticker, emojis, maskPosition)
)
suspend fun TelegramBot.createNewMaskAnimatedStickerSet(
userId: UserId,
name: String,
title: String,
sticker: MultipartFile,
emojis: String,
maskPosition: MaskPosition
) = execute(
CreateNewMaskAnimatedStickerSet(userId, name, title, sticker, emojis, maskPosition)
)
suspend fun TelegramBot.createNewMaskAnimatedStickerSet(
user: CommonUser,
name: String,
title: String,
sticker: FileId,
emojis: String,
maskPosition: MaskPosition
) = createNewMaskAnimatedStickerSet(
user.id, name, title, sticker, emojis, maskPosition
)
suspend fun TelegramBot.createNewMaskAnimatedStickerSet(
user: CommonUser,
name: String,
title: String,
sticker: MultipartFile,
emojis: String,
maskPosition: MaskPosition
) = createNewMaskAnimatedStickerSet(
user.id, name, title, sticker, emojis, maskPosition
)

View File

@@ -1,54 +0,0 @@
package dev.inmo.tgbotapi.extensions.api.stickers
import dev.inmo.tgbotapi.bot.TelegramBot
import dev.inmo.tgbotapi.requests.abstracts.FileId
import dev.inmo.tgbotapi.requests.abstracts.MultipartFile
import dev.inmo.tgbotapi.requests.stickers.*
import dev.inmo.tgbotapi.types.chat.CommonUser
import dev.inmo.tgbotapi.types.UserId
import dev.inmo.tgbotapi.types.stickers.MaskPosition
suspend fun TelegramBot.createNewMaskStickerSet(
userId: UserId,
name: String,
title: String,
sticker: FileId,
emojis: String,
maskPosition: MaskPosition
) = execute(
CreateNewMaskStickerSet(userId, name, title, sticker, emojis, maskPosition)
)
suspend fun TelegramBot.createNewMaskStickerSet(
userId: UserId,
name: String,
title: String,
sticker: MultipartFile,
emojis: String,
maskPosition: MaskPosition
) = execute(
CreateNewMaskStickerSet(userId, name, title, sticker, emojis, maskPosition)
)
suspend fun TelegramBot.createNewMaskStickerSet(
user: CommonUser,
name: String,
title: String,
sticker: FileId,
emojis: String,
maskPosition: MaskPosition
) = createNewMaskStickerSet(
user.id, name, title, sticker, emojis, maskPosition
)
suspend fun TelegramBot.createNewMaskStickerSet(
user: CommonUser,
name: String,
title: String,
sticker: MultipartFile,
emojis: String,
maskPosition: MaskPosition
) = createNewMaskStickerSet(
user.id, name, title, sticker, emojis, maskPosition
)

View File

@@ -1,54 +0,0 @@
package dev.inmo.tgbotapi.extensions.api.stickers
import dev.inmo.tgbotapi.bot.TelegramBot
import dev.inmo.tgbotapi.requests.abstracts.FileId
import dev.inmo.tgbotapi.requests.abstracts.MultipartFile
import dev.inmo.tgbotapi.requests.stickers.*
import dev.inmo.tgbotapi.types.chat.CommonUser
import dev.inmo.tgbotapi.types.UserId
import dev.inmo.tgbotapi.types.stickers.MaskPosition
suspend fun TelegramBot.createNewMaskVideoStickerSet(
userId: UserId,
name: String,
title: String,
sticker: FileId,
emojis: String,
maskPosition: MaskPosition
) = execute(
CreateNewMaskVideoStickerSet(userId, name, title, sticker, emojis, maskPosition)
)
suspend fun TelegramBot.createNewMaskVideoStickerSet(
userId: UserId,
name: String,
title: String,
sticker: MultipartFile,
emojis: String,
maskPosition: MaskPosition
) = execute(
CreateNewMaskVideoStickerSet(userId, name, title, sticker, emojis, maskPosition)
)
suspend fun TelegramBot.createNewMaskVideoStickerSet(
user: CommonUser,
name: String,
title: String,
sticker: FileId,
emojis: String,
maskPosition: MaskPosition
) = createNewMaskVideoStickerSet(
user.id, name, title, sticker, emojis, maskPosition
)
suspend fun TelegramBot.createNewMaskVideoStickerSet(
user: CommonUser,
name: String,
title: String,
sticker: MultipartFile,
emojis: String,
maskPosition: MaskPosition
) = createNewMaskVideoStickerSet(
user.id, name, title, sticker, emojis, maskPosition
)

View File

@@ -1,50 +0,0 @@
package dev.inmo.tgbotapi.extensions.api.stickers
import dev.inmo.tgbotapi.bot.TelegramBot
import dev.inmo.tgbotapi.requests.abstracts.FileId
import dev.inmo.tgbotapi.requests.abstracts.MultipartFile
import dev.inmo.tgbotapi.requests.stickers.*
import dev.inmo.tgbotapi.types.chat.CommonUser
import dev.inmo.tgbotapi.types.UserId
import dev.inmo.tgbotapi.types.stickers.MaskPosition
suspend fun TelegramBot.createNewRegularAnimatedStickerSet(
userId: UserId,
name: String,
title: String,
sticker: FileId,
emojis: String
) = execute(
CreateNewRegularAnimatedStickerSet(userId, name, title, sticker, emojis)
)
suspend fun TelegramBot.createNewRegularAnimatedStickerSet(
userId: UserId,
name: String,
title: String,
sticker: MultipartFile,
emojis: String
) = execute(
CreateNewRegularAnimatedStickerSet(userId, name, title, sticker, emojis)
)
suspend fun TelegramBot.createNewRegularAnimatedStickerSet(
user: CommonUser,
name: String,
title: String,
sticker: FileId,
emojis: String
) = createNewRegularAnimatedStickerSet(
user.id, name, title, sticker, emojis
)
suspend fun TelegramBot.createNewRegularAnimatedStickerSet(
user: CommonUser,
name: String,
title: String,
sticker: MultipartFile,
emojis: String
) = createNewRegularAnimatedStickerSet(
user.id, name, title, sticker, emojis
)

View File

@@ -1,50 +0,0 @@
package dev.inmo.tgbotapi.extensions.api.stickers
import dev.inmo.tgbotapi.bot.TelegramBot
import dev.inmo.tgbotapi.requests.abstracts.FileId
import dev.inmo.tgbotapi.requests.abstracts.MultipartFile
import dev.inmo.tgbotapi.requests.stickers.*
import dev.inmo.tgbotapi.types.chat.CommonUser
import dev.inmo.tgbotapi.types.UserId
import dev.inmo.tgbotapi.types.stickers.MaskPosition
suspend fun TelegramBot.createNewRegularStickerSet(
userId: UserId,
name: String,
title: String,
sticker: FileId,
emojis: String
) = execute(
CreateNewRegularStickerSet(userId, name, title, sticker, emojis)
)
suspend fun TelegramBot.createNewRegularStickerSet(
userId: UserId,
name: String,
title: String,
sticker: MultipartFile,
emojis: String
) = execute(
CreateNewRegularStickerSet(userId, name, title, sticker, emojis)
)
suspend fun TelegramBot.createNewRegularStickerSet(
user: CommonUser,
name: String,
title: String,
sticker: FileId,
emojis: String
) = createNewRegularStickerSet(
user.id, name, title, sticker, emojis
)
suspend fun TelegramBot.createNewRegularStickerSet(
user: CommonUser,
name: String,
title: String,
sticker: MultipartFile,
emojis: String
) = createNewRegularStickerSet(
user.id, name, title, sticker, emojis
)

View File

@@ -1,50 +0,0 @@
package dev.inmo.tgbotapi.extensions.api.stickers
import dev.inmo.tgbotapi.bot.TelegramBot
import dev.inmo.tgbotapi.requests.abstracts.FileId
import dev.inmo.tgbotapi.requests.abstracts.MultipartFile
import dev.inmo.tgbotapi.requests.stickers.*
import dev.inmo.tgbotapi.types.chat.CommonUser
import dev.inmo.tgbotapi.types.UserId
import dev.inmo.tgbotapi.types.stickers.MaskPosition
suspend fun TelegramBot.createNewRegularVideoStickerSet(
userId: UserId,
name: String,
title: String,
sticker: FileId,
emojis: String
) = execute(
CreateNewRegularVideoStickerSet(userId, name, title, sticker, emojis)
)
suspend fun TelegramBot.createNewRegularVideoStickerSet(
userId: UserId,
name: String,
title: String,
sticker: MultipartFile,
emojis: String
) = execute(
CreateNewRegularVideoStickerSet(userId, name, title, sticker, emojis)
)
suspend fun TelegramBot.createNewRegularVideoStickerSet(
user: CommonUser,
name: String,
title: String,
sticker: FileId,
emojis: String
) = createNewRegularVideoStickerSet(
user.id, name, title, sticker, emojis
)
suspend fun TelegramBot.createNewRegularVideoStickerSet(
user: CommonUser,
name: String,
title: String,
sticker: MultipartFile,
emojis: String
) = createNewRegularVideoStickerSet(
user.id, name, title, sticker, emojis
)

View File

@@ -1,58 +0,0 @@
package dev.inmo.tgbotapi.extensions.api.stickers
import dev.inmo.tgbotapi.bot.TelegramBot
import dev.inmo.tgbotapi.requests.abstracts.FileId
import dev.inmo.tgbotapi.requests.abstracts.MultipartFile
import dev.inmo.tgbotapi.requests.stickers.CreateNewStaticStickerSet
import dev.inmo.tgbotapi.types.chat.CommonUser
import dev.inmo.tgbotapi.types.UserId
import dev.inmo.tgbotapi.types.stickers.MaskPosition
suspend fun TelegramBot.createNewStaticStickerSet(
userId: UserId,
name: String,
title: String,
sticker: FileId,
emojis: String,
containsMasks: Boolean? = null,
maskPosition: MaskPosition? = null
) = execute(
CreateNewStaticStickerSet(userId, name, title, sticker, emojis, containsMasks, maskPosition)
)
suspend fun TelegramBot.createNewStaticStickerSet(
userId: UserId,
name: String,
title: String,
sticker: MultipartFile,
emojis: String,
containsMasks: Boolean? = null,
maskPosition: MaskPosition? = null
) = execute(
CreateNewStaticStickerSet(userId, name, title, sticker, emojis, containsMasks, maskPosition)
)
suspend fun TelegramBot.createNewStaticStickerSet(
user: CommonUser,
name: String,
title: String,
sticker: FileId,
emojis: String,
containsMasks: Boolean? = null,
maskPosition: MaskPosition? = null
) = createNewStaticStickerSet(
user.id, name, title, sticker, emojis, containsMasks, maskPosition
)
suspend fun TelegramBot.createNewStaticStickerSet(
user: CommonUser,
name: String,
title: String,
sticker: MultipartFile,
emojis: String,
containsMasks: Boolean? = null,
maskPosition: MaskPosition? = null
) = createNewStaticStickerSet(
user.id, name, title, sticker, emojis, containsMasks, maskPosition
)

View File

@@ -0,0 +1,31 @@
package dev.inmo.tgbotapi.extensions.api.stickers
import dev.inmo.tgbotapi.bot.TelegramBot
import dev.inmo.tgbotapi.requests.stickers.CreateNewStickerSet
import dev.inmo.tgbotapi.requests.stickers.InputSticker
import dev.inmo.tgbotapi.types.StickerFormat
import dev.inmo.tgbotapi.types.chat.CommonUser
import dev.inmo.tgbotapi.types.UserId
suspend fun TelegramBot.createNewStickerSet(
userId: UserId,
name: String,
title: String,
stickersFormat: StickerFormat,
stickers: List<InputSticker>,
needsRepainting: Boolean = false
) = execute(
CreateNewStickerSet(userId, name, title, stickersFormat, stickers, needsRepainting)
)
suspend fun TelegramBot.createNewStickerSet(
user: CommonUser,
name: String,
title: String,
stickersFormat: StickerFormat,
stickers: List<InputSticker>,
needsRepainting: Boolean = false,
) = createNewStickerSet(
user.id, name, title, stickersFormat, stickers, needsRepainting
)

View File

@@ -1,58 +0,0 @@
package dev.inmo.tgbotapi.extensions.api.stickers
import dev.inmo.tgbotapi.bot.TelegramBot
import dev.inmo.tgbotapi.requests.abstracts.FileId
import dev.inmo.tgbotapi.requests.abstracts.MultipartFile
import dev.inmo.tgbotapi.requests.stickers.CreateNewVideoStickerSet
import dev.inmo.tgbotapi.types.chat.CommonUser
import dev.inmo.tgbotapi.types.UserId
import dev.inmo.tgbotapi.types.stickers.MaskPosition
suspend fun TelegramBot.createNewVideoStickerSet(
userId: UserId,
name: String,
title: String,
sticker: FileId,
emojis: String,
containsMasks: Boolean? = null,
maskPosition: MaskPosition? = null
) = execute(
CreateNewVideoStickerSet(userId, name, title, sticker, emojis, containsMasks, maskPosition)
)
suspend fun TelegramBot.createNewVideoStickerSet(
userId: UserId,
name: String,
title: String,
sticker: MultipartFile,
emojis: String,
containsMasks: Boolean? = null,
maskPosition: MaskPosition? = null
) = execute(
CreateNewVideoStickerSet(userId, name, title, sticker, emojis, containsMasks, maskPosition)
)
suspend fun TelegramBot.createNewVideoStickerSet(
user: CommonUser,
name: String,
title: String,
sticker: FileId,
emojis: String,
containsMasks: Boolean? = null,
maskPosition: MaskPosition? = null
) = createNewVideoStickerSet(
user.id, name, title, sticker, emojis, containsMasks, maskPosition
)
suspend fun TelegramBot.createNewVideoStickerSet(
user: CommonUser,
name: String,
title: String,
sticker: MultipartFile,
emojis: String,
containsMasks: Boolean? = null,
maskPosition: MaskPosition? = null
) = createNewVideoStickerSet(
user.id, name, title, sticker, emojis, containsMasks, maskPosition
)

View File

@@ -0,0 +1,26 @@
package dev.inmo.tgbotapi.extensions.api.thumbs
import dev.inmo.tgbotapi.bot.TelegramBot
import dev.inmo.tgbotapi.requests.abstracts.FileId
import dev.inmo.tgbotapi.requests.abstracts.MultipartFile
import dev.inmo.tgbotapi.requests.stickers.SetCustomEmojiStickerSetThumbnail
import dev.inmo.tgbotapi.requests.stickers.SetStickerSetThumbnail
import dev.inmo.tgbotapi.types.CustomEmojiId
import dev.inmo.tgbotapi.types.StickerSetName
import dev.inmo.tgbotapi.types.chat.CommonUser
import dev.inmo.tgbotapi.types.UserId
import dev.inmo.tgbotapi.types.stickers.StickerSet
suspend fun TelegramBot.setCustomEmojiStickerSetThumbnail(
stickerSetName: StickerSetName,
customEmojiId: CustomEmojiId
) = execute(
SetCustomEmojiStickerSetThumbnail(stickerSetName, customEmojiId)
)
suspend fun TelegramBot.setCustomEmojiStickerSetThumbnail(
stickerSet: StickerSet,
customEmojiId: CustomEmojiId
) = setCustomEmojiStickerSetThumbnail(
stickerSet.name, customEmojiId
)

View File

@@ -3,19 +3,22 @@ package dev.inmo.tgbotapi.extensions.api.stickers
import dev.inmo.tgbotapi.bot.TelegramBot import dev.inmo.tgbotapi.bot.TelegramBot
import dev.inmo.tgbotapi.requests.abstracts.MultipartFile import dev.inmo.tgbotapi.requests.abstracts.MultipartFile
import dev.inmo.tgbotapi.requests.stickers.UploadStickerFile import dev.inmo.tgbotapi.requests.stickers.UploadStickerFile
import dev.inmo.tgbotapi.types.StickerFormat
import dev.inmo.tgbotapi.types.chat.CommonUser import dev.inmo.tgbotapi.types.chat.CommonUser
import dev.inmo.tgbotapi.types.UserId import dev.inmo.tgbotapi.types.UserId
suspend fun TelegramBot.uploadStickerFile( suspend fun TelegramBot.uploadStickerFile(
userId: UserId, userId: UserId,
sticker: MultipartFile sticker: MultipartFile,
stickerFormat: StickerFormat
) = execute( ) = execute(
UploadStickerFile(userId, sticker) UploadStickerFile(userId, sticker, stickerFormat)
) )
suspend fun TelegramBot.uploadStickerFile( suspend fun TelegramBot.uploadStickerFile(
user: CommonUser, user: CommonUser,
sticker: MultipartFile sticker: MultipartFile,
stickerFormat: StickerFormat
) = execute( ) = execute(
UploadStickerFile(user.id, sticker) UploadStickerFile(user.id, sticker, stickerFormat)
) )

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

@@ -93,8 +93,9 @@ interface BehaviourContextWithFSM<T : State> : BehaviourContext, StatesMachine<T
behaviourContext: BehaviourContext, behaviourContext: BehaviourContext,
handlers: List<BehaviourWithFSMStateHandlerHolder<*, T>>, handlers: List<BehaviourWithFSMStateHandlerHolder<*, T>>,
statesManager: StatesManager<T>, statesManager: StatesManager<T>,
fallbackHandler: BehaviourWithFSMStateHandlerHolder<T, T>? = null,
onStateHandlingErrorHandler: StateHandlingErrorHandler<T> = defaultStateHandlingErrorHandler() onStateHandlingErrorHandler: StateHandlingErrorHandler<T> = defaultStateHandlingErrorHandler()
) = DefaultBehaviourContextWithFSM<T>(behaviourContext, statesManager, handlers, onStateHandlingErrorHandler) ) = DefaultBehaviourContextWithFSM<T>(behaviourContext, statesManager, handlers, fallbackHandler, onStateHandlingErrorHandler)
} }
} }
@@ -129,11 +130,12 @@ class DefaultBehaviourContextWithFSM<T : State>(
private val behaviourContext: BehaviourContext, private val behaviourContext: BehaviourContext,
private val statesManager: StatesManager<T>, private val statesManager: StatesManager<T>,
private val handlers: List<BehaviourWithFSMStateHandlerHolder<*, T>>, private val handlers: List<BehaviourWithFSMStateHandlerHolder<*, T>>,
private val fallbackHandler: BehaviourWithFSMStateHandlerHolder<T, T>? = null,
private val onStateHandlingErrorHandler: StateHandlingErrorHandler<T> = defaultStateHandlingErrorHandler() private val onStateHandlingErrorHandler: StateHandlingErrorHandler<T> = defaultStateHandlingErrorHandler()
) : BehaviourContext by behaviourContext, BehaviourContextWithFSM<T> { ) : BehaviourContext by behaviourContext, BehaviourContextWithFSM<T> {
private val updatesFlows = mutableMapOf<Any, DefaultBehaviourContextWithFSM<T>>() private val updatesFlows = mutableMapOf<Any, DefaultBehaviourContextWithFSM<T>>()
private val additionalHandlers = mutableListOf<BehaviourWithFSMStateHandlerHolder<*, T>>() private val additionalHandlers = mutableListOf<BehaviourWithFSMStateHandlerHolder<*, T>>()
private var actualHandlersList = additionalHandlers + handlers private var actualHandlersList = additionalHandlers + handlers + listOfNotNull(fallbackHandler)
protected val statesJobs = mutableMapOf<T, Job>() protected val statesJobs = mutableMapOf<T, Job>()
protected val statesJobsMutex = Mutex() protected val statesJobsMutex = Mutex()
@@ -250,6 +252,7 @@ class DefaultBehaviourContextWithFSM<T : State>(
behaviourContext.copy(bot, scope, broadcastChannelsSize, onBufferOverflow, upstreamUpdatesFlow, triggersHolder), behaviourContext.copy(bot, scope, broadcastChannelsSize, onBufferOverflow, upstreamUpdatesFlow, triggersHolder),
handlers, handlers,
statesManager, statesManager,
fallbackHandler,
onStateHandlingErrorHandler onStateHandlingErrorHandler
) )
@@ -265,6 +268,7 @@ class DefaultBehaviourContextWithFSM<T : State>(
behaviourContext.copy(bot, scope, broadcastChannelsSize, onBufferOverflow, upstreamUpdatesFlow, triggersHolder), behaviourContext.copy(bot, scope, broadcastChannelsSize, onBufferOverflow, upstreamUpdatesFlow, triggersHolder),
handlers, handlers,
statesManager, statesManager,
fallbackHandler,
onStateHandlingErrorHandler onStateHandlingErrorHandler
) )
} }

View File

@@ -31,6 +31,7 @@ suspend fun <T : State> TelegramBot.buildBehaviourWithFSM(
defaultExceptionsHandler: ExceptionHandler<Unit>? = null, defaultExceptionsHandler: ExceptionHandler<Unit>? = null,
statesManager: StatesManager<T> = DefaultStatesManager(InMemoryDefaultStatesManagerRepo()), statesManager: StatesManager<T> = DefaultStatesManager(InMemoryDefaultStatesManagerRepo()),
presetHandlers: List<BehaviourWithFSMStateHandlerHolder<*, T>> = listOf(), presetHandlers: List<BehaviourWithFSMStateHandlerHolder<*, T>> = listOf(),
fallbackHandler: BehaviourWithFSMStateHandlerHolder<T, T>? = null,
onStateHandlingErrorHandler: StateHandlingErrorHandler<T> = defaultStateHandlingErrorHandler(), onStateHandlingErrorHandler: StateHandlingErrorHandler<T> = defaultStateHandlingErrorHandler(),
block: CustomBehaviourContextReceiver<DefaultBehaviourContextWithFSM<T>, Unit> block: CustomBehaviourContextReceiver<DefaultBehaviourContextWithFSM<T>, Unit>
): DefaultBehaviourContextWithFSM<T> = BehaviourContextWithFSM( ): DefaultBehaviourContextWithFSM<T> = BehaviourContextWithFSM(
@@ -41,6 +42,7 @@ suspend fun <T : State> TelegramBot.buildBehaviourWithFSM(
), ),
presetHandlers, presetHandlers,
statesManager, statesManager,
fallbackHandler,
onStateHandlingErrorHandler onStateHandlingErrorHandler
).apply { block() } ).apply { block() }
@@ -59,6 +61,7 @@ suspend fun <T : State> TelegramBot.buildBehaviourWithFSMAndStartLongPolling(
defaultExceptionsHandler: ExceptionHandler<Unit>? = null, defaultExceptionsHandler: ExceptionHandler<Unit>? = null,
statesManager: StatesManager<T> = DefaultStatesManager(InMemoryDefaultStatesManagerRepo()), statesManager: StatesManager<T> = DefaultStatesManager(InMemoryDefaultStatesManagerRepo()),
presetHandlers: List<BehaviourWithFSMStateHandlerHolder<*, T>> = listOf(), presetHandlers: List<BehaviourWithFSMStateHandlerHolder<*, T>> = listOf(),
fallbackHandler: BehaviourWithFSMStateHandlerHolder<T, T>? = null,
onStateHandlingErrorHandler: StateHandlingErrorHandler<T> = defaultStateHandlingErrorHandler(), onStateHandlingErrorHandler: StateHandlingErrorHandler<T> = defaultStateHandlingErrorHandler(),
timeoutSeconds: Seconds = 30, timeoutSeconds: Seconds = 30,
autoDisableWebhooks: Boolean = true, autoDisableWebhooks: Boolean = true,
@@ -71,6 +74,7 @@ suspend fun <T : State> TelegramBot.buildBehaviourWithFSMAndStartLongPolling(
defaultExceptionsHandler, defaultExceptionsHandler,
statesManager, statesManager,
presetHandlers, presetHandlers,
fallbackHandler,
onStateHandlingErrorHandler, onStateHandlingErrorHandler,
block block
).run { ).run {
@@ -104,6 +108,7 @@ suspend fun <T : State> TelegramBot.buildBehaviourWithFSM(
defaultExceptionsHandler: ExceptionHandler<Unit>? = null, defaultExceptionsHandler: ExceptionHandler<Unit>? = null,
statesManager: StatesManager<T> = DefaultStatesManager(InMemoryDefaultStatesManagerRepo()), statesManager: StatesManager<T> = DefaultStatesManager(InMemoryDefaultStatesManagerRepo()),
presetHandlers: List<BehaviourWithFSMStateHandlerHolder<*, T>> = listOf(), presetHandlers: List<BehaviourWithFSMStateHandlerHolder<*, T>> = listOf(),
fallbackHandler: BehaviourWithFSMStateHandlerHolder<T, T>? = null,
onStateHandlingErrorHandler: StateHandlingErrorHandler<T> = defaultStateHandlingErrorHandler(), onStateHandlingErrorHandler: StateHandlingErrorHandler<T> = defaultStateHandlingErrorHandler(),
block: CustomBehaviourContextReceiver<DefaultBehaviourContextWithFSM<T>, Unit> block: CustomBehaviourContextReceiver<DefaultBehaviourContextWithFSM<T>, Unit>
): DefaultBehaviourContextWithFSM<T> = BehaviourContextWithFSM( ): DefaultBehaviourContextWithFSM<T> = BehaviourContextWithFSM(
@@ -114,6 +119,7 @@ suspend fun <T : State> TelegramBot.buildBehaviourWithFSM(
), ),
presetHandlers, presetHandlers,
statesManager, statesManager,
fallbackHandler,
onStateHandlingErrorHandler onStateHandlingErrorHandler
).apply { block() } ).apply { block() }
@@ -137,6 +143,7 @@ suspend fun <T : State> TelegramBot.buildBehaviourWithFSMAndStartLongPolling(
defaultExceptionsHandler: ExceptionHandler<Unit>? = null, defaultExceptionsHandler: ExceptionHandler<Unit>? = null,
statesManager: StatesManager<T> = DefaultStatesManager(InMemoryDefaultStatesManagerRepo()), statesManager: StatesManager<T> = DefaultStatesManager(InMemoryDefaultStatesManagerRepo()),
presetHandlers: List<BehaviourWithFSMStateHandlerHolder<*, T>> = listOf(), presetHandlers: List<BehaviourWithFSMStateHandlerHolder<*, T>> = listOf(),
fallbackHandler: BehaviourWithFSMStateHandlerHolder<T, T>? = null,
onStateHandlingErrorHandler: StateHandlingErrorHandler<T> = defaultStateHandlingErrorHandler(), onStateHandlingErrorHandler: StateHandlingErrorHandler<T> = defaultStateHandlingErrorHandler(),
timeoutSeconds: Seconds = 30, timeoutSeconds: Seconds = 30,
autoDisableWebhooks: Boolean = true, autoDisableWebhooks: Boolean = true,
@@ -150,6 +157,7 @@ suspend fun <T : State> TelegramBot.buildBehaviourWithFSMAndStartLongPolling(
defaultExceptionsHandler, defaultExceptionsHandler,
statesManager, statesManager,
presetHandlers, presetHandlers,
fallbackHandler,
onStateHandlingErrorHandler, onStateHandlingErrorHandler,
block block
).run { ).run {

View File

@@ -46,6 +46,7 @@ suspend fun <T : State> telegramBotWithBehaviourAndFSM(
defaultExceptionsHandler: ExceptionHandler<Unit>? = null, defaultExceptionsHandler: ExceptionHandler<Unit>? = null,
statesManager: StatesManager<T> = DefaultStatesManager(InMemoryDefaultStatesManagerRepo()), statesManager: StatesManager<T> = DefaultStatesManager(InMemoryDefaultStatesManagerRepo()),
presetHandlers: List<BehaviourWithFSMStateHandlerHolder<*, T>> = listOf(), presetHandlers: List<BehaviourWithFSMStateHandlerHolder<*, T>> = listOf(),
fallbackHandler: BehaviourWithFSMStateHandlerHolder<T, T>? = null,
testServer: Boolean = false, testServer: Boolean = false,
onStateHandlingErrorHandler: StateHandlingErrorHandler<T> = defaultStateHandlingErrorHandler(), onStateHandlingErrorHandler: StateHandlingErrorHandler<T> = defaultStateHandlingErrorHandler(),
timeoutSeconds: Seconds = 30, timeoutSeconds: Seconds = 30,
@@ -65,6 +66,7 @@ suspend fun <T : State> telegramBotWithBehaviourAndFSM(
defaultExceptionsHandler, defaultExceptionsHandler,
statesManager, statesManager,
presetHandlers, presetHandlers,
fallbackHandler,
onStateHandlingErrorHandler, onStateHandlingErrorHandler,
timeoutSeconds, timeoutSeconds,
autoDisableWebhooks, autoDisableWebhooks,
@@ -97,6 +99,7 @@ suspend fun <T : State> telegramBotWithBehaviourAndFSMAndStartLongPolling(
defaultExceptionsHandler: ExceptionHandler<Unit>? = null, defaultExceptionsHandler: ExceptionHandler<Unit>? = null,
statesManager: StatesManager<T> = DefaultStatesManager(InMemoryDefaultStatesManagerRepo()), statesManager: StatesManager<T> = DefaultStatesManager(InMemoryDefaultStatesManagerRepo()),
presetHandlers: List<BehaviourWithFSMStateHandlerHolder<*, T>> = listOf(), presetHandlers: List<BehaviourWithFSMStateHandlerHolder<*, T>> = listOf(),
fallbackHandler: BehaviourWithFSMStateHandlerHolder<T, T>? = null,
testServer: Boolean = false, testServer: Boolean = false,
onStateHandlingErrorHandler: StateHandlingErrorHandler<T> = defaultStateHandlingErrorHandler(), onStateHandlingErrorHandler: StateHandlingErrorHandler<T> = defaultStateHandlingErrorHandler(),
timeoutSeconds: Seconds = 30, timeoutSeconds: Seconds = 30,
@@ -116,6 +119,7 @@ suspend fun <T : State> telegramBotWithBehaviourAndFSMAndStartLongPolling(
defaultExceptionsHandler, defaultExceptionsHandler,
statesManager, statesManager,
presetHandlers, presetHandlers,
fallbackHandler,
onStateHandlingErrorHandler, onStateHandlingErrorHandler,
timeoutSeconds, timeoutSeconds,
autoDisableWebhooks, autoDisableWebhooks,

View File

@@ -5,6 +5,7 @@ package dev.inmo.tgbotapi.extensions.behaviour_builder
import dev.inmo.micro_utils.coroutines.* import dev.inmo.micro_utils.coroutines.*
import dev.inmo.tgbotapi.bot.TelegramBot import dev.inmo.tgbotapi.bot.TelegramBot
import dev.inmo.tgbotapi.extensions.behaviour_builder.utils.handlers_registrar.TriggersHolder import dev.inmo.tgbotapi.extensions.behaviour_builder.utils.handlers_registrar.TriggersHolder
import dev.inmo.tgbotapi.types.UpdateIdentifier
import dev.inmo.tgbotapi.types.update.abstracts.Update import dev.inmo.tgbotapi.types.update.abstracts.Update
import dev.inmo.tgbotapi.updateshandlers.* import dev.inmo.tgbotapi.updateshandlers.*
import kotlinx.coroutines.* import kotlinx.coroutines.*
@@ -71,9 +72,17 @@ class DefaultBehaviourContext(
private val additionalUpdatesSharedFlow = MutableSharedFlow<Update>(0, broadcastChannelsSize, onBufferOverflow) private val additionalUpdatesSharedFlow = MutableSharedFlow<Update>(0, broadcastChannelsSize, onBufferOverflow)
override val allUpdatesFlow: Flow<Update> = (additionalUpdatesSharedFlow.asSharedFlow()).let { override val allUpdatesFlow: Flow<Update> = (additionalUpdatesSharedFlow.asSharedFlow()).let {
if (upstreamUpdatesFlow != null) { if (upstreamUpdatesFlow != null) {
var lastHandledUpdate = -1L val handledUpdates = mutableSetOf<UpdateIdentifier>()
(it + upstreamUpdatesFlow).filter { (it + upstreamUpdatesFlow).filter {
(it.updateId > lastHandledUpdate).also { passed -> if (passed) { lastHandledUpdate = it.updateId } } val passed = handledUpdates.add(it.updateId)
(passed).also { passed ->
val needToDropCount = handledUpdates.size - broadcastChannelsSize
if (needToDropCount > 0) {
handledUpdates.removeAll(
handledUpdates.take(needToDropCount).ifEmpty { return@also }
)
}
}
} }
} else { } else {
it it

View File

@@ -20,15 +20,6 @@ suspend inline fun <reified O : MessageContent> BehaviourContext.waitContent(
): Flow<O> = waitContentMessage<O>(initRequest, errorFactory).map { it.content } ): Flow<O> = waitContentMessage<O>(initRequest, errorFactory).map { it.content }
@Deprecated(
includeMediaGroupsDeprecationMessage,
ReplaceWith("waitAnyContent(initRequest, errorFactory)", "dev.inmo.tgbotapi.extensions.behaviour_builder.expectations.waitAnyContent")
)
suspend fun BehaviourContext.waitContent(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null },
includeMediaGroups: Boolean
) = waitContent<MessageContent>(initRequest, errorFactory)
suspend fun BehaviourContext.waitAnyContent( suspend fun BehaviourContext.waitAnyContent(
initRequest: Request<*>? = null, initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null } errorFactory: NullableRequestBuilder<*> = { null }
@@ -69,62 +60,26 @@ suspend fun BehaviourContext.waitVenue(
initRequest: Request<*>? = null, initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null } errorFactory: NullableRequestBuilder<*> = { null }
) = waitContent<VenueContent>(initRequest, errorFactory) ) = waitContent<VenueContent>(initRequest, errorFactory)
@Deprecated(includeMediaGroupsDeprecationMessage)
suspend fun BehaviourContext.waitAudioMediaGroupContent(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null },
includeMediaGroups: Boolean
) = waitContent<AudioMediaGroupPartContent>(initRequest, errorFactory)
suspend fun BehaviourContext.waitAudioMediaGroupContent( suspend fun BehaviourContext.waitAudioMediaGroupContent(
initRequest: Request<*>? = null, initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null }, errorFactory: NullableRequestBuilder<*> = { null },
) = waitContent<AudioMediaGroupPartContent>(initRequest, errorFactory) ) = waitContent<AudioMediaGroupPartContent>(initRequest, errorFactory)
@Deprecated(includeMediaGroupsDeprecationMessage)
suspend fun BehaviourContext.waitDocumentMediaGroupContent(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null },
includeMediaGroups: Boolean
) = waitContent<DocumentMediaGroupPartContent>(initRequest, errorFactory)
suspend fun BehaviourContext.waitDocumentMediaGroupContent( suspend fun BehaviourContext.waitDocumentMediaGroupContent(
initRequest: Request<*>? = null, initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null } errorFactory: NullableRequestBuilder<*> = { null }
) = waitContent<DocumentMediaGroupPartContent>(initRequest, errorFactory) ) = waitContent<DocumentMediaGroupPartContent>(initRequest, errorFactory)
@Deprecated(includeMediaGroupsDeprecationMessage)
suspend fun BehaviourContext.waitMedia(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null },
includeMediaGroups: Boolean
) = waitContent<MediaContent>(initRequest, errorFactory)
suspend fun BehaviourContext.waitMedia( suspend fun BehaviourContext.waitMedia(
initRequest: Request<*>? = null, initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null } errorFactory: NullableRequestBuilder<*> = { null }
) = waitContent<MediaContent>(initRequest, errorFactory) ) = waitContent<MediaContent>(initRequest, errorFactory)
@Deprecated(includeMediaGroupsDeprecationMessage)
suspend fun BehaviourContext.waitAnyMediaGroupContent(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null },
includeMediaGroups: Boolean
) = waitContent<MediaGroupPartContent>(initRequest, errorFactory)
suspend fun BehaviourContext.waitAnyMediaGroupContent( suspend fun BehaviourContext.waitAnyMediaGroupContent(
initRequest: Request<*>? = null, initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null }, errorFactory: NullableRequestBuilder<*> = { null },
) = waitContent<MediaGroupPartContent>(initRequest, errorFactory) ) = waitContent<MediaGroupPartContent>(initRequest, errorFactory)
@Deprecated(includeMediaGroupsDeprecationMessage)
suspend fun BehaviourContext.waitVisualMediaGroupContent(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null },
includeMediaGroups: Boolean
) = waitContent<VisualMediaGroupPartContent>(initRequest, errorFactory)
suspend fun BehaviourContext.waitVisualMediaGroupContent( suspend fun BehaviourContext.waitVisualMediaGroupContent(
initRequest: Request<*>? = null, initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null }, errorFactory: NullableRequestBuilder<*> = { null },
) = waitContent<VisualMediaGroupPartContent>(initRequest, errorFactory) ) = waitContent<VisualMediaGroupPartContent>(initRequest, errorFactory)
@Deprecated(includeMediaGroupsDeprecationMessage)
suspend fun BehaviourContext.waitTextedMediaContent(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null },
includeMediaGroups: Boolean
) = waitContent<TextedMediaContent>(initRequest, errorFactory)
suspend fun BehaviourContext.waitTextedMediaContent( suspend fun BehaviourContext.waitTextedMediaContent(
initRequest: Request<*>? = null, initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null }, errorFactory: NullableRequestBuilder<*> = { null },
@@ -133,32 +88,14 @@ suspend fun BehaviourContext.waitAnimation(
initRequest: Request<*>? = null, initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null } errorFactory: NullableRequestBuilder<*> = { null }
) = waitContent<AnimationContent>(initRequest, errorFactory) ) = waitContent<AnimationContent>(initRequest, errorFactory)
@Deprecated(includeMediaGroupsDeprecationMessage)
suspend fun BehaviourContext.waitAudio(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null },
includeMediaGroups: Boolean
) = waitContent<AudioContent>(initRequest, errorFactory)
suspend fun BehaviourContext.waitAudio( suspend fun BehaviourContext.waitAudio(
initRequest: Request<*>? = null, initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null }, errorFactory: NullableRequestBuilder<*> = { null },
) = waitContent<AudioContent>(initRequest, errorFactory) ) = waitContent<AudioContent>(initRequest, errorFactory)
@Deprecated(includeMediaGroupsDeprecationMessage)
suspend fun BehaviourContext.waitDocument(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null },
includeMediaGroups: Boolean
) = waitContent<DocumentContent>(initRequest, errorFactory)
suspend fun BehaviourContext.waitDocument( suspend fun BehaviourContext.waitDocument(
initRequest: Request<*>? = null, initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null }, errorFactory: NullableRequestBuilder<*> = { null },
) = waitContent<DocumentContent>(initRequest, errorFactory) ) = waitContent<DocumentContent>(initRequest, errorFactory)
@Deprecated(includeMediaGroupsDeprecationMessage)
suspend fun BehaviourContext.waitPhoto(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null },
includeMediaGroups: Boolean
) = waitContent<PhotoContent>(initRequest, errorFactory)
suspend fun BehaviourContext.waitPhoto( suspend fun BehaviourContext.waitPhoto(
initRequest: Request<*>? = null, initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null }, errorFactory: NullableRequestBuilder<*> = { null },
@@ -167,12 +104,6 @@ suspend fun BehaviourContext.waitSticker(
initRequest: Request<*>? = null, initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null } errorFactory: NullableRequestBuilder<*> = { null }
) = waitContent<StickerContent>(initRequest, errorFactory) ) = waitContent<StickerContent>(initRequest, errorFactory)
@Deprecated(includeMediaGroupsDeprecationMessage)
suspend fun BehaviourContext.waitVideo(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null },
includeMediaGroups: Boolean
) = waitContent<VideoContent>(initRequest, errorFactory)
suspend fun BehaviourContext.waitVideo( suspend fun BehaviourContext.waitVideo(
initRequest: Request<*>? = null, initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null } errorFactory: NullableRequestBuilder<*> = { null }

View File

@@ -13,7 +13,6 @@ import dev.inmo.tgbotapi.utils.RiskFeature
import dev.inmo.tgbotapi.utils.lowLevelRiskFeatureMessage import dev.inmo.tgbotapi.utils.lowLevelRiskFeatureMessage
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
const val includeMediaGroupsDeprecationMessage = "includeMediaGroups is deprecated and its usage will not lead to any changes"
typealias CommonMessageToCommonMessageMapper<T> = suspend CommonMessage<T>.() -> CommonMessage<T>? typealias CommonMessageToCommonMessageMapper<T> = suspend CommonMessage<T>.() -> CommonMessage<T>?
@RiskFeature(lowLevelRiskFeatureMessage) @RiskFeature(lowLevelRiskFeatureMessage)
@@ -47,15 +46,6 @@ internal inline fun <reified T : MessageContent> contentMessageConverter(
if (content is T) this as CommonMessage<T> else null if (content is T) this as CommonMessage<T> else null
} }
@Deprecated(
includeMediaGroupsDeprecationMessage,
ReplaceWith("waitAnyContentMessage(initRequest, errorFactory)", "dev.inmo.tgbotapi.extensions.behaviour_builder.expectations.waitAnyContentMessage")
)
suspend fun BehaviourContext.waitContentMessage(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null },
includeMediaGroups: Boolean
) = waitContentMessage<MessageContent>(initRequest, errorFactory)
suspend fun BehaviourContext.waitAnyContentMessage( suspend fun BehaviourContext.waitAnyContentMessage(
initRequest: Request<*>? = null, initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null }, errorFactory: NullableRequestBuilder<*> = { null },
@@ -96,62 +86,26 @@ suspend fun BehaviourContext.waitVenueMessage(
initRequest: Request<*>? = null, initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null } errorFactory: NullableRequestBuilder<*> = { null }
) = waitContentMessage<VenueContent>(initRequest, errorFactory) ) = waitContentMessage<VenueContent>(initRequest, errorFactory)
@Deprecated(includeMediaGroupsDeprecationMessage)
suspend fun BehaviourContext.waitAudioMediaGroupContentMessage(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null },
includeMediaGroups: Boolean
) = waitContentMessage<AudioMediaGroupPartContent>(initRequest, errorFactory)
suspend fun BehaviourContext.waitAudioMediaGroupContentMessage( suspend fun BehaviourContext.waitAudioMediaGroupContentMessage(
initRequest: Request<*>? = null, initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null } errorFactory: NullableRequestBuilder<*> = { null }
) = waitContentMessage<AudioMediaGroupPartContent>(initRequest, errorFactory) ) = waitContentMessage<AudioMediaGroupPartContent>(initRequest, errorFactory)
@Deprecated(includeMediaGroupsDeprecationMessage)
suspend fun BehaviourContext.waitDocumentMediaGroupContentMessage(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null },
includeMediaGroups: Boolean
) = waitContentMessage<DocumentMediaGroupPartContent>(initRequest, errorFactory)
suspend fun BehaviourContext.waitDocumentMediaGroupContentMessage( suspend fun BehaviourContext.waitDocumentMediaGroupContentMessage(
initRequest: Request<*>? = null, initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null } errorFactory: NullableRequestBuilder<*> = { null }
) = waitContentMessage<DocumentMediaGroupPartContent>(initRequest, errorFactory) ) = waitContentMessage<DocumentMediaGroupPartContent>(initRequest, errorFactory)
@Deprecated(includeMediaGroupsDeprecationMessage)
suspend fun BehaviourContext.waitMediaMessage(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null },
includeMediaGroups: Boolean
) = waitContentMessage<MediaContent>(initRequest, errorFactory)
suspend fun BehaviourContext.waitMediaMessage( suspend fun BehaviourContext.waitMediaMessage(
initRequest: Request<*>? = null, initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null } errorFactory: NullableRequestBuilder<*> = { null }
) = waitContentMessage<MediaContent>(initRequest, errorFactory) ) = waitContentMessage<MediaContent>(initRequest, errorFactory)
@Deprecated(includeMediaGroupsDeprecationMessage)
suspend fun BehaviourContext.waitAnyMediaGroupContentMessage(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null },
includeMediaGroups: Boolean
) = waitContentMessage<MediaGroupPartContent>(initRequest, errorFactory)
suspend fun BehaviourContext.waitAnyMediaGroupContentMessage( suspend fun BehaviourContext.waitAnyMediaGroupContentMessage(
initRequest: Request<*>? = null, initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null } errorFactory: NullableRequestBuilder<*> = { null }
) = waitContentMessage<MediaGroupPartContent>(initRequest, errorFactory) ) = waitContentMessage<MediaGroupPartContent>(initRequest, errorFactory)
@Deprecated(includeMediaGroupsDeprecationMessage)
suspend fun BehaviourContext.waitVisualMediaGroupContentMessage(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null },
includeMediaGroups: Boolean
) = waitContentMessage<VisualMediaGroupPartContent>(initRequest, errorFactory)
suspend fun BehaviourContext.waitVisualMediaGroupContentMessage( suspend fun BehaviourContext.waitVisualMediaGroupContentMessage(
initRequest: Request<*>? = null, initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null } errorFactory: NullableRequestBuilder<*> = { null }
) = waitContentMessage<VisualMediaGroupPartContent>(initRequest, errorFactory) ) = waitContentMessage<VisualMediaGroupPartContent>(initRequest, errorFactory)
@Deprecated(includeMediaGroupsDeprecationMessage)
suspend fun BehaviourContext.waitTextedMediaContentMessage(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null },
includeMediaGroups: Boolean
) = waitContentMessage<TextedMediaContent>(initRequest, errorFactory)
suspend fun BehaviourContext.waitTextedMediaContentMessage( suspend fun BehaviourContext.waitTextedMediaContentMessage(
initRequest: Request<*>? = null, initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null } errorFactory: NullableRequestBuilder<*> = { null }
@@ -160,32 +114,14 @@ suspend fun BehaviourContext.waitAnimationMessage(
initRequest: Request<*>? = null, initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null } errorFactory: NullableRequestBuilder<*> = { null }
) = waitContentMessage<AnimationContent>(initRequest, errorFactory) ) = waitContentMessage<AnimationContent>(initRequest, errorFactory)
@Deprecated(includeMediaGroupsDeprecationMessage)
suspend fun BehaviourContext.waitAudioMessage(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null },
includeMediaGroups: Boolean
) = waitContentMessage<AudioContent>(initRequest, errorFactory)
suspend fun BehaviourContext.waitAudioMessage( suspend fun BehaviourContext.waitAudioMessage(
initRequest: Request<*>? = null, initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null } errorFactory: NullableRequestBuilder<*> = { null }
) = waitContentMessage<AudioContent>(initRequest, errorFactory) ) = waitContentMessage<AudioContent>(initRequest, errorFactory)
@Deprecated(includeMediaGroupsDeprecationMessage)
suspend fun BehaviourContext.waitDocumentMessage(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null },
includeMediaGroups: Boolean
) = waitContentMessage<DocumentContent>(initRequest, errorFactory)
suspend fun BehaviourContext.waitDocumentMessage( suspend fun BehaviourContext.waitDocumentMessage(
initRequest: Request<*>? = null, initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null } errorFactory: NullableRequestBuilder<*> = { null }
) = waitContentMessage<DocumentContent>(initRequest, errorFactory) ) = waitContentMessage<DocumentContent>(initRequest, errorFactory)
@Deprecated(includeMediaGroupsDeprecationMessage)
suspend fun BehaviourContext.waitPhotoMessage(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null },
includeMediaGroups: Boolean
) = waitContentMessage<PhotoContent>(initRequest, errorFactory)
suspend fun BehaviourContext.waitPhotoMessage( suspend fun BehaviourContext.waitPhotoMessage(
initRequest: Request<*>? = null, initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null } errorFactory: NullableRequestBuilder<*> = { null }
@@ -194,12 +130,6 @@ suspend fun BehaviourContext.waitStickerMessage(
initRequest: Request<*>? = null, initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null } errorFactory: NullableRequestBuilder<*> = { null }
) = waitContentMessage<StickerContent>(initRequest, errorFactory) ) = waitContentMessage<StickerContent>(initRequest, errorFactory)
@Deprecated(includeMediaGroupsDeprecationMessage)
suspend fun BehaviourContext.waitVideoMessage(
initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null },
includeMediaGroups: Boolean
) = waitContentMessage<VideoContent>(initRequest, errorFactory)
suspend fun BehaviourContext.waitVideoMessage( suspend fun BehaviourContext.waitVideoMessage(
initRequest: Request<*>? = null, initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null } errorFactory: NullableRequestBuilder<*> = { null }

View File

@@ -109,7 +109,7 @@ suspend fun BehaviourContext.waitGroupChatCreatedEvents(
suspend fun BehaviourContext.waitLeftChatMemberEvents( suspend fun BehaviourContext.waitLeftChatMemberEvents(
initRequest: Request<*>? = null, initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null } errorFactory: NullableRequestBuilder<*> = { null }
) = waitEvents<LeftChatMember>(initRequest, errorFactory) ) = waitEvents<LeftChatMemberEvent>(initRequest, errorFactory)
suspend fun BehaviourContext.waitNewChatPhotoEvents( suspend fun BehaviourContext.waitNewChatPhotoEvents(
initRequest: Request<*>? = null, initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null } errorFactory: NullableRequestBuilder<*> = { null }

View File

@@ -106,7 +106,7 @@ suspend fun BehaviourContext.waitGroupChatCreatedEventsMessages(
suspend fun BehaviourContext.waitLeftChatMemberEventsMessages( suspend fun BehaviourContext.waitLeftChatMemberEventsMessages(
initRequest: Request<*>? = null, initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null } errorFactory: NullableRequestBuilder<*> = { null }
) = waitEventsMessages<LeftChatMember>(initRequest, errorFactory) ) = waitEventsMessages<LeftChatMemberEvent>(initRequest, errorFactory)
suspend fun BehaviourContext.waitNewChatPhotoEventsMessages( suspend fun BehaviourContext.waitNewChatPhotoEventsMessages(
initRequest: Request<*>? = null, initRequest: Request<*>? = null,
errorFactory: NullableRequestBuilder<*> = { null } errorFactory: NullableRequestBuilder<*> = { null }

View File

@@ -346,10 +346,10 @@ suspend fun <BC : BehaviourContext> BC.onGroupChatCreated(
* data * data
*/ */
suspend fun <BC : BehaviourContext> BC.onLeftChatMember( suspend fun <BC : BehaviourContext> BC.onLeftChatMember(
initialFilter: SimpleFilter<ChatEventMessage<LeftChatMember>>? = null, initialFilter: SimpleFilter<ChatEventMessage<LeftChatMemberEvent>>? = null,
subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, ChatEventMessage<LeftChatMember>, Update>? = MessageFilterByChat, subcontextUpdatesFilter: CustomBehaviourContextAndTwoTypesReceiver<BC, Boolean, ChatEventMessage<LeftChatMemberEvent>, Update>? = MessageFilterByChat,
markerFactory: MarkerFactory<in ChatEventMessage<LeftChatMember>, Any> = ByChatMessageMarkerFactory, markerFactory: MarkerFactory<in ChatEventMessage<LeftChatMemberEvent>, Any> = ByChatMessageMarkerFactory,
scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, ChatEventMessage<LeftChatMember>> scenarioReceiver: CustomBehaviourContextAndTypeReceiver<BC, Unit, ChatEventMessage<LeftChatMemberEvent>>
) = onEvent(initialFilter, subcontextUpdatesFilter, markerFactory, scenarioReceiver) ) = onEvent(initialFilter, subcontextUpdatesFilter, markerFactory, scenarioReceiver)
/** /**

View File

@@ -0,0 +1,6 @@
package dev.inmo.tgbotapi.extensions.behaviour_builder
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
actual var defaultCoroutineScopeProvider: () -> CoroutineScope = { CoroutineScope(Dispatchers.Default) }

View File

@@ -0,0 +1,6 @@
package dev.inmo.tgbotapi.extensions.behaviour_builder
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
actual var defaultCoroutineScopeProvider: () -> CoroutineScope = { CoroutineScope(Dispatchers.Default) }

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
@@ -47,11 +48,23 @@ kotlin {
api libs.javax.activation api libs.javax.activation
} }
} }
linuxX64Main {
dependencies {
api libs.ktor.client.curl
}
}
mingwX64Main {
dependencies {
api libs.ktor.client.winhttp
}
}
} }
} }
dependencies { dependencies {
add("kspJvm", project(":tgbotapi.ksp")) add("kspCommonMainMetadata", project(":tgbotapi.ksp"))
} }
ksp { ksp {

View File

@@ -0,0 +1,10 @@
package dev.inmo.tgbotapi.abstracts
import dev.inmo.tgbotapi.types.chat.Chat
/**
* All inheritors of this interface have [chat] field and related to this [chat]
*/
interface WithChat {
val chat: Chat
}

View File

@@ -1,134 +1,25 @@
package dev.inmo.tgbotapi.bot.ktor package dev.inmo.tgbotapi.bot.ktor
import dev.inmo.micro_utils.coroutines.runCatchingSafely
import dev.inmo.micro_utils.coroutines.safely
import dev.inmo.tgbotapi.bot.BaseRequestsExecutor import dev.inmo.tgbotapi.bot.BaseRequestsExecutor
import dev.inmo.tgbotapi.bot.TelegramBot
import dev.inmo.tgbotapi.bot.exceptions.*
import dev.inmo.tgbotapi.bot.ktor.base.*
import dev.inmo.tgbotapi.bot.settings.limiters.ExceptionsOnlyLimiter import dev.inmo.tgbotapi.bot.settings.limiters.ExceptionsOnlyLimiter
import dev.inmo.tgbotapi.bot.settings.limiters.RequestLimiter import dev.inmo.tgbotapi.bot.settings.limiters.RequestLimiter
import dev.inmo.tgbotapi.requests.abstracts.Request import dev.inmo.tgbotapi.utils.TelegramAPIUrlsKeeper
import dev.inmo.tgbotapi.types.Response import dev.inmo.tgbotapi.utils.nonstrictJsonFormat
import dev.inmo.tgbotapi.utils.* import io.ktor.client.*
import io.ktor.client.HttpClient
import io.ktor.client.plugins.*
import io.ktor.client.statement.bodyAsText
import io.ktor.client.statement.readText
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
@RiskFeature /**
fun createTelegramBotDefaultKtorCallRequestsFactories() = listOf( * Represents default [BaseRequestsExecutor] working on [Ktor](https://ktor.io) [HttpClient]
SimpleRequestCallFactory(), *
MultipartRequestCallFactory(), * * On JS, JVM and MingwX64 platforms it is [dev.inmo.tgbotapi.bot.ktor.base.DefaultKtorRequestsExecutor]
DownloadFileRequestCallFactory, * * On LinuxX64 it is [dev.inmo.tgbotapi.bot.ktor.base.MultipleClientKtorRequestsExecutor]
DownloadFileChannelRequestCallFactory */
) expect class KtorRequestsExecutor (
class KtorRequestsExecutor(
telegramAPIUrlsKeeper: TelegramAPIUrlsKeeper, telegramAPIUrlsKeeper: TelegramAPIUrlsKeeper,
client: HttpClient = HttpClient(), client: HttpClient = HttpClient(),
callsFactories: List<KtorCallFactory> = emptyList(), callsFactories: List<KtorCallFactory> = emptyList(),
excludeDefaultFactories: Boolean = false, excludeDefaultFactories: Boolean = false,
private val requestsLimiter: RequestLimiter = ExceptionsOnlyLimiter, requestsLimiter: RequestLimiter = ExceptionsOnlyLimiter,
private val jsonFormatter: Json = nonstrictJsonFormat, jsonFormatter: Json = nonstrictJsonFormat,
private val pipelineStepsHolder: KtorPipelineStepsHolder = KtorPipelineStepsHolder pipelineStepsHolder: KtorPipelineStepsHolder = KtorPipelineStepsHolder
) : BaseRequestsExecutor(telegramAPIUrlsKeeper) { ) : BaseRequestsExecutor
private val callsFactories: List<KtorCallFactory> = callsFactories.run {
if (!excludeDefaultFactories) {
this + createTelegramBotDefaultKtorCallRequestsFactories()
} else {
this
}
}
private val client = client.config {
if (client.pluginOrNull(HttpTimeout) == null) {
install(HttpTimeout)
}
}
override suspend fun <T : Any> execute(request: Request<T>): T {
return runCatchingSafely {
pipelineStepsHolder.onBeforeSearchCallFactory(request, callsFactories)
requestsLimiter.limit(request) {
var result: T? = null
lateinit var factoryHandledRequest: KtorCallFactory
for (potentialFactory in callsFactories) {
pipelineStepsHolder.onBeforeCallFactoryMakeCall(request, potentialFactory)
result = potentialFactory.makeCall(
client,
telegramAPIUrlsKeeper,
request,
jsonFormatter
)
result = pipelineStepsHolder.onAfterCallFactoryMakeCall(result, request, potentialFactory)
if (result != null) {
factoryHandledRequest = potentialFactory
break
}
}
result ?.let {
pipelineStepsHolder.onRequestResultPresented(it, request, factoryHandledRequest, callsFactories)
} ?: pipelineStepsHolder.onRequestResultAbsent(request, callsFactories) ?: error("Can't execute request: $request")
}
}.let {
val result = it.exceptionOrNull() ?.let { e ->
pipelineStepsHolder.onRequestException(request, e) ?.let { return@let it }
when (e) {
is ClientRequestException -> {
val exceptionResult = runCatchingSafely {
val content = e.response.bodyAsText()
val responseObject = jsonFormatter.decodeFromString(Response.serializer(), content)
newRequestException(
responseObject,
content,
"Can't get result object from $content"
)
}
exceptionResult.exceptionOrNull() ?.let {
CommonBotException(cause = e)
} ?: exceptionResult.getOrThrow()
}
is BotException -> e
else -> CommonBotException(cause = e)
}
} ?.let { Result.failure(it) } ?: it
pipelineStepsHolder.onRequestReturnResult(result, request, callsFactories)
}
}
override fun close() {
client.close()
}
}
class KtorRequestsExecutorBuilder(
var telegramAPIUrlsKeeper: TelegramAPIUrlsKeeper
) {
var client: HttpClient = HttpClient()
var callsFactories: List<KtorCallFactory> = emptyList()
var excludeDefaultFactories: Boolean = false
var requestsLimiter: RequestLimiter = ExceptionsOnlyLimiter
var jsonFormatter: Json = nonstrictJsonFormat
fun build() = KtorRequestsExecutor(telegramAPIUrlsKeeper, client, callsFactories, excludeDefaultFactories, requestsLimiter, jsonFormatter)
}
inline fun telegramBot(
telegramAPIUrlsKeeper: TelegramAPIUrlsKeeper,
builder: KtorRequestsExecutorBuilder.() -> Unit = {}
): TelegramBot = KtorRequestsExecutorBuilder(telegramAPIUrlsKeeper).apply(builder).build()
/**
* Shortcut for [telegramBot]
*/
@Suppress("NOTHING_TO_INLINE")
inline fun telegramBot(
token: String,
apiUrl: String = telegramBotAPIDefaultUrl,
testServer: Boolean = false,
builder: KtorRequestsExecutorBuilder.() -> Unit = {}
): TelegramBot = telegramBot(TelegramAPIUrlsKeeper(token, testServer, apiUrl), builder)

View File

@@ -0,0 +1,54 @@
package dev.inmo.tgbotapi.bot.ktor
import dev.inmo.tgbotapi.bot.BaseRequestsExecutor
import dev.inmo.tgbotapi.bot.TelegramBot
import dev.inmo.tgbotapi.bot.ktor.base.*
import dev.inmo.tgbotapi.bot.settings.limiters.ExceptionsOnlyLimiter
import dev.inmo.tgbotapi.bot.settings.limiters.RequestLimiter
import dev.inmo.tgbotapi.utils.*
import io.ktor.client.HttpClient
import kotlinx.serialization.json.Json
@RiskFeature
fun createTelegramBotDefaultKtorCallRequestsFactories() = listOf(
SimpleRequestCallFactory(),
MultipartRequestCallFactory(),
DownloadFileRequestCallFactory,
DownloadFileChannelRequestCallFactory
)
class KtorRequestsExecutorBuilder(
var telegramAPIUrlsKeeper: TelegramAPIUrlsKeeper
) {
var client: HttpClient = HttpClient()
var callsFactories: List<KtorCallFactory> = emptyList()
var excludeDefaultFactories: Boolean = false
var requestsLimiter: RequestLimiter = ExceptionsOnlyLimiter
var jsonFormatter: Json = nonstrictJsonFormat
fun build() = KtorRequestsExecutor(
telegramAPIUrlsKeeper,
client,
callsFactories,
excludeDefaultFactories,
requestsLimiter,
jsonFormatter
)
}
inline fun telegramBot(
telegramAPIUrlsKeeper: TelegramAPIUrlsKeeper,
builder: KtorRequestsExecutorBuilder.() -> Unit = {}
): TelegramBot = KtorRequestsExecutorBuilder(telegramAPIUrlsKeeper).apply(builder).build()
/**
* Shortcut for [telegramBot]
*/
@Suppress("NOTHING_TO_INLINE")
inline fun telegramBot(
token: String,
apiUrl: String = telegramBotAPIDefaultUrl,
testServer: Boolean = false,
builder: KtorRequestsExecutorBuilder.() -> Unit = {}
): TelegramBot = telegramBot(TelegramAPIUrlsKeeper(token, testServer, apiUrl), builder)

View File

@@ -1,6 +1,6 @@
package dev.inmo.tgbotapi.bot.ktor.base package dev.inmo.tgbotapi.bot.ktor.base
import dev.inmo.micro_utils.coroutines.safelyWithResult import dev.inmo.micro_utils.coroutines.runCatchingSafely
import dev.inmo.tgbotapi.bot.ktor.KtorCallFactory import dev.inmo.tgbotapi.bot.ktor.KtorCallFactory
import dev.inmo.tgbotapi.bot.exceptions.newRequestException import dev.inmo.tgbotapi.bot.exceptions.newRequestException
import dev.inmo.tgbotapi.requests.GetUpdates import dev.inmo.tgbotapi.requests.GetUpdates
@@ -56,7 +56,7 @@ abstract class AbstractRequestCallFactory : KtorCallFactory {
val content = response.bodyAsText() val content = response.bodyAsText()
val responseObject = jsonFormatter.decodeFromString(Response.serializer(), content) val responseObject = jsonFormatter.decodeFromString(Response.serializer(), content)
return safelyWithResult { return runCatchingSafely {
(responseObject.result?.let { (responseObject.result?.let {
jsonFormatter.decodeFromJsonElement(request.resultDeserializer, it) jsonFormatter.decodeFromJsonElement(request.resultDeserializer, it)
} ?: response.let { } ?: response.let {

View File

@@ -0,0 +1,100 @@
package dev.inmo.tgbotapi.bot.ktor.base
import dev.inmo.micro_utils.coroutines.runCatchingSafely
import dev.inmo.tgbotapi.bot.BaseRequestsExecutor
import dev.inmo.tgbotapi.bot.exceptions.BotException
import dev.inmo.tgbotapi.bot.exceptions.CommonBotException
import dev.inmo.tgbotapi.bot.exceptions.newRequestException
import dev.inmo.tgbotapi.bot.ktor.KtorCallFactory
import dev.inmo.tgbotapi.bot.ktor.KtorPipelineStepsHolder
import dev.inmo.tgbotapi.bot.ktor.createTelegramBotDefaultKtorCallRequestsFactories
import dev.inmo.tgbotapi.bot.settings.limiters.ExceptionsOnlyLimiter
import dev.inmo.tgbotapi.bot.settings.limiters.RequestLimiter
import dev.inmo.tgbotapi.requests.abstracts.Request
import dev.inmo.tgbotapi.types.Response
import dev.inmo.tgbotapi.utils.TelegramAPIUrlsKeeper
import dev.inmo.tgbotapi.utils.nonstrictJsonFormat
import io.ktor.client.*
import io.ktor.client.plugins.*
import io.ktor.client.statement.*
import kotlinx.serialization.json.Json
class DefaultKtorRequestsExecutor(
telegramAPIUrlsKeeper: TelegramAPIUrlsKeeper,
client: HttpClient = HttpClient(),
callsFactories: List<KtorCallFactory> = emptyList(),
excludeDefaultFactories: Boolean = false,
private val requestsLimiter: RequestLimiter = ExceptionsOnlyLimiter,
private val jsonFormatter: Json = nonstrictJsonFormat,
private val pipelineStepsHolder: KtorPipelineStepsHolder = KtorPipelineStepsHolder
) : BaseRequestsExecutor(telegramAPIUrlsKeeper) {
private val callsFactories: List<KtorCallFactory> = callsFactories.run {
if (!excludeDefaultFactories) {
this + createTelegramBotDefaultKtorCallRequestsFactories()
} else {
this
}
}
private val client = client.config {
if (client.pluginOrNull(HttpTimeout) == null) {
install(HttpTimeout)
}
}
override suspend fun <T : Any> execute(request: Request<T>): T {
return runCatchingSafely {
pipelineStepsHolder.onBeforeSearchCallFactory(request, callsFactories)
requestsLimiter.limit(request) {
var result: T? = null
lateinit var factoryHandledRequest: KtorCallFactory
for (potentialFactory in callsFactories) {
pipelineStepsHolder.onBeforeCallFactoryMakeCall(request, potentialFactory)
result = potentialFactory.makeCall(
client,
telegramAPIUrlsKeeper,
request,
jsonFormatter
)
result = pipelineStepsHolder.onAfterCallFactoryMakeCall(result, request, potentialFactory)
if (result != null) {
factoryHandledRequest = potentialFactory
break
}
}
result ?.let {
pipelineStepsHolder.onRequestResultPresented(it, request, factoryHandledRequest, callsFactories)
} ?: pipelineStepsHolder.onRequestResultAbsent(request, callsFactories) ?: error("Can't execute request: $request")
}
}.let {
val result = it.exceptionOrNull() ?.let { e ->
pipelineStepsHolder.onRequestException(request, e) ?.let { return@let it }
when (e) {
is ClientRequestException -> {
val exceptionResult = runCatchingSafely {
val content = e.response.bodyAsText()
val responseObject = jsonFormatter.decodeFromString(Response.serializer(), content)
newRequestException(
responseObject,
content,
"Can't get result object from $content"
)
}
exceptionResult.exceptionOrNull() ?.let {
CommonBotException(cause = e)
} ?: exceptionResult.getOrThrow()
}
is BotException -> e
else -> CommonBotException(cause = e)
}
} ?.let { Result.failure(it) } ?: it
pipelineStepsHolder.onRequestReturnResult(result, request, callsFactories)
}
}
override fun close() {
client.close()
}
}

View File

@@ -4,8 +4,7 @@ import dev.inmo.tgbotapi.requests.abstracts.*
import dev.inmo.tgbotapi.utils.TelegramAPIUrlsKeeper import dev.inmo.tgbotapi.utils.TelegramAPIUrlsKeeper
import dev.inmo.tgbotapi.utils.mapWithCommonValues import dev.inmo.tgbotapi.utils.mapWithCommonValues
import io.ktor.client.HttpClient import io.ktor.client.HttpClient
import io.ktor.client.request.forms.MultiPartFormDataContent import io.ktor.client.request.forms.*
import io.ktor.client.request.forms.formData
import io.ktor.http.Headers import io.ktor.http.Headers
import io.ktor.http.HttpHeaders import io.ktor.http.HttpHeaders

View File

@@ -0,0 +1,118 @@
package dev.inmo.tgbotapi.bot.ktor.base
import dev.inmo.micro_utils.coroutines.runCatchingSafely
import dev.inmo.tgbotapi.bot.BaseRequestsExecutor
import dev.inmo.tgbotapi.bot.ktor.KtorCallFactory
import dev.inmo.tgbotapi.bot.ktor.KtorPipelineStepsHolder
import dev.inmo.tgbotapi.bot.settings.limiters.RequestLimiter
import dev.inmo.tgbotapi.requests.abstracts.Request
import dev.inmo.tgbotapi.utils.TelegramAPIUrlsKeeper
import io.ktor.client.*
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.mapNotNull
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import kotlinx.serialization.json.Json
/**
* This function is used in default constructor of [MultipleClientKtorRequestsExecutor] and on all non-native
* platforms and MingwX64 should return [client]
*
* On LinuxX64 it will create copy with Curl engine or throw an exception if engine is different with Curl
*
* @throws IllegalArgumentException When pass non Curl-based [HttpClient] on LinuxX64
*/
internal expect inline fun platformClientCopy(client: HttpClient): HttpClient
/**
* Will use its parameters of constructor to create several [DefaultKtorRequestsExecutor] and use them in [execute]
* and [close] operations
*
* This [BaseRequestsExecutor] has been created for LinuxX64 target due to its inability of requests paralleling
*
* Under the hood on each [execute] it will take [DefaultKtorRequestsExecutor] and mark it as busy, execute
* [Request], free up taken [DefaultKtorRequestsExecutor] and return (or throw) the result of execution
*
* @param requestExecutorsCount Amount of [DefaultKtorRequestsExecutor] which will be created and used under the
* hood
*/
class MultipleClientKtorRequestsExecutor (
telegramAPIUrlsKeeper: TelegramAPIUrlsKeeper,
callsFactories: List<KtorCallFactory>,
excludeDefaultFactories: Boolean,
requestsLimiter: RequestLimiter,
jsonFormatter: Json,
pipelineStepsHolder: KtorPipelineStepsHolder,
requestExecutorsCount: Int,
clientFactory: () -> HttpClient
) : BaseRequestsExecutor(telegramAPIUrlsKeeper) {
private val requestExecutors = (0 until requestExecutorsCount).map {
DefaultKtorRequestsExecutor(
telegramAPIUrlsKeeper,
clientFactory(),
callsFactories,
excludeDefaultFactories,
requestsLimiter,
jsonFormatter,
pipelineStepsHolder
)
}.toSet()
private val freeClients = MutableStateFlow<Set<DefaultKtorRequestsExecutor>>(requestExecutors)
private val clientAllocationMutex = Mutex()
private val takerFlow = freeClients.mapNotNull {
clientAllocationMutex.withLock {
freeClients.value.firstOrNull() ?.also {
freeClients.value -= it
} ?: return@mapNotNull null
}
}
constructor(
telegramAPIUrlsKeeper: TelegramAPIUrlsKeeper,
client: HttpClient,
callsFactories: List<KtorCallFactory>,
excludeDefaultFactories: Boolean,
requestsLimiter: RequestLimiter,
jsonFormatter: Json,
pipelineStepsHolder: KtorPipelineStepsHolder
) : this(
telegramAPIUrlsKeeper,
callsFactories,
excludeDefaultFactories,
requestsLimiter,
jsonFormatter,
pipelineStepsHolder,
client.engineConfig.threadsCount,
{ platformClientCopy(client) }
)
private suspend fun prepareRequestsExecutor(): DefaultKtorRequestsExecutor {
return takerFlow.first()
}
private suspend fun freeRequestsExecutor(client: DefaultKtorRequestsExecutor) {
clientAllocationMutex.withLock {
freeClients.value += client
}
}
private suspend fun <T> withRequestExecutor(block: suspend (DefaultKtorRequestsExecutor) -> T): T {
val requestsExecutor = prepareRequestsExecutor()
val result = runCatchingSafely {
block(requestsExecutor)
}
freeRequestsExecutor(requestsExecutor)
return result.getOrThrow()
}
override suspend fun <T : Any> execute(request: Request<T>): T = withRequestExecutor {
it.execute(request)
}
override fun close() {
requestExecutors.forEach {
it.close()
}
}
}

View File

@@ -1,18 +1,27 @@
package dev.inmo.tgbotapi.bot.settings.limiters package dev.inmo.tgbotapi.bot.settings.limiters
import dev.inmo.micro_utils.coroutines.runCatchingSafely
import dev.inmo.tgbotapi.bot.exceptions.TooMuchRequestsException import dev.inmo.tgbotapi.bot.exceptions.TooMuchRequestsException
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
/** /**
* Simple limiter which will lock any request when [TooMuchRequestsExceptions] is thrown and rerun request after lock time * Simple limiter which will lock any request when [TooMuchRequestsException] is thrown and rerun request after lock time
*/ */
object ExceptionsOnlyLimiter : RequestLimiter { object ExceptionsOnlyLimiter : RequestLimiter {
override suspend fun <T> limit(block: suspend () -> T): T { override suspend fun <T> limit(block: suspend () -> T): T {
return try { var result: Result<T>? = null
block() while (result == null || result.isFailure) {
} catch (e: TooMuchRequestsException) { result = runCatchingSafely {
delay(e.retryAfter.leftToRetry) block()
limit(block) }.onFailure {
it.printStackTrace()
if (it is TooMuchRequestsException) {
delay(it.retryAfter.leftToRetry)
} else {
throw it
}
}
} }
return result.getOrThrow()
} }
} }

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

@@ -19,7 +19,7 @@ data class GetChat(
override val resultDeserializer: DeserializationStrategy<ExtendedChat> = if (chatId is ChatIdWithThreadId) { override val resultDeserializer: DeserializationStrategy<ExtendedChat> = if (chatId is ChatIdWithThreadId) {
ExtendedChatSerializer.BasedOnForumThread(chatId.threadId) ExtendedChatSerializer.BasedOnForumThread(chatId.threadId)
} else { } else {
ExtendedChatSerializer ExtendedChatSerializer.Companion
} }
override val requestSerializer: SerializationStrategy<*> override val requestSerializer: SerializationStrategy<*>
get() = serializer() get() = 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 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,50 +0,0 @@
package dev.inmo.tgbotapi.requests.stickers
import dev.inmo.tgbotapi.requests.abstracts.*
import dev.inmo.tgbotapi.requests.common.CommonMultipartFileRequest
import dev.inmo.tgbotapi.requests.stickers.abstracts.StandardStickerSetAction
import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.stickers.MaskPosition
import kotlinx.serialization.*
fun AddAnimatedStickerToSet(
userId: UserId,
stickerSetName: String,
sticker: InputFile,
emojis: String,
maskPosition: MaskPosition? = null
): Request<Boolean> {
val data = AddAnimatedStickerToSet(userId, stickerSetName, emojis, sticker as? FileId, maskPosition)
return when (sticker) {
is MultipartFile -> CommonMultipartFileRequest(
data,
mapOf(tgsStickerField to sticker)
)
is FileId -> data
}
}
@Serializable
data class AddAnimatedStickerToSet internal constructor(
@SerialName(userIdField)
override val userId: UserId,
@SerialName(nameField)
override val name: String,
@SerialName(emojisField)
override val emojis: String,
@SerialName(tgsStickerField)
val sticker: FileId? = null,
@SerialName(maskPositionField)
override val maskPosition: MaskPosition? = null
) : StandardStickerSetAction {
init {
if(emojis.isEmpty()) {
throw IllegalArgumentException("Emojis must not be empty")
}
}
override val requestSerializer: SerializationStrategy<*>
get() = serializer()
override fun method(): String = "addStickerToSet"
}

View File

@@ -1,50 +0,0 @@
package dev.inmo.tgbotapi.requests.stickers
import dev.inmo.tgbotapi.requests.abstracts.*
import dev.inmo.tgbotapi.requests.common.CommonMultipartFileRequest
import dev.inmo.tgbotapi.requests.stickers.abstracts.StandardStickerSetAction
import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.stickers.MaskPosition
import kotlinx.serialization.*
fun AddStaticStickerToSet(
userId: UserId,
stickerSetName: String,
sticker: InputFile,
emojis: String,
maskPosition: MaskPosition? = null
): Request<Boolean> {
val data = AddStaticStickerToSet(userId, stickerSetName, emojis, sticker as? FileId, maskPosition)
return when (sticker) {
is MultipartFile -> CommonMultipartFileRequest(
data,
mapOf(pngStickerField to sticker)
)
is FileId -> data
}
}
@Serializable
data class AddStaticStickerToSet internal constructor(
@SerialName(userIdField)
override val userId: UserId,
@SerialName(nameField)
override val name: String,
@SerialName(emojisField)
override val emojis: String,
@SerialName(pngStickerField)
val sticker: FileId? = null,
@SerialName(maskPositionField)
override val maskPosition: MaskPosition? = null
) : StandardStickerSetAction {
init {
if(emojis.isEmpty()) {
throw IllegalArgumentException("Emojis must not be empty")
}
}
override val requestSerializer: SerializationStrategy<*>
get() = serializer()
override fun method(): String = "addStickerToSet"
}

View File

@@ -4,45 +4,32 @@ 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.StandardStickerSetAction import dev.inmo.tgbotapi.requests.stickers.abstracts.StandardStickerSetAction
import dev.inmo.tgbotapi.types.* import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.stickers.MaskPosition
import kotlinx.serialization.* import kotlinx.serialization.*
fun AddVideoStickerToSet( fun AddStickerToSet(
userId: UserId, userId: UserId,
stickerSetName: String, stickerSetName: String,
sticker: InputFile, inputSticker: InputSticker
emojis: String,
maskPosition: MaskPosition? = null
): Request<Boolean> { ): Request<Boolean> {
val data = AddVideoStickerToSet(userId, stickerSetName, emojis, sticker as? FileId, maskPosition) val data = AddStickerToSetData(userId, stickerSetName, inputSticker)
return when (sticker) { return when (val sticker = inputSticker.sticker) {
is MultipartFile -> CommonMultipartFileRequest( is MultipartFile -> CommonMultipartFileRequest(
data, data,
mapOf(webmStickerField to sticker) mapOf(sticker.fileId to sticker)
) )
is FileId -> data is FileId -> data
} }
} }
@Serializable @Serializable
data class AddVideoStickerToSet internal constructor( data class AddStickerToSetData internal constructor(
@SerialName(userIdField) @SerialName(userIdField)
override val userId: UserId, override val userId: UserId,
@SerialName(nameField) @SerialName(nameField)
override val name: String, override val name: String,
@SerialName(emojisField) @SerialName(stickerField)
override val emojis: String, override val inputSticker: InputSticker
@SerialName(webmStickerField)
val sticker: FileId? = null,
@SerialName(maskPositionField)
override val maskPosition: MaskPosition? = null
) : StandardStickerSetAction { ) : StandardStickerSetAction {
init {
if(emojis.isEmpty()) {
throw IllegalArgumentException("Emojis must not be empty")
}
}
override val requestSerializer: SerializationStrategy<*> override val requestSerializer: SerializationStrategy<*>
get() = serializer() get() = serializer()

View File

@@ -1,40 +0,0 @@
package dev.inmo.tgbotapi.requests.stickers
import dev.inmo.tgbotapi.requests.abstracts.*
import dev.inmo.tgbotapi.requests.common.CommonMultipartFileRequest
import dev.inmo.tgbotapi.requests.stickers.abstracts.CreateStickerSetAction
import dev.inmo.tgbotapi.requests.stickers.abstracts.StandardStickerSetAction
import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.stickers.MaskPosition
import kotlinx.serialization.*
@Serializable
@Deprecated("Use CreateNewStickerSet class instead")
data class CreateNewAnimatedStickerSet internal constructor(
@SerialName(userIdField)
override val userId: UserId,
@SerialName(nameField)
override val name: String,
@SerialName(titleField)
override val title: String,
@SerialName(emojisField)
override val emojis: String,
@SerialName(tgsStickerField)
val sticker: FileId? = null,
@SerialName(containsMasksField)
@Deprecated("Will be removed soon due to its redundancy")
val containsMasks: Boolean? = null,
@SerialName(maskPositionField)
override val maskPosition: MaskPosition? = null
) : CreateStickerSetAction {
init {
if(emojis.isEmpty()) {
throw IllegalArgumentException("Emojis must not be empty")
}
}
override val requestSerializer: SerializationStrategy<*>
get() = serializer()
override fun method(): String = "createNewStickerSet"
}

View File

@@ -1,40 +0,0 @@
package dev.inmo.tgbotapi.requests.stickers
import dev.inmo.tgbotapi.requests.abstracts.*
import dev.inmo.tgbotapi.requests.common.CommonMultipartFileRequest
import dev.inmo.tgbotapi.requests.stickers.abstracts.CreateStickerSetAction
import dev.inmo.tgbotapi.requests.stickers.abstracts.StandardStickerSetAction
import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.stickers.MaskPosition
import kotlinx.serialization.*
@Serializable
@Deprecated("Use CreateNewStickerSet class instead")
data class CreateNewStaticStickerSet internal constructor(
@SerialName(userIdField)
override val userId: UserId,
@SerialName(nameField)
override val name: String,
@SerialName(titleField)
override val title: String,
@SerialName(emojisField)
override val emojis: String,
@SerialName(pngStickerField)
val sticker: FileId? = null,
@SerialName(containsMasksField)
@Deprecated("Will be removed soon due to its redundancy")
val containsMasks: Boolean? = null,
@SerialName(maskPositionField)
override val maskPosition: MaskPosition? = null
) : CreateStickerSetAction {
init {
if(emojis.isEmpty()) {
throw IllegalArgumentException("Emojis must not be empty")
}
}
override val requestSerializer: SerializationStrategy<*>
get() = serializer()
override fun method(): String = "createNewStickerSet"
}

View File

@@ -1,77 +1,186 @@
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
internal fun CreateNewStickerSet( /**
* Will create one of [CreateNewStickerSet] types based on the first element of [stickers]
*
* @param needsRepainting Will be used only if you are creating custom emojis sticker pack (by passing [stickers] with
* type [InputSticker.WithKeywords.CustomEmoji])
*/
fun CreateNewStickerSet(
userId: UserId, userId: UserId,
name: String, name: String,
title: String, title: String,
emojis: String, stickersFormat: StickerFormat,
stickerType: StickerType = StickerType.Regular, stickers: List<InputSticker>,
pngSticker: InputFile? = null, needsRepainting: Boolean? = null
tgsSticker: InputFile? = null,
webmSticker: InputFile? = null,
maskPosition: MaskPosition? = null
): Request<Boolean> { ): Request<Boolean> {
val data = CreateNewStickerSet( val data = when(stickers.first()) {
userId, is InputSticker.Mask -> CreateNewStickerSet.Mask(userId, name, title, stickersFormat, stickers.filterIsInstance<InputSticker.Mask>())
name, is InputSticker.WithKeywords.CustomEmoji -> CreateNewStickerSet.CustomEmoji(userId, name, title, stickersFormat, stickers.filterIsInstance<InputSticker.WithKeywords.CustomEmoji>(), needsRepainting)
title, is InputSticker.WithKeywords.Regular -> CreateNewStickerSet.Regular(userId, name, title, stickersFormat, stickers.filterIsInstance<InputSticker.WithKeywords.Regular>())
emojis, }
stickerType, val multipartParts = stickers.mapNotNull {
pngSticker as? FileId, (it.sticker as? MultipartFile)
tgsSticker as? FileId, }
webmSticker as? FileId, return if (multipartParts.isNotEmpty()) {
maskPosition when (data) { // cratch for exact determining of common multipart data type
) is CreateNewStickerSet.CustomEmoji -> CommonMultipartFileRequest(
return if (pngSticker is MultipartFile || tgsSticker is MultipartFile || webmSticker is MultipartFile) { data,
CommonMultipartFileRequest( multipartParts.associateBy { it.fileId }
data, )
listOfNotNull( is CreateNewStickerSet.Mask -> CommonMultipartFileRequest(
(pngSticker as? MultipartFile) ?.let { pngStickerField to it }, data,
(tgsSticker as? MultipartFile) ?.let { tgsStickerField to it }, multipartParts.associateBy { it.fileId }
(webmSticker as? MultipartFile) ?.let { webmStickerField to it }, )
).toMap() is CreateNewStickerSet.Regular -> CommonMultipartFileRequest(
) data,
multipartParts.associateBy { it.fileId }
)
}
} else { } else {
data data
} }
} }
@Serializable @Serializable(CreateNewStickerSetSerializer::class)
data class CreateNewStickerSet internal constructor( sealed interface CreateNewStickerSet : CreateStickerSetAction {
@SerialName(userIdField) val stickerType: StickerType
override val userId: UserId, val stickers: List<InputSticker>
@SerialName(nameField) val stickersFormat: StickerFormat
override val name: String,
@SerialName(titleField)
override val title: String,
@SerialName(emojisField)
override val emojis: String,
@SerialName(stickerTypeField)
val stickerType: StickerType = StickerType.Regular,
@SerialName(pngStickerField)
val pngSticker: FileId? = null,
@SerialName(tgsStickerField)
val tgsSticker: FileId? = null,
@SerialName(webmStickerField)
val webmSticker: FileId? = null,
@SerialName(maskPositionField)
override val maskPosition: MaskPosition? = null
) : CreateStickerSetAction {
init {
if(emojis.isEmpty()) {
throw IllegalArgumentException("Emojis must not be empty")
}
}
override val requestSerializer: SerializationStrategy<*> override val requestSerializer: SerializationStrategy<*>
get() = serializer() get() = serializer()
override fun method(): String = "createNewStickerSet" override fun method(): String = "createNewStickerSet"
@Serializable
data class Regular(
@SerialName(userIdField)
override val userId: UserId,
@SerialName(nameField)
override val name: String,
@SerialName(titleField)
override val title: String,
@SerialName(stickerFormatField)
override val stickersFormat: StickerFormat,
@SerialName(stickersField)
override val stickers: List<InputSticker.WithKeywords.Regular>
) : CreateNewStickerSet {
@SerialName(stickerTypeField)
override val stickerType: StickerType
get() = StickerType.Regular
}
@Serializable
data class Mask(
@SerialName(userIdField)
override val userId: UserId,
@SerialName(nameField)
override val name: String,
@SerialName(titleField)
override val title: String,
@SerialName(stickerFormatField)
override val stickersFormat: StickerFormat,
@SerialName(stickersField)
override val stickers: List<InputSticker.Mask>
) : CreateNewStickerSet {
@SerialName(stickerTypeField)
override val stickerType: StickerType
get() = StickerType.Mask
}
@Serializable
data class CustomEmoji(
@SerialName(userIdField)
override val userId: UserId,
@SerialName(nameField)
override val name: String,
@SerialName(titleField)
override val title: String,
@SerialName(stickerFormatField)
override val stickersFormat: StickerFormat,
@SerialName(stickersField)
override val stickers: List<InputSticker.WithKeywords.CustomEmoji>,
@SerialName(needsRepaintingField)
val needsRepainting: Boolean? = null
) : CreateNewStickerSet {
@SerialName(stickerTypeField)
override val stickerType: StickerType
get() = StickerType.CustomEmoji
}
@Serializable
data class SurrogateCreateNewSticker internal constructor(
@SerialName(userIdField)
override val userId: UserId,
@SerialName(nameField)
override val name: String,
@SerialName(titleField)
override val title: String,
@SerialName(stickerFormatField)
val stickersFormat: StickerFormat,
@SerialName(stickersField)
val stickers: List<InputSticker>,
@SerialName(stickerTypeField)
val stickerType: StickerType,
@SerialName(needsRepaintingField)
val needsRepainting: Boolean? = null
) : CreateStickerSetAction {
override val requestSerializer: SerializationStrategy<*>
get() = CreateNewStickerSet.serializer()
override fun method(): String = "createNewStickerSet"
}
} }
object CreateNewStickerSetSerializer : KSerializer<CreateNewStickerSet>,
MapperSerializer<CreateNewStickerSet.SurrogateCreateNewSticker, CreateNewStickerSet>(
CreateNewStickerSet.SurrogateCreateNewSticker.serializer(),
{
CreateNewStickerSet.SurrogateCreateNewSticker(
it.userId,
it.name,
it.title,
it.stickersFormat,
it.stickers,
it.stickerType,
(it as? CreateNewStickerSet.CustomEmoji)?.needsRepainting
)
},
{
when (it.stickerType) {
StickerType.CustomEmoji -> CreateNewStickerSet.CustomEmoji(
it.userId,
it.name,
it.title,
it.stickersFormat,
it.stickers.filterIsInstance<InputSticker.WithKeywords.CustomEmoji>(),
it.needsRepainting
)
StickerType.Mask -> CreateNewStickerSet.Mask(
it.userId,
it.name,
it.title,
it.stickersFormat,
it.stickers.filterIsInstance<InputSticker.Mask>(),
)
StickerType.Regular -> CreateNewStickerSet.Regular(
it.userId,
it.name,
it.title,
it.stickersFormat,
it.stickers.filterIsInstance<InputSticker.WithKeywords.Regular>(),
)
is StickerType.Unknown -> error("Unable to create new sticker set due to error in type format: ${it.stickerType}")
}
}
)

View File

@@ -1,40 +0,0 @@
package dev.inmo.tgbotapi.requests.stickers
import dev.inmo.tgbotapi.requests.abstracts.*
import dev.inmo.tgbotapi.requests.common.CommonMultipartFileRequest
import dev.inmo.tgbotapi.requests.stickers.abstracts.CreateStickerSetAction
import dev.inmo.tgbotapi.requests.stickers.abstracts.StandardStickerSetAction
import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.stickers.MaskPosition
import kotlinx.serialization.*
@Serializable
@Deprecated("Use CreateNewStickerSet class instead")
data class CreateNewVideoStickerSet internal constructor(
@SerialName(userIdField)
override val userId: UserId,
@SerialName(nameField)
override val name: String,
@SerialName(titleField)
override val title: String,
@SerialName(emojisField)
override val emojis: String,
@SerialName(webmStickerField)
val sticker: FileId? = null,
@SerialName(containsMasksField)
@Deprecated("Will be removed soon due to its redundancy")
val containsMasks: Boolean? = null,
@SerialName(maskPositionField)
override val maskPosition: MaskPosition? = null
) : CreateStickerSetAction {
init {
if(emojis.isEmpty()) {
throw IllegalArgumentException("Emojis must not be empty")
}
}
override val requestSerializer: SerializationStrategy<*>
get() = serializer()
override fun method(): String = "createNewStickerSet"
}

View File

@@ -0,0 +1,122 @@
package dev.inmo.tgbotapi.requests.stickers
import dev.inmo.micro_utils.serialization.mapper.MapperSerializer
import dev.inmo.tgbotapi.requests.abstracts.InputFile
import dev.inmo.tgbotapi.types.StickerType
import dev.inmo.tgbotapi.types.emojiListField
import dev.inmo.tgbotapi.types.keywordsField
import dev.inmo.tgbotapi.types.maskPositionField
import dev.inmo.tgbotapi.types.stickerField
import dev.inmo.tgbotapi.types.stickers.MaskPosition
import dev.inmo.tgbotapi.utils.internal.ClassCastsIncluded
import kotlinx.serialization.KSerializer
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
@ClassCastsIncluded
@Serializable(InputStickerSerializer::class)
sealed interface InputSticker {
val sticker: InputFile
val emojisList: List<String>
@Serializable
data class Mask(
@SerialName(stickerField)
override val sticker: InputFile,
@SerialName(emojiListField)
override val emojisList: List<String>,
@SerialName(maskPositionField)
val maskPosition: MaskPosition? = null
) : InputSticker
@Serializable
sealed interface WithKeywords : InputSticker {
val keywords: List<String>
@Serializable
data class Regular(
@SerialName(stickerField)
override val sticker: InputFile,
@SerialName(emojiListField)
override val emojisList: List<String>,
@SerialName(keywordsField)
override val keywords: List<String>
) : WithKeywords
@Serializable
data class CustomEmoji(
@SerialName(stickerField)
override val sticker: InputFile,
@SerialName(emojiListField)
override val emojisList: List<String>,
@SerialName(keywordsField)
override val keywords: List<String>
) : 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

@@ -1,105 +0,0 @@
package dev.inmo.tgbotapi.requests.stickers
import dev.inmo.tgbotapi.requests.abstracts.InputFile
import dev.inmo.tgbotapi.requests.abstracts.Request
import dev.inmo.tgbotapi.types.StickerType
import dev.inmo.tgbotapi.types.UserId
import dev.inmo.tgbotapi.types.stickers.MaskPosition
fun CreateNewRegularStickerSet(
userId: UserId,
name: String,
title: String,
sticker: InputFile,
emojis: String
): Request<Boolean> = CreateNewStickerSet(
userId,
name,
title,
emojis,
StickerType.Regular,
pngSticker = sticker
)
fun CreateNewRegularVideoStickerSet(
userId: UserId,
name: String,
title: String,
sticker: InputFile,
emojis: String
): Request<Boolean> = CreateNewStickerSet(
userId,
name,
title,
emojis,
StickerType.Regular,
webmSticker = sticker
)
fun CreateNewRegularAnimatedStickerSet(
userId: UserId,
name: String,
title: String,
sticker: InputFile,
emojis: String
): Request<Boolean> = CreateNewStickerSet(
userId,
name,
title,
emojis,
StickerType.Regular,
tgsSticker = sticker
)
fun CreateNewMaskStickerSet(
userId: UserId,
name: String,
title: String,
sticker: InputFile,
emojis: String,
maskPosition: MaskPosition
): Request<Boolean> = CreateNewStickerSet(
userId,
name,
title,
emojis,
StickerType.Mask,
pngSticker = sticker,
maskPosition = maskPosition
)
fun CreateNewMaskVideoStickerSet(
userId: UserId,
name: String,
title: String,
sticker: InputFile,
emojis: String,
maskPosition: MaskPosition
): Request<Boolean> = CreateNewStickerSet(
userId,
name,
title,
emojis,
StickerType.Mask,
webmSticker = sticker,
maskPosition = maskPosition
)
fun CreateNewMaskAnimatedStickerSet(
userId: UserId,
name: String,
title: String,
sticker: InputFile,
emojis: String,
maskPosition: MaskPosition
): Request<Boolean> = CreateNewStickerSet(
userId,
name,
title,
emojis,
StickerType.Mask,
tgsSticker = sticker,
maskPosition = maskPosition
)

View File

@@ -1,80 +0,0 @@
package dev.inmo.tgbotapi.requests.stickers
import dev.inmo.tgbotapi.requests.abstracts.InputFile
import dev.inmo.tgbotapi.requests.abstracts.Request
import dev.inmo.tgbotapi.types.StickerType
import dev.inmo.tgbotapi.types.UserId
import dev.inmo.tgbotapi.types.stickers.MaskPosition
fun CreateNewVideoStickerSet(
userId: UserId,
linkName: String,
title: String,
sticker: InputFile,
emojis: String,
containsMasks: Boolean? = null,
maskPosition: MaskPosition? = null
): Request<Boolean> = CreateNewStickerSet(
userId,
linkName,
title,
emojis,
if (containsMasks == true) StickerType.Mask else StickerType.Regular,
webmSticker = sticker,
maskPosition = maskPosition
)
fun CreateNewStaticStickerSet(
userId: UserId,
name: String,
title: String,
sticker: InputFile,
emojis: String,
containsMasks: Boolean? = null,
maskPosition: MaskPosition? = null
): Request<Boolean> = CreateNewStickerSet(
userId,
name,
title,
emojis,
if (containsMasks == true) StickerType.Mask else StickerType.Regular,
pngSticker = sticker,
maskPosition = maskPosition
)
fun CreateNewStickerSet(
userId: UserId,
name: String,
title: String,
sticker: InputFile,
emojis: String,
containsMasks: Boolean? = null,
maskPosition: MaskPosition? = null
): Request<Boolean> = CreateNewStickerSet(
userId,
name,
title,
emojis,
if (containsMasks == true) StickerType.Mask else StickerType.Regular,
pngSticker = sticker,
maskPosition = maskPosition
)
fun CreateNewAnimatedStickerSet(
userId: UserId,
name: String,
title: String,
sticker: InputFile,
emojis: String,
containsMasks: Boolean? = null,
maskPosition: MaskPosition? = null
): Request<Boolean> = CreateNewStickerSet(
userId,
name,
title,
emojis,
if (containsMasks == true) StickerType.Mask else StickerType.Regular,
tgsSticker = sticker,
maskPosition = maskPosition
)

View File

@@ -0,0 +1,21 @@
package dev.inmo.tgbotapi.requests.stickers
import dev.inmo.tgbotapi.requests.abstracts.*
import dev.inmo.tgbotapi.requests.common.CommonMultipartFileRequest
import dev.inmo.tgbotapi.requests.stickers.abstracts.OwnerStickerSetAction
import dev.inmo.tgbotapi.requests.stickers.abstracts.StickerSetAction
import dev.inmo.tgbotapi.types.*
import kotlinx.serialization.*
@Serializable
data class SetCustomEmojiStickerSetThumbnail (
@SerialName(nameField)
override val name: StickerSetName,
@SerialName(customEmojiIdField)
val customEmojiId: CustomEmojiId
) : StickerSetAction {
override val requestSerializer: SerializationStrategy<*>
get() = serializer()
override fun method(): String = "setCustomEmojiStickerSetThumbnail"
}

View File

@@ -17,13 +17,6 @@ fun SetStickerSetThumbnail(
) )
} }
@Deprecated("Renamed", ReplaceWith("SetStickerSetThumbnail(userId, stickerSetName, thumbnail)", "dev.inmo.tgbotapi.requests.stickers.SetStickerSetThumbnail"))
fun SetStickerSetThumb(
userId: UserId,
stickerSetName: String,
thumbnail: MultipartFile
): Request<Boolean> = SetStickerSetThumbnail(userId, stickerSetName, thumbnail)
@Serializable @Serializable
data class SetStickerSetThumbnail ( data class SetStickerSetThumbnail (
@SerialName(userIdField) @SerialName(userIdField)
@@ -38,10 +31,3 @@ data class SetStickerSetThumbnail (
override fun method(): String = "setStickerSetThumbnail" override fun method(): String = "setStickerSetThumbnail"
} }
@Deprecated("Renamed", ReplaceWith("SetStickerSetThumbnail(userId, name, thumbnail)", "dev.inmo.tgbotapi.requests.stickers.SetStickerSetThumbnail"))
fun SetStickerSetThumb(
userId: UserId,
name: StickerSetName,
thumbnail: FileId? = null
) = SetStickerSetThumbnail(userId, name, thumbnail)

View File

@@ -13,7 +13,9 @@ data class UploadStickerFile(
@SerialName(userIdField) @SerialName(userIdField)
val userId: UserId, val userId: UserId,
@Transient @Transient
val sticker: MultipartFile = throw IllegalStateException("Detected autocreating try: this class can't be deserialized") val sticker: MultipartFile = throw IllegalStateException("Detected autocreating try: this class can't be deserialized"),
@SerialName(stickerFormatField)
val stickerFormat: StickerFormat
): MultipartRequest<File> { ): MultipartRequest<File> {
init { init {
// TODO:: add check of width/height of image and type of file - it must be png with max side length is 512px // TODO:: add check of width/height of image and type of file - it must be png with max side length is 512px
@@ -21,7 +23,7 @@ data class UploadStickerFile(
override fun method(): String = "uploadStickerFile" override fun method(): String = "uploadStickerFile"
@Transient @Transient
override val mediaMap: Map<String, MultipartFile> = mapOf(pngStickerField to sticker) override val mediaMap: Map<String, MultipartFile> = mapOf(stickerField to sticker)
@Transient @Transient
override val paramsJson: JsonObject = toJsonWithoutNulls(serializer()) override val paramsJson: JsonObject = toJsonWithoutNulls(serializer())
override val resultDeserializer: DeserializationStrategy<File> override val resultDeserializer: DeserializationStrategy<File>

View File

@@ -1,5 +1,5 @@
package dev.inmo.tgbotapi.requests.stickers.abstracts package dev.inmo.tgbotapi.requests.stickers.abstracts
interface CreateStickerSetAction : StandardStickerSetAction { interface CreateStickerSetAction : OwnerStickerSetAction {
val title: String val title: String
} }

View File

@@ -1,8 +1,8 @@
package dev.inmo.tgbotapi.requests.stickers.abstracts package dev.inmo.tgbotapi.requests.stickers.abstracts
import dev.inmo.tgbotapi.requests.stickers.InputSticker
import dev.inmo.tgbotapi.types.stickers.MaskPosition import dev.inmo.tgbotapi.types.stickers.MaskPosition
interface StandardStickerSetAction : OwnerStickerSetAction { interface StandardStickerSetAction : OwnerStickerSetAction {
val emojis: String // must be more than one val inputSticker: InputSticker
val maskPosition: MaskPosition?
} }

View File

@@ -83,6 +83,38 @@ sealed interface StickerType {
} }
} }
@Serializable(StickerFormat.Serializer::class)
sealed interface StickerFormat {
val type: String
@Serializable
object Static : StickerFormat { override val type: String = "static" }
@Serializable
object Animated : StickerFormat { override val type: String = "animated" }
@Serializable
object Video : StickerFormat { override val type: String = "video" }
@Serializable
data class Unknown(override val type: String = "custom_emoji") : StickerFormat
object Serializer : KSerializer<StickerFormat> {
override val descriptor: SerialDescriptor = String.serializer().descriptor
override fun deserialize(decoder: Decoder): StickerFormat {
return when (val type = decoder.decodeString()) {
Static.type -> Static
Animated.type -> Animated
Video.type -> Video
else -> Unknown(type)
}
}
override fun serialize(encoder: Encoder, value: StickerFormat) {
encoder.encodeString(value.type)
}
}
}
val usernameRegex = Regex("@[\\w\\d_]+") val usernameRegex = Regex("@[\\w\\d_]+")
val degreesLimit = 1 .. 360 val degreesLimit = 1 .. 360
@@ -388,6 +420,8 @@ const val webmStickerField = "webm_sticker"
const val oldChatMemberField = "old_chat_member" const val oldChatMemberField = "old_chat_member"
const val newChatMemberField = "new_chat_member" const val newChatMemberField = "new_chat_member"
const val stickerTypeField = "sticker_type" const val stickerTypeField = "sticker_type"
const val stickerFormatField = "sticker_format"
const val needsRepaintingField = "needs_repainting"
const val okField = "ok" const val okField = "ok"
const val captionField = "caption" const val captionField = "caption"

View File

@@ -5,17 +5,17 @@ import dev.inmo.tgbotapi.types.message.abstracts.Message
import dev.inmo.tgbotapi.types.message.abstracts.TelegramBotAPIMessageDeserializeOnlySerializer import dev.inmo.tgbotapi.types.message.abstracts.TelegramBotAPIMessageDeserializeOnlySerializer
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
@Serializable(ExtendedChatSerializer::class) @Serializable(ExtendedChatSerializer.Companion::class)
sealed interface ExtendedChannelChat : ChannelChat, ExtendedPublicChat, ExtendedChatWithUsername { sealed interface ExtendedChannelChat : ChannelChat, ExtendedPublicChat, ExtendedChatWithUsername {
val linkedGroupChatId: IdChatIdentifier? val linkedGroupChatId: IdChatIdentifier?
} }
@Serializable(ExtendedChatSerializer::class) @Serializable(ExtendedChatSerializer.Companion::class)
sealed interface ExtendedGroupChat : GroupChat, ExtendedPublicChat { sealed interface ExtendedGroupChat : GroupChat, ExtendedPublicChat {
val permissions: ChatPermissions val permissions: ChatPermissions
} }
@Serializable(ExtendedChatSerializer::class) @Serializable(ExtendedChatSerializer.Companion::class)
sealed interface ExtendedPrivateChat : PrivateChat, ExtendedChatWithUsername { sealed interface ExtendedPrivateChat : PrivateChat, ExtendedChatWithUsername {
val bio: String val bio: String
val hasPrivateForwards: Boolean val hasPrivateForwards: Boolean
@@ -34,7 +34,7 @@ sealed interface ExtendedPublicChat : ExtendedChat, PublicChat {
val membersHidden: Boolean val membersHidden: Boolean
} }
@Serializable(ExtendedChatSerializer::class) @Serializable(ExtendedChatSerializer.Companion::class)
sealed interface ExtendedSupergroupChat : SupergroupChat, ExtendedGroupChat, ExtendedChatWithUsername { sealed interface ExtendedSupergroupChat : SupergroupChat, ExtendedGroupChat, ExtendedChatWithUsername {
val slowModeDelay: Long? val slowModeDelay: Long?
val stickerSetName: StickerSetName? val stickerSetName: StickerSetName?
@@ -58,15 +58,15 @@ sealed interface ExtendedSupergroupChat : SupergroupChat, ExtendedGroupChat, Ext
val isAggressiveAntiSpamEnabled: Boolean val isAggressiveAntiSpamEnabled: Boolean
} }
@Serializable(ExtendedChatSerializer::class) @Serializable(ExtendedChatSerializer.Companion::class)
sealed interface ExtendedForumChat : ExtendedSupergroupChat, ForumChat sealed interface ExtendedForumChat : ExtendedSupergroupChat, ForumChat
@Serializable(ExtendedChatSerializer::class) @Serializable(ExtendedChatSerializer.Companion::class)
sealed interface ExtendedChat : Chat { sealed interface ExtendedChat : Chat {
val chatPhoto: ChatPhoto? val chatPhoto: ChatPhoto?
} }
@Serializable(ExtendedChatSerializer::class) @Serializable(ExtendedChatSerializer.Companion::class)
sealed interface ExtendedChatWithUsername : UsernameChat, ExtendedChat { sealed interface ExtendedChatWithUsername : UsernameChat, ExtendedChat {
val activeUsernames: List<Username> val activeUsernames: List<Username>
} }

View File

@@ -1,5 +1,7 @@
package dev.inmo.tgbotapi.types.chat.member package dev.inmo.tgbotapi.types.chat.member
import dev.inmo.tgbotapi.abstracts.WithChat
import dev.inmo.tgbotapi.abstracts.WithUser
import dev.inmo.tgbotapi.types.* import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.chat.Chat import dev.inmo.tgbotapi.types.chat.Chat
import dev.inmo.tgbotapi.types.chat.User import dev.inmo.tgbotapi.types.chat.User
@@ -9,9 +11,9 @@ import kotlinx.serialization.Serializable
@Serializable @Serializable
data class ChatMemberUpdated( data class ChatMemberUpdated(
@SerialName(chatField) @SerialName(chatField)
val chat: Chat, override val chat: Chat,
@SerialName(fromField) @SerialName(fromField)
val user: User, override val user: User,
@SerialName(dateField) @SerialName(dateField)
val date: TelegramDate, val date: TelegramDate,
@SerialName(oldChatMemberField) @SerialName(oldChatMemberField)
@@ -20,4 +22,4 @@ data class ChatMemberUpdated(
val newChatMemberState: ChatMember, val newChatMemberState: ChatMember,
@SerialName(inviteLinkField) @SerialName(inviteLinkField)
val inviteLink: ChatInviteLink? = null val inviteLink: ChatInviteLink? = null
) ) : WithChat, WithUser

View File

@@ -1,6 +1,7 @@
package dev.inmo.tgbotapi.types.files package dev.inmo.tgbotapi.types.files
import dev.inmo.tgbotapi.requests.abstracts.FileId import dev.inmo.tgbotapi.requests.abstracts.FileId
import dev.inmo.tgbotapi.requests.stickers.InputSticker
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 dev.inmo.tgbotapi.utils.RiskFeature import dev.inmo.tgbotapi.utils.RiskFeature
@@ -27,7 +28,8 @@ data class StickerSurrogate(
val premium_animation: File? = null, val premium_animation: File? = null,
val mask_position: MaskPosition? = null, val mask_position: MaskPosition? = null,
val custom_emoji_id: CustomEmojiId? = null, val custom_emoji_id: CustomEmojiId? = null,
val file_size: Long? = null val file_size: Long? = null,
val needs_repainting: Boolean = false
) )
// TODO:: Serializer // TODO:: Serializer
@@ -35,11 +37,14 @@ data class StickerSurrogate(
sealed interface Sticker : TelegramMediaFile, SizedMediaFile, ThumbedMediaFile { sealed interface Sticker : TelegramMediaFile, SizedMediaFile, ThumbedMediaFile {
val emoji: String? val emoji: String?
val stickerSetName: StickerSetName? val stickerSetName: StickerSetName?
val stickerFormat: StickerFormat
val isAnimated val isAnimated
get() = false get() = false
val isVideo val isVideo
get() = false get() = false
fun asInputSticker(emojis: List<String> = emoji ?.let { listOf(it) } ?: error("Unable to create input sticker without emojis")): InputSticker
} }
@OptIn(RiskFeature::class) @OptIn(RiskFeature::class)
@@ -92,7 +97,7 @@ object StickerSerializer : KSerializer<Sticker> {
surrogate.file_unique_id, surrogate.file_unique_id,
surrogate.width, surrogate.width,
surrogate.height, surrogate.height,
surrogate.mask_position ?: error("For mask stickers field mask_position should be presented"), surrogate.mask_position,
surrogate.thumb, surrogate.thumb,
surrogate.emoji, surrogate.emoji,
surrogate.set_name, surrogate.set_name,
@@ -103,7 +108,7 @@ object StickerSerializer : KSerializer<Sticker> {
surrogate.file_unique_id, surrogate.file_unique_id,
surrogate.width, surrogate.width,
surrogate.height, surrogate.height,
surrogate.mask_position ?: error("For mask stickers field mask_position should be presented"), surrogate.mask_position,
surrogate.thumb, surrogate.thumb,
surrogate.emoji, surrogate.emoji,
surrogate.set_name, surrogate.set_name,
@@ -114,7 +119,7 @@ object StickerSerializer : KSerializer<Sticker> {
surrogate.file_unique_id, surrogate.file_unique_id,
surrogate.width, surrogate.width,
surrogate.height, surrogate.height,
surrogate.mask_position ?: error("For mask stickers field mask_position should be presented"), surrogate.mask_position,
surrogate.thumb, surrogate.thumb,
surrogate.emoji, surrogate.emoji,
surrogate.set_name, surrogate.set_name,
@@ -127,33 +132,36 @@ object StickerSerializer : KSerializer<Sticker> {
surrogate.file_unique_id, surrogate.file_unique_id,
surrogate.width, surrogate.width,
surrogate.height, surrogate.height,
surrogate.custom_emoji_id ?: error("For mask stickers field mask_position should be presented"), surrogate.custom_emoji_id ?: error("For custom emoji stickers field custom_emoji_id should be presented"),
surrogate.thumb, surrogate.thumb,
surrogate.emoji, surrogate.emoji,
surrogate.set_name, surrogate.set_name,
surrogate.file_size surrogate.file_size,
surrogate.needs_repainting
) )
surrogate.is_video == true -> CustomEmojiVideoSticker( surrogate.is_video == true -> CustomEmojiVideoSticker(
surrogate.file_id, surrogate.file_id,
surrogate.file_unique_id, surrogate.file_unique_id,
surrogate.width, surrogate.width,
surrogate.height, surrogate.height,
surrogate.custom_emoji_id ?: error("For mask stickers field mask_position should be presented"), surrogate.custom_emoji_id ?: error("For custom emoji stickers field custom_emoji_id should be presented"),
surrogate.thumb, surrogate.thumb,
surrogate.emoji, surrogate.emoji,
surrogate.set_name, surrogate.set_name,
surrogate.file_size surrogate.file_size,
surrogate.needs_repainting
) )
else -> CustomEmojiSimpleSticker( else -> CustomEmojiSimpleSticker(
surrogate.file_id, surrogate.file_id,
surrogate.file_unique_id, surrogate.file_unique_id,
surrogate.width, surrogate.width,
surrogate.height, surrogate.height,
surrogate.custom_emoji_id ?: error("For mask stickers field mask_position should be presented"), surrogate.custom_emoji_id ?: error("For custom emoji stickers field custom_emoji_id should be presented"),
surrogate.thumb, surrogate.thumb,
surrogate.emoji, surrogate.emoji,
surrogate.set_name, surrogate.set_name,
surrogate.file_size surrogate.file_size,
surrogate.needs_repainting
) )
} }
is StickerType.Unknown -> UnknownSticker( is StickerType.Unknown -> UnknownSticker(
@@ -165,6 +173,11 @@ object StickerSerializer : KSerializer<Sticker> {
surrogate.emoji, surrogate.emoji,
surrogate.set_name, surrogate.set_name,
surrogate.file_size, surrogate.file_size,
when {
surrogate.is_animated == true -> StickerFormat.Animated
surrogate.is_video == true -> StickerFormat.Video
else -> StickerFormat.Static
},
json json
) )
} }
@@ -180,16 +193,28 @@ object StickerSerializer : KSerializer<Sticker> {
sealed interface VideoSticker : Sticker { sealed interface VideoSticker : Sticker {
override val isVideo: Boolean override val isVideo: Boolean
get() = true get() = true
override val stickerFormat: StickerFormat
get() = StickerFormat.Video
} }
@Serializable @Serializable
sealed interface AnimatedSticker : Sticker { sealed interface AnimatedSticker : Sticker {
override val isAnimated: Boolean override val isAnimated: Boolean
get() = true get() = true
override val stickerFormat: StickerFormat
get() = StickerFormat.Animated
} }
@Serializable @Serializable
sealed interface RegularSticker : Sticker { sealed interface RegularSticker : Sticker {
val premiumAnimationFile: File? val premiumAnimationFile: File?
override fun asInputSticker(emojis: List<String>) = InputSticker.WithKeywords.Regular(
fileId,
emojis,
emptyList()
)
} }
@Serializable @Serializable
@@ -209,12 +234,15 @@ data class RegularSimpleSticker(
@SerialName(stickerSetNameField) @SerialName(stickerSetNameField)
override val stickerSetName: StickerSetName? = null, override val stickerSetName: StickerSetName? = null,
@SerialName(premiumAnimationField) @SerialName(premiumAnimationField)
override val premiumAnimationFile: File?, override val premiumAnimationFile: File? = null,
@SerialName(fileSizeField) @SerialName(fileSizeField)
override val fileSize: Long? = null, override val fileSize: Long? = null,
) : RegularSticker ) : RegularSticker {
@Deprecated("Renamed", ReplaceWith("SimpleRegularSticker", "dev.inmo.tgbotapi.types.files.SimpleRegularSticker")) @SerialName(stickerFormatField)
typealias SimpleSticker = RegularSimpleSticker @EncodeDefault
override val stickerFormat: StickerFormat = StickerFormat.Static
}
@Serializable @Serializable
data class RegularAnimatedSticker( data class RegularAnimatedSticker(
@SerialName(fileIdField) @SerialName(fileIdField)
@@ -232,7 +260,7 @@ data class RegularAnimatedSticker(
@SerialName(stickerSetNameField) @SerialName(stickerSetNameField)
override val stickerSetName: StickerSetName? = null, override val stickerSetName: StickerSetName? = null,
@SerialName(premiumAnimationField) @SerialName(premiumAnimationField)
override val premiumAnimationFile: File?, override val premiumAnimationFile: File? = null,
@SerialName(fileSizeField) @SerialName(fileSizeField)
override val fileSize: Long? = null, override val fileSize: Long? = null,
) : RegularSticker, AnimatedSticker ) : RegularSticker, AnimatedSticker
@@ -253,7 +281,7 @@ data class RegularVideoSticker(
@SerialName(stickerSetNameField) @SerialName(stickerSetNameField)
override val stickerSetName: StickerSetName? = null, override val stickerSetName: StickerSetName? = null,
@SerialName(premiumAnimationField) @SerialName(premiumAnimationField)
override val premiumAnimationFile: File?, override val premiumAnimationFile: File? = null,
@SerialName(fileSizeField) @SerialName(fileSizeField)
override val fileSize: Long? = null, override val fileSize: Long? = null,
) : RegularSticker, VideoSticker ) : RegularSticker, VideoSticker
@@ -261,7 +289,13 @@ data class RegularVideoSticker(
@Serializable @Serializable
sealed interface MaskSticker : Sticker { sealed interface MaskSticker : Sticker {
val maskPosition: MaskPosition val maskPosition: MaskPosition?
override fun asInputSticker(emojis: List<String>) = InputSticker.Mask(
fileId,
emojis,
maskPosition
)
} }
@Serializable @Serializable
data class MaskSimpleSticker( data class MaskSimpleSticker(
@@ -274,7 +308,7 @@ data class MaskSimpleSticker(
@SerialName(heightField) @SerialName(heightField)
override val height: Int, override val height: Int,
@SerialName(maskPositionField) @SerialName(maskPositionField)
override val maskPosition: MaskPosition, override val maskPosition: MaskPosition? = null,
@SerialName(thumbnailField) @SerialName(thumbnailField)
override val thumbnail: PhotoSize? = null, override val thumbnail: PhotoSize? = null,
@SerialName(emojiField) @SerialName(emojiField)
@@ -283,7 +317,11 @@ data class MaskSimpleSticker(
override val stickerSetName: StickerSetName? = null, override val stickerSetName: StickerSetName? = null,
@SerialName(fileSizeField) @SerialName(fileSizeField)
override val fileSize: Long? = null, override val fileSize: Long? = null,
) : MaskSticker ) : MaskSticker {
@SerialName(stickerFormatField)
@EncodeDefault
override val stickerFormat: StickerFormat = StickerFormat.Static
}
@Serializable @Serializable
data class MaskAnimatedSticker( data class MaskAnimatedSticker(
@SerialName(fileIdField) @SerialName(fileIdField)
@@ -295,7 +333,7 @@ data class MaskAnimatedSticker(
@SerialName(heightField) @SerialName(heightField)
override val height: Int, override val height: Int,
@SerialName(maskPositionField) @SerialName(maskPositionField)
override val maskPosition: MaskPosition, override val maskPosition: MaskPosition? = null,
@SerialName(thumbnailField) @SerialName(thumbnailField)
override val thumbnail: PhotoSize? = null, override val thumbnail: PhotoSize? = null,
@SerialName(emojiField) @SerialName(emojiField)
@@ -316,7 +354,7 @@ data class MaskVideoSticker(
@SerialName(heightField) @SerialName(heightField)
override val height: Int, override val height: Int,
@SerialName(maskPositionField) @SerialName(maskPositionField)
override val maskPosition: MaskPosition, override val maskPosition: MaskPosition? = null,
@SerialName(thumbnailField) @SerialName(thumbnailField)
override val thumbnail: PhotoSize? = null, override val thumbnail: PhotoSize? = null,
@SerialName(emojiField) @SerialName(emojiField)
@@ -330,6 +368,13 @@ data class MaskVideoSticker(
@Serializable @Serializable
sealed interface CustomEmojiSticker : Sticker { sealed interface CustomEmojiSticker : Sticker {
val customEmojiId: CustomEmojiId val customEmojiId: CustomEmojiId
val needsRepainting: Boolean
override fun asInputSticker(emojis: List<String>) = InputSticker.WithKeywords.CustomEmoji(
fileId,
emojis,
emptyList()
)
} }
@Serializable @Serializable
@@ -352,7 +397,13 @@ data class CustomEmojiSimpleSticker(
override val stickerSetName: StickerSetName? = null, override val stickerSetName: StickerSetName? = null,
@SerialName(fileSizeField) @SerialName(fileSizeField)
override val fileSize: Long? = null, override val fileSize: Long? = null,
) : CustomEmojiSticker @SerialName(needsRepaintingField)
override val needsRepainting: Boolean = false
) : CustomEmojiSticker {
@SerialName(stickerFormatField)
@EncodeDefault
override val stickerFormat: StickerFormat = StickerFormat.Static
}
@Serializable @Serializable
data class CustomEmojiAnimatedSticker( data class CustomEmojiAnimatedSticker(
@SerialName(fileIdField) @SerialName(fileIdField)
@@ -373,6 +424,8 @@ data class CustomEmojiAnimatedSticker(
override val stickerSetName: StickerSetName? = null, override val stickerSetName: StickerSetName? = null,
@SerialName(fileSizeField) @SerialName(fileSizeField)
override val fileSize: Long? = null, override val fileSize: Long? = null,
@SerialName(needsRepaintingField)
override val needsRepainting: Boolean = false,
) : CustomEmojiSticker, AnimatedSticker ) : CustomEmojiSticker, AnimatedSticker
@Serializable @Serializable
data class CustomEmojiVideoSticker( data class CustomEmojiVideoSticker(
@@ -394,6 +447,8 @@ data class CustomEmojiVideoSticker(
override val stickerSetName: StickerSetName? = null, override val stickerSetName: StickerSetName? = null,
@SerialName(fileSizeField) @SerialName(fileSizeField)
override val fileSize: Long? = null, override val fileSize: Long? = null,
@SerialName(needsRepaintingField)
override val needsRepainting: Boolean = false,
) : CustomEmojiSticker, VideoSticker ) : CustomEmojiSticker, VideoSticker
@Serializable @Serializable
@@ -414,5 +469,13 @@ data class UnknownSticker(
override val stickerSetName: StickerSetName? = null, override val stickerSetName: StickerSetName? = null,
@SerialName(fileSizeField) @SerialName(fileSizeField)
override val fileSize: Long? = null, override val fileSize: Long? = null,
@SerialName(stickerFormatField)
override val stickerFormat: StickerFormat = StickerFormat.Static,
val raw: JsonElement val raw: JsonElement
) : Sticker ) : Sticker {
override fun asInputSticker(emojis: List<String>) = InputSticker.WithKeywords.Regular(
fileId,
emojis,
emptyList()
)
}

View File

@@ -7,6 +7,3 @@ import dev.inmo.tgbotapi.types.message.ChatEvents.abstracts.PublicChatEvent
data class LeftChatMemberEvent( data class LeftChatMemberEvent(
override val user: User override val user: User
) : PublicChatEvent, WithUser ) : PublicChatEvent, WithUser
@Deprecated("Renamed", ReplaceWith("dev.inmo.tgbotapi.types.message.ChatEvents", "LeftChatMemberEvent"))
typealias LeftChatMember = LeftChatMemberEvent

View File

@@ -57,18 +57,3 @@ sealed interface ForwardInfo {
} }
} }
} }
@Deprecated("Replaced", ReplaceWith("ForwardInfo.ByAnonymous", "dev.inmo.tgbotapi.types.message.ForwardInfo"))
typealias AnonymousForwardInfo = ForwardInfo.ByAnonymous
@Deprecated("Replaced", ReplaceWith("ForwardInfo.ByUser", "dev.inmo.tgbotapi.types.message.ForwardInfo"))
typealias UserForwardInfo = ForwardInfo.ByUser
@Deprecated("Replaced", ReplaceWith("ForwardInfo.PublicChat", "dev.inmo.tgbotapi.types.message.ForwardInfo"))
typealias ForwardFromPublicChatInfo = ForwardInfo.PublicChat
@Deprecated("Replaced", ReplaceWith("ForwardInfo.PublicChat.FromChannel", "dev.inmo.tgbotapi.types.message.ForwardInfo"))
typealias ForwardFromChannelInfo = ForwardInfo.PublicChat.FromChannel
@Deprecated("Replaced", ReplaceWith("ForwardInfo.PublicChat.FromSupergroup", "dev.inmo.tgbotapi.types.message.ForwardInfo"))
typealias ForwardFromSupergroupInfo = ForwardInfo.PublicChat.FromSupergroup

View File

@@ -223,7 +223,7 @@ internal data class RawMessage(
private val chatEvent: ChatEvent? by lazy { private val chatEvent: ChatEvent? by lazy {
when { when {
new_chat_members != null -> NewChatMembers(new_chat_members.toList()) new_chat_members != null -> NewChatMembers(new_chat_members.toList())
left_chat_member != null -> LeftChatMember(left_chat_member) left_chat_member != null -> LeftChatMemberEvent(left_chat_member)
new_chat_title != null -> NewChatTitle(new_chat_title) new_chat_title != null -> NewChatTitle(new_chat_title)
new_chat_photo != null -> NewChatPhoto(new_chat_photo.toList()) new_chat_photo != null -> NewChatPhoto(new_chat_photo.toList())
video_chat_started != null -> video_chat_started video_chat_started != null -> video_chat_started
@@ -242,12 +242,15 @@ internal data class RawMessage(
group_chat_created -> GroupChatCreated( group_chat_created -> GroupChatCreated(
migrate_to_chat_id migrate_to_chat_id
) )
supergroup_chat_created -> SupergroupChatCreated( supergroup_chat_created -> SupergroupChatCreated(
migrate_from_chat_id migrate_from_chat_id
) )
migrate_from_chat_id != null -> MigratedToSupergroup( migrate_from_chat_id != null -> MigratedToSupergroup(
migrate_from_chat_id migrate_from_chat_id
) )
channel_chat_created -> ChannelChatCreated() channel_chat_created -> ChannelChatCreated()
pinned_message != null -> PinnedMessage(pinned_message.asMessage) pinned_message != null -> PinnedMessage(pinned_message.asMessage)
proximity_alert_triggered != null -> proximity_alert_triggered proximity_alert_triggered != null -> proximity_alert_triggered

View File

@@ -1,6 +1,7 @@
package dev.inmo.tgbotapi.types.message.abstracts package dev.inmo.tgbotapi.types.message.abstracts
import com.soywiz.klock.DateTime import com.soywiz.klock.DateTime
import dev.inmo.tgbotapi.abstracts.WithChat
import dev.inmo.tgbotapi.utils.internal.ClassCastsIncluded import dev.inmo.tgbotapi.utils.internal.ClassCastsIncluded
import dev.inmo.tgbotapi.types.MessageId import dev.inmo.tgbotapi.types.MessageId
import dev.inmo.tgbotapi.types.chat.Chat import dev.inmo.tgbotapi.types.chat.Chat
@@ -11,9 +12,8 @@ import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder import kotlinx.serialization.encoding.Encoder
@ClassCastsIncluded @ClassCastsIncluded
interface Message { interface Message : WithChat {
val messageId: MessageId val messageId: MessageId
val chat: Chat
val date: DateTime val date: DateTime
} }

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,

View File

@@ -27,6 +27,7 @@ data class StickerContent(
chatId, chatId,
media.fileId, media.fileId,
messageThreadId, messageThreadId,
media.emoji,
disableNotification, disableNotification,
protectContent, protectContent,
replyToMessageId, replyToMessageId,

View File

@@ -1,37 +1,78 @@
package dev.inmo.tgbotapi.types.message.textsources package dev.inmo.tgbotapi.types.message.textsources
import dev.inmo.micro_utils.serialization.mapper.MapperSerializer
import dev.inmo.micro_utils.serialization.typed_serializer.TypedSerializer import dev.inmo.micro_utils.serialization.typed_serializer.TypedSerializer
import kotlinx.serialization.KSerializer import kotlinx.serialization.KSerializer
import kotlinx.serialization.encoding.CompositeEncoder
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
private val baseSerializers: Map<String, KSerializer<out TextSource>> = mapOf( //private val baseSerializers: Map<String, KSerializer<out TextSource>> = mapOf(
"regular" to RegularTextSource.serializer(), // "regular" to RegularTextSource.serializer(),
"text_link" to TextLinkTextSource.serializer(), // "text_link" to TextLinkTextSource.serializer(),
"code" to CodeTextSource.serializer(), // "code" to CodeTextSource.serializer(),
"url" to URLTextSource.serializer(), // "url" to URLTextSource.serializer(),
"pre" to PreTextSource.serializer(), // "pre" to PreTextSource.serializer(),
"bot_command" to BotCommandTextSource.serializer(), // "bot_command" to BotCommandTextSource.serializer(),
"strikethrough" to StrikethroughTextSource.serializer(), // "strikethrough" to StrikethroughTextSource.serializer(),
"italic" to ItalicTextSource.serializer(), // "italic" to ItalicTextSource.serializer(),
"bold" to BoldTextSource.serializer(), // "bold" to BoldTextSource.serializer(),
"email" to EMailTextSource.serializer(), // "email" to EMailTextSource.serializer(),
"underline" to UnderlineTextSource.serializer(), // "underline" to UnderlineTextSource.serializer(),
"mention" to MentionTextSource.serializer(), // "mention" to MentionTextSource.serializer(),
"phone_number" to PhoneNumberTextSource.serializer(), // "phone_number" to PhoneNumberTextSource.serializer(),
"text_mention" to TextMentionTextSource.serializer(), // "text_mention" to TextMentionTextSource.serializer(),
"hashtag" to HashTagTextSource.serializer(), // "hashtag" to HashTagTextSource.serializer(),
"cashtag" to CashTagTextSource.serializer(), // "cashtag" to CashTagTextSource.serializer(),
"spoiler" to SpoilerTextSource.serializer(), // "spoiler" to SpoilerTextSource.serializer(),
"custom_emoji" to CustomEmojiTextSource.serializer(), // "custom_emoji" to CustomEmojiTextSource.serializer(),
) //)
object TextSourceSerializer : TypedSerializer<TextSource>(TextSource::class, emptyMap()) {
private val baseSerializers: Map<String, KSerializer<out TextSource>> by lazy {
mapOf(
"regular" to RegularTextSource.serializer(),
"text_link" to TextLinkTextSource.serializer(),
"code" to CodeTextSource.serializer(),
"url" to URLTextSource.serializer(),
"pre" to PreTextSource.serializer(),
"bot_command" to BotCommandTextSource.serializer(),
"strikethrough" to StrikethroughTextSource.serializer(),
"italic" to ItalicTextSource.serializer(),
"bold" to BoldTextSource.serializer(),
"email" to EMailTextSource.serializer(),
"underline" to UnderlineTextSource.serializer(),
"mention" to MentionTextSource.serializer(),
"phone_number" to PhoneNumberTextSource.serializer(),
"text_mention" to TextMentionTextSource.serializer(),
"hashtag" to HashTagTextSource.serializer(),
"cashtag" to CashTagTextSource.serializer(),
"spoiler" to SpoilerTextSource.serializer(),
"custom_emoji" to CustomEmojiTextSource.serializer(),
).also {
it.forEach { (k, s) ->
include(k, s)
}
}
}
override fun serialize(encoder: Encoder, value: TextSource) {
baseSerializers // init base serializers
super.serialize(encoder, value)
}
override fun deserialize(decoder: Decoder): TextSource {
baseSerializers // init base serializers
return super.deserialize(decoder)
}
object TextSourceSerializer : TypedSerializer<TextSource>(TextSource::class, baseSerializers) {
override fun <T: TextSource> include(type: String, serializer: KSerializer<T>) { override fun <T: TextSource> include(type: String, serializer: KSerializer<T>) {
require(type !in baseSerializers.keys) require(type !in serializers.keys)
super.include(type, serializer) super.include(type, serializer)
} }
override fun exclude(type: String) { override fun exclude(type: String) {
require(type !in baseSerializers.keys) require(type !in serializers.keys)
super.exclude(type) super.exclude(type)
} }
} }

View File

@@ -25,15 +25,16 @@ sealed interface StickerSet {
val name: String val name: String
val title: String val title: String
val stickerType: StickerType val stickerType: StickerType
val stickerFormat: StickerFormat
val stickers: List<Sticker> val stickers: List<Sticker>
val isAnimated: Boolean val isAnimated: Boolean
get() = false get() = false
val isVideo: Boolean val isVideo: Boolean
get() = false get() = false
val thumbnail: PhotoSize?
@Deprecated("Renamed in telegram bot api")
val thumb: PhotoSize? val thumb: PhotoSize?
@Deprecated("Will be removed soon due to its redundancy") get() = thumbnail
val containsMasks: Boolean
get() = this is MaskStickerSet
object Serializer : KSerializer<StickerSet> { object Serializer : KSerializer<StickerSet> {
override val descriptor: SerialDescriptor = JsonElement.serializer().descriptor override val descriptor: SerialDescriptor = JsonElement.serializer().descriptor
@@ -124,11 +125,19 @@ sealed interface StickerSet {
sealed interface AnimatedStickerSet : StickerSet { sealed interface AnimatedStickerSet : StickerSet {
override val isAnimated: Boolean override val isAnimated: Boolean
get() = true get() = true
@SerialName(stickerFormatField)
@EncodeDefault
override val stickerFormat: StickerFormat
get() = StickerFormat.Animated
} }
@Serializable @Serializable
sealed interface VideoStickerSet : StickerSet { sealed interface VideoStickerSet : StickerSet {
override val isVideo: Boolean override val isVideo: Boolean
get() = true get() = true
@SerialName(stickerFormatField)
@EncodeDefault
override val stickerFormat: StickerFormat
get() = StickerFormat.Video
} }
@Serializable @Serializable
sealed interface RegularStickerSet : StickerSet sealed interface RegularStickerSet : StickerSet
@@ -146,11 +155,14 @@ data class RegularSimpleStickerSet(
@SerialName(stickersField) @SerialName(stickersField)
override val stickers: List<RegularSimpleSticker>, override val stickers: List<RegularSimpleSticker>,
@SerialName(thumbnailField) @SerialName(thumbnailField)
override val thumb: PhotoSize? = null override val thumbnail: PhotoSize? = null
) : RegularStickerSet { ) : RegularStickerSet {
@SerialName(stickerTypeField) @SerialName(stickerTypeField)
@EncodeDefault @EncodeDefault
override val stickerType: StickerType = StickerType.Regular override val stickerType: StickerType = StickerType.Regular
@SerialName(stickerFormatField)
@EncodeDefault
override val stickerFormat: StickerFormat = StickerFormat.Static
} }
@Serializable @Serializable
@@ -162,7 +174,7 @@ data class RegularAnimatedStickerSet(
@SerialName(stickersField) @SerialName(stickersField)
override val stickers: List<RegularAnimatedSticker>, override val stickers: List<RegularAnimatedSticker>,
@SerialName(thumbnailField) @SerialName(thumbnailField)
override val thumb: PhotoSize? = null override val thumbnail: PhotoSize? = null
) : RegularStickerSet, AnimatedStickerSet { ) : RegularStickerSet, AnimatedStickerSet {
@SerialName(stickerTypeField) @SerialName(stickerTypeField)
@EncodeDefault @EncodeDefault
@@ -178,7 +190,7 @@ data class RegularVideoStickerSet(
@SerialName(stickersField) @SerialName(stickersField)
override val stickers: List<RegularVideoSticker>, override val stickers: List<RegularVideoSticker>,
@SerialName(thumbnailField) @SerialName(thumbnailField)
override val thumb: PhotoSize? = null override val thumbnail: PhotoSize? = null
) : RegularStickerSet, VideoStickerSet { ) : RegularStickerSet, VideoStickerSet {
@SerialName(stickerTypeField) @SerialName(stickerTypeField)
@EncodeDefault @EncodeDefault
@@ -194,11 +206,15 @@ data class MaskSimpleStickerSet(
@SerialName(stickersField) @SerialName(stickersField)
override val stickers: List<MaskSimpleSticker>, override val stickers: List<MaskSimpleSticker>,
@SerialName(thumbnailField) @SerialName(thumbnailField)
override val thumb: PhotoSize? = null override val thumbnail: PhotoSize? = null
) : MaskStickerSet { ) : MaskStickerSet {
@SerialName(stickerTypeField) @SerialName(stickerTypeField)
@EncodeDefault @EncodeDefault
override val stickerType: StickerType = StickerType.Mask override val stickerType: StickerType = StickerType.Mask
@SerialName(stickerFormatField)
@EncodeDefault
override val stickerFormat: StickerFormat = StickerFormat.Static
} }
@Serializable @Serializable
@@ -210,7 +226,7 @@ data class MaskAnimatedStickerSet(
@SerialName(stickersField) @SerialName(stickersField)
override val stickers: List<MaskAnimatedSticker>, override val stickers: List<MaskAnimatedSticker>,
@SerialName(thumbnailField) @SerialName(thumbnailField)
override val thumb: PhotoSize? = null override val thumbnail: PhotoSize? = null
) : MaskStickerSet, AnimatedStickerSet { ) : MaskStickerSet, AnimatedStickerSet {
@SerialName(stickerTypeField) @SerialName(stickerTypeField)
@EncodeDefault @EncodeDefault
@@ -226,7 +242,7 @@ data class MaskVideoStickerSet(
@SerialName(stickersField) @SerialName(stickersField)
override val stickers: List<MaskVideoSticker>, override val stickers: List<MaskVideoSticker>,
@SerialName(thumbnailField) @SerialName(thumbnailField)
override val thumb: PhotoSize? = null override val thumbnail: PhotoSize? = null
) : MaskStickerSet, VideoStickerSet { ) : MaskStickerSet, VideoStickerSet {
@SerialName(stickerTypeField) @SerialName(stickerTypeField)
@EncodeDefault @EncodeDefault
@@ -242,11 +258,15 @@ data class CustomEmojiSimpleStickerSet(
@SerialName(stickersField) @SerialName(stickersField)
override val stickers: List<CustomEmojiSimpleSticker>, override val stickers: List<CustomEmojiSimpleSticker>,
@SerialName(thumbnailField) @SerialName(thumbnailField)
override val thumb: PhotoSize? = null override val thumbnail: PhotoSize? = null
) : CustomEmojiStickerSet { ) : CustomEmojiStickerSet {
@SerialName(stickerTypeField) @SerialName(stickerTypeField)
@EncodeDefault @EncodeDefault
override val stickerType: StickerType = StickerType.CustomEmoji override val stickerType: StickerType = StickerType.CustomEmoji
@SerialName(stickerFormatField)
@EncodeDefault
override val stickerFormat: StickerFormat = StickerFormat.Static
} }
@Serializable @Serializable
@@ -258,7 +278,7 @@ data class CustomEmojiAnimatedStickerSet(
@SerialName(stickersField) @SerialName(stickersField)
override val stickers: List<CustomEmojiAnimatedSticker>, override val stickers: List<CustomEmojiAnimatedSticker>,
@SerialName(thumbnailField) @SerialName(thumbnailField)
override val thumb: PhotoSize? = null override val thumbnail: PhotoSize? = null
) : CustomEmojiStickerSet, AnimatedStickerSet { ) : CustomEmojiStickerSet, AnimatedStickerSet {
@SerialName(stickerTypeField) @SerialName(stickerTypeField)
@EncodeDefault @EncodeDefault
@@ -274,7 +294,7 @@ data class CustomEmojiVideoStickerSet(
@SerialName(stickersField) @SerialName(stickersField)
override val stickers: List<CustomEmojiVideoSticker>, override val stickers: List<CustomEmojiVideoSticker>,
@SerialName(thumbnailField) @SerialName(thumbnailField)
override val thumb: PhotoSize? = null override val thumbnail: PhotoSize? = null
) : CustomEmojiStickerSet, VideoStickerSet { ) : CustomEmojiStickerSet, VideoStickerSet {
@SerialName(stickerTypeField) @SerialName(stickerTypeField)
@EncodeDefault @EncodeDefault
@@ -292,6 +312,6 @@ data class UnknownStickerSet(
@SerialName(stickerTypeField) @SerialName(stickerTypeField)
override val stickerType: StickerType, override val stickerType: StickerType,
@SerialName(thumbnailField) @SerialName(thumbnailField)
override val thumb: PhotoSize? = null, override val thumbnail: PhotoSize? = null,
val raw: JsonElement val raw: JsonElement
) : CustomEmojiStickerSet, VideoStickerSet ) : CustomEmojiStickerSet, VideoStickerSet

View File

@@ -14,9 +14,6 @@ interface FlowsUpdatesFilter : UpdatesFilter {
override val allowedUpdates: List<String> override val allowedUpdates: List<String>
get() = ALL_UPDATES_LIST get() = ALL_UPDATES_LIST
val allUpdatesFlow: Flow<Update> val allUpdatesFlow: Flow<Update>
@Deprecated("Since 4.0.0 is not actual", ReplaceWith("allUpdatesFlow"))
val allUpdatesWithoutMediaGroupsGroupingFlow: Flow<Update>
get() = allUpdatesFlow
val messagesFlow: Flow<MessageUpdate> val messagesFlow: Flow<MessageUpdate>
val messageMediaGroupsFlow: Flow<MessageUpdate> val messageMediaGroupsFlow: Flow<MessageUpdate>

View File

@@ -0,0 +1,5 @@
package dev.inmo.tgbotapi.bot.ktor
import dev.inmo.tgbotapi.bot.ktor.base.DefaultKtorRequestsExecutor
actual typealias KtorRequestsExecutor = DefaultKtorRequestsExecutor

View File

@@ -0,0 +1,13 @@
package dev.inmo.tgbotapi.bot.ktor.base
import io.ktor.client.*
/**
* This function is used in default constructor of [MultipleClientKtorRequestsExecutor] and on all non-native
* platforms and MingwX64 should return [client]
*
* On LinuxX64 it will create copy with Curl engine or throw an exception if engine is different with Curl
*
* @throws IllegalArgumentException When pass non Curl-based [HttpClient] on LinuxX64
*/
internal actual inline fun platformClientCopy(client: HttpClient): HttpClient = client.config { }

View File

@@ -0,0 +1,5 @@
package dev.inmo.tgbotapi.bot.ktor
import dev.inmo.tgbotapi.bot.ktor.base.DefaultKtorRequestsExecutor
actual typealias KtorRequestsExecutor = DefaultKtorRequestsExecutor

View File

@@ -0,0 +1,13 @@
package dev.inmo.tgbotapi.bot.ktor.base
import io.ktor.client.*
/**
* This function is used in default constructor of [MultipleClientKtorRequestsExecutor] and on all non-native
* platforms and MingwX64 should return [client]
*
* On LinuxX64 it will create copy with Curl engine or throw an exception if engine is different with Curl
*
* @throws IllegalArgumentException When pass non Curl-based [HttpClient] on LinuxX64
*/
internal actual inline fun platformClientCopy(client: HttpClient): HttpClient = client.config { }

View File

@@ -0,0 +1 @@
package dev.inmo.tgbotapi

View File

@@ -0,0 +1,5 @@
package dev.inmo.tgbotapi.bot.ktor
import dev.inmo.tgbotapi.bot.ktor.base.MultipleClientKtorRequestsExecutor
actual typealias KtorRequestsExecutor = MultipleClientKtorRequestsExecutor

View File

@@ -0,0 +1,22 @@
package dev.inmo.tgbotapi.bot.ktor.base
import io.ktor.client.*
import io.ktor.client.engine.curl.*
/**
* This function is used in default constructor of [MultipleClientKtorRequestsExecutor] and on all non-native
* platforms and MingwX64 should return [client]
*
* On LinuxX64 it will create copy with Curl engine or throw an exception if engine is different with Curl
*
* @throws IllegalArgumentException When pass non Curl-based [HttpClient] on LinuxX64
*/
internal actual inline fun platformClientCopy(client: HttpClient): HttpClient = (client.engineConfig as? CurlClientEngineConfig) ?.let {
lateinit var config: HttpClientConfig<out CurlClientEngineConfig>
client.config {
config = this as HttpClientConfig<out CurlClientEngineConfig>
}.close()
HttpClient(Curl) {
this.plusAssign(config)
}
} ?: throw IllegalArgumentException("On LinuxX64 TelegramBotAPI currently support only Curl Ktor HttpClient engine")

View File

@@ -0,0 +1,9 @@
package dev.inmo.tgbotapi.requests.abstracts
import dev.inmo.micro_utils.common.MPPFile
import dev.inmo.micro_utils.ktor.common.input
import dev.inmo.tgbotapi.requests.abstracts.MultipartFile
actual fun MPPFile.asMultipartFile(): MultipartFile = MultipartFile(this.name) {
input()
}

View File

@@ -0,0 +1,7 @@
package dev.inmo.tgbotapi.utils
import io.ktor.utils.io.ByteReadChannel
import io.ktor.utils.io.core.Input
import io.ktor.utils.io.readRemaining
actual suspend fun ByteReadChannel.asInput(): Input = readRemaining()

View File

@@ -0,0 +1,11 @@
package dev.inmo.tgbotapi.utils
import kotlinx.serialization.Serializable
//actual typealias MimeType = MimeType
@Serializable(MimeTypeSerializer::class)
actual data class MimeType(
actual val raw: String
)
internal actual fun createMimeType(raw: String): MimeType = MimeType(raw)

View File

@@ -0,0 +1 @@
package dev.inmo.tgbotapi

Some files were not shown because too many files have changed in this diff Show More