• v0.4.0 e7a3f62a9a

    Media Server v0.4.0
    Lint & Test / test (push) Has been skipped
    Lint & Test / linux-smoke (push) Has been skipped
    Release / create-release (push) Successful in 3s
    Release / build-windows (push) Successful in 1m9s
    Release / build-linux (push) Successful in 1m10s
    Release / build-macos (push) Has been cancelled
    Stable

    alexei.dolgolyov released this 2026-05-28 17:27:37 +03:00 | 3 commits to master since this release

    v0.4.0 (2026-05-28)

    Two headline changes since v0.3.1: Media Server now ships first-class Linux and macOS builds (no more Windows-only), and the Windows app icon was redesigned with a proper multi-resolution ICO so the installer, Start Menu, desktop shortcut, Alt+Tab, and system tray all render sharp.

    Features

    • Linux support, production-ready. New linux extra (dbus-python, PyGObject, python-xlib) plus a build-dist-linux.sh that emits a portable tarball and a systemd user unit. The unit sets DBUS_SESSION_BUS_ADDRESS, XDG_RUNTIME_DIR, and ReadWritePaths for ~/.config / ~/.cache so MPRIS works and audit-log / thumbnail writes aren't blocked by ProtectHome. The Linux MPRIS controller now connects to the session bus lazily — a missing or late bus no longer crashes lifespan startup, and the user is logged a one-line hint about loginctl enable-linger. (ddf4a6c)
    • macOS support. New macos extra (pyobjc-framework-Cocoa, pyobjc-framework-Quartz), a build-dist-macos.sh script, and a per-user LaunchAgent installer producing MediaServer-vX.Y-macos-{arm64,x86_64}.tar.gz artifacts. Spotify URL artwork is wired through MediaController.get_album_art(). (ddf4a6c)
    • Cross-platform album artwork. MediaController.get_album_art() is now abstract with Linux (mpris:artUrl, file:// + http(s)://) and macOS (Spotify URL) implementations; the /api/media/artwork endpoint awaits the controller. (ddf4a6c)
    • Per-OS unavailable reasons on /api/media/visualizer/status so the Web UI can explain why the visualizer is off on Linux / macOS instead of just hiding it. (ddf4a6c)
    • Startup preflight on Linux warns when DBUS_SESSION_BUS_ADDRESS or XDG_RUNTIME_DIR is unset and informs the user when running under Wayland disables the foreground-window probe — so silent loss of features is now diagnosable from the log. (ddf4a6c)
    • Redesigned app icon ("Beacon"). Replaces the generic Spotify-green circle with a refined squircle + deep-teal diagonal gradient (#0B3D3B → #1A6B5E) + warm parchment play triangle (#F5F1E8) with a drop shadow, top sheen, and ghosted echo-chevrons that hint at broadcast/stream. (d798fed)
    • Multi-resolution Windows ICO. icon.ico grew from a single 16×16 frame (208 B) to a 10-frame ICO (16/20/24/32/40/48/64/96/128/256 — ~37 KB) so Windows no longer upscales 16×16 into mush for the installer chrome, Start Menu, desktop shortcuts, Alt+Tab, and File Explorer tiles. (d798fed)
    • System tray uses the new icon. tray.py now picks a 64×64 frame from the multi-res ICO; the procedural fallback was reskinned to the same Beacon palette so a missing ICO no longer regresses the tray back to the old Spotify-green circle. (d798fed)

    Bug Fixes

    • tray._confirm guarded against ctypes.windll on non-Windows so the new Linux / macOS builds don't crash when the tray prompts for confirmation. (ddf4a6c)
    • config.example.yaml defaults are now cross-platform. Per-OS commented examples for the on/off scripts, and on_turn_off defaults to a harmless echo (the previous default silently failed everywhere but Windows). (ddf4a6c)

    Development / Internal

    Build & Packaging

    • scripts/generate-icon.py — SVG is the canonical source; resvg-py rasterizes every ICO size; Pillow packs the multi-resolution icon.ico. Re-run any time the SVG changes. (d798fed)
    • Dependency reorganization in pyproject.tomlscreen-brightness-control and monitorcontrol are cross-platform and moved to base deps; new linux and macos optional-deps groups with sys_platform markers. resvg-py added to [dev] for the icon-generation script. (ddf4a6c, d798fed)
    • install_linux.sh — dropped the dead requirements.txt path; now installs via pip install ".[linux]" and pre-creates the writable state dirs. (ddf4a6c)
    • Templated media-server.service updated to match the new dist layout, with proper session-bus env vars and a writable state-dir grant. (ddf4a6c)

    CI

    • New linux-smoke job in .gitea/workflows/test.yml — installs .[linux], boots the server under dbus-run-session, and asserts /api/health. Catches dependency-resolution and import-time regressions for the Linux dist path. (ddf4a6c)
    • Release workflow gains apt-deps step for the Linux build and a best-effort macOS build job that produces the per-arch macOS tarballs. (ddf4a6c)

    Documentation

    • README rewritten for the new extras — replaces the stale pip install -r requirements.txt instructions, adds a systemd-lingering note + troubleshooting section, and a macOS LaunchAgent section. (ddf4a6c)

    All Commits
    Hash Message Author
    d798fed feat(icon): redesign app icon as "Beacon" and ship multi-resolution ICO alexei.dolgolyov
    ddf4a6c feat: production-ready Linux & macOS support alexei.dolgolyov

    Downloads

    Platform File
    Windows (installer) MediaServer-v0.4.0-setup.exe
    Windows (portable) MediaServer-v0.4.0-win-x64.zip
    Linux MediaServer-v0.4.0-linux-x64.tar.gz
    macOS (Apple Silicon) MediaServer-v0.4.0-macos-arm64.tar.gz
    macOS (Intel) MediaServer-v0.4.0-macos-x86_64.tar.gz
    Downloads
  • v0.3.1 82710c6457

    Media Server v0.3.1
    Lint & Test / test (push) Has been skipped
    Release / create-release (push) Successful in 4s
    Release / build-linux (push) Successful in 28s
    Release / build-windows (push) Successful in 52s
    Stable

    alexei.dolgolyov released this 2026-05-25 23:45:08 +03:00 | 6 commits to master since this release

    v0.3.1 (2026-05-25)

    Hotfix for the v0.3.0 production-readiness release: the new WebSocket Origin allow-list rejected same-origin connections from any LAN IP, breaking the Web UI on host: 0.0.0.0 deployments unless cors_origins was explicitly configured.

    Bug Fixes

    • WebSocket Origin check now accepts same-origin connections. When cors_origins is unset, the default allow-list was hard-coded to http://localhost:<port> + http://127.0.0.1:<port>, so a browser opening the UI via the LAN IP (e.g. http://192.168.2.100:8765) had its WebSocket closed with code 4003 ("Origin not allowed") and never recovered. The endpoint now also accepts any Origin whose authority matches the request's Host header (with either http:// or https:// scheme) — same-origin connections are by definition not CSWSH, so the cross-origin defence introduced in v0.3.0 is preserved. (9b9a2b5)

    All Commits
    Hash Message Author
    9b9a2b5 fix(ws): accept same-origin WebSocket connections in default Origin allow-list alexei.dolgolyov

    Downloads

    Platform File
    Windows (installer) MediaServer-v0.3.1-setup.exe
    Windows (portable) MediaServer-v0.3.1-win-x64.zip
    Linux MediaServer-v0.3.1-linux-x64.tar.gz
    Downloads
  • v0.3.0 b023d72165

    Media Server v0.3.0
    Lint & Test / test (push) Has been skipped
    Release / create-release (push) Successful in 4s
    Release / build-linux (push) Successful in 1m29s
    Release / build-windows (push) Successful in 1m42s
    Stable

    alexei.dolgolyov released this 2026-05-22 22:41:11 +03:00 | 8 commits to master since this release

    v0.3.0 (2026-05-22)

    Production-readiness hardening release: security, performance, accessibility, and observability. Substantial new functionality (HTTPS, audit log, OS mediaSession integration, rate limiter, X-Request-ID, ETag-cached artwork) alongside the security defaults flip described below.

    Behavioral Changes (worth reading before upgrade)

    • Admin scope is now required for management endpoints, and scripts_management, callbacks_management, links_management, media_folders_management default to False. Legacy bare-string api_tokens entries are auto-promoted to admin scope, so existing single-token deployments keep working. If you ran with a non-admin token and used CRUD on /api/scripts, /api/callbacks, /api/links, or /api/media-folders, you'll need an admin-scope token (see new TokenSpec format in config.example.yaml). (d131ba4)
    • cors_origins: ["*"] is now refused at startup — set explicit origins instead. (d131ba4)
    • Thumbnail cache directory moved from project-root .cache to %LOCALAPPDATA%/media-server/cache on Windows and $XDG_CACHE_HOME/media-server/thumbnails on POSIX. The old .cache directory can be deleted. (d131ba4)
    • WebSocket auth prefers the Sec-WebSocket-Protocol: media-server.token.<T> subprotocol so the token no longer ends up in URL/history/Referer. The ?token= query fallback is retained for HA integration back-compat. (d131ba4)

    Features

    • HTTPS support via ssl_certfile + ssl_keyfile (+ optional ssl_keyfile_password); startup refuses to launch with only one of the pair set. (d131ba4)
    • Reverse-proxy support: proxy_headers + forwarded_allow_ips plumbed through Settings to uvicorn.Config. (d131ba4)
    • OS media session integration: headset / lockscreen / Bluetooth media-key buttons now drive play/pause/next/prev/seek and the browser-level mediaSession shows track metadata + artwork. (d131ba4)
    • Token scope hierarchy (read | control | admin) with structured TokenSpec entries; legacy bare-string tokens promote to admin. (d131ba4)
    • In-process token-bucket rate limiter: 5/min for failed auths, 10/min for /api/scripts/execute and /api/callbacks/execute. (d131ba4)
    • WebSocket Origin allow-list check (CSWSH defence). (d131ba4)
    • Script parameter validation: per-parameter pattern regex in ScriptParameterConfig plus shell=False (shlex.split) execution path to harden against parameter injection on cmd.exe. (d131ba4)
    • CSP tightened with form-action, worker-src, manifest-src directives. (d131ba4)
    • noopener noreferrer + no-referrer referrerpolicy applied to every outbound link in the WebUI. (d131ba4)
    • Windows config.yaml ACL hardening via icacls (current user + SYSTEM + Administrators only); 0600 continues to be enforced on POSIX. (d131ba4)
    • PWA installability: manifest.json gets id, scope, and theme_color / background_color matching the Studio Reference base (#0E0D0B). (d131ba4)
    • Accessibility: ARIA labels on mini-player icon buttons; inner SVGs marked aria-hidden. (d131ba4)

    Performance

    • Album-art read in windows_media gated by track key — was decoding the WinRT thumbnail twice per second regardless of track changes. (d131ba4)
    • /api/media/artwork returns content-derived ETag + Cache-Control so the browser sends If-None-Match and gets 304 on track repeats. (d131ba4)
    • Foreground-service ctypes argtypes hoisted to one-time module init — was re-declaring ~14 prototypes per probe. (d131ba4)
    • display_service._static_cache keyed by (edid_hash, ...) tuple with eviction of disappeared monitors — fixes stale capabilities on hot-plug swaps where the new topology has the same monitor count. (d131ba4)
    • Visualizer requestAnimationFrame loop paused on document.hidden, resumed on visible. (d131ba4)

    Bug Fixes

    • Lifespan rewritten as try / yield / finally so a partial-startup failure cannot orphan background tasks or executors. (d131ba4)
    • _run_callback in routes/media.py keeps a strong task reference (GC-safe) and uses the dedicated callback executor instead of the default pool. (d131ba4)
    • macos_media.set_volume() no longer always returns True regardless of the underlying AppleScript result. (d131ba4)
    • TrayManager._restart_requested initialised in __init__ and set before signalling exit so the main thread observes it correctly. (d131ba4)
    • Missing static_dir now logs a WARNING instead of silently disabling the UI. (d131ba4)
    • WebSocket volume handler clamps input and never drops the socket on bad messages. (d131ba4)
    • Gitea release tag validated against a strict SemVer regex before being used in a release URL. (d131ba4)

    Observability

    • X-Request-ID middleware — accepts an upstream id if it matches a safe regex, otherwise generates a UUID4. request_id_var added to ContextVars and included in every log line alongside the token label. (d131ba4)
    • Append-only JSONL audit log for every script + callback execution (including on_play / on_pause / etc. event callbacks). Background-thread writer; queue capped; flushed in lifespan teardown. (d131ba4)
    • token=... stripped from uvicorn access logs. (d131ba4)

    Development / Internal

    Tests

    • 35 new tests across auth scopes, the rate limiter, browser path traversal (../, NUL, UNC, absolute paths), script-parameter validation including the regex, the Gitea tag whitelist, and atomic config writes + POSIX permissions. Suite: 47 passed / 4 skipped. (d131ba4)

    All Commits
    Hash Message Author
    d131ba4 fix: production-readiness hardening — security, perf, a11y, observability alexei.dolgolyov

    Downloads

    Platform File
    Windows (installer) MediaServer-v0.3.0-setup.exe
    Windows (portable) MediaServer-v0.3.0-win-x64.zip
    Linux MediaServer-v0.3.0-linux-x64.tar.gz
    Downloads
  • v0.2.7 450f9fe1ee

    Media Server v0.2.7
    Lint & Test / test (push) Has been skipped
    Release / create-release (push) Successful in 3s
    Release / build-linux (push) Successful in 30s
    Release / build-windows (push) Successful in 52s
    Stable

    alexei.dolgolyov released this 2026-05-19 01:34:36 +03:00 | 10 commits to master since this release

    v0.2.7 (2026-05-19)

    Bug Fixes

    • Display tab sliders + accent picker now respond to clicks/drags: Both the brightness and contrast sliders on the Display tab, and the accent-color picker in the header, were rendering dynamic HTML with inline oninput / onchange / onclick attributes — every one of which the server's strict script-src 'self' CSP silently dropped. The result: brightness and contrast couldn't be changed from the WebUI at all, and picking a custom accent did nothing. Replaced the inline attributes with data-* markers and wired proper addEventListener calls (delegated on the slider container, direct on the accent dropdown), so the controls work under the strict CSP without any unsafe-inline / unsafe-hashes relaxation. (e1c8474)

    All Commits
    Hash Message Author
    e1c8474 fix(csp): wire display sliders and accent picker without inline on* alexei.dolgolyov

    Downloads

    Platform File
    Windows (installer) MediaServer-v0.2.7-setup.exe
    Windows (portable) MediaServer-v0.2.7-win-x64.zip
    Linux MediaServer-v0.2.7-linux-x64.tar.gz
    Downloads
  • v0.2.6 fe82836f4d

    Media Server v0.2.6
    Lint & Test / test (push) Has been skipped
    Release / create-release (push) Successful in 3s
    Release / build-linux (push) Successful in 30s
    Release / build-windows (push) Successful in 55s
    Stable

    alexei.dolgolyov released this 2026-05-18 03:19:07 +03:00 | 12 commits to master since this release

    v0.2.6 (2026-05-18)

    Features

    • Foreground-window tracker (cross-platform): New /api/foreground endpoint plus live foreground / foreground_update messages on the existing WebSocket feed. Windows uses a ctypes GetForegroundWindow probe with HANDLE-correct argtypes so 64-bit window handles aren't truncated; macOS uses AppKit's NSWorkspace.frontmostApplication; Linux uses Xlib's _NET_ACTIVE_WINDOW (Wayland sessions return a structured "unavailable" so the UI can render gracefully). Each platform has a TTL cache and per-platform fallbacks. (61cdce9)
    • Browser page-title surfacing: When the foreground process is a recognised browser, the window title is stripped of the trailing browser-name suffix and exposed as browser_page_title alongside is_browser. Optional UIA-based URL extraction sits behind the MEDIA_SERVER_BROWSER_UIA env flag (off by default — Chromium browsers keep their accessibility tree dormant unless something asks, and enabling it has a measurable cost). (61cdce9)
    • Foreground card in the Web UI: New editorial card under the monitor list on the Display tab renders process name, window title, fullscreen / minimized / monitor chips, the browser block when applicable, exe path, PID, started-ago, geometry, and platform. 16px inter-section gap matches the Settings cadence. 25 new i18n keys added to both en.json and ru.json. (61cdce9)
    • WebSocket integration: The existing 1s status loop now polls foreground every tick, broadcasts foreground on connect, and emits foreground_update only when user-visible fields actually change — geometry deltas alone don't spam the channel. (61cdce9)

    Security

    • Loopback-by-default in the shipped config: config.example.yaml now defaults host: 127.0.0.1. The server still refuses to bind a non-loopback interface without either api_tokens configured or an explicit allow_lan_without_auth: true opt-in — this hardens fresh installs where a user copies the example config verbatim. (0cf49de)

    Reliability

    • Diagnosable silent boot failures: Pre-uvicorn fatal errors (config parse failures, port conflicts, missing dependencies on Windows) are now mirrored to startup-errors.log in the config directory. Previously, launches via wscript/pythonw (the hidden Startup-folder shortcut path) had no console attached, so any startup crash was effectively invisible — the user just saw "nothing happened". (0cf49de)

    Development / Internal

    • Lint cleanup: Sorted the Xlib import in foreground_service.py so ruff check is clean. Same module, no behaviour change.

    All Commits
    Hash Message Author
    61cdce9 feat(foreground): track topmost process + browser page title alexei.dolgolyov
    0cf49de fix(config): secure-by-default loopback bind and startup-error logging alexei.dolgolyov

    Downloads

    Platform File
    Windows (installer) MediaServer-v0.2.6-setup.exe
    Windows (portable) MediaServer-v0.2.6-win-x64.zip
    Linux MediaServer-v0.2.6-linux-x64.tar.gz
    Downloads
  • v0.2.5 527f3d0aa4

    Media Server v0.2.5
    Lint & Test / test (push) Has been skipped
    Release / create-release (push) Successful in 4s
    Release / build-linux (push) Successful in 44s
    Release / build-windows (push) Successful in 1m9s
    Stable

    alexei.dolgolyov released this 2026-05-16 20:16:45 +03:00 | 16 commits to master since this release

    v0.2.5 (2026-05-16)

    Security

    • Loopback-by-default + auto-generated token: Server now binds 127.0.0.1 by default; first-run bootstrap generates a random api_token and refuses to bind a non-loopback interface without auth unless explicitly opted in. (bcc6d40)
    • Browser path-traversal hardening: BrowserService.validate_path now rejects absolute paths, drive letters, UNC paths, and NUL bytes. /api/browser/{play,metadata,thumbnail} require a folder_id plus a folder-relative path — arbitrary filesystem reads via the browser API are no longer possible. (bcc6d40)
    • Strict input validation on links/scripts: Pydantic validators reject non-http(s) URLs and any icon outside the mdi:<slug> namespace. Create/update/delete on scripts, callbacks, and links is gated by the corresponding *_management flags. (bcc6d40)
    • Hardened response headers + CORS: Strict Content-Security-Policy, X-Frame-Options: DENY, Referrer-Policy: no-referrer, X-Content-Type-Options: nosniff. CORS locked to localhost:<port> + 127.0.0.1:<port> by default; configurable for trusted origins. (bcc6d40)
    • Atomic config writes with restrictive permissions: config.yaml writes go through a temp file + os.replace and land with 0o600 on POSIX, so a crash mid-write can never leave a half-written token on disk readable to other users. (bcc6d40)
    • Subprocess process-group isolation: Spawned scripts/callbacks now get their own process group (CREATE_NEW_PROCESS_GROUP on Windows, start_new_session=True on POSIX), so a timeout actually kills the whole tree instead of orphaning child processes. (bcc6d40)
    • Frontend XSS hardening: Monitor name + details are escapeHtml'd, the power button moved to a delegated data-action handler, and remote MDI SVGs are parsed and sanitized (strip <script>, <foreignObject>, on* handlers, javascript: hrefs) before they touch innerHTML. All dynamic URL segments now go through encodeURIComponent. (bcc6d40)
    • CSP-compliant event wiring: Strict script-src 'self' was blocking every inline onclick/onchange/oninput/onsubmit in the UI, leaving buttons and forms silently dead. All 53 inline handler attributes in index.html were renamed to data-on* and a new wireInlineHandlers() in app.js parses each expression on DOMContentLoaded and attaches a real addEventListener — supports no-arg calls, string/number/bool/null literals, and the event token. No unsafe-inline or unsafe-hashes needed. (eaeebb6)

    Bug Fixes

    • WebSocket reconnect robustness: Close the previous socket before opening a new one, clear the ping interval per-socket, clear reconnectTimeout up-front, retry on online/visibilitychange, and wrap JSON.parse in try/catch — eliminates the stale-socket leaks and "stuck offline after sleep" cases. (bcc6d40)
    • Artwork fetch race: AbortController + generation guard so a rapid track change can no longer paint the previous track's artwork over the current one. (bcc6d40)
    • Audio analyzer no longer spins infinitely without a loopback device: A sticky _unavailable flag short-circuits start/stop; cleared by set_device() so the user can recover once a device appears. (bcc6d40)
    • Volume short-circuit cache invalidation: Cache is now busted when the server reports a remote volume change, so the UI no longer ignores volume updates that happened outside the app. (bcc6d40)
    • Browser thumbnail race: Per-folder generation counter + isConnected checks; in-flight fetches are aborted on navigation, so thumbnails from a folder you already left can't paint into the current view. (bcc6d40)
    • Track-skip uses cached title instead of a full WinRT status round-trip — skip feedback is now instant. (bcc6d40)
    • Browser list column alignment: .browser-list switched to CSS grid + subgrid so header and rows share column tracks, eliminating the misaligned columns when content widths differed between rows. Matching responsive column overrides applied at the parent. Root-folder SVG sizing (hardcoded 24×24 in browser.js) now fills the 56px icon box instead of rendering at ~43%. Compact-grid icon fills its thumb wrapper so the emoji centers instead of being stranded top-left. Premature isConnected bail removed from loadThumbnail — the img element is intentionally detached when called from renderBrowserGrid/List, and the post-await checks already handle navigation-away correctly. (982dda4)

    Performance

    • Blocking IO off the event loop: Linux MPRIS/pactl calls, /api/display DDC/CI handlers, and browse_directory are all wrapped in asyncio.to_thread — slow SMB shares or laggy monitors can no longer stall the entire async runtime. (bcc6d40)
    • Windows status poll loop reuse: The 0.5s status poll now caches one asyncio loop per worker thread via threading.local instead of new_event_loop/close on every tick. (bcc6d40)
    • WebSocket broadcast: serialize once: broadcast() serializes JSON a single time and uses send_text to fan out to all clients. (bcc6d40)
    • Thumbnail cache cleanup actually runs: The hourly cleanup task was defined but never scheduled — it is now wired into the lifespan handler so the cache no longer grows unbounded. (bcc6d40)
    • Progress drag listeners attached only while dragging — no more global mousemove handler firing on every cursor twitch. (bcc6d40)

    UI/UX

    • Copper accent consistency: Green leftover focus rings (rgba(29,185,84,…)) replaced with copper (rgba(var(--copper-rgb),…)) across the UI. Dialogs now have square corners and a copper top hairline so they read as part of the editorial chrome. .browser-item is transparent with a copper hover border (was a filled card). (bcc6d40)
    • Audio device select uses var(--sans) instead of the generic system font so it matches surrounding controls. (bcc6d40)
    • Mobile padding tuned for ≤480px screens. (bcc6d40)
    • Accessible breadcrumb home: Now a real <button> with aria-label, and aria-current is set on the root. (bcc6d40)
    • i18n gaps filled: display.msg.power_*, execution.*, scripts.params.execute, callbacks.empty now have proper en + ru strings. (bcc6d40)

    Development / Internal

    Quality

    • All asyncio.get_event_loop() in coroutines migrated to get_running_loop() (the former is deprecated in Python 3.12+). (bcc6d40)
    • ThreadPoolExecutors now shut down cleanly during lifespan teardown. (bcc6d40)
    • config_manager dedup: 12 near-identical CRUD methods collapsed onto generic _upsert/_delete helpers — about 290 lines removed with no behavior change. (bcc6d40)
    • Service worker no longer pass-throughs every fetch. (bcc6d40)
    • M3U playlist written via NamedTemporaryFile so a fixed-path symlink can no longer clobber it. (bcc6d40)
    • __version__ prefers live pyproject.toml in dev checkouts so pip install -e . users see the source-of-truth version, not the stale metadata baked in at install time. (bcc6d40)
    • _broadcast_after_open hardening: initialize status, swallow per-poll errors, and track background tasks in a strong-ref set with done-callback cleanup so they aren't garbage-collected mid-flight. (bcc6d40)

    All Commits
    Hash Message Author
    982dda4 fix(browser): align list columns via subgrid and fix icon sizing alexei.dolgolyov
    eaeebb6 fix(csp): replace inline on* handlers with data-on* + JS wiring alexei.dolgolyov
    bcc6d40 fix: comprehensive security, bug, performance, and UI/UX audit alexei.dolgolyov

    Downloads

    Platform File
    Windows (installer) MediaServer-v0.2.5-setup.exe
    Windows (portable) MediaServer-v0.2.5-win-x64.zip
    Linux MediaServer-v0.2.5-linux-x64.tar.gz
    Downloads
  • v0.2.4 770bba7e60

    Media Server v0.2.4
    Lint & Test / test (push) Has been skipped
    Release / create-release (push) Successful in 3s
    Release / build-linux (push) Successful in 23s
    Release / build-windows (push) Successful in 50s
    Stable

    alexei.dolgolyov released this 2026-05-15 14:50:28 +03:00 | 20 commits to master since this release

    v0.2.4 (2026-05-15)

    Features

    • Displays — DDC/CI picture controls: Monitor cards now expose contrast (slider, same editorial copper treatment as brightness) plus a new "PICTURE TUNING" section with input source, color preset, and picture mode pickers built on the IconSelect widget — HDMI/DisplayPort/DVI/VGA/USB-C glyphs for inputs, thermometer for color temperatures, per-mode icons (movie reel, gamepad, ball, etc.) for picture modes. Backend probes DDC/CI capabilities per monitor at enumeration time and exposes *_supported flags so the UI hides rows the hardware doesn't advertise. New endpoints: POST /api/display/{contrast,input_source,color_preset,picture_mode}/{id}. Picture mode uses raw VCP 0xDC with MCCS-spec labels and vendor-friendly fallbacks. 14 new i18n keys per locale (en/ru). (57fdeb7)

    Bug Fixes

    • Displays — verify DDC/CI writes before reporting success: DDC/CI writes are fire-and-forget at the protocol level — a successful send does not mean the monitor honored the value. A new _verify_after_set helper polls readback after every write and reports {success: false} when the monitor silently dropped it (common on LG ultrawides for VCP codes whose registers exist but whose feature isn't really implemented in firmware). Wired into set_contrast, set_input_source, set_color_preset, set_picture_mode; input source uses a longer settle window since switching can briefly disrupt the DDC/CI link. Picture mode (VCP 0xDC) additionally requires the capability string to declare supported codes under cmds[0xDC] — without that declaration we treat the feature as unsupported even when reads succeed (the LG case where reads return a stuck value and every write is silently ignored). (d1f621f)

    Development / Internal

    Chores

    • restart-server.ps1 — installer vs dev launches: Previously only killed processes named media-server, silently missing the installer-bundled process (which runs as plain python.exe via media-server.bat). The script now kills whatever currently owns the listen port regardless of process name, adds -Mode auto|dev|installer with auto-detection based on whether the installer launcher exists in %LOCALAPPDATA%\Media Server, verifies the port is listening after start, and merges registry PATH so newly-installed dev tools are visible. (6120625)

    All Commits
    Hash Message Author
    57fdeb7 feat(displays): expose DDC/CI contrast, input source, color preset, picture mode alexei.dolgolyov
    6120625 chore(scripts): harden restart-server.ps1 against installer vs dev launches alexei.dolgolyov
    d1f621f fix(displays): verify DDC/CI writes and trust capability string for picture mode alexei.dolgolyov

    Downloads

    Platform File
    Windows (installer) MediaServer-v0.2.4-setup.exe
    Windows (portable) MediaServer-v0.2.4-win-x64.zip
    Linux MediaServer-v0.2.4-linux-x64.tar.gz
    Downloads
  • v0.2.3 0d07f7f1f4

    Media Server v0.2.3
    Lint & Test / test (push) Has been skipped
    Release / create-release (push) Successful in 4s
    Release / build-linux (push) Successful in 30s
    Release / build-windows (push) Successful in 1m21s
    Stable

    alexei.dolgolyov released this 2026-05-01 19:41:41 +03:00 | 24 commits to master since this release

    v0.2.3 (2026-05-01)

    UI / Player

    • Square the vinyl stage (1:0.851:1) and pin the tonearm to height: 36% instead of aspect-ratio: 1 so its vertical span tracks the stage on resize. Refines the geometry shipped in v0.2.2. (d27484a)
    • Brighten the tonearm SVG: lighter pivot/arm gradient stops, thicker stroke widths, stronger cartridge highlight. (d27484a)
    • Tilt the sleeve -2deg so it reads as resting on the disc rather than rectilinearly composed. (d27484a)

    Bug Fixes

    • Displays: keep the primary-display star visible on long monitor names. Move overflow: hidden + ellipsis off the parent flex container onto a new inner span, and add flex-shrink: 0 to the badge so the favourite indicator no longer gets clipped when the model name truncates. (372e4eb)

    All Commits
    Hash Message Author
    d27484a ui(player): square vinyl stage, brighter tonearm, tilted sleeve alexei.dolgolyov
    372e4eb fix(displays): keep primary-display star visible on long monitor names alexei.dolgolyov

    Downloads

    Platform File
    Windows (installer) MediaServer-v0.2.3-setup.exe
    Windows (portable) MediaServer-v0.2.3-win-x64.zip
    Linux MediaServer-v0.2.3-linux-x64.tar.gz
    Downloads
  • v0.2.2 261a14c575

    Media Server v0.2.2
    Lint & Test / test (push) Has been skipped
    Release / create-release (push) Successful in 3s
    Release / build-linux (push) Successful in 33s
    Release / build-windows (push) Successful in 1m22s
    Stable

    alexei.dolgolyov released this 2026-05-01 17:15:24 +03:00 | 27 commits to master since this release

    v0.2.2 (2026-05-01)

    UI / Player

    • Replace sticky footer with a dedicated About dialog opened from a new header button — frees up bottom space and removes the always-visible colophon strip (ec51781)
    • Reclaim dead space on the player view: drop ~64 px of bottom container padding now that the footer is gone (ec51781)
    • Loosen the vinyl stage aspect ratio (1:11:0.85) and switch the tonearm from height: 36% to aspect-ratio: 1 so the disc no longer leaves a tall empty band below the sleeve (ec51781)
    • Add about.* and dialog.close i18n keys for EN and RU (ec51781)

    Development / Internal

    Chores

    • Wire up the code-review-graph MCP server: add .mcp.json (uvx, stdio), document the graph tools in CLAUDE.md so structural exploration prefers graph queries over Grep/Read, and ignore the .code-review-graph/ index directory (e7372b0)

    All Commits
    Hash Message Author
    ec51781 ui(player): replace footer with About dialog + reclaim dead space alexei.dolgolyov
    e7372b0 chore: wire up code-review-graph MCP server alexei.dolgolyov

    Downloads

    Platform File
    Windows (installer) MediaServer-v0.2.2-setup.exe
    Windows (portable) MediaServer-v0.2.2-win-x64.zip
    Linux MediaServer-v0.2.2-linux-x64.tar.gz
    Downloads
  • v0.2.1 46af2bb8cc

    Media Server v0.2.1
    Lint & Test / test (push) Has been skipped
    Release / create-release (push) Successful in 3s
    Release / build-linux (push) Successful in 32s
    Release / build-windows (push) Successful in 49s
    Stable

    alexei.dolgolyov released this 2026-04-25 20:23:01 +03:00 | 30 commits to master since this release

    v0.2.1 (2026-04-25)

    A small polish release on top of the Studio Reference redesign — accent picker fix,
    visualizer performance work, and a couple of layout refinements for tablet and
    small-desktop widths.

    Bug Fixes

    • Accent picker now wired to the editorial copper palette + visual polish (f4be2bd)

    Performance

    • Visualizer — significant CPU cuts on spectrum rendering and track switches (51ec150)

    UI Improvements

    • Meaningful caps for tablet / small-desktop range + tighter footer (25a492d)

    Development / Internal

    CI/Build

    • Skip test workflow on release commits (08c3c80)

    All Commits
    Hash Message Author
    25a492d ui(player): meaningful caps for tablet/small-desktop range + tighter footer alexei.dolgolyov
    f4be2bd fix(player): wire accent picker to editorial copper palette + visual polish alexei.dolgolyov
    51ec150 perf(visualizer): cut spectrum + track-switch CPU significantly alexei.dolgolyov
    08c3c80 ci: skip test workflow on release commits alexei.dolgolyov

    Downloads

    Platform File
    Windows (installer) MediaServer-v0.2.1-setup.exe
    Windows (portable) MediaServer-v0.2.1-win-x64.zip
    Linux MediaServer-v0.2.1-linux-x64.tar.gz
    Downloads