iOS: episodes kept on the phone play with no connection (#425)
A WKWebView runs no service worker, so the page's Keep button (#412) was not shown in the app and everything played from the server. Now the page asks the app to keep the file (keep, unkeep, clearKept), and the app answers with what it holds (kept, keepFailed) whether or not anything plays. The app fetches with a background URLSession, so a download goes on with the app closed, into Application Support (not backed up; the files can be fetched again), and Playback plays from the file when there is one. The DeadAir copy is kept under its own path, as the browser keeps it. Places and finishes reached offline wait in an outbox, newest per address, and go when the network is back. Checked in the simulator against a local server: kept /media/42 and /media/42/deadair, then with the server refusing /media, a fresh launch played each from the phone and asked the server for nothing. The page itself still needs a connection to open (#435). Deploy the app (build 6) before the page: a new page in an old app shows a Keep button nothing answers. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -75,7 +75,10 @@ final class Playback: NSObject {
|
||||
AVURLAssetHTTPCookiesKey: HTTPCookieStorage.shared.cookies(for: item.url) ?? [],
|
||||
]
|
||||
if Credentials.isSet { options["AVURLAssetHTTPHeaderFieldsKey"] = Credentials.headers }
|
||||
let asset = AVURLAsset(url: item.url, options: options)
|
||||
// One kept on the phone plays from there, connection or not (#425). The page asks for it
|
||||
// as `/media/42?offline`; the path alone is what it was kept under.
|
||||
let asset = Offline.shared.store.fileURL(for: item.url.path).map { AVURLAsset(url: $0) }
|
||||
?? AVURLAsset(url: item.url, options: options)
|
||||
let playerItem = AVPlayerItem(asset: asset)
|
||||
let player = AVPlayer(playerItem: playerItem)
|
||||
player.volume = volume
|
||||
@@ -177,7 +180,10 @@ final class Playback: NSObject {
|
||||
if let d = duration { body["duration"] = Int(d.rounded()) }
|
||||
// DeadAir's copy runs on a shorter clock; the server has to know which one this is.
|
||||
if item.url.path.contains("/deadair") { body["deadair"] = item.enc }
|
||||
Task { await request("POST", entryPath(item, "position"), body) }
|
||||
let path = entryPath(item, "position")
|
||||
// Not arrived, kept for when the connection is back: offline, the ten-second retry would
|
||||
// only fail again, and the place reached on the last pause would be lost.
|
||||
Task { if await request("POST", path, body) == nil { Outbox.add(path: path, json: body) } }
|
||||
}
|
||||
|
||||
// MARK: - as it plays
|
||||
@@ -204,8 +210,9 @@ final class Playback: NSObject {
|
||||
private func markRead() {
|
||||
guard !markedRead, let item else { return }
|
||||
markedRead = true
|
||||
let path = entryPath(item, "flags")
|
||||
Task {
|
||||
await request("POST", entryPath(item, "flags"), ["read": true])
|
||||
if await request("POST", path, ["read": true]) == nil { Outbox.add(path: path, json: ["read": true]) }
|
||||
await Badge.refresh()
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user