mirror of
https://github.com/InsanusMokrassar/TelegramBotAPI-examples.git
synced 2026-06-29 14:45:08 +00:00
Compare commits
1 Commits
renovate/g
...
35.0.0
| Author | SHA1 | Date | |
|---|---|---|---|
| e70650d213 |
21
JoinRequestQueriesBot/build.gradle
Normal file
21
JoinRequestQueriesBot/build.gradle
Normal 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="JoinRequestQueriesBotKt"
|
||||
|
||||
|
||||
dependencies {
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
|
||||
|
||||
implementation "dev.inmo:tgbotapi:$telegram_bot_api_version"
|
||||
}
|
||||
106
JoinRequestQueriesBot/src/main/kotlin/JoinRequestQueriesBot.kt
Normal file
106
JoinRequestQueriesBot/src/main/kotlin/JoinRequestQueriesBot.kt
Normal file
@@ -0,0 +1,106 @@
|
||||
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.tgbotapi.extensions.api.bot.getMe
|
||||
import dev.inmo.tgbotapi.extensions.api.chat.get.getChat
|
||||
import dev.inmo.tgbotapi.extensions.api.chat.invite_links.answerChatJoinRequestQuery
|
||||
import dev.inmo.tgbotapi.extensions.api.chat.invite_links.sendChatJoinRequestWebApp
|
||||
import dev.inmo.tgbotapi.extensions.behaviour_builder.telegramBotWithBehaviourAndLongPolling
|
||||
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onChatJoinRequest
|
||||
import dev.inmo.tgbotapi.requests.chat.invite_links.ChatJoinRequestQueryResult
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
|
||||
/**
|
||||
* This bot demonstrates Join Request Queries support introduced in Telegram Bot API 10.1.
|
||||
*
|
||||
* A "guard bot" of a chat receives chat join requests as queries and must process them with
|
||||
* [answerChatJoinRequestQuery] or hand the user a Web App via [sendChatJoinRequestWebApp]
|
||||
* (for example, to run a captcha / verification flow before deciding).
|
||||
*
|
||||
* Your bot must be set as the guard bot of the chat and must have `can_invite_users` rights to
|
||||
* receive these requests.
|
||||
*
|
||||
* Key concepts demonstrated:
|
||||
* - [dev.inmo.tgbotapi.types.chat.ExtendedBot.supportsJoinRequestQueries] — whether the bot itself
|
||||
* supports join request queries (from getMe(), maps `User.supports_join_request_queries`)
|
||||
* - [dev.inmo.tgbotapi.types.chat.ExtendedChat.guardBot] — the bot that processes join request
|
||||
* queries in a chat (from getChat(), maps `ChatFullInfo.guard_bot`)
|
||||
* - [dev.inmo.tgbotapi.types.chat.ChatJoinRequest.queryId] — the [dev.inmo.tgbotapi.types.ChatJoinRequestQueryId]
|
||||
* present when the request arrives as a query to the guard bot
|
||||
* - [answerChatJoinRequestQuery] with [ChatJoinRequestQueryResult] (Approve / Decline / Queue / Unknown)
|
||||
* - [sendChatJoinRequestWebApp] — open a Web App to process the request
|
||||
*/
|
||||
suspend fun main(vararg args: String) {
|
||||
val botToken = args.first()
|
||||
val isDebug = args.any { it == "debug" }
|
||||
val isTestServer = args.any { it == "testServer" }
|
||||
// pass a https url as the second argument to demonstrate sendChatJoinRequestWebApp
|
||||
val webAppUrl = args.getOrNull(1) ?.takeIf { it.startsWith("https://") }
|
||||
|
||||
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
|
||||
) {
|
||||
val me = getMe()
|
||||
println("Bot info: $me")
|
||||
// supportsJoinRequestQueries reflects the supports_join_request_queries field from the Telegram API
|
||||
println("Supports join request queries: ${me.supportsJoinRequestQueries}")
|
||||
|
||||
onChatJoinRequest { request ->
|
||||
println("=== Chat join request received ===")
|
||||
println(" from: ${request.from}")
|
||||
println(" chat: ${request.chat}")
|
||||
println(" bio: ${request.bio}")
|
||||
// queryId is non-null only when the request arrives as a query to this bot as the guard bot
|
||||
println(" queryId: ${request.queryId}")
|
||||
|
||||
// guardBot is the bot processing join request queries in this chat (admins-only field)
|
||||
val guardBot = runCatching { getChat(request.chat).guardBot }.getOrNull()
|
||||
println(" guardBot: $guardBot")
|
||||
|
||||
val queryId = request.queryId
|
||||
if (queryId == null) {
|
||||
println(" -> request has no queryId, this bot is not the guard bot here")
|
||||
return@onChatJoinRequest
|
||||
}
|
||||
|
||||
if (webAppUrl != null) {
|
||||
// sendChatJoinRequestWebApp: hand the user a Web App (e.g. captcha) instead of deciding now
|
||||
sendChatJoinRequestWebApp(request, webAppUrl)
|
||||
println(" -> sent join request Web App: $webAppUrl")
|
||||
return@onChatJoinRequest
|
||||
}
|
||||
|
||||
// answerChatJoinRequestQuery with one of the ChatJoinRequestQueryResult variants:
|
||||
// Approve — allow the user to join
|
||||
// Decline — disallow the user to join
|
||||
// Queue — leave the decision to other administrators
|
||||
// Unknown — any future result not yet known to the library
|
||||
val result = if (request.bio.isNullOrBlank()) {
|
||||
// no bio -> let other admins decide
|
||||
ChatJoinRequestQueryResult.Queue
|
||||
} else {
|
||||
// has a bio -> approve
|
||||
ChatJoinRequestQueryResult.Approve
|
||||
}
|
||||
answerChatJoinRequestQuery(request, result)
|
||||
println(" -> answered with: ${result.name}")
|
||||
}
|
||||
|
||||
allUpdatesFlow.subscribeLoggingDropExceptions(scope = this) {
|
||||
println(it)
|
||||
}
|
||||
}.second.join()
|
||||
}
|
||||
@@ -25,6 +25,7 @@ import dev.inmo.tgbotapi.types.BotCommand
|
||||
import dev.inmo.tgbotapi.types.IdChatIdentifier
|
||||
import dev.inmo.tgbotapi.types.PollId
|
||||
import dev.inmo.tgbotapi.types.ReplyParameters
|
||||
import dev.inmo.tgbotapi.types.media.TelegramMediaLink
|
||||
import dev.inmo.tgbotapi.types.media.TelegramMediaLocation
|
||||
import dev.inmo.tgbotapi.types.media.TelegramMediaSticker
|
||||
import dev.inmo.tgbotapi.types.media.TelegramMediaVenue
|
||||
@@ -55,6 +56,8 @@ import kotlin.random.Random
|
||||
* * `/members_only` — poll with `membersOnly = true` (new [dev.inmo.tgbotapi.types.polls.Poll.membersOnly] field)
|
||||
* * `/country_codes` — poll with `countryCodes` (new [dev.inmo.tgbotapi.types.polls.Poll.countryCodes] field)
|
||||
* * `/single_option` — poll with just 1 option (minimum options count decreased from 2 to 1)
|
||||
* * `/link_poll` — poll whose options carry a [TelegramMediaLink] (InputMediaLink / Bot API 10.1
|
||||
* [dev.inmo.tgbotapi.types.Link]) as [dev.inmo.tgbotapi.types.media.InputPollOptionMedia]
|
||||
*
|
||||
* [onPollUpdates] prints [dev.inmo.tgbotapi.types.polls.Poll.media], [dev.inmo.tgbotapi.types.polls.Poll.membersOnly],
|
||||
* [dev.inmo.tgbotapi.types.polls.Poll.countryCodes], [QuizPoll.explanationMedia], and
|
||||
@@ -312,6 +315,30 @@ suspend fun main(vararg args: String) {
|
||||
}
|
||||
}
|
||||
|
||||
// Demonstrates TelegramMediaLink (InputMediaLink, Bot API 10.1) as poll option media.
|
||||
// Link is the only new poll media type in 10.1 and is allowed only as InputPollOptionMedia.
|
||||
onCommand("link_poll") {
|
||||
val sentPoll = sendRegularPoll(
|
||||
it.chat.id,
|
||||
buildEntities { regular("Pick your favourite resource") },
|
||||
listOf(
|
||||
// InputPollOptionMedia via TelegramMediaLink (InputMediaLink)
|
||||
InputPollOption(
|
||||
media = TelegramMediaLink("https://core.telegram.org/bots/api")
|
||||
) { regular("Bot API docs") },
|
||||
InputPollOption(
|
||||
media = TelegramMediaLink("https://github.com/InsanusMokrassar/ktgbotapi")
|
||||
) { regular("ktgbotapi") },
|
||||
InputPollOption { regular("None of these") },
|
||||
),
|
||||
isAnonymous = false,
|
||||
replyParameters = ReplyParameters(it)
|
||||
)
|
||||
pollToChatMutex.withLock {
|
||||
pollToChat[sentPoll.content.poll.id] = sentPoll.chat.id
|
||||
}
|
||||
}
|
||||
|
||||
onPollAnswer {
|
||||
val chatId = pollToChat[it.pollId] ?: return@onPollAnswer
|
||||
|
||||
@@ -380,6 +407,7 @@ suspend fun main(vararg args: String) {
|
||||
BotCommand("members_only", "Poll restricted to channel members only (membersOnly)"),
|
||||
BotCommand("country_codes", "Poll targeted to US, DE, JP users (countryCodes)"),
|
||||
BotCommand("single_option", "Poll with 1 option (minimum is now 1, not 2)"),
|
||||
BotCommand("link_poll", "Poll with link media (TelegramMediaLink) on options"),
|
||||
)
|
||||
|
||||
allUpdatesFlow.subscribeLoggingDropExceptions(scope = this) {
|
||||
|
||||
21
RichMessagesBot/build.gradle
Normal file
21
RichMessagesBot/build.gradle
Normal 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="RichMessagesBotKt"
|
||||
|
||||
|
||||
dependencies {
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
|
||||
|
||||
implementation "dev.inmo:tgbotapi:$telegram_bot_api_version"
|
||||
}
|
||||
408
RichMessagesBot/src/main/kotlin/RichMessagesBot.kt
Normal file
408
RichMessagesBot/src/main/kotlin/RichMessagesBot.kt
Normal file
@@ -0,0 +1,408 @@
|
||||
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.tgbotapi.extensions.api.answers.answer
|
||||
import dev.inmo.tgbotapi.extensions.api.bot.setMyCommands
|
||||
import dev.inmo.tgbotapi.extensions.api.send.reply
|
||||
import dev.inmo.tgbotapi.extensions.api.send.send
|
||||
import dev.inmo.tgbotapi.extensions.api.send.sendRichMessage
|
||||
import dev.inmo.tgbotapi.extensions.api.send.sendRichMessageDraft
|
||||
import dev.inmo.tgbotapi.extensions.behaviour_builder.expectations.waitRichMessage
|
||||
import dev.inmo.tgbotapi.extensions.behaviour_builder.telegramBotWithBehaviourAndLongPolling
|
||||
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onBaseInlineQuery
|
||||
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onCommand
|
||||
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onRichMessage
|
||||
import dev.inmo.tgbotapi.extensions.utils.baseSentMessageUpdateOrNull
|
||||
import dev.inmo.tgbotapi.extensions.utils.contentMessageOrNull
|
||||
import dev.inmo.tgbotapi.extensions.utils.onlyRichMessageContentMessages
|
||||
import dev.inmo.tgbotapi.requests.edit.text.EditChatMessageRichText
|
||||
import dev.inmo.tgbotapi.types.BotCommand
|
||||
import dev.inmo.tgbotapi.types.InlineQueries.InlineQueryResult.InlineQueryResultArticle
|
||||
import dev.inmo.tgbotapi.types.InlineQueries.InputMessageContent.InputRichMessageContent
|
||||
import dev.inmo.tgbotapi.types.InlineQueryId
|
||||
import dev.inmo.tgbotapi.types.rich.InputRichMessageHTML
|
||||
import dev.inmo.tgbotapi.types.rich.InputRichMessageMarkdown
|
||||
import dev.inmo.tgbotapi.types.toChatId
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.flow.mapNotNull
|
||||
|
||||
/**
|
||||
* This bot demonstrates Rich Messages support introduced in Telegram Bot API 10.1.
|
||||
*
|
||||
* Rich messages allow bots to send highly structured text (and to stream AI-generated replies
|
||||
* with seamless rich formatting). Telegram parses the provided HTML/Markdown into a structured
|
||||
* [dev.inmo.tgbotapi.types.rich.RichMessage] made of [dev.inmo.tgbotapi.types.rich.RichBlock]s.
|
||||
*
|
||||
* Key concepts demonstrated:
|
||||
* - [dev.inmo.tgbotapi.types.rich.InputRichMessage] — describes a rich message to send. Built only via
|
||||
* the [InputRichMessageHTML] / [InputRichMessageMarkdown] factories (exactly one format must be used)
|
||||
* - [sendRichMessage] — sendRichMessage method
|
||||
* - [sendRichMessageDraft] — sendRichMessageDraft method: stream partial rich messages by draftId
|
||||
* - [EditChatMessageRichText] — editMessageText with the new `rich_message` parameter
|
||||
* - [onRichMessage] — trigger for incoming [dev.inmo.tgbotapi.types.message.content.RichMessageContent]
|
||||
* (the new `rich_message` field of Message)
|
||||
* - [waitRichMessage] — expectation for a rich message
|
||||
* - [onlyRichMessageContentMessages] — flow filter keeping only rich message content
|
||||
* - [InputRichMessageContent] — usable as InputMessageContent in inline query results
|
||||
*/
|
||||
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
|
||||
) {
|
||||
// sendRichMessage with HTML-formatted content
|
||||
onCommand("rich_html") {
|
||||
sendRichMessage(
|
||||
it.chat.id,
|
||||
// InputRichMessageHTML factory — content described using HTML formatting
|
||||
InputRichMessageHTML(
|
||||
"""
|
||||
<a name="chapter-0"></a>
|
||||
<b>bold text</b>, <strong>bold text</strong>
|
||||
<i>italic text</i>, <em>italic text</em>
|
||||
<u>underlined text</u>, <ins>underlined text</ins>
|
||||
<s>strikethrough text</s>, <strike>strikethrough text</strike>, <del>strikethrough text</del>
|
||||
<code>inline fixed-width code</code>
|
||||
<mark>marked text</mark>
|
||||
<sub>subscript text</sub>
|
||||
<sup>superscript text</sup>
|
||||
<tg-spoiler>spoiler</tg-spoiler>
|
||||
|
||||
<a href="#note-1">Reference</a>
|
||||
<a href="https://t.me/">inline URL</a>
|
||||
<a href="mailto:user@example.com">inline e-mail</a>
|
||||
<a href="tel:+123456789">inline phone number</a>
|
||||
<a href="tg://user?id=123456789">inline mention of a user</a>
|
||||
<a href="#chapter-1">in-document link</a>
|
||||
<a name="chapter-1"></a>
|
||||
|
||||
<tg-reference name="note-1">Referenced text</tg-reference>
|
||||
<tg-emoji emoji-id="5368324170671202286">👍</tg-emoji>
|
||||
<img src="tg://emoji?id=5368324170671202286" alt="👍"/>
|
||||
<tg-time unix="1647531900" format="wDT">22:45 tomorrow</tg-time>
|
||||
<tg-math>x^2 + y^2</tg-math>
|
||||
|
||||
#hashtag ${'$'}USD +12345678901, card: 4242 4242 4242 4242, https://t.me t.me a@t.me /command @username
|
||||
|
||||
all the text above was on the same line
|
||||
|
||||
<h1>Heading 1</h1>
|
||||
<h2>Heading 2</h2>
|
||||
<h3>Heading 3</h3>
|
||||
<h4>Heading 4</h4>
|
||||
<h5>Heading 5</h5>
|
||||
<h6>Heading 6</h6>
|
||||
|
||||
<a name="chapter-2"></a>
|
||||
|
||||
<p>Paragraph text</p>
|
||||
<pre>pre-formatted fixed-width code block</pre>
|
||||
<pre><code class="language-python"> print('pre-formatted fixed-width code block written in the Python programming language')</code></pre>
|
||||
<footer>Footer text</footer>
|
||||
<hr/>
|
||||
<ul><li>unordered list item</li></ul>
|
||||
<ol><li>ordered list item</li></ol>
|
||||
<ol start="3" type="a" reversed><li>ordered list item</li></ol>
|
||||
<ol><li value="7" type="i">ordered list item with explicit number</li></ol>
|
||||
<ul>
|
||||
<li><input type="checkbox" checked>Checked checkbox</li>
|
||||
<li><input type="checkbox">Unchecked checkbox</li>
|
||||
</ul>
|
||||
|
||||
<blockquote>Block quotation started<br>Block quotation continued<br>The last line of the block quotation<cite>The Author</cite></blockquote>
|
||||
<aside>Pull quote<cite>The Author</cite></aside>
|
||||
|
||||
<img src="https://telegram.org/example/photo.jpg"/>
|
||||
<video src="https://telegram.org/example/video.mp4"></video>
|
||||
<audio src="https://telegram.org/example/audio.mp3"></audio>
|
||||
<audio src="https://telegram.org/example/audio.ogg"></audio>
|
||||
<video src="https://telegram.org/example/animation.gif"></video>
|
||||
|
||||
<figure><img src="https://telegram.org/example/photo.jpg" tg-spoiler/><figcaption>Photo caption<cite>Photo credit</cite></figcaption></figure>
|
||||
<figure><video src="https://telegram.org/example/video.mp4" tg-spoiler></video><figcaption>Video caption</figcaption></figure>
|
||||
<figure><audio src="https://telegram.org/example/audio.mp3"></audio><figcaption>Audio caption</figcaption></figure>
|
||||
<figure><audio src="https://telegram.org/example/audio.ogg"></audio><figcaption>Voice note caption</figcaption></figure>
|
||||
<figure><video src="https://telegram.org/example/animation.gif" tg-spoiler></video><figcaption>Animation caption</figcaption></figure>
|
||||
|
||||
<tg-map lat="41.9" long="12.5" zoom="14"/>
|
||||
<figure><tg-map lat="41.9" long="12.5" zoom="14"/><figcaption>Map caption</figcaption></figure>
|
||||
|
||||
<tg-collage><img src="https://telegram.org/example/photo.jpg"/><video src="https://telegram.org/example/video.mp4"/></tg-collage>
|
||||
<tg-collage><video src="https://telegram.org/example/video.mp4"/><img src="https://telegram.org/example/photo.jpg"/><figcaption>Collage caption</figcaption></tg-collage>
|
||||
<tg-slideshow><img src="https://telegram.org/example/photo.jpg"/><video src="https://telegram.org/example/video.mp4"/></tg-slideshow>
|
||||
<tg-slideshow><video src="https://telegram.org/example/video.mp4"/><img src="https://telegram.org/example/photo.jpg"/><figcaption>Slideshow caption</figcaption></tg-slideshow>
|
||||
|
||||
<table><tr><th>Header 1</th><th>Header 2</th></tr><tr><td>Value 1</td><td>Value 2</td></tr></table>
|
||||
<table bordered striped><caption>Table caption</caption>
|
||||
<tr><td colspan="2" rowspan="2" align="left">Value</td><td align="center">Value2</td><td align="right">Value3</td></tr>
|
||||
<tr><td valign="top">Value4</td><td valign="middle">Value5</td><td valign="bottom">Value6</td></tr>
|
||||
<tr><td>Value7</td></tr></table>
|
||||
|
||||
<details><summary>Title</summary>Content</details>
|
||||
<details open><summary>Title</summary>Content</details>
|
||||
<tg-math-block>E = mc^2</tg-math-block>
|
||||
""".trimIndent()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
// sendRichMessage with Markdown-formatted content
|
||||
onCommand("rich_markdown") {
|
||||
val sent = sendRichMessage(
|
||||
it.chat.id,
|
||||
// InputRichMessageMarkdown factory — content described using Markdown formatting
|
||||
InputRichMessageMarkdown(
|
||||
"""
|
||||
**bold text**
|
||||
__bold text__
|
||||
*italic text*
|
||||
_italic text_
|
||||
~~strikethrough text~~
|
||||
`inline fixed-width code`
|
||||
==marked text==
|
||||
||spoiler||
|
||||
|
||||
[inline URL](https://t.me/)
|
||||
[inline e-mail](mailto:user@example.com)
|
||||
[inline phone number](tel:+123456789)
|
||||
[inline mention of a user](tg://user?id=123456789)
|
||||

|
||||

|
||||
${'$'}x^2 + y^2$
|
||||
\#hashtag ${'$'}USD +12345678901, card: 4242 4242 4242 4242, https://t.me t.me a@t.me /command @username
|
||||
all the text above was on the same line
|
||||
|
||||
# Heading 1
|
||||
## Heading 2
|
||||
### Heading 3
|
||||
#### Heading 4
|
||||
##### Heading 5
|
||||
###### Heading 6
|
||||
|
||||
Paragraph text
|
||||
|
||||
```python
|
||||
print('pre-formatted fixed-width code block written in the Python programming language')
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
- unordered list item
|
||||
* unordered list item
|
||||
+ unordered list item
|
||||
|
||||
1. ordered list item
|
||||
2. ordered list item
|
||||
|
||||
- [ ] task list item
|
||||
- [x] completed task list item
|
||||
|
||||
>Block quotation started
|
||||
>
|
||||
>Block quotation continued on the next line
|
||||
>Block quotation continued on the same line
|
||||
>
|
||||
>The last line of the block quotation
|
||||
|
||||

|
||||

|
||||

|
||||

|
||||

|
||||
|
||||

|
||||

|
||||

|
||||

|
||||

|
||||
|
||||
| Header 1 | Header 2 |
|
||||
|:---------|:--------:|
|
||||
| left | center |
|
||||
|
||||
Text with a reference[^id1] and another one[^id2].
|
||||
|
||||
[^id1]: Definition of the first footnote.
|
||||
[^id2]: Definition of the second footnote.
|
||||
|
||||
$${'$'}E = mc^2$$
|
||||
|
||||
```math
|
||||
E = mc^2
|
||||
```
|
||||
|
||||
## Example Nested Syntax Report for _Q1_
|
||||
Intro with <u>underlined text</u>, ==marked text==, and ${'$'}x^2 + y^2$.
|
||||
**Bold _italic <u>underlined italic bold</u> italic_ bold**
|
||||
<u>In inline tags, nested **markdown** is parsed</u>
|
||||
>Quote with **bold text, ~~strikethrough, and <tg-spoiler>spoiler</tg-spoiler>~~**, plus [a link](https://t.me/).
|
||||
|
||||
- List item with `code`, <sup>superscript</sup>, <sub>subscript</sub>, and a footnote[^note]
|
||||
- Another item with **bold <tg-spoiler><code>spoiler code</code></tg-spoiler>**
|
||||
- Another item with ~~strikethrough and <ins>inserted text</ins>~~
|
||||
|
||||
| Metric | Value |
|
||||
|:-------|------:|
|
||||
| Speed | **42** <sup>ms</sup> |
|
||||
| Status | <tg-spoiler>ready</tg-spoiler> |
|
||||
|
||||
[^note]: Footnote with _italic text_ and <u>HTML underline</u>.
|
||||
|
||||
---
|
||||
|
||||
# Details blocks can contain Markdown content:
|
||||
|
||||
<details open><summary>Summary with **bold text**</summary>
|
||||
|
||||
### Details heading
|
||||
- List item with _italic text_
|
||||
- List item with <tg-spoiler>spoiler</tg-spoiler>
|
||||
|
||||
</details>
|
||||
|
||||
# Collages and slideshows can contain Markdown media blocks:
|
||||
|
||||
<tg-collage>
|
||||
|
||||

|
||||

|
||||
|
||||
</tg-collage>
|
||||
|
||||
<tg-slideshow>
|
||||
|
||||

|
||||

|
||||
|
||||
</tg-slideshow>
|
||||
""".trimIndent()
|
||||
)
|
||||
)
|
||||
println(sent)
|
||||
}
|
||||
|
||||
// sendRichMessageDraft: stream partial rich messages sharing one draftId, then finalize
|
||||
// with a full sendRichMessage. Emulates streaming of an AI-generated reply.
|
||||
onCommand("rich_draft") {
|
||||
val chatId = it.chat.id.toChatId()
|
||||
val draftId = 1L
|
||||
val parts = listOf(
|
||||
"Thinking",
|
||||
"Thinking about *rich* messages",
|
||||
"Thinking about *rich* messages and how to _stream_ them"
|
||||
)
|
||||
parts.forEach { part ->
|
||||
sendRichMessageDraft(chatId, draftId, InputRichMessageMarkdown(part))
|
||||
delay(1000)
|
||||
}
|
||||
// finalize the streamed draft with the real message
|
||||
sendRichMessage(chatId, InputRichMessageMarkdown("Done! Here is the *final* rich message."))
|
||||
}
|
||||
|
||||
// EditChatMessageRichText: send a rich message, then edit it with new rich content
|
||||
onCommand("rich_edit") {
|
||||
val sent = sendRichMessage(it.chat.id, InputRichMessageMarkdown("*Original* rich message"))
|
||||
delay(2000)
|
||||
execute(
|
||||
EditChatMessageRichText(
|
||||
chatId = sent.chat.id,
|
||||
messageId = sent.messageId,
|
||||
// the new rich_message parameter of editMessageText
|
||||
richMessage = InputRichMessageMarkdown("*Edited* rich message — now _updated_")
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
// waitRichMessage expectation: wait for the user to send a rich message
|
||||
onCommand("wait_rich") {
|
||||
reply(it, "Send me a rich message now")
|
||||
val richMessageContent = waitRichMessage().first()
|
||||
reply(
|
||||
it,
|
||||
"Got rich message with ${richMessageContent.richMessage.blocks.size} block(s)"
|
||||
)
|
||||
}
|
||||
|
||||
// onRichMessage trigger: incoming messages carrying the new rich_message field
|
||||
onRichMessage { message ->
|
||||
val richMessage = message.content.richMessage
|
||||
println("=== Rich message received ===")
|
||||
println(" isRtl: ${richMessage.isRtl}")
|
||||
println(" blocks: ${richMessage.blocks.size}")
|
||||
richMessage.blocks.forEachIndexed { index, block ->
|
||||
println(" [$index] $block")
|
||||
}
|
||||
reply(message, "Received a rich message with ${richMessage.blocks.size} block(s)")
|
||||
execute(
|
||||
message.content.createResend(
|
||||
message.chat.id,
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
// InputRichMessageContent as InputMessageContent of inline query results
|
||||
onBaseInlineQuery { query ->
|
||||
answer(
|
||||
query,
|
||||
results = listOf(
|
||||
InlineQueryResultArticle(
|
||||
InlineQueryId("rich_html"),
|
||||
"Rich message (HTML)",
|
||||
// InputRichMessageContent wraps an InputRichMessage and is a valid InputMessageContent
|
||||
InputRichMessageContent(
|
||||
InputRichMessageHTML("<b>Bold</b> rich message sent via inline query")
|
||||
),
|
||||
description = "InputRichMessageContent built from HTML"
|
||||
),
|
||||
InlineQueryResultArticle(
|
||||
InlineQueryId("rich_markdown"),
|
||||
"Rich message (Markdown)",
|
||||
InputRichMessageContent(
|
||||
InputRichMessageMarkdown("*Bold* rich message sent via inline query")
|
||||
),
|
||||
description = "InputRichMessageContent built from Markdown"
|
||||
)
|
||||
),
|
||||
cachedTime = 0
|
||||
)
|
||||
}
|
||||
|
||||
// onlyRichMessageContentMessages: filter a Flow<ContentMessage<*>> down to rich message content
|
||||
allUpdatesFlow
|
||||
.mapNotNull { it.baseSentMessageUpdateOrNull() ?.data ?.contentMessageOrNull() }
|
||||
.onlyRichMessageContentMessages()
|
||||
.subscribeLoggingDropExceptions(scope = this) { richMessageContentMessage ->
|
||||
println("[onlyRichMessageContentMessages] ${richMessageContentMessage.content.richMessage.blocks.size} blocks")
|
||||
}
|
||||
|
||||
setMyCommands(
|
||||
BotCommand("rich_html", "Send a rich message described with HTML"),
|
||||
BotCommand("rich_markdown", "Send a rich message described with Markdown"),
|
||||
BotCommand("rich_draft", "Stream a rich message draft, then finalize it"),
|
||||
BotCommand("rich_edit", "Send a rich message and edit it with new rich content"),
|
||||
BotCommand("wait_rich", "Wait for you to send a rich message"),
|
||||
)
|
||||
|
||||
allUpdatesFlow.subscribeLoggingDropExceptions(scope = this) {
|
||||
println(it)
|
||||
}
|
||||
}.second.join()
|
||||
}
|
||||
@@ -26,7 +26,7 @@ allprojects {
|
||||
}
|
||||
}
|
||||
|
||||
// maven { url "https://proxy.nexus.inmo.dev/repository/maven-releases/" }
|
||||
maven { url "https://nexus.inmo.dev/repository/maven-releases/" }
|
||||
mavenLocal()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ kotlin.daemon.jvmargs=-Xmx3g -Xms500m
|
||||
|
||||
|
||||
kotlin_version=2.3.20
|
||||
telegram_bot_api_version=34.0.0
|
||||
telegram_bot_api_version=35.0.0
|
||||
micro_utils_version=0.29.1
|
||||
serialization_version=1.10.0
|
||||
ktor_version=3.4.1
|
||||
|
||||
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Binary file not shown.
6
gradle/wrapper/gradle-wrapper.properties
vendored
6
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -1,9 +1,5 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-9.6.1-bin.zip
|
||||
networkTimeout=10000
|
||||
retries=0
|
||||
retryBackOffMs=500
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip
|
||||
|
||||
304
gradlew
vendored
304
gradlew
vendored
@@ -1,128 +1,78 @@
|
||||
#!/bin/sh
|
||||
|
||||
#
|
||||
# Copyright © 2015 the original authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
#!/usr/bin/env sh
|
||||
|
||||
##############################################################################
|
||||
#
|
||||
# gradlew start up script for POSIX generated by Gradle.
|
||||
#
|
||||
# Important for running:
|
||||
#
|
||||
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
|
||||
# noncompliant, but you have some other compliant shell such as ksh or
|
||||
# bash, then to run this script, type that shell name before the whole
|
||||
# command line, like:
|
||||
#
|
||||
# ksh gradlew
|
||||
#
|
||||
# Busybox and similar reduced shells will NOT work, because this script
|
||||
# requires all of these POSIX shell features:
|
||||
# * functions;
|
||||
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
|
||||
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
|
||||
# * compound commands having a testable exit status, especially «case»;
|
||||
# * various built-in commands including «command», «set», and «ulimit».
|
||||
#
|
||||
# Important for patching:
|
||||
#
|
||||
# (2) This script targets any POSIX shell, so it avoids extensions provided
|
||||
# by Bash, Ksh, etc; in particular arrays are avoided.
|
||||
#
|
||||
# The "traditional" practice of packing multiple parameters into a
|
||||
# space-separated string is a well documented source of bugs and security
|
||||
# problems, so this is (mostly) avoided, by progressively accumulating
|
||||
# options in "$@", and eventually passing that to Java.
|
||||
#
|
||||
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
|
||||
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
|
||||
# see the in-line comments for details.
|
||||
#
|
||||
# There are tweaks for specific operating systems such as AIX, CygWin,
|
||||
# Darwin, MinGW, and NonStop.
|
||||
#
|
||||
# (3) This script is generated from the Groovy template
|
||||
# https://github.com/gradle/gradle/blob/3d91ce3b8caaf77ad09f381f43615b715b53f72c/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# within the Gradle project.
|
||||
#
|
||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||
#
|
||||
##
|
||||
## Gradle start up script for UN*X
|
||||
##
|
||||
##############################################################################
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
|
||||
# Resolve links: $0 may be a link
|
||||
app_path=$0
|
||||
|
||||
# Need this for daisy-chained symlinks.
|
||||
while
|
||||
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
|
||||
[ -h "$app_path" ]
|
||||
do
|
||||
ls=$( ls -ld "$app_path" )
|
||||
link=${ls#*' -> '}
|
||||
case $link in #(
|
||||
/*) app_path=$link ;; #(
|
||||
*) app_path=$APP_HOME$link ;;
|
||||
esac
|
||||
PRG="$0"
|
||||
# Need this for relative symlinks.
|
||||
while [ -h "$PRG" ] ; do
|
||||
ls=`ls -ld "$PRG"`
|
||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||
if expr "$link" : '/.*' > /dev/null; then
|
||||
PRG="$link"
|
||||
else
|
||||
PRG=`dirname "$PRG"`"/$link"
|
||||
fi
|
||||
done
|
||||
SAVED="`pwd`"
|
||||
cd "`dirname \"$PRG\"`/" >/dev/null
|
||||
APP_HOME="`pwd -P`"
|
||||
cd "$SAVED" >/dev/null
|
||||
|
||||
# This is normally unused
|
||||
# shellcheck disable=SC2034
|
||||
APP_BASE_NAME=${0##*/}
|
||||
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
|
||||
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
|
||||
APP_NAME="Gradle"
|
||||
APP_BASE_NAME=`basename "$0"`
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS=""
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD=maximum
|
||||
MAX_FD="maximum"
|
||||
|
||||
warn () {
|
||||
echo "$*"
|
||||
} >&2
|
||||
}
|
||||
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
} >&2
|
||||
}
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
nonstop=false
|
||||
case "$( uname )" in #(
|
||||
CYGWIN* ) cygwin=true ;; #(
|
||||
Darwin* ) darwin=true ;; #(
|
||||
MSYS* | MINGW* ) msys=true ;; #(
|
||||
NONSTOP* ) nonstop=true ;;
|
||||
case "`uname`" in
|
||||
CYGWIN* )
|
||||
cygwin=true
|
||||
;;
|
||||
Darwin* )
|
||||
darwin=true
|
||||
;;
|
||||
MINGW* )
|
||||
msys=true
|
||||
;;
|
||||
NONSTOP* )
|
||||
nonstop=true
|
||||
;;
|
||||
esac
|
||||
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD=$JAVA_HOME/jre/sh/java
|
||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||
else
|
||||
JAVACMD=$JAVA_HOME/bin/java
|
||||
JAVACMD="$JAVA_HOME/bin/java"
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
@@ -131,118 +81,92 @@ Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD=java
|
||||
if ! command -v java >/dev/null 2>&1
|
||||
then
|
||||
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
JAVACMD="java"
|
||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||
case $MAX_FD in #(
|
||||
max*)
|
||||
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC2039,SC3045
|
||||
MAX_FD=$( ulimit -H -n ) ||
|
||||
warn "Could not query maximum file descriptor limit"
|
||||
esac
|
||||
case $MAX_FD in #(
|
||||
'' | soft) :;; #(
|
||||
*)
|
||||
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC2039,SC3045
|
||||
ulimit -n "$MAX_FD" ||
|
||||
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||
esac
|
||||
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
|
||||
MAX_FD_LIMIT=`ulimit -H -n`
|
||||
if [ $? -eq 0 ] ; then
|
||||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
||||
MAX_FD="$MAX_FD_LIMIT"
|
||||
fi
|
||||
ulimit -n $MAX_FD
|
||||
if [ $? -ne 0 ] ; then
|
||||
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
||||
fi
|
||||
else
|
||||
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Collect all arguments for the java command, stacking in reverse order:
|
||||
# * args from the command line
|
||||
# * the main class name
|
||||
# * -classpath
|
||||
# * -D...appname settings
|
||||
# * --module-path (only if needed)
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
|
||||
|
||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||
if "$cygwin" || "$msys" ; then
|
||||
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
||||
|
||||
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
||||
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
for arg do
|
||||
if
|
||||
case $arg in #(
|
||||
-*) false ;; # don't mess with options #(
|
||||
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
|
||||
[ -e "$t" ] ;; #(
|
||||
*) false ;;
|
||||
esac
|
||||
then
|
||||
arg=$( cygpath --path --ignore --mixed "$arg" )
|
||||
# For Darwin, add options to specify how the application appears in the dock
|
||||
if $darwin; then
|
||||
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
||||
fi
|
||||
# Roll the args list around exactly as many times as the number of
|
||||
# args, so each arg winds up back in the position where it started, but
|
||||
# possibly modified.
|
||||
#
|
||||
# NB: a `for` loop captures its iteration list before it begins, so
|
||||
# changing the positional parameters here affects neither the number of
|
||||
# iterations, nor the values presented in `arg`.
|
||||
shift # remove old arg
|
||||
set -- "$@" "$arg" # push replacement arg
|
||||
|
||||
# For Cygwin, switch paths to Windows format before running java
|
||||
if $cygwin ; then
|
||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||
JAVACMD=`cygpath --unix "$JAVACMD"`
|
||||
|
||||
# We build the pattern for arguments to be converted via cygpath
|
||||
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
||||
SEP=""
|
||||
for dir in $ROOTDIRSRAW ; do
|
||||
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
||||
SEP="|"
|
||||
done
|
||||
OURCYGPATTERN="(^($ROOTDIRS))"
|
||||
# Add a user-defined pattern to the cygpath arguments
|
||||
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
||||
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
||||
fi
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
i=0
|
||||
for arg in "$@" ; do
|
||||
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
||||
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
||||
|
||||
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
||||
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
||||
else
|
||||
eval `echo args$i`="\"$arg\""
|
||||
fi
|
||||
i=$((i+1))
|
||||
done
|
||||
case $i in
|
||||
(0) set -- ;;
|
||||
(1) set -- "$args0" ;;
|
||||
(2) set -- "$args0" "$args1" ;;
|
||||
(3) set -- "$args0" "$args1" "$args2" ;;
|
||||
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
||||
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
||||
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
||||
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
||||
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
||||
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# Escape application args
|
||||
save () {
|
||||
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
|
||||
echo " "
|
||||
}
|
||||
APP_ARGS=$(save "$@")
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
# Collect all arguments for the java command, following the shell quoting and substitution rules
|
||||
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
|
||||
|
||||
# Collect all arguments for the java command:
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
||||
# and any embedded shellness will be escaped.
|
||||
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
|
||||
# treated as '${Hostname}' itself on the command line.
|
||||
|
||||
set -- \
|
||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||
-jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
|
||||
"$@"
|
||||
|
||||
# Stop when "xargs" is not available.
|
||||
if ! command -v xargs >/dev/null 2>&1
|
||||
then
|
||||
die "xargs is not available"
|
||||
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
|
||||
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
|
||||
cd "$(dirname "$0")"
|
||||
fi
|
||||
|
||||
# Use "xargs" to parse quoted args.
|
||||
#
|
||||
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
|
||||
#
|
||||
# In Bash we could simply go:
|
||||
#
|
||||
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
|
||||
# set -- "${ARGS[@]}" "$@"
|
||||
#
|
||||
# but POSIX shell has neither arrays nor command substitution, so instead we
|
||||
# post-process each arg (as a line of input to sed) to backslash-escape any
|
||||
# character that might be a shell metacharacter, then use eval to reverse
|
||||
# that process (while maintaining the separation between arguments), and wrap
|
||||
# the whole thing up as a single "set" statement.
|
||||
#
|
||||
# This will of course break if any of these variables contains a newline or
|
||||
# an unmatched quote.
|
||||
#
|
||||
|
||||
eval "set -- $(
|
||||
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
|
||||
xargs -n1 |
|
||||
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
|
||||
tr '\n' ' '
|
||||
)" '"$@"'
|
||||
|
||||
exec "$JAVACMD" "$@"
|
||||
|
||||
96
gradlew.bat
vendored
96
gradlew.bat
vendored
@@ -1,82 +1,84 @@
|
||||
@rem
|
||||
@rem Copyright 2015 the original author or authors.
|
||||
@rem
|
||||
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@rem you may not use this file except in compliance with the License.
|
||||
@rem You may obtain a copy of the License at
|
||||
@rem
|
||||
@rem https://www.apache.org/licenses/LICENSE-2.0
|
||||
@rem
|
||||
@rem Unless required by applicable law or agreed to in writing, software
|
||||
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@rem See the License for the specific language governing permissions and
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
@rem SPDX-License-Identifier: Apache-2.0
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%" == "" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem gradlew startup script for Windows
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables, and ensure extensions are enabled
|
||||
setlocal EnableExtensions
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%" == "" set DIRNAME=.
|
||||
@rem This is normally unused
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||
set DEFAULT_JVM_OPTS=
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if %ERRORLEVEL% equ 0 goto execute
|
||||
if "%ERRORLEVEL%" == "0" goto init
|
||||
|
||||
echo. 1>&2
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
|
||||
echo. 1>&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||
echo location of your Java installation. 1>&2
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
"%COMSPEC%" /c exit 1
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto execute
|
||||
if exist "%JAVA_EXE%" goto init
|
||||
|
||||
echo. 1>&2
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
|
||||
echo. 1>&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||
echo location of your Java installation. 1>&2
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
"%COMSPEC%" /c exit 1
|
||||
goto fail
|
||||
|
||||
:init
|
||||
@rem Get command-line arguments, handling Windows variants
|
||||
|
||||
if not "%OS%" == "Windows_NT" goto win9xME_args
|
||||
|
||||
:win9xME_args
|
||||
@rem Slurp the command line arguments.
|
||||
set CMD_LINE_ARGS=
|
||||
set _SKIP=2
|
||||
|
||||
:win9xME_args_slurp
|
||||
if "x%~1" == "x" goto execute
|
||||
|
||||
set CMD_LINE_ARGS=%*
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
|
||||
|
||||
@rem Execute gradlew
|
||||
@rem endlocal doesn't take effect until after the line is parsed and variables are expanded
|
||||
@rem which allows us to clear the local environment before executing the java command
|
||||
endlocal & "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* & call :exitWithErrorLevel
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||
|
||||
:exitWithErrorLevel
|
||||
@rem Use "%COMSPEC%" /c exit to allow operators to work properly in scripts
|
||||
"%COMSPEC%" /c exit %ERRORLEVEL%
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||
exit /b 1
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
||||
|
||||
@@ -77,3 +77,7 @@ include ":GuestQueryBot"
|
||||
include ":LivePhotosBot"
|
||||
|
||||
include ":ChatManagementBot"
|
||||
|
||||
include ":RichMessagesBot"
|
||||
|
||||
include ":JoinRequestQueriesBot"
|
||||
|
||||
Reference in New Issue
Block a user