Add iOS app with CarPlay and Siri
SwiftUI port of the Android app under ios/, with CarPlay browse and Now Playing, Siri play-media intents, and a build-ipa.sh script that makes an unsigned IPA for sideloading. README gets an iOS section and the vibecoded disclaimer. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
45bc0eefe0
commit
fdf9e970b2
45 files changed
+9822
No files matched your search
@@ -0,0 +1,48 @@
|
||||
import Foundation
|
||||
import UIKit
|
||||
|
||||
/// Album art: a memory cache over a big disk URLCache, so downloaded albums keep their covers
|
||||
/// offline. Stands in for Coil on Android.
|
||||
final class ArtLoader: @unchecked Sendable {
|
||||
static let shared = ArtLoader()
|
||||
|
||||
private let memory = NSCache<NSURL, UIImage>()
|
||||
private let session: URLSession
|
||||
private let lock = NSLock()
|
||||
private var inflight: [URL: Task<UIImage?, Never>] = [:]
|
||||
|
||||
init() {
|
||||
let dir = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask)[0].appendingPathComponent("art", isDirectory: true)
|
||||
let cfg = URLSessionConfiguration.default
|
||||
cfg.urlCache = URLCache(memoryCapacity: 16 << 20, diskCapacity: 512 << 20, directory: dir)
|
||||
cfg.requestCachePolicy = .returnCacheDataElseLoad
|
||||
cfg.timeoutIntervalForRequest = 20
|
||||
session = URLSession(configuration: cfg)
|
||||
memory.totalCostLimit = 64 << 20
|
||||
}
|
||||
|
||||
func cached(_ url: URL) -> UIImage? { memory.object(forKey: url as NSURL) }
|
||||
|
||||
func image(_ url: URL) async -> UIImage? {
|
||||
if let img = cached(url) { return img }
|
||||
if let t = lock.withLock({ inflight[url] }) { return await t.value }
|
||||
let t = Task<UIImage?, Never> { [session] in
|
||||
guard let (data, resp) = try? await session.data(from: url),
|
||||
(resp as? HTTPURLResponse).map({ (200..<300).contains($0.statusCode) }) ?? true,
|
||||
let img = UIImage(data: data) else { return nil }
|
||||
let decoded = await img.byPreparingForDisplay() ?? img
|
||||
return decoded
|
||||
}
|
||||
lock.withLock { inflight[url] = t }
|
||||
let img = await t.value
|
||||
lock.withLock { inflight[url] = nil }
|
||||
if let img {
|
||||
memory.setObject(img, forKey: url as NSURL, cost: Int(img.size.width * img.size.height * img.scale * img.scale * 4))
|
||||
}
|
||||
return img
|
||||
}
|
||||
|
||||
func prefetch(_ url: URL) {
|
||||
Task.detached(priority: .utility) { _ = await self.image(url) }
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user