Compare commits

..

14 Commits

13 changed files with 406 additions and 34 deletions

View File

@@ -6,12 +6,22 @@ import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions
import dev.inmo.tgbotapi.extensions.api.bot.getMe
import dev.inmo.tgbotapi.extensions.api.bot.getMyStarBalance
import dev.inmo.tgbotapi.extensions.api.chat.get.getChat
import dev.inmo.tgbotapi.extensions.api.get.getUserProfileAudios
import dev.inmo.tgbotapi.extensions.api.send.media.sendPaidMedia
import dev.inmo.tgbotapi.extensions.api.send.reply
import dev.inmo.tgbotapi.extensions.api.send.replyWithAudio
import dev.inmo.tgbotapi.extensions.api.send.replyWithPlaylist
import dev.inmo.tgbotapi.extensions.behaviour_builder.BehaviourContextData
import dev.inmo.tgbotapi.extensions.behaviour_builder.buildSubcontextInitialAction
import dev.inmo.tgbotapi.extensions.behaviour_builder.telegramBotWithBehaviourAndLongPolling
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onChannelDirectMessagesConfigurationChanged
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onChatOwnerChanged
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onChatOwnerLeft
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onCommand
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onPhoto
import dev.inmo.tgbotapi.types.media.AudioMediaGroupMemberTelegramMedia
import dev.inmo.tgbotapi.types.media.toTelegramMediaAudio
import dev.inmo.tgbotapi.types.media.toTelegramPaidMediaPhoto
import dev.inmo.tgbotapi.types.message.abstracts.CommonMessage
import dev.inmo.tgbotapi.types.update.abstracts.Update
import kotlinx.coroutines.CoroutineScope
@@ -70,6 +80,32 @@ suspend fun main(vararg args: String) {
println(data.update)
println(data.commonMessage)
println(getChat(it.chat))
var currentOffset = 0
val pageSize = 2
do {
val userAudios = getUserProfileAudios(userId = it.chat.id, offset = currentOffset, limit = pageSize)
currentOffset += pageSize
println(userAudios)
when (userAudios.audios.size) {
1 -> {
replyWithAudio(
it,
userAudios.audios.first().fileId
)
}
0 -> {
// do nothing
}
else -> {
replyWithPlaylist(
it,
userAudios.audios.map {
it.toTelegramMediaAudio()
}
)
}
}
} while (currentOffset < userAudios.totalCount && userAudios.audios.isNotEmpty())
}
onCommand(

View File

@@ -1,29 +0,0 @@
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.tgbotapi.bot.ktor.telegramBot
import dev.inmo.tgbotapi.extensions.api.bot.getMe
import dev.inmo.tgbotapi.extensions.api.chat.get.getChat
/**
* This is one of the easiest bots - it will just print information about itself
*/
suspend fun main(vararg args: String) {
val botToken = args.first()
val isDebug = args.getOrNull(1) == "debug"
if (isDebug) {
setDefaultKSLog(
KSLog { level: LogLevel, tag: String?, message: Any, throwable: Throwable? ->
println(defaultMessageFormatter(level, tag, message, throwable))
}
)
}
val bot = telegramBot(botToken)
val me = bot.getMe()
println(me)
println(bot.getChat(me))
}

21
GiftsBot/build.gradle Normal file
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="GiftsBotKt"
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation "dev.inmo:tgbotapi:$telegram_bot_api_version"
}

View File

