Compare commits

...

80 Commits

Author SHA1 Message Date
Renovate Bot
6bf6f3e54e Update kotlin_version to v1.6.21 2022-05-07 18:53:56 +00:00
b740203116 0.38.23 2022-05-08 00:41:13 +06:00
149717301d Update gradle.properties 2022-05-05 15:16:24 +06:00
60e72be844 Merge pull request #103 from InsanusMokrassar/0.38.21
0.38.21
2022-05-04 14:54:45 +06:00
831b558724 fixes 2022-05-04 13:27:39 +06:00
df778b4e93 start migration onto 0.38.20 2022-05-04 12:22:49 +06:00
bf0c6497fe Merge pull request #101 from Akkihi/master
sendData does not work with inlineKeyboard
2022-05-03 23:57:07 +06:00
akkkihi
71a047f867 sendData does not work with inlineKeyboard 2022-05-03 17:55:08 +04:00
2ae3e1165d Update gradle.properties 2022-05-03 15:55:27 +06:00
9a5d02512b Update gradle.properties 2022-05-02 14:28:05 +06:00
dd2c528006 Update gradle.properties 2022-05-01 18:42:09 +06:00
1c16a9f868 Create README.md 2022-04-30 08:47:35 +06:00
00c3aba12b Merge pull request #97 from InsanusMokrassar/0.38.16
0.38.16
2022-04-30 08:40:17 +06:00
a547bbce65 Merge branch 'master' into 0.38.16 2022-04-30 08:39:01 +06:00
0b7d8c087f update tgbotapi and add webapps example 2022-04-29 20:57:16 +06:00
8ec282e3d5 Merge pull request #96 from InsanusMokrassar/renovate/telegram_bot_api_version
Update dependency dev.inmo:tgbotapi to v0.38.15
2022-04-26 15:48:10 +06:00
Renovate Bot
e8433cd8ac Update dependency dev.inmo:tgbotapi to v0.38.15 2022-04-26 09:46:32 +00:00
222134836a update up to 0.38.13 2022-04-17 00:26:04 +06:00
c18e02dcb3 Merge pull request #94 from InsanusMokrassar/0.38.12
Add keyboards and update tgbotapi up to 0.38.12
2022-04-16 23:52:43 +06:00
f9050061d1 add keyboards and update tgbotapi up to 0.38.12 2022-04-09 12:20:35 +06:00
a3e3f6c22c Update gradle.properties 2022-03-30 07:54:57 +06:00
516cc7bfcb Merge pull request #89 from InsanusMokrassar/0.38.10
Update up to 0.38.10
2022-03-25 21:26:18 +06:00
c707a11b66 update gradle 2022-03-24 16:53:32 +06:00
c6c418c393 update up to 0.38.10 2022-03-24 16:52:13 +06:00
e0795c3c14 update up to 0.38.8 2022-03-21 11:25:59 +06:00
dec55990dc Merge pull request #87 from InsanusMokrassar/renovate/telegram_bot_api_version
Update dependency dev.inmo:tgbotapi to v0.38.7
2022-03-12 22:59:42 +06:00
Renovate Bot
169f3f5bd5 Update dependency dev.inmo:tgbotapi to v0.38.7 2022-03-12 16:26:32 +00:00
e175bb6143 Update gradle-wrapper.properties 2022-02-28 09:07:15 +06:00
290d722ae6 Update gradle.properties 2022-02-28 09:06:50 +06:00
9ee85df1ad Merge pull request #85 from InsanusMokrassar/renovate/telegram_bot_api_version
Update dependency dev.inmo:tgbotapi to v0.38.6
2022-02-28 09:06:20 +06:00
Renovate Bot
2953c40963 Update dependency dev.inmo:tgbotapi to v0.38.6 2022-02-28 03:04:39 +00:00
512067b056 Merge pull request #84 from InsanusMokrassar/renovate/telegram_bot_api_version
Update dependency dev.inmo:tgbotapi to v0.38.5
2022-02-12 12:55:49 +06:00
Renovate Bot
0cb209dc6e Update dependency dev.inmo:tgbotapi to v0.38.5 2022-02-09 11:00:15 +00:00
7cf6814d89 update up to 0.38.4 2022-02-02 13:30:32 +06:00
09e8492439 Merge pull request #82 from InsanusMokrassar/renovate/telegram_bot_api_version
Update dependency dev.inmo:tgbotapi to v0.38.3
2022-01-14 23:19:51 +06:00
Renovate Bot
71222f42e5 Update dependency dev.inmo:tgbotapi to v0.38.3 2022-01-14 17:18:46 +00:00
426d649877 Merge pull request #81 from InsanusMokrassar/renovate/telegram_bot_api_version
Update dependency dev.inmo:tgbotapi to v0.38.2
2022-01-12 01:26:24 +06:00
Renovate Bot
93faf9654a Update dependency dev.inmo:tgbotapi to v0.38.2 2022-01-11 16:19:57 +00:00
288386e25a Update gradle.properties 2022-01-11 20:19:49 +06:00
99e83589a4 Merge pull request #80 from InsanusMokrassar/renovate/telegram_bot_api_version
Update dependency dev.inmo:tgbotapi to v0.38.1
2022-01-07 15:51:02 +06:00
Renovate Bot
fbea95fc0a Update dependency dev.inmo:tgbotapi to v0.38.1 2022-01-07 09:31:59 +00:00
0edaa28151 several small updates 2022-01-02 12:06:32 +06:00
df874b0783 update up to 0.38.0 2022-01-02 01:06:04 +06:00
5f5722398d update up to 0.37.3 2021-12-20 14:13:55 +06:00
cc29ec75ca Merge pull request #76 from InsanusMokrassar/renovate/telegram_bot_api_version
Update dependency dev.inmo:tgbotapi to v0.37.1
2021-11-15 09:57:36 +06:00
Renovate Bot
a42173acf6 Update dependency dev.inmo:tgbotapi to v0.37.1 2021-11-14 15:41:13 +00:00
d936bc4643 upgrade up to 0.37.0 2021-11-11 12:34:52 +06:00
1b340d8db5 Merge pull request #74 from InsanusMokrassar/renovate/telegram_bot_api_version
Update dependency dev.inmo:tgbotapi to v0.36.1
2021-10-24 11:52:00 +06:00
Renovate Bot
4cd1980778 Update dependency dev.inmo:tgbotapi to v0.36.1 2021-10-24 05:26:22 +00:00
d89202aebb update up to 0.36.0 2021-10-18 20:21:58 +06:00
be2de6e372 Merge pull request #71 from InsanusMokrassar/renovate/micro_utils_version
Update dependency dev.inmo:micro_utils.fsm.common to v0.5.31
2021-10-01 20:30:11 +06:00
Renovate Bot
08796f18e8 Update dependency dev.inmo:micro_utils.fsm.common to v0.5.31 2021-10-01 14:28:11 +00:00
8bd7e116e3 Merge pull request #70 from InsanusMokrassar/renovate/micro_utils_version
Update dependency dev.inmo:micro_utils.fsm.common to v0.5.30
2021-09-25 18:12:40 +06:00
Renovate Bot
39d7a95c95 Update dependency dev.inmo:micro_utils.fsm.common to v0.5.30 2021-09-25 12:11:44 +00:00
526ecac89a Merge pull request #68 from InsanusMokrassar/renovate/micro_utils_version
Update dependency dev.inmo:micro_utils.fsm.common to v0.5.29
2021-09-23 17:35:05 +06:00
Renovate Bot
1e4e246fab Update dependency dev.inmo:micro_utils.fsm.common to v0.5.29 2021-09-23 10:02:04 +00:00
6aa7fe151e update up to 0.35.9 2021-09-21 23:22:13 +06:00
16c27fa493 Merge pull request #67 from InsanusMokrassar/renovate/micro_utils_version
Update dependency dev.inmo:micro_utils.fsm.common to v0.5.26
2021-09-09 17:32:00 +06:00
Renovate Bot
f6a811acca Update dependency dev.inmo:micro_utils.fsm.common to v0.5.26 2021-09-09 11:26:29 +00:00
17c08fc906 Update RandomFileSenderBot.kt 2021-09-09 09:20:17 +06:00
aee0943a5e update dependencies and RandomFileSenderBot example 2021-09-08 23:00:19 +06:00
c07f4f2ed1 Update gradle-wrapper.properties 2021-09-05 09:23:25 +06:00
817acb8faf Update gradle.properties 2021-09-05 09:23:00 +06:00
8b294a0cc0 Merge pull request #66 from InsanusMokrassar/renovate/telegram_bot_api_version
Update dependency dev.inmo:tgbotapi to v0.35.7
2021-09-05 09:22:26 +06:00
Renovate Bot
0139cc5dcc Update dependency dev.inmo:tgbotapi to v0.35.7 2021-09-04 12:47:15 +00:00
6d16508277 small actualizations 2021-08-25 15:58:27 +06:00
ce2051d32d Update gradle.properties 2021-08-25 15:52:00 +06:00
1abbcc8789 Update gradle.properties 2021-08-17 09:23:50 +06:00
c5e05dfce1 Update gradle.properties 2021-08-13 22:24:44 +06:00
c1d7129af8 update dependencies 2021-08-09 17:39:04 +06:00
496fc45d2d tgbotapi -> 0.35.3 2021-08-08 20:32:26 +06:00
cdb634e91a Update gradle-wrapper.properties 2021-07-30 13:14:55 +06:00
9d17311918 Update dependencies 2021-07-30 13:14:14 +06:00
12ef88c757 Merge pull request #56 from InsanusMokrassar/0.35.1
0.35.1
2021-06-30 20:42:03 +06:00
4435fdc80c Merge branch 'master' into 0.35.1 2021-06-30 20:28:22 +06:00
cd9eba0393 Update gradle.properties 2021-06-30 20:25:08 +06:00
ef74b33d68 fix main in FSMBot 2021-06-30 13:50:08 +06:00
522d1b55ba add example with oneof and fsm 2021-06-30 13:12:15 +06:00
d062ab86ae update up to 0.35.1 2021-06-28 01:14:16 +06:00
48292ecf72 Merge pull request #54 from InsanusMokrassar/tgbotapi/0.35.0
tgbotapi 0.35.0
2021-06-13 10:08:19 +06:00
33 changed files with 741 additions and 151 deletions

