180 lines
11 KiB
Markdown
Executable File
180 lines
11 KiB
Markdown
Executable File
---
|
||
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/projects/media-toolbox-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/projects/media-toolbox-taiga]] — состояние стека на Тайге
|