@@ -0,0 +1,112 @@
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.business.getBusinessAccountGiftsFlow
import dev.inmo.tgbotapi.extensions.api.gifts.getChatGiftsFlow
import dev.inmo.tgbotapi.extensions.api.gifts.getUserGiftsFlow
import dev.inmo.tgbotapi.extensions.api.send.reply
import dev.inmo.tgbotapi.extensions.api.send.withTypingAction
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.onGiveawayCompleted
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onGiveawayContent
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onGiveawayCreated
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onGiveawayWinners
import dev.inmo.tgbotapi.types.chat.BusinessChat
import dev.inmo.tgbotapi.types.chat.PrivateChat
import dev.inmo.tgbotapi.types.chat.PublicChat
import dev.inmo.tgbotapi.types.chat.UnknownChatType
import dev.inmo.tgbotapi.types.gifts.OwnedGift
import dev.inmo.tgbotapi.types.message.textsources.splitForText
import dev.inmo.tgbotapi.utils.bold
import dev.inmo.tgbotapi.utils.buildEntities
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
suspend fun main(vararg args: String) {
val botToken = args.first()
val isDebug = args.any { it == "debug" }
val isTestServer = args.any { it == "testServer" }
if (isDebug) {
setDefaultKSLog(
KSLog { level: LogLevel, tag: String?, message: Any, throwable: Throwable? ->
println(defaultMessageFormatter(level, tag, message, throwable))
}
)
}
telegramBotWithBehaviourAndLongPolling(botToken, testServer = isTestServer) {
// start here!!
val me = getMe()
println(me)
onCommand("start") {
val giftsFlow = when (val chat = it.chat) {
is BusinessChat -> {
getBusinessAccountGiftsFlow(
chat.id.businessConnectionId
)
}
is PrivateChat -> {
getUserGiftsFlow(it.chat.id)
}
is UnknownChatType,
is PublicChat -> {
getChatGiftsFlow(it.chat.id)
}
}
withTypingAction(it.chat) {
val texts = buildEntities {
giftsFlow.collect { ownedGifts ->
ownedGifts.gifts.forEach {
when (it) {
is OwnedGift.Regular.Common -> {
bold("Type") + ": Regular common\n"
bold("Id") + ": ${it.gift.id.string}\n"
bold("Text") + ": ${it.text ?: "(None)"}\n"
bold("Stars cost") + ": ${it.gift.starCount}\n"
}
is OwnedGift.Unique.Common -> {
bold("Type") + ": Unique common\n"
bold("Id") + ": ${it.gift.id ?.string ?: "(None)"}\n"
bold("Name") + ": ${it.gift.name.value}\n"
bold("Model") + ": ${it.gift.model.name}\n"
bold("Number") + ": ${it.gift.number}\n"
}
is OwnedGift.Regular.OwnedByBusinessAccount -> {
bold("Type") + ": Regular owned by business\n"
bold("Id") + ": ${it.gift.id.string}\n"
bold("Text") + ": ${it.text ?: "(None)"}\n"
bold("Stars cost") + ": ${it.gift.starCount}\n"
}
is OwnedGift.Unique.OwnedByBusinessAccount -> {
bold("Type") + ": Unique owned by business\n"
bold("Id") + ": ${it.gift.id ?.string ?: "(None)"}\n"
bold("Name") + ": ${it.gift.name.value}\n"
bold("Model") + ": ${it.gift.model.name}\n"
bold("Number") + ": ${it.gift.number}\n"
}
}
}
}
}
val preparedTexts = texts.splitForText()
if (preparedTexts.isEmpty()) {
reply(it, "This chat have no any gifts")
} else {
preparedTexts.forEach { preparedText -> reply(it, preparedText) }
}
}
}
// allUpdatesFlow.subscribeSafelyWithoutExceptions(this) {
// println(it)
// }
}.second.join()
}

View File

@@ -0,0 +1,94 @@
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.launchLoggingDropExceptions
import dev.inmo.micro_utils.coroutines.runCatchingLogging
import dev.inmo.tgbotapi.bot.ktor.telegramBot
import dev.inmo.tgbotapi.extensions.api.bot.getMe
import dev.inmo.tgbotapi.extensions.api.bot.removeMyProfilePhoto
import dev.inmo.tgbotapi.extensions.api.bot.setMyProfilePhoto
import dev.inmo.tgbotapi.extensions.api.chat.get.getChat
import dev.inmo.tgbotapi.extensions.api.files.downloadFileToTemp
import dev.inmo.tgbotapi.extensions.api.send.reply
import dev.inmo.tgbotapi.extensions.api.send.sendMessageDraftFlowWithTexts
import dev.inmo.tgbotapi.extensions.behaviour_builder.expectations.waitPhotoMessage
import dev.inmo.tgbotapi.extensions.behaviour_builder.telegramBotWithBehaviourAndLongPolling
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onCommand
import dev.inmo.tgbotapi.extensions.utils.extensions.sameChat
import dev.inmo.tgbotapi.requests.abstracts.asMultipartFile
import dev.inmo.tgbotapi.requests.business_connection.InputProfilePhoto
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.consumeAsFlow
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.first
/**
* This is one of the easiest bots - it will just print information about itself
*/
suspend fun main(vararg args: String) {
val botToken = args.first()
val isDebug = args.any { it == "debug" }
val isTestServer = args.any { it == "testServer" }
if (isDebug) {
setDefaultKSLog(
KSLog { level: LogLevel, tag: String?, message: Any, throwable: Throwable? ->
println(defaultMessageFormatter(level, tag, message, throwable))
}
)
}
val bot = telegramBot(botToken)
telegramBotWithBehaviourAndLongPolling(
botToken,
CoroutineScope(Dispatchers.Default),
testServer = isTestServer,
) {
val me = bot.getMe()
println(me)
println(bot.getChat(me))
onCommand("setMyProfilePhoto") { commandMessage ->
reply(commandMessage, "ok, send me new photo")
val newPhotoMessage = waitPhotoMessage().filter { potentialPhotoMessage ->
potentialPhotoMessage.sameChat(commandMessage)
}.first()
val draftMessagesChannel = Channel<String>(capacity = 1)
launchLoggingDropExceptions {
sendMessageDraftFlowWithTexts(commandMessage.chat.id, draftMessagesChannel.consumeAsFlow())
}.invokeOnCompletion {
draftMessagesChannel.close(it)
}
draftMessagesChannel.send("Start downloading photo")
val photoFile = downloadFileToTemp(newPhotoMessage.content)
draftMessagesChannel.send("Photo file have been downloaded. Start set my profile photo")
val setResult = setMyProfilePhoto(
InputProfilePhoto.Static(
photoFile.asMultipartFile()
)
)
if (setResult) {
reply(commandMessage, "New photo have been set")
}
}
onCommand("removeMyProfilePhoto") {
runCatchingLogging {
if (removeMyProfilePhoto()) {
reply(it, "Photo have been removed")
}
}.onFailure { e ->
e.printStackTrace()
reply(it, "Something web wrong. See logs for details.")
}
}
}.second.join()
}

