big upgrade UwU
This commit is contained in:
@@ -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).
|
||||
|
||||
Reference in New Issue
Block a user