Add loading external subtitle files for media-source playback

Adds a "Load subtitle from file…" row to the Subtitles section on iOS
(document picker) and macOS (open panel), available when playing files
from local folder, SMB, or WebDAV sources. The picked file is copied
into the per-video temp subtitle directory, registered as a selectable
Caption (displayed by filename), and activated through the existing
loadCaption flow. The Subtitles tab and captions control button now
also appear for media-source files without any subtitles.
This commit is contained in:
Arkadiusz Fal
2026-07-30 23:59:26 +02:00
parent 6a0fe2fbbf
commit 8faf20c9e9
8 changed files with 238 additions and 4 deletions

View File

@@ -11,7 +11,7 @@ struct QualitySelectorView: View {
// MARK: - Environment
@Environment(\.dismiss) var dismiss
@Environment(\.appEnvironment) private var appEnvironment
@Environment(\.appEnvironment) var appEnvironment
// MARK: - Properties
@@ -79,6 +79,9 @@ struct QualitySelectorView: View {
@State var selectedTab: QualitySelectorTab = .video
@State var selectedVideoStream: Stream?
@State var selectedAudioStream: Stream?
#if os(iOS)
@State var showingSubtitleFilePicker = false
#endif
// MARK: - Settings Access
@@ -114,12 +117,22 @@ struct QualitySelectorView: View {
if (hasVideoOnlyStreams && !audioStreams.isEmpty) || embeddedAudioTracks.count > 1 {
tabs.append(.audio)
}
if !captions.isEmpty || !embeddedSubtitleTracks.isEmpty {
if !captions.isEmpty || !embeddedSubtitleTracks.isEmpty || canLoadExternalSubtitles {
tabs.append(.subtitles)
}
return tabs
}
/// Whether the "Load subtitle from file" row is available: media-source
/// playback (local folder/SMB/WebDAV) on platforms with a file picker.
var canLoadExternalSubtitles: Bool {
#if os(tvOS)
return false
#else
return appEnvironment?.playerService.state.currentVideo?.isFromMediaSource == true
#endif
}
/// Navigation title based on mode
var navigationTitle: String {
if showTabPicker {
@@ -144,7 +157,8 @@ struct QualitySelectorView: View {
/// Whether streams are empty (not loading, but no streams available)
var hasNoStreams: Bool {
if !showTabPicker && initialTab == .subtitles {
return !isLoading && captions.isEmpty && embeddedSubtitleTracks.isEmpty && !isPlayingDownloadedContent
return !isLoading && captions.isEmpty && embeddedSubtitleTracks.isEmpty
&& !isPlayingDownloadedContent && !canLoadExternalSubtitles
}
return !isLoading && streams.isEmpty && !isPlayingDownloadedContent
}
@@ -326,6 +340,13 @@ struct QualitySelectorView: View {
subtitlesDetailContent
}
}
#if os(iOS)
.sheet(isPresented: $showingSubtitleFilePicker) {
SubtitleFilePickerView { url in
handlePickedSubtitleFile(url)
}
}
#endif
.onAppear {
selectedVideoStream = currentStream
// In audio mode the audio track IS the main stream