Compare commits

..

9 Commits

Author SHA1 Message Date
acdbd4d2ea update HelloBot 2024-08-15 01:51:10 +06:00
d2d913fca8 update telegram bots api 2024-08-14 23:33:43 +06:00
75726cac89 Merge pull request #276 from InsanusMokrassar/16.0.0
16.0.0
2024-08-12 08:13:59 +06:00
71b64689d0 Update gradle.properties 2024-08-12 02:32:28 +06:00
5ba2fc5bab update githab workflow 2024-08-11 19:52:15 +06:00
51a5bfb81a update gradle wrapper 2024-08-11 19:49:31 +06:00
35e330c016 update kotlin 2024-08-11 19:49:31 +06:00
90d447fbcf update up to 16.0.0 2024-08-11 19:49:31 +06:00
2c5da5da9f Merge pull request #278 from InsanusMokrassar/15.3.0
15.3.0
2024-08-02 19:29:33 +06:00
12 changed files with 329 additions and 21 deletions

View File

@@ -10,6 +10,7 @@ jobs:
- uses: actions/checkout@v2
- name: Install dependencies
run: |
sudo apt update
sudo apt install -y libcurl4-openssl-dev
- name: Set up JDK 17
uses: actions/setup-java@v1

1
.gitignore vendored
View File

@@ -1,4 +1,5 @@
.idea
.kotlin
out/*
*.iml
target

2
.template/bot/.env Normal file
View File

@@ -0,0 +1,2 @@
title=$prompt
subtitle=Subtitle of {{$title}}

View File

@@ -0,0 +1,9 @@
# {{$title}}
## Launch
```bash
../gradlew run --args="BOT_TOKEN"
```

View File

@@ -0,0 +1,22 @@
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
apply plugin: 'kotlin'
apply plugin: 'application'
mainClassName="{{$title}}Kt"
{{$subtitle}}
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation "dev.inmo:tgbotapi:$telegram_bot_api_version"
}

View File

@@ -0,0 +1,34 @@
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.subscribeSafelyWithoutExceptions
import dev.inmo.tgbotapi.extensions.api.bot.getMe
import dev.inmo.tgbotapi.extensions.behaviour_builder.telegramBotWithBehaviourAndLongPolling
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
/**
* This place can be the playground for your code.
*/
suspend fun main(vararg args: String) {
val botToken = args.first()
val isDebug = args.any { it == "debug" }
if (isDebug) {
setDefaultKSLog(
KSLog { level: LogLevel, tag: String?, message: Any, throwable: Throwable? ->
println(defaultMessageFormatter(level, tag, message, throwable))
}
)
}
telegramBotWithBehaviourAndLongPolling(botToken, CoroutineScope(Dispatchers.IO)) {
// start here!!
val me = getMe()
println(me)
allUpdatesFlow.subscribeSafelyWithoutExceptions(this) { println(it) }
}.second.join()
}

View File

