From 2d3aec54b73c9e888d274c1da80e90d62e3efad1 Mon Sep 17 00:00:00 2001 From: Alexey Martemyanov Date: Sun, 17 May 2026 11:52:46 +0600 Subject: [PATCH] 2026-05-17 media-pipeline tracker parsers doc: genres fix, pitfalls, status update --- .../media-pipeline-tracker-parsers.md | 98 +++++++++++++++++++ 1 file changed, 98 insertions(+) create mode 100644 personal/projects/media-pipeline-tracker-parsers.md diff --git a/personal/projects/media-pipeline-tracker-parsers.md b/personal/projects/media-pipeline-tracker-parsers.md new file mode 100644 index 00000000..8771bc76 --- /dev/null +++ b/personal/projects/media-pipeline-tracker-parsers.md @@ -0,0 +1,98 @@ +--- +title: Media Pipeline — Multi-Tracker Support +created: '2026-05-17' +updated: '2026-05-17' +status: active +tags: + - media-pipeline + - rutracker + - rutor + - nnm-club +--- +# Media Pipeline — Multi-Tracker Support + +## Текущее состояние + +✅ Реализовано и задеплоено на Kraken: + +- `TrackerPageParserRegistry` — dispatch по `url.host`, парсеры: Rutracker, Rutor, NNMClub, PirateBay, Nyaa +- `RutrackerPageParser` — CP1251 decode через `/usr/bin/iconv`, SwiftSoup парсинг +- Жанры извлекаются из `[...]` в заголовке топика, страны фильтруются +- KP/IMDb ID extraction работает +- `TorrentSourceStrategy` использует registry вместо прямого вызова `RutrackerAPI` +- Fallback NFO при unresolved + `torrentPageMetadata.hasRichData` + +## Архитектура + +### TrackerPageParser protocol + +```swift +public protocol TrackerPageParser: Sendable { + var supportedHosts: [String] { get } + func parse(data: Data, url: URL) throws -> TorrentPageMetadata +} +``` + +### TrackerPageParserRegistry + +```swift +public struct TrackerPageParserRegistry: Sendable { + public static let defaults: [TrackerPageParser] = [ + RutrackerPageParser(), + RutorPageParser(), + NNMClubPageParser(), + PirateBayPageParser(), + NyaaPageParser(), + ] + public func parser(for url: URL) -> TrackerPageParser? +} +``` + +## Парсеры по трекерам + +### RutrackerPageParser ✅ +- Encoding: Windows-1251 (через `/usr/bin/iconv` temp files — swift-corelibs-foundation не поддерживает CP1251 на Linux) +- Title selector: `#topic-title`, `h1.maintitle`, `a.topictitle` +- **Genres: из заголовка топика `[YEAR, жанр1, жанр2, ..., TECH-TAG]`** — не из поста +- Страны фильтруются через `countryNames: Set` (30+ стран RU+EN) +- Poster: первый img в `div.post_body` не из rutracker UI +- IDs: `imdb.com/title/tt\d+`, `kinopoisk.ru/film/\d+` + +### RutorPageParser ✅ (структура реализована) +- Encoding: UTF-8 +- Title: `h1.topic-header` / `div#topic-title` +- Genres: паттерн `Жанр:` в тексте + +### NNMClubPageParser ✅ (структура реализована) +- Encoding: Windows-1251 (тот же iconv путь) +- Title: `h1.maintitle` / `a.maintitle` + +### PirateBayPageParser ✅ (структура реализована) +- Encoding: UTF-8 +- Title: `

` +- Нет IMDb/KP ссылок обычно → только title/year из названия торрента + +### NyaaPageParser ✅ (структура реализована) +- Encoding: UTF-8 +- Аниме: title из `h3.panel-title`, AniDB ID если есть + +## Ключевые питфоллы + +- `extractGenres` должен парсить из **заголовка топика** (`#topic-title`), а не из тела поста — Rutracker кодирует жанры в `[YEAR, жанр, ...]` в title +- CP1251 decode: использовать `/usr/bin/iconv` через temp files — единственный способ на Linux +- Кеш хранит сырые байты (binary) — `grep` по кешу не работает для CP1251 файлов +- `TrackerParsers.swift` — боевой файл (используется в продакшне); `RutrackerAPI.swift` — legacy, параллельно существует + +## Файлы + +- `Sources/MediaSources/APIs/TrackerParsers.swift` — все парсеры + registry (боевой) +- `Sources/MediaSources/APIs/RutrackerAPI.swift` — legacy парсер (используется в части flow) +- `Sources/MediaSources/Providers/TorrentSourceStrategy.swift` — dispatch через registry +- `Sources/MediaDomain/Facts/TorrentPageMetadataFact.swift` — модель: title, year, genres, posterURL, description, externalLinks + +## Roadmap + +- [ ] Шаг B — новые типы медиа: игры, музыка, книги (следующий) +- [ ] Реальные HTML fixture тесты для каждого трекера (rutor, nnm-club) +- [ ] Верификация RutorPageParser/NNMClubPageParser на живых торрентах +- [ ] `MediaKind` detection по категории торрента (напр. "Игры PC" → `.game`)