Merge branch 'main' of github.com:SamidyFR/monochrome

This commit is contained in:
Samidy 2026-01-08 23:32:59 +03:00
commit cd30df8d6a
8 changed files with 86 additions and 58 deletions

View file

@ -250,13 +250,10 @@
<div id="page-library" class="page">
<section class="content-section">
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 1rem;">
<h2 class="section-title" style="margin-bottom: 0;">My Playlists</h2>
<div style="display: flex; gap: 0.5rem;">
<button id="create-playlist-btn" class="btn-secondary">Create Playlist</button>
</div>
</div>
<div class="library-header">
<h2>My Playlists</h2>
<button id="create-playlist-btn" class="btn-primary">Create Playlist</button>
</div>
<div class="card-grid" id="my-playlists-container"></div>
</section>
@ -814,7 +811,7 @@
<div class="player-actions-row">
<button id="now-playing-like-btn" class="like-btn" data-action="toggle-like" title="Save to Favorites" style="display: none;">
</button>
<button id="now-playing-add-playlist-btn" title="Add to Playlist" class="desktop-only">
<button id="now-playing-add-playlist-btn" title="Add to Playlist" class="desktop-only" style="display: none;">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"/>
<path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"/>
@ -825,7 +822,7 @@
<path d="M12 3v10.55c-.59-.34-1.27-.55-2-.55-2.21 0-4 1.79-4 4s1.79 4 4 4 4-1.79 4-4V7h4V3h-6z"/>
</svg>
</button>
<button id="toggle-lyrics-btn" title="Lyrics">
<button id="toggle-lyrics-btn" title="Lyrics" style="display: none;">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-mic"><path d="M12 2a3 3 0 0 0-3 3v7a3 3 0 0 0 6 0V5a3 3 0 0 0-3-3Z"/><path d="M19 10v2a7 7 0 0 1-14 0v-2"/><line x1="12" y1="19" x2="12" y2="22"/><line x1="8" y1="22" x2="16" y2="22"/></svg>
</button>
<button id="download-current-btn" title="Download current track" class="desktop-only">
@ -836,7 +833,7 @@
</svg>
</button>
<button id="mobile-add-playlist-btn" class="mobile-only">
<button id="mobile-add-playlist-btn" class="mobile-only" style="display: none !important;">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"/>
<path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"/>

View file

