chore: update screenshots in readme and sso icon
This commit is contained in:
@@ -522,6 +522,17 @@ class VideoPlayer {
|
||||
// Setup custom video controls
|
||||
this.initCustomControls();
|
||||
|
||||
// Detect video resolution when metadata loads (works for all streams)
|
||||
this.video.addEventListener('loadedmetadata', () => {
|
||||
if (this.video.videoHeight > 0) {
|
||||
this.currentStreamInfo = {
|
||||
width: this.video.videoWidth,
|
||||
height: this.video.videoHeight
|
||||
};
|
||||
this.updateQualityBadge();
|
||||
}
|
||||
});
|
||||
|
||||
// Initialize HLS.js if supported
|
||||
if (Hls.isSupported()) {
|
||||
this.hls = new Hls(this.getHlsConfig());
|
||||
@@ -775,7 +786,11 @@ class VideoPlayer {
|
||||
try {
|
||||
const probeRes = await fetch(`/api/probe?url=${encodeURIComponent(streamUrl)}`);
|
||||
const info = await probeRes.json();
|
||||
console.log(`[Player] Probe result: video=${info.video}, audio=${info.audio}, compatible=${info.compatible}`);
|
||||
console.log(`[Player] Probe result: video=${info.video}, audio=${info.audio}, ${info.width}x${info.height}, compatible=${info.compatible}`);
|
||||
|
||||
// Store probe result for quality badge display
|
||||
this.currentStreamInfo = info;
|
||||
this.updateQualityBadge();
|
||||
|
||||
// Handle subtitles from probe result
|
||||
// Clear existing remote tracks (from previous streams)
|
||||
@@ -1122,6 +1137,34 @@ class VideoPlayer {
|
||||
el.classList.remove('hidden');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get quality label from video height
|
||||
*/
|
||||
getQualityLabel(height) {
|
||||
if (height >= 2160) return '4K';
|
||||
if (height >= 1440) return '1440p';
|
||||
if (height >= 1080) return '1080p';
|
||||
if (height >= 720) return '720p';
|
||||
if (height >= 480) return '480p';
|
||||
if (height > 0) return `${height}p`;
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update quality badge display
|
||||
*/
|
||||
updateQualityBadge() {
|
||||
const badge = document.getElementById('player-quality-badge');
|
||||
if (!badge) return;
|
||||
|
||||
if (this.currentStreamInfo?.height > 0) {
|
||||
badge.textContent = this.getQualityLabel(this.currentStreamInfo.height);
|
||||
badge.classList.remove('hidden');
|
||||
} else {
|
||||
badge.classList.add('hidden');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch EPG data for current channel
|
||||
*/
|
||||
@@ -1267,6 +1310,11 @@ class VideoPlayer {
|
||||
this.controlsOverlay?.classList.add('hidden'); // Hide controls
|
||||
this.loadingSpinner?.classList.remove('show');
|
||||
this.nowPlaying.classList.add('hidden');
|
||||
|
||||
// Hide quality badge
|
||||
this.currentStreamInfo = null;
|
||||
const badge = document.getElementById('player-quality-badge');
|
||||
if (badge) badge.classList.add('hidden');
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -26,6 +26,7 @@ const Icons = {
|
||||
check: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" class="icon"><path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z"/></svg>`,
|
||||
circle: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" class="icon"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8z"/></svg>`,
|
||||
close: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" class="icon"><path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/></svg>`,
|
||||
fingerprint: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" class="icon"><path d="M12 1L3 5v6c0 5.55 3.84 10.74 9 12 5.16-1.26 9-6.45 9-12V5l-9-4zm-2 16l-4-4 1.41-1.41L10 14.17l6.59-6.59L18 9l-8 8z"/></svg>`,
|
||||
};
|
||||
|
||||
window.Icons = Icons;
|
||||
|
||||
@@ -40,7 +40,10 @@ class HomePage {
|
||||
<svg viewBox="0 0 24 24" fill="currentColor"><path d="M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z"/></svg>
|
||||
</button>
|
||||
<div class="horizontal-scroll channel-tiles" id="favorite-channels-list">
|
||||
<div class="loading-state">Loading favorites...</div>
|
||||
<div class="loading-state">
|
||||
<div class="loading"></div>
|
||||
<span>Loading favorites...</span>
|
||||
</div>
|
||||
</div>
|
||||
<button class="scroll-arrow scroll-right" aria-label="Scroll right">
|
||||
<svg viewBox="0 0 24 24" fill="currentColor"><path d="M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z"/></svg>
|
||||
@@ -57,7 +60,10 @@ class HomePage {
|
||||
<svg viewBox="0 0 24 24" fill="currentColor"><path d="M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z"/></svg>
|
||||
</button>
|
||||
<div class="horizontal-scroll" id="continue-watching-list">
|
||||
<div class="loading-state">Loading history...</div>
|
||||
<div class="loading-state">
|
||||
<div class="loading"></div>
|
||||
<span>Loading history...</span>
|
||||
</div>
|
||||
</div>
|
||||
<button class="scroll-arrow scroll-right" aria-label="Scroll right">
|
||||
<svg viewBox="0 0 24 24" fill="currentColor"><path d="M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z"/></svg>
|
||||
@@ -74,7 +80,10 @@ class HomePage {
|
||||
<svg viewBox="0 0 24 24" fill="currentColor"><path d="M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z"/></svg>
|
||||
</button>
|
||||
<div class="horizontal-scroll" id="recent-movies-list">
|
||||
<div class="empty-state">Coming soon</div>
|
||||
<div class="loading-state">
|
||||
<div class="loading"></div>
|
||||
<span>Loading recently added...</span>
|
||||
</div>
|
||||
</div>
|
||||
<button class="scroll-arrow scroll-right" aria-label="Scroll right">
|
||||
<svg viewBox="0 0 24 24" fill="currentColor"><path d="M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z"/></svg>
|
||||
@@ -91,7 +100,10 @@ class HomePage {
|
||||
<svg viewBox="0 0 24 24" fill="currentColor"><path d="M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z"/></svg>
|
||||
</button>
|
||||
<div class="horizontal-scroll" id="recent-series-list">
|
||||
<div class="empty-state">Coming soon</div>
|
||||
<div class="loading-state">
|
||||
<div class="loading"></div>
|
||||
<span>Loading recently added...</span>
|
||||
</div>
|
||||
</div>
|
||||
<button class="scroll-arrow scroll-right" aria-label="Scroll right">
|
||||
<svg viewBox="0 0 24 24" fill="currentColor"><path d="M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z"/></svg>
|
||||
@@ -342,7 +354,7 @@ class HomePage {
|
||||
try {
|
||||
const movies = await window.API.request('GET', '/channels/recent?type=movie&limit=12');
|
||||
if (!movies || movies.length === 0) {
|
||||
list.innerHTML = '<div class="no-data">No recent movies found</div>';
|
||||
list.innerHTML = '<div class="empty-state hint">No recently added movies found</div>';
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -371,7 +383,7 @@ class HomePage {
|
||||
try {
|
||||
const series = await window.API.request('GET', '/channels/recent?type=series&limit=12');
|
||||
if (!series || series.length === 0) {
|
||||
list.innerHTML = '<div class="no-data">No recent series found</div>';
|
||||
list.innerHTML = '<div class="empty-state hint">No recently added series found</div>';
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -61,6 +61,7 @@ class WatchPage {
|
||||
|
||||
// Transcode Status
|
||||
this.transcodeStatusEx = document.getElementById('watch-transcode-status');
|
||||
this.qualityBadgeEl = document.getElementById('watch-quality-badge');
|
||||
|
||||
// State
|
||||
this.hls = null;
|
||||
@@ -331,6 +332,33 @@ class WatchPage {
|
||||
this.transcodeStatusEx.classList.remove('hidden');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get quality label from video height
|
||||
*/
|
||||
getQualityLabel(height) {
|
||||
if (height >= 2160) return '4K';
|
||||
if (height >= 1440) return '1440p';
|
||||
if (height >= 1080) return '1080p';
|
||||
if (height >= 720) return '720p';
|
||||
if (height >= 480) return '480p';
|
||||
if (height > 0) return `${height}p`;
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update quality badge display
|
||||
*/
|
||||
updateQualityBadge() {
|
||||
if (!this.qualityBadgeEl) return;
|
||||
|
||||
if (this.currentStreamInfo?.height > 0) {
|
||||
this.qualityBadgeEl.textContent = this.getQualityLabel(this.currentStreamInfo.height);
|
||||
this.qualityBadgeEl.classList.remove('hidden');
|
||||
} else {
|
||||
this.qualityBadgeEl.classList.add('hidden');
|
||||
}
|
||||
}
|
||||
|
||||
async loadVideo(url) {
|
||||
// Store the URL for copy functionality
|
||||
this.currentUrl = url;
|
||||
@@ -361,7 +389,11 @@ class WatchPage {
|
||||
const ua = settings.userAgentPreset === 'custom' ? settings.userAgentCustom : settings.userAgentPreset;
|
||||
const probeRes = await fetch(`/api/probe?url=${encodeURIComponent(url)}&ua=${encodeURIComponent(ua || '')}`);
|
||||
const info = await probeRes.json();
|
||||
console.log(`[WatchPage] Probe result: video=${info.video}, audio=${info.audio}, compatible=${info.compatible}`);
|
||||
console.log(`[WatchPage] Probe result: video=${info.video}, audio=${info.audio}, ${info.width}x${info.height}, compatible=${info.compatible}`);
|
||||
|
||||
// Store early probe info for quality display
|
||||
this.currentStreamInfo = info;
|
||||
this.updateQualityBadge();
|
||||
|
||||
if (info.needsTranscode) {
|
||||
console.log('[WatchPage] Auto: Using HLS transcode session (incompatible audio/video)');
|
||||
@@ -539,6 +571,12 @@ class WatchPage {
|
||||
this.stopTranscodeSession();
|
||||
this.updateTranscodeStatus('hidden');
|
||||
|
||||
// Hide quality badge
|
||||
this.currentStreamInfo = null;
|
||||
if (this.qualityBadgeEl) {
|
||||
this.qualityBadgeEl.classList.add('hidden');
|
||||
}
|
||||
|
||||
if (this.hls) {
|
||||
this.hls.destroy();
|
||||
this.hls = null;
|
||||
@@ -656,7 +694,14 @@ class WatchPage {
|
||||
}
|
||||
|
||||
onMetadataLoaded() {
|
||||
// Duration is unreliable for transcoded streams, so we don't display it
|
||||
// Detect resolution
|
||||
if (this.video && this.video.videoHeight > 0) {
|
||||
this.currentStreamInfo = {
|
||||
width: this.video.videoWidth,
|
||||
height: this.video.videoHeight
|
||||
};
|
||||
this.updateQualityBadge();
|
||||
}
|
||||
|
||||
// Handle resumption
|
||||
if (this.resumeTime > 0 && this.video) {
|
||||
|
||||
Reference in New Issue
Block a user