buildable new bots

This commit is contained in:
2026-06-06 13:33:37 +06:00
parent 95a619431c
commit 9318891d94
22 changed files with 690 additions and 64 deletions

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="LivePhotosBotKt"
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation "dev.inmo:tgbotapi:$telegram_bot_api_version"
}

View File

@@ -0,0 +1,166 @@
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.extensions.api.edit.media.editMessageMedia
import dev.inmo.tgbotapi.extensions.api.send.media.sendLivePhoto
import dev.inmo.tgbotapi.extensions.api.send.media.sendMediaGroup
import dev.inmo.tgbotapi.extensions.api.send.media.sendPaidMedia
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.onEditedLivePhoto
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onLivePhoto
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onLivePhotoGallery
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onPaidMediaInfoContent
import dev.inmo.tgbotapi.extensions.utils.withContentOrNull
import dev.inmo.tgbotapi.types.message.content.LivePhotoContent
import dev.inmo.tgbotapi.types.message.payments.PaidMedia
import dev.inmo.tgbotapi.types.media.TelegramMediaLivePhoto
import dev.inmo.tgbotapi.types.media.TelegramPaidMediaLivePhoto
import dev.inmo.tgbotapi.types.media.toTelegramPaidMediaLivePhoto
import dev.inmo.tgbotapi.utils.RiskFeature
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
/**
* This bot demonstrates Live Photos support introduced in Telegram Bot API.
*
* Key concepts demonstrated:
* - [dev.inmo.tgbotapi.types.files.LivePhotoFile] — the LivePhoto class: a photo with an attached short video
* - [TelegramMediaLivePhoto] — InputMediaLivePhoto: used in sendMediaGroup and editMessageMedia
* - [LivePhotoContent] — the content type carried in Message.live_photo / ExternalReplyInfo.live_photo
* - [sendLivePhoto] — method to send a live photo
* - [PaidMedia.LivePhoto] — PaidMediaLivePhoto: a live photo inside paid media content
* - [TelegramPaidMediaLivePhoto] — InputPaidMediaLivePhoto: used in sendPaidMedia
* - sendMediaGroup and editMessageMedia with live photos
*/
@OptIn(RiskFeature::class)
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,
CoroutineScope(Dispatchers.IO),
testServer = isTestServer
) {
// Demonstrates: LivePhoto class (LivePhotoFile), live_photo field in Message, sendLivePhoto,
// InputMediaLivePhoto (TelegramMediaLivePhoto), InputPaidMediaLivePhoto (TelegramPaidMediaLivePhoto),
// editMessageMedia with live photo
onLivePhoto { message ->
// message.content is LivePhotoContent — this is the live_photo field of Message
val content: LivePhotoContent = message.content
// content.media is LivePhotoFile — the LivePhoto class (photo + short video in one file)
val livePhotoFile = content.media
println("=== Live photo received ===")
println(" fileId: ${livePhotoFile.fileId}")
println(" fileUniqueId: ${livePhotoFile.fileUniqueId}")
println(" width: ${livePhotoFile.width}")
println(" height: ${livePhotoFile.height}")
println(" duration: ${livePhotoFile.duration}s")
println(" photo (thumb): ${livePhotoFile.photo?.fileId}")
println(" mimeType: ${livePhotoFile.mimeType}")
println(" fileSize: ${livePhotoFile.fileSize}")
println(" caption: ${content.text}")
// sendLivePhoto: resend the received live photo back using LivePhotoFile overload
val sent = sendLivePhoto(
chatId = message.chat.id,
livePhoto = livePhotoFile,
text = "Resent via sendLivePhoto"
)
println(" sent message id: ${sent.messageId}")
// InputPaidMediaLivePhoto (TelegramPaidMediaLivePhoto): send the live photo as paid media (1 star)
sendPaidMedia(
chatId = message.chat.id,
starCount = 1,
media = listOf(
// TelegramPaidMediaLivePhoto is InputPaidMediaLivePhoto
TelegramPaidMediaLivePhoto(
file = livePhotoFile.fileId,
photo = livePhotoFile.photo?.fileId ?: livePhotoFile.fileId
)
),
text = "Paid live photo (1 star)"
)
// editMessageMedia with InputMediaLivePhoto (TelegramMediaLivePhoto):
// edit the previously sent message to replace it with itself via TelegramMediaLivePhoto
val sentAsMedia = sent.withContentOrNull<LivePhotoContent>()
if (sentAsMedia != null) {
editMessageMedia(
message = sentAsMedia,
// TelegramMediaLivePhoto is InputMediaLivePhoto
media = TelegramMediaLivePhoto(
file = livePhotoFile.fileId,
photo = livePhotoFile.photo?.fileId ?: livePhotoFile.fileId,
text = "Edited via editMessageMedia with TelegramMediaLivePhoto"
)
)
}
}
// Demonstrates: sendMediaGroup with live photos, InputMediaLivePhoto (TelegramMediaLivePhoto)
onLivePhotoGallery { mediaGroupContent ->
println("=== Live photo gallery received (${mediaGroupContent.group.size} items) ===")
mediaGroupContent.group.forEach { groupMember ->
val livePhotoFile = groupMember.content.media
println(" - fileId: ${livePhotoFile.fileId}, ${livePhotoFile.width}x${livePhotoFile.height}")
}
// sendMediaGroup with TelegramMediaLivePhoto (InputMediaLivePhoto)
sendMediaGroup(
chatId = mediaGroupContent.group.first().sourceMessage.chat.id,
media = mediaGroupContent.group.map { groupMember ->
val livePhotoFile = groupMember.content.media
// TelegramMediaLivePhoto is InputMediaLivePhoto — used here in sendMediaGroup
TelegramMediaLivePhoto(
file = livePhotoFile.fileId,
photo = livePhotoFile.photo?.fileId ?: livePhotoFile.fileId
)
}
)
}
// Demonstrates: PaidMediaLivePhoto (PaidMedia.LivePhoto) in received paid media content
onPaidMediaInfoContent { message ->
val paidMedia = message.content.paidMediaInfo.media
val livePhotos = paidMedia.filterIsInstance<PaidMedia.LivePhoto>()
if (livePhotos.isNotEmpty()) {
println("=== Paid media with live photos received ===")
livePhotos.forEach { paidLivePhoto ->
// paidLivePhoto is PaidMedia.LivePhoto — PaidMediaLivePhoto class
val livePhotoFile = paidLivePhoto.livePhoto
println(" - fileId: ${livePhotoFile.fileId}, ${livePhotoFile.width}x${livePhotoFile.height}")
println(" duration: ${livePhotoFile.duration}s")
}
reply(message, "Received ${livePhotos.size} paid live photo(s)")
}
}
// Demonstrates: live_photo field in edited messages (EditedMessage with LivePhotoContent)
onEditedLivePhoto { message ->
println("=== Edited live photo received ===")
println(" fileId: ${message.content.media.fileId}")
println(" caption: ${message.content.text}")
}
allUpdatesFlow.subscribeLoggingDropExceptions(scope = this) {
println(it)
}
}.second.join()
}