mirror of
https://github.com/krau/SaveAny-Bot.git
synced 2026-07-17 18:51:26 +08:00
feat(docs): add CLI subcommands documentation and file naming strategies
- Introduced new documentation for CLI subcommands: `upload` and `watch`, detailing their usage, flags, and examples. - Added a section on file naming and conflict strategies, explaining how users can customize file names and handle duplicates via `/config` and `/fnametmpl` commands. - Translated the new documentation into Chinese for broader accessibility.
This commit is contained in:
@@ -113,6 +113,51 @@ secret = "your-rpc-secret"
|
||||
remove_after_transfer = true
|
||||
```
|
||||
|
||||
### yt-dlp Configuration
|
||||
|
||||
Configures the behavior of the `/ytdlp` command and the `ytdlp` HTTP-API task type when no custom flags are passed.
|
||||
|
||||
- `max_height`: Default maximum video resolution by height in pixels (e.g. `1080`, `720`). `0` means no limit (best available). Ignored when `format` is set.
|
||||
- `format`: A raw yt-dlp format selector (`-f`). When set, it takes precedence over `max_height` and gives you full control, e.g. `bv*[height<=720]+ba/b`.
|
||||
- `recode`: The target video container yt-dlp recodes into after download (e.g. `mp4`). Leave empty to disable recoding.
|
||||
|
||||
{{< hint info >}}
|
||||
These defaults only apply when using the `/ytdlp` command without passing any custom flags. Passing custom flags on the command (or `flags` in the API) overrides them.
|
||||
{{< /hint >}}
|
||||
|
||||
```toml
|
||||
[ytdlp]
|
||||
max_height = 1080
|
||||
format = "" # e.g. "bv*[height<=720]+ba/b"
|
||||
recode = "mp4" # empty disables recoding
|
||||
```
|
||||
|
||||
### HTTP API Configuration
|
||||
|
||||
When enabled, SaveAny-Bot exposes an HTTP API for creating/querying/canceling tasks programmatically. See [HTTP API](../../usage/api) for the full endpoint reference.
|
||||
|
||||
- `enable`: Whether to enable the HTTP API server, default is `false`.
|
||||
- `host`: Bind address, default `0.0.0.0`.
|
||||
- `port`: Listen port, default `8080`.
|
||||
- `token`: Authentication token. **Strongly recommended** — if empty, the API is exposed without any authentication.
|
||||
|
||||
```toml
|
||||
[api]
|
||||
enable = false
|
||||
host = "0.0.0.0"
|
||||
port = 8080
|
||||
token = "your-token"
|
||||
```
|
||||
|
||||
### Log Configuration
|
||||
|
||||
- `level`: Log level. One of `debug`, `info`, `warn`, `error`, `fatal`. Default is `info`.
|
||||
|
||||
```toml
|
||||
[log]
|
||||
level = "info"
|
||||
```
|
||||
|
||||
### Storage Endpoints List
|
||||
|
||||
The storage endpoints list is used to define the storage locations supported by the Bot. Each storage endpoint needs to specify a name, type, and related configuration, using the double bracket syntax `[[storages]]`.
|
||||
|
||||
90
docs/content/en/usage/cli.md
Normal file
90
docs/content/en/usage/cli.md
Normal file
@@ -0,0 +1,90 @@
|
||||
---
|
||||
title: "CLI Subcommands"
|
||||
weight: 21
|
||||
---
|
||||
|
||||
# CLI Subcommands
|
||||
|
||||
Besides running the Telegram bot with `./saveany-bot` (no subcommand), the binary exposes two helper subcommands for moving local files into a storage backend: `upload` (one-shot) and `watch` (continuous).
|
||||
|
||||
These subcommands load the same `config.toml` as the bot, initialize the database and caches, then perform their task. They do **not** start the Telegram bot itself, although storages of type `telegram` will spin up the bot client just for the upload.
|
||||
|
||||
## `upload` — Upload a Single File
|
||||
|
||||
```
|
||||
saveany-bot upload -f <file> -s <storage> [-d <dir>] [--no-progress]
|
||||
```
|
||||
|
||||
Flags:
|
||||
|
||||
| Flag | Required | Description |
|
||||
|---|---|---|
|
||||
| `-f, --file` | Yes | Path to the local file to upload |
|
||||
| `-s, --storage` | Yes | Target storage name (must exist in `config.toml`) |
|
||||
| `-d, --dir` | No | Destination directory within the storage. Defaults to the storage's `base_path` |
|
||||
| `--no-progress` | No | Disable the terminal progress bar |
|
||||
|
||||
Examples:
|
||||
|
||||
```bash
|
||||
# Upload a file to the default dir of storage "MyAlist"
|
||||
./saveany-bot upload -f ./movie.mp4 -s MyAlist
|
||||
|
||||
# Upload into a specific subdirectory
|
||||
./saveany-bot upload -f ./movie.mp4 -s MyAlist -d movies/2026
|
||||
|
||||
# Upload via Telegram storage without a progress bar
|
||||
./saveany-bot upload -f ./photo.jpg -s MyChannel --no-progress
|
||||
```
|
||||
|
||||
## `watch` — Watch a Directory and Auto-Upload
|
||||
|
||||
The `watch` subcommand continuously monitors a local directory and uploads created or modified files to a storage backend, preserving the relative directory structure from the watch root.
|
||||
|
||||
```
|
||||
saveany-bot watch -p <path> -s <storage> [-d <dir>] [options]
|
||||
```
|
||||
|
||||
Flags:
|
||||
|
||||
| Flag | Default | Description |
|
||||
|---|---|---|
|
||||
| `-p, --path` | *(required)* | Local directory to watch |
|
||||
| `-s, --storage` | *(required)* | Target storage name |
|
||||
| `-d, --dir` | storage's `base_path` | Destination directory within the storage |
|
||||
| `-r, --recursive` | `false` | Watch subdirectories recursively |
|
||||
| `--overwrite` | `false` | Overwrite existing files on the storage instead of skipping them |
|
||||
| `--initial-scan` | `false` | Upload files already present in the directory on startup |
|
||||
| `--debounce` | `2s` | How long to wait after the last write before uploading a file |
|
||||
| `--upload-workers` | `config.workers` | Number of concurrent uploads |
|
||||
| `--retry-delay` | `3s` | Delay between upload retries |
|
||||
|
||||
{{< hint info >}}
|
||||
Write-completion detection: the watcher debounces per file and only uploads once the file size stays unchanged across the debounce window, so partial/write-in-progress files are not uploaded.
|
||||
<br />
|
||||
If a file changes while being uploaded, it is re-uploaded once after the current upload finishes (instead of being queued multiple times).
|
||||
{{< /hint >}}
|
||||
|
||||
Examples:
|
||||
|
||||
```bash
|
||||
# Watch ./inbox and upload new files to "MyAlist" recursively
|
||||
./saveany-bot watch -p ./inbox -s MyAlist -r
|
||||
|
||||
# Watch with a custom destination dir and overwrite
|
||||
./saveany-bot watch -p ./inbox -s MyAlist -d backup --overwrite
|
||||
|
||||
# On startup, also upload everything already in ./inbox
|
||||
./saveany-bot watch -p ./inbox -s MyAlist --initial-scan
|
||||
```
|
||||
|
||||
### Behavior notes
|
||||
|
||||
- Relative directory structure is preserved under the destination directory. A file written to `./inbox/sub/file.txt` with `--path ./inbox` is uploaded to `<dest_dir>/sub/file.txt`.
|
||||
- `watch` runs until interrupted (e.g. `Ctrl-C` / `SIGINT`); in-flight uploads are drained before exit.
|
||||
- Retries follow the global `retry` value from `config.toml`, with `--retry-delay` between attempts.
|
||||
- Telegram-type storages will start the bot client automatically to perform uploads.
|
||||
|
||||
{{< hint warning >}}
|
||||
`watch` is unrelated to the in-bot `/watch` command (which watches Telegram chats). This subcommand watches a **local filesystem directory** and uploads to a storage backend, independent of Telegram.
|
||||
{{< /hint >}}
|
||||
75
docs/content/en/usage/config.md
Normal file
75
docs/content/en/usage/config.md
Normal file
@@ -0,0 +1,75 @@
|
||||
---
|
||||
title: "File Naming & Conflict Strategies"
|
||||
weight: 11
|
||||
---
|
||||
|
||||
# File Naming & Conflict Strategies
|
||||
|
||||
SaveAny-Bot lets you customize how saved files are named and how collisions with existing files are resolved, directly in Telegram via the `/config` and `/fnametmpl` commands.
|
||||
|
||||
## `/config` — User Configuration
|
||||
|
||||
The `/config` command opens an inline menu where you can change two per-user settings:
|
||||
|
||||
- **Filename strategy** — how the saved file is named
|
||||
- **Duplicate file strategy** — what happens when a file with the same name already exists in the target storage
|
||||
|
||||
Settings are stored per user and apply to all of that user's subsequent save/transfer tasks.
|
||||
|
||||
### Filename strategy
|
||||
|
||||
| Option | Behavior |
|
||||
|---|---|
|
||||
| `Default` | Use the original media filename, or a generated name when no original filename is available |
|
||||
| `Gen From Msg First` | Generate the filename from the message content (e.g. caption, text) and prefer that over the original filename |
|
||||
| `Template` | Render the filename from a custom template you define with `/fnametmpl` |
|
||||
|
||||
### Duplicate file strategy
|
||||
|
||||
| Option | Behavior |
|
||||
|---|---|
|
||||
| `Always rename` (default) | Keep the existing file and save the new one with an alternate name |
|
||||
| `Ask every time` | Prompt you with inline buttons each time a collision occurs |
|
||||
| `Always overwrite` | Replace the existing file with the new one |
|
||||
| `Always skip` | Do nothing for conflicting files |
|
||||
|
||||
{{< hint info >}}
|
||||
The conflict strategy only kicks in for storage backends that can detect the existence of a file. Backends that do not support existence checks will fall back to overwriting.
|
||||
{{< /hint >}}
|
||||
|
||||
## `/fnametmpl` — Custom Filename Template
|
||||
|
||||
When the filename strategy is set to `Template`, SaveAny-Bot renders each saved file's name using the template configured via `/fnametmpl`.
|
||||
|
||||
```
|
||||
/fnametmpl [template]
|
||||
```
|
||||
|
||||
- Running `/fnametmpl` without arguments shows your current template and the help text.
|
||||
- Running it with a template string sets that template as your filename template.
|
||||
|
||||
The template uses Go [`text/template`](https://pkg.go.dev/text/template) syntax. The available variables are:
|
||||
|
||||
| Variable | Description |
|
||||
|---|---|
|
||||
| `{{.msgid}}` | Telegram message ID |
|
||||
| `{{.msgtags}}` | Hashtags found in the message, joined with `_` |
|
||||
| `{{.msggen}}` | Filename generated from the message |
|
||||
| `{{.msgdate}}` | Message date, formatted `YYYY-MM-DD_HH-MM-SS` |
|
||||
| `{{.msgraw}}` | Raw, unprocessed message text |
|
||||
| `{{.origname}}` | The media's original filename (if any) |
|
||||
| `{{.chatid}}` | Chat ID of the message |
|
||||
|
||||
Examples:
|
||||
|
||||
```
|
||||
# Fixed prefix + message id + date
|
||||
/fnametmpl Image_{{.msgid}}_{{.msgdate}}.jpg
|
||||
|
||||
# Use original name if available, otherwise a generated name
|
||||
/fnametmpl {{.origname}}
|
||||
```
|
||||
|
||||
{{< hint warning >}}
|
||||
The template only takes effect when the filename strategy is set to `Template`. If template parsing fails, SaveAny-Bot falls back to the default filename naming logic.
|
||||
{{< /hint >}}
|
||||
@@ -27,6 +27,45 @@ Pay attention to spaces; the bot can only parse correctly formatted syntax. Belo
|
||||
|
||||
In addition, if `CHOSEN` is used as the storage name in the rule, it means files will be stored under the path of the storage you selected by clicking the inline button.
|
||||
|
||||
You can also toggle whether rules are applied with `/rule switch`. When rule mode is off, all files go to the default storage.
|
||||
|
||||
## Preset Rules
|
||||
|
||||
Manually writing regex rules for common file types is tedious, so the bot ships a built-in set of preset categories (video, image, audio, document, archive) that you can import in one command:
|
||||
|
||||
```
|
||||
/rule preset <storage> [base_path]
|
||||
```
|
||||
|
||||
Parameters:
|
||||
|
||||
- `storage`: Target storage name (must exist and be accessible to you)
|
||||
- `base_path`: Optional. Each preset category's subdirectory is created under this path. If omitted, the default category directory names are used directly.
|
||||
|
||||
Examples:
|
||||
|
||||
```
|
||||
# Import preset rules into "MyAlist" with the default directory layout
|
||||
/rule preset MyAlist
|
||||
|
||||
# Import preset rules with a custom base path "downloads/sorted"
|
||||
/rule preset MyAlist downloads/sorted
|
||||
```
|
||||
|
||||
This will create `FILENAME-REGEX` rules for each category, routing matched files to the corresponding subdirectory under `base_path`:
|
||||
|
||||
| Category | Matched extensions | Default directory |
|
||||
|---|---|---|
|
||||
| video | mp4, mkv, ts, avi, flv, mov, webm, wmv, rmvb, m2ts | `视频` |
|
||||
| image | jpg, jpeg, png, gif, webp, bmp | `图片` |
|
||||
| audio | mp3, flac, wav, aac, m4a, ogg | `音频` |
|
||||
| document | pdf, doc, docx, xls, xlsx, ppt, pptx, txt, md, csv, epub, mobi, azw3, chm | `文档` |
|
||||
| archive | zip, rar, 7z, tar, gz, bz2, xz, ... | `压缩包` |
|
||||
|
||||
{{< hint info >}}
|
||||
Preset rules are regular `FILENAME-REGEX` rules once imported. You can view, edit, or delete them individually with `/rule` and `/rule del <id>` like any other rule.
|
||||
{{< /hint >}}
|
||||
|
||||
Rule types:
|
||||
|
||||
## FILENAME-REGEX
|
||||
|
||||
Reference in New Issue
Block a user