mirror of
https://github.com/p-stream/p-stream.git
synced 2026-03-11 17:55:33 +00:00
attempt to fix airplay and add m3u8 proxy tool
This commit is contained in:
parent
328f50bbb9
commit
e658d13ec5
2 changed files with 132 additions and 1 deletions
|
|
@ -12,6 +12,11 @@ import {
|
|||
} from "@/components/player/display/displayInterface";
|
||||
import { handleBuffered } from "@/components/player/utils/handleBuffered";
|
||||
import { getMediaErrorDetails } from "@/components/player/utils/mediaErrorDetails";
|
||||
import {
|
||||
createM3U8ProxyUrl,
|
||||
createMP4ProxyUrl,
|
||||
isUrlAlreadyProxied,
|
||||
} from "@/components/player/utils/proxy";
|
||||
import { useLanguageStore } from "@/stores/language";
|
||||
import {
|
||||
LoadableSource,
|
||||
|
|
@ -579,7 +584,75 @@ export function makeVideoElementDisplayInterface(): DisplayInterface {
|
|||
},
|
||||
startAirplay() {
|
||||
const videoPlayer = videoElement as any;
|
||||
if (videoPlayer && videoPlayer.webkitShowPlaybackTargetPicker) {
|
||||
if (!videoPlayer || !videoPlayer.webkitShowPlaybackTargetPicker) return;
|
||||
|
||||
if (!source) {
|
||||
// No source loaded, just trigger Airplay
|
||||
videoPlayer.webkitShowPlaybackTargetPicker();
|
||||
return;
|
||||
}
|
||||
|
||||
// Store the original URL to restore later
|
||||
const originalUrl =
|
||||
source?.type === "hls" ? hls?.url || source.url : videoPlayer.src;
|
||||
|
||||
let proxiedUrl: string | null = null;
|
||||
|
||||
if (source?.type === "hls") {
|
||||
// Only proxy HLS streams if they need it:
|
||||
// 1. Not already proxied AND
|
||||
// 2. Has headers (either preferredHeaders or headers)
|
||||
const allHeaders = {
|
||||
...source.preferredHeaders,
|
||||
...source.headers,
|
||||
};
|
||||
const hasHeaders = Object.keys(allHeaders).length > 0;
|
||||
|
||||
// Don't create proxy URL if it's already using the proxy
|
||||
if (!isUrlAlreadyProxied(source.url) && hasHeaders) {
|
||||
proxiedUrl = createM3U8ProxyUrl(source.url, allHeaders);
|
||||
} else {
|
||||
proxiedUrl = source.url; // Already proxied or no headers needed
|
||||
}
|
||||
} else if (source?.type === "mp4") {
|
||||
// TODO: Implement MP4 proxy for protected streams
|
||||
const hasHeaders =
|
||||
source.headers && Object.keys(source.headers).length > 0;
|
||||
if (hasHeaders) {
|
||||
// Use MP4 proxy for streams with headers
|
||||
proxiedUrl = createMP4ProxyUrl(source.url, source.headers || {});
|
||||
} else {
|
||||
proxiedUrl = source.url;
|
||||
}
|
||||
}
|
||||
|
||||
if (proxiedUrl && proxiedUrl !== originalUrl) {
|
||||
// Temporarily set the proxied URL for Airplay
|
||||
if (source?.type === "hls") {
|
||||
if (hls) {
|
||||
hls.loadSource(proxiedUrl);
|
||||
}
|
||||
} else {
|
||||
videoPlayer.src = proxiedUrl;
|
||||
}
|
||||
|
||||
// Small delay to ensure the URL is set before triggering Airplay
|
||||
setTimeout(() => {
|
||||
videoPlayer.webkitShowPlaybackTargetPicker();
|
||||
|
||||
// Restore original URL after a short delay
|
||||
setTimeout(() => {
|
||||
if (source?.type === "hls") {
|
||||
if (hls && originalUrl) {
|
||||
hls.loadSource(originalUrl);
|
||||
}
|
||||
} else if (originalUrl) {
|
||||
videoPlayer.src = originalUrl;
|
||||
}
|
||||
}, 1000);
|
||||
}, 100);
|
||||
} else {
|
||||
// No proxying needed, just trigger Airplay
|
||||
videoPlayer.webkitShowPlaybackTargetPicker();
|
||||
}
|
||||
},
|
||||
|
|
|
|||
58
src/components/player/utils/proxy.ts
Normal file
58
src/components/player/utils/proxy.ts
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
import { getLoadbalancedM3U8ProxyUrl } from "@/backend/providers/fetchers";
|
||||
import { getM3U8ProxyUrls } from "@/utils/proxyUrls";
|
||||
|
||||
/**
|
||||
* Creates a proxied M3U8 URL for HLS streams using a random proxy from config
|
||||
* @param url - The original M3U8 URL to proxy
|
||||
* @param headers - Headers to include with the request
|
||||
* @returns The proxied M3U8 URL
|
||||
*/
|
||||
export function createM3U8ProxyUrl(
|
||||
url: string,
|
||||
headers: Record<string, string> = {},
|
||||
): string {
|
||||
// Get a random M3U8 proxy URL from the configuration
|
||||
const proxyBaseUrl = getLoadbalancedM3U8ProxyUrl();
|
||||
|
||||
if (!proxyBaseUrl) {
|
||||
console.warn("No M3U8 proxy URLs available in configuration");
|
||||
return url; // Fallback to original URL
|
||||
}
|
||||
|
||||
const encodedUrl = encodeURIComponent(url);
|
||||
const encodedHeaders = encodeURIComponent(JSON.stringify(headers));
|
||||
return `${proxyBaseUrl}/m3u8-proxy?url=${encodedUrl}${headers ? `&headers=${encodedHeaders}` : ""}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: Creates a proxied MP4 URL for MP4 streams
|
||||
* @param url - The original MP4 URL to proxy
|
||||
* @param headers - Headers to include with the request
|
||||
* @returns The proxied MP4 URL
|
||||
*/
|
||||
export function createMP4ProxyUrl(
|
||||
url: string,
|
||||
_headers: Record<string, string> = {},
|
||||
): string {
|
||||
// TODO: Implement MP4 proxy for protected streams
|
||||
// This would need a separate MP4 proxy service that can handle headers
|
||||
// For now, return the original URL
|
||||
console.warn("MP4 proxy not yet implemented - using original URL");
|
||||
return url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a URL is already using one of the configured M3U8 proxy services
|
||||
* @param url - The URL to check
|
||||
* @returns True if the URL is already proxied, false otherwise
|
||||
*/
|
||||
export function isUrlAlreadyProxied(url: string): boolean {
|
||||
// Check if URL contains the m3u8-proxy pattern
|
||||
if (url.includes("/m3u8-proxy?url=")) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Also check if URL starts with any of the configured proxy URLs
|
||||
const proxyUrls = getM3U8ProxyUrls();
|
||||
return proxyUrls.some((proxyUrl) => url.startsWith(proxyUrl));
|
||||
}
|
||||
Loading…
Reference in a new issue