- Meta-grid reduced from 4 cells to 2 (State / Source). Elapsed and
Length were duplicates of the timecodes already flanking the
timeline. Added .meta-grid-2 modifier with a 2-column layout.
- Timeline was distorted by legacy rules: .progress-bar:hover did
scaleY(1.4) (inflating the 2px hairline on hover) and the
progress-fill::after handle defaulted to scale(0). Both are now
forced via !important to keep the hairline flat and the copper
handle always visible.
- progress-row uses minmax(0, 1fr) for the bar cell so it shrinks
cleanly inside the grid.
- Removed unused meta.elapsed / meta.length keys from en.json + ru.json.
- Dead JS lookups for #meta-elapsed / #meta-length stay (cheap if-checks,
no-op when DOM elements gone).
Side-by-side comparison surfaced several layout regressions vs. the
mockup. This commit lands all of them at once.
Header
- Restore centered "Media Server / Studio Reference Edition" wordmark
in italic Fraunces
- Move folio marks to fixed page corners (visible on every tab):
TL = green pulse + "Connected · Local 8765"
TR = "Vol. I — Studio Reference · v0.x.x"
- Replace boxed version-label badge with copper mono inline in folio.tr
- Reduce header-to-content gap (container padding-top 28→56 with the
folio now anchored above)
Player view
- Spectrum bars: smaller height (32px), centered with max-width so
they don't span the whole right column
- Spectrogram canvas: hidden by default (opacity 0); reveals only when
visualizer toggle is active. No more leaking into bottom-left.
- VU cluster volume controls: strip legacy box (background, padding,
border-radius); compact stacked layout with thin slider, small mute
button, mono "VOL · XX%" readout
- Disable legacy applyVinylMode() — the .vinyl class added a SECOND
rotation animation on top of the structural .vinyl-stage spin,
causing visible compounding. Vinyl is now purely structural.
Toggles
- Remove vinyl mode toggle button (vinyl is always on)
- Keep audio visualizer (spectrum vis) toggle — still shown by JS
when supported
Mini player
- Force always-visible on non-player tabs regardless of scroll, by
short-circuiting setMiniPlayerVisible when activeTab !== 'player'
i18n
- New keys: header.connected, header.volume, header.edition,
header.edition_sub
- Removed unused: player.folio_left, player.folio_right
- en.json + ru.json updated
Restructures the player tab DOM to actually look like the editorial
mockup, not just inherit new fonts. The previous commit only swapped
tokens & typography on the legacy Spotify-clone layout.
DOM additions (all preserve existing JS-touched IDs):
- Vinyl stage: rotating vinyl wrapping the existing #album-art as a
circular center label; spins only when state=playing via CSS hook
- SVG tonearm: pivots in/out based on data-playstate
- Kicker line: copper italic mono header above the track title
- Editorial 4-cell metadata grid: State / Source / Elapsed / Length
- Decorative spectrum bars (30, CSS-only animation, paused when idle)
- VU meter cluster: needle visual driven by volume %, alongside the
preserved volume slider for a11y
- Folio marks: top-left and top-right of the player container
JS hooks (small, additive):
- updatePlaybackState now sets :root[data-playstate] for CSS
- progress tick mirrors timecode into meta-grid cells
- volume update rotates the VU needle
- folio-version mirrors the version label
i18n:
- new keys: player.kicker, player.modes, player.folio_*, meta.*
- added to both en.json and ru.json
Restored: media_server/static/redesign-mockup.html (Studio Reference
visual reference; deleting it in the prior commit was a mistake).
Replaces the Spotify-clone dark theme with a warm editorial design
language inspired by hi-fi audio mastering and magazine layouts.
- Self-host Fraunces, Geist, and Geist Mono as variable WOFF2 files
(Latin + Latin-ext + Cyrillic subsets, OFL-licensed)
- New design tokens: warm charcoal + copper accent (dark) /
cream paper + hunter emerald (light)
- Editorial typography: Fraunces serif for display + masthead,
Geist for UI, Geist Mono for technical readouts (timecodes, bitrates)
- Player view restyled as magazine spread with framed album art
- Mini player as glassy console strip with copper hairline glow
- Tabs as italic editorial nav with copper underline
- Browser items as gallery cards with editorial typography
- Settings as numbered sections with refined tables
- Quick Access as console rail
- Dialogs and auth modal as paper cards with mono kickers
- Subtle film-grain overlay for analog warmth
- Localized tab labels: Player → Now Spinning, Browser → Library
- Generate numpy/_distributor_init_local.py during build so libopenblas
can be located when running from the Windows installer
- Add os.add_dll_directory() call at runtime as a fallback for embedded Python
- Broaden audio import errors from ImportError to Exception, log at warning
- Move visualizer WS re-subscription into loadAudioDevices() so it runs
after availability is confirmed from the API
- Show/hide the visualizer toggle button based on fetched availability
Instead of waiting for the next poll cycle, new clients now get the
current playback status immediately on connect by calling get_status_func
if no cached status is available yet.
Patches HTMLDialogElement.prototype.showModal globally to move focus
onto the dialog element itself instead of the first focusable
descendant. On touch devices the previous behavior popped up the
on-screen keyboard whenever a modal opened, which was confusing.
- Root folder cards with hero-style layout and SVG icons
- Full-width thumbnails with aspect-ratio grid items
- List view column headers (Name, Bitrate, Duration, Size)
- Modernized breadcrumb with pill segments and overflow handling
- Proper skeleton shimmer replacing emoji hourglass on thumbnails
- Pagination shows "Showing X-Y of Z" item count
- Refined hover effects, animations, and visual hierarchy
- Download button revealed on row hover in list view
- Type badges hidden by default, shown on hover
- Localized new keys in en.json and ru.json
- Rename GITEA_TOKEN to DEPLOY_TOKEN in release workflow
- Extract shared version detection into build-common.sh
- Use importlib.metadata for runtime version instead of hardcoded string
- Use PEP 440 parsing (packaging lib) for update version comparison
- Add packaging>=23.0 to dependencies
- Fix update banner close button alignment (CSS)
- Update CLAUDE.md with versioning docs and frontend rebuild notes
- Abstract ReleaseProvider protocol for platform-agnostic version checking
- GiteaReleaseProvider implementation using stdlib urllib
- UpdateChecker service with periodic background checks and WS broadcast
- Persistent dismissible banner in Web UI when a new version is detected
- Health endpoint now returns cached update info
- Configurable via update_check_enabled and update_check_interval settings
- i18n support (EN/RU)
The previous os.execv approach and console_script detection both
failed on Windows. Now restart always spawns `python -m media_server.main`
via subprocess.Popen with start_new_session, which works regardless
of how the server was originally started.
- Rewrite tray to run on main thread (pystray owns message loop, uvicorn
in background thread) — fixes unresponsive confirmation dialogs
- Use native Windows MessageBoxW instead of tkinter (embedded Python
has no tkinter)
- Pin numpy <2.0 to fix soundcard's numpy.fromstring (removed in 2.0)
- Strip transitive numpy 2.x wheels in build script
- Installer copies config.example.yaml as config.yaml on fresh install
- Suppress noisy screen_brightness_control warnings
- Use custom icon.ico for installer/uninstaller UI
- LaunchApp opens server then browser after install
- .onInit detects running instance and offers to stop it
- Use WMIC-based process kill targeting embedded Python path
- start-hidden.vbs prefers embedded Python over system Python
- Add pystray dependency to build script
- CLAUDE.md: note to consult CI/CD guide for build changes
Adds pystray-based tray icon (green play button) that runs alongside
uvicorn. Double-click opens the web UI in the browser, Exit triggers
graceful shutdown. Disabled with --no-tray flag for headless/service mode.
When no api_tokens are configured (the new default), all endpoints
are accessible without authentication. The frontend detects this
via /api/health's auth_required field and skips the login form.
- Backend: auth.py skips verification when api_tokens is empty
- Frontend: shared getAuthHeaders()/hasCredentials() helpers replace
scattered token logic across all JS modules
- Health endpoint exposes auth_required for frontend discovery
- config.example.yaml ships with tokens commented out
- CLI --show-token and startup log reflect disabled state
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- WebGL shader background with flowing waves, radial pulse, and frequency ring arcs
- Reacts to captured audio data (frequency bands + bass) when visualizer is active
- Uses page accent color; adapts to dark/light theme via bg-primary blending
- Toggle button in header toolbar, state persisted in localStorage
- Cached uniform locations and color values to avoid per-frame getComputedStyle calls
- i18n support for EN/RU locales
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The POST /visualizer/device response has 'success' but no 'available'
field, causing updateAudioDeviceStatus to always fall to 'Unavailable'.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Service worker, manifest, and SVG icon for PWA installability
- Root /sw.js route for full-scope service worker registration
- Meta tags: theme-color, apple-mobile-web-app, viewport-fit=cover
- Safe area insets for notched phones (container, mini-player, footer, banner)
- Dynamic theme-color sync on light/dark toggle
- Overscroll prevention and touch-action optimization
- Hide mini-player prev/next buttons on small screens
- Updated README with PWA and new feature documentation
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Visualizer: FPS 25→30, chunk_size 2048→1024, smoothing 0.65→0.15
- Beat effect: scale 0.03→0.04, glow range 0.5-0.8→0.4-0.8
- UI: reduce container/section paddings from 2rem to 1rem
- Source name: add ellipsis overflow for long names
- Mobile browser toolbar: use flex-wrap instead of column stack,
hide "Items per page" label text on small screens
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Audio capture starts only when first client subscribes,
stops when last client unsubscribes (saves CPU/battery)
- Add lifecycle lock to AudioAnalyzer for thread-safe start/stop
- Status badge uses local visualizer state instead of server flag
- Fix script name vertical text break on narrow screens
- Fix script grid minimum column width on small viewports
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- 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>
- Registry of 17 popular media apps (browsers, players, streaming)
- Substring matching resolves raw process names to friendly names
- Brand-colored SVG icons displayed inline next to source name
- Russian locale support for Yandex Music (Яндекс Музыка)
- Unknown sources fall back to .exe-stripped name
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Unified header-toolbar container with border and rounded corners
- Consistent header-btn styling for all action buttons
- Compact locale select, separator before logout icon
- Header links integrate as part of the toolbar with divider
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Native select with explicit font stack and focus glow
- Hide mini player volume section below 900px
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Subtle oscillating Y/X rotation with perspective for depth
- Enhanced vinyl mode filter: more desaturation + sepia warmth
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Save vinyl rotation angle before flipping vinylMode flag off
- Wrap vinyl + visualizer buttons in .player-toggles container
- Move margin-left:auto from individual buttons to group
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- New audio_analyzer service: loopback capture via soundcard + numpy FFT
- Real-time spectrogram bars below album art with accent color gradient
- Album art and vinyl pulse to bass energy beats
- WebSocket subscriber pattern for opt-in audio data streaming
- Audio device selection in Settings tab with auto-detect fallback
- Optimized FFT pipeline: vectorized cumsum bin grouping, pre-serialized JSON broadcast
- Visualizer config: enabled/fps/bins/device in config.yaml
- Optional deps: soundcard + numpy (graceful degradation if missing)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Save current rotation angle to localStorage every 2s and on page unload
- Restore angle on page load via CSS custom property --vinyl-offset
- Extract angle from computed transform matrix
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Detect primary monitor via Windows EnumDisplayMonitors API and show badge
- Expand accent color picker with 9 presets and custom color input
- Auto-generate hover color for custom accent colors
- Re-render accent swatches on locale change for proper i18n
- Replace restart-server.bat with PowerShell restart-server.ps1
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Merge Scripts/Callbacks/Links tabs into single Settings tab with collapsible sections
- Rename Actions tab to Quick Access showing both scripts and configured links
- Add prev/next buttons to mini (secondary) player
- Add optional description field to links (backend + frontend)
- Add CSS chevron indicators on collapsible settings sections
- Persist section collapse/expand state in localStorage
- Fix race condition in Quick Access rendering with generation counter
- Order settings sections: Scripts, Links, Callbacks
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Add LinkConfig model and links field to settings
- Add CRUD API endpoints for links (list/create/update/delete)
- Add Links management tab in WebUI with add/edit/delete dialogs
- Add live icon preview in Link and Script dialog forms
- Show MDI icons inline in Quick Actions cards, Scripts table, Links table
- Add broadcast_links_changed WebSocket event for live updates
- Add EN/RU translations for all links management strings
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- New display service with DDC/CI brightness and power control via screen_brightness_control and monitorcontrol
- New /api/display/* endpoints (monitors, brightness, power)
- Display tab in WebUI with per-monitor brightness sliders and power toggle
- EDID resolution parsing to distinguish same-name monitors
- Throttled brightness slider (50ms) matching volume control pattern
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Reduce regular grid icon/thumbnail to 90px fixed
- Cap compact grid columns at 100px max width
- Compact thumbnails fill card width with aspect-ratio
- Reduce grid gap and column min-width
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Reduce card padding and gap
- Use fluid width thumbnails/icons instead of fixed 120px
- Fix cards stretching to tallest row height (align-items: start)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>