Heruntergeladenes lag auf dem Gerät und war nirgends zu sehen
Downloads gab es nur im Downloads-Bereich. Wer wissen wollte, was im Flugzeug läuft, musste zwei Listen vergleichen: die Mediathek und die Downloads. Jetzt sind sie eine Reihe auf der Startseite, tragen in jeder Kachel eine Marke, und in der Mediathek gibt es „Nur Heruntergeladene" — der Filter fragt den Server gar nicht erst, weil der nicht weiss, was auf diesem Gerät liegt. Dabei kam heraus, dass Downloads nie ein Bild mitbrachten: der Dateiname dafür stand im Modell, gesetzt hat ihn niemand. Neue holen es mit, alten wird es beim nächsten Start nachgereicht. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
fb8ad1c831
commit
77593105de
@@ -422,6 +422,40 @@ public final class DownloadCoordinator {
|
||||
return fileStore.url(forFileName: fileName)
|
||||
}
|
||||
|
||||
/// Das lokale Plakat eines Downloads — `nil`, wenn keines geholt wurde.
|
||||
///
|
||||
/// **Weil eine Reihe ohne Bilder keine Reihe ist.** Ohne Verbindung gibt
|
||||
/// es keine Adresse, von der ein Plakat nachzuladen wäre; was nicht beim
|
||||
/// Herunterladen mitkam, bleibt eine graue Fläche.
|
||||
public func artworkURL(forRatingKey key: String) -> URL? {
|
||||
guard let name = items.first(where: { $0.ratingKey == key })?.artworkFileName,
|
||||
fileStore.exists(fileName: name)
|
||||
else { return nil }
|
||||
return fileStore.url(forFileName: name)
|
||||
}
|
||||
|
||||
/// Holt das Plakat zu einem Eintrag nach und legt es ab.
|
||||
///
|
||||
/// **Beim Anlegen, nicht erst beim Fertigwerden.** Die Liste zeigt den
|
||||
/// Eintrag, sobald er in der Warteschlange steht; bis dahin wäre sonst
|
||||
/// nichts zu sehen. Es sind ein paar Kilobyte.
|
||||
public func fetchArtwork(for ratingKey: String, from url: URL) async {
|
||||
guard let item = items.first(where: { $0.ratingKey == ratingKey }),
|
||||
item.artworkFileName == nil
|
||||
else { return }
|
||||
|
||||
guard let (daten, antwort) = try? await URLSession.shared.data(from: url),
|
||||
(antwort as? HTTPURLResponse).map({ (200..<300).contains($0.statusCode) }) ?? true,
|
||||
!daten.isEmpty
|
||||
else { return }
|
||||
|
||||
let name = fileStore.artworkFileName(forRatingKey: ratingKey)
|
||||
guard fileStore.store(daten, as: name) != nil else { return }
|
||||
|
||||
item.artworkFileName = name
|
||||
save()
|
||||
}
|
||||
|
||||
public func offlineMedia(forRatingKey key: String) -> OfflineMedia? {
|
||||
guard let data = items.first(where: { $0.ratingKey == key })?.offlineMediaData else { return nil }
|
||||
return try? JSONDecoder().decode(OfflineMedia.self, from: data)
|
||||
|
||||
@@ -58,6 +58,29 @@ public struct DownloadFileStore: Sendable {
|
||||
return "\(key).\(ext)"
|
||||
}
|
||||
|
||||
/// Der Name des Plakats zu einem Titel.
|
||||
///
|
||||
/// **Eine eigene Datei, kein Anhängsel am Film.** Sie ist ein paar
|
||||
/// Kilobyte gross und wird gebraucht, solange der Eintrag steht — auch
|
||||
/// während der Film noch lädt und noch gar keine Datei hat.
|
||||
public func artworkFileName(forRatingKey key: String) -> String { "\(key).bild" }
|
||||
|
||||
/// Legt ein geholtes Plakat ab. Schlägt es fehl, gibt es eben keines.
|
||||
///
|
||||
/// **Wirft nicht.** Ein Download ohne Bild ist ein Download; ein
|
||||
/// Download, der am Bild scheitert, wäre keiner.
|
||||
@discardableResult
|
||||
public func store(_ data: Data, as name: String) -> URL? {
|
||||
let ziel = url(forFileName: name)
|
||||
do {
|
||||
try createRootIfNeeded()
|
||||
try data.write(to: ziel, options: .atomic)
|
||||
return ziel
|
||||
} catch {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
/// Verschiebt die fertige Datei aus dem temporären Ordner an ihren Platz.
|
||||
///
|
||||
/// Verschieben, nicht kopieren: iOS löscht die temporäre Datei, sobald der
|
||||
|
||||
Reference in New Issue
Block a user