diff --git a/NativeRandomFileSenderBot/README.md b/NativeRandomFileSenderBot/README.md new file mode 100644 index 0000000..4765c04 --- /dev/null +++ b/NativeRandomFileSenderBot/README.md @@ -0,0 +1,9 @@ +# RandomFileSenderBot + +This bot will send random file from input folder OR from bot working folder + +## Launch + +```bash +../gradlew run --args="BOT_TOKEN[ optional/folder/path]" +``` diff --git a/NativeRandomFileSenderBot/build.gradle b/NativeRandomFileSenderBot/build.gradle new file mode 100644 index 0000000..93a2e0b --- /dev/null +++ b/NativeRandomFileSenderBot/build.gradle @@ -0,0 +1,45 @@ +buildscript { + repositories { + mavenCentral() + } + + dependencies { + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +plugins { + id "org.jetbrains.kotlin.multiplatform" +} + + +kotlin { + def hostOs = System.getProperty("os.name") + def isMingwX64 = hostOs.startsWith("Windows") + def nativeTarget + if (hostOs == "Linux") nativeTarget = linuxX64("native") { binaries { executable() } } + else if (isMingwX64) nativeTarget = mingwX64("native") { binaries { executable() } } + else throw new GradleException("Host OS is not supported in Kotlin/Native.") + + sourceSets { + commonMain { + dependencies { + implementation kotlin('stdlib') + + api "dev.inmo:tgbotapi:$telegram_bot_api_version" + } + } + + nativeMain { + dependencies { + def engine + + if (hostOs == "Linux") engine = "curl" + else if (isMingwX64) engine = "winhttp" + else throw new GradleException("Host OS is not supported in Kotlin/Native.") + + api "io.ktor:ktor-client-$engine:$ktor_version" + } + } + } +} diff --git a/NativeRandomFileSenderBot/src/nativeMain/kotlin/RandomFileSenderBot.kt b/NativeRandomFileSenderBot/src/nativeMain/kotlin/RandomFileSenderBot.kt new file mode 100644 index 0000000..29bf284 --- /dev/null +++ b/NativeRandomFileSenderBot/src/nativeMain/kotlin/RandomFileSenderBot.kt @@ -0,0 +1,109 @@ +import dev.inmo.micro_utils.common.MPPFile +import dev.inmo.micro_utils.common.filesize +import dev.inmo.micro_utils.coroutines.runCatchingSafely +import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions +import dev.inmo.tgbotapi.bot.ktor.telegramBot +import dev.inmo.tgbotapi.bot.TelegramBot +import dev.inmo.tgbotapi.extensions.api.bot.getMe +import dev.inmo.tgbotapi.extensions.api.bot.setMyCommands +import dev.inmo.tgbotapi.extensions.api.send.* +import dev.inmo.tgbotapi.extensions.api.send.media.sendDocument +import dev.inmo.tgbotapi.extensions.api.send.media.sendDocumentsGroup +import dev.inmo.tgbotapi.extensions.behaviour_builder.buildBehaviourWithLongPolling +import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onCommandWithArgs +import dev.inmo.tgbotapi.requests.abstracts.asMultipartFile +import dev.inmo.tgbotapi.types.BotCommand +import dev.inmo.tgbotapi.types.chat.Chat +import dev.inmo.tgbotapi.types.files.DocumentFile +import dev.inmo.tgbotapi.types.media.TelegramMediaDocument +import dev.inmo.tgbotapi.types.mediaCountInMediaGroup +import kotlinx.coroutines.runBlocking +import okio.FileSystem +import okio.Path.Companion.toPath + +private const val command = "send_file" + +/** + * This bot will send files inside of working directory OR from directory in the second argument. + * You may send /send_file command to this bot to get random file from the directory OR + * `/send_file $number` when you want to receive required number of files. For example, + * /send_file and `/send_file 1` will have the same effect - bot will send one random file. + * But if you will send `/send_file 5` it will choose 5 random files and send them as group + */ +fun main(args: Array) = runBlocking { + val botToken = args.first() + val directoryOrFile = args.getOrNull(1) ?.toPath() ?: "".toPath() + + fun pickFile(currentRoot: MPPFile = directoryOrFile): MPPFile? { + if (FileSystem.SYSTEM.exists(currentRoot) && FileSystem.SYSTEM.listOrNull(currentRoot) == null) { + return currentRoot + } else { + return pickFile(FileSystem.SYSTEM.list(currentRoot).takeIf { it.isNotEmpty() } ?.random() ?: return null) + } + } + + suspend fun TelegramBot.sendFiles(chat: Chat, files: List) { + when (files.size) { + 1 -> { + sendDocument( + chat.id, + files.first().asMultipartFile(), + protectContent = true + ) + } + else -> sendDocumentsGroup( + chat, + files.map { TelegramMediaDocument(it.asMultipartFile()) }, + protectContent = true + ) + } + } + + val bot = telegramBot(botToken) + + bot.buildBehaviourWithLongPolling (defaultExceptionsHandler = { it.printStackTrace() }) { + onCommandWithArgs(command) { message, args -> + withUploadDocumentAction(message.chat) { + val count = args.firstOrNull() ?.toIntOrNull() ?: 1 + var sent = false + + var left = count + val chosen = mutableListOf() + + while (left > 0) { + val picked = pickFile() ?.takeIf { it.filesize > 0 } ?: continue + chosen.add(picked) + left-- + if (chosen.size >= mediaCountInMediaGroup.last) { + runCatchingSafely { + sendFiles(message.chat, chosen) + }.onFailure { + it.printStackTrace() + } + chosen.clear() + sent = true + } + } + + if (chosen.isNotEmpty()) { + sendFiles(message.chat, chosen) + sent = true + } + + if (!sent) { + reply(message, "Nothing selected :(") + } + } + } + + setMyCommands( + BotCommand(command, "Send some random file in picker directory") + ) + + allUpdatesFlow.subscribeSafelyWithoutExceptions(this) { + println(it) + } + + println(getMe()) + }.join() +}