mirror of
https://github.com/imgfloat/server.git
synced 2026-02-05 03:39:26 +00:00
Improve compatibility
This commit is contained in:
@@ -1,4 +1,7 @@
|
|||||||
const canvas = document.getElementById('broadcast-canvas');
|
const canvas = document.getElementById('broadcast-canvas');
|
||||||
|
const obsBrowser = !!window.obsstudio;
|
||||||
|
const supportsAnimatedDecode = typeof ImageDecoder !== 'undefined' && typeof createImageBitmap === 'function' && !obsBrowser;
|
||||||
|
const canPlayProbe = document.createElement('video');
|
||||||
const ctx = canvas.getContext('2d');
|
const ctx = canvas.getContext('2d');
|
||||||
let canvasSettings = { width: 1920, height: 1080 };
|
let canvasSettings = { width: 1920, height: 1080 };
|
||||||
canvas.width = canvasSettings.width;
|
canvas.width = canvasSettings.width;
|
||||||
@@ -313,6 +316,11 @@ function isDrawable(element) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function clearMedia(assetId) {
|
function clearMedia(assetId) {
|
||||||
|
const element = mediaCache.get(assetId);
|
||||||
|
if (isVideoElement(element)) {
|
||||||
|
element.src = '';
|
||||||
|
element.remove();
|
||||||
|
}
|
||||||
mediaCache.delete(assetId);
|
mediaCache.delete(assetId);
|
||||||
const animated = animatedCache.get(assetId);
|
const animated = animatedCache.get(assetId);
|
||||||
if (animated) {
|
if (animated) {
|
||||||
@@ -335,6 +343,8 @@ function clearMedia(assetId) {
|
|||||||
}
|
}
|
||||||
audio.element.pause();
|
audio.element.pause();
|
||||||
audio.element.currentTime = 0;
|
audio.element.currentTime = 0;
|
||||||
|
audio.element.src = '';
|
||||||
|
audio.element.remove();
|
||||||
audioControllers.delete(assetId);
|
audioControllers.delete(assetId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -398,7 +408,6 @@ function getAssetVolume(asset) {
|
|||||||
function applyMediaVolume(element, asset) {
|
function applyMediaVolume(element, asset) {
|
||||||
if (!element) return 1;
|
if (!element) return 1;
|
||||||
const volume = getAssetVolume(asset);
|
const volume = getAssetVolume(asset);
|
||||||
element.muted = volume === 0;
|
|
||||||
element.volume = Math.min(volume, 1);
|
element.volume = Math.min(volume, 1);
|
||||||
return volume;
|
return volume;
|
||||||
}
|
}
|
||||||
@@ -509,7 +518,7 @@ function ensureMedia(asset) {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isGifAsset(asset) && 'ImageDecoder' in window) {
|
if (isGifAsset(asset) && supportsAnimatedDecode) {
|
||||||
const animated = ensureAnimatedImage(asset);
|
const animated = ensureAnimatedImage(asset);
|
||||||
if (animated) {
|
if (animated) {
|
||||||
mediaCache.set(asset.id, animated);
|
mediaCache.set(asset.id, animated);
|
||||||
@@ -521,6 +530,9 @@ function ensureMedia(asset) {
|
|||||||
element.dataset.sourceUrl = asset.url;
|
element.dataset.sourceUrl = asset.url;
|
||||||
element.crossOrigin = 'anonymous';
|
element.crossOrigin = 'anonymous';
|
||||||
if (isVideoElement(element)) {
|
if (isVideoElement(element)) {
|
||||||
|
if (!canPlayVideoType(asset.mediaType)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
element.loop = true;
|
element.loop = true;
|
||||||
element.playsInline = true;
|
element.playsInline = true;
|
||||||
element.autoplay = true;
|
element.autoplay = true;
|
||||||
@@ -529,9 +541,8 @@ function ensureMedia(asset) {
|
|||||||
element.onloadedmetadata = () => recordDuration(asset.id, element.duration);
|
element.onloadedmetadata = () => recordDuration(asset.id, element.duration);
|
||||||
element.preload = 'auto';
|
element.preload = 'auto';
|
||||||
element.addEventListener('error', () => clearMedia(asset.id));
|
element.addEventListener('error', () => clearMedia(asset.id));
|
||||||
const volume = applyMediaVolume(element, asset);
|
applyMediaVolume(element, asset);
|
||||||
element.defaultMuted = volume === 0;
|
element.muted = true;
|
||||||
element.muted = element.defaultMuted;
|
|
||||||
setVideoSource(element, asset);
|
setVideoSource(element, asset);
|
||||||
} else {
|
} else {
|
||||||
element.onload = draw;
|
element.onload = draw;
|
||||||
@@ -611,6 +622,11 @@ function fetchAssetBlob(asset) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function setVideoSource(element, asset) {
|
function setVideoSource(element, asset) {
|
||||||
|
if (!shouldUseBlobUrl(asset)) {
|
||||||
|
applyVideoSource(element, asset.url, asset);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const cached = blobCache.get(asset.id);
|
const cached = blobCache.get(asset.id);
|
||||||
if (cached?.url === asset.url && cached.objectUrl) {
|
if (cached?.url === asset.url && cached.objectUrl) {
|
||||||
applyVideoSource(element, cached.objectUrl, asset);
|
applyVideoSource(element, cached.objectUrl, asset);
|
||||||
@@ -631,6 +647,18 @@ function applyVideoSource(element, objectUrl, asset) {
|
|||||||
startVideoPlayback(element, asset);
|
startVideoPlayback(element, asset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function shouldUseBlobUrl(asset) {
|
||||||
|
return !obsBrowser && asset?.mediaType && canPlayVideoType(asset.mediaType);
|
||||||
|
}
|
||||||
|
|
||||||
|
function canPlayVideoType(mediaType) {
|
||||||
|
if (!mediaType) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
const support = canPlayProbe.canPlayType(mediaType);
|
||||||
|
return support === 'probably' || support === 'maybe';
|
||||||
|
}
|
||||||
|
|
||||||
function getCachedSource(element) {
|
function getCachedSource(element) {
|
||||||
return element?.dataset?.sourceUrl || element?.src;
|
return element?.dataset?.sourceUrl || element?.src;
|
||||||
}
|
}
|
||||||
@@ -687,33 +715,25 @@ function startVideoPlayback(element, asset) {
|
|||||||
element.playbackRate = effectiveSpeed;
|
element.playbackRate = effectiveSpeed;
|
||||||
}
|
}
|
||||||
const volume = applyMediaVolume(element, asset);
|
const volume = applyMediaVolume(element, asset);
|
||||||
element.defaultMuted = volume === 0;
|
const shouldUnmute = volume > 0;
|
||||||
element.muted = element.defaultMuted;
|
element.muted = true;
|
||||||
|
|
||||||
if (effectiveSpeed === 0) {
|
if (effectiveSpeed === 0) {
|
||||||
element.pause();
|
element.pause();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const attemptPlay = (allowFallback) => {
|
element.play();
|
||||||
const playPromise = element.play();
|
|
||||||
if (playPromise?.then) {
|
|
||||||
playPromise.then(() => {
|
|
||||||
if (volume > 0) {
|
|
||||||
element.muted = false;
|
|
||||||
}
|
|
||||||
}).catch(() => {
|
|
||||||
if (!allowFallback) {
|
|
||||||
queueAudioForUnlock({ element });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
element.muted = true;
|
|
||||||
element.play().catch(() => queueAudioForUnlock({ element }));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
attemptPlay(true);
|
if (shouldUnmute) {
|
||||||
|
if (!element.paused && element.readyState >= 2) {
|
||||||
|
element.muted = false;
|
||||||
|
} else {
|
||||||
|
element.addEventListener('playing', () => {
|
||||||
|
element.muted = false;
|
||||||
|
}, { once: true });
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function startRenderLoop() {
|
function startRenderLoop() {
|
||||||
|
|||||||
Reference in New Issue
Block a user