diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml
index f4c92a597..768de88f6 100644
--- a/.github/workflows/docker.yml
+++ b/.github/workflows/docker.yml
@@ -33,7 +33,7 @@ jobs:
- uses: docker/setup-buildx-action@v1
- name: Cache Docker layers
- uses: actions/cache@v2
+ uses: actions/cache@v3.0.1
with:
path: /tmp/.buildx-cache
key: ${{ runner.os }}-buildx-${{ github.sha }}
diff --git a/motioneye/templates/main.html b/motioneye/templates/main.html
index 5d39a9e86..5340d831e 100644
--- a/motioneye/templates/main.html
+++ b/motioneye/templates/main.html
@@ -454,16 +454,17 @@
+
? |
-
+
| {{ _("Servila Adreso") }} |
|
? |
-
+
| {{ _("Servila haveno") }} |
|
? |
@@ -493,12 +494,12 @@
|
? |
-
+
| {{ _("Uzantnomo") }} |
|
? |
-
+
| {{ _("Pasvorto") }} |
|
? |
diff --git a/motioneye/uploadservices.py b/motioneye/uploadservices.py
index 9bc800638..3250e48bb 100644
--- a/motioneye/uploadservices.py
+++ b/motioneye/uploadservices.py
@@ -26,6 +26,7 @@
import urllib.error
import urllib.parse
import urllib.request
+from base64 import b64encode
import boto3
import pycurl
@@ -845,6 +846,79 @@ def _request_credentials(self, authorization_key):
return {'access_token': data['access_token']}
+class Webdav(UploadService):
+ NAME = 'webdav'
+
+ def __init__(self, camera_id):
+ self._server = None
+ self._port = None
+ self._username = None
+ self._password = None
+ self._location = None
+
+ UploadService.__init__(self, camera_id)
+
+ def _request(self, url, method, body=None):
+ base64string = b64encode(f'{self._username}:{self._password}')
+ headers = {'Authorization': 'Basic %s' % base64string}
+ if body is not None:
+ headers.update('Content-Length', '%d' % len(body))
+ self.debug('request: ' + method + ' ' + url)
+ request = urllib.request.Request(url, data=body, headers=headers)
+ request.get_method = lambda: method
+ try:
+ utils.urlopen(request)
+ except urllib.HTTPError as e:
+ if method == 'MKCOL' and e.code == 405:
+ self.debug(
+ 'MKCOL failed with code 405, this is normal if the folder exists'
+ )
+ else:
+ raise e
+
+ def _make_dirs(self, path):
+ dir_url = self._server
+ for folder in path.strip('/').split('/'):
+ dir_url = dir_url + folder + '/'
+ self._request(dir_url, 'MKCOL')
+
+ def test_access(self):
+ try:
+ test_path = self._location.strip('/') + '/' + str(time.time())
+ self._make_dirs(test_path)
+ self._request(self._server + test_path, 'DELETE')
+ return True
+ except Exception as e:
+ self.error(str(e), exc_info=True)
+ return str(e)
+
+ def upload_data(self, filename, mime_type, data, ctime, camera_name):
+ path = self._location.strip('/') + '/' + os.path.dirname(filename) + '/'
+ filename = os.path.basename(filename)
+ self._make_dirs(path)
+ self.debug(f'uploading {filename} of {len(data)} bytes')
+ self._request(self._server + path + filename, 'PUT', bytearray(data))
+ self.debug('upload done')
+
+ def dump(self):
+ return {
+ 'server': self._server,
+ 'username': self._username,
+ 'password': self._password,
+ 'location': self._location,
+ }
+
+ def load(self, data):
+ if data.get('server') is not None:
+ self._server = data['server']
+ if data.get('username') is not None:
+ self._username = data['username']
+ if data.get('password') is not None:
+ self._password = data['password']
+ if data.get('location'):
+ self._location = data['location']
+
+
class FTP(UploadService):
NAME = 'ftp'
CONN_LIFE_TIME = 60 # don't keep an FTP connection for more than 1 minute