diff --git a/CustomBot/README.md b/CustomBot/README.md new file mode 100644 index 0000000..13b72ef --- /dev/null +++ b/CustomBot/README.md @@ -0,0 +1,9 @@ +# CustomBot + +This bot basically have no any useful behaviour, but you may customize it as a playground + +## Launch + +```bash +../gradlew run --args="BOT_TOKEN" +``` diff --git a/CustomBot/build.gradle b/CustomBot/build.gradle new file mode 100644 index 0000000..fdbd23c --- /dev/null +++ b/CustomBot/build.gradle @@ -0,0 +1,21 @@ +buildscript { + repositories { + mavenCentral() + } + + dependencies { + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +apply plugin: 'kotlin' +apply plugin: 'application' + +mainClassName="CustomBotKt" + + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" + + implementation "dev.inmo:tgbotapi:$telegram_bot_api_version" +} diff --git a/CustomBot/src/main/kotlin/CustomBot.kt b/CustomBot/src/main/kotlin/CustomBot.kt new file mode 100644 index 0000000..45d3861 --- /dev/null +++ b/CustomBot/src/main/kotlin/CustomBot.kt @@ -0,0 +1,33 @@ +import dev.inmo.kslog.common.KSLog +import dev.inmo.kslog.common.LogLevel +import dev.inmo.kslog.common.defaultMessageFormatter +import dev.inmo.kslog.common.setDefaultKSLog +import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions +import dev.inmo.tgbotapi.extensions.api.bot.getMe +import dev.inmo.tgbotapi.extensions.behaviour_builder.telegramBotWithBehaviourAndLongPolling +import dev.inmo.tgbotapi.utils.PreviewFeature +import kotlinx.coroutines.* + +/** + * The main purpose of this bot is just to answer "Oh, hi, " and add user mention here + */ +@OptIn(PreviewFeature::class) +suspend fun main(vararg args: String) { + val botToken = args.first() + + val isDebug = args.any { it == "debug" } + + if (isDebug) { + setDefaultKSLog( + KSLog { level: LogLevel, tag: String?, message: Any, throwable: Throwable? -> + println(defaultMessageFormatter(level, tag, message, throwable)) + } + ) + } + + telegramBotWithBehaviourAndLongPolling(botToken, CoroutineScope(Dispatchers.IO)) { + val me = getMe() + + allUpdatesFlow.subscribeSafelyWithoutExceptions(this) { println(it) } + }.second.join() +} diff --git a/LiveLocationsBot/src/main/kotlin/LiveLocationsBot.kt b/LiveLocationsBot/src/main/kotlin/LiveLocationsBot.kt index 2abfd27..6815e79 100644 --- a/LiveLocationsBot/src/main/kotlin/LiveLocationsBot.kt +++ b/LiveLocationsBot/src/main/kotlin/LiveLocationsBot.kt @@ -1,33 +1,16 @@ import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions import dev.inmo.tgbotapi.extensions.api.EditLiveLocationInfo -import dev.inmo.tgbotapi.extensions.api.chat.get.getChat -import dev.inmo.tgbotapi.extensions.api.edit.edit import dev.inmo.tgbotapi.extensions.api.edit.location.live.stopLiveLocation import dev.inmo.tgbotapi.extensions.api.handleLiveLocation -import dev.inmo.tgbotapi.extensions.api.send.* import dev.inmo.tgbotapi.extensions.behaviour_builder.expectations.waitMessageDataCallbackQuery -import dev.inmo.tgbotapi.extensions.behaviour_builder.oneOf -import dev.inmo.tgbotapi.extensions.behaviour_builder.parallel import dev.inmo.tgbotapi.extensions.behaviour_builder.telegramBotWithBehaviourAndLongPolling import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onCommand -import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onContentMessage import dev.inmo.tgbotapi.extensions.utils.extensions.sameMessage -import dev.inmo.tgbotapi.extensions.utils.formatting.linkMarkdownV2 -import dev.inmo.tgbotapi.extensions.utils.formatting.textMentionMarkdownV2 -import dev.inmo.tgbotapi.extensions.utils.ifFromChannelGroupContentMessage import dev.inmo.tgbotapi.extensions.utils.types.buttons.dataButton import dev.inmo.tgbotapi.extensions.utils.types.buttons.flatInlineKeyboard -import dev.inmo.tgbotapi.types.chat.* -import dev.inmo.tgbotapi.types.chat.GroupChat -import dev.inmo.tgbotapi.types.chat.PrivateChat -import dev.inmo.tgbotapi.types.chat.SupergroupChat import dev.inmo.tgbotapi.types.location.LiveLocation -import dev.inmo.tgbotapi.types.message.MarkdownV2 import dev.inmo.tgbotapi.types.message.abstracts.ContentMessage -import dev.inmo.tgbotapi.types.message.content.LiveLocationContent import dev.inmo.tgbotapi.types.message.content.LocationContent -import dev.inmo.tgbotapi.utils.PreviewFeature -import dev.inmo.tgbotapi.utils.extensions.escapeMarkdownV2Common import kotlinx.coroutines.* import kotlinx.coroutines.flow.FlowCollector import kotlinx.coroutines.flow.MutableStateFlow @@ -64,7 +47,7 @@ suspend fun main(vararg args: String) { handleLiveLocation( it.chat.id, locationsFlow, - sentMessageFlow = FlowCollector { currentMessageState.emit(it) } + sentMessageFlow = FlowCollector { currentMessageState.emit(it) }, ) } diff --git a/PollsBot/src/main/kotlin/PollsBot.kt b/PollsBot/src/main/kotlin/PollsBot.kt index 647a167..e7f885c 100644 --- a/PollsBot/src/main/kotlin/PollsBot.kt +++ b/PollsBot/src/main/kotlin/PollsBot.kt @@ -1,11 +1,19 @@ import com.benasher44.uuid.uuid4 +import dev.inmo.kslog.common.KSLog +import dev.inmo.kslog.common.LogLevel +import dev.inmo.kslog.common.defaultMessageFormatter +import dev.inmo.kslog.common.setDefaultKSLog import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions import dev.inmo.tgbotapi.extensions.api.bot.getMe +import dev.inmo.tgbotapi.extensions.api.bot.setMyCommands import dev.inmo.tgbotapi.extensions.api.chat.get.getChat import dev.inmo.tgbotapi.extensions.api.send.* +import dev.inmo.tgbotapi.extensions.api.send.polls.sendQuizPoll import dev.inmo.tgbotapi.extensions.api.send.polls.sendRegularPoll import dev.inmo.tgbotapi.extensions.behaviour_builder.telegramBotWithBehaviourAndLongPolling import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.* +import dev.inmo.tgbotapi.extensions.utils.customEmojiTextSourceOrNull +import dev.inmo.tgbotapi.extensions.utils.extensions.parseCommandsWithArgsSources import dev.inmo.tgbotapi.extensions.utils.extensions.raw.sender_chat import dev.inmo.tgbotapi.extensions.utils.formatting.linkMarkdownV2 import dev.inmo.tgbotapi.extensions.utils.formatting.textMentionMarkdownV2 @@ -17,15 +25,13 @@ import dev.inmo.tgbotapi.types.chat.GroupChat import dev.inmo.tgbotapi.types.chat.PrivateChat import dev.inmo.tgbotapi.types.chat.SupergroupChat import dev.inmo.tgbotapi.types.message.MarkdownV2 -import dev.inmo.tgbotapi.types.polls.Poll -import dev.inmo.tgbotapi.types.polls.PollAnswer -import dev.inmo.tgbotapi.types.polls.PollOption -import dev.inmo.tgbotapi.types.polls.RegularPoll -import dev.inmo.tgbotapi.utils.PreviewFeature +import dev.inmo.tgbotapi.types.polls.* +import dev.inmo.tgbotapi.utils.* import dev.inmo.tgbotapi.utils.extensions.escapeMarkdownV2Common import kotlinx.coroutines.* import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.withLock +import kotlin.random.Random /** * This bot will answer with anonymous or public poll and send message on @@ -37,6 +43,15 @@ import kotlinx.coroutines.sync.withLock @OptIn(PreviewFeature::class) suspend fun main(vararg args: String) { val botToken = args.first() + val isDebug = args.any { it == "debug" } + + if (isDebug) { + setDefaultKSLog( + KSLog { level: LogLevel, tag: String?, message: Any, throwable: Throwable? -> + println(defaultMessageFormatter(level, tag, message, throwable)) + } + ) + } telegramBotWithBehaviourAndLongPolling(botToken, CoroutineScope(Dispatchers.IO)) { val me = getMe() @@ -44,12 +59,27 @@ suspend fun main(vararg args: String) { val pollToChat = mutableMapOf() val pollToChatMutex = Mutex() - onCommand("anonymous") { + onCommand("anonymous", requireOnlyCommandInMessage = false) { + val customEmoji = it.content.parseCommandsWithArgsSources() + .toList() + .firstOrNull { it.first.command == "anonymous" } + ?.second + ?.firstNotNullOfOrNull { it.customEmojiTextSourceOrNull() } val sentPoll = sendRegularPoll( - it.chat, - "Test regular anonymous poll", + it.chat.id, + buildEntities { + regular("Test regular anonymous poll") + if (customEmoji != null) { + customEmoji(customEmoji.customEmojiId, customEmoji.subsources) + } + }, (1 .. 10).map { - it.toString() + InputPollOption { + regular(it.toString()) + " " + if (customEmoji != null) { + customEmoji(customEmoji.customEmojiId, customEmoji.subsources) + } + } }, isAnonymous = true, replyParameters = ReplyParameters(it) @@ -59,12 +89,27 @@ suspend fun main(vararg args: String) { } } - onCommand("public") { + onCommand("public", requireOnlyCommandInMessage = false) { + val customEmoji = it.content.parseCommandsWithArgsSources() + .toList() + .firstOrNull { it.first.command == "public" } + ?.second + ?.firstNotNullOfOrNull { it.customEmojiTextSourceOrNull() } val sentPoll = sendRegularPoll( - it.chat, - "Test regular anonymous poll", + it.chat.id, + buildEntities { + regular("Test regular non anonymous poll") + if (customEmoji != null) { + customEmoji(customEmoji.customEmojiId, customEmoji.subsources) + } + }, (1 .. 10).map { - it.toString() + InputPollOption { + regular(it.toString()) + " " + if (customEmoji != null) { + customEmoji(customEmoji.customEmojiId, customEmoji.subsources) + } + } }, isAnonymous = false, replyParameters = ReplyParameters(it) @@ -74,6 +119,44 @@ suspend fun main(vararg args: String) { } } + onCommand("quiz", requireOnlyCommandInMessage = false) { + val customEmoji = it.content.parseCommandsWithArgsSources() + .toList() + .firstOrNull { it.first.command == "quiz" } + ?.second + ?.firstNotNullOfOrNull { it.customEmojiTextSourceOrNull() } + val correctAnswer = Random.nextInt(10) + val sentPoll = sendQuizPoll( + it.chat.id, + questionEntities = buildEntities { + regular("Test quiz poll") + if (customEmoji != null) { + customEmoji(customEmoji.customEmojiId, customEmoji.subsources) + } + }, + (1 .. 10).map { + InputPollOption { + regular(it.toString()) + " " + if (customEmoji != null) { + customEmoji(customEmoji.customEmojiId, customEmoji.subsources) + } + } + }, + isAnonymous = false, + replyParameters = ReplyParameters(it), + correctOptionId = correctAnswer, + explanationTextSources = buildEntities { + regular("Random solved it to be ") + underline((correctAnswer + 1).toString()) + " " + if (customEmoji != null) { + customEmoji(customEmoji.customEmojiId, customEmoji.subsources) + } + } + ) + pollToChatMutex.withLock { + pollToChat[sentPoll.content.poll.id] = sentPoll.chat.id + } + } + onPollAnswer { val chatId = pollToChat[it.pollId] ?: return@onPollAnswer @@ -92,6 +175,12 @@ suspend fun main(vararg args: String) { } } + setMyCommands( + BotCommand("anonymous", "Create anonymous regular poll"), + BotCommand("public", "Create non anonymous regular poll"), + BotCommand("quiz", "Create quiz poll with random right answer"), + ) + allUpdatesFlow.subscribeSafelyWithoutExceptions(this) { println(it) } }.second.join() } diff --git a/gradle.properties b/gradle.properties index 456645c..613a32e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -5,7 +5,7 @@ org.gradle.jvmargs=-Xmx2344m kotlin_version=1.9.23 -telegram_bot_api_version=12.0.1 +telegram_bot_api_version=13.0.0 micro_utils_version=0.20.45 serialization_version=1.6.3 ktor_version=2.3.10 diff --git a/settings.gradle b/settings.gradle index 57b91bf..ba16eb9 100644 --- a/settings.gradle +++ b/settings.gradle @@ -49,3 +49,5 @@ include ":LinkPreviewsBot" include ":BoostsInfoBot" include ":BusinessConnectionsBot" + +include ":CustomBot"