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>
32 lines
1.4 KiB
Swift
32 lines
1.4 KiB
Swift
import Foundation
|
|
|
|
/// Per-franchise overrides: movies the user unlinked from a series, and a manual
|
|
/// chronological order (when release-year ≠ in-universe order). Keyed by the
|
|
/// series' rootDir. Persisted to `~/.local/state/tv-anarchy/franchise.json`.
|
|
public struct FranchisePrefs: Codable, Sendable, Equatable {
|
|
/// franchise (series rootDir) → movie rootDirs the user removed from it.
|
|
public var unlinked: [String: [String]]
|
|
/// franchise (series rootDir) → item rootDirs in manual order (series + movies).
|
|
public var order: [String: [String]]
|
|
|
|
public init(unlinked: [String: [String]] = [:], order: [String: [String]] = [:]) {
|
|
self.unlinked = unlinked; self.order = order
|
|
}
|
|
}
|
|
|
|
public enum FranchiseStore {
|
|
private static var url: URL {
|
|
FileManager.default.homeDirectoryForCurrentUser
|
|
.appendingPathComponent(".local/state/tv-anarchy/franchise.json")
|
|
}
|
|
public static func load() -> FranchisePrefs {
|
|
guard let d = try? Data(contentsOf: url),
|
|
let p = try? JSONDecoder().decode(FranchisePrefs.self, from: d) else { return FranchisePrefs() }
|
|
return p
|
|
}
|
|
public static func save(_ p: FranchisePrefs) {
|
|
guard let d = try? JSONEncoder().encode(p) else { return }
|
|
try? FileManager.default.createDirectory(at: url.deletingLastPathComponent(), withIntermediateDirectories: true)
|
|
try? d.write(to: url, options: .atomic)
|
|
}
|
|
}
|