Merge pull request #26 from InsanusMokrassar/0.12.4

0.12.4 Better HTML parse mode support
This commit is contained in:
InsanusMokrassar 2019-04-03 07:22:50 -05:00 committed by GitHub
commit d41ce3b228
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
33 changed files with 494 additions and 155 deletions

View File

@ -49,6 +49,19 @@ media for present out)
* `PhotoContent` now choose biggest photo size from its collection as `media`
* Fix in order of media group messages which was received by webhooks
### 0.12.4
* Optimized preparing of media group in `UpdatesPoller`
* Add `CommonLimiter`
* Add `MessageEntity#asHtmlSource` and `String#toHtml`
* Add tools for work with html captions and texts
* `MessageContent` which using captions or text now have default parse mode `HTMLParseMode` due to issue with escaping
of `]` in links titles
* Added `Markdown` and `HTML` type aliases which actually means `MarkdownParseMode` and `HTMLParseMode`
* `ChatId` now have extension `link` which will automatically create link like `tg://user?id=<chatId>`
* Created a few of methods for all supported formats of text like bold, italic, links and others
* Rewritten `MessageEntities` to use new formatting options
## 0.11.0
* Kotlin `1.3.11` -> `1.3.21`

View File

@ -62,5 +62,6 @@ recommend to use some unique address for each bot which you are using
Template for Nginx server config you can find in [this gist](https://gist.github.com/InsanusMokrassar/fcc6e09cebd07e46e8f0fdec234750c4#file-nginxssl-conf).
For webhook you must provide `File` with public part of certificate, `URL` where bot placed and inner `PORT` which
will be used to start receiving of updates.
For webhook you can provide `File` with public part of certificate, `URL` where bot will be available and inner `PORT` which
will be used to start receiving of updates. Actually, you can skip passing of `File` when you have something like
nginx for proxy forwarding.

View File

@ -1,4 +1,4 @@
project.version = "0.12.3"
project.version = "0.12.4"
project.group = "com.github.insanusmokrassar"
buildscript {

View File

@ -0,0 +1,66 @@
package com.github.insanusmokrassar.TelegramBotAPI.bot.settings.limiters
import kotlinx.coroutines.*
import kotlinx.coroutines.channels.Channel
private fun now(): Long = System.currentTimeMillis()
class CommonLimiter(
private val lockCount: Int = 10,
private val regenTime: Long = 20 * 1000L // 20 seconds for full regen of opportunity to send message
) : RequestLimiter {
private var doLimit: Boolean = false
private val counterChannel = Channel<Unit>(Channel.UNLIMITED)
private val scope = CoroutineScope(Dispatchers.Default)
private val counterJob = scope.launch {
var wasLastSecond = 0
var lastCountTime = now()
var limitManagementJob: Job? = null
var removeLimitTime: Long = lastCountTime
for (counter in counterChannel) {
val now = now()
if (now - lastCountTime > 1000) {
lastCountTime = now
wasLastSecond = 1
} else {
wasLastSecond++
}
if (wasLastSecond >= lockCount) {
removeLimitTime = now + regenTime
if (limitManagementJob == null) {
limitManagementJob = launch {
doLimit = true
var internalNow = now()
while (internalNow < removeLimitTime) {
delay(removeLimitTime - internalNow)
internalNow = now()
}
doLimit = false
}
}
}
if (now > removeLimitTime) {
limitManagementJob = null
}
}
}
private val quoterChannel = Channel<Unit>(Channel.CONFLATED)
private val tickerJob = scope.launch {
while (isActive) {
quoterChannel.send(Unit)
delay(1000L)
}
}
override suspend fun <T> limit(block: suspend () -> T): T {
counterChannel.send(Unit)
return if (!doLimit) {
block()
} else {
quoterChannel.receive()
block()
}
}
}

View File

@ -13,6 +13,10 @@ data class ChatId(
val chatId: Identifier
) : ChatIdentifier()
val ChatId.link: String
get() = "tg://user?id=$chatId"
typealias UserId = ChatId
fun Identifier.toChatId(): ChatId = ChatId(this)

View File

@ -1,9 +1,13 @@
package com.github.insanusmokrassar.TelegramBotAPI.types.MessageEntity
import com.github.insanusmokrassar.TelegramBotAPI.utils.boldHTML
import com.github.insanusmokrassar.TelegramBotAPI.utils.boldMarkdown
data class BoldTextMessageEntity(
override val offset: Int,
override val length: Int,
override val sourceString: String
) : TextMessageEntity() {
override val formatSymbol: String = "*"
) : MessageEntity {
override val asMarkdownSource: String = sourceString.boldMarkdown()
override val asHtmlSource: String = sourceString.boldHTML()
}

View File

@ -1,10 +1,16 @@
package com.github.insanusmokrassar.TelegramBotAPI.types.MessageEntity
import com.github.insanusmokrassar.TelegramBotAPI.utils.commandHTML
import com.github.insanusmokrassar.TelegramBotAPI.utils.commandMarkdown
data class BotCommandMessageEntity(
override val offset: Int,
override val length: Int,
override val sourceString: String
) : MessageEntity {
override val asMarkdownSource: String = sourceString.commandMarkdown()
override val asHtmlSource: String = sourceString.commandHTML()
val command: String by lazy {
sourceString.substring(1)// skip first symbol like "/" or "!"
}

View File

@ -1,9 +1,13 @@
package com.github.insanusmokrassar.TelegramBotAPI.types.MessageEntity
import com.github.insanusmokrassar.TelegramBotAPI.utils.codeHTML
import com.github.insanusmokrassar.TelegramBotAPI.utils.codeMarkdown
data class CodeTextMessageEntity(
override val offset: Int,
override val length: Int,
override val sourceString: String
) : TextMessageEntity() {
override val formatSymbol: String = "`"
) : MessageEntity {
override val asMarkdownSource: String = sourceString.codeMarkdown()
override val asHtmlSource: String = sourceString.codeHTML()
}

View File

@ -1,11 +1,13 @@
package com.github.insanusmokrassar.TelegramBotAPI.types.MessageEntity
import com.github.insanusmokrassar.TelegramBotAPI.utils.emailHTML
import com.github.insanusmokrassar.TelegramBotAPI.utils.emailMarkdown
class EMailMessageEntity(
override val offset: Int,
override val length: Int,
override val sourceString: String
) : MessageEntity {
override val asMarkdownSource: String by lazy {
"[$sourceString](mailto://$sourceString)"
}
}
override val asMarkdownSource: String = sourceString.emailMarkdown()
override val asHtmlSource: String = sourceString.emailHTML()
}

View File

@ -1,7 +1,13 @@
package com.github.insanusmokrassar.TelegramBotAPI.types.MessageEntity
import com.github.insanusmokrassar.TelegramBotAPI.utils.hashTagHTML
import com.github.insanusmokrassar.TelegramBotAPI.utils.hashTagMarkdown
data class HashTagMessageEntity(
override val offset: Int,
override val length: Int,
override val sourceString: String
) : MessageEntity
) : MessageEntity {
override val asMarkdownSource: String = sourceString.hashTagMarkdown()
override val asHtmlSource: String = sourceString.hashTagHTML()
}

View File

@ -1,9 +1,13 @@
package com.github.insanusmokrassar.TelegramBotAPI.types.MessageEntity
import com.github.insanusmokrassar.TelegramBotAPI.utils.italicHTML
import com.github.insanusmokrassar.TelegramBotAPI.utils.italicMarkdown
data class ItalicTextMessageEntity(
override val offset: Int,
override val length: Int,
override val sourceString: String
) : TextMessageEntity() {
override val formatSymbol: String = "_"
) : MessageEntity {
override val asMarkdownSource: String = sourceString.italicMarkdown()
override val asHtmlSource: String = sourceString.italicHTML()
}

View File

@ -1,10 +1,13 @@
package com.github.insanusmokrassar.TelegramBotAPI.types.MessageEntity
import com.github.insanusmokrassar.TelegramBotAPI.utils.mentionHTML
import com.github.insanusmokrassar.TelegramBotAPI.utils.mentionMarkdown
class MentionMessageEntity(
override val offset: Int,
override val length: Int,
override val sourceString: String
) : MessageEntity {
override val asMarkdownSource: String
get() = sourceString
}
override val asMarkdownSource: String = sourceString.mentionMarkdown()
override val asHtmlSource: String = sourceString.mentionHTML()
}

