Codebase audit fixes: stability, performance, accessibility

- Fix CORS: set allow_credentials=False (token auth, not cookies)
- Add threading.Lock for position cache thread safety
- Add shutdown_executor() for clean ThreadPoolExecutor cleanup
- Dedicated ThreadPoolExecutors for script/callback execution
- Fix Mutagen file handle leaks with try/finally close
- Reduce idle WebSocket polling (0.5s → 2.0s when no clients)
- Add :focus-visible styles for playback control buttons
- Add aria-label to icon-only header buttons
- Dynamic album art alt text for screen readers
- Persist MDI icon cache to localStorage

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-28 12:10:24 +03:00
parent 73a6f387e1
commit 9404b37f05
9 changed files with 260 additions and 195 deletions

View File

@@ -1368,6 +1368,13 @@
currentState = status.state;
updatePlaybackState(status.state);
// Update album art alt text for accessibility
const altText = status.title && status.artist
? `${status.artist} ${status.title}`
: status.title || t('player.no_media');
dom.albumArt.alt = altText;
dom.miniAlbumArt.alt = altText;
// Update album art (skip if same track to avoid redundant network requests)
const artworkSource = status.album_art_url || null;
const artworkKey = `${status.title || ''}|${status.artist || ''}|${artworkSource || ''}`;
@@ -3468,7 +3475,16 @@ async function toggleDisplayPower(monitorId, monitorName) {
// Header Quick Links
// ============================================================
const mdiIconCache = {};
// In-memory + localStorage cache for MDI icons (persists across reloads)
const mdiIconCache = (() => {
try {
return JSON.parse(localStorage.getItem('mdiIconCache') || '{}');
} catch { return {}; }
})();
function _persistMdiCache() {
try { localStorage.setItem('mdiIconCache', JSON.stringify(mdiIconCache)); } catch {}
}
async function fetchMdiIcon(iconName) {
// Parse "mdi:icon-name" → "icon-name"
@@ -3480,6 +3496,7 @@ async function fetchMdiIcon(iconName) {
if (response.ok) {
const svg = await response.text();
mdiIconCache[name] = svg;
_persistMdiCache();
return svg;
}
} catch (e) {