package dev.inmo.tgbotapi.extensions.utils.shortcuts import dev.inmo.tgbotapi.extensions.utils.aggregateFlows import dev.inmo.tgbotapi.extensions.utils.flatMap import dev.inmo.tgbotapi.extensions.utils.flatten 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.MediaGroupContent import dev.inmo.tgbotapi.types.message.content.VisualMediaGroupContent import dev.inmo.tgbotapi.types.message.content.InvoiceContent import dev.inmo.tgbotapi.types.update.media_group.SentMediaGroupUpdate import dev.inmo.tgbotapi.types.update.abstracts.BaseSentMessageUpdate import dev.inmo.tgbotapi.updateshandlers.FlowsUpdatesFilter import dev.inmo.tgbotapi.utils.RiskFeature import dev.inmo.tgbotapi.utils.lowLevelRiskFeatureMessage import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.* @RiskFeature(lowLevelRiskFeatureMessage) inline fun filterForContentMessage(): suspend (ContentMessage<*>) -> ContentMessage? = { if (it.content is T) { @Suppress("UNCHECKED_CAST") it as ContentMessage } else { null } } @Suppress("UNCHECKED_CAST") @RiskFeature(lowLevelRiskFeatureMessage) inline fun Flow.filterContentMessages( ): Flow> = asContentMessagesFlow().mapNotNull(filterForContentMessage()) @RiskFeature("This method is low-level") inline fun Flow.filterMediaGroupMessages( ): Flow>> = map { it.data.mapNotNull { message -> if (message.content is T) { @Suppress("UNCHECKED_CAST") message as CommonMessage } else { null } } } /** * @param scopeToIncludeChannels This parameter is required when you want to include [textMessages] for channels too. * In this case will be created new channel which will aggregate messages from [FlowsUpdatesFilter.messagesFlow] and * [FlowsUpdatesFilter.channelPostsFlow]. In case it is null will be used [Flow]s mapping */ @Suppress("UNCHECKED_CAST") @RiskFeature(lowLevelRiskFeatureMessage) inline fun FlowsUpdatesFilter.filterContentMessages( scopeToIncludeChannels: CoroutineScope? = null ): Flow> { return (scopeToIncludeChannels ?.let { scope -> aggregateFlows( scope, messagesFlow, channelPostsFlow ) } ?: messagesFlow).filterContentMessages() } /** * @param scopeToIncludeChannels This parameter is required when you want to include [SentMediaGroupUpdate] for channels * too. In this case will be created new channel which will aggregate messages from [FlowsUpdatesFilter.messagesFlow] and * [FlowsUpdatesFilter.channelPostsFlow]. In case it is null will be used [Flow]s mapping */ @Suppress("UNCHECKED_CAST") @RiskFeature(lowLevelRiskFeatureMessage) inline fun FlowsUpdatesFilter.filterMediaGroupMessages( scopeToIncludeChannels: CoroutineScope? = null ): Flow>> { return (scopeToIncludeChannels ?.let { scope -> aggregateFlows( scope, messageMediaGroupsFlow, channelPostMediaGroupsFlow ) } ?: messageMediaGroupsFlow).filterMediaGroupMessages() } fun FlowsUpdatesFilter.sentMessages( scopeToIncludeChannels: CoroutineScope? = null ): Flow> = filterContentMessages(scopeToIncludeChannels) fun FlowsUpdatesFilter.sentMessagesWithMediaGroups( scopeToIncludeChannels: CoroutineScope? = null ): Flow> = merge( sentMessages(scopeToIncludeChannels), mediaGroupMessages(scopeToIncludeChannels).flatMap { it.mapNotNull { @Suppress("UNCHECKED_CAST") it as? ContentMessage } } ) fun Flow.animationMessages() = filterContentMessages() fun FlowsUpdatesFilter.animationMessages( scopeToIncludeChannels: CoroutineScope? = null ) = filterContentMessages(scopeToIncludeChannels) fun Flow.audioMessages() = filterContentMessages() fun FlowsUpdatesFilter.audioMessages( scopeToIncludeChannels: CoroutineScope? = null ) = filterContentMessages(scopeToIncludeChannels) fun FlowsUpdatesFilter.audioMessagesWithMediaGroups( scopeToIncludeChannels: CoroutineScope? = null ) = merge( filterContentMessages(scopeToIncludeChannels), mediaGroupAudioMessages(scopeToIncludeChannels).flatten() ) fun Flow.contactMessages() = filterContentMessages() fun FlowsUpdatesFilter.contactMessages( scopeToIncludeChannels: CoroutineScope? = null ) = filterContentMessages(scopeToIncludeChannels) fun Flow.diceMessages() = filterContentMessages() fun FlowsUpdatesFilter.diceMessages( scopeToIncludeChannels: CoroutineScope? = null ) = filterContentMessages(scopeToIncludeChannels) fun Flow.documentMessages() = filterContentMessages() fun FlowsUpdatesFilter.documentMessages( scopeToIncludeChannels: CoroutineScope? = null ) = filterContentMessages(scopeToIncludeChannels) fun FlowsUpdatesFilter.documentMessagesWithMediaGroups( scopeToIncludeChannels: CoroutineScope? = null ) = merge( filterContentMessages(scopeToIncludeChannels), mediaGroupDocumentMessages(scopeToIncludeChannels).flatten() ) fun Flow.gameMessages() = filterContentMessages() fun FlowsUpdatesFilter.gameMessages( scopeToIncludeChannels: CoroutineScope? = null ) = filterContentMessages(scopeToIncludeChannels) fun Flow.invoiceMessages() = filterContentMessages() fun FlowsUpdatesFilter.invoiceMessages( scopeToIncludeChannels: CoroutineScope? = null ) = filterContentMessages(scopeToIncludeChannels) fun Flow.locationMessages() = filterContentMessages() fun FlowsUpdatesFilter.locationMessages( scopeToIncludeChannels: CoroutineScope? = null ) = filterContentMessages(scopeToIncludeChannels) fun Flow.photoMessages() = filterContentMessages() fun Flow.imageMessages() = photoMessages() fun FlowsUpdatesFilter.photoMessages( scopeToIncludeChannels: CoroutineScope? = null ) = filterContentMessages(scopeToIncludeChannels) fun FlowsUpdatesFilter.photoMessagesWithMediaGroups( scopeToIncludeChannels: CoroutineScope? = null ) = merge( filterContentMessages(scopeToIncludeChannels), mediaGroupPhotosMessages(scopeToIncludeChannels).flatten() ) /** * Shortcut for [photoMessages] */ @Suppress("NOTHING_TO_INLINE") inline fun FlowsUpdatesFilter.imageMessages( scopeToIncludeChannels: CoroutineScope? = null ) = photoMessages(scopeToIncludeChannels) fun FlowsUpdatesFilter.imageMessagesWithMediaGroups( scopeToIncludeChannels: CoroutineScope? = null ) = photoMessagesWithMediaGroups(scopeToIncludeChannels) fun Flow.pollMessages() = filterContentMessages() fun FlowsUpdatesFilter.pollMessages( scopeToIncludeChannels: CoroutineScope? = null ) = filterContentMessages(scopeToIncludeChannels) fun Flow.stickerMessages() = filterContentMessages() fun FlowsUpdatesFilter.stickerMessages( scopeToIncludeChannels: CoroutineScope? = null ) = filterContentMessages(scopeToIncludeChannels) fun Flow.textMessages() = filterContentMessages() fun FlowsUpdatesFilter.textMessages( scopeToIncludeChannels: CoroutineScope? = null ) = filterContentMessages(scopeToIncludeChannels) fun Flow.venueMessages() = filterContentMessages() fun FlowsUpdatesFilter.venueMessages( scopeToIncludeChannels: CoroutineScope? = null ) = filterContentMessages(scopeToIncludeChannels) fun Flow.videoMessages() = filterContentMessages() fun FlowsUpdatesFilter.videoMessages( scopeToIncludeChannels: CoroutineScope? = null ) = filterContentMessages(scopeToIncludeChannels) fun FlowsUpdatesFilter.videoMessagesWithMediaGroups( scopeToIncludeChannels: CoroutineScope? = null ) = merge( filterContentMessages(scopeToIncludeChannels), mediaGroupVideosMessages(scopeToIncludeChannels).flatten() ) fun Flow.videoNoteMessages() = filterContentMessages() fun FlowsUpdatesFilter.videoNoteMessages( scopeToIncludeChannels: CoroutineScope? = null ) = filterContentMessages(scopeToIncludeChannels) fun Flow.voiceMessages() = filterContentMessages() fun FlowsUpdatesFilter.voiceMessages( scopeToIncludeChannels: CoroutineScope? = null ) = filterContentMessages(scopeToIncludeChannels) fun Flow.mediaGroupMessages() = filterMediaGroupMessages() fun FlowsUpdatesFilter.mediaGroupMessages( scopeToIncludeChannels: CoroutineScope? = null ) = filterMediaGroupMessages(scopeToIncludeChannels) fun Flow.mediaGroupPhotosMessages() = filterMediaGroupMessages() fun FlowsUpdatesFilter.mediaGroupPhotosMessages( scopeToIncludeChannels: CoroutineScope? = null ) = filterMediaGroupMessages(scopeToIncludeChannels) fun Flow.mediaGroupVideosMessages() = filterMediaGroupMessages() fun FlowsUpdatesFilter.mediaGroupVideosMessages( scopeToIncludeChannels: CoroutineScope? = null ) = filterMediaGroupMessages(scopeToIncludeChannels) fun Flow.mediaGroupVisualMessages() = filterMediaGroupMessages() fun FlowsUpdatesFilter.mediaGroupVisualMessages( scopeToIncludeChannels: CoroutineScope? = null ) = filterMediaGroupMessages(scopeToIncludeChannels) fun Flow.mediaGroupAudioMessages() = filterMediaGroupMessages() fun FlowsUpdatesFilter.mediaGroupAudioMessages( scopeToIncludeChannels: CoroutineScope? = null ) = filterMediaGroupMessages(scopeToIncludeChannels) fun Flow.mediaGroupDocumentMessages() = filterMediaGroupMessages() fun FlowsUpdatesFilter.mediaGroupDocumentMessages( scopeToIncludeChannels: CoroutineScope? = null ) = filterMediaGroupMessages(scopeToIncludeChannels)