View File

@@ -15,6 +15,7 @@ import dev.inmo.tgbotapi.extensions.utils.extensions.sameChat
import dev.inmo.tgbotapi.extensions.utils.types.buttons.*
import dev.inmo.tgbotapi.extensions.utils.withContentOrNull
import dev.inmo.tgbotapi.requests.abstracts.asMultipartFile
import dev.inmo.tgbotapi.types.ChatId
import dev.inmo.tgbotapi.types.RawChatId
import dev.inmo.tgbotapi.types.UserId
import dev.inmo.tgbotapi.types.buttons.InlineKeyboardMarkup
@@ -40,7 +41,7 @@ import kotlinx.coroutines.Dispatchers
*/
suspend fun main(vararg args: String) {
val botToken = args.first()
val adminUserId = args.getOrNull(1) ?.toLongOrNull() ?.let(::RawChatId) ?.let(::UserId) ?: error("Pass user-admin for full access to the bot")
val adminUserId = args.getOrNull(1) ?.toLongOrNull() ?.let(::RawChatId) ?.let(::ChatId) ?: error("Pass user-admin for full access to the bot")
val isDebug = args.any { it == "debug" }
val isTestServer = args.any { it == "testServer" }

21
TagsBot/build.gradle Normal file
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="TagsBotKt"
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation "dev.inmo:tgbotapi:$telegram_bot_api_version"
}

View File

