Merge branch 'main' of github.com:monochrome-music/monochrome

This commit is contained in:
Samidy 2026-03-09 03:11:58 +03:00
commit 0662796d73
10 changed files with 154 additions and 101 deletions

View file

@ -124,7 +124,20 @@
<div id="visualizer-container"> <div id="visualizer-container">
<canvas id="visualizer-canvas"></canvas> <canvas id="visualizer-canvas"></canvas>
</div> </div>
<div id="fullscreen-video-container" style="display: none; position: absolute; inset: 0; width: 100%; height: 100%; justify-content: center; align-items: center; background: black; z-index: 0;"></div> <div
id="fullscreen-video-container"
style="
display: none;
position: absolute;
inset: 0;
width: 100%;
height: 100%;
justify-content: center;
align-items: center;
background: black;
z-index: 0;
"
></div>
<button id="toggle-ui-btn" class="fullscreen-ui-toggle" title="Toggle UI"> <button id="toggle-ui-btn" class="fullscreen-ui-toggle" title="Toggle UI">
<svg <svg
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
@ -168,7 +181,6 @@
/> />
<div class="fullscreen-track-info"> <div class="fullscreen-track-info">
<h2 id="fullscreen-track-title"></h2> <h2 id="fullscreen-track-title"></h2>
<h3 id="fullscreen-track-artist"></h3> <h3 id="fullscreen-track-artist"></h3>
<div class="fullscreen-actions"> <div class="fullscreen-actions">
@ -3771,8 +3783,8 @@
<div class="info"> <div class="info">
<span class="label">Visualizer Brightness</span> <span class="label">Visualizer Brightness</span>
<span class="description" <span class="description"
>Adjust the brightness of the visualizer. Lower this if the visualizer >Adjust the brightness of the visualizer. Lower this if the visualizer is
is too bright for you.</span too bright for you.</span
> >
</div> </div>
<div style="display: flex; align-items: center; gap: 10px"> <div style="display: flex; align-items: center; gap: 10px">

View file