View File

@ -1,12 +1,10 @@
package com.github.insanusmokrassar.TelegramBotAPI.types.MessageEntity
import com.github.insanusmokrassar.TelegramBotAPI.utils.extensions.toMarkdown
interface MessageEntity {
val offset: Int
val length: Int
val sourceString: String
val asMarkdownSource: String
get() = sourceString.toMarkdown()
val asHtmlSource: String
}

View File

@ -1,7 +1,13 @@
package com.github.insanusmokrassar.TelegramBotAPI.types.MessageEntity
import com.github.insanusmokrassar.TelegramBotAPI.utils.phoneHTML
import com.github.insanusmokrassar.TelegramBotAPI.utils.phoneMarkdown
data class PhoneNumberMessageEntity(
override val offset: Int,
override val length: Int,
override val sourceString: String
) : MessageEntity
) : MessageEntity {
override val asMarkdownSource: String = sourceString.phoneMarkdown()
override val asHtmlSource: String = sourceString.phoneHTML()
}

View File

@ -1,9 +1,13 @@
package com.github.insanusmokrassar.TelegramBotAPI.types.MessageEntity
import com.github.insanusmokrassar.TelegramBotAPI.utils.preHTML
import com.github.insanusmokrassar.TelegramBotAPI.utils.preMarkdown
data class PreTextMessageEntity(
override val offset: Int,
override val length: Int,
override val sourceString: String
) : TextMessageEntity() {
override val formatSymbol: String = "```"
) : MessageEntity {
override val asMarkdownSource: String = sourceString.preMarkdown()
override val asHtmlSource: String = sourceString.preHTML()
}

