diff --git a/custom_components/frigate/manifest.json b/custom_components/frigate/manifest.json index c1e1bdf6..c3e322ef 100644 --- a/custom_components/frigate/manifest.json +++ b/custom_components/frigate/manifest.json @@ -15,6 +15,6 @@ "documentation": "https://github.com/blakeblackshear/frigate", "iot_class": "local_push", "issue_tracker": "https://github.com/blakeblackshear/frigate-hass-integration/issues", - "requirements": ["hass-web-proxy-lib==0.0.7", "pytz"], + "requirements": ["hass-web-proxy-lib==0.0.7"], "version": "5.5.1" } diff --git a/custom_components/frigate/media_source.py b/custom_components/frigate/media_source.py index fdfbf6e8..6165dded 100644 --- a/custom_components/frigate/media_source.py +++ b/custom_components/frigate/media_source.py @@ -9,7 +9,6 @@ import attr from dateutil.relativedelta import relativedelta -import pytz from homeassistant.components.media_player.const import MediaClass, MediaType from homeassistant.components.media_source.error import MediaSourceError, Unresolvable @@ -22,7 +21,7 @@ from homeassistant.core import HomeAssistant from homeassistant.helpers import system_info from homeassistant.helpers.template import DATE_STR_FORMAT -from homeassistant.util.dt import DEFAULT_TIME_ZONE +from homeassistant.util.dt import DEFAULT_TIME_ZONE, async_get_time_zone from . import get_friendly_name from .api import FrigateApiClient, FrigateApiClientError @@ -118,7 +117,7 @@ def get_identifier_type(cls) -> str: """Get the identifier type.""" raise NotImplementedError - def get_integration_proxy_path(self, timezone: str) -> str: + def get_integration_proxy_path(self, tz_info: dt.tzinfo) -> str: """Get the proxy (Home Assistant view) path for this identifier.""" raise NotImplementedError @@ -240,7 +239,7 @@ def get_identifier_type(cls) -> str: """Get the identifier type.""" return "event" - def get_integration_proxy_path(self, timezone: str) -> str: + def get_integration_proxy_path(self, tz_info: dt.tzinfo) -> str: """Get the equivalent Frigate server path.""" if self.frigate_media_type == FrigateMediaType.CLIPS: return f"vod/event/{self.id}/index.{self.frigate_media_type.extension}" @@ -444,7 +443,7 @@ def get_identifier_type(cls) -> str: """Get the identifier type.""" return "recordings" - def get_integration_proxy_path(self, timezone: str) -> str: + def get_integration_proxy_path(self, tz_info: dt.tzinfo) -> str: """Get the integration path that will proxy this identifier.""" if ( @@ -460,8 +459,8 @@ def get_integration_proxy_path(self, timezone: str) -> str: int(month), int(day), int(self.hour), - tzinfo=dt.timezone.utc, - ) - (dt.datetime.now(pytz.timezone(timezone)).utcoffset() or dt.timedelta()) + tzinfo=dt.UTC, + ) - (dt.datetime.now(tz_info).utcoffset() or dt.timedelta()) parts = [ "vod", @@ -565,9 +564,14 @@ async def async_resolve_media(self, item: MediaSourceItem) -> PlayMedia: identifier.frigate_instance_id ): info = await system_info.async_get_system_info(self.hass) - server_path = identifier.get_integration_proxy_path( - info.get("timezone", "utc") - ) + tz_name = info.get("timezone", "utc") + tz_info = await async_get_time_zone(tz_name) + if not tz_info: + raise Unresolvable( + f"Could not get timezone object for timezone: {tz_name}" + ) + + server_path = identifier.get_integration_proxy_path(tz_info) return PlayMedia( f"/api/frigate/{identifier.frigate_instance_id}/{server_path}", identifier.mime_type, diff --git a/requirements.txt b/requirements.txt index 43d8013e..a487ffda 100644 --- a/requirements.txt +++ b/requirements.txt @@ -6,5 +6,4 @@ homeassistant==2024.11.3 paho-mqtt python-dateutil yarl -pytz hass-web-proxy-lib==0.0.7 \ No newline at end of file diff --git a/requirements_dev.txt b/requirements_dev.txt index 9b1d25bc..8b45a4b9 100644 --- a/requirements_dev.txt +++ b/requirements_dev.txt @@ -10,4 +10,3 @@ pylint pytest-aiohttp pytest-asyncio types-python-dateutil -types-pytz diff --git a/tests/test_media_source.py b/tests/test_media_source.py index d3eb9479..2d92a2e5 100644 --- a/tests/test_media_source.py +++ b/tests/test_media_source.py @@ -12,7 +12,6 @@ from unittest.mock import AsyncMock, Mock, call, patch import pytest -import pytz from custom_components.frigate.api import FrigateApiClient, FrigateApiClientError from custom_components.frigate.const import ( @@ -37,6 +36,7 @@ from homeassistant.const import CONF_URL from homeassistant.core import HomeAssistant from homeassistant.helpers import system_info +from homeassistant.util.dt import DEFAULT_TIME_ZONE, async_get_time_zone from . import ( TEST_CONFIG, @@ -624,7 +624,7 @@ async def test_async_browse_media_clip_search_multi_month_drilldown( async def test_async_resolve_media( frigate_client: AsyncMock, hass: HomeAssistant ) -> None: - """Test successful resolve media.""" + """Test resolving media.""" await setup_mock_frigate_config_entry(hass, client=frigate_client) @@ -652,7 +652,9 @@ async def test_async_resolve_media( # Convert from HA local timezone to UTC. info = await system_info.async_get_system_info(hass) date = datetime.datetime(2021, 5, 30, 15, 46, 8, 0, datetime.timezone.utc) - ( - datetime.datetime.now(pytz.timezone(info.get("timezone", "utc"))).utcoffset() + datetime.datetime.now( + await async_get_time_zone(info.get("timezone", "utc")) + ).utcoffset() or datetime.timedelta() ) @@ -686,6 +688,18 @@ async def test_async_resolve_media( target_media_player="media_player.kitchen", ) + # Test resolving when system timezone is not found. + with patch( + "homeassistant.helpers.system_info.async_get_system_info", + return_value={"timezone": "UNKNOWN"}, + ): + with pytest.raises(Unresolvable): + media = await media_source.async_resolve_media( + hass, + f"{const.URI_SCHEME}{DOMAIN}/{TEST_FRIGATE_INSTANCE_ID}/event/clips/camera/CLIP-FOO", + target_media_player="media_player.kitchen", + ) + async def test_async_browse_media_recordings_root( caplog: Any, frigate_client: AsyncMock, hass: HomeAssistant @@ -998,7 +1012,7 @@ async def test_event_search_identifier() -> None: # Event searches have no equivalent Frigate server path (searches result in # EventIdentifiers, that do have a Frigate server path). with pytest.raises(NotImplementedError): - identifier.get_integration_proxy_path("utc") + identifier.get_integration_proxy_path(DEFAULT_TIME_ZONE) # Invalid "after" time. assert ( @@ -1091,7 +1105,7 @@ async def test_recordings_identifier() -> None: identifier_in = f"{TEST_FRIGATE_INSTANCE_ID}/recordings/front_door//15" identifier = RecordingIdentifier.from_str(identifier_in) assert identifier is not None - identifier.get_integration_proxy_path("utc") + identifier.get_integration_proxy_path(DEFAULT_TIME_ZONE) # Verify a zero hour: # https://github.com/blakeblackshear/frigate-hass-integration/issues/126