mirror of
https://github.com/tapframe/NuvioStreaming.git
synced 2026-05-01 21:24:52 +00:00
ksplayer sub rendering fix
This commit is contained in:
parent
9f461f7091
commit
985d01d5a9
10 changed files with 102 additions and 99 deletions
|
|
@ -132,7 +132,7 @@ class MPVView @JvmOverloads constructor(
|
||||||
MPVLib.setOptionString("sub-auto", "fuzzy")
|
MPVLib.setOptionString("sub-auto", "fuzzy")
|
||||||
MPVLib.setOptionString("sub-visibility", "yes")
|
MPVLib.setOptionString("sub-visibility", "yes")
|
||||||
MPVLib.setOptionString("sub-font-size", "48")
|
MPVLib.setOptionString("sub-font-size", "48")
|
||||||
MPVLib.setOptionString("sub-pos", "95")
|
MPVLib.setOptionString("sub-pos", "100")
|
||||||
MPVLib.setOptionString("sub-color", "#FFFFFFFF")
|
MPVLib.setOptionString("sub-color", "#FFFFFFFF")
|
||||||
MPVLib.setOptionString("sub-border-size", "3")
|
MPVLib.setOptionString("sub-border-size", "3")
|
||||||
MPVLib.setOptionString("sub-border-color", "#FF000000")
|
MPVLib.setOptionString("sub-border-color", "#FF000000")
|
||||||
|
|
@ -146,15 +146,15 @@ class MPVView @JvmOverloads constructor(
|
||||||
|
|
||||||
MPVLib.setOptionString("sub-codepage", "auto")
|
MPVLib.setOptionString("sub-codepage", "auto")
|
||||||
|
|
||||||
MPVLib.setOptionString("osc", "no")
|
|
||||||
MPVLib.setOptionString("osd-level", "1")
|
|
||||||
|
|
||||||
MPVLib.setOptionString("blend-subtitles", "no")
|
MPVLib.setOptionString("blend-subtitles", "no")
|
||||||
MPVLib.setOptionString("sub-use-margins", "no")
|
MPVLib.setOptionString("sub-use-margins", "yes")
|
||||||
MPVLib.setOptionString("sub-ass-override", "scale")
|
MPVLib.setOptionString("sub-ass-override", "force")
|
||||||
MPVLib.setOptionString("sub-scale", "1.0")
|
MPVLib.setOptionString("sub-scale", "1.0")
|
||||||
MPVLib.setOptionString("sub-fix-timing", "yes")
|
MPVLib.setOptionString("sub-fix-timing", "yes")
|
||||||
|
|
||||||
|
MPVLib.setOptionString("osc", "no")
|
||||||
|
MPVLib.setOptionString("osd-level", "1")
|
||||||
|
|
||||||
MPVLib.setOptionString("sid", "auto")
|
MPVLib.setOptionString("sid", "auto")
|
||||||
|
|
||||||
MPVLib.setOptionString("terminal", "no")
|
MPVLib.setOptionString("terminal", "no")
|
||||||
|
|
|
||||||
|
|
@ -246,20 +246,15 @@ class KSPlayerView: UIView {
|
||||||
}
|
}
|
||||||
|
|
||||||
private func setupPlayerCallbacks() {
|
private func setupPlayerCallbacks() {
|
||||||
// Configure KSOptions (use static defaults where required)
|
// Configure KSOptions
|
||||||
KSOptions.isAutoPlay = false
|
KSOptions.isAutoPlay = false
|
||||||
#if targetEnvironment(simulator)
|
|
||||||
// Simulator: disable hardware decode and MEPlayer to avoid VT/Vulkan issues
|
|
||||||
KSOptions.hardwareDecode = false
|
|
||||||
KSOptions.asynchronousDecompression = false
|
|
||||||
KSOptions.secondPlayerType = nil
|
|
||||||
#else
|
|
||||||
// PERFORMANCE OPTIMIZATION: Enable asynchronous decompression globally
|
|
||||||
// This ensures the global default is correct for all player instances
|
|
||||||
KSOptions.asynchronousDecompression = true
|
KSOptions.asynchronousDecompression = true
|
||||||
// Ensure hardware decode is enabled globally
|
|
||||||
KSOptions.hardwareDecode = true
|
KSOptions.hardwareDecode = true
|
||||||
#endif
|
|
||||||
|
// Set default subtitle font size - use standard size for readability
|
||||||
|
SubtitleModel.textFontSize = 20.0 // Moderate size that works on most devices
|
||||||
|
SubtitleModel.textBold = false
|
||||||
|
|
||||||
print("KSPlayerView: [PERF] Global settings: asyncDecomp=\(KSOptions.asynchronousDecompression), hwDecode=\(KSOptions.hardwareDecode)")
|
print("KSPlayerView: [PERF] Global settings: asyncDecomp=\(KSOptions.asynchronousDecompression), hwDecode=\(KSOptions.hardwareDecode)")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -298,21 +293,14 @@ class KSPlayerView: UIView {
|
||||||
|
|
||||||
// Choose player pipeline based on format
|
// Choose player pipeline based on format
|
||||||
let isMKV = uri.lowercased().contains(".mkv")
|
let isMKV = uri.lowercased().contains(".mkv")
|
||||||
#if targetEnvironment(simulator)
|
|
||||||
if isMKV {
|
if isMKV {
|
||||||
// MKV not supported on AVPlayer in Simulator and MEPlayer is disabled
|
// Prefer MEPlayer (FFmpeg) for MKV
|
||||||
sendEvent("onError", ["error": "MKV playback is not supported in the iOS Simulator. Test on a real device."])
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
if isMKV {
|
|
||||||
// Prefer MEPlayer (FFmpeg) for MKV on device
|
|
||||||
KSOptions.firstPlayerType = KSMEPlayer.self
|
KSOptions.firstPlayerType = KSMEPlayer.self
|
||||||
KSOptions.secondPlayerType = nil
|
KSOptions.secondPlayerType = nil
|
||||||
} else {
|
} else {
|
||||||
KSOptions.firstPlayerType = KSAVPlayer.self
|
KSOptions.firstPlayerType = KSAVPlayer.self
|
||||||
KSOptions.secondPlayerType = KSMEPlayer.self
|
KSOptions.secondPlayerType = KSMEPlayer.self
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
// Create KSPlayerResource with validated URL
|
// Create KSPlayerResource with validated URL
|
||||||
let resource = KSPlayerResource(url: url, options: createOptions(with: headers), name: "Video")
|
let resource = KSPlayerResource(url: url, options: createOptions(with: headers), name: "Video")
|
||||||
|
|
@ -376,15 +364,9 @@ class KSPlayerView: UIView {
|
||||||
|
|
||||||
// PERFORMANCE OPTIMIZATION: Hardware decode explicitly enabled
|
// PERFORMANCE OPTIMIZATION: Hardware decode explicitly enabled
|
||||||
// Ensure VideoToolbox hardware acceleration is always preferred for non-simulator
|
// Ensure VideoToolbox hardware acceleration is always preferred for non-simulator
|
||||||
#if targetEnvironment(simulator)
|
// Hardware decode and async decompression
|
||||||
options.hardwareDecode = false
|
options.hardwareDecode = true
|
||||||
options.asynchronousDecompression = false
|
|
||||||
#else
|
|
||||||
options.hardwareDecode = true // Explicitly enable hardware decode
|
|
||||||
// PERFORMANCE OPTIMIZATION: Asynchronous decompression (CRITICAL)
|
|
||||||
// Offloads VideoToolbox decompression to background threads, preventing main thread stalls
|
|
||||||
options.asynchronousDecompression = true
|
options.asynchronousDecompression = true
|
||||||
#endif
|
|
||||||
|
|
||||||
// HDR handling: Let KSPlayer automatically detect content's native dynamic range
|
// HDR handling: Let KSPlayer automatically detect content's native dynamic range
|
||||||
// Setting destinationDynamicRange to nil allows KSPlayer to use the content's actual HDR/SDR mode
|
// Setting destinationDynamicRange to nil allows KSPlayer to use the content's actual HDR/SDR mode
|
||||||
|
|
@ -557,22 +539,21 @@ class KSPlayerView: UIView {
|
||||||
}
|
}
|
||||||
|
|
||||||
func setTextTrack(_ trackId: Int) {
|
func setTextTrack(_ trackId: Int) {
|
||||||
print("KSPlayerView: [SET TEXT TRACK] Starting setTextTrack with trackId: \(trackId)")
|
NSLog("KSPlayerView: [SET TEXT TRACK] Starting setTextTrack with trackId: %d", trackId)
|
||||||
|
|
||||||
// Wait slightly longer than the 1-second delay for subtitle data source connection
|
// Small delay to ensure player is ready
|
||||||
// This ensures srtControl.addSubtitle(dataSouce:) has been called in VideoPlayerView
|
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { [weak self] in
|
||||||
DispatchQueue.main.asyncAfter(deadline: .now() + 1.2) { [weak self] in
|
|
||||||
guard let self = self else {
|
guard let self = self else {
|
||||||
print("KSPlayerView: [SET TEXT TRACK] self is nil, aborting")
|
NSLog("KSPlayerView: [SET TEXT TRACK] self is nil, aborting")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
print("KSPlayerView: [SET TEXT TRACK] Executing delayed track selection")
|
NSLog("KSPlayerView: [SET TEXT TRACK] Executing track selection")
|
||||||
|
|
||||||
if let player = self.playerView.playerLayer?.player {
|
if let player = self.playerView.playerLayer?.player {
|
||||||
let textTracks = player.tracks(mediaType: .subtitle)
|
let textTracks = player.tracks(mediaType: .subtitle)
|
||||||
print("KSPlayerView: Available text tracks count: \(textTracks.count)")
|
NSLog("KSPlayerView: Available text tracks count: %d", textTracks.count)
|
||||||
print("KSPlayerView: Requested text track ID: \(trackId)")
|
NSLog("KSPlayerView: Requested text track ID: %d", trackId)
|
||||||
|
|
||||||
// First try to find track by trackID (proper way)
|
// First try to find track by trackID (proper way)
|
||||||
var selectedTrack: MediaPlayerTrack? = nil
|
var selectedTrack: MediaPlayerTrack? = nil
|
||||||
|
|
@ -582,84 +563,57 @@ class KSPlayerView: UIView {
|
||||||
if let track = textTracks.first(where: { Int($0.trackID) == trackId }) {
|
if let track = textTracks.first(where: { Int($0.trackID) == trackId }) {
|
||||||
selectedTrack = track
|
selectedTrack = track
|
||||||
trackIndex = textTracks.firstIndex(where: { $0.trackID == track.trackID }) ?? -1
|
trackIndex = textTracks.firstIndex(where: { $0.trackID == track.trackID }) ?? -1
|
||||||
print("KSPlayerView: Found text track by trackID \(trackId) at index \(trackIndex)")
|
NSLog("KSPlayerView: Found text track by trackID %d at index %d", trackId, trackIndex)
|
||||||
}
|
}
|
||||||
// Fallback: treat trackId as array index
|
// Fallback: treat trackId as array index
|
||||||
else if trackId >= 0 && trackId < textTracks.count {
|
else if trackId >= 0 && trackId < textTracks.count {
|
||||||
selectedTrack = textTracks[trackId]
|
selectedTrack = textTracks[trackId]
|
||||||
trackIndex = trackId
|
trackIndex = trackId
|
||||||
print("KSPlayerView: Found text track by array index \(trackId) (fallback)")
|
NSLog("KSPlayerView: Found text track by array index %d (fallback)", trackId)
|
||||||
}
|
}
|
||||||
|
|
||||||
if let track = selectedTrack {
|
if let track = selectedTrack {
|
||||||
print("KSPlayerView: Selecting text track \(trackId) (index: \(trackIndex)): '\(track.name)' (ID: \(track.trackID))")
|
NSLog("KSPlayerView: Selecting text track %d (index: %d): '%@' (ID: %d)", trackId, trackIndex, track.name, track.trackID)
|
||||||
|
|
||||||
// First disable all tracks to ensure only one is active
|
// Disable all tracks first
|
||||||
for t in textTracks {
|
for t in textTracks {
|
||||||
t.isEnabled = false
|
t.isEnabled = false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use KSPlayer's select method which properly handles track selection
|
// Enable the selected track
|
||||||
|
track.isEnabled = true
|
||||||
|
|
||||||
|
// Use KSPlayer's select method to update player state
|
||||||
player.select(track: track)
|
player.select(track: track)
|
||||||
|
|
||||||
// Sync srtControl with player track selection
|
// CRITICAL: Cast MediaPlayerTrack to SubtitleInfo and set on srtControl
|
||||||
// Find the corresponding SubtitleInfo in srtControl and select it
|
// FFmpegAssetTrack conforms to SubtitleInfo via extension
|
||||||
if let matchingSubtitleInfo = self.playerView.srtControl.subtitleInfos.first(where: { subtitleInfo in
|
if let subtitleInfo = track as? SubtitleInfo {
|
||||||
// Try to match by name or track ID
|
self.playerView.srtControl.selectedSubtitleInfo = subtitleInfo
|
||||||
subtitleInfo.name.lowercased() == track.name.lowercased() ||
|
NSLog("KSPlayerView: Set srtControl.selectedSubtitleInfo to track '%@'", track.name)
|
||||||
subtitleInfo.subtitleID == String(track.trackID)
|
|
||||||
}) {
|
|
||||||
print("KSPlayerView: Found matching SubtitleInfo: \(matchingSubtitleInfo.name) (ID: \(matchingSubtitleInfo.subtitleID))")
|
|
||||||
self.playerView.srtControl.selectedSubtitleInfo = matchingSubtitleInfo
|
|
||||||
print("KSPlayerView: Set srtControl.selectedSubtitleInfo to: \(matchingSubtitleInfo.name)")
|
|
||||||
} else {
|
} else {
|
||||||
print("KSPlayerView: No matching SubtitleInfo found for track '\(track.name)' (ID: \(track.trackID))")
|
NSLog("KSPlayerView: Warning - track could not be cast to SubtitleInfo")
|
||||||
print("KSPlayerView: Available SubtitleInfos:")
|
|
||||||
for (index, info) in self.playerView.srtControl.subtitleInfos.enumerated() {
|
|
||||||
print("KSPlayerView: [\(index)] name='\(info.name)', subtitleID='\(info.subtitleID)'")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure subtitle views are visible after selection
|
// Ensure subtitle views are visible
|
||||||
self.playerView.subtitleLabel.isHidden = false
|
self.playerView.subtitleLabel.isHidden = false
|
||||||
self.playerView.subtitleBackView.isHidden = false
|
self.playerView.subtitleBackView.isHidden = false
|
||||||
|
|
||||||
// Debug: Check the enabled state of all tracks after selection
|
NSLog("KSPlayerView: Successfully selected and enabled text track %d", trackId)
|
||||||
print("KSPlayerView: Track states after selection:")
|
|
||||||
for (index, t) in textTracks.enumerated() {
|
|
||||||
print("KSPlayerView: Track \(index): ID=\(t.trackID), Name='\(t.name)', Enabled=\(t.isEnabled)")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verify the selection worked after a delay
|
|
||||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
|
|
||||||
let tracksAfter = player.tracks(mediaType: .subtitle)
|
|
||||||
print("KSPlayerView: Verification after subtitle selection:")
|
|
||||||
for (index, track) in tracksAfter.enumerated() {
|
|
||||||
print("KSPlayerView: Track \(index) (ID: \(track.trackID)) isEnabled: \(track.isEnabled)")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Also verify srtControl selection
|
|
||||||
if let selectedInfo = self.playerView.srtControl.selectedSubtitleInfo {
|
|
||||||
print("KSPlayerView: srtControl.selectedSubtitleInfo: \(selectedInfo.name) (ID: \(selectedInfo.subtitleID))")
|
|
||||||
} else {
|
|
||||||
print("KSPlayerView: srtControl.selectedSubtitleInfo is nil")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
print("KSPlayerView: Successfully selected text track \(trackId)")
|
|
||||||
} else if trackId == -1 {
|
} else if trackId == -1 {
|
||||||
// Disable all subtitles
|
// Disable all subtitles
|
||||||
for track in textTracks { track.isEnabled = false }
|
for track in textTracks {
|
||||||
// Clear srtControl selection and hide subtitle views
|
track.isEnabled = false
|
||||||
|
}
|
||||||
self.playerView.srtControl.selectedSubtitleInfo = nil
|
self.playerView.srtControl.selectedSubtitleInfo = nil
|
||||||
self.playerView.subtitleLabel.isHidden = true
|
self.playerView.subtitleLabel.isHidden = true
|
||||||
self.playerView.subtitleBackView.isHidden = true
|
self.playerView.subtitleBackView.isHidden = true
|
||||||
print("KSPlayerView: Disabled all text tracks and cleared srtControl selection")
|
NSLog("KSPlayerView: Disabled all text tracks")
|
||||||
} else {
|
} else {
|
||||||
print("KSPlayerView: Text track \(trackId) not found. Available track IDs: \(textTracks.map { Int($0.trackID) }), array indices: 0..\(textTracks.count - 1)")
|
NSLog("KSPlayerView: Text track %d not found. Available count: %d", trackId, textTracks.count)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
print("KSPlayerView: No player available for text track selection")
|
NSLog("KSPlayerView: No player available for text track selection")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1015,7 +969,18 @@ extension KSPlayerView: KSPlayerLayerDelegate {
|
||||||
if let part = playerView.srtControl.parts.first {
|
if let part = playerView.srtControl.parts.first {
|
||||||
print("KSPlayerView: [SUBTITLE RENDER] time=\(currentTime), text='\(part.text?.string ?? "nil")', hasImage=\(part.image != nil)")
|
print("KSPlayerView: [SUBTITLE RENDER] time=\(currentTime), text='\(part.text?.string ?? "nil")', hasImage=\(part.image != nil)")
|
||||||
playerView.subtitleBackView.image = part.image
|
playerView.subtitleBackView.image = part.image
|
||||||
playerView.subtitleLabel.attributedText = part.text
|
|
||||||
|
// Normalize font size for all subtitles to ensure consistent display
|
||||||
|
if let originalText = part.text {
|
||||||
|
let mutableText = NSMutableAttributedString(attributedString: originalText)
|
||||||
|
// Apply consistent font across the entire text
|
||||||
|
let font = UIFont.systemFont(ofSize: 20.0)
|
||||||
|
mutableText.addAttributes([.font: font], range: NSRange(location: 0, length: mutableText.length))
|
||||||
|
playerView.subtitleLabel.attributedText = mutableText
|
||||||
|
} else {
|
||||||
|
playerView.subtitleLabel.attributedText = nil
|
||||||
|
}
|
||||||
|
|
||||||
playerView.subtitleBackView.isHidden = false
|
playerView.subtitleBackView.isHidden = false
|
||||||
playerView.subtitleLabel.isHidden = false
|
playerView.subtitleLabel.isHidden = false
|
||||||
print("KSPlayerView: [SUBTITLE RENDER] Set subtitle text and made views visible")
|
print("KSPlayerView: [SUBTITLE RENDER] Set subtitle text and made views visible")
|
||||||
|
|
|
||||||
|
|
@ -87,9 +87,14 @@ class KSPlayerViewManager: RCTViewManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func setTextTrack(_ node: NSNumber, trackId: NSNumber) {
|
@objc func setTextTrack(_ node: NSNumber, trackId: NSNumber) {
|
||||||
|
NSLog("[KSPlayerViewManager] setTextTrack called - node: %@, trackId: %@", node, trackId)
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
|
NSLog("[KSPlayerViewManager] setTextTrack on main queue - looking for view with tag: %@", node)
|
||||||
if let view = self.bridge.uiManager.view(forReactTag: node) as? KSPlayerView {
|
if let view = self.bridge.uiManager.view(forReactTag: node) as? KSPlayerView {
|
||||||
|
NSLog("[KSPlayerViewManager] Found view, calling setTextTrack(%d)", Int(truncating: trackId))
|
||||||
view.setTextTrack(Int(truncating: trackId))
|
view.setTextTrack(Int(truncating: trackId))
|
||||||
|
} else {
|
||||||
|
NSLog("[KSPlayerViewManager] ERROR - Could not find KSPlayerView for tag: %@", node)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -476,6 +476,7 @@
|
||||||
OTHER_SWIFT_FLAGS = "$(inherited) -D EXPO_CONFIGURATION_DEBUG";
|
OTHER_SWIFT_FLAGS = "$(inherited) -D EXPO_CONFIGURATION_DEBUG";
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.nuvio.app;
|
PRODUCT_BUNDLE_IDENTIFIER = com.nuvio.app;
|
||||||
PRODUCT_NAME = Nuvio;
|
PRODUCT_NAME = Nuvio;
|
||||||
|
SUPPORTS_MACCATALYST = YES;
|
||||||
SWIFT_OBJC_BRIDGING_HEADER = "Nuvio/Nuvio-Bridging-Header.h";
|
SWIFT_OBJC_BRIDGING_HEADER = "Nuvio/Nuvio-Bridging-Header.h";
|
||||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
|
|
@ -508,6 +509,7 @@
|
||||||
OTHER_SWIFT_FLAGS = "$(inherited) -D EXPO_CONFIGURATION_RELEASE";
|
OTHER_SWIFT_FLAGS = "$(inherited) -D EXPO_CONFIGURATION_RELEASE";
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.nuvio.hub;
|
PRODUCT_BUNDLE_IDENTIFIER = com.nuvio.hub;
|
||||||
PRODUCT_NAME = Nuvio;
|
PRODUCT_NAME = Nuvio;
|
||||||
|
SUPPORTS_MACCATALYST = YES;
|
||||||
SWIFT_OBJC_BRIDGING_HEADER = "Nuvio/Nuvio-Bridging-Header.h";
|
SWIFT_OBJC_BRIDGING_HEADER = "Nuvio/Nuvio-Bridging-Header.h";
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
TARGETED_DEVICE_FAMILY = "1,2";
|
TARGETED_DEVICE_FAMILY = "1,2";
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@
|
||||||
<key>CFBundlePackageType</key>
|
<key>CFBundlePackageType</key>
|
||||||
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
|
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
|
||||||
<key>CFBundleShortVersionString</key>
|
<key>CFBundleShortVersionString</key>
|
||||||
<string>1.3.1</string>
|
<string>1.2.10</string>
|
||||||
<key>CFBundleSignature</key>
|
<key>CFBundleSignature</key>
|
||||||
<string>????</string>
|
<string>????</string>
|
||||||
<key>CFBundleURLTypes</key>
|
<key>CFBundleURLTypes</key>
|
||||||
|
|
|
||||||
2
package-lock.json
generated
2
package-lock.json
generated
|
|
@ -44,7 +44,7 @@
|
||||||
"expo-brightness": "~14.0.7",
|
"expo-brightness": "~14.0.7",
|
||||||
"expo-clipboard": "~8.0.8",
|
"expo-clipboard": "~8.0.8",
|
||||||
"expo-crypto": "~15.0.7",
|
"expo-crypto": "~15.0.7",
|
||||||
"expo-dev-client": "~6.0.15",
|
"expo-dev-client": "~6.0.20",
|
||||||
"expo-device": "~8.0.9",
|
"expo-device": "~8.0.9",
|
||||||
"expo-document-picker": "~14.0.7",
|
"expo-document-picker": "~14.0.7",
|
||||||
"expo-file-system": "~19.0.17",
|
"expo-file-system": "~19.0.17",
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,7 @@
|
||||||
"expo-brightness": "~14.0.7",
|
"expo-brightness": "~14.0.7",
|
||||||
"expo-clipboard": "~8.0.8",
|
"expo-clipboard": "~8.0.8",
|
||||||
"expo-crypto": "~15.0.7",
|
"expo-crypto": "~15.0.7",
|
||||||
"expo-dev-client": "~6.0.15",
|
"expo-dev-client": "~6.0.20",
|
||||||
"expo-device": "~8.0.9",
|
"expo-device": "~8.0.9",
|
||||||
"expo-document-picker": "~14.0.7",
|
"expo-document-picker": "~14.0.7",
|
||||||
"expo-file-system": "~19.0.17",
|
"expo-file-system": "~19.0.17",
|
||||||
|
|
|
||||||
|
|
@ -120,11 +120,16 @@ const KSPlayer = forwardRef<KSPlayerRef, KSPlayerProps>((props, ref) => {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
setTextTrack: (trackId: number) => {
|
setTextTrack: (trackId: number) => {
|
||||||
|
console.log('[KSPlayerComponent] setTextTrack called with trackId:', trackId);
|
||||||
if (nativeRef.current) {
|
if (nativeRef.current) {
|
||||||
const node = findNodeHandle(nativeRef.current);
|
const node = findNodeHandle(nativeRef.current);
|
||||||
|
console.log('[KSPlayerComponent] setTextTrack dispatching command to node:', node);
|
||||||
// @ts-ignore legacy UIManager commands path for Paper
|
// @ts-ignore legacy UIManager commands path for Paper
|
||||||
const commandId = UIManager.getViewManagerConfig('KSPlayerView').Commands.setTextTrack;
|
const commandId = UIManager.getViewManagerConfig('KSPlayerView').Commands.setTextTrack;
|
||||||
|
console.log('[KSPlayerComponent] setTextTrack commandId:', commandId);
|
||||||
UIManager.dispatchViewManagerCommand(node, commandId, [trackId]);
|
UIManager.dispatchViewManagerCommand(node, commandId, [trackId]);
|
||||||
|
} else {
|
||||||
|
console.warn('[KSPlayerComponent] setTextTrack: nativeRef.current is null');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
getTracks: async () => {
|
getTracks: async () => {
|
||||||
|
|
|
||||||
|
|
@ -389,6 +389,27 @@ const KSPlayerCore: React.FC = () => {
|
||||||
navigation.goBack();
|
navigation.goBack();
|
||||||
}, [navigation, currentTime, duration, traktAutosync]);
|
}, [navigation, currentTime, duration, traktAutosync]);
|
||||||
|
|
||||||
|
// Track selection handlers - update state, prop change triggers native update
|
||||||
|
const handleSelectTextTrack = useCallback((trackId: number) => {
|
||||||
|
console.log('[KSPlayerCore] handleSelectTextTrack called with trackId:', trackId);
|
||||||
|
|
||||||
|
// Disable custom subtitles when selecting a built-in track
|
||||||
|
// This ensures the textTrack prop is actually passed to the native player
|
||||||
|
if (trackId !== -1) {
|
||||||
|
customSubs.setUseCustomSubtitles(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Just update state - the textTrack prop change will trigger native update
|
||||||
|
tracks.selectTextTrack(trackId);
|
||||||
|
}, [tracks, customSubs]);
|
||||||
|
|
||||||
|
const handleSelectAudioTrack = useCallback((trackId: number) => {
|
||||||
|
tracks.selectAudioTrack(trackId);
|
||||||
|
if (ksPlayerRef.current) {
|
||||||
|
ksPlayerRef.current.setAudioTrack(trackId);
|
||||||
|
}
|
||||||
|
}, [tracks, ksPlayerRef]);
|
||||||
|
|
||||||
// Stream selection handler
|
// Stream selection handler
|
||||||
const handleSelectStream = async (newStream: any) => {
|
const handleSelectStream = async (newStream: any) => {
|
||||||
if (newStream.url === uri) {
|
if (newStream.url === uri) {
|
||||||
|
|
@ -498,8 +519,8 @@ const KSPlayerCore: React.FC = () => {
|
||||||
setZoomScale={setZoomScale}
|
setZoomScale={setZoomScale}
|
||||||
lastZoomScale={lastZoomScale}
|
lastZoomScale={lastZoomScale}
|
||||||
setLastZoomScale={setLastZoomScale}
|
setLastZoomScale={setLastZoomScale}
|
||||||
audioTrack={tracks.selectedAudioTrack !== null ? tracks.selectedAudioTrack : undefined}
|
audioTrack={tracks.selectedAudioTrack ?? undefined}
|
||||||
textTrack={customSubs.useCustomSubtitles ? undefined : (tracks.selectedTextTrack !== -1 ? tracks.selectedTextTrack : undefined)}
|
textTrack={customSubs.useCustomSubtitles ? -1 : tracks.selectedTextTrack}
|
||||||
onAudioTracks={(d) => tracks.setKsAudioTracks(d.audioTracks || [])}
|
onAudioTracks={(d) => tracks.setKsAudioTracks(d.audioTracks || [])}
|
||||||
onTextTracks={(d) => tracks.setKsTextTracks(d.textTracks || [])}
|
onTextTracks={(d) => tracks.setKsTextTracks(d.textTracks || [])}
|
||||||
onLoad={onLoad}
|
onLoad={onLoad}
|
||||||
|
|
@ -682,7 +703,7 @@ const KSPlayerCore: React.FC = () => {
|
||||||
setShowAudioModal={modals.setShowAudioModal}
|
setShowAudioModal={modals.setShowAudioModal}
|
||||||
ksAudioTracks={tracks.ksAudioTracks}
|
ksAudioTracks={tracks.ksAudioTracks}
|
||||||
selectedAudioTrack={tracks.selectedAudioTrack}
|
selectedAudioTrack={tracks.selectedAudioTrack}
|
||||||
selectAudioTrack={tracks.selectAudioTrack}
|
selectAudioTrack={handleSelectAudioTrack}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<ErrorModal
|
<ErrorModal
|
||||||
|
|
@ -744,10 +765,10 @@ const KSPlayerCore: React.FC = () => {
|
||||||
ksTextTracks={tracks.ksTextTracks}
|
ksTextTracks={tracks.ksTextTracks}
|
||||||
selectedTextTrack={tracks.selectedTextTrack !== null ? tracks.selectedTextTrack : -1}
|
selectedTextTrack={tracks.selectedTextTrack !== null ? tracks.selectedTextTrack : -1}
|
||||||
useCustomSubtitles={customSubs.useCustomSubtitles}
|
useCustomSubtitles={customSubs.useCustomSubtitles}
|
||||||
selectTextTrack={tracks.selectTextTrack}
|
selectTextTrack={handleSelectTextTrack}
|
||||||
disableCustomSubtitles={() => {
|
disableCustomSubtitles={() => {
|
||||||
customSubs.setUseCustomSubtitles(false);
|
customSubs.setUseCustomSubtitles(false);
|
||||||
tracks.selectTextTrack(-1);
|
handleSelectTextTrack(-1);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -87,6 +87,11 @@ export const KSPlayerSurface: React.FC<KSPlayerSurfaceProps> = ({
|
||||||
headers
|
headers
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Debug: log textTrack prop changes
|
||||||
|
React.useEffect(() => {
|
||||||
|
console.log('[KSPlayerSurface] textTrack prop changed to:', textTrack);
|
||||||
|
}, [textTrack]);
|
||||||
|
|
||||||
// Handle buffering - KSPlayerComponent uses onBuffering callback
|
// Handle buffering - KSPlayerComponent uses onBuffering callback
|
||||||
const handleBuffering = (data: any) => {
|
const handleBuffering = (data: any) => {
|
||||||
onBuffer(data?.isBuffering ?? false);
|
onBuffer(data?.isBuffering ?? false);
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue