add WakeLockSentinel (#6331)

* add WakeLockSentinel

prevents screen from sleeping ONLY in secure contexts (localhost, https)

closes #2884

* format, add types

* [wake-sentinel] add more releases, comments

release wakelock on dispose and end, call out secure contexts in error message
This commit is contained in:
feederbox826 2025-12-01 20:57:54 -05:00 committed by GitHub
parent 4017c42fe2
commit 90dd0b58d8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 77 additions and 1 deletions

View file

@ -92,6 +92,7 @@
"@graphql-codegen/typescript-react-apollo": "^4.1.0",
"@types/apollo-upload-client": "^18.0.0",
"@types/crypto-js": "^4.2.2",
"@types/dom-screen-wake-lock": "^1.0.3",
"@types/lodash-es": "^4.17.6",
"@types/mousetrap": "^1.6.11",
"@types/node": "^18.13.0",

View file

@ -216,6 +216,9 @@ importers:
'@types/crypto-js':
specifier: ^4.2.2
version: 4.2.2
'@types/dom-screen-wake-lock':
specifier: ^1.0.3
version: 1.0.3
'@types/lodash-es':
specifier: ^4.17.6
version: 4.17.12
@ -1907,6 +1910,9 @@ packages:
'@types/crypto-js@4.2.2':
resolution: {integrity: sha512-sDOLlVbHhXpAUAL0YHDUUwDZf3iN4Bwi4W6a0W0b+QcAezUbRtH4FVb+9J4h+XFPW7l/gQ9F8qC7P+Ec4k8QVQ==}
'@types/dom-screen-wake-lock@1.0.3':
resolution: {integrity: sha512-3Iten7X3Zgwvk6kh6/NRdwN7WbZ760YgFCsF5AxDifltUQzW1RaW+WRmcVtgwFzLjaNu64H+0MPJ13yRa8g3Dw==}
'@types/estree@1.0.8':
resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==}
@ -7315,6 +7321,8 @@ snapshots:
'@types/crypto-js@4.2.2': {}
'@types/dom-screen-wake-lock@1.0.3': {}
'@types/estree@1.0.8': {}
'@types/extract-files@13.0.2': {}

View file

@ -23,6 +23,7 @@ import "./big-buttons";
import "./track-activity";
import "./vrmode";
import "./media-session";
import "./wake-sentinel";
import cx from "classnames";
import {
useSceneSaveActivity,
@ -399,6 +400,7 @@ export const ScenePlayer: React.FC<IScenePlayerProps> = PatchComponent(
createButtons: uiConfig?.showAbLoopControls ?? false,
},
mediaSession: {},
wakeSentinel: {},
},
};

View file

@ -0,0 +1,65 @@
import videojs, { VideoJsPlayer } from "video.js";
class WakeSentinelPlugin extends videojs.getPlugin("plugin") {
public wakeLock: WakeLockSentinel | null = null;
public wakeLockFail: boolean = false;
constructor(player: VideoJsPlayer) {
super(player);
// listen for visibility change events
document.addEventListener("visibilitychange", async () => {
if (document.visibilityState === "visible") {
// reacquire the wake lock when the page becomes visible
await this.acquireWakeLock();
}
});
// acquire wake lock on ready and play
player.ready(async () => {
player.addClass("vjs-wake-sentinel");
await this.acquireWakeLock(true);
});
player.on("play", () => this.acquireWakeLock());
// release wake lock on pause, dispose and end
player.on("pause", () => this.releaseWakeLock());
player.on("dispose", () => this.releaseWakeLock());
player.on("ended", () => this.releaseWakeLock());
}
private async releaseWakeLock(): Promise<void> {
this.wakeLock?.release().then(() => (this.wakeLock = null));
}
private async acquireWakeLock(log = false): Promise<void> {
// if wake lock failed, don't even try
if (this.wakeLockFail) return;
// check for wake lock on startup
if ("wakeLock" in navigator) {
try {
this.wakeLock = await navigator.wakeLock.request("screen");
} catch (err) {
if (log) console.error("Failed to obtain Screen Wake Lock:", err);
this.wakeLockFail = true;
}
} else {
if (log) {
console.warn(
"Screen Wake Lock API not supported. Secure context (https or localhost) and modern browser required."
);
}
this.wakeLockFail = true;
}
}
}
videojs.registerPlugin("wakeSentinel", WakeSentinelPlugin);
/* eslint-disable @typescript-eslint/naming-convention */
declare module "video.js" {
interface VideoJsPlayer {
wakeSentinel: () => WakeSentinelPlugin;
}
}
export default WakeSentinelPlugin;

View file

@ -19,7 +19,7 @@
"isolatedModules": true,
"noFallthroughCasesInSwitch": true,
"useDefineForClassFields": true,
"types": ["vite/client"]
"types": ["vite/client", "dom-screen-wake-lock"]
},
"include": ["src"]
}