mirror of
https://github.com/home-assistant/core.git
synced 2025-07-21 12:17:07 +00:00
Implement NVR download for Reolink recordings (#144121)
This commit is contained in:
parent
dafda420e5
commit
a3b7cd7b4d
@ -27,6 +27,8 @@ from .views import async_generate_playback_proxy_url
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
VOD_SPLIT_TIME = dt.timedelta(minutes=5)
|
||||
|
||||
|
||||
async def async_get_media_source(hass: HomeAssistant) -> ReolinkVODMediaSource:
|
||||
"""Set up camera media source."""
|
||||
@ -60,11 +62,13 @@ class ReolinkVODMediaSource(MediaSource):
|
||||
"""Resolve media to a url."""
|
||||
identifier = ["UNKNOWN"]
|
||||
if item.identifier is not None:
|
||||
identifier = item.identifier.split("|", 5)
|
||||
identifier = item.identifier.split("|", 6)
|
||||
if identifier[0] != "FILE":
|
||||
raise Unresolvable(f"Unknown media item '{item.identifier}'.")
|
||||
|
||||
_, config_entry_id, channel_str, stream_res, filename = identifier
|
||||
_, config_entry_id, channel_str, stream_res, filename, start_time, end_time = (
|
||||
identifier
|
||||
)
|
||||
channel = int(channel_str)
|
||||
|
||||
host = get_host(self.hass, config_entry_id)
|
||||
@ -75,12 +79,19 @@ class ReolinkVODMediaSource(MediaSource):
|
||||
return VodRequestType.DOWNLOAD
|
||||
return VodRequestType.PLAYBACK
|
||||
if host.api.is_nvr:
|
||||
return VodRequestType.FLV
|
||||
return VodRequestType.NVR_DOWNLOAD
|
||||
return VodRequestType.RTMP
|
||||
|
||||
vod_type = get_vod_type()
|
||||
|
||||
if vod_type in [VodRequestType.DOWNLOAD, VodRequestType.PLAYBACK]:
|
||||
if vod_type == VodRequestType.NVR_DOWNLOAD:
|
||||
filename = f"{start_time}_{end_time}"
|
||||
|
||||
if vod_type in {
|
||||
VodRequestType.DOWNLOAD,
|
||||
VodRequestType.NVR_DOWNLOAD,
|
||||
VodRequestType.PLAYBACK,
|
||||
}:
|
||||
proxy_url = async_generate_playback_proxy_url(
|
||||
config_entry_id, channel, filename, stream_res, vod_type.value
|
||||
)
|
||||
@ -358,7 +369,7 @@ class ReolinkVODMediaSource(MediaSource):
|
||||
day,
|
||||
)
|
||||
_, vod_files = await host.api.request_vod_files(
|
||||
channel, start, end, stream=stream
|
||||
channel, start, end, stream=stream, split_time=VOD_SPLIT_TIME
|
||||
)
|
||||
for file in vod_files:
|
||||
file_name = f"{file.start_time.time()} {file.duration}"
|
||||
@ -372,7 +383,7 @@ class ReolinkVODMediaSource(MediaSource):
|
||||
children.append(
|
||||
BrowseMediaSource(
|
||||
domain=DOMAIN,
|
||||
identifier=f"FILE|{config_entry_id}|{channel}|{stream}|{file.file_name}",
|
||||
identifier=f"FILE|{config_entry_id}|{channel}|{stream}|{file.file_name}|{file.start_time_id}|{file.end_time_id}",
|
||||
media_class=MediaClass.VIDEO,
|
||||
media_content_type=MediaType.VIDEO,
|
||||
title=file_name,
|
||||
|
@ -51,8 +51,10 @@ TEST_DAY = 14
|
||||
TEST_DAY2 = 15
|
||||
TEST_HOUR = 13
|
||||
TEST_MINUTE = 12
|
||||
TEST_FILE_NAME = f"{TEST_YEAR}{TEST_MONTH}{TEST_DAY}{TEST_HOUR}{TEST_MINUTE}00"
|
||||
TEST_FILE_NAME_MP4 = f"{TEST_YEAR}{TEST_MONTH}{TEST_DAY}{TEST_HOUR}{TEST_MINUTE}00.mp4"
|
||||
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_FILE_NAME = f"{TEST_START}00"
|
||||
TEST_FILE_NAME_MP4 = f"{TEST_START}00.mp4"
|
||||
TEST_STREAM = "main"
|
||||
TEST_CHANNEL = "0"
|
||||
TEST_CAM_NAME = "Cam new name"
|
||||
@ -92,17 +94,15 @@ async def test_resolve(
|
||||
await hass.async_block_till_done()
|
||||
caplog.set_level(logging.DEBUG)
|
||||
|
||||
file_id = (
|
||||
f"FILE|{config_entry.entry_id}|{TEST_CHANNEL}|{TEST_STREAM}|{TEST_FILE_NAME}"
|
||||
)
|
||||
reolink_connect.get_vod_source.return_value = (TEST_MIME_TYPE, TEST_URL)
|
||||
file_id = f"FILE|{config_entry.entry_id}|{TEST_CHANNEL}|{TEST_STREAM}|{TEST_FILE_NAME}|{TEST_START}|{TEST_END}"
|
||||
reolink_connect.get_vod_source.return_value = (TEST_MIME_TYPE_MP4, TEST_URL)
|
||||
|
||||
play_media = await async_resolve_media(
|
||||
hass, f"{URI_SCHEME}{DOMAIN}/{file_id}", None
|
||||
)
|
||||
assert play_media.mime_type == TEST_MIME_TYPE
|
||||
assert play_media.mime_type == TEST_MIME_TYPE_MP4
|
||||
|
||||
file_id = f"FILE|{config_entry.entry_id}|{TEST_CHANNEL}|{TEST_STREAM}|{TEST_FILE_NAME_MP4}"
|
||||
file_id = f"FILE|{config_entry.entry_id}|{TEST_CHANNEL}|{TEST_STREAM}|{TEST_FILE_NAME_MP4}|{TEST_START}|{TEST_END}"
|
||||
reolink_connect.get_vod_source.return_value = (TEST_MIME_TYPE_MP4, TEST_URL2)
|
||||
|
||||
play_media = await async_resolve_media(
|
||||
@ -117,9 +117,7 @@ async def test_resolve(
|
||||
)
|
||||
assert play_media.mime_type == TEST_MIME_TYPE_MP4
|
||||
|
||||
file_id = (
|
||||
f"FILE|{config_entry.entry_id}|{TEST_CHANNEL}|{TEST_STREAM}|{TEST_FILE_NAME}"
|
||||
)
|
||||
file_id = f"FILE|{config_entry.entry_id}|{TEST_CHANNEL}|{TEST_STREAM}|{TEST_FILE_NAME}|{TEST_START}|{TEST_END}"
|
||||
reolink_connect.get_vod_source.return_value = (TEST_MIME_TYPE, TEST_URL)
|
||||
|
||||
play_media = await async_resolve_media(
|
||||
@ -217,6 +215,8 @@ async def test_browsing(
|
||||
mock_vod_file.start_time = datetime(
|
||||
TEST_YEAR, TEST_MONTH, TEST_DAY, TEST_HOUR, TEST_MINUTE
|
||||
)
|
||||
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.file_name = TEST_FILE_NAME
|
||||
reolink_connect.request_vod_files.return_value = ([mock_status], [mock_vod_file])
|
||||
@ -224,7 +224,7 @@ async def test_browsing(
|
||||
browse = await async_browse_media(hass, f"{URI_SCHEME}{DOMAIN}/{browse_day_0_id}")
|
||||
|
||||
browse_files_id = f"FILES|{entry_id}|{TEST_CHANNEL}|{TEST_STREAM}"
|
||||
browse_file_id = f"FILE|{entry_id}|{TEST_CHANNEL}|{TEST_STREAM}|{TEST_FILE_NAME}"
|
||||
browse_file_id = f"FILE|{entry_id}|{TEST_CHANNEL}|{TEST_STREAM}|{TEST_FILE_NAME}|{TEST_START}|{TEST_END}"
|
||||
assert browse.domain == DOMAIN
|
||||
assert (
|
||||
browse.title
|
||||
|
Loading…
x
Reference in New Issue
Block a user