Skip to content

Commit

Permalink
Merge branch 'master' of https://github.com/N4S4/synology-api
Browse files Browse the repository at this point in the history
  • Loading branch information
N4S4 committed Jan 12, 2023
2 parents 6a35ca1 + 83e91a7 commit 8d22d7f
Show file tree
Hide file tree
Showing 11 changed files with 144 additions and 66 deletions.
3 changes: 3 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
setuptools~=60.2.0
requests~=2.28.1
urllib3~=1.26.12
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

setup(
name='synology-api',
version='0.4.5',
version='0.5',
packages=find_packages(exclude=['tests*']),
license='MIT',
description='Python Synology API Wrapper',
Expand Down
5 changes: 1 addition & 4 deletions synology_api/audiostation.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,8 @@ def __init__(self, ip_address, port, username, password, secure=False, cert_veri
self._sid = self.session.sid
self.base_url = self.session.base_url

if debug is True:
print('You are now logged in!')

def logout(self):
self.session.logout('AudioStation')
print(self.session.logout('AudioStation'))

def get_info(self):
api_name = 'SYNO.AudioStation.Info'
Expand Down
96 changes: 58 additions & 38 deletions synology_api/auth.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import requests
from requests.packages.urllib3.exceptions import InsecureRequestWarning
from .error_codes import error_codes, CODE_SUCCESS, CODE_UNKNOWN
from urllib3 import disable_warnings
from urllib3.exceptions import InsecureRequestWarning


class Authentication:
def __init__(self, ip_address, port, username, password, secure=False, cert_verify=False, dsm_version=7, debug=True, otp_code=None):
def __init__(self, ip_address, port, username, password, secure=False, cert_verify=False, dsm_version=7, debug=True,
otp_code=None):
self._ip_address = ip_address
self._port = port
self._username = username
Expand All @@ -15,7 +18,7 @@ def __init__(self, ip_address, port, username, password, secure=False, cert_veri
self._debug = debug
self._otp_code = otp_code
if self._verify is False:
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
disable_warnings(InsecureRequestWarning)
schema = 'https' if secure else 'http'
self._base_url = '%s://%s:%s/webapi/' % (schema, self._ip_address, self._port)

Expand All @@ -27,38 +30,42 @@ def verify_cert_enabled(self):

def login(self, application):
login_api = 'auth.cgi?api=SYNO.API.Auth'
param = {'version': self._version, 'method': 'login', 'account': self._username,
'passwd': self._password, 'session': application, 'format': 'cookie'}
params = {'version': self._version, 'method': 'login', 'account': self._username,
'passwd': self._password, 'session': application, 'format': 'cookie'}
if self._otp_code:
param['otp_code'] = self._otp_code
params['otp_code'] = self._otp_code

if not self._session_expire:
if self._sid is not None:
self._session_expire = False
if self._debug is True:
return 'User already logged'
else:
session_request = requests.get(self._base_url + login_api, param, verify=self._verify)
self._sid = session_request.json()['data']['sid']
if not self._session_expire and self._sid is not None:
self._session_expire = False
if self._debug is True:
return 'User logging... New session started!'
print('User already logged in')
else:
session_request = requests.get(self._base_url + login_api, params, verify=self._verify)
session_request_json = session_request.json()
error_code = self._get_error_code(session_request_json)
if not error_code:
self._sid = session_request_json['data']['sid']
self._session_expire = False
if self._debug is True:
print('User logged in, new session started!')
else:
self._sid = None
if self._debug is True:
print('Login failed: ' + self._get_error_message(error_code))

def logout(self, application):
logout_api = 'auth.cgi?api=SYNO.API.Auth'
param = {'version': '2', 'method': 'logout', 'session': application}
param = {'version': self._version, 'method': 'logout', 'session': application}

response = requests.get(self._base_url + logout_api, param, verify=self._verify)
if response.json()['success'] is True:
self._session_expire = True
self._sid = None
if self._debug is True:
return 'Logged out'
else:
self._session_expire = True
self._sid = None
if self._debug is True:
return 'No valid session is open'
error_code = self._get_error_code(response.json())
self._session_expire = True
self._sid = None
if self._debug is True:
if not error_code:
print('Successfully logged out.')
else:
print('Logout failed: ' + self._get_error_message(error_code))

def get_api_list(self, app=None):
query_path = 'query.cgi?api=SYNO.API.Info'
Expand Down Expand Up @@ -114,23 +121,36 @@ def request_data(self, api_name, api_path, req_param, method=None, response_json

req_param['_sid'] = self._sid

url = ('%s%s' % (self._base_url, api_path)) + '?api=' + api_name

if method == 'get':
url = ('%s%s' % (self._base_url, api_path)) + '?api=' + api_name
response = requests.get(url, req_param, verify=self._verify)

if response_json is True:
return response.json()
else:
return response

elif method == 'post':
url = ('%s%s' % (self._base_url, api_path)) + '?api=' + api_name
response = requests.post(url, req_param, verify=self._verify)

if response_json is True:
return response.json()
else:
return response
error_code = self._get_error_code(response.json())

if error_code:
if self._debug is True:
print('Data request failed: ' + self._get_error_message(error_code))

if response_json is True:
return response.json()
else:
return response

@staticmethod
def _get_error_code(response: dict):
if response.get('success'):
code = CODE_SUCCESS
else:
code = response.get('error').get('code')
return code

@staticmethod
def _get_error_message(code: int) -> str:
message = error_codes.get(code, CODE_UNKNOWN)
return 'Error {} - {}'.format(code, message)

@property
def sid(self):
Expand Down
6 changes: 1 addition & 5 deletions synology_api/base_api_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ class Core(object):
def __init__(self, ip_address, port, username, password, secure=False, cert_verify=False, dsm_version=7, debug=True, otp_code=None):

self.session = syn.Authentication(ip_address, port, username, password, secure, cert_verify, dsm_version, debug, otp_code)

self.session.login('Core')
self.session.get_api_list('Core')
self.session.get_api_list()
Expand All @@ -16,8 +15,5 @@ def __init__(self, ip_address, port, username, password, secure=False, cert_veri
self._sid = self.session.sid
self.base_url = self.session.base_url

if debug is True:
print('You are now logged in!')

def logout(self):
self.session.logout('Core')
print(self.session.logout('Core'))
5 changes: 1 addition & 4 deletions synology_api/downloadstation.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,8 @@ def __init__(self, ip_address, port, username, password, secure=False, cert_veri
self._sid = self.session.sid
self.base_url = self.session.base_url

if debug is True:
print('You are now logged in!')

def logout(self):
self.session.logout('DownloadStation')
print(self.session.logout('DownloadStation'))

def get_info(self):
api_name = 'SYNO.DownloadStation.Info'
Expand Down
71 changes: 71 additions & 0 deletions synology_api/error_codes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# source: pages 8 and 16 on PDF:
# https://global.download.synology.com/download/Document/Software/DeveloperGuide/Os/DSM/All/enu/DSM_Login_Web_API_Guide_enu.pdf
CODE_SUCCESS = 0
CODE_UNKNOWN = 9999

error_codes = {
CODE_SUCCESS: 'Success',
100: 'Unknown error',
101: 'No parameter of API, method or version',
102: 'The requested API does not exist',
103: 'The requested method does not exist',
104: 'The requested version does not support the functionality',
105: 'The logged in session does not have permission',
106: 'Session timeout',
107: 'Session interrupted by duplicated login',
108: 'Failed to upload the file',
109: 'The network connection is unstable or the system is busy',
110: 'The network connection is unstable or the system is busy',
111: 'The network connection is unstable or the system is busy',
112: 'Preserve for other purpose',
113: 'Preserve for other purpose',
114: 'Lost parameters for this API',
115: 'Not allowed to upload a file',
116: 'Not allowed to perform for a demo site',
117: 'The network connection is unstable or the system is busy',
118: 'The network connection is unstable or the system is busy',
119: 'Invalid session',
# 120-149 Preserve for other purpose
120: 'Preserve for other purpose',
121: 'Preserve for other purpose',
122: 'Preserve for other purpose',
123: 'Preserve for other purpose',
124: 'Preserve for other purpose',
125: 'Preserve for other purpose',
126: 'Preserve for other purpose',
127: 'Preserve for other purpose',
128: 'Preserve for other purpose',
129: 'Preserve for other purpose',
130: 'Preserve for other purpose',
131: 'Preserve for other purpose',
132: 'Preserve for other purpose',
133: 'Preserve for other purpose',
134: 'Preserve for other purpose',
135: 'Preserve for other purpose',
136: 'Preserve for other purpose',
137: 'Preserve for other purpose',
138: 'Preserve for other purpose',
139: 'Preserve for other purpose',
140: 'Preserve for other purpose',
141: 'Preserve for other purpose',
142: 'Preserve for other purpose',
143: 'Preserve for other purpose',
144: 'Preserve for other purpose',
145: 'Preserve for other purpose',
146: 'Preserve for other purpose',
147: 'Preserve for other purpose',
148: 'Preserve for other purpose',
149: 'Preserve for other purpose',
150: 'Request source IP does not match the login IP',
400: 'No such account or incorrect password',
401: 'Disabled account',
402: 'Denied permission',
403: '2 - factor authentication code required',
404: 'Failed to authenticate 2 - factor authentication code',
406: 'Enforce to authenticate with 2 - factor authentication code',
407: 'Blocked IP source',
408: 'Expired password cannot change',
409: 'Expired password',
410: 'Password must be changed',
CODE_UNKNOWN: 'Unknown Error',
}
11 changes: 4 additions & 7 deletions synology_api/filestation.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,19 +30,16 @@ def __init__(self, ip_address, port, username, password, secure=False, cert_veri
self._compress_taskid = ''
self._compress_taskid_list = []
self.request_data = self.session.request_data

self.session.login('FileStation')
self.session.get_api_list('FileStation')

self.file_station_list = self.session.app_api_list
self._sid = self.session.sid
self.base_url = self.session.base_url

if debug is True:
print('You are now logged in!')

def logout(self):
self.session.logout('FileStation')
print(self.session.logout('FileStation'))

def get_info(self):
api_name = 'SYNO.FileStation.Info'
Expand Down Expand Up @@ -532,7 +529,7 @@ def get_shared_link_list(self, offset=None, limit=None, sort_by=None,
return self.request_data(api_name, api_path, req_param)

def create_sharing_link(self, path=None, password=None, date_expired=None,
date_available=None):
date_available=None, expire_times=0):
api_name = 'SYNO.FileStation.Sharing'
info = self.file_station_list[api_name]
api_path = info['path']
Expand Down Expand Up @@ -570,7 +567,7 @@ def clear_invalid_shared_link(self):
return self.request_data(api_name, api_path, req_param)

def edit_shared_link(self, link_id=None, password=None, date_expired=None,
date_available=None):
date_available=None, expire_times=0):
api_name = 'SYNO.FileStation.Sharing'
info = self.file_station_list[api_name]
api_path = info['path']
Expand Down
6 changes: 3 additions & 3 deletions synology_api/photos.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@

class Photos:

def __init__(self, ip_address, port, username, password, secure=False, cert_verify=False, dsm_version=7, otp_code=None):
self.session = syn.Authentication(ip_address, port, username, password, secure, cert_verify, dsm_version, otp_code)
def __init__(self, ip_address, port, username, password, secure=False, cert_verify=False, dsm_version=7, debug=True, otp_code=None):
self.session = syn.Authentication(ip_address, port, username, password, secure, cert_verify, dsm_version, debug, otp_code)

self.session.login('Foto')
self.session.get_api_list('Foto')
Expand All @@ -18,7 +18,7 @@ def __init__(self, ip_address, port, username, password, secure=False, cert_veri
self._userinfo = None

def logout(self):
self.session.logout('Foto')
print(self.session.logout('Foto'))

def get_userinfo(self):
if self._userinfo is not None:
Expand Down
3 changes: 0 additions & 3 deletions synology_api/universal_search.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,6 @@ def __init__(self, ip_address, port, username, password, secure=False, cert_veri
self._sid = self.session.sid
self.base_url = self.session.base_url

if debug is True:
print('You are now logged in!')

def search(self, keyword):
api_name = 'SYNO.Finder.FileIndexing.Search'
info = self.finder_list[api_name]
Expand Down
2 changes: 1 addition & 1 deletion synology_api/virtualization.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ def __init__(self, ip_address, port, username, password, secure=False, cert_veri
self.base_url = self.session.base_url

def logout(self):
self.session.logout('Virtualization')
print(self.session.logout('Virtualization'))

def get_task_list(self):
api_name = 'SYNO.Virtualization.API.Task.Info'
Expand Down

0 comments on commit 8d22d7f

Please sign in to comment.