98 lines
5.8 KiB
Markdown
98 lines
5.8 KiB
Markdown
---
|
|
title: Media Pipeline — Roadmap
|
|
aliases:
|
|
- "Медиа пайплайн роадмап"
|
|
- "Media Pipeline roadmap"
|
|
- "tracker parsers roadmap"
|
|
created: '2026-05-17'
|
|
updated: '2026-05-24'
|
|
status: active
|
|
tags:
|
|
- media-pipeline
|
|
- rutracker
|
|
- rutor
|
|
- nnm-club
|
|
related:
|
|
- "[[personal/projects/media-pipeline-file-routing]]"
|
|
- "[[family/projects/media-toolbox-kraken]]"
|
|
---
|
|
# Media Pipeline — Roadmap
|
|
|
|
## ✅ Сделано
|
|
|
|
### Шаг A — Transmission flow + Rutracker парсинг
|
|
- `TrackerPageParserRegistry` — dispatch по `url.host`
|
|
- `RutrackerPageParser` — CP1251/iconv, SwiftSoup, жанры из заголовка топика, KP/IMDb IDs
|
|
- `TrackerMediaKind` — enum: movie/series/cartoon/documentary/music/audiobook/game/book/unknown
|
|
- `extractMediaKind` — детект по `BB.catId` / `FORUM_ID` на странице Rutracker (100+ forum IDs)
|
|
- `TorrentPageMetadataFact.mediaKind` + `TorrentLocator.torrentId` — пробрасывается через весь стек
|
|
- `QueryBuilderStrategy` — `torrentTitle` как предпочитаемый source для поиска
|
|
- Fallback NFO при unresolved + `torrentPageMetadata.hasRichData`
|
|
|
|
### Шаг B — Структура парсеров других трекеров
|
|
- `RutorPageParser`, `NNMClubPageParser`, `PirateBayPageParser`, `NyaaPageParser` — структура реализована
|
|
- Требуют верификации на живых HTML (нет тестовых fixture)
|
|
|
|
### Шаг C — DirectoryPolicy + transmissionMove
|
|
- `DirectoryPolicy` / `MatchPolicy` / `MoveStrategy` в конфиге — backward-compatible
|
|
- `FileAction.transmissionMove(torrentId:, from:, to:)` — Codable
|
|
- `ApplyPhase` — async execute, RPC → fallback filesystem
|
|
- `buildMovieActions` — читает policy, `needsSymlink`, `needsNFO`, `effectiveOutputDir`
|
|
- `kindKey` из реального `TrackerMediaKind` → `destination_by_kind`
|
|
- `transmissionMove` когда есть `torrentId`, иначе `move`
|
|
- `config.json` на Кракене — `directory_policies` для всех директорий
|
|
- Canonical маркер `.media-pipeline-canonical` для music/books/games пишется в `output` директорию рядом с файлом
|
|
|
|
## ⚠️ Частично работает
|
|
|
|
### Фильмы из downloads
|
|
- `.mkv/.mp4` → scanner видит → регион → `transmissionMove` → `/media/movies/` → canonical marker → повторный run скипает ✅
|
|
- `TrackerMediaKind` детектится по forum_id → правильная `destination_by_kind` ✅
|
|
|
|
### Музыка/книги/игры из downloads
|
|
- Scanner не видит `.mp3/.flac/.epub/.zip` — нет `videoExtensions` для аудио ❌
|
|
- Регион не создаётся → `buildMovieActions` не вызывается → файл остаётся в downloads
|
|
|
|
## 📋 Следующие шаги
|
|
|
|
### Шаг D — Audio/non-video scanner (приоритет)
|
|
Чтобы музыка/книги/игры из downloads реально перекладывались:
|
|
|
|
1. **`AudioClassifier`** — `isAudioFile()` для `.mp3/.flac/.m4a/.ogg/.aac/.wav/.opus`
|
|
2. **`NonVideoRegionBuilder`** — создаёт регионы для директорий без video но с audio/doc файлами
|
|
3. **`FileScanner`** — при наличии `TrackerMediaKind != .movie/.series` (из Transmission метаданных) создавать регион даже без video
|
|
4. **`buildAudioActions`** в `MediaFinalizer` — move + NFO рядом, без symlink, canonical marker рядом
|
|
5. **Альтернатива (проще)**: unsorted fallback — отдельный pass по `unsorted_dir` через Transmission API, для торрентов без региона вызывать `torrent-set-location` на основе `mediaKind` из страницы трекера
|
|
|
|
### Шаг E — Верификация парсеров
|
|
- HTML fixture тесты для rutor, nnm-club на живых страницах
|
|
- Проверить `extractMediaKind` на реальных forum_id
|
|
|
|
### Шаг F — Series из downloads
|
|
- `buildSeriesActions` сейчас не читает policy → нет move для сериалов из downloads
|
|
- Нужно прокинуть `torrentURLFacts`/`torrentPageFacts` аналогично movie
|
|
|
|
## Ключевые питфоллы
|
|
|
|
- CP1251: `/usr/bin/iconv` через temp files — единственный способ на Linux
|
|
- `extractGenres` — из заголовка топика `[YEAR, жанр, ...]`, не из тела поста
|
|
- `transmissionMove` генерируется только если scanner создал регион (нужен video файл)
|
|
- Canonical marker для music/books: `output == source dir` → повторный run скипает через `agentResolvedInLibrary`
|
|
- `allOutputDirs` в PipelineRunner не включает `directoryPolicies[].output` → нужно обновить
|
|
|
|
## Файлы
|
|
|
|
- `Sources/MediaSources/APIs/TrackerParsers.swift` — парсеры + registry + `extractMediaKind`
|
|
- `Sources/MediaDomain/Facts/TorrentPageMetadataFact.swift` — `TrackerMediaKind`, поля
|
|
- `Sources/MediaDomain/Facts/TorrentInfoURLFact.swift` — `torrentId: Int?`
|
|
- `Sources/MediaSources/Protocol/TorrentInfoProvider.swift` — `TorrentLocator.torrentId`
|
|
- `Sources/MediaPipeline/Config/Config.swift` — `DirectoryPolicy`, `MatchPolicy`, `MoveStrategy`
|
|
- `Sources/MediaPipeline/Apply/FileAction.swift` — `transmissionMove` case
|
|
- `Sources/MediaPipeline/Apply/ApplyPhase.swift` — async execute, RPC fallback
|
|
- `Sources/MediaPipeline/Apply/MediaFinalizer.swift` — policy-aware routing, torrent extractors
|
|
|
|
## Связанные заметки
|
|
|
|
- [[personal/projects/media-pipeline-file-routing]]
|
|
- [[family/projects/media-toolbox-kraken]]
|