@ -585,7 +585,9 @@ const syncManager = {
id: playlist.id, id: playlist.id,
name: playlist.name, name: playlist.name,
cover: playlist.cover || null, cover: playlist.cover || null,
tracks: playlist.tracks ? playlist.tracks.map((t) => this._minifyItem(t.type || 'track', t)) : [], tracks: playlist.tracks
? playlist.tracks.map((t) => this._minifyItem(t.type || 'track', t))
: [],
createdAt: playlist.createdAt || Date.now(), createdAt: playlist.createdAt || Date.now(),
updatedAt: playlist.updatedAt || Date.now(), updatedAt: playlist.updatedAt || Date.now(),
numberOfTracks: playlist.tracks ? playlist.tracks.length : 0, numberOfTracks: playlist.tracks ? playlist.tracks.length : 0,

View file

@ -892,10 +892,10 @@ export class LosslessAPI {
const numericArtistId = Number(artistId); const numericArtistId = Number(artistId);
for (const item of videoSearch.items) { for (const item of videoSearch.items) {
const itemArtistId = item.artist?.id; const itemArtistId = item.artist?.id;
const matchesArtist = const matchesArtist =
itemArtistId === numericArtistId || itemArtistId === numericArtistId ||
(Array.isArray(item.artists) && item.artists.some(a => a.id === numericArtistId)); (Array.isArray(item.artists) && item.artists.some((a) => a.id === numericArtistId));
if (matchesArtist && !videoMap.has(item.id)) { if (matchesArtist && !videoMap.has(item.id)) {
videoMap.set(item.id, item); videoMap.set(item.id, item);
} }
@ -918,8 +918,9 @@ export class LosslessAPI {
.sort((a, b) => (b.popularity || 0) - (a.popularity || 0)) .sort((a, b) => (b.popularity || 0) - (a.popularity || 0))
.slice(0, 15); .slice(0, 15);
const videos = Array.from(videoMap.values()) const videos = Array.from(videoMap.values()).sort(
.sort((a, b) => new Date(b.releaseDate || 0) - new Date(a.releaseDate || 0)); (a, b) => new Date(b.releaseDate || 0) - new Date(a.releaseDate || 0)
);
// Enrich tracks with album release dates // Enrich tracks with album release dates
const tracks = options.lightweight ? topTracks : await this.enrichTracksWithAlbumDates(topTracks); const tracks = options.lightweight ? topTracks : await this.enrichTracksWithAlbumDates(topTracks);
@ -1281,8 +1282,8 @@ export class LosslessAPI {
return null; return null;
}; };
const manifest = isVideo const manifest = isVideo
? (findValue(lookup, 'manifest') || findValue(lookup, 'Manifest')) ? findValue(lookup, 'manifest') || findValue(lookup, 'Manifest')
: lookup.info?.manifest; : lookup.info?.manifest;
if (!manifest) { if (!manifest) {
@ -1325,7 +1326,8 @@ export class LosslessAPI {
console.error('HLS download failed:', hlsError); console.error('HLS download failed:', hlsError);
throw hlsError; throw hlsError;
} }
} else { const response = await fetch(streamUrl, { } else {
const response = await fetch(streamUrl, {
cache: 'no-store', cache: 'no-store',
signal: options.signal, signal: options.signal,
}); });
@ -1389,38 +1391,38 @@ export class LosslessAPI {
} }
} }
if (quality.endsWith('LOSSLESS')) { if (quality.endsWith('LOSSLESS')) {
try { try {
switch (losslessContainerSettings.getContainer()) { switch (losslessContainerSettings.getContainer()) {
case 'flac': case 'flac':
if ((await getExtensionFromBlob(blob)) != 'flac') { if ((await getExtensionFromBlob(blob)) != 'flac') {
blob = await ffmpeg(
blob,
{ args: ['-vn', '-map_metadata', '-1', '-map', '0:a', '-c:a', 'flac'] },
'output.flac',
'audio/flac',
onProgress,
options.signal
);
}
break;
case 'alac':
blob = await ffmpeg( blob = await ffmpeg(
blob, blob,
{ args: ['-vn', '-map_metadata', '-1', '-map', '0:a', '-c:a', 'flac'] }, { args: ['-c:a', 'alac'] },
'output.flac', 'output.m4a',
'audio/flac', 'audio/mp4',
onProgress, onProgress,
options.signal options.signal
); );
} break;
break; default:
case 'alac': break;
blob = await ffmpeg( }
blob, } catch (error) {
{ args: ['-c:a', 'alac'] }, if (error?.name === 'AbortError') {
'output.m4a', throw error;
'audio/mp4', }
onProgress,
options.signal
);
break;
default:
break;
}
} catch (error) {
if (error?.name === 'AbortError') {
throw error;
}
console.error('Lossless container conversion failed:', error); console.error('Lossless container conversion failed:', error);
} }

View file

@ -1074,7 +1074,10 @@ export async function handleTrackAction(
trackDataStore.set(newEl, item); trackDataStore.set(newEl, item);
ui.updateLikeState(newEl, 'video', item.id); ui.updateLikeState(newEl, 'video', item.id);
newEl.addEventListener('click', (e) => { newEl.addEventListener('click', (e) => {
if (e.target.closest('.card-play-btn') || e.target.closest('.card-image-container')) { if (
e.target.closest('.card-play-btn') ||
e.target.closest('.card-image-container')
) {
e.stopPropagation(); e.stopPropagation();
player.playVideo(item); player.playVideo(item);
} }

View file

@ -8,7 +8,7 @@ export class HlsDownloader {
const masterText = await response.text(); const masterText = await response.text();
const variantUrl = this.getBestVariantUrl(masterUrl, masterText); const variantUrl = this.getBestVariantUrl(masterUrl, masterText);
const mediaResponse = await fetch(variantUrl, { signal }); const mediaResponse = await fetch(variantUrl, { signal });
const mediaText = await mediaResponse.text(); const mediaText = await mediaResponse.text();

View file

@ -166,7 +166,7 @@ export class MusicAPI {
const data = await response.json(); const data = await response.json();
const result = { const result = {
videoUrl: data.videoUrl || null, videoUrl: data.videoUrl || null,
hlsUrl: data.animated || null hlsUrl: data.animated || null,
}; };
this.videoArtworkCache.set(cacheKey, result); this.videoArtworkCache.set(cacheKey, result);
return result; return result;

View file

@ -203,7 +203,8 @@ export class Player {
if (coverEl) { if (coverEl) {
const videoCoverUrl = track.videoUrl || track.videoCoverUrl || track.album?.videoCoverUrl || null; const videoCoverUrl = track.videoUrl || track.videoCoverUrl || track.album?.videoCoverUrl || null;
const coverUrl = videoCoverUrl || this.api.getCoverUrl(track.image || track.cover || track.album?.cover); const coverUrl =
videoCoverUrl || this.api.getCoverUrl(track.image || track.cover || track.album?.cover);
if (videoCoverUrl) { if (videoCoverUrl) {
if (coverEl.tagName === 'IMG') { if (coverEl.tagName === 'IMG') {
@ -453,7 +454,7 @@ export class Player {
...video, ...video,
type: 'video', type: 'video',
artist: video.artist || (video.artists && video.artists[0]) || 'Unknown Artist', artist: video.artist || (video.artists && video.artists[0]) || 'Unknown Artist',
album: video.album || { title: 'Video', cover: video.image || video.cover } album: video.album || { title: 'Video', cover: video.image || video.cover },
}; };
this.setQueue([videoTrack], 0); this.setQueue([videoTrack], 0);
await this.playTrackFromQueue(); await this.playTrackFromQueue();
@ -490,12 +491,12 @@ export class Player {
const trackInfo = document.querySelector('.now-playing-bar .track-info'); const trackInfo = document.querySelector('.now-playing-bar .track-info');
const coverEl = trackInfo?.querySelector('.cover:not(#audio-player)'); const coverEl = trackInfo?.querySelector('.cover:not(#audio-player)');
if (track.type === 'video') { if (track.type === 'video') {
if (coverEl) coverEl.style.display = 'none'; if (coverEl) coverEl.style.display = 'none';
if (this.audio) { if (this.audio) {
const isInFullscreen = document.getElementById('fullscreen-cover-overlay')?.style.display === 'flex'; const isInFullscreen = document.getElementById('fullscreen-cover-overlay')?.style.display === 'flex';
if (!isInFullscreen) { if (!isInFullscreen) {
this.audio.style.display = 'block'; this.audio.style.display = 'block';
this.audio.className = 'cover video-cover-mirror'; this.audio.className = 'cover video-cover-mirror';

View file

@ -2143,9 +2143,7 @@ export function initializeSettings(scrobbler, player, api, ui) {
const newDimming = parseFloat(e.target.value); const newDimming = parseFloat(e.target.value);
visualizerSettings.setDimAmount(newDimming); visualizerSettings.setDimAmount(newDimming);
visualizerDimmingValue.textContent = `${(newDimming * 100).toFixed(0)}%`; visualizerDimmingValue.textContent = `${(newDimming * 100).toFixed(0)}%`;
window.dispatchEvent( window.dispatchEvent(new CustomEvent('visualizer-dim-change', { detail: { dimAmount: newDimming } }));
new CustomEvent('visualizer-dim-change', { detail: { dimAmount: newDimming } })
);
}); });
} }

114
js/ui.js
View file

@ -343,7 +343,7 @@ export class UIRenderer {
const isUnavailable = track.isUnavailable; const isUnavailable = track.isUnavailable;
const isBlocked = contentBlockingSettings?.shouldHideTrack(track); const isBlocked = contentBlockingSettings?.shouldHideTrack(track);
const isVideo = track.type === 'video'; const isVideo = track.type === 'video';
let trackImageHTML = ''; let trackImageHTML = '';
if (showCover) { if (showCover) {
if (isVideo && this.currentPage === 'playlist') { if (isVideo && this.currentPage === 'playlist') {
@ -351,7 +351,12 @@ export class UIRenderer {
} else if (isVideo && (this.currentPage === 'search' || this.currentPage === 'library')) { } else if (isVideo && (this.currentPage === 'search' || this.currentPage === 'library')) {
trackImageHTML = `<div class="track-item-cover video-icon-placeholder" style="display: flex; align-items: center; justify-content: center; background: var(--secondary);"><svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor" style="opacity: 0.7;"><path d="M8 5v14l11-7z"/></svg></div>`; trackImageHTML = `<div class="track-item-cover video-icon-placeholder" style="display: flex; align-items: center; justify-content: center; background: var(--secondary);"><svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor" style="opacity: 0.7;"><path d="M8 5v14l11-7z"/></svg></div>`;
} else { } else {
trackImageHTML = this.getCoverHTML(track.image || track.cover || track.album?.cover, 'Track Cover', 'track-item-cover', 'lazy'); trackImageHTML = this.getCoverHTML(
track.image || track.cover || track.album?.cover,
'Track Cover',
'track-item-cover',
'lazy'
);
} }
} }
@ -365,7 +370,9 @@ export class UIRenderer {
displayIndex = index + 1; displayIndex = index + 1;
} }
const videoIcon = isVideo ? '<span class="video-item-icon" title="Music Video" style="display: inline-flex; align-items: center; margin-right: 4px; color: var(--muted-foreground);"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m22 8-6 4 6 4V8Z"/><rect width="14" height="12" x="2" y="6" rx="2" ry="2"/></svg></span>' : ''; const videoIcon = isVideo
? '<span class="video-item-icon" title="Music Video" style="display: inline-flex; align-items: center; margin-right: 4px; color: var(--muted-foreground);"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m22 8-6 4 6 4V8Z"/><rect width="14" height="12" x="2" y="6" rx="2" ry="2"/></svg></span>'
: '';
const trackNumberHTML = `<div class="track-number">${showCover ? trackImageHTML : displayIndex}</div>`; const trackNumberHTML = `<div class="track-number">${showCover ? trackImageHTML : displayIndex}</div>`;
const explicitBadge = hasExplicitContent(track) ? this.createExplicitBadge() : ''; const explicitBadge = hasExplicitContent(track) ? this.createExplicitBadge() : '';
const qualityBadge = createQualityBadgeHTML(track); const qualityBadge = createQualityBadgeHTML(track);
@ -638,7 +645,13 @@ export class UIRenderer {
href: `/album/${album.id}`, href: `/album/${album.id}`,
title: `${escapeHtml(album.title)} ${explicitBadge} ${qualityBadge}`, title: `${escapeHtml(album.title)} ${explicitBadge} ${qualityBadge}`,
subtitle: `${escapeHtml(artistName)}${yearDisplay}${typeLabel}`, subtitle: `${escapeHtml(artistName)}${yearDisplay}${typeLabel}`,
imageHTML: this.getCoverHTML(album.cover, escapeHtml(album.title), 'card-image', 'lazy', album.videoCoverUrl), imageHTML: this.getCoverHTML(
album.cover,
escapeHtml(album.title),
'card-image',
'lazy',
album.videoCoverUrl
),
actionButtonsHTML: ` actionButtonsHTML: `
<button class="like-btn card-like-btn" data-action="toggle-like" data-type="album" title="Add to Liked"> <button class="like-btn card-like-btn" data-action="toggle-like" data-type="album" title="Add to Liked">
${this.createHeartIcon(false)} ${this.createHeartIcon(false)}
@ -655,10 +668,10 @@ export class UIRenderer {
createVideoCardHTML(video) { createVideoCardHTML(video) {
const duration = formatTime(video.duration); const duration = formatTime(video.duration);
const artistName = getTrackArtists(video); const artistName = getTrackArtists(video);
const cover = video.image || video.cover; const cover = video.image || video.cover;
let imageHTML; let imageHTML;
if (cover) { if (cover) {
imageHTML = this.getCoverHTML(cover, escapeHtml(video.title)); imageHTML = this.getCoverHTML(cover, escapeHtml(video.title));
} else { } else {
@ -998,7 +1011,8 @@ export class UIRenderer {
if (image) image.style.display = 'block'; if (image) image.style.display = 'block';
if (visualizerContainer) visualizerContainer.style.display = 'block'; if (visualizerContainer) visualizerContainer.style.display = 'block';
const videoCoverUrl = track.videoUrl || track.videoCoverUrl || track.album?.videoCoverUrl || null; const coverUrl = videoCoverUrl || this.api.getCoverUrl(track.album?.cover, '1280'); const videoCoverUrl = track.videoUrl || track.videoCoverUrl || track.album?.videoCoverUrl || null;
const coverUrl = videoCoverUrl || this.api.getCoverUrl(track.album?.cover, '1280');
const fsLikeBtn = document.getElementById('fs-like-btn'); const fsLikeBtn = document.getElementById('fs-like-btn');
if (fsLikeBtn) { if (fsLikeBtn) {
@ -1150,10 +1164,10 @@ export class UIRenderer {
const coverContainer = document.querySelector('.now-playing-bar .track-info'); const coverContainer = document.querySelector('.now-playing-bar .track-info');
const audioPlayer = document.getElementById('audio-player'); const audioPlayer = document.getElementById('audio-player');
const imgCover = coverContainer?.querySelector('.cover:not(#audio-player)'); const imgCover = coverContainer?.querySelector('.cover:not(#audio-player)');
if (audioPlayer && coverContainer) { if (audioPlayer && coverContainer) {
if (imgCover) imgCover.style.display = 'none'; if (imgCover) imgCover.style.display = 'none';
audioPlayer.style.display = 'block'; audioPlayer.style.display = 'block';
audioPlayer.classList.add('cover', 'video-cover-mirror'); audioPlayer.classList.add('cover', 'video-cover-mirror');
audioPlayer.style.width = '56px'; audioPlayer.style.width = '56px';
@ -1161,7 +1175,7 @@ export class UIRenderer {
audioPlayer.style.borderRadius = 'var(--radius-sm)'; audioPlayer.style.borderRadius = 'var(--radius-sm)';
audioPlayer.style.objectFit = 'cover'; audioPlayer.style.objectFit = 'cover';
audioPlayer.style.gridArea = 'none'; audioPlayer.style.gridArea = 'none';
if (audioPlayer.parentElement !== coverContainer) { if (audioPlayer.parentElement !== coverContainer) {
coverContainer.insertBefore(audioPlayer, coverContainer.firstChild); coverContainer.insertBefore(audioPlayer, coverContainer.firstChild);
} }
@ -1752,7 +1766,9 @@ export class UIRenderer {
if (myPlaylistsContainer) { if (myPlaylistsContainer) {
if (visiblePlaylists.length) { if (visiblePlaylists.length) {
myPlaylistsContainer.innerHTML = visiblePlaylists.map((p) => this.createUserPlaylistCardHTML(p)).join(''); myPlaylistsContainer.innerHTML = visiblePlaylists
.map((p) => this.createUserPlaylistCardHTML(p))
.join('');
visiblePlaylists.forEach((playlist) => { visiblePlaylists.forEach((playlist) => {
const el = myPlaylistsContainer.querySelector(`[data-user-playlist-id="${playlist.id}"]`); const el = myPlaylistsContainer.querySelector(`[data-user-playlist-id="${playlist.id}"]`);
if (el) { if (el) {
@ -2231,7 +2247,13 @@ export class UIRenderer {
href: `/track/${track.id}`, href: `/track/${track.id}`,
title: `${escapeHtml(getTrackTitle(track))} ${explicitBadge} ${qualityBadge}`, title: `${escapeHtml(getTrackTitle(track))} ${explicitBadge} ${qualityBadge}`,
subtitle: escapeHtml(getTrackArtists(track)), subtitle: escapeHtml(getTrackArtists(track)),
imageHTML: this.getCoverHTML(track.album?.cover, escapeHtml(track.title), 'card-image', 'lazy', track.videoUrl || track.album?.videoCoverUrl), imageHTML: this.getCoverHTML(
track.album?.cover,
escapeHtml(track.title),
'card-image',
'lazy',
track.videoUrl || track.album?.videoCoverUrl
),
actionButtonsHTML: ` actionButtonsHTML: `
<button class="like-btn card-like-btn" data-action="toggle-like" data-type="track" title="Add to Liked"> <button class="like-btn card-like-btn" data-action="toggle-like" data-type="track" title="Add to Liked">
${this.createHeartIcon(false)} ${this.createHeartIcon(false)}
@ -2634,19 +2656,23 @@ export class UIRenderer {
video.replaceWith(img); video.replaceWith(img);
}; };
video.addEventListener('error', (e) => { video.addEventListener(
if (video.src === result.videoUrl && result.hlsUrl) { 'error',
this.setupHlsVideo(video, { videoUrl: null, hlsUrl: result.hlsUrl }, img); (e) => {
return; if (video.src === result.videoUrl && result.hlsUrl) {
} this.setupHlsVideo(video, { videoUrl: null, hlsUrl: result.hlsUrl }, img);
console.warn('Video decoding error:', e); return;
video.replaceWith(img); }
}, true); console.warn('Video decoding error:', e);
video.replaceWith(img);
},
true
);
img.replaceWith(video); img.replaceWith(video);
this.setupHlsVideo(video, result, img); this.setupHlsVideo(video, result, img);
// If HLS, dont play // If HLS, dont play
const hls = video._hls; const hls = video._hls;
if (hls) { if (hls) {
@ -2932,7 +2958,8 @@ export class UIRenderer {
this.setupHlsVideo(video, result, currentImageEl); this.setupHlsVideo(video, result, currentImageEl);
currentImageEl.replaceWith(video); currentImageEl.replaceWith(video);
} } }
}
}); });
} }
@ -3696,7 +3723,8 @@ export class UIRenderer {
// Try to get cover from first track album // Try to get cover from first track album
if (tracks.length > 0 && tracks[0].album?.cover) { if (tracks.length > 0 && tracks[0].album?.cover) {
const firstTrack = tracks[0]; const firstTrack = tracks[0];
let videoCoverUrl = firstTrack.videoUrl || firstTrack.videoCoverUrl || firstTrack.album?.videoCoverUrl || null; let videoCoverUrl =
firstTrack.videoUrl || firstTrack.videoCoverUrl || firstTrack.album?.videoCoverUrl || null;
if (!videoCoverUrl && (firstTrack.album || firstTrack.type === 'video')) { if (!videoCoverUrl && (firstTrack.album || firstTrack.type === 'video')) {
const fetchArtwork = () => { const fetchArtwork = () => {
@ -3727,14 +3755,17 @@ export class UIRenderer {
}; };
if (firstTrack.type === 'video') { if (firstTrack.type === 'video') {
this.api.getVideoStreamUrl(firstTrack.id).then((url) => { this.api
if (url) { .getVideoStreamUrl(firstTrack.id)
firstTrack.videoUrl = url; .then((url) => {
this.renderMixPage(mixId); if (url) {
} else { firstTrack.videoUrl = url;
fetchArtwork(); this.renderMixPage(mixId);
} } else {
}).catch(fetchArtwork); fetchArtwork();
}
})
.catch(fetchArtwork);
} else { } else {
fetchArtwork(); fetchArtwork();
} }
@ -4833,14 +4864,17 @@ export class UIRenderer {
}; };
if (track.type === 'video') { if (track.type === 'video') {
this.api.getVideoStreamUrl(track.id).then((url) => { this.api
if (url) { .getVideoStreamUrl(track.id)
track.videoUrl = url; .then((url) => {
this.renderTrackPage(trackId, provider); if (url) {
} else { track.videoUrl = url;
fetchArtwork(); this.renderTrackPage(trackId, provider);
} } else {
}).catch(fetchArtwork); fetchArtwork();
}
})
.catch(fetchArtwork);
} else { } else {
fetchArtwork(); fetchArtwork();
} }

View file

@ -5348,7 +5348,7 @@ img[src=''] {
align-items: flex-start; align-items: flex-start;
padding: 2rem 2rem 6rem; padding: 2rem 2rem 6rem;
pointer-events: none; pointer-events: none;
background: linear-gradient(to top, rgba(0,0,0,0.6) 0%, rgba(0,0,0,0.2) 15%, transparent 40%); background: linear-gradient(to top, rgb(0, 0, 0, 0.6) 0%, rgb(0, 0, 0, 0.2) 15%, transparent 40%);
} }
#fullscreen-cover-overlay.is-video-mode .fullscreen-track-info { #fullscreen-cover-overlay.is-video-mode .fullscreen-track-info {
@ -5366,13 +5366,13 @@ img[src=''] {
#fullscreen-cover-overlay.is-video-mode #fullscreen-track-title { #fullscreen-cover-overlay.is-video-mode #fullscreen-track-title {
font-size: 1.1rem; font-size: 1.1rem;
font-weight: 600; font-weight: 600;
text-shadow: 0 1px 3px rgba(0,0,0,0.8); text-shadow: 0 1px 3px rgb(0, 0, 0, 0.8);
margin-bottom: 0.1rem; margin-bottom: 0.1rem;
} }
#fullscreen-cover-overlay.is-video-mode #fullscreen-track-artist { #fullscreen-cover-overlay.is-video-mode #fullscreen-track-artist {
font-size: 0.9rem; font-size: 0.9rem;
text-shadow: 0 1px 2px rgba(0,0,0,0.8); text-shadow: 0 1px 2px rgb(0, 0, 0, 0.8);
opacity: 0.7; opacity: 0.7;
} }
@ -5383,13 +5383,15 @@ img[src=''] {
right: 2rem; right: 2rem;
max-width: 500px; max-width: 500px;
margin: 0 auto; margin: 0 auto;
background: rgba(15, 15, 15, 0.5); background: rgb(15, 15, 15, 0.5);
backdrop-filter: blur(12px); backdrop-filter: blur(12px);
padding: 0.6rem 1rem; padding: 0.6rem 1rem;
border-radius: 10px; border-radius: 10px;
border: 1px solid rgba(255, 255, 255, 0.05); border: 1px solid rgb(255, 255, 255, 0.05);
box-shadow: 0 4px 20px rgba(0,0,0,0.4); box-shadow: 0 4px 20px rgb(0, 0, 0, 0.4);
transition: transform 0.4s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.4s ease; transition:
transform 0.4s cubic-bezier(0.4, 0, 0.2, 1),
opacity 0.4s ease;
pointer-events: auto; pointer-events: auto;
z-index: 100; z-index: 100;
} }
@ -5427,7 +5429,6 @@ img[src=''] {
margin-top: 0.5rem; margin-top: 0.5rem;
} }
#fullscreen-cover-overlay.ui-hidden .fullscreen-main-view, #fullscreen-cover-overlay.ui-hidden .fullscreen-main-view,
#fullscreen-cover-overlay.ui-hidden .fullscreen-controls, #fullscreen-cover-overlay.ui-hidden .fullscreen-controls,
#fullscreen-cover-overlay.ui-hidden #fullscreen-next-track, #fullscreen-cover-overlay.ui-hidden #fullscreen-next-track,
@ -8150,7 +8151,7 @@ body:has(#side-panel.active) #close-fullscreen-cover-btn {
position: absolute; position: absolute;
bottom: 8px; bottom: 8px;
right: 8px; right: 8px;
background: rgba(0, 0, 0, 0.7); background: rgb(0, 0, 0, 0.7);
color: white; color: white;
padding: 2px 6px; padding: 2px 6px;
border-radius: 4px; border-radius: 4px;
@ -8178,7 +8179,7 @@ body:has(#side-panel.active) #close-fullscreen-cover-btn {
object-fit: contain; object-fit: contain;
} }
.search-tab[data-tab="videos"] { .search-tab[data-tab='videos'] {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 0.5rem; gap: 0.5rem;