56 lines
2.2 KiB
Swift
56 lines
2.2 KiB
Swift
|
|
import Foundation
|
||
|
|
|
||
|
|
/// The persisted sub/dub choices: a global default plus per-series overrides.
|
||
|
|
/// Keyed by normalized show name so a choice survives across episodes and app
|
||
|
|
/// restarts. anime defaults to `sub` at resolve time even without an override.
|
||
|
|
public struct TrackPreferences: Codable, Sendable, Equatable {
|
||
|
|
public var globalDefault: DubSub
|
||
|
|
public var perSeries: [String: DubSub]
|
||
|
|
|
||
|
|
public init(globalDefault: DubSub = .dub, perSeries: [String: DubSub] = [:]) {
|
||
|
|
self.globalDefault = globalDefault
|
||
|
|
self.perSeries = perSeries
|
||
|
|
}
|
||
|
|
|
||
|
|
static func key(_ name: String) -> String {
|
||
|
|
name.lowercased().trimmingCharacters(in: .whitespaces)
|
||
|
|
}
|
||
|
|
|
||
|
|
/// Resolve the effective choice: explicit per-series override wins; otherwise
|
||
|
|
/// anime defaults to `sub`; otherwise the global default (`dub` — native audio,
|
||
|
|
/// no forced subs, which is right for English-language content).
|
||
|
|
public func choice(series: String?, category: String?) -> DubSub {
|
||
|
|
if let series, let explicit = perSeries[Self.key(series)] { return explicit }
|
||
|
|
if category == "anime" { return .sub }
|
||
|
|
return globalDefault
|
||
|
|
}
|
||
|
|
|
||
|
|
public mutating func setSeries(_ name: String, _ choice: DubSub) {
|
||
|
|
perSeries[Self.key(name)] = choice
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// JSON store at `~/.local/state/tv-anarchy/track-prefs.json`. Mirrors
|
||
|
|
/// PlayerStatusCache's load/save shape.
|
||
|
|
public enum TrackPreferenceStore {
|
||
|
|
private static var url: URL {
|
||
|
|
FileManager.default.homeDirectoryForCurrentUser
|
||
|
|
.appendingPathComponent(".local/state/tv-anarchy/track-prefs.json")
|
||
|
|
}
|
||
|
|
|
||
|
|
public static func load() -> TrackPreferences {
|
||
|
|
guard let data = try? Data(contentsOf: url),
|
||
|
|
let prefs = try? JSONDecoder().decode(TrackPreferences.self, from: data) else {
|
||
|
|
return TrackPreferences()
|
||
|
|
}
|
||
|
|
return prefs
|
||
|
|
}
|
||
|
|
|
||
|
|
public static func save(_ prefs: TrackPreferences) {
|
||
|
|
guard let data = try? JSONEncoder().encode(prefs) else { return }
|
||
|
|
try? FileManager.default.createDirectory(at: url.deletingLastPathComponent(),
|
||
|
|
withIntermediateDirectories: true)
|
||
|
|
try? data.write(to: url, options: .atomic)
|
||
|
|
}
|
||
|
|
}
|