rpi: скачать Бёрта Уандерстоуна и уведомить о готовности
This commit is contained in:
@@ -84,6 +84,8 @@ OneDrive на внешний HDD; с того же дня ещё и медиац
|
||||
- Для перевёрстки извлечённого текста в PDF установлен `python3-reportlab` 4.3.1 (2026-10-11; ранее средств создания PDF с кириллицей не было), с зависимостями Pillow/Cairo. Шрифт DejaVu Sans внедряется в PDF; PNG-предпросмотр строится из итогового серого PDF. Проверено на комплекте Лермонтова: 3 страницы A4, текст со скриншотов и исходный портрет.
|
||||
|
||||
## Медиацентр (с 2026-10-11, код — `stacks/rpi-media/`)
|
||||
|
||||
- 2026-10-18 по просьбе владельца добавлен «Невероятный Бёрт Уандерстоун» (2013, TMDB 124459, Radarr id=3), вручную выбрана RuTracker-раздача BDRip 1080p MVO + Original Eng RUS, 11,4 ГБ. Установлен `notify-movie-ready.timer` (раз в 2 мин, ранее уведомления для этого фильма не было): после импорта с русской аудиодорожкой и появления в Jellyfin отправляет владельцу 607015 ссылку на фильм. Скрипт и юниты — `stacks/rpi-media/`; отметка доставки `/var/lib/media-ready/burt-wonderstone.sent`, после неё повторно не шлёт. Секреты читает из существующих env, в логах только тип ошибки, чтобы не раскрыть Telegram URL с токеном. ⚠️ Ссылка доступна в домашней сети; таймер не означает, что загрузка уже завершилась.
|
||||
Docker CE 29.9 + Compose v5.6 из репо download.docker.com (в Debian старее). `/etc/docker/daemon.json`: json-file `10m×3` — чтобы логи контейнеров не точили SD. `rus` в группе `docker` (= root-эквивалент; у него и так sudo NOPASSWD). Стек — `/opt/media/docker-compose.yml`, конфиги — `/opt/media/config/<сервис>` (SD, ~20 МБ), образы ~7.8 ГБ на SD.
|
||||
|
||||
| Сервис | Порт | Зачем | Версия на 2026-10-11 |
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
[Unit]
|
||||
Description=Notify owner when Burt Wonderstone is ready in Jellyfin
|
||||
After=network-online.target docker.service
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
ExecStart=/usr/bin/python3 /usr/local/lib/media-ready/notify-movie-ready.py
|
||||
StateDirectory=media-ready
|
||||
UMask=0077
|
||||
NoNewPrivileges=true
|
||||
PrivateTmp=true
|
||||
ProtectSystem=strict
|
||||
ProtectHome=true
|
||||
TimeoutStartSec=120
|
||||
@@ -0,0 +1,10 @@
|
||||
[Unit]
|
||||
Description=Check requested movie readiness every two minutes
|
||||
|
||||
[Timer]
|
||||
OnBootSec=2min
|
||||
OnUnitInactiveSec=2min
|
||||
Unit=notify-movie-ready.service
|
||||
|
||||
[Install]
|
||||
WantedBy=timers.target
|
||||
@@ -0,0 +1,66 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Send one owner notification after Radarr import and Jellyfin indexing."""
|
||||
import json
|
||||
from pathlib import Path
|
||||
import urllib.request
|
||||
|
||||
TMDB = 124459
|
||||
STATE = Path('/var/lib/media-ready/burt-wonderstone.sent')
|
||||
|
||||
def env(path):
|
||||
return dict(line.strip().split('=', 1) for line in open(path)
|
||||
if '=' in line and not line.startswith('#'))
|
||||
|
||||
def api(base, path, headers=None, data=None):
|
||||
request = urllib.request.Request(base + path, headers=headers or {},
|
||||
data=None if data is None else json.dumps(data).encode())
|
||||
with urllib.request.urlopen(request, timeout=30) as response:
|
||||
body = response.read()
|
||||
return json.loads(body) if body else None
|
||||
|
||||
def main():
|
||||
if STATE.exists():
|
||||
return
|
||||
keys = env('/etc/media.env')
|
||||
movies = api('http://127.0.0.1:7878', '/api/v3/movie',
|
||||
{'X-Api-Key': keys['RADARR_KEY']})
|
||||
movie = next((m for m in movies if m['tmdbId'] == TMDB), None)
|
||||
if not movie or not movie.get('hasFile'):
|
||||
print('Waiting for Radarr import')
|
||||
return
|
||||
audio = str(movie.get('movieFile', {}).get('mediaInfo', {}).get('audioLanguages', '')).lower()
|
||||
if not any(language in audio.replace('/', ' ').replace(',', ' ').split()
|
||||
for language in ('russian', 'rus', 'ru')):
|
||||
print('Waiting for an imported file with Russian audio')
|
||||
return
|
||||
base = 'http://127.0.0.1:8096'
|
||||
headers = {'Authorization': 'MediaBrowser Token="' + keys['JELLYFIN_KEY'] + '"'}
|
||||
items = api(base, '/Items?Recursive=true&IncludeItemTypes=Movie&Fields=ProviderIds', headers)
|
||||
item = next((i for i in items['Items']
|
||||
if i.get('ProviderIds', {}).get('Tmdb') == str(TMDB)), None)
|
||||
if not item:
|
||||
api(base, '/Library/Refresh', headers, {})
|
||||
print('Waiting for Jellyfin index; refresh requested')
|
||||
return
|
||||
server = api(base, '/System/Info/Public')['Id']
|
||||
link = ('http://192.168.10.25:8096/web/#/details?id='
|
||||
+ item['Id'] + '&serverId=' + server)
|
||||
token = env('/etc/astra-bot.env')['TG_TOKEN']
|
||||
result = api('https://api.telegram.org', '/bot' + token + '/sendMessage',
|
||||
{'Content-Type': 'application/json'},
|
||||
{'chat_id': 607015, 'text': '«Невероятный Бёрт Уандерстоун» скачался. '
|
||||
'Русская озвучка, 1080p. Смотреть дома:\n' + link,
|
||||
'disable_web_page_preview': True})
|
||||
if not result.get('ok'):
|
||||
raise RuntimeError('Telegram did not confirm delivery')
|
||||
STATE.parent.mkdir(parents=True, exist_ok=True)
|
||||
STATE.write_text(str(result['result']['message_id']) + '\n')
|
||||
print('Ready notification delivered')
|
||||
|
||||
if __name__ == '__main__':
|
||||
# urllib exceptions can contain the Telegram token in their URL.
|
||||
try:
|
||||
main()
|
||||
except Exception as error:
|
||||
print('Movie notification failed: ' + type(error).__name__)
|
||||
raise SystemExit(1)
|
||||
Reference in New Issue
Block a user