rpi-media: приоритет русской дорожки и автозамена, ручные субтитры из Sub-раздачи
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
716539def3
commit
b8a31c7e54
+2
-1
@@ -101,7 +101,8 @@ Docker CE 29.9 + Compose v5.6 из репо download.docker.com (в Debian ст
|
|||||||
- Метаданные и интерфейс — ru, предпочтительные аудио/субтитры у пользователя — `rus`, режим субтитров Smart. Библиотеки «Фильмы» (`/data/library/movies`) и «Сериалы» (`/data/library/tv`), в Jellyfin только чтение.
|
- Метаданные и интерфейс — ru, предпочтительные аудио/субтитры у пользователя — `rus`, режим субтитров Smart. Библиотеки «Фильмы» (`/data/library/movies`) и «Сериалы» (`/data/library/tv`), в Jellyfin только чтение.
|
||||||
- Индексаторы (публичные, без аккаунтов): NoNaMe Club, The Pirate Bay, YTS — синхронизированы в Radarr/Sonarr; Rutor и EZTV есть в Prowlarr, но в *arr не доехали (Rutor не проходит тест по категориям, EZTV на момент настройки лежал); 1337x не добавился (таймаут даже через FlareSolverr). **RuTracker** (добавлен 2026-10-11, аккаунт пользователя; логин/пароль — только в БД Prowlarr): через FlareSolverr, опции «убрать кириллицу», «добавить RUS», «первые теги в конец» — чтобы *arr сопоставляли английские названия и видели русскую дорожку; приоритет 10 (выше публичных, 25). Синхронизирован в Radarr и Sonarr. Kinozal и прочие приватные — руками.
|
- Индексаторы (публичные, без аккаунтов): NoNaMe Club, The Pirate Bay, YTS — синхронизированы в Radarr/Sonarr; Rutor и EZTV есть в Prowlarr, но в *arr не доехали (Rutor не проходит тест по категориям, EZTV на момент настройки лежал); 1337x не добавился (таймаут даже через FlareSolverr). **RuTracker** (добавлен 2026-10-11, аккаунт пользователя; логин/пароль — только в БД Prowlarr): через FlareSolverr, опции «убрать кириллицу», «добавить RUS», «первые теги в конец» — чтобы *arr сопоставляли английские названия и видели русскую дорожку; приоритет 10 (выше публичных, 25). Синхронизирован в Radarr и Sonarr. Kinozal и прочие приватные — руками.
|
||||||
- ⚠️ RuTracker закрывает `login.php`/`tracker.php` челленджем Cloudflare (по IPv4; IPv6 у малины нет маршрута). FlareSolverr на Pi решает его **80–180 с** — у прокси в Prowlarr `requestTimeout=180` (было 60, с ним добавление падало по таймауту). После решения Prowlarr держит cookie и поиск идёт ~4 с; когда cookie протухнет, первый поиск снова будет минутами, и *arr могут на время пометить индексатор недоступным.
|
- ⚠️ RuTracker закрывает `login.php`/`tracker.php` челленджем Cloudflare (по IPv4; IPv6 у малины нет маршрута). FlareSolverr на Pi решает его **80–180 с** — у прокси в Prowlarr `requestTimeout=180` (было 60, с ним добавление падало по таймауту). После решения Prowlarr держит cookie и поиск идёт ~4 с; когда cookie протухнет, первый поиск снова будет минутами, и *arr могут на время пометить индексатор недоступным.
|
||||||
- Bazarr: провайдеры без аккаунтов (`embeddedsubtitles`, `podnapisi`, `yifysubtitles`); для русских субтитров лучший — OpenSubtitles.com, нужен аккаунт.
|
- **Языки дорожек** (2026-10-11, `provision.py langs`): custom formats «Русская дорожка» (язык Russian или `RUS|MVO|DVO|Dub|Дубляж` в названии) = 100 и «Оригинальная»/«Английская дорожка» = 50 во всех профилях Radarr/Sonarr; `minFormatScore=0` (ничего не отклоняется), `cutoffFormatScore=150` + `upgradeAllowed` — *arr сами перекачают, когда появится раздача с русской дорожкой. Язык профилей Radarr — Any (было Original: раздачи только с дубляжом отклонялись). Повод — первый фильм (The Fix, 2026) скачался с YTS только на английском; русского дубляжа у свежих релизов ещё нет неделями, есть только `Sub`-раздачи.
|
||||||
|
- Bazarr: провайдеры без аккаунтов (`embeddedsubtitles`, `podnapisi`, `yifysubtitles`); для русских субтитров лучший — OpenSubtitles.com, нужен аккаунт. ⚠️ Бесплатные провайдеры для свежих фильмов русских субтитров не находят (The Fix — пусто); тогда субтитры вытаскивали из `Sub`-раздачи RuTor: mkv в `torrents/other`, `ffmpeg -map 0:s:m:language:rus -c copy` → `<имя>.ru.srt` рядом с фильмом (сверить длительность/fps — иначе рассинхрон), лишнюю раздачу удалить.
|
||||||
- **Авторизация:** везде пользователь `rus`, один пароль — `/opt/media/.admin-password` (rus 600). *arr — формы, пароль **всегда** (режим «без пароля из LAN» в новых *arr требует `AllowedHosts`). Между собой сервисы ходят по API-ключам из `config/<app>/config.xml`.
|
- **Авторизация:** везде пользователь `rus`, один пароль — `/opt/media/.admin-password` (rus 600). *arr — формы, пароль **всегда** (режим «без пароля из LAN» в новых *arr требует `AllowedHosts`). Между собой сервисы ходят по API-ключам из `config/<app>/config.xml`.
|
||||||
- **Точка входа для пользователя — http://192.168.10.25:3000** (Homepage, конфиги `stacks/rpi-media/homepage/` → `/opt/media/homepage/`). Ключи виджетов — `/opt/media/homepage.env` (rus 600, `HOMEPAGE_VAR_*`, генерит `provision.py homepage`). ⚠️ Там же пароль qBittorrent: после смены общего пароля перегенерировать env и `docker compose up -d homepage`, иначе виджет qBittorrent отвалится. `HOMEPAGE_ALLOWED_HOSTS` обязателен — без него 400 на любой Host, кроме localhost.
|
- **Точка входа для пользователя — http://192.168.10.25:3000** (Homepage, конфиги `stacks/rpi-media/homepage/` → `/opt/media/homepage/`). Ключи виджетов — `/opt/media/homepage.env` (rus 600, `HOMEPAGE_VAR_*`, генерит `provision.py homepage`). ⚠️ Там же пароль qBittorrent: после смены общего пароля перегенерировать env и `docker compose up -d homepage`, иначе виджет qBittorrent отвалится. `HOMEPAGE_ALLOWED_HOSTS` обязателен — без него 400 на любой Host, кроме localhost.
|
||||||
- ⚠️ Встроенный виджет `jellyfin` Homepage 2.5 с Jellyfin 12 не работает: ходит на `/emby/…?api_key=` — пути нет (404), ключ в query отключён (`EnableLegacyAuthorization=false`, включать не стали). Вместо него `customapi` на `/Items/Counts` с заголовком `Authorization: MediaBrowser Token=…`.
|
- ⚠️ Встроенный виджет `jellyfin` Homepage 2.5 с Jellyfin 12 не работает: ходит на `/emby/…?api_key=` — пути нет (404), ключ в query отключён (`EnableLegacyAuthorization=false`, включать не стали). Вместо него `customapi` на `/Items/Counts` с заголовком `Authorization: MediaBrowser Token=…`.
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
ничего не ломает, уже сделанное пропускает.
|
ничего не ломает, уже сделанное пропускает.
|
||||||
|
|
||||||
Запуск на малине: python3 /opt/media/provision.py [шаг ...]
|
Запуск на малине: python3 /opt/media/provision.py [шаг ...]
|
||||||
Шаги: qbit jellyfin arr prowlarr bazarr seerr connect homepage (без аргументов — все).
|
Шаги: qbit jellyfin arr langs prowlarr bazarr seerr connect homepage (без аргументов — все).
|
||||||
Пароль админа берётся из /opt/media/.admin-password, API-ключи — из config.xml.
|
Пароль админа берётся из /opt/media/.admin-password, API-ключи — из config.xml.
|
||||||
"""
|
"""
|
||||||
from http.cookiejar import CookieJar
|
from http.cookiejar import CookieJar
|
||||||
@@ -187,6 +187,48 @@ def arr():
|
|||||||
log(name, "ok")
|
log(name, "ok")
|
||||||
|
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------- языки в *arr
|
||||||
|
def langs():
|
||||||
|
"""Приоритет дорожек: русская+оригинал (150) > русская (100) > оригинал (50). Ничего не отклоняется,
|
||||||
|
а cutoffFormatScore=150 + upgradeAllowed — *arr сами перекачают, когда появится раздача с русской дорожкой
|
||||||
|
(у свежих фильмов дубляж выходит через недели после оригинала)."""
|
||||||
|
for name, a in ARR.items():
|
||||||
|
h = {"X-Api-Key": apikey(name)}
|
||||||
|
u = f"{a['url']}/api/{a['api']}"
|
||||||
|
st, ll = http("GET", u + "/language", headers=h)
|
||||||
|
lid = {l["name"]: l["id"] for l in ll}
|
||||||
|
spec = lambda n, impl, v: {"name": n, "implementation": impl, "negate": False, "required": False,
|
||||||
|
"fields": [{"name": "value", "value": v}]}
|
||||||
|
orig = ("Оригинальная дорожка", "Original") if name == "radarr" else ("Английская дорожка", "English")
|
||||||
|
defs = {
|
||||||
|
# RuTracker с опцией «добавить RUS»: язык может не распознаться, а тег в названии есть
|
||||||
|
"Русская дорожка": [spec("Russian", "LanguageSpecification", lid["Russian"]),
|
||||||
|
spec("RUS в названии", "ReleaseTitleSpecification", r"\b(RUS|Rus|MVO|DVO|Dub|Дубляж)\b")],
|
||||||
|
orig[0]: [spec(orig[1], "LanguageSpecification", lid[orig[1]])],
|
||||||
|
}
|
||||||
|
scores = {"Русская дорожка": 100, orig[0]: 50}
|
||||||
|
st, cfs = http("GET", u + "/customformat", headers=h)
|
||||||
|
ids = {c["name"]: c["id"] for c in cfs}
|
||||||
|
for cname, specs in defs.items():
|
||||||
|
if cname not in ids:
|
||||||
|
st, r = http("POST", u + "/customformat",
|
||||||
|
{"name": cname, "includeCustomFormatWhenRenaming": False, "specifications": specs}, h)
|
||||||
|
ids[cname] = r["id"]
|
||||||
|
st, profs = http("GET", u + "/qualityprofile", headers=h)
|
||||||
|
for p in profs:
|
||||||
|
items = {fi["format"]: fi for fi in p["formatItems"]}
|
||||||
|
for cname, sc in scores.items():
|
||||||
|
if ids[cname] in items:
|
||||||
|
items[ids[cname]]["score"] = sc
|
||||||
|
else:
|
||||||
|
p["formatItems"].append({"format": ids[cname], "name": cname, "score": sc})
|
||||||
|
p.update({"minFormatScore": 0, "cutoffFormatScore": 150, "upgradeAllowed": True})
|
||||||
|
if name == "radarr": # было Original — отклоняло раздачи только с дубляжом
|
||||||
|
p["language"] = {"id": lid["Any"], "name": "Any"}
|
||||||
|
http("PUT", u + "/qualityprofile/%d" % p["id"], p, h)
|
||||||
|
log(name, "langs ok")
|
||||||
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------- Prowlarr
|
# ---------------------------------------------------------------- Prowlarr
|
||||||
def prowlarr():
|
def prowlarr():
|
||||||
k = apikey("prowlarr")
|
k = apikey("prowlarr")
|
||||||
@@ -385,7 +427,7 @@ def jellyseerr():
|
|||||||
log("seerr ok")
|
log("seerr ok")
|
||||||
|
|
||||||
|
|
||||||
STEPS = {"qbit": qbit, "jellyfin": jellyfin, "arr": arr, "prowlarr": prowlarr, "bazarr": bazarr, "connect": connect, "homepage": homepage, "seerr": jellyseerr}
|
STEPS = {"qbit": qbit, "jellyfin": jellyfin, "arr": arr, "langs": langs, "prowlarr": prowlarr, "bazarr": bazarr, "connect": connect, "homepage": homepage, "seerr": jellyseerr}
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
for s in sys.argv[1:] or list(STEPS):
|
for s in sys.argv[1:] or list(STEPS):
|
||||||
|
|||||||
Reference in New Issue
Block a user