Merge branch 'main' of github.com:monochrome-music/monochrome
This commit is contained in:
commit
0662796d73
10 changed files with 154 additions and 101 deletions
20
index.html
20
index.html
|
|
@ -124,7 +124,20 @@
|
|||
<div id="visualizer-container">
|
||||
<canvas id="visualizer-canvas"></canvas>
|
||||
</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">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
|
|
@ -168,7 +181,6 @@
|
|||
/>
|
||||
|
||||
<div class="fullscreen-track-info">
|
||||
|
||||
<h2 id="fullscreen-track-title"></h2>
|
||||
<h3 id="fullscreen-track-artist"></h3>
|
||||
<div class="fullscreen-actions">
|
||||
|
|
@ -3771,8 +3783,8 @@
|
|||
<div class="info">
|
||||
<span class="label">Visualizer Brightness</span>
|
||||
<span class="description"
|
||||
>Adjust the brightness of the visualizer. Lower this if the visualizer
|
||||
is too bright for you.</span
|
||||
>Adjust the brightness of the visualizer. Lower this if the visualizer is
|
||||
too bright for you.</span
|
||||
>
|
||||
</div>
|
||||
<div style="display: flex; align-items: center; gap: 10px">
|
||||
|
|
|
|||
|
|
@ -585,7 +585,9 @@ const syncManager = {
|
|||
id: playlist.id,
|
||||
name: playlist.name,
|
||||
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(),
|
||||
updatedAt: playlist.updatedAt || Date.now(),
|
||||
numberOfTracks: playlist.tracks ? playlist.tracks.length : 0,
|
||||
|
|
|
|||
74
js/api.js
74
js/api.js
|
|
@ -892,10 +892,10 @@ export class LosslessAPI {
|
|||
const numericArtistId = Number(artistId);
|
||||
for (const item of videoSearch.items) {
|
||||
const itemArtistId = item.artist?.id;
|
||||
const matchesArtist =
|
||||
itemArtistId === numericArtistId ||
|
||||
(Array.isArray(item.artists) && item.artists.some(a => a.id === numericArtistId));
|
||||
|
||||
const matchesArtist =
|
||||
itemArtistId === numericArtistId ||
|
||||
(Array.isArray(item.artists) && item.artists.some((a) => a.id === numericArtistId));
|
||||
|
||||
if (matchesArtist && !videoMap.has(item.id)) {
|
||||
videoMap.set(item.id, item);
|
||||
}
|
||||
|
|
@ -918,8 +918,9 @@ export class LosslessAPI {
|
|||
.sort((a, b) => (b.popularity || 0) - (a.popularity || 0))
|
||||
.slice(0, 15);
|
||||
|
||||
const videos = Array.from(videoMap.values())
|
||||
.sort((a, b) => new Date(b.releaseDate || 0) - new Date(a.releaseDate || 0));
|
||||
const videos = Array.from(videoMap.values()).sort(
|
||||
(a, b) => new Date(b.releaseDate || 0) - new Date(a.releaseDate || 0)
|
||||
);
|
||||
|
||||
// Enrich tracks with album release dates
|
||||
const tracks = options.lightweight ? topTracks : await this.enrichTracksWithAlbumDates(topTracks);
|
||||
|
|
@ -1281,8 +1282,8 @@ export class LosslessAPI {
|
|||
return null;
|
||||
};
|
||||
|
||||
const manifest = isVideo
|
||||
? (findValue(lookup, 'manifest') || findValue(lookup, 'Manifest'))
|
||||
const manifest = isVideo
|
||||
? findValue(lookup, 'manifest') || findValue(lookup, 'Manifest')
|
||||
: lookup.info?.manifest;
|
||||
|
||||
if (!manifest) {
|
||||
|
|
@ -1325,7 +1326,8 @@ export class LosslessAPI {
|
|||
console.error('HLS download failed:', hlsError);
|
||||
throw hlsError;
|
||||
}
|
||||
} else { const response = await fetch(streamUrl, {
|
||||
} else {
|
||||
const response = await fetch(streamUrl, {
|
||||
cache: 'no-store',
|
||||
signal: options.signal,
|
||||
});
|
||||
|
|
@ -1389,38 +1391,38 @@ export class LosslessAPI {
|
|||
}
|
||||
}
|
||||
|
||||
if (quality.endsWith('LOSSLESS')) {
|
||||
try {
|
||||
switch (losslessContainerSettings.getContainer()) {
|
||||
case 'flac':
|
||||
if ((await getExtensionFromBlob(blob)) != 'flac') {
|
||||
if (quality.endsWith('LOSSLESS')) {
|
||||
try {
|
||||
switch (losslessContainerSettings.getContainer()) {
|
||||
case '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,
|
||||
{ args: ['-vn', '-map_metadata', '-1', '-map', '0:a', '-c:a', 'flac'] },
|
||||
'output.flac',
|
||||
'audio/flac',
|
||||
{ args: ['-c:a', 'alac'] },
|
||||
'output.m4a',
|
||||
'audio/mp4',
|
||||
onProgress,
|
||||
options.signal
|
||||
);
|
||||
}
|
||||
break;
|
||||
case 'alac':
|
||||
blob = await ffmpeg(
|
||||
blob,
|
||||
{ args: ['-c:a', 'alac'] },
|
||||
'output.m4a',
|
||||
'audio/mp4',
|
||||
onProgress,
|
||||
options.signal
|
||||
);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} catch (error) {
|
||||
if (error?.name === 'AbortError') {
|
||||
throw error;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} catch (error) {
|
||||
if (error?.name === 'AbortError') {
|
||||
throw error;
|
||||
}
|
||||
|
||||
console.error('Lossless container conversion failed:', error);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1074,7 +1074,10 @@ export async function handleTrackAction(
|
|||
trackDataStore.set(newEl, item);
|
||||
ui.updateLikeState(newEl, 'video', item.id);
|
||||
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();
|
||||
player.playVideo(item);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ export class HlsDownloader {
|
|||
const masterText = await response.text();
|
||||
|
||||
const variantUrl = this.getBestVariantUrl(masterUrl, masterText);
|
||||
|
||||
|
||||
const mediaResponse = await fetch(variantUrl, { signal });
|
||||
const mediaText = await mediaResponse.text();
|
||||
|
||||
|
|
|
|||
|
|
@ -166,7 +166,7 @@ export class MusicAPI {
|
|||
const data = await response.json();
|
||||
const result = {
|
||||
videoUrl: data.videoUrl || null,
|
||||
hlsUrl: data.animated || null
|
||||
hlsUrl: data.animated || null,
|
||||
};
|
||||
this.videoArtworkCache.set(cacheKey, result);
|
||||
return result;
|
||||
|
|
|
|||
|
|
@ -203,7 +203,8 @@ export class Player {
|
|||
|
||||
if (coverEl) {
|
||||
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 (coverEl.tagName === 'IMG') {
|
||||
|
|
@ -453,7 +454,7 @@ export class Player {
|
|||
...video,
|
||||
type: 'video',
|
||||
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);
|
||||
await this.playTrackFromQueue();
|
||||
|
|
@ -490,12 +491,12 @@ export class Player {
|
|||
|
||||
const trackInfo = document.querySelector('.now-playing-bar .track-info');
|
||||
const coverEl = trackInfo?.querySelector('.cover:not(#audio-player)');
|
||||
|
||||
|
||||
if (track.type === 'video') {
|
||||
if (coverEl) coverEl.style.display = 'none';
|
||||
if (this.audio) {
|
||||
const isInFullscreen = document.getElementById('fullscreen-cover-overlay')?.style.display === 'flex';
|
||||
|
||||
|
||||
if (!isInFullscreen) {
|
||||
this.audio.style.display = 'block';
|
||||
this.audio.className = 'cover video-cover-mirror';
|
||||
|
|
|
|||
|
|
@ -2143,9 +2143,7 @@ export function initializeSettings(scrobbler, player, api, ui) {
|
|||
const newDimming = parseFloat(e.target.value);
|
||||
visualizerSettings.setDimAmount(newDimming);
|
||||
visualizerDimmingValue.textContent = `${(newDimming * 100).toFixed(0)}%`;
|
||||
window.dispatchEvent(
|
||||
new CustomEvent('visualizer-dim-change', { detail: { dimAmount: newDimming } })
|
||||
);
|
||||
window.dispatchEvent(new CustomEvent('visualizer-dim-change', { detail: { dimAmount: newDimming } }));
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
114
js/ui.js
114
js/ui.js
|
|
@ -343,7 +343,7 @@ export class UIRenderer {
|
|||
const isUnavailable = track.isUnavailable;
|
||||
const isBlocked = contentBlockingSettings?.shouldHideTrack(track);
|
||||
const isVideo = track.type === 'video';
|
||||
|
||||
|
||||
let trackImageHTML = '';
|
||||
if (showCover) {
|
||||
if (isVideo && this.currentPage === 'playlist') {
|
||||
|
|
@ -351,7 +351,12 @@ export class UIRenderer {
|
|||
} 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>`;
|
||||
} 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;
|
||||
}
|
||||
|
||||
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 explicitBadge = hasExplicitContent(track) ? this.createExplicitBadge() : '';
|
||||
const qualityBadge = createQualityBadgeHTML(track);
|
||||
|
|
@ -638,7 +645,13 @@ export class UIRenderer {
|
|||
href: `/album/${album.id}`,
|
||||
title: `${escapeHtml(album.title)} ${explicitBadge} ${qualityBadge}`,
|
||||
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: `
|
||||
<button class="like-btn card-like-btn" data-action="toggle-like" data-type="album" title="Add to Liked">
|
||||
${this.createHeartIcon(false)}
|
||||
|
|
@ -655,10 +668,10 @@ export class UIRenderer {
|
|||
createVideoCardHTML(video) {
|
||||
const duration = formatTime(video.duration);
|
||||
const artistName = getTrackArtists(video);
|
||||
|
||||
|
||||
const cover = video.image || video.cover;
|
||||
let imageHTML;
|
||||
|
||||
|
||||
if (cover) {
|
||||
imageHTML = this.getCoverHTML(cover, escapeHtml(video.title));
|
||||
} else {
|
||||
|
|
@ -998,7 +1011,8 @@ export class UIRenderer {
|
|||
if (image) image.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');
|
||||
if (fsLikeBtn) {
|
||||
|
|
@ -1150,10 +1164,10 @@ export class UIRenderer {
|
|||
const coverContainer = document.querySelector('.now-playing-bar .track-info');
|
||||
const audioPlayer = document.getElementById('audio-player');
|
||||
const imgCover = coverContainer?.querySelector('.cover:not(#audio-player)');
|
||||
|
||||
|
||||
if (audioPlayer && coverContainer) {
|
||||
if (imgCover) imgCover.style.display = 'none';
|
||||
|
||||
|
||||
audioPlayer.style.display = 'block';
|
||||
audioPlayer.classList.add('cover', 'video-cover-mirror');
|
||||
audioPlayer.style.width = '56px';
|
||||
|
|
@ -1161,7 +1175,7 @@ export class UIRenderer {
|
|||
audioPlayer.style.borderRadius = 'var(--radius-sm)';
|
||||
audioPlayer.style.objectFit = 'cover';
|
||||
audioPlayer.style.gridArea = 'none';
|
||||
|
||||
|
||||
if (audioPlayer.parentElement !== coverContainer) {
|
||||
coverContainer.insertBefore(audioPlayer, coverContainer.firstChild);
|
||||
}
|
||||
|
|
@ -1752,7 +1766,9 @@ export class UIRenderer {
|
|||
|
||||
if (myPlaylistsContainer) {
|
||||
if (visiblePlaylists.length) {
|
||||
myPlaylistsContainer.innerHTML = visiblePlaylists.map((p) => this.createUserPlaylistCardHTML(p)).join('');
|
||||
myPlaylistsContainer.innerHTML = visiblePlaylists
|
||||
.map((p) => this.createUserPlaylistCardHTML(p))
|
||||
.join('');
|
||||
visiblePlaylists.forEach((playlist) => {
|
||||
const el = myPlaylistsContainer.querySelector(`[data-user-playlist-id="${playlist.id}"]`);
|
||||
if (el) {
|
||||
|
|
@ -2231,7 +2247,13 @@ export class UIRenderer {
|
|||
href: `/track/${track.id}`,
|
||||
title: `${escapeHtml(getTrackTitle(track))} ${explicitBadge} ${qualityBadge}`,
|
||||
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: `
|
||||
<button class="like-btn card-like-btn" data-action="toggle-like" data-type="track" title="Add to Liked">
|
||||
${this.createHeartIcon(false)}
|
||||
|
|
@ -2634,19 +2656,23 @@ export class UIRenderer {
|
|||
video.replaceWith(img);
|
||||
};
|
||||
|
||||
video.addEventListener('error', (e) => {
|
||||
if (video.src === result.videoUrl && result.hlsUrl) {
|
||||
this.setupHlsVideo(video, { videoUrl: null, hlsUrl: result.hlsUrl }, img);
|
||||
return;
|
||||
}
|
||||
console.warn('Video decoding error:', e);
|
||||
video.replaceWith(img);
|
||||
}, true);
|
||||
video.addEventListener(
|
||||
'error',
|
||||
(e) => {
|
||||
if (video.src === result.videoUrl && result.hlsUrl) {
|
||||
this.setupHlsVideo(video, { videoUrl: null, hlsUrl: result.hlsUrl }, img);
|
||||
return;
|
||||
}
|
||||
console.warn('Video decoding error:', e);
|
||||
video.replaceWith(img);
|
||||
},
|
||||
true
|
||||
);
|
||||
|
||||
img.replaceWith(video);
|
||||
|
||||
|
||||
this.setupHlsVideo(video, result, img);
|
||||
|
||||
|
||||
// If HLS, dont play
|
||||
const hls = video._hls;
|
||||
if (hls) {
|
||||
|
|
@ -2932,7 +2958,8 @@ export class UIRenderer {
|
|||
|
||||
this.setupHlsVideo(video, result, currentImageEl);
|
||||
currentImageEl.replaceWith(video);
|
||||
} }
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -3696,7 +3723,8 @@ export class UIRenderer {
|
|||
// Try to get cover from first track album
|
||||
if (tracks.length > 0 && tracks[0].album?.cover) {
|
||||
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')) {
|
||||
const fetchArtwork = () => {
|
||||
|
|
@ -3727,14 +3755,17 @@ export class UIRenderer {
|
|||
};
|
||||
|
||||
if (firstTrack.type === 'video') {
|
||||
this.api.getVideoStreamUrl(firstTrack.id).then((url) => {
|
||||
if (url) {
|
||||
firstTrack.videoUrl = url;
|
||||
this.renderMixPage(mixId);
|
||||
} else {
|
||||
fetchArtwork();
|
||||
}
|
||||
}).catch(fetchArtwork);
|
||||
this.api
|
||||
.getVideoStreamUrl(firstTrack.id)
|
||||
.then((url) => {
|
||||
if (url) {
|
||||
firstTrack.videoUrl = url;
|
||||
this.renderMixPage(mixId);
|
||||
} else {
|
||||
fetchArtwork();
|
||||
}
|
||||
})
|
||||
.catch(fetchArtwork);
|
||||
} else {
|
||||
fetchArtwork();
|
||||
}
|
||||
|
|
@ -4833,14 +4864,17 @@ export class UIRenderer {
|
|||
};
|
||||
|
||||
if (track.type === 'video') {
|
||||
this.api.getVideoStreamUrl(track.id).then((url) => {
|
||||
if (url) {
|
||||
track.videoUrl = url;
|
||||
this.renderTrackPage(trackId, provider);
|
||||
} else {
|
||||
fetchArtwork();
|
||||
}
|
||||
}).catch(fetchArtwork);
|
||||
this.api
|
||||
.getVideoStreamUrl(track.id)
|
||||
.then((url) => {
|
||||
if (url) {
|
||||
track.videoUrl = url;
|
||||
this.renderTrackPage(trackId, provider);
|
||||
} else {
|
||||
fetchArtwork();
|
||||
}
|
||||
})
|
||||
.catch(fetchArtwork);
|
||||
} else {
|
||||
fetchArtwork();
|
||||
}
|
||||
|
|
|
|||
21
styles.css
21
styles.css
|
|
@ -5348,7 +5348,7 @@ img[src=''] {
|
|||
align-items: flex-start;
|
||||
padding: 2rem 2rem 6rem;
|
||||
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 {
|
||||
|
|
@ -5366,13 +5366,13 @@ img[src=''] {
|
|||
#fullscreen-cover-overlay.is-video-mode #fullscreen-track-title {
|
||||
font-size: 1.1rem;
|
||||
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;
|
||||
}
|
||||
|
||||
#fullscreen-cover-overlay.is-video-mode #fullscreen-track-artist {
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
@ -5383,13 +5383,15 @@ img[src=''] {
|
|||
right: 2rem;
|
||||
max-width: 500px;
|
||||
margin: 0 auto;
|
||||
background: rgba(15, 15, 15, 0.5);
|
||||
background: rgb(15, 15, 15, 0.5);
|
||||
backdrop-filter: blur(12px);
|
||||
padding: 0.6rem 1rem;
|
||||
border-radius: 10px;
|
||||
border: 1px solid rgba(255, 255, 255, 0.05);
|
||||
box-shadow: 0 4px 20px rgba(0,0,0,0.4);
|
||||
transition: transform 0.4s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.4s ease;
|
||||
border: 1px solid rgb(255, 255, 255, 0.05);
|
||||
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;
|
||||
pointer-events: auto;
|
||||
z-index: 100;
|
||||
}
|
||||
|
|
@ -5427,7 +5429,6 @@ img[src=''] {
|
|||
margin-top: 0.5rem;
|
||||
}
|
||||
|
||||
|
||||
#fullscreen-cover-overlay.ui-hidden .fullscreen-main-view,
|
||||
#fullscreen-cover-overlay.ui-hidden .fullscreen-controls,
|
||||
#fullscreen-cover-overlay.ui-hidden #fullscreen-next-track,
|
||||
|
|
@ -8150,7 +8151,7 @@ body:has(#side-panel.active) #close-fullscreen-cover-btn {
|
|||
position: absolute;
|
||||
bottom: 8px;
|
||||
right: 8px;
|
||||
background: rgba(0, 0, 0, 0.7);
|
||||
background: rgb(0, 0, 0, 0.7);
|
||||
color: white;
|
||||
padding: 2px 6px;
|
||||
border-radius: 4px;
|
||||
|
|
@ -8178,7 +8179,7 @@ body:has(#side-panel.active) #close-fullscreen-cover-btn {
|
|||
object-fit: contain;
|
||||
}
|
||||
|
||||
.search-tab[data-tab="videos"] {
|
||||
.search-tab[data-tab='videos'] {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
|
|
|
|||
Loading…
Reference in a new issue