-
Media Server v0.4.0
StableLint & Test / test (push) Has been skippedLint & Test / linux-smoke (push) Has been skippedRelease / create-release (push) Successful in 3sRelease / build-windows (push) Successful in 1m9sRelease / build-linux (push) Successful in 1m10sRelease / build-macos (push) Has been cancelledreleased this
2026-05-28 17:27:37 +03:00 | 3 commits to master since this releasev0.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
linuxextra (dbus-python,PyGObject,python-xlib) plus abuild-dist-linux.shthat emits a portable tarball and a systemd user unit. The unit setsDBUS_SESSION_BUS_ADDRESS,XDG_RUNTIME_DIR, andReadWritePathsfor~/.config/~/.cacheso MPRIS works and audit-log / thumbnail writes aren't blocked byProtectHome. 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 aboutloginctl enable-linger. (ddf4a6c) - macOS support. New
macosextra (pyobjc-framework-Cocoa,pyobjc-framework-Quartz), abuild-dist-macos.shscript, and a per-user LaunchAgent installer producingMediaServer-vX.Y-macos-{arm64,x86_64}.tar.gzartifacts. Spotify URL artwork is wired throughMediaController.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/artworkendpoint awaits the controller. (ddf4a6c) - Per-OS unavailable reasons on
/api/media/visualizer/statusso 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_ADDRESSorXDG_RUNTIME_DIRis 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.icogrew 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.pynow 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._confirmguarded againstctypes.windllon non-Windows so the new Linux / macOS builds don't crash when the tray prompts for confirmation. (ddf4a6c)config.example.yamldefaults are now cross-platform. Per-OS commented examples for the on/off scripts, andon_turn_offdefaults to a harmlessecho(the previous default silently failed everywhere but Windows). (ddf4a6c)
Development / Internal
Build & Packaging
scripts/generate-icon.py— SVG is the canonical source;resvg-pyrasterizes every ICO size; Pillow packs the multi-resolutionicon.ico. Re-run any time the SVG changes. (d798fed)- Dependency reorganization in
pyproject.toml—screen-brightness-controlandmonitorcontrolare cross-platform and moved to base deps; newlinuxandmacosoptional-deps groups withsys_platformmarkers.resvg-pyadded to[dev]for the icon-generation script. (ddf4a6c, d798fed) install_linux.sh— dropped the deadrequirements.txtpath; now installs viapip install ".[linux]"and pre-creates the writable state dirs. (ddf4a6c)- Templated
media-server.serviceupdated to match the new dist layout, with proper session-bus env vars and a writable state-dir grant. (ddf4a6c)
CI
- New
linux-smokejob in.gitea/workflows/test.yml— installs.[linux], boots the server underdbus-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.txtinstructions, 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.exeWindows (portable) MediaServer-v0.4.0-win-x64.zipLinux MediaServer-v0.4.0-linux-x64.tar.gzmacOS (Apple Silicon) MediaServer-v0.4.0-macos-arm64.tar.gzmacOS (Intel) MediaServer-v0.4.0-macos-x86_64.tar.gzDownloads
- Linux support, production-ready. New
-
Media Server v0.3.1
Stablereleased this
2026-05-25 23:45:08 +03:00 | 6 commits to master since this releasev0.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.0deployments unlesscors_originswas explicitly configured.Bug Fixes
- WebSocket Origin check now accepts same-origin connections. When
cors_originsis unset, the default allow-list was hard-coded tohttp://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 anyOriginwhose authority matches the request'sHostheader (with eitherhttp://orhttps://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.exeWindows (portable) MediaServer-v0.3.1-win-x64.zipLinux MediaServer-v0.3.1-linux-x64.tar.gzDownloads
- WebSocket Origin check now accepts same-origin connections. When
-
Media Server v0.3.0
Stablereleased this
2026-05-22 22:41:11 +03:00 | 8 commits to master since this releasev0.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_managementdefault toFalse. Legacy bare-stringapi_tokensentries are auto-promoted toadminscope, 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 newTokenSpecformat inconfig.example.yaml). (d131ba4) cors_origins: ["*"]is now refused at startup — set explicit origins instead. (d131ba4)- Thumbnail cache directory moved from project-root
.cacheto%LOCALAPPDATA%/media-server/cacheon Windows and$XDG_CACHE_HOME/media-server/thumbnailson POSIX. The old.cachedirectory 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(+ optionalssl_keyfile_password); startup refuses to launch with only one of the pair set. (d131ba4) - Reverse-proxy support:
proxy_headers+forwarded_allow_ipsplumbed throughSettingstouvicorn.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 structuredTokenSpecentries; legacy bare-string tokens promote toadmin. (d131ba4) - In-process token-bucket rate limiter: 5/min for failed auths, 10/min for
/api/scripts/executeand/api/callbacks/execute. (d131ba4) - WebSocket Origin allow-list check (CSWSH defence). (d131ba4)
- Script parameter validation: per-parameter
patternregex inScriptParameterConfigplusshell=False(shlex.split) execution path to harden against parameter injection oncmd.exe. (d131ba4) - CSP tightened with
form-action,worker-src,manifest-srcdirectives. (d131ba4) noopener noreferrer+no-referrerreferrerpolicy applied to every outbound link in the WebUI. (d131ba4)- Windows config.yaml ACL hardening via
icacls(current user + SYSTEM + Administrators only);0600continues to be enforced on POSIX. (d131ba4) - PWA installability:
manifest.jsongetsid,scope, andtheme_color/background_colormatching 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_mediagated by track key — was decoding the WinRT thumbnail twice per second regardless of track changes. (d131ba4) /api/media/artworkreturns content-derivedETag+Cache-Controlso the browser sendsIf-None-Matchand gets304on track repeats. (d131ba4)- Foreground-service
ctypesargtypes hoisted to one-time module init — was re-declaring ~14 prototypes per probe. (d131ba4) display_service._static_cachekeyed 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
requestAnimationFrameloop paused ondocument.hidden, resumed onvisible. (d131ba4)
Bug Fixes
- Lifespan rewritten as
try/yield/finallyso a partial-startup failure cannot orphan background tasks or executors. (d131ba4) _run_callbackinroutes/media.pykeeps 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 returnsTrueregardless of the underlying AppleScript result. (d131ba4)TrayManager._restart_requestedinitialised in__init__and set before signalling exit so the main thread observes it correctly. (d131ba4)- Missing
static_dirnow logs aWARNINGinstead 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-IDmiddleware — accepts an upstream id if it matches a safe regex, otherwise generates aUUID4.request_id_varadded toContextVarsand 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.exeWindows (portable) MediaServer-v0.3.0-win-x64.zipLinux MediaServer-v0.3.0-linux-x64.tar.gzDownloads
- Admin scope is now required for management endpoints, and
-
Media Server v0.2.7
Stablereleased this
2026-05-19 01:34:36 +03:00 | 10 commits to master since this releasev0.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/onclickattributes — every one of which the server's strictscript-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 withdata-*markers and wired properaddEventListenercalls (delegated on the slider container, direct on the accent dropdown), so the controls work under the strict CSP without anyunsafe-inline/unsafe-hashesrelaxation. (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.exeWindows (portable) MediaServer-v0.2.7-win-x64.zipLinux MediaServer-v0.2.7-linux-x64.tar.gzDownloads
- 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
-
Media Server v0.2.6
Stablereleased this
2026-05-18 03:19:07 +03:00 | 12 commits to master since this releasev0.2.6 (2026-05-18)
Features
- Foreground-window tracker (cross-platform): New
/api/foregroundendpoint plus liveforeground/foreground_updatemessages on the existing WebSocket feed. Windows uses a ctypesGetForegroundWindowprobe with HANDLE-correctargtypesso 64-bit window handles aren't truncated; macOS uses AppKit'sNSWorkspace.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_titlealongsideis_browser. Optional UIA-based URL extraction sits behind theMEDIA_SERVER_BROWSER_UIAenv 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.jsonandru.json. (61cdce9) - WebSocket integration: The existing 1s status loop now polls foreground every tick, broadcasts
foregroundon connect, and emitsforeground_updateonly 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.yamlnow defaultshost: 127.0.0.1. The server still refuses to bind a non-loopback interface without eitherapi_tokensconfigured or an explicitallow_lan_without_auth: trueopt-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.login the config directory. Previously, launches viawscript/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.pysoruff checkis 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.exeWindows (portable) MediaServer-v0.2.6-win-x64.zipLinux MediaServer-v0.2.6-linux-x64.tar.gzDownloads
- Foreground-window tracker (cross-platform): New
-
Media Server v0.2.5
Stablereleased this
2026-05-16 20:16:45 +03:00 | 16 commits to master since this releasev0.2.5 (2026-05-16)
Security
- Loopback-by-default + auto-generated token: Server now binds
127.0.0.1by default; first-run bootstrap generates a randomapi_tokenand refuses to bind a non-loopback interface without auth unless explicitly opted in. (bcc6d40) - Browser path-traversal hardening:
BrowserService.validate_pathnow rejects absolute paths, drive letters, UNC paths, and NUL bytes./api/browser/{play,metadata,thumbnail}require afolder_idplus 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*_managementflags. (bcc6d40) - Hardened response headers + CORS: Strict
Content-Security-Policy,X-Frame-Options: DENY,Referrer-Policy: no-referrer,X-Content-Type-Options: nosniff. CORS locked tolocalhost:<port>+127.0.0.1:<port>by default; configurable for trusted origins. (bcc6d40) - Atomic config writes with restrictive permissions:
config.yamlwrites go through a temp file +os.replaceand land with0o600on 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_GROUPon Windows,start_new_session=Trueon 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 delegateddata-actionhandler, and remote MDI SVGs are parsed and sanitized (strip<script>,<foreignObject>,on*handlers,javascript:hrefs) before they touchinnerHTML. All dynamic URL segments now go throughencodeURIComponent. (bcc6d40) - CSP-compliant event wiring: Strict
script-src 'self'was blocking every inlineonclick/onchange/oninput/onsubmitin the UI, leaving buttons and forms silently dead. All 53 inline handler attributes inindex.htmlwere renamed todata-on*and a newwireInlineHandlers()inapp.jsparses each expression onDOMContentLoadedand attaches a realaddEventListener— supports no-arg calls, string/number/bool/null literals, and theeventtoken. Nounsafe-inlineorunsafe-hashesneeded. (eaeebb6)
Bug Fixes
- WebSocket reconnect robustness: Close the previous socket before opening a new one, clear the ping interval per-socket, clear
reconnectTimeoutup-front, retry ononline/visibilitychange, and wrapJSON.parsein 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
_unavailableflag short-circuits start/stop; cleared byset_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 +
isConnectedchecks; 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-listswitched 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 inbrowser.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. PrematureisConnectedbail removed fromloadThumbnail— the img element is intentionally detached when called fromrenderBrowserGrid/List, and the post-await checks already handle navigation-away correctly. (982dda4)
Performance
- Blocking IO off the event loop: Linux MPRIS/
pactlcalls,/api/displayDDC/CI handlers, andbrowse_directoryare all wrapped inasyncio.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.localinstead ofnew_event_loop/closeon every tick. (bcc6d40) - WebSocket broadcast: serialize once:
broadcast()serializes JSON a single time and usessend_textto 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
mousemovehandler 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-itemis 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>witharia-label, andaria-currentis set on the root. (bcc6d40) - i18n gaps filled:
display.msg.power_*,execution.*,scripts.params.execute,callbacks.emptynow have proper en + ru strings. (bcc6d40)
Development / Internal
Quality
- All
asyncio.get_event_loop()in coroutines migrated toget_running_loop()(the former is deprecated in Python 3.12+). (bcc6d40) ThreadPoolExecutors now shut down cleanly during lifespan teardown. (bcc6d40)config_managerdedup: 12 near-identical CRUD methods collapsed onto generic_upsert/_deletehelpers — about 290 lines removed with no behavior change. (bcc6d40)- Service worker no longer pass-throughs every fetch. (bcc6d40)
- M3U playlist written via
NamedTemporaryFileso a fixed-path symlink can no longer clobber it. (bcc6d40) __version__prefers livepyproject.tomlin dev checkouts sopip install -e .users see the source-of-truth version, not the stale metadata baked in at install time. (bcc6d40)_broadcast_after_openhardening: 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.exeWindows (portable) MediaServer-v0.2.5-win-x64.zipLinux MediaServer-v0.2.5-linux-x64.tar.gzDownloads
- Loopback-by-default + auto-generated token: Server now binds
-
Media Server v0.2.4
Stablereleased this
2026-05-15 14:50:28 +03:00 | 20 commits to master since this releasev0.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
*_supportedflags 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 VCP0xDCwith 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_sethelper 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 intoset_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 (VCP0xDC) additionally requires the capability string to declare supported codes undercmds[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 namedmedia-server, silently missing the installer-bundled process (which runs as plainpython.exeviamedia-server.bat). The script now kills whatever currently owns the listen port regardless of process name, adds-Mode auto|dev|installerwith 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.exeWindows (portable) MediaServer-v0.2.4-win-x64.zipLinux MediaServer-v0.2.4-linux-x64.tar.gzDownloads
- 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
-
Media Server v0.2.3
Stablereleased this
2026-05-01 19:41:41 +03:00 | 24 commits to master since this releasev0.2.3 (2026-05-01)
UI / Player
- Square the vinyl stage (
1:0.85→1:1) and pin the tonearm toheight: 36%instead ofaspect-ratio: 1so 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
-2degso 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 addflex-shrink: 0to 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.exeWindows (portable) MediaServer-v0.2.3-win-x64.zipLinux MediaServer-v0.2.3-linux-x64.tar.gzDownloads
- Square the vinyl stage (
-
Media Server v0.2.2
Stablereleased this
2026-05-01 17:15:24 +03:00 | 27 commits to master since this releasev0.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:1→1:0.85) and switch the tonearm fromheight: 36%toaspect-ratio: 1so the disc no longer leaves a tall empty band below the sleeve (ec51781) - Add
about.*anddialog.closei18n 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 inCLAUDE.mdso 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.exeWindows (portable) MediaServer-v0.2.2-win-x64.zipLinux MediaServer-v0.2.2-linux-x64.tar.gzDownloads
-
Media Server v0.2.1
Stablereleased this
2026-04-25 20:23:01 +03:00 | 30 commits to master since this releasev0.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.exeWindows (portable) MediaServer-v0.2.1-win-x64.zipLinux MediaServer-v0.2.1-linux-x64.tar.gzDownloads