update readmes

This commit is contained in:
2026-08-21 15:51:06 +06:00
parent 016400a821
commit ce48393895
104 changed files with 2615 additions and 333 deletions

View File

@@ -1,9 +1,76 @@
# RandomFileSenderBot
This bot will send random file from input folder OR from bot working folder
This Kotlin Multiplatform example sends randomly selected local files in response to a Telegram command. It uses long
polling and can run on the JVM or as a Kotlin/Native executable.
## Launch
## Behavior
The bot registers one command:
- `/send_file` requests one file;
- `/send_file N` requests `N` files when `N` is a positive integer; and
- a missing or non-numeric count defaults to one. Zero and negative counts select nothing and receive
`Nothing selected :(`.
For each requested file, the picker starts at the configured root. A file root is selected directly; a directory root
is searched by choosing one random child at each level until a file is reached. This is not a uniform choice among all
files in an uneven directory tree, and the same file may be selected more than once. Zero-byte files and unsuccessful
selections are retried. Consequently, a positive request can keep retrying indefinitely when no non-empty file is
reachable.
One file is sent as a document. Multiple files are sent as document media groups, split at Telegram's maximum media
group size. All sends enable Telegram's protected-content flag. The bot also prints its own account information at
startup and prints polling exceptions.
## Setup and security
Create a bot with BotFather and obtain its token. Give the process read access to a dedicated directory containing only
files that every bot user may receive, and pass that directory explicitly. The bot has no user or chat allowlist and no
file-name or file-type filter; anyone able to send it the command can request files reachable through the configured
tree. Protected content is not an access-control mechanism.
Keep the token private. These launchers accept it on the command line, where it may be retained in shell history or be
visible to other local processes. Also avoid roots containing secrets or links to locations outside the intended tree.
## Arguments
Both launchers interpret arguments in the same order:
1. `BOT_TOKEN` (required). Omitting it fails immediately.
2. `ROOT_PATH` (optional in code), either a file or directory. Relative paths are resolved from the process working
directory; use an explicit absolute path for predictable behavior. The launchers pass an empty path when this
argument is omitted, whose filesystem behavior differs by platform and is not a reliable working-directory default.
Additional arguments are ignored.
## Launch from the repository root
### JVM
```bash
../gradlew run --args="BOT_TOKEN[ optional/folder/path]"
./gradlew :RandomFileSenderBot:runJvm --args="<BOT_TOKEN> /absolute/path/to/files"
```
The JVM picker uses `java.io.File`. A missing, empty, or unreadable directory produces no selection and therefore causes
a positive request to keep retrying.
### Kotlin/Native
The shared native configuration selects Linux x64, Linux Arm64, or Windows x64 for the current host. macOS is not
configured. Link the debug executable with Gradle, then pass the arguments directly to the generated program:
```bash
./gradlew :RandomFileSenderBot:linkDebugExecutableNative
./RandomFileSenderBot/build/bin/native/debugExecutable/RandomFileSenderBot.kexe "<BOT_TOKEN>" "/absolute/path/to/files"
```
On Windows, run
`RandomFileSenderBot\build\bin\native\debugExecutable\RandomFileSenderBot.exe "<BOT_TOKEN>" "C:\path\to\files"`
after the same Gradle link task. The native picker uses Okio; unlike the JVM picker, inaccessible or invalid paths may
raise a filesystem exception that is printed by the polling exception handler.
## Source sets
- `commonMain` contains the picker contract and the long-polling bot behavior.
- `jvmMain` implements recursive selection with `java.io.File` and provides the suspending JVM entry point.
- `nativeMain` implements recursive selection with Okio and provides a `runBlocking` native entry point.

View File

@@ -18,14 +18,18 @@ import dev.inmo.tgbotapi.types.mediaCountInMediaGroup
private const val command = "send_file"
/**
* Selects a file by recursively choosing random children below [currentRoot].
*
* @return the selected file, or `null` when the picker cannot continue from the current root
*/
expect fun pickFile(currentRoot: MPPFile): MPPFile?
/**
* 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
* Runs the long-polling random-file bot using [token] and serving selections rooted at [folder].
*
* `/send_file` selects one non-empty file, while `/send_file N` selects `N` files and splits them into valid Telegram
* media-group sizes.
*/
suspend fun doRandomFileSenderBot(token: String, folder: MPPFile) {
val bot = telegramBot(token)

View File

@@ -1,6 +1,7 @@
import dev.inmo.micro_utils.common.MPPFile
import java.io.File
/** JVM picker backed by [File], returning a file root directly or descending through random directory children. */
actual fun pickFile(currentRoot: MPPFile): File? {
if (currentRoot.isFile) {
return currentRoot

View File

@@ -1,5 +1,6 @@
import dev.inmo.micro_utils.common.MPPFile
/** JVM entry point; [args] contains the bot token followed by an optional picker root. */
suspend fun main(args: Array<String>) {
doRandomFileSenderBot(args.first(), MPPFile(args.getOrNull(1) ?: ""))
}

View File

@@ -1,6 +1,7 @@
import dev.inmo.micro_utils.common.MPPFile
import okio.FileSystem
/** Native picker backed by Okio, returning a file root directly or descending through random directory children. */
actual fun pickFile(currentRoot: MPPFile): MPPFile? {
if (FileSystem.SYSTEM.exists(currentRoot) && FileSystem.SYSTEM.listOrNull(currentRoot) == null) {
return currentRoot

View File

@@ -1,6 +1,7 @@
import kotlinx.coroutines.runBlocking
import okio.Path.Companion.toPath
/** Kotlin/Native entry point; [args] contains the bot token followed by an optional picker root. */
fun main(args: Array<String>) {
runBlocking {
doRandomFileSenderBot(args.first(), args.getOrNull(1) ?.toPath() ?: "".toPath())