@@ -0,0 +1,208 @@
#!/usr/bin/env kotlin
/**
* Generates files and folders as they have been put in the folder. Envs uses common syntax, but
* values may contains {{${'$'}sampleVariable}} parts, where {{${'$'}sampleVariable}} will be replaced with variable value.
* Example:
*
* .env:
* sampleVariable=${'$'}prompt # require request from command line
* sampleVariable2=just some value
* sampleVariable3=${'$'}{sampleVariable}.${'$'}{sampleVariable2}
*
* Result variables:
* sampleVariable=your input in console # lets imagine you typed it
* sampleVariable2=just some value
* sampleVariable3=your input in console.just some value
*
* To use these variables in template, you will need to write {{${'$'}sampleVariable}}.
* You may use it in text of files as well as in files/folders names.
*
* Usage: kotlin generator.kts [args] folders...
* Args:
* -e, --env: Path to file with args for generation; Use "${'$'}prompt" as values to read variable value from console
* -o, --outputFolder: Folder where templates should be used. Folder of calling by default
* folders: Folders-templates
*/
import java.io.File
val console = System.console()
fun String.replaceWithVariables(envs: Map<String, String>): String {
var currentString = this
var changed = false
do {
changed = false
envs.forEach { (k, v) ->
val previousString = currentString
currentString = currentString.replace("{{$${k}}}", v)
changed = changed || currentString != previousString
}
} while (changed)
return currentString
}
fun requestVariable(variableName: String, defaultValue: String?): String {
console.printf("Enter value for variable $variableName${defaultValue ?.let { " [$it]" } ?: ""}: ")
return console.readLine().ifEmpty { defaultValue } ?: ""
}
fun readEnvs(content: String, presets: Map<String, String>): Map<String, String> {
val initialEnvs = mutableMapOf<String, String>()
content.split("\n").forEach {
val withoutComment = it.replace(Regex("\\#.*"), "")
runCatching {
val (key, value) = withoutComment.split("=")
val existsValue = presets[key]
if (value == "\$prompt") {
initialEnvs[key] = requestVariable(key, existsValue)
} else {
initialEnvs[key] = requestVariable(key, value.replaceWithVariables(initialEnvs))
}
}
}
var i = 0
val readEnvs = initialEnvs.toMutableMap()
while (i < readEnvs.size) {
val key = readEnvs.keys.elementAt(i)
val currentValue = readEnvs.getValue(key)
val withReplaced = currentValue.replaceWithVariables(readEnvs)
var changed = false
if (withReplaced != currentValue) {
i = 0
readEnvs[key] = withReplaced
} else {
i++
}
}
return presets + readEnvs
}
var envFile: File? = null
var outputFolder: File = File("./") // current folder by default
val templatesFolders = mutableListOf<File>()
var extensions: List<String>? = null
fun readParameters() {
var i = 0
while (i < args.size) {
val arg = args[i]
when (arg) {
"--env",
"-e" -> {
i++
envFile = File(args[i])
}
"--extensions",
"-ex" -> {
i++
extensions = args[i].split(",")
}
"--outputFolder",
"-o" -> {
i++
outputFolder = File(args[i])
}
"--help",
"-h" -> {
println("""
Generates files and folders as the have been put in the folder. Envs uses common syntax, but
values may contains {{${'$'}sampleVariable}} parts, where {{${'$'}sampleVariable}} will be replaced with variable value.
Example:
.env:
sampleVariable=${'$'}prompt # require request from command line
sampleVariable2=just some value
sampleVariable3=${'$'}{sampleVariable}.${'$'}{sampleVariable2}
Result variables:
sampleVariable=your input in console # lets imagine you typed it
sampleVariable2=just some value
sampleVariable3=your input in console.just some value
To use these variables in template, you will need to write {{${'$'}sampleVariable}}.
You may use it in text of files as well as in files/folders names.
Usage: kotlin generator.kts [args] folders...
Args:
-e, --env: Path to file with args for generation; Use "${'$'}prompt" as values to read variable value from console
-o, --outputFolder: Folder where templates should be used. Folder of calling by default
folders: Folders-templates
""".trimIndent())
Runtime.getRuntime().exit(0)
}
else -> {
val potentialFile = File(arg)
println("Potential file/folder as template: ${potentialFile.absolutePath}")
runCatching {
if (potentialFile.exists()) {
println("Adding file/folder as template: ${potentialFile.absolutePath}")
templatesFolders.add(potentialFile)
}
}.onFailure { e ->
println("Unable to use folder $arg as template folder")
e.printStackTrace()
}
}
}
i++
}
}
readParameters()
val envs: MutableMap<String, String> = envFile ?.let { readEnvs(it.readText(), emptyMap()) } ?.toMutableMap() ?: mutableMapOf()
println(
"""
Result environments:
${envs.toList().joinToString("\n ") { (k, v) -> "$k=$v" }}
Result extensions:
${extensions ?.joinToString()}
Input folders:
${templatesFolders.joinToString("\n ") { it.absolutePath }}
Output folder:
${outputFolder.absolutePath}
""".trimIndent()
)
fun File.handleTemplate(targetFolder: File, envs: Map<String, String>) {
println("Handling $absolutePath")
val localEnvs = File(absolutePath, ".env").takeIf { it.exists() } ?.let {
println("Reading .env in ${absolutePath}")
readEnvs(it.readText(), envs)
} ?: envs
println(
"""
Local environments:
${localEnvs.toList().joinToString("\n ") { (k, v) -> "$k=$v" }}
""".trimIndent()
)
val newName = name.replaceWithVariables(localEnvs)
println("New name $newName")
when {
!exists() -> return
isFile -> {
val content = useLines {
it.map { it.replaceWithVariables(localEnvs) }.toList()
}.joinToString("\n")
val targetFile = File(targetFolder, newName)
targetFile.writeText(content)
println("Target file: ${targetFile.absolutePath}")
}
else -> {
val folder = File(targetFolder, newName)
println("Target folder: ${folder.absolutePath}")
folder.mkdirs()
listFiles() ?.forEach { fileOrFolder ->
fileOrFolder.handleTemplate(folder, localEnvs)
}
}
}
}
templatesFolders.forEach { folderOrFile ->
folderOrFile.handleTemplate(outputFolder, envs)
}

