mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2026-10-27 07:52:24 +00:00
203 lines
5.2 KiB
JavaScript
203 lines
5.2 KiB
JavaScript
import { devLogger } from "../utils/logger.js";
|
|
|
|
export default class VideoModalController {
|
|
constructor({
|
|
getVideoModal,
|
|
callbacks: {
|
|
showError,
|
|
getLastModalTrigger,
|
|
setLastModalTrigger,
|
|
getCurrentVideo,
|
|
} = {},
|
|
}) {
|
|
this.getVideoModal = getVideoModal;
|
|
this.showError = showError;
|
|
this.getLastModalTrigger = getLastModalTrigger;
|
|
this.setLastModalTrigger = setLastModalTrigger;
|
|
this.getCurrentVideo = getCurrentVideo;
|
|
|
|
this.videoModalReadyPromise = null;
|
|
}
|
|
|
|
get videoModal() {
|
|
return this.getVideoModal ? this.getVideoModal() : null;
|
|
}
|
|
|
|
log(message, ...args) {
|
|
devLogger.log("[VideoModalController]", message, ...args);
|
|
}
|
|
|
|
/**
|
|
* Show the modal and set the "Please stand by" poster on the video.
|
|
*/
|
|
async showModalWithPoster(video = null, options = {}) {
|
|
if (!this.videoModal) {
|
|
return null;
|
|
}
|
|
|
|
if (Object.prototype.hasOwnProperty.call(options || {}, "trigger")) {
|
|
if (this.setLastModalTrigger) {
|
|
this.setLastModalTrigger(options.trigger);
|
|
}
|
|
}
|
|
|
|
const targetVideo =
|
|
video || (this.getCurrentVideo ? this.getCurrentVideo() : null);
|
|
if (!targetVideo) {
|
|
this.log("Skipping video modal open; no target video is available.");
|
|
return null;
|
|
}
|
|
|
|
try {
|
|
const { root } = await this.ensureVideoModalReady({
|
|
ensureVideoElement: true,
|
|
});
|
|
|
|
if (!this.videoModal) {
|
|
return root || null;
|
|
}
|
|
|
|
const trigger = this.getLastModalTrigger
|
|
? this.getLastModalTrigger()
|
|
: null;
|
|
this.videoModal.open(targetVideo, {
|
|
triggerElement: trigger,
|
|
});
|
|
this.applyModalLoadingPoster();
|
|
|
|
return (
|
|
root ||
|
|
(typeof this.videoModal.getRoot === "function"
|
|
? this.videoModal.getRoot()
|
|
: null)
|
|
);
|
|
} catch (error) {
|
|
devLogger.error(
|
|
"[VideoModalController] Failed to open the video modal before playback:",
|
|
error,
|
|
);
|
|
if (this.showError) {
|
|
this.showError("Could not open the video player. Please try again.");
|
|
}
|
|
return null;
|
|
}
|
|
}
|
|
|
|
applyModalLoadingPoster() {
|
|
if (!this.videoModal) {
|
|
return;
|
|
}
|
|
this.videoModal.applyLoadingPoster();
|
|
}
|
|
|
|
forceRemoveModalPoster(reason = "manual-clear") {
|
|
if (!this.videoModal) {
|
|
return false;
|
|
}
|
|
return this.videoModal.forceRemovePoster(reason);
|
|
}
|
|
|
|
async ensureVideoModalReady({ ensureVideoElement = false } = {}) {
|
|
if (!this.videoModal) {
|
|
throw new Error("Video modal instance is not available.");
|
|
}
|
|
|
|
const getRoot = () =>
|
|
typeof this.videoModal.getRoot === "function"
|
|
? this.videoModal.getRoot()
|
|
: null;
|
|
const getVideoElement = () =>
|
|
typeof this.videoModal.getVideoElement === "function"
|
|
? this.videoModal.getVideoElement()
|
|
: null;
|
|
|
|
const existingRoot = getRoot();
|
|
const existingVideoElement = getVideoElement();
|
|
const rootConnected = Boolean(existingRoot && existingRoot.isConnected);
|
|
const hasVideoElement = Boolean(existingVideoElement);
|
|
const videoConnected = Boolean(
|
|
existingVideoElement && existingVideoElement.isConnected,
|
|
);
|
|
|
|
const needsRehydrate =
|
|
!rootConnected || !hasVideoElement || !videoConnected;
|
|
|
|
if (!needsRehydrate) {
|
|
if (
|
|
existingVideoElement &&
|
|
this.videoModal &&
|
|
typeof this.videoModal.setVideoElement === "function"
|
|
) {
|
|
const currentModalVideo =
|
|
typeof this.videoModal.getVideoElement === "function"
|
|
? this.videoModal.getVideoElement()
|
|
: null;
|
|
if (currentModalVideo !== existingVideoElement) {
|
|
this.videoModal.setVideoElement(existingVideoElement);
|
|
}
|
|
}
|
|
|
|
return {
|
|
root: existingRoot,
|
|
videoElement: existingVideoElement,
|
|
};
|
|
}
|
|
|
|
if (!videoConnected) {
|
|
if (
|
|
this.videoModal &&
|
|
typeof this.videoModal.setVideoElement === "function"
|
|
) {
|
|
this.videoModal.setVideoElement(null);
|
|
}
|
|
}
|
|
|
|
if (!this.videoModalReadyPromise) {
|
|
if (typeof this.videoModal.load !== "function") {
|
|
throw new Error("Video modal does not expose a load() method.");
|
|
}
|
|
this.videoModalReadyPromise = Promise.resolve(this.videoModal.load());
|
|
}
|
|
|
|
try {
|
|
await this.videoModalReadyPromise;
|
|
} catch (error) {
|
|
this.videoModalReadyPromise = null;
|
|
throw error;
|
|
}
|
|
|
|
this.videoModalReadyPromise = null;
|
|
|
|
const readyRoot = getRoot();
|
|
const readyVideoElement = getVideoElement();
|
|
const readyVideoConnected = Boolean(
|
|
readyVideoElement && readyVideoElement.isConnected,
|
|
);
|
|
|
|
if (readyVideoConnected) {
|
|
if (
|
|
this.videoModal &&
|
|
typeof this.videoModal.setVideoElement === "function"
|
|
) {
|
|
this.videoModal.setVideoElement(readyVideoElement);
|
|
}
|
|
} else {
|
|
if (
|
|
this.videoModal &&
|
|
typeof this.videoModal.setVideoElement === "function"
|
|
) {
|
|
this.videoModal.setVideoElement(null);
|
|
}
|
|
}
|
|
|
|
if (ensureVideoElement && !readyVideoConnected) {
|
|
throw new Error("Video modal video element is missing after load().");
|
|
}
|
|
|
|
return {
|
|
root: readyRoot,
|
|
videoElement: readyVideoConnected ? readyVideoElement : null,
|
|
};
|
|
}
|
|
}
|