import { esc, toast } from '../utils.js'; import { api } from '../api.js'; const _NOTIF_KEY = 'ns_notifications'; function _loadNotifs() { try { return JSON.parse(localStorage.getItem(_NOTIF_KEY) || '[]'); } catch { return []; } } function _saveNotifs(n) { localStorage.setItem(_NOTIF_KEY, JSON.stringify(n.slice(0, 100))); } export function _addNotif(notif) { const list = _loadNotifs(); list.unshift(notif); _saveNotifs(list); _renderNotifBell(); _renderNotifList(); } export function deleteNotif(id) { _saveNotifs(_loadNotifs().filter(n => n.id !== id)); _renderNotifBell(); _renderNotifList(); } export function clearNotifs() { _saveNotifs([]); _renderNotifBell(); _renderNotifList(); } export function toggleNotifPanel() { const panel = document.getElementById('notif-panel'); const overlay = document.getElementById('notif-overlay'); if (!panel) return; const isOpen = panel.classList.contains('open'); if (isOpen) { panel.classList.remove('open'); overlay?.classList.remove('active'); } else { _saveNotifs(_loadNotifs().map(n => ({...n, read: true}))); _renderNotifList(); _renderNotifBell(); panel.classList.add('open'); overlay?.classList.add('active'); } } export function initNotifBell() { _renderNotifBell(); } function _renderNotifBell() { const unread = _loadNotifs().filter(n => !n.read).length; document.querySelectorAll('.notif-badge').forEach(b => { b.textContent = unread > 9 ? '9+' : unread; b.style.display = unread > 0 ? '' : 'none'; }); } function _renderNotifList() { const list = document.getElementById('notif-list'); if (!list) return; const notifs = _loadNotifs(); if (!notifs.length) { list.innerHTML = '
Keine Benachrichtigungen
'; return; } list.innerHTML = notifs.map(n => { const d = new Date(n.timestamp); const time = d.toLocaleDateString('de-DE', {day:'2-digit', month:'2-digit'}) + ' ' + d.toLocaleTimeString('de-DE', {hour:'2-digit', minute:'2-digit'}); const icon = n.status === 'done' ? '✅' : '❌'; const failedHtml = n.failed?.length ? `
${n.failed.length} Track${n.failed.length > 1 ? 's' : ''} fehlgeschlagen
` : ''; const missingHtml = n.missing?.length ? `
${n.missing.length} Track${n.missing.length > 1 ? 's' : ''} nicht in Navidrome gefunden
` : ''; const hasNav = n.status === 'done' && ((n.navType === 'playlist' && n.navId) || n.navArtist || n.navAlbum); const navLabel = n.navType === 'artist' ? 'Zum Künstler →' : (n.navType === 'track' || n.navType === 'album') ? 'Zum Album →' : 'Öffnen →'; const navBtn = hasNav ? `` : ''; return `
${icon}
${esc(n.title)}
${n.artist ? esc(n.artist) + ' · ' : ''}${time}
${n.message ? `
${esc(n.message)}
` : ''} ${failedHtml} ${missingHtml} ${navBtn}
`; }).join(''); } export async function _notifNavigate(notifId) { const notifs = _loadNotifs(); const n = notifs.find(x => x.id === notifId); if (!n) return; const panel = document.getElementById('notif-panel'); const overlay = document.getElementById('notif-overlay'); panel?.classList.remove('open'); overlay?.classList.remove('active'); const { navigate } = await import('../views/views.js'); if (n.navType === 'playlist' && n.navId) { navigate('playlist-detail', { id: n.navId, name: n.navName || n.title.replace(/^Playlist:\s*/, '') }); return; } const norm = s => s?.toLowerCase().trim() || ''; if (n.navType === 'track' || n.navType === 'album') { const albumQuery = n.navAlbum || n.navTitle; if (albumQuery) { try { const r = await api('search3', `&query=${encodeURIComponent(albumQuery)}&artistCount=0&albumCount=10&songCount=0`); const albums = r.searchResult3?.album || []; const match = albums.find(a => norm(a.name) === norm(albumQuery) && norm(a.artist) === norm(n.navArtist)) || albums.find(a => norm(a.name) === norm(albumQuery)) || albums[0]; if (match) { navigate('album-detail', { id: match.id, name: match.name, artist: match.artist || '', artistId: match.artistId || '', coverArt: match.coverArt || '' }); return; } } catch {} } toast('Album nicht gefunden — Library-Scan nötig?'); return; } if (n.navArtist) { try { const r = await api('search3', `&query=${encodeURIComponent(n.navArtist)}&artistCount=5&albumCount=0&songCount=0`); const artists = r.searchResult3?.artist || []; const match = artists.find(a => norm(a.name) === norm(n.navArtist)) || artists[0]; if (match) { navigate('artist-detail', { id: match.id, name: match.name }); return; } } catch {} toast('Künstler nicht gefunden — Library-Scan nötig?'); } }