Files
stemify/ios/Stemify/App/AppGraph.swift
T

81 lines
3.6 KiB
Swift

import Foundation
/// Hand-wired singletons, shared by the phone UI, CarPlay and Siri.
@MainActor
final class AppGraph {
static let shared = AppGraph()
let settings: Settings
let net: Connectivity
/// Library calls: kept on disk and served from there when the server is unreachable.
let apiHttp: Http
/// Same disk cache, but away from home it reads only from disk instead of waiting on LAN timeouts.
let carHttp: Http
/// Media ranges; MediaCache is the cache. Long timeout covers server-side Opus transcodes.
let mediaSession: URLSession
let plex: PlexClient
let reach: HomeReach
let carPlex: PlexClient
let stems: StemServer
let cache: MediaCache
let eq: EqController
let playback: PlaybackManager
let stemPlaylists: StemPlaylists
let downloads: Downloads
let coverage: StemCoverage
let nowPlaying: NowPlaying
let radio: WebRadio
let car: CarLibrary
private init() {
let fm = FileManager.default
let support = fm.urls(for: .applicationSupportDirectory, in: .userDomainMask)[0]
let caches = fm.urls(for: .cachesDirectory, in: .userDomainMask)[0]
try? fm.createDirectory(at: support, withIntermediateDirectories: true)
settings = Settings()
net = Connectivity()
apiHttp = Http(connectTimeout: 6, readTimeout: 30, offlineCache: caches.appendingPathComponent("http"))
carHttp = Http(connectTimeout: 6, readTimeout: 30, offlineCache: caches.appendingPathComponent("http"))
let m = URLSessionConfiguration.default
m.timeoutIntervalForRequest = 90
m.timeoutIntervalForResource = 24 * 3600
m.urlCache = nil
m.requestCachePolicy = .reloadIgnoringLocalCacheData
mediaSession = URLSession(configuration: m)
plex = PlexClient(http: apiHttp, settings: settings)
reach = HomeReach(settings: settings, net: net)
let reach = reach
carHttp.forceCache = { !reach.lastKnown }
carPlex = PlexClient(http: carHttp, settings: settings)
stems = StemServer(http: apiHttp, settings: settings, dir: support)
// Media lives outside Caches' purge-anytime rules and out of iCloud backups.
var media = support.appendingPathComponent("media", isDirectory: true)
try? fm.createDirectory(at: media, withIntermediateDirectories: true)
var rv = URLResourceValues()
rv.isExcludedFromBackup = true
try? media.setResourceValues(rv)
let settings = settings
cache = MediaCache(dir: media, session: mediaSession) { Int64(settings.cacheLimitGb) << 30 }
eq = EqController(dir: support)
stemPlaylists = StemPlaylists(dir: support)
playback = PlaybackManager(settings: settings, plex: plex, stems: stems, cache: cache, eq: eq, dir: support)
downloads = Downloads(settings: settings, plex: plex, stems: stems, cache: cache, net: net, dir: support)
coverage = StemCoverage(plex: plex, stems: stems, settings: settings, dir: support)
radio = WebRadio(pm: playback)
nowPlaying = NowPlaying(pm: playback, plex: plex, radio: radio, settings: settings)
radio.nowPlaying = nowPlaying
car = CarLibrary(plex: carPlex, reach: reach, downloads: downloads, stems: stems, pm: playback)
// Mix names and the rotation show on the lock screen and in the widgets, so redraw those when the Stem Editor or Appearance change them.
let np = nowPlaying, pm = playback
settings.onChange("acapella", "presets", "presetOrder", "hiddenPresets") {
np.refresh()
WidgetBridge.shared.publish(pm, settings)
}
WidgetBridge.shared.start(self)
}
}