fix: implemented safari webkit support for fullscreen and PiP

This commit is contained in:
Trevor Mears
2026-01-21 20:36:34 -08:00
parent 6f966f1095
commit ea4a0a4577
4 changed files with 49 additions and 14 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "nodecast-tv",
"version": "2.1.2",
"version": "2.1.3",
"lockfileVersion": 3,
"requires": true,
"packages": {
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "nodecast-tv",
"version": "2.1.2",
"version": "2.1.3",
"description": "Modern IPTV Player",
"license": "GPL-3.0-only",
"main": "server/index.js",
+25 -8
View File
@@ -349,30 +349,47 @@ class VideoPlayer {
}
/**
* Toggle fullscreen mode
* Toggle fullscreen mode (cross-browser including Safari)
*/
toggleFullscreen() {
if (document.fullscreenElement) {
document.exitFullscreen();
const isFullscreen = document.fullscreenElement || document.webkitFullscreenElement;
if (isFullscreen) {
if (document.exitFullscreen) {
document.exitFullscreen();
} else if (document.webkitExitFullscreen) {
document.webkitExitFullscreen();
}
} else {
this.container.requestFullscreen().catch(err => {
console.error('Fullscreen error:', err);
});
const element = this.container;
if (element.requestFullscreen) {
element.requestFullscreen().catch(err => console.error('Fullscreen error:', err));
} else if (element.webkitRequestFullscreen) {
element.webkitRequestFullscreen();
} else if (this.video.webkitEnterFullscreen) {
// iOS Safari: use native video fullscreen
this.video.webkitEnterFullscreen();
}
}
}
/**
* Toggle Picture-in-Picture mode
* Toggle Picture-in-Picture mode (cross-browser including Safari)
*/
async togglePictureInPicture() {
try {
// Standard PiP API (Chrome, Edge, Firefox)
if (document.pictureInPictureElement) {
await document.exitPictureInPicture();
} else if (document.pictureInPictureEnabled && this.video.readyState >= 2) {
await this.video.requestPictureInPicture();
}
// Safari fallback using webkitPresentationMode
else if (typeof this.video.webkitSetPresentationMode === 'function') {
const mode = this.video.webkitPresentationMode;
this.video.webkitSetPresentationMode(mode === 'picture-in-picture' ? 'inline' : 'picture-in-picture');
}
} catch (err) {
// Silently fail - Firefox users can use native PiP button
if (err.name !== 'NotAllowedError') {
console.error('Picture-in-Picture error:', err);
}
+22 -4
View File
@@ -634,22 +634,40 @@ class WatchPage {
toggleFullscreen() {
const container = document.querySelector('.watch-video-section');
if (!document.fullscreenElement) {
container?.requestFullscreen?.() || container?.webkitRequestFullscreen?.();
const isFullscreen = document.fullscreenElement || document.webkitFullscreenElement;
if (isFullscreen) {
if (document.exitFullscreen) {
document.exitFullscreen();
} else if (document.webkitExitFullscreen) {
document.webkitExitFullscreen();
}
} else {
document.exitFullscreen?.() || document.webkitExitFullscreen?.();
if (container?.requestFullscreen) {
container.requestFullscreen();
} else if (container?.webkitRequestFullscreen) {
container.webkitRequestFullscreen();
} else if (this.video?.webkitEnterFullscreen) {
// iOS Safari: use native video fullscreen
this.video.webkitEnterFullscreen();
}
}
}
async togglePictureInPicture() {
try {
// Standard PiP API (Chrome, Edge, Firefox)
if (document.pictureInPictureElement) {
await document.exitPictureInPicture();
} else if (document.pictureInPictureEnabled && this.video.readyState >= 2) {
await this.video.requestPictureInPicture();
}
// Safari fallback using webkitPresentationMode
else if (typeof this.video.webkitSetPresentationMode === 'function') {
const mode = this.video.webkitPresentationMode;
this.video.webkitSetPresentationMode(mode === 'picture-in-picture' ? 'inline' : 'picture-in-picture');
}
} catch (err) {
// Silently fail - Firefox users can use native PiP button
if (err.name !== 'NotAllowedError') {
console.error('Picture-in-Picture error:', err);
}