mirror of
				https://github.com/yattee/yattee.git
				synced 2025-10-31 12:41:57 +00:00 
			
		
		
		
	improved subtitle handling
- fix subtitle disabling not working - make subtitle adding/removing async - make subtitle menu non blocking Signed-off-by: Toni Förster <toni.foerster@gmail.com>
This commit is contained in:
		| @@ -23,15 +23,14 @@ final class MPVBackend: PlayerBackend { | ||||
|  | ||||
|     var stream: Stream? | ||||
|     var video: Video? | ||||
|     var captions: Captions? { didSet { | ||||
|         guard let captions else { | ||||
|             if client?.areSubtitlesAdded == true { | ||||
|                 client?.removeSubs() | ||||
|     var captions: Captions? { | ||||
|         didSet { | ||||
|             Task { | ||||
|                 await handleCaptionsChange() | ||||
|             } | ||||
|             return | ||||
|         } | ||||
|         addSubTrack(captions.url) | ||||
|     }} | ||||
|     } | ||||
|  | ||||
|     var currentTime: CMTime? | ||||
|  | ||||
|     var loadedVideo = false | ||||
| @@ -617,10 +616,14 @@ final class MPVBackend: PlayerBackend { | ||||
|     } | ||||
|  | ||||
|     func addSubTrack(_ url: URL) { | ||||
|         if client?.areSubtitlesAdded == true { | ||||
|             client?.removeSubs() | ||||
|         Task { | ||||
|             if let areSubtitlesAdded = client?.areSubtitlesAdded { | ||||
|                 if await areSubtitlesAdded() { | ||||
|                     await client?.removeSubs() | ||||
|                 } | ||||
|             } | ||||
|             await client?.addSubTrack(url) | ||||
|         } | ||||
|         client?.addSubTrack(url) | ||||
|     } | ||||
|  | ||||
|     func setVideoToAuto() { | ||||
| @@ -684,6 +687,17 @@ final class MPVBackend: PlayerBackend { | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private func handleCaptionsChange() async { | ||||
|         guard let captions else { | ||||
|             if let isSubtitlesAdded = client?.areSubtitlesAdded, await isSubtitlesAdded() { | ||||
|                 await client?.removeSubs() | ||||
|             } | ||||
|             return | ||||
|         } | ||||
|  | ||||
|         addSubTrack(captions.url) | ||||
|     } | ||||
|  | ||||
|     private func handlePropertyChange(_ name: String, _ property: mpv_event_property) { | ||||
|         switch name { | ||||
|         case "pause": | ||||
|   | ||||
| @@ -349,21 +349,15 @@ final class MPVClient: ObservableObject { | ||||
|         return Int(fps.rounded()) | ||||
|     } | ||||
|  | ||||
|     var areSubtitlesAdded: Bool { | ||||
|     func areSubtitlesAdded() async -> Bool { | ||||
|         guard !mpv.isNil else { return false } | ||||
|  | ||||
|         // Retrieve the number of tracks | ||||
|         let trackCount = getInt("track-list/count") | ||||
|         let trackCount = await Task(operation: { getInt("track-list/count") }).value | ||||
|         guard trackCount > 0 else { return false } | ||||
|  | ||||
|         for index in 0 ..< trackCount { | ||||
|             // Get the type of each track | ||||
|             if let trackType = getString("track-list/\(index)/type"), trackType == "sub" { | ||||
|                 // Check if the subtitle track is currently selected | ||||
|                 let selected = getInt("track-list/\(index)/selected") | ||||
|                 if selected == 1 { | ||||
|                     return true | ||||
|                 } | ||||
|             if let trackType = await Task(operation: { getString("track-list/\(index)/type") }).value, trackType == "sub" { | ||||
|                 return true | ||||
|             } | ||||
|         } | ||||
|         return false | ||||
| @@ -539,12 +533,16 @@ final class MPVClient: ObservableObject { | ||||
|         command("video-add", args: [url.absoluteString]) | ||||
|     } | ||||
|  | ||||
|     func addSubTrack(_ url: URL) { | ||||
|         command("sub-add", args: [url.absoluteString]) | ||||
|     func addSubTrack(_ url: URL) async { | ||||
|         await Task { | ||||
|             command("sub-add", args: [url.absoluteString]) | ||||
|         }.value | ||||
|     } | ||||
|  | ||||
|     func removeSubs() { | ||||
|         command("sub-remove") | ||||
|     func removeSubs() async { | ||||
|         await Task { | ||||
|             command("sub-remove") | ||||
|         }.value | ||||
|     } | ||||
|  | ||||
|     func setVideoToAuto() { | ||||
|   | ||||
| @@ -5,6 +5,8 @@ struct ControlsOverlay: View { | ||||
|     @ObservedObject private var player = PlayerModel.shared | ||||
|     private var model = PlayerControlsModel.shared | ||||
|  | ||||
|     @State private var availableCaptions: [Captions] = [] | ||||
|     @State private var isLoadingCaptions = true | ||||
|     @State private var contentSize: CGSize = .zero | ||||
|  | ||||
|     @Default(.showMPVPlaybackStats) private var showMPVPlaybackStats | ||||
| @@ -335,7 +337,6 @@ struct ControlsOverlay: View { | ||||
|                     Image(systemName: "text.bubble") | ||||
|                     if let captions = captionsBinding.wrappedValue, | ||||
|                        let language = LanguageCodes(rawValue: captions.code) | ||||
|  | ||||
|                     { | ||||
|                         Text("\(language.description.capitalized) (\(language.rawValue))") | ||||
|                             .foregroundColor(.accentColor) | ||||
| @@ -380,17 +381,16 @@ struct ControlsOverlay: View { | ||||
|             .contextMenu { | ||||
|                 Button("Disabled") { captionsBinding.wrappedValue = nil } | ||||
|  | ||||
|                 ForEach(player.currentVideo?.captions ?? []) { caption in | ||||
|                 ForEach(availableCaptions) { caption in | ||||
|                     Button(caption.description) { captionsBinding.wrappedValue = caption } | ||||
|                 } | ||||
|                 Button("Cancel", role: .cancel) {} | ||||
|             } | ||||
|  | ||||
|         #endif | ||||
|     } | ||||
|  | ||||
|     @ViewBuilder private var captionsPicker: some View { | ||||
|         let captions = player.currentVideo?.captions ?? [] | ||||
|         let captions = availableCaptions | ||||
|         Picker("Captions", selection: captionsBinding) { | ||||
|             if captions.isEmpty { | ||||
|                 Text("Not available").tag(Captions?.none) | ||||
| @@ -402,6 +402,31 @@ struct ControlsOverlay: View { | ||||
|             } | ||||
|         } | ||||
|         .disabled(captions.isEmpty) | ||||
|         .onAppear { | ||||
|             loadCaptions() | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private func loadCaptions() { | ||||
|         isLoadingCaptions = true | ||||
|  | ||||
|         // Fetch captions asynchronously | ||||
|         Task { | ||||
|             let fetchedCaptions = await fetchCaptions() | ||||
|             await MainActor.run { | ||||
|                 // Update state on the main thread | ||||
|                 self.availableCaptions = fetchedCaptions | ||||
|                 self.isLoadingCaptions = false | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private func fetchCaptions() async -> [Captions] { | ||||
|         // Access currentVideo from the main actor context | ||||
|         await MainActor.run { | ||||
|             // Safely access the main actor-isolated currentVideo property | ||||
|             player.currentVideo?.captions ?? [] | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private var captionsBinding: Binding<Captions?> { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Toni Förster
					Toni Förster