HLS for ios

This commit is contained in:
mrjvs 2023-11-29 17:27:17 +01:00
parent 9f7330fc5b
commit b9f4e7f412
4 changed files with 46 additions and 7 deletions

View File

@ -17,6 +17,7 @@ import {
canFullscreen, canFullscreen,
canFullscreenAnyElement, canFullscreenAnyElement,
canPictureInPicture, canPictureInPicture,
canPlayHlsNatively,
canWebkitFullscreen, canWebkitFullscreen,
canWebkitPictureInPicture, canWebkitPictureInPicture,
} from "@/utils/detectFeatures"; } from "@/utils/detectFeatures";
@ -69,6 +70,10 @@ export function makeVideoElementDisplayInterface(): DisplayInterface {
} }
function setupQualityForHls() { function setupQualityForHls() {
if (videoElement && canPlayHlsNatively(videoElement)) {
return; // nothing to change
}
if (!hls) return; if (!hls) return;
if (!automaticQuality) { if (!automaticQuality) {
const qualities = hlsLevelsToQualities(hls.levels); const qualities = hlsLevelsToQualities(hls.levels);
@ -95,8 +100,13 @@ export function makeVideoElementDisplayInterface(): DisplayInterface {
function setupSource(vid: HTMLVideoElement, src: LoadableSource) { function setupSource(vid: HTMLVideoElement, src: LoadableSource) {
if (src.type === "hls") { if (src.type === "hls") {
if (!Hls.isSupported()) throw new Error("HLS not supported"); if (canPlayHlsNatively(vid)) {
vid.src = src.url;
vid.currentTime = startAt;
return;
}
if (!Hls.isSupported()) throw new Error("HLS not supported");
if (!hls) { if (!hls) {
hls = new Hls({ hls = new Hls({
maxBufferSize: 500 * 1000 * 1000, // 500 mb of buffering, should load more fragments at once maxBufferSize: 500 * 1000 * 1000, // 500 mb of buffering, should load more fragments at once
@ -178,6 +188,14 @@ export function makeVideoElementDisplayInterface(): DisplayInterface {
emit("time", videoElement?.currentTime ?? 0) emit("time", videoElement?.currentTime ?? 0)
); );
videoElement.addEventListener("loadedmetadata", () => { videoElement.addEventListener("loadedmetadata", () => {
if (
source?.type === "hls" &&
videoElement &&
canPlayHlsNatively(videoElement)
) {
emit("qualities", ["unknown"]);
emit("changedquality", "unknown");
}
emit("duration", videoElement?.duration ?? 0); emit("duration", videoElement?.duration ?? 0);
}); });
videoElement.addEventListener("progress", () => { videoElement.addEventListener("progress", () => {

View File

@ -0,0 +1,19 @@
export interface VideoTrack {
selected: boolean;
id: string;
kind: string;
label: string;
language: string;
}
export type VideoTrackList = Array<VideoTrack> & {
selectedIndex: number;
getTrackById(id: string): VideoTrack | null;
addEventListener(type: "change", listener: (ev: Event) => any): void;
};
export function getVideoTracks(video: HTMLVideoElement): VideoTrackList | null {
const videoAsAny = video as any;
if (!videoAsAny.videoTracks) return null;
return videoAsAny.videoTracks;
}

View File

@ -13,6 +13,7 @@ import { generateQuickSearchMediaUrl } from "@/backend/metadata/tmdb";
import { useOnlineListener } from "@/hooks/usePing"; import { useOnlineListener } from "@/hooks/usePing";
import { AboutPage } from "@/pages/About"; import { AboutPage } from "@/pages/About";
import { AdminPage } from "@/pages/admin/AdminPage"; import { AdminPage } from "@/pages/admin/AdminPage";
import VideoTesterView from "@/pages/developer/VideoTesterView";
import { DmcaPage } from "@/pages/Dmca"; import { DmcaPage } from "@/pages/Dmca";
import { NotFoundPage } from "@/pages/errors/NotFoundPage"; import { NotFoundPage } from "@/pages/errors/NotFoundPage";
import { HomePage } from "@/pages/HomePage"; import { HomePage } from "@/pages/HomePage";
@ -106,15 +107,12 @@ function App() {
path="/dev" path="/dev"
component={lazy(() => import("@/pages/DeveloperPage"))} component={lazy(() => import("@/pages/DeveloperPage"))}
/> />
<Route <Route path="/dev/video">
exact <VideoTesterView />
path="/dev/video" </Route>
component={lazy(() => import("@/pages/developer/VideoTesterView"))}
/>
{/* developer routes that can abuse workers are disabled in production */} {/* developer routes that can abuse workers are disabled in production */}
{process.env.NODE_ENV === "development" ? ( {process.env.NODE_ENV === "development" ? (
<Route <Route
exact
path="/dev/test" path="/dev/test"
component={lazy(() => import("@/pages/developer/TestView"))} component={lazy(() => import("@/pages/developer/TestView"))}
/> />

View File

@ -46,3 +46,7 @@ export function canPictureInPicture(): boolean {
export function canWebkitPictureInPicture(): boolean { export function canWebkitPictureInPicture(): boolean {
return "webkitSupportsPresentationMode" in document.createElement("video"); return "webkitSupportsPresentationMode" in document.createElement("video");
} }
export function canPlayHlsNatively(video: HTMLVideoElement): boolean {
return !!video.canPlayType("application/vnd.apple.mpegurl");
}