@ -301,10 +301,18 @@ document.addEventListener('DOMContentLoaded', async () => {
try {
let playlist, tracks;
const userPlaylist = await db.getPlaylist(playlistId);
let userPlaylist = await db.getPlaylist(playlistId);
if (!userPlaylist) {
try {
userPlaylist = await syncManager.getPublicPlaylist(playlistId);
} catch (e) {
// Not a public playlist
}
}
if (userPlaylist) {
playlist = { ...userPlaylist, title: userPlaylist.name };
playlist = { ...userPlaylist, title: userPlaylist.name || userPlaylist.title };
tracks = userPlaylist.tracks || [];
} else {
const data = await api.getPlaylist(playlistId);

View file

@ -399,8 +399,15 @@ export async function handleTrackAction(action, item, player, api, lyricsManager
const data = await api.getPlaylist(item.uuid);
tracks = data.tracks;
} else if (type === 'user-playlist') {
const playlist = await db.getPlaylist(item.id);
tracks = playlist ? playlist.tracks : [];
let playlist = await db.getPlaylist(item.id);
if (!playlist) {
try {
playlist = await syncManager.getPublicPlaylist(item.id);
} catch (e) {
// Ignore
}
}
tracks = playlist ? playlist.tracks : (item.tracks || []);
}
if (tracks.length > 0) {

View file

@ -574,35 +574,44 @@ export class Player {
updateSleepTimerUI() {
const timerBtn = document.getElementById('sleep-timer-btn');
if (!timerBtn) return;
if (this.isSleepTimerActive()) {
const remaining = this.getSleepTimerRemaining();
if (remaining > 0) {
const minutes = Math.floor(remaining / 60);
const seconds = remaining % 60;
timerBtn.innerHTML = `<span style="font-size: 12px; font-weight: bold;">${minutes}:${seconds.toString().padStart(2, '0')}</span>`;
timerBtn.title = `Sleep Timer: ${minutes}:${seconds.toString().padStart(2, '0')} remaining`;
timerBtn.classList.add('active');
const timerBtnDesktop = document.getElementById('sleep-timer-btn-desktop');
const updateBtn = (btn) => {
if (!btn) return;
if (this.isSleepTimerActive()) {
const remaining = this.getSleepTimerRemaining();
if (remaining > 0) {
const minutes = Math.floor(remaining / 60);
const seconds = remaining % 60;
btn.innerHTML = `<span style="font-size: 12px; font-weight: bold;">${minutes}:${seconds.toString().padStart(2, '0')}</span>`;
btn.title = `Sleep Timer: ${minutes}:${seconds.toString().padStart(2, '0')} remaining`;
btn.classList.add('active');
btn.style.color = 'var(--primary)';
} else {
btn.innerHTML = `
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<circle cx="12" cy="12" r="10"/>
<polyline points="12,6 12,12 16,14"/>
</svg>
`;
btn.title = 'Sleep Timer';
btn.classList.remove('active');
btn.style.color = '';
}
} else {
timerBtn.innerHTML = `
btn.innerHTML = `
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<circle cx="12" cy="12" r="10"/>
<polyline points="12,6 12,12 16,14"/>
</svg>
`;
timerBtn.title = 'Sleep Timer';
timerBtn.classList.remove('active');
btn.title = 'Sleep Timer';
btn.classList.remove('active');
btn.style.color = '';
}
} else {
timerBtn.innerHTML = `
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<circle cx="12" cy="12" r="10"/>
<polyline points="12,6 12,12 16,14"/>
</svg>
`;
timerBtn.title = 'Sleep Timer';
timerBtn.classList.remove('active');
}
};
updateBtn(timerBtn);
updateBtn(timerBtnDesktop);
}
}

View file

@ -53,7 +53,10 @@ export const apiSettings = {
} catch (error) {
console.error('Failed to load instances from GitHub:', error);
this.defaultInstances = {
api: ["https://monochrome-api.samidy.com"],
api: [
"https://tidal-api.binimum.org",
"https://monochrome-api.samidy.com"
],
streaming: [
"https://triton.squid.wtf",
"https://wolf.qqdl.site",
@ -63,7 +66,7 @@ export const apiSettings = {
"https://hund.qqdl.site",
"https://tidal.kinoplus.online",
"https://tidal-api.binimum.org"
]
]
};
this.instancesLoaded = true;
return this.defaultInstances;

View file

@ -81,14 +81,23 @@ export class UIRenderer {
this.updateGlobalTheme();
const likeBtn = document.getElementById('now-playing-like-btn');
if (likeBtn) {
if (track) {
const addPlaylistBtn = document.getElementById('now-playing-add-playlist-btn');
const mobileAddPlaylistBtn = document.getElementById('mobile-add-playlist-btn');
const lyricsBtn = document.getElementById('toggle-lyrics-btn');
if (track) {
if (likeBtn) {
likeBtn.style.display = 'flex';
// Use the centralized update logic if possible, or manual here
this.updateLikeState(likeBtn.parentElement, 'track', track.id);
} else {
likeBtn.style.display = 'none';
}
if (addPlaylistBtn) addPlaylistBtn.style.removeProperty('display');
if (mobileAddPlaylistBtn) mobileAddPlaylistBtn.style.removeProperty('display');
if (lyricsBtn) lyricsBtn.style.removeProperty('display');
} else {
if (likeBtn) likeBtn.style.display = 'none';
if (addPlaylistBtn) addPlaylistBtn.style.setProperty('display', 'none', 'important');
if (mobileAddPlaylistBtn) mobileAddPlaylistBtn.style.setProperty('display', 'none', 'important');
if (lyricsBtn) lyricsBtn.style.display = 'none';
}
}

View file

@ -1,5 +1,6 @@
{
"api": [
"https://tidal-api.binimum.org",
"https://monochrome-api.samidy.com"
],
"streaming": [

View file

@ -1575,7 +1575,6 @@ input:checked + .slider::before {
position: relative;
font-size: 0.8rem;
font-weight: bold;
color: var(--foreground);
transition: all var(--transition);
}
@ -2687,8 +2686,7 @@ input:checked + .slider::before {
}
.player-controls .buttons {
gap: var(--spacing-sm);
margin-bottom: var(--spacing-xs);
gap: var(--spacing-md);
}
.player-controls .buttons button {
@ -2715,17 +2713,6 @@ input:checked + .slider::before {
display: flex;
}
.volume-controls button {
padding: 0.375rem;
min-width: 32px;
min-height: 32px;
}
.volume-controls button svg {
width: 18px;
height: 18px;
}
#download-notifications {
bottom: 10px;
right: 10px;
@ -3850,3 +3837,10 @@ img:not([src]), img[src=''] {
}
}
.library-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: var(--spacing-md);
}