mirror of
https://github.com/tapframe/NuvioStreaming.git
synced 2026-03-29 22:10:32 +00:00
ksp test
This commit is contained in:
parent
eb3615acc6
commit
0011079199
2 changed files with 84 additions and 27 deletions
|
|
@ -109,6 +109,14 @@ class KSPlayerView: UIView {
|
|||
|
||||
guard let uri = source["uri"] as? String else {
|
||||
print("KSPlayerView: No URI provided")
|
||||
sendEvent("onError", ["error": "No URI provided in source"])
|
||||
return
|
||||
}
|
||||
|
||||
// Validate URL before proceeding
|
||||
guard let url = URL(string: uri), url.scheme != nil else {
|
||||
print("KSPlayerView: Invalid URL format: \(uri)")
|
||||
sendEvent("onError", ["error": "Invalid URL format: \(uri)"])
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -135,11 +143,24 @@ class KSPlayerView: UIView {
|
|||
}
|
||||
#endif
|
||||
|
||||
// Create KSPlayerResource
|
||||
let url = URL(string: uri)!
|
||||
// Create KSPlayerResource with validated URL
|
||||
let resource = KSPlayerResource(url: url, options: createOptions(with: headers), name: "Video")
|
||||
|
||||
print("KSPlayerView: Setting source: \(uri)")
|
||||
print("KSPlayerView: URL scheme: \(url.scheme ?? "unknown"), host: \(url.host ?? "unknown")")
|
||||
|
||||
// Add timeout for source loading
|
||||
loadTimeoutWorkItem?.cancel()
|
||||
let work = DispatchWorkItem { [weak self] in
|
||||
guard let self = self else { return }
|
||||
let dur = self.playerView.playerLayer?.player.duration ?? 0
|
||||
if dur <= 0 {
|
||||
self.sendEvent("onError", ["error": "Stream timeout: unable to open input after 8 seconds"])
|
||||
}
|
||||
}
|
||||
loadTimeoutWorkItem = work
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 8, execute: work)
|
||||
|
||||
playerView.set(resource: resource)
|
||||
|
||||
// Set up delegate after setting the resource
|
||||
|
|
@ -153,18 +174,6 @@ class KSPlayerView: UIView {
|
|||
}
|
||||
|
||||
setVolume(currentVolume)
|
||||
|
||||
// Start a safety timeout to surface errors if never ready
|
||||
loadTimeoutWorkItem?.cancel()
|
||||
let work = DispatchWorkItem { [weak self] in
|
||||
guard let self = self else { return }
|
||||
let dur = self.playerView.playerLayer?.player.duration ?? 0
|
||||
if dur <= 0 {
|
||||
self.sendEvent("onError", ["error": "Playback timeout: stream did not become ready."])
|
||||
}
|
||||
}
|
||||
loadTimeoutWorkItem = work
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 8, execute: work)
|
||||
}
|
||||
|
||||
private func createOptions(with headers: [String: String]) -> KSOptions {
|
||||
|
|
@ -192,9 +201,23 @@ class KSPlayerView: UIView {
|
|||
options.hardwareDecode = KSOptions.hardwareDecode
|
||||
#endif
|
||||
if !headers.isEmpty {
|
||||
options.appendHeader(headers)
|
||||
if let referer = headers["Referer"] ?? headers["referer"] {
|
||||
options.referer = referer
|
||||
// Clean and validate headers before adding
|
||||
var cleanHeaders: [String: String] = [:]
|
||||
for (key, value) in headers {
|
||||
// Remove any null or empty values
|
||||
if !value.isEmpty && value != "null" {
|
||||
cleanHeaders[key] = value
|
||||
}
|
||||
}
|
||||
|
||||
if !cleanHeaders.isEmpty {
|
||||
options.appendHeader(cleanHeaders)
|
||||
print("KSPlayerView: Added headers: \(cleanHeaders.keys.joined(separator: ", "))")
|
||||
|
||||
if let referer = cleanHeaders["Referer"] ?? cleanHeaders["referer"] {
|
||||
options.referer = referer
|
||||
print("KSPlayerView: Set referer: \(referer)")
|
||||
}
|
||||
}
|
||||
}
|
||||
return options
|
||||
|
|
@ -447,7 +470,22 @@ extension KSPlayerView: KSPlayerLayerDelegate {
|
|||
|
||||
func player(layer: KSPlayerLayer, finish error: Error?) {
|
||||
if let error = error {
|
||||
sendEvent("onError", ["error": error.localizedDescription])
|
||||
let errorMessage = error.localizedDescription
|
||||
print("KSPlayerView: Player finished with error: \(errorMessage)")
|
||||
|
||||
// Provide more specific error messages for common issues
|
||||
var detailedError = errorMessage
|
||||
if errorMessage.contains("avformat can't open input") {
|
||||
detailedError = "Unable to open video stream. This could be due to:\n• Invalid or malformed URL\n• Network connectivity issues\n• Server blocking the request\n• Unsupported video format\n• Missing required headers"
|
||||
} else if errorMessage.contains("timeout") {
|
||||
detailedError = "Stream connection timed out. The server may be slow or unreachable."
|
||||
} else if errorMessage.contains("404") || errorMessage.contains("Not Found") {
|
||||
detailedError = "Video stream not found. The URL may be expired or incorrect."
|
||||
} else if errorMessage.contains("403") || errorMessage.contains("Forbidden") {
|
||||
detailedError = "Access denied. The server may be blocking requests or require authentication."
|
||||
}
|
||||
|
||||
sendEvent("onError", ["error": detailedError])
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -212,19 +212,38 @@ const VideoPlayerCore: React.FC = () => {
|
|||
const [isLoadingSubtitleList, setIsLoadingSubtitleList] = useState<boolean>(false);
|
||||
const [showSourcesModal, setShowSourcesModal] = useState<boolean>(false);
|
||||
const [availableStreams, setAvailableStreams] = useState<{ [providerId: string]: { streams: any[]; addonName: string } }>(passedAvailableStreams || {});
|
||||
// Decode URLs for KSPlayer compatibility - KSPlayer handles encoded URLs better
|
||||
const decodeUrlForKsPlayer = (url: string): string => {
|
||||
// Smart URL processing for KSPlayer compatibility
|
||||
const processUrlForKsPlayer = (url: string): string => {
|
||||
try {
|
||||
// KSPlayer handles encoded URLs well, but decode for consistency
|
||||
const decoded = decodeURIComponent(url);
|
||||
return decoded;
|
||||
// Validate URL first
|
||||
const urlObj = new URL(url);
|
||||
|
||||
// Only decode if the URL appears to be double-encoded
|
||||
// Check if URL contains encoded characters that shouldn't be there
|
||||
const hasDoubleEncoding = url.includes('%25') ||
|
||||
(url.includes('%2F') && url.includes('//')) ||
|
||||
(url.includes('%3A') && url.includes('://'));
|
||||
|
||||
if (hasDoubleEncoding) {
|
||||
logger.log('[VideoPlayer] Detected double-encoded URL, decoding once');
|
||||
return decodeURIComponent(url);
|
||||
}
|
||||
|
||||
// For URLs with special characters in query params, ensure proper encoding
|
||||
if (urlObj.search) {
|
||||
const searchParams = new URLSearchParams(urlObj.search);
|
||||
urlObj.search = searchParams.toString();
|
||||
return urlObj.toString();
|
||||
}
|
||||
|
||||
return url;
|
||||
} catch (e) {
|
||||
logger.warn('[VideoPlayer] URL decoding failed, using original:', e);
|
||||
logger.warn('[VideoPlayer] URL processing failed, using original:', e);
|
||||
return url;
|
||||
}
|
||||
};
|
||||
|
||||
const [currentStreamUrl, setCurrentStreamUrl] = useState<string>(decodeUrlForKsPlayer(uri));
|
||||
const [currentStreamUrl, setCurrentStreamUrl] = useState<string>(processUrlForKsPlayer(uri));
|
||||
const [isChangingSource, setIsChangingSource] = useState<boolean>(false);
|
||||
const [showErrorModal, setShowErrorModal] = useState(false);
|
||||
const [errorDetails, setErrorDetails] = useState<string>('');
|
||||
|
|
@ -2365,8 +2384,8 @@ const VideoPlayerCore: React.FC = () => {
|
|||
// Set pending seek state
|
||||
setPendingSeek({ position: savedPosition, shouldPlay: wasPlaying });
|
||||
|
||||
// Update the stream URL and details immediately (decode URL for KSPlayer)
|
||||
setCurrentStreamUrl(decodeUrlForKsPlayer(newStream.url));
|
||||
// Update the stream URL and details immediately (process URL for KSPlayer)
|
||||
setCurrentStreamUrl(processUrlForKsPlayer(newStream.url));
|
||||
setCurrentQuality(newQuality);
|
||||
setCurrentStreamProvider(newProvider);
|
||||
setCurrentStreamName(newStreamName);
|
||||
|
|
|
|||
Loading…
Reference in a new issue