Files
obsidian-vault/personal/tech/skill-arr-media-stack-setup-additions.md

180 lines
11 KiB
Markdown
Executable File
Raw Permalink 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.
---
title: Skill — arr-media-stack-setup (дополнения 2026-09-26)
created: '2026-09-26'
updated: '2026-09-28'
type: tech
namespace: personal
tags:
- skill
- arr
- prowlarr
- dns
- truenas
- blocked
- pitfalls
- lidarr
- navidrome
related:
- '[[family/how-to/arr-stack-taiga]]'
- '[[family/how-to/arr-stack-taiga]]'
- '[[family/how-to/navidrome-truenas-android]]'
---
# Skill `arr-media-stack-setup` — дополнения 2026-09-26
> Зеркало патча скилла. Что добавлено после разведки на Тайге (задача «Lidarr + музыка + синк с Jellyfin»).
> Полный скилл: `~/.hermes/hermes-whale/skills/devops/arr-media-stack-setup/SKILL.md`
## 1a. Lidarr — музыкальный *arr (патч 2026-09-28)
**Связка — с NAVIDROME, не с Jellyfin.** Jellyfin для музыки непригоден (баг #18162, имя папки
перекрывает теги). Актуальный Taiga runbook — [[family/how-to/arr-stack-taiga]].
**Сервис = копия radarr:** `lscr.io/linuxserver/lidarr:latest`, порт `8686`, `PUID=950 PGID=950`,
volumes `/mnt/RED_2TB/docker/arr/lidarr:/config` + `/mnt/RED_2TB/storage:/storage` (`:rw`),
сети `media_net` + `caddy_default`. Старт — из папки проекта `/mnt/RED_2TB/docker/arr`.
**Root folder — та же папка, что читает Navidrome** (`/storage/Music`).
🔴 **`Write Metadata Tags` обязателен** — без него Lidarr не пишет `Album Artist`, и при
отсутствии `ALBUMARTIST` Navidrome подставляет track artist → сборники и фиты разваливаются
на альбомы-одиночки.
🔴 **Существующую библиотеку в Lidarr НЕ импортировать** — импорт как «Existing Albums» заставит
Lidarr перезаписать теги из MusicBrainz, ручной ремонт тегов уйдёт. Lidarr отвечает только
за новые закачки.
### Audio-категории — проверять `?t=caps`, не предполагать
```bash
# внутри контейнера prowlarr (в linuxserver-образах есть /usr/bin/curl)
docker exec prowlarr curl -s -H 'X-Api-Key: <KEY>' \
'http://localhost:9696/api/v1/indexer/<ID>' > /tmp/idx.json
jq -r '.capabilities.categories[] | "\(.id) | \(.name)"' /tmp/idx.json | grep -E '^3|Audio'
```
**Факт Taiga 2026-09-28:** RuTracker → `3000 Audio` ✅, NoNaMe Club → `3000 Audio` ✅,
**RuTor → категории не отдал**. Живых индексеров 3/6 (RuTracker/Kinozal за Cloudflare).
### Prowlarr → Lidarr
`POST /api/v1/applications`: `implementation=Lidarr`, `configContract=LidarrSettings`,
`syncLevel=fullSync`, `baseUrl=http://lidarr:8686`, `appProfileId` из `GET /api/v1/appprofile`
(на Taiga — `1`, `Standard`), `syncCategories=[3000,3010,3020,3030,3040,3050,3060]`.
## 1. Индексеры недоступны: DNS-фильтр провайдера (НЕ Cloudflare, НЕ Pi-hole)
**Новый класс проблемы**, ранее не описанный в скилле. Задокументированы были только
«Cloudflare 403 на `indexers.prowlarr.com`» и «RuTracker Turnstile». Здесь **DNS не отдаёт IP вообще**.
```bash
# InitialFailure показывает НАЧАЛО проблемы, а не «сейчас»
GET /api/v1/indexerstatus → initialFailure: "2026-05-20T05:4x:xx" ← день деплоя
→ disabledTill: +24 ч карантин
# Резолв проверять ДВУМЯ резолверами
nslookup rutracker.org 192.168.2.2 # роутер
nslookup rutracker.org 8.8.8.8 # внешний
# NXDOMAIN на ОБОИХ → фильтр на стороне аплинка/провайдера
# NXDOMAIN на роутере → Pi-hole/локальный DNS
```
**Быстрый чек всех индексеров** — `wget -S` на каждый домен из контейнера prowlarr:
`wget: bad address '<domain>'` = DNS-провал, `HTTP/1.1 200 OK` = домен жив.
**Фикс:** SOCKS5-прокси, но сперва убедиться, что прокси-контейнер виден целевой сети
(`docker network inspect media_net --format '{{range .Containers}}{{.Name}} {{end}}'`).
После `docker network connect` — **добавить сеть в compose**, иначе потеряется при пересоздании.
Затем `POST /api/v1/indexer/testall` снимает `disabledTill`.
## 2. `disabledTill` НЕ виден в Radarr/Sonarr
`GET /api/v3/indexer` отдаёт `"status": {}` — пусто. Карантин смотреть **только** в Prowlarr
(`/api/v1/indexerstatus`, `/api/v1/health`). Не делать вывод «индексеры свободны» по Radarr.
## 3. TrueNAS: `python3` ЕСТЬ, `curl` и `sqlite3` — НЕТ
**Исправление распространённой ошибки в доке** («нет curl и python3»). Факт 2026-09-26:
`python3` на хосте работает (использовался для разбора JSON). Нет **`curl`** и **`sqlite3`**.
**Рабочий паттерн API = `wget` в контейнере + хостовый `python3`:**
```bash
ssh truenas_admin@HOST \
"docker exec prowlarr sh -c 'wget -qO- --header=\"X-Api-Key: <KEY>\" http://localhost:9696/api/v1/health'"
```
- busybox-`wget`: только `-qO-` / `-S` / `--header` / `--timeout`.
**`-e use_proxy=yes` НЕ поддерживается** (GNU-опция) → прокси-тест изнутри linuxserver-контейнера
этим способом невозможен.
- Экранирование JSON через ssh ломается на кавычках в `--header` → надёжнее писать вывод
в файл (`> /tmp/x.json`) и разбирать отдельным вызовом.
- `jq` с дефисами: `.["download-dir"]`, не `.download-dir`.
## 4. `/etc/resolv.conf` контейнеров = `127.0.0.11`
Docker embedded DNS. В linuxserver-образах **нет `getent`** → использовать `nslookup`/`wget`.
## 5. RemotePathMapping: health жалуется при «задокументированном» маппинге
```
RemotePathMappingCheck error
"download client Transmission places downloads in /storage/Downloads/radarr
but this directory does not appear to exist inside the container"
```
Проверять **фактический** download-dir, а не предполагаемый:
```bash
docker exec transmission sh -c 'cat /config/settings.json' # → "download-dir": "/mnt/storage/Downloads"
```
Если download-dir **плоский** (без подкаталога категории) — сам маппинг не спасёт: подкаталога нет.
Плюс Transmission монтирует `/mnt/storage`, Radarr — `/storage` (один хост-путь под двумя именами).
**Всегда проверять наличие записей в API** (`GET /api/v3/remotepathmapping`), а не то, что записано в доке.
## 6. 🔴 Прокси в Lidarr: «записан» ≠ «применяется» (2026-09-28, поздний вечер)
**Конфиг-ридбэк ИДЕАЛЬНЫЙ** — `proxyEnabled:true`, `proxyType:"http"`, `proxyHostname:"vless-proxy"`,
`proxyPort:1081`, `proxyBypassFilter` расширен на все docker-имена стека — **а Lidarr всё равно
ходит напрямую**:
```
docker logs lidarr | grep -i proxy
[Error] ProxyCheck: Proxy Health Check failed
```
`artist/lookup` → **403 Cloudflare**, и сама страница ошибки CF выдаёт egress-IP:
`Your IP: 90.189.160.148` — **домашний аплинк**, не VPS. `docker restart lidarr` **не помог**.
### Диагностическая триада: «прокси настроен неверно» vs «прокси не применяется»
```bash
# 1. конфиг верный? GET /api/v1/config/host → proxyEnabled / proxyType / proxyPort
# 2. прокси САМ работает? (из того же контейнера)
docker exec lidarr sh -c 'curl -s -m 15 -x http://vless-proxy:1081 https://api.ipify.org' # VPS IP
docker exec lidarr sh -c 'curl -s -m 15 https://api.ipify.org' # домашний IP
# 3. Lidarr ЕГО ИСПОЛЬЗУЕТ? ЛОГ — единственный надёжный сигнал
docker logs lidarr 2>&1 | grep -i proxy # ProxyCheck failed ⇒ НЕ использует
```
Если (1) ✅ и (2) ✅, а (3) даёт `ProxyCheck failed` — **конфиг инертен**.
- **Подозреваемый №1: `proxyBypassLocalAddresses: true`.** `api.lidarr.audio` резолвится в
Cloudflare-IP; эвристика «локальный адрес» может его проглотить. Проверить с `false`.
- **Подозреваемый №2: IPv6-цель против IPv4-only прокси.** В контейнере `api.lidarr.audio` даёт
`2606:4700:...` (AAAA), а `vless-proxy:1081` — только IPv4. CONNECT к v6-цели падает, и
.NET-клиент **молча откатывается** на прямое соединение.
Проверка: `curl -x http://vless-proxy:1081 -6 https://api.lidarr.audio/...`
- **Подозреваемый №3: `proxyType:"socks5"` + порт `1080`** — обойти специфику HTTP-CONNECT.
> 🔴 **`GET /api/v1/health` → `[]` НЕ значит «сервис здоров».** Lidarr пишет провал `ProxyCheck`
> **только в лог** — в health-API он не попадает. `health: []` сосуществовал с жёстким `403` на
> каждом вызове метаданных. **Проверять живым `artist/lookup` + `docker logs | grep`, не `health`.**
> 🔴 **Обобщённое правило для этого хоста:** любой сервис, который ходит в интернет сам
> (Lidarr → SkyHook, FlareSolverr → Chrome), по умолчанию выходит через **домашний аплинк**
> (`90.189.160.148`). `curl api.ipify.org` **на хосте Тайги** возвращает домашний IP — VPS-выход
> существует **только** за `vless-proxy`. ⇒ «прокси настроен» бессмысленно; доказательство одно:
> **отличается ли egress-IP этого сервиса от `90.189.160.148`**.
## Связанные заметки
- [[family/how-to/arr-stack-taiga]] — актуальная реализация на Taiga
- [[family/how-to/arr-stack-taiga]] — состояние стека на Тайге