${escapeHtml(trackTitle)} ${qualityBadge}
diff --git a/js/ui.js b/js/ui.js
index 0b6ef28..891ff56 100644
--- a/js/ui.js
+++ b/js/ui.js
@@ -348,9 +348,19 @@ export class UIRenderer {
let trackImageHTML = '';
if (showCover) {
if (isVideo && this.currentPage === 'playlist') {
- trackImageHTML = `
`;
+ const videoCoverUrl = this.api.getVideoCoverUrl(track.imageId);
+ if (videoCoverUrl) {
+ trackImageHTML = `

`;
+ } else {
+ trackImageHTML = `
`;
+ }
} else if (isVideo && (this.currentPage === 'search' || this.currentPage === 'library')) {
- trackImageHTML = `
`;
+ const videoCoverUrl = this.api.getVideoCoverUrl(track.imageId);
+ if (videoCoverUrl) {
+ trackImageHTML = `

`;
+ } else {
+ trackImageHTML = `
`;
+ }
} else {
trackImageHTML = this.getCoverHTML(
track.image || track.cover || track.album?.cover,
@@ -670,10 +680,13 @@ export class UIRenderer {
const duration = formatTime(video.duration);
const artistName = getTrackArtists(video);
+ const videoCoverUrl = this.api.getVideoCoverUrl(video.imageId);
const cover = video.image || video.cover;
let imageHTML;
- if (cover) {
+ if (videoCoverUrl) {
+ imageHTML = `

`;
+ } else if (cover) {
imageHTML = this.getCoverHTML(cover, escapeHtml(video.title));
} else {
imageHTML = `
`;
@@ -1012,6 +1025,11 @@ export class UIRenderer {
if (image) image.style.display = 'block';
if (visualizerContainer) visualizerContainer.style.display = 'block';
+ const qualityBtn = document.getElementById('fs-quality-btn');
+ const qualityMenu = document.getElementById('fs-quality-menu');
+ if (qualityBtn) qualityBtn.style.display = 'none';
+ if (qualityMenu) qualityMenu.style.display = 'none';
+
const videoCoverUrl = track.videoUrl || track.videoCoverUrl || track.album?.videoCoverUrl || null;
const coverUrl = videoCoverUrl || this.api.getCoverUrl(track.album?.cover, '1280');
@@ -1227,50 +1245,20 @@ export class UIRenderer {
// Mouse move handler
const handleMouseMove = (e) => {
const rect = overlay.getBoundingClientRect();
- // Check if mouse is near the top-right corner (within 150px from right, 100px from top)
const isNearTopRight = e.clientY < 100 && e.clientX > rect.width - 150;
if (isUIHidden) {
if (overlay.classList.contains('is-video-mode')) {
- toggleUI();
+ if (isNearTopRight) {
+ showButton();
+ } else {
+ hideButton();
+ }
} else if (isNearTopRight) {
showButton();
} else {
hideButton();
}
- } else if (overlay.classList.contains('is-video-mode')) {
- resetVideoHideTimer();
- }
- };
-
- let videoHideTimer = null;
- const resetVideoHideTimer = () => {
- if (videoHideTimer) clearTimeout(videoHideTimer);
- if (!overlay.classList.contains('is-video-mode') || isUIHidden) return;
-
- videoHideTimer = setTimeout(() => {
- if (!isUIHidden && overlay.classList.contains('is-video-mode')) {
- toggleUI();
- }
- }, 3000);
- };
-
- resetVideoHideTimer();
-
- // Toggle UI visibility
- const toggleUI = () => {
- isUIHidden = !isUIHidden;
- overlay.classList.toggle('ui-hidden', isUIHidden);
- toggleBtn.classList.toggle('active', isUIHidden);
- toggleBtn.title = isUIHidden ? 'Show UI' : 'Hide UI';
-
- if (isUIHidden) {
- // When UI is hidden, immediately hide the button
- // It will reappear when mouse nears top-right
- hideButton();
- } else {
- // When UI is shown, keep button visible
- showButton();
}
};
diff --git a/styles.css b/styles.css
index dfc3a65..d0c3942 100644
--- a/styles.css
+++ b/styles.css
@@ -2113,6 +2113,10 @@ input[type='search']::-webkit-search-cancel-button {
color: var(--highlight);
}
+.track-item.video-track-item {
+ gap: var(--spacing-xl);
+}
+
.track-item.unavailable {
opacity: 0.5;
cursor: not-allowed;
@@ -5436,12 +5440,12 @@ img[src=''] {
right: 2rem;
max-width: 500px;
margin: 0 auto;
- background: rgb(15, 15, 15, 0.5);
- backdrop-filter: blur(12px);
+ background: transparent;
+ backdrop-filter: none;
padding: 0.6rem 1rem;
border-radius: 10px;
- border: 1px solid rgb(255, 255, 255, 0.05);
- box-shadow: 0 4px 20px rgb(0, 0, 0, 0.4);
+ border: none;
+ box-shadow: none;
transition:
transform 0.4s cubic-bezier(0.4, 0, 0.2, 1),
opacity 0.4s ease;
@@ -5478,6 +5482,84 @@ img[src=''] {
display: none;
}
+#fullscreen-cover-overlay.is-video-mode .fs-quality-btn {
+ display: flex !important;
+ width: 28px;
+ height: 28px;
+ padding: 0.25rem;
+}
+
+#fullscreen-cover-overlay.is-video-mode .fs-quality-btn svg {
+ width: 18px;
+ height: 18px;
+}
+
+#fullscreen-cover-overlay.is-video-mode .fs-quality-label {
+ display: none;
+}
+
+.fs-quality-btn {
+ background: transparent;
+ border: none;
+ color: white;
+ padding: 4px 8px;
+ border-radius: 4px;
+ cursor: pointer;
+ font-size: 0.75rem;
+ display: flex;
+ align-items: center;
+ gap: 4px;
+ opacity: 0.7;
+ transition: opacity 0.2s;
+ position: relative;
+}
+
+.fs-quality-btn:hover {
+ opacity: 1;
+ background: rgba(255, 255, 255, 0.1);
+}
+
+.fullscreen-volume-container {
+ position: relative;
+}
+
+.fs-quality-menu {
+ position: absolute;
+ bottom: 100%;
+ right: 0;
+ background: rgb(20, 20, 20);
+ border: 1px solid rgba(255, 255, 255, 0.1);
+ border-radius: 8px;
+ padding: 4px;
+ min-width: 120px;
+ box-shadow: 0 4px 20px rgba(0, 0, 0, 0.5);
+ z-index: 1000;
+ margin-bottom: 8px;
+}
+
+.fs-quality-option {
+ display: block;
+ width: 100%;
+ padding: 8px 12px;
+ border: none;
+ background: transparent;
+ color: white;
+ text-align: left;
+ cursor: pointer;
+ font-size: 0.85rem;
+ border-radius: 4px;
+ transition: background 0.2s;
+}
+
+.fs-quality-option:hover {
+ background: rgba(255, 255, 255, 0.1);
+}
+
+.fs-quality-option.active {
+ background: var(--primary);
+ color: white;
+}
+
#fullscreen-cover-overlay.is-video-mode .fullscreen-volume-container {
margin-top: 0.5rem;
}
@@ -8193,6 +8275,7 @@ body:has(#side-panel.active) #close-fullscreen-cover-btn {
.video-card .card-image-container {
aspect-ratio: 16 / 9 !important;
+ margin-bottom: var(--spacing-sm);
}
.video-card .card-image {