HLS support and some styling fixes for context menus

Co-authored-by: Jip Frijlink <JipFr@users.noreply.github.com>
This commit is contained in:
mrjvs 2023-10-14 16:32:54 +02:00
parent 8f8bbf28c1
commit f2266bff6b
4 changed files with 59 additions and 20 deletions

View File

@ -11,6 +11,7 @@ import { useOverlayRouter } from "@/hooks/useOverlayRouter";
import { usePlayerStore } from "@/stores/player/store";
import {
SourceQuality,
allQualities,
qualityToString,
} from "@/stores/player/utils/qualities";
@ -26,7 +27,7 @@ function QualityOption(props: {
textClasses = "text-video-context-type-main text-opacity-40";
return (
<Context.Link noHover={props.disabled} onClick={props.onClick}>
<Context.Link onClick={props.disabled ? undefined : props.onClick}>
<Context.LinkTitle textClass={textClasses}>
{props.children}
</Context.LinkTitle>
@ -54,23 +55,28 @@ function QualityView({ id }: { id: string }) {
[router, switchQuality]
);
const allVisibleQualities = allQualities.filter((t) => t !== "unknown");
return (
<>
<Context.BackLink onClick={() => router.navigate("/")}>
Quality
</Context.BackLink>
<Context.Section>
{availableQualities.map((v) => (
{allVisibleQualities.map((v) => (
<QualityOption
key={v}
selected={v === currentQuality}
onClick={() => change(v)}
onClick={
availableQualities.includes(v) ? () => change(v) : undefined
}
disabled={!availableQualities.includes(v)}
>
{qualityToString(v)}
</QualityOption>
))}
<Context.Divider />
<Context.Link noHover onClick={() => router.navigate("/")}>
<Context.Link>
<Context.LinkTitle>Automatic quality</Context.LinkTitle>
<span>Toggle</span>
</Context.Link>

View File

@ -1,4 +1,5 @@
import fscreen from "fscreen";
import Hls from "hls.js";
import {
DisplayInterface,
@ -17,15 +18,38 @@ import { makeEmitter } from "@/utils/events";
export function makeVideoElementDisplayInterface(): DisplayInterface {
const { emit, on, off } = makeEmitter<DisplayInterfaceEvents>();
let source: LoadableSource | null = null;
let hls: Hls | null = null;
let videoElement: HTMLVideoElement | null = null;
let containerElement: HTMLElement | null = null;
let isFullscreen = false;
let isPausedBeforeSeeking = false;
let isSeeking = false;
function setupSource(vid: HTMLVideoElement, src: LoadableSource) {
if (src.type === "hls") {
if (!Hls.isSupported()) throw new Error("HLS not supported");
hls = new Hls({ enableWorker: false });
hls.on(Hls.Events.ERROR, (event, data) => {
console.error("HLS error", data);
if (data.fatal) {
throw new Error(
`HLS ERROR:${data.error?.message ?? "Something went wrong"}`
);
}
});
hls.attachMedia(vid);
hls.loadSource(src.url);
return;
}
vid.src = src.url;
}
function setSource() {
if (!videoElement || !source) return;
videoElement.src = source.url;
setupSource(videoElement, source);
videoElement.addEventListener("play", () => {
emit("play", undefined);
@ -64,6 +88,7 @@ export function makeVideoElementDisplayInterface(): DisplayInterface {
on,
off,
destroy: () => {
if (hls) hls.destroy();
if (videoElement) {
videoElement.src = "";
videoElement.remove();

View File

@ -31,21 +31,29 @@ function Section(props: { children: React.ReactNode }) {
return <div className="my-5">{props.children}</div>;
}
function Link(props: {
onClick?: () => void;
children: React.ReactNode;
noHover?: boolean;
}) {
function Link(props: { onClick?: () => void; children: React.ReactNode }) {
const classes = classNames(
"flex justify-between items-center py-2 pl-3 pr-3 -ml-3 rounded w-full",
{
"cursor-default": !props.onClick,
"hover:bg-video-context-border hover:bg-opacity-10": !!props.onClick,
}
);
const styles = { width: "calc(100% + 1.5rem)" };
if (!props.onClick) {
return (
<div className={classes} style={styles}>
{props.children}
</div>
);
}
return (
<button
type="button"
className={classNames([
"flex justify-between items-center py-2 pl-3 pr-3 -ml-3 rounded w-full",
props.noHover
? "cursor-default"
: "hover:bg-video-context-border hover:bg-opacity-10",
])}
style={{ width: "calc(100% + 1.5rem)" }}
className={classes}
style={styles}
onClick={props.onClick}
>
{props.children}
@ -59,11 +67,11 @@ function BackLink(props: {
rightSide?: React.ReactNode;
}) {
return (
<h3 className="font-bold text-video-context-type-main pb-4 pt-5 border-b border-opacity-25 border-video-context-border mb-6 flex justify-between items-center">
<h3 className="font-bold text-video-context-type-main pb-3 pt-5 border-b border-opacity-25 border-video-context-border mb-6 flex justify-between items-center">
<div className="flex items-center space-x-3">
<button
type="button"
className="-ml-1 p-1 rounded hover:bg-video-context-light hover:bg-opacity-10"
className="-ml-2 p-2 rounded hover:bg-video-context-light hover:bg-opacity-10"
onClick={props.onClick}
>
<Icon className="text-xl" icon={Icons.ARROW_LEFT} />

View File

@ -51,7 +51,7 @@ const qualityMap: Record<SourceQuality, string> = {
unknown: "unknown",
};
export const allQualities = Object.keys(qualityMap);
export const allQualities = Object.keys(qualityMap) as SourceQuality[];
export function qualityToString(quality: SourceQuality): string {
return qualityMap[quality];