diff --git a/homeassistant/components/plex/manifest.json b/homeassistant/components/plex/manifest.json
index bc0c54c49bf..6cf94793173 100644
--- a/homeassistant/components/plex/manifest.json
+++ b/homeassistant/components/plex/manifest.json
@@ -8,7 +8,7 @@
"iot_class": "local_push",
"loggers": ["plexapi", "plexwebsocket"],
"requirements": [
- "PlexAPI==4.13.2",
+ "PlexAPI==4.15.3",
"plexauth==0.0.6",
"plexwebsocket==0.0.13"
],
diff --git a/requirements_all.txt b/requirements_all.txt
index a0b33962ea4..1c3b3b58098 100644
--- a/requirements_all.txt
+++ b/requirements_all.txt
@@ -46,7 +46,7 @@ Mastodon.py==1.5.1
Pillow==10.0.0
# homeassistant.components.plex
-PlexAPI==4.13.2
+PlexAPI==4.15.3
# homeassistant.components.progettihwsw
ProgettiHWSW==0.1.3
diff --git a/requirements_test_all.txt b/requirements_test_all.txt
index 153083fbcf3..986828f170c 100644
--- a/requirements_test_all.txt
+++ b/requirements_test_all.txt
@@ -42,7 +42,7 @@ HATasmota==0.7.3
Pillow==10.0.0
# homeassistant.components.plex
-PlexAPI==4.13.2
+PlexAPI==4.15.3
# homeassistant.components.progettihwsw
ProgettiHWSW==0.1.3
diff --git a/tests/components/plex/conftest.py b/tests/components/plex/conftest.py
index e4bf61ccd94..78a3b7387ea 100644
--- a/tests/components/plex/conftest.py
+++ b/tests/components/plex/conftest.py
@@ -232,6 +232,12 @@ def player_plexweb_resources_fixture():
return load_fixture("plex/player_plexweb_resources.xml")
+@pytest.fixture(name="player_plexhtpc_resources", scope="session")
+def player_plexhtpc_resources_fixture():
+ """Load resources payload for a Plex HTPC player and return it."""
+ return load_fixture("plex/player_plexhtpc_resources.xml")
+
+
@pytest.fixture(name="playlists", scope="session")
def playlists_fixture():
"""Load payload for all playlists and return it."""
@@ -450,8 +456,8 @@ def mock_plex_calls(
"""Mock Plex API calls."""
requests_mock.get("https://plex.tv/api/users/", text=plextv_shared_users)
requests_mock.get("https://plex.tv/api/invites/requested", text=empty_payload)
- requests_mock.get("https://plex.tv/users/account", text=plextv_account)
- requests_mock.get("https://plex.tv/api/resources", text=plextv_resources)
+ requests_mock.get("https://plex.tv/api/v2/user", text=plextv_account)
+ requests_mock.get("https://plex.tv/api/v2/resources", text=plextv_resources)
url = plex_server_url(entry)
diff --git a/tests/components/plex/fixtures/player_plexhtpc_resources.xml b/tests/components/plex/fixtures/player_plexhtpc_resources.xml
new file mode 100644
index 00000000000..6cc9cc0afbd
--- /dev/null
+++ b/tests/components/plex/fixtures/player_plexhtpc_resources.xml
@@ -0,0 +1,3 @@
+
+
+
diff --git a/tests/components/plex/fixtures/plextv_account.xml b/tests/components/plex/fixtures/plextv_account.xml
index 32d6eec7c2d..b47896de577 100644
--- a/tests/components/plex/fixtures/plextv_account.xml
+++ b/tests/components/plex/fixtures/plextv_account.xml
@@ -1,15 +1,18 @@
-
-
-
+
+
+
+
+
+
+
+
+
-
-
-
- testuser
- testuser@email.com
- 2000-01-01 12:34:56 UTC
- faketoken
+
+
+
+
diff --git a/tests/components/plex/fixtures/plextv_resources_one_server.xml b/tests/components/plex/fixtures/plextv_resources_one_server.xml
index ff2e458ff24..75b7e54b7e6 100644
--- a/tests/components/plex/fixtures/plextv_resources_one_server.xml
+++ b/tests/components/plex/fixtures/plextv_resources_one_server.xml
@@ -1,18 +1,22 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/components/plex/fixtures/plextv_resources_two_servers.xml b/tests/components/plex/fixtures/plextv_resources_two_servers.xml
index 7da5df4c1df..f14b55fe161 100644
--- a/tests/components/plex/fixtures/plextv_resources_two_servers.xml
+++ b/tests/components/plex/fixtures/plextv_resources_two_servers.xml
@@ -1,21 +1,27 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/components/plex/test_config_flow.py b/tests/components/plex/test_config_flow.py
index beb454e2e9c..235596715f4 100644
--- a/tests/components/plex/test_config_flow.py
+++ b/tests/components/plex/test_config_flow.py
@@ -143,7 +143,7 @@ async def test_no_servers_found(
current_request_with_host: None,
) -> None:
"""Test when no servers are on an account."""
- requests_mock.get("https://plex.tv/api/resources", text=empty_payload)
+ requests_mock.get("https://plex.tv/api/v2/resources", text=empty_payload)
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": SOURCE_USER}
@@ -225,7 +225,7 @@ async def test_multiple_servers_with_selection(
assert result["step_id"] == "user"
requests_mock.get(
- "https://plex.tv/api/resources",
+ "https://plex.tv/api/v2/resources",
text=plextv_resources_two_servers,
)
with patch("plexauth.PlexAuth.initiate_auth"), patch(
@@ -289,7 +289,7 @@ async def test_adding_last_unconfigured_server(
assert result["step_id"] == "user"
requests_mock.get(
- "https://plex.tv/api/resources",
+ "https://plex.tv/api/v2/resources",
text=plextv_resources_two_servers,
)
@@ -346,9 +346,9 @@ async def test_all_available_servers_configured(
assert result["type"] == FlowResultType.FORM
assert result["step_id"] == "user"
- requests_mock.get("https://plex.tv/users/account", text=plextv_account)
+ requests_mock.get("https://plex.tv/api/v2/user", text=plextv_account)
requests_mock.get(
- "https://plex.tv/api/resources",
+ "https://plex.tv/api/v2/resources",
text=plextv_resources_two_servers,
)
@@ -776,7 +776,7 @@ async def test_reauth_multiple_servers_available(
) -> None:
"""Test setup and reauthorization of a Plex token when multiple servers are available."""
requests_mock.get(
- "https://plex.tv/api/resources",
+ "https://plex.tv/api/v2/resources",
text=plextv_resources_two_servers,
)
diff --git a/tests/components/plex/test_init.py b/tests/components/plex/test_init.py
index bc43a1e0d89..6e1043b5c52 100644
--- a/tests/components/plex/test_init.py
+++ b/tests/components/plex/test_init.py
@@ -231,7 +231,7 @@ async def test_setup_when_certificate_changed(
# Test with account failure
requests_mock.get(
- "https://plex.tv/users/account", status_code=HTTPStatus.UNAUTHORIZED
+ "https://plex.tv/api/v2/user", status_code=HTTPStatus.UNAUTHORIZED
)
old_entry.add_to_hass(hass)
assert await hass.config_entries.async_setup(old_entry.entry_id) is False
@@ -241,8 +241,8 @@ async def test_setup_when_certificate_changed(
await hass.config_entries.async_unload(old_entry.entry_id)
# Test with no servers found
- requests_mock.get("https://plex.tv/users/account", text=plextv_account)
- requests_mock.get("https://plex.tv/api/resources", text=empty_payload)
+ requests_mock.get("https://plex.tv/api/v2/user", text=plextv_account)
+ requests_mock.get("https://plex.tv/api/v2/resources", text=empty_payload)
assert await hass.config_entries.async_setup(old_entry.entry_id) is False
await hass.async_block_till_done()
@@ -252,7 +252,7 @@ async def test_setup_when_certificate_changed(
# Test with success
new_url = PLEX_DIRECT_URL
- requests_mock.get("https://plex.tv/api/resources", text=plextv_resources)
+ requests_mock.get("https://plex.tv/api/v2/resources", text=plextv_resources)
for resource_url in [new_url, "http://1.2.3.4:32400"]:
requests_mock.get(resource_url, text=plex_server_default)
requests_mock.get(f"{new_url}/accounts", text=plex_server_accounts)
@@ -287,7 +287,7 @@ async def test_bad_token_with_tokenless_server(
) -> None:
"""Test setup with a bad token and a server with token auth disabled."""
requests_mock.get(
- "https://plex.tv/users/account", status_code=HTTPStatus.UNAUTHORIZED
+ "https://plex.tv/api/v2/user", status_code=HTTPStatus.UNAUTHORIZED
)
await setup_plex_server()
diff --git a/tests/components/plex/test_media_players.py b/tests/components/plex/test_media_players.py
index 27fea36e3b0..e9efc945f71 100644
--- a/tests/components/plex/test_media_players.py
+++ b/tests/components/plex/test_media_players.py
@@ -12,10 +12,10 @@ async def test_plex_tv_clients(
entry,
setup_plex_server,
requests_mock: requests_mock.Mocker,
- player_plexweb_resources,
+ player_plexhtpc_resources,
) -> None:
"""Test getting Plex clients from plex.tv."""
- requests_mock.get("/resources", text=player_plexweb_resources)
+ requests_mock.get("/resources", text=player_plexhtpc_resources)
with patch("plexapi.myplex.MyPlexResource.connect", side_effect=NotFound):
await setup_plex_server()
diff --git a/tests/components/plex/test_media_search.py b/tests/components/plex/test_media_search.py
index 0cc94134f1c..21b50724786 100644
--- a/tests/components/plex/test_media_search.py
+++ b/tests/components/plex/test_media_search.py
@@ -70,7 +70,10 @@ async def test_media_lookups(
)
assert "Library 'Not a Library' not found in" in str(excinfo.value)
- with patch("plexapi.library.LibrarySection.search") as search:
+ with patch(
+ "plexapi.library.LibrarySection.search",
+ __qualname__="search",
+ ) as search:
await hass.services.async_call(
MEDIA_PLAYER_DOMAIN,
SERVICE_PLAY_MEDIA,
@@ -261,7 +264,11 @@ async def test_media_lookups(
with pytest.raises(MediaNotFound) as excinfo:
payload = '{"library_name": "Movies", "title": "Not a Movie"}'
- with patch("plexapi.library.LibrarySection.search", side_effect=BadRequest):
+ with patch(
+ "plexapi.library.LibrarySection.search",
+ side_effect=BadRequest,
+ __qualname__="search",
+ ):
await hass.services.async_call(
MEDIA_PLAYER_DOMAIN,
SERVICE_PLAY_MEDIA,
diff --git a/tests/components/plex/test_playback.py b/tests/components/plex/test_playback.py
index c9dba4e4aca..9ea684256c4 100644
--- a/tests/components/plex/test_playback.py
+++ b/tests/components/plex/test_playback.py
@@ -49,14 +49,14 @@ async def test_media_player_playback(
setup_plex_server,
requests_mock: requests_mock.Mocker,
playqueue_created,
- player_plexweb_resources,
+ player_plexhtpc_resources,
) -> None:
"""Test playing media on a Plex media_player."""
- requests_mock.get("http://1.2.3.5:32400/resources", text=player_plexweb_resources)
+ requests_mock.get("http://1.2.3.6:32400/resources", text=player_plexhtpc_resources)
await setup_plex_server()
- media_player = "media_player.plex_plex_web_chrome"
+ media_player = "media_player.plex_plex_htpc_for_mac_plex_htpc"
requests_mock.post("/playqueues", text=playqueue_created)
playmedia_mock = requests_mock.get(
"/player/playback/playMedia", status_code=HTTPStatus.OK
@@ -65,7 +65,9 @@ async def test_media_player_playback(
# Test media lookup failure
payload = '{"library_name": "Movies", "title": "Movie 1" }'
with patch(
- "plexapi.library.LibrarySection.search", return_value=None
+ "plexapi.library.LibrarySection.search",
+ return_value=None,
+ __qualname__="search",
), pytest.raises(HomeAssistantError) as excinfo:
await hass.services.async_call(
MP_DOMAIN,
@@ -86,7 +88,11 @@ async def test_media_player_playback(
# Test movie success
movies = [movie1]
- with patch("plexapi.library.LibrarySection.search", return_value=movies):
+ with patch(
+ "plexapi.library.LibrarySection.search",
+ return_value=movies,
+ __qualname__="search",
+ ):
await hass.services.async_call(
MP_DOMAIN,
SERVICE_PLAY_MEDIA,
@@ -101,7 +107,11 @@ async def test_media_player_playback(
# Test movie success with resume
playmedia_mock.reset()
- with patch("plexapi.library.LibrarySection.search", return_value=movies):
+ with patch(
+ "plexapi.library.LibrarySection.search",
+ return_value=movies,
+ __qualname__="search",
+ ):
await hass.services.async_call(
MP_DOMAIN,
SERVICE_PLAY_MEDIA,
@@ -163,7 +173,11 @@ async def test_media_player_playback(
# Test multiple choices with exact match
playmedia_mock.reset()
movies = [movie1, movie2]
- with patch("plexapi.library.LibrarySection.search", return_value=movies):
+ with patch(
+ "plexapi.library.LibrarySection.search",
+ return_value=movies,
+ __qualname__="search",
+ ):
await hass.services.async_call(
MP_DOMAIN,
SERVICE_PLAY_MEDIA,
@@ -181,7 +195,11 @@ async def test_media_player_playback(
movies = [movie2, movie3]
with pytest.raises(HomeAssistantError) as excinfo:
payload = '{"library_name": "Movies", "title": "Movie" }'
- with patch("plexapi.library.LibrarySection.search", return_value=movies):
+ with patch(
+ "plexapi.library.LibrarySection.search",
+ return_value=movies,
+ __qualname__="search",
+ ):
await hass.services.async_call(
MP_DOMAIN,
SERVICE_PLAY_MEDIA,
@@ -197,7 +215,11 @@ async def test_media_player_playback(
# Test multiple choices with allow_multiple
movies = [movie1, movie2, movie3]
- with patch("plexapi.library.LibrarySection.search", return_value=movies), patch(
+ with patch(
+ "plexapi.library.LibrarySection.search",
+ return_value=movies,
+ __qualname__="search",
+ ), patch(
"homeassistant.components.plex.server.PlexServer.create_playqueue"
) as mock_create_playqueue:
await hass.services.async_call(
diff --git a/tests/components/plex/test_sensor.py b/tests/components/plex/test_sensor.py
index 9c73bf9f915..5b9729792f4 100644
--- a/tests/components/plex/test_sensor.py
+++ b/tests/components/plex/test_sensor.py
@@ -129,7 +129,11 @@ async def test_library_sensor_values(
)
media = [MockPlexTVEpisode()]
- with patch("plexapi.library.LibrarySection.recentlyAdded", return_value=media):
+ with patch(
+ "plexapi.library.LibrarySection.recentlyAdded",
+ return_value=media,
+ __qualname__="recentlyAdded",
+ ):
await hass.async_block_till_done()
library_tv_sensor = hass.states.get("sensor.plex_server_1_library_tv_shows")
@@ -165,7 +169,11 @@ async def test_library_sensor_values(
trigger_plex_update(
mock_websocket, msgtype="status", payload=LIBRARY_UPDATE_PAYLOAD
)
- with patch("plexapi.library.LibrarySection.recentlyAdded", return_value=media):
+ with patch(
+ "plexapi.library.LibrarySection.recentlyAdded",
+ return_value=media,
+ __qualname__="recentlyAdded",
+ ):
await hass.async_block_till_done()
library_tv_sensor = hass.states.get("sensor.plex_server_1_library_tv_shows")
@@ -200,7 +208,11 @@ async def test_library_sensor_values(
)
media = [MockPlexMovie()]
- with patch("plexapi.library.LibrarySection.recentlyAdded", return_value=media):
+ with patch(
+ "plexapi.library.LibrarySection.recentlyAdded",
+ return_value=media,
+ __qualname__="recentlyAdded",
+ ):
await hass.async_block_till_done()
library_movies_sensor = hass.states.get("sensor.plex_server_1_library_movies")
@@ -210,7 +222,11 @@ async def test_library_sensor_values(
# Test with clip
media = [MockPlexClip()]
- with patch("plexapi.library.LibrarySection.recentlyAdded", return_value=media):
+ with patch(
+ "plexapi.library.LibrarySection.recentlyAdded",
+ return_value=media,
+ __qualname__="recentlyAdded",
+ ):
async_dispatcher_send(
hass, PLEX_UPDATE_LIBRARY_SIGNAL.format(mock_plex_server.machine_identifier)
)
@@ -236,7 +252,11 @@ async def test_library_sensor_values(
)
media = [MockPlexMusic()]
- with patch("plexapi.library.LibrarySection.recentlyAdded", return_value=media):
+ with patch(
+ "plexapi.library.LibrarySection.recentlyAdded",
+ return_value=media,
+ __qualname__="recentlyAdded",
+ ):
await hass.async_block_till_done()
library_music_sensor = hass.states.get("sensor.plex_server_1_library_music")
diff --git a/tests/components/plex/test_services.py b/tests/components/plex/test_services.py
index a74b3e91460..dfd02bb1d3f 100644
--- a/tests/components/plex/test_services.py
+++ b/tests/components/plex/test_services.py
@@ -190,7 +190,11 @@ async def test_lookup_media_for_other_integrations(
assert result.shuffle
# Test with media not found
- with patch("plexapi.library.LibrarySection.search", return_value=None):
+ with patch(
+ "plexapi.library.LibrarySection.search",
+ return_value=None,
+ __qualname__="search",
+ ):
with pytest.raises(HomeAssistantError) as excinfo:
process_plex_payload(hass, MediaType.MUSIC, CONTENT_ID_BAD_MEDIA)
assert f"No {MediaType.MUSIC} results in 'Music' for" in str(excinfo.value)