Browse Source

first init

master
gsd 8 months ago
commit
6121d11ab7
  1. 2
      .gitignore
  2. 2
      README
  3. 72
      config_parser.py
  4. 45
      nvr_core.py
  5. 137
      nvr_types.py
  6. 0
      server.py

2
.gitignore

@ -0,0 +1,2 @@
config.json
__pycache__

2
README

@ -0,0 +1,2 @@
install https://github.com/OpenIPC/python-dvr
test on python 3.11

72
config_parser.py

@ -0,0 +1,72 @@
import os, sys
from json import loads
from dvrip import DVRIPCam
from nvr_core import NVR
def app_dir():
return os.path.dirname(os.path.abspath(__file__))
def load_config():
try:
path = os.path.join(app_dir(),"config.json")
print("Looking config file", path)
with open(path, "r", encoding="utf8") as f:
return loads(f.read())
except Exception as e:
print("cannot find or parse config.json", e)
sys.exit(1)
class Recorder:
def __init__(self, address, port, username, password):
self.address = address
self.port = int(port)
self.username = username
self.password = password
@property
def client(self) -> DVRIPCam:
return DVRIPCam(self.address, port = self.port, user = self.username, password = self.password)
@property
def nvr(self) -> NVR:
return NVR(self.client)
def __str__(self) -> str:
return f"{self.address}:{self.port}"
class Config:
def __init__(self) -> None:
raw = load_config()
self.listen_address = raw.get("backend", {}).get("address", "0.0.0.0")
self.listen_port = int(raw.get("backend", {}).get("port", "8080"))
self.recorders = []
for raw_server in raw.get("recorders", []):
self.recorders.append(Recorder(raw_server.get("ip"), raw_server.get("port"), raw_server.get("user"), raw_server.get("password")))
if (self.recorders.__len__() == 0):
print("Recorders not find")
else:
for recorder in self.recorders:
print(recorder)
def getRecorder(self, index = 0):
return self.recorders[index]
if __name__ == "__main__":
print(app_dir())
config = Config()
recorder: Recorder = config.getRecorder()
nvr: NVR = recorder.nvr
nvr.login()
print(nvr.download_test())
nvr.logout()
#client: DVRIPCam = recorder.client
#client.debug()
#if not client.login():
# print("can't login")
# sys.exit(2)
#print(client.get_system_info())
#print(client.get_channel_titles())
#print(client.get_channel_statuses())
#print(client.list_local_files(START, END, "h264", channel=3))
#client.close()

45
nvr_core.py

@ -0,0 +1,45 @@
from datetime import datetime
from dvrip import DVRIPCam
from nvr_types import File as NvrFile
START = "2024-08-04 6:22:34"
END = "2024-08-04 23:23:09"
CHANNEL = 0
def date_today(begin = True):
if begin:
return datetime.now().strftime("%Y-%m-%d 00:00:00")
else:
return datetime.now().strftime("%Y-%m-%d 23:59:59")
class NVR:
def __init__(self, client) -> None:
self.client:DVRIPCam = client
def login(self):
self.client.login()
def logout(self):
self.client.close()
@property
def channels(self):
return self.client.get_channel_titles()
def files(self, channel, start = None, end = None, ftype = "h264"):
if not start:
start = date_today()
if not end:
start = date_today(False)
for raw_file in self.client.list_local_files(startTime=start, endTime=end, filetype=ftype, channel=channel):
yield NvrFile(raw_file)
def download_test(self, filename = "testfile.unknown"):
download_file = list(self.files(0))[0]
downloaded_bytes = 0
with open(filename, "wb") as f:
for byte in download_file.download_stream(self.client):
downloaded_bytes += len(byte)
f.write(byte)
print("\r", downloaded_bytes, "/", download_file.size)

137
nvr_types.py

@ -0,0 +1,137 @@
from datetime import datetime
from dvrip import DVRIPCam
import json
import struct
NVR_DATETIME_FORMAT = "%Y-%m-%d %H:%M:%S"
class File:
def __init__(self, data, channel = 0) -> None:
self.begin = datetime.strptime(data.get("BeginTime"), NVR_DATETIME_FORMAT)
self.end = datetime.strptime(data.get("EndTime"), NVR_DATETIME_FORMAT)
self.diskNo = data.get("DiskNo")
self.SerialNo = data.get("SerialNo")
self.size = int(data.get("FileLength"), 0)
self.filename = data.get("FileName")
self.channel = channel
def __str__(self) -> str:
return self.filename
def __repr__(self) -> str:
return self.__str__()
def download_stream(self, client:DVRIPCam, stream = 0, version = 0):
#init request
client.send(
1424,
{
"Name": "OPPlayBack",
"OPPlayBack": {
"Action": "Claim",
"Parameter": {
"PlayMode": "ByName",
"FileName": self.filename,
"StreamType": stream,
"Value": 0,
"TransMode": "TCP",
},
"StartTime": self.begin.strftime(NVR_DATETIME_FORMAT),
"EndTime": self.end.strftime(NVR_DATETIME_FORMAT),
},
},
)
#download request
msg = 1420
data = {
"Name": "OPPlayBack",
"OPPlayBack": {
"Action": "DownloadStart",
"Parameter": {
"PlayMode": "ByName",
"FileName": self.filename,
"StreamType": stream,
"Value": 0,
"TransMode": "TCP",
},
"StartTime": self.begin.strftime(NVR_DATETIME_FORMAT),
"EndTime": self.end.strftime(NVR_DATETIME_FORMAT),
},
}
if client.socket is None:
#todo raise error
return []
client.busy.acquire()
if hasattr(data, "__iter__"):
if version == 1:
data["SessionID"] = f"{client.session:#0{12}x}"
data = bytes(
json.dumps(data, ensure_ascii=False, separators=(",", ":")), "utf-8"
)
tail = b"\x00"
if version == 0:
tail = b"\x0a" + tail
pkt = (
struct.pack(
"BB2xII2xHI",
255,
version,
client.session,
client.packet_count,
msg,
len(data) + len(tail),
)
+ data
+ tail
)
client.socket_send(pkt)
data = client.socket_recv(20)
if data is None or len(data) < 20:
return []
(
head,
version,
client.session,
sequence_number,
msgid,
len_data,
) = struct.unpack("BB2xII2xHI", data)
return self.get_file_stream(client, len_data, stream)
def get_file_stream(self, client, first_chunk_size, stream):
yield client.receive_with_timeout(first_chunk_size)
while True:
header = client.receive_with_timeout(20)
len_data = struct.unpack("I", header[16:])[0]
if len_data == 0:
break
yield client.receive_with_timeout(len_data)
client.busy.release()
client.send(
1420,
{
"Name": "OPPlayBack",
"OPPlayBack": {
"Action": "DownloadStop",
"Parameter": {
"FileName": self.filename,
"PlayMode": "ByName",
"StreamType": stream,
"TransMode": "TCP",
"Channel": self.channel,
"Value": 0,
},
"StartTime": self.begin.strftime(NVR_DATETIME_FORMAT),
"EndTime": self.end.strftime(NVR_DATETIME_FORMAT),
},
},
)
yield b""

0
server.py

Loading…
Cancel
Save