Files
signal-bot/README.md
James Price d16c025753 Fix YouTube downloads: bump yt-dlp, require Node 22, drop YT cookies
Two YouTube regressions stacked up:

- yt-dlp 2026.3.17 hit "HTTP Error 403: Forbidden" on the actual media
  download. Bumping to 2026.6.9 fixes the data-download 403, but its EJS
  n-sig challenge solver now requires Node >= 22, and Debian 13 only ships
  Node 20 ("node-20.x (unsupported)" -> only image formats resolve). bot.py
  now points --js-runtimes at a standalone /opt/node22 via the new
  JS_RUNTIME constant.

- With a cookies.txt present, yt-dlp skips the cookieless android_vr/android
  clients (whose URLs work) and falls back to the `tv` client, whose media
  URLs 403. New _cookie_args(url) withholds cookies for YouTube hosts only,
  while still sending them to Instagram/TikTok/X.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-16 16:12:17 -04:00

75 lines
3.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# signal-bot
A Signal group-chat bot that grabs videos from links people post (X/Twitter,
Instagram, YouTube, TikTok) and posts them back into the chat, plus a couple of
toys for messing with the last video.
## What it does
- **Auto-download** — watches every group message for a supported link and
replies with the video. Powered by [yt-dlp](https://github.com/yt-dlp/yt-dlp).
Videos over 100 MB are auto re-encoded with ffmpeg to fit.
- **`/speed [n]`** — re-posts the last video sped up `n`× (default 2×), pitch-shifted
like tape. e.g. `/speed 4`, `/speed 0.5`.
- **`/rev`** — re-posts the last video reversed (audio too).
- **`/cookies`** (DM, admins only) — paste exported `.instagram.com` cookie lines
to refresh Instagram auth without touching the server.
Supported links: `x.com` / `twitter.com` (and `fxtwitter`/`vxtwitter`/`fixupx`
wrappers), `instagram.com/reel|p`, `youtube.com` / `youtu.be` / Shorts, and TikTok.
## How it's wired
```
Signal ──► signal-cli-rest-api (json-rpc, :8080) ──► bot.py (signalbot lib)
[docker-compose.yml] [systemd service]
yt-dlp + ffmpeg + cookies.txt
```
- `bot.py` connects to a [signal-cli-rest-api](https://github.com/bbernhard/signal-cli-rest-api)
daemon over a websocket in `json-rpc` mode.
- `docker-compose.yml` runs that daemon; the linked-account data lives in a
`./signal-cli-data` volume (gitignored — it holds private keys).
- `signal-bot.service.example` is the systemd unit that runs `bot.py`.
## Setup
1. **Run signal-cli-rest-api and link it as a device** to your Signal account:
```
docker compose up -d
```
Then link via the QR at `http://127.0.0.1:8080/v1/qrcodelink?device_name=bot`
(scan from Signal → Settings → Linked devices). Keep signal-cli up to date —
an out-of-date signal-cli silently stops receiving messages when Signal
changes its server protocol (`getServerGuid must not be null` in the logs);
`docker compose pull && docker compose up -d` fixes it.
2. **Python env:**
```
python3 -m venv venv
venv/bin/pip install -r requirements.txt
```
YouTube also needs **Node >= 22** on PATH (for `yt-dlp-ejs`'s challenge
solver). If your distro only ships an older Node, install a standalone Node 22+
and point `bot.py`'s `_NODE22` at it. Note: YouTube cookies are deliberately
withheld (`_cookie_args`) — sending account cookies forces yt-dlp onto a player
client whose media URLs 403; cookieless YouTube requests work.
3. **Cookies:** copy `cookies.txt.example` to `cookies.txt` and fill in real
exported cookies for the sites you want auth'd. (gitignored)
4. **Service:** copy `signal-bot.service.example` to `signal-bot.service`, set
your user / phone number / paths, install it:
```
sudo cp signal-bot.service /etc/systemd/system/
sudo systemctl enable --now signal-bot
```
## Notes
- The bot only acts in **group** chats (except `/cookies`, which is DM-only).
- Reply-targeting (e.g. "speed up *this* video") was intentionally dropped:
Signal Desktop strips quote metadata from synced transcripts, so `/speed` and
`/rev` always act on the last video seen in the group.