Marcel van der Veldt [Tue, 17 Feb 2026 12:40:24 +0000 (13:40 +0100)]
Some small tweaks to the AirPlay provider
OzGav [Tue, 17 Feb 2026 10:45:01 +0000 (20:45 +1000)]
Cap Apple Music artwork resolution to 1000x1000 (#3177)
Apple Music API returns artwork URLs with the maximum available resolution
(e.g. 6605x6605, 3000x3000) which causes excessive bandwidth usage, slower
page loads, and unnecessary memory consumption. Since Apple Music artwork
URLs support dynamic sizing via {w}x{h} placeholders, cap the requested
dimensions to 1000x1000 which is sufficient for all UI contexts. The
existing image proxy can further downscale for thumbnails as needed.
https://claude.ai/code/session_01AxXvTSeiZyCmnNqYLtfhLH
Co-authored-by: Claude <noreply@anthropic.com>
Mikhail Nevskiy [Tue, 17 Feb 2026 09:27:53 +0000 (12:27 +0300)]
feat(kion_music): add configurable My Mix settings and improvements (#3145)
* feat(kion_music): add configurable My Mix settings and improvements
Add comprehensive configuration options for My Mix (radio) feature and
various provider improvements synchronized from Yandex Music provider.
## New Features
### My Mix Configuration
- `my_mix_max_tracks`: Maximum tracks for My Mix playlist (default: 150)
- `my_mix_batch_size`: API batch count for Browse/Discover (default: 3)
- `track_batch_size`: Track details batch size (default: 50)
- `discovery_initial_tracks`: Initial tracks in Discover section (default: 5)
- `browse_initial_tracks`: Initial tracks when browsing My Mix (default: 15)
### Feature Toggles (Advanced, disabled by default)
- `enable_recommendations`: Show My Mix in Discover/Recommendations
- `enable_my_mix_browse`: Show My Mix folder in Browse section
- `enable_my_mix_playlist`: Show My Mix as virtual playlist
- `enable_my_mix_radio`: Enable radio feedback (like/dislike)
### Base URL Configuration (Advanced)
- `base_url`: Configurable API endpoint (default: https://music.mts.ru/ya_proxy_api)
- Fixes connection issue from endpoint change (/ya_api → /ya_proxy_api)
## Provider Improvements
### API Client
- Add batching for liked albums/tracks fetching
- Add retry logic for network errors
- Add My Mix tracks fetching with batch_id support
- Add radio station feedback support
- Accept optional base_url parameter
- Use DEFAULT_BASE_URL constant
### Provider Features
- Add SIMILAR_TRACKS and RECOMMENDATIONS features
- Add My Mix as virtual playlist (playlist_id: "my_mix")
- Add radio feedback for track started/finished/like/dislike
- Add duplicate track filtering in My Mix
- Add locale-based browse folder names (Russian/English)
- Conditional feature enabling based on config
### Streaming
- Add quality selection logic for FLAC/AAC/MP3
- Add content type detection for audio formats
- Support for flac-mp4 and aac-mp4 formats
### Parsers
- Add radio track ID parsing (track_id@station_id format)
- Improve external URL generation for artists/albums/tracks/playlists
- Use music.mts.ru domain
## Testing
- Add test_streaming.py (7 tests for quality selection)
- Add test_my_mix.py (2 tests for radio ID parsing)
- Update test_api_client.py (8 tests for batching/retry/My Mix)
- Update test_parsers.py (16 tests with snapshots)
- All 44 tests pass ✅
## Constants
- Add My Mix configuration keys
- Add DEFAULT_BASE_URL constant
- Add ROTOR_STATION_MY_MIX constant
- Add MY_MIX_PLAYLIST_ID constant
- Add RADIO_TRACK_ID_SEP constant
- Add browse folder name dictionaries
This brings KION Music provider feature parity with Yandex Music provider
while maintaining MTS-specific branding and API endpoints.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(kion_music): use DEFAULT_BASE_URL when base_url not provided
Set self._base_url to DEFAULT_BASE_URL if base_url parameter is None
in KionMusicClient.__init__(). This ensures tests pass and the client
always has a valid base URL.
Fixes test_connect_sets_base_url failure in CI.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Address PR #3145 review comments
- Remove all tuning/toggle config entries; use hardcoded constants with
sane defaults (all features always enabled)
- Fix documentation URL (beta.music-assistant.io → music-assistant.io)
- Extract magic string to ROTOR_FEEDBACK_FROM constant with comment
- Switch from private client._request to public client.request
- Update docstrings: Yandex → KION / generic wording
- Fix test import path (yandex_music → kion_music)
- Refactor duplicated My Mix code into shared _fetch_my_mix_tracks()
helper; browse(), _get_my_mix_playlist_tracks(), recommendations()
are now thin wrappers
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Increase Discovery initial tracks to 20 and cache to 10 minutes
Show more tracks in Discovery on Home and reduce API load by caching
recommendations for 10 minutes instead of 1 minute.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: address Copilot review comments and improve robustness
- Use == instead of is for dict comparison (BROWSE_NAMES_RU)
- Remove dead _get_content_type stub in parsers.py, inline ContentType.UNKNOWN
- Add AAC variants (aac-mp4, he-aac, he-aac-mp4) to streaming content type mapping
- Fix cache key collision: normalize composite track IDs before caching
- Add retry with reconnect to get_track_file_info_lossless
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: trudenboy0 <trudenboy0@gmail.com>
Julian Daberkow [Tue, 17 Feb 2026 09:06:19 +0000 (10:06 +0100)]
feat(deezer): Genre and mood flows (#3171)
* Add basic mood and genre flow support for Deezer
* Fetch Deezer flows and their images dynamically
* Address PR review comments
- Narrow exception handling from `Exception` to `DeezerErrorResponse`
for recommended albums/artists endpoints
- Parse GW track data directly via `_parse_gw_track()` instead of
making individual REST API calls per track
- Add early return check in `get_user_radio` when data key is missing
- Remove unnecessary `:param: None` docstring in `get_home_flows`
- Add defensive `.get()` check for "sections" key in `get_home_flows`
to prevent KeyError
* Shrink function documentation of _parse_gw_track
* Revert to previous approach of fetching gw tracks seperately
---------
Co-authored-by: jdaberkow <13017916+jdaberkow@users.noreply.github.com>
dependabot[bot] [Tue, 17 Feb 2026 08:25:21 +0000 (08:25 +0000)]
Chore(deps): Bump aioslimproto from 3.1.4 to 3.1.5 (#3176)
* Chore(deps): Bump aioslimproto from 3.1.4 to 3.1.5
Bumps aioslimproto from 3.1.4 to 3.1.5.
---
updated-dependencies:
- dependency-name: aioslimproto
dependency-version: 3.1.5
dependency-type: direct:production
update-type: version-update:semver-patch
...
Signed-off-by: dependabot[bot] <support@github.com>
* Also bump version in provider manifest
---------
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Marvin Schenkel <marvinschenkel@gmail.com>
David Bishop [Tue, 17 Feb 2026 07:36:57 +0000 (23:36 -0800)]
Fix RuntimeError from dict/set mutation during iteration (#3159)
* Fix RuntimeError from dict/set mutation during iteration
Several collections are iterated while concurrent callbacks can
modify them, causing "Set/dictionary changed size during iteration"
RuntimeErrors:
- mass.py: _subscribers set iterated in signal_event() while
subscribe/unsubscribe callbacks modify it
- mass.py: _providers dict iterated in get_provider() and
_on_mdns_service_state_change() while providers load/unload
- player_controller.py: _players dict iterated in get_players(),
get_player_by_name(), and update_player_control() while players
register/unregister
- music.py: in_progress_syncs list iterated while done-callbacks
call .remove() on it
Snapshot via list() before iterating in all affected locations.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Fix additional dict mutation during iteration in mass.py
Snapshot via list() in three more locations where self._providers
or self._tracked_tasks are iterated while concurrent callbacks can
modify them: get_providers(), get_providers_by_domain(), and stop().
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Fix dict mutation during iteration in webserver dynamic routes
Snapshot self._dynamic_routes.items() via list() in _handle_catch_all()
to prevent RuntimeError when routes are registered or unregistered by
providers while a request is being matched against prefix routes.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: David Bishop <git@gnuconsulting.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
music-assistant-machine [Tue, 17 Feb 2026 03:46:31 +0000 (04:46 +0100)]
⬆️ Update music-assistant-frontend to 2.17.88 (#3178)
Co-authored-by: marcelveldt <6389780+marcelveldt@users.noreply.github.com>
Fabian Munkes [Mon, 16 Feb 2026 18:24:01 +0000 (19:24 +0100)]
fix: adapt playlog for all users if no user present (#3169)
adapt playlog for all users
Fabian Munkes [Mon, 16 Feb 2026 17:45:12 +0000 (18:45 +0100)]
fix: add name back to abs/itunes recommendation folders (#3170)
add name back to recommendation folders
Fabian Munkes [Mon, 16 Feb 2026 17:30:04 +0000 (18:30 +0100)]
abs: report correct time_listened in sessions (#3163)
* abs sessions statistics
* small progress sync fix
Marvin Schenkel [Mon, 16 Feb 2026 13:23:25 +0000 (14:23 +0100)]
Auto cleanup cache db when it grows >= 2GB (#3174)
Auto cleanup cachedb when it grows >= 2GB
Marcel van der Veldt [Mon, 16 Feb 2026 11:51:35 +0000 (12:51 +0100)]
Fix: restart playback when switching to other output protocol
Marcel van der Veldt [Mon, 16 Feb 2026 09:34:42 +0000 (10:34 +0100)]
Some small follow-up fixes for protocols linking
David Bishop [Mon, 16 Feb 2026 09:08:35 +0000 (01:08 -0800)]
Fix index_in_buffer or current_index treating index 0 as unset (#3160)
index_in_buffer and current_index are int | None where 0 is a valid
value (first track in queue). Two locations use chained `or` to
select between them:
- set_shuffle: `queue.index_in_buffer or queue.current_index`
- play_media_from_queue: `queue.index_in_buffer or queue.current_index or 0`
When index_in_buffer is 0 (first track buffered), Python's `or`
treats it as falsy and falls through to current_index. This causes
shuffle reshuffling and queue insertion to use the wrong position.
Replace with explicit `is not None` checks in both locations.
Co-authored-by: David Bishop <git@gnuconsulting.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
David Bishop [Mon, 16 Feb 2026 08:24:19 +0000 (00:24 -0800)]
Fix AttributeError when provider is temporarily unavailable (#3157)
get_provider() can return None when a provider is temporarily
unavailable (e.g., during reload or network issues). Both
remove_item_from_library() and add_item_to_library() call
.library_edit_supported() on the result without a None check,
causing an AttributeError that surfaces as a 500 error.
Co-authored-by: David Bishop <git@gnuconsulting.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
music-assistant-machine [Mon, 16 Feb 2026 03:52:05 +0000 (04:52 +0100)]
⬆️ Update music-assistant-frontend to 2.17.87 (#3172)
Co-authored-by: marcelveldt <6389780+marcelveldt@users.noreply.github.com>
Chris [Sun, 15 Feb 2026 17:32:54 +0000 (11:32 -0600)]
Fix HTTP proxy URL parsing for wss:// WebSocket URLs (#3168)
* Fix HTTP proxy URL parsing for wss:// WebSocket URLs
The HTTP proxy handler constructed the local HTTP URL by stripping
"ws://" from local_ws_url with a simple string replace. When the
server uses SSL, local_ws_url is "wss://..." which didn't match the
replace, producing a broken URL like "http://wss:/imageproxy?..." and
causing all proxy requests to fail with DNS resolution errors.
Use urllib.parse.urlparse instead, which correctly handles both ws://
and wss:// schemes.
* Move urlparse import to top-level to fix PLC0415 lint error
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Marcel van der Veldt [Sun, 15 Feb 2026 14:50:45 +0000 (15:50 +0100)]
Merge players with multiple protocols together (#3150)
* Base implementation of merging players through protocol linking
* Restore after merge conflict
* follow-up
* Fix config handling for players
* some tweaks
* Handle more (edge) cases
* bunch of fixes
* More fixes
* Some more tweaks
* Fix group_members calc
* A bunch of tweaks and refactoring
* more tweaks
* more follow-up
* Update controller.py
* refactoring groups
* more fixes for syncgroup
* fix readme nitpick
* revert frozen in uv run
* Add default providers conf
* fix tests
* more tweaks
* fixes for syncgroups
* More small tweaks
* more sync player tweaks
Marcel van der Veldt [Sat, 14 Feb 2026 07:36:32 +0000 (08:36 +0100)]
Fix typo in Sonos provider
music-assistant-machine [Sat, 14 Feb 2026 03:38:43 +0000 (04:38 +0100)]
⬆️ Update music-assistant-frontend to 2.17.86 (#3162)
Co-authored-by: marcelveldt <6389780+marcelveldt@users.noreply.github.com>
Marcel van der Veldt [Sat, 14 Feb 2026 00:02:19 +0000 (01:02 +0100)]
Fix typo in Airplay provider on setting new ip
Marcel van der Veldt [Fri, 13 Feb 2026 23:17:47 +0000 (00:17 +0100)]
Fix NO_CONTENT error on Sonos playback
Marcel van der Veldt [Fri, 13 Feb 2026 20:08:35 +0000 (21:08 +0100)]
Host streamserver by default on port 8097
Marcel van der Veldt [Fri, 13 Feb 2026 20:01:56 +0000 (21:01 +0100)]
guard against invalid volume normalization values
Marvin Schenkel [Fri, 13 Feb 2026 12:25:51 +0000 (13:25 +0100)]
Fix for Spotify returning endless tracks from playlist (#3155)
* Fix for Spotify returning endless tracks from playlist
* Auto cleanup cache for Spotify
Marvin Schenkel [Fri, 13 Feb 2026 12:04:47 +0000 (13:04 +0100)]
Always cleanup smart fades tmp files (#3143)
* Always cleanup smart fades tmp files
* Cleanup
dependabot[bot] [Fri, 13 Feb 2026 09:54:16 +0000 (10:54 +0100)]
Chore(deps): Bump docker/build-push-action from 6.19.1 to 6.19.2 (#3148)
Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 6.19.1 to 6.19.2.
- [Release notes](https://github.com/docker/build-push-action/releases)
- [Commits](https://github.com/docker/build-push-action/compare/v6.19.1...v6.19.2)
---
updated-dependencies:
- dependency-name: docker/build-push-action
dependency-version: 6.19.2
dependency-type: direct:production
update-type: version-update:semver-patch
...
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
David Bishop [Fri, 13 Feb 2026 09:53:46 +0000 (01:53 -0800)]
Fix operator precedence and inverted dedup logic in audiobooks playlog (#3153)
Two bugs in the audiobook resume/playlog tracking:
1. `int(media_item.resume_position_ms or 0 / 1000)` never divides by
1000 because `/` binds tighter than `or`. The expression evaluates as
`int(resume_position_ms or (0 / 1000))`, so non-zero values pass
through as raw milliseconds instead of seconds.
2. The dedup check `abs(difference) > 2` skips the DB write when data
HAS changed (difference > 2 seconds) and writes when it has NOT
changed (difference <= 2 seconds). The comparison is inverted.
Co-authored-by: David Bishop <git@gnuconsulting.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
David Bishop [Fri, 13 Feb 2026 09:48:06 +0000 (01:48 -0800)]
Fix M3U parser truncating EXTINF duration to single character (#3152)
The EXTINF duration parser used `info[0].strip()[0]` which takes only
the first character of the duration string. For multi-digit durations
like "120", this truncates to "1". Also, the `-1` check on line 79
compared against "-1" but could only ever see "-" (a single char),
so negative/unknown durations were never properly detected.
Remove the erroneous `[0]` index so the full duration string is used
and the `-1` sentinel is correctly recognized.
Co-authored-by: David Bishop <git@gnuconsulting.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
David Bishop [Fri, 13 Feb 2026 09:33:02 +0000 (01:33 -0800)]
Fix case-sensitive comparison in compare_strings fuzzy matching (#3151)
In non-strict mode, compare_strings lowercases str1 but passes the
original-case str2 to SequenceMatcher on line 564. This causes fuzzy
matching to penalize case differences, making it fail to match strings
like "Track Feat. John" vs "TRACK FT. JOHN" that should be considered
equivalent.
Also fix the elif branch (line 559) to replace on str2_lower instead
of str2, so the result is consistently lowered.
Co-authored-by: David Bishop <git@gnuconsulting.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Chris [Thu, 12 Feb 2026 20:24:47 +0000 (14:24 -0600)]
Add save_as_playlist command to player queue controller (#3149)
OzGav [Thu, 12 Feb 2026 07:24:36 +0000 (17:24 +1000)]
Fix sync group toggle (#3142)
* Fix dynamic sync group toggle having no effect on member checkboxes
PR #3118 made _attr_static_group_members unconditionally populated for
both dynamic and static groups. Since the frontend uses
static_group_members to determine which players are non-removable
(greyed out, no checkbox), this caused all members to appear locked
regardless of the dynamic toggle setting.
Restore the conditional assignment: dynamic groups get an empty
static_group_members list (all members removable), static groups get
the configured members list (all members locked). Fix the power-off
reset to read configured members directly from config instead of
_attr_static_group_members, so dynamic groups preserve their member
list on power-off without needing them marked as static.
https://claude.ai/code/session_01VVeBMzkvqTrutpg53aMtBY
* Remove added comments
https://claude.ai/code/session_01VVeBMzkvqTrutpg53aMtBY
---------
Co-authored-by: Claude <noreply@anthropic.com>
dependabot[bot] [Wed, 11 Feb 2026 18:41:30 +0000 (19:41 +0100)]
Chore(deps): Bump docker/build-push-action from 6.18.0 to 6.19.1 (#3138)
Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 6.18.0 to 6.19.1.
- [Release notes](https://github.com/docker/build-push-action/releases)
- [Commits](https://github.com/docker/build-push-action/compare/v6.18.0...v6.19.1)
---
updated-dependencies:
- dependency-name: docker/build-push-action
dependency-version: 6.19.1
dependency-type: direct:production
update-type: version-update:semver-minor
...
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
dependabot[bot] [Wed, 11 Feb 2026 17:44:13 +0000 (18:44 +0100)]
Chore(deps): Bump pillow from 12.1.0 to 12.1.1 (#3137)
Bumps [pillow](https://github.com/python-pillow/Pillow) from 12.1.0 to 12.1.1.
- [Release notes](https://github.com/python-pillow/Pillow/releases)
- [Changelog](https://github.com/python-pillow/Pillow/blob/main/CHANGES.rst)
- [Commits](https://github.com/python-pillow/Pillow/compare/12.1.0...12.1.1)
---
updated-dependencies:
- dependency-name: pillow
dependency-version: 12.1.1
dependency-type: direct:production
...
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
music-assistant-machine [Wed, 11 Feb 2026 16:47:53 +0000 (17:47 +0100)]
⬆️ Update music-assistant-frontend to 2.17.85 (#3136)
Co-authored-by: stvncode <25082266+stvncode@users.noreply.github.com>
dependabot[bot] [Wed, 11 Feb 2026 10:11:35 +0000 (11:11 +0100)]
Chore(deps): Bump cryptography from 46.0.4 to 46.0.5 (#3134)
Bumps [cryptography](https://github.com/pyca/cryptography) from 46.0.4 to 46.0.5.
- [Changelog](https://github.com/pyca/cryptography/blob/main/CHANGELOG.rst)
- [Commits](https://github.com/pyca/cryptography/compare/46.0.4...46.0.5)
---
updated-dependencies:
- dependency-name: cryptography
dependency-version: 46.0.5
dependency-type: direct:production
...
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
music-assistant-machine [Wed, 11 Feb 2026 03:58:56 +0000 (04:58 +0100)]
⬆️ Update music-assistant-frontend to 2.17.84 (#3135)
Co-authored-by: marcelveldt <6389780+marcelveldt@users.noreply.github.com>
Marvin Schenkel [Tue, 10 Feb 2026 18:10:43 +0000 (19:10 +0100)]
Fix DLNA players not reconnecting (#3132)
* Fix DLNA players not reconnecting
* Change to public method for availability
Mikhail Nevskiy [Tue, 10 Feb 2026 17:31:03 +0000 (20:31 +0300)]
Yandex Music: My Wave Browse folder and locale-based names (#3122)
* Yandex Music: add My Wave (Моя волна) Browse folder
- Add ROTOR_STATION_MY_WAVE constant (user:onyourwave)
- Add get_my_wave_tracks() to api_client using rotor_station_tracks API
- Add My Wave folder to Browse root (first in list)
- When opening My Wave, return tracks from Rotor API as Track items
- Order: Моя волна, Мои исполнители, Мои альбомы, Мне нравится, Мои плейлисты
- On API errors, log and return [] to keep Browse working
Co-authored-by: Cursor <cursoragent@cursor.com>
* Yandex Music: locale-based Browse folder names (EN/RU)
- Add BROWSE_NAMES_RU and BROWSE_NAMES_EN in constants (My Favorites for tracks)
- In browse(), use Russian names when locale starts with ru, else English
- Fallback to English if metadata.locale unavailable
- Test: assert first root folder name is from locale mapping
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix: sort imports in yandex_music provider (I001)
Co-authored-by: Cursor <cursoragent@cursor.com>
* Yandex Music: My Wave — browse, recommendations, similar tracks, virtual playlist, rotor feedback
- My Wave in Browse: root folder (up to 3 batches) and Load more pagination
- Recommendations (Discover): My Wave section with first batch
- Similar tracks (radio mode): Rotor station track:{id} for radio queue
- Virtual playlist My Wave in library (get_playlist / get_playlist_tracks with page)
- My Wave listed first in get_library_playlists
- Rotor feedback: radioStarted, trackStarted, trackFinished, skip
- Reconnect and retry on Server disconnected in api_client
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(yandex_music): resolve ruff/mypy — duplicate methods, line length, type for browse tracks
Co-authored-by: Cursor <cursoragent@cursor.com>
* refactor(yandex_music): use constants instead of string literals, extract locale helper
Replace all "my_wave" string literals with MY_WAVE_PLAYLIST_ID constant
and extract _get_browse_names() helper to deduplicate locale detection
logic across browse(), get_playlist(), and recommendations().
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Михаил Невский <renso@MacBook-Pro-Mihail.local>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Fabian Munkes [Tue, 10 Feb 2026 17:30:04 +0000 (18:30 +0100)]
ABS: Use playback sessions, and optionally allow HLS stream (#3079)
* option to use abs sessions
* bump lib
* more useful exception
* use session progress if it is available
* add session helper
* playback hls
* bump
* remove redundant methods
* add media type
* more hls
* cleanup & session creation lock
* typo
* stream socket event
* bump lib
* edge case
OzGav [Tue, 10 Feb 2026 16:19:51 +0000 (02:19 +1000)]
Radio Paradise revert to using enriched API endpoint (#3130)
hatharry [Tue, 10 Feb 2026 13:48:47 +0000 (02:48 +1300)]
Add Emby Music Provider (#3096)
* Add Emby Music Provider
* Update constants, Error handling and Audio Format for Emby Music Provider
* Fix StreamDetails AudioFormat for Emby Music Provider
* Revert "Fix StreamDetails AudioFormat for Emby Music Provider"
This reverts commit
41ee5616ff6ee3216e5bc31df7426c8bc124f8de.
* Fix StreamDetails AudioFormat for Emby Music Provider
---------
Co-authored-by: Marcel van der Veldt <m.vanderveldt@outlook.com>
Mikhail Nevskiy [Tue, 10 Feb 2026 13:42:45 +0000 (16:42 +0300)]
Add KION Music (MTS Music) provider (#3100)
* feat(kion_music): add KION Music (MTS Music) provider
Add a new music provider for KION Music (music.mts.ru), the MTS telecom
music streaming service. The provider adapts the Yandex Music API client
(yandex-music library) to work with KION's API endpoint at
music.mts.ru/ya_api.
Features:
- Search (tracks, albums, artists, playlists)
- Library access (liked artists, albums, tracks; user playlists)
- Add/remove library items (like/unlike)
- Streaming with quality selection (High 320kbps / Lossless FLAC)
- Lossless streaming via get-file-info API with flac-mp4 codec support
- Playlist track loading with pagination fix and batch fetching
- Retry on NetworkError to handle transient failures
The provider reuses the same yandex-music==2.2.0 dependency already
present for the Yandex Music provider — no new dependencies required.
Co-authored-by: Cursor <cursoragent@cursor.com>
* chore(kion_music): update documentation URL in manifest
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(kion_music): fix missing album cover art in library
- In parse_track(), use parse_album() instead of ItemMapping so albums
get full metadata (including cover_uri) when tracks are synced
- In get_liked_albums(), fetch full album details via client.albums()
in batches of 50 (likes endpoint returns minimal data without cover_uri)
- Remove unused noqa in provider.py (ruff)
Co-authored-by: Cursor <cursoragent@cursor.com>
* Address PR #3100 review: fix base_url, performance, redundant condition, docstrings; add tests
- Pass KION_BASE_URL to ClientAsync in connect() so API calls go to music.mts.ru
- Use set(batch) for O(1) lookups in get_liked_albums() fallback path
- Remove redundant `track_count > 0` check already guaranteed by outer condition
- Replace "Yandex Music" with "KION Music" in docstrings/comments
- Add full test suite: 5 api_client unit tests, 18 parser tests, 11 integration tests
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Михаил Невский <renso@MacBook-Pro-Mihail.local>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Marvin Schenkel [Tue, 10 Feb 2026 10:08:20 +0000 (11:08 +0100)]
Fix filtering and sorting within Artist, Album and Track views (#3131)
Fix filtering and sorting within views
Marvin Schenkel [Tue, 10 Feb 2026 07:53:38 +0000 (08:53 +0100)]
Fix adding an item to library from browse results (#3120)
* Fix adding an item from browse results to library
* Fix adding an item from browse results to library
* Change dict to ItemMapping
dependabot[bot] [Tue, 10 Feb 2026 07:38:23 +0000 (07:38 +0000)]
Chore(deps): Bump soco from 0.30.12 to 0.30.14 (#3125)
* Chore(deps): Bump soco from 0.30.12 to 0.30.14
Bumps [soco](https://github.com/SoCo/SoCo) from 0.30.12 to 0.30.14.
- [Release notes](https://github.com/SoCo/SoCo/releases)
- [Changelog](https://github.com/SoCo/SoCo/blob/master/doc/release_notes.rst)
- [Commits](https://github.com/SoCo/SoCo/compare/v0.30.12...v0.30.14)
---
updated-dependencies:
- dependency-name: soco
dependency-version: 0.30.14
dependency-type: direct:production
update-type: version-update:semver-patch
...
Signed-off-by: dependabot[bot] <support@github.com>
* Also bump provider manifest
---------
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Marvin Schenkel <marvinschenkel@gmail.com>
Mischa Siekmann [Tue, 10 Feb 2026 07:09:05 +0000 (08:09 +0100)]
Snapcast: Fix elapsed time not updated issue (#3119)
snapcast: fix elapsed time not updated issue
dependabot[bot] [Tue, 10 Feb 2026 07:02:19 +0000 (08:02 +0100)]
Chore(deps): Bump cryptography from 46.0.3 to 46.0.4 (#3124)
Bumps [cryptography](https://github.com/pyca/cryptography) from 46.0.3 to 46.0.4.
- [Changelog](https://github.com/pyca/cryptography/blob/main/CHANGELOG.rst)
- [Commits](https://github.com/pyca/cryptography/compare/46.0.3...46.0.4)
---
updated-dependencies:
- dependency-name: cryptography
dependency-version: 46.0.4
dependency-type: direct:production
update-type: version-update:semver-patch
...
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Mikhail Nevskiy [Tue, 10 Feb 2026 07:01:39 +0000 (10:01 +0300)]
Add Zvuk Music provider (#3090)
* Add zvuk_music provider scaffold (manifest, constants, icons)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Add Zvuk Music API client wrapper
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Add Zvuk Music model parsers
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Add ZvukMusicProvider implementation
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Update zvuk_music icons to official 2024 logo
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Add Zvuk Music provider integration tests
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Replace Zvuk Music integration tests with unit tests
Remove integration tests that required real API tokens and a running MA
server. Add comprehensive unit tests for parsers using mock objects,
covering all parser functions (parse_artist, parse_album, parse_track,
parse_playlist) with various scenarios.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Address PR #3090 review: decorator, duration, allow_seek
- Refactor API error handling into @handle_zvuk_errors(not_found_return=...)
decorator (api_client.py)
- Add duration from get_track() and allow_seek=True in get_stream_details
(provider.py)
Co-authored-by: Cursor <cursoragent@cursor.com>
* docs(zvuk): clarify why get_track is needed for duration in get_stream_details
Co-authored-by: Cursor <cursoragent@cursor.com>
---------
Co-authored-by: Михаил Невский <renso@MacBook-Pro-Mihail.local>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: Marcel van der Veldt <m.vanderveldt@outlook.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Marvin Schenkel [Tue, 10 Feb 2026 06:56:55 +0000 (07:56 +0100)]
Airplay stability fixes (#3121)
Dionysis Fortis [Tue, 10 Feb 2026 06:56:01 +0000 (08:56 +0200)]
feat(deezer): add Flow, Radios and Top Charts as recommendations (#3077)
* feat(deezer): add Flow, Radios and Top Charts as dynamic playlists
Implements recommendations for Deezer provider:
- User's personalized Flow as a virtual playlist
- All available Deezer Radios (genres, moods, etc.)
- Top Charts by country
These appear under the Recommendations panel and use virtual
playlist objects (in_library=false) for dynamic content.
Tested on dev environment and working as expected.
* fix: add missing type annotations for mypy
* Extract virtual playlist IDs and radio IDs into module-level constants
music-assistant-machine [Tue, 10 Feb 2026 04:01:00 +0000 (05:01 +0100)]
⬆️ Update music-assistant-frontend to 2.17.83 (#3129)
Co-authored-by: marcelveldt <6389780+marcelveldt@users.noreply.github.com>
Marvin Schenkel [Mon, 9 Feb 2026 14:32:31 +0000 (15:32 +0100)]
Add back pressure to radio streams (#3116)
OzGav [Mon, 9 Feb 2026 12:58:50 +0000 (22:58 +1000)]
Fix sync groups with dynamic option losing members on power off (#3118)
* Fix sync groups with dynamic option losing members on power off
* Remove comment
* Apply suggestion from @OzGav
music-assistant-machine [Mon, 9 Feb 2026 11:28:36 +0000 (12:28 +0100)]
⬆️ Update music-assistant-models to 1.1.98 (#3117)
Co-authored-by: MarvinSchenkel <17671719+MarvinSchenkel@users.noreply.github.com>
Fabian Munkes [Mon, 9 Feb 2026 08:43:50 +0000 (09:43 +0100)]
Add PlayerOptions to backend and MusicCast (#3064)
Mikhail Nevskiy [Mon, 9 Feb 2026 08:42:59 +0000 (11:42 +0300)]
fix(yandex_music): fix playlist loading and missing album cover art (#3099)
* fix(yandex_music): fix playlist tracks not loading in UI
- Return empty list for page > 0 since Yandex Music API returns all
tracks in a single call; without this the controller pagination loop
never terminates
- Add fetch_tracks_async() fallback when API returns playlist metadata
without tracks
- Raise ResourceTemporarilyUnavailable instead of returning empty list
when tracks are expected but unavailable, preventing cache of empty
results
- Fetch full track details in batches of 50 to reduce timeout risk
- Retry get_tracks once on NetworkError in api_client
- Raise ResourceTemporarilyUnavailable on NetworkError in get_playlist
to prevent caching None as empty result
- Suppress yandex_music library DEBUG logs to avoid huge API dumps
Co-authored-by: Cursor <cursoragent@cursor.com>
* chore: apply ruff fixes and update snapshot
- Remove unused noqa comment (RUF100) in provider.py
- Update test_parsers snapshot for upstream model changes (year/style fields)
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(yandex_music): fix missing album cover art in library
- In parse_track(), use parse_album() instead of ItemMapping for the
track's album reference so albums are created with full metadata
(including cover_uri) when tracks are synced to the library
- In get_liked_albums(), fetch full album details via client.albums()
in batches of 50, since the users_likes_albums endpoint returns
minimal data without cover_uri
Co-authored-by: Cursor <cursoragent@cursor.com>
* chore(yandex_music): regenerate parser snapshots after models bump
Co-authored-by: Cursor <cursoragent@cursor.com>
* Update music_assistant/providers/yandex_music/api_client.py
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update music_assistant/providers/yandex_music/provider.py
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Add tests for api_client batching/retry and playlist edge cases
Cover the 3 unresolved Copilot review comments from PR #3099:
- get_liked_albums() batch fetching and NetworkError fallback
- get_tracks() retry-on-NetworkError logic
- get_playlist_tracks() page>0, fetch_tracks_async fallback, empty batch error
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Михаил Невский <renso@MacBook-Pro-Mihail.local>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
MizterB [Mon, 9 Feb 2026 08:28:13 +0000 (03:28 -0500)]
Apple Music: Fix syncing shared playlists (#3095)
* Catch MediaNotFoundError in get_library_playlists
* Undo try/except, fix is_library_id
* Tests for is_library_id
---------
Co-authored-by: Marvin Schenkel <marvinschenkel@gmail.com>
OzGav [Mon, 9 Feb 2026 07:35:38 +0000 (17:35 +1000)]
Allow radio stations to be added to playlists (#2951)
* Add support for radio station URIs in playlists
Enable radio stations to be added to Music Assistant (builtin) playlists
by expanding the playlist track type system to support both Track and Radio items.
Changes:
- playlists.py: Add RADIO media type handling in add_playlist_tracks()
- playlists.py: Update return types to support Track | Radio
- music_provider.py: Expand get_playlist_tracks() return type to list[Track | Radio]
- builtin/__init__.py: Replace Track assertion with type check for Track | Radio
This allows users to mix tracks and radio stations in the same playlist,
with radio URIs stored and retrieved alongside track URIs.
* Add validation to restrict radio items to builtin playlists only
Radio items can only be added to builtin playlists because other streaming
providers (Spotify, Apple Music, etc.) don't support arbitrary radio stream
URLs in their playlists. This adds backend validation to enforce this
constraint and provide a clear error message when attempted.
* Fix bug: Radio URIs were being resolved as track IDs
When adding radio items with library URIs (library://radio/ID) to builtin
playlists, the code was incorrectly passing through track-specific resolution
logic that called tracks.get(ID) instead of radio.get(ID), causing the wrong
items to be added.
Fixed by handling all radio items for builtin playlists early in the URI
processing, adding them directly by URI before the track-specific logic runs.
This ensures library://radio/8 adds radio ID 8, not track ID 8.
* Fix metadata and queue controllers to handle Radio items in playlists
The metadata controller was crashing when processing playlists containing
radio items because it tried to access track.album on Radio objects.
The player_queues controller had incorrect type annotations that assumed
playlist items were always Tracks.
Changes:
- metadata.py: Add isinstance(track, Track) check before accessing .album
- player_queues.py: Update get_playlist_tracks() return type to Track | Radio
- player_queues.py: Add Radio to imports
Both controllers now properly handle playlists containing mixed Track and
Radio items.
* Fix mypy type errors for radio playlist support
The previous implementation changed the base MusicProvider.get_playlist_tracks()
interface to return list[Track | Radio], which caused type errors across all
provider implementations that only return list[Track].
Fixes:
1. Reverted base interface to return list[Track] (standard for all providers)
2. Builtin provider overrides with list[Track | Radio] (covariant return type)
3. Added type: ignore[override] for builtin's covariant override
4. Added type: ignore[return-value] where playlist controller calls providers
5. Fixed radio_mode_base_tracks to filter out Radio items (only works with Track)
6. Fixed variable naming: 'track' -> 'item' where both types are possible
This approach is correct because:
- Only builtin provider supports radio in playlists
- All other providers (Spotify, Tidal, etc.) only support tracks
- Python's type system supports covariant return types in overrides
- list[Track] is compatible with list[Track | Radio] at call sites
* Refactor playlist URI handling logic for clarity
The previous logic combined radio and track handling in one condition,
making it unclear why library URIs were being added for radio items.
Separated into two clear cases:
1. Radio items: ALWAYS add by URI (even library://radio/ID)
- Radio items cannot go through track-matching logic
- They must be retrieved by their full URI
- This is a necessary exception to the "no library URIs" rule
2. Track items: Only add non-library URIs directly
- Provider URIs (spotify://track/xyz) are portable
- Library URIs (library://track/123) fall through to matching logic
- This finds the actual provider URI to store instead
This addresses the review concern that the logic didn't make sense and
makes the special handling of radio items explicit.
* Convert library radio URIs to provider URIs for DB rebuild resilience
Previously, library radio URIs (library://radio/8) were being stored
directly in playlists. This would break on database rebuilds when the
radio item gets a different database ID.
Now when adding a library radio URI:
1. Fetch the full radio item from the library
2. Get its provider mapping (typically builtin)
3. Extract the actual provider item_id (the real stream URL)
4. Create and store the provider URI (builtin://radio/https://stream...)
This ensures playlists contain portable provider URIs with the actual
stream URLs, surviving database rebuilds.
Example:
- Before: Stored library://radio/8 (breaks on rebuild)
- After: Stored builtin://radio/https://stream.example.com/radio.mp3 (portable)
Provider radio URIs are already portable and stored as-is.
* Apply reviewer suggestion: simplify comment in radio_mode_base_tracks
Changed comment from 'filter out unavailable tracks and radio items' to
'filter out unavailable items' as suggested by reviewer for better clarity.
* Make playlist validation generic for non-track items
Changed validation from checking specifically for radio items to checking
for any non-track media type. This makes the code more future-proof for
supporting other media types like podcast episodes in playlists.
Applied reviewer suggestion to make the logic more generic.
* Make library URI conversion universal using get_item_by_uri
Refactored the radio-specific library URI conversion to work universally
for all non-track media types (radio, podcast episodes, audiobooks, etc.)
by using self.mass.music.get_item_by_uri() instead of calling media-type-
specific controllers.
This addresses reviewer feedback to avoid code duplication and makes the
backend ready to support additional media types in playlists as the
frontend adds support for them.
Changes:
- Changed condition from "media_type == MediaType.RADIO" to "media_type != MediaType.TRACK"
- Use get_item_by_uri() to fetch items generically
- Renamed variables from radio-specific to generic (prov_mapping, full_item)
- Updated comments to reflect universal support
* Add type safety check for items with provider_mappings
Fixed mypy error where get_item_by_uri can return BrowseFolder which
doesn't have provider_mappings attribute. Added hasattr check and
restructured to use if/else instead of early continue to properly
handle items without provider mappings.
* Replace hasattr with isinstance for type-safe media item checking
Replaced hasattr() check with isinstance() for better type safety:
- Added Audiobook and PodcastEpisode to imports
- Use isinstance(full_item, (Radio, Audiobook, PodcastEpisode))
- Removed need for type: ignore[attr-defined] comment
- mypy now understands full_item has provider_mappings attribute
This is more explicit, type-safe, and self-documenting about which
media types are supported in playlists.
* Add PlaylistItem type alias for better maintainability
Created a shared type alias PlaylistItem = Track | Radio | PodcastEpisode | Audiobook
to avoid hardcoding union types in multiple places.
Changes:
- playlists.py: Added PlaylistItem type alias at top of file
- playlists.py: Updated all Track | Radio annotations to use PlaylistItem
- player_queues.py: Added PlaylistItem type alias
- player_queues.py: Updated get_playlist_tracks to use PlaylistItem
- builtin/__init__.py: Added Audiobook and PodcastEpisode to imports
- builtin/__init__.py: Updated all type annotations to include all supported types
- builtin/__init__.py: Updated isinstance checks to include all types
Now there's a single source of truth for what media types can be in playlists.
Adding future types only requires changing the type alias definition.
* Add PlaylistItem type alias for better maintainability
Added type aliases and constants to keep all playlist item type definitions synchronized:
- PlaylistItem type alias defined in playlists.py, builtin/__init__.py, and player_queues.py
- PLAYLIST_MEDIA_TYPES constant for MediaType enum checks
- PLAYLIST_ITEM_CLASSES constant for isinstance checks
This ensures that adding new playlist item types in the future only requires updating the type alias and constants, with all runtime checks automatically including the new type.
* Centralize playlist item type definitions in constants.py
Moved all playlist item type definitions to a single location in constants.py to eliminate duplication and ensure consistency:
- PlaylistItem type alias
- PLAYLIST_MEDIA_TYPES tuple for MediaType enum checks
- PLAYLIST_ITEM_CLASSES tuple for isinstance checks
- PLAYLIST_NON_TRACK_ITEM_CLASSES for cases where Track needs separate handling
Updated playlists.py, builtin/__init__.py, and player_queues.py to import from constants.py.
Also improved comments:
- Better explanation of type ignore for covariant override
- More generic comment for radio mode filtering
- Updated to reference PlaylistItem instead of specific types
* Replace hardcoded types with type ignore comments
Removed cast statements with hardcoded types and replaced with type ignore comments for mypy:
- playlists.py: Added type: ignore[union-attr] for provider_mappings access
- builtin/__init__.py: Added type: ignore[attr-defined] and type: ignore[arg-type] for position and append
This ensures all type checking uses the constants from constants.py without any hardcoded type repetition.
* Use cast with type alias constants instead of type ignore
Added PlaylistNonTrackItem type alias to constants.py and updated code to use cast() with type aliases instead of type ignore comments:
- playlists.py: cast(PlaylistNonTrackItem, full_item)
- builtin/__init__.py: cast(PlaylistItem, track)
This maintains type safety while using only the centralized type definitions from constants.py.
* Simplify type definitions using get_args()
Reduced complexity by deriving PLAYLIST_ITEM_CLASSES from PlaylistItem using get_args():
- Removed PlaylistNonTrackItem type alias (only used once)
- PLAYLIST_ITEM_CLASSES now auto-derived from PlaylistItem
- Replaced cast with type ignore comment for single non-track case
This reduces maintenance: adding a new type only requires updating PlaylistItem and PLAYLIST_MEDIA_TYPES.
* Use get_args() inline instead of PLAYLIST_ITEM_CLASSES constant
Removed PLAYLIST_ITEM_CLASSES constant and use get_args(PlaylistItem) directly at the single call site.
This reduces to just 3 definitions in constants.py:
- PlaylistItem type alias
- PLAYLIST_MEDIA_TYPES tuple
- PLAYLIST_NON_TRACK_ITEM_CLASSES tuple
* Add type ignore for cast assignment in builtin provider
Added type: ignore[assignment] comment to fix mypy error where cast result is assigned to broader-typed variable.
* Use new variable name instead of type ignore for cast
Instead of reassigning track with a type ignore, use a new variable playlist_item.
This makes the isinstance check meaningful for type narrowing without needing type ignore comments.
* Clarify comments about playlist types in builtin provider
Updated comments to distinguish between:
- System-generated playlists (favorites, random, etc.) which only contain tracks
- User-created playlists which can contain Track, Radio, PodcastEpisode, and Audiobook items
This makes it clear that the new support for non-track items only applies to user-created playlists.
* Lint
* Unify track and non-track playlist item handling logic
Merged separate code paths for tracks and non-track items into unified logic:
- Same structure for all media types (Track, Radio, PodcastEpisode, Audiobook)
- For builtin playlists: Get full item, iterate provider mappings, add first available
- Tracks get quality sorting before selection
- Non-track items use first available mapping (typically only one)
This simplifies maintenance and follows the same pattern for all playlist item types.
* Fix mypy error in unified playlist logic
Added cast to Track type for match_provider call since full_item has broad union type from get_item_by_uri().
We know it's a Track from the media_type check but mypy can't infer this.
* Rename PlaylistItem to PlaylistPlayableItem to avoid naming conflict
The PlaylistItem union type conflicted with the existing PlaylistItem
dataclass in music_assistant.helpers.playlists, causing import collisions
and confusing type hints. Renamed the union type to PlaylistPlayableItem
to clearly distinguish it from the helper dataclass.
Changes:
- Renamed type alias in constants.py
- Updated all imports and usages in:
- playlists.py (import, return types, comments)
- builtin/__init__.py (import, return type, isinstance, cast)
- player_queues.py (import, return types)
- Updated comments to reference new name
* Remove unused constant and duplicate import
- Remove PLAYLIST_NON_TRACK_ITEM_CLASSES as it was declared but never used
- Remove duplicate AsyncGenerator import from TYPE_CHECKING block in playlists.py
* Sort provider mappings for deterministic non-track item selection
---------
Co-authored-by: Claude <noreply@anthropic.com>
Mischa Siekmann [Mon, 9 Feb 2026 07:34:16 +0000 (08:34 +0100)]
Snapcast: Introduce fallback Snapcast setup for dev environments (#3108)
* snapcast: introduce fallback config and plugin-directory for dev environments
* snapcast: suggested copilot fixes
* snapcast: another comment with a local path in the snapserver.conf
* merge fixes
Fabian Munkes [Mon, 9 Feb 2026 07:16:00 +0000 (08:16 +0100)]
Print provider name in logging output (#3113)
* multi-instance logging name
* use only name
Mischa Siekmann [Sun, 8 Feb 2026 19:18:50 +0000 (20:18 +0100)]
Snapcast: Fix player availability issues and align state with server truth (#3104)
music-assistant-machine [Sun, 8 Feb 2026 19:07:32 +0000 (20:07 +0100)]
⬆️ Update music-assistant-models to 1.1.97 (#3114)
Co-authored-by: marcelveldt <6389780+marcelveldt@users.noreply.github.com>
Firdavs Murodov [Sun, 8 Feb 2026 18:36:30 +0000 (19:36 +0100)]
Fix IPv6 address handling in bind config and ifaddr parsing (#3111)
Fabian Munkes [Sun, 8 Feb 2026 18:34:29 +0000 (19:34 +0100)]
Sanitize queue_item.name in icy headers (#3112)
OzGav [Sat, 7 Feb 2026 12:32:34 +0000 (23:32 +1100)]
Support multiple artist and other tags in FLAC/OGG files (#3076)
music-assistant-machine [Sat, 7 Feb 2026 03:35:34 +0000 (04:35 +0100)]
⬆️ Update music-assistant-frontend to 2.17.82 (#3107)
Co-authored-by: marcelveldt <6389780+marcelveldt@users.noreply.github.com>
OzGav [Fri, 6 Feb 2026 22:39:36 +0000 (09:39 +1100)]
Fix local file system audiobook edge cases (#3080)
scyto [Fri, 6 Feb 2026 22:38:01 +0000 (14:38 -0800)]
Add group volume mute support (#3034)
dependabot[bot] [Fri, 6 Feb 2026 18:51:08 +0000 (19:51 +0100)]
Chore(deps): Bump actions/github-script from 7 to 8 (#3105)
Bumps [actions/github-script](https://github.com/actions/github-script) from 7 to 8.
- [Release notes](https://github.com/actions/github-script/releases)
- [Commits](https://github.com/actions/github-script/compare/v7...v8)
---
updated-dependencies:
- dependency-name: actions/github-script
dependency-version: '8'
dependency-type: direct:production
update-type: version-update:semver-major
...
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Marcel van der Veldt [Fri, 6 Feb 2026 18:26:56 +0000 (19:26 +0100)]
Remove Sonos ERA from broken AirPlay models
Marcel van der Veldt [Fri, 6 Feb 2026 18:25:09 +0000 (19:25 +0100)]
Fix zeroconf interfaces config
Marcel van der Veldt [Fri, 6 Feb 2026 13:42:29 +0000 (14:42 +0100)]
Improve dependency checks workflow
Justin Kenyon [Fri, 6 Feb 2026 12:12:35 +0000 (07:12 -0500)]
Use RAOP protocol for Juke Audio devices (#3102)
Marcel van der Veldt [Fri, 6 Feb 2026 12:11:33 +0000 (13:11 +0100)]
Improve dependency check workflow
Firdavs Murodov [Fri, 6 Feb 2026 09:34:22 +0000 (10:34 +0100)]
Enable IPv6 support for zeroconf, stream server and AirPlay DACP (#3086)
music-assistant-machine [Fri, 6 Feb 2026 08:51:31 +0000 (09:51 +0100)]
⬆️ Update music-assistant-frontend to 2.17.81 (#3101)
Co-authored-by: marcelveldt <6389780+marcelveldt@users.noreply.github.com>
Marcel van der Veldt [Fri, 6 Feb 2026 08:32:09 +0000 (09:32 +0100)]
Merge branch 'dev' of https://github.com/music-assistant/server into dev
Marcel van der Veldt [Fri, 6 Feb 2026 08:32:00 +0000 (09:32 +0100)]
Fix broken test
Marvin Schenkel [Fri, 6 Feb 2026 08:25:05 +0000 (09:25 +0100)]
Revert "Fix squeezelite WAV playback" (#3103)
Revert "Fix squeezelite WAV playback (#3084)"
This reverts commit
fdc7b350949c83cc34d413e04c732acbd446fb49.
Marcel van der Veldt [Thu, 5 Feb 2026 23:38:55 +0000 (00:38 +0100)]
Another small fix for the security workflow
Marcel van der Veldt [Thu, 5 Feb 2026 23:07:50 +0000 (00:07 +0100)]
Fix issue in workflow
Marcel van der Veldt [Thu, 5 Feb 2026 22:30:52 +0000 (23:30 +0100)]
Add workflow to check dependencies for supply chain risks
OzGav [Thu, 5 Feb 2026 21:27:17 +0000 (08:27 +1100)]
Fix squeezelite WAV playback (#3084)
Mischa Siekmann [Thu, 5 Feb 2026 13:52:29 +0000 (14:52 +0100)]
Snapcast: Stop the control scripts gracefully before shutting down the built-in snapcast server (#3092)
gracefully stop control scripts before shutting down the snapcast server
Monkey Do [Thu, 5 Feb 2026 13:27:27 +0000 (14:27 +0100)]
Add debug logging for scrobbled tracks (#3091)
There is a debug trace for playing-now listens, but not for full scrobbles, making it harder to diagnose potential issues
Mikhail Nevskiy [Thu, 5 Feb 2026 13:25:29 +0000 (16:25 +0300)]
Fix Yandex Music provider for lossless streaming support (#3093)
* yandex_music: Add lossless streaming via get-file-info API and unit tests
Improve Yandex Music provider with proper lossless (FLAC) streaming support
and comprehensive test coverage.
## Changes
### Lossless Streaming (api_client.py, streaming.py)
- Add `get_track_file_info_lossless()` API method using `/get-file-info`
endpoint with quality=lossless parameter
- Prefer flac-mp4/aac-mp4 codecs (Yandex API 2025 format)
- Implement retry logic: try transports=encraw first, fallback to
transports=raw on 401 Unauthorized
- When lossless requested, try get-file-info first (returns FLAC),
fallback to download-info if unavailable
### Provider improvements (provider.py)
- Minor variable naming fix in get_track()
### Documentation (README.md)
- Add provider README with OAuth token instructions
- Document audio quality settings and lossless troubleshooting
### Tests
- Add unit tests for parsers (artists, albums, tracks, playlists)
- Add unit tests for streaming quality selection logic
- Add snapshot tests for consistent parsing output
- Add fixtures and stubs in conftest.py
- Add integration and e2e test scaffolding
https://claude.ai/code/session_01S4Eth5mUC7hLd3K3JxX7Cy
* Delete tests/providers/yandex_music/test_e2e_server.py
* Update Yandex Music documentation URL
---------
Co-authored-by: Claude <noreply@anthropic.com>
Dionysis Fortis [Thu, 5 Feb 2026 13:04:04 +0000 (15:04 +0200)]
Add album year to track SQL query (#3085)
* Add album year to track SQL query
* Bump models to 1.1.96 and update snapshots
relic664 [Thu, 5 Feb 2026 10:24:18 +0000 (05:24 -0500)]
fix: cache check for expire (#3087)
* fix: cache check for expire
* fixed formatting
MizterB [Thu, 5 Feb 2026 09:32:59 +0000 (04:32 -0500)]
Apple Music: Limit get_library_tracks to 150 songs per batch (#3094)
Reduce max_limit to 150
music-assistant-machine [Thu, 5 Feb 2026 03:42:16 +0000 (04:42 +0100)]
⬆️ Update music-assistant-frontend to 2.17.80 (#3097)
Co-authored-by: marcelveldt <6389780+marcelveldt@users.noreply.github.com>
music-assistant-machine [Wed, 4 Feb 2026 03:41:30 +0000 (04:41 +0100)]
⬆️ Update music-assistant-frontend to 2.17.79 (#3089)
Co-authored-by: marcelveldt <6389780+marcelveldt@users.noreply.github.com>
dependabot[bot] [Tue, 3 Feb 2026 10:18:48 +0000 (10:18 +0000)]
Chore(deps): Bump ytmusicapi from 1.11.3 to 1.11.5 (#3081)
* Chore(deps): Bump ytmusicapi from 1.11.3 to 1.11.5
Bumps [ytmusicapi](https://github.com/sigma67/ytmusicapi) from 1.11.3 to 1.11.5.
- [Release notes](https://github.com/sigma67/ytmusicapi/releases)
- [Commits](https://github.com/sigma67/ytmusicapi/compare/1.11.3...1.11.5)
---
updated-dependencies:
- dependency-name: ytmusicapi
dependency-version: 1.11.5
dependency-type: direct:production
update-type: version-update:semver-patch
...
Signed-off-by: dependabot[bot] <support@github.com>
* Also bump the provider manifest.
---------
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Marvin Schenkel <marvinschenkel@gmail.com>
dependabot[bot] [Tue, 3 Feb 2026 07:39:45 +0000 (08:39 +0100)]
Chore(deps-dev): Bump pre-commit from 4.5.0 to 4.5.1 (#3082)
Bumps [pre-commit](https://github.com/pre-commit/pre-commit) from 4.5.0 to 4.5.1.
- [Release notes](https://github.com/pre-commit/pre-commit/releases)
- [Changelog](https://github.com/pre-commit/pre-commit/blob/main/CHANGELOG.md)
- [Commits](https://github.com/pre-commit/pre-commit/compare/v4.5.0...v4.5.1)
---
updated-dependencies:
- dependency-name: pre-commit
dependency-version: 4.5.1
dependency-type: direct:development
update-type: version-update:semver-patch
...
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
dependabot[bot] [Tue, 3 Feb 2026 07:39:31 +0000 (08:39 +0100)]
Chore(deps): Bump mashumaro from 3.17 to 3.18 (#3083)
Bumps [mashumaro](https://github.com/Fatal1ty/mashumaro) from 3.17 to 3.18.
- [Release notes](https://github.com/Fatal1ty/mashumaro/releases)
- [Commits](https://github.com/Fatal1ty/mashumaro/compare/v3.17...v3.18)
---
updated-dependencies:
- dependency-name: mashumaro
dependency-version: '3.18'
dependency-type: direct:production
update-type: version-update:semver-minor
...
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
OzGav [Mon, 2 Feb 2026 13:12:55 +0000 (00:12 +1100)]
Allow all special characters in passwords (#3072)
* fix-commas-in-passwords
* shorten comment
music-assistant-machine [Mon, 2 Feb 2026 12:58:32 +0000 (13:58 +0100)]
⬆️ Update music-assistant-frontend to 2.17.78 (#3075)
Co-authored-by: MarvinSchenkel <17671719+MarvinSchenkel@users.noreply.github.com>
Ulrich Lichtenegger [Mon, 2 Feb 2026 11:48:21 +0000 (12:48 +0100)]
hass_players: Show now playing info from external playback (#3015)
* HASS Provider: Show now-playing information if playback is steered externally
* Fix: Prev/Next action availability not updated in hass player
dependabot[bot] [Mon, 2 Feb 2026 10:43:39 +0000 (11:43 +0100)]
Chore(deps): Bump pylast from 6.0.0 to 7.0.2 (#2994)
* Chore(deps): Bump pylast from 6.0.0 to 7.0.2
Bumps [pylast](https://github.com/pylast/pylast) from 6.0.0 to 7.0.2.
- [Release notes](https://github.com/pylast/pylast/releases)
- [Changelog](https://github.com/pylast/pylast/blob/main/CHANGELOG.md)
- [Commits](https://github.com/pylast/pylast/compare/6.0.0...7.0.2)
---
updated-dependencies:
- dependency-name: pylast
dependency-version: 7.0.2
dependency-type: direct:production
update-type: version-update:semver-major
...
Signed-off-by: dependabot[bot] <support@github.com>
* Also bump the provider manifest.
---------
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Marvin Schenkel <marvinschenkel@gmail.com>
Co-authored-by: OzGav <gavnosp@hotmail.com>
Tom Matheussen [Mon, 2 Feb 2026 10:28:08 +0000 (11:28 +0100)]
Add auto discovery to HEOS (#3056)
* Adjust player registration and availability state
* Discover controller via mDNS
* Add some logging, fix possible None references
* Review adjustments
* Minor docstring update
* Move manual config to advanced section