Fix safe login submission, mobile fullscreen, and OIDC discovery

This commit is contained in:
Technomancer702
2026-10-13 18:31:48 -07:00
parent b85b160013
commit ce122eb34b
16 changed files with 479 additions and 72 deletions

View File

@ -1107,7 +1107,8 @@
<script src="/js/components/VodDuration.js?v=1"></script>
<script src="/js/components/CaptionTracks.js?v=2"></script>
<script src="/js/components/HlsAudioRecovery.js?v=1"></script>
<script src="/js/components/VideoPlayer.js?v=6"></script>
<script src="/js/components/PlayerFullscreen.js?v=1"></script>
<script src="/js/components/VideoPlayer.js?v=7"></script>
<script src="/js/components/ChannelList.js?v=4"></script>
<script src="/js/components/SourceManager.js?v=3"></script>
<script src="/js/components/EpgGuide.js?v=2"></script>
@ -1117,7 +1118,7 @@
<script src="/js/pages/MoviesPage.js?v=4"></script>
<script src="/js/pages/SeriesPage.js?v=1"></script>
<script src="/js/pages/Settings.js?v=2"></script>
<script src="/js/pages/WatchPage.js?v=6"></script>
<script src="/js/pages/WatchPage.js?v=7"></script>
<script src="/js/app.js?v=5"></script>
</body>

View File

@ -0,0 +1,31 @@
/** Invoke fullscreen synchronously within the click/keyboard gesture, then handle its promise. */
const PlayerFullscreen = {
async toggle(video, container, doc = document) {
try {
if (doc.fullscreenElement && doc.exitFullscreen) {
await doc.exitFullscreen();
} else if (doc.webkitFullscreenElement && doc.webkitExitFullscreen) {
await doc.webkitExitFullscreen();
} else if (video?.webkitDisplayingFullscreen && video.webkitExitFullscreen) {
await video.webkitExitFullscreen();
} else {
const target = container || video;
// Some iPhones expose element methods even though element fullscreen is disabled.
const standard = doc.fullscreenEnabled === true ||
(doc.fullscreenEnabled === undefined && !video?.webkitEnterFullscreen);
const prefixed = doc.webkitFullscreenEnabled === true ||
(doc.webkitFullscreenEnabled === undefined && doc.fullscreenEnabled !== false && !video?.webkitEnterFullscreen);
if (standard && target?.requestFullscreen) await target.requestFullscreen();
else if (prefixed && target?.webkitRequestFullscreen) await target.webkitRequestFullscreen();
else if (video?.webkitEnterFullscreen) await video.webkitEnterFullscreen();
else return false;
}
return true;
} catch (error) {
console.error('Fullscreen failed:', error.message);
return false;
}
}
};
if (typeof window !== 'undefined') window.PlayerFullscreen = PlayerFullscreen;
if (typeof module !== 'undefined') module.exports = PlayerFullscreen;

View File

@ -422,25 +422,7 @@ class VideoPlayer {
* Toggle fullscreen mode (cross-browser including Safari)
*/
toggleFullscreen() {
const isFullscreen = document.fullscreenElement || document.webkitFullscreenElement;
if (isFullscreen) {
if (document.exitFullscreen) {
document.exitFullscreen();
} else if (document.webkitExitFullscreen) {
document.webkitExitFullscreen();
}
} else {
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();
}
}
return PlayerFullscreen.toggle(this.video, this.container, document);
}
/**
@ -1306,17 +1288,6 @@ class VideoPlayer {
window.app.channelList.selectChannel({ channelId: channels[nextIdx].id });
}
/**
* Toggle fullscreen
*/
toggleFullscreen() {
if (document.fullscreenElement) {
document.exitFullscreen();
} else if (this.container) {
this.container.requestFullscreen();
}
}
async zapBeforeStreaming(channel, streamUrl, signal) {
if (!channel?.zapBeforeStreaming) return;
if (!channel?.streamId || !streamUrl) return;

View File

@ -756,25 +756,7 @@ class WatchPage {
}
toggleFullscreen() {
const container = document.querySelector('.watch-video-section');
const isFullscreen = document.fullscreenElement || document.webkitFullscreenElement;
if (isFullscreen) {
if (document.exitFullscreen) {
document.exitFullscreen();
} else if (document.webkitExitFullscreen) {
document.webkitExitFullscreen();
}
} else {
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();
}
}
return PlayerFullscreen.toggle(this.video, document.querySelector('.watch-video-section'), document);
}
async togglePictureInPicture() {

View File

@ -180,7 +180,7 @@
Welcome! Please create your admin account to get started.
</div>
<form id="login-form">
<form id="login-form" method="post" action="/api/auth/login">
<div class="form-group">
<label for="username">Username</label>
<input type="text" id="username" name="username" required autocomplete="username"
@ -193,8 +193,9 @@
minlength="6" placeholder="Enter your password">
</div>
<button type="submit" class="btn-login" id="submit-btn">Sign In</button>
<button type="submit" class="btn-login" id="submit-btn" disabled>Sign In</button>
</form>
<noscript><p class="hint">JavaScript is required to sign in.</p></noscript>
<div class="sso-divider" style="text-align: center; margin: 20px 0; position: relative;">
<span
@ -248,7 +249,9 @@
async function checkSetupRequired() {
try {
const response = await fetch('/api/auth/setup-required');
if (!response.ok) throw new Error('Sign-in status unavailable');
const data = await response.json();
if (typeof data.setupRequired !== 'boolean') throw new Error('Invalid sign-in status');
if (data.setupRequired) {
isSetupMode = true;
@ -260,8 +263,12 @@
document.querySelector('.sso-divider').style.display = 'none';
document.getElementById('btn-sso-login').style.display = 'none';
}
document.getElementById('submit-btn').disabled = false;
} catch (err) {
console.error('Error checking setup status:', err);
const message = document.getElementById('error-message');
message.textContent = 'Could not load sign-in status. Reload the page to try again.';
message.classList.add('show');
}
}