mirror of
https://github.com/InsanusMokrassar/TelegramBotAPI.git
synced 2025-11-28 02:05:46 +00:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| eb08732938 |
65
CHANGELOG.md
65
CHANGELOG.md
@@ -1,70 +1,5 @@
|
||||
# TelegramBotAPI changelog
|
||||
|
||||
## 0.29.3
|
||||
|
||||
* `Common`:
|
||||
* Version updates:
|
||||
* `Serialization`: `1.0.0` -> `1.0.1`
|
||||
* `Core`:
|
||||
* New annotation `RiskFeature`. This annotation will be applied to the things which contains unsafe types usage
|
||||
* `SendMediaGroup` factory now marked with `RiskFeature`
|
||||
* Media groups updates:
|
||||
* New functions `SendPlaylist`
|
||||
* New functions `SendDocumentsGroup`
|
||||
* New functions `SendVisualMediaGroup`
|
||||
* New type `VisualMediaGroupMemberInputMedia : MediaGroupMemberInputMedia`
|
||||
* `InputMediaPhoto` now implements `VisualMediaGroupMemberInputMedia` instead of `MediaGroupMemberInputMedia`
|
||||
* `InputMediaVideo` now implements `VisualMediaGroupMemberInputMedia` instead of `MediaGroupMemberInputMedia`
|
||||
* New type `VisualMediaGroupContent : MediaGroupContent`
|
||||
* `PhotoContent` now implements `VisualMediaGroupContent` instead of `MediaGroupContent`
|
||||
* `VideoContent` now implements `VisualMediaGroupContent` instead of `MediaGroupContent`
|
||||
* New type `AudioMediaGroupContent : MediaGroupContent`
|
||||
* `AudioContent` now implements `AudioMediaGroupContent` instead of `MediaContent` and `CaptionedInput`
|
||||
* New type `DocumentMediaGroupContent : MediaGroupContent`
|
||||
* `DocumentContent` now implements `DocumentMediaGroupContent` instead of `MediaContent` and `CaptionedInput`
|
||||
* New type `AudioMediaGroupMemberInputMedia : MediaGroupMemberInputMedia`
|
||||
* `InputMediaAudio` now implements `AudioMediaGroupMemberInputMedia`
|
||||
* New type `DocumentMediaGroupMemberInputMedia : MediaGroupMemberInputMedia`
|
||||
* `InputMediaDocument` now implements `DocumentMediaGroupMemberInputMedia`
|
||||
* New extension `AudioFile#toInputMediaAudio`
|
||||
* `AudioContent` now implements `MediaGroupContent`
|
||||
* New extension `DocumentFile#toInputMediaDocument`
|
||||
* `DocumentContent` now implements `MediaGroupContent`
|
||||
* New dice type `SlotMachineDiceAnimationType`
|
||||
* New extension `TelegramMediaFile#asDocumentFile`
|
||||
* New extension `VideoFile#toInputMediaVideo`
|
||||
* New exception `WrongFileIdentifierException`
|
||||
* Extension `String#toInputMediaFileAttachmentName` now is deprecated
|
||||
* Property `ThumbedInputMedia#thumbMedia` now is deprecated
|
||||
* `API`:
|
||||
* New extensions for media groups:
|
||||
* `TelegramBot#sendPlaylist`
|
||||
* `TelegramBot#replyWithPlaylist`
|
||||
* `TelegramBot#sendDocumentsGroup`
|
||||
* `TelegramBot#replyWithDocumentsGroup`
|
||||
* `TelegramBot#sendVisualMediaGroup`
|
||||
* `TelegramBot#replyWithVisualMediaGroup`
|
||||
* `Utils`:
|
||||
* New extensions for `Flow`s:
|
||||
* `Flow<SentMediaGroupUpdate>#mediaGroupVisualMessages`
|
||||
* `Flow<SentMediaGroupUpdate>#mediaGroupAudioMessages`
|
||||
* `Flow<SentMediaGroupUpdate>#mediaGroupDocumentMessages`
|
||||
* New extensions for `FlowsUpdatesFilter`:
|
||||
* `FlowsUpdatesFilter#audioMessagesWithMediaGroups`
|
||||
* `FlowsUpdatesFilter#mediaGroupAudioMessages`
|
||||
* `FlowsUpdatesFilter#documentMessagesWithMediaGroups`
|
||||
* `FlowsUpdatesFilter#mediaGroupDocumentMessages`
|
||||
* `FlowsUpdatesFilter#mediaGroupVisualMessages`
|
||||
|
||||
## 0.29.2
|
||||
|
||||
* `Common`:
|
||||
* Version updates:
|
||||
* `Coroutines`: `1.3.9` -> `1.4.0`
|
||||
* Internal broadcast channels were replaced with `SharedFlow`
|
||||
* `TelegramBotAPI-extensions-utils`:
|
||||
* Extension `ReceiveChannel#debounceByValue` has been deprecated
|
||||
|
||||
## 0.29.1
|
||||
|
||||
* `Common`:
|
||||
|
||||
@@ -74,7 +74,7 @@ kotlin {
|
||||
|
||||

|
||||
|
||||
In most cases, the most simple way will be to implement [TelegramBotAPI](tgbotapi/README.md) - it contains
|
||||
In most cases, the most simple way will be to implement [TelegramBotAPI](TelegramBotAPI/README.md) - it contains
|
||||
all necessary tools for comfort usage of this library. If you want to exclude some libraries, you can implement just
|
||||
[TelegramBotAPI API Extensions](tgbotapi.extensions.api/README.md),
|
||||
[TelegramBotAPI Util Extensions](tgbotapi.extensions.utils/README.md) or even
|
||||
|
||||
@@ -46,17 +46,29 @@ kotlin {
|
||||
}
|
||||
}
|
||||
|
||||
private List<SourceDirectorySet> findSourcesWithName(String... approximateNames) {
|
||||
return parent.subprojects
|
||||
.findAll { it != project }
|
||||
.collectMany { it.kotlin.sourceSets }
|
||||
.findAll { sourceSet -> approximateNames.any {
|
||||
nameToFilter -> sourceSet.name.contains(nameToFilter)
|
||||
private Closure includeSourcesInDokka(String... approximateNames) {
|
||||
return {
|
||||
parent.subprojects.forEach {
|
||||
if (it != project) {
|
||||
File srcDir = new File(it.projectDir.absolutePath, "src")
|
||||
if (srcDir.exists() && srcDir.isDirectory()) {
|
||||
srcDir.eachFile { file ->
|
||||
if (approximateNames.any { file.name.contains(it) } && file.isDirectory()) {
|
||||
String pathToSrc = file.absolutePath
|
||||
sourceRoot {
|
||||
path = pathToSrc
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}.collect { it.kotlin }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tasks.dokkaHtml {
|
||||
dokka {
|
||||
outputFormat = 'html'
|
||||
|
||||
switch (true) {
|
||||
case project.hasProperty("DOKKA_PATH"):
|
||||
outputDirectory = project.property("DOKKA_PATH").toString()
|
||||
@@ -66,27 +78,19 @@ tasks.dokkaHtml {
|
||||
break
|
||||
}
|
||||
|
||||
dokkaSourceSets {
|
||||
configureEach {
|
||||
skipDeprecated.set(true)
|
||||
multiplatform {
|
||||
global {
|
||||
skipDeprecated = true
|
||||
|
||||
sourceLink {
|
||||
localDirectory.set(file("./"))
|
||||
remoteUrl.set(new URL("https://github.com/InsanusMokrassar/TelegramBotAPI/blob/master/"))
|
||||
remoteLineSuffix.set("#L")
|
||||
path = "./"
|
||||
url = "https://github.com/InsanusMokrassar/TelegramBotAPI/blob/master/"
|
||||
lineSuffix = "#L"
|
||||
}
|
||||
}
|
||||
|
||||
named("commonMain") {
|
||||
sourceRoots.setFrom(findSourcesWithName("commonMain"))
|
||||
}
|
||||
|
||||
named("jsMain") {
|
||||
sourceRoots.setFrom(findSourcesWithName("jsMain", "commonMain"))
|
||||
}
|
||||
|
||||
named("jvmMain") {
|
||||
sourceRoots.setFrom(findSourcesWithName("jvmMain", "commonMain"))
|
||||
}
|
||||
common(includeSourcesInDokka("commonMain"))
|
||||
js(includeSourcesInDokka("jsMain"/*, "commonMain"*/))
|
||||
jvm(includeSourcesInDokka("jvmMain"/*, "commonMain"*/))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
dokka_version=1.4.0
|
||||
dokka_version=0.10.1
|
||||
|
||||
org.gradle.jvmargs=-Xmx1024m
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
org.gradle.jvmargs=-Xmx2048m
|
||||
org.gradle.jvmargs=-Xmx1024m
|
||||
kotlin.code.style=official
|
||||
org.gradle.parallel=true
|
||||
kotlin.js.generate.externals=true
|
||||
@@ -6,8 +6,8 @@ kotlin.incremental=true
|
||||
kotlin.incremental.js=true
|
||||
|
||||
kotlin_version=1.4.10
|
||||
kotlin_coroutines_version=1.4.0
|
||||
kotlin_serialisation_runtime_version=1.0.1
|
||||
kotlin_coroutines_version=1.3.9
|
||||
kotlin_serialisation_runtime_version=1.0.0
|
||||
klock_version=1.12.1
|
||||
uuid_version=0.2.2
|
||||
ktor_version=1.4.1
|
||||
@@ -15,7 +15,7 @@ ktor_version=1.4.1
|
||||
javax_activation_version=1.1.1
|
||||
|
||||
library_group=dev.inmo
|
||||
library_version=0.29.3
|
||||
library_version=0.29.1
|
||||
|
||||
gradle_bintray_plugin_version=1.8.5
|
||||
github_release_plugin_version=2.2.12
|
||||
|
||||
@@ -1,10 +1,3 @@
|
||||
pluginManagement {
|
||||
repositories {
|
||||
gradlePluginPortal()
|
||||
jcenter()
|
||||
}
|
||||
}
|
||||
|
||||
include ":tgbotapi.core"
|
||||
include ":tgbotapi.extensions.api"
|
||||
include ":tgbotapi.extensions.utils"
|
||||
|
||||
@@ -15,7 +15,6 @@ fun newRequestException(
|
||||
description.contains("Bad Request: message is not modified") -> MessageIsNotModifiedException(response, plainAnswer, message, cause)
|
||||
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)
|
||||
else -> null
|
||||
}
|
||||
} ?: CommonRequestException(response, plainAnswer, message, cause)
|
||||
@@ -46,6 +45,3 @@ class MessageToEditNotFoundException(response: Response, plainAnswer: String, me
|
||||
|
||||
class InvalidPhotoDimensionsException(response: Response, plainAnswer: String, message: String?, cause: Throwable?) :
|
||||
RequestException(response, plainAnswer, message, cause)
|
||||
|
||||
class WrongFileIdentifierException(response: Response, plainAnswer: String, message: String?, cause: Throwable?) :
|
||||
RequestException(response, plainAnswer, message, cause)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package dev.inmo.tgbotapi.requests.abstracts
|
||||
|
||||
import dev.inmo.tgbotapi.types.InputMedia.toInputMediaFileAttachmentName
|
||||
import dev.inmo.tgbotapi.utils.StorageFile
|
||||
import kotlinx.serialization.*
|
||||
import kotlinx.serialization.descriptors.*
|
||||
@@ -11,14 +12,6 @@ sealed class InputFile {
|
||||
abstract val fileId: String
|
||||
}
|
||||
|
||||
internal inline val InputFile.attachFileId
|
||||
get() = "attach://$fileId"
|
||||
internal inline val InputFile.fileIdToSend
|
||||
get() = when (this) {
|
||||
is FileId -> fileId
|
||||
is MultipartFile -> attachFileId
|
||||
}
|
||||
|
||||
// TODO:: add checks for file url/file id regex
|
||||
/**
|
||||
* Contains file id or file url
|
||||
@@ -37,6 +30,12 @@ internal object InputFileSerializer : KSerializer<InputFile> {
|
||||
override fun deserialize(decoder: Decoder): FileId = FileId(decoder.decodeString())
|
||||
}
|
||||
|
||||
internal val InputFile.asMediaData: String
|
||||
get() = when (this) {
|
||||
is FileId -> fileId
|
||||
is MultipartFile -> fileId.toInputMediaFileAttachmentName()
|
||||
}
|
||||
|
||||
// TODO:: add checks for files size
|
||||
/**
|
||||
* Contains info about file for sending
|
||||
|
||||
@@ -8,16 +8,12 @@ import dev.inmo.tgbotapi.types.*
|
||||
import dev.inmo.tgbotapi.types.InputMedia.*
|
||||
import dev.inmo.tgbotapi.types.message.abstracts.MediaGroupMessage
|
||||
import dev.inmo.tgbotapi.types.message.abstracts.TelegramBotAPIMessageDeserializeOnlySerializerClass
|
||||
import dev.inmo.tgbotapi.utils.*
|
||||
import dev.inmo.tgbotapi.utils.throwRangeError
|
||||
import dev.inmo.tgbotapi.utils.toJsonWithoutNulls
|
||||
import kotlinx.serialization.*
|
||||
import kotlinx.serialization.builtins.ListSerializer
|
||||
import kotlinx.serialization.json.buildJsonArray
|
||||
|
||||
const val rawSendingMediaGroupsWarning = "Media groups contains restrictions related to combinations of media" +
|
||||
" types. Currently it is possible to combine photo + video OR audio OR documents"
|
||||
|
||||
@RiskFeature(rawSendingMediaGroupsWarning)
|
||||
fun SendMediaGroup(
|
||||
chatId: ChatIdentifier,
|
||||
media: List<MediaGroupMemberInputMedia>,
|
||||
@@ -56,46 +52,6 @@ fun SendMediaGroup(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this method to be sure that you are correctly sending playlist with audios
|
||||
*
|
||||
* @see InputMediaAudio
|
||||
*/
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
inline fun SendPlaylist(
|
||||
chatId: ChatIdentifier,
|
||||
media: List<AudioMediaGroupMemberInputMedia>,
|
||||
disableNotification: Boolean = false,
|
||||
replyToMessageId: MessageIdentifier? = null
|
||||
) = SendMediaGroup(chatId, media, disableNotification, replyToMessageId)
|
||||
|
||||
/**
|
||||
* Use this method to be sure that you are correctly sending documents media group
|
||||
*
|
||||
* @see InputMediaDocument
|
||||
*/
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
inline fun SendDocumentsGroup(
|
||||
chatId: ChatIdentifier,
|
||||
media: List<DocumentMediaGroupMemberInputMedia>,
|
||||
disableNotification: Boolean = false,
|
||||
replyToMessageId: MessageIdentifier? = null
|
||||
) = SendMediaGroup(chatId, media, disableNotification, replyToMessageId)
|
||||
|
||||
/**
|
||||
* Use this method to be sure that you are correctly sending visual media group
|
||||
*
|
||||
* @see InputMediaPhoto
|
||||
* @see InputMediaVideo
|
||||
*/
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
inline fun SendVisualMediaGroup(
|
||||
chatId: ChatIdentifier,
|
||||
media: List<VisualMediaGroupMemberInputMedia>,
|
||||
disableNotification: Boolean = false,
|
||||
replyToMessageId: MessageIdentifier? = null
|
||||
) = SendMediaGroup(chatId, media, disableNotification, replyToMessageId)
|
||||
|
||||
private val messagesListSerializer: KSerializer<List<MediaGroupMessage>>
|
||||
= ListSerializer(TelegramBotAPIMessageDeserializeOnlySerializerClass())
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@ package dev.inmo.tgbotapi.types.InputMedia
|
||||
import dev.inmo.tgbotapi.requests.abstracts.InputFile
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Deprecated("Will be removed due to redundancy for end-side users")
|
||||
fun String.toInputMediaFileAttachmentName() = "attach://$this"
|
||||
|
||||
@Serializable(InputMediaSerializer::class)
|
||||
|
||||
@@ -23,5 +23,5 @@ data class InputMediaAnimation(
|
||||
|
||||
@SerialName(mediaField)
|
||||
override val media: String
|
||||
init { media = file.fileIdToSend } // crutch until js compiling will be fixed
|
||||
init { media = file.fileId } // crutch until js compiling will be fixed
|
||||
}
|
||||
|
||||
@@ -5,13 +5,9 @@ import dev.inmo.tgbotapi.CommonAbstracts.Performerable
|
||||
import dev.inmo.tgbotapi.requests.abstracts.*
|
||||
import dev.inmo.tgbotapi.types.ParseMode.ParseMode
|
||||
import dev.inmo.tgbotapi.types.ParseMode.parseModeField
|
||||
import dev.inmo.tgbotapi.types.files.AudioFile
|
||||
import dev.inmo.tgbotapi.types.files.PhotoSize
|
||||
import dev.inmo.tgbotapi.types.mediaField
|
||||
import dev.inmo.tgbotapi.types.message.content.media.AudioContent
|
||||
import kotlinx.serialization.*
|
||||
|
||||
internal const val audioInputMediaType = "audio"
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class InputMediaAudio(
|
||||
@@ -23,26 +19,10 @@ data class InputMediaAudio(
|
||||
override val performer: String? = null,
|
||||
override val title: String? = null,
|
||||
override val thumb: InputFile? = null
|
||||
) : InputMedia, AudioMediaGroupMemberInputMedia, DuratedInputMedia, ThumbedInputMedia, TitledInputMedia, CaptionedOutput, Performerable {
|
||||
override val type: String = audioInputMediaType
|
||||
|
||||
override fun serialize(format: StringFormat): String = format.encodeToString(serializer(), this)
|
||||
) : InputMedia, DuratedInputMedia, ThumbedInputMedia, TitledInputMedia, CaptionedOutput, Performerable {
|
||||
override val type: String = "audio"
|
||||
|
||||
@SerialName(mediaField)
|
||||
override val media: String
|
||||
init { media = file.fileIdToSend } // crutch until js compiling will be fixed
|
||||
init { media = file.fileId } // crutch until js compiling will be fixed
|
||||
}
|
||||
|
||||
fun AudioFile.toInputMediaAudio(
|
||||
caption: String? = null,
|
||||
parseMode: ParseMode? = null,
|
||||
title: String? = this.title
|
||||
): InputMediaAudio = InputMediaAudio(
|
||||
fileId,
|
||||
caption,
|
||||
parseMode,
|
||||
duration,
|
||||
performer,
|
||||
title,
|
||||
thumb ?.fileId
|
||||
)
|
||||
|
||||
@@ -4,11 +4,9 @@ import dev.inmo.tgbotapi.CommonAbstracts.CaptionedOutput
|
||||
import dev.inmo.tgbotapi.requests.abstracts.*
|
||||
import dev.inmo.tgbotapi.types.ParseMode.ParseMode
|
||||
import dev.inmo.tgbotapi.types.ParseMode.parseModeField
|
||||
import dev.inmo.tgbotapi.types.files.DocumentFile
|
||||
import dev.inmo.tgbotapi.types.mediaField
|
||||
import kotlinx.serialization.*
|
||||
|
||||
internal const val documentInputMediaType = "document"
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class InputMediaDocument(
|
||||
@@ -17,22 +15,10 @@ data class InputMediaDocument(
|
||||
@SerialName(parseModeField)
|
||||
override val parseMode: ParseMode? = null,
|
||||
override val thumb: InputFile? = null
|
||||
) : InputMedia, DocumentMediaGroupMemberInputMedia, ThumbedInputMedia, CaptionedOutput {
|
||||
override val type: String = documentInputMediaType
|
||||
|
||||
override fun serialize(format: StringFormat): String = format.encodeToString(serializer(), this)
|
||||
) : InputMedia, ThumbedInputMedia, CaptionedOutput {
|
||||
override val type: String = "document"
|
||||
|
||||
@SerialName(mediaField)
|
||||
override val media: String
|
||||
init { media = file.fileIdToSend } // crutch until js compiling will be fixed
|
||||
init { media = file.fileId } // crutch until js compiling will be fixed
|
||||
}
|
||||
|
||||
fun DocumentFile.toInputMediaDocument(
|
||||
caption: String? = null,
|
||||
parseMode: ParseMode? = null
|
||||
) = InputMediaDocument(
|
||||
fileId,
|
||||
caption,
|
||||
parseMode,
|
||||
thumb ?.fileId
|
||||
)
|
||||
|
||||
@@ -17,14 +17,14 @@ data class InputMediaPhoto(
|
||||
override val caption: String? = null,
|
||||
@SerialName(parseModeField)
|
||||
override val parseMode: ParseMode? = null
|
||||
) : InputMedia, VisualMediaGroupMemberInputMedia {
|
||||
) : InputMedia, MediaGroupMemberInputMedia {
|
||||
override val type: String = photoInputMediaType
|
||||
|
||||
override fun serialize(format: StringFormat): String = format.encodeToString(serializer(), this)
|
||||
|
||||
@SerialName(mediaField)
|
||||
override val media: String
|
||||
init { media = file.fileIdToSend } // crutch until js compiling will be fixed
|
||||
init { media = file.fileId } // crutch until js compiling will be fixed
|
||||
}
|
||||
|
||||
fun PhotoSize.toInputMediaPhoto(
|
||||
|
||||
@@ -19,12 +19,12 @@ data class InputMediaVideo(
|
||||
override val height: Int? = null,
|
||||
override val duration: Long? = null,
|
||||
override val thumb: InputFile? = null
|
||||
) : InputMedia, SizedInputMedia, DuratedInputMedia, ThumbedInputMedia, VisualMediaGroupMemberInputMedia {
|
||||
) : InputMedia, SizedInputMedia, DuratedInputMedia, ThumbedInputMedia, MediaGroupMemberInputMedia {
|
||||
override val type: String = videoInputMediaType
|
||||
|
||||
override fun serialize(format: StringFormat): String = format.encodeToString(serializer(), this)
|
||||
|
||||
@SerialName(mediaField)
|
||||
override val media: String
|
||||
init { media = file.fileIdToSend } // crutch until js compiling will be fixed
|
||||
init { media = file.fileId } // crutch until js compiling will be fixed
|
||||
}
|
||||
|
||||
@@ -18,9 +18,3 @@ internal fun <T> T.buildArguments(withSerializer: SerializationStrategy<T>) = ar
|
||||
interface MediaGroupMemberInputMedia : InputMedia, CaptionedOutput {
|
||||
fun serialize(format: StringFormat): String
|
||||
}
|
||||
|
||||
interface AudioMediaGroupMemberInputMedia: MediaGroupMemberInputMedia
|
||||
interface DocumentMediaGroupMemberInputMedia: MediaGroupMemberInputMedia
|
||||
|
||||
@Serializable(MediaGroupMemberInputMediaSerializer::class)
|
||||
interface VisualMediaGroupMemberInputMedia : MediaGroupMemberInputMedia
|
||||
|
||||
@@ -16,8 +16,6 @@ internal object MediaGroupMemberInputMediaSerializer : KSerializer<MediaGroupMem
|
||||
when (value) {
|
||||
is InputMediaPhoto -> InputMediaPhoto.serializer().serialize(encoder, value)
|
||||
is InputMediaVideo -> InputMediaVideo.serializer().serialize(encoder, value)
|
||||
is InputMediaAudio -> InputMediaAudio.serializer().serialize(encoder, value)
|
||||
is InputMediaDocument -> InputMediaDocument.serializer().serialize(encoder, value)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,8 +25,6 @@ internal object MediaGroupMemberInputMediaSerializer : KSerializer<MediaGroupMem
|
||||
return when (json[typeField] ?.jsonPrimitive ?.contentOrNull) {
|
||||
photoInputMediaType -> nonstrictJsonFormat.decodeFromJsonElement(InputMediaPhoto.serializer(), json)
|
||||
videoInputMediaType -> nonstrictJsonFormat.decodeFromJsonElement(InputMediaVideo.serializer(), json)
|
||||
audioInputMediaType -> nonstrictJsonFormat.decodeFromJsonElement(InputMediaAudio.serializer(), json)
|
||||
documentInputMediaType -> nonstrictJsonFormat.decodeFromJsonElement(InputMediaDocument.serializer(), json)
|
||||
else -> error("Illegal type of incoming MediaGroupMemberInputMedia")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@ interface ThumbedInputMedia : InputMedia {
|
||||
val thumb: InputFile?
|
||||
@Serializable
|
||||
@SerialName(thumbField)
|
||||
@Deprecated("Will be removed due to useless state")
|
||||
val thumbMedia: String?
|
||||
get() = thumb ?.let {
|
||||
when (it) {
|
||||
|
||||
@@ -22,10 +22,6 @@ object BasketballDiceAnimationType : DiceAnimationType() {
|
||||
override val emoji: String = "\uD83C\uDFC0"
|
||||
}
|
||||
@Serializable(DiceAnimationTypeSerializer::class)
|
||||
object SlotMachineDiceAnimationType : DiceAnimationType() {
|
||||
override val emoji: String = "\uD83C\uDFB0"
|
||||
}
|
||||
@Serializable(DiceAnimationTypeSerializer::class)
|
||||
data class CustomDiceAnimationType(
|
||||
override val emoji: String
|
||||
) : DiceAnimationType()
|
||||
@@ -38,7 +34,6 @@ internal object DiceAnimationTypeSerializer : KSerializer<DiceAnimationType> {
|
||||
CubeDiceAnimationType.emoji -> CubeDiceAnimationType
|
||||
DartsDiceAnimationType.emoji -> DartsDiceAnimationType
|
||||
BasketballDiceAnimationType.emoji -> BasketballDiceAnimationType
|
||||
SlotMachineDiceAnimationType.emoji -> SlotMachineDiceAnimationType
|
||||
else -> CustomDiceAnimationType(type)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,13 +22,3 @@ data class DocumentFile(
|
||||
@SerialName(fileNameField)
|
||||
override val fileName: String? = null
|
||||
) : TelegramMediaFile, MimedMediaFile, ThumbedMediaFile, CustomNamedMediaFile
|
||||
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
inline fun TelegramMediaFile.asDocumentFile() = DocumentFile(
|
||||
fileId,
|
||||
fileUniqueId,
|
||||
fileSize,
|
||||
(this as? ThumbedMediaFile) ?.thumb,
|
||||
(this as? MimedMediaFile) ?.mimeType,
|
||||
(this as? CustomNamedMediaFile) ?.fileName
|
||||
)
|
||||
|
||||
@@ -2,13 +2,9 @@ package dev.inmo.tgbotapi.types.files
|
||||
|
||||
import dev.inmo.tgbotapi.requests.abstracts.FileId
|
||||
import dev.inmo.tgbotapi.types.FileUniqueId
|
||||
import dev.inmo.tgbotapi.types.InputMedia.InputMediaVideo
|
||||
import dev.inmo.tgbotapi.types.ParseMode.HTMLParseMode
|
||||
import dev.inmo.tgbotapi.types.ParseMode.ParseMode
|
||||
import dev.inmo.tgbotapi.types.fileUniqueIdField
|
||||
import dev.inmo.tgbotapi.types.files.abstracts.*
|
||||
import dev.inmo.tgbotapi.utils.MimeType
|
||||
import dev.inmo.tgbotapi.utils.toHtmlCaptions
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@@ -27,17 +23,3 @@ data class VideoFile(
|
||||
@SerialName(fileSizeField)
|
||||
override val fileSize: Long? = null
|
||||
) : TelegramMediaFile, MimedMediaFile, ThumbedMediaFile, PlayableMediaFile, SizedMediaFile
|
||||
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
inline fun VideoFile.toInputMediaVideo(
|
||||
caption: String? = null,
|
||||
parseMode: ParseMode? = null
|
||||
) = InputMediaVideo(
|
||||
fileId,
|
||||
caption,
|
||||
parseMode,
|
||||
width,
|
||||
height,
|
||||
duration,
|
||||
thumb ?.fileId
|
||||
)
|
||||
|
||||
@@ -220,20 +220,17 @@ internal data class RawMessage(
|
||||
}
|
||||
} ?: content?.let { content ->
|
||||
media_group_id?.let {
|
||||
val checkedContent = when (content) {
|
||||
is PhotoContent -> content
|
||||
is VideoContent -> content
|
||||
is AudioContent -> content
|
||||
is DocumentContent -> content
|
||||
else -> error("Unsupported content for media group")
|
||||
}
|
||||
when (from) {
|
||||
null -> ChannelMediaGroupMessage(
|
||||
messageId,
|
||||
chat,
|
||||
date.asDate,
|
||||
it,
|
||||
checkedContent,
|
||||
when (content) {
|
||||
is PhotoContent -> content
|
||||
is VideoContent -> content
|
||||
else -> error("Unsupported content for media group")
|
||||
},
|
||||
edit_date?.asDate,
|
||||
forwarded,
|
||||
reply_to_message?.asMessage,
|
||||
@@ -245,7 +242,11 @@ internal data class RawMessage(
|
||||
chat,
|
||||
date.asDate,
|
||||
it,
|
||||
checkedContent,
|
||||
when (content) {
|
||||
is PhotoContent -> content
|
||||
is VideoContent -> content
|
||||
else -> error("Unsupported content for media group")
|
||||
},
|
||||
edit_date?.asDate,
|
||||
forwarded,
|
||||
reply_to_message?.asMessage,
|
||||
|
||||
@@ -5,8 +5,4 @@ import dev.inmo.tgbotapi.types.InputMedia.MediaGroupMemberInputMedia
|
||||
|
||||
interface MediaGroupContent : MediaContent, CaptionedInput {
|
||||
fun toMediaGroupMemberInputMedia(): MediaGroupMemberInputMedia
|
||||
}
|
||||
|
||||
interface VisualMediaGroupContent : MediaGroupContent
|
||||
interface AudioMediaGroupContent : MediaGroupContent
|
||||
interface DocumentMediaGroupContent : MediaGroupContent
|
||||
}
|
||||
@@ -1,17 +1,18 @@
|
||||
package dev.inmo.tgbotapi.types.message.content.media
|
||||
|
||||
import dev.inmo.tgbotapi.CommonAbstracts.CaptionedInput
|
||||
import dev.inmo.tgbotapi.CommonAbstracts.TextPart
|
||||
import dev.inmo.tgbotapi.requests.abstracts.Request
|
||||
import dev.inmo.tgbotapi.requests.send.media.SendAudio
|
||||
import dev.inmo.tgbotapi.types.ChatIdentifier
|
||||
import dev.inmo.tgbotapi.types.InputMedia.*
|
||||
import dev.inmo.tgbotapi.types.InputMedia.InputMediaAudio
|
||||
import dev.inmo.tgbotapi.types.MessageIdentifier
|
||||
import dev.inmo.tgbotapi.types.ParseMode.HTMLParseMode
|
||||
import dev.inmo.tgbotapi.types.ParseMode.MarkdownV2
|
||||
import dev.inmo.tgbotapi.types.buttons.KeyboardMarkup
|
||||
import dev.inmo.tgbotapi.types.files.AudioFile
|
||||
import dev.inmo.tgbotapi.types.message.abstracts.ContentMessage
|
||||
import dev.inmo.tgbotapi.types.message.content.abstracts.*
|
||||
import dev.inmo.tgbotapi.types.message.content.abstracts.MediaContent
|
||||
import dev.inmo.tgbotapi.utils.toHtmlCaptions
|
||||
import dev.inmo.tgbotapi.utils.toMarkdownV2Captions
|
||||
|
||||
@@ -19,7 +20,7 @@ data class AudioContent(
|
||||
override val media: AudioFile,
|
||||
override val caption: String? = null,
|
||||
override val captionEntities: List<TextPart> = emptyList()
|
||||
) : AudioMediaGroupContent {
|
||||
) : MediaContent, CaptionedInput {
|
||||
override fun createResend(
|
||||
chatId: ChatIdentifier,
|
||||
disableNotification: Boolean,
|
||||
@@ -39,10 +40,13 @@ data class AudioContent(
|
||||
replyMarkup
|
||||
)
|
||||
|
||||
override fun toMediaGroupMemberInputMedia(): InputMediaAudio = asInputMedia()
|
||||
|
||||
override fun asInputMedia(): InputMediaAudio = media.toInputMediaAudio(
|
||||
toHtmlCaptions().firstOrNull(),
|
||||
HTMLParseMode
|
||||
override fun asInputMedia(): InputMediaAudio = InputMediaAudio(
|
||||
media.fileId,
|
||||
toMarkdownV2Captions().firstOrNull(),
|
||||
MarkdownV2,
|
||||
media.duration,
|
||||
media.performer,
|
||||
media.title,
|
||||
media.thumb ?.fileId
|
||||
)
|
||||
}
|
||||
|
||||
@@ -5,15 +5,14 @@ import dev.inmo.tgbotapi.CommonAbstracts.TextPart
|
||||
import dev.inmo.tgbotapi.requests.abstracts.Request
|
||||
import dev.inmo.tgbotapi.requests.send.media.SendDocument
|
||||
import dev.inmo.tgbotapi.types.ChatIdentifier
|
||||
import dev.inmo.tgbotapi.types.InputMedia.*
|
||||
import dev.inmo.tgbotapi.types.InputMedia.InputMediaDocument
|
||||
import dev.inmo.tgbotapi.types.MessageIdentifier
|
||||
import dev.inmo.tgbotapi.types.ParseMode.HTMLParseMode
|
||||
import dev.inmo.tgbotapi.types.ParseMode.MarkdownV2
|
||||
import dev.inmo.tgbotapi.types.buttons.KeyboardMarkup
|
||||
import dev.inmo.tgbotapi.types.files.DocumentFile
|
||||
import dev.inmo.tgbotapi.types.files.asDocumentFile
|
||||
import dev.inmo.tgbotapi.types.message.abstracts.ContentMessage
|
||||
import dev.inmo.tgbotapi.types.message.content.abstracts.*
|
||||
import dev.inmo.tgbotapi.types.message.content.abstracts.MediaContent
|
||||
import dev.inmo.tgbotapi.utils.toHtmlCaptions
|
||||
import dev.inmo.tgbotapi.utils.toMarkdownV2Captions
|
||||
|
||||
@@ -21,7 +20,7 @@ data class DocumentContent(
|
||||
override val media: DocumentFile,
|
||||
override val caption: String? = null,
|
||||
override val captionEntities: List<TextPart> = emptyList()
|
||||
) : DocumentMediaGroupContent {
|
||||
) : MediaContent, CaptionedInput {
|
||||
override fun createResend(
|
||||
chatId: ChatIdentifier,
|
||||
disableNotification: Boolean,
|
||||
@@ -38,22 +37,10 @@ data class DocumentContent(
|
||||
replyMarkup
|
||||
)
|
||||
|
||||
override fun toMediaGroupMemberInputMedia(): InputMediaDocument = asInputMedia()
|
||||
|
||||
override fun asInputMedia(): InputMediaDocument = media.toInputMediaDocument(
|
||||
toHtmlCaptions().firstOrNull(),
|
||||
HTMLParseMode
|
||||
)
|
||||
}
|
||||
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
inline fun MediaContent.asDocumentContent() = when (this) {
|
||||
is CaptionedInput -> DocumentContent(
|
||||
media.asDocumentFile(),
|
||||
caption,
|
||||
captionEntities
|
||||
)
|
||||
else -> DocumentContent(
|
||||
media.asDocumentFile()
|
||||
override fun asInputMedia(): InputMediaDocument = InputMediaDocument(
|
||||
media.fileId,
|
||||
toMarkdownV2Captions().firstOrNull(),
|
||||
MarkdownV2,
|
||||
media.thumb ?.fileId
|
||||
)
|
||||
}
|
||||
|
||||
@@ -4,14 +4,16 @@ import dev.inmo.tgbotapi.CommonAbstracts.TextPart
|
||||
import dev.inmo.tgbotapi.requests.abstracts.Request
|
||||
import dev.inmo.tgbotapi.requests.send.media.SendPhoto
|
||||
import dev.inmo.tgbotapi.types.ChatIdentifier
|
||||
import dev.inmo.tgbotapi.types.InputMedia.*
|
||||
import dev.inmo.tgbotapi.types.InputMedia.InputMediaPhoto
|
||||
import dev.inmo.tgbotapi.types.InputMedia.MediaGroupMemberInputMedia
|
||||
import dev.inmo.tgbotapi.types.MessageIdentifier
|
||||
import dev.inmo.tgbotapi.types.ParseMode.HTMLParseMode
|
||||
import dev.inmo.tgbotapi.types.ParseMode.MarkdownV2
|
||||
import dev.inmo.tgbotapi.types.buttons.KeyboardMarkup
|
||||
import dev.inmo.tgbotapi.types.files.*
|
||||
import dev.inmo.tgbotapi.types.message.abstracts.ContentMessage
|
||||
import dev.inmo.tgbotapi.types.message.content.abstracts.*
|
||||
import dev.inmo.tgbotapi.types.message.content.abstracts.MediaCollectionContent
|
||||
import dev.inmo.tgbotapi.types.message.content.abstracts.MediaGroupContent
|
||||
import dev.inmo.tgbotapi.utils.toHtmlCaptions
|
||||
import dev.inmo.tgbotapi.utils.toMarkdownV2Captions
|
||||
|
||||
@@ -19,7 +21,7 @@ data class PhotoContent(
|
||||
override val mediaCollection: Photo,
|
||||
override val caption: String? = null,
|
||||
override val captionEntities: List<TextPart> = emptyList()
|
||||
) : MediaCollectionContent<PhotoSize>, VisualMediaGroupContent {
|
||||
) : MediaCollectionContent<PhotoSize>, MediaGroupContent {
|
||||
override val media: PhotoSize = mediaCollection.biggest() ?: throw IllegalStateException("Can't locate any photo size for this content")
|
||||
|
||||
override fun createResend(
|
||||
@@ -37,10 +39,15 @@ data class PhotoContent(
|
||||
replyMarkup
|
||||
)
|
||||
|
||||
override fun toMediaGroupMemberInputMedia(): InputMediaPhoto = asInputMedia()
|
||||
|
||||
override fun asInputMedia(): InputMediaPhoto = media.toInputMediaPhoto(
|
||||
override fun toMediaGroupMemberInputMedia(): MediaGroupMemberInputMedia = InputMediaPhoto(
|
||||
media.fileId,
|
||||
toHtmlCaptions().firstOrNull(),
|
||||
HTMLParseMode
|
||||
)
|
||||
|
||||
override fun asInputMedia(): InputMediaPhoto = InputMediaPhoto(
|
||||
media.fileId,
|
||||
toMarkdownV2Captions().firstOrNull(),
|
||||
MarkdownV2
|
||||
)
|
||||
}
|
||||
|
||||
@@ -11,10 +11,8 @@ import dev.inmo.tgbotapi.types.ParseMode.HTMLParseMode
|
||||
import dev.inmo.tgbotapi.types.ParseMode.MarkdownV2
|
||||
import dev.inmo.tgbotapi.types.buttons.KeyboardMarkup
|
||||
import dev.inmo.tgbotapi.types.files.VideoFile
|
||||
import dev.inmo.tgbotapi.types.files.toInputMediaVideo
|
||||
import dev.inmo.tgbotapi.types.message.abstracts.ContentMessage
|
||||
import dev.inmo.tgbotapi.types.message.content.abstracts.MediaGroupContent
|
||||
import dev.inmo.tgbotapi.types.message.content.abstracts.VisualMediaGroupContent
|
||||
import dev.inmo.tgbotapi.utils.toHtmlCaptions
|
||||
import dev.inmo.tgbotapi.utils.toMarkdownV2Captions
|
||||
|
||||
@@ -22,7 +20,7 @@ data class VideoContent(
|
||||
override val media: VideoFile,
|
||||
override val caption: String? = null,
|
||||
override val captionEntities: List<TextPart> = emptyList()
|
||||
) : VisualMediaGroupContent {
|
||||
) : MediaGroupContent {
|
||||
override fun createResend(
|
||||
chatId: ChatIdentifier,
|
||||
disableNotification: Boolean,
|
||||
@@ -43,10 +41,23 @@ data class VideoContent(
|
||||
replyMarkup
|
||||
)
|
||||
|
||||
override fun toMediaGroupMemberInputMedia(): InputMediaVideo = asInputMedia()
|
||||
|
||||
override fun asInputMedia(): InputMediaVideo = media.toInputMediaVideo(
|
||||
override fun toMediaGroupMemberInputMedia(): MediaGroupMemberInputMedia = InputMediaVideo(
|
||||
media.fileId,
|
||||
toHtmlCaptions().firstOrNull(),
|
||||
HTMLParseMode
|
||||
HTMLParseMode,
|
||||
media.width,
|
||||
media.height,
|
||||
media.duration,
|
||||
media.thumb ?.fileId
|
||||
)
|
||||
|
||||
override fun asInputMedia(): InputMediaVideo = InputMediaVideo(
|
||||
media.fileId,
|
||||
toMarkdownV2Captions().firstOrNull(),
|
||||
MarkdownV2,
|
||||
media.width,
|
||||
media.height,
|
||||
media.duration,
|
||||
media.thumb ?.fileId
|
||||
)
|
||||
}
|
||||
|
||||
@@ -5,20 +5,21 @@ import dev.inmo.tgbotapi.types.update.*
|
||||
import dev.inmo.tgbotapi.types.update.MediaGroupUpdates.*
|
||||
import dev.inmo.tgbotapi.types.update.abstracts.UnknownUpdate
|
||||
import dev.inmo.tgbotapi.types.update.abstracts.Update
|
||||
import kotlinx.coroutines.channels.BroadcastChannel
|
||||
import kotlinx.coroutines.flow.*
|
||||
|
||||
@Suppress("EXPERIMENTAL_API_USAGE", "unused")
|
||||
class FlowsUpdatesFilter(
|
||||
broadcastChannelsSize: Int = 100
|
||||
): UpdatesFilter {
|
||||
private val updatesSharedFlow = MutableSharedFlow<Update>(extraBufferCapacity = broadcastChannelsSize)
|
||||
private val updatesReceivingChannel = BroadcastChannel<Update>(broadcastChannelsSize)
|
||||
@Suppress("MemberVisibilityCanBePrivate")
|
||||
val allUpdatesFlow: Flow<Update> = updatesSharedFlow.asSharedFlow()
|
||||
val allUpdatesFlow: Flow<Update> = updatesReceivingChannel.asFlow()
|
||||
|
||||
override val allowedUpdates: List<String>
|
||||
get() = ALL_UPDATES_LIST
|
||||
override val asUpdateReceiver: UpdateReceiver<Update> = {
|
||||
updatesSharedFlow.emit(it)
|
||||
updatesReceivingChannel.send(it)
|
||||
}
|
||||
|
||||
val messageFlow: Flow<MessageUpdate> = allUpdatesFlow.filterIsInstance()
|
||||
|
||||
@@ -17,21 +17,3 @@ package dev.inmo.tgbotapi.utils
|
||||
AnnotationTarget.TYPE_PARAMETER
|
||||
)
|
||||
annotation class PreviewFeature
|
||||
|
||||
@RequiresOptIn(
|
||||
"This feature can work unstable and may have some restrictions in Telegram System",
|
||||
RequiresOptIn.Level.WARNING
|
||||
)
|
||||
@Target(
|
||||
AnnotationTarget.CLASS,
|
||||
AnnotationTarget.CONSTRUCTOR,
|
||||
AnnotationTarget.FIELD,
|
||||
AnnotationTarget.PROPERTY,
|
||||
AnnotationTarget.PROPERTY_GETTER,
|
||||
AnnotationTarget.PROPERTY_SETTER,
|
||||
AnnotationTarget.FUNCTION,
|
||||
AnnotationTarget.TYPE,
|
||||
AnnotationTarget.TYPEALIAS,
|
||||
AnnotationTarget.TYPE_PARAMETER
|
||||
)
|
||||
annotation class RiskFeature(val message: String)
|
||||
|
||||
@@ -11,7 +11,6 @@ private sealed class DebounceAction<T> {
|
||||
private data class AddValue<T>(override val value: T) : DebounceAction<T>()
|
||||
private data class RemoveJob<T>(override val value: T, val job: Job) : DebounceAction<T>()
|
||||
|
||||
@Deprecated("Unused and will be removed in next major release")
|
||||
fun <T> ReceiveChannel<T>.debounceByValue(
|
||||
delayMillis: Long,
|
||||
scope: CoroutineScope = CoroutineScope(Dispatchers.Default),
|
||||
|
||||
@@ -1,18 +1,13 @@
|
||||
package dev.inmo.tgbotapi.extensions.api.send.media
|
||||
|
||||
import dev.inmo.tgbotapi.bot.TelegramBot
|
||||
import dev.inmo.tgbotapi.requests.send.media.*
|
||||
import dev.inmo.tgbotapi.requests.send.media.SendMediaGroup
|
||||
import dev.inmo.tgbotapi.types.ChatIdentifier
|
||||
import dev.inmo.tgbotapi.types.InputMedia.*
|
||||
import dev.inmo.tgbotapi.types.InputMedia.MediaGroupMemberInputMedia
|
||||
import dev.inmo.tgbotapi.types.MessageIdentifier
|
||||
import dev.inmo.tgbotapi.types.chat.abstracts.Chat
|
||||
import dev.inmo.tgbotapi.types.message.abstracts.Message
|
||||
import dev.inmo.tgbotapi.utils.RiskFeature
|
||||
|
||||
/**
|
||||
* @see SendMediaGroup
|
||||
*/
|
||||
@RiskFeature(rawSendingMediaGroupsWarning)
|
||||
suspend fun TelegramBot.sendMediaGroup(
|
||||
chatId: ChatIdentifier,
|
||||
media: List<MediaGroupMemberInputMedia>,
|
||||
@@ -24,10 +19,6 @@ suspend fun TelegramBot.sendMediaGroup(
|
||||
)
|
||||
)
|
||||
|
||||
/**
|
||||
* @see SendMediaGroup
|
||||
*/
|
||||
@RiskFeature(rawSendingMediaGroupsWarning)
|
||||
suspend fun TelegramBot.sendMediaGroup(
|
||||
chat: Chat,
|
||||
media: List<MediaGroupMemberInputMedia>,
|
||||
@@ -37,108 +28,12 @@ suspend fun TelegramBot.sendMediaGroup(
|
||||
chat.id, media, disableNotification, replyToMessageId
|
||||
)
|
||||
|
||||
/**
|
||||
* @see SendPlaylist
|
||||
*/
|
||||
suspend fun TelegramBot.sendPlaylist(
|
||||
chatId: ChatIdentifier,
|
||||
media: List<AudioMediaGroupMemberInputMedia>,
|
||||
disableNotification: Boolean = false,
|
||||
replyToMessageId: MessageIdentifier? = null
|
||||
) = execute(
|
||||
SendPlaylist(
|
||||
chatId, media, disableNotification, replyToMessageId
|
||||
)
|
||||
)
|
||||
|
||||
/**
|
||||
* @see SendPlaylist
|
||||
*/
|
||||
suspend fun TelegramBot.sendPlaylist(
|
||||
chat: Chat,
|
||||
media: List<AudioMediaGroupMemberInputMedia>,
|
||||
disableNotification: Boolean = false,
|
||||
replyToMessageId: MessageIdentifier? = null
|
||||
) = sendPlaylist(
|
||||
chat.id, media, disableNotification, replyToMessageId
|
||||
)
|
||||
|
||||
/**
|
||||
* @see SendDocumentsGroup
|
||||
*/
|
||||
suspend fun TelegramBot.sendDocumentsGroup(
|
||||
chatId: ChatIdentifier,
|
||||
media: List<DocumentMediaGroupMemberInputMedia>,
|
||||
disableNotification: Boolean = false,
|
||||
replyToMessageId: MessageIdentifier? = null
|
||||
) = execute(
|
||||
SendDocumentsGroup(
|
||||
chatId, media, disableNotification, replyToMessageId
|
||||
)
|
||||
)
|
||||
|
||||
/**
|
||||
* @see SendDocumentsGroup
|
||||
*/
|
||||
suspend fun TelegramBot.sendDocumentsGroup(
|
||||
chat: Chat,
|
||||
media: List<DocumentMediaGroupMemberInputMedia>,
|
||||
disableNotification: Boolean = false,
|
||||
replyToMessageId: MessageIdentifier? = null
|
||||
) = sendDocumentsGroup(
|
||||
chat.id, media, disableNotification, replyToMessageId
|
||||
)
|
||||
|
||||
/**
|
||||
* @see SendVisualMediaGroup
|
||||
*/
|
||||
suspend fun TelegramBot.sendVisualMediaGroup(
|
||||
chatId: ChatIdentifier,
|
||||
media: List<VisualMediaGroupMemberInputMedia>,
|
||||
disableNotification: Boolean = false,
|
||||
replyToMessageId: MessageIdentifier? = null
|
||||
) = execute(
|
||||
SendVisualMediaGroup(
|
||||
chatId, media, disableNotification, replyToMessageId
|
||||
)
|
||||
)
|
||||
|
||||
/**
|
||||
* @see SendVisualMediaGroup
|
||||
*/
|
||||
suspend fun TelegramBot.sendVisualMediaGroup(
|
||||
chat: Chat,
|
||||
media: List<VisualMediaGroupMemberInputMedia>,
|
||||
disableNotification: Boolean = false,
|
||||
replyToMessageId: MessageIdentifier? = null
|
||||
) = sendVisualMediaGroup(
|
||||
chat.id, media, disableNotification, replyToMessageId
|
||||
)
|
||||
|
||||
suspend inline fun TelegramBot.replyWithMediaGroup(
|
||||
to: Message,
|
||||
media: List<MediaGroupMemberInputMedia>,
|
||||
disableNotification: Boolean = false
|
||||
) = sendMediaGroup(to.chat, media, disableNotification, to.messageId)
|
||||
|
||||
suspend inline fun TelegramBot.replyWithPlaylist(
|
||||
to: Message,
|
||||
media: List<AudioMediaGroupMemberInputMedia>,
|
||||
disableNotification: Boolean = false
|
||||
) = sendPlaylist(to.chat, media, disableNotification, to.messageId)
|
||||
|
||||
suspend inline fun TelegramBot.replyWithDocumentsGroup(
|
||||
to: Message,
|
||||
media: List<DocumentMediaGroupMemberInputMedia>,
|
||||
disableNotification: Boolean = false
|
||||
) = sendDocumentsGroup(to.chat, media, disableNotification, to.messageId)
|
||||
|
||||
suspend inline fun TelegramBot.replyWithVisualMediaGroup(
|
||||
to: Message,
|
||||
media: List<VisualMediaGroupMemberInputMedia>,
|
||||
disableNotification: Boolean = false
|
||||
) = sendVisualMediaGroup(to.chat, media, disableNotification, to.messageId)
|
||||
|
||||
suspend inline fun TelegramBot.reply(
|
||||
to: Message,
|
||||
media: List<MediaGroupMemberInputMedia>,
|
||||
|
||||
@@ -2,6 +2,7 @@ package dev.inmo.tgbotapi.extensions.utils
|
||||
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.channels.BroadcastChannel
|
||||
import kotlinx.coroutines.channels.Channel
|
||||
import kotlinx.coroutines.flow.*
|
||||
|
||||
/**
|
||||
@@ -10,15 +11,15 @@ import kotlinx.coroutines.flow.*
|
||||
fun <T> aggregateFlows(
|
||||
withScope: CoroutineScope,
|
||||
vararg flows: Flow<T>,
|
||||
internalBufferSize: Int = 64
|
||||
internalBufferSize: Int = Channel.BUFFERED
|
||||
): Flow<T> {
|
||||
val sharedFlow = MutableSharedFlow<T>(extraBufferCapacity = internalBufferSize)
|
||||
val bc = BroadcastChannel<T>(internalBufferSize)
|
||||
flows.forEach {
|
||||
it.onEach {
|
||||
safely { sharedFlow.emit(it) }
|
||||
safely { bc.send(it) }
|
||||
}.launchIn(withScope)
|
||||
}
|
||||
return sharedFlow
|
||||
return bc.asFlow()
|
||||
}
|
||||
|
||||
fun <T> Flow<Iterable<T>>.flatMap(): Flow<T> = flow {
|
||||
|
||||
@@ -6,7 +6,8 @@ import dev.inmo.tgbotapi.extensions.utils.updates.asContentMessagesFlow
|
||||
import dev.inmo.tgbotapi.types.message.abstracts.CommonMessage
|
||||
import dev.inmo.tgbotapi.types.message.abstracts.ContentMessage
|
||||
import dev.inmo.tgbotapi.types.message.content.*
|
||||
import dev.inmo.tgbotapi.types.message.content.abstracts.*
|
||||
import dev.inmo.tgbotapi.types.message.content.abstracts.MediaGroupContent
|
||||
import dev.inmo.tgbotapi.types.message.content.abstracts.MessageContent
|
||||
import dev.inmo.tgbotapi.types.message.content.media.*
|
||||
import dev.inmo.tgbotapi.types.message.payments.InvoiceContent
|
||||
import dev.inmo.tgbotapi.types.update.MediaGroupUpdates.SentMediaGroupUpdate
|
||||
@@ -100,12 +101,6 @@ fun Flow<BaseSentMessageUpdate>.audioMessages() = filterContentMessages<AudioCon
|
||||
fun FlowsUpdatesFilter.audioMessages(
|
||||
scopeToIncludeChannels: CoroutineScope? = null
|
||||
) = filterContentMessages<AudioContent>(scopeToIncludeChannels)
|
||||
fun FlowsUpdatesFilter.audioMessagesWithMediaGroups(
|
||||
scopeToIncludeChannels: CoroutineScope? = null
|
||||
) = merge(
|
||||
filterContentMessages<AudioContent>(scopeToIncludeChannels),
|
||||
mediaGroupAudioMessages(scopeToIncludeChannels).flatMap()
|
||||
)
|
||||
|
||||
fun Flow<BaseSentMessageUpdate>.contactMessages() = filterContentMessages<ContactContent>()
|
||||
fun FlowsUpdatesFilter.contactMessages(
|
||||
@@ -121,12 +116,6 @@ fun Flow<BaseSentMessageUpdate>.documentMessages() = filterContentMessages<Docum
|
||||
fun FlowsUpdatesFilter.documentMessages(
|
||||
scopeToIncludeChannels: CoroutineScope? = null
|
||||
) = filterContentMessages<DocumentContent>(scopeToIncludeChannels)
|
||||
fun FlowsUpdatesFilter.documentMessagesWithMediaGroups(
|
||||
scopeToIncludeChannels: CoroutineScope? = null
|
||||
) = merge(
|
||||
filterContentMessages<DocumentContent>(scopeToIncludeChannels),
|
||||
mediaGroupDocumentMessages(scopeToIncludeChannels).flatMap()
|
||||
)
|
||||
|
||||
fun Flow<BaseSentMessageUpdate>.gameMessages() = filterContentMessages<GameContent>()
|
||||
fun FlowsUpdatesFilter.gameMessages(
|
||||
@@ -221,18 +210,3 @@ fun Flow<SentMediaGroupUpdate>.mediaGroupVideosMessages() = filterMediaGroupMess
|
||||
fun FlowsUpdatesFilter.mediaGroupVideosMessages(
|
||||
scopeToIncludeChannels: CoroutineScope? = null
|
||||
) = filterMediaGroupMessages<VideoContent>(scopeToIncludeChannels)
|
||||
|
||||
fun Flow<SentMediaGroupUpdate>.mediaGroupVisualMessages() = filterMediaGroupMessages<VisualMediaGroupContent>()
|
||||
fun FlowsUpdatesFilter.mediaGroupVisualMessages(
|
||||
scopeToIncludeChannels: CoroutineScope? = null
|
||||
) = filterMediaGroupMessages<VisualMediaGroupContent>(scopeToIncludeChannels)
|
||||
|
||||
fun Flow<SentMediaGroupUpdate>.mediaGroupAudioMessages() = filterMediaGroupMessages<AudioContent>()
|
||||
fun FlowsUpdatesFilter.mediaGroupAudioMessages(
|
||||
scopeToIncludeChannels: CoroutineScope? = null
|
||||
) = filterMediaGroupMessages<AudioContent>(scopeToIncludeChannels)
|
||||
|
||||
fun Flow<SentMediaGroupUpdate>.mediaGroupDocumentMessages() = filterMediaGroupMessages<DocumentContent>()
|
||||
fun FlowsUpdatesFilter.mediaGroupDocumentMessages(
|
||||
scopeToIncludeChannels: CoroutineScope? = null
|
||||
) = filterMediaGroupMessages<DocumentContent>(scopeToIncludeChannels)
|
||||
|
||||
Reference in New Issue
Block a user