Files
obsidian-vault/family/projects/media-toolbox-kraken.md
T

680 lines
24 KiB
Markdown
Raw 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.
---
created: '2026-05-13'
updated: '2026-05-13'
status: planning
tags:
- kraken
- media
- jellyfin
- transmission
- swift
- project
---
# Media Toolbox на Кракене
> Создано: 2026-05-13. Цель: полноценный медиасервер на Кракене (RPi 5) — перенос библиотеки с HTPC, автосортировка через kodi-media-sync, Jellyfin, торренты.
---
## Архитектура (целевая)
```
HTPC (Bazzite 192.168.1.86)
└── /run/media/bazzite/Data/{Мультфильмы,Сериалы,movies,...}
└─── rsync ──→ Kraken HDD /srv/.../media/
Kraken (RPi 5, 192.168.1.14)
├── /srv/dev-disk-by-uuid-.../media/
│ ├── movies/ ← фильмы
│ ├── cartoons/ ← мультфильмы
│ ├── series/ ← сериалы
│ ├── documentaries/ ← документальные
│ └── downloads/ ← папка Transmission (входящие)
├── Docker: Transmission (скачка торрентов)
├── Docker: Jellyfin (стриминг на TV/телефоны)
└── Docker: kodi-media-sync (сортировщик + метаданные)
kodi-media-sync (Swift CLI, cross-compile Mac → Linux ARM64)
├── Читает downloads/ + необработанные папки
├── Идентифицирует через Transmission RPC (если торрент) или поиск по имени
├── Создаёт NFO-файлы (Kodi/Jellyfin-совместимые)
├── Раскладывает по категориям (movies/cartoons/series/docs)
├── Обновляет пути скачки в Transmission через RPC API
└── Запускается как download-complete скрипт Transmission
Hermes cron (Кракен, 1-2x/day)
└── kodi-media-sync --dry-run → лог → manual confirm / auto-apply
TrueNAS (Taiga)
└── Transmission → миграция на Крaken (или оставить для seed, скопировать БД торрентов)
```
---
## Статус по шагам
| Шаг | Статус | Заметки |
|-----|--------|---------|
| 1 — Исследование (Kodi lib на HTPC) | 🔲 | |
| 2 — Wake HTPC + prevent sleep | 🔲 | |
| 3 — Копирование медиа HTPC → Kraken | 🔲 | |
| 4 — Transmission на Кракене | 🔲 | уже есть контейнер в /home/kraken/media/ |
| 5 — Перенос torrent-базы с HTPC | 🔲 | Windows раздел или Bazzite Transmission |
| 6 — kodi-media-sync: изучить + расширить | 🔲 | Swift, scaffold готов |
| 7 — Cross-compile Mac → Linux ARM64 | 🔲 | Swift toolchain для aarch64 |
| 8 — Docker-образ kodi-media-sync на Кракене | 🔲 | |
| 9 — Config: пути, Transmission, категории | 🔲 | |
| 10 — Dry run: проверка сортировки | 🔲 | |
| 11 — Jellyfin: настройка библиотек | 🔲 | уже есть контейнер |
| 12 — Transmission download-complete hook | 🔲 | |
| 13 — Hermes cron на Кракене | 🔲 | |
| 14 — Руtracker-скилл (поиск/закачка) | 🔲 | |
| 15 — Музыка: скачка + sync с TrueNAS | 🔲 | |
---
## Шаг 1 — Исследование: Kodi lib на HTPC
**Цель:** найти реальную структуру медиабиблиотеки, где симлинки, куда ведут.
```bash
ssh -i ~/.ssh/id_rsa bazzite@192.168.1.86
# Kodi userdata (может быть в двух местах)
ls ~/.kodi/userdata/
ls ~/.kodi/userdata/sources.xml # список медиаисточников
# Если Kodi с Windows раздела мигрировал
ls /run/media/bazzite/Data/AppData/Roaming/Kodi/ 2>/dev/null
# Найти симлинки в home
find ~ -type l 2>/dev/null | head -30
# Медиа на Data разделе
ls /run/media/bazzite/Data/ | grep -iE "film|movie|кино|мульт|serial|сери|doc"
```
**Ожидаемые пути на Data:**
- `/run/media/bazzite/Data/Мультфильмы/`
- `/run/media/bazzite/Data/Сериалы/`
- `/run/media/bazzite/Data/movies/`
- `/run/media/bazzite/Data/документальные/` (или аналог)
---
## Шаг 2 — Wake HTPC + предотвращение сна
### Wake on LAN
```bash
# С Mac или Кракена:
wakeonlan B0:6E:BF:60:6D:64
# или
python3 ~/Automation/wake-on-lan.py
```
### Предотвратить сон во время SSH / копирования
**Вариант A — systemd-inhibit (рекомендуется):**
```bash
# Запустить на HTPC в отдельной SSH-сессии, оставить висеть пока идёт копирование:
systemd-inhibit --what=sleep:idle --who="media-copy" \
--why="Copying media to Kraken" --mode=block \
sleep infinity
```
Закрыть эту сессию = сон разрешён снова.
**Вариант B — через systemd сервис-lockfile (долгосрочно):**
Если SSH-сессия падает, нужен более надёжный способ. Создать временный `inhibit.service` который поднимается на время rsync.
**Вариант C — xdg-screensaver (только экран):**
```bash
# Только блокирует screensaver, не suspend
while true; do xdg-screensaver reset; sleep 60; done &
```
**Рекомендация:** вариант A (systemd-inhibit). Запускать в tmux, чтобы сессия жила независимо от SSH:
```bash
ssh bazzite@192.168.1.86 "tmux new-session -d -s inhibit 'systemd-inhibit --what=sleep:idle --who=media-copy --why=Copying --mode=block sleep 86400'"
```
---
## Шаг 3 — Копирование медиа HTPC → Kraken
### Целевая структура на Кракене
```
/srv/dev-disk-by-uuid-49e8f586-3839-4c5d-a1e1-58bfc3579ade/media/
├── movies/
├── cartoons/
├── series/
├── documentaries/
└── downloads/ ← Transmission download dir
└── complete/ ← сюда Transmission кладёт готовые
```
### Создать директории
```bash
ssh kraken@192.168.1.14 "mkdir -p /srv/dev-disk-by-uuid-49e8f586-3839-4c5d-a1e1-58bfc3579ade/media/{movies,cartoons,series,documentaries,downloads/complete,downloads/incomplete}"
```
### rsync HTPC → Kraken (прямо с Кракена)
```bash
# Запустить на Кракене (pull с HTPC):
HDD=/srv/dev-disk-by-uuid-49e8f586-3839-4c5d-a1e1-58bfc3579ade
# Мультфильмы
rsync -avh --progress --no-links \
bazzite@192.168.1.86:"/run/media/bazzite/Data/Мультфильмы/" \
"$HDD/media/cartoons/"
# Сериалы
rsync -avh --progress --no-links \
bazzite@192.168.1.86:"/run/media/bazzite/Data/Сериалы/" \
"$HDD/media/series/"
# Фильмы (уточнить точное имя папки)
rsync -avh --progress --no-links \
bazzite@192.168.1.86:"/run/media/bazzite/Data/movies/" \
"$HDD/media/movies/"
# Документальные (если есть)
rsync -avh --progress --no-links \
bazzite@192.168.1.86:"/run/media/bazzite/Data/документальные/" \
"$HDD/media/documentaries/" 2>/dev/null || true
```
> ⚠️ `--no-links` — не копировать симлинки как симлинки, следовать им.
> ⚠️ Для SSH без пароля с Кракена нужен ключ: `ssh-copy-id -i ~/.ssh/id_rsa bazzite@192.168.1.86`
### Альтернатива — пушить с HTPC через SSH:
```bash
# На HTPC:
rsync -avh --progress /run/media/bazzite/Data/Мультфильмы/ \
kraken@192.168.1.14:/srv/.../media/cartoons/
```
---
## Шаг 4 — Transmission на Кракене
Transmission уже задеплоен вместе с Jellyfin в `/home/kraken/media/docker-compose.yml`.
**Проверить конфиг:**
```bash
cat /home/kraken/media/docker-compose.yml
```
**Download dir** должен быть смонтирован как HDD/media/downloads.
**Порты:** 9091 (RPC), 51413 (peers)
**Если Transmission ещё не настроен** — проверить и обновить docker-compose, добавить volume:
```yaml
volumes:
- /srv/dev-disk-by-uuid-.../media/downloads:/downloads
- /srv/dev-disk-by-uuid-.../docker/transmission:/config
```
---
## Шаг 5 — Перенос torrent-базы с HTPC
### Найти торрент-клиент на HTPC
```bash
ssh bazzite@192.168.1.86
# Что стоит?
which transmission-daemon qbittorrent-nox rtorrent 2>/dev/null
systemctl list-units | grep -iE "torrent|transmission|qbit"
# Transmission (если есть):
ls ~/.config/transmission/torrents/ | head -10
ls ~/.config/transmission/resume/ | head -10
# qBittorrent:
ls ~/.local/share/data/qBittorrent/BT_backup/ | head -10
```
### Если Transmission на Bazzite:
```bash
# Скопировать на Кракен:
rsync -avh bazzite@192.168.1.86:~/.config/transmission/ \
kraken@192.168.1.14:/tmp/htpc-transmission/
```
### Если торрент-клиент был на Windows (TrueNAS Transmission):
Торрентная БД TrueNAS уже работает. Нужно решить:
- **Вариант A:** Перенести TrueNAS Transmission на Крaken (один клиент)
- **Вариант B:** Оставить TrueNAS для seed, Крaken для новых загрузок
**Миграция `.torrent` + `.resume` файлов:**
```bash
# Скопировать с TrueNAS (через duckdns):
rsync -avh -e "ssh -i ~/.ssh/id_rsa" \
truenas_admin@mallexxx.duckdns.org:/mnt/RED_2TB/docker/transmission/ \
/tmp/taiga-transmission/
# Поправить пути в .resume файлах:
# Старый путь TrueNAS: /mnt/storage/Downloads/...
# Новый путь Кракена: /downloads/complete/...
for f in /tmp/taiga-transmission/resume/*.resume; do
# .resume это bencoded файл — нужен python с bencode или transmission-edit
echo "$f"
done
```
> ⚠️ Файлы `.resume` — бинарный bencode-формат. Для правки путей использовать:
> `pip install bencoder.pyx` или `transmission-remote --torrent N --find /new/path`
> Проще: после импорта торрентов запустить media-sync с --fix-paths флагом через RPC API.
### Исправление путей через Transmission RPC:
```bash
# Transmission RPC: изменить путь для конкретного торрента
curl -s -u user:pass http://kraken:9091/transmission/rpc \
-H "X-Transmission-Session-Id: TOKEN" \
-d '{"method":"torrent-set-location","arguments":{"ids":[N],"location":"/downloads/complete/FolderName","move":false}}'
```
**kodi-media-sync должен уметь это автоматически** (см. шаг 6).
---
## Шаг 6 — kodi-media-sync: функциональность
### Текущее состояние проекта
Проект `~/Developer/kodi-media-sync` (Swift):
- `Config.swift` — читает config.json: `transmission` URL, `directories[]`, `output.{movies,series}`
- `MediaSync.swift` — scaffold: сканирует директории, вызывает `updateMetadata` (пустая)
- `Path.swift` — утилиты для файловой системы
**Нужно реализовать:**
### 6.1 Transmission RPC клиент
```swift
// Sources/TransmissionClient.swift
struct TransmissionClient {
let url: URL
// Получить все торренты
func getTorrents() async throws -> [Torrent]
// Найти торрент по имени файла / папке
func findTorrent(forPath path: Path) async throws -> Torrent?
// Обновить путь торрента
func setLocation(torrentId: Int, location: Path) async throws
}
```
### 6.2 Идентификация медиа
```swift
// Sources/MediaIdentifier.swift
enum MediaType {
case movie(title: String, year: Int?)
case series(title: String, season: Int?, episode: Int?)
case cartoon(title: String, year: Int?)
case documentary(title: String, year: Int?)
case unknown
}
struct MediaIdentifier {
// Из имени папки/файла → тип медиа + нормализованное название
func identify(path: Path, torrent: Torrent?) -> MediaType
// Поиск метаданных (TMDB/OMDB/локальный поиск)
func fetchMetadata(for media: MediaType) async throws -> MediaMetadata
}
```
**Алгоритм идентификации:**
1. Если есть торрент в Transmission — взять имя торрента, категорию
2. Парсить имя файла/папки: регексы для `S01E01`, год `(2024)`, качество `1080p`
3. Для документалок типа "знакомимся с кабанами" — поиск по названию (TMDB API)
4. Маппинг исходной папки → тип: `Мультфильмы/` → cartoon, `Сериалы/` → series
### 6.3 NFO-файлы (Kodi/Jellyfin)
```swift
// Sources/NFOWriter.swift
// Формат Kodi NFO: https://kodi.wiki/view/NFO_files/Movies
struct NFOWriter {
func writeMovieNFO(_ metadata: MediaMetadata, to path: Path) throws
func writeSeriesNFO(_ metadata: MediaMetadata, to path: Path) throws
func writeTVShowNFO(_ metadata: MediaMetadata, to path: Path) throws
}
```
### 6.4 Config расширение
```json
{
"transmission": "http://user:pass@192.168.1.14:9091/transmission/rpc",
"tmdb_api_key": "...",
"directories": [
"/media/downloads/complete",
"/media/movies",
"/media/cartoons"
],
"output": {
"movies": "/media/movies",
"series": "/media/series",
"cartoons": "/media/cartoons",
"documentaries": "/media/documentaries"
},
"dry_run": false,
"category_hints": {
"/media/cartoons": "cartoon",
"/media/series": "series",
"/media/documentaries": "documentary"
}
}
```
### 6.5 CLI флаги
```
kodi-media-sync [--config path] [--dry-run] [--path <specific_path>] [--fix-paths]
--dry-run Показать что будет сделано, не двигать файлы
--path PATH Обработать только конкретную папку/файл
--fix-paths Обновить пути в Transmission для уже существующих файлов
```
---
## Шаг 7 — Cross-compilation Mac → Linux ARM64
**Swift на Mac имеет встроенный cross-compiler для Linux.**
### Установить Swift toolchain для Linux (если не стоит):
```bash
# На Mac:
swiftly install latest
# или скачать Linux ARM toolchain:
# https://www.swift.org/install/linux/
```
### Build для aarch64-linux:
```bash
cd ~/Developer/kodi-media-sync
# Вариант A — через Docker buildx (рекомендуется):
docker buildx build --platform linux/arm64 \
-f Dockerfile.linux \
-t kodi-media-sync:arm64 \
--output type=local,dest=./build-arm64 .
# Вариант B — swift cross-compile (нужен SDK):
swift build --triple aarch64-unknown-linux-gnu \
--sdk /path/to/linux-arm64-sdk
```
### Dockerfile.linux для Крaken:
```dockerfile
FROM swift:5.9-jammy AS builder
WORKDIR /build
COPY . .
RUN swift build -c release
FROM ubuntu:22.04
RUN apt-get update && apt-get install -y libstdc++6 libgcc-s1 && rm -rf /var/lib/apt/lists/*
COPY --from=builder /build/.build/release/kodi-media-sync /usr/local/bin/
COPY config.json /etc/kodi-media-sync/config.json
ENTRYPOINT ["kodi-media-sync"]
CMD ["--config", "/etc/kodi-media-sync/config.json"]
```
> ⚠️ Собирать образ на Mac через buildx с эмуляцией QEMU — не на RPi5 (undervoltage под нагрузкой)!
### Deploy на Кракен:
```bash
# Сохранить образ и скопировать:
docker save kodi-media-sync:arm64 | gzip | ssh kraken@192.168.1.14 "docker load"
```
---
## Шаг 8 — Docker-образ на Кракене
### `/home/kraken/media-sync/docker-compose.yml`:
```yaml
version: '3.8'
services:
kodi-media-sync:
image: kodi-media-sync:arm64
container_name: kodi-media-sync
restart: "no" # запускается по требованию, не автостарт
volumes:
- /srv/dev-disk-by-uuid-.../media:/media
- /srv/dev-disk-by-uuid-.../docker/media-sync:/config
environment:
- CONFIG=/config/config.json
network_mode: host # доступ к Transmission на localhost
```
### Запуск (разовый):
```bash
cd /home/kraken/media-sync
sudo docker compose run --rm kodi-media-sync --dry-run
sudo docker compose run --rm kodi-media-sync
```
---
## Шаг 9 — Config для Кракена
```json
{
"transmission": "http://admin:pass@192.168.1.14:9091/transmission/rpc",
"tmdb_api_key": "КЛЮЧ_ИЗ_TMDB",
"directories": [
"/media/downloads/complete"
],
"category_hints": {
"/media/cartoons": "cartoon",
"/media/series": "series",
"/media/documentaries": "documentary",
"/media/movies": "movie"
},
"output": {
"movies": "/media/movies",
"series": "/media/series",
"cartoons": "/media/cartoons",
"documentaries": "/media/documentaries"
},
"dry_run": false
}
```
> TMDB API key: получить на https://www.themoviedb.org/settings/api (бесплатно)
---
## Шаг 10 — Dry run и ручная проверка
```bash
# Dry run — показывает что будет сделано
sudo docker run --rm \
-v /srv/.../media:/media \
-v /srv/.../docker/media-sync:/config \
kodi-media-sync:arm64 --dry-run
# Проверить проблемные документалки
sudo docker run --rm ... kodi-media-sync:arm64 --dry-run \
--path "/media/downloads/complete/знакомимся с кабанами"
# Проверить NFO файлы
cat /srv/.../media/movies/SomeMovie/SomeMovie.nfo
```
**Что проверить:**
- [ ] Фильмы попали в movies/, мультфильмы в cartoons/ и т.д.
- [ ] NFO-файлы созданы и содержат правильные title/year/plot
- [ ] Документалки с нестандартными названиями найдены через TMDB
- [ ] Торренты в Transmission показывают правильные пути
---
## Шаг 11 — Jellyfin: настройка библиотек
Jellyfin уже работает на Кракене: http://192.168.1.14:8096
### Категории библиотек:
| Библиотека | Тип | Путь | Язык |
|------------|-----|------|------|
| Детские мультфильмы | Animated Movies | /media/cartoons | ru |
| Детские сериалы | Series | /media/cartoons-series | ru |
| Документальные | Movies | /media/documentaries | ru |
| Сериалы | TV Shows | /media/series | ru |
| Фильмы | Movies | /media/movies | ru |
### Настройки библиотеки:
- **Metadata Language:** Russian (или auto-detect)
- **NFO reading:** включить (Kodi-compatible NFO)
- **Sort by:** Date Added (поле из NFO), Rating, Title
### Сортировка и фильтрация в UI (Jellyfin):
- Детские: отдельная коллекция "Детям" → мультфильмы + детские сериалы
- Можно использовать **Collections** для кастомных подборок
- **Recently Added** — показывает по дате скачки (metadata: dateadded в NFO)
- Рейтинг: IMDB/TMDB — парсится из NFO `<rating>` тег
---
## Шаг 12 — Transmission download-complete hook
Transmission вызывает скрипт при завершении скачки:
```bash
# settings.json Transmission (в /config/):
# "script-torrent-done-enabled": true,
# "script-torrent-done-filename": "/usr/local/bin/on-download-complete.sh"
```
### `/usr/local/bin/on-download-complete.sh` (внутри контейнера):
```bash
#!/bin/bash
# Transmission передаёт переменные:
# TR_TORRENT_NAME, TR_TORRENT_DIR, TR_TORRENT_ID, TR_APP_VERSION
logger "Transmission: download complete: $TR_TORRENT_NAME"
# Запустить media-sync для этой конкретной папки
docker run --rm \
-v /srv/.../media:/media \
-v /srv/.../docker/media-sync:/config \
kodi-media-sync:arm64 \
--path "$TR_TORRENT_DIR/$TR_TORRENT_NAME"
```
> ⚠️ Скрипт должен быть доступен изнутри контейнера Transmission, или монтируется туда.
> Альтернатива: Transmission вызывает скрипт на хосте → хост запускает docker run.
---
## Шаг 13 — Hermes cron на Кракене
**Добавить через Hermes на Кракене:**
```
Крон: каждые 12 часов
Задача: запустить kodi-media-sync --dry-run на папке downloads, прислать отчёт в Telegram
```
### Cron job (добавить в Hermes Кракена):
```
Schedule: 0 */12 * * *
Prompt: Запусти kodi-media-sync на Кракене:
sudo docker run --rm \
-v /srv/.../media:/media \
-v /srv/.../docker/media-sync:/config \
kodi-media-sync:arm64 --dry-run
Пришли отчёт: что было распознано, что нет.
```
---
## Шаг 14 — Rutracker / торрент-поиск скилл
**Добавить скилл Кракену:**
- Поиск по Rutracker (может требовать авторизацию)
- Альтернативы: Jackett (агрегатор) + Prowlarr
- Добавление торрента в Transmission через RPC API
**Jackett** (рекомендуется как агрегатор):
```yaml
# docker-compose для Jackett:
services:
jackett:
image: linuxserver/jackett
ports:
- "9117:9117"
volumes:
- /srv/.../docker/jackett:/config
```
Jackett поддерживает Rutracker + сотни других tracker-ов, отдаёт unified API.
---
## Шаг 15 — Музыка: скачка + sync с TrueNAS
### Структура:
```
Kraken: /media/music/
├── [Artist]/
│ └── [Album]/
│ └── *.mp3
TrueNAS: /mnt/RED_2TB/storage/Music/ (master copy)
```
### kodi-media-sync — расширение для музыки:
- Идентификация: MusicBrainz / Beets
- Тегирование через `beets` (python tool)
- Sync Kraken → TrueNAS через rsync
### Jellyfin музыкальная библиотека:
- Тип: Music
- Путь: /media/music
- Плеер: Jellyfin + Finamp на Android
---
## Технические детали
### HTPC
- IP: 192.168.1.86
- SSH: `ssh -i ~/.ssh/id_rsa bazzite@192.168.1.86`
- Data mount: `/run/media/bazzite/Data/`
- WoL MAC: `B0:6E:BF:60:6D:64`
### Крaken
- IP: 192.168.1.14
- SSH: `ssh -i ~/.ssh/id_rsa kraken@192.168.1.14`
- HDD: `/srv/dev-disk-by-uuid-49e8f586-3839-4c5d-a1e1-58bfc3579ade/`
- Jellyfin: http://192.168.1.14:8096
- Transmission: http://192.168.1.14:9091
### kodi-media-sync
- Исходники: `~/Developer/kodi-media-sync/` (Mac)
- Язык: Swift 5.9+
- Зависимости: swift-argument-parser
- Target: Linux ARM64 (aarch64)
### TrueNAS (Taiga)
- SSH: `truenas_admin@mallexxx.duckdns.org`
- Transmission config: `/mnt/RED_2TB/docker/transmission/`
- Downloads: `/mnt/RED_2TB/storage/Downloads/`
---
## Журнал выполнения
### 2026-05-13 — Планирование
- Изучена структура: HTPC (Bazzite), Кракен (OMV/Docker), TrueNAS (Taiga)
- Найден проект kodi-media-sync: scaffold (Config + Path + пустой MediaSync)
- Jellyfin + Transmission уже есть на Кракене в `/home/kraken/media/`
- Transmission на TrueNAS: конфиг в `/mnt/RED_2TB/docker/transmission/`, скачки в `storage/Downloads/`
- Plan создан в Obsidian
### TODO (следующий сеанс)
- [ ] Разбудить HTPC, исследовать структуру медиа (шаг 1)
- [ ] Решить вопрос сна HTPC (шаг 2)
- [ ] Запустить rsync HTPC → Крaken (шаг 3)