Basic loading of videos

ElementalAlchemist 3 weeks ago
parent 6608555a8b
commit 89ff17564e

@ -1,4 +1,5 @@
import { Accessor, Component, createSignal, Setter, Show } from "solid-js"; import { Accessor, Component, createEffect, createSignal, Setter, Show } from "solid-js";
import Hls from "hls.js";
import { DateTime } from "luxon"; import { DateTime } from "luxon";
import { import {
TimeType, TimeType,
@ -8,6 +9,8 @@ import {
} from "./convertTime"; } from "./convertTime";
import styles from "./video.module.scss"; import styles from "./video.module.scss";
Hls.DefaultConfig.maxBufferHole = 600;
export const VIDEO_FRAMES_PER_SECOND = 30; export const VIDEO_FRAMES_PER_SECOND = 30;
export const PLAYBACK_RATES = [0.25, 0.5, 0.75, 1, 1.25, 1.5, 1.75, 2, 4, 8]; export const PLAYBACK_RATES = [0.25, 0.5, 0.75, 1, 1.25, 1.5, 1.75, 2, 4, 8];
@ -177,3 +180,28 @@ export const KeyboardShortcuts: Component<KeyboardShortcutProps> = (
</details> </details>
); );
}; };
export interface VideoPlayerProps {
videoURL: string;
errorList: Accessor<string[]>;
setErrorList: Setter<string[]>;
videoPlayer: Accessor<Hls>;
}
export const VideoPlayer: Component<VideoPlayerProps> = (props) => {
if (!Hls.isSupported()) {
const newError =
"Your browser doesn't support MediaSource extensions. Video playback and editing won't work.";
props.setErrorList([...props.errorList(), newError]);
return <></>;
}
let videoElement;
createEffect(() => {
if (videoElement) {
props.videoPlayer().attachMedia(videoElement);
}
});
return <video ref={videoElement} controls={true}></video>;
};

@ -1,3 +1,8 @@
.hidden { .hidden {
display: none; display: none;
} }
video {
max-width: 100%;
max-height: 50vh;
}

@ -1,8 +1,23 @@
import { Accessor, Component, createResource, createSignal, For, Show, Suspense } from "solid-js"; import {
Accessor,
Component,
createResource,
createSignal,
For,
Setter,
Show,
Suspense,
} from "solid-js";
import Hls from "hls.js";
import { DateTime } from "luxon"; import { DateTime } from "luxon";
import styles from "./Restreamer.module.scss"; import styles from "./Restreamer.module.scss";
import { dateTimeFromWubloaderTime } from "../common/convertTime"; import { dateTimeFromWubloaderTime, wubloaderTimeFromDateTime } from "../common/convertTime";
import { KeyboardShortcuts, StreamTimeSettings, StreamVideoInfo } from "../common/video"; import {
KeyboardShortcuts,
StreamTimeSettings,
StreamVideoInfo,
VideoPlayer,
} from "../common/video";
export interface DefaultsData { export interface DefaultsData {
video_channel: string; video_channel: string;
@ -51,7 +66,11 @@ export const Restreamer: Component = () => {
</div> </div>
<Suspense> <Suspense>
<Show when={defaultsData()}> <Show when={defaultsData()}>
<RestreamerWithDefaults defaults={defaultsData()} /> <RestreamerWithDefaults
defaults={defaultsData()}
errorList={pageErrors}
setErrorList={setPageErrors}
/>
</Show> </Show>
</Suspense> </Suspense>
</> </>
@ -60,6 +79,8 @@ export const Restreamer: Component = () => {
interface RestreamerDefaultProps { interface RestreamerDefaultProps {
defaults: DefaultsData; defaults: DefaultsData;
errorList: Accessor<string[]>;
setErrorList: Setter<string[]>;
} }
const RestreamerWithDefaults: Component<RestreamerDefaultProps> = (props) => { const RestreamerWithDefaults: Component<RestreamerDefaultProps> = (props) => {
@ -72,6 +93,26 @@ const RestreamerWithDefaults: Component<RestreamerDefaultProps> = (props) => {
streamEndTime: null, streamEndTime: null,
}); });
const [videoPlayer, setVideoPlayer] = createSignal(new Hls());
const videoURL = () => {
const streamInfo = streamVideoInfo();
const startTime = wubloaderTimeFromDateTime(streamInfo.streamStartTime);
const query = new URLSearchParams({ start: startTime });
if (streamInfo.streamEndTime) {
const endTime = wubloaderTimeFromDateTime(streamInfo.streamEndTime);
query.append("end", endTime);
}
const queryString = query.toString();
let url = `/playlist/${streamInfo.streamName}.m3u8`;
if (queryString !== "") {
url += `?${queryString}`;
}
return url;
};
videoPlayer().loadSource(videoURL());
return ( return (
<> <>
<StreamTimeSettings <StreamTimeSettings
@ -80,6 +121,12 @@ const RestreamerWithDefaults: Component<RestreamerDefaultProps> = (props) => {
setStreamVideoInfo={setStreamVideoInfo} setStreamVideoInfo={setStreamVideoInfo}
showTimeRangeLink={false} showTimeRangeLink={false}
/> />
<VideoPlayer
videoURL={videoURL()}
errorList={props.errorList}
setErrorList={props.setErrorList}
videoPlayer={videoPlayer}
/>
</> </>
); );
}; };

@ -334,7 +334,9 @@ const ThumbnailManager: Component = () => {
</div> </div>
<div> <div>
<button type="submit">Submit</button> <button type="submit">Submit</button>
<button type="button" onClick={(event) => setEditing(false)}>Cancel</button> <button type="button" onClick={(event) => setEditing(false)}>
Cancel
</button>
<ul class={styles.templateUpdateErrors}> <ul class={styles.templateUpdateErrors}>
<For each={formErrors()}> <For each={formErrors()}>
{(error: string, index: Accessor<number>) => <li>{error}</li>} {(error: string, index: Accessor<number>) => <li>{error}</li>}

Loading…
Cancel
Save