big upgrade UwU

This commit is contained in:
2026-07-27 15:16:01 +02:00
parent 9fb2bf0a74
commit 1ff979f1e5
30 changed files with 3304 additions and 183 deletions
+224 -2
View File
@@ -1,5 +1,227 @@
# telegram-sticker-downloader
a python telegram sticker downloader
Download Telegram sticker packs to your disk — one folder per pack, in the file
formats you ask for.
with more info
- Downloads static (`.webp`), animated (`.tgs`), video (`.webm`) stickers and PNG
thumbnails, filtered to whichever types you want.
- Downloads files **in parallel**, with retries and Telegram rate-limit handling.
- **Resumable**: files already on disk are skipped without spending API calls.
- Writes a `pack.json` per pack with each sticker's emoji, size and file names.
- Works as a scriptable CLI *and* as the original interactive prompt.
## Requirements
- Python 3.10 or newer
- A Telegram **bot token** (free, takes a minute — see below)
## Install
```bash
git clone https://git.hiddenden.cafe/Hiddenden/telegram-sticker-downloader
cd telegram-sticker-downloader
python3 -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -e . # installs the `tg-stickers` command
# or, without installing the package:
pip install -r requirements.txt
```
## Get a bot token
1. Open Telegram and message [@BotFather](https://t.me/BotFather).
2. Send `/newbot` and follow the prompts.
3. Copy the token it gives you.
4. Save it next to the project:
```bash
cp example.env .env
# then edit .env:
# TELEGRAM_BOT_TOKEN=123456:ABC-DEF...
```
The token can also come from the `TELEGRAM_BOT_TOKEN` environment variable or
from `--token`. You do not need to add the bot to any chat — reading public
sticker packs is enough.
## Usage
```bash
# One pack
tg-stickers https://t.me/addstickers/SomePack
# Several packs, only the static images and thumbnails
tg-stickers SomePack AnotherPack --types webp,png
# Everything listed in urls.txt, 16 files at a time
tg-stickers --from-file urls.txt --concurrency 16
# From a pipe
printf 'PackOne\nPackTwo\n' | tg-stickers --from-file -
# See what would happen without writing anything
tg-stickers --from-file urls.txt --dry-run
# No arguments: the original interactive prompts
tg-stickers
```
Without installing the package, the same thing works as
`python -m sticker_downloader ...` or `python app.py ...`.
### Pack references
Anything recognisable is accepted, so you can paste straight from Telegram:
```
https://t.me/addstickers/SomePack t.me/addstickers/SomePack
https://telegram.me/addstickers/Pack tg://addstickers?set=SomePack
https://t.me/addemoji/SomePack SomePack
```
In a `--from-file` list, blank lines and `#` comments are ignored, and duplicate
packs are downloaded only once.
### Options
| Option | Description |
| --- | --- |
| `PACK ...` | One or more pack URLs / names |
| `-f, --from-file PATH` | Read references from a file, one per line (`-` for stdin) |
| `-t, --types LIST` | `webp`, `tgs`, `webm`, `png`, comma-separated, or `all` (default: `all`) |
| `-o, --output DIR` | Where packs are written (default: `downloads`) |
| `-c, --concurrency N` | Files downloaded in parallel per pack (default: `8`) |
| `--retries N` | Attempts per network call (default: `3`) |
| `--overwrite` | Re-download files that already exist |
| `--emoji-names` | Put each sticker's emoji in its file name |
| `--no-metadata` | Skip writing `pack.json` |
| `--no-pack-thumbnail` | Skip the pack's own cover image |
| `--dry-run` | Report what would be downloaded, write nothing |
| `--token TOKEN` | Bot token (overrides the environment) |
| `--env-file PATH` | dotenv file to read the token from (default: `.env`) |
| `-v, --verbose` | Log every file individually |
| `-q, --quiet` | Only report fatal errors |
| `--version` | Print the version |
### File types
| Type | What it is | Notes |
| --- | --- | --- |
| `webp` | Static stickers | Regular image, opens anywhere |
| `tgs` | Animated stickers | Gzipped Lottie JSON, not a video file |
| `webm` | Video stickers | VP9 with alpha |
| `png` | Thumbnails | Small preview Telegram generates per sticker |
A sticker has exactly one primary type — `--types tgs` on a pack of static
stickers downloads nothing but the thumbnails you asked for.
## Output
```
downloads/
└── SomePack/
├── 001.webp
├── 001_thumb.png
├── 002.webp
├── 002_thumb.png
├── _pack_thumbnail.webp
└── pack.json
```
Files are numbered in pack order. With `--emoji-names` they become
`001_🦊.webp`. `pack.json` records what was downloaded:
```json
{
"pack": {
"reference": "https://t.me/addstickers/SomePack",
"name": "SomePack",
"title": "Some Pack",
"sticker_type": "regular"
},
"generated_at": "2026-07-27T12:00:00+00:00",
"downloader_version": "1.0.0",
"requested_file_types": ["webp", "png"],
"sticker_count": 2,
"stickers": [
{
"index": 1,
"emoji": "🦊",
"file_unique_id": "AgADBAADwqbcCw",
"type": "regular",
"width": 512,
"height": 512,
"is_animated": false,
"is_video": false,
"files": ["001.webp", "001_thumb.png"]
}
]
}
```
## How it works
Packs are processed one at a time so progress stays readable; the files inside a
pack download concurrently, bounded by `--concurrency`.
- **Resume.** Existing files are detected *before* any API call, so re-running a
large batch costs almost nothing. Use `--overwrite` to force a refresh.
- **Atomic writes.** Files land via a temporary `.part` file, so an interrupted
run never leaves a half-written sticker that a later run would skip.
- **Retries.** Timeouts, connection errors and HTTP 429/5xx are retried with
exponential backoff; Telegram's own `retry_after` hint is respected. Genuine
errors (unknown pack, bad token) fail immediately instead of being retried.
- **Partial failure is not fatal.** A file that cannot be downloaded is reported
and the rest of the pack continues; the run's exit code reflects it.
### Exit codes
| Code | Meaning |
| --- | --- |
| `0` | Everything downloaded |
| `1` | One or more packs or files failed |
| `2` | Bad arguments, missing/rejected token, or aborted |
## Development
```bash
pip install -r requirements-dev.txt
pytest # test suite
ruff check . # lint
ruff format . # format
```
The tests use fakes for the Telegram bot, plus a real local HTTP server for the
download layer, so the whole suite runs offline in well under a second.
`.gitea/workflows/ci.yml` runs lint and tests on Python 3.10–3.13. It needs
Gitea Actions enabled on the repository and a registered `act_runner`; without a
runner the file is simply ignored.
Layout:
| Module | Responsibility |
| --- | --- |
| `sticker_downloader/cli.py` | Argument parsing, interactive prompts, wiring |
| `sticker_downloader/downloader.py` | Planning and downloading a pack |
| `sticker_downloader/urls.py` | Pack-reference parsing |
| `sticker_downloader/config.py` | Settings and file-type handling |
| `sticker_downloader/fetcher.py` | HTTP layer behind a small protocol |
| `sticker_downloader/retry.py` | Retry policy and backoff |
| `sticker_downloader/progress.py` | Console reporting |
| `sticker_downloader/results.py` | Result and totals objects |
## Limitations
- The Bot API only serves files up to 20 MB. Stickers are far smaller, so this
is not normally a concern.
- `.tgs` and `.webm` are downloaded as-is; no conversion to GIF/APNG is done.
- Private or deleted packs cannot be read, and are reported as
`sticker pack not found`.
## License
MIT — see [LICENSE](LICENSE).