@@ -0,0 +1,101 @@
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.subscribeLoggingDropExceptions
import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions
import dev.inmo.tgbotapi.abstracts.FromUser
import dev.inmo.tgbotapi.extensions.api.bot.getMe
import dev.inmo.tgbotapi.extensions.api.business.getBusinessAccountGiftsFlow
import dev.inmo.tgbotapi.extensions.api.chat.members.promoteChatAdministrator
import dev.inmo.tgbotapi.extensions.api.chat.members.promoteChatMember
import dev.inmo.tgbotapi.extensions.api.chat.members.setChatMemberTag
import dev.inmo.tgbotapi.extensions.api.gifts.getChatGiftsFlow
import dev.inmo.tgbotapi.extensions.api.gifts.getUserGiftsFlow
import dev.inmo.tgbotapi.extensions.api.send.reply
import dev.inmo.tgbotapi.extensions.api.send.withTypingAction
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.behaviour_builder.triggers_handling.onGiveawayCompleted
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onGiveawayContent
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onGiveawayCreated
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onGiveawayWinners
import dev.inmo.tgbotapi.extensions.utils.extensions.raw.sender_chat
import dev.inmo.tgbotapi.extensions.utils.extensions.raw.sender_tag
import dev.inmo.tgbotapi.extensions.utils.fromUserOrNull
import dev.inmo.tgbotapi.extensions.utils.groupContentMessageOrNull
import dev.inmo.tgbotapi.extensions.utils.idChatIdentifierOrNull
import dev.inmo.tgbotapi.extensions.utils.potentiallyFromUserGroupContentMessageOrNull
import dev.inmo.tgbotapi.types.UserTag
import dev.inmo.tgbotapi.types.chat.BusinessChat
import dev.inmo.tgbotapi.types.chat.PrivateChat
import dev.inmo.tgbotapi.types.chat.PublicChat
import dev.inmo.tgbotapi.types.chat.UnknownChatType
import dev.inmo.tgbotapi.types.gifts.OwnedGift
import dev.inmo.tgbotapi.types.message.abstracts.OptionallyFromUserMessage
import dev.inmo.tgbotapi.types.message.textsources.splitForText
import dev.inmo.tgbotapi.utils.bold
import dev.inmo.tgbotapi.utils.buildEntities
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
suspend fun main(vararg args: String) {
val botToken = args.first()
val isDebug = args.any { it == "debug" }
val isTestServer = args.any { it == "testServer" }
if (isDebug) {
setDefaultKSLog(
KSLog { level: LogLevel, tag: String?, message: Any, throwable: Throwable? ->
println(defaultMessageFormatter(level, tag, message, throwable))
}
)
}
telegramBotWithBehaviourAndLongPolling(botToken, testServer = isTestServer) {
// start here!!
val me = getMe()
println(me)
onCommand("setChatMemberTag", requireOnlyCommandInMessage = false) {
val reply = it.replyTo ?.groupContentMessageOrNull() ?: return@onCommand
val title = it.content.text.removePrefix("/setChatMemberTag").removePrefix(" ")
setChatMemberTag(
chatId = reply.chat.id,
userId = reply.fromUserOrNull() ?.user ?.id ?: return@onCommand,
tag = UserTag(title)
)
}
onCommand("setCanManageTags", requireOnlyCommandInMessage = false) {
val reply = it.replyTo ?.groupContentMessageOrNull() ?: return@onCommand
val setOrUnset = it.content.text.removePrefix("/setCanManageTags").removePrefix(" ") == "true"
promoteChatAdministrator(
it.chat.id,
reply.fromUserOrNull() ?.user ?.id ?: return@onCommand,
canManageTags = setOrUnset
)
}
onCommand("removeChatMemberTag") {
val reply = it.replyTo ?.groupContentMessageOrNull() ?: return@onCommand
setChatMemberTag(
chatId = reply.chat.id,
userId = reply.fromUserOrNull() ?.user ?.id ?: return@onCommand,
tag = null
)
}
onContentMessage {
val groupContentMessage = it.potentiallyFromUserGroupContentMessageOrNull() ?: return@onContentMessage
reply(it, "Tag after casting: ${groupContentMessage.senderTag}")
reply(it, "Tag by getting via risk API: ${it.sender_tag}")
}
allUpdatesFlow.subscribeLoggingDropExceptions(this) {
println(it)
}
}.second.join()
}

View File

@@ -1,5 +1,6 @@
import androidx.compose.runtime.*
import dev.inmo.micro_utils.coroutines.launchLoggingDropExceptions
import dev.inmo.tgbotapi.types.CustomEmojiId
import dev.inmo.tgbotapi.types.userIdField
import dev.inmo.tgbotapi.types.webAppQueryIdField
import dev.inmo.tgbotapi.webapps.*
@@ -395,6 +396,11 @@ fun main() {
}
mainButton.apply {
setText("Main button")
setParams(
BottomButtonParams(
iconCustomEmojiId = CustomEmojiId("5370976574969486150") // 😏
)
)
onClick {
logsState.add("Main button clicked")
hapticFeedback.notificationOccurred(
@@ -405,6 +411,11 @@ fun main() {
}
secondaryButton.apply {
setText("Secondary button")
setParams(
BottomButtonParams(
iconCustomEmojiId = CustomEmojiId("5370763368497944736") // 😒
)
)
onClick {
logsState.add("Secondary button clicked")
hapticFeedback.notificationOccurred(

View File

@@ -5,9 +5,9 @@ org.gradle.jvmargs=-Xmx3148m
kotlin.daemon.jvmargs=-Xmx3g -Xms500m
kotlin_version=2.2.21
telegram_bot_api_version=31.0.0
micro_utils_version=0.26.8
kotlin_version=2.3.20
telegram_bot_api_version=31.2.0
micro_utils_version=0.26.9
serialization_version=1.9.0
ktor_version=3.3.2
compose_version=1.8.2

View File

@@ -6,7 +6,7 @@ include ":HelloBot"
include ":PollsBot"
include ":GetMeBot"
include ":MyBot"
include ":DeepLinksBot"
@@ -65,3 +65,7 @@ include ":SuggestedPosts"
include ":ChecklistsBot"
include ":DraftsBot"
include ":GiftsBot"
include ":TagsBot"