mirror of
https://github.com/home-assistant/core.git
synced 2025-07-23 21:27:38 +00:00
Add event browsing to Reolink recordings (#144259)
This commit is contained in:
parent
109bcf362a
commit
0d81694640
@ -7,6 +7,7 @@ import logging
|
||||
|
||||
from reolink_aio.api import DUAL_LENS_MODELS
|
||||
from reolink_aio.enums import VodRequestType
|
||||
from reolink_aio.typings import VOD_trigger
|
||||
|
||||
from homeassistant.components.camera import DOMAIN as CAM_DOMAIN, DynamicStreamSettings
|
||||
from homeassistant.components.media_player import MediaClass, MediaType
|
||||
@ -152,6 +153,26 @@ class ReolinkVODMediaSource(MediaSource):
|
||||
int(month_str),
|
||||
int(day_str),
|
||||
)
|
||||
if item_type == "EVE":
|
||||
(
|
||||
_,
|
||||
config_entry_id,
|
||||
channel_str,
|
||||
stream,
|
||||
year_str,
|
||||
month_str,
|
||||
day_str,
|
||||
event,
|
||||
) = identifier
|
||||
return await self._async_generate_camera_files(
|
||||
config_entry_id,
|
||||
int(channel_str),
|
||||
stream,
|
||||
int(year_str),
|
||||
int(month_str),
|
||||
int(day_str),
|
||||
event,
|
||||
)
|
||||
|
||||
raise Unresolvable(f"Unknown media item '{item.identifier}' during browsing.")
|
||||
|
||||
@ -352,6 +373,7 @@ class ReolinkVODMediaSource(MediaSource):
|
||||
year: int,
|
||||
month: int,
|
||||
day: int,
|
||||
event: str | None = None,
|
||||
) -> BrowseMediaSource:
|
||||
"""Return all recording files on a specific day of a Reolink camera."""
|
||||
host = get_host(self.hass, config_entry_id)
|
||||
@ -368,9 +390,34 @@ class ReolinkVODMediaSource(MediaSource):
|
||||
month,
|
||||
day,
|
||||
)
|
||||
event_trigger = VOD_trigger[event] if event is not None else None
|
||||
_, vod_files = await host.api.request_vod_files(
|
||||
channel, start, end, stream=stream, split_time=VOD_SPLIT_TIME
|
||||
channel,
|
||||
start,
|
||||
end,
|
||||
stream=stream,
|
||||
split_time=VOD_SPLIT_TIME,
|
||||
trigger=event_trigger,
|
||||
)
|
||||
|
||||
if event is None and host.api.is_nvr and not host.api.is_hub:
|
||||
triggers = VOD_trigger.NONE
|
||||
for file in vod_files:
|
||||
triggers |= file.triggers
|
||||
|
||||
children.extend(
|
||||
BrowseMediaSource(
|
||||
domain=DOMAIN,
|
||||
identifier=f"EVE|{config_entry_id}|{channel}|{stream}|{year}|{month}|{day}|{trigger.name}",
|
||||
media_class=MediaClass.DIRECTORY,
|
||||
media_content_type=MediaType.PLAYLIST,
|
||||
title=str(trigger.name).title(),
|
||||
can_play=False,
|
||||
can_expand=True,
|
||||
)
|
||||
for trigger in triggers
|
||||
)
|
||||
|
||||
for file in vod_files:
|
||||
file_name = f"{file.start_time.time()} {file.duration}"
|
||||
if file.triggers != file.triggers.NONE:
|
||||
@ -397,6 +444,8 @@ class ReolinkVODMediaSource(MediaSource):
|
||||
)
|
||||
if host.api.model in DUAL_LENS_MODELS:
|
||||
title = f"{host.api.camera_name(channel)} lens {channel} {res_name(stream)} {year}/{month}/{day}"
|
||||
if event:
|
||||
title = f"{title} {event.title()}"
|
||||
|
||||
return BrowseMediaSource(
|
||||
domain=DOMAIN,
|
||||
|
@ -6,6 +6,7 @@ from unittest.mock import AsyncMock, MagicMock, patch
|
||||
|
||||
import pytest
|
||||
from reolink_aio.exceptions import ReolinkError
|
||||
from reolink_aio.typings import VOD_trigger
|
||||
|
||||
from homeassistant.components.media_source import (
|
||||
DOMAIN as MEDIA_SOURCE_DOMAIN,
|
||||
@ -16,6 +17,7 @@ from homeassistant.components.media_source import (
|
||||
)
|
||||
from homeassistant.components.reolink.config_flow import DEFAULT_PROTOCOL
|
||||
from homeassistant.components.reolink.const import CONF_BC_PORT, CONF_USE_HTTPS, DOMAIN
|
||||
from homeassistant.components.reolink.media_source import VOD_SPLIT_TIME
|
||||
from homeassistant.components.stream import DOMAIN as MEDIA_STREAM_DOMAIN
|
||||
from homeassistant.const import (
|
||||
CONF_HOST,
|
||||
@ -53,6 +55,8 @@ TEST_HOUR = 13
|
||||
TEST_MINUTE = 12
|
||||
TEST_START = f"{TEST_YEAR}{TEST_MONTH}{TEST_DAY}{TEST_HOUR}{TEST_MINUTE}"
|
||||
TEST_END = f"{TEST_YEAR}{TEST_MONTH}{TEST_DAY}{TEST_HOUR}{TEST_MINUTE + 5}"
|
||||
TEST_START_TIME = datetime(TEST_YEAR, TEST_MONTH, TEST_DAY, 0, 0)
|
||||
TEST_END_TIME = datetime(TEST_YEAR, TEST_MONTH, TEST_DAY, 23, 59, 59)
|
||||
TEST_FILE_NAME = f"{TEST_START}00"
|
||||
TEST_FILE_NAME_MP4 = f"{TEST_START}00.mp4"
|
||||
TEST_STREAM = "main"
|
||||
@ -212,13 +216,12 @@ async def test_browsing(
|
||||
|
||||
# browse camera recording files on day
|
||||
mock_vod_file = MagicMock()
|
||||
mock_vod_file.start_time = datetime(
|
||||
TEST_YEAR, TEST_MONTH, TEST_DAY, TEST_HOUR, TEST_MINUTE
|
||||
)
|
||||
mock_vod_file.start_time = TEST_START_TIME
|
||||
mock_vod_file.start_time_id = TEST_START
|
||||
mock_vod_file.end_time_id = TEST_END
|
||||
mock_vod_file.duration = timedelta(minutes=15)
|
||||
mock_vod_file.duration = timedelta(minutes=5)
|
||||
mock_vod_file.file_name = TEST_FILE_NAME
|
||||
mock_vod_file.triggers = VOD_trigger.PERSON
|
||||
reolink_connect.request_vod_files.return_value = ([mock_status], [mock_vod_file])
|
||||
|
||||
browse = await async_browse_media(hass, f"{URI_SCHEME}{DOMAIN}/{browse_day_0_id}")
|
||||
@ -232,9 +235,46 @@ async def test_browsing(
|
||||
)
|
||||
assert browse.identifier == browse_files_id
|
||||
assert browse.children[0].identifier == browse_file_id
|
||||
reolink_connect.request_vod_files.assert_called_with(
|
||||
int(TEST_CHANNEL),
|
||||
TEST_START_TIME,
|
||||
TEST_END_TIME,
|
||||
stream=TEST_STREAM,
|
||||
split_time=VOD_SPLIT_TIME,
|
||||
trigger=None,
|
||||
)
|
||||
|
||||
reolink_connect.model = TEST_HOST_MODEL
|
||||
|
||||
# browse event trigger person on a NVR
|
||||
reolink_connect.is_nvr = True
|
||||
browse_event_person_id = f"EVE|{entry_id}|{TEST_CHANNEL}|{TEST_STREAM}|{TEST_YEAR}|{TEST_MONTH}|{TEST_DAY}|{VOD_trigger.PERSON.name}"
|
||||
|
||||
browse = await async_browse_media(hass, f"{URI_SCHEME}{DOMAIN}/{browse_day_0_id}")
|
||||
assert browse.children[0].identifier == browse_event_person_id
|
||||
|
||||
browse = await async_browse_media(
|
||||
hass, f"{URI_SCHEME}{DOMAIN}/{browse_event_person_id}"
|
||||
)
|
||||
|
||||
assert browse.domain == DOMAIN
|
||||
assert (
|
||||
browse.title
|
||||
== f"{TEST_NVR_NAME} High res. {TEST_YEAR}/{TEST_MONTH}/{TEST_DAY} Person"
|
||||
)
|
||||
assert browse.identifier == browse_files_id
|
||||
assert browse.children[0].identifier == browse_file_id
|
||||
reolink_connect.request_vod_files.assert_called_with(
|
||||
int(TEST_CHANNEL),
|
||||
TEST_START_TIME,
|
||||
TEST_END_TIME,
|
||||
stream=TEST_STREAM,
|
||||
split_time=VOD_SPLIT_TIME,
|
||||
trigger=VOD_trigger.PERSON,
|
||||
)
|
||||
|
||||
reolink_connect.is_nvr = False
|
||||
|
||||
|
||||
async def test_browsing_h265_encoding(
|
||||
hass: HomeAssistant,
|
||||
|
Loading…
x
Reference in New Issue
Block a user