From a6076a0d33326f467f59c017a8f4d9d0d452ff7e Mon Sep 17 00:00:00 2001
From: Pete Sage <76050312+PeteRager@users.noreply.github.com>
Date: Tue, 2 Apr 2024 04:11:45 -0400
Subject: [PATCH] Display sonos album title with URL encoding (#113693)

* unescape the title

When extracting the title from the item_id, it needs to be unescaped.

* sort imports
---
 .../components/sonos/media_browser.py         |  2 +-
 tests/components/sonos/test_media_browser.py  | 96 +++++++++++++++++++
 2 files changed, 97 insertions(+), 1 deletion(-)
 create mode 100644 tests/components/sonos/test_media_browser.py

diff --git a/homeassistant/components/sonos/media_browser.py b/homeassistant/components/sonos/media_browser.py
index 17327bf4be1..9d3ef5d353b 100644
--- a/homeassistant/components/sonos/media_browser.py
+++ b/homeassistant/components/sonos/media_browser.py
@@ -201,7 +201,7 @@ def build_item_response(
 
     if not title:
         try:
-            title = payload["idstring"].split("/")[1]
+            title = urllib.parse.unquote(payload["idstring"].split("/")[1])
         except IndexError:
             title = LIBRARY_TITLES_MAPPING[payload["idstring"]]
 
diff --git a/tests/components/sonos/test_media_browser.py b/tests/components/sonos/test_media_browser.py
new file mode 100644
index 00000000000..cb6303c800d
--- /dev/null
+++ b/tests/components/sonos/test_media_browser.py
@@ -0,0 +1,96 @@
+"""Tests for the Sonos Media Browser."""
+
+from functools import partial
+
+from homeassistant.components.media_player.browse_media import BrowseMedia
+from homeassistant.components.media_player.const import MediaClass, MediaType
+from homeassistant.components.sonos.media_browser import (
+    build_item_response,
+    get_thumbnail_url_full,
+)
+from homeassistant.core import HomeAssistant
+
+from .conftest import SoCoMockFactory
+
+
+class MockMusicServiceItem:
+    """Mocks a Soco MusicServiceItem."""
+
+    def __init__(
+        self,
+        title: str,
+        item_id: str,
+        parent_id: str,
+        item_class: str,
+    ) -> None:
+        """Initialize the mock item."""
+        self.title = title
+        self.item_id = item_id
+        self.item_class = item_class
+        self.parent_id = parent_id
+
+    def get_uri(self) -> str:
+        """Return URI."""
+        return self.item_id.replace("S://", "x-file-cifs://")
+
+
+def mock_browse_by_idstring(
+    search_type: str, idstring: str, start=0, max_items=100, full_album_art_uri=False
+) -> list[MockMusicServiceItem]:
+    """Mock the call to browse_by_id_string."""
+    if search_type == "albums" and (
+        idstring == "A:ALBUM/Abbey%20Road" or idstring == "A:ALBUM/Abbey Road"
+    ):
+        return [
+            MockMusicServiceItem(
+                "Come Together",
+                "S://192.168.42.10/music/The%20Beatles/Abbey%20Road/01%20Come%20Together.mp3",
+                "A:ALBUM/Abbey%20Road",
+                "object.item.audioItem.musicTrack",
+            ),
+            MockMusicServiceItem(
+                "Something",
+                "S://192.168.42.10/music/The%20Beatles/Abbey%20Road/03%20Something.mp3",
+                "A:ALBUM/Abbey%20Road",
+                "object.item.audioItem.musicTrack",
+            ),
+        ]
+    return None
+
+
+async def test_build_item_response(
+    hass: HomeAssistant,
+    soco_factory: SoCoMockFactory,
+    async_autosetup_sonos,
+    soco,
+    discover,
+) -> None:
+    """Test building a browse item response."""
+    soco_mock = soco_factory.mock_list.get("192.168.42.2")
+    soco_mock.music_library.browse_by_idstring = mock_browse_by_idstring
+    browse_item: BrowseMedia = build_item_response(
+        soco_mock.music_library,
+        {"search_type": MediaType.ALBUM, "idstring": "A:ALBUM/Abbey%20Road"},
+        partial(
+            get_thumbnail_url_full,
+            soco_mock.music_library,
+            True,
+            None,
+        ),
+    )
+    assert browse_item.title == "Abbey Road"
+    assert browse_item.media_class == MediaClass.ALBUM
+    assert browse_item.media_content_id == "A:ALBUM/Abbey%20Road"
+    assert len(browse_item.children) == 2
+    assert browse_item.children[0].media_class == MediaClass.TRACK
+    assert browse_item.children[0].title == "Come Together"
+    assert (
+        browse_item.children[0].media_content_id
+        == "x-file-cifs://192.168.42.10/music/The%20Beatles/Abbey%20Road/01%20Come%20Together.mp3"
+    )
+    assert browse_item.children[1].media_class == MediaClass.TRACK
+    assert browse_item.children[1].title == "Something"
+    assert (
+        browse_item.children[1].media_content_id
+        == "x-file-cifs://192.168.42.10/music/The%20Beatles/Abbey%20Road/03%20Something.mp3"
+    )