pyezvizapi 1.0.3.6__py3-none-any.whl → 1.0.3.7__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of pyezvizapi might be problematic. Click here for more details.
- pyezvizapi/__main__.py +2 -2
- pyezvizapi/client.py +10 -0
- pyezvizapi/constants.py +1 -0
- pyezvizapi/feature.py +7 -11
- pyezvizapi/mqtt.py +1 -1
- pyezvizapi/test_mqtt.py +1 -1
- pyezvizapi/utils.py +52 -11
- {pyezvizapi-1.0.3.6.dist-info → pyezvizapi-1.0.3.7.dist-info}/METADATA +1 -1
- pyezvizapi-1.0.3.7.dist-info/RECORD +22 -0
- pyezvizapi-1.0.3.6.dist-info/RECORD +0 -22
- {pyezvizapi-1.0.3.6.dist-info → pyezvizapi-1.0.3.7.dist-info}/WHEEL +0 -0
- {pyezvizapi-1.0.3.6.dist-info → pyezvizapi-1.0.3.7.dist-info}/entry_points.txt +0 -0
- {pyezvizapi-1.0.3.6.dist-info → pyezvizapi-1.0.3.7.dist-info}/licenses/LICENSE +0 -0
- {pyezvizapi-1.0.3.6.dist-info → pyezvizapi-1.0.3.7.dist-info}/licenses/LICENSE.md +0 -0
- {pyezvizapi-1.0.3.6.dist-info → pyezvizapi-1.0.3.7.dist-info}/top_level.txt +0 -0
pyezvizapi/__main__.py
CHANGED
|
@@ -421,7 +421,7 @@ def _handle_devices_light(args: argparse.Namespace, client: EzvizClient) -> int:
|
|
|
421
421
|
|
|
422
422
|
def _handle_pagelist(client: EzvizClient) -> int:
|
|
423
423
|
"""Output full pagelist (raw JSON) for exploration in editors like Notepad++."""
|
|
424
|
-
data = client.
|
|
424
|
+
data = client.get_page_list()
|
|
425
425
|
_write_json(data)
|
|
426
426
|
return 0
|
|
427
427
|
|
|
@@ -611,7 +611,7 @@ def main(argv: list[str] | None = None) -> int:
|
|
|
611
611
|
return 2
|
|
612
612
|
finally:
|
|
613
613
|
if args.save_token and args.token_file:
|
|
614
|
-
_save_token_file(args.token_file,
|
|
614
|
+
_save_token_file(args.token_file, client.export_token())
|
|
615
615
|
client.close_session()
|
|
616
616
|
|
|
617
617
|
|
pyezvizapi/client.py
CHANGED
|
@@ -4398,6 +4398,16 @@ class EzvizClient:
|
|
|
4398
4398
|
json_key=None,
|
|
4399
4399
|
)
|
|
4400
4400
|
|
|
4401
|
+
def get_page_list(self) -> Any:
|
|
4402
|
+
"""Return the full pagelist payload without filtering."""
|
|
4403
|
+
|
|
4404
|
+
return self._get_page_list()
|
|
4405
|
+
|
|
4406
|
+
def export_token(self) -> dict[str, Any]:
|
|
4407
|
+
"""Return a shallow copy of the current authentication token."""
|
|
4408
|
+
|
|
4409
|
+
return dict(self._token)
|
|
4410
|
+
|
|
4401
4411
|
def get_device(self) -> Any:
|
|
4402
4412
|
"""Get ezviz devices filter."""
|
|
4403
4413
|
return self._api_get_pagelist(page_filter="CLOUD", json_key="deviceInfos")
|
pyezvizapi/constants.py
CHANGED
pyezvizapi/feature.py
CHANGED
|
@@ -5,22 +5,18 @@ from __future__ import annotations
|
|
|
5
5
|
from collections.abc import Iterable, Iterator, Mapping, MutableMapping
|
|
6
6
|
from typing import Any, cast
|
|
7
7
|
|
|
8
|
-
from .utils import coerce_int, decode_json
|
|
8
|
+
from .utils import WILDCARD_STEP, coerce_int, decode_json, first_nested
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
def _feature_video_section(camera_data: Mapping[str, Any]) -> dict[str, Any]:
|
|
12
12
|
"""Return the nested Video feature section from feature info payload."""
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
video = group.get("Video")
|
|
21
|
-
if isinstance(video, MutableMapping):
|
|
22
|
-
return cast(dict[str, Any], video)
|
|
23
|
-
|
|
14
|
+
video = first_nested(
|
|
15
|
+
camera_data,
|
|
16
|
+
("FEATURE_INFO", WILDCARD_STEP, "Video"),
|
|
17
|
+
)
|
|
18
|
+
if isinstance(video, MutableMapping):
|
|
19
|
+
return cast(dict[str, Any], video)
|
|
24
20
|
return {}
|
|
25
21
|
|
|
26
22
|
|
pyezvizapi/mqtt.py
CHANGED
|
@@ -247,7 +247,7 @@ class MQTTClient:
|
|
|
247
247
|
# Stop background thread and disconnect
|
|
248
248
|
self.mqtt_client.loop_stop()
|
|
249
249
|
self.mqtt_client.disconnect()
|
|
250
|
-
except
|
|
250
|
+
except (OSError, ValueError, RuntimeError) as err:
|
|
251
251
|
_LOGGER.debug("MQTT disconnect failed: %s", err)
|
|
252
252
|
# Always attempt to stop push on server side
|
|
253
253
|
self._stop_ezviz_push()
|
pyezvizapi/test_mqtt.py
CHANGED
|
@@ -125,7 +125,7 @@ def main(argv: list[str] | None = None) -> int:
|
|
|
125
125
|
print("Stopped.")
|
|
126
126
|
|
|
127
127
|
if args.save_token and args.token_file:
|
|
128
|
-
_save_token_file(args.token_file,
|
|
128
|
+
_save_token_file(args.token_file, client.export_token())
|
|
129
129
|
|
|
130
130
|
return 0
|
|
131
131
|
|
pyezvizapi/utils.py
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
+
from collections.abc import Iterable, Iterator
|
|
5
6
|
import datetime
|
|
6
7
|
from hashlib import md5
|
|
7
8
|
import json
|
|
@@ -13,6 +14,7 @@ from zoneinfo import ZoneInfo, ZoneInfoNotFoundError
|
|
|
13
14
|
|
|
14
15
|
from Crypto.Cipher import AES
|
|
15
16
|
|
|
17
|
+
from .constants import HIK_ENCRYPTION_HEADER
|
|
16
18
|
from .exceptions import PyEzvizError
|
|
17
19
|
|
|
18
20
|
_LOGGER = logging.getLogger(__name__)
|
|
@@ -74,6 +76,49 @@ def string_to_list(data: Any, separator: str = ",") -> Any:
|
|
|
74
76
|
return data
|
|
75
77
|
|
|
76
78
|
|
|
79
|
+
PathComponent = str | int
|
|
80
|
+
WILDCARD_STEP = "*"
|
|
81
|
+
_MISSING = object()
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def iter_nested(data: Any, path: Iterable[PathComponent]) -> Iterator[Any]:
|
|
85
|
+
"""Yield values reachable by following a dotted path with optional wildcards."""
|
|
86
|
+
|
|
87
|
+
current: list[Any] = [data]
|
|
88
|
+
|
|
89
|
+
for step in path:
|
|
90
|
+
next_level: list[Any] = []
|
|
91
|
+
for candidate in current:
|
|
92
|
+
if step == WILDCARD_STEP:
|
|
93
|
+
if isinstance(candidate, dict):
|
|
94
|
+
next_level.extend(candidate.values())
|
|
95
|
+
elif isinstance(candidate, (list, tuple)):
|
|
96
|
+
next_level.extend(candidate)
|
|
97
|
+
continue
|
|
98
|
+
|
|
99
|
+
if isinstance(candidate, dict) and step in candidate:
|
|
100
|
+
next_level.append(candidate[step])
|
|
101
|
+
continue
|
|
102
|
+
|
|
103
|
+
if isinstance(candidate, (list, tuple)) and isinstance(step, int):
|
|
104
|
+
if -len(candidate) <= step < len(candidate):
|
|
105
|
+
next_level.append(candidate[step])
|
|
106
|
+
|
|
107
|
+
current = next_level
|
|
108
|
+
if not current:
|
|
109
|
+
break
|
|
110
|
+
|
|
111
|
+
yield from current
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def first_nested(
|
|
115
|
+
data: Any, path: Iterable[PathComponent], default: Any = None
|
|
116
|
+
) -> Any:
|
|
117
|
+
"""Return the first value produced by iter_nested or ``default``."""
|
|
118
|
+
|
|
119
|
+
return next(iter_nested(data, path), default)
|
|
120
|
+
|
|
121
|
+
|
|
77
122
|
def fetch_nested_value(data: Any, keys: list, default_value: Any = None) -> Any:
|
|
78
123
|
"""Fetch the value corresponding to the given nested keys in a dictionary.
|
|
79
124
|
|
|
@@ -88,14 +133,8 @@ def fetch_nested_value(data: Any, keys: list, default_value: Any = None) -> Any:
|
|
|
88
133
|
The value corresponding to the nested keys or the default value.
|
|
89
134
|
|
|
90
135
|
"""
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
data = data[key]
|
|
94
|
-
|
|
95
|
-
except (KeyError, TypeError):
|
|
96
|
-
return default_value
|
|
97
|
-
|
|
98
|
-
return data
|
|
136
|
+
value = first_nested(data, keys, _MISSING)
|
|
137
|
+
return default_value if value is _MISSING else value
|
|
99
138
|
|
|
100
139
|
|
|
101
140
|
def decrypt_image(input_data: bytes, password: str) -> bytes:
|
|
@@ -116,8 +155,10 @@ def decrypt_image(input_data: bytes, password: str) -> bytes:
|
|
|
116
155
|
raise PyEzvizError("Invalid image data")
|
|
117
156
|
|
|
118
157
|
# check header
|
|
119
|
-
|
|
120
|
-
|
|
158
|
+
header_len = len(HIK_ENCRYPTION_HEADER)
|
|
159
|
+
|
|
160
|
+
if input_data[:header_len] != HIK_ENCRYPTION_HEADER:
|
|
161
|
+
_LOGGER.debug("Image header doesn't contain %s", HIK_ENCRYPTION_HEADER)
|
|
121
162
|
return input_data
|
|
122
163
|
|
|
123
164
|
file_hash = input_data[16:48]
|
|
@@ -132,7 +173,7 @@ def decrypt_image(input_data: bytes, password: str) -> bytes:
|
|
|
132
173
|
next_chunk = b""
|
|
133
174
|
output_data = b""
|
|
134
175
|
finished = False
|
|
135
|
-
i = 48 # offset
|
|
176
|
+
i = 48 # offset HIK header + hash
|
|
136
177
|
chunk_size = 1024 * AES.block_size
|
|
137
178
|
while not finished:
|
|
138
179
|
chunk, next_chunk = next_chunk, cipher.decrypt(input_data[i : i + chunk_size])
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
pyezvizapi/__init__.py,sha256=-OxHqxA9h0JZQW__GoZd1aByGquIHawCnNdeNlIg2Qo,3382
|
|
2
|
+
pyezvizapi/__main__.py,sha256=6vFvkh8gCD-Mo4CXd1deZfDeaaHR-Kc8pOu9vkUjQf4,20878
|
|
3
|
+
pyezvizapi/api_endpoints.py,sha256=2M5Vs4YB1VWZGcowT-4Fj2hhRNjFh976LT3jtRrqvrc,5754
|
|
4
|
+
pyezvizapi/camera.py,sha256=Pl5oIEdrFcv1Hz5sQI1IyyJIDCMjOjQdtExgKzmLoK8,22102
|
|
5
|
+
pyezvizapi/cas.py,sha256=3zHe-_a0KchCmGeAj1of-pV6oMPRUmSCIiDqBFsTK8A,6025
|
|
6
|
+
pyezvizapi/client.py,sha256=CKSK7hdQFmJAD0p1GPgEaqw7QAtqyhqLN8soR_VmSeA,142146
|
|
7
|
+
pyezvizapi/constants.py,sha256=4aoo2jKV88quLIPRwRAH0xW7yCuQfsU9tNtSxq7Xnnk,12854
|
|
8
|
+
pyezvizapi/exceptions.py,sha256=8rmxEUQdrziqMe-M1SeeRd0HtP2IDQ2xpJVj7wvOQyo,976
|
|
9
|
+
pyezvizapi/feature.py,sha256=TwQDAVFXqrpe5s0rXyJSqsHCnQsw1MNSTsUGhb61EzI,15886
|
|
10
|
+
pyezvizapi/light_bulb.py,sha256=9wgycG3dTvBbrsxQjQnXal-GA8VXPsIN1m-CTtRh8i0,7797
|
|
11
|
+
pyezvizapi/models.py,sha256=NQzwTP0yEe2IWU-Vc6nAn87xulpTuo0MX2Rcf0WxifA,4176
|
|
12
|
+
pyezvizapi/mqtt.py,sha256=_JHklUsqqwrgKk3k8RyBgo3bp1utEOr5KSBe8Oz92qg,22375
|
|
13
|
+
pyezvizapi/test_cam_rtsp.py,sha256=O9NHh-vcNFfnzNw8jbuhM9a_5TWfNZIMXaJP7Lmkaj4,5162
|
|
14
|
+
pyezvizapi/test_mqtt.py,sha256=-0L621V4nzm6x0oLgurAgkJZopVZ5Os7n1hLVMh3qIc,4117
|
|
15
|
+
pyezvizapi/utils.py,sha256=Gmn6Ljuo7SUSt1nFN-JmuoWAJGKqUYqur4SBESlhjKI,14153
|
|
16
|
+
pyezvizapi-1.0.3.7.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
17
|
+
pyezvizapi-1.0.3.7.dist-info/licenses/LICENSE.md,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
18
|
+
pyezvizapi-1.0.3.7.dist-info/METADATA,sha256=UYwabH3pFMA4UryJZ8h9Pu-alu2TuG1ee-enZQ2j8bU,695
|
|
19
|
+
pyezvizapi-1.0.3.7.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
20
|
+
pyezvizapi-1.0.3.7.dist-info/entry_points.txt,sha256=_BSJ3eNb2H_AZkRdsv1s4mojqWn3N7m503ujvg1SudA,56
|
|
21
|
+
pyezvizapi-1.0.3.7.dist-info/top_level.txt,sha256=gMZTelIi8z7pXyTCQLLaIkxVRrDQ_lS2NEv0WgfHrHs,11
|
|
22
|
+
pyezvizapi-1.0.3.7.dist-info/RECORD,,
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
pyezvizapi/__init__.py,sha256=-OxHqxA9h0JZQW__GoZd1aByGquIHawCnNdeNlIg2Qo,3382
|
|
2
|
-
pyezvizapi/__main__.py,sha256=9uttTuOfO22tzyomJIV8ebFJ-G-YUNDYOadZ_0AgdNA,20925
|
|
3
|
-
pyezvizapi/api_endpoints.py,sha256=2M5Vs4YB1VWZGcowT-4Fj2hhRNjFh976LT3jtRrqvrc,5754
|
|
4
|
-
pyezvizapi/camera.py,sha256=Pl5oIEdrFcv1Hz5sQI1IyyJIDCMjOjQdtExgKzmLoK8,22102
|
|
5
|
-
pyezvizapi/cas.py,sha256=3zHe-_a0KchCmGeAj1of-pV6oMPRUmSCIiDqBFsTK8A,6025
|
|
6
|
-
pyezvizapi/client.py,sha256=LroaR4h_wYu8HB74l4_X6Vjq7rTiL88Idf18elUBj4A,141851
|
|
7
|
-
pyezvizapi/constants.py,sha256=5AxJYfof6NvebBcFvPkoKI6xinpkwmCnaauUvhvBMDY,12810
|
|
8
|
-
pyezvizapi/exceptions.py,sha256=8rmxEUQdrziqMe-M1SeeRd0HtP2IDQ2xpJVj7wvOQyo,976
|
|
9
|
-
pyezvizapi/feature.py,sha256=inqqk14Jgo3HOzml2GRUgz-hxbne4kT5iJ3L6SJhU8s,15990
|
|
10
|
-
pyezvizapi/light_bulb.py,sha256=9wgycG3dTvBbrsxQjQnXal-GA8VXPsIN1m-CTtRh8i0,7797
|
|
11
|
-
pyezvizapi/models.py,sha256=NQzwTP0yEe2IWU-Vc6nAn87xulpTuo0MX2Rcf0WxifA,4176
|
|
12
|
-
pyezvizapi/mqtt.py,sha256=aOL-gexZgYvCCaNQ03M4vZan91d5p2Fl_qsFykn9NW4,22365
|
|
13
|
-
pyezvizapi/test_cam_rtsp.py,sha256=O9NHh-vcNFfnzNw8jbuhM9a_5TWfNZIMXaJP7Lmkaj4,5162
|
|
14
|
-
pyezvizapi/test_mqtt.py,sha256=Orn-fwZPJIE4G5KROMX0MRAkLwU6nLb9LUtXyb2ZCQs,4147
|
|
15
|
-
pyezvizapi/utils.py,sha256=ozGncEyaIJJ8VYw8f-xfM2OBmqR8eNYLq728FFvbvr8,12757
|
|
16
|
-
pyezvizapi-1.0.3.6.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
17
|
-
pyezvizapi-1.0.3.6.dist-info/licenses/LICENSE.md,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
18
|
-
pyezvizapi-1.0.3.6.dist-info/METADATA,sha256=jp0jUC6j-BihBfzY79Qo_bdmk_yT6Db5wiJdlTHolmQ,695
|
|
19
|
-
pyezvizapi-1.0.3.6.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
20
|
-
pyezvizapi-1.0.3.6.dist-info/entry_points.txt,sha256=_BSJ3eNb2H_AZkRdsv1s4mojqWn3N7m503ujvg1SudA,56
|
|
21
|
-
pyezvizapi-1.0.3.6.dist-info/top_level.txt,sha256=gMZTelIi8z7pXyTCQLLaIkxVRrDQ_lS2NEv0WgfHrHs,11
|
|
22
|
-
pyezvizapi-1.0.3.6.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|