705 lines
27 KiB
Markdown
705 lines
27 KiB
Markdown
---
|
||
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) | ✅ | Data: мультфильмы(229G) сериалы(116G) movies(673G) bbc(284G). kodi/movies/ — NFO+симлинки уже есть |
|
||
| 2 — Wake HTPC + prevent sleep | ✅ | sleep/suspend/hibernate masked (systemctl mask). loginctl linger=yes. Процессы выживают после SSH |
|
||
| 3 — Копирование медиа HTPC → Kraken | 🔄 | 4x rsync via systemd-run --user, активны. ~1.3TB total |
|
||
| 4 — Transmission на Кракене | 🔲 | уже есть контейнер в /home/kraken/media/ |
|
||
| 5 — Перенос torrent-базы с HTPC | ✅ | 7 торрентов Windows Transmission добавлены в Крaken Transmission (paused), пути обновить после rsync |
|
||
| 6 — MediaFilesScraper: изучить + настроить | ✅ | Полный Swift 6 SPM. media-pipeline CLI. Пропатчен для Linux (AVFoundation stub, Swift 6 existential fix) |
|
||
| 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, сон заблокирован: `systemctl mask` sleep/suspend + `loginctl enable-linger bazzite`
|
||
- 4x rsync запущены через `systemd-run --user` (выживают без SSH): ~1.3TB
|
||
- Torrent-база Windows найдена (7 торрентов, `D:/Movies`), скопирована в `/tmp/transmission-backup/`
|
||
- Изучен MediaFilesScraper: полный Swift 6.0 SPM, бинарь `media-pipeline`, команды scan/resolve/apply/sync
|
||
- Пропатчен AVFoundationMediaMetadataReader для Linux (`#if canImport(AVFoundation)` + stub)
|
||
- `Package.swift`: платформа понижена до macOS(.v14) для совместимости
|
||
- `Dockerfile.kraken` + `docker-compose.kraken.yml` написаны
|
||
- `config.kraken.json` готов: Transmission RPC, TMDB/KP, все провайдеры, `dry_run=true`
|
||
- macOS build запущен в фоне для проверки компиляции
|
||
|
||
### 2026-05-13 — Сессия 2 (Docker build + resolve)
|
||
|
||
**Docker build `media-pipeline:kraken`**
|
||
- `.dockerignore` добавлен — исключает `.build/` (6.7GB), OOM устранён
|
||
- Colima: 24GB RAM, 8 CPU; `--memory=20g -j 1`
|
||
- Linux-фиксы: `#if os(Linux)` для CF-encoding (RutrackerAPI), `FoundationNetworking` в 3 файлах
|
||
- Образ `media-pipeline:kraken` (78MB) собран и задеплоен на Кракен ✅
|
||
|
||
**Resolve dry run (первый)**
|
||
- 6 region'ов; **1 resolved**: Black Mirror S06E01 → `seriesEpisodesNumbered`, support=0.90 ✅
|
||
- Проблема: `ProviderSearchStrategy.aggregateCandidates` — `originalVariant` выбирался по non-ASCII (кириллица), которая давала 0 результатов от TMDB
|
||
- **Фикс**: `originalVariant` → первый вариант с реальными результатами; high-confidence (≥0.85) single-variant принимается без unique-result требования
|
||
- Все 6 ProviderSearchStrategy тестов прошли, образ пересобран и задеплоен
|
||
- `on-download-complete.sh` установлен, прописан в Transmission settings ✅
|
||
|
||
**Текущее состояние**
|
||
- rsync идёт (~19-20GB из сотен GB по категориям)
|
||
- Следующий dry run — когда rsync скопирует больше файлов с правильной структурой подпапок
|
||
|
||
### Что осталось
|
||
- [ ] Дождаться rsync (~1.3TB), прогнать полный dry run
|
||
- [ ] torrent-set-location для 7 перенесённых торрентов (после rsync)
|
||
- [ ] Настроить Jellyfin библиотеки (шаг 11)
|
||
- [ ] Hermes cron на Кракене (шаг 13)
|
||
- [ ] Rutracker-скилл (шаг 14)
|