Skip to content

Commit d2e988b

Browse files
authored
Merge pull request #71 from hkhodr/master
feat: nvrdownload command
2 parents f151711 + 4c8d93c commit d2e988b

File tree

3 files changed

+103
-1
lines changed

3 files changed

+103
-1
lines changed
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
"""Downloads a video from camera from start to end time."""
2+
import os
3+
from configparser import RawConfigParser
4+
from datetime import datetime as dt, timedelta
5+
from reolinkapi import Camera
6+
import requests
7+
import pandas as pd
8+
9+
def read_config(props_path: str) -> dict:
10+
"""Reads in a properties file into variables.
11+
12+
NB! this config file is kept out of commits with .gitignore. The structure of this file is such:
13+
# secrets.cfg
14+
[camera]
15+
ip={ip_address}
16+
username={username}
17+
password={password}
18+
"""
19+
config = RawConfigParser()
20+
assert os.path.exists(props_path), f"Path does not exist: {props_path}"
21+
config.read(props_path)
22+
return config
23+
24+
25+
# Read in your ip, username, & password
26+
# (NB! you'll likely have to create this file. See tests/test_camera.py for details on structure)
27+
config = read_config('camera.cfg')
28+
29+
ip = config.get('camera', 'ip')
30+
un = config.get('camera', 'username')
31+
pw = config.get('camera', 'password')
32+
33+
# Connect to camera
34+
cam = Camera(ip, un, pw)
35+
36+
start = dt.now() - timedelta(minutes=10)
37+
end = dt.now() - timedelta(minutes=9)
38+
channel = 0
39+
40+
files = cam.get_playback_files(start=start, end=end, channel= channel)
41+
print(files)
42+
dl_dir = os.path.join(os.path.expanduser('~'), 'Downloads')
43+
for fname in files:
44+
print(fname)
45+
# Download the mp4
46+
cam.get_file(fname, output_path=os.path.join(dl_dir, fname))

reolinkapi/handlers/api_handler.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
from reolinkapi.mixins.system import SystemAPIMixin
1515
from reolinkapi.mixins.user import UserAPIMixin
1616
from reolinkapi.mixins.zoom import ZoomAPIMixin
17+
from reolinkapi.mixins.nvrdownload import NvrDownloadAPIMixin
1718

1819

1920
class APIHandler(AlarmAPIMixin,
@@ -28,7 +29,8 @@ class APIHandler(AlarmAPIMixin,
2829
SystemAPIMixin,
2930
UserAPIMixin,
3031
ZoomAPIMixin,
31-
StreamAPIMixin):
32+
StreamAPIMixin,
33+
NvrDownloadAPIMixin):
3234
"""
3335
The APIHandler class is the backend part of the API, the actual API calls
3436
are implemented in Mixins.

reolinkapi/mixins/nvrdownload.py

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
from datetime import datetime as dt
2+
3+
class NvrDownloadAPIMixin:
4+
"""API calls for NvrDownload."""
5+
def get_playback_files(self, start: dt, end: dt = dt.now(), channel: int = 0,
6+
streamtype: str = 'sub'):
7+
"""
8+
Get the filenames of the videos for the time range provided.
9+
10+
Args:
11+
start: the starting time range to examine
12+
end: the end time of the time range to examine
13+
channel: which channel to download from
14+
streamtype: 'main' or 'sub' - the stream to examine
15+
:return: response json
16+
"""
17+
search_params = {
18+
'NvrDownload': {
19+
'channel': channel,
20+
'iLogicChannel': 0,
21+
'streamType': streamtype,
22+
'StartTime': {
23+
'year': start.year,
24+
'mon': start.month,
25+
'day': start.day,
26+
'hour': start.hour,
27+
'min': start.minute,
28+
'sec': start.second
29+
},
30+
'EndTime': {
31+
'year': end.year,
32+
'mon': end.month,
33+
'day': end.day,
34+
'hour': end.hour,
35+
'min': end.minute,
36+
'sec': end.second
37+
}
38+
}
39+
}
40+
body = [{"cmd": "NvrDownload", "action": 1, "param": search_params}]
41+
try:
42+
resp = self._execute_command('NvrDownload', body)[0]
43+
except Exception as e:
44+
print(f"Error: {e}")
45+
return []
46+
if 'value' not in resp:
47+
return []
48+
values = resp['value']
49+
if 'fileList' not in values:
50+
return []
51+
files = values['fileList']
52+
if len(files) > 0:
53+
return [file['fileName'] for file in files]
54+
return []

0 commit comments

Comments
 (0)