tv-anarchy/Sources/TVAnarchyCore/Metadata/MetaModels.swift
Natalie 92b38b1bae refactor(tv-anarchy): rename PlumTV→TVAnarchy and land session work
Renames Sources/PlumTV→TVAnarchy and PlumTVCore→TVAnarchyCore (the rename
the auto-commit service couldn't stage — it git-add'd the old, now-gone
paths and aborted every cycle), and commits the accumulated work:

- Library: black-built index fast path (LibraryIndex + scanFromIndex) with
  NFS-walk fallback; incremental --add on download-complete; mtime staleness
  gate; loose-file series-collapse fix; determinate scan/index progress.
- Cover art: keyless TVmaze cartoon-vs-live-action disambiguation (type/year).
- Player: sleep timer (timed + end-of-episode); visibility-gated polling.
- Home: Continue Watching cover art + live refresh; Recently Added; adult gate.
- Logs: multi-line selection + copy; truncated giant tx-list errors.
- Hover previews (opt-in) via black ffmpeg + scp.

Also gitignores foreign project trees (governor/mcp/fleet/recommender) that
sit in this directory but belong to their own repos.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 22:04:22 -07:00

71 lines
2.7 KiB
Swift

import Foundation
/// Deterministic fields pulled from a filename by regex (no network).
public struct ParsedFilename: Codable, Sendable, Equatable {
public var title: String
public var year: Int?
public var season: Int?
public var episode: Int?
public var quality: String? // 2160p / 1080p / 720p / 480p
public var codec: String? // x265 / x264 / HEVC / XviD
public var releaseSource: String? // BluRay / WEB-DL / HDTV /
public init(title: String, year: Int? = nil, season: Int? = nil, episode: Int? = nil,
quality: String? = nil, codec: String? = nil, releaseSource: String? = nil) {
self.title = title; self.year = year; self.season = season; self.episode = episode
self.quality = quality; self.codec = codec; self.releaseSource = releaseSource
}
}
/// What `media_rec.enrich` returns (snake_case JSON). All optional the CLI
/// degrades to a partial result when TMDB/IMDb aren't configured.
public struct EnrichResult: Decodable, Sendable, Equatable {
public var tmdb_id: Int?
public var media_type: String?
public var title: String?
public var year: Int?
public var overview: String?
public var poster_url: String?
public var vote_average: Double?
public var vote_count: Int?
public var imdb_rating: Double?
public var imdb_votes: Int?
public var genres: [String]?
public var tmdb_error: String?
public var imdb_error: String?
}
/// The `.meta` sidecar payload: the parse plus whatever enrichment resolved.
/// Cached per-path on plum, mirrored next to the file on black opportunistically.
public struct MediaMeta: Codable, Sendable, Equatable {
public var path: String
public var parsed: ParsedFilename
public var resolvedTitle: String?
public var mediaType: String?
public var overview: String?
public var posterURL: String?
public var voteAverage: Double?
public var voteCount: Int?
public var imdbRating: Double?
public var imdbVotes: Int?
public var genres: [String]?
public var enrichedAt: Date?
public init(path: String, parsed: ParsedFilename) {
self.path = path; self.parsed = parsed
}
/// Fold a (possibly partial) enrich result into this meta.
public mutating func apply(_ e: EnrichResult, at now: Date) {
resolvedTitle = e.title ?? resolvedTitle
mediaType = e.media_type ?? mediaType
overview = e.overview ?? overview
posterURL = e.poster_url ?? posterURL
voteAverage = e.vote_average ?? voteAverage
voteCount = e.vote_count ?? voteCount
imdbRating = e.imdb_rating ?? imdbRating
imdbVotes = e.imdb_votes ?? imdbVotes
genres = e.genres ?? genres
enrichedAt = now
}
}