Beim Umpacken wird nach der Tonspur gefragt, nicht geraten
Mein Fehler, und ein vermeidbarer. Beim Umpacken legt der Server genau eine Tonspur in die Datei, und welche, hat bisher allein die Abwägung entschieden — bei einer Aufnahme mit Audiodeskription die falsche. Nach dem Herunterladen gibt es nichts mehr zu korrigieren; drei Gigabyte Datenvolumen waren weg. Wo eine Spur verlorengeht, wird jetzt gefragt. Nur dort: bei einer Datei, die der Systemplayer ohnehin öffnet, kommt alles mit, und eine Frage ohne Folgen ist nur ein Klick mehr. **Der Vorschlag kommt aus dem, was schon bekannt ist.** Die gemerkte Sprache der Serie zuerst, dann die Serieneinstellung, dann die allgemeine — dieselbe Abwägung wie beim Abspielen (`AudioTrackChooser`), über denselben Weg. Sie ist jetzt Vorschlag statt Entscheidung und steht als „· empfohlen" dabei. Beim Stapel aus der Mehrfachauswahl wird einmal gefragt, nicht je Folge: die Folgen einer Staffel sind gleich aufgebaut, und zwanzigmal dieselbe Frage wäre keine Wahl, sondern eine Prüfung der Geduld. **Was am Server gemessen wurde, und warum es nicht besser geht:** - `static=true` liefert die Datei unverändert — alle Spuren, aber Matroska; die Magie am Dateianfang ist `1a45dfa3`, auch wenn im Pfad `.mp4` steht. - `stream.mp4` bildet genau eine Tonspur ab. - Die HLS-Liste des Servers führt **eine** Variante und **keine** `EXT-X-MEDIA`-Tonspuren. Mehrere Tonspuren offline gibt dieser Server auf keinem seiner Wege her. Das liegt nicht an MP4 — das kann mehrere — und nicht an AVFoundation, sondern am Transcoder, der je Sitzung eine Spur abbildet. iOS und tvOS bauen. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
24d80e5c95
commit
93695dc332
@@ -43,6 +43,8 @@ struct QuickPlayTile<Card: View>: View {
|
||||
/// nachgeladen werden. Ein eigenes `Bool` daneben wäre ein zweiter
|
||||
/// Zustand, der mit diesem gleichziehen müsste.
|
||||
@State private var downloadChoice: MediaItem?
|
||||
/// Stufe steht, Tonspur fehlt — siehe `DownloadButton`.
|
||||
@State private var pendingQuality: (item: MediaItem, quality: DownloadQuality)?
|
||||
|
||||
/// Was die umgebende Seite tun soll, wenn sich am Server etwas geändert
|
||||
/// hat. Siehe `ItemActionEntries`.
|
||||
@@ -147,13 +149,40 @@ struct QuickPlayTile<Card: View>: View {
|
||||
if let ziel = downloadChoice {
|
||||
let wahl = DownloadQualityChoice(item: ziel, backend: session.backend)
|
||||
ForEach(wahl.available) { quality in
|
||||
Button(wahl.label(for: quality)) { enqueue(ziel, quality: quality) }
|
||||
Button(wahl.label(for: quality)) { chose(ziel, quality: quality) }
|
||||
}
|
||||
}
|
||||
Button("action.cancel", role: .cancel) {}
|
||||
} message: {
|
||||
Text("downloads.quality.hint")
|
||||
}
|
||||
.confirmationDialog(
|
||||
Text("downloads.audio.title"),
|
||||
isPresented: Binding(
|
||||
get: { pendingQuality != nil },
|
||||
set: { if !$0 { pendingQuality = nil } }
|
||||
),
|
||||
titleVisibility: .visible
|
||||
) {
|
||||
if let offen = pendingQuality {
|
||||
let spuren = offen.item.preferredVersion?.files.first?.audioStreams ?? []
|
||||
let empfohlen = offen.item.preferredVersion?.files.first.flatMap {
|
||||
service.preferredAudioStream(in: $0, of: offen.item)
|
||||
}
|
||||
ForEach(spuren) { stream in
|
||||
Button(
|
||||
stream == empfohlen
|
||||
? String(localized: "downloads.audio.recommended \(stream.name)")
|
||||
: stream.name
|
||||
) {
|
||||
enqueue(offen.item, quality: offen.quality, audioStream: stream)
|
||||
}
|
||||
}
|
||||
}
|
||||
Button("action.cancel", role: .cancel) {}
|
||||
} message: {
|
||||
Text("downloads.audio.hint")
|
||||
}
|
||||
.alert(
|
||||
Text("error.title"),
|
||||
isPresented: Binding(get: { errorMessage != nil }, set: { if !$0 { errorMessage = nil } })
|
||||
@@ -232,12 +261,24 @@ struct QuickPlayTile<Card: View>: View {
|
||||
downloadChoice = (try? await session.backend?.item(id: item.id)) ?? item
|
||||
}
|
||||
|
||||
private func enqueue(_ ziel: MediaItem, quality: DownloadQuality) {
|
||||
let service = DownloadService(
|
||||
backend: session.backend, coordinator: downloads, languages: languages
|
||||
)
|
||||
private var service: DownloadService {
|
||||
DownloadService(backend: session.backend, coordinator: downloads, languages: languages)
|
||||
}
|
||||
|
||||
/// Nach der Stufe: fragen, wenn beim Umpacken eine Tonspur verlorenginge.
|
||||
private func chose(_ ziel: MediaItem, quality: DownloadQuality) {
|
||||
downloadChoice = nil
|
||||
if service.needsAudioChoice(for: ziel, quality: quality) {
|
||||
pendingQuality = (ziel, quality)
|
||||
} else {
|
||||
enqueue(ziel, quality: quality, audioStream: nil)
|
||||
}
|
||||
}
|
||||
|
||||
private func enqueue(_ ziel: MediaItem, quality: DownloadQuality, audioStream: MediaStream?) {
|
||||
pendingQuality = nil
|
||||
do {
|
||||
_ = try service.download(ziel, quality: quality)
|
||||
_ = try service.download(ziel, quality: quality, audioStream: audioStream)
|
||||
} catch {
|
||||
errorMessage = error.explanation
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user