pstream is dead; long live pstream
taciturnaxolotl.github.io/pstream-ng/
1import { detect } from "detect-browser";
2import fscreen from "fscreen";
3import Hls from "hls.js";
4
5export const isSafari = /^((?!chrome|android).)*safari/i.test(
6 navigator.userAgent,
7);
8
9export const isFirefox = detect()?.name === "firefox";
10
11let cachedVolumeResult: boolean | null = null;
12export async function canChangeVolume(): Promise<boolean> {
13 if (cachedVolumeResult === null) {
14 const timeoutPromise = new Promise<false>((resolve) => {
15 setTimeout(() => resolve(false), 1e3);
16 });
17 const promise = new Promise<true>((resolve) => {
18 const video = document.createElement("video");
19 const handler = () => {
20 video.removeEventListener("volumechange", handler);
21 resolve(true);
22 };
23
24 video.addEventListener("volumechange", handler);
25
26 video.volume = 0.5;
27 });
28
29 cachedVolumeResult = await Promise.race([promise, timeoutPromise]);
30 }
31 return cachedVolumeResult;
32}
33
34export function canFullscreenAnyElement(): boolean {
35 return fscreen.fullscreenEnabled;
36}
37
38export function canWebkitFullscreen(): boolean {
39 return canFullscreenAnyElement() || isSafari;
40}
41
42export function canFullscreen(): boolean {
43 return canFullscreenAnyElement() || canWebkitFullscreen();
44}
45
46export function canPictureInPicture(): boolean {
47 return "pictureInPictureEnabled" in document;
48}
49
50export function canWebkitPictureInPicture(): boolean {
51 return "webkitSupportsPresentationMode" in document.createElement("video");
52}
53
54export function canPlayHlsNatively(video: HTMLVideoElement): boolean {
55 if (Hls.isSupported()) return false; // no need to play natively
56 return !!video.canPlayType("application/vnd.apple.mpegurl");
57}
58
59export type ExtensionDetectionResult =
60 | "unknown" // unknown detection or weird browser
61 | "firefox" // firefox extensions
62 | "chrome" // chrome extension (could be chromium, but still works with chrome extensions)
63 | "ios"; // ios, no extensions
64
65export function detectExtensionInstall(): ExtensionDetectionResult {
66 const res = detect();
67
68 // not a browser or failed to detect
69 if (res?.type !== "browser") return "unknown";
70
71 if (res.name === "ios" || res.name === "ios-webview") return "ios";
72 if (
73 res.name === "chrome" ||
74 res.name === "chromium-webview" ||
75 res.name === "edge-chromium" ||
76 res.name === "opera"
77 )
78 return "chrome";
79 if (res.name === "firefox") return "firefox";
80 return "unknown";
81}