Merge branch 'main' of github.com:SamidyFR/monochrome
This commit is contained in:
commit
cd30df8d6a
8 changed files with 86 additions and 58 deletions
17
index.html
17
index.html
|
|
@ -250,13 +250,10 @@
|
||||||
|
|
||||||
<div id="page-library" class="page">
|
<div id="page-library" class="page">
|
||||||
<section class="content-section">
|
<section class="content-section">
|
||||||
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 1rem;">
|
<div class="library-header">
|
||||||
<h2 class="section-title" style="margin-bottom: 0;">My Playlists</h2>
|
<h2>My Playlists</h2>
|
||||||
<div style="display: flex; gap: 0.5rem;">
|
<button id="create-playlist-btn" class="btn-primary">Create Playlist</button>
|
||||||
|
</div>
|
||||||
<button id="create-playlist-btn" class="btn-secondary">Create Playlist</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="card-grid" id="my-playlists-container"></div>
|
<div class="card-grid" id="my-playlists-container"></div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
|
@ -814,7 +811,7 @@
|
||||||
<div class="player-actions-row">
|
<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 id="now-playing-like-btn" class="like-btn" data-action="toggle-like" title="Save to Favorites" style="display: none;">
|
||||||
</button>
|
</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">
|
<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="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"/>
|
<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"/>
|
<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>
|
</svg>
|
||||||
</button>
|
</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>
|
<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>
|
||||||
<button id="download-current-btn" title="Download current track" class="desktop-only">
|
<button id="download-current-btn" title="Download current track" class="desktop-only">
|
||||||
|
|
@ -836,7 +833,7 @@
|
||||||
</svg>
|
</svg>
|
||||||
</button>
|
</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">
|
<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="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"/>
|
<path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"/>
|
||||||
|
|
|
||||||
12
js/app.js
12
js/app.js
|
|
@ -301,10 +301,18 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
let playlist, tracks;
|
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) {
|
if (userPlaylist) {
|
||||||
playlist = { ...userPlaylist, title: userPlaylist.name };
|
playlist = { ...userPlaylist, title: userPlaylist.name || userPlaylist.title };
|
||||||
tracks = userPlaylist.tracks || [];
|
tracks = userPlaylist.tracks || [];
|
||||||
} else {
|
} else {
|
||||||
const data = await api.getPlaylist(playlistId);
|
const data = await api.getPlaylist(playlistId);
|
||||||
|
|
|
||||||
11
js/events.js
11
js/events.js
|
|
@ -399,8 +399,15 @@ export async function handleTrackAction(action, item, player, api, lyricsManager
|
||||||
const data = await api.getPlaylist(item.uuid);
|
const data = await api.getPlaylist(item.uuid);
|
||||||
tracks = data.tracks;
|
tracks = data.tracks;
|
||||||
} else if (type === 'user-playlist') {
|
} else if (type === 'user-playlist') {
|
||||||
const playlist = await db.getPlaylist(item.id);
|
let playlist = await db.getPlaylist(item.id);
|
||||||
tracks = playlist ? playlist.tracks : [];
|
if (!playlist) {
|
||||||
|
try {
|
||||||
|
playlist = await syncManager.getPublicPlaylist(item.id);
|
||||||
|
} catch (e) {
|
||||||
|
// Ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tracks = playlist ? playlist.tracks : (item.tracks || []);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tracks.length > 0) {
|
if (tracks.length > 0) {
|
||||||
|
|
|
||||||
55
js/player.js
55
js/player.js
|
|
@ -574,35 +574,44 @@ export class Player {
|
||||||
|
|
||||||
updateSleepTimerUI() {
|
updateSleepTimerUI() {
|
||||||
const timerBtn = document.getElementById('sleep-timer-btn');
|
const timerBtn = document.getElementById('sleep-timer-btn');
|
||||||
if (!timerBtn) return;
|
const timerBtnDesktop = document.getElementById('sleep-timer-btn-desktop');
|
||||||
|
|
||||||
if (this.isSleepTimerActive()) {
|
const updateBtn = (btn) => {
|
||||||
const remaining = this.getSleepTimerRemaining();
|
if (!btn) return;
|
||||||
if (remaining > 0) {
|
if (this.isSleepTimerActive()) {
|
||||||
const minutes = Math.floor(remaining / 60);
|
const remaining = this.getSleepTimerRemaining();
|
||||||
const seconds = remaining % 60;
|
if (remaining > 0) {
|
||||||
timerBtn.innerHTML = `<span style="font-size: 12px; font-weight: bold;">${minutes}:${seconds.toString().padStart(2, '0')}</span>`;
|
const minutes = Math.floor(remaining / 60);
|
||||||
timerBtn.title = `Sleep Timer: ${minutes}:${seconds.toString().padStart(2, '0')} remaining`;
|
const seconds = remaining % 60;
|
||||||
timerBtn.classList.add('active');
|
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 {
|
} 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">
|
<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"/>
|
<circle cx="12" cy="12" r="10"/>
|
||||||
<polyline points="12,6 12,12 16,14"/>
|
<polyline points="12,6 12,12 16,14"/>
|
||||||
</svg>
|
</svg>
|
||||||
`;
|
`;
|
||||||
timerBtn.title = 'Sleep Timer';
|
btn.title = 'Sleep Timer';
|
||||||
timerBtn.classList.remove('active');
|
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">
|
updateBtn(timerBtn);
|
||||||
<circle cx="12" cy="12" r="10"/>
|
updateBtn(timerBtnDesktop);
|
||||||
<polyline points="12,6 12,12 16,14"/>
|
|
||||||
</svg>
|
|
||||||
`;
|
|
||||||
timerBtn.title = 'Sleep Timer';
|
|
||||||
timerBtn.classList.remove('active');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,10 @@ export const apiSettings = {
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to load instances from GitHub:', error);
|
console.error('Failed to load instances from GitHub:', error);
|
||||||
this.defaultInstances = {
|
this.defaultInstances = {
|
||||||
api: ["https://monochrome-api.samidy.com"],
|
api: [
|
||||||
|
"https://tidal-api.binimum.org",
|
||||||
|
"https://monochrome-api.samidy.com"
|
||||||
|
],
|
||||||
streaming: [
|
streaming: [
|
||||||
"https://triton.squid.wtf",
|
"https://triton.squid.wtf",
|
||||||
"https://wolf.qqdl.site",
|
"https://wolf.qqdl.site",
|
||||||
|
|
@ -63,7 +66,7 @@ export const apiSettings = {
|
||||||
"https://hund.qqdl.site",
|
"https://hund.qqdl.site",
|
||||||
"https://tidal.kinoplus.online",
|
"https://tidal.kinoplus.online",
|
||||||
"https://tidal-api.binimum.org"
|
"https://tidal-api.binimum.org"
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
this.instancesLoaded = true;
|
this.instancesLoaded = true;
|
||||||
return this.defaultInstances;
|
return this.defaultInstances;
|
||||||
|
|
|
||||||
19
js/ui.js
19
js/ui.js
|
|
@ -81,14 +81,23 @@ export class UIRenderer {
|
||||||
this.updateGlobalTheme();
|
this.updateGlobalTheme();
|
||||||
|
|
||||||
const likeBtn = document.getElementById('now-playing-like-btn');
|
const likeBtn = document.getElementById('now-playing-like-btn');
|
||||||
if (likeBtn) {
|
const addPlaylistBtn = document.getElementById('now-playing-add-playlist-btn');
|
||||||
if (track) {
|
const mobileAddPlaylistBtn = document.getElementById('mobile-add-playlist-btn');
|
||||||
|
const lyricsBtn = document.getElementById('toggle-lyrics-btn');
|
||||||
|
|
||||||
|
if (track) {
|
||||||
|
if (likeBtn) {
|
||||||
likeBtn.style.display = 'flex';
|
likeBtn.style.display = 'flex';
|
||||||
// Use the centralized update logic if possible, or manual here
|
|
||||||
this.updateLikeState(likeBtn.parentElement, 'track', track.id);
|
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';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
{
|
{
|
||||||
"api": [
|
"api": [
|
||||||
|
"https://tidal-api.binimum.org",
|
||||||
"https://monochrome-api.samidy.com"
|
"https://monochrome-api.samidy.com"
|
||||||
],
|
],
|
||||||
"streaming": [
|
"streaming": [
|
||||||
|
|
|
||||||
22
styles.css
22
styles.css
|
|
@ -1575,7 +1575,6 @@ input:checked + .slider::before {
|
||||||
position: relative;
|
position: relative;
|
||||||
font-size: 0.8rem;
|
font-size: 0.8rem;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
color: var(--foreground);
|
|
||||||
transition: all var(--transition);
|
transition: all var(--transition);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2687,8 +2686,7 @@ input:checked + .slider::before {
|
||||||
}
|
}
|
||||||
|
|
||||||
.player-controls .buttons {
|
.player-controls .buttons {
|
||||||
gap: var(--spacing-sm);
|
gap: var(--spacing-md);
|
||||||
margin-bottom: var(--spacing-xs);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.player-controls .buttons button {
|
.player-controls .buttons button {
|
||||||
|
|
@ -2715,17 +2713,6 @@ input:checked + .slider::before {
|
||||||
display: flex;
|
display: flex;
|
||||||
}
|
}
|
||||||
|
|
||||||
.volume-controls button {
|
|
||||||
padding: 0.375rem;
|
|
||||||
min-width: 32px;
|
|
||||||
min-height: 32px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.volume-controls button svg {
|
|
||||||
width: 18px;
|
|
||||||
height: 18px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#download-notifications {
|
#download-notifications {
|
||||||
bottom: 10px;
|
bottom: 10px;
|
||||||
right: 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);
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue