mirror of
https://github.com/sussy-code/smov.git
synced 2024-12-29 16:07:40 +01:00
HLS support and some styling fixes for context menus
Co-authored-by: Jip Frijlink <JipFr@users.noreply.github.com>
This commit is contained in:
parent
8f8bbf28c1
commit
f2266bff6b
4 changed files with 59 additions and 20 deletions
|
@ -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>
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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} />
|
||||
|
|
|
@ -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];
|
||||
|
|
Loading…
Reference in a new issue