View File

@ -1,7 +1,13 @@
package com.github.insanusmokrassar.TelegramBotAPI.types.MessageEntity
import com.github.insanusmokrassar.TelegramBotAPI.utils.extensions.toHtml
import com.github.insanusmokrassar.TelegramBotAPI.utils.extensions.toMarkdown
data class RegularTextMessageEntity(
override val offset: Int,
override val length: Int,
override val sourceString: String
) : MessageEntity
) : MessageEntity {
override val asMarkdownSource: String = sourceString.toMarkdown()
override val asHtmlSource: String = sourceString.toHtml()
}

View File

@ -1,12 +1,14 @@
package com.github.insanusmokrassar.TelegramBotAPI.types.MessageEntity
import com.github.insanusmokrassar.TelegramBotAPI.utils.linkHTML
import com.github.insanusmokrassar.TelegramBotAPI.utils.linkMarkdown
data class TextLinkMessageEntity(
override val offset: Int,
override val length: Int,
override val sourceString: String,
val url: String
) : MessageEntity {
override val asMarkdownSource: String by lazy {
"[$sourceString]($url)"
}
override val asMarkdownSource: String = sourceString.linkMarkdown(url)
override val asHtmlSource: String = sourceString.linkHTML(url)
}

View File

@ -1,6 +1,7 @@
package com.github.insanusmokrassar.TelegramBotAPI.types.MessageEntity
import com.github.insanusmokrassar.TelegramBotAPI.types.User
import com.github.insanusmokrassar.TelegramBotAPI.utils.mentionMarkdown
class TextMentionMessageEntity(
override val offset: Int,
@ -8,7 +9,6 @@ class TextMentionMessageEntity(
override val sourceString: String,
val user: User
) : MessageEntity {
override val asMarkdownSource: String by lazy {
"[$sourceString](tg://user?id=${user.id})"
}
}
override val asMarkdownSource: String = sourceString.mentionMarkdown(user.id)
override val asHtmlSource: String = sourceString.mentionMarkdown(user.id)
}

View File

@ -1,9 +0,0 @@
package com.github.insanusmokrassar.TelegramBotAPI.types.MessageEntity
abstract class TextMessageEntity : MessageEntity {
protected abstract val formatSymbol: String
override val asMarkdownSource: String by lazy {
"$formatSymbol$sourceString$formatSymbol"
}
}

View File

@ -1,14 +1,15 @@
package com.github.insanusmokrassar.TelegramBotAPI.types.MessageEntity
import com.github.insanusmokrassar.TelegramBotAPI.utils.linkHTML
import com.github.insanusmokrassar.TelegramBotAPI.utils.linkMarkdown
data class URLMessageEntity(
override val offset: Int,
override val length: Int,
override val sourceString: String
) : MessageEntity {
val url: String
get() = sourceString
) : MessageEntity{
val url: String = sourceString
override val asMarkdownSource: String by lazy {
"[$sourceString]($url)"
}
override val asMarkdownSource: String = sourceString.linkMarkdown(url)
override val asHtmlSource: String = sourceString.linkHTML(url)
}

View File