View File

@@ -7,7 +7,7 @@ import dev.inmo.tgbotapi.extensions.behaviour_builder.telegramBotWithBehaviourAn
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onCommand
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onMedia
import dev.inmo.tgbotapi.requests.abstracts.asMultipartFile
import dev.inmo.tgbotapi.types.actions.TypingAction
import dev.inmo.tgbotapi.types.actions.*
import dev.inmo.tgbotapi.types.media.TelegramMediaAudio
import dev.inmo.tgbotapi.types.media.TelegramMediaDocument
import dev.inmo.tgbotapi.types.media.TelegramMediaPhoto
@@ -34,13 +34,27 @@ suspend fun main(args: Array<String>) {
val content = it.content
val pathedFile = bot.getFileAdditionalInfo(content.media)
val outFile = File(directoryOrFile, pathedFile.filePath.filenameFromUrl)
runCatching {
bot.downloadFile(content.media, outFile)
}.onFailure {
it.printStackTrace()
withTypingAction(it.chat.id) {
runCatching {
bot.downloadFile(content.media, outFile)
}.onFailure {
it.printStackTrace()
}.onSuccess { _ ->
reply(it, "Saved to ${outFile.absolutePath}")
}
}.onSuccess { _ ->
reply(it, "Saved to ${outFile.absolutePath}")
withAction(it.chat.id, TypingAction) {
val action = when (content) {
is PhotoContent -> UploadPhotoAction
is AnimationContent,
is VideoContent -> UploadVideoAction
is StickerContent -> ChooseStickerAction
is MediaGroupContent<*> -> UploadPhotoAction
is DocumentContent -> UploadDocumentAction
is VoiceContent,
is AudioContent -> RecordVoiceAction
is VideoNoteContent -> UploadVideoNoteAction
}
withAction(it.chat.id, action) {
when (content) {
is PhotoContent -> replyWithPhoto(
it,

View File

@@ -3,7 +3,10 @@ import dev.inmo.tgbotapi.extensions.api.bot.getMe
import dev.inmo.tgbotapi.extensions.api.chat.get.getChat
import dev.inmo.tgbotapi.extensions.api.send.reply
import dev.inmo.tgbotapi.extensions.behaviour_builder.telegramBotWithBehaviourAndLongPolling
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onContentMessage
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onMentionWithAnyContent
import dev.inmo.tgbotapi.extensions.utils.extensions.raw.sender_chat
import dev.inmo.tgbotapi.extensions.utils.extensions.raw.text
import dev.inmo.tgbotapi.extensions.utils.formatting.linkMarkdownV2
import dev.inmo.tgbotapi.extensions.utils.formatting.textMentionMarkdownV2
import dev.inmo.tgbotapi.extensions.utils.ifFromChannelGroupContentMessage
@@ -23,22 +26,35 @@ suspend fun main(vararg args: String) {
telegramBotWithBehaviourAndLongPolling(botToken, CoroutineScope(Dispatchers.IO)) {
val me = getMe()
onMentionWithAnyContent(me) { message ->
onContentMessage(
initialFilter = initialFilter@{ it.text ?.contains(me.username ?.full ?: return@initialFilter false) == true }
) { message ->
val answerText = when (val chat = message.chat) {
is PreviewChannelChat -> {
val answer = "Hi everybody in this channel \"${chat.title}\""
reply(message, answer, MarkdownV2)
return@onMentionWithAnyContent
val sender = message.sender_chat
val answer = "Hi everybody in this channel \"${chat.title}\"" + if (sender != null) {
" and you, " + when (sender) {
is BusinessChat -> "business chat (wat) ${sender.original}"
is PrivateChat -> "${sender.lastName} ${sender.firstName}"
is GroupChat -> "group ${sender.title}"
is ChannelChat -> "channel ${sender.title}"
is UnknownChatType -> "wat chat (${sender})"
}
} else {
""
}
reply(message, answer.escapeMarkdownV2Common(), MarkdownV2)
return@onContentMessage
}
is PreviewPrivateChat -> {
reply(message, "Hi, " + "${chat.firstName} ${chat.lastName}".textMentionMarkdownV2(chat.id), MarkdownV2)
return@onMentionWithAnyContent
return@onContentMessage
}
is PreviewGroupChat -> {
message.ifFromChannelGroupContentMessage<Unit> {
val answer = "Hi, ${it.senderChat.title}"
reply(message, answer, MarkdownV2)
return@onMentionWithAnyContent
return@onContentMessage
}
"Oh, hi, " + when (chat) {
is SupergroupChat -> (chat.username ?.username ?: getChat(chat).inviteLink) ?.let {
@@ -51,7 +67,7 @@ suspend fun main(vararg args: String) {
}
is PreviewBusinessChat -> {
reply(message, "Hi, " + "${chat.original.firstName} ${chat.original.lastName} (as business chat :) )".textMentionMarkdownV2(chat.original.id), MarkdownV2)
return@onMentionWithAnyContent
return@onContentMessage
}
is UnknownChatType -> "Unknown :(".escapeMarkdownV2Common()
}

View File

@@ -48,6 +48,7 @@ suspend fun main(vararg args: String) {
when (it) {
is Reaction.CustomEmoji -> regular("") + customEmoji(it.customEmojiId) + regular("(customEmojiId: ${it.customEmojiId})")
is Reaction.Emoji -> regular("${it.emoji}")
is Reaction.Paid -> regular("• Some paid reaction")
is Reaction.Unknown -> regular("• Unknown emoji ($it)")
}
regular("\n")

View File

@@ -1,12 +1,12 @@
kotlin.code.style=official
org.gradle.parallel=true
# Due to parallel compilation project require next amount of memory on full build
org.gradle.jvmargs=-Xmx2344m
kotlin.daemon.jvmargs=-Xmx2g -Xms500m
org.gradle.jvmargs=-Xmx3148m
kotlin.daemon.jvmargs=-Xmx3g -Xms500m
kotlin_version=1.9.23
telegram_bot_api_version=15.3.0
micro_utils_version=0.21.2
serialization_version=1.6.3
kotlin_version=2.0.10
telegram_bot_api_version=17.0.0
micro_utils_version=0.22.0
serialization_version=1.7.1
ktor_version=2.3.11

View File

@@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip