# tgstat-puller

Тянет посты со статистикой из 3 каналов в SQLite + JSON/MD-файлы в волт. Запускается автоматически через Mac launchd три раза в неделю.

## Что собирает

- `@natashhhh` (личный) → `projects/channel/{channel} {source} TGStat архив постов канала.json` + `.md`
- `@marsingru` (Mars) → `projects/mars/tgstat-snapshots/{mars} {source} посты канала marsingru – YYYY-MM-DD.json`
- `@choooooooir` (Хор) → то же, `– choooooooir`

По каждому посту: текст, дата (ISO-8601 UTC), просмотры, реакции (счётчик), комменты (счётчик), репосты, ER/ERR от TGStat, динамика просмотров по дням.

Не собирает: тексты комментов, разбивку реакций по эмодзи (TGStat не отдаёт).

## Архитектура

- **Источник правды:** `data/channels.db` (SQLite). Все JSON/MD-выходы перегенерируются из БД.
- **Окно обновления:** свежие посты (≤14 дней) переобновляются каждый запуск.
- **Расписание:** Mac launchd, пн/чт/вс в 16:00 локального времени.
- **Защита:** flock от двойного запуска, бэкап БД перед каждым прогоном, ретраи на сетевые ошибки, классификация ошибок TGStat (limit/rate/not_found).
- **Алерт:** если 3 запуска подряд `failed` — `alert_check.py` шлёт сообщение через Telegram Bot API.

Полный дизайн: `docs/specs/2026-06-13-channels-expansion-design.md`.

## Установка с нуля

1. Положить токен в `.env`:
   ```
   TGSTAT_TOKEN=...
   TELEGRAM_BOT_TOKEN=...       # опционально, для алертов
   TELEGRAM_OWNER_USER_ID=...   # опционально, куда слать алерт
   ```

2. Поставить зависимости:
   ```
   /opt/homebrew/bin/python3.11 -m venv venv
   ./venv/bin/pip install -r requirements.txt
   ```

3. Прогнать миграцию старых данных (разово):
   ```
   ./venv/bin/python migrate.py
   ```

4. Проверить dry-run:
   ```
   ./venv/bin/python pull.py --dry-run
   ```

5. Прогнать боевой запуск:
   ```
   ./venv/bin/python pull.py
   ```

6. Подставить путь к проекту в launchd-плисте:
   ```
   PROJECT_DIR=$(pwd)
   sed "s|PROJECT_DIR_PLACEHOLDER|$PROJECT_DIR|g; s|HOME_DIR_PLACEHOLDER|$HOME|g" launchd/com.natasha.tgstat-puller.plist > ~/Library/LaunchAgents/com.natasha.tgstat-puller.plist
   launchctl load ~/Library/LaunchAgents/com.natasha.tgstat-puller.plist
   ```

7. Проверить, что агент видится в списке:
   ```
   launchctl list | grep tgstat
   ```

## CLI-флаги

- `--dry-run` — ходит в API, в БД не пишет, файлы не рендерит
- `--channel <username>` — обработать только один канал
- `--no-refresh` — пропустить обновление статистики свежих (только новые посты). **Это основной потребитель квоты API**: refresh дёргает `posts/stat` по одному запросу на каждый пост за последние 14 дней (`REFRESH_WINDOW_DAYS`), а не один запрос на канал — с `--no-refresh` расход падает до одного `channels/posts` на канал

## Ручной запуск с остановленным агентом

```
launchctl unload ~/Library/LaunchAgents/com.natasha.tgstat-puller.plist
./venv/bin/python pull.py
launchctl load ~/Library/LaunchAgents/com.natasha.tgstat-puller.plist
```

## Логи

- `~/Library/Application Support/tgstat-puller/launchd-stdout.log` — stdout от launchd, перезатирается каждый запуск
- `~/Library/Application Support/tgstat-puller/launchd-stderr.log` — stderr от launchd, traceback'и идут сюда
- БД-таблица `runs` — структурированная история (`started_at`, `status`, `succeeded_channels`, `failed_channels`, `error_summary`)

## Где живёт БД

`~/Library/Application Support/tgstat-puller/channels.db`. Эта папка не синхронизируется в iCloud — БД защищена от конфликтов синка, даже если вольт лежит на iCloud Drive.

## Бэкап БД

Перед каждым запуском — `~/Library/Application Support/tgstat-puller/channels.db` → `channels.db.bak` (одно поколение).

Если что-то пошло не так:
```
cp ~/Library/Application\ Support/tgstat-puller/channels.db.bak ~/Library/Application\ Support/tgstat-puller/channels.db
```

## Тесты

```
./venv/bin/pytest
```

## Файлы

- `pull.py` — оркестратор
- `db.py` — SQLite-модель
- `tgstat.py` — обёртка TGStat API
- `render.py` — генерация JSON/MD
- `migrate.py` — миграция старых данных (разово)
- `alert_check.py` — алерт через Telegram Bot API
- `launchd/com.natasha.tgstat-puller.plist` — расписание

Legacy:
- `import_xlsx.py` — для ручного импорта XLSX из TGStat (если когда-нибудь понадобится)
- `md_to_pdf.py` — конвертер MD → PDF
- `data/posts-*.jsonl` — старый формат хранения (заменён SQLite)

Trendwatch (отдельная подсистема, читает тот же `.env` и `tgstat.py`, но не пишет в `channels.db`):
- `watch.py`, `sources_watch.py` — сбор постов/сигналов референс-каналов через TGStat
- `telegraph.py` — публикация дайджеста на Telegraph
- `trendwatch.sh`, `enwatch.sh` — обёртки-крон-джобы (RU/EN-контур), шлют сводку headless Claude в Telegram
- `trendwatch-prompt.md`, `trendwatch-signals-prompt.md`, `enwatch-signals-prompt.md` — промпты для Claude
- `sources.txt`, `watch_channels.txt` — списки отслеживаемых каналов
- `build_dashboard.py` + `dashboard_template.html` — сборка автономного `dashboard.html` (генерируется, в git не хранится)