@ -23,6 +23,9 @@ object HTMLParseMode : ParseMode() {
override val parseModeName: String = "HTML"
}
typealias Markdown = MarkdownParseMode
typealias HTML = HTMLParseMode
@Serializer(ParseMode::class)
internal class ParseModeSerializerObject: KSerializer<ParseMode> {
override fun deserialize(decoder: Decoder): ParseMode {

View File

@ -5,10 +5,11 @@ import com.github.insanusmokrassar.TelegramBotAPI.requests.send.SendMessage
import com.github.insanusmokrassar.TelegramBotAPI.types.ChatIdentifier
import com.github.insanusmokrassar.TelegramBotAPI.types.MessageEntity.MessageEntity
import com.github.insanusmokrassar.TelegramBotAPI.types.MessageIdentifier
import com.github.insanusmokrassar.TelegramBotAPI.types.ParseMode.MarkdownParseMode
import com.github.insanusmokrassar.TelegramBotAPI.types.ParseMode.*
import com.github.insanusmokrassar.TelegramBotAPI.types.buttons.KeyboardMarkup
import com.github.insanusmokrassar.TelegramBotAPI.types.message.RawMessage
import com.github.insanusmokrassar.TelegramBotAPI.types.message.content.abstracts.MessageContent
import com.github.insanusmokrassar.TelegramBotAPI.utils.toHtmlTexts
import com.github.insanusmokrassar.TelegramBotAPI.utils.toMarkdownTexts
data class TextContent(
@ -22,8 +23,8 @@ data class TextContent(
replyMarkup: KeyboardMarkup?
): Request<RawMessage> = SendMessage(
chatId,
toMarkdownTexts().first(),
MarkdownParseMode,
toHtmlTexts().first(),
HTMLParseMode,
false,
disableNotification,
replyToMessageId,
@ -35,11 +36,28 @@ data class TextContent(
disableNotification: Boolean,
replyToMessageId: MessageIdentifier?,
replyMarkup: KeyboardMarkup?
): List<Request<RawMessage>> = toMarkdownTexts().map {
): List<Request<RawMessage>> = createResends(
chatId,
disableNotification,
replyToMessageId,
replyMarkup,
HTMLParseMode
)
fun createResends(
chatId: ChatIdentifier,
disableNotification: Boolean,
replyToMessageId: MessageIdentifier?,
replyMarkup: KeyboardMarkup?,
parseMode: ParseMode = HTMLParseMode
): List<Request<RawMessage>> = when (parseMode) {
is MarkdownParseMode -> toMarkdownTexts()
is HTMLParseMode -> toHtmlTexts()
}.map {
SendMessage(
chatId,
it,
MarkdownParseMode,
parseMode,
false,
disableNotification,
replyToMessageId,

View File

@ -5,13 +5,13 @@ import com.github.insanusmokrassar.TelegramBotAPI.requests.send.media.SendAudio
import com.github.insanusmokrassar.TelegramBotAPI.types.ChatIdentifier
import com.github.insanusmokrassar.TelegramBotAPI.types.MessageEntity.MessageEntity
import com.github.insanusmokrassar.TelegramBotAPI.types.MessageIdentifier
import com.github.insanusmokrassar.TelegramBotAPI.types.ParseMode.MarkdownParseMode
import com.github.insanusmokrassar.TelegramBotAPI.types.ParseMode.HTMLParseMode
import com.github.insanusmokrassar.TelegramBotAPI.types.buttons.KeyboardMarkup
import com.github.insanusmokrassar.TelegramBotAPI.types.files.AudioFile
import com.github.insanusmokrassar.TelegramBotAPI.types.message.RawMessage
import com.github.insanusmokrassar.TelegramBotAPI.types.message.content.abstracts.CaptionedMediaContent
import com.github.insanusmokrassar.TelegramBotAPI.types.message.content.abstracts.MediaContent
import com.github.insanusmokrassar.TelegramBotAPI.utils.toMarkdownCaptions
import com.github.insanusmokrassar.TelegramBotAPI.utils.toHtmlCaptions
data class AudioContent(
override val media: AudioFile,
@ -27,8 +27,8 @@ data class AudioContent(
chatId,
media.fileId,
media.thumb ?.fileId,
toMarkdownCaptions().firstOrNull(),
MarkdownParseMode,
toHtmlCaptions().firstOrNull(),
HTMLParseMode,
media.duration,
media.performer,
media.title,

View File

@ -5,13 +5,13 @@ import com.github.insanusmokrassar.TelegramBotAPI.requests.send.media.SendDocume
import com.github.insanusmokrassar.TelegramBotAPI.types.ChatIdentifier
import com.github.insanusmokrassar.TelegramBotAPI.types.MessageEntity.MessageEntity
import com.github.insanusmokrassar.TelegramBotAPI.types.MessageIdentifier
import com.github.insanusmokrassar.TelegramBotAPI.types.ParseMode.MarkdownParseMode
import com.github.insanusmokrassar.TelegramBotAPI.types.ParseMode.HTMLParseMode
import com.github.insanusmokrassar.TelegramBotAPI.types.buttons.KeyboardMarkup
import com.github.insanusmokrassar.TelegramBotAPI.types.files.DocumentFile
import com.github.insanusmokrassar.TelegramBotAPI.types.message.RawMessage
import com.github.insanusmokrassar.TelegramBotAPI.types.message.content.abstracts.CaptionedMediaContent
import com.github.insanusmokrassar.TelegramBotAPI.types.message.content.abstracts.MediaContent
import com.github.insanusmokrassar.TelegramBotAPI.utils.toMarkdownCaptions
import com.github.insanusmokrassar.TelegramBotAPI.utils.toHtmlCaptions
data class DocumentContent(
override val media: DocumentFile,
@ -27,8 +27,8 @@ data class DocumentContent(
chatId,
media.fileId,
media.thumb ?.fileId,
toMarkdownCaptions().firstOrNull(),
MarkdownParseMode,
toHtmlCaptions().firstOrNull(),
HTMLParseMode,
disableNotification,
replyToMessageId,
replyMarkup

View File

@ -7,13 +7,13 @@ import com.github.insanusmokrassar.TelegramBotAPI.types.InputMedia.InputMediaPho
import com.github.insanusmokrassar.TelegramBotAPI.types.InputMedia.MediaGroupMemberInputMedia
import com.github.insanusmokrassar.TelegramBotAPI.types.MessageEntity.MessageEntity
import com.github.insanusmokrassar.TelegramBotAPI.types.MessageIdentifier
import com.github.insanusmokrassar.TelegramBotAPI.types.ParseMode.MarkdownParseMode
import com.github.insanusmokrassar.TelegramBotAPI.types.ParseMode.HTMLParseMode
import com.github.insanusmokrassar.TelegramBotAPI.types.buttons.KeyboardMarkup
import com.github.insanusmokrassar.TelegramBotAPI.types.files.PhotoSize
import com.github.insanusmokrassar.TelegramBotAPI.types.files.biggest
import com.github.insanusmokrassar.TelegramBotAPI.types.message.RawMessage
import com.github.insanusmokrassar.TelegramBotAPI.types.message.content.abstracts.*
import com.github.insanusmokrassar.TelegramBotAPI.utils.toMarkdownCaptions
import com.github.insanusmokrassar.TelegramBotAPI.utils.toHtmlCaptions
data class PhotoContent(
override val mediaCollection: List<PhotoSize>,
@ -30,8 +30,8 @@ data class PhotoContent(
): Request<RawMessage> = SendPhoto(
chatId,
media.fileId,
toMarkdownCaptions().firstOrNull(),
MarkdownParseMode,
toHtmlCaptions().firstOrNull(),
HTMLParseMode,
disableNotification,
replyToMessageId,
replyMarkup
@ -39,7 +39,7 @@ data class PhotoContent(
override fun toMediaGroupMemberInputMedia(): MediaGroupMemberInputMedia = InputMediaPhoto(
media.fileId,
toMarkdownCaptions().firstOrNull(),
MarkdownParseMode
toHtmlCaptions().firstOrNull(),
HTMLParseMode
)
}

View File

@ -7,12 +7,12 @@ import com.github.insanusmokrassar.TelegramBotAPI.types.InputMedia.InputMediaVid
import com.github.insanusmokrassar.TelegramBotAPI.types.InputMedia.MediaGroupMemberInputMedia
import com.github.insanusmokrassar.TelegramBotAPI.types.MessageEntity.MessageEntity
import com.github.insanusmokrassar.TelegramBotAPI.types.MessageIdentifier
import com.github.insanusmokrassar.TelegramBotAPI.types.ParseMode.MarkdownParseMode
import com.github.insanusmokrassar.TelegramBotAPI.types.ParseMode.HTMLParseMode
import com.github.insanusmokrassar.TelegramBotAPI.types.buttons.KeyboardMarkup
import com.github.insanusmokrassar.TelegramBotAPI.types.files.VideoFile
import com.github.insanusmokrassar.TelegramBotAPI.types.message.RawMessage
import com.github.insanusmokrassar.TelegramBotAPI.types.message.content.abstracts.*
import com.github.insanusmokrassar.TelegramBotAPI.utils.toMarkdownCaptions
import com.github.insanusmokrassar.TelegramBotAPI.utils.toHtmlCaptions
data class VideoContent(
override val media: VideoFile,
@ -28,8 +28,8 @@ data class VideoContent(
chatId,
media.fileId,
media.thumb ?.fileId,
toMarkdownCaptions().firstOrNull(),
MarkdownParseMode,
toHtmlCaptions().firstOrNull(),
HTMLParseMode,
media.duration,
media.width,
media.height,
@ -41,8 +41,8 @@ data class VideoContent(
override fun toMediaGroupMemberInputMedia(): MediaGroupMemberInputMedia = InputMediaVideo(
media.fileId,
toMarkdownCaptions().firstOrNull(),
MarkdownParseMode,
toHtmlCaptions().firstOrNull(),
HTMLParseMode,
media.width,
media.height,
media.duration,

View File

@ -5,13 +5,13 @@ import com.github.insanusmokrassar.TelegramBotAPI.requests.send.media.SendVoice
import com.github.insanusmokrassar.TelegramBotAPI.types.ChatIdentifier
import com.github.insanusmokrassar.TelegramBotAPI.types.MessageEntity.MessageEntity
import com.github.insanusmokrassar.TelegramBotAPI.types.MessageIdentifier
import com.github.insanusmokrassar.TelegramBotAPI.types.ParseMode.MarkdownParseMode
import com.github.insanusmokrassar.TelegramBotAPI.types.ParseMode.HTMLParseMode
import com.github.insanusmokrassar.TelegramBotAPI.types.buttons.KeyboardMarkup
import com.github.insanusmokrassar.TelegramBotAPI.types.files.VoiceFile
import com.github.insanusmokrassar.TelegramBotAPI.types.message.RawMessage
import com.github.insanusmokrassar.TelegramBotAPI.types.message.content.abstracts.CaptionedMediaContent
import com.github.insanusmokrassar.TelegramBotAPI.types.message.content.abstracts.MediaContent
import com.github.insanusmokrassar.TelegramBotAPI.utils.toMarkdownCaptions
import com.github.insanusmokrassar.TelegramBotAPI.utils.toHtmlCaptions
data class VoiceContent(
override val media: VoiceFile,
@ -27,8 +27,8 @@ data class VoiceContent(
chatId,
media.fileId,
null,
toMarkdownCaptions().firstOrNull(),
MarkdownParseMode,
toHtmlCaptions().firstOrNull(),
HTMLParseMode,
media.duration,
disableNotification,
replyToMessageId,

View File

@ -2,90 +2,14 @@ package com.github.insanusmokrassar.TelegramBotAPI.utils
import com.github.insanusmokrassar.TelegramBotAPI.types.MessageEntity.MessageEntity
import com.github.insanusmokrassar.TelegramBotAPI.types.MessageEntity.RegularTextMessageEntity
import com.github.insanusmokrassar.TelegramBotAPI.types.captionLength
import com.github.insanusmokrassar.TelegramBotAPI.types.ParseMode.*
import com.github.insanusmokrassar.TelegramBotAPI.types.message.content.TextContent
import com.github.insanusmokrassar.TelegramBotAPI.types.message.content.abstracts.CaptionedMediaContent
import com.github.insanusmokrassar.TelegramBotAPI.types.textLength
@Deprecated(
"Deprecated because old version have problem with long texts, but new one must return list of strings"
)
fun createMarkdownText(
text: String,
messageEntities: List<MessageEntity>
): String {
return createMarkdownText(
convertToFullMessageEntityList(text, messageEntities)
).first()
}
fun createMarkdownText(
entities: List<MessageEntity>,
partLength: Int = 4096
): List<String> {
val texts = mutableListOf<String>()
val textBuilder = StringBuilder(partLength)
for (entity in entities) {
val string = entity.asMarkdownSource
if (textBuilder.length + string.length > partLength) {
if (textBuilder.isNotEmpty()) {
texts.add(textBuilder.toString())
textBuilder.clear()
}
val chunked = string.chunked(partLength)
val last = chunked.last()
textBuilder.append(last)
val listToAdd = if (chunked.size > 1) {
chunked.subList(0, chunked.size - 1)
} else {
emptyList()
}
listToAdd.forEach {
texts.add(it)
}
} else {
textBuilder.append(string)
}
}
if (textBuilder.isNotEmpty()) {
texts.add(textBuilder.toString())
textBuilder.clear()
}
return texts
}
@Deprecated(
"Deprecated because old version have problem with long texts, but new one must return list of strings",
ReplaceWith(
"toMarkdownCaptions().firstOrNull()",
"com.github.insanusmokrassar.TelegramBotAPI.utils.toMarkdownCaptions"
)
)
fun CaptionedMediaContent.toMarkdownCaption(): String? = toMarkdownCaptions().firstOrNull()
fun CaptionedMediaContent.toMarkdownCaptions(): List<String> = createMarkdownText(
fullEntitiesList(),
captionLength.endInclusive + 1
)
fun CaptionedMediaContent.fullEntitiesList(): List<MessageEntity> = caption ?.let {
convertToFullMessageEntityList(it, captionEntities)
} ?: emptyList()
@Deprecated(
"Deprecated because old version have problem with long texts, but new one must return list of strings",
ReplaceWith(
"toMarkdownTexts().first()",
"com.github.insanusmokrassar.TelegramBotAPI.utils.toMarkdownTexts"
)
)
fun TextContent.toMarkdownText(): String = toMarkdownTexts().first()
fun TextContent.toMarkdownTexts(): List<String> = createMarkdownText(
fullEntitiesList(),
textLength.endInclusive + 1
)
fun TextContent.fullEntitiesList(): List<MessageEntity> = convertToFullMessageEntityList(text, entities)
fun convertToFullMessageEntityList(
@ -111,3 +35,42 @@ fun convertToFullMessageEntityList(
}
return result
}
fun createFormattedText(
entities: List<MessageEntity>,
partLength: Int = 4096,
mode: ParseMode = MarkdownParseMode
): List<String> {
val texts = mutableListOf<String>()
val textBuilder = StringBuilder(partLength)
for (entity in entities) {
val string = when (mode) {
is MarkdownParseMode -> entity.asMarkdownSource
is HTMLParseMode -> entity.asHtmlSource
}
if (textBuilder.length + string.length > partLength) {
if (textBuilder.isNotEmpty()) {
texts.add(textBuilder.toString())
textBuilder.clear()
}
val chunked = string.chunked(partLength)
val last = chunked.last()
textBuilder.append(last)
val listToAdd = if (chunked.size > 1) {
chunked.subList(0, chunked.size - 1)
} else {
emptyList()
}
listToAdd.forEach {
texts.add(it)
}
} else {
textBuilder.append(string)
}
}
if (textBuilder.isNotEmpty()) {
texts.add(textBuilder.toString())
textBuilder.clear()
}
return texts
}

View File

@ -0,0 +1,23 @@
package com.github.insanusmokrassar.TelegramBotAPI.utils
import com.github.insanusmokrassar.TelegramBotAPI.types.MessageEntity.MessageEntity
import com.github.insanusmokrassar.TelegramBotAPI.types.ParseMode.HTMLParseMode
import com.github.insanusmokrassar.TelegramBotAPI.types.captionLength
import com.github.insanusmokrassar.TelegramBotAPI.types.message.content.TextContent
import com.github.insanusmokrassar.TelegramBotAPI.types.message.content.abstracts.CaptionedMediaContent
import com.github.insanusmokrassar.TelegramBotAPI.types.textLength
fun createHtmlText(
entities: List<MessageEntity>,
partLength: Int = 4096
): List<String> = createFormattedText(entities, partLength, HTMLParseMode)
fun CaptionedMediaContent.toHtmlCaptions(): List<String> = createHtmlText(
fullEntitiesList(),
captionLength.endInclusive + 1
)
fun TextContent.toHtmlTexts(): List<String> = createHtmlText(
fullEntitiesList(),
textLength.endInclusive + 1
)

View File

@ -0,0 +1,53 @@
package com.github.insanusmokrassar.TelegramBotAPI.utils
import com.github.insanusmokrassar.TelegramBotAPI.types.MessageEntity.MessageEntity
import com.github.insanusmokrassar.TelegramBotAPI.types.ParseMode.MarkdownParseMode
import com.github.insanusmokrassar.TelegramBotAPI.types.captionLength
import com.github.insanusmokrassar.TelegramBotAPI.types.message.content.TextContent
import com.github.insanusmokrassar.TelegramBotAPI.types.message.content.abstracts.CaptionedMediaContent
import com.github.insanusmokrassar.TelegramBotAPI.types.textLength
@Deprecated(
"Deprecated because old version have problem with long texts, but new one must return list of strings"
)
fun createMarkdownText(
text: String,
messageEntities: List<MessageEntity>
): String {
return createMarkdownText(
convertToFullMessageEntityList(text, messageEntities)
).first()
}
fun createMarkdownText(
entities: List<MessageEntity>,
partLength: Int = 4096
): List<String> = createFormattedText(entities, partLength, MarkdownParseMode)
@Deprecated(
"Deprecated because old version have problem with long texts, but new one must return list of strings",
ReplaceWith(
"toMarkdownCaptions().firstOrNull()",
"com.github.insanusmokrassar.TelegramBotAPI.utils.toMarkdownCaptions"
)
)
fun CaptionedMediaContent.toMarkdownCaption(): String? = toMarkdownCaptions().firstOrNull()
fun CaptionedMediaContent.toMarkdownCaptions(): List<String> = createMarkdownText(
fullEntitiesList(),
captionLength.endInclusive + 1
)
@Deprecated(
"Deprecated because old version have problem with long texts, but new one must return list of strings",
ReplaceWith(
"toMarkdownTexts().first()",
"com.github.insanusmokrassar.TelegramBotAPI.utils.toMarkdownTexts"
)
)
fun TextContent.toMarkdownText(): String = toMarkdownTexts().first()
fun TextContent.toMarkdownTexts(): List<String> = createMarkdownText(
fullEntitiesList(),
textLength.endInclusive + 1
)

View File

@ -0,0 +1,139 @@
package com.github.insanusmokrassar.TelegramBotAPI.utils
import com.github.insanusmokrassar.TelegramBotAPI.types.*
import com.github.insanusmokrassar.TelegramBotAPI.types.ParseMode.*
import com.github.insanusmokrassar.TelegramBotAPI.utils.extensions.toHtml
import com.github.insanusmokrassar.TelegramBotAPI.utils.extensions.toMarkdown
const val markdownBoldControl = "*"
const val markdownItalicControl = "_"
const val markdownCodeControl = "`"
const val markdownPreControl = "```"
const val htmlBoldControl = "b"
const val htmlItalicControl = "i"
const val htmlCodeControl = "code"
const val htmlPreControl = "pre"
private infix fun String.markdownDefault(controlSymbol: String) = "$controlSymbol$this$controlSymbol"
private infix fun String.htmlDefault(controlSymbol: String) = "<$controlSymbol>$this</$controlSymbol>"
infix fun String.linkMarkdown(link: String): String = "[$this]($link)"
infix fun String.linkHTML(link: String): String = "<a href=\"$link\">$this</a>"
fun String.boldMarkdown(): String = markdownDefault(markdownBoldControl)
fun String.boldHTML(): String = htmlDefault(htmlBoldControl)
fun String.italicMarkdown(): String = markdownDefault(markdownItalicControl)
fun String.italicHTML(): String =htmlDefault(htmlItalicControl)
fun String.codeMarkdown(): String = markdownDefault(markdownCodeControl)
fun String.codeHTML(): String = htmlDefault(htmlCodeControl)
fun String.preMarkdown(): String = markdownDefault(markdownPreControl)
fun String.preHTML(): String = htmlDefault(htmlPreControl)
fun String.emailMarkdown(): String = linkMarkdown("mailto://$this")
fun String.emailHTML(): String = linkHTML("mailto://$this")
private inline infix fun String.mention(adapt: String.() -> String): String = if (startsWith("@")) {
this
} else {
"@${adapt()}"
}
private inline infix fun String.hashTag(adapt: String.() -> String): String = if (startsWith("#")) {
this
} else {
"#${adapt()}"
}
infix fun String.mentionMarkdown(userId: UserId): String = linkMarkdown(userId.link)
infix fun String.mentionHTML(userId: UserId): String = linkHTML(userId.link)
fun String.mentionMarkdown(): String = mention(String::toMarkdown)
fun String.mentionHTML(): String = mention(String::toHtml)
fun String.hashTagMarkdown(): String = hashTag(String::toMarkdown)
fun String.hashTagHTML(): String = hashTag(String::toHtml)
fun String.phoneMarkdown(): String = toMarkdown()
fun String.phoneHTML(): String = toHtml()
fun String.command(): String = if (startsWith("/")) {
this
} else {
"/$this"
}
fun String.commandMarkdown(): String = command()
fun String.commandHTML(): String = command()
infix fun String.bold(parseMode: ParseMode): String = when (parseMode) {
is HTML -> boldHTML()
is Markdown -> boldMarkdown()
}
infix fun String.italic(parseMode: ParseMode): String = when (parseMode) {
is HTML -> italicHTML()
is Markdown -> italicMarkdown()
}
infix fun String.hashTag(parseMode: ParseMode): String = when (parseMode) {
is HTML -> hashTagHTML()
is Markdown -> hashTagMarkdown()
}
infix fun String.code(parseMode: ParseMode): String = when (parseMode) {
is HTML -> codeHTML()
is Markdown -> codeMarkdown()
}
infix fun String.pre(parseMode: ParseMode): String = when (parseMode) {
is HTML -> preHTML()
is Markdown -> preMarkdown()
}
infix fun String.email(parseMode: ParseMode): String = when (parseMode) {
is HTML -> emailHTML()
is Markdown -> emailMarkdown()
}
infix fun Pair<String, String>.link(parseMode: ParseMode): String = when (parseMode) {
is HTML -> first.linkHTML(second)
is Markdown -> first.linkMarkdown(second)
}
infix fun String.mention(parseMode: ParseMode): String = when (parseMode) {
is HTML -> mentionHTML()
is Markdown -> mentionMarkdown()
}
infix fun Pair<String, ChatId>.mention(parseMode: ParseMode): String = when (parseMode) {
is HTML -> first.mentionHTML(second)
is Markdown -> first.mentionMarkdown(second)
}
infix fun String.phone(parseMode: ParseMode): String = when (parseMode) {
is HTML -> phoneHTML()
is Markdown -> phoneMarkdown()
}
infix fun String.command(parseMode: ParseMode): String = when (parseMode) {
is HTML -> commandHTML()
is Markdown -> commandMarkdown()
}

View File

@ -9,3 +9,17 @@ fun String.toMarkdown(): String {
"\\_"
)
}
fun String.toHtml(): String = replace(
"<",
"&lt;"
).replace(
">",
"&gt;"
).replace(
"&",
"&amp;"
).replace(
"\"",
"&quot;"
)

View File

@ -31,7 +31,8 @@ class UpdatesPoller(
private suspend fun pushMediaGroupUpdate(update: BaseMessageUpdate? = null) {
val inputMediaGroupId = (update ?.data as? MediaGroupMessage) ?.mediaGroupId
if (mediaGroup.isNotEmpty() && inputMediaGroupId ?.equals(mediaGroup.mediaGroupId) != true) {
listOf(*mediaGroup.toTypedArray()).toMediaGroupUpdate() ?.let {
mediaGroup.sortBy { it.updateId }
mediaGroup.toMediaGroupUpdate() ?.let {
sendToBlock(it)
} ?: mediaGroup.forEach {
sendToBlock(it)
@ -55,9 +56,13 @@ class UpdatesPoller(
}
private suspend fun handleUpdates(updates: List<Update>) {
updates.forEach { update ->
for (update in updates) {
(update as? BaseMessageUpdate) ?.let {
pushMediaGroupUpdate(it)
if (it.data is MediaGroupMessage) {
pushMediaGroupUpdate(it)
} else {
null
}
} ?:let {
pushMediaGroupUpdate()
sendToBlock(update)