1
0
mirror of https://github.com/InsanusMokrassar/TelegramBotAPI.git synced 2025-11-17 04:20:13 +00:00

Compare commits

..

85 Commits

Author SHA1 Message Date
b22118b400 add suppressing of unchecked casts 2021-01-05 23:04:09 +06:00
2006e45b57 last update of classcasts 2021-01-05 23:02:00 +06:00
c091098feb remove *Impl casts 2021-01-05 22:37:52 +06:00
6cf8d47cbf update classcasts 2021-01-05 22:27:42 +06:00
3dc4e9dda4 preview of solution for #145 2021-01-05 11:54:02 +06:00
6407ad1a93 Revert "one more update of klassindex"
This reverts commit f974e5787f.
2021-01-05 11:11:50 +06:00
f974e5787f one more update of klassindex 2021-01-05 11:11:37 +06:00
28a9bbd310 Revert "add klassindex"
This reverts commit 599d5a51e3.
2021-01-05 01:37:01 +06:00
599d5a51e3 add klassindex 2021-01-05 01:36:52 +06:00
25f8d15a4b start 0.3.12 2021-01-05 00:16:11 +06:00
66c2cb2d30 Merge pull request #243 from InsanusMokrassar/0.30.11
0.30.11
2021-01-04 14:35:56 +06:00
74fb448378 update klock 2021-01-04 14:29:06 +06:00
3417ec060f Update README.md 2021-01-03 15:22:19 +06:00
4f54a00003 Update README.md 2021-01-03 15:20:42 +06:00
4fb187da30 Update README.md 2021-01-03 15:19:35 +06:00
7637b6f69a Update README.md 2021-01-03 15:17:58 +06:00
9df9af193c bot actions got class-cast shortcuts 2021-01-02 16:06:00 +06:00
ba4b4c4b64 bot actions shortcut 2021-01-02 15:51:26 +06:00
fa0861b8bc update micro_utils 2020-12-23 13:42:00 +06:00
20494e1d4a Update CHANGELOG.md 2020-12-22 17:34:14 +06:00
a404008dee Update dependencies 2020-12-22 17:33:20 +06:00
881205dd80 update dependencies 2020-12-16 14:25:09 +06:00
2096c44811 start 0.30.11 2020-12-13 22:25:57 +06:00
1a3da33589 Merge pull request #237 from InsanusMokrassar/0.30.10
0.30.10
2020-12-08 14:25:00 +06:00
be28c9bd5d update dependencies 2020-12-08 12:03:45 +06:00
a193ef5fd5 buildBot 2020-12-04 16:29:50 +06:00
7c43d3aaa5 update dependencies 2020-12-04 16:13:02 +06:00
e034afc75c start 0.30.10 2020-12-04 16:06:14 +06:00
08e3326d1a Merge pull request #226 from InsanusMokrassar/0.30.9
0.30.9
2020-11-27 00:59:33 +06:00
6dd1825b98 update dependencies 2020-11-27 00:44:29 +06:00
bd4eb29fc1 update limits of dices 2020-11-26 19:37:35 +06:00
2cc66ef13c BowlingDiceAnimationType 2020-11-25 23:09:49 +06:00
9a8175d1c8 update dependencies 2020-11-25 23:02:54 +06:00
25285b2e8a start 0.30.9 2020-11-25 23:01:19 +06:00
bb09f05d7b Merge pull request #223 from InsanusMokrassar/0.30.8
0.30.8
2020-11-21 16:37:47 +06:00
da5e46e59f remove several PreviewFeature 2020-11-21 15:19:31 +06:00
a3f315a73a update micro_utils 2020-11-21 15:15:07 +06:00
43583a885a update versions 2020-11-21 14:40:34 +06:00
ec02257ecd start 0.30.8 2020-11-21 14:32:32 +06:00
29ee4a9396 update publishing urls 2020-11-18 17:51:53 +06:00
2717cb4fc6 exprimentally update publishing scripts 2020-11-18 17:18:51 +06:00
1ce2526401 Merge pull request #217 from InsanusMokrassar/0.30.7
0.30.7
2020-11-17 16:32:19 +06:00
74c480b07e one new telegramBot function 2020-11-17 16:18:58 +06:00
657e9aa770 add KtorRequestsExecutorBuilder 2020-11-17 16:06:25 +06:00
0d19952ba7 PowLimiter and CommonLimiter rewriting (#210) 2020-11-17 15:48:58 +06:00
f8cccc3e17 update gradle 2020-11-17 14:41:53 +06:00
bc1b7c3f25 fix ending of host url in TelegramAPIUrlsKeeper 2020-11-17 13:18:11 +06:00
ec74111a9d update micro_utils version 2020-11-17 12:51:55 +06:00
2dadeb7eb7 start 0.30.7 2020-11-17 12:50:54 +06:00
24bd65501b Update README.md 2020-11-16 21:59:25 +06:00
574ca803fa Update README.md 2020-11-16 21:56:31 +06:00
947e3bf34e add fast start 2020-11-16 21:55:22 +06:00
488158d8fb Merge pull request #214 from InsanusMokrassar/0.30.6
0.30.6
2020-11-16 16:29:46 +06:00
41bf3c7f0b filling of changelog and renaming of new function makeLink -> makeUsernameLink 2020-11-16 16:25:10 +06:00
c2032d21cd TextSource properties has been renamed 2020-11-16 13:32:20 +06:00
6650dd9cfe reworking of links extension 2020-11-16 13:22:08 +06:00
af1d6d6f1a start 0.30.6 2020-11-15 23:05:19 +06:00
a5861d659d Merge pull request #212 from InsanusMokrassar/0.30.5
0.30.5
2020-11-14 19:44:26 +06:00
b36f80a6d3 update micro_utils 2020-11-14 19:41:26 +06:00
7c4f034a6c fixes in imports 2020-11-14 14:41:16 +06:00
3b08bc6dd2 serialization of ChatMember and changing of id type in User 2020-11-14 14:38:54 +06:00
ed87c0ad95 start 0.30.5 2020-11-14 11:19:53 +06:00
c8c0fc2ce8 Merge pull request #211 from InsanusMokrassar/0.30.4
0.30.4
2020-11-12 23:05:49 +06:00
1f40ce1a81 add a lot of shortcuts for events 2020-11-12 22:35:27 +06:00
b0219389fc add several functions and changelog notes 2020-11-12 22:23:10 +06:00
f6ec82b449 deprecate old asChatEventsFlow 2020-11-12 22:04:46 +06:00
71dac70635 deprecations in old functions 2020-11-12 22:02:06 +06:00
98f68a9e1e filling of changelog 2020-11-12 21:54:14 +06:00
e7199e7451 fix use user in group messages 2020-11-12 21:46:33 +06:00
33b50c6c68 events filters 2020-11-12 21:17:11 +06:00
e4ce6f8fc7 fixes in events 2020-11-12 17:44:33 +06:00
8764f18ca8 TextContent now implements TextedInput 2020-11-12 16:57:32 +06:00
b2fa7fee9d rename MultilevelTextSource#textSources 2020-11-12 16:37:17 +06:00
0121e3a104 update micro_utils 2020-11-12 16:33:48 +06:00
f6e5664632 start 0.30.4 2020-11-12 16:31:02 +06:00
c5b7c4e1f5 Merge pull request #209 from InsanusMokrassar/0.30.3
0.30.3
2020-11-11 11:25:25 +06:00
53800d49bf small rework in ExceptionsOnlyLimiter 2020-11-11 11:23:24 +06:00
d83e3eb10a add handling of 429 status 2020-11-11 11:15:19 +06:00
66b4d06064 limiter rework 2020-11-11 10:23:20 +06:00
4fab01b2a2 update micro_utils 2020-11-11 10:15:06 +06:00
b81086c4bb start 0.30.3 2020-11-11 10:14:10 +06:00
d776071cac Update build.gradle 2020-11-11 01:32:25 +06:00
5f33d05deb Update extensions utils dependencies 2020-11-11 01:31:28 +06:00
912cc7217c Update extensions api dependencies 2020-11-11 01:30:31 +06:00
96e00f6e31 Merge pull request #207 from InsanusMokrassar/0.30.2
0.30.2
2020-11-10 21:52:37 +06:00
88 changed files with 1900 additions and 886 deletions

View File

@@ -1,5 +1,135 @@
# TelegramBotAPI changelog
## 0.30.12
* `Utils`:
* Class casts has been added. Now you can write something like `message.asGroupMessage() ?.let { ... }` instead of
`(message as? GroupMessage<*>) ?.let { ... }`
## 0.30.11
* `Common`:
* `Version`:
* `MicroUtils`: `0.4.11` -> `0.4.15`
* `Klock`: `2.0.1` -> `2.0.3`
* `Ktor`: `1.4.3` -> `1.5.0`
* `Core`:
* All bot actions got functions for short calling, like `recordVideo` for `RecordVideoNote`
* All bot actions got class-cast shortcuts
## 0.30.10
* `Common`:
* `Version`:
* `Kotlin`: `1.4.20` -> `1.4.21`
* `Klock`: `2.0.0` -> `2.0.1`
* `Ktor`: `1.4.2` -> `1.4.3`
* `MicroUtils`: `0.4.6` -> `0.4.11`
* `API Extensions`:
* New function `buildBot`
## 0.30.9
* `Common`:
* `Version`:
* `UUID`: `0.2.2` -> `0.2.3`
* `Coroutines`: `1.4.1` -> `1.4.2`
* `MicroUtils`: `0.4.3` -> `0.4.6`
* `Core`:
* Add `BowlingDiceAnimationType`
## 0.30.8
* `Common`:
* `Version`:
* `Kotlin`: `1.4.10` -> `1.4.20`
* `Klock`: `1.12.1` -> `2.0.0`
* `MicroUtils`: `0.4.1` -> `0.4.3`
## 0.30.7
* `Common`:
* `Version`:
* `MicroUtils`: `0.4.0` -> `0.4.1`
* `Core`:
* `TelegramAPIUrlsKeeper` will fix ending of host url since this version
* New mechanisms in`PowLimiter` and `CommonLimiter` has been added
* New builder `KtorRequestsExecutorBuilder`
* New function `telegramBot`
* `Utils`:
* Simple function `telegramBot(TelegramAPIUrlsKeeper)` has been deprecated with replacement by almost the same
function in `Core`
## 0.30.6
* `Core`
* `TextSource` properties has been renamed:
* `asMarkdownSource` -> `markdown`
* `asMarkdownV2Source` -> `markdownV2`
* `asHtmlSource` -> `html`
* `PrivateChat` override `id` property with type `UserId`
* Several new extensions and functions in links creation:
* New function `makeUsernameLink` with parameter `String`
* New extension `Username#link` and function `makeLink(Username)`
* Function `makeLinkToMessage` now able to get any type of chat
* New extension `Message#link`
* Old functions `makeLinkToAddStickerSet...` has been deprecated:
* `makeLinkToAddStickerSet`
* `makeLinkToAddStickerSetInMarkdownV2`
* `makeLinkToAddStickerSetInMarkdown`
* `makeLinkToAddStickerSetInHtml`
## 0.30.5
* `Common`:
* `Version`:
* `MicroUtils`: `0.3.3` -> `0.4.0`
* `Core`:
* Mechanism of `ChatMember` serialization has been changed
* Since this version any `ChatMember` can be serialized (even outside in case it marked by `@Serializable`)
* Since this version any `ChatMember` (included in this project) can be deserialized in common way
* `User` property `id` has changed its type: now it is `UserId` (under the hood it is the same as `ChatId`)
## 0.30.4
* `Common`:
* `Version`:
* `MicroUtils`: `0.3.1` -> `0.3.3`
* `Core`:
* `MultilevelTextSource#textSources` has been safely renamed to `subsources`
* `TextContent#fullEntitiesList` has been deprecated
* Now `TextContent` implements `TextedInput`
* `TextContent#entities` has been deprecated
* `GroupEventMessage` now overrides `chatEvent` with type `GroupEvent`
* `SupergroupEventMessage` now overrides `chatEvent` with type `SupergroupEvent`
* Any `ChatEventMessage` now have generic type of its `chatEvent` (just like messages)
* `Utils`:
* Old extensions related to chat events are deprecated:
* `Flow<ChatEventMessage<*>>#divideBySource`
* `Flow<ChatEventMessage<*>>#onlyChannelEvents`
* `Flow<ChatEventMessage<*>>#onlyGroupEvents`
* `Flow<ChatEventMessage<*>>#onlySupergroupEvents`
* A lot of extensions for `Flow<ChatEventMessage>` has been added:
* `FlowsUpdatesFilter#events`
* `FlowsUpdatesFilter#channelEvents`
* `FlowsUpdatesFilter#groupEvents`
* `FlowsUpdatesFilter#supergroupEvents`
* And a lot of other filters with specific types
## 0.30.3
* `Common`:
* `Version`:
* `MicroUtils`: `0.3.0` -> `0.3.1`
* `Core`:
* New type of requests exceptions `TooMuchRequestsException`. In fact it will be rare case when you will get this
exception
* `EmptyLimiter` has been renamed to `ExceptionsOnlyLimiter` and currently will stop requests after
`TooMuchRequestsException` happen until retry time is actual
* Now `ExceptionsOnlyLimiter` (previously `EmptyLimiter`) is a class
* `AbstractRequestCallFactory` currently will not look at the response and wait if it have `RetryAfter` error. New
behaviour aimed on delegating of this work to `RequestsLimiter`
## 0.30.2
* `Common`:

View File

@@ -1,5 +1,16 @@
# TelegramBotAPI
<details>
<summary><b>I do not wanna read a lot, just give me my bot</b></summary>
You can simply use <a href="https://github.com/InsanusMokrassar/TelegramBotAPI-bot_template">this template</a> (and button
<a href="https://github.com/InsanusMokrassar/TelegramBotAPI-bot_template/generate">Use template</a>) to get your copy of bot and start to code.
<p></p>
<b>P.S. Do not forget to look into our <a href="https://bookstack.inmo.dev/books/telegrambotapi/">minidocs</a> and
<a href="https://tgbotapi.inmo.dev/docs/index.html">kdocs</a></b>
</details>
| Common info | [![Awesome Kotlin Badge](https://kotlin.link/awesome-kotlin.svg)](https://github.com/KotlinBy/awesome-kotlin) [![Build Status](https://travis-ci.com/InsanusMokrassar/TelegramBotAPI.svg?branch=master)](https://travis-ci.com/InsanusMokrassar/TelegramBotAPI) [Small survey](https://forms.gle/2Hex2ynbHWHhi1KY7)|
| -------------------------------------:|:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Useful links | [![Chat in Telegram](badges/chat.svg)](https://t.me/InMoTelegramBotAPI) [![Create bot](badges/template.svg)](https://github.com/InsanusMokrassar/TelegramBotAPI-bot_template/generate) [![KDocs](badges/kdocs.svg)](https://tgbotapi.inmo.dev/docs/index.html) [Examples](https://github.com/InsanusMokrassar/TelegramBotAPI-examples/), [Mini tutorial](https://bookstack.inmo.dev/books/telegrambotapi/chapter/introduction-tutorial) |
@@ -12,6 +23,7 @@
[kotlinx.serialization#1004](https://github.com/Kotlin/kotlinx.serialization/issues/1004). It is possible, that both JVM
and JS version may work improperly in some cases with `kotlinx.serialization` version `1.0.0-RC`**
## What is it?
It is a complex of libraries for working with `TelegramBotAPI` in type-safe and strict way as much as it possible. In
the list of this complex currently next projects:

View File

@@ -9,7 +9,6 @@ buildscript {
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version"
classpath "com.jfrog.bintray.gradle:gradle-bintray-plugin:$gradle_bintray_plugin_version"
classpath "com.github.breadmoirai:github-release:$github_release_plugin_version"
}
}

View File

@@ -1,3 +1,3 @@
dokka_version=1.4.0
dokka_version=1.4.20
org.gradle.jvmargs=-Xmx1024m

View File

@@ -5,19 +5,18 @@ kotlin.js.generate.externals=true
kotlin.incremental=true
kotlin.incremental.js=true
kotlin_version=1.4.10
kotlin_coroutines_version=1.4.1
kotlin_version=1.4.21
kotlin_coroutines_version=1.4.2
kotlin_serialisation_runtime_version=1.0.1
klock_version=1.12.1
uuid_version=0.2.2
ktor_version=1.4.2
klock_version=2.0.3
uuid_version=0.2.3
ktor_version=1.5.0
micro_utils_version=0.3.0
micro_utils_version=0.4.15
javax_activation_version=1.1.1
library_group=dev.inmo
library_version=0.30.2
library_version=0.30.12
gradle_bintray_plugin_version=1.8.5
github_release_plugin_version=2.2.12

View File

@@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.6.1-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-bin.zip

View File

@@ -8,7 +8,6 @@ buildscript {
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version"
classpath "com.jfrog.bintray.gradle:gradle-bintray-plugin:$gradle_bintray_plugin_version"
}
}

View File

@@ -1,53 +0,0 @@
apply plugin: 'maven-publish'
task javadocsJar(type: Jar) {
classifier = 'javadoc'
}
afterEvaluate {
project.publishing.publications.all {
// rename artifacts
groupId "${project.group}"
if (it.name.contains('kotlinMultiplatform')) {
artifactId = "${project.name}"
} else {
artifactId = "${project.name}-$name"
}
}
}
publishing {
publications.all {
artifact javadocsJar
pom {
description = "Library for Object-Oriented and type-safe work with Telegram Bot API"
name = "Telegram Bot API Core"
url = "https://insanusmokrassar.github.io/TelegramBotAPI"
scm {
developerConnection = "scm:git:[fetch=]https://github.com/insanusmokrassar/TelegramBotAPI.git[push=]https://github.com/insanusmokrassar/TelegramBotAPI.git"
url = "https://github.com/insanusmokrassar/TelegramBotAPI.git"
}
developers {
developer {
id = "InsanusMokrassar"
name = "Ovsiannikov Aleksei"
email = "ovsyannikov.alexey95@gmail.com"
}
}
licenses {
license {
name = "Apache Software License 2.0"
url = "https://github.com/InsanusMokrassar/TelegramBotAPI/blob/master/LICENSE"
}
}
}
}
}

View File

@@ -1,59 +1,65 @@
apply plugin: 'com.jfrog.bintray'
apply plugin: 'maven-publish'
apply from: "maven.publish.gradle"
bintray {
user = project.hasProperty('BINTRAY_USER') ? project.property('BINTRAY_USER') : System.getenv('BINTRAY_USER')
key = project.hasProperty('BINTRAY_KEY') ? project.property('BINTRAY_KEY') : System.getenv('BINTRAY_KEY')
filesSpec {
from "${buildDir}/publications/"
eachFile {
String directorySubname = it.getFile().parentFile.name
if (it.getName() == "module.json") {
if (directorySubname == "kotlinMultiplatform") {
it.setPath("${project.name}/${project.version}/${project.name}-${project.version}.module")
} else {
it.setPath("${project.name}-${directorySubname}/${project.version}/${project.name}-${directorySubname}-${project.version}.module")
}
} else {
if (directorySubname == "kotlinMultiplatform" && it.getName() == "pom-default.xml") {
it.setPath("${project.name}/${project.version}/${project.name}-${project.version}.pom")
} else {
it.exclude()
}
}
}
into "${project.group}".replace(".", "/")
}
publish = true
override = true
pkg {
repo = "TelegramBotAPI"
name = "${project.name}"
vcsUrl = "https://github.com/InsanusMokrassar/TelegramBotAPI"
licenses = ["Apache-2.0"]
version {
name = "${project.version}"
released = new Date()
vcsTag = "${project.version}"
gpg {
sign = true
passphrase = project.hasProperty('signing.gnupg.passphrase') ? project.property('signing.gnupg.passphrase') : System.getenv('signing.gnupg.passphrase')
}
}
}
task javadocsJar(type: Jar) {
classifier = 'javadoc'
}
bintrayUpload.doFirst {
publications = publishing.publications.collect {
afterEvaluate {
project.publishing.publications.all {
// rename artifacts
groupId "${project.group}"
if (it.name.contains('kotlinMultiplatform')) {
null
artifactId = "${project.name}"
} else {
it.name
artifactId = "${project.name}-$name"
}
} - null
}
}
bintrayUpload.dependsOn publishToMavenLocal
publishing {
publications.all {
artifact javadocsJar
pom {
description = "Library for Object-Oriented and type-safe work with Telegram Bot API"
name = "Telegram Bot API Core"
url = "https://insanusmokrassar.github.io/TelegramBotAPI"
scm {
developerConnection = "scm:git:[fetch=]https://github.com/insanusmokrassar/TelegramBotAPI.git[push=]https://github.com/insanusmokrassar/TelegramBotAPI.git"
url = "https://github.com/insanusmokrassar/TelegramBotAPI.git"
}
developers {
developer {
id = "InsanusMokrassar"
name = "Ovsiannikov Aleksei"
email = "ovsyannikov.alexey95@gmail.com"
}
}
licenses {
license {
name = "Apache Software License 2.0"
url = "https://github.com/InsanusMokrassar/TelegramBotAPI/blob/master/LICENSE"
}
}
}
repositories {
maven {
name = "bintray"
url = uri("https://api.bintray.com/maven/${project.hasProperty('BINTRAY_USER') ? project.property('BINTRAY_USER') : System.getenv('BINTRAY_USER')}/TelegramBotAPI/${project.name}/;publish=1;override=1")
credentials {
username = project.hasProperty('BINTRAY_USER') ? project.property('BINTRAY_USER') : System.getenv('BINTRAY_USER')
password = project.hasProperty('BINTRAY_KEY') ? project.property('BINTRAY_KEY') : System.getenv('BINTRAY_KEY')
}
}
}
}
}

View File

@@ -14,13 +14,23 @@ typealias FullTextSourcesList = List<TextSource>
typealias FullTextPartsList = List<TextPart>
interface TextSource {
val asMarkdownSource: String
val asMarkdownV2Source: String
val asHtmlSource: String
val markdown: String
val markdownV2: String
val html: String
val source: String
val asText: String
get() = source
@Deprecated("Rename", ReplaceWith("markdown"))
val asMarkdownSource: String
get() = markdown
@Deprecated("Rename", ReplaceWith("markdownV2"))
val asMarkdownV2Source: String
get() = markdownV2
@Deprecated("Rename", ReplaceWith("html"))
val asHtmlSource: String
get() = html
}
@Suppress("NOTHING_TO_INLINE")
@@ -36,7 +46,10 @@ interface MultilevelTextSource : TextSource {
@Deprecated("Will be removed in near major release")
val textParts: List<TextPart>
get() = textParts(0)
val subsources: List<TextSource>
@Deprecated("Will be removed in near major release", ReplaceWith("subsources"))
val textSources: List<TextSource>
get() = subsources
}
data class TextPart(
@@ -46,7 +59,7 @@ data class TextPart(
fun List<TextPart>.justTextSources() = map { it.source }
fun List<TextSource>.makeString() = joinToString("") { it.source }
internal fun MultilevelTextSource.textParts(offset: Int): List<TextPart> = textSources.toTextParts(offset)
internal fun MultilevelTextSource.textParts(offset: Int): List<TextPart> = subsources.toTextParts(offset)
fun List<TextSource>.separateForMessage(limit: IntRange, numberOfParts: Int? = null): List<List<TextSource>> {
if (isEmpty()) {
return emptyList()

View File

@@ -3,9 +3,9 @@ package dev.inmo.tgbotapi.bot.Ktor
import dev.inmo.micro_utils.coroutines.safely
import dev.inmo.tgbotapi.bot.BaseRequestsExecutor
import dev.inmo.tgbotapi.bot.Ktor.base.*
import dev.inmo.tgbotapi.bot.TelegramBot
import dev.inmo.tgbotapi.bot.exceptions.newRequestException
import dev.inmo.tgbotapi.bot.settings.limiters.EmptyLimiter
import dev.inmo.tgbotapi.bot.settings.limiters.RequestLimiter
import dev.inmo.tgbotapi.bot.settings.limiters.*
import dev.inmo.tgbotapi.requests.abstracts.Request
import dev.inmo.tgbotapi.types.Response
import dev.inmo.tgbotapi.utils.*
@@ -14,12 +14,39 @@ import io.ktor.client.features.*
import io.ktor.client.statement.readText
import kotlinx.serialization.json.Json
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,
crossinline builder: KtorRequestsExecutorBuilder.() -> Unit = {}
): TelegramBot = KtorRequestsExecutorBuilder(telegramAPIUrlsKeeper).apply(builder).build()
/**
* Shortcut for [telegramBot]
*/
@Suppress("NOTHING_TO_INLINE")
inline fun telegramBot(
token: String,
apiUrl: String = telegramBotAPIDefaultUrl,
crossinline builder: KtorRequestsExecutorBuilder.() -> Unit = {}
): TelegramBot = telegramBot(TelegramAPIUrlsKeeper(token, apiUrl), builder)
class KtorRequestsExecutor(
telegramAPIUrlsKeeper: TelegramAPIUrlsKeeper,
client: HttpClient = HttpClient(),
callsFactories: List<KtorCallFactory> = emptyList(),
excludeDefaultFactories: Boolean = false,
private val requestsLimiter: RequestLimiter = EmptyLimiter,
private val requestsLimiter: RequestLimiter = ExceptionsOnlyLimiter(),
private val jsonFormatter: Json = nonstrictJsonFormat
) : BaseRequestsExecutor(telegramAPIUrlsKeeper) {
private val callsFactories: List<KtorCallFactory> = callsFactories.run {

View File

@@ -1,5 +1,6 @@
package dev.inmo.tgbotapi.bot.Ktor.base
import dev.inmo.micro_utils.coroutines.safely
import dev.inmo.tgbotapi.bot.Ktor.KtorCallFactory
import dev.inmo.tgbotapi.bot.exceptions.newRequestException
import dev.inmo.tgbotapi.requests.GetUpdates
@@ -51,23 +52,17 @@ abstract class AbstractRequestCallFactory : KtorCallFactory {
val content = response.receive<String>()
val responseObject = jsonFormatter.decodeFromString(Response.serializer(), content)
return (responseObject.result?.let {
jsonFormatter.decodeFromJsonElement(request.resultDeserializer, it)
} ?: responseObject.parameters?.let {
val error = it.error
if (error is RetryAfterError) {
delay(error.leftToRetry)
makeCall(client, urlsKeeper, request, jsonFormatter)
} else {
null
}
} ?: response.let {
throw newRequestException(
responseObject,
content,
"Can't get result object from $content"
)
})
return safely {
(responseObject.result?.let {
jsonFormatter.decodeFromJsonElement(request.resultDeserializer, it)
} ?: response.let {
throw newRequestException(
responseObject,
content,
"Can't get result object from $content"
)
})
}
}
}

View File

@@ -1,6 +1,7 @@
package dev.inmo.tgbotapi.bot.exceptions
import dev.inmo.tgbotapi.types.Response
import com.soywiz.klock.DateTime
import dev.inmo.tgbotapi.types.*
import io.ktor.utils.io.errors.IOException
fun newRequestException(
@@ -16,6 +17,13 @@ fun newRequestException(
description == "Unauthorized" -> UnauthorizedException(response, plainAnswer, message, cause)
description.contains("PHOTO_INVALID_DIMENSIONS") -> InvalidPhotoDimensionsException(response, plainAnswer, message, cause)
description.contains("wrong file identifier") -> WrongFileIdentifierException(response, plainAnswer, message, cause)
description.contains("Too Many Requests") -> TooMuchRequestsException(
(response.parameters ?.error as? RetryAfterError) ?: RetryAfterError(60, DateTime.now().unixMillisLong),
response,
plainAnswer,
message,
cause
)
else -> null
}
} ?: CommonRequestException(response, plainAnswer, message, cause)
@@ -49,3 +57,6 @@ class InvalidPhotoDimensionsException(response: Response, plainAnswer: String, m
class WrongFileIdentifierException(response: Response, plainAnswer: String, message: String?, cause: Throwable?) :
RequestException(response, plainAnswer, message, cause)
class TooMuchRequestsException(val retryAfter: RetryAfterError, response: Response, plainAnswer: String, message: String?, cause: Throwable?) :
RequestException(response, plainAnswer, message, cause)

View File

@@ -1,67 +1,43 @@
package dev.inmo.tgbotapi.bot.settings.limiters
import com.soywiz.klock.DateTime
import dev.inmo.micro_utils.coroutines.*
import dev.inmo.tgbotapi.types.MilliSeconds
import kotlinx.coroutines.*
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.sync.Semaphore
import kotlinx.serialization.Serializable
import kotlinx.serialization.Transient
import kotlin.coroutines.Continuation
import kotlin.math.roundToLong
private fun now(): Long = DateTime.nowUnixLong()
@Serializable
class CommonLimiter(
private val lockCount: Int = 10,
private val regenTime: Long = 20 * 1000L // 20 seconds for full regen of opportunity to send message
private val regenTime: MilliSeconds = 15 * 1000, // 15 seconds for full regen of opportunity to send message
@Transient
private val scope: CoroutineScope = CoroutineScope(Dispatchers.Default)
) : RequestLimiter {
private var doLimit: Boolean = false
private val counterChannel = Channel<Unit>(Channel.UNLIMITED)
private val scope = CoroutineScope(Dispatchers.Default)
private val counterJob = scope.launch {
var wasLastSecond = 0
var lastCountTime = now()
var limitManagementJob: Job? = null
var removeLimitTime: Long = lastCountTime
for (counter in counterChannel) {
val now = now()
if (now - lastCountTime > 1000) {
lastCountTime = now
wasLastSecond = 1
} else {
wasLastSecond++
}
if (wasLastSecond >= lockCount) {
removeLimitTime = now + regenTime
if (limitManagementJob == null) {
limitManagementJob = launch {
doLimit = true
var internalNow = now()
while (internalNow < removeLimitTime) {
delay(removeLimitTime - internalNow)
internalNow = now()
}
doLimit = false
}
private val quotaSemaphore = Semaphore(lockCount)
private val counterRegeneratorJob = scope.launch {
val regenDelay: MilliSeconds = (regenTime.toDouble() / lockCount).roundToLong()
while (isActive) {
delay(regenDelay)
if (quotaSemaphore.availablePermits < lockCount) {
try {
quotaSemaphore.release()
} catch (_: IllegalStateException) {
// Skip IllegalStateException due to the fact that this exception may happens in release method
}
}
if (now > removeLimitTime) {
limitManagementJob = null
}
}
}
private val quoterChannel = Channel<Unit>(Channel.CONFLATED)
private val tickerJob = scope.launch {
while (isActive) {
quoterChannel.send(Unit)
delay(1000L)
}
}
override suspend fun <T> limit(block: suspend () -> T): T {
counterChannel.send(Unit)
return if (!doLimit) {
block()
} else {
quoterChannel.receive()
block()
}
quotaSemaphore.acquire()
return block()
}
}

View File

@@ -1,5 +0,0 @@
package dev.inmo.tgbotapi.bot.settings.limiters
object EmptyLimiter : RequestLimiter {
override suspend fun <T> limit(block: suspend () -> T): T = block()
}

View File

@@ -0,0 +1,65 @@
package dev.inmo.tgbotapi.bot.settings.limiters
import dev.inmo.micro_utils.coroutines.safely
import dev.inmo.tgbotapi.bot.exceptions.TooMuchRequestsException
import dev.inmo.tgbotapi.types.*
import io.ktor.client.features.ClientRequestException
import io.ktor.http.HttpStatusCode
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.*
/**
* This limiter will limit requests only after getting a [RetryAfterError] or [ClientRequestException] with
* [HttpStatusCode.TooManyRequests] status code. Important thing is that in case if some of block has been blocked, all
* the others will wait until it will be possible to be called
*
* @param defaultTooManyRequestsDelay This parameter will be used in case of getting [ClientRequestException] with
* [HttpStatusCode.TooManyRequests] as a parameter for delay like it would be [TooMuchRequestsException]. The reason of
* it is that in [ClientRequestException] there is no information about required delay between requests
*/
class ExceptionsOnlyLimiter(
private val defaultTooManyRequestsDelay: MilliSeconds = 1000L
) : RequestLimiter {
private val lockState = MutableStateFlow(false)
private suspend fun lock(timeMillis: MilliSeconds) {
try {
safely {
lockState.emit(true)
delay(timeMillis)
}
} finally {
lockState.emit(false)
}
}
override suspend fun <T> limit(block: suspend () -> T): T {
while (true) {
lockState.first { !it }
val result = safely({
when (it) {
is TooMuchRequestsException -> {
lock(it.retryAfter.leftToRetry)
Result.failure(it)
}
is ClientRequestException -> {
if (it.response.status == HttpStatusCode.TooManyRequests) {
lock(defaultTooManyRequestsDelay)
} else {
throw it
}
Result.failure(it)
}
else -> throw it
}
}) {
Result.success(block())
}
if (result.isSuccess) {
return result.getOrNull()!!
}
}
}
}
@Deprecated("Renamed", ReplaceWith("ExceptionsOnlyLimiter", "dev.inmo.tgbotapi.bot.settings.limiters.ExceptionsOnlyLimiter"))
typealias EmptyLimiter = ExceptionsOnlyLimiter

View File

@@ -1,5 +1,7 @@
package dev.inmo.tgbotapi.bot.settings.limiters
import dev.inmo.micro_utils.coroutines.*
import dev.inmo.tgbotapi.types.MilliSeconds
import kotlinx.coroutines.*
import kotlinx.coroutines.channels.Channel
import kotlinx.serialization.Serializable
@@ -9,62 +11,60 @@ import kotlin.math.pow
private sealed class RequestEvent
private class AddRequest(
val continuation: Continuation<Long>
val continuation: Continuation<MilliSeconds>
) : RequestEvent()
private object CompleteRequest : RequestEvent()
@Serializable
data class PowLimiter(
private val minAwaitTime: Long = 0L,
private val maxAwaitTime: Long = 10000L,
private val minAwaitTime: MilliSeconds = 0L,
private val maxAwaitTime: MilliSeconds = 10000L,
private val powValue: Double = 4.0,
private val powK: Double = 0.0016
private val powK: Double = 1.6,
@Transient
private val scope: CoroutineScope = CoroutineScope(Dispatchers.Default)
) : RequestLimiter {
@Transient
private val scope = CoroutineScope(Dispatchers.Default)
@Transient
private val eventsChannel = Channel<RequestEvent>(Channel.UNLIMITED)
@Transient
private val awaitTimeRange = minAwaitTime .. maxAwaitTime
@Transient
private val eventsChannel = let {
var requestsInWork = 0.0
scope.actor<RequestEvent> {
when (it) {
is AddRequest -> {
val awaitTime = (requestsInWork.pow(powValue) * powK).toLong()
requestsInWork++
init {
scope.launch {
var requestsInWork: Double = 0.0
for (event in eventsChannel) {
when (event) {
is AddRequest -> {
val awaitTime = (((requestsInWork.pow(powValue) * powK) * 1000L).toLong())
requestsInWork++
event.continuation.resume(
if (awaitTime in awaitTimeRange) {
awaitTime
} else {
if (awaitTime < minAwaitTime) {
minAwaitTime
} else {
maxAwaitTime
}
}
)
}
is CompleteRequest -> requestsInWork--
it.continuation.resume(
when {
awaitTime in awaitTimeRange -> awaitTime
awaitTime < awaitTimeRange.first -> awaitTimeRange.first
else -> awaitTimeRange.last
}
)
}
is CompleteRequest -> requestsInWork--
}
}
}
override suspend fun <T> limit(
block: suspend () -> T
private suspend inline fun <T> withDelay(
crossinline block: suspend () -> T
): T {
val delayMillis = suspendCoroutine<Long> {
scope.launch { eventsChannel.send(AddRequest(it)) }
}
delay(delayMillis)
return try {
block()
safely { block() }
} finally {
eventsChannel.send(CompleteRequest)
}
}
override suspend fun <T> limit(
block: suspend () -> T
): T {
return withDelay(block)
}
}

View File

@@ -4,13 +4,13 @@ import dev.inmo.tgbotapi.CommonAbstracts.types.ChatRequest
import dev.inmo.tgbotapi.requests.abstracts.SimpleRequest
import dev.inmo.tgbotapi.types.ChatIdentifier
import dev.inmo.tgbotapi.types.ChatMember.abstracts.AdministratorChatMember
import dev.inmo.tgbotapi.types.ChatMember.abstracts.AdministratorChatMemberSerializerWithoutDeserialization
import dev.inmo.tgbotapi.types.ChatMember.abstracts.AdministratorChatMemberSerializer
import dev.inmo.tgbotapi.types.chatIdField
import kotlinx.serialization.*
import kotlinx.serialization.builtins.ListSerializer
private val chatMembersListSerializer = ListSerializer(
AdministratorChatMemberSerializerWithoutDeserialization
AdministratorChatMemberSerializer
)
@Serializable

View File

@@ -3,7 +3,7 @@ package dev.inmo.tgbotapi.requests.chat.members
import dev.inmo.tgbotapi.requests.chat.abstracts.ChatMemberRequest
import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.ChatMember.abstracts.ChatMember
import dev.inmo.tgbotapi.types.ChatMember.abstracts.ChatMemberDeserializationStrategy
import dev.inmo.tgbotapi.types.ChatMember.abstracts.ChatMemberSerializer
import kotlinx.serialization.*
@Serializable
@@ -15,7 +15,7 @@ data class GetChatMember(
) : ChatMemberRequest<ChatMember> {
override fun method(): String = "getChatMember"
override val resultDeserializer: DeserializationStrategy<ChatMember>
get() = ChatMemberDeserializationStrategy
get() = ChatMemberSerializer
override val requestSerializer: SerializationStrategy<*>
get() = serializer()
}

View File

@@ -1,19 +1,37 @@
package dev.inmo.tgbotapi.types.ChatMember
import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.ChatMember.abstracts.AdministratorChatMember
import dev.inmo.tgbotapi.types.User
import kotlinx.serialization.*
@Serializable
data class AdministratorChatMemberImpl(
@SerialName(userField)
override val user: User,
override val canBeEdited: Boolean,
override val canChangeInfo: Boolean,
override val canPostMessages: Boolean,
override val canEditMessages: Boolean,
override val canRemoveMessages: Boolean,
override val canInviteUsers: Boolean,
override val canRestrictMembers: Boolean,
override val canPinMessages: Boolean,
override val canPromoteMembers: Boolean,
override val isAnonymous: Boolean,
override val customTitle: String?
) : AdministratorChatMember
@SerialName(canBeEditedField)
override val canBeEdited: Boolean = false,
@SerialName(canChangeInfoField)
override val canChangeInfo: Boolean = false,
@SerialName(canPostMessagesField)
override val canPostMessages: Boolean = false,
@SerialName(canEditMessagesField)
override val canEditMessages: Boolean = false,
@SerialName(canDeleteMessagesField)
override val canRemoveMessages: Boolean = false,
@SerialName(canInviteUsersField)
override val canInviteUsers: Boolean = false,
@SerialName(canRestrictMembersField)
override val canRestrictMembers: Boolean = false,
@SerialName(canPinMessagesField)
override val canPinMessages: Boolean = false,
@SerialName(canPromoteMembersField)
override val canPromoteMembers: Boolean = false,
@SerialName(isAnonymousField)
override val isAnonymous: Boolean = false,
@SerialName(customTitleField)
override val customTitle: String? = null
) : AdministratorChatMember {
@SerialName(statusField)
@Required
private val type: String = "administrator"
}

View File

@@ -1,20 +1,36 @@
package dev.inmo.tgbotapi.types.ChatMember
import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.ChatMember.abstracts.AdministratorChatMember
import dev.inmo.tgbotapi.types.User
import kotlinx.serialization.*
@Serializable
data class CreatorChatMember(
override val user: User,
override val isAnonymous: Boolean,
override val customTitle: String?
@SerialName(isAnonymousField)
override val isAnonymous: Boolean = false,
@SerialName(customTitleField)
override val customTitle: String? = null
) : AdministratorChatMember {
@Transient
override val canBeEdited: Boolean = true
@Transient
override val canChangeInfo: Boolean = true
@Transient
override val canPostMessages: Boolean = true
@Transient
override val canEditMessages: Boolean = true
@Transient
override val canRemoveMessages: Boolean = true
@Transient
override val canInviteUsers: Boolean = true
@Transient
override val canRestrictMembers: Boolean = true
@Transient
override val canPinMessages: Boolean = true
@Transient
override val canPromoteMembers: Boolean = true
@SerialName(statusField)
@Required
private val type: String = "creator"
}

View File

@@ -1,10 +1,17 @@
package dev.inmo.tgbotapi.types.ChatMember
import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.ChatMember.abstracts.BannedChatMember
import dev.inmo.tgbotapi.types.TelegramDate
import dev.inmo.tgbotapi.types.User
import kotlinx.serialization.*
@Serializable
data class KickedChatMember(
@SerialName(userField)
override val user: User,
override val untilDate: TelegramDate?
) : BannedChatMember
@SerialName(untilDateField)
override val untilDate: TelegramDate? = null
) : BannedChatMember {
@SerialName(statusField)
@Required
private val type: String = "kicked"
}

View File

@@ -1,7 +1,12 @@
package dev.inmo.tgbotapi.types.ChatMember
import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.ChatMember.abstracts.ChatMember
import dev.inmo.tgbotapi.types.User
import kotlinx.serialization.*
data class LeftChatMember(override val user: User) :
ChatMember
@Serializable
data class LeftChatMember(@SerialName(userField) override val user: User) : ChatMember {
@SerialName(statusField)
@Required
private val type: String = "left"
}

View File

@@ -1,7 +1,12 @@
package dev.inmo.tgbotapi.types.ChatMember
import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.ChatMember.abstracts.ChatMember
import dev.inmo.tgbotapi.types.User
import kotlinx.serialization.*
data class MemberChatMember(override val user: User) :
ChatMember
@Serializable
data class MemberChatMember(@SerialName(userField) override val user: User) : ChatMember {
@SerialName(statusField)
@Required
private val type: String = "member"
}

View File

@@ -1,87 +0,0 @@
package dev.inmo.tgbotapi.types.ChatMember
import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.ChatMember.abstracts.ChatMember
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
@Serializable
internal data class RawChatMember(
val user: User,
private val status: String,
private val until_date: TelegramDate? = null,
@SerialName(canBeEditedField)
private val canBeEdited: Boolean = false,
@SerialName(canChangeInfoField)
private val canChangeInfo: Boolean = false,
@SerialName(canPostMessagesField)
private val canPostMessages: Boolean = false,
@SerialName(canEditMessagesField)
private val canEditMessages: Boolean = false,
@SerialName(canDeleteMessagesField)
private val canDeleteMessages: Boolean = false,
@SerialName(canInviteUsersField)
private val canInviteUsers: Boolean = false,
@SerialName(canRestrictMembersField)
private val canRestrictMembers: Boolean = false,
@SerialName(canPinMessagesField)
private val canPinMessages: Boolean = false,
@SerialName(canPromoteMembersField)
private val canPromoteMembers: Boolean = false,
@SerialName(isMemberField)
private val isMember: Boolean = false,
@SerialName(canSendMessagesField)
private val canSendMessages: Boolean = false,
@SerialName(canSendMediaMessagesField)
private val canSendMediaMessages: Boolean = false,
@SerialName(canSendPollsField)
private val canSendPolls: Boolean = false,
@SerialName(canSendOtherMessagesField)
private val canSendOtherMessages: Boolean = false,
@SerialName(canAddWebPagePreviewsField)
private val canAddWebPagePreviews: Boolean = false,
@SerialName(isAnonymousField)
private val isAnonymous: Boolean = false,
@SerialName(customTitleField)
private val customTitle: String? = null
) {
val asChatMember: ChatMember by lazy {
when (status) {
"creator" -> CreatorChatMember(user, isAnonymous, customTitle)
"administrator" -> AdministratorChatMemberImpl(
user,
canBeEdited,
canChangeInfo,
canPostMessages,
canEditMessages,
canDeleteMessages,
canInviteUsers,
canRestrictMembers,
canPinMessages,
canPromoteMembers,
isAnonymous,
customTitle
)
"member" -> MemberChatMember(user)
"restricted" -> RestrictedChatMember(
user,
until_date,
isMember,
canSendMessages,
canSendMediaMessages,
canSendPolls,
canSendOtherMessages,
canAddWebPagePreviews,
canChangeInfo,
canInviteUsers,
canPinMessages
)
"left" -> LeftChatMember(user)
"kicked" -> KickedChatMember(
user,
until_date
)
else -> throw IllegalStateException("Can't understand type of user: $status")
}
}
}

View File

@@ -1,20 +1,36 @@
package dev.inmo.tgbotapi.types.ChatMember
import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.ChatMember.abstracts.BannedChatMember
import dev.inmo.tgbotapi.types.ChatMember.abstracts.SpecialRightsChatMember
import dev.inmo.tgbotapi.types.TelegramDate
import dev.inmo.tgbotapi.types.User
import kotlinx.serialization.*
@Serializable
data class RestrictedChatMember(
@SerialName(userField)
override val user: User,
override val untilDate: TelegramDate?,
val isMember: Boolean,
val canSendMessages: Boolean,
val canSendMediaMessages: Boolean,
val canSendPolls: Boolean,
val canSendOtherMessages: Boolean,
val canAddWebpagePreviews: Boolean,
override val canChangeInfo: Boolean,
override val canInviteUsers: Boolean,
override val canPinMessages: Boolean
) : BannedChatMember, SpecialRightsChatMember
@SerialName(untilDateField)
override val untilDate: TelegramDate? = null,
@SerialName(isMemberField)
val isMember: Boolean = false,
@SerialName(canSendMessagesField)
val canSendMessages: Boolean = false,
@SerialName(canSendMediaMessagesField)
val canSendMediaMessages: Boolean = false,
@SerialName(canSendPollsField)
val canSendPolls: Boolean = false,
@SerialName(canSendOtherMessagesField)
val canSendOtherMessages: Boolean = false,
@SerialName(canAddWebPagePreviewsField)
val canAddWebpagePreviews: Boolean = false,
@SerialName(canChangeInfoField)
override val canChangeInfo: Boolean = false,
@SerialName(canInviteUsersField)
override val canInviteUsers: Boolean = false,
@SerialName(canPinMessagesField)
override val canPinMessages: Boolean = false
) : BannedChatMember, SpecialRightsChatMember {
@SerialName(statusField)
@Required
private val type: String = "restricted"
}

View File

@@ -1,5 +1,11 @@
package dev.inmo.tgbotapi.types.ChatMember.abstracts
import kotlinx.serialization.*
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
@Serializable(AdministratorChatMemberSerializer::class)
interface AdministratorChatMember : SpecialRightsChatMember {
val canBeEdited: Boolean
val canPostMessages: Boolean
@@ -9,4 +15,12 @@ interface AdministratorChatMember : SpecialRightsChatMember {
val canPromoteMembers: Boolean
val isAnonymous: Boolean
val customTitle: String?
}
}
@Serializer(AdministratorChatMember::class)
internal object AdministratorChatMemberSerializer : KSerializer<AdministratorChatMember> {
override val descriptor: SerialDescriptor = ChatMemberSerializer.descriptor
override fun deserialize(decoder: Decoder): AdministratorChatMember = ChatMemberSerializer.deserialize(decoder) as AdministratorChatMember
override fun serialize(encoder: Encoder, value: AdministratorChatMember) = ChatMemberSerializer.serialize(encoder, value)
}

View File

@@ -1,5 +1,7 @@
package dev.inmo.tgbotapi.types.ChatMember.abstracts
import dev.inmo.tgbotapi.CommonAbstracts.types.UntilDate
import kotlinx.serialization.Serializable
@Serializable(ChatMemberSerializer::class)
interface BannedChatMember : ChatMember, UntilDate

View File

@@ -1,27 +1,46 @@
package dev.inmo.tgbotapi.types.ChatMember.abstracts
import dev.inmo.tgbotapi.types.ChatMember.RawChatMember
import dev.inmo.tgbotapi.types.ChatMember.*
import dev.inmo.tgbotapi.types.User
import kotlinx.serialization.DeserializationStrategy
import kotlinx.serialization.KSerializer
import dev.inmo.tgbotapi.types.statusField
import dev.inmo.tgbotapi.utils.nonstrictJsonFormat
import kotlinx.serialization.*
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.jsonPrimitive
@Serializable(ChatMemberSerializer::class)
interface ChatMember {
val user: User
}
internal object AdministratorChatMemberSerializerWithoutDeserialization : KSerializer<AdministratorChatMember> {
override val descriptor: SerialDescriptor = ChatMemberDeserializationStrategy.descriptor
@Serializer(ChatMember::class)
internal object ChatMemberSerializer : KSerializer<ChatMember> {
override val descriptor: SerialDescriptor = JsonObject.serializer().descriptor
override fun deserialize(decoder: Decoder): AdministratorChatMember
= ChatMemberDeserializationStrategy.deserialize(decoder) as AdministratorChatMember
override fun serialize(encoder: Encoder, value: AdministratorChatMember) = throw UnsupportedOperationException()
}
internal object ChatMemberDeserializationStrategy : DeserializationStrategy<ChatMember> {
override val descriptor: SerialDescriptor = RawChatMember.serializer().descriptor
override fun deserialize(decoder: Decoder): ChatMember = RawChatMember.serializer().deserialize(decoder).asChatMember
override fun deserialize(decoder: Decoder): ChatMember {
val json = JsonObject.serializer().deserialize(decoder)
return when (json[statusField] ?.jsonPrimitive ?.content ?: error("Status field of chat member must be specified, but incoming json contains next: $json")) {
"creator" -> nonstrictJsonFormat.decodeFromJsonElement(CreatorChatMember.serializer(), json)
"administrator" -> nonstrictJsonFormat.decodeFromJsonElement(AdministratorChatMemberImpl.serializer(), json)
"member" -> nonstrictJsonFormat.decodeFromJsonElement(MemberChatMember.serializer(), json)
"restricted" -> nonstrictJsonFormat.decodeFromJsonElement(RestrictedChatMember.serializer(), json)
"left" -> nonstrictJsonFormat.decodeFromJsonElement(LeftChatMember.serializer(), json)
"kicked" -> nonstrictJsonFormat.decodeFromJsonElement(KickedChatMember.serializer(), json)
else -> error("Unknown type of chat member in json: $json")
}
}
override fun serialize(encoder: Encoder, value: ChatMember) {
when (value) {
is CreatorChatMember -> CreatorChatMember.serializer()
is AdministratorChatMemberImpl -> AdministratorChatMemberImpl.serializer()
is MemberChatMember -> MemberChatMember.serializer()
is RestrictedChatMember -> RestrictedChatMember.serializer()
is LeftChatMember -> LeftChatMember.serializer()
is KickedChatMember -> KickedChatMember.serializer()
}
}
}

View File

@@ -1,5 +1,8 @@
package dev.inmo.tgbotapi.types.ChatMember.abstracts
import kotlinx.serialization.Serializable
@Serializable(ChatMemberSerializer::class)
interface SpecialRightsChatMember : ChatMember {
val canChangeInfo: Boolean
val canInviteUsers: Boolean

View File

@@ -28,6 +28,7 @@ typealias GooglePlaceId = String
typealias GooglePlaceType = String
typealias Seconds = Int
typealias MilliSeconds = Long
typealias LongSeconds = Long
typealias Meters = Float
@@ -60,10 +61,13 @@ val inlineQueryAnswerResultsLimit = 0 .. 50
val customTitleLength = 0 .. 16
val dartsAndCubeDiceResultLimit = 1 .. 6
@Deprecated("Renamed", ReplaceWith("dartsAndCubeDiceResultLimit", "dev.inmo.tgbotapi.types.dartsAndCubeDiceResultLimit"))
val dartsCubeAndBowlingDiceResultLimit = 1 .. 6
@Deprecated("Renamed", ReplaceWith("dartsCubeAndBowlingDiceResultLimit", "dev.inmo.tgbotapi.types.dartsCubeAndBowlingDiceResultLimit"))
val dartsAndCubeDiceResultLimit
get() = dartsCubeAndBowlingDiceResultLimit
@Deprecated("Renamed", ReplaceWith("dartsCubeAndBowlingDiceResultLimit", "dev.inmo.tgbotapi.types.dartsCubeAndBowlingDiceResultLimit"))
val diceResultLimit
get() = dartsAndCubeDiceResultLimit
get() = dartsCubeAndBowlingDiceResultLimit
val basketballAndFootballDiceResultLimit = 1 .. 5
val slotMachineDiceResultLimit = 1 .. 64
@@ -231,6 +235,7 @@ const val canSendPollsField = "can_send_polls"
const val canAddWebPagePreviewsField = "can_add_web_page_previews"
const val canSetStickerSetField = "can_set_sticker_set"
const val statusField = "status"
const val canBeEditedField = "can_be_edited"
const val canChangeInfoField = "can_change_info"
const val canPostMessagesField = "can_post_messages"

View File

@@ -11,11 +11,11 @@ import dev.inmo.tgbotapi.utils.internal.boldMarkdownV2
*/
data class BoldTextSource @RiskFeature(DirectInvocationOfTextSourceConstructor) constructor (
override val source: String,
override val textSources: List<TextSource>
override val subsources: List<TextSource>
) : MultilevelTextSource {
override val asMarkdownSource: String by lazy { source.boldMarkdown() }
override val asMarkdownV2Source: String by lazy { boldMarkdownV2() }
override val asHtmlSource: String by lazy { boldHTML() }
override val markdown: String by lazy { source.boldMarkdown() }
override val markdownV2: String by lazy { boldMarkdownV2() }
override val html: String by lazy { boldHTML() }
}
@Suppress("NOTHING_TO_INLINE")

View File

@@ -18,9 +18,9 @@ data class BotCommandTextSource @RiskFeature(DirectInvocationOfTextSourceConstru
commandRegex.find(source) ?.value ?.substring(1) ?: source.substring(1)// skip first symbol like "/" or "!"
}
override val asMarkdownSource: String by lazy { source.commandMarkdown() }
override val asMarkdownV2Source: String by lazy { source.commandMarkdownV2() }
override val asHtmlSource: String by lazy { source.commandHTML() }
override val markdown: String by lazy { source.commandMarkdown() }
override val markdownV2: String by lazy { source.commandMarkdownV2() }
override val html: String by lazy { source.commandHTML() }
}
/**

View File

@@ -11,11 +11,11 @@ import dev.inmo.tgbotapi.utils.internal.cashTagMarkdownV2
*/
data class CashTagTextSource @RiskFeature(DirectInvocationOfTextSourceConstructor) constructor (
override val source: String,
override val textSources: List<TextSource>
override val subsources: List<TextSource>
) : MultilevelTextSource {
override val asMarkdownSource: String by lazy { source.cashTagMarkdown() }
override val asMarkdownV2Source: String by lazy { cashTagMarkdownV2() }
override val asHtmlSource: String by lazy { cashTagHTML() }
override val markdown: String by lazy { source.cashTagMarkdown() }
override val markdownV2: String by lazy { cashTagMarkdownV2() }
override val html: String by lazy { cashTagHTML() }
}
@Suppress("NOTHING_TO_INLINE")

View File

@@ -13,9 +13,9 @@ import dev.inmo.tgbotapi.utils.internal.codeMarkdownV2
data class CodeTextSource @RiskFeature(DirectInvocationOfTextSourceConstructor) constructor (
override val source: String
) : TextSource {
override val asMarkdownSource: String by lazy { source.codeMarkdown() }
override val asMarkdownV2Source: String by lazy { source.codeMarkdownV2() }
override val asHtmlSource: String by lazy { source.codeHTML() }
override val markdown: String by lazy { source.codeMarkdown() }
override val markdownV2: String by lazy { source.codeMarkdownV2() }
override val html: String by lazy { source.codeHTML() }
}
@Suppress("NOTHING_TO_INLINE")

View File

@@ -11,11 +11,11 @@ import dev.inmo.tgbotapi.utils.internal.emailMarkdownV2
*/
data class EMailTextSource @RiskFeature(DirectInvocationOfTextSourceConstructor) constructor (
override val source: String,
override val textSources: List<TextSource>
override val subsources: List<TextSource>
) : MultilevelTextSource {
override val asMarkdownSource: String by lazy { source.emailMarkdown() }
override val asMarkdownV2Source: String by lazy { emailMarkdownV2(source) }
override val asHtmlSource: String by lazy { emailHTML(source) }
override val markdown: String by lazy { source.emailMarkdown() }
override val markdownV2: String by lazy { emailMarkdownV2(source) }
override val html: String by lazy { emailHTML(source) }
}
@Suppress("NOTHING_TO_INLINE")

View File

@@ -11,11 +11,11 @@ import dev.inmo.tgbotapi.utils.internal.hashTagMarkdownV2
*/
data class HashTagTextSource @RiskFeature(DirectInvocationOfTextSourceConstructor) constructor (
override val source: String,
override val textSources: List<TextSource>
override val subsources: List<TextSource>
) : MultilevelTextSource {
override val asMarkdownSource: String by lazy { source.hashTagMarkdown() }
override val asMarkdownV2Source: String by lazy { hashTagMarkdownV2() }
override val asHtmlSource: String by lazy { hashTagHTML() }
override val markdown: String by lazy { source.hashTagMarkdown() }
override val markdownV2: String by lazy { hashTagMarkdownV2() }
override val html: String by lazy { hashTagHTML() }
init {
if (!source.startsWith("#")) {

View File

@@ -11,11 +11,11 @@ import dev.inmo.tgbotapi.utils.internal.italicMarkdownV2
*/
data class ItalicTextSource @RiskFeature(DirectInvocationOfTextSourceConstructor) constructor (
override val source: String,
override val textSources: List<TextSource>
override val subsources: List<TextSource>
) : MultilevelTextSource {
override val asMarkdownSource: String by lazy { source.italicMarkdown() }
override val asMarkdownV2Source: String by lazy { italicMarkdownV2() }
override val asHtmlSource: String by lazy { italicHTML() }
override val markdown: String by lazy { source.italicMarkdown() }
override val markdownV2: String by lazy { italicMarkdownV2() }
override val html: String by lazy { italicHTML() }
}
@Suppress("NOTHING_TO_INLINE")

View File

@@ -18,11 +18,11 @@ private val String.withoutCommercialAt
*/
data class MentionTextSource @RiskFeature(DirectInvocationOfTextSourceConstructor) constructor (
override val source: String,
override val textSources: List<TextSource>
override val subsources: List<TextSource>
) : MultilevelTextSource {
override val asMarkdownSource: String by lazy { source.mentionMarkdown() }
override val asMarkdownV2Source: String by lazy { mentionMarkdownV2() }
override val asHtmlSource: String by lazy { mentionHTML() }
override val markdown: String by lazy { source.mentionMarkdown() }
override val markdownV2: String by lazy { mentionMarkdownV2() }
override val html: String by lazy { mentionHTML() }
init {
if (!source.startsWith("@")) {

View File

@@ -11,11 +11,11 @@ import dev.inmo.tgbotapi.utils.internal.phoneMarkdownV2
*/
data class PhoneNumberTextSource @RiskFeature(DirectInvocationOfTextSourceConstructor) constructor (
override val source: String,
override val textSources: List<TextSource>
override val subsources: List<TextSource>
) : MultilevelTextSource {
override val asMarkdownSource: String by lazy { source.phoneMarkdown() }
override val asMarkdownV2Source: String by lazy { phoneMarkdownV2() }
override val asHtmlSource: String by lazy { phoneHTML() }
override val markdown: String by lazy { source.phoneMarkdown() }
override val markdownV2: String by lazy { phoneMarkdownV2() }
override val html: String by lazy { phoneHTML() }
}
@Suppress("NOTHING_TO_INLINE")

View File

@@ -13,9 +13,9 @@ data class PreTextSource @RiskFeature(DirectInvocationOfTextSourceConstructor) c
override val source: String,
val language: String? = null
) : TextSource {
override val asMarkdownSource: String by lazy { source.preMarkdown(language) }
override val asMarkdownV2Source: String by lazy { source.preMarkdownV2(language) }
override val asHtmlSource: String by lazy { source.preHTML(language) }
override val markdown: String by lazy { source.preMarkdown(language) }
override val markdownV2: String by lazy { source.preMarkdownV2(language) }
override val html: String by lazy { source.preHTML(language) }
}
@Suppress("NOTHING_TO_INLINE")

View File

@@ -12,9 +12,9 @@ import dev.inmo.tgbotapi.utils.internal.regularMarkdownV2
data class RegularTextSource @RiskFeature(DirectInvocationOfTextSourceConstructor) constructor (
override val source: String
) : TextSource {
override val asMarkdownSource: String by lazy { source.regularMarkdown() }
override val asMarkdownV2Source: String by lazy { source.regularMarkdownV2() }
override val asHtmlSource: String by lazy { source.regularHtml() }
override val markdown: String by lazy { source.regularMarkdown() }
override val markdownV2: String by lazy { source.regularMarkdownV2() }
override val html: String by lazy { source.regularHtml() }
}
@Suppress("NOTHING_TO_INLINE")

View File

@@ -11,11 +11,11 @@ import dev.inmo.tgbotapi.utils.internal.strikethroughMarkdownV2
*/
data class StrikethroughTextSource @RiskFeature(DirectInvocationOfTextSourceConstructor) constructor (
override val source: String,
override val textSources: List<TextSource>
override val subsources: List<TextSource>
) : MultilevelTextSource {
override val asHtmlSource: String by lazy { strikethroughHTML() }
override val asMarkdownV2Source: String by lazy { strikethroughMarkdownV2() }
override val asMarkdownSource: String by lazy { source.strikethroughMarkdown() }
override val html: String by lazy { strikethroughHTML() }
override val markdownV2: String by lazy { strikethroughMarkdownV2() }
override val markdown: String by lazy { source.strikethroughMarkdown() }
}
@Suppress("NOTHING_TO_INLINE")

View File

@@ -13,9 +13,9 @@ data class TextLinkTextSource @RiskFeature(DirectInvocationOfTextSourceConstruct
override val source: String,
val url: String
) : TextSource {
override val asMarkdownSource: String by lazy { source.linkMarkdown(url) }
override val asMarkdownV2Source: String by lazy { source.linkMarkdownV2(url) }
override val asHtmlSource: String by lazy { source.linkHTML(url) }
override val markdown: String by lazy { source.linkMarkdown(url) }
override val markdownV2: String by lazy { source.linkMarkdownV2(url) }
override val html: String by lazy { source.linkHTML(url) }
}
@Suppress("NOTHING_TO_INLINE")

View File

@@ -13,11 +13,11 @@ import dev.inmo.tgbotapi.utils.internal.textMentionMarkdownV2
data class TextMentionTextSource @RiskFeature(DirectInvocationOfTextSourceConstructor) constructor (
override val source: String,
val user: User,
override val textSources: List<TextSource>
override val subsources: List<TextSource>
) : MultilevelTextSource {
override val asMarkdownSource: String by lazy { source.textMentionMarkdown(user.id) }
override val asMarkdownV2Source: String by lazy { textMentionMarkdownV2(user.id) }
override val asHtmlSource: String by lazy { textMentionHTML(user.id) }
override val markdown: String by lazy { source.textMentionMarkdown(user.id) }
override val markdownV2: String by lazy { textMentionMarkdownV2(user.id) }
override val html: String by lazy { textMentionHTML(user.id) }
}
@Suppress("NOTHING_TO_INLINE")

View File

@@ -12,9 +12,9 @@ import dev.inmo.tgbotapi.utils.internal.linkMarkdownV2
data class URLTextSource @RiskFeature(DirectInvocationOfTextSourceConstructor) constructor (
override val source: String
) : TextSource {
override val asMarkdownSource: String by lazy { source.linkMarkdown(source) }
override val asMarkdownV2Source: String by lazy { source.linkMarkdownV2(source) }
override val asHtmlSource: String by lazy { source.linkHTML(source) }
override val markdown: String by lazy { source.linkMarkdown(source) }
override val markdownV2: String by lazy { source.linkMarkdownV2(source) }
override val html: String by lazy { source.linkHTML(source) }
}
@Suppress("NOTHING_TO_INLINE")

View File

@@ -11,11 +11,11 @@ import dev.inmo.tgbotapi.utils.internal.underlineMarkdownV2
*/
data class UnderlineTextSource @RiskFeature(DirectInvocationOfTextSourceConstructor) constructor (
override val source: String,
override val textSources: List<TextSource>
override val subsources: List<TextSource>
) : MultilevelTextSource {
override val asMarkdownSource: String by lazy { source.underlineMarkdown() }
override val asMarkdownV2Source: String by lazy { underlineMarkdownV2() }
override val asHtmlSource: String by lazy { underlineHTML() }
override val markdown: String by lazy { source.underlineMarkdown() }
override val markdownV2: String by lazy { underlineMarkdownV2() }
override val html: String by lazy { underlineHTML() }
}
@Suppress("NOTHING_TO_INLINE")

View File

@@ -5,7 +5,7 @@ import com.soywiz.klock.DateTime
sealed class RequestError
data class RetryAfterError(
val seconds: Long,
val seconds: Seconds,
val startCountingMillis: Long
) : RequestError() {
val canContinue = (seconds * 1000L) + startCountingMillis

View File

@@ -8,7 +8,7 @@ data class ResponseParametersRaw(
@SerialName("migrate_to_chat_id")
private val migrateToChatId: ChatId? = null,
@SerialName("retry_after")
private val retryAfter: Long? = null
private val retryAfter: Seconds? = null
) {
@Transient
private val createTime: Long = DateTime.now().unixMillisLong

View File

@@ -14,7 +14,7 @@ sealed class User : PrivateChat
@Serializable
data class CommonUser(
override val id: ChatId,
override val id: UserId,
@SerialName(firstNameField)
override val firstName: String,
@SerialName(lastNameField)
@@ -35,7 +35,7 @@ sealed class Bot : User() {
@Serializable
data class CommonBot(
override val id: ChatId,
override val id: UserId,
@SerialName(usernameField)
override val username: Username,
@SerialName(firstNameField)
@@ -49,7 +49,7 @@ data class CommonBot(
@Serializable
data class ExtendedBot(
override val id: ChatId,
override val id: UserId,
@SerialName(usernameField)
override val username: Username,
@SerialName(firstNameField)

View File

@@ -42,6 +42,9 @@ internal object BotActionSerializer: KSerializer<BotAction> {
object TypingAction : BotAction() {
override val actionName: String = "typing"
}
inline val typing
get() = TypingAction
inline fun BotAction.asTyping() = this as? TypingAction
/**
* Will notify user that bot is uploading some photo
@@ -50,6 +53,9 @@ object TypingAction : BotAction() {
object UploadPhotoAction : BotAction() {
override val actionName: String = "upload_photo"
}
inline val uploadPhoto
get() = UploadPhotoAction
inline fun BotAction.asUploadPhoto() = this as? UploadPhotoAction
/**
* Will notify user that bot is recording some video
@@ -58,6 +64,9 @@ object UploadPhotoAction : BotAction() {
object RecordVideoAction : BotAction() {
override val actionName: String = "record_video"
}
inline val recordVideo
get() = RecordVideoAction
inline fun BotAction.asRecordVideo() = this as? RecordVideoAction
/**
* Will notify user that bot is uploading some photo
@@ -66,6 +75,9 @@ object RecordVideoAction : BotAction() {
object UploadVideoAction : BotAction() {
override val actionName: String = "upload_video"
}
inline val uploadVideo
get() = UploadVideoAction
inline fun BotAction.asUploadVideo() = this as? UploadVideoAction
/**
* Will notify user that bot is recording some audio
@@ -74,6 +86,9 @@ object UploadVideoAction : BotAction() {
object RecordAudioAction : BotAction() {
override val actionName: String = "record_audio"
}
inline val recordAudio
get() = RecordAudioAction
inline fun BotAction.asRecordAudio() = this as? RecordAudioAction
/**
* Will notify user that bot is uploading some audio
@@ -82,6 +97,9 @@ object RecordAudioAction : BotAction() {
object UploadAudioAction : BotAction() {
override val actionName: String = "upload_audio"
}
inline val uploadAudio
get() = UploadAudioAction
inline fun BotAction.asUploadAudio() = this as? UploadAudioAction
/**
* Will notify user that bot is uploading some document
@@ -90,6 +108,9 @@ object UploadAudioAction : BotAction() {
object UploadDocumentAction : BotAction() {
override val actionName: String = "upload_document"
}
inline val uploadDocument
get() = UploadDocumentAction
inline fun BotAction.asUploadDocument() = this as? UploadDocumentAction
/**
* Will notify user that bot is trying to find location
@@ -98,6 +119,9 @@ object UploadDocumentAction : BotAction() {
object FindLocationAction : BotAction() {
override val actionName: String = "find_location"
}
inline val findLocation
get() = FindLocationAction
inline fun BotAction.asFindLocation() = this as? FindLocationAction
/**
* Will notify user that bot is recording video note
@@ -106,6 +130,9 @@ object FindLocationAction : BotAction() {
object RecordVideoNoteAction : BotAction() {
override val actionName: String = "record_video_note"
}
inline val recordVideoNote
get() = RecordVideoNoteAction
inline fun BotAction.asRecordVideoNote() = this as? RecordVideoNoteAction
/**
* Will notify user that bot is uploading video note
@@ -114,3 +141,6 @@ object RecordVideoNoteAction : BotAction() {
object UploadVideoNoteAction : BotAction() {
override val actionName: String = "upload_video_note"
}
inline val uploadVideoNote
get() = UploadVideoNoteAction
inline fun BotAction.asUploadVideoNote() = this as? UploadVideoNoteAction

View File

@@ -1,10 +1,13 @@
package dev.inmo.tgbotapi.types.chat.abstracts
import dev.inmo.tgbotapi.types.ChatId
import dev.inmo.tgbotapi.types.UserId
import dev.inmo.tgbotapi.types.chat.PreviewChatSerializer
import kotlinx.serialization.Serializable
@Serializable(PreviewChatSerializer::class)
interface PrivateChat : Chat, UsernameChat {
override val id: UserId
val firstName: String
val lastName: String
}

View File

@@ -15,13 +15,13 @@ sealed class DiceAnimationType {
object CubeDiceAnimationType : DiceAnimationType() {
override val emoji: String = "\uD83C\uDFB2"
override val valueLimits: IntRange
get() = dartsAndCubeDiceResultLimit
get() = dartsCubeAndBowlingDiceResultLimit
}
@Serializable(DiceAnimationTypeSerializer::class)
object DartsDiceAnimationType : DiceAnimationType() {
override val emoji: String = "\uD83C\uDFAF"
override val valueLimits: IntRange
get() = dartsAndCubeDiceResultLimit
get() = dartsCubeAndBowlingDiceResultLimit
}
@Serializable(DiceAnimationTypeSerializer::class)
object BasketballDiceAnimationType : DiceAnimationType() {
@@ -36,6 +36,12 @@ object FootballDiceAnimationType : DiceAnimationType() {
get() = basketballAndFootballDiceResultLimit
}
@Serializable(DiceAnimationTypeSerializer::class)
object BowlingDiceAnimationType : DiceAnimationType() {
override val emoji: String = "\uD83C\uDFB3"
override val valueLimits: IntRange
get() = dartsCubeAndBowlingDiceResultLimit
}
@Serializable(DiceAnimationTypeSerializer::class)
object SlotMachineDiceAnimationType : DiceAnimationType() {
override val emoji: String = "\uD83C\uDFB0"
override val valueLimits: IntRange
@@ -59,6 +65,7 @@ internal object DiceAnimationTypeSerializer : KSerializer<DiceAnimationType> {
BasketballDiceAnimationType.emoji -> BasketballDiceAnimationType
SlotMachineDiceAnimationType.emoji -> SlotMachineDiceAnimationType
FootballDiceAnimationType.emoji -> FootballDiceAnimationType
BowlingDiceAnimationType.emoji -> BowlingDiceAnimationType
else -> CustomDiceAnimationType(type)
}
}

View File

@@ -4,11 +4,12 @@ import com.soywiz.klock.DateTime
import dev.inmo.tgbotapi.types.MessageIdentifier
import dev.inmo.tgbotapi.types.chat.abstracts.ChannelChat
import dev.inmo.tgbotapi.types.message.ChatEvents.abstracts.ChannelEvent
import dev.inmo.tgbotapi.types.message.ChatEvents.abstracts.GroupEvent
import dev.inmo.tgbotapi.types.message.abstracts.ChatEventMessage
data class ChannelEventMessage(
data class ChannelEventMessage<T : ChannelEvent>(
override val messageId: MessageIdentifier,
override val chat: ChannelChat,
override val chatEvent: ChannelEvent,
override val chatEvent: T,
override val date: DateTime
) : ChatEventMessage
) : ChatEventMessage<T>

View File

@@ -1,3 +1,3 @@
package dev.inmo.tgbotapi.types.message.ChatEvents.abstracts
interface SupergroupEvent: ChatEvent
interface SupergroupEvent: GroupEvent

View File

@@ -8,12 +8,12 @@ import dev.inmo.tgbotapi.types.message.ChatEvents.abstracts.GroupEvent
import dev.inmo.tgbotapi.types.message.abstracts.GroupEventMessage
@Deprecated("Renamed", ReplaceWith("CommonGroupEventMessage"))
typealias GroupEventMessage = CommonGroupEventMessage
typealias GroupEventMessage = CommonGroupEventMessage<*>
data class CommonGroupEventMessage(
data class CommonGroupEventMessage<T : GroupEvent>(
override val messageId: MessageIdentifier,
override val user: User,
override val chat: GroupChat,
override val chatEvent: GroupEvent,
override val chatEvent: T,
override val date: DateTime
) : GroupEventMessage
) : GroupEventMessage<T>

View File

@@ -4,16 +4,17 @@ import com.soywiz.klock.DateTime
import dev.inmo.tgbotapi.types.MessageIdentifier
import dev.inmo.tgbotapi.types.User
import dev.inmo.tgbotapi.types.chat.abstracts.SupergroupChat
import dev.inmo.tgbotapi.types.message.ChatEvents.abstracts.GroupEvent
import dev.inmo.tgbotapi.types.message.ChatEvents.abstracts.SupergroupEvent
import dev.inmo.tgbotapi.types.message.abstracts.SupergroupEventMessage
@Deprecated("Renamed", ReplaceWith("CommonSupergroupEventMessage"))
typealias SupergroupEventMessage = CommonSupergroupEventMessage
typealias SupergroupEventMessage = CommonSupergroupEventMessage<*>
data class CommonSupergroupEventMessage(
data class CommonSupergroupEventMessage<T : SupergroupEvent>(
override val messageId: MessageIdentifier,
override val user: User,
override val chat: SupergroupChat,
override val chatEvent: SupergroupEvent,
override val chatEvent: T,
override val date: DateTime
) : SupergroupEventMessage
) : SupergroupEventMessage<T>

View File

@@ -38,6 +38,7 @@ data class AnonymousGroupMessageImpl<T : MessageContent>(
data class CommonGroupMessageImpl<T : MessageContent>(
override val chat: GroupChat,
override val messageId: MessageIdentifier,
override val user: User,
override val date: DateTime,
override val forwardInfo: ForwardInfo?,
override val editDate: DateTime?,

View File

@@ -296,6 +296,7 @@ internal data class RawMessage(
null -> CommonGroupMessageImpl(
chat,
messageId,
from ?: error("It is expected that in messages from non anonymous users and channels user must be specified"),
date.asDate,
forwarded,
edit_date ?.asDate,

View File

@@ -2,6 +2,6 @@ package dev.inmo.tgbotapi.types.message.abstracts
import dev.inmo.tgbotapi.types.message.ChatEvents.abstracts.ChatEvent
interface ChatEventMessage : Message {
val chatEvent: ChatEvent
interface ChatEventMessage<T : ChatEvent> : Message {
val chatEvent: T
}

View File

@@ -1,3 +1,5 @@
package dev.inmo.tgbotapi.types.message.abstracts
interface GroupEventMessage : ChatEventMessage, FromUserMessage
import dev.inmo.tgbotapi.types.message.ChatEvents.abstracts.GroupEvent
interface GroupEventMessage<T : GroupEvent> : ChatEventMessage<T>, FromUserMessage

View File

@@ -17,4 +17,4 @@ interface AnonymousGroupMessage<T : MessageContent> : GroupMessage<T>, SignedMes
override val senderChat: GroupChat
get() = chat
}
interface CommonGroupMessage<T : MessageContent> : GroupMessage<T>
interface CommonGroupMessage<T : MessageContent> : GroupMessage<T>, FromUserMessage

View File

@@ -1,3 +1,5 @@
package dev.inmo.tgbotapi.types.message.abstracts
interface SupergroupEventMessage : GroupEventMessage
import dev.inmo.tgbotapi.types.message.ChatEvents.abstracts.SupergroupEvent
interface SupergroupEventMessage<T : SupergroupEvent> : GroupEventMessage<T>

View File

@@ -1,7 +1,6 @@
package dev.inmo.tgbotapi.types.message.content
import dev.inmo.tgbotapi.CommonAbstracts.TextSourcesList
import dev.inmo.tgbotapi.CommonAbstracts.TextPart
import dev.inmo.tgbotapi.CommonAbstracts.*
import dev.inmo.tgbotapi.requests.abstracts.Request
import dev.inmo.tgbotapi.requests.send.SendTextMessage
import dev.inmo.tgbotapi.types.ChatIdentifier
@@ -15,13 +14,13 @@ import dev.inmo.tgbotapi.utils.internal.fullListOfSubSource
import dev.inmo.tgbotapi.utils.internal.toMarkdownTexts
data class TextContent(
val text: String,
/**
* Not full list of entities. This list WILL NOT contain [TextPart]s with [dev.inmo.tgbotapi.types.MessageEntity.textsources.RegularTextSource]
* @see [TextContent.fullEntitiesList]
*/
val entities: List<TextPart> = emptyList()
) : MessageContent {
override val text: String,
override val textEntities: List<TextPart> = emptyList()
) : MessageContent, TextedInput {
@Deprecated("Has been renamed", ReplaceWith("textEntities"))
val entities: List<TextPart>
get() = textEntities
override fun createResend(
chatId: ChatIdentifier,
disableNotification: Boolean,
@@ -83,4 +82,5 @@ data class TextContent(
* Convert its [TextContent.entities] to list of [dev.inmo.tgbotapi.CommonAbstracts.TextSource]
* with [dev.inmo.tgbotapi.types.MessageEntity.textsources.RegularTextSource]
*/
@Deprecated("Useless due to the fact that currently every message contains full list of sources")
fun TextContent.fullEntitiesList(): TextSourcesList = text.fullListOfSubSource(entities).map { it.source }

View File

@@ -2,10 +2,28 @@ package dev.inmo.tgbotapi.utils
const val telegramBotAPIDefaultUrl = "https://api.telegram.org"
private inline val String.withoutLastSlash: String
get() {
var correctedUrl = this
while (true) {
val withoutSuffix = correctedUrl.removeSuffix("/")
if (withoutSuffix == correctedUrl) {
return correctedUrl
}
correctedUrl = withoutSuffix
}
}
class TelegramAPIUrlsKeeper(
token: String,
hostUrl: String = telegramBotAPIDefaultUrl
) {
val commonAPIUrl = "$hostUrl/bot$token"
val fileBaseUrl = "$hostUrl/file/bot$token"
val commonAPIUrl: String
val fileBaseUrl: String
init {
val correctedHost = hostUrl.withoutLastSlash
commonAPIUrl = "$correctedHost/bot$token"
fileBaseUrl = "$correctedHost/file/bot$token"
}
}

View File

@@ -15,9 +15,9 @@ internal fun createFormattedText(
val textBuilder = StringBuilder(partLength)
for (entity in entities) {
val string = when (mode) {
is MarkdownParseMode -> entity.asMarkdownSource
is MarkdownV2ParseMode -> entity.asMarkdownV2Source
is HTMLParseMode -> entity.asHtmlSource
is MarkdownParseMode -> entity.markdown
is MarkdownV2ParseMode -> entity.markdownV2
is HTMLParseMode -> entity.html
}
if (textBuilder.length + string.length > partLength) {
if (textBuilder.isNotEmpty()) {

View File

@@ -73,29 +73,29 @@ internal fun List<TextPart>.shiftSourcesToTheLeft(shiftCount: Int = 1): List<Tex
}
private fun List<TextSource>.joinSubSourcesMarkdownV2() = joinToString("") {
it.asMarkdownV2Source
it.markdownV2
}
private fun List<TextSource>.joinSubSourcesHtml() = joinToString("") {
it.asHtmlSource
it.html
}
internal fun MultilevelTextSource.markdownV2Default(
openControlSymbol: String,
closeControlSymbol: String = openControlSymbol
) = "$openControlSymbol${textSources.joinSubSourcesMarkdownV2()}$closeControlSymbol"
) = "$openControlSymbol${subsources.joinSubSourcesMarkdownV2()}$closeControlSymbol"
internal fun MultilevelTextSource.htmlDefault(
openControlSymbol: String,
closeControlSymbol: String = openControlSymbol
) = "<$openControlSymbol>${textSources.joinSubSourcesHtml()}</$closeControlSymbol>"
) = "<$openControlSymbol>${subsources.joinSubSourcesHtml()}</$closeControlSymbol>"
internal fun MultilevelTextSource.linkMarkdownV2(
link: String
) = "[${textSources.joinSubSourcesMarkdownV2()}](${link.escapeMarkdownV2Link()})"
) = "[${subsources.joinSubSourcesMarkdownV2()}](${link.escapeMarkdownV2Link()})"
internal fun MultilevelTextSource.linkHTML(
link: String
) = "<a href=\"${link.toHtml()}\">${textSources.joinSubSourcesHtml()}</a>"
) = "<a href=\"${link.toHtml()}\">${subsources.joinSubSourcesHtml()}</a>"
internal fun MultilevelTextSource.optionalPrefix(
@@ -116,8 +116,8 @@ internal fun MultilevelTextSource.boldMarkdownV2(): String = markdownV2Default(m
internal fun MultilevelTextSource.boldHTML(): String = htmlDefault(htmlBoldControl)
internal fun MultilevelTextSource.cashTagMarkdownV2(): String = textSources.joinSubSourcesMarkdownV2()
internal fun MultilevelTextSource.cashTagHTML(): String = textSources.joinSubSourcesHtml()
internal fun MultilevelTextSource.cashTagMarkdownV2(): String = subsources.joinSubSourcesMarkdownV2()
internal fun MultilevelTextSource.cashTagHTML(): String = subsources.joinSubSourcesHtml()
internal fun MultilevelTextSource.italicMarkdownV2(): String = markdownV2Default(markdownItalicControl)
@@ -135,21 +135,21 @@ internal fun MultilevelTextSource.underlineHTML(): String = htmlDefault(htmlUnde
internal fun MultilevelTextSource.textMentionMarkdownV2(userId: UserId): String = linkMarkdownV2(userId.link)
internal fun MultilevelTextSource.textMentionHTML(userId: UserId): String = linkHTML(userId.link)
internal fun MultilevelTextSource.mentionMarkdownV2(): String = optionalPrefix("@") + textSources.joinSubSourcesMarkdownV2()
internal fun MultilevelTextSource.mentionHTML(): String = optionalPrefix("@") + textSources.joinSubSourcesHtml()
internal fun MultilevelTextSource.mentionMarkdownV2(): String = optionalPrefix("@") + subsources.joinSubSourcesMarkdownV2()
internal fun MultilevelTextSource.mentionHTML(): String = optionalPrefix("@") + subsources.joinSubSourcesHtml()
internal fun MultilevelTextSource.hashTagMarkdownV2(): String = when {
source.startsWith("\\#") || source.startsWith("#") -> ""
else -> "\\#"
} + textSources.joinSubSourcesMarkdownV2()
internal fun MultilevelTextSource.hashTagHTML(): String = optionalPrefix("#") + textSources.joinSubSourcesHtml()
} + subsources.joinSubSourcesMarkdownV2()
internal fun MultilevelTextSource.hashTagHTML(): String = optionalPrefix("#") + subsources.joinSubSourcesHtml()
internal fun MultilevelTextSource.phoneMarkdownV2(): String = textSources.joinSubSourcesMarkdownV2()
internal fun MultilevelTextSource.phoneHTML(): String = textSources.joinSubSourcesHtml()
internal fun MultilevelTextSource.phoneMarkdownV2(): String = subsources.joinSubSourcesMarkdownV2()
internal fun MultilevelTextSource.phoneHTML(): String = subsources.joinSubSourcesHtml()
internal fun MultilevelTextSource.commandMarkdownV2(): String = optionalPrefix("/") + textSources.joinSubSourcesMarkdownV2()
internal fun MultilevelTextSource.commandHTML(): String = optionalPrefix("/") + textSources.joinSubSourcesHtml()
internal fun MultilevelTextSource.commandMarkdownV2(): String = optionalPrefix("/") + subsources.joinSubSourcesMarkdownV2()
internal fun MultilevelTextSource.commandHTML(): String = optionalPrefix("/") + subsources.joinSubSourcesHtml()

View File

@@ -49,8 +49,8 @@ fun List<TextPart>.testTextParts() {
assertTrue (get(5).source is MentionTextSource)
val boldSource = get(1).source as BoldTextSource
assertTrue (boldSource.textSources.first() is ItalicTextSource)
assertTrue (boldSource.textSources[1] is RegularTextSource)
assertTrue (boldSource.textSources[2] is StrikethroughTextSource)
assertTrue ((boldSource.textSources[2] as StrikethroughTextSource).textSources.first() is UnderlineTextSource)
assertTrue (boldSource.subsources.first() is ItalicTextSource)
assertTrue (boldSource.subsources[1] is RegularTextSource)
assertTrue (boldSource.subsources[2] is StrikethroughTextSource)
assertTrue ((boldSource.subsources[2] as StrikethroughTextSource).subsources.first() is UnderlineTextSource)
}

View File

@@ -8,7 +8,6 @@ buildscript {
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version"
classpath "com.jfrog.bintray.gradle:gradle-bintray-plugin:$gradle_bintray_plugin_version"
}
}
@@ -40,11 +39,7 @@ kotlin {
commonMain {
dependencies {
implementation kotlin('stdlib')
if ((project.hasProperty('RELEASE_MODE') && project.property('RELEASE_MODE') == "true") || System.getenv('RELEASE_MODE') == "true") {
api "${project.group}:tgbotapi.core:$library_version"
} else {
api project(":tgbotapi.core")
}
api project(":tgbotapi.core")
}
}
}

View File

@@ -1,53 +0,0 @@
apply plugin: 'maven-publish'
task javadocsJar(type: Jar) {
classifier = 'javadoc'
}
afterEvaluate {
project.publishing.publications.all {
// rename artifacts
groupId "${project.group}"
if (it.name.contains('kotlinMultiplatform')) {
artifactId = "${project.name}"
} else {
artifactId = "${project.name}-$name"
}
}
}
publishing {
publications.all {
artifact javadocsJar
pom {
description = "API extensions which provide work with RequestsExecutor of TelegramBotAPI almost like it is described in original Telegram Bot API reference"
name = "Telegram Bot API Extensions for API"
url = "https://insanusmokrassar.github.io/TelegramBotAPI/TelegramBotAPI-extensions-api"
scm {
developerConnection = "scm:git:[fetch=]https://github.com/insanusmokrassar/TelegramBotAPI.git[push=]https://github.com/insanusmokrassar/TelegramBotAPI.git"
url = "https://github.com/insanusmokrassar/TelegramBotAPI.git"
}
developers {
developer {
id = "InsanusMokrassar"
name = "Ovsiannikov Aleksei"
email = "ovsyannikov.alexey95@gmail.com"
}
}
licenses {
license {
name = "Apache Software License 2.0"
url = "https://github.com/InsanusMokrassar/TelegramBotAPI/blob/master/LICENSE"
}
}
}
}
}

View File

@@ -1,59 +1,65 @@
apply plugin: 'com.jfrog.bintray'
apply plugin: 'maven-publish'
apply from: "maven.publish.gradle"
bintray {
user = project.hasProperty('BINTRAY_USER') ? project.property('BINTRAY_USER') : System.getenv('BINTRAY_USER')
key = project.hasProperty('BINTRAY_KEY') ? project.property('BINTRAY_KEY') : System.getenv('BINTRAY_KEY')
filesSpec {
from "${buildDir}/publications/"
eachFile {
String directorySubname = it.getFile().parentFile.name
if (it.getName() == "module.json") {
if (directorySubname == "kotlinMultiplatform") {
it.setPath("${project.name}/${project.version}/${project.name}-${project.version}.module")
} else {
it.setPath("${project.name}-${directorySubname}/${project.version}/${project.name}-${directorySubname}-${project.version}.module")
}
} else {
if (directorySubname == "kotlinMultiplatform" && it.getName() == "pom-default.xml") {
it.setPath("${project.name}/${project.version}/${project.name}-${project.version}.pom")
} else {
it.exclude()
}
}
}
into "${project.group}".replace(".", "/")
}
publish = true
override = true
pkg {
repo = "TelegramBotAPI"
name = "${project.name}"
vcsUrl = "https://github.com/InsanusMokrassar/TelegramBotAPI"
licenses = ["Apache-2.0"]
version {
name = "${project.version}"
released = new Date()
vcsTag = "${project.version}"
gpg {
sign = true
passphrase = project.hasProperty('signing.gnupg.passphrase') ? project.property('signing.gnupg.passphrase') : System.getenv('signing.gnupg.passphrase')
}
}
}
task javadocsJar(type: Jar) {
classifier = 'javadoc'
}
bintrayUpload.doFirst {
publications = publishing.publications.collect {
afterEvaluate {
project.publishing.publications.all {
// rename artifacts
groupId "${project.group}"
if (it.name.contains('kotlinMultiplatform')) {
null
artifactId = "${project.name}"
} else {
it.name
artifactId = "${project.name}-$name"
}
} - null
}
}
bintrayUpload.dependsOn publishToMavenLocal
publishing {
publications.all {
artifact javadocsJar
pom {
description = "API extensions which provide work with RequestsExecutor of TelegramBotAPI almost like it is described in original Telegram Bot API reference"
name = "Telegram Bot API Extensions for API"
url = "https://insanusmokrassar.github.io/TelegramBotAPI/TelegramBotAPI-extensions-api"
scm {
developerConnection = "scm:git:[fetch=]https://github.com/insanusmokrassar/TelegramBotAPI.git[push=]https://github.com/insanusmokrassar/TelegramBotAPI.git"
url = "https://github.com/insanusmokrassar/TelegramBotAPI.git"
}
developers {
developer {
id = "InsanusMokrassar"
name = "Ovsiannikov Aleksei"
email = "ovsyannikov.alexey95@gmail.com"
}
}
licenses {
license {
name = "Apache Software License 2.0"
url = "https://github.com/InsanusMokrassar/TelegramBotAPI/blob/master/LICENSE"
}
}
}
repositories {
maven {
name = "bintray"
url = uri("https://api.bintray.com/maven/${project.hasProperty('BINTRAY_USER') ? project.property('BINTRAY_USER') : System.getenv('BINTRAY_USER')}/TelegramBotAPI/${project.name}/;publish=1;override=1")
credentials {
username = project.hasProperty('BINTRAY_USER') ? project.property('BINTRAY_USER') : System.getenv('BINTRAY_USER')
password = project.hasProperty('BINTRAY_KEY') ? project.property('BINTRAY_KEY') : System.getenv('BINTRAY_KEY')
}
}
}
}
}

View File

@@ -2,6 +2,7 @@ package dev.inmo.tgbotapi.extensions.api
import dev.inmo.tgbotapi.bot.TelegramBot
import dev.inmo.tgbotapi.utils.TelegramAPIUrlsKeeper
import dev.inmo.tgbotapi.utils.telegramBotAPIDefaultUrl
import io.ktor.client.HttpClient
import io.ktor.client.HttpClientConfig
import io.ktor.client.engine.*
@@ -36,10 +37,25 @@ data class BotBuilder internal constructor(
* @return Created by [telegramBotWithCustomClientConfig] function [TelegramBot]. This executor will be preconfigured using [token] and
* [block]
*/
fun buildBot(
token: String,
apiUrl: String = telegramBotAPIDefaultUrl,
block: BotBuilder.() -> Unit
) = telegramBot(
TelegramAPIUrlsKeeper(token, apiUrl),
BotBuilder().apply(block).createHttpClient()
)
/**
* @return Created by [telegramBotWithCustomClientConfig] function [TelegramBot]. This executor will be preconfigured using [token] and
* [block]
*/
@Deprecated("Renamed", ReplaceWith("buildBot", "dev.inmo.tgbotapi.extensions.api.buildBot"))
fun telegramBot(
token: String,
block: BotBuilder.() -> Unit
): TelegramBot = telegramBot(
TelegramAPIUrlsKeeper(token),
BotBuilder().apply(block).createHttpClient()
): TelegramBot = buildBot(
token,
telegramBotAPIDefaultUrl,
block
)

View File

@@ -1,6 +1,6 @@
package dev.inmo.tgbotapi.extensions.api
import dev.inmo.tgbotapi.bot.Ktor.KtorRequestsExecutor
import dev.inmo.tgbotapi.bot.Ktor.KtorRequestsExecutorBuilder
import dev.inmo.tgbotapi.bot.TelegramBot
import dev.inmo.tgbotapi.utils.TelegramAPIUrlsKeeper
import dev.inmo.tgbotapi.utils.telegramBotAPIDefaultUrl
@@ -11,11 +11,11 @@ import io.ktor.client.engine.*
/**
* Allows to create bot using bot [urlsKeeper]
*/
@Deprecated("Replaced in core", ReplaceWith("telegramBot", "dev.inmo.tgbotapi.bot.Ktor.telegramBot"))
fun telegramBot(
urlsKeeper: TelegramAPIUrlsKeeper
): TelegramBot = KtorRequestsExecutor(
urlsKeeper,
HttpClient()
): TelegramBot = dev.inmo.tgbotapi.bot.Ktor.telegramBot(
urlsKeeper
)
/**
@@ -24,10 +24,9 @@ fun telegramBot(
fun telegramBot(
urlsKeeper: TelegramAPIUrlsKeeper,
client: HttpClient
): TelegramBot = KtorRequestsExecutor(
urlsKeeper,
client
)
): TelegramBot = dev.inmo.tgbotapi.bot.Ktor.telegramBot(urlsKeeper) {
this.client = client
}
/**
* Allows to create bot using bot [urlsKeeper] and specify [HttpClientEngineFactory] by passing [clientFactory] param and optionally
@@ -73,11 +72,12 @@ inline fun telegramBot(
/**
* Allows to create bot using bot [token], [apiUrl] (for custom api servers) and already prepared [client]
*/
@Deprecated("Replaced in core", ReplaceWith("telegramBot", "dev.inmo.tgbotapi.bot.Ktor.telegramBot"))
@Suppress("NOTHING_TO_INLINE")
inline fun telegramBot(
token: String,
apiUrl: String = telegramBotAPIDefaultUrl
): TelegramBot = telegramBot(TelegramAPIUrlsKeeper(token, apiUrl))
): TelegramBot = dev.inmo.tgbotapi.bot.Ktor.telegramBot(token, apiUrl)
/**
* Allows to create bot using bot [token], [apiUrl] (for custom api servers) and already prepared [client]

View File

@@ -8,7 +8,6 @@ buildscript {
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version"
classpath "com.jfrog.bintray.gradle:gradle-bintray-plugin:$gradle_bintray_plugin_version"
}
}
@@ -40,11 +39,7 @@ kotlin {
commonMain {
dependencies {
implementation kotlin('stdlib')
if ((project.hasProperty('RELEASE_MODE') && project.property('RELEASE_MODE') == "true") || System.getenv('RELEASE_MODE') == "true") {
api "${project.group}:tgbotapi.core:$library_version"
} else {
api project(":tgbotapi.core")
}
api project(":tgbotapi.core")
}
}
}

View File

@@ -1,53 +0,0 @@
apply plugin: 'maven-publish'
task javadocsJar(type: Jar) {
classifier = 'javadoc'
}
afterEvaluate {
project.publishing.publications.all {
// rename artifacts
groupId "${project.group}"
if (it.name.contains('kotlinMultiplatform')) {
artifactId = "${project.name}"
} else {
artifactId = "${project.name}-$name"
}
}
}
publishing {
publications.all {
artifact javadocsJar
pom {
description = "Util extensions for more useful work with updates and other things"
name = "Telegram Bot API Utility Extensions"
url = "https://insanusmokrassar.github.io/TelegramBotAPI/TelegramBotAPI-extensions-utils"
scm {
developerConnection = "scm:git:[fetch=]https://github.com/insanusmokrassar/TelegramBotAPI.git[push=]https://github.com/insanusmokrassar/TelegramBotAPI.git"
url = "https://github.com/insanusmokrassar/TelegramBotAPI.git"
}
developers {
developer {
id = "InsanusMokrassar"
name = "Ovsiannikov Aleksei"
email = "ovsyannikov.alexey95@gmail.com"
}
}
licenses {
license {
name = "Apache Software License 2.0"
url = "https://github.com/InsanusMokrassar/TelegramBotAPI/blob/master/LICENSE"
}
}
}
}
}

View File

@@ -1,59 +1,65 @@
apply plugin: 'com.jfrog.bintray'
apply plugin: 'maven-publish'
apply from: "maven.publish.gradle"
bintray {
user = project.hasProperty('BINTRAY_USER') ? project.property('BINTRAY_USER') : System.getenv('BINTRAY_USER')
key = project.hasProperty('BINTRAY_KEY') ? project.property('BINTRAY_KEY') : System.getenv('BINTRAY_KEY')
filesSpec {
from "${buildDir}/publications/"
eachFile {
String directorySubname = it.getFile().parentFile.name
if (it.getName() == "module.json") {
if (directorySubname == "kotlinMultiplatform") {
it.setPath("${project.name}/${project.version}/${project.name}-${project.version}.module")
} else {
it.setPath("${project.name}-${directorySubname}/${project.version}/${project.name}-${directorySubname}-${project.version}.module")
}
} else {
if (directorySubname == "kotlinMultiplatform" && it.getName() == "pom-default.xml") {
it.setPath("${project.name}/${project.version}/${project.name}-${project.version}.pom")
} else {
it.exclude()
}
}
}
into "${project.group}".replace(".", "/")
}
publish = true
override = true
pkg {
repo = "TelegramBotAPI"
name = "${project.name}"
vcsUrl = "https://github.com/InsanusMokrassar/TelegramBotAPI"
licenses = ["Apache-2.0"]
version {
name = "${project.version}"
released = new Date()
vcsTag = "${project.version}"
gpg {
sign = true
passphrase = project.hasProperty('signing.gnupg.passphrase') ? project.property('signing.gnupg.passphrase') : System.getenv('signing.gnupg.passphrase')
}
}
}
task javadocsJar(type: Jar) {
classifier = 'javadoc'
}
bintrayUpload.doFirst {
publications = publishing.publications.collect {
afterEvaluate {
project.publishing.publications.all {
// rename artifacts
groupId "${project.group}"
if (it.name.contains('kotlinMultiplatform')) {
null
artifactId = "${project.name}"
} else {
it.name
artifactId = "${project.name}-$name"
}
} - null
}
}
bintrayUpload.dependsOn publishToMavenLocal
publishing {
publications.all {
artifact javadocsJar
pom {
description = "Util extensions for more useful work with updates and other things"
name = "Telegram Bot API Utility Extensions"
url = "https://insanusmokrassar.github.io/TelegramBotAPI/TelegramBotAPI-extensions-utils"
scm {
developerConnection = "scm:git:[fetch=]https://github.com/insanusmokrassar/TelegramBotAPI.git[push=]https://github.com/insanusmokrassar/TelegramBotAPI.git"
url = "https://github.com/insanusmokrassar/TelegramBotAPI.git"
}
developers {
developer {
id = "InsanusMokrassar"
name = "Ovsiannikov Aleksei"
email = "ovsyannikov.alexey95@gmail.com"
}
}
licenses {
license {
name = "Apache Software License 2.0"
url = "https://github.com/InsanusMokrassar/TelegramBotAPI/blob/master/LICENSE"
}
}
}
repositories {
maven {
name = "bintray"
url = uri("https://api.bintray.com/maven/${project.hasProperty('BINTRAY_USER') ? project.property('BINTRAY_USER') : System.getenv('BINTRAY_USER')}/TelegramBotAPI/${project.name}/;publish=1;override=1")
credentials {
username = project.hasProperty('BINTRAY_USER') ? project.property('BINTRAY_USER') : System.getenv('BINTRAY_USER')
password = project.hasProperty('BINTRAY_KEY') ? project.property('BINTRAY_KEY') : System.getenv('BINTRAY_KEY')
}
}
}
}
}

View File

@@ -0,0 +1,755 @@
@file:Suppress("NOTHING_TO_INLINE", "unused", "UNCHECKED_CAST")
package dev.inmo.tgbotapi.extensions.utils
import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.CallbackQuery.*
import dev.inmo.tgbotapi.types.ChatMember.*
import dev.inmo.tgbotapi.types.ChatMember.abstracts.*
import dev.inmo.tgbotapi.types.InlineQueries.InlineQueryResult.*
import dev.inmo.tgbotapi.types.InlineQueries.InlineQueryResult.abstracts.*
import dev.inmo.tgbotapi.types.InlineQueries.InlineQueryResult.abstracts.results.audio.*
import dev.inmo.tgbotapi.types.InlineQueries.InlineQueryResult.abstracts.results.document.*
import dev.inmo.tgbotapi.types.InlineQueries.InlineQueryResult.abstracts.results.gif.*
import dev.inmo.tgbotapi.types.InlineQueries.InlineQueryResult.abstracts.results.mpeg4gif.*
import dev.inmo.tgbotapi.types.InlineQueries.InlineQueryResult.abstracts.results.photo.*
import dev.inmo.tgbotapi.types.InlineQueries.InlineQueryResult.abstracts.results.video.*
import dev.inmo.tgbotapi.types.InlineQueries.InlineQueryResult.abstracts.results.voice.*
import dev.inmo.tgbotapi.types.InlineQueries.InputMessageContent.*
import dev.inmo.tgbotapi.types.InlineQueries.abstracts.InlineQuery
import dev.inmo.tgbotapi.types.InlineQueries.abstracts.InputMessageContent
import dev.inmo.tgbotapi.types.InlineQueries.query.BaseInlineQuery
import dev.inmo.tgbotapi.types.InlineQueries.query.LocationInlineQuery
import dev.inmo.tgbotapi.types.InputMedia.*
import dev.inmo.tgbotapi.types.actions.*
import dev.inmo.tgbotapi.types.buttons.*
import dev.inmo.tgbotapi.types.buttons.InlineKeyboardButtons.*
import dev.inmo.tgbotapi.types.chat.abstracts.*
import dev.inmo.tgbotapi.types.chat.abstracts.extended.*
import dev.inmo.tgbotapi.types.files.*
import dev.inmo.tgbotapi.types.files.abstracts.*
import dev.inmo.tgbotapi.types.message.*
import dev.inmo.tgbotapi.types.message.ChatEvents.abstracts.*
import dev.inmo.tgbotapi.types.message.abstracts.*
import dev.inmo.tgbotapi.types.message.abstracts.ChannelMessage
import dev.inmo.tgbotapi.types.message.abstracts.GroupEventMessage
import dev.inmo.tgbotapi.types.message.abstracts.SupergroupEventMessage
import dev.inmo.tgbotapi.types.message.content.abstracts.MessageContent
import dev.inmo.tgbotapi.types.message.content.abstracts.PossiblySentViaBotCommonMessage
import dev.inmo.tgbotapi.types.polls.*
import dev.inmo.tgbotapi.types.update.*
import dev.inmo.tgbotapi.types.update.MediaGroupUpdates.*
import dev.inmo.tgbotapi.types.update.abstracts.*
import dev.inmo.tgbotapi.utils.PreviewFeature
@PreviewFeature
inline fun Chat.asBot(): Bot? = this as? Bot
@PreviewFeature
inline fun Chat.requireBot(): Bot = this as Bot
@PreviewFeature
inline fun Chat.asCommonBot(): CommonBot? = this as? CommonBot
@PreviewFeature
inline fun Chat.requireCommonBot(): CommonBot = this as CommonBot
@PreviewFeature
inline fun Chat.asCommonUser(): CommonUser? = this as? CommonUser
@PreviewFeature
inline fun Chat.requireCommonUser(): CommonUser = this as CommonUser
@PreviewFeature
inline fun Chat.asExtendedBot(): ExtendedBot? = this as? ExtendedBot
@PreviewFeature
inline fun Chat.requireExtendedBot(): ExtendedBot = this as ExtendedBot
@PreviewFeature
inline fun Chat.asUser(): User? = this as? User
@PreviewFeature
inline fun Chat.requireUser(): User = this as User
@PreviewFeature
inline fun Chat.asChannelChat(): ChannelChat? = this as? ChannelChat
@PreviewFeature
inline fun Chat.requireChannelChat(): ChannelChat = this as ChannelChat
@PreviewFeature
inline fun Chat.asGroupChat(): GroupChat? = this as? GroupChat
@PreviewFeature
inline fun Chat.requireGroupChat(): GroupChat = this as GroupChat
@PreviewFeature
inline fun Chat.asPrivateChat(): PrivateChat? = this as? PrivateChat
@PreviewFeature
inline fun Chat.requirePrivateChat(): PrivateChat = this as PrivateChat
@PreviewFeature
inline fun Chat.asPublicChat(): PublicChat? = this as? PublicChat
@PreviewFeature
inline fun Chat.requirePublicChat(): PublicChat = this as PublicChat
@PreviewFeature
inline fun Chat.asSuperPublicChat(): SuperPublicChat? = this as? SuperPublicChat
@PreviewFeature
inline fun Chat.requireSuperPublicChat(): SuperPublicChat = this as SuperPublicChat
@PreviewFeature
inline fun Chat.asSupergroupChat(): SupergroupChat? = this as? SupergroupChat
@PreviewFeature
inline fun Chat.requireSupergroupChat(): SupergroupChat = this as SupergroupChat
@PreviewFeature
inline fun Chat.asUnknownChatType(): UnknownChatType? = this as? UnknownChatType
@PreviewFeature
inline fun Chat.requireUnknownChatType(): UnknownChatType = this as UnknownChatType
@PreviewFeature
inline fun Chat.asUsernameChat(): UsernameChat? = this as? UsernameChat
@PreviewFeature
inline fun Chat.requireUsernameChat(): UsernameChat = this as UsernameChat
@PreviewFeature
inline fun Chat.asExtendedChannelChat(): ExtendedChannelChat? = this as? ExtendedChannelChat
@PreviewFeature
inline fun Chat.requireExtendedChannelChat(): ExtendedChannelChat = this as ExtendedChannelChat
@PreviewFeature
inline fun Chat.asExtendedChat(): ExtendedChat? = this as? ExtendedChat
@PreviewFeature
inline fun Chat.requireExtendedChat(): ExtendedChat = this as ExtendedChat
@PreviewFeature
inline fun Chat.asExtendedGroupChat(): ExtendedGroupChat? = this as? ExtendedGroupChat
@PreviewFeature
inline fun Chat.requireExtendedGroupChat(): ExtendedGroupChat = this as ExtendedGroupChat
@PreviewFeature
inline fun Chat.asExtendedPrivateChat(): ExtendedPrivateChat? = this as? ExtendedPrivateChat
@PreviewFeature
inline fun Chat.requireExtendedPrivateChat(): ExtendedPrivateChat = this as ExtendedPrivateChat
@PreviewFeature
inline fun Chat.asExtendedPublicChat(): ExtendedPublicChat? = this as? ExtendedPublicChat
@PreviewFeature
inline fun Chat.requireExtendedPublicChat(): ExtendedPublicChat = this as ExtendedPublicChat
@PreviewFeature
inline fun Chat.asExtendedSupergroupChat(): ExtendedSupergroupChat? = this as? ExtendedSupergroupChat
@PreviewFeature
inline fun Chat.requireExtendedSupergroupChat(): ExtendedSupergroupChat = this as ExtendedSupergroupChat
@PreviewFeature
inline fun CallbackQuery.asDataCallbackQuery(): DataCallbackQuery? = this as? DataCallbackQuery
@PreviewFeature
inline fun CallbackQuery.requireDataCallbackQuery(): DataCallbackQuery = this as DataCallbackQuery
@PreviewFeature
inline fun CallbackQuery.asGameShortNameCallbackQuery(): GameShortNameCallbackQuery? = this as? GameShortNameCallbackQuery
@PreviewFeature
inline fun CallbackQuery.requireGameShortNameCallbackQuery(): GameShortNameCallbackQuery = this as GameShortNameCallbackQuery
@PreviewFeature
inline fun CallbackQuery.asInlineMessageIdCallbackQuery(): InlineMessageIdCallbackQuery? = this as? InlineMessageIdCallbackQuery
@PreviewFeature
inline fun CallbackQuery.requireInlineMessageIdCallbackQuery(): InlineMessageIdCallbackQuery = this as InlineMessageIdCallbackQuery
@PreviewFeature
inline fun CallbackQuery.asInlineMessageIdDataCallbackQuery(): InlineMessageIdDataCallbackQuery? = this as? InlineMessageIdDataCallbackQuery
@PreviewFeature
inline fun CallbackQuery.requireInlineMessageIdDataCallbackQuery(): InlineMessageIdDataCallbackQuery = this as InlineMessageIdDataCallbackQuery
@PreviewFeature
inline fun CallbackQuery.asInlineMessageIdGameShortNameCallbackQuery(): InlineMessageIdGameShortNameCallbackQuery? = this as? InlineMessageIdGameShortNameCallbackQuery
@PreviewFeature
inline fun CallbackQuery.requireInlineMessageIdGameShortNameCallbackQuery(): InlineMessageIdGameShortNameCallbackQuery = this as InlineMessageIdGameShortNameCallbackQuery
@PreviewFeature
inline fun CallbackQuery.asMessageCallbackQuery(): MessageCallbackQuery? = this as? MessageCallbackQuery
@PreviewFeature
inline fun CallbackQuery.requireMessageCallbackQuery(): MessageCallbackQuery = this as MessageCallbackQuery
@PreviewFeature
inline fun CallbackQuery.asMessageDataCallbackQuery(): MessageDataCallbackQuery? = this as? MessageDataCallbackQuery
@PreviewFeature
inline fun CallbackQuery.requireMessageDataCallbackQuery(): MessageDataCallbackQuery = this as MessageDataCallbackQuery
@PreviewFeature
inline fun CallbackQuery.asMessageGameShortNameCallbackQuery(): MessageGameShortNameCallbackQuery? = this as? MessageGameShortNameCallbackQuery
@PreviewFeature
inline fun CallbackQuery.requireMessageGameShortNameCallbackQuery(): MessageGameShortNameCallbackQuery = this as MessageGameShortNameCallbackQuery
@PreviewFeature
inline fun CallbackQuery.asUnknownCallbackQueryType(): UnknownCallbackQueryType? = this as? UnknownCallbackQueryType
@PreviewFeature
inline fun CallbackQuery.requireUnknownCallbackQueryType(): UnknownCallbackQueryType = this as UnknownCallbackQueryType
@PreviewFeature
inline fun Message.asChannelEventMessage(): ChannelEventMessage<ChannelEvent>? = this as? ChannelEventMessage<ChannelEvent>
@PreviewFeature
inline fun Message.requireChannelEventMessage(): ChannelEventMessage<ChannelEvent> = this as ChannelEventMessage<ChannelEvent>
@PreviewFeature
inline fun Message.asChannelMediaGroupMessage(): ChannelMediaGroupMessage? = this as? ChannelMediaGroupMessage
@PreviewFeature
inline fun Message.requireChannelMediaGroupMessage(): ChannelMediaGroupMessage = this as ChannelMediaGroupMessage
@PreviewFeature
inline fun Message.asCommonGroupEventMessage(): CommonGroupEventMessage<GroupEvent>? = this as? CommonGroupEventMessage<GroupEvent>
@PreviewFeature
inline fun Message.requireCommonGroupEventMessage(): CommonGroupEventMessage<GroupEvent> = this as CommonGroupEventMessage<GroupEvent>
@PreviewFeature
inline fun Message.asCommonMediaGroupMessage(): CommonMediaGroupMessage? = this as? CommonMediaGroupMessage
@PreviewFeature
inline fun Message.requireCommonMediaGroupMessage(): CommonMediaGroupMessage = this as CommonMediaGroupMessage
@PreviewFeature
inline fun Message.asCommonSupergroupEventMessage(): CommonSupergroupEventMessage<SupergroupEvent>? = this as? CommonSupergroupEventMessage<SupergroupEvent>
@PreviewFeature
inline fun Message.requireCommonSupergroupEventMessage(): CommonSupergroupEventMessage<SupergroupEvent> = this as CommonSupergroupEventMessage<SupergroupEvent>
@PreviewFeature
inline fun Message.asAnonymousGroupMessage(): AnonymousGroupMessage<MessageContent>? = this as? AnonymousGroupMessage<MessageContent>
@PreviewFeature
inline fun Message.requireAnonymousGroupMessage(): AnonymousGroupMessage<MessageContent> = this as AnonymousGroupMessage<MessageContent>
@PreviewFeature
inline fun Message.asChannelMessage(): ChannelMessage<MessageContent>? = this as? ChannelMessage<MessageContent>
@PreviewFeature
inline fun Message.requireChannelMessage(): ChannelMessage<MessageContent> = this as ChannelMessage<MessageContent>
@PreviewFeature
inline fun Message.asChatEventMessage(): ChatEventMessage<ChatEvent>? = this as? ChatEventMessage<ChatEvent>
@PreviewFeature
inline fun Message.requireChatEventMessage(): ChatEventMessage<ChatEvent> = this as ChatEventMessage<ChatEvent>
@PreviewFeature
inline fun Message.asCommonGroupMessage(): CommonGroupMessage<MessageContent>? = this as? CommonGroupMessage<MessageContent>
@PreviewFeature
inline fun Message.requireCommonGroupMessage(): CommonGroupMessage<MessageContent> = this as CommonGroupMessage<MessageContent>
@PreviewFeature
inline fun Message.asCommonMessage(): CommonMessage<MessageContent>? = this as? CommonMessage<MessageContent>
@PreviewFeature
inline fun Message.requireCommonMessage(): CommonMessage<MessageContent> = this as CommonMessage<MessageContent>
@PreviewFeature
inline fun Message.asContentMessage(): ContentMessage<MessageContent>? = this as? ContentMessage<MessageContent>
@PreviewFeature
inline fun Message.requireContentMessage(): ContentMessage<MessageContent> = this as ContentMessage<MessageContent>
@PreviewFeature
inline fun Message.asFromChannelGroupMessage(): FromChannelGroupMessage<MessageContent>? = this as? FromChannelGroupMessage<MessageContent>
@PreviewFeature
inline fun Message.requireFromChannelGroupMessage(): FromChannelGroupMessage<MessageContent> = this as FromChannelGroupMessage<MessageContent>
@PreviewFeature
inline fun Message.asGroupEventMessage(): GroupEventMessage<GroupEvent>? = this as? GroupEventMessage<GroupEvent>
@PreviewFeature
inline fun Message.requireGroupEventMessage(): GroupEventMessage<GroupEvent> = this as GroupEventMessage<GroupEvent>
@PreviewFeature
inline fun Message.asGroupMessage(): GroupMessage<MessageContent>? = this as? GroupMessage<MessageContent>
@PreviewFeature
inline fun Message.requireGroupMessage(): GroupMessage<MessageContent> = this as GroupMessage<MessageContent>
@PreviewFeature
inline fun Message.asMediaGroupMessage(): MediaGroupMessage? = this as? MediaGroupMessage
@PreviewFeature
inline fun Message.requireMediaGroupMessage(): MediaGroupMessage = this as MediaGroupMessage
@PreviewFeature
inline fun Message.asPossiblyEditedMessage(): PossiblyEditedMessage? = this as? PossiblyEditedMessage
@PreviewFeature
inline fun Message.requirePossiblyEditedMessage(): PossiblyEditedMessage = this as PossiblyEditedMessage
@PreviewFeature
inline fun Message.asPossiblyForwardedMessage(): PossiblyForwardedMessage? = this as? PossiblyForwardedMessage
@PreviewFeature
inline fun Message.requirePossiblyForwardedMessage(): PossiblyForwardedMessage = this as PossiblyForwardedMessage
@PreviewFeature
inline fun Message.asPossiblyPaymentMessage(): PossiblyPaymentMessage? = this as? PossiblyPaymentMessage
@PreviewFeature
inline fun Message.requirePossiblyPaymentMessage(): PossiblyPaymentMessage = this as PossiblyPaymentMessage
@PreviewFeature
inline fun Message.asPrivateMessage(): PrivateMessage<MessageContent>? = this as? PrivateMessage<MessageContent>
@PreviewFeature
inline fun Message.requirePrivateMessage(): PrivateMessage<MessageContent> = this as PrivateMessage<MessageContent>
@PreviewFeature
inline fun Message.asPublicMessage(): PublicMessage<MessageContent>? = this as? PublicMessage<MessageContent>
@PreviewFeature
inline fun Message.requirePublicMessage(): PublicMessage<MessageContent> = this as PublicMessage<MessageContent>
@PreviewFeature
inline fun Message.asSignedMessage(): SignedMessage? = this as? SignedMessage
@PreviewFeature
inline fun Message.requireSignedMessage(): SignedMessage = this as SignedMessage
@PreviewFeature
inline fun Message.asSupergroupEventMessage(): SupergroupEventMessage<SupergroupEvent>? = this as? SupergroupEventMessage<SupergroupEvent>
@PreviewFeature
inline fun Message.requireSupergroupEventMessage(): SupergroupEventMessage<SupergroupEvent> = this as SupergroupEventMessage<SupergroupEvent>
@PreviewFeature
inline fun Message.asUnknownMessageType(): UnknownMessageType? = this as? UnknownMessageType
@PreviewFeature
inline fun Message.requireUnknownMessageType(): UnknownMessageType = this as UnknownMessageType
@PreviewFeature
inline fun Message.asPossiblySentViaBotCommonMessage(): PossiblySentViaBotCommonMessage<MessageContent>? = this as? PossiblySentViaBotCommonMessage<MessageContent>
@PreviewFeature
inline fun Message.requirePossiblySentViaBotCommonMessage(): PossiblySentViaBotCommonMessage<MessageContent> = this as PossiblySentViaBotCommonMessage<MessageContent>
@PreviewFeature
inline fun BotAction.asFindLocationAction(): FindLocationAction? = this as? FindLocationAction
@PreviewFeature
inline fun BotAction.requireFindLocationAction(): FindLocationAction = this as FindLocationAction
@PreviewFeature
inline fun BotAction.asRecordAudioAction(): RecordAudioAction? = this as? RecordAudioAction
@PreviewFeature
inline fun BotAction.requireRecordAudioAction(): RecordAudioAction = this as RecordAudioAction
@PreviewFeature
inline fun BotAction.asRecordVideoAction(): RecordVideoAction? = this as? RecordVideoAction
@PreviewFeature
inline fun BotAction.requireRecordVideoAction(): RecordVideoAction = this as RecordVideoAction
@PreviewFeature
inline fun BotAction.asRecordVideoNoteAction(): RecordVideoNoteAction? = this as? RecordVideoNoteAction
@PreviewFeature
inline fun BotAction.requireRecordVideoNoteAction(): RecordVideoNoteAction = this as RecordVideoNoteAction
@PreviewFeature
inline fun BotAction.asTypingAction(): TypingAction? = this as? TypingAction
@PreviewFeature
inline fun BotAction.requireTypingAction(): TypingAction = this as TypingAction
@PreviewFeature
inline fun BotAction.asUploadAudioAction(): UploadAudioAction? = this as? UploadAudioAction
@PreviewFeature
inline fun BotAction.requireUploadAudioAction(): UploadAudioAction = this as UploadAudioAction
@PreviewFeature
inline fun BotAction.asUploadDocumentAction(): UploadDocumentAction? = this as? UploadDocumentAction
@PreviewFeature
inline fun BotAction.requireUploadDocumentAction(): UploadDocumentAction = this as UploadDocumentAction
@PreviewFeature
inline fun BotAction.asUploadPhotoAction(): UploadPhotoAction? = this as? UploadPhotoAction
@PreviewFeature
inline fun BotAction.requireUploadPhotoAction(): UploadPhotoAction = this as UploadPhotoAction
@PreviewFeature
inline fun BotAction.asUploadVideoAction(): UploadVideoAction? = this as? UploadVideoAction
@PreviewFeature
inline fun BotAction.requireUploadVideoAction(): UploadVideoAction = this as UploadVideoAction
@PreviewFeature
inline fun BotAction.asUploadVideoNoteAction(): UploadVideoNoteAction? = this as? UploadVideoNoteAction
@PreviewFeature
inline fun BotAction.requireUploadVideoNoteAction(): UploadVideoNoteAction = this as UploadVideoNoteAction
@PreviewFeature
inline fun InlineQuery.asBaseInlineQuery(): BaseInlineQuery? = this as? BaseInlineQuery
@PreviewFeature
inline fun InlineQuery.requireBaseInlineQuery(): BaseInlineQuery = this as BaseInlineQuery
@PreviewFeature
inline fun InlineQuery.asLocationInlineQuery(): LocationInlineQuery? = this as? LocationInlineQuery
@PreviewFeature
inline fun InlineQuery.requireLocationInlineQuery(): LocationInlineQuery = this as LocationInlineQuery
@PreviewFeature
inline fun InputMessageContent.asInputContactMessageContent(): InputContactMessageContent? = this as? InputContactMessageContent
@PreviewFeature
inline fun InputMessageContent.requireInputContactMessageContent(): InputContactMessageContent = this as InputContactMessageContent
@PreviewFeature
inline fun InputMessageContent.asInputLocationMessageContent(): InputLocationMessageContent? = this as? InputLocationMessageContent
@PreviewFeature
inline fun InputMessageContent.requireInputLocationMessageContent(): InputLocationMessageContent = this as InputLocationMessageContent
@PreviewFeature
inline fun InputMessageContent.asInputTextMessageContent(): InputTextMessageContent? = this as? InputTextMessageContent
@PreviewFeature
inline fun InputMessageContent.requireInputTextMessageContent(): InputTextMessageContent = this as InputTextMessageContent
@PreviewFeature
inline fun InputMessageContent.asInputVenueMessageContent(): InputVenueMessageContent? = this as? InputVenueMessageContent
@PreviewFeature
inline fun InputMessageContent.requireInputVenueMessageContent(): InputVenueMessageContent = this as InputVenueMessageContent
@PreviewFeature
inline fun InlineQueryResult.asInlineQueryResultArticle(): InlineQueryResultArticle? = this as? InlineQueryResultArticle
@PreviewFeature
inline fun InlineQueryResult.requireInlineQueryResultArticle(): InlineQueryResultArticle = this as InlineQueryResultArticle
@PreviewFeature
inline fun InlineQueryResult.asInlineQueryResultContact(): InlineQueryResultContact? = this as? InlineQueryResultContact
@PreviewFeature
inline fun InlineQueryResult.requireInlineQueryResultContact(): InlineQueryResultContact = this as InlineQueryResultContact
@PreviewFeature
inline fun InlineQueryResult.asInlineQueryResultGame(): InlineQueryResultGame? = this as? InlineQueryResultGame
@PreviewFeature
inline fun InlineQueryResult.requireInlineQueryResultGame(): InlineQueryResultGame = this as InlineQueryResultGame
@PreviewFeature
inline fun InlineQueryResult.asInlineQueryResultLocation(): InlineQueryResultLocation? = this as? InlineQueryResultLocation
@PreviewFeature
inline fun InlineQueryResult.requireInlineQueryResultLocation(): InlineQueryResultLocation = this as InlineQueryResultLocation
@PreviewFeature
inline fun InlineQueryResult.asInlineQueryResultStickerCached(): InlineQueryResultStickerCached? = this as? InlineQueryResultStickerCached
@PreviewFeature
inline fun InlineQueryResult.requireInlineQueryResultStickerCached(): InlineQueryResultStickerCached = this as InlineQueryResultStickerCached
@PreviewFeature
inline fun InlineQueryResult.asInlineQueryResultVenue(): InlineQueryResultVenue? = this as? InlineQueryResultVenue
@PreviewFeature
inline fun InlineQueryResult.requireInlineQueryResultVenue(): InlineQueryResultVenue = this as InlineQueryResultVenue
@PreviewFeature
inline fun InlineQueryResult.asDescribedInlineQueryResult(): DescribedInlineQueryResult? = this as? DescribedInlineQueryResult
@PreviewFeature
inline fun InlineQueryResult.requireDescribedInlineQueryResult(): DescribedInlineQueryResult = this as DescribedInlineQueryResult
@PreviewFeature
inline fun InlineQueryResult.asFileInlineQueryResult(): FileInlineQueryResult? = this as? FileInlineQueryResult
@PreviewFeature
inline fun InlineQueryResult.requireFileInlineQueryResult(): FileInlineQueryResult = this as FileInlineQueryResult
@PreviewFeature
inline fun InlineQueryResult.asOptionallyTitledInlineQueryResult(): OptionallyTitledInlineQueryResult? = this as? OptionallyTitledInlineQueryResult
@PreviewFeature
inline fun InlineQueryResult.requireOptionallyTitledInlineQueryResult(): OptionallyTitledInlineQueryResult = this as OptionallyTitledInlineQueryResult
@PreviewFeature
inline fun InlineQueryResult.asSizedInlineQueryResult(): SizedInlineQueryResult? = this as? SizedInlineQueryResult
@PreviewFeature
inline fun InlineQueryResult.requireSizedInlineQueryResult(): SizedInlineQueryResult = this as SizedInlineQueryResult
@PreviewFeature
inline fun InlineQueryResult.asThumbSizedInlineQueryResult(): ThumbSizedInlineQueryResult? = this as? ThumbSizedInlineQueryResult
@PreviewFeature
inline fun InlineQueryResult.requireThumbSizedInlineQueryResult(): ThumbSizedInlineQueryResult = this as ThumbSizedInlineQueryResult
@PreviewFeature
inline fun InlineQueryResult.asThumbedInlineQueryResult(): ThumbedInlineQueryResult? = this as? ThumbedInlineQueryResult
@PreviewFeature
inline fun InlineQueryResult.requireThumbedInlineQueryResult(): ThumbedInlineQueryResult = this as ThumbedInlineQueryResult
@PreviewFeature
inline fun InlineQueryResult.asThumbedWithMimeTypeInlineQueryResult(): ThumbedWithMimeTypeInlineQueryResult? = this as? ThumbedWithMimeTypeInlineQueryResult
@PreviewFeature
inline fun InlineQueryResult.requireThumbedWithMimeTypeInlineQueryResult(): ThumbedWithMimeTypeInlineQueryResult = this as ThumbedWithMimeTypeInlineQueryResult
@PreviewFeature
inline fun InlineQueryResult.asTitledInlineQueryResult(): TitledInlineQueryResult? = this as? TitledInlineQueryResult
@PreviewFeature
inline fun InlineQueryResult.requireTitledInlineQueryResult(): TitledInlineQueryResult = this as TitledInlineQueryResult
@PreviewFeature
inline fun InlineQueryResult.asUrlInlineQueryResult(): UrlInlineQueryResult? = this as? UrlInlineQueryResult
@PreviewFeature
inline fun InlineQueryResult.requireUrlInlineQueryResult(): UrlInlineQueryResult = this as UrlInlineQueryResult
@PreviewFeature
inline fun InlineQueryResult.asWithInputMessageContentInlineQueryResult(): WithInputMessageContentInlineQueryResult? = this as? WithInputMessageContentInlineQueryResult
@PreviewFeature
inline fun InlineQueryResult.requireWithInputMessageContentInlineQueryResult(): WithInputMessageContentInlineQueryResult = this as WithInputMessageContentInlineQueryResult
@PreviewFeature
inline fun InlineQueryResult.asInlineQueryResultAudio(): InlineQueryResultAudio? = this as? InlineQueryResultAudio
@PreviewFeature
inline fun InlineQueryResult.requireInlineQueryResultAudio(): InlineQueryResultAudio = this as InlineQueryResultAudio
@PreviewFeature
inline fun InlineQueryResult.asInlineQueryResultAudioCached(): InlineQueryResultAudioCached? = this as? InlineQueryResultAudioCached
@PreviewFeature
inline fun InlineQueryResult.requireInlineQueryResultAudioCached(): InlineQueryResultAudioCached = this as InlineQueryResultAudioCached
@PreviewFeature
inline fun InlineQueryResult.asInlineQueryResultAudioCommon(): InlineQueryResultAudioCommon? = this as? InlineQueryResultAudioCommon
@PreviewFeature
inline fun InlineQueryResult.requireInlineQueryResultAudioCommon(): InlineQueryResultAudioCommon = this as InlineQueryResultAudioCommon
@PreviewFeature
inline fun InlineQueryResult.asInlineQueryResultDocument(): InlineQueryResultDocument? = this as? InlineQueryResultDocument
@PreviewFeature
inline fun InlineQueryResult.requireInlineQueryResultDocument(): InlineQueryResultDocument = this as InlineQueryResultDocument
@PreviewFeature
inline fun InlineQueryResult.asInlineQueryResultDocumentCached(): InlineQueryResultDocumentCached? = this as? InlineQueryResultDocumentCached
@PreviewFeature
inline fun InlineQueryResult.requireInlineQueryResultDocumentCached(): InlineQueryResultDocumentCached = this as InlineQueryResultDocumentCached
@PreviewFeature
inline fun InlineQueryResult.asInlineQueryResultDocumentCommon(): InlineQueryResultDocumentCommon? = this as? InlineQueryResultDocumentCommon
@PreviewFeature
inline fun InlineQueryResult.requireInlineQueryResultDocumentCommon(): InlineQueryResultDocumentCommon = this as InlineQueryResultDocumentCommon
@PreviewFeature
inline fun InlineQueryResult.asInlineQueryResultGif(): InlineQueryResultGif? = this as? InlineQueryResultGif
@PreviewFeature
inline fun InlineQueryResult.requireInlineQueryResultGif(): InlineQueryResultGif = this as InlineQueryResultGif
@PreviewFeature
inline fun InlineQueryResult.asInlineQueryResultGifCached(): InlineQueryResultGifCached? = this as? InlineQueryResultGifCached
@PreviewFeature
inline fun InlineQueryResult.requireInlineQueryResultGifCached(): InlineQueryResultGifCached = this as InlineQueryResultGifCached
@PreviewFeature
inline fun InlineQueryResult.asInlineQueryResultGifCommon(): InlineQueryResultGifCommon? = this as? InlineQueryResultGifCommon
@PreviewFeature
inline fun InlineQueryResult.requireInlineQueryResultGifCommon(): InlineQueryResultGifCommon = this as InlineQueryResultGifCommon
@PreviewFeature
inline fun InlineQueryResult.asInlineQueryResultMpeg4Gif(): InlineQueryResultMpeg4Gif? = this as? InlineQueryResultMpeg4Gif
@PreviewFeature
inline fun InlineQueryResult.requireInlineQueryResultMpeg4Gif(): InlineQueryResultMpeg4Gif = this as InlineQueryResultMpeg4Gif
@PreviewFeature
inline fun InlineQueryResult.asInlineQueryResultMpeg4GifCached(): InlineQueryResultMpeg4GifCached? = this as? InlineQueryResultMpeg4GifCached
@PreviewFeature
inline fun InlineQueryResult.requireInlineQueryResultMpeg4GifCached(): InlineQueryResultMpeg4GifCached = this as InlineQueryResultMpeg4GifCached
@PreviewFeature
inline fun InlineQueryResult.asInlineQueryResultMpeg4GifCommon(): InlineQueryResultMpeg4GifCommon? = this as? InlineQueryResultMpeg4GifCommon
@PreviewFeature
inline fun InlineQueryResult.requireInlineQueryResultMpeg4GifCommon(): InlineQueryResultMpeg4GifCommon = this as InlineQueryResultMpeg4GifCommon
@PreviewFeature
inline fun InlineQueryResult.asInlineQueryResultPhoto(): InlineQueryResultPhoto? = this as? InlineQueryResultPhoto
@PreviewFeature
inline fun InlineQueryResult.requireInlineQueryResultPhoto(): InlineQueryResultPhoto = this as InlineQueryResultPhoto
@PreviewFeature
inline fun InlineQueryResult.asInlineQueryResultPhotoCached(): InlineQueryResultPhotoCached? = this as? InlineQueryResultPhotoCached
@PreviewFeature
inline fun InlineQueryResult.requireInlineQueryResultPhotoCached(): InlineQueryResultPhotoCached = this as InlineQueryResultPhotoCached
@PreviewFeature
inline fun InlineQueryResult.asInlineQueryResultPhotoCommon(): InlineQueryResultPhotoCommon? = this as? InlineQueryResultPhotoCommon
@PreviewFeature
inline fun InlineQueryResult.requireInlineQueryResultPhotoCommon(): InlineQueryResultPhotoCommon = this as InlineQueryResultPhotoCommon
@PreviewFeature
inline fun InlineQueryResult.asInlineQueryResultVideo(): InlineQueryResultVideo? = this as? InlineQueryResultVideo
@PreviewFeature
inline fun InlineQueryResult.requireInlineQueryResultVideo(): InlineQueryResultVideo = this as InlineQueryResultVideo
@PreviewFeature
inline fun InlineQueryResult.asInlineQueryResultVideoCached(): InlineQueryResultVideoCached? = this as? InlineQueryResultVideoCached
@PreviewFeature
inline fun InlineQueryResult.requireInlineQueryResultVideoCached(): InlineQueryResultVideoCached = this as InlineQueryResultVideoCached
@PreviewFeature
inline fun InlineQueryResult.asInlineQueryResultVideoCommon(): InlineQueryResultVideoCommon? = this as? InlineQueryResultVideoCommon
@PreviewFeature
inline fun InlineQueryResult.requireInlineQueryResultVideoCommon(): InlineQueryResultVideoCommon = this as InlineQueryResultVideoCommon
@PreviewFeature
inline fun InlineQueryResult.asInlineQueryResultVoice(): InlineQueryResultVoice? = this as? InlineQueryResultVoice
@PreviewFeature
inline fun InlineQueryResult.requireInlineQueryResultVoice(): InlineQueryResultVoice = this as InlineQueryResultVoice
@PreviewFeature
inline fun InlineQueryResult.asInlineQueryResultVoiceCached(): InlineQueryResultVoiceCached? = this as? InlineQueryResultVoiceCached
@PreviewFeature
inline fun InlineQueryResult.requireInlineQueryResultVoiceCached(): InlineQueryResultVoiceCached = this as InlineQueryResultVoiceCached
@PreviewFeature
inline fun InlineQueryResult.asInlineQueryResultVoiceCommon(): InlineQueryResultVoiceCommon? = this as? InlineQueryResultVoiceCommon
@PreviewFeature
inline fun InlineQueryResult.requireInlineQueryResultVoiceCommon(): InlineQueryResultVoiceCommon = this as InlineQueryResultVoiceCommon
@PreviewFeature
inline fun ChatMember.asCreatorChatMember(): CreatorChatMember? = this as? CreatorChatMember
@PreviewFeature
inline fun ChatMember.requireCreatorChatMember(): CreatorChatMember = this as CreatorChatMember
@PreviewFeature
inline fun ChatMember.asKickedChatMember(): KickedChatMember? = this as? KickedChatMember
@PreviewFeature
inline fun ChatMember.requireKickedChatMember(): KickedChatMember = this as KickedChatMember
@PreviewFeature
inline fun ChatMember.asLeftChatMember(): LeftChatMember? = this as? LeftChatMember
@PreviewFeature
inline fun ChatMember.requireLeftChatMember(): LeftChatMember = this as LeftChatMember
@PreviewFeature
inline fun ChatMember.asMemberChatMember(): MemberChatMember? = this as? MemberChatMember
@PreviewFeature
inline fun ChatMember.requireMemberChatMember(): MemberChatMember = this as MemberChatMember
@PreviewFeature
inline fun ChatMember.asRestrictedChatMember(): RestrictedChatMember? = this as? RestrictedChatMember
@PreviewFeature
inline fun ChatMember.requireRestrictedChatMember(): RestrictedChatMember = this as RestrictedChatMember
@PreviewFeature
inline fun ChatMember.asAdministratorChatMember(): AdministratorChatMember? = this as? AdministratorChatMember
@PreviewFeature
inline fun ChatMember.requireAdministratorChatMember(): AdministratorChatMember = this as AdministratorChatMember
@PreviewFeature
inline fun ChatMember.asBannedChatMember(): BannedChatMember? = this as? BannedChatMember
@PreviewFeature
inline fun ChatMember.requireBannedChatMember(): BannedChatMember = this as BannedChatMember
@PreviewFeature
inline fun ChatMember.asSpecialRightsChatMember(): SpecialRightsChatMember? = this as? SpecialRightsChatMember
@PreviewFeature
inline fun ChatMember.requireSpecialRightsChatMember(): SpecialRightsChatMember = this as SpecialRightsChatMember
@PreviewFeature
inline fun InputMedia.asAudioMediaGroupMemberInputMedia(): AudioMediaGroupMemberInputMedia? = this as? AudioMediaGroupMemberInputMedia
@PreviewFeature
inline fun InputMedia.requireAudioMediaGroupMemberInputMedia(): AudioMediaGroupMemberInputMedia = this as AudioMediaGroupMemberInputMedia
@PreviewFeature
inline fun InputMedia.asDocumentMediaGroupMemberInputMedia(): DocumentMediaGroupMemberInputMedia? = this as? DocumentMediaGroupMemberInputMedia
@PreviewFeature
inline fun InputMedia.requireDocumentMediaGroupMemberInputMedia(): DocumentMediaGroupMemberInputMedia = this as DocumentMediaGroupMemberInputMedia
@PreviewFeature
inline fun InputMedia.asDuratedInputMedia(): DuratedInputMedia? = this as? DuratedInputMedia
@PreviewFeature
inline fun InputMedia.requireDuratedInputMedia(): DuratedInputMedia = this as DuratedInputMedia
@PreviewFeature
inline fun InputMedia.asInputMediaAnimation(): InputMediaAnimation? = this as? InputMediaAnimation
@PreviewFeature
inline fun InputMedia.requireInputMediaAnimation(): InputMediaAnimation = this as InputMediaAnimation
@PreviewFeature
inline fun InputMedia.asInputMediaAudio(): InputMediaAudio? = this as? InputMediaAudio
@PreviewFeature
inline fun InputMedia.requireInputMediaAudio(): InputMediaAudio = this as InputMediaAudio
@PreviewFeature
inline fun InputMedia.asInputMediaDocument(): InputMediaDocument? = this as? InputMediaDocument
@PreviewFeature
inline fun InputMedia.requireInputMediaDocument(): InputMediaDocument = this as InputMediaDocument
@PreviewFeature
inline fun InputMedia.asInputMediaPhoto(): InputMediaPhoto? = this as? InputMediaPhoto
@PreviewFeature
inline fun InputMedia.requireInputMediaPhoto(): InputMediaPhoto = this as InputMediaPhoto
@PreviewFeature
inline fun InputMedia.asInputMediaVideo(): InputMediaVideo? = this as? InputMediaVideo
@PreviewFeature
inline fun InputMedia.requireInputMediaVideo(): InputMediaVideo = this as InputMediaVideo
@PreviewFeature
inline fun InputMedia.asMediaGroupMemberInputMedia(): MediaGroupMemberInputMedia? = this as? MediaGroupMemberInputMedia
@PreviewFeature
inline fun InputMedia.requireMediaGroupMemberInputMedia(): MediaGroupMemberInputMedia = this as MediaGroupMemberInputMedia
@PreviewFeature
inline fun InputMedia.asSizedInputMedia(): SizedInputMedia? = this as? SizedInputMedia
@PreviewFeature
inline fun InputMedia.requireSizedInputMedia(): SizedInputMedia = this as SizedInputMedia
@PreviewFeature
inline fun InputMedia.asThumbedInputMedia(): ThumbedInputMedia? = this as? ThumbedInputMedia
@PreviewFeature
inline fun InputMedia.requireThumbedInputMedia(): ThumbedInputMedia = this as ThumbedInputMedia
@PreviewFeature
inline fun InputMedia.asTitledInputMedia(): TitledInputMedia? = this as? TitledInputMedia
@PreviewFeature
inline fun InputMedia.requireTitledInputMedia(): TitledInputMedia = this as TitledInputMedia
@PreviewFeature
inline fun InputMedia.asVisualMediaGroupMemberInputMedia(): VisualMediaGroupMemberInputMedia? = this as? VisualMediaGroupMemberInputMedia
@PreviewFeature
inline fun InputMedia.requireVisualMediaGroupMemberInputMedia(): VisualMediaGroupMemberInputMedia = this as VisualMediaGroupMemberInputMedia
@PreviewFeature
inline fun Update.asCallbackQueryUpdate(): CallbackQueryUpdate? = this as? CallbackQueryUpdate
@PreviewFeature
inline fun Update.requireCallbackQueryUpdate(): CallbackQueryUpdate = this as CallbackQueryUpdate
@PreviewFeature
inline fun Update.asChannelPostUpdate(): ChannelPostUpdate? = this as? ChannelPostUpdate
@PreviewFeature
inline fun Update.requireChannelPostUpdate(): ChannelPostUpdate = this as ChannelPostUpdate
@PreviewFeature
inline fun Update.asChosenInlineResultUpdate(): ChosenInlineResultUpdate? = this as? ChosenInlineResultUpdate
@PreviewFeature
inline fun Update.requireChosenInlineResultUpdate(): ChosenInlineResultUpdate = this as ChosenInlineResultUpdate
@PreviewFeature
inline fun Update.asEditChannelPostUpdate(): EditChannelPostUpdate? = this as? EditChannelPostUpdate
@PreviewFeature
inline fun Update.requireEditChannelPostUpdate(): EditChannelPostUpdate = this as EditChannelPostUpdate
@PreviewFeature
inline fun Update.asEditMessageUpdate(): EditMessageUpdate? = this as? EditMessageUpdate
@PreviewFeature
inline fun Update.requireEditMessageUpdate(): EditMessageUpdate = this as EditMessageUpdate
@PreviewFeature
inline fun Update.asInlineQueryUpdate(): InlineQueryUpdate? = this as? InlineQueryUpdate
@PreviewFeature
inline fun Update.requireInlineQueryUpdate(): InlineQueryUpdate = this as InlineQueryUpdate
@PreviewFeature
inline fun Update.asChannelPostMediaGroupUpdate(): ChannelPostMediaGroupUpdate? = this as? ChannelPostMediaGroupUpdate
@PreviewFeature
inline fun Update.requireChannelPostMediaGroupUpdate(): ChannelPostMediaGroupUpdate = this as ChannelPostMediaGroupUpdate
@PreviewFeature
inline fun Update.asEditChannelPostMediaGroupUpdate(): EditChannelPostMediaGroupUpdate? = this as? EditChannelPostMediaGroupUpdate
@PreviewFeature
inline fun Update.requireEditChannelPostMediaGroupUpdate(): EditChannelPostMediaGroupUpdate = this as EditChannelPostMediaGroupUpdate
@PreviewFeature
inline fun Update.asEditMediaGroupUpdate(): EditMediaGroupUpdate? = this as? EditMediaGroupUpdate
@PreviewFeature
inline fun Update.requireEditMediaGroupUpdate(): EditMediaGroupUpdate = this as EditMediaGroupUpdate
@PreviewFeature
inline fun Update.asEditMessageMediaGroupUpdate(): EditMessageMediaGroupUpdate? = this as? EditMessageMediaGroupUpdate
@PreviewFeature
inline fun Update.requireEditMessageMediaGroupUpdate(): EditMessageMediaGroupUpdate = this as EditMessageMediaGroupUpdate
@PreviewFeature
inline fun Update.asMediaGroupUpdate(): MediaGroupUpdate? = this as? MediaGroupUpdate
@PreviewFeature
inline fun Update.requireMediaGroupUpdate(): MediaGroupUpdate = this as MediaGroupUpdate
@PreviewFeature
inline fun Update.asMessageMediaGroupUpdate(): MessageMediaGroupUpdate? = this as? MessageMediaGroupUpdate
@PreviewFeature
inline fun Update.requireMessageMediaGroupUpdate(): MessageMediaGroupUpdate = this as MessageMediaGroupUpdate
@PreviewFeature
inline fun Update.asSentMediaGroupUpdate(): SentMediaGroupUpdate? = this as? SentMediaGroupUpdate
@PreviewFeature
inline fun Update.requireSentMediaGroupUpdate(): SentMediaGroupUpdate = this as SentMediaGroupUpdate
@PreviewFeature
inline fun Update.asMessageUpdate(): MessageUpdate? = this as? MessageUpdate
@PreviewFeature
inline fun Update.requireMessageUpdate(): MessageUpdate = this as MessageUpdate
@PreviewFeature
inline fun Update.asPollAnswerUpdate(): PollAnswerUpdate? = this as? PollAnswerUpdate
@PreviewFeature
inline fun Update.requirePollAnswerUpdate(): PollAnswerUpdate = this as PollAnswerUpdate
@PreviewFeature
inline fun Update.asPollUpdate(): PollUpdate? = this as? PollUpdate
@PreviewFeature
inline fun Update.requirePollUpdate(): PollUpdate = this as PollUpdate
@PreviewFeature
inline fun Update.asPreCheckoutQueryUpdate(): PreCheckoutQueryUpdate? = this as? PreCheckoutQueryUpdate
@PreviewFeature
inline fun Update.requirePreCheckoutQueryUpdate(): PreCheckoutQueryUpdate = this as PreCheckoutQueryUpdate
@PreviewFeature
inline fun Update.asShippingQueryUpdate(): ShippingQueryUpdate? = this as? ShippingQueryUpdate
@PreviewFeature
inline fun Update.requireShippingQueryUpdate(): ShippingQueryUpdate = this as ShippingQueryUpdate
@PreviewFeature
inline fun Update.asBaseEditMessageUpdate(): BaseEditMessageUpdate? = this as? BaseEditMessageUpdate
@PreviewFeature
inline fun Update.requireBaseEditMessageUpdate(): BaseEditMessageUpdate = this as BaseEditMessageUpdate
@PreviewFeature
inline fun Update.asBaseMessageUpdate(): BaseMessageUpdate? = this as? BaseMessageUpdate
@PreviewFeature
inline fun Update.requireBaseMessageUpdate(): BaseMessageUpdate = this as BaseMessageUpdate
@PreviewFeature
inline fun Update.asBaseSentMessageUpdate(): BaseSentMessageUpdate? = this as? BaseSentMessageUpdate
@PreviewFeature
inline fun Update.requireBaseSentMessageUpdate(): BaseSentMessageUpdate = this as BaseSentMessageUpdate
@PreviewFeature
inline fun Update.asUnknownUpdate(): UnknownUpdate? = this as? UnknownUpdate
@PreviewFeature
inline fun Update.requireUnknownUpdate(): UnknownUpdate = this as UnknownUpdate
@PreviewFeature
inline fun TelegramMediaFile.asAnimationFile(): AnimationFile? = this as? AnimationFile
@PreviewFeature
inline fun TelegramMediaFile.requireAnimationFile(): AnimationFile = this as AnimationFile
@PreviewFeature
inline fun TelegramMediaFile.asAudioFile(): AudioFile? = this as? AudioFile
@PreviewFeature
inline fun TelegramMediaFile.requireAudioFile(): AudioFile = this as AudioFile
@PreviewFeature
inline fun TelegramMediaFile.asDocumentFile(): DocumentFile? = this as? DocumentFile
@PreviewFeature
inline fun TelegramMediaFile.requireDocumentFile(): DocumentFile = this as DocumentFile
@PreviewFeature
inline fun TelegramMediaFile.asFile(): File? = this as? File
@PreviewFeature
inline fun TelegramMediaFile.requireFile(): File = this as File
@PreviewFeature
inline fun TelegramMediaFile.asPathedFile(): PathedFile? = this as? PathedFile
@PreviewFeature
inline fun TelegramMediaFile.requirePathedFile(): PathedFile = this as PathedFile
@PreviewFeature
inline fun TelegramMediaFile.asPhotoSize(): PhotoSize? = this as? PhotoSize
@PreviewFeature
inline fun TelegramMediaFile.requirePhotoSize(): PhotoSize = this as PhotoSize
@PreviewFeature
inline fun TelegramMediaFile.asSticker(): Sticker? = this as? Sticker
@PreviewFeature
inline fun TelegramMediaFile.requireSticker(): Sticker = this as Sticker
@PreviewFeature
inline fun TelegramMediaFile.asVideoFile(): VideoFile? = this as? VideoFile
@PreviewFeature
inline fun TelegramMediaFile.requireVideoFile(): VideoFile = this as VideoFile
@PreviewFeature
inline fun TelegramMediaFile.asVideoNoteFile(): VideoNoteFile? = this as? VideoNoteFile
@PreviewFeature
inline fun TelegramMediaFile.requireVideoNoteFile(): VideoNoteFile = this as VideoNoteFile
@PreviewFeature
inline fun TelegramMediaFile.asVoiceFile(): VoiceFile? = this as? VoiceFile
@PreviewFeature
inline fun TelegramMediaFile.requireVoiceFile(): VoiceFile = this as VoiceFile
@PreviewFeature
inline fun TelegramMediaFile.asMimedMediaFile(): MimedMediaFile? = this as? MimedMediaFile
@PreviewFeature
inline fun TelegramMediaFile.requireMimedMediaFile(): MimedMediaFile = this as MimedMediaFile
@PreviewFeature
inline fun TelegramMediaFile.asPlayableMediaFile(): PlayableMediaFile? = this as? PlayableMediaFile
@PreviewFeature
inline fun TelegramMediaFile.requirePlayableMediaFile(): PlayableMediaFile = this as PlayableMediaFile
@PreviewFeature
inline fun TelegramMediaFile.asSizedMediaFile(): SizedMediaFile? = this as? SizedMediaFile
@PreviewFeature
inline fun TelegramMediaFile.requireSizedMediaFile(): SizedMediaFile = this as SizedMediaFile
@PreviewFeature
inline fun TelegramMediaFile.asThumbedMediaFile(): ThumbedMediaFile? = this as? ThumbedMediaFile
@PreviewFeature
inline fun TelegramMediaFile.requireThumbedMediaFile(): ThumbedMediaFile = this as ThumbedMediaFile
@PreviewFeature
inline fun KeyboardMarkup.asForceReply(): ForceReply? = this as? ForceReply
@PreviewFeature
inline fun KeyboardMarkup.requireForceReply(): ForceReply = this as ForceReply
@PreviewFeature
inline fun KeyboardMarkup.asInlineKeyboardMarkup(): InlineKeyboardMarkup? = this as? InlineKeyboardMarkup
@PreviewFeature
inline fun KeyboardMarkup.requireInlineKeyboardMarkup(): InlineKeyboardMarkup = this as InlineKeyboardMarkup
@PreviewFeature
inline fun KeyboardMarkup.asReplyKeyboardMarkup(): ReplyKeyboardMarkup? = this as? ReplyKeyboardMarkup
@PreviewFeature
inline fun KeyboardMarkup.requireReplyKeyboardMarkup(): ReplyKeyboardMarkup = this as ReplyKeyboardMarkup
@PreviewFeature
inline fun KeyboardMarkup.asReplyKeyboardRemove(): ReplyKeyboardRemove? = this as? ReplyKeyboardRemove
@PreviewFeature
inline fun KeyboardMarkup.requireReplyKeyboardRemove(): ReplyKeyboardRemove = this as ReplyKeyboardRemove
@PreviewFeature
inline fun InlineKeyboardButton.asCallbackDataInlineKeyboardButton(): CallbackDataInlineKeyboardButton? = this as? CallbackDataInlineKeyboardButton
@PreviewFeature
inline fun InlineKeyboardButton.requireCallbackDataInlineKeyboardButton(): CallbackDataInlineKeyboardButton = this as CallbackDataInlineKeyboardButton
@PreviewFeature
inline fun InlineKeyboardButton.asCallbackGameInlineKeyboardButton(): CallbackGameInlineKeyboardButton? = this as? CallbackGameInlineKeyboardButton
@PreviewFeature
inline fun InlineKeyboardButton.requireCallbackGameInlineKeyboardButton(): CallbackGameInlineKeyboardButton = this as CallbackGameInlineKeyboardButton
@PreviewFeature
inline fun InlineKeyboardButton.asLoginURLInlineKeyboardButton(): LoginURLInlineKeyboardButton? = this as? LoginURLInlineKeyboardButton
@PreviewFeature
inline fun InlineKeyboardButton.requireLoginURLInlineKeyboardButton(): LoginURLInlineKeyboardButton = this as LoginURLInlineKeyboardButton
@PreviewFeature
inline fun InlineKeyboardButton.asPayInlineKeyboardButton(): PayInlineKeyboardButton? = this as? PayInlineKeyboardButton
@PreviewFeature
inline fun InlineKeyboardButton.requirePayInlineKeyboardButton(): PayInlineKeyboardButton = this as PayInlineKeyboardButton
@PreviewFeature
inline fun InlineKeyboardButton.asSwitchInlineQueryCurrentChatInlineKeyboardButton(): SwitchInlineQueryCurrentChatInlineKeyboardButton? = this as? SwitchInlineQueryCurrentChatInlineKeyboardButton
@PreviewFeature
inline fun InlineKeyboardButton.requireSwitchInlineQueryCurrentChatInlineKeyboardButton(): SwitchInlineQueryCurrentChatInlineKeyboardButton = this as SwitchInlineQueryCurrentChatInlineKeyboardButton
@PreviewFeature
inline fun InlineKeyboardButton.asSwitchInlineQueryInlineKeyboardButton(): SwitchInlineQueryInlineKeyboardButton? = this as? SwitchInlineQueryInlineKeyboardButton
@PreviewFeature
inline fun InlineKeyboardButton.requireSwitchInlineQueryInlineKeyboardButton(): SwitchInlineQueryInlineKeyboardButton = this as SwitchInlineQueryInlineKeyboardButton
@PreviewFeature
inline fun InlineKeyboardButton.asURLInlineKeyboardButton(): URLInlineKeyboardButton? = this as? URLInlineKeyboardButton
@PreviewFeature
inline fun InlineKeyboardButton.requireURLInlineKeyboardButton(): URLInlineKeyboardButton = this as URLInlineKeyboardButton
@PreviewFeature
inline fun InlineKeyboardButton.asUnknownInlineKeyboardButton(): UnknownInlineKeyboardButton? = this as? UnknownInlineKeyboardButton
@PreviewFeature
inline fun InlineKeyboardButton.requireUnknownInlineKeyboardButton(): UnknownInlineKeyboardButton = this as UnknownInlineKeyboardButton
@PreviewFeature
inline fun Poll.asMultipleAnswersPoll(): MultipleAnswersPoll? = this as? MultipleAnswersPoll
@PreviewFeature
inline fun Poll.requireMultipleAnswersPoll(): MultipleAnswersPoll = this as MultipleAnswersPoll
@PreviewFeature
inline fun Poll.asQuizPoll(): QuizPoll? = this as? QuizPoll
@PreviewFeature
inline fun Poll.requireQuizPoll(): QuizPoll = this as QuizPoll
@PreviewFeature
inline fun Poll.asRegularPoll(): RegularPoll? = this as? RegularPoll
@PreviewFeature
inline fun Poll.requireRegularPoll(): RegularPoll = this as RegularPoll
@PreviewFeature
inline fun Poll.asUnknownPollType(): UnknownPollType? = this as? UnknownPollType
@PreviewFeature
inline fun Poll.requireUnknownPollType(): UnknownPollType = this as UnknownPollType

View File

@@ -7,7 +7,6 @@ import kotlinx.coroutines.CoroutineScope
/**
* Shortcut for [dev.inmo.micro_utils.coroutines.safely]. It was created for more comfortable way of handling different things
*/
@PreviewFeature
@Deprecated("In future will be used typealias from micro_utils", ReplaceWith("safely", "dev.inmo.micro_utils.coroutines.safely"))
suspend inline fun <T> safely(
noinline onException: ExceptionHandler<T> = { throw it },

View File

@@ -1,13 +1,13 @@
package dev.inmo.tgbotapi.extensions.utils.chat_events
import dev.inmo.tgbotapi.types.message.*
import dev.inmo.tgbotapi.extensions.utils.shortcuts.*
import dev.inmo.tgbotapi.types.message.abstracts.ChatEventMessage
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.mapNotNull
import kotlin.reflect.KClass
fun <T : ChatEventMessage> Flow<ChatEventMessage>.divideBySource(contentType: KClass<T>) = mapNotNull {
@Deprecated("Refactored, replaced and renamed", ReplaceWith("filterByChatEvent", "dev.inmo.tgbotapi.extensions.utils.shortcuts.filterByChatEvent"))
fun <T : ChatEventMessage<*>> Flow<ChatEventMessage<*>>.divideBySource(contentType: KClass<T>) = mapNotNull {
if (contentType.isInstance(it)) {
@Suppress("UNCHECKED_CAST")
it as T
@@ -16,6 +16,9 @@ fun <T : ChatEventMessage> Flow<ChatEventMessage>.divideBySource(contentType: KC
}
}
fun Flow<ChatEventMessage>.onlyChannelEvents() = divideBySource(ChannelEventMessage::class)
fun Flow<ChatEventMessage>.onlyGroupEvents() = divideBySource(CommonGroupEventMessage::class)
fun Flow<ChatEventMessage>.onlySupergroupEvents() = divideBySource(CommonSupergroupEventMessage::class)
@Deprecated("Replaced and renamed", ReplaceWith("channelEvents", "dev.inmo.tgbotapi.extensions.utils.shortcuts.channelEvents"))
fun Flow<ChatEventMessage<*>>.onlyChannelEvents() = channelEvents()
@Deprecated("Replaced and renamed", ReplaceWith("groupEvents", "dev.inmo.tgbotapi.extensions.utils.shortcuts.groupEvents"))
fun Flow<ChatEventMessage<*>>.onlyGroupEvents() = groupEvents()
@Deprecated("Replaced and renamed", ReplaceWith("supergroupEvents", "dev.inmo.tgbotapi.extensions.utils.shortcuts.supergroupEvents"))
fun Flow<ChatEventMessage<*>>.onlySupergroupEvents() = supergroupEvents()

View File

@@ -1,13 +1,19 @@
package dev.inmo.tgbotapi.extensions.utils.formatting
import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.MessageEntity.textsources.link
import dev.inmo.tgbotapi.types.ParseMode.*
import dev.inmo.tgbotapi.types.chat.abstracts.PrivateChat
import dev.inmo.tgbotapi.types.chat.abstracts.UsernameChat
import dev.inmo.tgbotapi.types.chat.abstracts.extended.ExtendedChat
import dev.inmo.tgbotapi.types.chat.abstracts.*
import dev.inmo.tgbotapi.types.chat.abstracts.extended.ExtendedPublicChat
import dev.inmo.tgbotapi.types.message.abstracts.Message
private const val internalLinkBeginning = "https://t.me"
fun makeUsernameLink(username: String) = "$internalLinkBeginning/$username"
inline val Username.link
get() = makeUsernameLink(username)
inline fun makeLink(username: Username) = username.link
fun makeLinkToMessage(
username: String,
messageId: MessageIdentifier
@@ -24,8 +30,12 @@ fun makeLinkToMessage(
private val linkIdRedundantPartRegex = Regex("^-100")
private val usernameBeginSymbolRegex = Regex("^@")
/**
* Link which can be used as by any user to get access to [Message]. Returns null in case when there are no
* known way to build link (for [PrivateChat]s, for example)
*/
fun makeLinkToMessage(
chat: ExtendedChat,
chat: Chat,
messageId: MessageIdentifier
): String? {
return when {
@@ -43,8 +53,55 @@ fun makeLinkToMessage(
}
}
/**
* @see makeLinkToMessage
*/
val Message.link: String?
get() = makeLinkToMessage(
chat,
messageId
)
/**
* Link which can be used as by any user to get access to [Chat]. Returns null in case when there are no
* known way to build link
*/
val Chat.link: String?
get() {
if (this is UsernameChat) {
username ?.username ?.let { return it }
}
if (this is ExtendedPublicChat) {
inviteLink ?.let { return it }
}
if (this is PrivateChat) {
return id.link
}
return null
}
private const val stickerSetAddingLinkPrefix = "$internalLinkBeginning/addstickers"
val StickerSetName.stickerSetLink
get() = link(this, "$stickerSetAddingLinkPrefix/$this")
/**
* @return Link for adding of sticker set with name [stickerSetName] with formatting for [MarkdownV2]
*/
@Deprecated("Use extension `stickerSetLink` + getting of `asMarkdownV2Source` property")
fun makeLinkToAddStickerSetInMarkdownV2(
stickerSetName: StickerSetName
) = stickerSetName.stickerSetLink.markdownV2
/**
* @return Link for adding of sticker set with name [stickerSetName] with formatting for [Markdown]
*/
@Deprecated("Use extension `stickerSetLink` + getting of `asMarkdownSource` property")
fun makeLinkToAddStickerSetInMarkdown(stickerSetName: StickerSetName) = stickerSetName.stickerSetLink.markdown
/**
* @return Link for adding of sticker set with name [stickerSetName] with formatting for [HTML]
*/
@Deprecated("Use extension `stickerSetLink` + getting of `asHtmlSource` property")
fun makeLinkToAddStickerSetInHtml(stickerSetName: StickerSetName) = stickerSetName.stickerSetLink.html
/**
* Create a link for adding of sticker set with name [stickerSetName]. Was added thanks to user Djaler and based on
* https://github.com/Djaler/evil-bot/blob/master/src/main/kotlin/com/github/djaler/evilbot/utils/StickerUtils.kt#L6-L8
@@ -53,34 +110,12 @@ private const val stickerSetAddingLinkPrefix = "$internalLinkBeginning/addsticke
* @see [makeLinkToAddStickerSetInMarkdown]
* @see [makeLinkToAddStickerSetInHtml]
*/
@Deprecated("Use extension `stickerSetLink` + getting of required property")
fun makeLinkToAddStickerSet(
stickerSetName: StickerSetName,
parseMode: ParseMode
) = (stickerSetName to "$stickerSetAddingLinkPrefix/$stickerSetName").link(
parseMode
)
/**
* @return Link for adding of sticker set with name [stickerSetName] with formatting for [MarkdownV2]
*/
fun makeLinkToAddStickerSetInMarkdownV2(stickerSetName: StickerSetName) =
makeLinkToAddStickerSet(
stickerSetName,
MarkdownV2
)
/**
* @return Link for adding of sticker set with name [stickerSetName] with formatting for [Markdown]
*/
fun makeLinkToAddStickerSetInMarkdown(stickerSetName: StickerSetName) =
makeLinkToAddStickerSet(
stickerSetName,
Markdown
)
/**
* @return Link for adding of sticker set with name [stickerSetName] with formatting for [HTML]
*/
fun makeLinkToAddStickerSetInHtml(stickerSetName: StickerSetName) =
makeLinkToAddStickerSet(
stickerSetName,
HTML
)
) = when (parseMode) {
MarkdownParseMode -> makeLinkToAddStickerSetInMarkdown(stickerSetName)
MarkdownV2ParseMode -> makeLinkToAddStickerSetInMarkdownV2(stickerSetName)
HTMLParseMode -> makeLinkToAddStickerSetInHtml(stickerSetName)
}

View File

@@ -15,9 +15,9 @@ fun createFormattedText(
val textBuilder = StringBuilder(partLength)
for (entity in entities) {
val string = when (mode) {
is MarkdownParseMode -> entity.asMarkdownSource
is MarkdownV2ParseMode -> entity.asMarkdownV2Source
is HTMLParseMode -> entity.asHtmlSource
is MarkdownParseMode -> entity.markdown
is MarkdownV2ParseMode -> entity.markdownV2
is HTMLParseMode -> entity.html
}
if (textBuilder.length + string.length > partLength) {
if (textBuilder.isNotEmpty()) {

View File

@@ -1,6 +1,7 @@
package dev.inmo.tgbotapi.extensions.utils.shortcuts
import dev.inmo.tgbotapi.CommonAbstracts.TextSource
import dev.inmo.tgbotapi.CommonAbstracts.textSources
import dev.inmo.tgbotapi.extensions.utils.onlyTextContentMessages
import dev.inmo.tgbotapi.extensions.utils.updates.asContentMessagesFlow
import dev.inmo.tgbotapi.types.MessageEntity.textsources.BotCommandTextSource
@@ -27,7 +28,7 @@ import kotlinx.coroutines.flow.*
fun <T : ContentMessage<TextContent>> Flow<T>.filterExactCommands(
commandRegex: Regex
) = filter { contentMessage ->
(contentMessage.content.fullEntitiesList().singleOrNull() as? BotCommandTextSource) ?.let { commandRegex.matches(it.command) } == true
(contentMessage.content.textSources.singleOrNull() as? BotCommandTextSource) ?.let { commandRegex.matches(it.command) } == true
}
/**
@@ -46,7 +47,7 @@ fun <T : ContentMessage<TextContent>> Flow<T>.filterExactCommands(
fun <T : ContentMessage<TextContent>> Flow<T>.filterCommandsInsideTextMessages(
commandRegex: Regex
) = filter { contentMessage ->
contentMessage.content.fullEntitiesList().any {
contentMessage.content.textSources.any {
(it as? BotCommandTextSource) ?.let { commandRegex.matches(it.command) } == true
}
}
@@ -70,7 +71,7 @@ fun <T : ContentMessage<TextContent>> Flow<T>.filterCommandsInsideTextMessages(
fun <T : ContentMessage<TextContent>> Flow<T>.filterCommandsWithArgs(
commandRegex: Regex
) = mapNotNull { contentMessage ->
val allEntities = contentMessage.content.fullEntitiesList()
val allEntities = contentMessage.content.textSources
(allEntities.firstOrNull() as? BotCommandTextSource) ?.let {
if (commandRegex.matches(it.command)) {
contentMessage to allEntities.flatMap {

View File

@@ -0,0 +1,98 @@
@file:Suppress("NOTHING_TO_INLINE", "unused", "EXPERIMENTAL_API_USAGE")
package dev.inmo.tgbotapi.extensions.utils.shortcuts
import dev.inmo.micro_utils.coroutines.plus
import dev.inmo.tgbotapi.types.message.ChannelEventMessage
import dev.inmo.tgbotapi.types.message.ChatEvents.*
import dev.inmo.tgbotapi.types.message.ChatEvents.abstracts.*
import dev.inmo.tgbotapi.types.message.abstracts.*
import dev.inmo.tgbotapi.updateshandlers.FlowsUpdatesFilter
import dev.inmo.tgbotapi.utils.RiskFeature
import kotlinx.coroutines.flow.*
@RiskFeature("Use with caution")
inline fun FlowsUpdatesFilter.events(): Flow<ChatEventMessage<*>> {
return channelPostFlow.mapNotNull { it.data as? ChatEventMessage<*> } + messageFlow.mapNotNull { it.data as? ChatEventMessage<*> }
}
@RiskFeature("Use with caution")
inline fun FlowsUpdatesFilter.channelEvents(): Flow<ChannelEventMessage<*>> = channelPostFlow.mapNotNull {
it.data as? ChannelEventMessage<*>
}
@RiskFeature("Use with caution")
inline fun FlowsUpdatesFilter.groupEvents(): Flow<GroupEventMessage<*>> = messageFlow.mapNotNull {
it.data as? GroupEventMessage<*>
}
@RiskFeature("Use with caution")
inline fun FlowsUpdatesFilter.supergroupEvents(): Flow<SupergroupEventMessage<*>> = messageFlow.mapNotNull {
it.data as? SupergroupEventMessage<*>
}
@RiskFeature("Use with caution")
inline fun <reified T: ChatEvent, reified O: ChatEventMessage<T>> Flow<ChatEventMessage<*>>.filterByChatEvent(): Flow<O> = mapNotNull {
if (it.chatEvent is T) it as? O else null
}
@RiskFeature("Use with caution")
inline fun <reified T : ChannelEvent> Flow<ChatEventMessage<*>>.filterChannelEvents() = filterByChatEvent<T, ChannelEventMessage<T>>()
@RiskFeature("Use with caution")
inline fun <reified T : ChannelEvent> FlowsUpdatesFilter.filterChannelEvents() = channelEvents().filterChannelEvents<T>()
inline fun Flow<ChatEventMessage<*>>.channelCreatedEvents() = filterChannelEvents<ChannelChatCreated>()
inline fun FlowsUpdatesFilter.channelCreatedEvents() = filterChannelEvents<ChannelChatCreated>()
inline fun Flow<ChatEventMessage<*>>.deletedChannelPhotoEvents() = filterChannelEvents<DeleteChatPhoto>()
inline fun FlowsUpdatesFilter.deletedChannelPhotoEvents() = filterChannelEvents<DeleteChatPhoto>()
inline fun Flow<ChatEventMessage<*>>.newChannelPhotoEvents() = filterChannelEvents<NewChatPhoto>()
inline fun FlowsUpdatesFilter.newChannelPhotoEvents() = filterChannelEvents<NewChatPhoto>()
inline fun Flow<ChatEventMessage<*>>.newChannelTitleEvents() = filterChannelEvents<NewChatTitle>()
inline fun FlowsUpdatesFilter.newChannelTitleEvents() = filterChannelEvents<NewChatTitle>()
inline fun Flow<ChatEventMessage<*>>.newChannelPinnedMessageEvents() = filterChannelEvents<PinnedMessage>()
inline fun FlowsUpdatesFilter.newChannelPinnedMessageEvents() = filterChannelEvents<PinnedMessage>()
inline fun Flow<ChatEventMessage<*>>.channelEvents() = filterChannelEvents<ChannelEvent>()
@RiskFeature("Use with caution")
inline fun <reified T : GroupEvent> Flow<ChatEventMessage<*>>.filterGroupEvents() = filterByChatEvent<T, GroupEventMessage<T>>()
@RiskFeature("Use with caution")
inline fun <reified T : GroupEvent> FlowsUpdatesFilter.filterGroupEvents() = groupEvents().filterByChatEvent<T, GroupEventMessage<T>>()
inline fun Flow<ChatEventMessage<*>>.groupCreatedEvents() = filterGroupEvents<GroupChatCreated>()
inline fun FlowsUpdatesFilter.groupCreatedEvents() = filterGroupEvents<GroupChatCreated>()
inline fun Flow<ChatEventMessage<*>>.deletedGroupPhotoEvents() = filterGroupEvents<DeleteChatPhoto>()
inline fun FlowsUpdatesFilter.deletedGroupPhotoEvents() = filterGroupEvents<DeleteChatPhoto>()
inline fun Flow<ChatEventMessage<*>>.newGroupMembersEvents() = filterGroupEvents<NewChatMembers>()
inline fun FlowsUpdatesFilter.newGroupMembersEvents() = filterGroupEvents<NewChatMembers>()
inline fun Flow<ChatEventMessage<*>>.leftGroupMemberEvents() = filterGroupEvents<LeftChatMember>()
inline fun FlowsUpdatesFilter.leftGroupMemberEvents() = filterGroupEvents<LeftChatMember>()
inline fun Flow<ChatEventMessage<*>>.newGroupPhotoEvents() = filterGroupEvents<NewChatPhoto>()
inline fun FlowsUpdatesFilter.newGroupPhotoEvents() = filterGroupEvents<NewChatPhoto>()
inline fun Flow<ChatEventMessage<*>>.newGroupTitleEvents() = filterGroupEvents<NewChatTitle>()
inline fun FlowsUpdatesFilter.newGroupTitleEvents() = filterGroupEvents<NewChatTitle>()
inline fun Flow<ChatEventMessage<*>>.newGroupPinnedMessageEvents() = filterGroupEvents<PinnedMessage>()
inline fun FlowsUpdatesFilter.newGroupPinnedMessageEvents() = filterGroupEvents<PinnedMessage>()
inline fun Flow<ChatEventMessage<*>>.proximityAlertTriggeredInGroupEvents() = filterGroupEvents<ProximityAlertTriggered>()
inline fun FlowsUpdatesFilter.proximityAlertTriggeredInGroupEvents() = filterGroupEvents<ProximityAlertTriggered>()
inline fun Flow<ChatEventMessage<*>>.groupEvents() = filterGroupEvents<GroupEvent>()
@RiskFeature("Use with caution")
inline fun <reified T : SupergroupEvent> Flow<ChatEventMessage<*>>.filterSupergroupEvents() = filterByChatEvent<T, SupergroupEventMessage<T>>()
@RiskFeature("Use with caution")
inline fun <reified T : SupergroupEvent> FlowsUpdatesFilter.filterSupergroupEvents() = supergroupEvents().filterByChatEvent<T, SupergroupEventMessage<T>>()
inline fun Flow<ChatEventMessage<*>>.supergroupCreatedEvents() = filterSupergroupEvents<SupergroupChatCreated>()
inline fun FlowsUpdatesFilter.supergroupCreatedEvents() = filterSupergroupEvents<SupergroupChatCreated>()
inline fun Flow<ChatEventMessage<*>>.deletedSupergroupPhotoEvents() = filterSupergroupEvents<DeleteChatPhoto>()
inline fun FlowsUpdatesFilter.deletedSupergroupPhotoEvents() = filterSupergroupEvents<DeleteChatPhoto>()
inline fun Flow<ChatEventMessage<*>>.newSupergroupMembersEvents() = filterSupergroupEvents<NewChatMembers>()
inline fun FlowsUpdatesFilter.newSupergroupMembersEvents() = filterSupergroupEvents<NewChatMembers>()
inline fun Flow<ChatEventMessage<*>>.leftSupergroupMemberEvents() = filterSupergroupEvents<LeftChatMember>()
inline fun FlowsUpdatesFilter.leftSupergroupMemberEvents() = filterSupergroupEvents<LeftChatMember>()
inline fun Flow<ChatEventMessage<*>>.newSupergroupPhotoEvents() = filterSupergroupEvents<NewChatPhoto>()
inline fun FlowsUpdatesFilter.newSupergroupPhotoEvents() = filterSupergroupEvents<NewChatPhoto>()
inline fun Flow<ChatEventMessage<*>>.newSupergroupTitleEvents() = filterSupergroupEvents<NewChatTitle>()
inline fun FlowsUpdatesFilter.newSupergroupTitleEvents() = filterSupergroupEvents<NewChatTitle>()
inline fun Flow<ChatEventMessage<*>>.newSupergroupPinnedMessageEvents() = filterSupergroupEvents<PinnedMessage>()
inline fun FlowsUpdatesFilter.newSupergroupPinnedMessageEvents() = filterSupergroupEvents<PinnedMessage>()
inline fun Flow<ChatEventMessage<*>>.proximityAlertTriggeredInSupergroupEvents() = filterSupergroupEvents<ProximityAlertTriggered>()
inline fun FlowsUpdatesFilter.proximityAlertTriggeredInSupergroupEvents() = filterSupergroupEvents<ProximityAlertTriggered>()
inline fun Flow<ChatEventMessage<*>>.supergroupEvents() = filterSupergroupEvents<SupergroupEvent>()

View File

@@ -19,12 +19,15 @@ fun <T : BaseSentMessageUpdate> Flow<T>.asCommonMessagesFlow() = mapNotNull {
it.data as? CommonMessage<*>
}
@Suppress("NOTHING_TO_INLINE")
inline fun <T : BaseSentMessageUpdate> Flow<T>.chatEvents() = mapNotNull {
it.data as? ChatEventMessage<*>
}
/**
* Will map incoming [BaseSentMessageUpdate]s to [ChatEventMessage] from [BaseSentMessageUpdate.data]
*/
fun <T : BaseSentMessageUpdate> Flow<T>.asChatEventsFlow() = mapNotNull {
it.data as? ChatEventMessage
}
@Deprecated("Renamed", ReplaceWith("chatEvents", "dev.inmo.tgbotapi.extensions.utils.updates.chatEvents"))
fun <T : BaseSentMessageUpdate> Flow<T>.asChatEventsFlow() = chatEvents()
/**
* Will map incoming [BaseSentMessageUpdate]s to [UnknownMessageType] from [BaseSentMessageUpdate.data]

View File

@@ -72,7 +72,6 @@ fun RequestsExecutor.startGettingOfUpdatesByLongPolling(
* [flowUpdatesPreset] lambda - it will be called BEFORE starting updates getting
*/
@FlowPreview
@PreviewFeature
@Suppress("unused")
fun RequestsExecutor.startGettingFlowsUpdatesByLongPolling(
timeoutSeconds: Seconds = 30,

View File

@@ -8,7 +8,6 @@ buildscript {
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version"
classpath "com.jfrog.bintray.gradle:gradle-bintray-plugin:$gradle_bintray_plugin_version"
}
}
@@ -40,15 +39,9 @@ kotlin {
commonMain {
dependencies {
implementation kotlin('stdlib')
if ((project.hasProperty('RELEASE_MODE') && project.property('RELEASE_MODE') == "true") || System.getenv('RELEASE_MODE') == "true") {
api "${project.group}:tgbotapi.core:$library_version"
api "${project.group}:tgbotapi.extensions.api:$library_version"
api "${project.group}:tgbotapi.extensions.utils:$library_version"
} else {
api project(":tgbotapi.core")
api project(":tgbotapi.extensions.api")
api project(":tgbotapi.extensions.utils")
}
api project(":tgbotapi.core")
api project(":tgbotapi.extensions.api")
api project(":tgbotapi.extensions.utils")
}
}
}

View File

@@ -1,53 +0,0 @@
apply plugin: 'maven-publish'
task javadocsJar(type: Jar) {
classifier = 'javadoc'
}
afterEvaluate {
project.publishing.publications.all {
// rename artifacts
groupId "${project.group}"
if (it.name.contains('kotlinMultiplatform')) {
artifactId = "${project.name}"
} else {
artifactId = "${project.name}-$name"
}
}
}
publishing {
publications.all {
artifact javadocsJar
pom {
description = "This project just include all subproject of TelegramBotAPI"
name = "Telegram Bot API"
url = "https://insanusmokrassar.github.io/TelegramBotAPI/TelegramBotAPI"
scm {
developerConnection = "scm:git:[fetch=]https://github.com/insanusmokrassar/TelegramBotAPI.git[push=]https://github.com/insanusmokrassar/TelegramBotAPI.git"
url = "https://github.com/insanusmokrassar/TelegramBotAPI.git"
}
developers {
developer {
id = "InsanusMokrassar"
name = "Ovsiannikov Aleksei"
email = "ovsyannikov.alexey95@gmail.com"
}
}
licenses {
license {
name = "Apache Software License 2.0"
url = "https://github.com/InsanusMokrassar/TelegramBotAPI/blob/master/LICENSE"
}
}
}
}
}

View File

@@ -1,59 +1,65 @@
apply plugin: 'com.jfrog.bintray'
apply plugin: 'maven-publish'
apply from: "maven.publish.gradle"
bintray {
user = project.hasProperty('BINTRAY_USER') ? project.property('BINTRAY_USER') : System.getenv('BINTRAY_USER')
key = project.hasProperty('BINTRAY_KEY') ? project.property('BINTRAY_KEY') : System.getenv('BINTRAY_KEY')
filesSpec {
from "${buildDir}/publications/"
eachFile {
String directorySubname = it.getFile().parentFile.name
if (it.getName() == "module.json") {
if (directorySubname == "kotlinMultiplatform") {
it.setPath("${project.name}/${project.version}/${project.name}-${project.version}.module")
} else {
it.setPath("${project.name}-${directorySubname}/${project.version}/${project.name}-${directorySubname}-${project.version}.module")
}
} else {
if (directorySubname == "kotlinMultiplatform" && it.getName() == "pom-default.xml") {
it.setPath("${project.name}/${project.version}/${project.name}-${project.version}.pom")
} else {
it.exclude()
}
}
}
into "${project.group}".replace(".", "/")
}
publish = true
override = true
pkg {
repo = "TelegramBotAPI"
name = "${project.name}"
vcsUrl = "https://github.com/InsanusMokrassar/TelegramBotAPI"
licenses = ["Apache-2.0"]
version {
name = "${project.version}"
released = new Date()
vcsTag = "${project.version}"
gpg {
sign = true
passphrase = project.hasProperty('signing.gnupg.passphrase') ? project.property('signing.gnupg.passphrase') : System.getenv('signing.gnupg.passphrase')
}
}
}
task javadocsJar(type: Jar) {
classifier = 'javadoc'
}
bintrayUpload.doFirst {
publications = publishing.publications.collect {
afterEvaluate {
project.publishing.publications.all {
// rename artifacts
groupId "${project.group}"
if (it.name.contains('kotlinMultiplatform')) {
null
artifactId = "${project.name}"
} else {
it.name
artifactId = "${project.name}-$name"
}
} - null
}
}
bintrayUpload.dependsOn publishToMavenLocal
publishing {
publications.all {
artifact javadocsJar
pom {
description = "This project just include all subproject of TelegramBotAPI"
name = "Telegram Bot API"
url = "https://insanusmokrassar.github.io/TelegramBotAPI/TelegramBotAPI"
scm {
developerConnection = "scm:git:[fetch=]https://github.com/insanusmokrassar/TelegramBotAPI.git[push=]https://github.com/insanusmokrassar/TelegramBotAPI.git"
url = "https://github.com/insanusmokrassar/TelegramBotAPI.git"
}
developers {
developer {
id = "InsanusMokrassar"
name = "Ovsiannikov Aleksei"
email = "ovsyannikov.alexey95@gmail.com"
}
}
licenses {
license {
name = "Apache Software License 2.0"
url = "https://github.com/InsanusMokrassar/TelegramBotAPI/blob/master/LICENSE"
}
}
}
repositories {
maven {
name = "bintray"
url = uri("https://api.bintray.com/maven/${project.hasProperty('BINTRAY_USER') ? project.property('BINTRAY_USER') : System.getenv('BINTRAY_USER')}/TelegramBotAPI/${project.name}/;publish=1;override=1")
credentials {
username = project.hasProperty('BINTRAY_USER') ? project.property('BINTRAY_USER') : System.getenv('BINTRAY_USER')
password = project.hasProperty('BINTRAY_KEY') ? project.property('BINTRAY_KEY') : System.getenv('BINTRAY_KEY')
}
}
}
}
}