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>
49 lines
2.2 KiB
Swift
49 lines
2.2 KiB
Swift
import Foundation
|
|
|
|
/// User-facing app preferences that aren't host/franchise specific. Persisted to
|
|
/// `~/.local/state/tv-anarchy/settings.json`. Kept deliberately small — one file,
|
|
/// tolerant decode, sensible defaults — so adding a preference is one field here
|
|
/// plus its wiring, no migration.
|
|
public struct AppSettings: Codable, Sendable, Equatable {
|
|
/// When false (the default), the Home screen hides everything from the `porn`
|
|
/// media dir — its category rails, plus any adult item in Continue Watching or
|
|
/// Recently Added. Independent of the Library tab's own porn browse toggle, so
|
|
/// you can deliberately browse adult content in Library without it leaking onto
|
|
/// the landing screen.
|
|
public var surfaceAdultOnHome: Bool
|
|
/// When true, hovering a poster plays a short muted preview clip (built on
|
|
/// black, seeked past the intro, cached). Off by default — it triggers ffmpeg
|
|
/// work on black, so it's opt-in.
|
|
public var hoverPreviews: Bool
|
|
|
|
public init(surfaceAdultOnHome: Bool = false, hoverPreviews: Bool = false) {
|
|
self.surfaceAdultOnHome = surfaceAdultOnHome
|
|
self.hoverPreviews = hoverPreviews
|
|
}
|
|
|
|
public init(from decoder: Decoder) throws {
|
|
let c = try decoder.container(keyedBy: CodingKeys.self)
|
|
surfaceAdultOnHome = try c.decodeIfPresent(Bool.self, forKey: .surfaceAdultOnHome) ?? false
|
|
hoverPreviews = try c.decodeIfPresent(Bool.self, forKey: .hoverPreviews) ?? false
|
|
}
|
|
}
|
|
|
|
public enum SettingsStore {
|
|
private static var url: URL {
|
|
FileManager.default.homeDirectoryForCurrentUser
|
|
.appendingPathComponent(".local/state/tv-anarchy/settings.json")
|
|
}
|
|
|
|
public static func load() -> AppSettings {
|
|
guard let d = try? Data(contentsOf: url),
|
|
let s = try? JSONDecoder().decode(AppSettings.self, from: d) else { return AppSettings() }
|
|
return s
|
|
}
|
|
|
|
public static func save(_ s: AppSettings) {
|
|
guard let d = try? JSONEncoder().encode(s) else { return }
|
|
try? FileManager.default.createDirectory(at: url.deletingLastPathComponent(),
|
|
withIntermediateDirectories: true)
|
|
try? d.write(to: url, options: .atomic)
|
|
}
|
|
}
|