2
.gitignore vendored
View File

@@ -8,3 +8,5 @@ settings.xml
.gradle/
build/
out/
kotlin-js-store/

View File

@@ -1,11 +0,0 @@
language: java
install: true
os: linux
dist: trusty
jdk: oraclejdk8
script:
- ./gradlew build -s

10
FSMBot/README.md Normal file
View File

@@ -0,0 +1,10 @@
# FSM
This bot contains an example of working with FSM included in project
[MicroUtils](https://github.com/InsanusMokrassar/MicroUtils)
## Launch
```bash
../gradlew run --args="BOT_TOKEN"
```

26
FSMBot/build.gradle Normal file
View File

@@ -0,0 +1,26 @@
buildscript {
repositories {
mavenLocal()
mavenCentral()
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
apply plugin: 'kotlin'
apply plugin: 'application'
mainClassName="SimpleFSMBotKt"
repositories {
mavenLocal()
mavenCentral()
}
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation "dev.inmo:tgbotapi:$telegram_bot_api_version"
}

View File

@@ -0,0 +1,50 @@
import dev.inmo.micro_utils.fsm.common.State
import dev.inmo.tgbotapi.extensions.api.send.sendMessage
import dev.inmo.tgbotapi.extensions.behaviour_builder.*
import dev.inmo.tgbotapi.extensions.behaviour_builder.expectations.*
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.*
import dev.inmo.tgbotapi.extensions.utils.extensions.parseCommandsWithParams
import dev.inmo.tgbotapi.extensions.utils.formatting.*
import dev.inmo.tgbotapi.types.ChatId
import dev.inmo.tgbotapi.types.message.abstracts.CommonMessage
import dev.inmo.tgbotapi.types.message.content.TextContent
import kotlinx.coroutines.*
sealed interface BotState : State
data class ExpectContentOrStopState(override val context: ChatId, val sourceMessage: CommonMessage<TextContent>) : BotState
data class StopState(override val context: ChatId) : BotState
suspend fun main(args: Array<String>) {
val botToken = args.first()
telegramBotWithBehaviourAndFSMAndStartLongPolling<BotState>(botToken, CoroutineScope(Dispatchers.IO)) {
strictlyOn<ExpectContentOrStopState> {
sendMessage(
it.context,
buildEntities {
+"Send me some content or " + botCommand("stop") + " if you want to stop sending"
}
)
val contentMessage = waitContentMessage().first()
val content = contentMessage.content
when {
content is TextContent && content.parseCommandsWithParams().keys.contains("stop") -> StopState(it.context)
else -> {
execute(content.createResend(it.context))
it
}
}
}
strictlyOn<StopState> {
sendMessage(it.context, "You have stopped sending of content")
null
}
command("start") {
startChain(ExpectContentOrStopState(it.chat.id, it))
}
}.second.join()
}

View File

@@ -1,6 +1,6 @@
buildscript {
repositories {
jcenter()
mavenCentral()
}
dependencies {
@@ -14,7 +14,7 @@ apply plugin: 'application'
mainClassName="FilesLoaderBotKt"
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation "dev.inmo:tgbotapi:$telegram_bot_api_version"
}

View File

@@ -1,14 +1,13 @@
import dev.inmo.micro_utils.coroutines.safely
import dev.inmo.tgbotapi.bot.Ktor.telegramBot
import dev.inmo.tgbotapi.extensions.api.downloadFile
import dev.inmo.tgbotapi.extensions.api.files.downloadFile
import dev.inmo.tgbotapi.extensions.api.get.getFileAdditionalInfo
import dev.inmo.tgbotapi.extensions.utils.flatMap
import dev.inmo.tgbotapi.extensions.utils.shortcuts.*
import dev.inmo.tgbotapi.extensions.utils.updates.retrieving.longPolling
import dev.inmo.tgbotapi.types.message.content.abstracts.MediaContent
import dev.inmo.tgbotapi.extensions.api.send.reply
import dev.inmo.tgbotapi.extensions.behaviour_builder.telegramBotWithBehaviour
import dev.inmo.tgbotapi.extensions.behaviour_builder.telegramBotWithBehaviourAndLongPolling
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onContentMessage
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onMedia
import dev.inmo.tgbotapi.utils.filenameFromUrl
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import java.io.File
/**
@@ -19,24 +18,15 @@ suspend fun main(args: Array<String>) {
val directoryOrFile = args.getOrNull(1) ?.let { File(it) } ?: File("")
directoryOrFile.mkdirs()
val bot = telegramBot(botToken)
val scope = CoroutineScope(Dispatchers.Default)
bot.longPolling(scope = scope) {
val flow = merge (
filterContentMessages<MediaContent>(),
mediaGroupMessages().flatMap()
)
flow.onEach {
safely({ it.printStackTrace() }) {
val pathedFile = bot.getFileAdditionalInfo(it.content.media)
File(directoryOrFile, pathedFile.filePath.filenameFromUrl).apply {
createNewFile()
writeBytes(bot.downloadFile(pathedFile))
}
telegramBotWithBehaviourAndLongPolling(botToken, CoroutineScope(Dispatchers.IO)) {
onMedia(initialFilter = null) {
val pathedFile = bot.getFileAdditionalInfo(it.content.media)
val file = File(directoryOrFile, pathedFile.filePath.filenameFromUrl).apply {
createNewFile()
writeBytes(bot.downloadFile(pathedFile))
}
}.launchIn(scope)
}
scope.coroutineContext[Job]!!.join()
reply(it, "Saved to ${file.absolutePath}")
}
onContentMessage { println(it) }
}.second.join()
}

View File

@@ -1,6 +1,6 @@
buildscript {
repositories {
jcenter()
mavenCentral()
}
dependencies {
@@ -15,7 +15,7 @@ mainClassName="ForwardInfoSenderBotKt"
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation "dev.inmo:tgbotapi:$telegram_bot_api_version"
}

View File

@@ -1,17 +1,10 @@
import dev.inmo.micro_utils.coroutines.safely
import dev.inmo.tgbotapi.bot.Ktor.telegramBot
import dev.inmo.tgbotapi.extensions.api.send.sendTextMessage
import dev.inmo.tgbotapi.extensions.api.telegramBot
import dev.inmo.tgbotapi.extensions.utils.*
import dev.inmo.tgbotapi.extensions.utils.formatting.codeMarkdownV2
import dev.inmo.tgbotapi.extensions.utils.formatting.regularMarkdownV2
import dev.inmo.tgbotapi.extensions.utils.shortcuts.mediaGroupMessages
import dev.inmo.tgbotapi.extensions.utils.updates.asContentMessagesFlow
import dev.inmo.tgbotapi.extensions.utils.updates.retrieving.longPolling
import dev.inmo.tgbotapi.types.ParseMode.MarkdownV2
import dev.inmo.tgbotapi.extensions.api.send.reply
import dev.inmo.tgbotapi.extensions.behaviour_builder.telegramBotWithBehaviourAndLongPolling
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onContentMessage
import dev.inmo.tgbotapi.extensions.utils.formatting.*
import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.message.*
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
/**
* This bot will always return message about forwarder. In cases when sent message was not a forward message it will
@@ -20,26 +13,29 @@ import kotlinx.coroutines.flow.*
suspend fun main(vararg args: String) {
val botToken = args.first()
val bot = telegramBot(botToken)
val scope = CoroutineScope(Dispatchers.Default)
bot.longPolling(scope = scope) {
(merge(messageFlow.asContentMessagesFlow(), mediaGroupMessages(scope).flatMap())).mapNotNull { it.asPossiblyForwardedMessage() }.onEach { message ->
safely({ it.printStackTrace() }) {
val toAnswer = when (val forwardInfo = message.forwardInfo) {
null -> "There is no forward info"
is AnonymousForwardInfo -> "Anonymous user which signed as \"${forwardInfo.senderName.codeMarkdownV2()}\""
is UserForwardInfo -> forwardInfo.from.let { user ->
"User ${user.id.chatId.toString().codeMarkdownV2()} " + "(${user.firstName} ${user.lastName}: ${user.username ?.username ?: "Without username"})".regularMarkdownV2()
telegramBotWithBehaviourAndLongPolling(botToken, CoroutineScope(Dispatchers.IO)) {
onContentMessage(subcontextUpdatesFilter = { _, _ -> true }) {
val toAnswer = buildEntities {
when (val forwardInfo = it.forwardInfo) {
null -> +"There is no forward info"
is AnonymousForwardInfo -> {
regular("Anonymous user which signed as \"") + code(forwardInfo.senderName) + "\""
}
is ForwardFromChannelInfo -> "Channel (".regularMarkdownV2() + (forwardInfo.channelChat).title.codeMarkdownV2() + ")".regularMarkdownV2()
is ForwardFromSupergroupInfo -> "Supergroup (".regularMarkdownV2() + (forwardInfo.group).title.codeMarkdownV2() + ")".regularMarkdownV2()
is UserForwardInfo -> {
val user = forwardInfo.from
when (user) {
is CommonUser -> regular("User ")
is CommonBot,
is ExtendedBot -> regular("Bot ")
} + code(user.id.chatId.toString()) + " (${user.firstName} ${user.lastName}: ${user.username ?.username ?: "Without username"})"
}
is ForwardFromChannelInfo -> regular("Channel (") + code((forwardInfo.channelChat).title) + ")"
is ForwardFromSupergroupInfo -> regular("Supergroup (") + code((forwardInfo.group).title) + ")"
}
bot.sendTextMessage(message.chat, toAnswer, MarkdownV2)
}
}.launchIn(scope)
}
scope.coroutineContext[Job]!!.join()
reply(it, toAnswer)
coroutineContext.job.invokeOnCompletion { println("completance of onContentMessage") }
}
coroutineContext.job.invokeOnCompletion { println("Completed :)") }
}.second.join()
}

View File

@@ -1,6 +1,6 @@
buildscript {
repositories {
jcenter()
mavenCentral()
}
dependencies {
@@ -15,7 +15,7 @@ mainClassName="HelloBotKt"
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation "dev.inmo:tgbotapi:$telegram_bot_api_version"
}

View File

@@ -1,6 +1,6 @@
buildscript {
repositories {
jcenter()
mavenCentral()
}
dependencies {
@@ -15,7 +15,7 @@ mainClassName="HelloBotKt"
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation "dev.inmo:tgbotapi:$telegram_bot_api_version"
}

View File

@@ -1,19 +1,16 @@
import dev.inmo.micro_utils.coroutines.safely
import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions
import dev.inmo.tgbotapi.extensions.api.chat.get.getChat
import dev.inmo.tgbotapi.extensions.api.send.reply
import dev.inmo.tgbotapi.extensions.api.send.sendTextMessage
import dev.inmo.tgbotapi.bot.Ktor.telegramBot
import dev.inmo.tgbotapi.extensions.utils.asChannelChat
import dev.inmo.tgbotapi.extensions.behaviour_builder.telegramBotWithBehaviourAndLongPolling
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onContentMessage
import dev.inmo.tgbotapi.extensions.utils.formatting.linkMarkdownV2
import dev.inmo.tgbotapi.extensions.utils.formatting.textMentionMarkdownV2
import dev.inmo.tgbotapi.extensions.utils.updates.retrieving.longPolling
import dev.inmo.tgbotapi.types.ParseMode.MarkdownV2
import dev.inmo.tgbotapi.types.User
import dev.inmo.tgbotapi.types.chat.abstracts.*
import dev.inmo.tgbotapi.utils.extensions.escapeMarkdownV2Common
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
/**
* The main purpose of this bot is just to answer "Oh, hi, " and add user mention here
@@ -21,41 +18,31 @@ import kotlinx.coroutines.flow.onEach
suspend fun main(vararg args: String) {
val botToken = args.first()
val bot = telegramBot(botToken)
val scope = CoroutineScope(Dispatchers.Default)
bot.longPolling(scope = scope) {
messageFlow.onEach {
safely {
val message = it.data
val chat = message.chat
val answerText = "Oh, hi, " + when (chat) {
is PrivateChat -> "${chat.firstName} ${chat.lastName}".textMentionMarkdownV2(chat.id)
is User -> "${chat.firstName} ${chat.lastName}".textMentionMarkdownV2(chat.id)
is SupergroupChat -> (chat.username ?.username ?: bot.getChat(chat).inviteLink) ?.let {
chat.title.linkMarkdownV2(it)
} ?: chat.title
is GroupChat -> bot.getChat(chat).inviteLink ?.let {
chat.title.linkMarkdownV2(it)
} ?: chat.title
else -> "Unknown :(".escapeMarkdownV2Common()
}
bot.reply(
message,
answerText,
MarkdownV2
)
telegramBotWithBehaviourAndLongPolling(botToken, CoroutineScope(Dispatchers.IO)) {
onContentMessage { message ->
val chat = message.chat
if (chat is ChannelChat) {
val answer = "Hi everybody in this channel \"${chat.title}\""
sendTextMessage(chat, answer, MarkdownV2)
return@onContentMessage
}
}.launchIn(scope)
channelPostFlow.onEach {
safely {
val chat = it.data.chat
val message = "Hi everybody in this channel \"${(chat.asChannelChat()) ?.title}\""
bot.sendTextMessage(chat, message, MarkdownV2)
val answerText = "Oh, hi, " + when (chat) {
is PrivateChat -> "${chat.firstName} ${chat.lastName}".textMentionMarkdownV2(chat.id)
is User -> "${chat.firstName} ${chat.lastName}".textMentionMarkdownV2(chat.id)
is SupergroupChat -> (chat.username ?.username ?: getChat(chat).inviteLink) ?.let {
chat.title.linkMarkdownV2(it)
} ?: chat.title
is GroupChat -> bot.getChat(chat).inviteLink ?.let {
chat.title.linkMarkdownV2(it)
} ?: chat.title
else -> "Unknown :(".escapeMarkdownV2Common()
}
}.launchIn(scope)
}
scope.coroutineContext[Job]!!.join()
}
reply(
message,
answerText,
MarkdownV2
)
}
allUpdatesFlow.subscribeSafelyWithoutExceptions(this) { println(it) }
}.second.join()
}

View File

@@ -0,0 +1,32 @@
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
plugins {
id "org.jetbrains.kotlin.multiplatform" version "$kotlin_version"
}
kotlin {
jvm()
js(IR) {
browser()
binaries.executable()
}
sourceSets {
commonMain {
dependencies {
implementation kotlin('stdlib')
api "dev.inmo:tgbotapi:$telegram_bot_api_version"
}
}
}
}

View File

@@ -0,0 +1,107 @@
import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions
import dev.inmo.tgbotapi.extensions.api.bot.getMe
import dev.inmo.tgbotapi.bot.Ktor.telegramBot
import dev.inmo.tgbotapi.extensions.api.answers.answer
import dev.inmo.tgbotapi.extensions.api.edit.text.editMessageText
import dev.inmo.tgbotapi.extensions.api.send.*
import dev.inmo.tgbotapi.extensions.api.send.media.*
import dev.inmo.tgbotapi.extensions.behaviour_builder.*
import dev.inmo.tgbotapi.extensions.behaviour_builder.filters.CommonMessageFilterExcludeMediaGroups
import dev.inmo.tgbotapi.extensions.behaviour_builder.filters.MessageFilterByChat
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.*
import dev.inmo.tgbotapi.extensions.utils.shortcuts.*
import dev.inmo.tgbotapi.extensions.utils.types.buttons.*
import dev.inmo.tgbotapi.extensions.utils.withContent
import dev.inmo.tgbotapi.types.message.content.TextContent
import kotlinx.coroutines.*
private const val nextPageData = "next"
private const val previousPageData = "previous"
fun String.parsePageAndCount(): Pair<Int, Int>? {
val (pageString, countString) = split(" ").takeIf { it.count() > 1 } ?: return null
return Pair(
pageString.toIntOrNull() ?: return null,
countString.toIntOrNull() ?: return null
)
}
fun InlineKeyboardBuilder.includePageButtons(page: Int, count: Int) {
val numericButtons = listOfNotNull(
page - 1,
page,
page + 1,
)
row {
val numbersRange = 1 .. count
numericButtons.forEach {
if (it in numbersRange) {
dataButton(it.toString(), "$it $count")
}
}
}
row {
if (page - 1 > 2) {
dataButton("<<", "1 $count")
}
if (page - 1 > 1) {
dataButton("<", "${page - 2} $count")
}
if (page + 1 < count) {
dataButton(">", "${page + 2} $count")
}
if (page + 2 < count) {
dataButton(">>", "$count $count")
}
}
}
suspend fun activateKeyboardsBot(
token: String,
print: (Any) -> Unit
) {
val bot = telegramBot(token)
print(bot.getMe())
bot.buildBehaviourWithLongPolling(CoroutineScope(currentCoroutineContext() + SupervisorJob())) {
onCommandWithArgs("inline") { message, args ->
val numberOfPages = args.firstOrNull() ?.toIntOrNull() ?: 10
reply(
message,
"Your inline keyboard with $numberOfPages pages",
replyMarkup = inlineKeyboard {
row {
includePageButtons(1, numberOfPages)
}
}
)
}
onMessageDataCallbackQuery {
val (page, count) = it.data.parsePageAndCount() ?: it.let {
answer(it, "Unsupported data :(")
return@onMessageDataCallbackQuery
}
editMessageText(
it.message.withContent<TextContent>() ?: it.let {
answer(it, "Unsupported message type :(")
return@onMessageDataCallbackQuery
},
"This is $page of $count",
replyMarkup = inlineKeyboard {
row {
includePageButtons(page, count)
}
}
)
}
allUpdatesFlow.subscribeSafelyWithoutExceptions(this) {
println(it)
}
}.join()
}

View File

@@ -0,0 +1,32 @@
import kotlinx.browser.document
import kotlinx.coroutines.*
import org.w3c.dom.*
private val scope = CoroutineScope(Dispatchers.Default)
fun main() {
document.addEventListener(
"DOMContentLoaded",
{
val botsContainer = document.getElementById("bots_container") ?: return@addEventListener
(document.getElementById("bot_token_form") as? HTMLFormElement) ?.onsubmit = {
(document.getElementById("bot_token") as? HTMLInputElement) ?.value ?.let { token ->
val botContainer = document.createElement("div") as HTMLDivElement
botsContainer.append(botContainer)
val infoDiv = document.createElement("div") as HTMLDivElement
botContainer.append(infoDiv)
scope.launch {
activateKeyboardsBot(token) {
infoDiv.innerHTML = it.toString()
}
}
}
false
}
}
)
}

View File

@@ -0,0 +1,16 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Keyboards bot</title>
</head>
<body>
<form id="bot_token_form">
<input type="text" id="bot_token">
<input type="submit" value="Start bot">
</form>
<div id="start_offer">Type your bot token to the input above to start its work</div>
<script type="text/javascript" src="KeyboardsBotLib.js"></script>
<div id="bots_container"></div>
</body>
</html>

View File

@@ -0,0 +1,21 @@
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
apply plugin: 'kotlin'
apply plugin: 'application'
mainClassName="KeyboardsBotJvmKt"
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation project(":KeyboardsBot:KeyboardsBotLib")
}

View File

@@ -0,0 +1,10 @@
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
suspend fun main(args: Array<String>) {
withContext(Dispatchers.IO) { // IO for inheriting of it in side of activateKeyboardsBot
activateKeyboardsBot(args.first()) {
println(it)
}
}
}

View File

@@ -1,6 +1,6 @@
buildscript {
repositories {
jcenter()
mavenCentral()
}
dependencies {
@@ -15,7 +15,7 @@ mainClassName="RandomFileSenderBotKt"
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation "dev.inmo:tgbotapi:$telegram_bot_api_version"
}

View File

@@ -1,19 +1,33 @@
import dev.inmo.tgbotapi.bot.Ktor.telegramBot
import dev.inmo.tgbotapi.bot.TelegramBot
import dev.inmo.tgbotapi.extensions.api.bot.getMe
import dev.inmo.tgbotapi.extensions.api.bot.setMyCommands
import dev.inmo.tgbotapi.extensions.api.send.media.sendDocument
import dev.inmo.tgbotapi.extensions.api.send.media.sendDocumentsGroup
import dev.inmo.tgbotapi.extensions.api.send.reply
import dev.inmo.tgbotapi.extensions.api.send.withUploadDocumentAction
import dev.inmo.tgbotapi.extensions.behaviour_builder.buildBehaviour
import dev.inmo.tgbotapi.extensions.behaviour_builder.buildBehaviourWithLongPolling
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onCommand
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onCommandWithArgs
import dev.inmo.tgbotapi.requests.abstracts.asMultipartFile
import dev.inmo.tgbotapi.requests.abstracts.toInputFile
import dev.inmo.tgbotapi.types.BotCommand
import dev.inmo.tgbotapi.types.InputMedia.DocumentMediaGroupMemberInputMedia
import dev.inmo.tgbotapi.types.InputMedia.InputMediaDocument
import dev.inmo.tgbotapi.types.chat.abstracts.Chat
import dev.inmo.tgbotapi.types.mediaCountInMediaGroup
import kotlinx.coroutines.*
import java.io.File
private const val command = "send_file"
/**
* This bot will send files inside of working directory OR from directory in the second argument
* This bot will send files inside of working directory OR from directory in the second argument.
* You may send /send_file command to this bot to get random file from the directory OR
* `/send_file $number` when you want to receive required number of files. For example,
* /send_file and `/send_file 1` will have the same effect - bot will send one random file.
* But if you will send `/send_file 5` it will choose 5 random files and send them as group
*/
suspend fun main(args: Array<String>) {
val botToken = args.first()
@@ -23,25 +37,63 @@ suspend fun main(args: Array<String>) {
if (currentRoot.isFile) {
return currentRoot
} else {
return pickFile(currentRoot.listFiles() ?.random() ?: return null)
return pickFile(currentRoot.listFiles() ?.takeIf { it.isNotEmpty() } ?.random() ?: return null)
}
}
suspend fun TelegramBot.sendFiles(chat: Chat, files: List<File>) {
when (files.size) {
1 -> sendDocument(
chat.id,
files.first().asMultipartFile(),
protectContent = true
)
else -> sendDocumentsGroup(
chat,
files.map { InputMediaDocument(it.asMultipartFile()) },
protectContent = true
)
}
}
val bot = telegramBot(botToken)
val scope = CoroutineScope(Dispatchers.Default)
bot.buildBehaviour(scope) {
onCommand(command.toRegex()) { message ->
pickFile() ?.let {
bot.sendDocument(
message.chat.id,
it.toInputFile()
)
} ?: bot.reply(message, "Nothing selected :(")
bot.buildBehaviourWithLongPolling (defaultExceptionsHandler = { it.printStackTrace() }) {
onCommandWithArgs(command) { message, args ->
withUploadDocumentAction(message.chat) {
val count = args.firstOrNull() ?.toIntOrNull() ?: 1
var sent = false
var left = count
val chosen = mutableListOf<File>()
while (left > 0) {
left--
val picked = pickFile() ?: continue
chosen.add(picked)
if (chosen.size >= mediaCountInMediaGroup.last) {
sendFiles(message.chat, chosen)
chosen.clear()
sent = true
}
}
if (chosen.isNotEmpty()) {
sendFiles(message.chat, chosen)
sent = true
}
if (!sent) {
bot.reply(message, "Nothing selected :(")
}
}
}
setMyCommands(
BotCommand(command, "Send some random file in picker directory")
)
println(getMe())
}.join()
}

View File

@@ -1,6 +1,6 @@
buildscript {
repositories {
jcenter()
mavenCentral()
}
dependencies {

View File

@@ -1,12 +1,15 @@
import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions
import dev.inmo.tgbotapi.extensions.api.bot.getMe
import dev.inmo.tgbotapi.bot.Ktor.telegramBot
import dev.inmo.tgbotapi.extensions.api.send.*
import dev.inmo.tgbotapi.extensions.api.send.media.*
import dev.inmo.tgbotapi.extensions.behaviour_builder.*
import dev.inmo.tgbotapi.extensions.behaviour_builder.filters.CommonMessageFilterExcludeMediaGroups
import dev.inmo.tgbotapi.extensions.behaviour_builder.filters.MessageFilterByChat
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.*
import dev.inmo.tgbotapi.extensions.utils.shortcuts.*
import dev.inmo.tgbotapi.types.message.abstracts.MediaGroupMessage
import dev.inmo.tgbotapi.types.message.abstracts.Message
import kotlinx.coroutines.*
import kotlin.coroutines.coroutineContext
suspend fun activateResenderBot(
token: String,
@@ -16,20 +19,37 @@ suspend fun activateResenderBot(
print(bot.getMe())
bot.buildBehaviour(CoroutineScope(coroutineContext + SupervisorJob())) {
bot.buildBehaviourWithLongPolling(CoroutineScope(currentCoroutineContext() + SupervisorJob())) {
onContentMessage(
additionalFilter = { it !is MediaGroupMessage<*> }
initialFilter = CommonMessageFilterExcludeMediaGroups,
subcontextUpdatesFilter = MessageFilterByChat
) {
executeUnsafe(it.content.createResend(it.chat.id, replyToMessageId = it.messageId))
val chat = it.chat
withTypingAction(chat) {
executeUnsafe(it.content.createResend(chat.id, replyToMessageId = it.messageId))
}
}
onVisualGallery {
sendVisualMediaGroup(it.chat!!, it.map { it.content.toMediaGroupMemberInputMedia() })
val chat = it.chat ?: return@onVisualGallery
withUploadPhotoAction(chat) {
sendVisualMediaGroup(chat, it.map { it.content.toMediaGroupMemberInputMedia() })
}
}
onPlaylist {
sendPlaylist(it.chat!!, it.map { it.content.toMediaGroupMemberInputMedia() })
val chat = it.chat ?: return@onPlaylist
withUploadDocumentAction(chat) {
sendPlaylist(chat, it.map { it.content.toMediaGroupMemberInputMedia() })
}
}
onDocumentsGroup {
sendDocumentsGroup(it.chat!!, it.map { it.content.toMediaGroupMemberInputMedia() })
val chat = it.chat ?: return@onDocumentsGroup
withUploadDocumentAction(chat) {
sendDocumentsGroup(chat, it.map { it.content.toMediaGroupMemberInputMedia() })
}
}
allUpdatesFlow.subscribeSafelyWithoutExceptions(this) {
println(it)
}
}.join()
}

View File

@@ -1,6 +1,6 @@
buildscript {
repositories {
jcenter()
mavenCentral()
}
dependencies {
@@ -15,7 +15,7 @@ mainClassName="ResenderBotJvmKt"
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation project(":ResenderBot:ResenderBotLib")
}

View File

@@ -1,6 +1,6 @@
buildscript {
repositories {
jcenter()
mavenCentral()
}
dependencies {
@@ -15,7 +15,7 @@ mainClassName="SlotMachineDetectorBotKt"
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation "dev.inmo:tgbotapi:$telegram_bot_api_version"
}

17
WebApp/README.md Normal file
View File

@@ -0,0 +1,17 @@
# WebApp
Here you may find simple example of `WebApp`. For work of this example you will need one of two things:
* Your own domain with SSL (letsencrypt is okay)
* Test account in telegram
What is there in this module:
* JVM part of this example is a server with simple static webapp sharing and bot which just gives the webapp button to open webapp
* JS part is the WebApp with one button and reacting to chaged user theme and app viewport
## How to run
```kotlin
./gradlew run --args="TOKEN WEB_APP_ADDRESS"
```

55
WebApp/build.gradle Normal file
View File

@@ -0,0 +1,55 @@
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
plugins {
id "org.jetbrains.kotlin.multiplatform" version "$kotlin_version"
}
apply plugin: 'application'
kotlin {
jvm()
js(IR) {
browser()
binaries.executable()
}
sourceSets {
commonMain {
dependencies {
implementation kotlin('stdlib')
}
}
jsMain {
dependencies {
implementation "dev.inmo:tgbotapi.webapps:$telegram_bot_api_version"
}
}
jvmMain {
dependencies {
implementation "dev.inmo:tgbotapi:$telegram_bot_api_version"
implementation "dev.inmo:micro_utils.ktor.server:$micro_utils_version"
implementation "io.ktor:ktor-server-cio:$ktor_version"
}
}
}
}
application {
mainClassName = "WebAppServerKt"
}
tasks.getByName("compileKotlinJvm")
.dependsOn(jsBrowserDistribution)
tasks.getByName("compileKotlinJvm").configure {
mustRunAfter jsBrowserDistribution
}

View File

@@ -0,0 +1,55 @@
import dev.inmo.micro_utils.coroutines.launchSafelyWithoutExceptions
import dev.inmo.tgbotapi.types.webAppQueryIdField
import dev.inmo.tgbotapi.webapps.*
import io.ktor.client.HttpClient
import io.ktor.client.call.receive
import io.ktor.client.request.*
import io.ktor.client.statement.HttpResponse
import io.ktor.client.statement.readText
import io.ktor.http.*
import io.ktor.http.content.TextContent
import kotlinx.browser.document
import kotlinx.browser.window
import kotlinx.coroutines.*
import kotlinx.dom.appendElement
import kotlinx.dom.appendText
import org.w3c.dom.HTMLElement
fun HTMLElement.log(text: String) {
appendElement("p", {})
appendText(text)
}
fun main() {
console.log("Web app started")
window.onload = {
val scope = CoroutineScope(Dispatchers.Default)
runCatching {
document.body ?.appendElement("button") {
addEventListener("click", {
scope.launchSafelyWithoutExceptions {
handleResult({ "Clicked" }) {
HttpClient().post<HttpResponse>("${window.location.origin.removeSuffix("/")}/inline") {
parameter(webAppQueryIdField, it)
body = TextContent("Clicked", ContentType.Text.Plain)
document.body ?.log(url.build().toString())
}.coroutineContext.job.join()
}
}
})
appendText("Example button")
} ?: window.alert("Unable to load body")
webApp.apply {
onThemeChanged {
document.body ?.log("Theme changed: ${webApp.themeParams}")
}
onViewportChanged {
document.body ?.log("Viewport changed: ${it.isStateStable}")
}
}
webApp.ready()
}.onFailure {
window.alert(it.stackTraceToString())
}
}
}

View File

@@ -0,0 +1,11 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Web App Example</title>
</head>
<body>
<script type="application/javascript" src="https://telegram.org/js/telegram-web-app.js"></script>
<script type="application/javascript" src="WebApp.js"></script>
</body>
</html>

View File

@@ -0,0 +1,96 @@
import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions
import dev.inmo.micro_utils.ktor.server.createKtorServer
import dev.inmo.tgbotapi.extensions.api.answers.answer
import dev.inmo.tgbotapi.extensions.api.bot.getMe
import dev.inmo.tgbotapi.extensions.api.bot.setMyCommands
import dev.inmo.tgbotapi.extensions.api.send.*
import dev.inmo.tgbotapi.extensions.api.telegramBot
import dev.inmo.tgbotapi.extensions.behaviour_builder.*
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.*
import dev.inmo.tgbotapi.extensions.utils.types.buttons.*
import dev.inmo.tgbotapi.types.BotCommand
import dev.inmo.tgbotapi.types.InlineQueries.InlineQueryResult.InlineQueryResultArticle
import dev.inmo.tgbotapi.types.InlineQueries.InputMessageContent.InputTextMessageContent
import dev.inmo.tgbotapi.types.webAppQueryIdField
import dev.inmo.tgbotapi.types.webapps.WebAppInfo
import io.ktor.application.call
import io.ktor.http.HttpStatusCode
import io.ktor.http.content.*
import io.ktor.request.receiveText
import io.ktor.response.respond
import io.ktor.routing.*
import kotlinx.coroutines.Dispatchers
import java.io.File
/**
* Accepts two parameters:
*
* * Telegram Token
* * URL where will be placed
*
* Will start the server to share the static (index.html and WebApp.js) on 0.0.0.0:8080
*/
suspend fun main(vararg args: String) {
val bot = telegramBot(args.first(), testServer = args.any { it == "testServer" })
createKtorServer(
"0.0.0.0",
8080,
additionalEngineEnvironmentConfigurator = {
parentCoroutineContext += Dispatchers.IO
}
) {
routing {
static {
files(File("WebApp/build/distributions"))
default("WebApp/build/distributions/index.html")
}
post("inline") {
val requestBody = call.receiveText()
val queryId = call.parameters[webAppQueryIdField] ?: error("$webAppQueryIdField should be presented")
bot.answer(queryId, InlineQueryResultArticle(queryId, "Result", InputTextMessageContent(requestBody)))
call.respond(HttpStatusCode.OK)
}
}
}.start(false)
bot.buildBehaviourWithLongPolling(
defaultExceptionsHandler = { it.printStackTrace() }
) {
onCommand("reply_markup") {
reply(
it,
"Button",
replyMarkup = replyKeyboard(resizeKeyboard = true, oneTimeKeyboard = true) {
row {
webAppButton("Open WebApp", WebAppInfo(args[1]))
}
}
)
}
onCommand("inline") {
reply(
it,
"Button",
replyMarkup = inlineKeyboard {
row {
webAppButton("Open WebApp", WebAppInfo(args[1]))
}
}
)
}
onUnhandledCommand {
println("Unhandled command: ${it.content}")
}
setMyCommands(
BotCommand("reply_markup", "Use to get reply markup keyboard with web app trigger"),
BotCommand("inline", "Use to get inline keyboard with web app trigger"),
)
allUpdatesFlow.subscribeSafelyWithoutExceptions(this) {
println(it)
}
println(getMe())
}.join()
}

View File

@@ -1,7 +1,7 @@
allprojects {
repositories {
mavenLocal()
jcenter()
mavenCentral()
if (project.hasProperty("GITHUB_USER") && project.hasProperty("GITHUB_TOKEN")) {
maven {
url "https://maven.pkg.github.com/InsanusMokrassar/TelegramBotAPI"
@@ -12,4 +12,4 @@ allprojects {
}
}
}
}
}

View File

@@ -1,5 +1,8 @@
kotlin.code.style=official
org.gradle.parallel=true
kotlin_version=1.5.10
telegram_bot_api_version=0.35.0
kotlin_version=1.6.21
telegram_bot_api_version=0.38.23
micro_utils_version=0.9.24
ktor_version=1.6.8

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-7.0-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-bin.zip

View File

@@ -1,8 +1,21 @@
include ":ForwardInfoSenderBot"
include ":RandomFileSenderBot"
include ":HelloBot"
include ":GetMeBot"
include ":FilesLoaderBot"
include ":ResenderBot:ResenderBotLib"
include ":ResenderBot:jvm_launcher"
include ":KeyboardsBot:KeyboardsBotLib"
include ":KeyboardsBot:jvm_launcher"
include ":SlotMachineDetectorBot"
include ":WebApp"
include ":FSMBot"