Files
obsidian-vault/personal/projects/media-pipeline-tracker-parsers.md
T

4.3 KiB

title, created, updated, status, tags
title created updated status tags
Media Pipeline — Multi-Tracker Support 2026-05-17 2026-05-17 active
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

public protocol TrackerPageParser: Sendable {
    var supportedHosts: [String] { get }
    func parse(data: Data, url: URL) throws -> TorrentPageMetadata
}

TrackerPageParserRegistry

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<String> (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: <h1 id="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)