`SYNO.Core.TaskScheduler`
@@ -1219,65 +1232,63 @@ Modify settings of a Recycle Bin Control task.
**_task_id_** `int`
The ID of the task.
-**_task_name_** `str `
+**_task_name_** `str`
The name of the task.
-**_real_owner_** `str `
-The task real owner, usually it is `root`, you can double check from the result of `get_task_config()`.
+**_real_owner_** `str`
+The task real owner, usually it is `root`. You can double check from the result of `get_task_config()`.
+
+**_clean_all_shares_** `bool`
+Whether the task should empty the recycle bins of all shares. If set to `False`, `shares` must be specified.
-**_clean_all_shares_** `bool `
-Whether the task should empty the recycle bins of all shares or not, if set to `False`, shares must be specified.
+**_policy_** `dict`
+Determines what files will be deleted from the recycle bins.
+Possible values are:
+ - \{"policy": "clean_all"\}: Clean all files.
+ - \{"policy": "time", "time": int\}: Clean all files older than X days, where X is the value for "time".
+ - \{"policy": "size", "size": int, "sort_type": int\}: Clean files until recycle bin size reaches given "size" in MB, delete files by "sort_type".
+Possible values for "sort_type":
+ - 0: Delete bigger files first.
+ - 1: Delete older files first.
**_shares_** `list[str]`
-List of shares of which to clean the recycle bins. Pass only the name of the shares without slashes, e.g. `shares=['photo', 'web']`. Defaults to `[]`.
+List of shares of which to clean the recycle bins. Pass only the name of the shares without slashes, e.g. `shares=['photo', 'web']`. Defaults to [].
-**_policy (dict)_** ``
-Determines what files will be deleted from the recycle bins.
-Possible values are:
-- `{"policy": "clean_all"}` -> Clean all files
-- `{"policy": "time", "time": int}` -> Clean all files older than X days, days being possed as value for "time" key.
-- `{"policy": "size", "size": int , "sort_type": int}` -> Clean files until recycle bin size reaches given "size" in MB, delete files by "sort_type".
-Possible values for "sort_type" are:
-- `0` -> Delete bigger files first
-- `1` -> Delete older files first
-
-**_enable_** `bool, optional `
-Whether the task should be enabled upon creation. Defaults to `True`.
+**_enable_** `bool`
+Whether the task should be enabled upon modification. Defaults to `True`.
-**_run_frequently_** `bool, optional `
+**_run_frequently_** `bool`
Determines whether the task runs on a recurring schedule (True) or only on a specific date (False). Defaults to `True`.
-**_run_days_** `str, optional `
-Days of the week when the task should run, used if `run_frequently` is set to `True`, specified as a comma-separated list (e.g., '0,1,2' for Sunday, Monday, Tuesday). Defaults to `'0,1,2,3,4,5,6'` (Daily).
+**_run_days_** `str`
+Days of the week when the task should run, used if `run_frequently` is set to `True`, specified as a comma-separated list (e.g., '0,1,2' for Sunday, Monday, Tuesday). Defaults to `'0,1,2,3,4,5,6'`.
-**_run_date_** `str, optional `
-The specific date the task should run, used if `run_frequently` is set to `False`. Format: `yyyy/m/d` (no prefix zeros).
-Defaults to `""`.
+**_run_date_** `str`
+The specific date the task should run, used if `run_frequently` is set to `False`. Format: `yyyy/m/d` (no prefix zeros). Defaults to `""`.
-**_repeat_** `str, optional `
+**_repeat_** `str`
How often the task should repeat. Defaults to `'daily'`.
Possible values:
-- `daily` -> Only when 'run_frequently=True'
-- `weekly` -> Only when 'run_frequently=True'
-- `monthly` -> Works for both 'run_frequently=True' and 'run_frequently=False'
-- `no_repeat` -> Only when 'run_frequently=False'
-- `every_3_months` -> Only when 'run_frequently=False'
-- `every_6_months` -> Only when 'run_frequently=False'
-- `yearly` -> Only when 'run_frequently=False'
-
-**_monthly_week_** `list[str], optional `
-If `run_frequently=True` and `repeat='monthly'`, specifies the weeks the task should run, e.g., `['first', 'third']`.
-Defaults to `[]`.
-
-**_start_time_h_** `int, optional `
+ - `daily` (only when run_frequently=True)
+ - `weekly` (only when run_frequently=True)
+ - `monthly` (works for both run_frequently=True and run_frequently=False)
+ - `no_repeat` (only when run_frequently=False)
+ - `every_3_months` (only when run_frequently=False)
+ - `every_6_months` (only when run_frequently=False)
+ - `yearly` (only when run_frequently=False)
+
+**_monthly_week_** `list[str]`
+If `run_frequently=True` and `repeat='monthly'`, specifies the weeks the task should run, e.g., `['first', 'third']`. Defaults to [].
+
+**_start_time_h_** `int`
Hour at which the task should start. Defaults to `0`.
-**_start_time_m_** `int, optional `
+**_start_time_m_** `int`
Minute at which the task should start. Defaults to `0`.
-**_same_day_repeat_h_** `int, optional `
-Number of hours between repeated executions on the same day (run every x hours), if "Continue running within the same day" is desired.
-Set to `0` to disable same-day repeats. Defaults to `0` (disable same day repeat).
+**_same_day_repeat_h_** `int`
+Number of hours between repeated executions on the same day (run every x hours), if "Continue running within the same day" is desired.
+Set to `0` to disable same-day repeats. Defaults to `0`.
Possible values: `0..23`
:::info
@@ -1286,10 +1297,10 @@ Possible values: `0..23`
:::
-**_same_day_repeat_m_** `int, optional `
-Number of minutes between repeated executions on the same day (run every x minutes), if "Continue running within the same day" is desired.
-Set to `0` to disable same-day repeats. Defaults to `0` (disable same day repeat).
-Posible values: `1`, `5`, `10`, `15`, `20`, `30`
+**_same_day_repeat_m_** `int`
+Number of minutes between repeated executions on the same day (run every x minutes), if "Continue running within the same day" is desired.
+Set to `0` to disable same-day repeats. Defaults to `0`.
+Possible values: `1`, `5`, `10`, `15`, `20`, `30`
:::info
The args `same_day_repeat_h` and `same_day_repeat_m` cannot be used at the same time, if both are passed, `same_day_repeat_h` will be prioritized.
@@ -1297,7 +1308,7 @@ Posible values: `1`, `5`, `10`, `15`, `20`, `30`
:::
-**_same_day_repeat_until_** `int, optional `
+**_same_day_repeat_until_** `int`
Last hour of the day when the task can repeat. Defaults to `start_time_h`.
@@ -1305,7 +1316,7 @@ Last hour of the day when the task can repeat. Defaults to `start_time_h`.
#### Returns
`dict[str, object]`
-A dictionary with the id of the created task.
+A dictionary with the id of the modified task.
#### Example return
diff --git a/documentation/docs/apis/classes/universal_search.md b/documentation/docs/apis/classes/universal_search.md
index fb1b5917..328ab16a 100644
--- a/documentation/docs/apis/classes/universal_search.md
+++ b/documentation/docs/apis/classes/universal_search.md
@@ -14,9 +14,31 @@ This API is not documented yet.
:::
## Overview
+API wrapper for Synology Universal Search.
+Provides methods to perform keyword-based searches using Synology's Universal Search API.
## Methods
### `search`
+Search for files and metadata matching the given keyword.
+
+#### Internal API
+
+**_keyword_** `str`
+The search keyword.
+
+
+
+`dict[str, object] or str`
+Search results as a dictionary, or a string with error details.
+
+
diff --git a/documentation/docs/apis/classes/usb_copy.md b/documentation/docs/apis/classes/usb_copy.md
index 2ccbab77..06214515 100644
--- a/documentation/docs/apis/classes/usb_copy.md
+++ b/documentation/docs/apis/classes/usb_copy.md
@@ -9,17 +9,17 @@ title: ✅ USBCopy
# USBCopy
## Overview
-USB Copy Implementation.
+USB Copy API wrapper for Synology NAS.
-### Supported methods
+Methods
+-------
+**Getters** :
+ - Get package settings
+ - Get package logs
+ - Get task settings
- - **Getters** :
- - Get package settings
- - Get package logs
- - Get task settings
-
- - **Actions** :
- - Enable / Disable task
+**Actions** :
+ - Enable / Disable task
## Methods
### `get_package_settings`
Retrieve package settings.
@@ -32,21 +32,21 @@ Retrieve package settings.
#### Returns
`dict[str, object]`
-Parsed JSON into `dict`
+Parsed JSON into a dictionary.
**_offset_** `int`
-Defaults to `0`.
+Offset for logs. Defaults to 0.
**_limit_** `int`
-Defaults to `200`.
+Maximum number of logs to retrieve. Defaults to 200.
`dict[str, object]`
-Parsed response JSON into `dict`
+Parsed response JSON into a dictionary.
@@ -108,7 +108,7 @@ Parsed response JSON into `dict`
### `get_task_settings`
-Retrieve task settings
+Retrieve task settings.
#### Internal API
@@ -118,54 +118,54 @@ Retrieve task settings
#### Parameters
**_task_id_** `int`
-Task ID to retrieve info for
+Task ID to retrieve info for.
#### Returns
`dict[str, object]`
-Parsed response JSON into `dict`
+Parsed response JSON into a dictionary.
#### Example return
Click to expand
```python
-{
- "data" : {
- "task" : {
- "conflict_policy" : "rename",
- "copy_file_path" : "",
- "copy_strategy" : "versioning",
- "default_device_port" : "NA",
- "destination_path" : "[USB]",
- "eject_when_task_done" : True,
- "enable_rotation" : False,
- "error_code" : 0,
- "id" : 2,
- "is_default_task" : False,
- "is_ds_mounted" : False,
- "is_task_runnable" : False,
- "is_usb_mounted" : False,
- "latest_finish_time" : 1738341351,
- "max_version_count" : 256,
- "name" : "asdf",
- "next_run_time" : "N/A",
- "not_keep_dir_structure" : False,
- "remove_src_file" : False,
- "rename_photo_video" : False,
- "rotation_policy" : "oldest_version",
- "run_when_plug_in" : False,
- "schedule_id" : 13,
- "smart_create_date_dir" : False,
- "source_path" : "/music",
- "status" : "unmounted",
- "type" : "export_general"
- }
- },
- "success" : True
-}
+ {
+ "data": {
+ "task": {
+ "conflict_policy": "rename",
+ "copy_file_path": "",
+ "copy_strategy": "versioning",
+ "default_device_port": "NA",
+ "destination_path": "[USB]",
+ "eject_when_task_done": True,
+ "enable_rotation": False,
+ "error_code": 0,
+ "id": 2,
+ "is_default_task": False,
+ "is_ds_mounted": False,
+ "is_task_runnable": False,
+ "is_usb_mounted": False,
+ "latest_finish_time": 1738341351,
+ "max_version_count": 256,
+ "name": "asdf",
+ "next_run_time": "N/A",
+ "not_keep_dir_structure": False,
+ "remove_src_file": False,
+ "rename_photo_video": False,
+ "rotation_policy": "oldest_version",
+ "run_when_plug_in": False,
+ "schedule_id": 13,
+ "smart_create_date_dir": False,
+ "source_path": "/music",
+ "status": "unmounted",
+ "type": "export_general"
+ }
+ },
+ "success": True
+ }
```
@@ -175,7 +175,7 @@ Parsed response JSON into `dict`
### `toggle_task`
-Enable or disable USB Copy task
+Enable or disable a USB Copy task.
#### Internal API
@@ -188,23 +188,23 @@ Enable or disable USB Copy task
Task ID to apply the setting to.
**_enable_** `bool`
-Whether to enable (`True`) or disable (`False`) USB Copy. Defaults to `True`.
+Whether to enable (True) or disable (False) the USB Copy task. Defaults to True.
#### Returns
`dict[str, object]`
-Parsed response JSON into `dict`
+Parsed response JSON into a dictionary.
#### Example return
Click to expand
```python
-{
- "success": True
-}
+ {
+ "success": True
+ }
```
diff --git a/documentation/docs/apis/classes/virtualization.md b/documentation/docs/apis/classes/virtualization.md
index b1a462af..06f255c8 100644
--- a/documentation/docs/apis/classes/virtualization.md
+++ b/documentation/docs/apis/classes/virtualization.md
@@ -14,9 +14,45 @@ This API is not documented yet.
:::
## Overview
-
+API wrapper for Synology Virtual Machine Manager.
+
+Provides methods to manage tasks, networks, storage, hosts, VMs, and images.
+
+Parameters
+----------
+ip_address : str
+ IP address of the Synology NAS.
+port : str
+ Port number to connect to.
+username : str
+ DSM username.
+password : str
+ DSM password.
+secure : bool, optional
+ Use HTTPS if True. Default is False.
+cert_verify : bool, optional
+ Verify SSL certificate if True. Default is False.
+dsm_version : int, optional
+ DSM version. Default is 7.
+debug : bool, optional
+ Enable debug mode. Default is True.
+otp_code : str, optional
+ One-time password for 2FA, if required.
## Methods
### `get_task_list`
+Get the list of virtualization tasks.
+
+#### Internal API
+
+`SYNO.Virtualization.API.Task.Info`
+
+
+#### Returns
+
+`list of str`
+List of task IDs.
+
+
@@ -24,6 +60,26 @@ This API is not documented yet.
### `clear_task`
+Clear a specific task by its ID.
+
+#### Internal API
+
+`SYNO.Virtualization.API.Task.Info`
+
+
+#### Parameters
+
+**_taskid_** `str`
+Task ID to clear.
+
+
+
+#### Returns
+
+`dict[str, object] or str`
+Result of the clear operation or error message.
+
+
@@ -31,6 +87,26 @@ This API is not documented yet.
### `get_task_info`
+Get information about a specific task.
+
+#### Internal API
+
+`SYNO.Virtualization.API.Task.Info`
+
+
+#### Parameters
+
+**_taskid_** `str`
+Task ID to retrieve information for.
+
+
+
+#### Returns
+
+`dict[str, object] or str`
+Task information or error message.
+
+
@@ -38,6 +114,19 @@ This API is not documented yet.
### `get_network_group_list`
+Get the list of network groups.
+
+#### Internal API
+
+`SYNO.Virtualization.API.Network`
+
+
+#### Returns
+
+`list of dict`
+List of network group information.
+
+
@@ -45,6 +134,19 @@ This API is not documented yet.
### `get_storage_operation`
+Get the list of storage operations.
+
+#### Internal API
+
+`SYNO.Virtualization.API.Storage`
+
+
+#### Returns
+
+`list of str`
+List of storage operation information.
+
+
@@ -52,6 +154,19 @@ This API is not documented yet.
### `get_host_operation`
+Get the list of host operations.
+
+#### Internal API
+
+`SYNO.Virtualization.API.Host`
+
+
+#### Returns
+
+`list of str`
+List of host operation information.
+
+
@@ -59,6 +174,26 @@ This API is not documented yet.
### `get_vm_operation`
+Get the list of virtual machines.
+
+#### Internal API
+
+`SYNO.Virtualization.API.Guest`
+
+
+#### Parameters
+
+**_additional_** `bool`
+Whether to include additional information. Default is False.
+
+
+
+#### Returns
+
+`list of dict`
+List of VM information.
+
+
@@ -66,6 +201,32 @@ This API is not documented yet.
### `get_specific_vm_info`
+Get information about a specific virtual machine.
+
+#### Internal API
+
+`SYNO.Virtualization.API.Guest`
+
+
+#### Parameters
+
+**_additional_** `str or list of str`
+Additional fields to include.
+
+**_guest_id_** `str`
+Guest VM ID.
+
+**_guest_name_** `str`
+Guest VM name.
+
+
+
+#### Returns
+
+`dict[str, object] or str`
+VM information or error message.
+
+
@@ -73,6 +234,44 @@ This API is not documented yet.
### `set_vm_property`
+Set properties for a virtual machine.
+
+#### Internal API
+
+`SYNO.Virtualization.API.Guest`
+
+
+#### Parameters
+
+**_guest_id_** `str`
+Guest VM ID.
+
+**_guest_name_** `str`
+Guest VM name.
+
+**_autorun_** `int`
+Autorun setting (0: off, 1: last state, 2: on).
+
+**_description_** `str`
+VM description.
+
+**_new_guest_name_** `str`
+New VM name.
+
+**_vcpu_num_** `int`
+Number of virtual CPUs.
+
+**_vram_size_** `int`
+RAM size in MB.
+
+
+
+#### Returns
+
+`dict[str, object] or str`
+Result of the set operation or error message.
+
+
@@ -80,6 +279,29 @@ This API is not documented yet.
### `delete_vm`
+Delete a virtual machine.
+
+#### Internal API
+
+`SYNO.Virtualization.API.Guest`
+
+
+#### Parameters
+
+**_guest_id_** `str`
+Guest VM ID.
+
+**_guest_name_** `str`
+Guest VM name.
+
+
+
+#### Returns
+
+`dict[str, object] or str`
+Result of the delete operation or error message.
+
+
@@ -87,6 +309,35 @@ This API is not documented yet.
### `vm_power_on`
+Power on a virtual machine.
+
+#### Internal API
+
+`SYNO.Virtualization.API.Guest.Action`
+
+
+#### Parameters
+
+**_guest_id_** `str`
+Guest VM ID.
+
+**_guest_name_** `str`
+Guest VM name.
+
+**_host_id_** `str`
+Host ID.
+
+**_host_name_** `str`
+Host name.
+
+
+
+#### Returns
+
+`dict[str, object] or str`
+Result of the power on operation or error message.
+
+
@@ -94,6 +345,29 @@ This API is not documented yet.
### `vm_force_power_off`
+Force power off a virtual machine.
+
+#### Internal API
+
+`SYNO.Virtualization.API.Guest.Action`
+
+
+#### Parameters
+
+**_guest_id_** `str`
+Guest VM ID.
+
+**_guest_name_** `str`
+Guest VM name.
+
+
+
+#### Returns
+
+`dict[str, object] or str`
+Result of the power off operation or error message.
+
+
@@ -101,6 +375,29 @@ This API is not documented yet.
### `vm_shut_down`
+Shut down a virtual machine.
+
+#### Internal API
+
+`SYNO.Virtualization.API.Guest.Action`
+
+
+#### Parameters
+
+**_guest_id_** `str`
+Guest VM ID.
+
+**_guest_name_** `str`
+Guest VM name.
+
+
+
+#### Returns
+
+`dict[str, object] or str`
+Result of the shutdown operation or error message.
+
+
@@ -108,6 +405,19 @@ This API is not documented yet.
### `get_images_list`
+Get the list of VM images.
+
+#### Internal API
+
+`SYNO.Virtualization.API.Guest.Image`
+
+
+#### Returns
+
+`dict[str, object]`
+Dictionary containing image information.
+
+
@@ -115,6 +425,29 @@ This API is not documented yet.
### `delete_image`
+Delete a VM image.
+
+#### Internal API
+
+`SYNO.Virtualization.API.Guest.Image`
+
+
+#### Parameters
+
+**_image_id_** `str`
+Image ID.
+
+**_image_name_** `str`
+Image name.
+
+
+
+#### Returns
+
+`dict[str, object] or str`
+Result of the delete operation or error message.
+
+
@@ -122,6 +455,41 @@ This API is not documented yet.
### `create_image`
+Create a new VM image.
+
+#### Internal API
+
+`SYNO.Virtualization.API.Guest.Image`
+
+
+#### Parameters
+
+**_auto_clean_task_** `bool`
+Whether to auto-clean the task after creation. Default is True.
+
+**_storage_names_** `str`
+Storage names.
+
+**_storage_ids_** `str`
+Storage IDs.
+
+**_type_** `str`
+Image type ('disk', 'vdsm', or 'iso').
+
+**_ds_file_path_** `str`
+File path (should begin with a shared folder).
+
+**_image_name_** `str`
+Name of the image.
+
+
+
+#### Returns
+
+`dict[str, object] or str`
+Result of the create operation or error message.
+
+
diff --git a/documentation/docs/apis/classes/vpn.md b/documentation/docs/apis/classes/vpn.md
index a0ca683e..33872cb0 100644
--- a/documentation/docs/apis/classes/vpn.md
+++ b/documentation/docs/apis/classes/vpn.md
@@ -14,9 +14,25 @@ This API is not documented yet.
:::
## Overview
+API wrapper for Synology VPN Server.
+Provides methods to retrieve VPN settings, active connections, logs, network interfaces,
+security autoblock settings, permissions, and VPN protocol-specific settings.
## Methods
### `settings_list`
+Retrieve VPN server settings.
+
+#### Internal API
+
+`SYNO.VPNServer.Settings.Config`
+
+
+#### Returns
+
+`dict[str, object] or str`
+VPN server settings as a dictionary, or an error message as a string.
+
+
@@ -24,6 +40,35 @@ This API is not documented yet.
### `active_connections_list`
+Retrieve a list of active VPN connections.
+
+#### Internal API
+
+`SYNO.VPNServer.Management.Connection`
+
+
+#### Parameters
+
+**_sort_** `str`
+Field to sort by. Default is 'login_time'.
+
+**_sort_dir_** `str`
+Sort direction ('ASC' or 'DESC'). Default is 'DESC'.
+
+**_start_** `int`
+Pagination start index. Default is 0.
+
+**_limit_** `int`
+Maximum number of results to return. Default is 100.
+
+
+
+#### Returns
+
+`dict[str, object] or str`
+Active connections as a dictionary, or an error message as a string.
+
+
@@ -31,6 +76,32 @@ This API is not documented yet.
### `log_list`
+Retrieve VPN server logs.
+
+#### Internal API
+
+`SYNO.VPNServer.Management.Log`
+
+
+#### Parameters
+
+**_start_** `int`
+Pagination start index. Default is 0.
+
+**_limit_** `int`
+Maximum number of logs to return. Default is 50.
+
+**_prtltype_** `int`
+Protocol type filter. Default is 0 (all).
+
+
+
+#### Returns
+
+`dict[str, object] or str`
+Logs as a dictionary, or an error message as a string.
+
+
@@ -38,6 +109,19 @@ This API is not documented yet.
### `network_interface_setting`
+Retrieve VPN network interface settings.
+
+#### Internal API
+
+`SYNO.VPNServer.Management.Interface`
+
+
+#### Returns
+
+`dict[str, object] or str`
+Network interface settings as a dictionary, or an error message as a string.
+
+
@@ -45,6 +129,19 @@ This API is not documented yet.
### `security_autoblock_setting`
+Retrieve security autoblock settings.
+
+#### Internal API
+
+`SYNO.Core.Security.AutoBlock`
+
+
+#### Returns
+
+`dict[str, object] or str`
+Autoblock settings as a dictionary, or an error message as a string.
+
+
@@ -52,6 +149,29 @@ This API is not documented yet.
### `permission_setting`
+Retrieve VPN permission settings.
+
+#### Internal API
+
+`SYNO.VPNServer.Management.Account`
+
+
+#### Parameters
+
+**_start_** `int`
+Pagination start index. Default is 0.
+
+**_limit_** `int`
+Maximum number of results to return. Default is 100.
+
+
+
+#### Returns
+
+`dict[str, object] or str`
+Permission settings as a dictionary, or an error message as a string.
+
+
@@ -59,6 +179,19 @@ This API is not documented yet.
### `pptp_settings_info`
+Retrieve PPTP VPN settings.
+
+#### Internal API
+
+`SYNO.VPNServer.Settings.Config`
+
+
+#### Returns
+
+`dict[str, object] or str`
+PPTP settings as a dictionary, or an error message as a string.
+
+
@@ -66,6 +199,19 @@ This API is not documented yet.
### `openvpn_settings_info`
+Retrieve OpenVPN settings.
+
+#### Internal API
+
+`SYNO.VPNServer.Settings.Config`
+
+
+#### Returns
+
+`dict[str, object] or str`
+OpenVPN settings as a dictionary, or an error message as a string.
+
+
@@ -73,6 +219,46 @@ This API is not documented yet.
### `l2tp_settings_info`
+Retrieve L2TP VPN settings.
+
+#### Internal API
+
+`SYNO.VPNServer.Settings.Config`
+
+
+#### Returns
+
+`dict[str, object] or str`
+L2TP settings as a dictionary, or an error message as a string.
+
+
+
+
+
+---
+
+
+### `openvpn_export_configuration`
+Download the OpenVPN configuration as a zip file or bytes.
+
+#### Internal API
+
+`SYNO.VPNServer.Settings.Certificate`
+
+
+#### Parameters
+
+**_as_zip_file_** `bool`
+If True, return a ZipFile object. If False, return bytes. Default is False.
+
+
+
+#### Returns
+
+`bytes or ZipFile`
+The OpenVPN configuration file as bytes, or a ZipFile object if `as_zip_file` is True.
+
+
diff --git a/documentation/docs/apis/readme.md b/documentation/docs/apis/readme.md
index c51368e9..a8630c4a 100644
--- a/documentation/docs/apis/readme.md
+++ b/documentation/docs/apis/readme.md
@@ -63,24 +63,28 @@ At the moment there are quite a few APIs implemented. They could be totally or p
### [Share](./apis/classes/core_share)
- `SYNO.Core.Share`
+- `SYNO.Core.Share.Crypto`
- `SYNO.Core.Share.Permission`
- `SYNO.Core.Share.KeyManager.Store`
- `SYNO.Core.Share.KeyManager.AutoKey`
### [SharePermission](./apis/classes/core_share)
- `SYNO.Core.Share`
+- `SYNO.Core.Share.Crypto`
- `SYNO.Core.Share.Permission`
- `SYNO.Core.Share.KeyManager.Store`
- `SYNO.Core.Share.KeyManager.AutoKey`
### [KeyManagerStore](./apis/classes/core_share)
- `SYNO.Core.Share`
+- `SYNO.Core.Share.Crypto`
- `SYNO.Core.Share.Permission`
- `SYNO.Core.Share.KeyManager.Store`
- `SYNO.Core.Share.KeyManager.AutoKey`
### [KeyManagerAutoKey](./apis/classes/core_share)
- `SYNO.Core.Share`
+- `SYNO.Core.Share.Crypto`
- `SYNO.Core.Share.Permission`
- `SYNO.Core.Share.KeyManager.Store`
- `SYNO.Core.Share.KeyManager.AutoKey`
@@ -148,7 +152,6 @@ At the moment there are quite a few APIs implemented. They could be totally or p
- `SYNO.Core.ExternalDevice.Storage.eSATA`
- `SYNO.Finder.FileIndexing.Status`
- `SYNO.Core.CMS.Info`
-- `SYNO.Core.Service.PortInfo`
- `SYNO.Core.PortForwarding.Rules`
- `SYNO.Core.PortForwarding.RouterConf`
- `SYNO.Core.Polling.Data`
@@ -215,12 +218,17 @@ At the moment there are quite a few APIs implemented. They could be totally or p
- `SYNO.Docker.Image`
- `SYNO.Docker.Registry`
- `SYNO.Docker.Network`
+- `SYNO.Docker.Project`
+- `SYNO.Docker.Container.Profile`
+- `SYNO.Docker.Container.Log`
### [DownloadStation](./apis/classes/downloadstation)
- `SYNO.DownloadStation.Info`
- `SYNO.DownloadStation.Schedule`
- `SYNO.DownloadStation{DOWNLOAD_ST_VERSION}.Task`
- `SYNO.DownloadStation2.Task.Source`
+- `SYNO.DownloadStation{DOWNLOAD_ST_VERSION}.Task.List`
+- `SYNO.DownloadStation{DOWNLOAD_ST_VERSION}.Task.List.Polling`
- `SYNO.DownloadStation.Statistic`
- `SYNO.DownloadStation.RSS.Site`
- `SYNO.DownloadStation{DOWNLOAD_ST_VERSION}.RSS.Feed`
diff --git a/documentation/package-lock.json b/documentation/package-lock.json
index bf0941f1..f1dc55c4 100644
--- a/documentation/package-lock.json
+++ b/documentation/package-lock.json
@@ -167,6 +167,7 @@
"resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-5.20.0.tgz",
"integrity": "sha512-KL1zWTzrlN4MSiaK1ea560iCA/UewMbS4ZsLQRPoDTWyrbDKVbztkPwwv764LAqgXk0fvkNZvJ3IelcK7DqhjQ==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"@algolia/client-common": "5.20.0",
"@algolia/requester-browser-xhr": "5.20.0",
@@ -305,6 +306,7 @@
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.26.7.tgz",
"integrity": "sha512-SRijHmF0PSPgLIBYlWnG0hyeJLwXE2CgpsXaMOrtt2yp9/86ALw6oUlj9KYuZ0JN07T4eBMVIW4li/9S1j2BGA==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"@ampproject/remapping": "^2.2.0",
"@babel/code-frame": "^7.26.2",
@@ -2070,6 +2072,7 @@
}
],
"license": "MIT",
+ "peer": true,
"engines": {
"node": ">=18"
},
@@ -2092,6 +2095,7 @@
}
],
"license": "MIT",
+ "peer": true,
"engines": {
"node": ">=18"
}
@@ -2172,6 +2176,7 @@
"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz",
"integrity": "sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"cssesc": "^3.0.0",
"util-deprecate": "^1.0.2"
@@ -2506,6 +2511,7 @@
"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz",
"integrity": "sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"cssesc": "^3.0.0",
"util-deprecate": "^1.0.2"
@@ -3335,6 +3341,7 @@
"resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-docs/-/plugin-content-docs-3.7.0.tgz",
"integrity": "sha512-GXg5V7kC9FZE4FkUZA8oo/NrlRb06UwuICzI6tcbzj0+TVgjq/mpUXXzSgKzMS82YByi4dY2Q808njcBCyy6tQ==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"@docusaurus/core": "3.7.0",
"@docusaurus/logger": "3.7.0",
@@ -3951,6 +3958,7 @@
"resolved": "https://registry.npmjs.org/@mdx-js/react/-/react-3.1.0.tgz",
"integrity": "sha512-QjHtSaoameoalGnKDT3FoIl4+9RwyTmo9ZJGBdLOks/YOiWHoRDI3PUwEzOE7kEmGcV3AFcp9K6dYu9rEuKLAQ==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"@types/mdx": "^2.0.0"
},
@@ -4109,6 +4117,7 @@
"resolved": "https://registry.npmjs.org/@octokit/core/-/core-6.1.3.tgz",
"integrity": "sha512-z+j7DixNnfpdToYsOutStDgeRzJSMnbj8T1C/oQjB6Aa+kRfNjs/Fn7W6c8bmlt6mfy3FkgeKBRnDjxQow5dow==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"@octokit/auth-token": "^5.0.0",
"@octokit/graphql": "^8.1.2",
@@ -4595,6 +4604,7 @@
"resolved": "https://registry.npmjs.org/@svgr/core/-/core-8.1.0.tgz",
"integrity": "sha512-8QqtOQT5ACVlmsvKOJNEaWmRPmcojMOzCz4Hs2BGG/toAp/K38LcsMRyLp349glq5AzJbCEeimEoxaX6v/fLrA==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/core": "^7.21.3",
"@svgr/babel-preset": "8.1.0",
@@ -5005,6 +5015,7 @@
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.18.tgz",
"integrity": "sha512-t4yC+vtgnkYjNSKlFx1jkAhH8LgTo2N/7Qvi83kdEaUtMDiwpbLAktKDaAMlRcJ5eSxZkH74eEGt1ky31d7kfQ==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"@types/prop-types": "*",
"csstype": "^3.0.2"
@@ -5338,6 +5349,7 @@
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz",
"integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==",
"license": "MIT",
+ "peer": true,
"bin": {
"acorn": "bin/acorn"
},
@@ -5393,6 +5405,7 @@
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz",
"integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"fast-deep-equal": "^3.1.3",
"fast-uri": "^3.0.1",
@@ -5438,6 +5451,7 @@
"resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-5.20.0.tgz",
"integrity": "sha512-groO71Fvi5SWpxjI9Ia+chy0QBwT61mg6yxJV27f5YFf+Mw+STT75K6SHySpP8Co5LsCrtsbCH5dJZSRtkSKaQ==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"@algolia/client-abtesting": "5.20.0",
"@algolia/client-analytics": "5.20.0",
@@ -5912,6 +5926,7 @@
}
],
"license": "MIT",
+ "peer": true,
"dependencies": {
"caniuse-lite": "^1.0.30001688",
"electron-to-chromium": "^1.5.73",
@@ -6434,16 +6449,16 @@
}
},
"node_modules/compression": {
- "version": "1.7.5",
- "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.5.tgz",
- "integrity": "sha512-bQJ0YRck5ak3LgtnpKkiabX5pNF7tMUh1BSy2ZBOTh0Dim0BUu6aPPwByIns6/A5Prh8PufSPerMDUklpzes2Q==",
+ "version": "1.8.1",
+ "resolved": "https://registry.npmjs.org/compression/-/compression-1.8.1.tgz",
+ "integrity": "sha512-9mAqGPHLakhCLeNyxPkK4xVo746zQ/czLH1Ky+vkitMnWfWZps8r0qXuwhwizagCRttsL4lfG4pIOvaWLpAP0w==",
"license": "MIT",
"dependencies": {
"bytes": "3.1.2",
"compressible": "~2.0.18",
"debug": "2.6.9",
"negotiator": "~0.6.4",
- "on-headers": "~1.0.2",
+ "on-headers": "~1.1.0",
"safe-buffer": "5.2.1",
"vary": "~1.1.2"
},
@@ -6858,6 +6873,7 @@
"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz",
"integrity": "sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"cssesc": "^3.0.0",
"util-deprecate": "^1.0.2"
@@ -8016,39 +8032,39 @@
}
},
"node_modules/express": {
- "version": "4.21.2",
- "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz",
- "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==",
+ "version": "4.22.1",
+ "resolved": "https://registry.npmjs.org/express/-/express-4.22.1.tgz",
+ "integrity": "sha512-F2X8g9P1X7uCPZMA3MVf9wcTqlyNp7IhH5qPCI0izhaOIYXaW9L535tGA3qmjRzpH+bZczqq7hVKxTR4NWnu+g==",
"license": "MIT",
"dependencies": {
"accepts": "~1.3.8",
"array-flatten": "1.1.1",
- "body-parser": "1.20.3",
- "content-disposition": "0.5.4",
+ "body-parser": "~1.20.3",
+ "content-disposition": "~0.5.4",
"content-type": "~1.0.4",
- "cookie": "0.7.1",
- "cookie-signature": "1.0.6",
+ "cookie": "~0.7.1",
+ "cookie-signature": "~1.0.6",
"debug": "2.6.9",
"depd": "2.0.0",
"encodeurl": "~2.0.0",
"escape-html": "~1.0.3",
"etag": "~1.8.1",
- "finalhandler": "1.3.1",
- "fresh": "0.5.2",
- "http-errors": "2.0.0",
+ "finalhandler": "~1.3.1",
+ "fresh": "~0.5.2",
+ "http-errors": "~2.0.0",
"merge-descriptors": "1.0.3",
"methods": "~1.1.2",
- "on-finished": "2.4.1",
+ "on-finished": "~2.4.1",
"parseurl": "~1.3.3",
- "path-to-regexp": "0.1.12",
+ "path-to-regexp": "~0.1.12",
"proxy-addr": "~2.0.7",
- "qs": "6.13.0",
+ "qs": "~6.14.0",
"range-parser": "~1.2.1",
"safe-buffer": "5.2.1",
- "send": "0.19.0",
- "serve-static": "1.16.2",
+ "send": "~0.19.0",
+ "serve-static": "~1.16.2",
"setprototypeof": "1.2.0",
- "statuses": "2.0.1",
+ "statuses": "~2.0.1",
"type-is": "~1.6.18",
"utils-merge": "1.0.1",
"vary": "~1.1.2"
@@ -8094,6 +8110,21 @@
"integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==",
"license": "MIT"
},
+ "node_modules/express/node_modules/qs": {
+ "version": "6.14.0",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz",
+ "integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==",
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "side-channel": "^1.1.0"
+ },
+ "engines": {
+ "node": ">=0.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/express/node_modules/range-parser": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
@@ -8276,6 +8307,7 @@
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"fast-deep-equal": "^3.1.1",
"fast-json-stable-stringify": "^2.0.0",
@@ -8479,6 +8511,7 @@
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"fast-deep-equal": "^3.1.1",
"fast-json-stable-stringify": "^2.0.0",
@@ -8967,9 +9000,9 @@
}
},
"node_modules/gray-matter/node_modules/js-yaml": {
- "version": "3.14.1",
- "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
- "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
+ "version": "3.14.2",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz",
+ "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==",
"license": "MIT",
"dependencies": {
"argparse": "^1.0.7",
@@ -10111,9 +10144,9 @@
"license": "MIT"
},
"node_modules/js-yaml": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
- "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz",
+ "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==",
"license": "MIT",
"dependencies": {
"argparse": "^2.0.1"
@@ -10748,9 +10781,9 @@
}
},
"node_modules/mdast-util-to-hast": {
- "version": "13.2.0",
- "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.2.0.tgz",
- "integrity": "sha512-QGYKEuUsYT9ykKBCMOEDLsU5JRObWQusAolFMeko/tYPufNkRffBAQjIE+99jbA87xv6FgmjLtwjh9wBWajwAA==",
+ "version": "13.2.1",
+ "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.2.1.tgz",
+ "integrity": "sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==",
"license": "MIT",
"dependencies": {
"@types/hast": "^3.0.0",
@@ -12890,9 +12923,9 @@
}
},
"node_modules/node-forge": {
- "version": "1.3.1",
- "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz",
- "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==",
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.2.tgz",
+ "integrity": "sha512-6xKiQ+cph9KImrRh0VsjH2d8/GXA4FIMlgU4B757iI1ApvcyA9VlouP0yZJha01V+huImO+kKMU7ih+2+E14fw==",
"license": "(BSD-3-Clause OR GPL-2.0)",
"engines": {
"node": ">= 6.13.0"
@@ -12989,6 +13022,7 @@
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"fast-deep-equal": "^3.1.1",
"fast-json-stable-stringify": "^2.0.0",
@@ -13123,9 +13157,9 @@
}
},
"node_modules/on-headers": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz",
- "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==",
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.1.0.tgz",
+ "integrity": "sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A==",
"license": "MIT",
"engines": {
"node": ">= 0.8"
@@ -13572,6 +13606,7 @@
}
],
"license": "MIT",
+ "peer": true,
"dependencies": {
"nanoid": "^3.3.8",
"picocolors": "^1.1.1",
@@ -14475,6 +14510,7 @@
"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz",
"integrity": "sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"cssesc": "^3.0.0",
"util-deprecate": "^1.0.2"
@@ -15268,6 +15304,7 @@
"resolved": "https://registry.npmjs.org/react/-/react-19.0.0.tgz",
"integrity": "sha512-V8AVnmPIICiWpGfm6GLzCR/W5FXLchHop40W4nXBmdlEceh16rCN8O8LNWm5bh5XUX91fh7KpA+W0TgMKmgTpQ==",
"license": "MIT",
+ "peer": true,
"engines": {
"node": ">=0.10.0"
}
@@ -15416,6 +15453,7 @@
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.0.0.tgz",
"integrity": "sha512-4GV5sHFG0e/0AD4X+ySy6UJd3jVl1iNsNHdpad0qhABJ11twS3TTBnseqsKurKcsNqCEFeGL3uLpVChpIO3QfQ==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"scheduler": "^0.25.0"
},
@@ -15474,6 +15512,7 @@
"resolved": "https://registry.npmjs.org/@docusaurus/react-loadable/-/react-loadable-6.0.0.tgz",
"integrity": "sha512-YMMxTUQV/QFSnbgrP3tjDzLHRg7vsbMn8e9HAa8o/1iXoiomo48b7sk/kkmWEuWNDPJVlKSJRB6Y2fHqdJk+SQ==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"@types/react": "*"
},
@@ -15502,6 +15541,7 @@
"resolved": "https://registry.npmjs.org/react-router/-/react-router-5.3.4.tgz",
"integrity": "sha512-Ys9K+ppnJah3QuaRiLxk+jDWOR1MekYQrlytiXxC1RyfbdsZkS5pvKAzCCr031xHixZwpnsYNT5xysdFHQaYsA==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/runtime": "^7.12.13",
"history": "^4.9.0",
@@ -17340,6 +17380,7 @@
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz",
"integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==",
"license": "Apache-2.0",
+ "peer": true,
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
@@ -17719,6 +17760,7 @@
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"fast-deep-equal": "^3.1.1",
"fast-json-stable-stringify": "^2.0.0",
@@ -17917,6 +17959,7 @@
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.97.1.tgz",
"integrity": "sha512-EksG6gFY3L1eFMROS/7Wzgrii5mBAFe4rIr3r2BTfo7bcc+DWwFZ4OJ/miOuHJO/A85HwyI4eQ0F6IKXesO7Fg==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"@types/eslint-scope": "^3.7.7",
"@types/estree": "^1.0.6",
@@ -18154,6 +18197,7 @@
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"fast-deep-equal": "^3.1.1",
"fast-json-stable-stringify": "^2.0.0",
diff --git a/requirements-dev.txt b/requirements-dev.txt
index 24c1bd4c..8be12690 100644
Binary files a/requirements-dev.txt and b/requirements-dev.txt differ
diff --git a/requirements.txt b/requirements.txt
index 9f1d1105..f93c7126 100644
Binary files a/requirements.txt and b/requirements.txt differ
diff --git a/setup.cfg b/setup.cfg
index 2070cac7..f8e32896 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -1,5 +1,5 @@
[tool:numpydoc_validation]
; to ignore some check add them after for example: checks = all,GL02, GL08
-checks = all,SA01,ES01,EX01
+checks = all,SA01,ES01,EX01,RT04,PR09
exclude = \.undocumented_method$,\.__repr__$
diff --git a/setup.py b/setup.py
index 3c2703c0..d3542965 100644
--- a/setup.py
+++ b/setup.py
@@ -8,14 +8,16 @@
setup(
name='synology-api',
- version='0.8.1',
+ version='0.8.2',
packages=find_packages(exclude=['tests*']),
license='MIT',
description='Python Synology API Wrapper',
long_description=long_description,
long_description_content_type='text/markdown',
install_requires=['requests', 'urllib3', 'setuptools',
- 'requests_toolbelt', 'tqdm', 'cryptography', 'treelib'],
+ 'requests_toolbelt', 'tqdm', 'cryptography', 'treelib',
+ 'noiseprotocol',
+ ],
url='https://github.com/N4S4/synology-api',
author='Renato Visaggio',
author_email='synology.python.api@gmail.com'
diff --git a/synology_api/DSM/ControlPanel/ApplicationPrivileges.py b/synology_api/DSM/ControlPanel/ApplicationPrivileges.py
new file mode 100644
index 00000000..9224f438
--- /dev/null
+++ b/synology_api/DSM/ControlPanel/ApplicationPrivileges.py
@@ -0,0 +1,304 @@
+"""
+Manage application privileges.
+"""
+
+from synology_api import base_api
+import json
+
+
+class ApplicationPrivileges(base_api.BaseApi):
+ """
+ Manage application privileges.
+ """
+
+ def list_all(self, offset: int = 0, limit: int = 20) -> dict:
+ """
+ List applications privileges.
+
+ Parameters
+ ----------
+ offset : int, optional
+ Offset in the application list. Defaults to `0`
+ limit : int, optional
+ Limit the len of the returned list. Defaults to `20`
+
+ Returns
+ -------
+ dict
+ List of applications privileges.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "applications": [
+ {
+ "app_id": "SYNO.AFP",
+ "grant_by_default": true,
+ "grant_type": [
+ "local",
+ "domain",
+ "ldap"
+ ],
+ "isInternal": true,
+ "name": "AFP",
+ "service_type": "modules/LegacyApps",
+ "supportIP": true
+ },
+ {
+ "app_id": "SYNO.Desktop",
+ "grant_by_default": true,
+ "grant_type": [
+ "local",
+ "domain",
+ "ldap"
+ ],
+ "isInternal": true,
+ "name": "DSM",
+ "service_type": "modules/LegacyApps",
+ "supportIP": true
+ }
+ ],
+ "offset": 0,
+ "total": 2
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.AppPriv.App'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'list',
+ 'offset': offset,
+ 'limit': limit
+ }
+
+ return self.request_data(api_name, api_path, req_param)
+
+ def list_entities(self, app_id: str, type: str = "local", filter_type: str = "all", rule_type: str = "user", offset: int = 0, limit: int = 50) -> dict:
+ """
+ List entities of the specify app_id.
+
+ Parameters
+ ----------
+ app_id : str
+ Application ID
+ type : str, optional
+ Type to filter for rule_type. Defaults to `"local"`
+ Example: for rule_type = "user", type = "local"
+ All known values are: `["local"]`
+ filter_type : str, optional
+ Filter actual rules. Defaults to `"all"`
+ All known values are: `["all", "allow", "deny", "any", "custom"]`
+ rule_type : str, optional
+ Type of the rule. Defaults to `"user"`
+ All known values are: `["user", "group"]`
+ offset : int, optional
+ Offset in entity list. Defaults to `0`
+ limit : int, optional
+ Limit the len of the returned list. Defaults to `50`
+
+ Returns
+ -------
+ dict
+ Return list of entity available.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "offset": 0,
+ "total": 3,
+ "users": [
+ {
+ "name": "admin"
+ },
+ {
+ "name": "guest"
+ },
+ {
+ "name": "test_api"
+ }
+ ]
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.AppPriv'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'list',
+ 'action': 'list',
+ 'offset': offset,
+ 'limit': limit,
+ 'type': type,
+ 'app_id': app_id,
+ 'filter_type': filter_type,
+ 'rule_type': rule_type
+ }
+
+ return self.request_data(api_name, api_path, req_param)
+
+ def list_app_rules(self, app_id: str) -> dict:
+ """
+ Retrieve application rules.
+
+ Parameters
+ ----------
+ app_id : str
+ Application ID
+
+ Returns
+ -------
+ dict
+ List of rules.
+
+ Examples
+ --------
+ ```json
+ "data": {
+ "rules": [
+ {
+ "allow_ip": [
+ "0.0.0.0"
+ ],
+ "app_id": "SYNO.AFP",
+ "deny_ip": [],
+ "entity_name": "everyone",
+ "entity_type": "everyone"
+ },
+ {
+ "allow_ip": [
+ "0.0.0.0"
+ ],
+ "app_id": "SYNO.AFP",
+ "deny_ip": [],
+ "entity_name": "test_api",
+ "entity_type": "user"
+ },
+ {
+ "allow_ip": [
+ "0.0.0.0"
+ ],
+ "app_id": "SYNO.AFP",
+ "deny_ip": [],
+ "entity_name": "test_group",
+ "entity_type": "group"
+ }
+ ]
+ },
+ "success": true
+ }
+ ```
+ """
+
+ api_name = 'SYNO.Core.AppPriv.Rule'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'list',
+ 'app_id': app_id
+ }
+
+ return self.request_data(api_name, api_path, req_param)
+
+ def set_app_rules(self, app_id: str, rules: list) -> dict:
+ """
+ Set application rules.
+
+ Parameters
+ ----------
+ app_id : str
+ Application ID
+ rules : list
+ List of rules, a rule is a dict with the following keys:
+ ```json
+ {
+ "entity_type":"user",
+ "entity_name":"test_api",
+ "app_id":"SYNO.AFP",
+ "allow_ip":["0.0.0.0"],
+ "deny_ip":[]
+ }
+ ```
+
+ Returns
+ -------
+ dict
+ Success.
+
+ Examples
+ --------
+ ```json
+ {
+ "success": true
+ }
+ ```
+ """
+
+ api_name = 'SYNO.Core.AppPriv.Rule'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'set',
+ 'app_id': app_id,
+ 'rules': json.dumps(rules)
+ }
+
+ return self.request_data(api_name, api_path, req_param)
+
+ def delete_app_rules(self, app_id: str, rules: list) -> dict:
+ """
+ Delete application rules.
+
+ Parameters
+ ----------
+ app_id : str
+ Application ID
+ rules : list
+ List of rules, a rule is a dict with the following keys:
+ ```json
+ {
+ "entity_type":"user",
+ "entity_name":"test_api",
+ "app_id":"SYNO.AFP",
+ "allow_ip":["0.0.0.0"],
+ "deny_ip":[]
+ }
+ ```
+
+ Returns
+ -------
+ dict
+ Success.
+
+ Examples
+ --------
+ ```json
+ {
+ "success": true
+ }
+ ```
+ """
+
+ api_name = 'SYNO.Core.AppPriv.Rule'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'delete',
+ 'app_id': app_id,
+ 'rules': json.dumps(rules)
+ }
+
+ return self.request_data(api_name, api_path, req_param)
diff --git a/synology_api/DSM/ControlPanel/DomainLDAP.py b/synology_api/DSM/ControlPanel/DomainLDAP.py
new file mode 100644
index 00000000..3edf8ffd
--- /dev/null
+++ b/synology_api/DSM/ControlPanel/DomainLDAP.py
@@ -0,0 +1,262 @@
+"""
+Manage Domain and LDAP settings.
+"""
+
+from synology_api import base_api
+
+
+class DomainLDAP(base_api.BaseApi):
+ """
+ Manage Domain and LDAP settings.
+ """
+
+ def get_ldap_info(self) -> dict:
+ """
+ Get LDAP information.
+
+ Returns
+ -------
+ dict
+ Informations about LDAP settings.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "base_dn": "dc=test_api,dc=dev",
+ "enable_cifs": false,
+ "enable_cifs_pam": false,
+ "enable_client": false,
+ "enable_client_certificate": false,
+ "enable_idmap": false,
+ "encryption": "no",
+ "error": 2703,
+ "expand_nested_groups": true,
+ "is_syno_server": false,
+ "ldap_schema": "rfc2307bis",
+ "nested_group_level": 5,
+ "profile": "standard",
+ "server_address": "127.0.0.1",
+ "tls_reqcert": false,
+ "update_min": 60
+ },
+ "success": true,
+ ```
+ """
+
+ api_name = 'SYNO.Core.Directory.LDAP'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'get'
+ }
+
+ return self.request_data(api_name, api_path, req_param)
+
+ def get_domain_info(self) -> dict:
+ """
+ Get domain info.
+
+ Returns
+ -------
+ dict
+ Informations about domain settings.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "enable_domain": false
+ },
+ "success": true,
+ }
+ ```
+ """
+
+ api_name = 'SYNO.Core.Directory.Domain'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'get'
+ }
+
+ return self.request_data(api_name, api_path, req_param)
+
+ def get_sso_login_settings(self) -> dict:
+ """
+ Get SSO login settings.
+
+ Returns
+ -------
+ dict
+ Informations about SSO login settings.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "sso_default_login": false
+ },
+ "success": true,
+ }
+ ```
+ """
+
+ api_name = 'SYNO.Core.Directory.SSO.Setting'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'get'
+ }
+
+ return self.request_data(api_name, api_path, req_param)
+
+ def get_synology_sso_settings(self) -> dict:
+ """
+ Get Synology SSO service settings.
+
+ Returns
+ -------
+ dict
+ Informations about Synology SSO service settings.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "allow_local_user": true,
+ "appid": "",
+ "enable_sso": false,
+ "host": "",
+ "name": "Synology SSO",
+ "pingpong": null,
+ "sso_default_login": false
+ },
+ "success": true
+ }
+ ```
+ """
+
+ api_name = 'SYNO.Core.Directory.SSO'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'get'
+ }
+
+ return self.request_data(api_name, api_path, req_param)
+
+ def get_sso_profile(self) -> dict:
+ """
+ Get SSO profile.
+
+ Returns
+ -------
+ dict
+ Informations about SSO profile.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "sso_enable": false,
+ "sso_profile": ""
+ },
+ "success": true
+ }
+ ```
+ """
+
+ api_name = 'SYNO.Core.Directory.SSO.Profile'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'get'
+ }
+
+ return self.request_data(api_name, api_path, req_param)
+
+ def get_sam_sso_settings(self) -> dict:
+ """
+ Get SAM SSO settings.
+
+ Returns
+ -------
+ dict
+ Informations about SAM SSO settings.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "saml_allow_local_user": false,
+ "saml_cert_detail": "",
+ "saml_idp_entity_id": "",
+ "saml_idp_signin_url": "",
+ "saml_name": "SAML",
+ "saml_response_signature": "response",
+ "saml_system_date": "",
+ "saml_valid_date": "",
+ "sso_saml_enable": ""
+ },
+ "success": true
+ }
+ ```
+ """
+
+ api_name = 'SYNO.Core.Directory.SSO.SAM'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'get'
+ }
+
+ return self.request_data(api_name, api_path, req_param)
+
+ def get_cas_sso_settings(self) -> dict:
+ """
+ Get CAS SSO settings.
+
+ Returns
+ -------
+ dict
+ Informations about CAS SSO settings.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "cas_allow_local_user": true,
+ "cas_auth_url": "",
+ "cas_name": "CAS",
+ "cas_service_ids": "",
+ "cas_validate_url": "",
+ "sso_cas_enable": ""
+ },
+ "success": true
+ }
+ ```
+ """
+
+ api_name = 'SYNO.Core.Directory.SSO.CAS'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'get'
+ }
+
+ return self.request_data(api_name, api_path, req_param)
diff --git a/synology_api/DSM/ControlPanel/ExternalAccess.py b/synology_api/DSM/ControlPanel/ExternalAccess.py
new file mode 100644
index 00000000..c3aa6c6a
--- /dev/null
+++ b/synology_api/DSM/ControlPanel/ExternalAccess.py
@@ -0,0 +1,883 @@
+"""
+External access class for Synology DSM.
+"""
+from synology_api import base_api
+
+
+class ExternalAccess(base_api.BaseApi):
+ """
+ External access class for interacting with Synology DSM External Access settings.
+
+ Supported methods:
+ - Getters:
+ - get_ddns_provider_list
+ - get_ddns_record_list
+ - get_external_ip_list
+ - get_ddns_synology_account
+ - get_certificate_list
+ - get_ethernet_port_list
+ - get_quickconnect_info
+ - get_quickconnect_status
+ - get_quickconnect_permission
+ - check_quickconnect_availability
+ - get_quickconnect_misc_config
+ - get_detect_router_information_task
+ - get_detect_router_information_status
+ - get_router_list
+ - get_port_forwarding_rule_list
+ - get_services_port_info
+ - get_advanced_external_access
+
+ - Setters:
+ - set_quickconnect_server_alias
+ - set_quickconnect_enable
+ - set_router_config
+ - set_advanced_external_access
+ """
+
+ def get_ddns_provider_list(self) -> dict:
+ """
+ Get the list of DDNS providers.
+
+ Returns
+ -------
+ dict
+ List of ddns provider.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "providers":
+ [
+ {
+ "id": "Synology",
+ "provider": "Synology",
+ "website": "https://account.synology.com"
+ },
+ {
+ "id": "Oray.com",
+ "provider": "Oray.com",
+ "website": ""
+ }
+ ]
+ }
+ },
+ "success": true
+ ```
+ """
+ api_name = 'SYNO.Core.DDNS.Provider'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'list'
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def get_ddns_record_list(self) -> dict:
+ """
+ Get the list of DDNS records.
+
+ Returns
+ -------
+ dict
+ List of ddns record.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "next_update_time": "",
+ "records": []
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.DDNS.Record'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'list'
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def get_external_ip_list(self) -> dict:
+ """
+ Get the list of external IP addresses.
+
+ Returns
+ -------
+ dict
+ List of external IP addresses.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": [
+ {
+ "ip": "XXX.XXX.XXX.XXX",
+ "ipv6": "cf92:1469:123f:219f:73af:319a:1c77:181e",
+ "type": "WAN"
+ }
+ ],
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.DDNS.ExtIP'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'list'
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def get_ddns_synology_account(self) -> dict:
+ """
+ Get the Synology DDNS account email.
+
+ Returns
+ -------
+ dict
+ Synology DDNS account email.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "email": "YOUR_EMAIL",
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.DDNS.Synology'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'get_myds_account'
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def get_certificate_list(self) -> dict:
+ """
+ Get the list of certificates.
+
+ Returns
+ -------
+ dict
+ List of certificates.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "certificates": [
+ {
+ "desc": "",
+ "id": "C6meKD",
+ "is_broken": false,
+ "is_default": false,
+ "issuer": {
+ "city": "Taipel",
+ "common_name": "Synology Inc. CA",
+ "country": "TW",
+ "organization": "Synology Inc."
+ },
+ "key_types": "",
+ "renewable": false,
+ "self_signed_cacrt_info": {
+ "issuer": {
+ "city": "Taipel",
+ "common_name": "Synology Inc. CA",
+ "country": "TW",
+ "organization": "Synology Inc."
+ },
+ "subject": {
+ "city": "Taipel",
+ "common_name": "Synology Inc. CA",
+ "country": "TW",
+ "organization": "Synology Inc."
+ }
+ },
+ "services": [],
+ "signature_algorithm": "sha256WithRSAEncryption",
+ "subject": {
+ "city": "Taipel",
+ "common_name": "synology",
+ "country": "TW",
+ "organization": "Synology Inc.",
+ "sub_alt_name": [
+ "synology"
+ ]
+ },
+ "user_deletable": true,
+ "valid_from": "Nov 4 12:33:40 2024 GMT",
+ "valid_till": "Nov 5 12:33:40 2025 GMT"
+ }
+ }
+ ]
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.Certificate.CRT'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'list'
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def get_ethernet_port_list(self) -> dict:
+ """
+ Get the list of ethernet ports.
+
+ Returns
+ -------
+ dict
+ List of ethernet ports.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": [
+ {
+ "ifname": "ovs_eth0",
+ "ip": "XXX.XXX.XXX.XXX",
+ "ipv6": [
+ "XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX"
+ ]
+ },
+ {
+ "ifname": "ovs_eth1",
+ "ip": "XXX.XXX.XXX.XXX",
+ "ipv6": []
+ }
+ ],
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.DDNS.Ethernet'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'list'
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def get_quickconnect_info(self) -> dict:
+ """
+ Get the QuickConnect information.
+
+ Returns
+ -------
+ dict
+ QuickConnect information.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "ddns_domain": "direct.quickconnect.to",
+ "domain": "quickconnect.to",
+ "enabled": false,
+ "myds_account": "YOUR_MYDS_ACCOUNT",
+ "region": "fr",
+ "server_alias": "YOUR_SERVER_ALIAS",
+ "server_id": ""
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.QuickConnect'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'get'
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def get_quickconnect_status(self) -> dict:
+ """
+ Get the QuickConnect status.
+
+ Returns
+ -------
+ dict
+ QuickConnect status.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "alias_status": "success",
+ "status": "not_running"
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.QuickConnect'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'status'
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def get_quickconnect_permission(self) -> dict:
+ """
+ Get the QuickConnect permission.
+
+ Returns
+ -------
+ dict
+ QuickConnect permission.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "services": [
+ {
+ "enabled": true,
+ "id": "mobile_apps"
+ },
+ {
+ "enabled": true,
+ "id": "cloudstation"
+ },
+ {
+ "enabled": true,
+ "id": "file_sharing"
+ },
+ {
+ "enabled": true,
+ "id": "dsm_portal"
+ }
+ ]
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.QuickConnect.Permission'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'get'
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def check_quickconnect_availability(self) -> dict:
+ """
+ Check the availability of QuickConnect.
+
+ Returns
+ -------
+ dict
+ Availability status of QuickConnect.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "available": true,
+ "code": 2908,
+ "country": "FR"
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.QuickConnect'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'check_availability'
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def get_quickconnect_misc_config(self) -> dict:
+ """
+ Get the QuickConnect miscellaneous configuration.
+
+ Returns
+ -------
+ dict
+ QuickConnect miscellaneous configuration.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "relay_enabled": true
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.QuickConnect'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'get_misc_config'
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def set_quickconnect_server_alias(self, server_alias: str) -> dict:
+ """
+ Set the QuickConnect server alias.
+
+ Parameters
+ ----------
+ server_alias : str
+ The server alias to set.
+
+ Returns
+ -------
+ dict
+ Result of the operation.
+
+ Examples
+ --------
+ ```json
+ {
+ "success": true,
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.QuickConnect'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'set_server_alias',
+ 'server_alias': server_alias
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def set_quickconnect_enable(self, enable: bool) -> dict:
+ """
+ Enable or disable QuickConnect.
+
+ Parameters
+ ----------
+ enable : bool
+ True to enable, False to disable.
+
+ Returns
+ -------
+ dict
+ Result of the operation.
+
+ Examples
+ --------
+ ```json
+ {
+ "success": true,
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.QuickConnect'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'set',
+ 'enable': enable
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def get_detect_router_information_task(self) -> dict:
+ """
+ Get the task information for detecting router.
+
+ Returns
+ -------
+ dict
+ Task information for detecting router.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "task_id": "@administrators/SYNO.Core.PortForwarding.detect174570013646DCEDAC"
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.PortForwarding'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'detect'
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def get_detect_router_information_status(self, task_id: str) -> dict:
+ """
+ Get the status of the task for detecting router.
+
+ Parameters
+ ----------
+ task_id : str
+ The task ID to check the status of.
+
+ Returns
+ -------
+ dict
+ Status of the task for detecting router.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "percentage": 30,
+ "progress": {
+ "check_connect_wan_step": {
+ "check_id": 3,
+ "status": "initial"
+ },
+ "check_dns_setting_step": {
+ "check_id": 5,
+ "status": "initial"
+ },
+ "check_gateway_setting_step": {
+ "check_id": 2,
+ "status": "processing"
+ },
+ "check_hops_lan2wan_step": {
+ "check_id": 4,
+ "status": "initial"
+ },
+ "check_interface_enable_step": {
+ "check_id": 1,
+ "network_interface": "ovs_eth0",
+ "status": "success"
+ },
+ "detect_router_step": {
+ "check_id": 6,
+ "status": "initial"
+ }
+ }
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.PortForwarding'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'detect_status',
+ 'task_id': task_id
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def get_router_list(self) -> dict:
+ """
+ Get the list of routers.
+
+ Returns
+ -------
+ dict
+ List of routers.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "routers":[
+ {
+ "generic": false,
+ "router_brand": "3rd Party",
+ "router_model": "DD-WRT",
+ "router_version": "v24-sp1 micro"
+ },
+ {
+ "generic": false,
+ "router_brand": "3rd Party",
+ "router_model": "DD-WRT",
+ "router_version": "v24-sp2 std - build 14896"
+ }
+ ]
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.PortForwarding.RouterList'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'list'
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def set_router_config(self,
+ router_brand: str, router_model: str, router_version: str, router_protocol: str, router_port: int,
+ support_upnp: bool = False, support_natpmp: bool = False
+ ) -> dict:
+ """
+ Set the router configuration.
+
+ Parameters
+ ----------
+ router_brand : str
+ The brand of the router.
+ router_model : str
+ The model of the router.
+ router_version : str
+ The version of the router.
+ router_protocol : str
+ The protocol used by the router.
+ router_port : int
+ The port used by the router.
+ support_upnp : bool, optional
+ Whether UPnP is supported (default is False).
+ support_natpmp : bool, optional
+ Whether NAT-PMP is supported (default is False).
+
+ Returns
+ -------
+ dict
+ Result of the operation.
+
+ Examples
+ --------
+ ```json
+ {
+ "success": true,
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.PortForwarding.RouterConf'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'set',
+ 'router_brand': router_brand,
+ 'router_model': router_model,
+ 'router_version': router_version,
+ 'router_protocol': router_protocol,
+ 'router_port': router_port,
+ 'support_upnp': "yes" if support_upnp else "no",
+ 'support_natpmp': "yes" if support_natpmp else "no"
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def get_port_forwarding_rule_list(self) -> dict:
+ """
+ Get the list of port forwarding rules.
+
+ Returns
+ -------
+ dict
+ List of port forwarding rules.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": [
+ {
+ "ds_port": "873",
+ "enable": true,
+ "router_port": "873",
+ "router_protocol": "tcp",
+ "rule_id": "1",
+ "service_name": "",
+ "serviceid": "netbkp"
+ }
+ ],
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.PortForwarding.Rules'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'load'
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def get_services_port_info(self) -> dict:
+ """
+ Get the port information of services.
+
+ Returns
+ -------
+ dict
+ Port information of services.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "service": [
+ {
+ "additional": {
+ "port_info": [
+ {
+ "desc": "Share files with Mac",
+ "dst_port": [
+ "548"
+ ],
+ "name": "AFP",
+ "port_id": "afp",
+ "protocol": "tcp",
+ "src_port": null
+ }
+ ]
+ },
+ "display_name": "AFP",
+ "enable_status": "disabled",
+ "service_id": "atalk"
+ },
+ {
+ "additional": {
+ "port_info": [
+ {
+ "desc": "Bonjour",
+ "dst_port": [
+ "5353"
+ ],
+ "name": "Bonjour Service",
+ "port_id": "bonjour",
+ "protocol": "udp",
+ "src_port": null
+ }
+ ]
+ },
+ "display_name": "Bonjour Printer Broadcast",
+ "enable_status": "disabled",
+ "service_id": "bonjour"
+ }
+ ]
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.Service'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'get',
+ 'additional': ["port_info"]
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def get_advanced_external_access(self) -> dict:
+ """
+ Get the advanced external access settings.
+
+ Returns
+ -------
+ dict
+ Advanced external access settings:
+ - `hostname`: The hostname of the DSM.
+ - `http_port`: The HTTP port of the DSM.
+ - `https_port`: The HTTPS port of the DSM.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "hostname": "HOSTNAME",
+ "http_port": 5000,
+ "https_port": 5001
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.Web.DSM.External'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'get'
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def set_advanced_external_access(self, hostname: str, http_port: int, https_port: int) -> dict:
+ """
+ Set the advanced external access settings.
+
+ Parameters
+ ----------
+ hostname : str
+ The hostname of the DSM.
+ http_port : int
+ The HTTP port of the DSM.
+ https_port : int
+ The HTTPS port of the DSM.
+
+ Returns
+ -------
+ dict
+ Result of the operation.
+
+ Examples
+ --------
+ ```json
+ {
+ "success": true,
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.Web.DSM.External'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'set',
+ 'hostname': hostname,
+ 'http_port': http_port,
+ 'https_port': https_port
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ pass
diff --git a/synology_api/DSM/ControlPanel/ExternalDevices.py b/synology_api/DSM/ControlPanel/ExternalDevices.py
new file mode 100644
index 00000000..fda878c7
--- /dev/null
+++ b/synology_api/DSM/ControlPanel/ExternalDevices.py
@@ -0,0 +1,399 @@
+"""
+External devices class for Synology DSM.
+"""
+
+from synology_api import base_api
+from typing import List
+
+
+class ExternalDevices(base_api.BaseApi):
+ """
+ External devices class for interacting with Synology DSM External devices settings.
+
+ Supported methods:
+ - Getters:
+ - get_printer_driver_list()
+ - get_printer_bonjour_enabled()
+ - get_storage_settings()
+ - get_list_usb_devices()
+ - get_list_esata_devices()
+ - get_list_of_printer()
+ - get_permissions()
+ - Setters:
+ - set_printer_bonjour_enabled()
+ - set_permissions()
+ """
+
+ def get_printer_driver_list(self) -> dict:
+ """
+ Get the list of printer driver.
+
+ Returns
+ -------
+ dict
+ List of printer driver.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "Apollo": [
+ [
+ "Apollo P-2100",
+ "stp-pcl-apollo-p2100.5.2.ppd.tgz",
+ "",
+ ""
+ ],
+ [
+ "Apollo P-2150",
+ "stp-pcl-apollo-p2150.5.2.ppd.tgz",
+ "",
+ ""
+ ],
+ [
+ "Apollo P-2200",
+ "stp-pcl-apollo-p2200.5.2.ppd.tgz",
+ "EPSON",
+ "Stylus DX4800"
+ ],
+ [
+ "Apollo P-2250",
+ "stp-pcl-apollo-p2250.5.2.ppd.tgz",
+ "",
+ ""
+ ],
+ [
+ "Apollo P-2500",
+ "stp-pcl-apollo-p2500.5.2.ppd.tgz",
+ "",
+ ""
+ ],
+ [
+ "Apollo P-2550",
+ "stp-pcl-apollo-p2550.5.2.ppd.tgz",
+ "",
+ ""
+ ],
+ [
+ "Apollo P-2600",
+ "stp-pcl-apollo-p2600.5.2.ppd.tgz",
+ "",
+ ""
+ ],
+ [
+ "Apollo P-2650",
+ "stp-pcl-apollo-p2650.5.2.ppd.tgz",
+ "",
+ ""
+ ]
+ ]
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.ExternalDevice.Printer.Driver'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'list'
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def get_printer_bonjour_enabled(self) -> dict:
+ """
+ Get the printer bonjour enabled status.
+
+ Returns
+ -------
+ dict
+ Printer bonjour enabled status.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "enable_bonjour_support": false
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.ExternalDevice.Printer.BonjourSharing'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'get'
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def set_printer_bonjour_enabled(self, enable: bool) -> dict:
+ """
+ Set the printer bonjour enabled status.
+
+ Parameters
+ ----------
+ enable : bool
+ Printer bonjour enabled status.
+
+ Returns
+ -------
+ dict
+ Result of the operation.
+
+ Examples
+ --------
+ ```json
+ {
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.ExternalDevice.Printer.BonjourSharing'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'set',
+ 'enable_bonjour_support': enable
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def get_storage_settings(self) -> dict:
+ """
+ Get the external devices storage settings.
+
+ Returns
+ -------
+ dict
+ External devices storage settings.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "delalloc": false,
+ "forbid_usb": false,
+ "needReboot": false,
+ "non_admin_eject": false,
+ "setting": false,
+ "support_exfat_mkfs": false
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.ExternalDevice.Storage.Setting'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'get'
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def get_list_usb_devices(self) -> dict:
+ """
+ Get the list of USB devices.
+
+ Returns
+ -------
+ dict
+ List of USB devices.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "devices": []
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.ExternalDevice.Storage.USB'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'list',
+ 'additional': ["all"],
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def get_list_esata_devices(self) -> dict:
+ """
+ Get the list of eSATA devices.
+
+ Returns
+ -------
+ dict
+ List of eSATA devices.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "devices": []
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.ExternalDevice.Storage.eSATA'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'list',
+ 'additional': ["all"],
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def get_list_of_printer(self) -> dict:
+ """
+ Get the list of printers.
+
+ Returns
+ -------
+ dict
+ List of printers.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "printers": []
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.ExternalDevice.Printer'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'list',
+ 'additional': ["all"],
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def get_permissions(self,
+ offset: int = 0, limit: int = 50,
+ user_group_type: str = "local_user"
+ ) -> dict:
+ """
+ Get the permissions of the external devices.
+
+ Parameters
+ ----------
+ offset : int, optional
+ The offset for pagination. Defaults to `0`.
+ limit : int, optional
+ The limit for pagination. Defaults to `50`.
+ user_group_type : str, optional
+ The type of user group to list permissions for. Defaults to `"local_user"`.
+ All known values are: `["system", "local_user", "local_group", "ldap_user", "ldap_group"]`.
+
+ Returns
+ -------
+ dict
+ Permissions of the external devices.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "items": [
+ {
+ "is_admin": true,
+ "is_deny": false,
+ "is_readonly": false,
+ "is_writable": false,
+ "name": "admin"
+ },
+ {
+ "is_admin": false,
+ "is_deny": false,
+ "is_readonly": false,
+ "is_writable": false,
+ "name": "guest"
+ }
+ ],
+ "total": 2
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.ExternalDevice.DefaultPermission'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'list',
+ 'action': 'enum',
+ 'offset': offset,
+ 'limit': limit,
+ 'user_group_type': user_group_type
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def set_permissions(self, user_group_type: str, permissions: List[dict[str, object]]) -> dict:
+ """
+ Set the permissions of the external devices.
+
+ Parameters
+ ----------
+ user_group_type : str
+ The type of user group to set permissions for. All known values are: `["system", "local_user", "local_group", "ldap_user", "ldap_group"]`.
+ permissions : List[dict[str, object]]
+ List of permissions to set. Each permission is a dictionary.
+ Example:
+ ```json
+ [
+ {
+ "name":"guest",
+ "is_readonly":false,
+ "is_writable":true,
+ "is_deny":false,
+ "is_custom":false
+ }
+ ]
+ ```
+
+ Returns
+ -------
+ dict
+ Result of the operation.
+
+ Examples
+ --------
+ ```json
+ {
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.ExternalDevice.DefaultPermission'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'set',
+ 'user_group_type': user_group_type,
+ 'permissions': permissions
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ pass
diff --git a/synology_api/DSM/ControlPanel/FileServices.py b/synology_api/DSM/ControlPanel/FileServices.py
new file mode 100644
index 00000000..4d93b21c
--- /dev/null
+++ b/synology_api/DSM/ControlPanel/FileServices.py
@@ -0,0 +1,831 @@
+
+"""
+File services class for interacting with Synology DSM File services settings.
+"""
+
+from synology_api import base_api
+
+
+class FileServices(base_api.BaseApi):
+ """
+ File services class for interacting with Synology DSM File services settings.
+
+ Provides methods to get and set SMB, AFP, NFS, FTP, SFTP, and other file service settings.
+ """
+
+ def get_smb_settings(self):
+ """
+ Get SMB settings.
+
+ Returns
+ -------
+ dict
+ SMB settings data.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "disable_shadow_copy": false,
+ "disable_strict_allocate": false,
+ "enable_access_based_share_enum": false,
+ "enable_adserver": null,
+ "enable_aio_read": false,
+ "enable_delete_vetofiles": false,
+ "enable_dirsort": false,
+ "enable_durable_handles": false,
+ "enable_enhance_log": false,
+ "enable_fruit_locking": false,
+ "enable_local_master_browser": false,
+ "enable_mask": false,
+ "enable_msdfs": false,
+ "enable_multichannel": false,
+ "enable_ntlmv1_auth": false,
+ "enable_op_lock": true,
+ "enable_perf_chart": false,
+ "enable_reset_on_zero_vc": false,
+ "enable_samba": true,
+ "enable_server_signing": 0,
+ "enable_smb2_leases": true,
+ "enable_smb3_directory_leasing": true,
+ "enable_strict_sync": false,
+ "enable_symlink": true,
+ "enable_syno_catia": true,
+ "enable_synotify": true,
+ "enable_vetofile": false,
+ "enable_widelink": false,
+ "offline_files_support": false,
+ "smb3_directory_leasing_scope": "home_only",
+ "smb_encrypt_transport": 1,
+ "smb_max_protocol": 3,
+ "smb_min_protocol": 1,
+ "syno_wildcard_search": false,
+ "vetofile": "",
+ "wins": "",
+ "workgroup": "WORKGROUP"
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.FileServ.SMB'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'get'
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def get_afp_settings(self) -> dict:
+ """
+ Get AFP settings.
+
+ Returns
+ -------
+ dict
+ AFP settings data.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "enable_afp": false,
+ "enable_disconnect_quick": false,
+ "enable_umask": false,
+ "time_machine": ""
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.FileServ.AFP'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'get'
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def get_nfs_settings(self) -> dict:
+ """
+ Get NFS settings.
+
+ Returns
+ -------
+ dict
+ NFS settings data.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "enable_nfs": false,
+ "enable_nfs_v4": false,
+ "enabled_minor_ver": 0,
+ "nfs_v4_domain": "",
+ "read_size": 8192,
+ "support_encrypt_share": 1,
+ "support_major_ver": 4,
+ "support_minor_ver": 1,
+ "unix_pri_enable": true,
+ "write_size": 8192
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.FileServ.NFS'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'get'
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def get_ftp_settings(self) -> dict:
+ """
+ Get FTP settings.
+
+ Returns
+ -------
+ dict
+ FTP settings data.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "custom_port": "55536:55899",
+ "custom_port_range": false,
+ "enable_ascii": false,
+ "enable_fips": false,
+ "enable_flow_ctrl": false,
+ "enable_ftp": false,
+ "enable_ftps": false,
+ "enable_fxp": false,
+ "ext_ip": "",
+ "max_conn_per_ip": 0,
+ "maxdownloadrate": 0,
+ "maxuploadrate": 0,
+ "modify_time_std": "utc",
+ "portnum": 21,
+ "timeout": 300,
+ "use_ext_ip": false,
+ "utf8_mode": 1
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.FileServ.FTP'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'get'
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def get_sftp_settings(self) -> dict:
+ """
+ Get SFTP settings.
+
+ Returns
+ -------
+ dict
+ SFTP settings data.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "enable": false,
+ "portnum": 22
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.FileServ.FTP.SFTP'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'get'
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def get_bandwidth_control_protocol_settings(self, protocol: str, schedule_plan: str) -> dict:
+ """
+ Get bandwidth control protocol settings.
+
+ Parameters
+ ----------
+ protocol : str
+ Protocol name (e.g. "FTP", "NetworkBackup").
+ schedule_plan : str
+ Schedule plan, a 128-bit binary string.
+
+ Returns
+ -------
+ dict
+ Bandwidth control protocol settings data.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "policy": "disabled",
+ "protocol": "FTP",
+ "schedule_plan": "111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111"
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.BandwidthControl.Protocol'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'get',
+ 'protocol': protocol
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def get_network_backup_settings(self) -> dict:
+ """
+ Get network backup settings.
+
+ Returns
+ -------
+ dict
+ Network backup settings data.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "enable": false,
+ "enable_custom_config": false,
+ "enable_rsync_account": false,
+ "rsync_sshd_port": "22"
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Backup.Service.NetworkBackup'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'get'
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def get_domain_settings(self) -> dict:
+ """
+ Get domain settings.
+
+ Returns
+ -------
+ dict
+ Domain settings data.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "enable_domain": false
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.Directory.Domain'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'get'
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def get_service_discovery_settings(self) -> dict:
+ """
+ Get service discovery settings.
+
+ Returns
+ -------
+ dict
+ Service discovery settings data.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "enable_afp_time_machine": false,
+ "enable_smb_time_machine": false,
+ "time_machine_disable_shares": [],
+ "time_machine_shares": []
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.FileServ.ServiceDiscovery'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'get'
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def get_wstransfer_settings(self) -> dict:
+ """
+ Get WSTransfer settings.
+
+ Returns
+ -------
+ dict
+ WSTransfer settings data.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "enable_wstransfer": true
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.FileServ.ServiceDiscovery.WSTransfer'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'get'
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def get_reflink_copy_settings(self) -> dict:
+ """
+ Get reflink copy settings.
+
+ Returns
+ -------
+ dict
+ Reflink copy settings data.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "reflink_copy_enable": false
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.FileServ.ReflinkCopy'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'get'
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def get_tftp_settings(self) -> dict:
+ """
+ Get TFTP settings.
+
+ Returns
+ -------
+ dict
+ TFTP settings data.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "enable": false,
+ "enable_log": false,
+ "endip": "255.255.255.255",
+ "permission": "r",
+ "root_path": "",
+ "startip": "0.0.0.0",
+ "timeout": 3
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.TFTP'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'get'
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def clean_smb_cache(self) -> dict:
+ """
+ Clean SMB cache.
+
+ Returns
+ -------
+ dict
+ Result of the operation.
+
+ Examples
+ --------
+ ```json
+ {
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.FileServ.SMB'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'clean_cache'
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def set_afp_settings(self, enable: bool, enable_transfer_log: bool, enable_umask: bool, enable_disconnect_quick: bool) -> dict:
+ """
+ Set AFP settings.
+
+ Parameters
+ ----------
+ enable : bool
+ Enable or disable AFP.
+ enable_transfer_log : bool
+ Enable or disable transfer log.
+ enable_umask : bool
+ Enable or disable umask.
+ enable_disconnect_quick : bool
+ Enable or disable quick disconnect.
+
+ Returns
+ -------
+ dict
+ Result of the operation.
+
+ Examples
+ --------
+ ```json
+ {
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.FileServ.AFP'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'set',
+ 'enable': enable,
+ 'enable_transfer_log': enable_transfer_log,
+ 'enable_umask': enable_umask,
+ 'enable_disconnect_quick': enable_disconnect_quick
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def set_nfs_settings(self, enable: bool, max_protocol: int, enable_v4: bool, enabled_minor_ver: int) -> dict:
+ """
+ Set NFS settings.
+
+ Parameters
+ ----------
+ enable : bool
+ Enable or disable NFS.
+ max_protocol : int
+ Maximum NFS protocol version.
+ enable_v4 : bool
+ Enable or disable NFSv4.
+ enabled_minor_ver : int
+ Enabled minor version.
+
+ Returns
+ -------
+ dict
+ Result of the operation.
+
+ Examples
+ --------
+ ```json
+ {
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.FileServ.NFS'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'set',
+ 'enable': enable,
+ 'max_protocol': max_protocol,
+ 'enable_v4': enable_v4,
+ 'enabled_minor_ver': enabled_minor_ver
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def get_ftp_security_settings(self) -> dict:
+ """
+ Get FTP security settings.
+
+ Returns
+ -------
+ dict
+ FTP security settings data.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "anonymous": false,
+ "anonymous_chroot": false,
+ "anonymous_chroot_share": "",
+ "enable_umask": false,
+ "user_chroot": false
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.FileServ.FTP.Security'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'get'
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def get_ftp_security_share_list(self) -> dict:
+ """
+ Get FTP security share list.
+
+ Returns
+ -------
+ dict
+ FTP security share list data.
+
+ Examples
+ --------
+ ```json
+ {
+ "data":{
+ "share": [
+ "docker"
+ ]
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.FileServ.FTP.Security.ShareList'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'get'
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def set_ftp_settings(self, enable_ftp: bool, enable_ftps: bool,
+ timeout: int = 300, portnum: int = 21, custom_port_range: bool = False,
+ use_ext_ip: bool = False, enable_fxp: bool = True, enable_ascii: bool = True,
+ utf8_mode: int = 1, modify_time_std: str = "utc", custom_port: str = "55536:55899",
+ external_ip: str = "default"
+ ) -> dict:
+ """
+ Set FTP settings.
+
+ Parameters
+ ----------
+ enable_ftp : bool
+ Enable or disable FTP.
+ enable_ftps : bool
+ Enable or disable FTPS.
+ timeout : int, optional
+ Timeout in seconds. Default is 300.
+ portnum : int, optional
+ Port number. Default is 21.
+ custom_port_range : bool, optional
+ Enable or disable custom port range. Default is False.
+ use_ext_ip : bool, optional
+ Enable or disable external IP. Default is False.
+ enable_fxp : bool, optional
+ Enable or disable FXP. Default is True.
+ enable_ascii : bool, optional
+ Enable or disable ASCII mode. Default is True.
+ utf8_mode : int, optional
+ UTF-8 mode (0: disable, 1: Auto, 2: Force). Default is 1.
+ modify_time_std : str, optional
+ Modify time standard ("utc", "local"). Default is "utc".
+ custom_port : str, optional
+ Custom port range. Default is "55536:55899".
+ external_ip : str, optional
+ External IP address. Default is "default".
+
+ Returns
+ -------
+ dict
+ Result of the operation.
+
+ Examples
+ --------
+ ```json
+ {
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.FileServ.FTP'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'set',
+ 'enable_ftp': enable_ftp,
+ 'enable_ftps': enable_ftps,
+ 'timeout': timeout,
+ 'portnum': portnum,
+ 'custom_port_range': custom_port_range,
+ 'use_ext_ip': use_ext_ip,
+ 'enable_fxp': enable_fxp,
+ 'enable_ascii': enable_ascii,
+ 'utf8_mode': utf8_mode,
+ 'modify_time_std': modify_time_std,
+ 'custom_port': custom_port,
+ 'external_ip': external_ip
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def set_sftp_settings(self, enable: bool, portnum: int = 22) -> dict:
+ """
+ Set SFTP settings.
+
+ Parameters
+ ----------
+ enable : bool
+ Enable or disable SFTP.
+ portnum : int, optional
+ Port number. Default is 22.
+
+ Returns
+ -------
+ dict
+ Result of the operation.
+
+ Examples
+ --------
+ ```json
+ {
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.FileServ.FTP.SFTP'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'set',
+ 'enable': enable,
+ 'portnum': portnum,
+ 'sftp_portnum': portnum
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def set_rsync_settings(self, enable: bool, port: int = 22) -> dict:
+ """
+ Set rsync settings.
+
+ Parameters
+ ----------
+ enable : bool
+ Enable or disable rsync.
+ port : int, optional
+ Rsync SSHD port. Default is 22.
+
+ Returns
+ -------
+ dict
+ Result of the operation.
+
+ Examples
+ --------
+ ```json
+ {
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Backup.Service.NetworkBackup'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'set',
+ 'enable': enable,
+ 'rsync_sshd_port': port
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def set_reflink_copy_settings(self, reflink_copy_enable: bool) -> dict:
+ """
+ Set reflink copy settings.
+
+ Parameters
+ ----------
+ reflink_copy_enable : bool
+ Enable or disable reflink copy.
+
+ Returns
+ -------
+ dict
+ Result of the operation.
+
+ Examples
+ --------
+ ```json
+ {
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.FileServ.ReflinkCopy'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'set',
+ 'reflink_copy_enable': reflink_copy_enable
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def set_tftp_settings(self, enable: bool, root_path: str) -> dict:
+ """
+ Set TFTP settings.
+
+ Parameters
+ ----------
+ enable : bool
+ Enable or disable TFTP.
+ root_path : str
+ Root path for TFTP. Path must be a valid directory.
+
+ Returns
+ -------
+ dict
+ Result of the operation.
+
+ Examples
+ --------
+ ```json
+ {
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.TFTP'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'set',
+ 'enable': enable,
+ 'root_path': root_path
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ pass
diff --git a/synology_api/DSM/ControlPanel/HardwarePower.py b/synology_api/DSM/ControlPanel/HardwarePower.py
new file mode 100644
index 00000000..19346030
--- /dev/null
+++ b/synology_api/DSM/ControlPanel/HardwarePower.py
@@ -0,0 +1,830 @@
+"""
+Hardware power class for Synology DSM.
+"""
+
+from synology_api import base_api
+import json
+from typing import List
+
+
+class HardwarePower(base_api.BaseApi):
+ """
+ Hardware power class for interacting with Synology DSM Hardware & Power settings.
+
+ Supported methods:
+ - Getters:
+
+ - Setters:
+ """
+
+ def need_reboot(self) -> dict:
+ """
+ TODO: Determine usage of this method.
+
+ Returns
+ -------
+ dict
+ Return boolean value indicating if a reboot is needed.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "need_reboot": false
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.Hardware.NeedReboot'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'get'
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def set_need_reboot(self) -> dict:
+ """
+ TODO: Determine usage of this method.
+
+ Returns
+ -------
+ dict
+ Return success status.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "success": true
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.Hardware.NeedReboot'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'set'
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def get_led_brightness_stats(self) -> dict:
+ """
+ Get LED brightness stats.
+
+ Returns
+ -------
+ dict
+ Return LED brightness default settigns and min / max.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "default": 3,
+ "max": 3,
+ "min": 0
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.Hardware.Led.Brightness'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'get_static_data'
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def get_zram_settings(self) -> dict:
+ """
+ Get ZRAM settings.
+
+ Returns
+ -------
+ dict
+ Return ZRAM settings.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "enable_zram": true
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.Hardware.ZRAM'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'get'
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def get_power_recovery_settings(self) -> dict:
+ """
+ Get power recovery settings.
+
+ Returns
+ -------
+ dict
+ Return power recovery settings.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "internal_lan_num": 2,
+ "rc_power_config": true,
+ "wol": [
+ {
+ "enable": false,
+ "idx": 1
+ },
+ {
+ "enable": false,
+ "idx": 2
+ }
+ ],
+ "wol1": false,
+ "wol2": false
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.Hardware.PowerRecovery'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'get'
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def get_beep_control_settings(self) -> dict:
+ """
+ Get beep control settings.
+
+ Returns
+ -------
+ dict
+ Return beep control settings.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "enc_module_fail": true,
+ "eunit_redundant_power_fail": true,
+ "fan_fail": true,
+ "poweroff_beep": true,
+ "poweron_beep": true,
+ "redundant_power_fail": true,
+ "reset_beep": true,
+ "sas_link_fail": true,
+ "support_fan_fail": true,
+ "support_poweroff_beep": true,
+ "support_poweron_beep": true,
+ "support_redundant_power_fail": false,
+ "support_reset_beep": false,
+ "support_volume_or_cache_crash": true,
+ "volume_or_cache_crash": true
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.Hardware.BeepControl'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'get'
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def get_fan_speed_settings(self) -> dict:
+ """
+ Get fan speed settings.
+
+ Returns
+ -------
+ dict
+ Return fan speed settings.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "enc_module_fail": true,
+ "eunit_redundant_power_fail": true,
+ "fan_fail": true,
+ "poweroff_beep": true,
+ "poweron_beep": true,
+ "redundant_power_fail": true,
+ "reset_beep": true,
+ "sas_link_fail": true,
+ "support_fan_fail": true,
+ "support_poweroff_beep": true,
+ "support_poweron_beep": true,
+ "support_redundant_power_fail": false,
+ "support_reset_beep": false,
+ "support_volume_or_cache_crash": true,
+ "volume_or_cache_crash": true
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.Hardware.FanSpeed'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'get'
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def get_led_brightness_schedule(self) -> dict:
+ """
+ Get LED brightness settings.
+
+ Returns
+ -------
+ dict
+ Return LED brightness settings. Schedule is a 144 character string.
+ 1 character = 1 hour. Start from Sunday 00:00 to Saturday 23:00.
+ 0 = Default, 1= Ajusted, 2 = Off.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "led_brightness": 3,
+ "schedule": "111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111"
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.Hardware.Led.Brightness'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'get'
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def get_power_schedule_settings(self) -> dict:
+ """
+ Get power schedule settings.
+
+ Returns
+ -------
+ dict
+ Return power schedule settings.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "poweroff_tasks": [],
+ "poweron_tasks": []
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.Hardware.PowerSchedule'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'load'
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def get_hibernation_settings(self) -> dict:
+ """
+ Get hibernation settings.
+
+ Returns
+ -------
+ dict
+ Return hibernation settings.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "auto_poweroff_enable": false,
+ "enable_log": false,
+ "eunit_deep_sleep": 0,
+ "eunit_dsleep_blacklist": "none",
+ "hibernation_blacklist": "none",
+ "ignore_netbios_broadcast": false,
+ "internal_hd_idletime": 20,
+ "sata_deep_sleep": 1,
+ "sata_dsleep_blacklist": "none",
+ "support_esata": "yes",
+ "support_eunit_deep_sleep": false,
+ "support_eunit_switch_mode": true,
+ "usb_idletime": 0
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.Hardware.Hibernation'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'get'
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def get_ups_settings(self) -> dict:
+ """
+ Get UPS settings.
+
+ Returns
+ -------
+ dict
+ Return UPS settings.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "ACL_enable": false,
+ "ACL_list": [],
+ "charge": 0,
+ "delay_time": -1,
+ "enable": false,
+ "manufacture": "",
+ "mode": "SLAVE",
+ "model": "",
+ "net_server_ip": "",
+ "runtime": 0,
+ "shutdown_device": false,
+ "snmp_auth": false,
+ "snmp_auth_key": false,
+ "snmp_auth_type": "",
+ "snmp_community": "",
+ "snmp_mib": "",
+ "snmp_privacy": false,
+ "snmp_privacy_key": false,
+ "snmp_privacy_type": "",
+ "snmp_server_ip": "",
+ "snmp_user": "",
+ "snmp_version": "",
+ "status": "usb_ups_status_unknown",
+ "usb_ups_connect": false
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.ExternalDevice.UPS'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'get'
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def set_led_brightness(self, brightness: int = 3) -> dict:
+ """
+ Set LED brightness.
+
+ Parameters
+ ----------
+ brightness : int
+ LED brightness level (0-3). Default is `3`.
+
+ Returns
+ -------
+ dict
+ Return success status.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "success": true
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.Hardware.Led.Brightness'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'set',
+ 'brightness': brightness
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def set_zram_settings(self, enable_zram: bool = False) -> dict:
+ """
+ Set ZRAM settings.
+
+ Parameters
+ ----------
+ enable_zram : bool
+ Enable or disable ZRAM. Default is `False`.
+
+ Returns
+ -------
+ dict
+ Return success status.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "success": true
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.Hardware.ZRAM'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'set',
+ 'enable_zram': enable_zram
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def set_power_recovery_settings(self,
+ enable: bool = False, wol1: bool = False, wol2: bool = False, wol3: bool = False
+ ) -> dict:
+ """
+ Set power recovery settings. Note if a wol option is enabled, the enable option will be forced to `True`.
+
+ Parameters
+ ----------
+ enable : bool
+ Enable or disable power recovery configuration. Default is `False`.
+ wol1 : bool
+ Enable or disable Wake on LAN for port 1. Default is `False`.
+ wol2 : bool
+ Enable or disable Wake on LAN for port 2. Default is `False`.
+ wol3 : bool
+ Enable or disable Wake on LAN for port 3. Default is `False`.
+
+ Returns
+ -------
+ dict
+ Return success status.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "success": true
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.Hardware.PowerRecovery'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'set',
+ 'enable': enable,
+ 'wol1': wol1,
+ 'wol2': wol2,
+ 'wol3': wol3
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def set_beep_control_settings(self,
+ fan_fail: bool = True, volume_or_cache_crash: bool = True,
+ poweroff_beep: bool = True, poweron_beep: bool = True
+ ) -> dict:
+ """
+ Set beep control settings.
+
+ Parameters
+ ----------
+ fan_fail : bool
+ Enable or disable fan failure beep. Default is `True`.
+ volume_or_cache_crash : bool
+ Enable or disable volume or cache crash beep. Default is `True`.
+ poweroff_beep : bool
+ Enable or disable power off beep. Default is `True`.
+ poweron_beep : bool
+ Enable or disable power on beep. Default is `True`.
+
+ Returns
+ -------
+ dict
+ Return success status.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "success": true
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.Hardware.BeepControl'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'set',
+ 'fan_fail': fan_fail,
+ 'volume_or_cache_crash': volume_or_cache_crash,
+ 'poweroff_beep': poweroff_beep,
+ 'poweron_beep': poweron_beep
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def set_fan_speed_settings(self, fan_speed: str = "coolfan") -> dict:
+ """
+ Set fan speed settings.
+
+ Parameters
+ ----------
+ fan_speed : str
+ Fan speed level (0-2). Default is `quietfan`.
+ Known values are `quietfan`, `coolfan`, and `fullspeed`.
+
+ Returns
+ -------
+ dict
+ Return success status.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "success": true
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.Hardware.FanSpeed'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'set',
+ 'dual_fan_speed': fan_speed
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def set_led_brightness_schedule(self,
+ led_brightness: int = 3, schedule: str = "1"*144
+ ) -> dict:
+ """
+ Set LED brightness schedule.
+
+ Parameters
+ ----------
+ led_brightness : int
+ LED brightness level (0-3). Default is `3`.
+ schedule : str
+ Schedule string for LED brightness. 1 character = 1 hour. Start from Sunday 00:00 to Saturday 23:00.
+ Default is `1` for all hours.
+
+ Returns
+ -------
+ dict
+ Return success status.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "success": true
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.Hardware.Led.Brightness'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'set',
+ 'led_brightness': led_brightness,
+ 'schedule': schedule
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def set_hibernation_settings(self,
+ internal_hd_idletime: int = 20, stat_deep_sleep: bool = True,
+ ignore_netbios_broadcast: bool = False, usb_idletime: int = 0,
+ enable_log: bool = False
+ ) -> dict:
+ """
+ Set hibernation settings.
+
+ Parameters
+ ----------
+ internal_hd_idletime : int
+ Internal hard drive idle time in minutes. Default is `20`.
+ stat_deep_sleep : bool
+ Enable or disable SATA deep sleep. Default is `True`.
+ ignore_netbios_broadcast : bool
+ Enable or disable ignoring NetBIOS broadcast. Default is `False`.
+ usb_idletime : int
+ USB idle time in minutes. Default is `0`.
+ enable_log : bool
+ Enable or disable logging. Default is `False`.
+
+ Returns
+ -------
+ dict
+ Return success status.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "success": true
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.Hardware.Hibernation'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'set',
+ 'internal_hd_idletime': internal_hd_idletime,
+ 'stat_deep_sleep': stat_deep_sleep,
+ 'ignore_netbios_broadcast': ignore_netbios_broadcast,
+ 'usb_idletime': usb_idletime,
+ 'enable_log': enable_log
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def set_ups_settings(self,
+ enable: bool = False, mode: str = "SLAVE", delay_time: str = "-1",
+ snmp_auth_key_dirty: bool = False, snmp_privacy_key_dirty: bool = False,
+ ) -> dict:
+ """
+ Set UPS settings.
+
+ Parameters
+ ----------
+ enable : bool
+ Enable or disable UPS. Default is `False`.
+ mode : str
+ UPS mode. Default is `SLAVE`.
+ TODO: Determine valid values for this parameter.
+ delay_time : str
+ Delay time in seconds. Default is `-1`.
+ TODO: Determine valid values for this parameter.
+ snmp_auth_key_dirty : bool
+ SNMP authentication key dirty flag. Default is `False`.
+ snmp_privacy_key_dirty : bool
+ SNMP privacy key dirty flag. Default is `False`.
+
+ Returns
+ -------
+ dict
+ Return success status.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "success": true
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.ExternalDevice.UPS'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'set',
+ 'enable': enable,
+ 'mode': mode,
+ 'delay_time': delay_time,
+ 'snmp_auth_key_dirty': snmp_auth_key_dirty,
+ 'snmp_privacy_key_dirty': snmp_privacy_key_dirty
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def set_power_schedule(self, poweron_tasks: List[dict] = [], poweroff_tasks: List[dict] = []) -> dict:
+ """
+ Set the power schedule, poweron tasks and poweroff tasks.
+
+ Parameters
+ ----------
+ poweron_tasks : List[dict], optional
+ List of tasks for power on. Defaults to `[]`
+ Example of a task:
+ ```python
+ {
+ "enabled": True, # Enable or not the task
+ "hour": 13, # Hour 0-23
+ "min": 59, # Minutes 0-59
+ "weekdays": "0,1,2,3,4,5,6" # All days of the week (Sunday, Monday, Tuesday, Wednesday, Thrusday, Friday, Saturday)
+ }
+ ```
+ poweroff_tasks : List[dict], optional
+ List of tasks for power off. Defaults to `[]`
+ Example of a task:
+ ```python
+ {
+ "enabled": True, # Enable or not the task
+ "hour": 13, # Hour 0-23
+ "min": 59, # Minutes 0-59
+ "weekdays": "0,1,2,3,4,5,6" # All days of the week (Sunday, Monday, Tuesday, Wednesday, Thrusday, Friday, Saturday)
+ }
+ ```
+
+ Returns
+ -------
+ dict
+ List of tasks in power schedule.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "poweroff_tasks": [],
+ "poweron_tasks": [
+ {
+ "enabled": true,
+ "hour": 0,
+ "min": 0,
+ "weekdays": "1,2,3,4,5"
+ }
+ ]
+ },
+ "success": true
+ }
+ ```
+ """
+
+ api_name = 'SYNO.Core.Hardware.PowerSchedule'
+ info = self.core_list[api_name]
+ api_path = info["path"]
+ req_param = {
+ "version": info["maxVersion"],
+ "method": "save",
+ "poweron_tasks": json.dumps(poweron_tasks),
+ "poweroff_tasks": json.dumps(poweroff_tasks)
+ }
+
+ return self.request_data(api_name, api_path, req_param)
+
+ pass
diff --git a/synology_api/DSM/ControlPanel/IndexingService.py b/synology_api/DSM/ControlPanel/IndexingService.py
new file mode 100644
index 00000000..ae80b1f5
--- /dev/null
+++ b/synology_api/DSM/ControlPanel/IndexingService.py
@@ -0,0 +1,316 @@
+"""
+Indexing service class for Synology DSM.
+"""
+
+from synology_api import base_api
+
+
+class IndexingService(base_api.BaseApi):
+ """
+ Indexing service class for interacting with Synology DSM Indexing service settings.
+
+ Supported methods:
+ - Getters:
+
+ - Setters:
+ """
+
+ def get_indexed_folders(self) -> dict:
+ """
+ Get indexed folders.
+
+ Returns
+ -------
+ dict
+ Return list of folders indexed by the indexing service.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "folders": [
+ {
+ "default": false,
+ "exist": true,
+ "name": "Films",
+ "path": "/Films",
+ "types": [
+ "video"
+ ]
+ },
+ {
+ "default": false,
+ "exist": true,
+ "name": "Series",
+ "path": "/Series",
+ "types": [
+ "video"
+ ]
+ }
+ ]
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.MediaIndexing.IndexFolder'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'get'
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def get_media_indexing_status(self) -> dict:
+ """
+ Get media indexing status.
+
+ Returns
+ -------
+ dict
+ Return the status of the media indexing service.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "reindexing": false
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.MediaIndexing'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'status'
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def get_thumbnail_quality_settings(self) -> dict:
+ """
+ Get thumbnail quality settings.
+
+ Returns
+ -------
+ dict
+ Return the thumbnail quality settings.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "packages": [],
+ "thumbnail_quality": "normal"
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.MediaIndexing.ThumbnailQuality'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'get'
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def get_scheduler_settings(self) -> dict:
+ """
+ Get scheduler settings.
+
+ Returns
+ -------
+ dict
+ Return the scheduler settings of the indexing service.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "duration": 1,
+ "manual_action_by_user": "none",
+ "mode": "schedule",
+ "start": {
+ "hour": 0
+ },
+ "week": [
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true
+ ]
+ },
+ "success": true,
+ ```
+ """
+ api_name = 'SYNO.Core.MediaIndexing.Scheduler'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'get'
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def set_indexed_folders(self, folders: list) -> dict:
+ """
+ Set indexed folders.
+
+ Parameters
+ ----------
+ folders : list
+ A list of dictionaries representing the folders to be indexed. Each dictionary should contain:
+ - `path`: The path of the folder to be indexed.
+ - `name`: The name of the folder.
+ - `default`: A boolean indicating if this is a default folder. Should be `False`
+ - `types`: A list of media types to index in the folder (e.g., `["video"]`). Fields are `photo`, `video`, `music`.
+ example:
+ ```json
+ [
+ {
+ "path": "/Films",
+ "name": "Films",
+ "default": false,
+ "types": ["video"]
+ },
+ {
+ "path": "/Series",
+ "name": "Series",
+ "default": false,
+ "types": ["video"]
+ }
+ ]
+ ```
+
+ Returns
+ -------
+ dict
+ Return the result of the operation.
+
+ Examples
+ --------
+ ```json
+ {
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.MediaIndexing.IndexFolder'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'set',
+ 'folders': folders
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def set_thumbnail_quality_settings(self, quality: str = "normal") -> dict:
+ """
+ Set thumbnail quality settings.
+
+ Parameters
+ ----------
+ quality : str
+ The desired thumbnail quality setting. Options are `normal`, `high`. Default to `normal`.
+
+ Returns
+ -------
+ dict
+ Return the result of the operation.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "thumbnail_quality": "normal"
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.MediaIndexing.ThumbnailQuality'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'set',
+ 'quality': quality
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def set_shudler_settings(self, mode: str = "always", start_hour: int = 0, duration: int = 1, week: list = [True, True, True, True, True, True, True]) -> dict:
+ """
+ Set scheduler settings.
+
+ Parameters
+ ----------
+ mode : str
+ The scheduling mode. Options are `schedule`, `always`. Default to `always`.
+ start_hour : int
+ The hour to start the indexing service. Default to `0`. Not used if `mode` is set to `always`.
+ duration : int
+ The duration in hours for the indexing service. Default to `1`. Not used if `mode` is set to `always`.
+ week : list
+ A list of booleans indicating which days of the week the service should run. Default to `[True, True, True, True, True, True, True]`. Not used if `mode` is set to `always`.
+
+ Returns
+ -------
+ dict
+ Return the result of the operation.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "duration": 1,
+ "manual_action_by_user": "none",
+ "mode": "schedule",
+ "start": {
+ "hour": 0
+ },
+ "week": [
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true
+ ]
+ },
+ "success": true
+ }
+ ```
+ """
+ if week is None:
+ week = [True] * 7
+
+ api_name = 'SYNO.Core.MediaIndexing.Scheduler'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'set',
+ 'mode': mode,
+ 'start': {'hour': start_hour},
+ 'duration': duration,
+ 'week': week
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ pass
diff --git a/synology_api/DSM/ControlPanel/InfoCenter.py b/synology_api/DSM/ControlPanel/InfoCenter.py
new file mode 100644
index 00000000..1fea0059
--- /dev/null
+++ b/synology_api/DSM/ControlPanel/InfoCenter.py
@@ -0,0 +1,589 @@
+"""
+Info center class for Synology DSM Info center settings.
+"""
+
+from synology_api import base_api
+
+
+class InfoCenter(base_api.BaseApi):
+ """
+ Info center class for interacting with Synology DSM Info center settings.
+
+ Supported methods:
+ - Getters:
+
+ - Setters:
+ """
+
+ def get_system_info(self) -> dict:
+ """
+ Get system information.
+
+ Returns
+ -------
+ dict
+ Return system information including CPU, memory, and disk usage.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "cpu_clock_speed": 2600,
+ "cpu_cores": "2",
+ "cpu_family": "Ryzen",
+ "cpu_series": "R1600",
+ "cpu_vendor": "AMD",
+ "enabled_ntp": true,
+ "external_pci_slot_info": [
+ {
+ "Occupied": "no",
+ "Recognized": "no",
+ "cardName": "-",
+ "slot": "1"
+ }
+ ],
+ "firmware_date": "2025/01/20",
+ "firmware_ver": "DSM 7.2.2-72806 Update 3",
+ "model": "DS723+",
+ "ntp_server": "time.google.com",
+ "ram_size": 2048,
+ "sata_dev": [],
+ "serial": "YOUR-SERIAL-NUMBER",
+ "support_esata": "yes",
+ "sys_temp": 47,
+ "sys_tempwarn": false,
+ "systempwarn": false,
+ "temperature_warning": false,
+ "time": "2025-07-06 00:23:44",
+ "time_zone": "Amsterdam",
+ "time_zone_desc": "(GMT+01:00) Amsterdam, Berlin, Rome, Stockholm, Vienna",
+ "up_time": "49:46:21",
+ "usb_dev": []
+ },
+ "success": true,
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.System'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'info'
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def get_network_info(self) -> dict:
+ """
+ Get network information.
+
+ Returns
+ -------
+ dict
+ Return network information including interfaces, IP addresses, and DNS settings.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "dns": "YOUR-DNS",
+ "enabled_domain": false,
+ "enabled_samba": true,
+ "gateway": "YOUR-GATEWAY",
+ "hostname": "YOUR-HOSTNAME",
+ "nif": [
+ {
+ "addr": "YOUR-IP-ADDRESS",
+ "duplex": true,
+ "id": "ovs_eth0",
+ "ipv6": [
+ {
+ "addr": "YOUR-IPv6-ADDRESS",
+ "prefix_len": 64,
+ "scope": "global"
+ },
+ {
+ "addr": "YOUR-IPv6-ADDRESS",
+ "prefix_len": 64,
+ "scope": "link"
+ }
+ ],
+ "mac": "YOUR-MAC-ADDRESS",
+ "mask": "255.255.255.0",
+ "mtu": 1500,
+ "speed": 1000,
+ "status": "connected",
+ "type": "ovseth",
+ "use_dhcp": true
+ },
+ {
+ "addr": "YOUR-SECOND-IP-ADDRESS",
+ "duplex": true,
+ "id": "ovs_eth1",
+ "mac": "YOUR-SECOND-MAC-ADDRESS",
+ "mask": "255.255.0.0",
+ "mtu": 1500,
+ "speed": -1,
+ "status": "disconnected",
+ "type": "ovseth",
+ "use_dhcp": true
+ }
+ ],
+ "wins": "",
+ "workgroup": "WORKGROUP"
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.System'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'info',
+ 'type': 'network'
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def get_storage_info(self) -> dict:
+ """
+ Get storage information.
+
+ Returns
+ -------
+ dict
+ Return storage information including volumes, disks, and RAID status.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "hdd_info": [
+ {
+ "action": {
+ "alert": false,
+ "notification": false,
+ "selectable": true,
+ "show_lifetime_chart": true
+ },
+ "action_status": {
+ "action_name": "idle",
+ "action_progress": ""
+ },
+ "action_status_category": "processing",
+ "action_status_key": "idle",
+ "adv_progress": "",
+ "adv_status": "not_support",
+ "allocation_role": "reuse_1",
+ "below_remain_life_mail_notify_thr": false,
+ "below_remain_life_show_thr": false,
+ "below_remain_life_thr": false,
+ "compatibility": "support",
+ "container": {
+ "order": 0,
+ "str": "DS723+",
+ "supportPwrBtnDisable": false,
+ "type": "internal"
+ },
+ "container_id": 0,
+ "device": "/dev/sata1",
+ "disable_secera": false,
+ "diskType": "SATA",
+ "disk_code": "",
+ "disk_location": "Main",
+ "drive_status_category": "health",
+ "drive_status_key": "normal",
+ "erase_time": 450,
+ "firm": "SC60",
+ "firmware_status": "-",
+ "has_system": true,
+ "hide_info": [],
+ "i18nNamingInfo": "[\"dsm:volume:volume_disk\",\" \",\"1\"]",
+ "id": "sata1",
+ "ihm_testing": false,
+ "is4Kn": false,
+ "isSsd": false,
+ "isSynoDrive": false,
+ "isSynoPartition": true,
+ "is_bundle_ssd": false,
+ "is_erasing": false,
+ "longName": "Drive 1",
+ "m2_pool_support": false,
+ "model": "ST4000VN006-3CW104",
+ "name": "Drive 1",
+ "num_id": 1,
+ "order": 1,
+ "overview_status": "normal",
+ "pciSlot": -1,
+ "perf_testing": false,
+ "portType": "normal",
+ "remain_life": {
+ "trustable": true,
+ "value": -1
+ },
+ "remain_life_danger": false,
+ "remote_info": {
+ "compatibility": "disabled",
+ "unc": 0
+ },
+ "sb_days_left": 0,
+ "sb_days_left_below_show_thres": false,
+ "sb_days_left_critical": false,
+ "sb_days_left_warning": false,
+ "serial": "YOUR-FIRST-SERIAL-NUMBER",
+ "size_total": "4000787030016",
+ "slot_id": 1,
+ "smart_progress": "",
+ "smart_status": "normal",
+ "smart_test_limit": 0,
+ "smart_test_support": true,
+ "smart_testing": false,
+ "ssd_unhealth_reason": "none",
+ "status": "normal",
+ "summary_status_category": "health",
+ "summary_status_key": "normal",
+ "temp": 35,
+ "testing_progress": "",
+ "testing_type": "idle",
+ "tray_status": "join",
+ "ui_serial": "YOUR-FIRST-SERIAL-NUMBER",
+ "unc": 0,
+ "used_by": "reuse_1",
+ "vendor": "Seagate",
+ "wcache_force_off": false,
+ "wcache_force_on": false,
+ "wdda_support": false
+ },
+ {
+ "action": {
+ "alert": false,
+ "notification": false,
+ "selectable": true,
+ "show_lifetime_chart": true
+ },
+ "action_status": {
+ "action_name": "idle",
+ "action_progress": ""
+ },
+ "action_status_category": "processing",
+ "action_status_key": "idle",
+ "adv_progress": "",
+ "adv_status": "not_support",
+ "allocation_role": "reuse_1",
+ "below_remain_life_mail_notify_thr": false,
+ "below_remain_life_show_thr": false,
+ "below_remain_life_thr": false,
+ "compatibility": "support",
+ "container": {
+ "order": 0,
+ "str": "DS723+",
+ "supportPwrBtnDisable": false,
+ "type": "internal"
+ },
+ "container_id": 0,
+ "device": "/dev/sata2",
+ "disable_secera": false,
+ "diskType": "SATA",
+ "disk_code": "",
+ "disk_location": "Main",
+ "drive_status_category": "health",
+ "drive_status_key": "normal",
+ "erase_time": 462,
+ "firm": "SC60",
+ "firmware_status": "-",
+ "has_system": true,
+ "hide_info": [],
+ "i18nNamingInfo": "[\"dsm:volume:volume_disk\",\" \",\"2\"]",
+ "id": "sata2",
+ "ihm_testing": false,
+ "is4Kn": false,
+ "isSsd": false,
+ "isSynoDrive": false,
+ "isSynoPartition": true,
+ "is_bundle_ssd": false,
+ "is_erasing": false,
+ "longName": "Drive 2",
+ "m2_pool_support": false,
+ "model": "ST4000VN006-3CW104",
+ "name": "Drive 2",
+ "num_id": 2,
+ "order": 2,
+ "overview_status": "normal",
+ "pciSlot": -1,
+ "perf_testing": false,
+ "portType": "normal",
+ "remain_life": {
+ "trustable": true,
+ "value": -1
+ },
+ "remain_life_danger": false,
+ "remote_info": {
+ "compatibility": "disabled",
+ "unc": 0
+ },
+ "sb_days_left": 0,
+ "sb_days_left_below_show_thres": false,
+ "sb_days_left_critical": false,
+ "sb_days_left_warning": false,
+ "serial": "YOUR-SECOND-SERIAL-NUMBER",
+ "size_total": "4000787030016",
+ "slot_id": 2,
+ "smart_progress": "",
+ "smart_status": "normal",
+ "smart_test_limit": 0,
+ "smart_test_support": true,
+ "smart_testing": false,
+ "ssd_unhealth_reason": "none",
+ "status": "normal",
+ "summary_status_category": "health",
+ "summary_status_key": "normal",
+ "temp": 37,
+ "testing_progress": "",
+ "testing_type": "idle",
+ "tray_status": "join",
+ "ui_serial": "YOUR-SECOND-SERIAL-NUMBER",
+ "unc": 0,
+ "used_by": "reuse_1",
+ "vendor": "Seagate",
+ "wcache_force_off": false,
+ "wcache_force_on": false,
+ "wdda_support": false
+ }
+ ],
+ "vol_info": [
+ {
+ "desc": "",
+ "inode_free": "0",
+ "inode_total": "0",
+ "is_encrypted": false,
+ "name": "volume_1",
+ "status": "normal",
+ "total_size": "206158430208",
+ "used_size": "16905019392",
+ "vol_desc": "Apps",
+ "volume": "volume_1"
+ },
+ {
+ "desc": "",
+ "inode_free": "0",
+ "inode_total": "0",
+ "is_encrypted": false,
+ "name": "volume_2",
+ "status": "normal",
+ "total_size": "3623234412544",
+ "used_size": "1154716925952",
+ "vol_desc": "Stockage",
+ "volume": "volume_2"
+ }
+ ]
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.Storage'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'info',
+ 'type': 'storage_v2'
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def get_services_status(self) -> dict:
+ """
+ Get services status.
+
+ Returns
+ -------
+ dict
+ Return the status of various services running on the Synology DSM.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "service": [
+ {
+ "additional": {
+ "active_status": "inactive"
+ },
+ "display_name_section_key": "helptoc:winmacnfs_mac",
+ "enable_status": "disabled",
+ "service_id": "atalk"
+ },
+ {
+ "additional": {
+ "active_status": "inactive"
+ },
+ "display_name_section_key": "network:bonjourPrinter_subject",
+ "enable_status": "enabled",
+ "service_id": "bonjour"
+ },
+ {
+ "additional": {
+ "active_status": "active"
+ },
+ "display_name_section_key": "helptoc:ntp_service",
+ "enable_status": "enabled",
+ "service_id": "chronyd"
+ },
+ {
+ "additional": {
+ "active_status": "inactive"
+ },
+ "display_name_section_key": "service:cups_printer_daemon",
+ "enable_status": "static",
+ "service_id": "cupsd"
+ },
+ {
+ "additional": {
+ "active_status": "inactive"
+ },
+ "display_name_section_key": "tree:leaf_ftp",
+ "enable_status": "disabled",
+ "service_id": "ftp-pure"
+ },
+ {
+ "additional": {
+ "active_status": "inactive"
+ },
+ "display_name_section_key": "tree:leaf_ftpes",
+ "enable_status": "disabled",
+ "service_id": "ftp-ssl"
+ },
+ {
+ "additional": {
+ "active_status": "inactive"
+ },
+ "display_name_section_key": "remote_key:kmip_tab_title",
+ "enable_status": "disabled",
+ "service_id": "kmip-server"
+ },
+ {
+ "additional": {
+ "active_status": "inactive"
+ },
+ "display_name_section_key": "nfs:nfs_title",
+ "enable_status": "disabled",
+ "service_id": "nfs-server"
+ },
+ {
+ "additional": {
+ "active_status": "active"
+ },
+ "display_name_section_key": "tree:leaf_iscsi",
+ "enable_status": "static",
+ "service_id": "pkg-iscsi"
+ },
+ {
+ "additional": {
+ "active_status": "active"
+ },
+ "display_name_section_key": "helptoc:winmacnfs_win",
+ "enable_status": "enabled",
+ "service_id": "pkg-synosamba-smbd"
+ },
+ {
+ "additional": {
+ "active_status": "active"
+ },
+ "display_name_section_key": "service:wstransfer_title",
+ "enable_status": "enabled",
+ "service_id": "pkg-synosamba-wstransfer-genconf"
+ },
+ {
+ "additional": {
+ "active_status": "active"
+ },
+ "display_name_section_key": "service:service_rsync",
+ "enable_status": "enabled",
+ "service_id": "rsyncd"
+ },
+ {
+ "additional": {
+ "active_status": "inactive"
+ },
+ "display_name_section_key": "tree:leaf_sftp",
+ "enable_status": "disabled",
+ "service_id": "sftp"
+ },
+ {
+ "additional": {
+ "active_status": "active"
+ },
+ "display_name_section_key": "SNMP",
+ "enable_status": "static",
+ "service_id": "snmpd"
+ },
+ {
+ "additional": {
+ "active_status": "active"
+ },
+ "display_name_section_key": "firewall:firewall_service_opt_ssh",
+ "enable_status": "enabled",
+ "service_id": "ssh-shell"
+ },
+ {
+ "additional": {
+ "active_status": "active"
+ },
+ "display_name_section_key": "about:dsm",
+ "enable_status": "static",
+ "service_id": "synoscgi"
+ },
+ {
+ "additional": {
+ "active_status": "inactive"
+ },
+ "display_name_section_key": "firewall:firewall_service_opt_telnet",
+ "enable_status": "disabled",
+ "service_id": "telnetd"
+ },
+ {
+ "additional": {
+ "active_status": "inactive"
+ },
+ "display_name_section_key": "ftp:tftp_title",
+ "enable_status": "disabled",
+ "service_id": "tftp"
+ },
+ {
+ "additional": {
+ "active_status": "inactive"
+ },
+ "display_name_section_key": "helptoc:power_ups",
+ "enable_status": "disabled",
+ "service_id": "ups-net"
+ },
+ {
+ "additional": {
+ "active_status": "inactive"
+ },
+ "display_name_section_key": "helptoc:power_ups",
+ "enable_status": "static",
+ "service_id": "ups-usb"
+ }
+ ]
+ },
+ "success": true,
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.Service'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'get',
+ 'additional': ['active_status']
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ pass
diff --git a/synology_api/DSM/ControlPanel/LoginPortal.py b/synology_api/DSM/ControlPanel/LoginPortal.py
new file mode 100644
index 00000000..2fe0df0d
--- /dev/null
+++ b/synology_api/DSM/ControlPanel/LoginPortal.py
@@ -0,0 +1,829 @@
+"""
+Login portal class for Synology DSM.
+"""
+from synology_api import base_api
+import json
+
+
+class LoginPortal(base_api.BaseApi):
+ """
+ Login portal class for Synology DSM.
+ """
+
+ def get_dsm_web_service_info(self) -> dict:
+ """
+ Get the web status of the login portal.
+
+ Returns
+ -------
+ dict
+ The response from the API call.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "enable_avahi": true,
+ "enable_custom_domain": false,
+ "enable_hsts": false,
+ "enable_https_redirect": false,
+ "enable_max_connections": false,
+ "enable_reuseport": false,
+ "enable_server_header": true,
+ "enable_spdy": true,
+ "enable_ssdp": true,
+ "fqdn": null,
+ "http_port": 5000,
+ "https_port": 5001,
+ "main_app": "DSM",
+ "max_connections": 2048,
+ "max_connections_limit": {
+ "lower": 2048,
+ "upper": 131070
+ },
+ "server_header": "nginx",
+ "support_reuseport": true
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = "SYNO.Core.Web.DSM"
+ info = self.core_list[api_name]
+ api_path = info["path"]
+ req_param = {
+ "version": info["maxVersion"],
+ "method": "get",
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def list_app_portal(self, additionnal: list = []) -> dict:
+ """
+ List application portals.
+
+ Parameters
+ ----------
+ additionnal : list, optional
+ Additional fields to include in the response, by default []. Possible values are "default_setting".
+
+ Returns
+ -------
+ dict
+ The response from the API call.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "portal": [
+ {
+ "display_name": "Active Backup for Microsoft 365 Portal",
+ "enable_redirect": false,
+ "id": "SYNO.SDS.ActiveBackupOffice365.Portal.Instance"
+ },
+ {
+ "display_name": "Synology Calendar",
+ "enable_redirect": false,
+ "id": "SYNO.Cal.Application"
+ },
+ {
+ "display_name": "Synology Contacts",
+ "enable_redirect": false,
+ "id": "SYNO.Contacts.AppInstance"
+ },
+ {
+ "display_name": "Download Station",
+ "enable_redirect": false,
+ "id": "SYNO.SDS.DownloadStation.Application"
+ },
+ {
+ "display_name": "File Station",
+ "enable_redirect": false,
+ "id": "SYNO.SDS.App.FileStation3.Instance"
+ },
+ {
+ "display_name": "Note Station",
+ "enable_redirect": false,
+ "id": "SYNO.SDS.NoteStation.Application"
+ },
+ {
+ "acl": null,
+ "alias": "cam",
+ "display_name": "Surveillance Station",
+ "enable_redirect": false,
+ "fqdn": null,
+ "hsts": false,
+ "http_port": 9900,
+ "id": "SYNO.SDS.SurveillanceStation"
+ },
+ {
+ "display_name": "Synology Drive",
+ "enable_redirect": false,
+ "id": "SYNO.SDS.SheetStation.Application"
+ },
+ {
+ "display_name": "Virtual Machine Manager",
+ "enable_redirect": false,
+ "id": "SYNO.SDS.Virtualization.Application"
+ }
+ ]
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = "SYNO.Core.AppPortal"
+ info = self.core_list[api_name]
+ api_path = info["path"]
+ req_param = {
+ "version": info["maxVersion"],
+ "method": "list",
+ "additional": json.dumps(additionnal),
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def list_reverse_proxy(self) -> dict:
+ """
+ List reverse proxy rules.
+
+ Returns
+ -------
+ dict
+ The response from the API call.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "entries": []
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = "SYNO.Core.AppPortal.ReverseProxy"
+ info = self.core_list[api_name]
+ api_path = info["path"]
+ req_param = {
+ "version": info["maxVersion"],
+ "method": "list",
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def list_access_control(self) -> dict:
+ """
+ List access control rules.
+
+ Returns
+ -------
+ dict
+ The response from the API call.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "entries": [
+ {
+ "UUID": "4d0b7d3d-d8a5-4b91-a160-efd45703005f",
+ "name": "test",
+ "rules": [
+ {
+ "access": true,
+ "address": "127.0.0.1"
+ }
+ ]
+ }
+ ]
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = "SYNO.Core.AppPortal.AccessControl"
+ info = self.core_list[api_name]
+ api_path = info["path"]
+ req_param = {
+ "version": info["maxVersion"],
+ "method": "list",
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def get_login_theme(self) -> dict:
+ """
+ Get the current login theme.
+
+ Returns
+ -------
+ dict
+ The response from the API call.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "background_color": "#FFFFFF",
+ "background_position": "fill",
+ "background_seq": 0,
+ "enable_background_customize": false,
+ "enable_logo_customize": false,
+ "login_footer_enable_html": false,
+ "login_title": "",
+ "login_version_logo": false,
+ "logo_position": "center",
+ "logo_seq": 0,
+ "only_background_color": false,
+ "weather_info": "display"
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = "SYNO.Core.Theme.Login"
+ info = self.core_list[api_name]
+ api_path = info["path"]
+ req_param = {
+ "version": info["maxVersion"],
+ "method": "get",
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def get_app_theme(self, app_id: str) -> dict:
+ """
+ Get the theme for a specific application.
+
+ Parameters
+ ----------
+ app_id : str
+ The ID of the application. The app_id can be found in the `list_app_portal()` returns.
+
+ Returns
+ -------
+ dict
+ The response from the API call.
+
+ Examples
+ --------
+ ```json
+ {
+ "background_color": "#FFFFFF",
+ "background_position": "fill",
+ "background_seq": 0,
+ "enable_background_customize": false,
+ "enable_logo_customize": false,
+ "from_dsm": true,
+ "login_footer_enable_html": false,
+ "login_title": "",
+ "login_version_logo": false,
+ "logo_position": "center",
+ "logo_seq": 0,
+ "only_background_color": false,
+ "weather_info": "display"
+ }
+ ```
+ """
+ api_name = "SYNO.Core.Theme.AppPortalLogin"
+ info = self.core_list[api_name]
+ api_path = info["path"]
+ req_param = {
+ "version": info["maxVersion"],
+ "method": "get",
+ "app": app_id,
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def set_dsm_web_service_info(self,
+ enable_custom_domain: bool, enable_avahi: bool, enable_hsts: bool, enable_https_redirect: bool,
+ enable_max_connections: bool, enable_reuseport: bool, enable_server_header: bool, enable_spdy: bool,
+ enable_ssdp: bool, fqdn: str = "", http_port: int = 5000, https_port: int = 5001, main_app: str = "DSM", max_connections: int = 2048,
+ max_connections_limit: dict = {"lower": 2048, "upper": 131070}, server_header: str = "nginx", support_reuseport: bool = True
+ ) -> dict:
+ """
+ Set the web service information for DSM. Note that this will likely restart the web service.
+
+ Parameters
+ ----------
+ enable_custom_domain : bool
+ Enable custom domain.
+ enable_avahi : bool
+ Enable Avahi (mDNS) support.
+ enable_hsts : bool
+ Enable HTTP Strict Transport Security (HSTS).
+ enable_https_redirect : bool
+ Enable HTTPS redirection.
+ enable_max_connections : bool
+ Enable maximum connections limit.
+ enable_reuseport : bool
+ Enable SO_REUSEPORT option.
+ enable_server_header : bool
+ Enable server header in responses.
+ enable_spdy : bool
+ Enable SPDY protocol support.
+ enable_ssdp : bool
+ Enable SSDP support.
+ fqdn : str, optional
+ Fully qualified domain name, by default "".
+ http_port : int, optional
+ HTTP port number, by default 5000.
+ https_port : int, optional
+ HTTPS port number, by default 5001.
+ main_app : str, optional
+ Main application to launch on login, by default "DSM".
+ max_connections : int, optional
+ Maximum number of connections, by default 2048.
+ max_connections_limit : dict, optional
+ Dictionary with 'lower' and 'upper' keys for max connections limit, by default {"lower": 2048, "upper": 131070}.
+ server_header : str, optional
+ Server header string, by default "nginx".
+ support_reuseport : bool, optional
+ Whether SO_REUSEPORT is supported, by default True.
+
+ Returns
+ -------
+ dict
+ The response from the API call.
+
+ Examples
+ --------
+ ```json
+ {
+ "success": true
+ }
+ ```
+ """
+ api_name = "SYNO.Core.Web.DSM"
+ info = self.core_list[api_name]
+ api_path = info["path"]
+ req_param = {
+ "version": info["maxVersion"],
+ "method": "set",
+ "enable_custom_domain": enable_custom_domain,
+ "enable_avahi": enable_avahi,
+ "enable_hsts": enable_hsts,
+ "enable_https_redirect": enable_https_redirect,
+ "enable_max_connections": enable_max_connections,
+ "enable_reuseport": enable_reuseport,
+ "enable_server_header": enable_server_header,
+ "enable_spdy": enable_spdy,
+ "enable_ssdp": enable_ssdp,
+ "fqdn": fqdn,
+ "http_port": http_port,
+ "https_port": https_port,
+ "main_app": main_app,
+ "max_connections": max_connections,
+ "max_connections_limit": json.dumps(max_connections_limit),
+ "server_header": server_header,
+ "support_reuseport": support_reuseport
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def set_login_theme(self,
+ background_color: str = "#FFFFFF", background_position: str = "fill", background_seq: int = 0,
+ enable_background_customize: bool = False, enable_logo_customize: bool = False,
+ login_footer_enable_html: bool = False, login_title: str = "", login_version_logo: bool = False,
+ logo_position: str = "center", logo_seq: int = 0, only_background_color: bool = False,
+ weather_info: str = "display"
+ ) -> dict:
+ """
+ Set the login theme for DSM.
+
+ Parameters
+ ----------
+ background_color : str, optional
+ Background color in HEX format, by default "#FFFFFF".
+ background_position : str, optional
+ Background image position, by default "fill". Possible values are "fill", "fit", "stretch", "center", "tile".
+ background_seq : int, optional
+ Background image sequence number, by default 0.
+ enable_background_customize : bool, optional
+ Enable custom background image, by default False.
+ enable_logo_customize : bool, optional
+ Enable custom logo image, by default False.
+ login_footer_enable_html : bool, optional
+ Enable HTML in the login footer, by default False.
+ login_title : str, optional
+ Custom login title text, by default "".
+ login_version_logo : bool, optional
+ Show DSM version logo on the login page, by default False.
+ logo_position : str, optional
+ Logo image position, by default "center". Possible values are "left", "center", "right".
+ logo_seq : int, optional
+ Logo image sequence number, by default 0.
+ only_background_color : bool, optional
+ Use only background color without image, by default False.
+ weather_info : str, optional
+ Weather information display option, by default "display". Possible values are "display", "hide".
+
+ Returns
+ -------
+ dict
+ The response from the API call.
+
+ Examples
+ --------
+ ```json
+ {
+ "success": true
+ }
+ ```
+ """
+ api_name = "SYNO.Core.Theme.Login"
+ info = self.core_list[api_name]
+ api_path = info["path"]
+ req_param = {
+ "version": info["maxVersion"],
+ "method": "set",
+ "background_color": background_color,
+ "background_position": background_position,
+ "background_seq": background_seq,
+ "enable_background_customize": enable_background_customize,
+ "enable_logo_customize": enable_logo_customize,
+ "login_footer_enable_html": login_footer_enable_html,
+ "login_title": login_title,
+ "login_version_logo": login_version_logo,
+ "logo_position": logo_position,
+ "logo_seq": logo_seq,
+ "only_background_color": only_background_color,
+ "weather_info": weather_info
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def get_config(self) -> dict:
+ """
+ Get the login portal configuration.
+
+ Returns
+ -------
+ dict
+ The response from the API call.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "show_titlebar": true
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = "SYNO.Core.AppPortal.Config"
+ info = self.core_list[api_name]
+ api_path = info["path"]
+ req_param = {
+ "version": info["maxVersion"],
+ "method": "get",
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def set_config(self, show_titlebar: bool) -> dict:
+ """
+ Set the login portal configuration.
+
+ Parameters
+ ----------
+ show_titlebar : bool
+ Whether to show the title bar on the login portal.
+
+ Returns
+ -------
+ dict
+ The response from the API call.
+
+ Examples
+ --------
+ ```json
+ {
+ "success": true
+ }
+ ```
+ """
+ api_name = "SYNO.Core.AppPortal.Config"
+ info = self.core_list[api_name]
+ api_path = info["path"]
+ req_param = {
+ "version": info["maxVersion"],
+ "method": "set",
+ "show_titlebar": show_titlebar
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def create_access_control_profile(self, name: str, rules: list) -> dict:
+ """
+ Create an access control profile.
+
+ Parameters
+ ----------
+ name : str
+ Name of the access control profile.
+ rules : list
+ List of rules for the access control profile. Each rule is a dictionary with keys:
+ - action: "allow" or "deny"
+ - source: source IP or subnet in CIDR notation
+ - protocol: "http", "https", or "both"
+ - port: port number or range (e.g., "80", "443", "8000-9000")
+
+ Returns
+ -------
+ dict
+ The response from the API call.
+
+ Examples
+ --------
+ ```json
+ {
+ "success": true
+ }
+ ```
+ """
+ api_name = "SYNO.Core.AppPortal.AccessControl"
+ info = self.core_list[api_name]
+ api_path = info["path"]
+ req_param = {
+ "version": info["maxVersion"],
+ "method": "create",
+ "name": name,
+ "rules": json.dumps(rules)
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def edit_access_control_profile(self, uuid: str, name: str, rules: list) -> dict:
+ """
+ Edit an existing access control profile.
+
+ Parameters
+ ----------
+ uuid : str
+ UUID of the access control profile to edit. The UUID can be found in the `list_access_control()` returns.
+ name : str
+ New name for the access control profile.
+ rules : list
+ New list of rules for the access control profile. Each rule is a dictionary with keys:
+ - address : str (source IP or subnet in CIDR notation)
+ - access : bool (True for allow, False for deny)
+
+ Returns
+ -------
+ dict
+ The response from the API call.
+
+ Examples
+ --------
+ ```json
+ {
+ "success": true
+ }
+ ```
+ """
+ api_name = "SYNO.Core.AppPortal.AccessControl"
+ info = self.core_list[api_name]
+ api_path = info["path"]
+ req_param = {
+ "version": info["maxVersion"],
+ "method": "edit",
+ "uuid": uuid,
+ "name": name,
+ "rules": json.dumps(rules)
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def delete_access_control_profile(self, uuids: list) -> dict:
+ """
+ Delete one or more access control profiles.
+
+ Parameters
+ ----------
+ uuids : list
+ List of UUIDs of the access control profiles to delete.
+
+ Returns
+ -------
+ dict
+ The response from the API call.
+
+ Examples
+ --------
+ ```json
+ {
+ "success": true
+ }
+ ```
+ """
+ api_name = "SYNO.Core.AppPortal.AccessControl"
+ info = self.core_list[api_name]
+ api_path = info["path"]
+ req_param = {
+ "version": info["maxVersion"],
+ "method": "delete",
+ "uuids": json.dumps(uuids)
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def create_reverse_proxy_rule(self, entry: dict) -> dict:
+ """
+ Create a reverse proxy rule.
+
+ Parameters
+ ----------
+ entry : dict
+ The reverse proxy rule configuration. Example:
+ {
+ "description": "yrdy",
+ "proxy_connect_timeout": 60,
+ "proxy_read_timeout": 60,
+ "proxy_send_timeout": 60,
+ "proxy_http_version": 1,
+ "proxy_intercept_errors": False,
+ "frontend": {
+ "acl": None,
+ "fqdn": None,
+ "port": 8000,
+ "protocol": 0,
+ "https": {"hsts": False}
+ },
+ "backend": {
+ "fqdn": "localhost",
+ "port": 8080,
+ "protocol": 0
+ },
+ "customize_headers": [
+ {"name": "yoyo", "value": "test"}
+ ]
+ }
+
+ Returns
+ -------
+ dict
+ Success response from the API.
+
+ Examples
+ --------
+ ```json
+ {
+ 'success': True
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.AppPortal.ReverseProxy'
+ info = self.core_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': 1,
+ 'method': 'create',
+ 'entry': json.dumps(entry)
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def edit_reverse_proxy_rule(self, entry: dict) -> dict:
+ """
+ Edit a reverse proxy rule.
+
+ Parameters
+ ----------
+ entry : dict
+ The reverse proxy rule configuration, including UUID and _key. Example:
+ {
+ "description": "yrdy",
+ "proxy_connect_timeout": 60,
+ "proxy_read_timeout": 60,
+ "proxy_send_timeout": 60,
+ "proxy_http_version": 1,
+ "proxy_intercept_errors": False,
+ "UUID": "91dbcc5b-2467-4047-996c-2b5beb4fbefa",
+ "backend": {
+ "fqdn": "localhost",
+ "port": 8080,
+ "protocol": 0
+ },
+ "customize_headers": [
+ {"name": "yoyo", "value": "test"}
+ ],
+ "frontend": {
+ "acl": None,
+ "fqdn": None,
+ "port": 8000,
+ "protocol": 0,
+ "https": {"hsts": False}
+ }
+ }
+
+ Returns
+ -------
+ dict
+ API response.
+
+ Examples
+ --------
+ ```json
+ {
+ 'success': True
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.AppPortal.ReverseProxy'
+ info = self.core_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': 1,
+ 'method': 'update',
+ 'entry': json.dumps(entry)
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def delete_reverse_proxy_rule(self, uuids: list) -> dict:
+ """
+ Delete one or more reverse proxy rules.
+
+ Parameters
+ ----------
+ uuids : list
+ List of UUIDs of the reverse proxy rules to delete.
+
+ Returns
+ -------
+ dict
+ The response from the API call.
+
+ Examples
+ --------
+ ```json
+ {
+ "success": true
+ }
+ ```
+ """
+ api_name = "SYNO.Core.AppPortal.ReverseProxy"
+ info = self.core_list[api_name]
+ api_path = info["path"]
+ req_param = {
+ "version": info["maxVersion"],
+ "method": "delete",
+ "uuids": json.dumps(uuids)
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def edit_app_portal(self, id: str, display_name: str, additional: dict, enable_custom_domain: bool = False,
+ acl: str = None, fqdn: str = None, enable_redirect: bool = False) -> dict:
+ """
+ Edit (set) an app portal.
+
+ Parameters
+ ----------
+ id : str
+ The app portal instance ID.
+ display_name : str
+ The display name for the portal.
+ additional : dict
+ Additional settings, e.g.:
+ {
+ "default_setting": {
+ "alias": "microsoft365",
+ "fqdn": "",
+ "hsts": False,
+ "http_port": 28003,
+ "https_port": 28004
+ }
+ }
+ enable_custom_domain : bool, optional
+ Enable custom domain. Default is False.
+ acl : str, optional
+ Access control profile uuid. Default is None.
+ fqdn : str, optional
+ Fully qualified domain name. Default is None.
+ enable_redirect : bool, optional
+ Enable redirect. Default is False.
+
+ Returns
+ -------
+ dict
+ API response.
+
+ Examples
+ --------
+ ```json
+ {
+ 'success': True
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.AppPortal'
+ info = self.core_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': 2,
+ 'method': 'set',
+ 'id': id,
+ 'display_name': display_name,
+ 'additional': json.dumps(additional),
+ 'enable_custom_domain': enable_custom_domain,
+ 'acl': acl,
+ 'fqdn': fqdn,
+ 'enable_redirect': enable_redirect
+ }
+ return self.request_data(api_name, api_path, req_param)
diff --git a/synology_api/DSM/ControlPanel/Network.py b/synology_api/DSM/ControlPanel/Network.py
new file mode 100644
index 00000000..9a221ad6
--- /dev/null
+++ b/synology_api/DSM/ControlPanel/Network.py
@@ -0,0 +1,906 @@
+"""
+Network class for Synology DSM network settings.
+"""
+
+from synology_api import base_api
+import json
+
+
+class Network(base_api.BaseApi):
+ """
+ Network class for interacting with Synology DSM network settings.
+
+ Supported methods:
+ - Getters:
+ - Get general settings
+ - Get proxy settings
+ - Get list of gateways
+ - Get list of network interfaces
+ - Get OVS status
+ - Get list of bond interfaces
+ - Get list of ethernet interfaces
+ - Get list of PPPoE interfaces
+ - Get list of PPTP VPN interfaces
+ - Get list of OpenVPN with conf file VPN interfaces
+ - Get list of OpenVPN VPN interfaces
+ - Get list of L2TP VPN interfaces
+ - Get traffic control rules
+ - Get port list per service
+
+ - Setters:
+ - Set general settings
+ - Set proxy settings
+ - Set ethernet interfaces
+ """
+
+ def get_general_settings(self) -> dict:
+ """
+ Get general network settings.
+
+ Returns
+ -------
+ dict
+ General network settings.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "arp_ignore": true,
+ "dns_manual": true,
+ "dns_primary": "103.86.96.100",
+ "dns_secondary": "192.168.1.1",
+ "enable_ip_conflict_detect": true,
+ "enable_windomain": false,
+ "gateway": "192.168.1.1",
+ "gateway_info": {
+ "ifname": "ovs_eth0",
+ "ip": "192.168.1.14",
+ "mask": "255.255.255.0",
+ "status": "connected",
+ "type": "ovseth",
+ "use_dhcp": true
+ },
+ "ipv4_first": false,
+ "multi_gateway": false,
+ "server_name": "SERVER-NAME",
+ "use_dhcp_domain": true,
+ "v6gateway": "fe80::670:56ff:fe48:1f94"
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.Network'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'get'
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def set_general_settings(
+ self, server_name: str, dns_manual: bool, dns_primary: str,
+ dns_secondary: str, arp_ignore: bool, multi_gateway: bool,
+ ipv4_first: bool, enable_ip_conflict_detect: bool, use_dhcp_domain: bool
+ ) -> dict:
+ """
+ Set general network settings.
+
+ Parameters
+ ----------
+ server_name : str
+ Server name.
+ dns_manual : bool
+ Whether to set DNS manually.
+ dns_primary : str
+ Primary DNS server.
+ dns_secondary : str
+ Secondary DNS server.
+ arp_ignore : bool
+ Whether to ignore ARP.
+ multi_gateway : bool
+ Whether to enable multiple gateways.
+ ipv4_first : bool
+ Whether to prioritize IPv4.
+ enable_ip_conflict_detect : bool
+ Whether to enable IP conflict detection.
+ use_dhcp_domain : bool
+ Whether to use DHCP domain.
+
+ Returns
+ -------
+ dict
+ Result of setting general network settings.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "has_fail": false,
+ "result": [
+ {
+ "api": "SYNO.Core.Network",
+ "data": {
+ "hostname_changed_and_join_domain": false
+ },
+ "method": "set",
+ "success": true,
+ "version": 2
+ }
+ ]
+ },
+ "success": true
+ }
+ ```
+ """
+
+ api_name = 'SYNO.Core.Network'
+ info = self.gen_list[api_name]
+ compound = [
+ {
+ 'api': api_name,
+ 'version': info['maxVersion'],
+ 'method': 'set',
+ 'server_name': server_name,
+ 'dns_manual': dns_manual,
+ 'dns_primary': dns_primary,
+ 'dns_secondary': dns_secondary,
+ 'arp_ignore': arp_ignore,
+ 'multi_gateway': multi_gateway,
+ 'ipv4_first': ipv4_first,
+ 'enable_ip_conflict_detect': enable_ip_conflict_detect,
+ 'use_dhcp_domain': use_dhcp_domain
+ }
+ ]
+ return self.batch_request(compound=compound)
+
+ def get_proxy_settings(self) -> dict:
+ """
+ Get proxy settings.
+
+ Returns
+ -------
+ dict
+ Proxy settings.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "enable": false,
+ "enable_auth": false,
+ "enable_bypass": true,
+ "enable_different_host": false,
+ "http_host": "",
+ "http_port": "80",
+ "https_host": "",
+ "https_port": "80",
+ "password": "\t\t\t\t\t\t\t\t",
+ "username": ""
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.Network.Proxy'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'get'
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def set_proxy_settings(
+ self, enable: bool, enable_auth: bool, enable_bypass: bool,
+ enable_different_host: bool, http_host: str, http_port: str,
+ https_host: str, https_port: str, username: str = None, password: str = None
+ ) -> dict:
+ """
+ Set proxy settings.
+
+ Parameters
+ ----------
+ enable : bool
+ Whether to enable proxy.
+ enable_auth : bool
+ Whether to enable authentication.
+ enable_bypass : bool
+ Whether to enable bypass.
+ enable_different_host : bool
+ Whether to enable different host.
+ http_host : str
+ HTTP host.
+ http_port : str
+ HTTP port.
+ https_host : str
+ HTTPS host.
+ https_port : str
+ HTTPS port.
+ username : str, optional
+ Username for authentication. Default is None.
+ password : str, optional
+ Password for authentication. Default is None.
+
+ Returns
+ -------
+ dict
+ Result of setting proxy settings.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "has_fail": false,
+ "result": [
+ {
+ "api": "SYNO.Core.Network.Proxy",
+ "method": "set",
+ "success": true,
+ "version": 1
+ }
+ ]
+ },
+ "success": true
+ }
+ ```
+ """
+
+ api_name = 'SYNO.Core.Network.Proxy'
+ info = self.gen_list[api_name]
+ compound = [
+ {
+ 'api': api_name,
+ 'version': info['maxVersion'],
+ 'method': 'set',
+ 'enable': enable,
+ 'enable_auth': enable_auth,
+ 'enable_bypass': enable_bypass,
+ 'enable_different_host': enable_different_host,
+ 'http_host': http_host,
+ 'http_port': http_port,
+ 'https_host': https_host,
+ 'https_port': https_port
+ }
+ ]
+
+ if username and password:
+ if self.session._secure:
+ compound[0]['username'] = username
+ compound[0]['password'] = password
+ else:
+ params_enc = {
+ 'username': username,
+ 'password': password
+ }
+ compound[0].update(self.session.encrypt_params(params_enc))
+
+ return self.batch_request(compound=compound)
+
+ def get_gateway_list(self) -> dict:
+ """
+ Get list of gateways.
+
+ Returns
+ -------
+ dict
+ List of gateways.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "configs": [
+ {
+ "class": "ethernet",
+ "dns": "192.168.1.1",
+ "gateway": "192.168.1.1",
+ "ifname": "ovs_eth0",
+ "priority": 0,
+ "slave": false
+ }
+ ]
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.Network.Gateway.List'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'get'
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def get_interfaces_list(self) -> dict:
+ """
+ Get list of network interfaces.
+
+ Returns
+ -------
+ dict
+ List of network interfaces.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": [
+ {
+ "ifname": "ovs_eth0",
+ "ip": "192.168.1.14",
+ "mask": "255.255.255.0",
+ "speed": 1000,
+ "status": "connected",
+ "type": "ovseth",
+ "use_dhcp": true
+ },
+ {
+ "ifname": "ovs_eth1",
+ "ip": "169.254.183.6",
+ "mask": "255.255.0.0",
+ "speed": -1,
+ "status": "disconnected",
+ "type": "ovseth",
+ "use_dhcp": true
+ },
+ {
+ "ifname": "pppoe",
+ "ip": "",
+ "mask": "",
+ "speed": 0,
+ "status": "disconnected",
+ "type": "pppoe",
+ "use_dhcp": true
+ }
+ ],
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.Network.Interface'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'list'
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def get_ovs_status(self) -> dict:
+ """
+ Get infos if ovs is enabled or not.
+
+ Returns
+ -------
+ dict
+ Infos about ovs status.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "enable_ovs": true
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.Network.OVS'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'get'
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def get_bond_list(self) -> dict:
+ """
+ Get list of bond interfaces.
+
+ Returns
+ -------
+ dict
+ List of bond interfaces.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": [
+ {
+ "block": 0,
+ "dns": "192.168.1.1",
+ "duplex": true,
+ "enable_ha_ip": false,
+ "enable_vlan": false,
+ "enabled": true,
+ "error": false,
+ "gateway": "192.168.1.1",
+ "ha_local_ip": "",
+ "ha_local_mask": "",
+ "ifname": "ovs_bond0",
+ "ip": "192.168.1.14",
+ "ipv6": [
+ "2a01:cb05:814e:7d00:9209:d0ff:fe25:7371/64",
+ "fe80::9209:d0ff:fe25:7371/64"
+ ],
+ "is_default_gateway": false,
+ "is_main_ha_ip": false,
+ "mask": "255.255.255.0",
+ "max_supported_speed": -1,
+ "mode": "balance-slb",
+ "mtu": 1500,
+ "mtu_config": 1500,
+ "nat": false,
+ "slaves": [
+ {
+ "block": 0,
+ "dns": "",
+ "duplex": true,
+ "enable_ha_ip": false,
+ "enable_vlan": false,
+ "gateway": "",
+ "ha_local_ip": "",
+ "ha_local_mask": "",
+ "ifname": "eth0",
+ "ip": "",
+ "ipv6": [],
+ "is_default_gateway": false,
+ "is_main_ha_ip": false,
+ "mask": "",
+ "max_supported_speed": 1000,
+ "mtu": 1500,
+ "mtu_config": 1500,
+ "nat": false,
+ "speed": 1000,
+ "status": "connected",
+ "type": "lan",
+ "use_dhcp": true,
+ "vlan_id": 0
+ },
+ {
+ "block": 0,
+ "dns": "",
+ "duplex": true,
+ "enable_ha_ip": false,
+ "enable_vlan": false,
+ "gateway": "",
+ "ha_local_ip": "",
+ "ha_local_mask": "",
+ "ifname": "eth1",
+ "ip": "",
+ "ipv6": [],
+ "is_default_gateway": false,
+ "is_main_ha_ip": false,
+ "mask": "",
+ "max_supported_speed": 1000,
+ "mtu": 1500,
+ "mtu_config": 1500,
+ "nat": false,
+ "speed": -1,
+ "status": "disconnected",
+ "type": "lan",
+ "use_dhcp": true,
+ "vlan_id": 0
+ }
+ ],
+ "speed": 1000,
+ "status": "connected",
+ "type": "ovsbond",
+ "use_dhcp": true,
+ "vlan_id": 0
+ }
+ ],
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.Network.Bond'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'list'
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def get_ethernet_interface_list(self) -> dict:
+ """
+ Get list of ethernet interfaces.
+
+ Returns
+ -------
+ dict
+ List of ethernet interfaces.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": [
+ {
+ "block": 0,
+ "dns": "192.168.1.1",
+ "duplex": true,
+ "enable_ha_ip": false,
+ "enable_vlan": false,
+ "gateway": "192.168.1.1",
+ "ha_local_ip": "",
+ "ha_local_mask": "",
+ "ifname": "ovs_eth0",
+ "ip": "192.168.1.14",
+ "ipv6": [
+ "2a01:cb05:814e:7d00:9209:d0ff:fe25:7371/64",
+ "fe80::9209:d0ff:fe25:7371/64"
+ ],
+ "is_default_gateway": false,
+ "is_main_ha_ip": false,
+ "mask": "255.255.255.0",
+ "max_supported_speed": 1000,
+ "mtu": 1500,
+ "mtu_config": 1500,
+ "nat": false,
+ "speed": 1000,
+ "status": "connected",
+ "type": "ovseth",
+ "use_dhcp": true,
+ "vlan_id": 0
+ },
+ {
+ "block": 0,
+ "dns": "",
+ "duplex": true,
+ "enable_ha_ip": false,
+ "enable_vlan": false,
+ "gateway": "",
+ "ha_local_ip": "",
+ "ha_local_mask": "",
+ "ifname": "ovs_eth1",
+ "ip": "169.254.183.6",
+ "ipv6": [],
+ "is_default_gateway": false,
+ "is_main_ha_ip": false,
+ "mask": "255.255.0.0",
+ "max_supported_speed": 1000,
+ "mtu": 1500,
+ "mtu_config": 1500,
+ "nat": false,
+ "speed": -1,
+ "status": "disconnected",
+ "type": "ovseth",
+ "use_dhcp": true,
+ "vlan_id": 0
+ }
+ ],
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.Network.Ethernet'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'list'
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def set_ethernet_interfaces(self, configs: list) -> dict:
+ """
+ Set ethernet interfaces.
+
+ Parameters
+ ----------
+ configs : list
+ List of configurations for ethernet interfaces. Each configuration is a dictionary with the following keys:
+ - ifname : str
+ Interface name.
+ - use_dhcp : bool
+ Whether to use DHCP.
+ - enable_ha_ip : bool, optional
+ Whether to enable HA IP.
+ - is_default_gateway : bool, optional
+ Whether this interface is the default gateway.
+ - mtu : int, optional
+ MTU size.
+ - enable_vlan : bool, optional
+ Whether to enable VLAN.
+ - ip : str, optional
+ IP address.
+ - mask : str, optional
+ Subnet mask.
+ - gateway : str, optional
+ Gateway address.
+ - dns : str, optional
+ DNS server address.
+
+ Returns
+ -------
+ dict
+ Result of setting ethernet interfaces.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "has_fail": false,
+ "result": [
+ {
+ "api": "SYNO.Core.Network.Ethernet",
+ "method": "set",
+ "success": true,
+ "version": 2
+ }
+ ]
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.Network.Ethernet'
+ info = self.gen_list[api_name]
+ compound = [
+ {
+ 'api': api_name,
+ 'version': info['maxVersion'],
+ 'method': 'set',
+ 'configs': configs
+ }
+ ]
+ return self.batch_request(compound=compound)
+
+ def get_pppoe_interface_list(self) -> dict:
+ """
+ Get list of pppoe interfaces.
+
+ Returns
+ -------
+ dict
+ List of pppoe interfaces.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": [
+ {
+ "devs": [
+ "ovs_eth0",
+ "ovs_eth1"
+ ],
+ "guest_enabled": false,
+ "ifname": "pppoe",
+ "ip": "",
+ "is_default_gateway": 1,
+ "mask": "",
+ "mtu_config": "1492",
+ "password": "",
+ "real_ifname": "ovs_eth0",
+ "status": "disconnected",
+ "type": "pppoe",
+ "use_dhcp": true,
+ "username": ""
+ }
+ ],
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.Network.PPPoE'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'list'
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def get_vpn_pptp_list(self) -> dict:
+ """
+ Get list of pptp vpn interfaces.
+
+ Returns
+ -------
+ dict
+ List of pptp vpn interfaces.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": [],
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.Network.VPN.PPTP'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'list'
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def get_vpn_openvpn_with_conf_list(self) -> dict:
+ """
+ Get list of openvpn with conf file vpn interfaces.
+
+ Returns
+ -------
+ dict
+ List of openvpn with conf file vpn interfaces.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": [],
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.Network.VPN.OpenVPNWithConf'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'list'
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def get_vpn_openvpn_list(self) -> dict:
+ """
+ Get list of openvpn vpn interfaces.
+
+ Returns
+ -------
+ dict
+ List of openvpn vpn interfaces.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": [],
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.Network.VPN.OpenVPN'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'list'
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def get_vpn_l2tp_list(self) -> dict:
+ """
+ Get list of l2tp vpn interfaces.
+
+ Returns
+ -------
+ dict
+ List of l2tp vpn interfaces.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": [],
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.Network.VPN.L2TP'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'list'
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def get_traffic_control_rules(self, adapter: str) -> dict:
+ """
+ Get traffic control rules.
+
+ Parameters
+ ----------
+ adapter : str
+ Adapter name, e.g. 'ovs_eth0'.
+
+ Returns
+ -------
+ dict
+ A dictionary containing the traffic control rules for the specified adapter.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "rules": [],
+ "total": 0
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.Network.TrafficControl.Rules'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'load',
+ 'adapter': adapter
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def get_port_list_per_service(self) -> dict:
+ """
+ Get port list per service.
+
+ Returns
+ -------
+ dict
+ Port list per service.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "port_info": [
+ {
+ "desc": "rsync",
+ "dst_port": [
+ "873"
+ ],
+ "name": "rsync",
+ "port_id": "netbkp",
+ "protocol": "tcp",
+ "src_port": null
+ },
+ {
+ "desc": "Network MFP",
+ "dst_port": [
+ "3240-3259"
+ ],
+ "name": "Network MFP",
+ "port_id": "mfp",
+ "protocol": "tcp",
+ "src_port": null
+ }
+ ]
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.Service.PortInfo'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'load',
+ 'target': json.dumps(["traffic_control"])
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ pass
diff --git a/synology_api/DSM/ControlPanel/Notifications.py b/synology_api/DSM/ControlPanel/Notifications.py
new file mode 100644
index 00000000..46fc1f66
--- /dev/null
+++ b/synology_api/DSM/ControlPanel/Notifications.py
@@ -0,0 +1,1204 @@
+"""
+Notifications API endpoint.
+"""
+from synology_api import base_api
+import json
+
+
+class Notifications(base_api.BaseApi):
+ """
+ Notifications API endpoint.
+ """
+
+ def list_filter_settings(self) -> dict:
+ """
+ List current filter settings.
+
+ Returns
+ -------
+ dict
+ Current filter settings including enabled rule levels and types.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "All": [
+ {
+ "appid": "SYNO.SDS.AdminCenter.Application",
+ "format": "mail",
+ "group": "System",
+ "level": "NOTIFICATION_INFO",
+ "name": "AutoBlockAdd",
+ "source": "dsm",
+ "tag": "AutoBlockAdd",
+ "title": "IP address blocked",
+ "warnPercent": 1
+ },
+ {
+ "appid": "SYNO.SDS.AdminCenter.Application",
+ "format": "mail",
+ "group": "System",
+ "level": "NOTIFICATION_WARN",
+ "name": "AutoBlockDatabaseRulesWarning",
+ "source": "dsm",
+ "tag": "AutoBlockDatabaseRulesWarning",
+ "title": "Too many IP addresses in the Block List on %HOSTNAME%",
+ "warnPercent": 1
+ },
+ {
+ "appid": "SYNO.SDS.AdminCenter.Application",
+ "format": "mail",
+ "group": "System",
+ "level": "NOTIFICATION_ERROR",
+ "name": "CMSClientConnectFailed",
+ "source": "dsm",
+ "tag": "CMSClientConnectFailed",
+ "title": "Unable to connect to the CMS Host",
+ "warnPercent": 1
+ },
+ {
+ "appid": "SYNO.SDS.AdminCenter.Application",
+ "format": "mail",
+ "group": "System",
+ "level": "NOTIFICATION_INFO",
+ "name": "CMSClientDetachSuccess",
+ "source": "dsm",
+ "tag": "CMSClientDetachSuccess",
+ "title": "Disjoined from CMS host",
+ "warnPercent": 1
+ },
+ {
+ "appid": "SYNO.SDS.AdminCenter.Application",
+ "format": "mail",
+ "group": "System",
+ "level": "NOTIFICATION_INFO",
+ "name": "CMSClientJoinSuccess",
+ "source": "dsm",
+ "tag": "CMSClientJoinSuccess",
+ "title": "Joined CMS host",
+ "warnPercent": 1
+ }
+ ],
+ "send_welcome_mail": false,
+ "sender_mail": "test@gmail.com",
+ "sender_name": "",
+ "smtp_auth": {
+ "enable": true,
+ "user": "test@gmail.com"
+ },
+ "smtp_info": {
+ "port": 465,
+ "server": "smtp.gmail.com",
+ "ssl": true
+ },
+ "subject_prefix": "[SYNO-FLORENTB]"
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.Notification.Mail.Conf'
+ info = self.core_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'get'
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def list_event(self) -> dict:
+ """
+ List recent notification events.
+
+ Returns
+ -------
+ dict
+ Recent notification events including timestamps, app IDs, levels, and messages.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "All": [
+ {
+ "appid": "SYNO.SDS.AdminCenter.Application",
+ "format": "mail",
+ "group": "System",
+ "level": "NOTIFICATION_INFO",
+ "name": "AutoBlockAdd",
+ "source": "dsm",
+ "tag": "AutoBlockAdd",
+ "title": "IP address blocked",
+ "warnPercent": 1
+ },
+ {
+ "appid": "SYNO.SDS.AdminCenter.Application",
+ "format": "mail",
+ "group": "System",
+ "level": "NOTIFICATION_WARN",
+ "name": "AutoBlockDatabaseRulesWarning",
+ "source": "dsm",
+ "tag": "AutoBlockDatabaseRulesWarning",
+ "title": "Too many IP addresses in the Block List on %HOSTNAME%",
+ "warnPercent": 1
+ },
+ {
+ "appid": "SYNO.SDS.AdminCenter.Application",
+ "format": "mail",
+ "group": "System",
+ "level": "NOTIFICATION_ERROR",
+ "name": "CMSClientConnectFailed",
+ "source": "dsm",
+ "tag": "CMSClientConnectFailed",
+ "title": "Unable to connect to the CMS Host",
+ "warnPercent": 1
+ },
+ {
+ "appid": "SYNO.SDS.AdminCenter.Application",
+ "format": "mail",
+ "group": "System",
+ "level": "NOTIFICATION_INFO",
+ "name": "CMSClientDetachSuccess",
+ "source": "dsm",
+ "tag": "CMSClientDetachSuccess",
+ "title": "Disjoined from CMS host",
+ "warnPercent": 1
+ }
+ ]
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.Notification.Advance.FilterSettings.Template'
+ info = self.core_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['minVersion'],
+ 'method': 'list'
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def get_filter_rule_settings(self, template_id: int) -> dict:
+ """
+ Get the filter settings for a specific template.
+
+ Parameters
+ ----------
+ template_id : int
+ The ID of the template to retrieve settings for.
+
+ Returns
+ -------
+ dict
+ API response containing the filter settings for the specified template.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "All": [
+ {
+ "appid": "SYNO.SDS.AdminCenter.Application",
+ "enabled": false,
+ "format": "mail",
+ "group": "System",
+ "level": "NOTIFICATION_INFO",
+ "name": "AutoBlockAdd",
+ "source": "dsm",
+ "tag": "AutoBlockAdd",
+ "title": "IP address blocked",
+ "warnPercent": 1
+ },
+ {
+ "appid": "SYNO.SDS.AdminCenter.Application",
+ "enabled": true,
+ "format": "mail",
+ "group": "System",
+ "level": "NOTIFICATION_WARN",
+ "name": "AutoBlockDatabaseRulesWarning",
+ "source": "dsm",
+ "tag": "AutoBlockDatabaseRulesWarning",
+ "title": "Too many IP addresses in the Block List on %HOSTNAME%",
+ "warnPercent": 1
+ },
+ {
+ "appid": "SYNO.SDS.AdminCenter.Application",
+ "enabled": true,
+ "format": "mail",
+ "group": "System",
+ "level": "NOTIFICATION_ERROR",
+ "name": "CMSClientConnectFailed",
+ "source": "dsm",
+ "tag": "CMSClientConnectFailed",
+ "title": "Unable to connect to the CMS Host",
+ "warnPercent": 1
+ }
+ ],
+ "template_id": 5,
+ "template_name": "test"
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.Notification.Advance.FilterSettings.Template'
+ info = self.core_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['minVersion'],
+ 'method': 'get',
+ 'template_id': template_id
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def get_push_mail(self) -> dict:
+ """
+ Get push mail configuration.
+
+ Returns
+ -------
+ dict
+ Push notification configuration details including service status and linked devices.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "enable_mail": true,
+ "mail": [
+ "test@gmail.com"
+ ],
+ "subject_prefix": "",
+ "template_id": 1
+ },
+ "success": true
+ }
+ """
+ api_name = 'SYNO.Core.Notification.Push.Mail'
+ info = self.core_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'get'
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def refresh_token(self) -> dict:
+ """
+ Refresh the push notification token.
+
+ Returns
+ -------
+ dict
+ Status of the token refresh operation.
+
+ Examples
+ --------
+ ```json
+ {
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.Notification.Mail'
+ info = self.core_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'refresh_token'
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def set_mail_config(self,
+ enable_mail: bool,
+ enable_oauth: bool,
+ subject_prefix: str,
+ smtp_info: dict,
+ send_welcome_mail: bool,
+ sender_name: str,
+ sender_mail: str,
+ oauth_provider: str) -> dict:
+ """
+ Set the mail configuration for notifications.
+
+ Parameters
+ ----------
+ enable_mail : bool
+ Enable mail notifications.
+ enable_oauth : bool
+ Enable OAuth authentication.
+ subject_prefix : str
+ Prefix for the email subject.
+ smtp_info : dict
+ SMTP server information, e.g.:
+ {"server": "smtp.gmail.com", "port": 465, "ssl": True}
+ send_welcome_mail : bool
+ Send a welcome mail after configuration.
+ sender_name : str
+ Name of the sender.
+ sender_mail : str
+ Email address of the sender.
+ oauth_provider : str
+ OAuth provider (e.g., "gmail").
+
+ Returns
+ -------
+ dict
+ API response.
+
+ Examples
+ --------
+ ```json
+ {
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.Notification.Mail.Conf'
+ info = self.core_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'set',
+ 'enable_mail': enable_mail,
+ 'enable_oauth': enable_oauth,
+ 'subject_prefix': subject_prefix,
+ 'smtp_info': json.dumps(smtp_info),
+ 'send_welcome_mail': send_welcome_mail,
+ 'sender_name': sender_name,
+ 'sender_mail': sender_mail,
+ 'oauth_provider': oauth_provider
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def send_test_mail(self, smtp_info: dict, mail: list[str], subject_prefix: str) -> dict:
+ """
+ Send a test mail to verify the mail configuration.
+
+ Parameters
+ ----------
+ smtp_info : dict
+ SMTP server information, e.g.:
+ {"server": "smtp.gmail.com", "port": 465, "ssl": True}
+ mail : list[str]
+ List of email addresses to send the test email to.
+ subject_prefix : str
+ Prefix for the email subject.
+
+ Returns
+ -------
+ dict
+ Status of the test email operation.
+
+ Examples
+ --------
+ ```json
+ {
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.Notification.Mail'
+ info = self.core_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'send_test',
+ 'smtp_info': json.dumps(smtp_info) if smtp_info else None,
+ 'mail': json.dumps(mail) if mail else None,
+ 'subject_prefix': subject_prefix
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def send_test_push_mail(self, target_id_list: list[int] = None) -> dict:
+ """
+ Send a test push mail to synology account.
+
+ Parameters
+ ----------
+ target_id_list : list[int], optional
+ List of target IDs to send the test push mail to. If None, sends to all linked devices.
+
+ Returns
+ -------
+ dict
+ Status of the test email operation.
+
+ Examples
+ --------
+ ```json
+ {
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.Notification.Push.Mail'
+ info = self.core_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['minVersion'],
+ 'method': 'send_test'
+ }
+ if target_id_list:
+ req_param['target_id_list'] = json.dumps(target_id_list) if len(
+ target_id_list) > 1 else target_id_list[0]
+
+ return self.request_data(api_name, api_path, req_param)
+
+ def create_mail_profile(self, template_id: int, mail: list[str]) -> dict:
+ """
+ Create a new mail profile for notifications.
+
+ Parameters
+ ----------
+ template_id : int
+ ID of the filter template to use. Use `list_filter_template` to get available templates.
+ mail : list[str]
+ List of email addresses to receive notifications.
+
+ Returns
+ -------
+ dict
+ API response success status.
+
+ Examples
+ --------
+ ```json
+ {
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.Notification.Mail.Profile.Conf'
+ info = self.core_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'create',
+ 'template_id': template_id,
+ 'mail': json.dumps(mail)
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def edit_mail_profile(self, profile_id: int, template_id: int, mail: list[str]) -> dict:
+ """
+ Edit an existing mail profile for notifications.
+
+ Parameters
+ ----------
+ profile_id : int
+ ID of the profile to edit. Use `get_mail_config` to get existing profiles.
+ template_id : int
+ ID of the filter template to use. Use `list_filter_template` to get available templates.
+ mail : list[str]
+ List of email addresses to receive notifications.
+
+ Returns
+ -------
+ dict
+ API response success status.
+
+ Examples
+ --------
+ ```json
+ {
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.Notification.Mail.Profile.Conf'
+ info = self.core_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'set',
+ 'profile_id': profile_id,
+ 'template_id': template_id,
+ 'mail': json.dumps(mail)
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def delete_mail_profile(self, profile_id: int) -> dict:
+ """
+ Delete a mail profile for notifications.
+
+ Parameters
+ ----------
+ profile_id : int
+ ID of the profile to delete. Use `get_mail_config` to get existing profiles.
+
+ Returns
+ -------
+ dict
+ API response success status.
+
+ Examples
+ --------
+ ```json
+ {
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.Notification.Mail.Profile.Conf'
+ info = self.core_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'delete',
+ 'profile_id': profile_id
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def create_filter_rule(self, template_name: str, settings: list[dict]) -> dict:
+ """
+ Create a new notification filter rule template.
+
+ Parameters
+ ----------
+ template_name : str
+ The name of the filter template.
+ settings : list of dict
+ List of filter settings, e.g.:
+ [
+ {"tag": "AutoBlockAdd", "enabled": False},
+ {"tag": "AutoBlockDatabaseRulesWarning", "enabled": True},
+ ...
+ ]
+
+ Returns
+ -------
+ dict
+ template ID.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "template_id": 2
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.Notification.Advance.FilterSettings.Template'
+ info = self.core_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['minVersion'],
+ 'method': 'create',
+ 'template_name': template_name,
+ 'settings': json.dumps(settings)
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def edit_filter_rule(self, template_id: int, template_name: str, settings: list[dict]) -> dict:
+ """
+ Edit an existing notification filter rule template.
+
+ Parameters
+ ----------
+ template_id : int
+ ID of the filter template to edit. Use `list_filter_template` to get existing templates.
+ template_name : str
+ The name of the filter template.
+ settings : list of dict
+ List of filter settings, e.g.:
+ [
+ {"tag": "AutoBlockAdd", "enabled": False},
+ {"tag": "AutoBlockDatabaseRulesWarning", "enabled": True},
+ ...
+ ]
+
+ Returns
+ -------
+ dict
+ API response success status.
+
+ Examples
+ --------
+ ```json
+ {
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.Notification.Advance.FilterSettings.Template'
+ info = self.core_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['minVersion'],
+ 'method': 'set',
+ 'template_id': template_id,
+ 'template_name': template_name,
+ 'settings': json.dumps(settings)
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def delete_filter_rule(self, template_id: int) -> dict:
+ """
+ Delete a notification filter rule template.
+
+ Parameters
+ ----------
+ template_id : int
+ ID of the filter template to delete. Use `list_filter_template` to get existing templates.
+
+ Returns
+ -------
+ dict
+ API response success status.
+
+ Examples
+ --------
+ ```json
+ {
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.Notification.Advance.FilterSettings.Template'
+ info = self.core_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['minVersion'],
+ 'method': 'delete',
+ 'template_id': template_id
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def list_push_service(self) -> dict:
+ """
+ List available push notification services.
+
+ Returns
+ -------
+ dict
+ Available push notification services.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "count": 1,
+ "list": [
+ {
+ "app_version": "2.5.4-468",
+ "device_name": "IN2013",
+ "firmware_version": "13",
+ "profile_id": 5,
+ "target_id": 61451444,
+ "template_id": 2
+ }
+ ],
+ "success": true
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.Notification.Push.Mobile'
+ info = self.core_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'list'
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def get_push_service_auth_token(self) -> dict:
+ """
+ Get authentication token for push notification services.
+
+ Returns
+ -------
+ dict
+ Authentication token details.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "oauth_id": xxxxxxxxxxxxxxxxxxx,
+ "pushbrowser_server": "https://notification.synology.com/web/",
+ "register_token": "YOUR_REGISTER_TOKEN"
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.Notification.Push.Mobile'
+ info = self.core_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['minVersion'],
+ 'method': 'get'
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def unpair_push_service(self, target_id: int) -> dict:
+ """
+ Unpair a push notification service.
+
+ Parameters
+ ----------
+ target_id : int
+ Target ID of the push service to unpair. Use `list_push_service` to get existing services.
+
+ Returns
+ -------
+ dict
+ API response success status.
+
+ Examples
+ --------
+ ```json
+ {
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.Notification.Push.Mobile'
+ info = self.core_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'unpair',
+ 'target_id_list': str(target_id)
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def list_webhook(self) -> dict:
+ """
+ List configured webhooks for notifications.
+
+ Returns
+ -------
+ dict
+ Configured webhooks details.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "count": 1,
+ "list": [
+ {
+ "profile_id": 6,
+ "target_config": {
+ "interval": 0,
+ "needssl": true,
+ "port": 443,
+ "prefix": "[SYNO-FLORENTB]",
+ "provider": "test",
+ "req_header": "",
+ "req_method": "get",
+ "req_param": "",
+ "sepchar": " ",
+ "type": "custom",
+ "url": "https://webhook.site/558e159f-2dd8-48a1-8afb-ee9715ef5753?text=%40%40TEXT%40%40",
+ "use_default_lang": true
+ },
+ "target_id": 6,
+ "target_name": "test",
+ "target_type": "webhook",
+ "template_config": {
+ "default_enabled_rule_level": "NOTIFICATION_ERROR",
+ "default_type": "Critical",
+ "is_default": true
+ },
+ "template_id": 3,
+ "template_name": "Critical"
+ }
+ ]
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.Notification.Push.Webhook.Provider'
+ info = self.core_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'list'
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def _format_req_list(self, req_list):
+ """
+ Convert a list of dicts or tuples to Synology API string format. Example: [{"name": "X-Token", "value": "abc"}, {"name": "X-Id", "value": "123"}] -> "X-Token:abc\rX-Id:123\r".
+
+ Parameters
+ ----------
+ req_list : list of dict
+ List of dicts with 'name' and 'value' keys.
+
+ Returns
+ -------
+ str
+ Formatted string for Synology API.
+ """
+ if not req_list:
+ return "\r"
+ formatted = "".join(
+ f"{item['name']}:{item['value']}\r" for item in req_list)
+ return formatted
+
+ def create_webhook(self,
+ provider: str,
+ url: str,
+ template_id: int,
+ req_header: list = None,
+ req_param: list = [
+ {"name": "text", "value": "@@TEXT@@"}],
+ port: int = 443,
+ type_: str = "custom",
+ interval: int = 0,
+ req_method: str = "get",
+ needssl: bool = True,
+ use_default_lang: bool = True,
+ prefix: str = "",
+ sepchar: str = " ") -> dict:
+ """
+ Create a new webhook provider for notifications, formatting req_header and req_param as required.
+
+ Parameters
+ ----------
+ provider : str
+ The provider name.
+ url : str
+ The webhook URL.
+ template_id : int
+ The template ID.
+ req_header : list of dict, optional
+ Example: [{"name": "X-Token", "value": "abc"}].
+ req_param : list of dict, optional
+ Example: [{"name": "X-Token", "value": "abc"}].
+ port : int, optional
+ The port to use (default: 443).
+ type_ : str, optional
+ The type of webhook (default: "custom"). Only "custom" is supported, TODO: Add others types.
+ interval : int, optional
+ The interval (default: 0).
+ req_method : str, optional
+ The HTTP request method (default: "get").
+ needssl : bool, optional
+ Whether SSL is needed (default: True).
+ use_default_lang : bool, optional
+ Use default language (default: True).
+ prefix : str, optional
+ Prefix for the notification (default: "").
+ sepchar : str, optional
+ Separator character (default: " ").
+
+ Returns
+ -------
+ dict
+ API response success.
+
+ Examples
+ --------
+ ```json
+ {
+ "success": true
+ }
+ ```
+ """
+
+ api_name = 'SYNO.Core.Notification.Push.Webhook.Provider'
+ info = self.core_list[api_name]
+ api_path = info['path']
+ req_param_dict = {
+ 'version': info['maxVersion'],
+ 'method': 'create',
+ 'type': type_,
+ 'port': port,
+ 'template_id': template_id,
+ 'interval': interval,
+ 'req_method': req_method,
+ 'req_header': self._format_req_list(req_header),
+ 'req_param': self._format_req_list(req_param),
+ 'needssl': needssl,
+ 'provider': provider,
+ 'use_default_lang': use_default_lang,
+ 'prefix': prefix,
+ 'sepchar': sepchar,
+ 'url': url
+ }
+
+ return self.request_data(api_name, api_path, req_param_dict)
+
+ def edit_webhook(self,
+ profile_id: int,
+ provider: str,
+ url: str,
+ template_id: int,
+ req_header: list = None,
+ req_param: list = None,
+ port: int = 443,
+ type_: str = "custom",
+ interval: int = 0,
+ req_method: str = "get",
+ needssl: bool = True,
+ use_default_lang: bool = True,
+ prefix: str = "",
+ sepchar: str = " ") -> dict:
+ """
+ Update (set) a webhook provider for notifications, formatting req_header and req_param as required.
+
+ Parameters
+ ----------
+ profile_id : int
+ The profile ID of the webhook provider.
+ provider : str
+ The provider name.
+ url : str
+ The webhook URL.
+ template_id : int
+ The template ID.
+ req_header : list of dict, optional
+ Example: [{"name": "X-Token", "value": "abc"}]
+ req_param : list of dict, optional
+ Example: [{"name": "foo", "value": "bar"}]
+ port : int, optional
+ The port to use (default: 443).
+ type_ : str, optional
+ The type of webhook (default: "custom"). Only "custom" is supported, TODO: Add others types.
+ interval : int, optional
+ The interval (default: 0).
+ req_method : str, optional
+ The HTTP request method (default: "get").
+ needssl : bool, optional
+ Whether SSL is needed (default: True).
+ use_default_lang : bool, optional
+ Use default language (default: True).
+ prefix : str, optional
+ Prefix for the notification (default: "").
+ sepchar : str, optional
+ Separator character (default: " ").
+
+ Returns
+ -------
+ dict
+ API response.
+
+ Examples
+ --------
+ ```json
+ {
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.Notification.Push.Webhook.Provider'
+ info = self.core_list[api_name]
+ api_path = info['path']
+ req_param_dict = {
+ 'version': info['maxVersion'],
+ 'method': 'set',
+ 'profile_id': profile_id,
+ 'type': type_,
+ 'port': port,
+ 'template_id': template_id,
+ 'interval': interval,
+ 'req_method': req_method,
+ 'req_header': self._format_req_list(req_header),
+ 'req_param': self._format_req_list(req_param),
+ 'needssl': needssl,
+ 'provider': provider,
+ 'use_default_lang': use_default_lang,
+ 'prefix': prefix,
+ 'sepchar': sepchar,
+ 'url': url
+ }
+ return self.request_data(api_name, api_path, req_param_dict)
+
+ def delete_webhook(self, profile_id: int) -> dict:
+ """
+ Delete a webhook provider for notifications.
+
+ Parameters
+ ----------
+ profile_id : int
+ The profile ID of the webhook provider to delete.
+
+ Returns
+ -------
+ dict
+ API response success status.
+
+ Examples
+ --------
+ ```json
+ {
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.Notification.Push.Webhook.Provider'
+ info = self.core_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'delete',
+ 'profile_id': profile_id
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def get_variables(self) -> dict:
+ """
+ Get notification variables such as company name and HTTP URL.
+
+ Returns
+ -------
+ dict
+ Notification variables including company name and HTTP URL.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "company_name": "Synology",
+ "http_url": "http://www.synology.com"
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.Notification.Advance.Variables'
+ info = self.core_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'get'
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def edit_variables(self, company_name: str, http_url: str) -> dict:
+ """
+ Edit notification variables such as company name and HTTP URL.
+
+ Parameters
+ ----------
+ company_name : str
+ The company name to set.
+ http_url : str
+ The HTTP URL to set.
+
+ Returns
+ -------
+ dict
+ API response success status.
+
+ Examples
+ --------
+ ```json
+ {
+ "success": true
+ }
+ ```
+ """
+ # If http_url is not empty, verify it's a valid URL
+ if http_url and not (http_url.startswith("http://") or http_url.startswith("https://")):
+ raise ValueError(
+ "http_url must start with 'http://' or 'https://'")
+
+ api_name = 'SYNO.Core.Notification.Advance.Variables'
+ info = self.core_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'set',
+ 'company_name': company_name,
+ 'http_url': http_url
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def get_event_message(self, event_tag: str) -> dict:
+ """
+Get the subject and message for a specific event tag.
+
+ Parameters
+ ----------
+ event_tag : str
+ The event tag to retrieve (e.g., "ActiveBackupOffice365_restore_warning").
+
+ Returns
+ -------
+ dict
+ API response containing the subject and message for the specified event tag.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "content": "",
+ "default_content": "Les données [%SERVICENAME%] du compte [%SRCUSERNAME%] ont été partiellement restaurées sur le compte [%DESTUSERNAME%] par [%TRIGGER%] (succès : %SUCCESSNUM% ; avertissement : %WARNINGNUM%).\nHeure de début : %STARTTIME%\nHeure de fin : %ENDTIME%\nConnectez-vous à la console d'administration d'Active Backup for Microsoft 365 pour plus d'informations, puis réessayez plus tard.\n\nDe %HOSTNAME%",
+ "default_subject": "%PACKAGENAME% - Les données de sauvegarde sur [%HOSTNAME%] ont été partiellement restaurées",
+ "subject": ""
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.Notification.Advance.CustomizedData'
+ info = self.core_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'get',
+ 'event_tag': event_tag
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def edit_event_message(self, event_tag: str, subject: str, message: str) -> dict:
+ """
+ Edit the subject and message for a specific event tag.
+
+ Parameters
+ ----------
+ event_tag : str
+ The event tag to edit (e.g., "ActiveBackupOffice365_restore_warning").
+ subject : str
+ The subject template for the event.
+ message : str
+ The message template for the event. Must be a valid html
...
with text in it.
+ E.g., "
Les données [%SERVICENAME%] du compte [%SRCUSERNAME%] ont été partiellement restaurées sur le compte [%DESTUSERNAME%] par [%TRIGGER%] (succès : %SUCCESSNUM% ; avertissement : %WARNINGNUM%).
Heure de début : %STARTTIME%
Heure de fin : %ENDTIME%
Connectez-vous à la console d'administration d'Active Backup for Microsoft 365 pour plus d'informations, puis réessayez plus tard.
De %HOSTNAME%
".
+
+ Returns
+ -------
+ dict
+ API response success status.
+
+ Examples
+ --------
+ ```json
+ {
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.Notification.Advance.CustomizedData'
+ info = self.core_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'set',
+ 'event_tag': event_tag,
+ 'subject': subject,
+ 'message': message
+ }
+ return self.request_data(api_name, api_path, req_param)
diff --git a/synology_api/DSM/ControlPanel/RegionalOptions.py b/synology_api/DSM/ControlPanel/RegionalOptions.py
new file mode 100644
index 00000000..104c4b9d
--- /dev/null
+++ b/synology_api/DSM/ControlPanel/RegionalOptions.py
@@ -0,0 +1,384 @@
+"""
+Regional options class for Synology DSM.
+"""
+from synology_api import base_api
+import enum
+
+
+class LanguageEnum(enum.Enum):
+ """
+ Enum for available languages in Synology DSM.
+ """
+ ENGLISH = "enu"
+ FRENCH = "fre"
+ GERMAN = "ger"
+ GREEK = "gre"
+ HEBREW = "heb"
+ THAI = "tha"
+ ITALIAN = "ita"
+ SPANISH = "spn"
+ TRADITIONAL_CHINESE = "cht"
+ SIMPLIFIED_CHINESE = "chs"
+ JAPANESE = "jpn"
+ KOREAN = "krn"
+ PORTUGUESE_BRAZIL = "ptb"
+ RUSSIAN = "rus"
+ DANISH = "dan"
+ NORWEGIAN = "nor"
+ SWEDISH = "sve"
+ DUTCH = "nld"
+ POLISH = "plk"
+ PORTUGUESE_GALICIAN = "ptg"
+ HUNGARIAN = "hun"
+ TURKISH = "trk"
+ CZECH = "csy"
+ ARABIC = "ara"
+ DEFAULT = "def"
+
+
+class RegionalOptions(base_api.BaseApi):
+ """
+Regional options class for Synology DSM.
+ """
+
+ def get_time_info(self) -> dict:
+ """
+Get Date & Time information, Time Zone and Time Settings.
+
+ Returns
+ -------
+ dict
+ Date & Time information, Time Zone and Time Settings.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "date": "2025/9/15",
+ "date_format": "d/m/Y",
+ "enable_ntp": "ntp",
+ "hour": 20,
+ "minute": 48,
+ "now": "Mon Sep 15 20:48:00 2025\n",
+ "second": 0,
+ "server": "time.google.com",
+ "time_format": "H:i",
+ "timestamp": 1757962080,
+ "timezone": "Amsterdam"
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.Region.NTP'
+ info = self.core_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'get'
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def get_language_info(self) -> dict:
+ """
+ Get Language information.
+
+ Returns
+ -------
+ dict
+ Language information.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "codepage": "fre",
+ "language": "def",
+ "maillang": "fre"
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.Region.Language'
+ info = self.core_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'get'
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def get_ntp_service_info(self) -> dict:
+ """
+ Get NTP Service information.
+
+ Returns
+ -------
+ dict
+ NTP Service information.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "enable": true
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.Region.NTP.Server'
+ info = self.core_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'get'
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def get_ntp_service_status(self) -> dict:
+ """
+ Get NTP Service status.
+
+ Returns
+ -------
+ dict
+ NTP Service status.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "ntp_status": true
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.Region.NTP'
+ info = self.core_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'status'
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def list_timezone(self) -> dict:
+ """
+ List available time zones.
+
+ Returns
+ -------
+ dict
+ Available time zones.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "zonedata": [
+ {
+ "display": "(GMT-11:00) Samoa Standard Time; Midway Is.",
+ "offset": -39600,
+ "value": "Midway"
+ },
+ {
+ "display": "(GMT-10:00) Hawaii Standard Time",
+ "offset": -36000,
+ "value": "Hawaii"
+ },
+ {
+ "display": "(GMT-09:00) Alaska Standard Time",
+ "offset": -32400,
+ "value": "Alaska"
+ },
+ {
+ "display": "(GMT-08:00) Pacific Time (US & Canada); Tijuana",
+ "offset": -28800,
+ "value": "Pacific"
+ },
+ {
+ "display": "(GMT-07:00) Arizona",
+ "offset": -25200,
+ "value": "Arizona"
+ },
+ {
+ "display": "(GMT-07:00) Mountain Time (US & Canada)",
+ "offset": -25200,
+ "value": "Mountain"
+ },
+ {
+ "display": "(GMT-06:00) Central Time (US & Canada)",
+ "offset": -21600,
+ "value": "Central"
+ },
+ {
+ "display": "(GMT-06:00) Chihuahua, Mazatlan",
+ "offset": -21600,
+ "value": "Chihuahua"
+ },
+ {
+ "display": "(GMT-06:00) Central America Standard Time; Guatemala",
+ "offset": -21600,
+ "value": "Guatemala"
+ }
+ ]
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.Region.NTP'
+ info = self.core_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['minVersion'],
+ 'method': 'listzone'
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def set_time_info(self, date_format: str, time_format: str, timezone: str, enable_ntp: str, server: str, date: str, hour: int, minute: int, second: int, change_time: bool = False) -> dict:
+ """
+ Set Date & Time information, Time Zone and Time Settings.
+
+ Parameters
+ ----------
+ date_format : str
+ Date format, known formats are `YYYY-MM-dd`, `YYYY/MM/dd`, `YYYY.MM.dd`, `dd-MM-YYYY`, `dd/MM/YYYY`, `dd.MM.YYYY`, `MM-dd-YYYY`, `MM/dd/YYYY`, `MM.dd.YYYY`.
+ time_format : str
+ Time format, known formats are `H:i`, `h:i A`.
+ timezone : str
+ Time zone, can be get from `list_timezone` field "value".
+ enable_ntp : str
+ NTP setting ('ntp' to enable, 'manual' to disable).
+ server : str
+ NTP server address, only if `enable_ntp` is set to 'ntp'.
+ date : str
+ Date in 'YYYY/MM/DD' format, only if `enable_ntp` is set to 'manual'.
+ hour : int
+ Hour (0-23), only if `enable_ntp` is set to 'manual'.
+ minute : int
+ Minute (0-59), only if `enable_ntp` is set to 'manual'.
+ second : int
+ Second (0-59), only if `enable_ntp` is set to 'manual'.
+ change_time : bool, optional
+ Whether to change the time immediately, defaults to False.
+
+ Returns
+ -------
+ dict
+ Response from the API.
+
+ Examples
+ --------
+ ```json
+ {
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.Region.NTP'
+ info = self.core_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'set',
+ 'date_format': date_format,
+ 'time_format': time_format,
+ 'timezone': timezone,
+ 'enable_ntp': enable_ntp,
+ 'change_time': change_time
+ }
+ if enable_ntp == 'manual':
+ req_param.update({
+ 'date': date,
+ 'hour': hour,
+ 'minute': minute,
+ 'second': second
+ })
+ elif enable_ntp == 'ntp':
+ # server is required in this case
+ req_param.update({
+ 'server': server
+ })
+ return self.request_data(api_name, api_path, req_param)
+
+ def list_language(self) -> LanguageEnum:
+ """
+ List available languages.
+
+ Returns
+ -------
+ LanguageEnum
+ Available languages.
+ """
+ return LanguageEnum
+
+ def set_language_info(self, language: LanguageEnum, maillang: LanguageEnum, codepage: LanguageEnum) -> dict:
+ """
+ Set Language information.
+
+ Parameters
+ ----------
+ language : LanguageEnum
+ Display language, you can use the `DEFAULT` from the LanguageEnum.
+ maillang : LanguageEnum
+ Notification language, you cannot use `DEFAULT` from the LanguageEnum.
+ codepage : LanguageEnum
+ Codepage, you cannot use `DEFAULT` from the LanguageEnum.
+
+ Returns
+ -------
+ dict
+ Response from the API.
+ """
+ api_name = 'SYNO.Core.Region.Language'
+ info = self.core_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'set',
+ 'language': language.value,
+ 'maillang': maillang.value,
+ 'codepage': codepage.value
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def set_ntp_service_info(self, enable: bool) -> dict:
+ """
+ Set NTP Service information.
+
+ Parameters
+ ----------
+ enable : bool
+ Whether to enable the NTP service.
+
+ Returns
+ -------
+ dict
+ Response from the API.
+
+ Examples
+ --------
+ ```json
+ {
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.Region.NTP.Server'
+ info = self.core_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'set',
+ 'enable': enable
+ }
+ return self.request_data(api_name, api_path, req_param)
diff --git a/synology_api/DSM/ControlPanel/Security.py b/synology_api/DSM/ControlPanel/Security.py
new file mode 100644
index 00000000..39a49005
--- /dev/null
+++ b/synology_api/DSM/ControlPanel/Security.py
@@ -0,0 +1,473 @@
+"""
+Security class for Synology DSM.
+"""
+from synology_api import base_api
+import json
+
+
+class Security(base_api.BaseApi):
+ """
+ Security class for Synology DSM.
+ """
+
+ def get_security_settings(self) -> dict:
+ """
+ Get security settings, Security tab: General, Login Settings.
+
+ Returns
+ -------
+ dict
+ Security settings information.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "allow_stay_signed_in_option": true,
+ "allow_trust_device_2fa_option": true,
+ "csp_header_option": true,
+ "enable_csrf_protection": true,
+ "restart_clean_session": true,
+ "skip_ip_checking": true,
+ "timeout": 15
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.Security.DSM'
+ info = self.core_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'get'
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def get_dsm_embedded_settings(self) -> dict:
+ """
+ Get DSM embedded settings.
+
+ Returns
+ -------
+ dict
+ DSM embedded settings information.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "enable_block": true,
+ "whitelist": [
+ "find.synology.com/",
+ "gofile.me/"
+ ]
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.Security.DSM.Embed'
+ info = self.core_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'get'
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def get_2fa_settings(self) -> dict:
+ """
+ Get 2-factor authentication settings, Account tab: 2-factor authentication.
+
+ Returns
+ -------
+ dict
+ 2-factor authentication settings information.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "otp_enforce_option": "custom"
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.OTP.EnforcePolicy'
+ info = self.core_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'get'
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def get_amfa_settings(self) -> dict:
+ """
+ Get AMFA (Adaptive Multi-Factor Authentication) settings, Account tab: Adaptive multi-factor authentication.
+
+ Returns
+ -------
+ dict
+ AMFA settings information.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "group_list": "",
+ "type": "admin",
+ "user_list": ""
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.SecureSignIn.AMFA.Policy'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'get'
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def get_smartblock_settings(self) -> dict:
+ """
+ Get Smart Block settings, Login Settings tab: Smart Block.
+
+ Returns
+ -------
+ dict
+ Smart Block settings information.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "enabled": true,
+ "trust_lock": 30,
+ "trust_minute": 1,
+ "trust_try": 10,
+ "untrust_lock": 30,
+ "untrust_minute": 1,
+ "untrust_try": 5
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.SmartBlock'
+ info = self.core_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'get'
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def get_firewall_status(self) -> dict:
+ """
+ Get firewall status, Firewall tab: Enable firewall.
+
+ Returns
+ -------
+ dict
+ Firewall status information.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "enable_firewall": true,
+ "profile_name": "default"
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.Security.Firewall'
+ info = self.core_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'get'
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def get_firewall_notifications_settings(self) -> dict:
+ """
+ Get firewall notifications settings, Firewall tab: Enable firewall notifications.
+
+ Returns
+ -------
+ dict
+ Firewall notifications settings information.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "enable_port_check": true
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.Security.Firewall.Conf'
+ info = self.core_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'get'
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def get_auto_block_settings(self) -> dict:
+ """
+ Get auto block settings, Auto Block tab: Enable auto block.
+
+ Returns
+ -------
+ dict
+ Auto block settings information.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "attempts": 10,
+ "enable": true,
+ "expire_day": 0,
+ "within_mins": 5
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.Security.AutoBlock'
+ info = self.core_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'get'
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def get_dos_settings(self, adapter_list: list[str]) -> dict:
+ """
+ Get DoS settings, Protect tab: Denial-of-Service (DoS) Protection.
+
+ Parameters
+ ----------
+ adapter_list : list[str]
+ List of network interfaces to get DoS settings for. Can be obtained via `Network.get_network_interface()` and get `ifname` from the response.
+
+ Returns
+ -------
+ dict
+ DoS settings information.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": [
+ {
+ "adapter": "ovs_eth0",
+ "dos_protect_enable": true
+ },
+ {
+ "adapter": "ovs_eth1",
+ "dos_protect_enable": false
+ },
+ {
+ "adapter": "pppoe",
+ "dos_protect_enable": false
+ }
+ ],
+ "success": true
+ }
+ ```
+ """
+ configs = [{"adapter": adapter} for adapter in adapter_list]
+
+ api_name = 'SYNO.Core.Security.DoS'
+ info = self.core_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'get',
+ 'configs': json.dumps(configs)
+ }
+
+ return self.request_data(api_name, api_path, req_param)
+
+ def get_http_compression_settings(self) -> dict:
+ """
+ Get HTTP compression settings, Advanced tab: HTTP compression.
+
+ Returns
+ -------
+ dict
+ HTTP compression settings information.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "http_compression": true
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.Web.Security.HTTPCompression'
+ info = self.core_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'get'
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def get_tls_profile_settings(self) -> dict:
+ """
+ Get TLS profile settings, Advanced tab: TLS / SSL Profile level.
+
+ Returns
+ -------
+ dict
+ TLS profile settings information.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "default-level": 1,
+ "services": {
+ "LogCenter": {
+ "current-level": 0,
+ "display-name": "Log Receiving",
+ "display-name-i18n": "helptoc:logcenter_server"
+ },
+ "WebStation_4437801d-caf5-45d6-afbd-99fc2f9f91dc": {
+ "current-level": 0,
+ "display-name": "*:8080"
+ },
+ "dsm": {
+ "current-level": 0,
+ "display-name": "DSM Desktop Service",
+ "display-name-i18n": "common:web_desktop"
+ },
+ "openldap": {
+ "current-level": 0,
+ "display-name": "LDAP Server"
+ },
+ "smbftpd": {
+ "current-level": 0,
+ "display-name": "FTPS",
+ "display-name-i18n": "tree:leaf_ftpes"
+ },
+ "system_quickconnect": {
+ "current-level": 0,
+ "display-name": "QuickConnect",
+ "display-name-i18n": "helptoc:quickconnect"
+ }
+ }
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.Web.Security.TLSProfile'
+ info = self.core_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'get'
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def get_spectre_meldown_settings(self) -> dict:
+ """
+ Get Spectre/Meltdown settings, Advanced tab: Spectre/Meltdown Protection.
+
+ Returns
+ -------
+ dict
+ Spectre/Meltdown settings information.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "enable_spectre_meltdown_mitigation": true
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.Hardware.SpectreMeltdown'
+ info = self.core_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'get'
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def get_kmip_settings(self) -> dict:
+ """
+ Get KMIP settings, KMIP tab.
+
+ Returns
+ -------
+ dict
+ KMIP settings information.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "client_cert_info": null,
+ "client_enable": false,
+ "conn_success": false,
+ "conn_time": "",
+ "kmip_conn_server_desc": "",
+ "kmip_conn_server_port": "5696",
+ "kmip_db_loc": "",
+ "kmip_enabled": "",
+ "kmip_mode": "",
+ "kmip_server": "",
+ "kmip_server_port": "5696",
+ "server_cert_info": null,
+ "server_enable": false,
+ "support_kmip": "yes"
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Storage.CGI.KMIP'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'get'
+ }
+ return self.request_data(api_name, api_path, req_param)
diff --git a/synology_api/DSM/ControlPanel/SharedFolder.py b/synology_api/DSM/ControlPanel/SharedFolder.py
new file mode 100644
index 00000000..d2222b40
--- /dev/null
+++ b/synology_api/DSM/ControlPanel/SharedFolder.py
@@ -0,0 +1,1025 @@
+"""
+Core Share API implementation.
+"""
+
+from synology_api import base_api
+import json
+from typing import List, Any
+
+
+class SharedFolder(base_api.BaseApi):
+ """
+ Core Share API implementation.
+
+ Supported methods:
+ - Getters:
+ - Validate set of parameters for a new/modified shared folder
+ - List all folders information
+ - Get a folder by name
+ - Retrieve share permissions for a given folder filtered by permission name (sub string)
+ - Retrieve share permissions for a given folder
+ - Retrieve share permissions for a given group
+
+ - Setters:
+ - Create a new shared folder
+ - Set folder permissions for a given folder
+ - Set group permissions for a given share
+
+ - Actions:
+ - Delete folder(s) by name(s)
+ - Clone existing shared folder
+ """
+
+ def validate_set(self, name: str, vol_path: str, desc: str = "", enable_share_compress: bool = False, enable_share_cow: bool = False, enc_passwd: str = "", encryption: bool = False) -> dict:
+ """
+ Validate set of parameter for a new / modified shared folder.
+
+ Parameters
+ ----------
+ name : str
+ Share name.
+ vol_path : str
+ Volume path.
+ desc : str, optional
+ Share description. Defaults to `""`.
+ enable_share_compress : bool, optional
+ Enable share compress. Defaults to `False`.
+ enable_share_cow : bool, optional
+ Enable share cow. Defaults to `False`.
+ enc_passwd : str, optional
+ Encrypted password. Defaults to `""`.
+ encryption : bool, optional
+ Enable encryption. Defaults to `False`.
+
+ Returns
+ -------
+ dict
+ Success.
+
+ Examples
+ --------
+ ```json
+ {
+ "success": true,
+ }
+ ```
+ """
+ api_name = "SYNO.Core.Share"
+ info = self.core_list[api_name]
+ api_path = info["path"]
+ req_param = {
+ "method": "validate_set",
+ "version": info['maxVersion'],
+ "name": name,
+ }
+
+ req_param_encrypted = {
+ "shareinfo": json.dumps({
+ "name": name,
+ "vol_path": vol_path,
+ "desc": desc,
+ "enable_share_compress": enable_share_compress,
+ "enable_share_cow": enable_share_cow,
+ "enc_passwd": enc_passwd,
+ "encryption": encryption,
+ })
+ }
+
+ # If using https don't use encryption
+ if self.session._secure:
+ req_param.update(req_param_encrypted)
+ else:
+ encrypted_params = self.session.encrypt_params(req_param_encrypted)
+ req_param.update(encrypted_params)
+
+ return self.request_data(api_name, api_path, req_param, method="post")
+
+ def list_folders(self, share_type: str = "all", additional: list = []) -> dict:
+ """
+ List all folders informations.
+
+ Parameters
+ ----------
+ share_type : str, optional
+ Share type. Defaults to `all`.
+ additional : list[str], optional
+ Additional fields to retrieve. Defaults to `[]`.
+ All fields known are: `[
+ "hidden","encryption","is_aclmode","unite_permission","is_support_acl","is_sync_share","is_force_readonly","force_readonly_reason",
+ "recyclebin","is_share_moving","is_cluster_share","is_exfat_share","is_c2_share","is_cold_storage_share","is_missing_share",
+ "is_offline_share","support_snapshot","share_quota","enable_share_compress","enable_share_cow","enable_share_tiering",
+ "load_worm_attr","include_cold_storage_share","is_cold_storage_share","include_missing_share","is_missing_share",
+ "include_offline_share","is_offline_share","include_worm_share"
+ ]`.
+
+ Returns
+ -------
+ dict
+ A dictionary containing the shared folders information.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "shares": [
+ {
+ "desc": "",
+ "is_usb_share": false,
+ "name": "test_shared_folder",
+ "uuid": "18585c8d-4d74-41a1-b561-21906a7f6f14",
+ "vol_path": "/volume1"
+ }
+ ],
+ "total": 1
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = "SYNO.Core.Share"
+ info = self.core_list[api_name]
+ api_path = info["path"]
+ req_param = {
+ "method": "list",
+ "version": info['minVersion'],
+ "shareType": share_type,
+ "additional": json.dumps(additional)
+ }
+
+ return self.request_data(api_name, api_path, req_param)
+
+ def get_folder(self, name: str, additional: list = []) -> dict:
+ """
+ Get a folder by name.
+
+ Parameters
+ ----------
+ name : str
+ Share name.
+ additional : list, optional
+ Additional fields to retrieve. Defaults to `[]`.
+ All fields known are: `["disable_list","disable_modify","disable_download","unite_permission","is_aclmode"]`.
+
+ Returns
+ -------
+ dict
+ A dictionary containing the shared folder information.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "desc": "",
+ "disable_download": false,
+ "disable_list": false,
+ "disable_modify": false,
+ "is_aclmode": true,
+ "is_usb_share": false,
+ "name": "test_shared_folder",
+ "unite_permission": false,
+ "uuid": "18585c8d-4d74-41a1-b561-21906a7f6f14",
+ "vol_path": "/volume1"
+ },
+ "success": true,
+ ```
+ """
+ api_name = "SYNO.Core.Share"
+ info = self.core_list[api_name]
+ api_path = info["path"]
+ req_param = {
+ "method": "get",
+ "version": info['minVersion'],
+ "name": name,
+ "additional": json.dumps(additional)
+ }
+
+ return self.request_data(api_name, api_path, req_param)
+
+ def create_folder(self,
+ name: str, vol_path: str, desc: str = "", hidden: bool = False,
+ enable_recycle_bin: bool = True, recycle_bin_admin_only: bool = True,
+ hide_unreadable: bool = False, enable_share_cow: bool = False,
+ enable_share_compress: bool = False, share_quota: int = 0, name_org: str = "",
+ encryption: bool = False, enc_passwd: str = ""
+ ) -> dict:
+ """
+ Create a new shared folder.
+
+ Parameters
+ ----------
+ name : str
+ Share name.
+ vol_path : str
+ Volume path.
+ desc : str, optional
+ Share description. Defaults to `""`.
+ hidden : bool, optional
+ Hide share. Defaults to `False`.
+ enable_recycle_bin : bool, optional
+ Enable recycle bin. Defaults to `True`.
+ recycle_bin_admin_only : bool, optional
+ Recycle bin admin only. Defaults to `True`.
+ hide_unreadable : bool, optional
+ Hide unreadable. Defaults to `False`.
+ enable_share_cow : bool, optional
+ Enable share cow. Defaults to `False`.
+ enable_share_compress : bool, optional
+ Enable share compress. Defaults to `False`.
+ share_quota : int, optional
+ Share quota. Defaults to `0`.
+ name_org : str, optional
+ Defaults to `""`.
+ encryption : bool, optional
+ Enable encryption. Defaults to `False`.
+ enc_passwd : str, optional
+ Encrypted password. Defaults to `""`.
+
+ Returns
+ -------
+ dict
+ Name of the created shared folder.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "name": "test_shared_folder"
+ },
+ "success": true,
+ ```
+ """
+
+ api_name = "SYNO.Core.Share"
+ info = self.core_list[api_name]
+ api_path = info["path"]
+ req_param = {
+ "method": "create",
+ "version": info['maxVersion'],
+ "name": name,
+ }
+ req_param_encrypted = {
+ "shareinfo": json.dumps({
+ "desc": desc,
+ "enable_recycle_bin": enable_recycle_bin,
+ "enable_share_compress": enable_share_compress,
+ "enable_share_cow": enable_share_cow,
+ "name": name,
+ "name_org": name_org,
+ "vol_path": vol_path,
+ "recycle_bin_admin_only": recycle_bin_admin_only,
+ "hidden": hidden,
+ "hide_unreadable": hide_unreadable,
+ "share_quota": share_quota,
+ "encryption": encryption,
+ "enc_passwd": enc_passwd,
+ })
+ }
+ # If using https don't use encryption
+ if self.session._secure:
+ req_param.update(req_param_encrypted)
+ else:
+ encrypted_params = self.session.encrypt_params(req_param_encrypted)
+ req_param.update(encrypted_params)
+
+ return self.request_data(api_name, api_path, req_param, method="post")
+
+ def delete_folders(self, name: List[str]) -> dict:
+ """
+ Delete folder(s) by name(s).
+
+ Parameters
+ ----------
+ name : List[str]
+ Share names.
+
+ Returns
+ -------
+ dict
+ Success.
+
+ Examples
+ --------
+ ```json
+ {
+ "success": true
+ }
+ ```
+ """
+ api_name = "SYNO.Core.Share"
+ info = self.core_list[api_name]
+ api_path = info["path"]
+ req_param = {
+ "method": "delete",
+ "version": info['minVersion'],
+ "name": name
+ }
+
+ return self.request_data(api_name, api_path, req_param)
+
+ def clone(self,
+ name: str, name_org: str, vol_path: str, desc: str = "", hidden: bool = False,
+ enable_recycle_bin: bool = True, recycle_bin_admin_only: bool = True,
+ hide_unreadable: bool = False, enable_share_cow: bool = False,
+ enable_share_compress: bool = False, share_quota: int = 0
+ ) -> dict:
+ """
+ Clone existing shared folder.
+
+ Parameters
+ ----------
+ name : str
+ New shared folder name.
+ name_org : str
+ Original shared folder name.
+ vol_path : str
+ Volume path.
+ desc : str, optional
+ Shared folder description. Defaults to `""`.
+ hidden : bool, optional
+ Hide shared folder. Defaults to `False`.
+ enable_recycle_bin : bool, optional
+ Enable recycle bin. Defaults to `True`.
+ recycle_bin_admin_only : bool, optional
+ Recycle bin admin only. Defaults to `True`.
+ hide_unreadable : bool, optional
+ Hide unreadable. Defaults to `False`.
+ enable_share_cow : bool, optional
+ Enable share cow. Defaults to `False`.
+ enable_share_compress : bool, optional
+ Enable share compress. Defaults to `False`.
+ share_quota : int, optional
+ Share quota. Defaults to `0`.
+
+ Returns
+ -------
+ dict
+ Name of the created shared folder.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "name": "test_shared_folder"
+ },
+ "success": true,
+ ```
+ """
+ api_name = "SYNO.Core.Share"
+ info = self.core_list[api_name]
+ api_path = info["path"]
+ req_param = {
+ "method": "clone",
+ "version": info['maxVersion'],
+ "name": name,
+ }
+
+ req_param_encrypted = {
+ "shareinfo": json.dumps({
+ "desc": desc,
+ "enable_recycle_bin": enable_recycle_bin,
+ "enable_share_compress": enable_share_compress,
+ "enable_share_cow": enable_share_cow,
+ "name": name,
+ "name_org": name_org,
+ "vol_path": vol_path,
+ "recycle_bin_admin_only": recycle_bin_admin_only,
+ "hidden": hidden,
+ "hide_unreadable": hide_unreadable,
+ "share_quota": share_quota,
+ })
+ }
+
+ # If using https don't use encryption
+ if self.session._secure:
+ req_param.update(req_param_encrypted)
+ else:
+ encrypted_params = self.session.encrypt_params(req_param_encrypted)
+ req_param.update(encrypted_params)
+
+ return self.request_data(api_name, api_path, req_param, method="post")
+
+ def get_folder_permission_by_name(self,
+ name: str, permission_substr: str, offset: int = 0, limit: int = 50, is_unite_permission: bool = False, with_inherit: bool = False,
+ user_group_type: str = "local_user"
+ ) -> dict:
+ """
+ Retrieve share permissions for a given folder filtered by permission name (sub string).
+
+ Parameters
+ ----------
+ name : str
+ The folder name to list permissions for.
+ permission_substr : str
+ The substring to search for in the permissions.
+ offset : int, optional
+ The offset to start at. Defaults to `0`.
+ limit : int, optional
+ The maximum number of results to return. Defaults to `50`.
+ is_unite_permission : bool, optional
+ Whether to return unified permissions. Defaults to `False`.
+ with_inherit : bool, optional
+ Whether to include inherited permissions. Defaults to `False`.
+ user_group_type : str, optional
+ The type of user group to list permissions for. Defaults to `"local_user"`.
+ All known values are: `["system", "local_user", "local_group", "ldap_user", "ldap_group"]`.
+
+ Returns
+ -------
+ dict
+ List of permission(s) on the folder.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "items": [
+ {
+ "inherit": "-",
+ "is_admin": false,
+ "is_custom": false,
+ "is_deny": false,
+ "is_readonly": false,
+ "is_writable": false,
+ "name": "guest"
+ }
+ ],
+ "total": 1
+ },
+ "success": true
+ }
+ ```
+ """
+
+ api_name = "SYNO.Core.Share.Permission"
+ info = self.core_list[api_name]
+ api_path = info["path"]
+ req_param = {
+ "version": info["minVersion"],
+ "method": "list",
+ "name": name,
+ "offset": offset,
+ "limit": limit,
+ "action": "find",
+ "substr": permission_substr,
+ "is_unite_permission": is_unite_permission,
+ "with_inherit": with_inherit,
+ "user_group_type": user_group_type,
+ }
+ return self.request_data(api_name, api_path, req_param, method="get")
+
+ def get_folder_permissions(self,
+ name: str, offset: int = 0, limit: int = 50, is_unite_permission: bool = False, with_inherit: bool = False,
+ user_group_type: str = "local_user"
+ ) -> dict:
+ """
+ Retrieve share permissions for a given folder.
+
+ Parameters
+ ----------
+ name : str
+ The folder name to list permissions for.
+ offset : int, optional
+ The offset to start at. Defaults to `0`.
+ limit : int, optional
+ The maximum number of results to return. Defaults to `50`.
+ is_unite_permission : bool, optional
+ Whether to return unified permissions. Defaults to `False`.
+ with_inherit : bool, optional
+ Whether to include inherited permissions. Defaults to `False`.
+ user_group_type : str, optional
+ The type of user group to list permissions for. Defaults to `"local_user"`.
+ All known values are: `["system", "local_user", "local_group", "ldap_user", "ldap_group"]`.
+
+ Returns
+ -------
+ dict
+ All permissions on the folder.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "items": [
+ {
+ "inherit": "rw",
+ "is_admin": true,
+ "is_custom": false,
+ "is_deny": true,
+ "is_readonly": false,
+ "is_writable": false,
+ "name": "admin"
+ },
+ {
+ "inherit": "-",
+ "is_admin": false,
+ "is_custom": false,
+ "is_deny": false,
+ "is_readonly": false,
+ "is_writable": false,
+ "name": "guest"
+ },
+ {
+ "inherit": "rw",
+ "is_admin": true,
+ "is_custom": false,
+ "is_deny": false,
+ "is_readonly": false,
+ "is_writable": true,
+ "name": "test_api"
+ },
+ {
+ "inherit": "-",
+ "is_admin": false,
+ "is_custom": false,
+ "is_deny": false,
+ "is_readonly": false,
+ "is_writable": false,
+ "name": "test_test"
+ }
+ ],
+ "total": 5
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = "SYNO.Core.Share.Permission"
+ info = self.core_list[api_name]
+ api_path = info["path"]
+ req_param = {
+ "version": info["minVersion"],
+ "method": "list",
+ "name": name,
+ "offset": offset,
+ "limit": limit,
+ "action": "enum",
+ "is_unite_permission": is_unite_permission,
+ "with_inherit": with_inherit,
+ "user_group_type": user_group_type,
+ }
+ return self.request_data(api_name, api_path, req_param, method="get")
+
+ def set_folder_permissions(self, name: str, user_group_type: str, permissions: List[dict[str, object]]) -> dict:
+ """
+ Set folder permissions for a given folder.
+
+ Parameters
+ ----------
+ name : str
+ The folder name to set permissions for.
+ user_group_type : str
+ The type of user group to set permissions for.
+ All known values are: `["system", "local_user", "local_group", "ldap_user", "ldap_group"]`.
+ permissions : dict
+ The permissions to set for the folder.
+ Example:
+ ```json
+ [
+ {
+ "name":"guest",
+ "is_readonly":false,
+ "is_writable":true,
+ "is_deny":false,
+ "is_custom":false
+ }
+ ]
+ ```
+
+ Returns
+ -------
+ dict
+ Success.
+
+ Examples
+ --------
+ ```json
+ {
+ "success": true
+ }
+ ```
+ """
+ api_name = "SYNO.Core.Share.Permission"
+ info = self.core_list[api_name]
+ api_path = info["path"]
+ req_param = {
+ "version": info["minVersion"],
+ "method": "set",
+ "name": name,
+ "user_group_type": user_group_type,
+ "permissions": json.dumps(permissions),
+ }
+ return self.request_data(api_name, api_path, req_param, method="get")
+
+ def get_local_group_permissions(self, group: str) -> dict:
+ """
+ Retrieve share permissions for a given group.
+
+ Parameters
+ ----------
+ group : str
+ The group to list permissions for.
+
+ Returns
+ -------
+ dict
+ Permissions of a group on Shared folders.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "shares": [
+ {
+ "is_aclmode": true,
+ "is_custom": false,
+ "is_deny": true,
+ "is_mask": false,
+ "is_readonly": false,
+ "is_sync_share": false,
+ "is_unite_permission": false,
+ "is_writable": false,
+ "name": "ActiveBackupforBusiness",
+ "share_path": "/volume3/ActiveBackupforBusiness"
+ }
+ ],
+ "total": 1
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = "SYNO.Core.Share.Permission"
+ info = self.core_list[api_name]
+ api_path = info["path"]
+ req_param = {
+ "version": 1,
+ "method": "list_by_group",
+ "name": group,
+ "user_group_type": "local_group",
+ "share_type": json.dumps(
+ ["dec", "local", "usb", "sata", "cluster",
+ "c2", "cold_storage", "worm"]
+ ),
+ "additional": json.dumps(["hidden", "encryption", "is_aclmode"]),
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def set_local_group_permissions(
+ self, group: str, permissions: list[dict[str, Any]]
+ ) -> dict:
+ """
+ Set group permissions for a given share.
+
+ Parameters
+ ----------
+ group : str
+ The group to set the permissions for.
+
+ permissions : list[dict[str, Any]]
+ The permissions to set for the group.
+ Example:
+ ```
+ [
+ {
+ "name": "web",
+ "is_readonly": False,
+ "is_writable": False,
+ "is_deny": True
+ },
+ {
+ "name": "ActiveBackupforBusiness",
+ "is_readonly": False,
+ "is_writable": True,
+ "is_deny": False
+ }
+ ]
+ ```
+
+ Returns
+ -------
+ dict
+ Success.
+
+ Examples
+ --------
+ ```json
+ {
+ "success": true
+ }
+ ```
+ """
+ api_name = "SYNO.Core.Share.Permission"
+ info = self.core_list[api_name]
+ api_path = info["path"]
+ req_param = {
+ "version": info["minVersion"],
+ "method": "set_by_user_group",
+ "name": group,
+ "user_group_type": "local_group",
+ "permissions": json.dumps(permissions),
+ }
+
+ return self.request_data(api_name, api_path, req_param)
+
+ def export_encryption_key(self, name: str, password: str) -> dict:
+ """
+ Export encryption key for a given share.
+
+ Parameters
+ ----------
+ name : str
+ The share name to export the encryption key for.
+ password : str
+ The password to use for exporting the encryption key.
+
+ Returns
+ -------
+ dict
+ Success.
+
+ Examples
+ --------
+ ```json
+ {
+ "success": true
+ }
+ ```
+ """
+ api_name = "SYNO.Core.Share.Crypto.Key"
+ info = self.core_list[api_name]
+ api_path = info["path"]
+ req_param = {
+ "method": "export",
+ "version": info['maxVersion'],
+ "name": name,
+ }
+
+ enc_req_param = {
+ "password": password,
+ }
+ # If using https don't use encryption
+ if self.session._secure:
+ req_param.update(enc_req_param)
+ else:
+ encrypted_params = self.session.encrypt_params(enc_req_param)
+ req_param.update(encrypted_params)
+
+ return self.request_data(api_name, api_path, req_param, method="post")
+
+ def decrypt_folder(self, name: str, password: str) -> dict:
+ """
+ Decrypt a given share.
+
+ Parameters
+ ----------
+ name : str
+ The share name to decrypt.
+ password : str
+ The password to use for decrypting the share.
+
+ Returns
+ -------
+ dict
+ Success.
+
+ Examples
+ --------
+ ```json
+ {
+ "success": true
+ }
+ ```
+ """
+ api_name = "SYNO.Core.Share.Crypto"
+ info = self.core_list[api_name]
+ api_path = info["path"]
+ req_param = {
+ "method": "decrypt",
+ "version": info['maxVersion'],
+ "name": name,
+ }
+
+ req_param_encrypted = {
+ "password": password,
+ }
+ # If using https don't use encryption
+ if self.session._secure:
+ req_param.update(req_param_encrypted)
+ else:
+ encrypted_params = self.session.encrypt_params(req_param_encrypted)
+ req_param.update(encrypted_params)
+
+ return self.request_data(api_name, api_path, req_param, method="post")
+
+ def encrypt_folder(self, name: str) -> dict:
+ """
+ Encrypt a given share.
+
+ Parameters
+ ----------
+ name : str
+ The share name to encrypt.
+
+ Returns
+ -------
+ dict
+ Success.
+
+ Examples
+ --------
+ ```json
+ {
+ "success": true
+ }
+ ```
+ """
+ api_name = "SYNO.Core.Share.Crypto"
+ info = self.core_list[api_name]
+ api_path = info["path"]
+ req_param = {
+ "method": "encrypt",
+ "version": info['maxVersion'],
+ "name": name,
+ }
+ return self.request_data(api_name, api_path, req_param, method="post")
+
+
+class KeyManagerStore(base_api.BaseApi):
+ """
+ Core Share KeyManager Store API implementation.
+ """
+
+ def init(self) -> dict:
+ """
+ Initialize KeyManagerStore API.
+
+ Returns
+ -------
+ dict
+ Not implemented yet.
+ """
+
+ raise NotImplementedError(
+ "This method is not completly implemented yet. API return error 403")
+
+ api_name = "SYNO.Core.Share.KeyManager.Store"
+ version = self.core_list[api_name]["maxVersion"]
+ api_path = self.core_list[api_name]["path"]
+ req_param = {
+ "version": version,
+ "method": "init",
+ "share_path": "/usr/syno/etc/.encrypt"
+ }
+
+ req_param_encrypted = {
+ "passphrase": "",
+ }
+
+ # If using https don't use encryption
+ if self.session._secure:
+ req_param.update(req_param_encrypted)
+ else:
+ encrypted_params = self.session.encrypt_params(req_param_encrypted)
+ req_param.update(encrypted_params)
+
+ return self.request_data(api_name, api_path, req_param, method="post")
+
+ def verify(self) -> dict:
+ """
+ Verify KeyManagerStore API.
+
+ Returns
+ -------
+ dict
+ Not implemented yet.
+ """
+ raise NotImplementedError("This method is not implemented yet.")
+
+ api_name = "SYNO.Core.Share.KeyManager.Store"
+ version = self.core_list[api_name]["maxVersion"]
+ api_path = self.core_list[api_name]["path"]
+ req_param = {
+ "version": version,
+ "method": "verify",
+ }
+
+ req_param_encrypted = {
+ "passphrase": "",
+ }
+
+ # If using https don't use encryption
+ if self.session._secure:
+ req_param.update(req_param_encrypted)
+ else:
+ encrypted_params = self.session.encrypt_params(req_param_encrypted)
+ req_param.update(encrypted_params)
+
+ return self.request_data(api_name, api_path, req_param, method="post")
+
+ def explore(self) -> dict:
+ """
+ Explore KeyManagerStore API. Get list of existing stores.
+
+ Returns
+ -------
+ dict
+ List of stores existing on the NAS.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "stores": []
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = "SYNO.Core.Share.KeyManager.Store"
+ version = self.core_list[api_name]["minVersion"]
+ api_path = self.core_list[api_name]["path"]
+ req_param = {
+ "version": version,
+ "method": "explore",
+ }
+
+ return self.request_data(api_name, api_path, req_param)
+
+ def add(self, share_name: str, share_cypher: int, share_password: str) -> dict:
+ """
+ Add KeyManagerStore API. Add a new store.
+
+ Parameters
+ ----------
+ share_name : str
+ The share name to add to the store.
+ share_cypher : int
+ The share cypher to use.
+ share_password : str
+ The share password to use.
+
+ Returns
+ -------
+ dict
+ Not implemented yet.
+ """
+ raise NotImplementedError(
+ "This method is not completly implemented yet. API return error 403")
+
+ api_name = "SYNO.Core.Share.KeyManager.Key"
+ version = self.core_list[api_name]["maxVersion"]
+ api_path = self.core_list[api_name]["path"]
+ req_param = {
+ "version": version,
+ "method": "add",
+ "share_name": share_name,
+ "share_cypher": share_cypher,
+ "share_password": share_password,
+ "passphrase": "2PassValidation",
+ }
+
+ return self.request_data(api_name, api_path, req_param, method="post")
+
+
+class KeyManagerAutoKey(base_api.BaseApi):
+ """
+ Core Share KeyManager AutoKey API implementation.
+ """
+
+ def list(self) -> dict:
+ """
+ List KeyManagerStore API.
+
+ Returns
+ -------
+ dict
+ List of keys in the manager.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "keys": []
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = "SYNO.Core.Share.KeyManager.AutoKey"
+ version = self.core_list[api_name]["minVersion"]
+ api_path = self.core_list[api_name]["path"]
+ req_param = {
+ "version": version,
+ "method": "list",
+ }
+
+ return self.request_data(api_name, api_path, req_param)
diff --git a/synology_api/DSM/ControlPanel/SynologyAccount.py b/synology_api/DSM/ControlPanel/SynologyAccount.py
new file mode 100644
index 00000000..23a16f7f
--- /dev/null
+++ b/synology_api/DSM/ControlPanel/SynologyAccount.py
@@ -0,0 +1,11 @@
+"""
+Synology Account API endpoint.
+"""
+from synology_api import base_api
+
+
+class SynologyAccount(base_api.BaseApi):
+ """
+ Synology Account API endpoint.
+ """
+ pass
diff --git a/synology_api/DSM/ControlPanel/TaskScheduler.py b/synology_api/DSM/ControlPanel/TaskScheduler.py
new file mode 100644
index 00000000..62098203
--- /dev/null
+++ b/synology_api/DSM/ControlPanel/TaskScheduler.py
@@ -0,0 +1,11 @@
+"""
+Task Scheduler API endpoint.
+"""
+from synology_api import base_api
+
+
+class TaskScheduler(base_api.BaseApi):
+ """
+ Task Scheduler API endpoint.
+ """
+ pass
diff --git a/synology_api/DSM/ControlPanel/TerminalSNMP.py b/synology_api/DSM/ControlPanel/TerminalSNMP.py
new file mode 100644
index 00000000..f4483900
--- /dev/null
+++ b/synology_api/DSM/ControlPanel/TerminalSNMP.py
@@ -0,0 +1,11 @@
+"""
+Terminal SNMP class for Synology DSM.
+"""
+from synology_api import base_api
+
+
+class TerminalSNMP(base_api.BaseApi):
+ """
+ Terminal SNMP class for Synology DSM.
+ """
+ pass
diff --git a/synology_api/DSM/ControlPanel/UpdateRestore.py b/synology_api/DSM/ControlPanel/UpdateRestore.py
new file mode 100644
index 00000000..ac2d618d
--- /dev/null
+++ b/synology_api/DSM/ControlPanel/UpdateRestore.py
@@ -0,0 +1,11 @@
+"""
+Update and restore class for Synology DSM.
+"""
+from synology_api import base_api
+
+
+class UpdateRestore(base_api.BaseApi):
+ """
+ Update and restore class for Synology DSM.
+ """
+ pass
diff --git a/synology_api/DSM/ControlPanel/UserGroup.py b/synology_api/DSM/ControlPanel/UserGroup.py
new file mode 100644
index 00000000..67903d0f
--- /dev/null
+++ b/synology_api/DSM/ControlPanel/UserGroup.py
@@ -0,0 +1,11 @@
+"""
+User Group API endpoint.
+"""
+from synology_api import base_api
+
+
+class UserGroup(base_api.BaseApi):
+ """
+ User Group API endpoint.
+ """
+ pass
diff --git a/synology_api/DSM/ControlPanel/__init__.py b/synology_api/DSM/ControlPanel/__init__.py
new file mode 100644
index 00000000..32bc6060
--- /dev/null
+++ b/synology_api/DSM/ControlPanel/__init__.py
@@ -0,0 +1,375 @@
+"""
+ControlPanel submodule for Synology DSM API. Provides access to all DSM Control Panel APIs.
+"""
+
+from .ApplicationPrivileges import ApplicationPrivileges
+from .DomainLDAP import DomainLDAP
+from .ExternalAccess import ExternalAccess
+from .ExternalDevices import ExternalDevices
+from .FileServices import FileServices
+from .HardwarePower import HardwarePower
+from .IndexingService import IndexingService
+from .InfoCenter import InfoCenter
+from .LoginPortal import LoginPortal
+from .Network import Network
+from .Notifications import Notifications
+from .RegionalOptions import RegionalOptions
+from .Security import Security
+from .SharedFolder import SharedFolder
+from .SynologyAccount import SynologyAccount
+from .TaskScheduler import TaskScheduler
+from .Security import Security
+from .TerminalSNMP import TerminalSNMP
+from .UpdateRestore import UpdateRestore
+from .UserGroup import UserGroup
+
+from synology_api import base_api
+
+
+class ControlPanel(base_api.BaseApi):
+ """
+ ControlPanel submodule for Synology DSM API. Provides access to all DSM Control Panel APIs.
+ """
+ _app_priv = None
+ _domain_ldap = None
+ _ext_access = None
+ _ext_devices = None
+ _file_services = None
+ _hard_power = None
+ _idx_service = None
+ _info_center = None
+ _log_portal = None
+ _network = None
+ _notification = None
+ _region_opt = None
+ _security = None
+ _shared_folder = None
+ _syno_account = None
+ _task_scheduler = None
+ _terminal_snmp = None
+ _update_restore = None
+ _user_group = None
+
+ @property
+ def ApplicationPrivileges(self):
+ """
+ ControlPanel: ApplicationPrivileges.
+
+ Returns
+ -------
+ ApplicationPrivileges
+ Instance of the ApplicationPrivileges API, sharing the same state as DSM.
+ """
+ if self._app_priv is None:
+ # Create ApplicationPrivileges instance without calling __init__
+ self._app_priv = ApplicationPrivileges.__new__(
+ ApplicationPrivileges)
+ # Share the state
+ self._app_priv.__dict__ = self.__dict__
+ return self._app_priv
+
+ @property
+ def DomainLDAP(self):
+ """
+ ControlPanel: DomainLDAP.
+
+ Returns
+ -------
+ DomainLDAP
+ Instance of the DomainLDAP API, sharing the same state as DSM.
+ """
+ if self._domain_ldap is None:
+ # Create DomainLDAP instance without calling __init__
+ self._domain_ldap = DomainLDAP.__new__(DomainLDAP)
+ # Share the state
+ self._domain_ldap.__dict__ = self.__dict__
+ return self._domain_ldap
+
+ @property
+ def ExternalAccess(self):
+ """
+ ControlPanel: ExternalAccess.
+
+ Returns
+ -------
+ ExternalAccess
+ Instance of the ExternalAccess API, sharing the same state as DSM.
+ """
+ if self._ext_access is None:
+ # Create ExternalAccess instance without calling __init__
+ self._ext_access = ExternalAccess.__new__(ExternalAccess)
+ # Share the state
+ self._ext_access.__dict__ = self.__dict__
+ return self._ext_access
+
+ @property
+ def ExternalDevices(self):
+ """
+ ControlPanel: ExternalDevices.
+
+ Returns
+ -------
+ ExternalDevices
+ Instance of the ExternalDevices API, sharing the same state as DSM.
+ """
+ if self._ext_devices is None:
+ # Create ExternalDevices instance without calling __init__
+ self._ext_devices = ExternalDevices.__new__(ExternalDevices)
+ # Share the state
+ self._ext_devices.__dict__ = self.__dict__
+ return self._ext_devices
+
+ @property
+ def FileServices(self):
+ """
+ ControlPanel: FileServices.
+
+ Returns
+ -------
+ FileServices
+ Instance of the FileServices API, sharing the same state as DSM.
+ """
+ if self._file_services is None:
+ # Create FileServices instance without calling __init__
+ self._file_services = FileServices.__new__(FileServices)
+ # Share the state
+ self._file_services.__dict__ = self.__dict__
+ return self._file_services
+
+ @property
+ def HardwarePower(self):
+ """
+ ControlPanel: HardwarePower.
+
+ Returns
+ -------
+ HardwarePower
+ Instance of the HardwarePower API, sharing the same state as DSM.
+ """
+ if self._hard_power is None:
+ # Create HardwarePower instance without calling __init__
+ self._hard_power = HardwarePower.__new__(HardwarePower)
+ # Share the state
+ self._hard_power.__dict__ = self.__dict__
+ return self._hard_power
+
+ @property
+ def IndexingService(self):
+ """
+ ControlPanel: IndexingService.
+
+ Returns
+ -------
+ IndexingService
+ Instance of the IndexingService API, sharing the same state as DSM.
+ """
+ if self._idx_service is None:
+ # Create IndexingService instance without calling __init__
+ self._idx_service = IndexingService.__new__(IndexingService)
+ # Share the state
+ self._idx_service.__dict__ = self.__dict__
+ return self._idx_service
+
+ @property
+ def InfoCenter(self):
+ """
+ ControlPanel: InfoCenter.
+
+ Returns
+ -------
+ InfoCenter
+ Instance of the InfoCenter API, sharing the same state as DSM.
+ """
+ if self._info_center is None:
+ # Create InfoCenter instance without calling __init__
+ self._info_center = InfoCenter.__new__(InfoCenter)
+ # Share the state
+ self._info_center.__dict__ = self.__dict__
+ return self._info_center
+
+ @property
+ def LoginPortal(self):
+ """
+ ControlPanel: LoginPortal.
+
+ Returns
+ -------
+ LoginPortal
+ Instance of the LoginPortal API, sharing the same state as DSM.
+ """
+ if self._log_portal is None:
+ # Create LoginPortal instance without calling __init__
+ self._log_portal = LoginPortal.__new__(LoginPortal)
+ # Share the state
+ self._log_portal.__dict__ = self.__dict__
+ return self._log_portal
+
+ @property
+ def Network(self):
+ """
+ ControlPanel: Network.
+
+ Returns
+ -------
+ Network
+ Instance of the Network API, sharing the same state as DSM.
+ """
+ if self._network is None:
+ # Create Network instance without calling __init__
+ self._network = Network.__new__(Network)
+ # Share the state
+ self._network.__dict__ = self.__dict__
+ return self._network
+
+ @property
+ def Notifications(self):
+ """
+ ControlPanel: Notifications.
+
+ Returns
+ -------
+ Notifications
+ Instance of the Notifications API, sharing the same state as DSM.
+ """
+ if self._notification is None:
+ # Create Notifications instance without calling __init__
+ self._notification = Notifications.__new__(Notifications)
+ # Share the state
+ self._notification.__dict__ = self.__dict__
+ return self._notification
+
+ @property
+ def RegionalOptions(self):
+ """
+ ControlPanel: RegionalOptions.
+
+ Returns
+ -------
+ RegionalOptions
+ Instance of the RegionalOptions API, sharing the same state as DSM.
+ """
+ if self._region_opt is None:
+ # Create RegionalOptions instance without calling __init__
+ self._region_opt = RegionalOptions.__new__(RegionalOptions)
+ # Share the state
+ self._region_opt.__dict__ = self.__dict__
+ return self._region_opt
+
+ @property
+ def Security(self):
+ """
+ ControlPanel: Security.
+
+ Returns
+ -------
+ Security
+ Instance of the Security API, sharing the same state as DSM.
+ """
+ if self._security is None:
+ # Create Security instance without calling __init__
+ self._security = Security.__new__(Security)
+ # Share the state
+ self._security.__dict__ = self.__dict__
+ return self._security
+
+ @property
+ def SharedFolder(self):
+ """
+ ControlPanel: SharedFolder.
+
+ Returns
+ -------
+ SharedFolder
+ Instance of the SharedFolder API, sharing the same state as DSM.
+ """
+ if self._shared_folder is None:
+ # Create SharedFolder instance without calling __init__
+ self._shared_folder = SharedFolder.__new__(SharedFolder)
+ # Share the state
+ self._shared_folder.__dict__ = self.__dict__
+ return self._shared_folder
+
+ @property
+ def SynologyAccount(self):
+ """
+ ControlPanel: SynologyAccount.
+
+ Returns
+ -------
+ SynologyAccount
+ Instance of the SynologyAccount API, sharing the same state as DSM.
+ """
+ if self._syno_account is None:
+ # Create ApplicationPrivileges instance without calling __init__
+ self._syno_account = SynologyAccount.__new__(SynologyAccount)
+ # Share the state
+ self._syno_account.__dict__ = self.__dict__
+ return self._syno_account
+
+ @property
+ def TaskScheduler(self):
+ """
+ ControlPanel: TaskScheduler.
+
+ Returns
+ -------
+ TaskScheduler
+ Instance of the TaskScheduler API, sharing the same state as DSM.
+ """
+ if self._task_scheduler is None:
+ # Create TaskScheduler instance without calling __init__
+ self._task_scheduler = TaskScheduler.__new__(TaskScheduler)
+ # Share the state
+ self._task_scheduler.__dict__ = self.__dict__
+ return self._task_scheduler
+
+ @property
+ def TerminalSNMP(self):
+ """
+ ControlPanel: TerminalSNMP.
+
+ Returns
+ -------
+ TerminalSNMP
+ Instance of the TerminalSNMP API, sharing the same state as DSM.
+ """
+ if self._terminal_snmp is None:
+ # Create TerminalSNMP instance without calling __init__
+ self._terminal_snmp = TerminalSNMP.__new__(TerminalSNMP)
+ # Share the state
+ self._terminal_snmp.__dict__ = self.__dict__
+ return self._terminal_snmp
+
+ @property
+ def UpdateRestore(self):
+ """
+ ControlPanel: UpdateRestore.
+
+ Returns
+ -------
+ UpdateRestore
+ Instance of the UpdateRestore API, sharing the same state as DSM.
+ """
+ if self._update_restore is None:
+ # Create UpdateRestore instance without calling __init__
+ self._update_restore = UpdateRestore.__new__(UpdateRestore)
+ # Share the state
+ self._update_restore.__dict__ = self.__dict__
+ return self._update_restore
+
+ @property
+ def UserGroup(self):
+ """
+ ControlPanel: UserGroup.
+
+ Returns
+ -------
+ UserGroup
+ Instance of the UserGroup API, sharing the same state as DSM.
+ """
+ if self._user_group is None:
+ # Create UserGroup instance without calling __init__
+ self._user_group = UserGroup.__new__(UserGroup)
+ # Share the state
+ self._user_group.__dict__ = self.__dict__
+ return self._user_group
diff --git a/synology_api/DSM/Package/FileStation.py b/synology_api/DSM/Package/FileStation.py
new file mode 100644
index 00000000..1d3655ca
--- /dev/null
+++ b/synology_api/DSM/Package/FileStation.py
@@ -0,0 +1,2605 @@
+"""
+Implementation of FileStation API based on the Synology API documentation.
+"""
+
+from __future__ import annotations
+from typing import Optional, Any
+from datetime import datetime
+import requests
+import tqdm
+import time
+import io
+import json
+import os
+import sys
+from requests_toolbelt import MultipartEncoder, MultipartEncoderMonitor
+from urllib import parse
+from treelib import Tree
+import warnings
+from synology_api import base_api
+
+
+class FileStation(base_api.BaseApi):
+ """
+ Implementation of FileStation API based on the Synology API documentation. See: https://global.download.synology.com/download/Document/Software/DeveloperGuide/Package/FileStation/All/enu/Synology_File_Station_API_Guide.pdf .
+ """
+
+ def get_info(self) -> dict[str, object]:
+ """
+ Get info about FileStation.
+
+ Returns
+ -------
+ dict of str to object
+ List of FileStation info.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "allow_normal_disable_html": true,
+ "enable_list_usergrp": false,
+ "enable_send_email_attachment": true,
+ "enable_view_google": true,
+ "enable_view_microsoft": true,
+ "hostname": "SYNO-FLORENTB",
+ "is_manager": true,
+ "items": [
+ {
+ "gid": 100
+ },
+ {
+ "gid": 101
+ },
+ {
+ "gid": 1023
+ }
+ ],
+ "support_file_request": true,
+ "support_sharing": true,
+ "support_vfs": true,
+ "support_virtual": {
+ "enable_iso_mount": true,
+ "enable_remote_mount": true
+ },
+ "support_virtual_protocol": [
+ "cifs",
+ "nfs",
+ "iso"
+ ],
+ "system_codepage": "fre",
+ "uid": 1027
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.FileStation.Info'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {'version': info['maxVersion'], 'method': 'get'}
+
+ return self.request_data(api_name, api_path, req_param)
+
+ def get_list_share(self,
+ additional: Optional[list[str]] = None,
+ offset: Optional[int] = None,
+ limit: Optional[int] = None,
+ sort_by: Optional[str] = None,
+ sort_direction: Optional[str] = None,
+ onlywritable: bool = False
+ ) -> dict[str, object]:
+ """
+ Get list of shared folders.
+
+ Parameters
+ ----------
+ additional : Optional[list[str]], optional
+ Additionnal field to retrieve from shared folder. Defaults to `None`
+ All fields known are: `["real_path","size","owner","time","perm","mount_point_type","sync_share","volume_status","indexed","hybrid_share","worm_share"]`.
+ offset : Optional[int], optional
+ Offset in the shared folder list. Defaults to `None`
+ limit : Optional[int], optional
+ Limit the len of the returned list. Defaults to `None`
+ sort_by : Optional[str], optional
+ Specify which file information to sort on. Defaults to `None`
+ All fields know are: `["name","user","group","mtime","atime","ctime","crtime","posix"]`
+ sort_direction : Optional[str], optional
+ Specify to sort ascending or to sort descending. Defaults to `None`
+ All possible direction are: `["asc","desc"]`
+ onlywritable : bool, optional
+ Force list of shared folder where the user as write access. Defaults to `False`
+
+ Returns
+ -------
+ dict[str, object]
+ List of shared folder in FileStation.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "offset": 0,
+ "shares": [
+ {
+ "isdir": true,
+ "name": "docker",
+ "path": "/docker"
+ },
+ {
+ "isdir": true,
+ "name": "Documents",
+ "path": "/Documents"
+ }
+ ],
+ "total": 2
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.FileStation.List'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'list_share',
+ 'onlywritable': onlywritable,
+ 'offset': offset,
+ 'limit': limit,
+ 'sort_by': sort_by,
+ 'sort_direction': sort_direction,
+ 'additional': json.dumps(additional)
+ }
+
+ return self.request_data(api_name, api_path, req_param)
+
+ def get_file_list(self,
+ folder_path: str,
+ offset: Optional[int] = None,
+ limit: Optional[int] = None,
+ sort_by: Optional[str] = None,
+ sort_direction: Optional[str] = None,
+ pattern: Optional[list[str]] = None,
+ filetype: Optional[str] = None,
+ goto_path: Optional[str] = None,
+ additional: Optional[list[str]] = None,
+ check_dir: Optional[bool] = None
+ ) -> dict[str, object]:
+ """
+ Get list of files in a folder.
+
+ Parameters
+ ----------
+ folder_path : str
+ A listed folder path starting with a shared folder.
+ offset : Optional[int], optional
+ Specify how many files are skipped before beginning to return listed files. Defaults to `None`
+ limit : Optional[int], optional
+ Number of files requested. 0 indicates to list all files with a given folder. Defaults to `None`
+ sort_by : Optional[str], optional
+ Specify which file information to sort on. Defaults to `None`
+ All fields known are: `["name","size","user","group","mtime","atime","ctime","crtime","posix","type"]`
+ sort_direction : Optional[str], optional
+ Specify to sort ascending or to sort descending. Defaults to `None`
+ All possible direction are: `["asc","desc"]`
+ pattern : Optional[list[str]], optional
+ Given glob pattern(s) to find files whose names and extensions match a case insensitive glob pattern. Defaults to `None`
+ Note: 1. If the pattern doesn't contain any glob syntax (? and *), * of glob syntax will be added at begin and end of the string automatically for partially matching the pattern.
+ filetype : Optional[str], optional
+ "file": only enumerate regular files; "dir": only enumerate folders; "all" enumerate regular files and folders. Defaults to `None`
+ All fields know are: `["file","dir","all"]`
+ goto_path : Optional[str], optional
+ Folder path starting with a shared folder. Return all files and sub-folders within folder_path path until goto_path path recursively. Defaults to `None`
+ Note: goto_path is only valid with parameter "additional" contains real_path.
+ additional : Optional[list[str]], optional
+ Additionnal field to retrieve from file. Defaults to `None`
+ All fields known are: `["real_path","size","owner","time","perm","type","mount_point_type"]`.
+ check_dir : Optional[bool], optional
+ _description_. Defaults to `None`
+
+ Returns
+ -------
+ dict[str, object]
+ Information about the files in the folder.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "files": [
+ {
+ "isdir": false,
+ "name": "compose.yaml",
+ "path": "/docker/compose.yaml"
+ }
+ ],
+ "offset": 0,
+ "total": 1
+ },
+ "success": true
+ }
+ ```
+ """
+
+ api_name = 'SYNO.FileStation.List'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'action': 'list',
+ 'method': 'list',
+ 'folder_path': folder_path,
+ 'offset': offset,
+ 'limit': limit,
+ 'sort_by': sort_by,
+ 'sort_direction': sort_direction,
+ 'pattern': ', '.join(pattern) if isinstance(pattern, list) else pattern if isinstance(pattern, str) else None,
+ 'filetype': filetype,
+ 'goto_path': goto_path,
+ 'additional': json.dumps(additional),
+ 'check_dir': check_dir
+ }
+
+ return self.request_data(api_name, api_path, req_param)
+
+ def get_file_info(self, path: list[str], additional: Optional[list[str]] = None) -> dict[str, object]:
+ """
+ Get information of file(s) / folder(s).
+
+ Parameters
+ ----------
+ path : list[str]
+ One or more folder/file path(s) starting with a shared folder
+ additional : Optional[list[str]], optional
+ Additionnal field to retrieve from file. Defaults to `None`
+ All fields known are: `["real_path","size","owner","time","perm","type","mount_point_type"]`.
+
+ Returns
+ -------
+ dict[str, object]
+ Information of file(s) / folder(s).
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "files": [
+ {
+ "isdir": true,
+ "name": "Films",
+ "path": "/Films"
+ },
+ {
+ "isdir": true,
+ "name": "Documents",
+ "path": "/Documents"
+ }
+ ]
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.FileStation.List'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'getinfo',
+ 'path': json.dumps(path),
+ 'additional': json.dumps(additional)
+ }
+
+ return self.request_data(api_name, api_path, req_param)
+
+ def search_start(self,
+ folder_path: str = None, recursive: Optional[bool] = None, pattern: Optional[list[str]] = None,
+ extension: Optional[list[str]] = None, filetype: Optional[str] = None, size_from: Optional[int] = None,
+ size_to: Optional[int] = None, mtime_from: Optional[int] = None, mtime_to: Optional[int] = None,
+ crtime_from: Optional[int] = None, crtime_to: Optional[int] = None, atime_from: Optional[int] = None,
+ atime_to: Optional[int] = None, owner: Optional[str] = None, group: Optional[str] = None
+ ) -> dict[str, object]:
+ """
+ Start to search files according to given criteria. If more than one criterion is given in different parameters, searched files match all these criteria.
+
+ Parameters
+ ----------
+ folder_path : str, optional
+ A searched folder path starting with a shared folder. One or more folder paths to be searched, separated by commas "," and around brackets. Defaults to `None`
+ recursive : Optional[bool], optional
+ If searching files within a folder and subfolders recursively or not. Defaults to `None`
+ pattern : Optional[list[str]], optional
+ Given glob pattern(s) to find files whose names and extensions match a case insensitive glob pattern. Defaults to `None`
+ Note: 1. If the pattern doesn't contain any glob syntax (? and *), * of glob syntax will be added at begin and end of the string automatically for partially matching the pattern.. Defaults to `None`
+ extension : Optional[list[str]], optional
+ Search for files whose extensions match a file type pattern in a case-insensitive glob pattern. If you give this criterion, folders aren't matched. Defaults to `None`
+ filetype : Optional[str], optional
+ "file": only enumerate regular files; "dir": only enumerate folders; "all" enumerate regular files and folders. Defaults to `None`
+ All fields know are: `["file","dir","all"]`
+ size_from : Optional[int], optional
+ Search for files whose sizes are greater than the given byte size. Defaults to `None`
+ size_to : Optional[int], optional
+ Search for files whose sizes are less than the given byte size. Defaults to `None`
+ mtime_from : Optional[int], optional
+ Search for files whose last modified time after the given Linux timestamp (UTC) in second. Defaults to `None`
+ mtime_to : Optional[int], optional
+ Search for files whose last modified time before the given Linux timestamp (UTC) in second. Defaults to `None`
+ crtime_from : Optional[int], optional
+ Search for files whose create time after the given Linux timestamp (UTC) in second. Defaults to `None`
+ crtime_to : Optional[int], optional
+ Search for files whose create time before the given Linux timestamp (UTC) in second. Defaults to `None`
+ atime_from : Optional[int], optional
+ Search for files whose last access time after the given Linux timestamp (UTC) in second. Defaults to `None`
+ atime_to : Optional[int], optional
+ Search for files whose last access time before the given Linux timestamp (UTC) in second. Defaults to `None`
+ owner : Optional[str], optional
+ Search for files whose user name matches this criterion. This criterion is case-insensitive. Defaults to `None`
+ group : Optional[str], optional
+ Search for files whose group name matches this criterion. This criterion is case-insensitive. Defaults to `None`
+
+ Returns
+ -------
+ dict[str, object]
+ A unique ID for the search task.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "has_not_index_share": true,
+ "taskid": "51CE617CF57B24E5"
+ },
+ "success": true
+ }
+ ```
+ """
+
+ api_name = 'SYNO.FileStation.Search'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'start',
+ 'folder_path': folder_path,
+ 'recursive': recursive,
+ 'pattern': ', '.join(pattern) if isinstance(pattern, list) else pattern if isinstance(pattern, str) else None,
+ 'extension': ', '.join(extension) if isinstance(extension, list) else extension if isinstance(extension, str) else None,
+ 'filetype': filetype,
+ 'size_from': size_from,
+ 'size_to': size_to,
+ 'mtime_from': mtime_from,
+ 'mtime_to': mtime_to,
+ 'crtime_from': crtime_from,
+ 'crtime_to': crtime_to,
+ 'atime_from': atime_from,
+ 'atime_to': atime_to,
+ 'owner': owner,
+ 'group': group
+ }
+
+ return self.request_data(api_name, api_path, req_param)
+
+ def get_search_list(self,
+ taskid: str,
+ offset: Optional[int] = None,
+ limit: Optional[int] = None,
+ sort_by: Optional[str] = None,
+ sort_direction: Optional[str] = None,
+ pattern: Optional[list[str]] = None,
+ filetype: Optional[str] = None,
+ additional: Optional[list[str]] = None
+ ) -> dict[str, object]:
+ """
+ List matched files in a search temporary database. You can check the finished value in response to know if the search operation is processing or has been finished.
+
+ Parameters
+ ----------
+ taskid : str
+ A unique ID for the search task which is obtained from `search_start` method.
+ offset : Optional[int], optional
+ Specify how many files are skipped before beginning to return listed files. Defaults to `None`
+ limit : Optional[int], optional
+ Number of files requested. 0 indicates to list all files with a given folder. Defaults to `None`
+ sort_by : Optional[str], optional
+ Specify which file information to sort on. Defaults to `None`
+ All fields known are: `["name","size","user","group","mtime","atime","ctime","crtime","posix","type"]`
+ sort_direction : Optional[str], optional
+ Specify to sort ascending or to sort descending. Defaults to `None`
+ All possible direction are: `["asc","desc"]`
+ pattern : Optional[list[str]], optional
+ Given glob pattern(s) to find files whose names and extensions match a case insensitive glob pattern. Defaults to `None`
+ Note: 1. If the pattern doesn't contain any glob syntax (? and *), * of glob syntax will be added at begin and end of the string automatically for partially matching the pattern.
+ filetype : Optional[str], optional
+ "file": only enumerate regular files; "dir": only enumerate folders; "all" enumerate regular files and folders. Defaults to `None`
+ All fields know are: `["file","dir","all"]`
+ additional : Optional[list[str]], optional
+ Additionnal field to retrieve from file. Defaults to `None`
+ All fields known are: `["real_path","size","owner","time","perm","type"]`.
+
+ Returns
+ -------
+ dict[str, object]
+ Infos about the search and the matched files.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "files": [
+ {
+ "isdir": false,
+ "name": "compose.yaml",
+ "path": "/docker/compose.yaml"
+ }
+ ],
+ "finished": true,
+ "offset": 0,
+ "total": 1
+ },
+ "success": true
+ }
+ ```
+ """
+
+ api_name = 'SYNO.FileStation.Search'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'list',
+ 'taskid': taskid,
+ 'offset': offset,
+ 'limit': limit,
+ 'sort_by': sort_by,
+ 'sort_direction': sort_direction,
+ 'pattern': ', '.join(pattern) if isinstance(pattern, list) else pattern if isinstance(pattern, str) else None,
+ 'filetype': filetype,
+ 'additional': json.dumps(additional)
+ }
+
+ return self.request_data(api_name, api_path, req_param)
+
+ def stop_search_task(self, taskid: str | list[str]) -> dict[str, object]:
+ """
+ Stop the searching task(s). The search temporary database won't be deleted, so it's possible to list the search result using list method after stopping it.
+
+ Parameters
+ ----------
+ taskid : str | list[str]
+ Unique ID(s) for the search task which are obtained from `search_start` method. Specify multiple search task IDs by using list type.
+
+ Returns
+ -------
+ dict[str, object]
+ No specific response. It returns an empty success response if completed without error.
+
+ Examples
+ --------
+ ```json
+ {
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.FileStation.Search'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'stop',
+ 'taskid': json.dumps(taskid) if isinstance(taskid, list) else taskid,
+ }
+
+ return self.request_data(api_name, api_path, req_param)
+
+ def clean_search_task(self, taskid: str | list[str]) -> dict[str, object]:
+ """
+ Delete search temporary database(s).
+
+ Parameters
+ ----------
+ taskid : str | list[str]
+ Unique ID(s) for the search task which are obtained from `search_start` method. Specify multiple search task IDs by using list type.
+
+ Returns
+ -------
+ dict[str, object]
+ No specific response. It returns an empty success response if completed without error.
+
+ Examples
+ --------
+ ```json
+ {
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.FileStation.Search'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'clean',
+ 'taskid': json.dumps(taskid) if isinstance(taskid, list) else taskid,
+ }
+
+ return self.request_data(api_name, api_path, req_param)
+
+ def get_mount_point_list(self, mount_type: str, offset: Optional[int] = None, limit: Optional[int] = None,
+ sort_by: Optional[str] = None, sort_direction: Optional[str] = None, additional: Optional[list[str]] = None
+ ) -> dict[str, object]:
+ """
+ List all mount point folders on one given type of virtual file system.
+
+ Parameters
+ ----------
+ mount_type : str
+ A type of virtual file systems.
+ All fields known are: `["cifs","nfs","iso"]`
+ offset : Optional[int], optional
+ Specify how many mount point folders are skipped before beginning to return listed files. Defaults to `None`
+ limit : Optional[int], optional
+ Number of mount point folders requested. 0 indicates to list all files with a given folder. Defaults to `None`
+ sort_by : Optional[str], optional
+ Specify which file information to sort on. Defaults to `None`
+ All fields known are: `["name",,"user","group","mtime","atime","ctime","crtime","posix"]`
+ sort_direction : Optional[str], optional
+ Specify to sort ascending or to sort descending. Defaults to `None`
+ All possible direction are: `["asc","desc"]`
+ additional : Optional[list[str]], optional
+ Additionnal field to retrieve from file. Defaults to `None`
+ All fields known are: `["real_path","size","owner","time","perm","volume_status"]`.
+
+ Returns
+ -------
+ dict[str, object]
+ List of mount point folders.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "folders": [
+ {
+ "additional": {
+ "mount_point_type": "remote",
+ "owner": {
+ "gid": 100,
+ "group": "users",
+ "uid": 1024,
+ "user": "admin"
+ },
+ "perm": {
+ "acl": {
+ "append": true,
+ "del": true,
+ "exec": true,
+ "read": true,
+ "write": true
+ },
+ "is_acl_mode": false,
+ "posix": 777
+ },
+ "real_path": "/volume1/vidoe/remote",
+ "time": {
+ "atime": 1372313445,
+ "crtime": 1320204670,
+ "ctime": 1371206944,
+ "mtime": 1371206944
+ },
+ "volume_status": {
+ "freespace": 12282422599680,
+ "readonly": false,
+ "totalspace": 801958928384
+ }
+ },
+ "isdir": true,
+ "name": "remote",
+ "path": "/video/remote"
+ }
+ ],
+ "offset": 0,
+ "total": 0
+ },
+ "success": true
+ }
+ ```
+ """
+
+ api_name = 'SYNO.FileStation.VirtualFolder'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'list',
+ 'type': mount_type,
+ 'offset': offset,
+ 'limit': limit,
+ 'sort_by': sort_by,
+ 'sort_direction': sort_direction,
+ 'additional': json.dumps(additional)
+ }
+
+ return self.request_data(api_name, api_path, req_param)
+
+ def get_favorite_list(self,
+ offset: Optional[int] = None,
+ limit: Optional[int] = None,
+ status_filter: Optional[str] = None,
+ additional: Optional[str | list[str]] = None
+ ) -> dict[str, object]:
+ """
+ List user's favorites.
+
+ Parameters
+ ----------
+ offset : Optional[int], optional
+ Specify how many favorites are skipped before beginning to return user's favorites. Defaults to `None`
+ limit : Optional[int], optional
+ Number of favorites requested. 0 indicates to list all favorites. Defaults to `None`
+ status_filter : Optional[str], optional
+ Show favorites with a given favorite status. Defaults to `None`
+ All fields known are: `["valid","broken","all"]`
+ additional : Optional[str | list[str]], optional
+ Additionnal field to retrieve from file. Defaults to `None`
+ All fields known are: `["real_path","owner","time","perm","mount_point_type"]`.
+
+ Returns
+ -------
+ dict[str, object]
+ List of user's favorites.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "favorites": [
+ {
+ "isdir": true,
+ "name": "My Video Shared folder",
+ "path": "/video",
+ "status": "valid"
+ },
+ {
+ "isdir": false,
+ "name": "deletedfolder",
+ "path": "/share/deletedfolder",
+ "status": "broken"
+ }
+ ],
+ "offset": 0,
+ "total": 2
+ },
+ "success": true
+ }
+ ```
+ """
+
+ api_name = 'SYNO.FileStation.Favorite'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'list',
+ 'offset': offset,
+ 'limit': limit,
+ 'status_filter': status_filter,
+ 'additional': json.dumps(additional)
+ }
+
+ return self.request_data(api_name, api_path, req_param)
+
+ def add_a_favorite(self, path: str, name: Optional[str] = None, index: Optional[int] = -1) -> dict[str, object]:
+ """
+ Add a folder to user's favorites.
+
+ Parameters
+ ----------
+ path : str
+ A folder path starting with a shared folder is added to the user's favorites.
+ name : Optional[str], optional
+ A favorite name. Defaults to `None`
+ index : Optional[int], optional
+ Index of location of an added favorite. Defaults to `-1`
+ If it's equal to -1, the favorite will be added to the last one in user's favorite.
+ If it's between 0 ~ total number of favorites-1, the favorite will be inserted into user's favorites by the index.
+
+ Returns
+ -------
+ dict[str, object]
+ No specific response. It returns an empty success response if completed without error.
+
+ Examples
+ --------
+ ```json
+ {
+ "success": true
+ }
+ ```
+ """
+
+ api_name = 'SYNO.FileStation.Favorite'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'add',
+ 'path': path,
+ 'name': name,
+ 'index': index
+ }
+
+ return self.request_data(api_name, api_path, req_param)
+
+ def delete_a_favorite(self, path: str) -> dict[str, object]:
+ """
+ Delete a favorite in user's favorites.
+
+ Parameters
+ ----------
+ path : str
+ A folder path starting with a shared folder is deleted from a user's favorites.
+
+ Returns
+ -------
+ dict[str, object]
+ No specific response. It returns an empty success response if completed without error.
+
+ Examples
+ --------
+ ```json
+ {
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.FileStation.Favorite'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'delete',
+ 'path': path
+ }
+
+ return self.request_data(api_name, api_path, req_param)
+
+ def clear_broken_favorite(self) -> dict[str, object]:
+ """
+ Delete all broken statuses of favorites.
+
+ Returns
+ -------
+ dict[str, object]
+ No specific response. It returns an empty success response if completed without error.
+
+ Examples
+ --------
+ ```json
+ {
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.FileStation.Favorite'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'clear_broken'
+ }
+
+ return self.request_data(api_name, api_path, req_param)
+
+ def edit_favorite_name(self, path: str, new_name: str) -> dict[str, object]:
+ """
+ Edit a favorite name.
+
+ Parameters
+ ----------
+ path : str
+ A folder path starting with a shared folder is edited from a user's favorites.
+ new_name : str
+ New favorite name.
+
+ Returns
+ -------
+ dict[str, object]
+ No specific response. It returns an empty success response if completed without error.
+
+ Examples
+ --------
+ ```json
+ {
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.FileStation.Favorite'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'edit',
+ 'path': path,
+ 'new_name': new_name
+ }
+
+ return self.request_data(api_name, api_path, req_param)
+
+ def replace_all_favorite(self, path: str | list[str], name: str | list[str]) -> dict[str, object]:
+ """
+ Replace multiple favorites of folders to the existing user's favorites.
+
+ Parameters
+ ----------
+ path : str | list[str]
+ One or more folder paths starting with a shared folder is added to the user's favorites.
+ The number of paths must be the same as the number of favorite names in the name parameter.
+ The first path parameter corresponds to the first name parameter.
+ name : str | list[str]
+ One or more new favorite names. The number of favorite names must be the same as the number of folder paths in the path parameter.
+ The first name parameter corresponding to the first path parameter.
+
+ Returns
+ -------
+ dict[str, object]
+ No specific response. It returns an empty success response if completed without error.
+
+ Examples
+ --------
+ ```json
+ {
+ "success": true
+ }
+ ```
+ """
+
+ api_name = 'SYNO.FileStation.Favorite'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'edit',
+ 'path': json.dumps(path) if isinstance(path, list) else path,
+ 'name': json.dumps(name) if isinstance(name, list) else name
+ }
+
+ return self.request_data(api_name, api_path, req_param)
+
+ def get_thumbnail(self, path: str, size: Optional[str] = "small", rotate: Optional[int] = None) -> bytes:
+ """
+ Get a thumbnail of a file.
+
+ Parameters
+ ----------
+ path : str
+ A file path starting with a shared folder.
+ size : str
+ The size of the thumbnail. Defaults to `small`
+ All fields known are: `["small","medium","large","original"]`
+ rotate : Optional[int], optional
+ The angle of the thumbnail. Defaults to `None`
+ All fields known are: `[0,1,2,3,4] = ["0°","90°","180°","270°","360°"]`
+
+ Returns
+ -------
+ bytes
+ The thumbnail of the file. If the file is not found, it will raise an exception.
+ """
+
+ api_name = 'SYNO.FileStation.Thumb'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': "get",
+ 'path': path,
+ 'size': size,
+ 'rotate': rotate
+ }
+ response = self.request_data(
+ api_name, api_path, req_param, response_json=False)
+ match response.status_code:
+ case 200:
+ return response.content
+ case 404:
+ raise Exception("File not found")
+ case _:
+ raise Exception(f"HTTP Status error : {response.status_code}")
+
+ def start_dir_size_calc(self, path: str | list[str]) -> dict[str, object]:
+ """
+ Start to calculate size for one or more file/folder paths.
+
+ Parameters
+ ----------
+ path : str | list[str]
+ One or more file/folder paths starting with a shared folder for calculating cumulative size
+
+ Returns
+ -------
+ dict[str, object]
+ Task ID for the size calculation request.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "taskid": "51CBD7CD5C76E461"
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.FileStation.DirSize'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'start',
+ 'path': json.dumps(path) if isinstance(path, list) else path
+ }
+ return self.request_data(api_name, api_path, req_param)['data']['taskid']
+
+ def get_dir_status(self, taskid: str) -> dict[str, object]:
+ """
+ Get the status of the size calculating task.
+
+ Parameters
+ ----------
+ taskid : str
+ A unique ID for the task which is obtained from `start_dir_size_calc` method.
+
+ Returns
+ -------
+ dict[str, object]
+ Infos about the size calculating task.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "finished": true,
+ "num_dir": 3,
+ "num_file": 104,
+ "total_size": 29973265
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.FileStation.DirSize'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'status',
+ 'taskid': taskid
+ }
+
+ return self.request_data(api_name, api_path, req_param)
+
+ def stop_dir_size_calc(self, taskid: str) -> dict[str, object]:
+ """
+ Stop the calculation.
+
+ Parameters
+ ----------
+ taskid : str
+ A unique ID for the task which is obtained from `start_dir_size_calc` method.
+
+ Returns
+ -------
+ dict[str, object]
+ No specific response. It returns an empty success response if completed without error.
+
+ Examples
+ --------
+ ```json
+ {
+ "success": true
+ }
+ ```
+ """
+
+ api_name = 'SYNO.FileStation.DirSize'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'stop',
+ 'taskid': taskid
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def start_md5_calc(self, file_path: str) -> dict[str, object]:
+ """
+ Start to get MD5 of a file.
+
+ Parameters
+ ----------
+ file_path : str
+ A file path starting with a shared folder for calculating MD5 value.
+
+ Returns
+ -------
+ dict[str, object]
+ Task ID for the size calculation request.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "taskid": "51CBD7CD5C76E461"
+ },
+ "success": true
+ }
+ ```
+ """
+
+ api_name = 'SYNO.FileStation.MD5'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'start',
+ 'file_path': file_path
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def get_md5_status(self, taskid: str) -> dict[str, object]:
+ """
+ Get the status of the MD5 calculation task.
+
+ Parameters
+ ----------
+ taskid : str
+ A unique ID for the task which is obtained from `start_md5_status` method.
+
+ Returns
+ -------
+ dict[str, object]
+ Finished status of the MD5 calculation task and the md5 of requested file.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "finished": true,
+ "md5": "6336c5a59aa63dd2042783f88e15410a"
+ },
+ "success": true
+ }
+ ```
+ """
+
+ api_name = 'SYNO.FileStation.MD5'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'status',
+ 'taskid': taskid
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def stop_md5_calc(self, taskid: str) -> dict[str, object]:
+ """
+ Stop calculating the MD5 of a file.
+
+ Parameters
+ ----------
+ taskid : str
+ A unique ID for the task which is obtained from `start_md5_status` method.
+
+ Returns
+ -------
+ dict[str, object]
+ No specific response. It returns an empty success response if completed without error.
+
+ Examples
+ --------
+ ```json
+ {
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.FileStation.DirSize'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'stop',
+ 'taskid': taskid
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def check_permissions(self,
+ path: str,
+ filename: str,
+ overwrite: Optional[bool] = False,
+ create_only: Optional[bool] = True
+ ) -> dict[str, object]:
+ """
+ Check if a logged-in user has write permission to create new files/folders in a given folder.
+
+ Parameters
+ ----------
+ path : str
+ A folder path starting with a shared folder to check write permission
+ filename : str
+ A filename you want to write to given path
+ overwrite : Optional[bool], optional
+ The value could be one of following: Defaults to `False`
+ - "true": overwrite the destination file if one exists.
+ - "false": skip if the destination file exists.
+
+ Note: when it's not specified as true or false, it will be responded with error when the destination file exists.
+
+ create_only : Optional[bool], optional
+ If set to "true", the permission will be allowed when there is non-existent file/folder. Defaults to `True`
+
+ Returns
+ -------
+ dict[str, object]
+ The request will get error response if no write permission for the specified path.
+
+ Examples
+ --------
+ ```json
+ {
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.FileStation.CheckPermission'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'write',
+ 'path': path,
+ 'filename': filename,
+ 'overwrite': overwrite,
+ 'create_only': create_only
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def upload_file(self,
+ dest_path: str,
+ file_path: str,
+ create_parents: bool = True,
+ overwrite: bool = True,
+ verify: bool = False,
+ progress_bar: bool = True
+ ) -> tuple[int, dict[str, object]]:
+ """
+ Upload a file to a given destination path.
+
+ Parameters
+ ----------
+ dest_path : str
+ A destination folder path starting with a shared folder.
+ file_path : str
+ A file path to be uploaded.
+ create_parents : bool, optional
+ Create parent folder(s) if none exist. Defaults to `True`
+ overwrite : bool, optional
+ If `True` overwrite the destination file if one exist else skip the upload if the destination file exist. Defaults to `True`
+ verify : bool, optional
+ If `True` use HTTPS else use HTTP. Defaults to `False`
+ progress_bar : bool, optional
+ Enable or note the progress bar in the stdout. Defaults to `True`
+
+ Returns
+ -------
+ tuple[int, dict[str, object]]
+ If failed return a tuple with the status code and the error message
+ else return the response json.
+
+ Examples
+ --------
+ ```json
+ {
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.FileStation.Upload'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ filename = os.path.basename(file_path)
+
+ session = requests.session()
+
+ with open(file_path, 'rb') as payload:
+ url = ('%s%s' % (self.base_url, api_path)) + '?api=%s&version=%s&method=upload&_sid=%s' % (
+ api_name, info['minVersion'], self._sid)
+
+ encoder = MultipartEncoder({
+ 'path': dest_path,
+ 'create_parents': str(create_parents).lower(),
+ 'overwrite': str(overwrite).lower(),
+ 'files': (filename, payload, 'application/octet-stream')
+ })
+
+ if progress_bar:
+ bar = tqdm.tqdm(desc='Upload Progress',
+ total=encoder.len,
+ dynamic_ncols=True,
+ unit='B',
+ unit_scale=True,
+ unit_divisor=1024
+ )
+
+ monitor = MultipartEncoderMonitor(
+ encoder, lambda monitor: bar.update(monitor.bytes_read - bar.n))
+
+ r = session.post(
+ url,
+ data=monitor,
+ verify=verify,
+ headers={"X-SYNO-TOKEN": self.session._syno_token,
+ 'Content-Type': monitor.content_type}
+ )
+
+ else:
+ r = session.post(
+ url,
+ data=encoder,
+ verify=verify,
+ headers={"X-SYNO-TOKEN": self.session._syno_token,
+ 'Content-Type': encoder.content_type}
+ )
+
+ session.close()
+ if r.status_code != 200 or not r.json()['success']:
+ return r.status_code, r.json()
+
+ return r.json()
+
+ def get_shared_link_info(self, link_id: str) -> dict[str, object]:
+ """
+ Get information of a sharing link by the sharing link ID.
+
+ Parameters
+ ----------
+ link_id : str
+ A unique ID of a sharing link.
+
+ Returns
+ -------
+ dict[str, object]
+ Information about the sharing link.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "date_available": "0",
+ "date_expired": "0",
+ "has_password": false,
+ "id": "pHTBKQf9",
+ "isFolder": false,
+ "link_owner": "admin",
+ "name": "ITEMA_20448251-0.mp3",
+ "path": "/test/ITEMA_20448251-0.mp3",
+ "status": "valid",
+ "url": "http://myds.com:5000/fbsharing/pHTBKQf9"
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.FileStation.Sharing'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'getinfo',
+ 'id': link_id
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def get_shared_link_list(self, offset: Optional[int] = None, limit: Optional[int] = None, sort_by: Optional[str] = None,
+ sort_direction: Optional[str] = None, force_clean: Optional[bool] = None
+ ) -> dict[str, object]:
+ """
+ List user's file sharing links.
+
+ Parameters
+ ----------
+ offset : Optional[int], optional
+ Specify how many sharing links are skipped before beginning to return listed sharing links. Defaults to `None`
+ limit : Optional[int], optional
+ Number of sharing links requested. 0 means to list all sharing links. Defaults to `None`
+ sort_by : Optional[str], optional
+ Specify which file information to sort on. Defaults to `None`
+ All fields known are: `["name","isFolder","path","date_expired","date_available","status","has_password","id","url","link_owner"]`
+ sort_direction : Optional[str], optional
+ Specify to sort ascending or to sort descending. Defaults to `None`
+ All possible direction are: `["asc","desc"]`
+ force_clean : Optional[bool], optional
+ If set to false, the data will be retrieved from cache database rapidly. If set to true, all sharing information including sharing statuses and user name of sharing owner will be synchronized. It consumes some time. Defaults to `None`
+
+ Returns
+ -------
+ dict[str, object]
+ Information about the sharing links.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "links": [
+ {
+ "date_available": "0",
+ "date_expired": "0",
+ "has_password": false,
+ "id": "pHTBKQf9",
+ "isFolder": false,
+ "link_owner": "admin",
+ "name": "ITEMA_20448251-0.mp3",
+ "path": "/test/ITEMA_20448251-0.mp3",
+ "status": "valid",
+ "url": "http://myds.com:5000/fbsharing/pHTBKQf9"
+ }
+ ],
+ "offset": 0,
+ "total": 1
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.FileStation.Sharing'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'list',
+ 'offset': offset,
+ 'limit': limit,
+ 'sort_by': sort_by,
+ 'sort_direction': sort_direction,
+ 'force_clean': force_clean
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def create_sharing_link(self, path: str | list[str], password: Optional[str] = None, date_expired: Optional[str | int] = None,
+ date_available: Optional[str | int] = None
+ ) -> dict[str, object]:
+ """
+ Generate one or more sharing link(s) by file/folder path(s).
+
+ Parameters
+ ----------
+ path : str | list[str]
+ One or more file/folder paths with which to generate sharing links.
+ password : Optional[str], optional
+ The password for the sharing link when accessing it. The max password length are 16 characters. Defaults to `None`
+ date_expired : Optional[str | int], optional
+ The expiration date for the sharing link, written in the format YYYYMM-DD. When set to 0 (default), the sharing link is permanent. Defaults to `None`
+
+ Note: SHOULD put the double quote outside expiration date and is based on user's DS date.
+
+ date_available : Optional[str | int], optional
+ The available date for the sharing link to become effective, written in the format YYYY-MM-DD. When set to 0 (default), the sharing link is valid immediately after creation. Defaults to `None`
+
+ Note: SHOULD put the double quote outside available date and is based on user's DS date.
+
+ Returns
+ -------
+ dict[str, object]
+ Information about the sharing link(s) generated.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "links": [
+ {
+ "error": 0,
+ "id": "y4LmvpaX",
+ "path": "/test/ITEMA_20445972-0.mp3",
+ "qrcode": "iVBORw0KGgoAAAANSUh...",
+ "url": "http://myds.com:5000/fbsharing/y4LmvpaX"
+ }
+ ]
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.FileStation.Sharing'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'create',
+ 'path': json.dumps(path) if isinstance(path, list) else path,
+ 'password': password,
+ 'date_expired': date_expired,
+ 'date_available': date_available
+ }
+
+ return self.request_data(api_name, api_path, req_param)
+
+ def delete_shared_link(self, link_id: str | list[str]) -> dict[str, object]:
+ """
+ Delete one or more sharing links.
+
+ Parameters
+ ----------
+ link_id : str | list[str]
+ Unique IDs of file sharing link(s) to be deleted
+
+ Returns
+ -------
+ dict[str, object]
+ Returns an empty success response if completed without error; otherwise returns error object array contains failed IDs.
+
+ Examples
+ --------
+ ```json
+ {,
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.FileStation.Sharing'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'delete',
+ 'id': json.dumps(link_id) if isinstance(link_id, list) else link_id
+ }
+
+ return self.request_data(api_name, api_path, req_param)
+
+ def clear_invalid_shared_link(self) -> dict[str, object]:
+ """
+ Remove all expired and broken sharing links.
+
+ Returns
+ -------
+ dict[str, object]
+ No specific response. It returns an empty success response if completed without error.
+
+ Examples
+ --------
+ ```json
+ {
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.FileStation.Sharing'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'clear_invalid'
+ }
+
+ return self.request_data(api_name, api_path, req_param)
+
+ def edit_shared_link(self, link_id: str | list[str], password: Optional[str] = None, date_expired: Optional[str | int] = None,
+ date_available: Optional[str | int] = None
+ ) -> dict[str, object]:
+ """
+ Edit sharing link(s).
+
+ Parameters
+ ----------
+ link_id : str | list[str]
+ Unique ID(s) of sharing link(s) to edit.
+ password : Optional[str], optional
+ The password for the sharing link when accessing it. The max password length are 16 characters. Defaults to `None`
+ date_expired : Optional[str | int], optional
+ The expiration date for the sharing link, written in the format YYYYMM-DD. When set to 0 (default), the sharing link is permanent. Defaults to `None`
+
+ Note: SHOULD put the double quote outside expiration date and is based on user's DS date.
+
+ date_available : Optional[str | int], optional
+ The available date for the sharing link to become effective, written in the format YYYY-MM-DD. When set to 0 (default), the sharing link is valid immediately after creation. Defaults to `None`
+
+ Note: SHOULD put the double quote outside available date and is based on user's DS date.
+
+ Returns
+ -------
+ dict[str, object]
+ No specific response. It returns an empty success response if completed without error.
+
+ Examples
+ --------
+ ```json
+ {
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.FileStation.Sharing'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'edit',
+ 'id': json.dumps(link_id) if isinstance(link_id, list) else link_id,
+ 'password': password,
+ 'date_expired': date_expired,
+ 'date_available': date_available
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def create_folder(self, folder_path: str | list[str], name: str | list[str],
+ force_parent: Optional[bool] = False, additional: Optional[str | list[str]] = None
+ ) -> dict[str, object]:
+ """
+ Create folders.
+
+ Parameters
+ ----------
+ folder_path : str | list[str]
+ One or more shared folder paths, separated by commas and around brackets.
+ If `force_parent` is `true`, and `folder_path` does not exist, the `folder_path` will be created.
+ If `force_parent` is `false`, `folder_path` must exist or a false value will be returned.
+ The number of paths must be the same as the number of names in the name parameter.
+ The first `folder_path` parameter corresponds to the first name parameter.
+ name : str | list[str]
+ One or more new folder names.
+ The number of names must be the same as the number of folder_paths paths in the `folder_path` parameter.
+ The first `name` parameter corresponding to the first `folder_path` parameter.
+ force_parent : Optional[bool], optional
+ Defaults to `False`.
+ If `true` : no error occurs if a folder exists and create parent folders as needed.
+ If `false` : parent folders are not created.
+ additional : Optional[str | list[str]], optional
+ Additionnal field to retrieve from folder. Defaults to `None`
+ All fields known are: `["real_path","size","owner","time","perm","type"]`.
+
+ Returns
+ -------
+ dict[str, object]
+ List of folder(s) created informations.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "folders": [
+ {
+ "isdir": true,
+ "name": "test",
+ "path": "/video/test"
+ }
+ ]
+ },
+ "success": true
+ }
+ ```
+ """
+
+ api_name = 'SYNO.FileStation.CreateFolder'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'create',
+ 'folder_path': json.dumps(folder_path) if isinstance(folder_path, list) else folder_path,
+ 'name': json.dumps(name) if isinstance(name, list) else name,
+ 'force_parent': force_parent
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def rename_folder(self, path: str | list[str], name: str | list[str], additional: Optional[str | list[str]] = None, search_taskid: Optional[str] = None) -> dict[str, object]:
+ """
+ Rename folders.
+
+ Parameters
+ ----------
+ path : str | list[str]
+ One or more paths of files/folders to be renamed.
+ The number of paths must be the same as the number of names in the `name` parameter.
+ The first `path` parameter corresponds to the first `name` parameter.
+ name : str | list[str]
+ One or more new folder names.
+ The number of names must be the same as the number of paths paths in the `path` parameter.
+ The first `name` parameter corresponding to the first `path` parameter.
+ additional : Optional[str | list[str]], optional
+ Defaults to `None`
+ Additionnal field to retrieve from folder.
+ All fields known are: `["real_path","size","owner","time","perm","type"]`.
+ search_taskid : Optional[str], optional
+ The task ID of the `search_start` method. Defaults to `None`
+
+ Returns
+ -------
+ dict[str, object]
+ List of folder(s) renamed informations.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "files": [
+ {
+ "isdir": true,
+ "name": "test",
+ "path": "/video/test"
+ }
+ ]
+ },
+ "success": true
+ }
+ ```
+ """
+
+ api_name = 'SYNO.FileStation.Rename'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'rename',
+ 'path': json.dumps(path) if isinstance(path, list) else path,
+ 'name': json.dumps(name) if isinstance(name, list) else name,
+ 'search_taskid': search_taskid
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def start_copy_move(self,
+ path: str | list[str],
+ dest_folder_path: str,
+ overwrite: Optional[bool] = None,
+ remove_src: Optional[bool] = False,
+ accurate_progress: Optional[bool] = True,
+ search_taskid: Optional[str] = None
+ ) -> dict[str, object]:
+ """
+ Start to copy/move files.
+
+ Parameters
+ ----------
+ path : str | list[str]
+ One or more file/folder paths starting with a shared folder to copy/move.
+ dest_folder_path : str
+ A destination folder path where files/folders are copied/moved.
+ overwrite : Optional[bool], optional
+ Defaults to `None`.
+ If `true` : overwrite all existing files with the same name.
+ If `false` : skip all existing files with the same name.
+
+ Note: do not overwrite or skip existed files. If there is any existing files, an error occurs (error code: 1003).
+
+ remove_src : Optional[bool], optional
+ Defaults to `False`.
+ If `true`: move files/folders. If `false`: copy files/folders.
+ accurate_progress : Optional[bool], optional
+ Defaults to `True`.
+ If `true` : calculate the progress by each moved/copied file within sub-folder.
+ If `false` : calculate the progress by files which you give in path parameters. This calculates the progress faster, but is less precise.
+ search_taskid : Optional[str], optional
+ The task ID of the `search_start` method. Defaults to `None`.
+
+ Returns
+ -------
+ dict[str, object]
+ Return unique task ID for the copy/move task.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "taskid": "FileStation_51D00B7912CDE0B0"
+ },
+ "success": true
+ }
+ ```
+ """
+
+ api_name = 'SYNO.FileStation.CopyMove'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'start',
+ 'path': json.dumps(path) if isinstance(path, list) else path,
+ 'dest_folder_path': dest_folder_path,
+ 'overwrite': overwrite,
+ 'remove_src': remove_src,
+ 'accurate_progress': accurate_progress,
+ 'search_taskid': search_taskid
+ }
+
+ return self.request_data(api_name, api_path, req_param)
+
+ def get_copy_move_status(self, taskid: str) -> dict[str, object]:
+ """
+ Get the copying/moving status.
+
+ Parameters
+ ----------
+ taskid : str
+ A unique ID for the copy/move task which is obtained from `start_copy_move` method
+
+ Returns
+ -------
+ dict[str, object]
+ Infos about the copy/move task.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "dest_folder_path": "/video/test",
+ "finished": false,
+ "path": "/video/test.avi",
+ "processed_size": 1057,
+ "progress": 0.01812258921563625,
+ "total": 58325
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.FileStation.CopyMove'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'status',
+ 'taskid': taskid
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def stop_copy_move_task(self, taskid: str) -> dict[str, object]:
+ """
+ Stop a copy/move task.
+
+ Parameters
+ ----------
+ taskid : str
+ A unique ID for the copy/move task which is obtained from `start_copy_move` method
+
+ Returns
+ -------
+ dict[str, object]
+ No specific response. It returns an empty success response if completed without error.
+
+ Examples
+ --------
+ ```json
+ {
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.FileStation.CopyMove'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'stop',
+ 'taskid': taskid
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def start_delete_task(self,
+ path: str | list[str],
+ accurate_progress: Optional[bool] = True,
+ recursive: Optional[bool] = True,
+ search_taskid: Optional[str] = None
+ ) -> dict[str, object]:
+ """
+ Delete file(s)/folder(s). This is a non-blocking method. You should poll a request with `get_delete_status` method to get the task status or stop the task with `stop_delete_task` method.
+
+ Parameters
+ ----------
+ path : str | list[str]
+ One or more file/folder paths starting with a shared folder to delete.
+ accurate_progress : Optional[bool], optional
+ Defaults to `True`
+ If `true` : calculates the progress of each deleted file with the sub-folder recursively.
+ If `false` : calculates the progress of files which you give in `path` parameters. The latter is faster than recursively, but less precise.
+ Note: Only non-blocking methods suits using the `get_delete_status` method to get progress.
+ recursive : Optional[bool], optional
+ Defaults to `True`.
+ If `true` : delete files/folders recursively.
+ If `false` : Only delete first-level file/folder. If a deleted folder contains any file, an error occurs because the folder can't be directly deleted.
+ search_taskid : Optional[str], optional
+ A unique ID for the search task which is obtained from `search_start` method. It's used to delete the file in the search result. Defaults to `None`
+
+ Returns
+ -------
+ dict[str, object]
+ A unique task ID for the delete task.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "taskid": "FileStation_51CEC9C979340E5A"
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.FileStation.Delete'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'start',
+ 'path': json.dumps(path) if isinstance(path, list) else path,
+ 'accurate_progress': accurate_progress,
+ 'recursive': recursive,
+ 'search_taskid': search_taskid
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def get_delete_status(self, taskid: str) -> dict[str, object]:
+ """
+ Get the deleting status.
+
+ Parameters
+ ----------
+ taskid : str
+ A unique ID for the delete task which is obtained from `start_delete_task` method.
+
+ Returns
+ -------
+ dict[str, object]
+ Infos about the delete task.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "finished": false,
+ "path": "/video/1000",
+ "processed_num": 193,
+ "processing_path": "/video/1000/509",
+ "progress": 0.03199071809649467,
+ "total": 6033
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.FileStation.Delete'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'status',
+ 'taskid': taskid
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def stop_delete_task(self, taskid: str) -> dict[str, object]:
+ """
+ Stop a delete task.
+
+ Parameters
+ ----------
+ taskid : str
+ A unique ID for the delete task which is obtained from `start_delete_task` method.
+
+ Returns
+ -------
+ dict[str, object]
+ No specific response. It returns an empty success response if completed without error.
+
+ Examples
+ --------
+ ```json
+ {
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.FileStation.Delete'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'stop',
+ 'taskid': taskid
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def delete_delete_task(self, path: str | list[str], recursive: Optional[bool] = True, search_taskid: Optional[str] = None) -> dict[str, object]:
+ """
+ Delete files/folders. This is a blocking method. The response is not returned until the deletion operation is completed.
+
+ Parameters
+ ----------
+ path : str | list[str]
+ One or more file/folder paths starting with a shared folder to delete.
+ recursive : Optional[bool], optional
+ Defaults to `True`.
+ If `true` : Recursively delete files within a folder.
+ If `false` : Only delete first-level file/folder. If a deleted folder contains any file, an error occurs because the folder can't be directly deleted.
+ search_taskid : Optional[str], optional
+ A unique ID for the search task which is obtained from `search_start` method. It's used to delete the file in the search result. Defaults to `None`
+
+ Returns
+ -------
+ dict[str, object]
+ No specific response. It returns an empty success response if completed without error.
+
+ Examples
+ --------
+ ```json
+ {
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.FileStation.Delete'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'delete',
+ 'path': json.dumps(path) if isinstance(path, list) else path,
+ 'recursive': recursive,
+ 'search_taskid': search_taskid
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def start_extract_task(self, file_path: str, dest_folder_path: str, overwrite: Optional[bool] = False,
+ keep_dir: Optional[bool] = True, create_subfolder: Optional[bool] = False, codepage: Optional[str] = None,
+ password: Optional[str] = None, item_id: Optional[str | list[str]] = None
+ ) -> dict[str, object]:
+ """
+ Start to extract an archive. This is a non-blocking method. You should poll a request with `get_extract_status` method to get the task status or stop the task with `stop_extract_task` method.
+
+ Parameters
+ ----------
+ file_path : str
+ A file path of an archive to be extracted, starting with a shared folder
+ dest_folder_path : str
+ A destination folder path starting with a shared folder to which the archive will be extracted.
+ overwrite : Optional[bool], optional
+ Whether or not to overwrite if the extracted file exists in the destination folder. Defaults to `False`
+ keep_dir : Optional[bool], optional
+ Whether to keep the folder structure within an archive. Defaults to `True`
+ create_subfolder : Optional[bool], optional
+ Whether to create a subfolder with an archive name which archived files are extracted to. Defaults to `False`
+ codepage : Optional[str], optional
+ The language codepage used for decoding file name with an archive. Defaults to `None`
+ All fields known are: `["enu","cht","chs","krn","ger","fre","ita","spn","jpn","dan","nor","sve","nld","rus","plk","ptb","ptg","hun","trk","csy"]`
+ password : Optional[str], optional
+ The password for extracting the file. Defaults to `None`
+ item_id : Optional[str | list[str]], optional
+ Item IDs of archived files used for extracting files within an archive. Item IDs could be listed by requesting the `get_file_list_of_archive` method. Defaults to `None`
+
+ Returns
+ -------
+ dict[str, object]
+ Unique task ID for the extract task.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "taskid": "FileStation_51CBB59C68EFE6A3"
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.FileStation.Extract'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'start',
+ 'file_path': file_path,
+ 'dest_folder_path': dest_folder_path,
+ 'overwrite': overwrite,
+ 'keep_dir': keep_dir,
+ 'create_subfolder': create_subfolder,
+ 'codepage': codepage,
+ 'password': password,
+ 'item_id': json.dumps(item_id) if isinstance(item_id, list) else item_id
+ }
+ return self.request_data(api_name, api_path, req_param)['data']['taskid']
+
+ def get_extract_status(self, taskid: str) -> dict[str, object]:
+ """
+ Get the extract task status.
+
+ Parameters
+ ----------
+ taskid : str
+ A unique ID for the extract task which is obtained from `start_extract_task` method
+
+ Returns
+ -------
+ dict[str, object]
+ Information about the extract task.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "dest_folder_path": "/download/download",
+ "finished": false,
+ "progress": 0.1
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.FileStation.Extract'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'status',
+ 'taskid': taskid
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def stop_extract_task(self, taskid: str) -> dict[str, object]:
+ """
+ Stop the extract task.
+
+ Parameters
+ ----------
+ taskid : str
+ A unique ID for the extract task which is obtained from `start_extract_task` method
+
+ Returns
+ -------
+ dict[str, object]
+ No specific response. It returns an empty success response if completed without error.
+
+ Examples
+ --------
+ ```json
+ {
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.FileStation.Extract'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'stop',
+ 'taskid': taskid
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def get_file_list_of_archive(self, file_path: str, offset: Optional[int] = 0, limit: Optional[int] = -1,
+ sort_by: Optional[str] = 'name', sort_direction: Optional[str] = 'asc', codepage: Optional[str] = None,
+ password: Optional[str] = None, item_id: Optional[str] = None
+ ) -> dict[str, object]:
+ """
+ List archived files contained in an archive.
+
+ Parameters
+ ----------
+ file_path : str
+ An archive file path starting with a shared folder to list.
+ offset : Optional[int], optional
+ Specify how many archived files are skipped before beginning to return listed archived files in an archive. Defaults to `0`.
+ limit : Optional[int], optional
+ Number of archived files requested. -1 indicates in an archive to list all archived files. Defaults to `-1`.
+ sort_by : Optional[str], optional
+ Specify which archived file information to sort on. Defaults to `'name'`
+ All fields known are: `["name","size","pack_size","mtime"]`
+ sort_direction : Optional[str], optional
+ Specify to sort ascending or to sort descending. Defaults to `'asc'`
+ All possible direction are: `["asc","desc"]`.
+ codepage : Optional[str], optional
+ The language codepage used for decoding file name with an archive. Defaults to `None`
+ All fields known are: `["enu","cht","chs","krn","ger","fre","ita","spn","jpn","dan","nor","sve","nld","rus","plk","ptb","ptg","hun","trk","csy"]`
+ password : Optional[str], optional
+ The password for extracting the file.. Defaults to `None`
+ item_id : Optional[str], optional
+ Item ID of an archived folder to be listed within an archive. (None) or -1 will list archive files in a root folder within an archive. Defaults to `None`
+
+ Returns
+ -------
+ dict[str, object]
+ Information about the archived files.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "items": [
+ {
+ "is_dir": false,
+ "item_id": 1,
+ "mtime": "2013-02-03 00:17:12",
+ "name": "ITEMA_20445972-0.mp3",
+ "pack_size": 51298633,
+ "path": "ITEMA_20445972-0.mp3",
+ "size": 51726464
+ },
+ {
+ "is_dir": false,
+ "item_id": 0,
+ "mtime": "2013-03-03 00:18:12",
+ "name": "ITEMA_20455319-0.mp3",
+ "pack_size": 51434239,
+ "path": "ITEMA_20455319-0.mp3",
+ "size": 51896448
+ }
+ ],
+ "total":2
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.FileStation.Extract'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'list',
+ 'file_path': file_path,
+ 'offset': offset,
+ 'limit': limit,
+ 'sort_by': sort_by,
+ 'sort_direction': sort_direction,
+ 'codepage': codepage,
+ 'password': password,
+ 'item_id': item_id
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def start_file_compression(self, path: str | list[str], dest_file_path: str, level: Optional[int] = 'moderate',
+ mode: Optional[str] = 'add', format: Optional[str] = 'zip', password: Optional[str] = None
+ ) -> dict[str, object] | tuple[str]:
+ """
+ Start to compress file(s)/folder(s).
+
+ Parameters
+ ----------
+ path : str | list[str]
+ One or more file paths to be compressed, starting with a shared folder.
+ dest_file_path : str
+ A destination file path (including file name) of an archive for the compressed archive.
+ level : Optional[int], optional
+ Defaults to `'moderate'`.
+ Compress level used, could be one of following values:
+ - `moderate`: moderate compression and normal compression speed.
+ - `store`: pack files with no compress. fastest: fastest compression speed but less compression.
+ - `best`: slowest compression speed but optimal compression.
+ mode : Optional[str], optional
+ Defaults to `'add'`
+ Compress mode used, could be one of following values:
+ - `add`: Update existing items and add new files. If an archive does not exist, a new one is created.
+ - `update`: Update existing items if newer on the file system and add new files. If the archive does not exist create a new archive.
+ - `refreshen`: Update existing items of an archive if newer on the file system. Does not add new files to the archive.
+ - `synchronize`: Update older files in the archive and add files that are not already in the archive.
+ format : Optional[str], optional
+ The compress format, ZIP or 7z format. Defaults to `'zip'`
+ All fields known are: `["zip","7z"]`
+ password : Optional[str], optional
+ The password for the archive. Defaults to `None`
+
+ Returns
+ -------
+ dict[str, object] | tuple[str]
+ Unique task ID for the compress task.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "taskid": "FileStation_51CBB25CC31961FD"
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.FileStation.Compress'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'start',
+ 'path': json.dumps(path) if isinstance(path, list) else path,
+ 'dest_file_path': dest_file_path,
+ 'level': level,
+ 'mode': mode,
+ 'format': format,
+ 'password': password
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def get_compress_status(self, taskid: str) -> dict[str, object]:
+ """
+ Get the compress task status.
+
+ Parameters
+ ----------
+ taskid : str
+ A unique ID for the compress task. This is obtained from `start_file_compression` method.
+
+ Returns
+ -------
+ dict[str, object]
+ Information about the compress task.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "dest_file_path": "/download/download.zip",
+ "finished": true
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.FileStation.Compress'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'status',
+ 'taskid': taskid
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def stop_compress_task(self, taskid: str) -> dict[str, object]:
+ """
+ Stop the compress task.
+
+ Parameters
+ ----------
+ taskid : str
+ A unique ID for the compress task. This is obtained from `start_file_compression` method.
+
+ Returns
+ -------
+ dict[str, object]
+ No specific response. It returns an empty success response if completed without error.
+
+ Examples
+ --------
+ ```json
+ {
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.FileStation.Compress'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'stop',
+ 'taskid': taskid
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def get_list_of_all_background_task(self, offset: Optional[int] = 0, limit: Optional[int] = 0,
+ sort_by: Optional[str] = 'crtime', sort_direction: Optional[str] = 'asc', api_filter: Optional[str | list[str]] = None
+ ) -> dict[str, object]:
+ """
+ List all background tasks including copy, move, delete, compress and extract tasks.
+
+ Parameters
+ ----------
+ offset : Optional[int], optional
+ Specify how many background tasks are skipped before beginning to return listed background tasks. Defaults to `0`
+ limit : Optional[int], optional
+ Number of background tasks requested. 0 indicates to list all background tasks. Defaults to `0`
+ sort_by : Optional[str], optional
+ Specify which information of the background task to sort on. Defaults to `'crtime'`
+ All fields known are: `["crtime","finished"]`
+ sort_direction : Optional[str], optional
+ Specify to sort ascending or to sort descending. Defaults to `'asc'`
+ All possible direction are: `["asc","desc"]`
+ api_filter : Optional[str | list[str]], optional
+ List background tasks with one or more given API name(s). If not given, all background tasks are listed. Defaults to `None`
+ All fields known are: `["SYNO.FileStation.CopyMove","SYNO.FileStation.Delete","SYNO.FileStation.Compress","SYNO.FileStation.Extract"]`
+
+ Returns
+ -------
+ dict[str, object]
+ List of background tasks.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "tasks": [
+ {
+ "api": "SYNO.FileStation.CopyMove",
+ "crtime": 1372926088,
+ "finished": true,
+ "method": "start",
+ "params": {
+ "accurate_progress": true,
+ "dest_folder_path": "/video/test",
+ "overwrite": true,
+ "path": [
+ "/video/test2/test.avi"
+ ],
+ "remove_src": false
+ },
+ "path": "/video/test2/test.avi",
+ "processed_size": 12800,
+ "processing_path": "/video/test2/test.avi",
+ "progress": 1,
+ "taskid": "FileStation_51D53088860DD653",
+ "total": 12800,
+ "version": 1
+ },
+ {
+ "api": "SYNO.FileStation.Compress",
+ "crtime": 1372926097,
+ "finished": true,
+ "method": "start",
+ "params": {
+ "dest_file_path": "/video/test/test.zip",
+ "format": "zip",
+ "level": "",
+ "mode": "",
+ "password": "",
+ "path": [
+ "/video/test/test.avi"
+ ]
+ },
+ "progress": 0,
+ "taskid": "FileStation_51D53091A82CD948",
+ "total": -1,
+ "version": 1
+ },
+ {
+ "api": "SYNO.FileStation.Extract",
+ "crtime": 1372926103,
+ "finished": true,
+ "method": "start",
+ "params": {
+ "create_subfolder": false,
+ "dest_folder_path": "/video/test",
+ "file_path": [
+ "/video/test/test.zip"
+ ],
+ "keep_dir": true,
+ "overwrite": false
+ },
+ "progress": 1,
+ "taskid": "FileStation_51D530978633C014",
+ "total": -1,
+ "version": 1
+ },
+ {
+ "api": "SYNO.FileStation.Delete",
+ "crtime": 1372926110,
+ "finished": true,
+ "method": "start",
+ "params": {
+ "accurate_progress": true,
+ "path": [
+ "/video/test/test.avi"
+ ]
+ },
+ "path": "/video/test/test.avi",
+ "processed_num": 1,
+ "processing_path": "/video/test/test.avi",
+ "progress": 1,
+ "taskid": "FileStation_51D5309EE1E10BD9",
+ "total": 1,
+ "version": 1
+ }
+ ],
+ "offset": 0,
+ "total": 4
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.FileStation.BackgroundTask'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'list',
+ 'offset': offset,
+ 'limit': limit,
+ 'sort_by': sort_by,
+ 'sort_direction': sort_direction,
+ 'filter': json.dumps(api_filter) if isinstance(api_filter, list) else api_filter
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def clear_all_finished_background_task(self, taskid: Optional[str | list[str]] = None) -> dict[str, object]:
+ """
+ Delete all finished background tasks.
+
+ Parameters
+ ----------
+ taskid : Optional[str | list[str]], optional
+ Unique IDs of finished copy, move, delete, compress or extract tasks. If it's not given, all finished tasks are deleted. Defaults to `None`
+
+ Returns
+ -------
+ dict[str, object]
+ No specific response. It returns an empty success response if completed without error.
+
+ Examples
+ --------
+ ```json
+ {
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.FileStation.BackgroundTask'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+ req_param = {
+ 'version': info['maxVersion'],
+ 'method': 'clear_finished',
+ 'taskid': json.dumps(taskid) if isinstance(taskid, list) else taskid
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def get_file(self, path: str | list[str], mode: str, dest_path: str = ".", chunk_size: int = 8192, verify: bool = False) -> Optional[io.BytesIO]:
+ """
+ Download a file.
+
+ Parameters
+ ----------
+ path : str | list[str]
+ One or more file/folder paths starting with a shared folder to be downloaded. When more than one file is to be downloaded, files/folders will be compressed as a zip file.
+ mode : str
+ Mode used to download files/folders, value could be:
+ - `open`: print the file content to stdout
+ - `download`: write the file content to a file based on the `dest_path` parameter
+ - `serve`: return the file content as a stream
+ dest_path : str, optional
+ Destination folder where the file is downloaded, if mode is `download`. Defaults to `"."`
+ chunk_size : int, optional
+ Size of chunk to download. Defaults to `8192`
+ verify : bool, optional
+ If `True` use HTTPS else use HTTP. Defaults to `False`
+
+ Returns
+ -------
+ Optional[io.BytesIO]
+ If mode is `serve`, return the file content as a stream.
+ """
+ api_name = 'SYNO.FileStation.Download'
+ info = self.gen_list[api_name]
+ api_path = info['path']
+
+ session = requests.session()
+ str_path: str = json.dumps(path) if isinstance(path, list) else path
+ url = ('%s%s' % (self.base_url, api_path)) + '?api=%s&version=%s&method=download&path=%s&mode=%s&_sid=%s' % (
+ api_name, info['maxVersion'], str_path, mode, self._sid)
+
+ if mode == r'open':
+ with session.get(url, stream=True, verify=verify, headers={"X-SYNO-TOKEN": self.session._syno_token}) as r:
+ r.raise_for_status()
+ for chunk in r.iter_content(chunk_size=chunk_size):
+ if chunk: # filter out keep-alive new chunks
+ sys.stdout.buffer.write(chunk)
+
+ if mode == r'download':
+ with session.get(url, stream=True, verify=verify, headers={"X-SYNO-TOKEN": self.session._syno_token}) as r:
+ r.raise_for_status()
+ if not os.path.isdir(dest_path):
+ os.makedirs(dest_path)
+
+ if isinstance(path, list):
+ if len(path) > 1:
+ file_name = f"{os.path.splitext(os.path.basename(path[0]))[0]}.zip"
+ else:
+ file_name = os.path.basename(path[0])
+ else:
+ file_name = os.path.basename(path)
+ with open(dest_path + "/" + file_name, 'wb') as f:
+ for chunk in r.iter_content(chunk_size=chunk_size):
+ if chunk: # filter out keep-alive new chunks
+ f.write(chunk)
+
+ if mode == r'serve':
+ with session.get(url, stream=True, verify=verify, headers={"X-SYNO-TOKEN": self.session._syno_token}) as r:
+ r.raise_for_status()
+ return io.BytesIO(r.content)
+
+ def generate_file_tree(self,
+ folder_path: str,
+ tree: Tree,
+ max_depth: Optional[int] = 1,
+ start_depth: Optional[int] = 0) -> None:
+ """
+ Recursively generate the file tree based on the folder path you give constrained with.
+
+ You need to create the root node before calling this function.
+
+ Parameters
+ ----------
+ folder_path : str
+ Folder path to generate file tree.
+ tree : Tree
+ Instance of the Tree from the `treelib` library.
+ max_depth : int, optional
+ Non-negative number of maximum depth of tree generation if node tree is directory, default to '1' to generate full tree. If 'max_depth=0' it will be equivalent to no recursion.
+ start_depth : int, optional
+ Non negative number to start to control tree generation default to '0'.
+ """
+ api_name = 'hotfix' # fix for docs_parser.py issue
+
+ if start_depth < 0:
+ start_depth = 0
+ warnings.warn(
+ f"'start_depth={start_depth}'. It should not be less or than 0, setting 'start_depth' to 0!",
+ RuntimeWarning,
+ stacklevel=2
+ )
+
+ assert start_depth <= max_depth, ValueError(
+ f"'start_depth' should not be greater than 'max_depth'. Got '{start_depth=}, {max_depth=}'")
+ assert isinstance(tree, Tree), ValueError(
+ "'tree' has to be a type of 'Tree'")
+
+ data: dict[str, object] = self.get_file_list(
+ folder_path=folder_path
+ ).get("data")
+
+ files = data.get("files")
+ _file_info_getter = map(lambda x: (
+ x.get('isdir'), x.get('name'), x.get('path')), files)
+ for isdir, file_name, file_path in _file_info_getter:
+
+ if isdir and (start_depth >= max_depth):
+ tree.create_node(file_name, file_path, parent=folder_path, data={
+ "isdir": isdir, "max_depth": True})
+
+ elif isdir:
+ tree.create_node(file_name, file_path, parent=folder_path, data={
+ "isdir": isdir, "max_depth": False})
+ self.generate_file_tree(
+ file_path, tree, max_depth, start_depth + 1)
+
+ else:
+ tree.create_node(file_name, file_path, parent=folder_path, data={
+ "isdir": isdir, "max_depth": False})
diff --git a/synology_api/DSM/Package/PackageCenter.py b/synology_api/DSM/Package/PackageCenter.py
new file mode 100644
index 00000000..7db980b6
--- /dev/null
+++ b/synology_api/DSM/Package/PackageCenter.py
@@ -0,0 +1,1131 @@
+"""
+Core Package API implementation.
+
+Implementation of the PackageCenter application APIs.
+"""
+
+import json
+from typing import List
+from requests_toolbelt import MultipartEncoder, MultipartEncoderMonitor
+import os
+import requests
+import tqdm
+import time
+from synology_api import base_api
+
+
+class PackageCenter(base_api.BaseApi):
+ """
+ Core Package API implementation.
+
+ Implementation of the PackageCenter application APIs.
+ """
+
+ def get_package(self, package_id: str, additional: List[str] = []) -> dict:
+ """
+ Get infos of a package.
+
+ Parameters
+ ----------
+ package_id : str
+ Package ID.
+ additional : list of str, optional
+ Additional fields to retrieve. Defaults to [].
+ All fields known are: ["status", "dsm_apps"].
+
+ Returns
+ -------
+ dict
+ Information about the package.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "additional": {
+ "dsm_apps": " com.plexapp.plexmediaserver",
+ "status": "running",
+ "status_code": 0,
+ "status_description": "retrieve from status script",
+ "status_origin": "running"
+ },
+ "id": "PlexMediaServer",
+ "name": "Plex Media Server",
+ "timestamp": 1739228562839,
+ "version": "1.41.3.9314-72009314"
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.Package'
+ info = self.core_list[api_name]
+ api_path = info['path']
+ req_param = {
+ "method": "get",
+ "version": info['minVersion'],
+ "id": package_id,
+ "additional": json.dumps(additional)
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def list_installed(self, additional: list = [], ignore_hidden: bool = False) -> dict:
+ """
+ List installed packages.
+
+ Parameters
+ ----------
+ additional : list[str], optional
+ Additional fields to retrieve. Defaults to `[]`.
+ All fields known are:
+ `["description", "description_enu", "dependent_packages", "beta", "distributor", "distributor_url",
+ "maintainer", "maintainer_url", "dsm_apps", "dsm_app_page", "dsm_app_launch_name","report_beta_url",
+ "support_center", "startable", "installed_info", "support_url", "is_uninstall_pages","install_type",
+ "autoupdate", "silent_upgrade", "installing_progress", "ctl_uninstall", "updated_at", "status",
+ "url","available_operation"]`.
+ ignore_hidden : bool
+ TODO: Write description
+
+ Returns
+ -------
+ dict
+ List of packages installed on the NAS.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "packages": [
+ {
+ "additional": {
+ "install_type": ""
+ },
+ "id": "ActiveBackup-Office365",
+ "name": "Active Backup for Microsoft 365",
+ "timestamp": 1738880043640,
+ "version": "2.5.5-14034"
+ }
+ ]
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.Package'
+ info = self.core_list[api_name]
+ api_path = info['path']
+ req_param = {
+ "method": "list",
+ "version": info['maxVersion'],
+ "ignore_hidden": ignore_hidden,
+ "additional": json.dumps(additional)
+ }
+
+ return self.request_data(api_name, api_path, req_param)
+
+ def list_installable(self) -> dict:
+ """
+ List installable packages.
+
+ Returns
+ -------
+ dict
+ List of beta_package, categories and packages available.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "banners": [],
+ "beta_packages": [...],
+ "categories": [...],
+ "packages": [...]
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.Package.Server'
+ info = self.core_list[api_name]
+ api_path = info['path']
+ req_param = {
+ "method": "list",
+ "version": info['maxVersion'],
+ "blforcereload": False,
+ "blloadothers": False
+ }
+
+ return self.request_data(api_name, api_path, req_param)
+
+ def get_package_center_settings(self) -> dict:
+ """
+ Get package center settings.
+
+ Returns
+ -------
+ dict
+ List settings of the Package center.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "autoupdateall": false,
+ "autoupdateimportant": true,
+ "default_vol": "/volume1",
+ "enable_autoupdate": true,
+ "enable_dsm": true,
+ "enable_email": false,
+ "mailset": true,
+ "trust_level": 0,
+ "update_channel": true,
+ "volume_count": 2,
+ "volume_list": [
+ {
+ "desc": "",
+ "display": "Volume 1 (Available capacity: 184.72 GB )",
+ "mount_point": "/volume1",
+ "size_free": "198336327680",
+ "size_total": "206158430208",
+ "vol_desc": "Apps",
+ "volume_features": []
+ },
+ {
+ "desc": "",
+ "display": "Volume 2 (Available capacity: 2391.14 GB )",
+ "mount_point": "/volume2",
+ "size_free": "2567467421696",
+ "size_total": "3623234412544",
+ "vol_desc": "Stockage",
+ "volume_features": []
+ }
+ ]
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.Package.Setting'
+ info = self.core_list[api_name]
+ api_path = info['path']
+ req_param = {
+ "method": "get",
+ "version": info['maxVersion'],
+ }
+
+ return self.request_data(api_name, api_path, req_param)
+
+ def set_package_center_settings(self,
+ enable_email: bool, enable_dsm: bool, enable_autoupdate: bool,
+ autoupdateall: bool, autoupdateimportant: bool,
+ default_vol: str, update_channel: str
+ ) -> dict:
+ """
+ Set settings of the package center.
+
+ Parameters
+ ----------
+ enable_email : bool
+ Enable email notification
+ enable_dsm : bool
+ Enable desktop notification
+ enable_autoupdate : bool
+ Update packages automatically
+ autoupdateall : bool
+ Auto update all packages
+ autoupdateimportant : bool
+ Auto update "important" packages
+ default_vol : str
+ Default volume for installation, all your volumes or `"no_default_vol" = Always ask me`
+ update_channel : str
+ "stable" => Disable beta packages
+ "beta" => Enable beta packages
+
+ Returns
+ -------
+ dict
+ Return some settings.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "enable_dsm": true,
+ "enable_email": false,
+ "update_channel": "stable"
+ },
+ "success": true
+ }
+ ```
+ """
+
+ api_name = 'SYNO.Core.Package.Setting'
+ info = self.core_list[api_name]
+ api_path = info['path']
+ req_param = {
+ "method": "set",
+ "version": info['maxVersion'],
+ "enable_email": enable_email,
+ "enable_dsm": enable_dsm,
+ "enable_autoupdate": enable_autoupdate,
+ "autoupdateall": autoupdateall,
+ "autoupdateimportant": autoupdateimportant,
+ "default_vol": default_vol,
+ "update_channel": update_channel
+ }
+
+ return self.request_data(api_name, api_path, req_param)
+
+ def get_package_center_infos(self) -> dict:
+ """
+ Get package center informations.
+
+ Returns
+ -------
+ dict
+ List of configs.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "config": {
+ "auth_key": "------------------------------",
+ "blBetaChannel": false,
+ "blOtherServer": false,
+ "def_void": "",
+ "ds_build": "72806",
+ "ds_major": "7",
+ "ds_minor": "2",
+ "ds_timezone": "Amsterdam",
+ "ds_unique": "synology_r1000_723+",
+ "myPayBaseURL": "https://payment.synology.com",
+ "myds_id": "7886858",
+ "serial": "2260TPR7X30E6",
+ "success": true
+ },
+ "prerelease": {
+ "agreed": true,
+ "success": true
+ },
+ "term": {
+ "agreed_term_version": "0003",
+ "curr_term_version": "0003",
+ "success": true
+ }
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.Package.Info'
+ info = self.core_list[api_name]
+ api_path = info['path']
+ req_param = {
+ "method": "get",
+ "version": info['maxVersion'],
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def feasibility_check_install(self, packages: List[str]) -> dict:
+ """
+ Check if installation is possible.
+
+ Parameters
+ ----------
+ packages : List[str]
+ List of package IDs to check for feasibility
+
+ Returns
+ -------
+ dict
+ A dictionary containing the feasibility check results.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "template": "data"
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.Package.Setting'
+ info = self.core_list[api_name]
+ api_path = info['path']
+ req_param = {
+ "method": "feasibility_check",
+ "version": info['maxVersion'],
+ "type": "install_check",
+ "packages": json.dumps(packages)
+ }
+
+ return self.request_data(api_name, api_path, req_param)
+
+ def download_package(self, url: str, package_id: str, checksum: str, filesize: str) -> dict:
+ """
+ Start download of the package, return a taskId for check status.
+
+ Parameters
+ ----------
+ url : str
+ Url that can be retrieve from package info using `get_installable` function, in the `link` field
+ package_id : str
+ Package ID that can be retrieve from package info using `get_installable` function, in the `id` field
+ checksum : str
+ Checksum that can be retrieve from package info using `get_installable` function, in the `md5` field
+ filesize : str
+ Filesize that can be retrieve from package info using `get_installable` function, in the `size` field
+
+ Returns
+ -------
+ dict
+ Retreive first progress of the download and the taskid used to check download status with `get_dowload_package_status` function.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "progress": 1.0000000000000001e-05,
+ "taskid": "@SYNOPKG_DOWNLOAD_DhcpServer"
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.Package.Installation'
+ info = self.core_list[api_name]
+ api_path = info['path']
+ req_param = {
+ "method": "install",
+ "version": info['minVersion'],
+ "operation": "install",
+ "type": 0,
+ "blqinst": False,
+ "url": url,
+ "name": package_id,
+ "checksum": checksum,
+ "filesize": filesize
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def get_dowload_package_status(self, task_id: str) -> dict:
+ """
+ Get current download status of the package.
+
+ Parameters
+ ----------
+ task_id : str
+ Task ID retrieve from response of `download_package` function
+
+ Returns
+ -------
+ dict
+ Retrieve informations about the download, important info is the `progress` field.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "beta": false,
+ "blqinst": false,
+ "finished": false,
+ "id": "DhcpServer",
+ "installing": false,
+ "name": "DhcpServer",
+ "pid": 27844,
+ "progress": 1.0000000000000001e-05,
+ "remote_link": "https://global.synologydownload.com/download/Package/spk/DhcpServer/1.0.2-0046/DhcpServer-x86_64-1.0.2-0046.spk",
+ "size": "1378697",
+ "success": true,
+ "taskid": "@SYNOPKG_DOWNLOAD_DhcpServer",
+ "tmp_folder": "/volume1/@tmp/synopkg/download.esnnkb"
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.Package.Installation'
+ info = self.core_list[api_name]
+ api_path = info['path']
+ req_param = {
+ "method": "status",
+ "version": info['minVersion'],
+ "task_id": task_id
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def check_installation_from_download(self, task_id: str) -> dict:
+ """
+ Get info about downloaded package file, response field is used for `check_installation` and `install_package` function.
+
+ Parameters
+ ----------
+ task_id : str
+ Task ID retrieve from response of `download_package` function
+
+ Returns
+ -------
+ dict
+ Retrieve information about downloaded package installation file, response field is used for `check_installation` and `install_package` function.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "description": "DHCP Server turns your DiskStation into a DHCP server within LAN to assign dynamic IP addresses and manage DHCP clients.",
+ "distributor": "",
+ "dsm_apps": "SYNO.SDS.DHCP.Instance",
+ "filename": "/volume1/@tmp/synopkg/download.esnnkb/@SYNOPKG_DOWNLOAD_DhcpServer",
+ "id": "DhcpServer",
+ "install_on_cold_storage": false,
+ "install_reboot": false,
+ "install_type": "system",
+ "maintainer": "Synology Inc.",
+ "name": "DHCP Server",
+ "startable": true,
+ "status": "non_installed",
+ "status_code": 255,
+ "status_description": "failed to locate given package",
+ "status_origin": "non_installed",
+ "version": "1.0.2-0046"
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.Package.Installation.Download'
+ info = self.core_list[api_name]
+ api_path = info['path']
+ req_param = {
+ "method": "check",
+ "version": info['minVersion'],
+ "taskid": task_id
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def upload_package_file(self, file_path: str, verify: bool = False, progress_bar: bool = True, additional: list = []) -> dict:
+ """
+ Upload a file for install a package.
+
+ Parameters
+ ----------
+ file_path : str
+ File path
+ verify : bool, optional
+ Use https. Defaults to `False`
+ progress_bar : bool, optional
+ Enable progress bar in the terminal. Defaults to `True`
+ additional : list, optional
+ Additional field to retrieves. Defaults to `[]`
+ All fields know are:
+ `["description","maintainer","distributor","startable","dsm_apps","status","install_reboot",
+ "install_type","install_on_cold_storage","break_pkgs","replace_pkgs"]`.
+
+ Returns
+ -------
+ dict
+ Informations about the uploaded file for installation.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "additional": {
+ "break_pkgs": null,
+ "description": "Plex organizes all of your personal media so you can easily access and enjoy it.",
+ "distributor": "",
+ "dsm_apps": " com.plexapp.plexmediaserver",
+ "install_on_cold_storage": false,
+ "install_reboot": false,
+ "install_type": "",
+ "maintainer": "Plex Inc",
+ "replace_pkgs": { "Plex Media Server": "" },
+ "startable": true,
+ "status": "running",
+ "status_code": 0,
+ "status_description": "retrieve from status script",
+ "status_origin": "running"
+ },
+ "codesign_error": 4532,
+ "id": "PlexMediaServer",
+ "name": "Plex Media Server",
+ "task_id": "@SYNOPKG_UPLOAD_17392283048566DD3",
+ "version": "1.41.3.9314-72009314"
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.Package.Installation'
+ info = self.core_list[api_name]
+ api_path = info['path']
+ filename = os.path.basename(file_path)
+
+ session = requests.session()
+
+ with open(file_path, 'rb') as payload:
+ url = ('%s%s' % (self.base_url, api_path)) + '?api=%s&version=%s&method=upload&_sid=%s' % (
+ api_name, info['minVersion'], self._sid)
+
+ encoder = MultipartEncoder({
+ 'additional': json.dumps(additional),
+ 'file': (filename, payload, 'application/octet-stream')
+ })
+
+ if progress_bar:
+ bar = tqdm.tqdm(desc='Upload Progress',
+ total=encoder.len,
+ dynamic_ncols=True,
+ unit='B',
+ unit_scale=True,
+ unit_divisor=1024
+ )
+
+ monitor = MultipartEncoderMonitor(
+ encoder, lambda monitor: bar.update(monitor.bytes_read - bar.n))
+
+ r = session.post(
+ url,
+ data=monitor,
+ verify=verify,
+ headers={"X-SYNO-TOKEN": self.session._syno_token,
+ 'Content-Type': monitor.content_type}
+ )
+
+ else:
+ r = session.post(
+ url,
+ data=encoder,
+ verify=verify,
+ headers={"X-SYNO-TOKEN": self.session._syno_token,
+ 'Content-Type': encoder.content_type}
+ )
+
+ session.close()
+ if r.status_code != 200 or not r.json()['success']:
+ return r.status_code, r.json()
+
+ return r.json()
+
+ def get_default_install_volume(self) -> dict:
+ """
+ Get default install volume for package.
+
+ Returns
+ -------
+ dict
+ Return default volume, if default volume is set to `Always ask me` it return error 4501.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "default_vol": "/volume1"
+ },
+ "success": true
+ }
+ ```
+ """
+ api_name = 'SYNO.Core.Package.Setting.Volume'
+ info = self.core_list[api_name]
+ api_path = info['path']
+ req_param = {
+ "method": "get",
+ "version": info['maxVersion'],
+ }
+
+ return self.request_data(api_name, api_path, req_param)
+
+ def check_installation(self,
+ package_id: str, install_type: str = "", install_on_cold_storage: bool = False,
+ blCheckDep: bool = False, replacepkgs: dict = {}
+ ) -> dict:
+ """
+ Check installation of the package on the default volume.
+
+ Parameters
+ ----------
+ package_id : str
+ Id of the package to install
+ install_type : str, optionnal
+ Installation type, Defaults to `""`. TODO: Add description and possible types
+ install_on_cold_storage : bool, optional
+ Defaults to `False`. TODO: Add description
+ blCheckDep : bool, optional
+ Defaults to `False`. TODO: Add description
+ replacepkgs : dict, optional
+ Defaults to `{}`. TODO: Add description
+
+ Returns
+ -------
+ dict
+ List of usefull informations about volumes.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "is_occupied": false,
+ "volume_count": 2,
+ "volume_list": [
+ {
+ "desc": "",
+ "display": "Volume 1 (Available capacity: 184.52 GB )",
+ "mount_point": "/volume1",
+ "size_free": "198126022656",
+ "size_total": "206158430208",
+ "vol_desc": "vol1",
+ "volume_features": []
+ },
+ {
+ "desc": "",
+ "display": "Volume 2 (Available capacity: 2391.16 GB )",
+ "mount_point": "/volume2",
+ "size_free": "2567484923904",
+ "size_total": "3623234412544",
+ "vol_desc": "vol2",
+ "volume_features": []
+ }
+ ],
+ "volume_path": "/volume1"
+ },
+ "success": true,
+ }
+ ```
+ """
+
+ api_name = 'SYNO.Core.Package.Installation'
+ info = self.core_list[api_name]
+ api_path = info['path']
+ req_param = {
+ "method": "check",
+ "version": info['maxVersion'],
+ "id": package_id,
+ "install_type": install_type,
+ "install_on_cold_storage": install_on_cold_storage,
+ "breakpkgs": None,
+ "blCheckDep": blCheckDep,
+ "replacepkgs": json.dumps(replacepkgs)
+ }
+
+ return self.request_data(api_name, api_path, req_param)
+
+ def upgrade_package(self, task_id: str, check_codesign: bool = False, force: bool = False, installrunpackage: bool = True, extra_values: dict = {}) -> dict:
+ """
+Upgrade an existing package.
+
+ Parameters
+ ----------
+ task_id : str
+ Task id of the download or the upload file
+ check_codesign : bool, optional
+ Check signature of the source code of the package (is it a Synology one). Defaults to `False`
+ force : bool, optional
+ Force installation. Defaults to `False`
+ installrunpackage : bool, optional
+ Run package after installation. Defaults to `True`
+ extra_values : dict, optional
+ Extra values due to some package installation. Defaults to `{}`
+ All known extra values are:
+ - Surveillance station
+ ```json
+ {
+ "chkSVS_Alias": true,
+ "strSVS_Alias": "cam",
+ "chkSVS_HTTP": true,
+ "strSVS_HTTP": "9900",
+ "chkSVS_HTTPS": true,
+ "strSVS_HTTPS": "9901"
+ }
+ ```
+
+ Returns
+ -------
+ dict
+ Message and some info about installation.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "message": "
Installation Successful!
\n
Note: If Plex cannot access your media, verify user PlexMediaServer is granted permission in Control Panel.
\nSet access to your media share(s) by performing the following steps:
\n1. Open Control Panel and select Shared Folder
\n2. Select the share which contains your media and click Edit
\n3. Click the Permissions tab
\n4. Change the dropdown from Local Users to System internal user
\n5. Check the Read/Write checkbox for the PlexMediaServer user
\n6. Click Save to confirm the new permissions
\n7. Repeat steps 2-6 for each share you want Plex Media Server to access
\n",
+ "packageName": "Plex Media Server",
+ "worker_message": []
+ },
+ "success": true,
+ }
+ ```
+ """
+
+ api_name = 'SYNO.Core.Package.Installation'
+ info = self.core_list[api_name]
+ api_path = info['path']
+ req_param = {
+ "method": "upgrade",
+ "version": info['minVersion'],
+ "type": 0,
+ "check_codesign": check_codesign,
+ "force": force,
+ "installrunpackage": installrunpackage,
+ "task_id": task_id,
+ "extra_values": json.dumps(extra_values),
+ }
+ return self.request_data(api_name, api_path, req_param)
+
+ def install_package(self, package_id: str, volume_path: str, file_path: str, check_codesign: bool = True, force: bool = True, installrunpackage: bool = True, extra_values: dict = {}) -> dict:
+ """
+ Install a package that is already downloaded.
+
+ Parameters
+ ----------
+ package_id : str
+ Id of the package to install
+ volume_path : str
+ Volume path of the installation, can get from `check_installation` function
+ file_path : str
+ File path of the installation, can get from `check_installation_from_download` function
+ check_codesign : bool, optional
+ Check signature of the source code of the package (is it a Synology one). Defaults to `False`
+ force : bool, optional
+ Force installation. Defaults to `False`
+ installrunpackage : bool, optional
+ Run package after installation. Defaults to `True`
+ extra_values : dict, optional
+ Extra values due to some package installation. Defaults to `{}`
+ All known extra values are:
+ - Surveillance station
+ ```json
+ {
+ "chkSVS_Alias": true,
+ "strSVS_Alias": "cam",
+ "chkSVS_HTTP": true,
+ "strSVS_HTTP": "9900",
+ "chkSVS_HTTPS": true,
+ "strSVS_HTTPS": "9901"
+ }
+ ```
+
+ Returns
+ -------
+ dict
+ Message and some info about installation.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "has_fail": false,
+ "result": [
+ {
+ "api": "SYNO.Core.Package.Installation",
+ "data": {
+ "is_occupied": false,
+ "volume_count": 2,
+ "volume_list": [
+ {
+ "desc": "",
+ "display": "Volume 1 (Available capacity: 185.09 GB )",
+ "mount_point": "/volume1",
+ "size_free": "198739943424",
+ "size_total": "206158430208",
+ "vol_desc": "Apps",
+ "volume_features": []
+ },
+ {
+ "desc": "",
+ "display": "Volume 2 (Available capacity: 2391.17 GB )",
+ "mount_point": "/volume2",
+ "size_free": "2567495630848",
+ "size_total": "3623234412544",
+ "vol_desc": "Stockage",
+ "volume_features": []
+ }
+ ],
+ "volume_path": "/volume1"
+ },
+ "method": "check",
+ "success": true,
+ "version": 1
+ },
+ {
+ "api": "SYNO.Core.Package.Installation",
+ "data": {
+ "packageName": "Text Editor",
+ "worker_message": []
+ },
+ "method": "install",
+ "success": true,
+ "version": 1
+ }
+ ]
+ },
+ "success": true
+ }
+ ```
+ """
+ compound = [
+ {
+ "api": "SYNO.Core.Package.Installation",
+ "method": "check",
+ "version": self.core_list['SYNO.Core.Package.Installation']['minVersion'],
+ "id": package_id,
+ "install_type": "",
+ "install_on_cold_storage": False,
+ "breakpkgs": None,
+ "blCheckDep": False,
+ "replacepkgs": None
+ },
+ {
+ "api": "SYNO.Core.Package.Installation",
+ "method": "install",
+ "version": self.core_list["SYNO.Core.Package.Installation"]['minVersion'],
+ "type": 0,
+ "volume_path": volume_path,
+ "path": file_path,
+ "check_codesign": check_codesign,
+ "force": force,
+ "installrunpackage": installrunpackage,
+ "extra_values": json.dumps(extra_values),
+ }
+ ]
+ return self.batch_request(compound=compound)
+
+ def uninstall_package(self, package_id: str) -> dict:
+ """
+ Uninstall a package.
+
+ Parameters
+ ----------
+ package_id : str
+ Id of the package to uninstall
+
+ Returns
+ -------
+ dict
+ Possible message to the user.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "message": "",
+ "worker_message": []
+ },
+ "success": true
+ }
+ ```
+ """
+
+ if not self._is_package_already_installed(package_id=package_id):
+ raise Exception(
+ f"""Package "{package_id}" is not installed, it cannot be uninstalled""")
+
+ api_name = 'SYNO.Core.Package.Uninstallation'
+ info = self.core_list[api_name]
+ api_path = info['path']
+ req_param = {
+ "method": "uninstall",
+ "version": info['minVersion'],
+ "id": package_id,
+ "dsm_apps": ""
+ }
+
+ return self.request_data(api_name, api_path, req_param)
+
+ def _is_package_already_installed(self, package_id: str) -> bool:
+ """
+ Check if a package is already installed.
+
+ Parameters
+ ----------
+ package_id : str
+ Package ID to check
+
+ Returns
+ -------
+ bool
+ `True` if the package is already installed, `False` otherwise.
+ """
+ response: dict = self.list_installed()
+ data: dict = response.get("data")
+ installed_packages = data.get("packages")
+ package_infos: dict = next(
+ (package for package in installed_packages if package["id"] == package_id), None)
+ return package_infos != None
+
+ def easy_install(self, package_id: str, volume_path: str, install_dependencies: bool = True) -> dict:
+ """
+ Execute an "easy" installation process of the package.
+
+ Parameters
+ ----------
+ package_id : str
+ Package ID to install
+ volume_path : str
+ Volume path where you want to install the package
+ install_dependencies : bool, optional
+ If you want to install dependencies. Defaults to `True`
+
+ Returns
+ -------
+ dict
+ Information about installation, same as `install_package` function.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "has_fail": false,
+ "result": [
+ {
+ "api": "SYNO.Core.Package.Installation",
+ "data": {
+ "is_occupied": false,
+ "volume_count": 2,
+ "volume_list": [
+ {
+ "desc": "",
+ "display": "Volume 1 (Available capacity: 185.11 GB )",
+ "mount_point": "/volume1",
+ "size_free": "198759485440",
+ "size_total": "206158430208",
+ "vol_desc": "Apps",
+ "volume_features": []
+ },
+ {
+ "desc": "",
+ "display": "Volume 2 (Available capacity: 2391.17 GB )",
+ "mount_point": "/volume2",
+ "size_free": "2567495565312",
+ "size_total": "3623234412544",
+ "vol_desc": "Stockage",
+ "volume_features": []
+ }
+ ],
+ "volume_path": "/volume1"
+ },
+ "method": "check",
+ "success": true,
+ "version": 1
+ },
+ {
+ "api": "SYNO.Core.Package.Installation",
+ "data": {
+ "packageName": "Text Editor",
+ "worker_message": []
+ },
+ "method": "install",
+ "success": true,
+ "version": 1
+ }
+ ]
+ },
+ "success": true
+ }
+ ```
+ """
+
+ # Package already installed
+ if self._is_package_already_installed(package_id):
+ raise Exception(f"""Package "{package_id}" already installed""")
+
+ response: dict = self.list_installable()
+ data: dict = response.get("data")
+ installable_packages = data.get("packages")
+ package_infos: dict = next(
+ (package for package in installable_packages if package["id"] == package_id), None)
+ # Package not found
+ if package_infos == None:
+ raise Exception(
+ f"""Package "{package_id}" not found in installable list, installation not possible""")
+
+ # Check dependencies
+ deppkgs = package_infos.get("deppkgs")
+ if deppkgs:
+ if not install_dependencies:
+ raise Exception(
+ f"""Package "{package_id}" has dependencies that needs to be installed but "install_dependencies" is set to "False" """)
+ deppkg: str
+ for deppkg in deppkgs:
+ if not self._is_package_already_installed(deppkg):
+ print(
+ f"""Installation of dependency "{deppkg}" for "{package_id}" started""")
+ self.easy_install(package_id=deppkg,
+ volume_path=volume_path)
+ print(
+ f"""Installation of dependency "{deppkg}" for "{package_id}" done""")
+
+ # Store information of the package
+ url = package_infos.get("link")
+ filesize = package_infos.get("size")
+ version = package_infos.get("version")
+ checksum = package_infos.get("md5")
+
+ # Start installation sequence
+
+ # Start download the package installation file
+ response: dict = self.download_package(
+ url=url, package_id=package_id, checksum=checksum, filesize=filesize)
+ data: dict = response.get("data")
+ task_id = data.get("taskid")
+
+ # Create progress bar of the status
+ response: dict = self.get_dowload_package_status(task_id=task_id)
+ data: dict = response.get("data")
+ progress = data.get("progress")
+ if not data.get("finished"):
+ with tqdm.tqdm(total=100) as pbar:
+ while not data.get("finished"):
+ response: dict = self.get_dowload_package_status(
+ task_id=task_id)
+ data: dict = response.get("data")
+ progress: float = data.get("progress")
+ if progress:
+ pbar.update(int(progress*100))
+ time.sleep(0.500)
+ pbar.update(100)
+
+ print(f"""Download of "{package_id}" done""")
+
+ # Check downloaded file
+ response: dict = self.check_installation_from_download(task_id=task_id)
+ data: dict = response.get("data")
+ status = data.get("status")
+ file_path = data.get("filename")
+ print(f"""Downloaded file status : {status}""")
+
+ # Check installation
+ response = self.check_installation(package_id=package_id)
+
+ # Install package
+ extra_values = {}
+ if package_id == "SurveillanceStation":
+ extra_values = {
+ "chkSVS_Alias": True,
+ "strSVS_Alias": "cam",
+ "chkSVS_HTTP": True,
+ "strSVS_HTTP": "9900",
+ "chkSVS_HTTPS": True,
+ "strSVS_HTTPS": "9901"
+ }
+
+ return self.install_package(package_id=package_id, volume_path=volume_path, file_path=file_path, extra_values=extra_values)
diff --git a/synology_api/DSM/Package/__init__.py b/synology_api/DSM/Package/__init__.py
new file mode 100644
index 00000000..4ab7b736
--- /dev/null
+++ b/synology_api/DSM/Package/__init__.py
@@ -0,0 +1,9 @@
+
+"""
+Package submodule for Synology DSM API.
+
+Provides FileStation and PackageCenter API classes.
+"""
+
+from .FileStation import FileStation
+from .PackageCenter import PackageCenter
diff --git a/synology_api/DSM/__init__.py b/synology_api/DSM/__init__.py
new file mode 100644
index 00000000..42906cec
--- /dev/null
+++ b/synology_api/DSM/__init__.py
@@ -0,0 +1,88 @@
+"""
+Main entry point for Synology DSM API access.
+"""
+
+from .ControlPanel import ControlPanel
+from .Package.FileStation import FileStation
+from .Package.PackageCenter import PackageCenter
+from synology_api import base_api
+
+
+class DSM(base_api.BaseApi):
+ """
+ Main entry point for Synology DSM API access. Provides access to ControlPanel, FileStation, and PackageCenter APIs.
+
+ Parameters
+ ----------
+ *args : tuple
+ Positional arguments passed to BaseApi.
+ **kwargs : dict
+ Keyword arguments passed to BaseApi.
+ """
+ _ctrl_panel = None
+ _file_station = None
+ _package_center = None
+
+ def __init__(self, *args, **kwargs):
+ """
+ Initialize DSM API wrapper.
+
+ Parameters
+ ----------
+ *args : tuple
+ Positional arguments passed to BaseApi.
+ **kwargs : dict
+ Keyword arguments passed to BaseApi.
+ """
+ super().__init__(*args, **kwargs)
+
+ @property
+ def ControlPanel(self):
+ """
+ ControlPanel: ControlPanel.
+
+ Returns
+ -------
+ ControlPanel
+ Instance of the ControlPanel API, sharing the same state as DSM.
+ """
+ if self._ctrl_panel is None:
+ # Create ControlPanel instance without calling __init__
+ self._ctrl_panel = ControlPanel.__new__(ControlPanel)
+ # Share the state
+ self._ctrl_panel.__dict__ = self.__dict__
+ return self._ctrl_panel
+
+ @property
+ def FileStation(self):
+ """
+ FileStation: FileStation.
+
+ Returns
+ -------
+ FileStation
+ Instance of the FileStation API, sharing the same state as DSM.
+ """
+ if self._file_station is None:
+ # Create FileStation instance without calling __init__
+ self._file_station = FileStation.__new__(FileStation)
+ # Share the state
+ self._file_station.__dict__ = self.__dict__
+ return self._file_station
+
+ @property
+ def PackageCenter(self):
+ """
+ PackageCenter: PackageCenter.
+
+ Returns
+ -------
+ PackageCenter
+ Instance of the PackageCenter API, sharing the same state as DSM.
+ """
+ if self._package_center is None:
+ # Create PackageCenter instance without calling __init__
+ self._package_center = PackageCenter.__new__(PackageCenter)
+ # Share the state
+ self._package_center.__dict__ = self.__dict__
+ return self._package_center
diff --git a/synology_api/__init__.py b/synology_api/__init__.py
index 1f5f8a19..bf061576 100755
--- a/synology_api/__init__.py
+++ b/synology_api/__init__.py
@@ -1,3 +1,4 @@
+"""Synology API Python Client."""
from . import \
audiostation, \
auth, \
@@ -28,3 +29,28 @@
universal_search, \
snapshot, \
surveillancestation
+
+from .DSM import DSM
+from .DSM.ControlPanel import \
+ ControlPanel, \
+ ApplicationPrivileges, \
+ DomainLDAP, \
+ ExternalAccess, \
+ ExternalDevices, \
+ FileServices, \
+ HardwarePower, \
+ IndexingService, \
+ InfoCenter, \
+ LoginPortal, \
+ Network, \
+ Notifications, \
+ RegionalOptions, \
+ Security, \
+ SharedFolder, \
+ SynologyAccount, \
+ TaskScheduler, \
+ TerminalSNMP, \
+ UpdateRestore, \
+ UserGroup
+from .DSM.Package import \
+ FileStation
diff --git a/synology_api/abm.py b/synology_api/abm.py
index 41025428..03961dc6 100644
--- a/synology_api/abm.py
+++ b/synology_api/abm.py
@@ -1,6 +1,4 @@
-"""
-Active Backup for Microsoft 365 Implementation.
-"""
+"""Active Backup for Microsoft 365 Implementation."""
from __future__ import annotations
import json
@@ -735,7 +733,7 @@ def set_task_schedule(self,
"repeat_every_hours": 1,
"run_days": [0, 1, 2, 3, 4, 5, 6]
}
- ```.
+ ```
Returns
-------
diff --git a/synology_api/auth.py b/synology_api/auth.py
index 32710226..7a5c936d 100644
--- a/synology_api/auth.py
+++ b/synology_api/auth.py
@@ -1,11 +1,12 @@
-"""
-Provides authentication and API request handling for Synology DSM, including session management, encryption utilities, and error handling for various Synology services.
-"""
+"""Provides authentication and API request handling for Synology DSM, including session management, encryption utilities, and error handling for various Synology services."""
from __future__ import annotations
from random import randint
-from typing import Optional
+from typing import Optional, Any, Union
import requests
import json
+
+from requests_toolbelt import MultipartEncoder, MultipartEncoderMonitor
+
from .error_codes import error_codes, CODE_SUCCESS, download_station_error_codes, file_station_error_codes
from .error_codes import auth_error_codes, virtualization_error_codes
from urllib3 import disable_warnings
@@ -24,7 +25,10 @@
import base64
import hashlib
import urllib
-
+from cryptography.hazmat.primitives.asymmetric.x25519 import X25519PrivateKey
+import base64
+from noise.connection import NoiseConnection, Keypair
+import time
USE_EXCEPTIONS: bool = True
@@ -131,6 +135,52 @@ def __init__(self,
self.full_api_list = {}
self.app_api_list = {}
+ def get_ik_message(self) -> str:
+ """
+ Get the IK message for authentication.
+
+ Returns
+ -------
+ str
+ The IK message.
+ """
+
+ url = self._base_url + 'entry.cgi/SYNO.API.Auth.UIConfig'
+ data = {
+ "api": "SYNO.API.Auth.UIConfig",
+ "method": "get",
+ "version": "1"
+ }
+ response = requests.post(url, data=data, verify=self._verify)
+
+ # Try to get cookie "_SSID"
+ if response.status_code != 200:
+ raise Exception("Failed to access the URL for IK message. Status code: {}".format(
+ response.status_code))
+ cookies = response.cookies
+ if "_SSID" not in cookies:
+ raise Exception("Cookie '_SSID' not found in the response.")
+ _SSID_encoded = cookies["_SSID"]
+ _SSID = self.decode_ssid_cookie(_SSID_encoded)
+
+ private_bytes = X25519PrivateKey.generate().private_bytes_raw()
+
+ noise = NoiseConnection.from_name(b"Noise_IK_25519_ChaChaPoly_BLAKE2b")
+ noise.set_as_initiator()
+ noise.set_keypair_from_private_bytes(Keypair.STATIC, private_bytes)
+ noise.set_keypair_from_public_bytes(Keypair.REMOTE_STATIC, _SSID)
+
+ noise.start_handshake()
+
+ payload = json.dumps({
+ "time": int(time.time()),
+ }).encode('utf-8')
+
+ message = noise.write_message(payload)
+ ik_message = self.encode_ssid_cookie(message)
+
+ return ik_message
+
def verify_cert_enabled(self) -> bool:
"""
Check if SSL certificate verification is enabled.
@@ -161,6 +211,9 @@ def login(self) -> None:
params = {'api': "SYNO.API.Auth", 'version': self._version,
'method': 'login', 'enable_syno_token': 'yes', 'client': 'browser'}
+ if self._version >= 7:
+ params.update({'ik_message': self.get_ik_message()})
+
params_enc = {
'account': self._username,
'enable_device_token': 'no',
@@ -325,9 +378,7 @@ def get_api_list(self, app: Optional[str] = None) -> None:
return
def show_api_name_list(self) -> None:
- """
- Print the list of available API names.
- """
+ """Print the list of available API names."""
prev_key = ''
for key in self.full_api_list:
if key != prev_key:
@@ -336,9 +387,7 @@ def show_api_name_list(self) -> None:
return
def show_json_response_type(self) -> None:
- """
- Print API names that return JSON data.
- """
+ """Print API names that return JSON data."""
for key in self.full_api_list:
for sub_key in self.full_api_list[key]:
if sub_key == 'requestFormat':
@@ -577,6 +626,7 @@ def request_data(self,
api_path: str,
req_param: dict[str, object],
method: Optional[str] = None,
+ data: MultiPartEncoderMonitor | MultipartEncoder | str | None = None,
response_json: bool = True
) -> dict[str, object] | str | list | requests.Response: # 'post' or 'get'
"""
@@ -592,6 +642,8 @@ def request_data(self,
The parameters to include in the request.
method : str, optional
The HTTP method to use ('get' or 'post'). Defaults to 'get' if not specified.
+ data : str, optional
+ The data to send to upload a file like a torrent file.
response_json : bool, optional
Whether to return the response as JSON. If False, returns the raw response object.
@@ -630,8 +682,15 @@ def request_data(self,
response = requests.get(url, req_param, verify=self._verify, headers={
"X-SYNO-TOKEN": self._syno_token})
elif method == 'post':
- response = requests.post(url, req_param, verify=self._verify, headers={
- "X-SYNO-TOKEN": self._syno_token})
+ if data is None:
+ response = requests.post(url, req_param, verify=self._verify, headers={
+ "X-SYNO-TOKEN": self._syno_token})
+ else:
+ url = ('%s%s' % (self._base_url, api_path)) + \
+ '/' + api_name
+ response = requests.post(url, data=data, params=req_param, verify=self._verify, headers={
+ "Content-Type": data.content_type, "X-SYNO-TOKEN": self._syno_token})
+ response.raise_for_status()
except requests.exceptions.ConnectionError as e:
raise SynoConnectionError(error_message=e.args[0])
except requests.exceptions.HTTPError as e:
@@ -644,6 +703,7 @@ def request_data(self,
elif method == 'post':
response = requests.post(url, req_param, verify=self._verify, headers={
"X-SYNO-TOKEN": self._syno_token})
+ response.raise_for_status()
# Check for error response from dsm:
error_code = 0
@@ -808,6 +868,52 @@ def _get_error_message(code: int, api_name: str) -> str:
message = "" % api_name
return 'Error {} - {}'.format(code, message)
+ @staticmethod
+ def decode_ssid_cookie(ssid: str) -> bytes:
+ """
+ Decode the SSID cookie.
+
+ Parameters
+ ----------
+ ssid : str
+ The SSID cookie string to decode.
+
+ Returns
+ -------
+ bytes
+ The decoded SSID cookie.
+ """
+ # Replace '-' with '+' and '_' with '/'
+ ssid_fixed = ssid.replace('-', '+').replace('_', '/')
+ # Pad with '=' if needed
+ padding = '=' * (-len(ssid_fixed) % 4)
+ ssid_fixed += padding
+ # Decode base64
+ return base64.b64decode(ssid_fixed)
+
+ @staticmethod
+ def encode_ssid_cookie(ssid_bytes: bytes) -> str:
+ """
+ Encode the SSID cookie.
+
+ Parameters
+ ----------
+ ssid_bytes : bytes
+ The SSID cookie bytes to encode.
+
+ Returns
+ -------
+ str
+ The encoded SSID cookie.
+ """
+ # Encode to base64
+ ssid_b64 = base64.b64encode(ssid_bytes).decode('utf-8')
+ # Replace '+' with '-' and '/' with '_'
+ ssid_fixed = ssid_b64.replace('+', '-').replace('/', '_')
+ # Remove padding '='
+ ssid_fixed = ssid_fixed.rstrip('=')
+ return ssid_fixed
+
@property
def sid(self) -> Optional[str]:
"""
diff --git a/synology_api/base_api.py b/synology_api/base_api.py
index c1702e64..909456d5 100644
--- a/synology_api/base_api.py
+++ b/synology_api/base_api.py
@@ -1,42 +1,46 @@
+"""
+Base API module for Synology DSM.
+
+Provides a base class for all API implementations, handling authentication,
+session management, and connection setup to a Synology NAS device.
+"""
from typing import Optional, Any
from . import auth as syn
class BaseApi(object):
- """Base class to be used for all API implementations.
-
- Takes auth and connection information to create a session to the NAS.
-
- The session is created on instanciation.
-
- Parameters
- ----------
- ip_address : str
- The IP/DNS address of the NAS.
-
- port : str
- The port of the NAS. Defaults to `5000`.
-
- username : str
- The username to use for authentication.
-
- password : str
- The password to use for authentication.
-
- secure : bool
- Whether to use HTTPS or not. Defaults to `False`.
-
- cert_verify : bool
- Whether to verify the SSL certificate or not. Defaults to `False`.
-
- dsm_version : int
- The DSM version. Defaults to `7`.
-
- debug : bool
- Whether to print debug messages or not. Defaults to `True`.
-
- otp_code : str
- The OTP code to use for authentication. Defaults to `None`
+ """
+ Base class to be used for all API implementations.
+
+ Takes auth and connection information to create a session to the NAS.
+ The session is created on instanciation.
+
+ Parameters
+ ----------
+ ip_address : str
+ The IP/DNS address of the NAS.
+ port : str
+ The port of the NAS. Defaults to `5000`.
+ username : str
+ The username to use for authentication.
+ password : str
+ The password to use for authentication.
+ secure : bool, optional
+ Whether to use HTTPS or not. Defaults to `False`.
+ cert_verify : bool, optional
+ Whether to verify the SSL certificate or not. Defaults to `False`.
+ dsm_version : int, optional
+ The DSM version. Defaults to `7`.
+ debug : bool, optional
+ Whether to print debug messages or not. Defaults to `True`.
+ otp_code : str, optional
+ The OTP code to use for authentication. Defaults to `None`.
+ device_id : str, optional
+ Device ID for device binding. Defaults to `None`.
+ device_name : str, optional
+ Device name for device binding. Defaults to `None`.
+ application : str, optional
+ The application context for API list retrieval. Defaults to `'Core'`.
"""
# Class-level attribute to store the shared session
@@ -56,7 +60,41 @@ def __init__(self,
device_name: Optional[str] = None,
application: str = 'Core',
) -> None:
+ """
+ Initialize the BaseApi object and create or reuse a session.
+ Parameters
+ ----------
+ ip_address : str
+ The IP/DNS address of the NAS.
+ port : str
+ The port of the NAS.
+ username : str
+ The username to use for authentication.
+ password : str
+ The password to use for authentication.
+ secure : bool, optional
+ Whether to use HTTPS or not. Defaults to `False`.
+ cert_verify : bool, optional
+ Whether to verify the SSL certificate or not. Defaults to `False`.
+ dsm_version : int, optional
+ The DSM version. Defaults to `7`.
+ debug : bool, optional
+ Whether to print debug messages or not. Defaults to `True`.
+ otp_code : str, optional
+ The OTP code to use for authentication. Defaults to `None`.
+ device_id : str, optional
+ Device ID for device binding. Defaults to `None`.
+ device_name : str, optional
+ Device name for device binding. Defaults to `None`.
+ application : str, optional
+ The application context for API list retrieval. Defaults to `'Core'`.
+
+ Returns
+ -------
+ None
+ Just actions, no return values.
+ """
self.application = application
# Reuse shared session if it exists, otherwise create a new one
@@ -87,7 +125,14 @@ def __init__(self,
self.base_url: str = self.session.base_url
def logout(self) -> None:
- """Close current session."""
+ """
+ Close current session.
+
+ Returns
+ -------
+ None
+ Action, no return values.
+ """
api_name = 'hotfix' # fix for docs_parser.py issue
if self.session:
self.session.logout()
diff --git a/synology_api/cloud_sync.py b/synology_api/cloud_sync.py
index bb95f033..1c90ba07 100644
--- a/synology_api/cloud_sync.py
+++ b/synology_api/cloud_sync.py
@@ -1,3 +1,9 @@
+"""
+CloudSync API module.
+
+This module provides the CloudSync class, which implements methods to interact with Synology's Cloud Sync API.
+It allows retrieving and setting package settings, managing cloud connections and tasks, and handling synchronization processes.
+"""
from __future__ import annotations
from typing import Any
from . import base_api
@@ -6,7 +12,8 @@
class CloudSync(base_api.BaseApi):
- """Cloud Sync API implementation.
+ """
+ Cloud Sync API implementation.
This API provides the functionality to get information related to the package settings and current connections and tasks.
It also provides functionalities to set most of the settings for tasks and package configuration, as well as manage the current syncing processes.
@@ -45,11 +52,11 @@ class CloudSync(base_api.BaseApi):
- Delete task
- Validate task settings
- Create S3 task
-
"""
def get_pkg_config(self) -> dict[str, object]:
- """Retrieve package settings.
+ """
+ Retrieve package settings.
Returns
-------
@@ -103,7 +110,8 @@ def get_pkg_config(self) -> dict[str, object]:
return self.request_data(api_name, api_path, req_param)
def get_connections(self, group_by: str = 'group_by_user') -> dict[str, object]:
- """Retrieve a list of current cloud connections.
+ """
+ Retrieve a list of current cloud connections.
Parameters
----------
@@ -175,7 +183,8 @@ def get_connections(self, group_by: str = 'group_by_user') -> dict[str, object]:
return self.request_data(api_name, api_path, req_param)
def get_connection_settings(self, conn_id: int) -> dict[str, object]:
- """Retrieve settings for a specific connection.
+ """
+ Retrieve settings for a specific connection.
Parameters
----------
@@ -219,7 +228,8 @@ def get_connection_settings(self, conn_id: int) -> dict[str, object]:
return self.request_data(api_name, api_path, req_param)
def get_connection_information(self, conn_id: int) -> dict[str, object]:
- """Retrieve cloud information for a specific connection.
+ """
+ Retrieve cloud information for a specific connection.
Parameters
----------
@@ -267,7 +277,8 @@ def get_connection_information(self, conn_id: int) -> dict[str, object]:
return self.request_data(api_name, api_path, req_param)
def get_connection_auth(self, conn_id: int) -> dict[str, object]:
- """Retrieve authentication information for a specific connection.
+ """
+ Retrieve authentication information for a specific connection.
Parameters
----------
@@ -344,7 +355,8 @@ def get_connection_logs(
offset: int = 0,
limit: int = 200
) -> dict[str, object]:
- """Retrieve logs for a specific connection.
+ """
+ Retrieve logs for a specific connection.
Parameters
----------
@@ -445,7 +457,8 @@ def get_connection_logs(
return self.request_data(api_name, api_path, req_param)
def get_tasks(self, conn_id: int) -> dict[str, object]:
- """Retrieve a list of tasks related to a specific connection.
+ """
+ Retrieve a list of tasks related to a specific connection.
Parameters
----------
@@ -495,7 +508,8 @@ def get_tasks(self, conn_id: int) -> dict[str, object]:
return self.request_data(api_name, api_path, req_param)
def get_task_filters(self, sess_id: int) -> dict[str, object]:
- """Retrieve filter information for a specific task.
+ """
+ Retrieve filter information for a specific task.
Parameters
----------
@@ -553,7 +567,8 @@ def get_task_cloud_folders(
remote_folder_id: str,
path: str = '/'
) -> dict[str, object]:
- """Retrieve a list of children directories in the cloud for a specific task.
+ """
+ Retrieve a list of children directories in the cloud for a specific task.
Parameters
----------
@@ -622,7 +637,8 @@ def get_task_cloud_folders(
return self.request_data(api_name, api_path, req_param)
def get_recently_modified(self) -> dict[str, object]:
- """Retrieve the 5 latest modified files and the currently syncing items.
+ """
+ Retrieve the 5 latest modified files and the currently syncing items.
Returns
-------
@@ -722,7 +738,8 @@ def set_pkg_config(
workers: int = 3,
admin_mode: bool = True
) -> dict[str, object]:
- """Set package configuration settings.
+ """
+ Set package configuration settings.
Parameters
----------
@@ -768,7 +785,8 @@ def set_pkg_config(
return self.request_data(api_name, api_path, req_param)
def set_relink_behavior(self, delete_from_cloud: bool) -> dict[str, object]:
- """Set the relinking behavior for personal user accounts.
+ """
+ Set the relinking behavior for personal user accounts.
Warning: Miss-configuration of this action may lead to data loss.
@@ -814,7 +832,8 @@ def set_connection_settings(
isSSE: bool = False,
part_size: int = 128
) -> dict[str, object]:
- """Set settings for a specific cloud connection.
+ """
+ Set settings for a specific cloud connection.
Parameters
----------
@@ -880,7 +899,8 @@ def set_connection_schedule(
enable: bool,
schedule_info: list[str] = []
) -> dict[str, object]:
- """Set the schedule for a specific connection.
+ """
+ Set the schedule for a specific connection.
Parameters
----------
@@ -951,7 +971,8 @@ def set_task_settings(
no_delete_on_cloud: bool = True,
convert_gd: bool = False
) -> dict[str, object]:
- """Set the task settings for a specific session.
+ """
+ Set the task settings for a specific session.
Parameters
----------
@@ -1011,7 +1032,8 @@ def set_task_filters(
filtered_extensions: list[str] = [],
max_upload_size: int = 0
) -> dict[str, object]:
- """Set task filters for selective synchronization in a specific session.
+ """
+ Set task filters for selective synchronization in a specific session.
Parameters
----------
@@ -1061,7 +1083,8 @@ def set_task_filters(
return self.request_data(api_name, api_path, req_param)
def connection_pause(self, conn_id: int = -1) -> dict[str, object]:
- """Pause one or all connections.
+ """
+ Pause one or all connections.
Parameters
----------
@@ -1095,7 +1118,8 @@ def connection_pause(self, conn_id: int = -1) -> dict[str, object]:
return self.request_data(api_name, api_path, req_param)
def connection_resume(self, conn_id: int = -1) -> dict[str, object]:
- """Resume one or all connections.
+ """
+ Resume one or all connections.
Parameters
----------
@@ -1129,7 +1153,8 @@ def connection_resume(self, conn_id: int = -1) -> dict[str, object]:
return self.request_data(api_name, api_path, req_param)
def connection_remove(self, conn_id: int) -> dict[str, object]:
- """Remove a specific connection and all associated tasks.
+ """
+ Remove a specific connection and all associated tasks.
The data will remain in both the local and remote directories.
@@ -1167,7 +1192,8 @@ def task_remove(
conn_id: int,
sess_id: int
) -> dict[str, object]:
- """Remove a specific task.
+ """
+ Remove a specific task.
The data will remain in both the local and remote directories.
@@ -1215,7 +1241,8 @@ def __generate_sync_task_s3_params(
filter_names: list[str] = [],
server_folder_id: str = '',
) -> dict[str, Any]:
- """Generate parameters for creating a sync task with S3.
+ """
+ Generate parameters for creating a sync task with S3.
Parameters
----------
@@ -1243,6 +1270,9 @@ def __generate_sync_task_s3_params(
filter_names : list[str], optional
List of file names to filter. Defaults to `[]`.
+ server_folder_id : str, optional
+ The unique identifier of the remote (cloud) folder to be synchronized. Defaults ``.
+
Returns
-------
dict[str, Any]
@@ -1294,7 +1324,7 @@ def __generate_sync_task_s3_params(
# Merge authentication details with request parameters
return merge_dicts(auth['data'], create_session_request_params)
- def test_task_setting(
+ def create_sync_task_s3(
self,
conn_id: int,
local_path: str,
@@ -1304,8 +1334,9 @@ def test_task_setting(
file_filter: list[str] = [],
filter_max_upload_size: int = 0,
filter_names: list[str] = [],
- ) -> tuple[bool, dict[str, object] | str]:
- """Test the task settings make sure they are valid.
+ ) -> tuple[bool, Any]:
+ """
+ Add a new synchronization task.
Parameters
----------
@@ -1335,11 +1366,17 @@ def test_task_setting(
Returns
-------
- tuple[bool, dict[str, object] | str]
- A tuple containing a boolean indicating success, and a dictionary or string with the result.
+ tuple[bool, Any]
+ A tuple containing the result of the task creation.
"""
- # Generate sync task parameters
- creation_params = self.generate_sync_task_s3_params(
+
+ # Validate is connection is Amazon S3
+ conn_info = self.get_connection_information(conn_id)
+ if conn_info['data']['type'] != 'az':
+ return (False, 'Connection is not Amazon S3')
+
+ # Merge authentication details with request parameters
+ creation_params = self.__generate_sync_task_s3_params(
conn_id,
local_path,
cloud_path,
@@ -1349,41 +1386,53 @@ def test_task_setting(
filter_max_upload_size,
filter_names
)
-
# Prepare API request data
api_name = 'SYNO.CloudSync'
info = self.gen_list[api_name]
- request_params = {
+ # Run test task setting
+ test_result = self.test_task_setting(
+ conn_id,
+ local_path,
+ cloud_path,
+ sync_direction,
+ storage_class,
+ file_filter,
+ filter_max_upload_size,
+ filter_names
+ )
+ if not test_result[0]:
+ return (False, test_result[1])
+
+ create_session_request = {
'api': api_name,
- 'method': 'test_task_setting',
+ 'method': 'create_session',
'version': info['minVersion'],
- 'conn_info': creation_params
+ 'conn_info': creation_params,
}
+ list_session_request = {
+ 'api': api_name,
+ 'method': 'list_sess',
+ 'version': info['minVersion'],
+ 'connection_id': conn_id
+ }
+ # Compound data
+ compound_data = [create_session_request, list_session_request]
+ # Send request and return response
+ return (True, self.batch_request(compound_data, method='post'))
- # Send request and get result
- compound_data = [request_params]
- result = self.batch_request(compound_data, method='post')
-
- # Check if the request was successful
- if result is not None and result['data']['has_fail'] == False:
- # print('Task setting is valid')
- return (True, result['data'])
- else:
- # print('Task setting is invalid')
- return (False, 'Invalid task setting')
-
- def create_sync_task_s3(
+ def test_task_setting(
self,
conn_id: int,
local_path: str,
cloud_path: str,
sync_direction='BIDIRECTION',
storage_class='STANDARD',
- filter_max_upload_size: int = 0,
file_filter: list[str] = [],
+ filter_max_upload_size: int = 0,
filter_names: list[str] = [],
- ) -> tuple[bool, Any]:
- """Add a new synchronization task.
+ ) -> tuple[bool, dict[str, object] | str]:
+ """
+ Test the task settings make sure they are valid.
Parameters
----------
@@ -1411,20 +1460,13 @@ def create_sync_task_s3(
filter_names : list[str], optional
List of file names to filter. Defaults to `[]`.
-
Returns
-------
- tuple[bool, Any]
- A tuple containing the result of the task creation.
+ tuple[bool, dict[str, object] | str]
+ A tuple containing a boolean indicating success, and a dictionary or string with the result.
"""
-
- # Validate is connection is Amazon S3
- conn_info = self.get_connection_information(conn_id)
- if conn_info['data']['type'] != 'az':
- return (False, 'Connection is not Amazon S3')
-
- # Merge authentication details with request parameters
- creation_params = self.__generate_sync_task_s3_params(
+ # Generate sync task parameters
+ creation_params = self.generate_sync_task_s3_params(
conn_id,
local_path,
cloud_path,
@@ -1434,36 +1476,25 @@ def create_sync_task_s3(
filter_max_upload_size,
filter_names
)
+
# Prepare API request data
api_name = 'SYNO.CloudSync'
info = self.gen_list[api_name]
- # Run test task setting
- test_result = self.test_task_setting(
- conn_id,
- local_path,
- cloud_path,
- sync_direction,
- storage_class,
- file_filter,
- filter_max_upload_size,
- filter_names
- )
- if not test_result[0]:
- return (False, test_result[1])
-
- create_session_request = {
- 'api': api_name,
- 'method': 'create_session',
- 'version': info['minVersion'],
- 'conn_info': creation_params,
- }
- list_session_request = {
+ request_params = {
'api': api_name,
- 'method': 'list_sess',
+ 'method': 'test_task_setting',
'version': info['minVersion'],
- 'connection_id': conn_id
+ 'conn_info': creation_params
}
- # Compound data
- compound_data = [create_session_request, list_session_request]
- # Send request and return response
- return (True, self.batch_request(compound_data, method='post'))
+
+ # Send request and get result
+ compound_data = [request_params]
+ result = self.batch_request(compound_data, method='post')
+
+ # Check if the request was successful
+ if result is not None and result['data']['has_fail'] == False:
+ # print('Task setting is valid')
+ return (True, result['data'])
+ else:
+ # print('Task setting is invalid')
+ return (False, 'Invalid task setting')
diff --git a/synology_api/core_active_backup.py b/synology_api/core_active_backup.py
index fe730dc5..21830afb 100644
--- a/synology_api/core_active_backup.py
+++ b/synology_api/core_active_backup.py
@@ -1,3 +1,4 @@
+"""Active Backup for Business API Implementation."""
from __future__ import annotations
from . import base_api
@@ -6,7 +7,8 @@
class ActiveBackupBusiness(base_api.BaseApi):
- """Active Backup for Business API Implementation.
+ """
+ Active Backup for Business API Implementation.
This class provides methods to interact with the Active Backup for Business package.
@@ -46,7 +48,31 @@ def __create_filter(
action_type: str = ""
):
"""
- Create a filter dictionary based on the provided parameters.
+ Create a filter dictionary for API requests based on provided parameters.
+
+ Parameters
+ ----------
+ log_level : str, optional
+ Log level to filter by. Possible values: 'error', 'warning', 'information'. Defaults to "" (all).
+ keyword : str, optional
+ Keyword to filter logs or tasks. Defaults to "" (no keyword).
+ from_date : int, optional
+ Start of the time window (epoch seconds). Defaults to 0 (no lower bound).
+ to_date : int, optional
+ End of the time window (epoch seconds). Defaults to 0 (no upper bound).
+ task_status : str, optional
+ Task status to filter by. Defaults to "" (all statuses).
+ result_status : str, optional
+ Result status to filter by. Possible values: 'success', 'partial_success', 'fail', 'cancel', 'no_backup'. Defaults to "" (all).
+ backup_type : str, optional
+ Backup type to filter by. Possible values: 'vm', 'pc', 'physical_server', 'file_server', 'nas'. Defaults to "" (all).
+ action_type : str, optional
+ Action type to filter by. Possible values: 'backup', 'dedup_data', 'restore', 'migrate', 'delete_target', 'delete_version', 'delete_host', 'relink', 'create_task'. Defaults to "" (all).
+
+ Returns
+ -------
+ dict
+ Dictionary containing filter parameters for API requests.
"""
log_level_map = {
'error': 0,
@@ -104,7 +130,8 @@ def __create_filter(
return filter
def get_settings(self) -> dict[str, object]:
- """Get the package settings including certificate information.
+ """
+ Get the package settings including certificate information.
Returns
-------
@@ -198,7 +225,8 @@ def get_settings(self) -> dict[str, object]:
return self.request_data(api_name, api_path, req_param)
def set_concurrent_devices(self, value: int) -> dict[str, object]:
- """Set the maximum number of concurrent devices that can be backed up at the same time.
+ """
+ Set the maximum number of concurrent devices that can be backed up at the same time.
Note: You can run multiple concurrent backup devices, but only up to the maximum limit you set—provided that your NAS's RAM usage does not exceed its limit.
@@ -239,7 +267,8 @@ def set_concurrent_devices(self, value: int) -> dict[str, object]:
return self.request_data(api_name, api_path, req_param)
def set_retention_policy_exec_time(self, hour: int, minute: int) -> dict[str, object]:
- """Set the time of day when the retention policy will be executed.
+ """
+ Set the time of day when the retention policy will be executed.
Parameters
----------
@@ -247,7 +276,7 @@ def set_retention_policy_exec_time(self, hour: int, minute: int) -> dict[str, ob
Hour in 24-hour format (0 - 23) when the retention policy will be executed.
minute : int
- Minute (0 - 59) when the retention policy will be executed
+ Minute (0 - 59) when the retention policy will be executed.
Returns
-------
@@ -283,7 +312,8 @@ def set_traffic_throttle(
traffic_control: dict[str, object] = {"enable": False, "bandwidth": 0},
ip_range: list[str] = ["", ""]
) -> dict[str, object]:
- """Set the global bandwidth control and IP range bandwidth control.
+ """
+ Set the global bandwidth control and IP range bandwidth control.
Note: Applies only to PC, Physical Server and NAS devices.
@@ -329,6 +359,21 @@ def set_traffic_throttle(
settings = []
def item(key: str, value: str) -> dict[str, str]:
+ """
+ Create a dictionary representing a setting item.
+
+ Parameters
+ ----------
+ key : str
+ The name of the setting.
+ value : str
+ The value of the setting.
+
+ Returns
+ -------
+ dict[str, str]
+ Dictionary with 'name' and 'value' keys.
+ """
return {'name': key, 'value': value}
if traffic_control['enable'] and traffic_control['bandwidth'] > -1:
@@ -357,7 +402,8 @@ def item(key: str, value: str) -> dict[str, str]:
return self.request_data(api_name, api_path, req_param)
def set_use_pkg_cert(self, use_package_cert: bool) -> dict[str, object]:
- """Set whether to use the self signed certificate provided by the package.
+ """
+ Set whether to use the self signed certificate provided by the package.
Parameters
----------
@@ -391,7 +437,8 @@ def set_use_pkg_cert(self, use_package_cert: bool) -> dict[str, object]:
return self.request_data(api_name, api_path, req_param)
def list_vm_hypervisor(self) -> dict[str, object]:
- """Get a list of all configured hypervisors present in ABB.
+ """
+ Get a list of all configured hypervisors present in ABB.
Returns
-------
@@ -416,7 +463,8 @@ def list_device_transfer_size(
time_start: int = int(time.time() - 86400),
time_end: int = int(time.time())
) -> dict[str, object]:
- """Get a list of all devices and their respective transfer size for the given time frame.
+ """
+ Get a list of all devices and their respective transfer size for the given time frame.
Parameters
----------
@@ -558,12 +606,13 @@ def list_tasks(
to_date: int = 0,
include_versions: bool = False,
) -> dict[str, object]:
- """Get information of one or all tasks.
+ """
+ Get information of one or all tasks.
Parameters
----------
task_id : int, optional
- Get information of specific task. Defaults to `-1` (all tasks)
+ Get information of specific task. Defaults to `-1` (all tasks).
backup_type : str, optional
Return only tasks matching the device type provided. Defaults to `""` (all device types).
@@ -575,7 +624,6 @@ def list_tasks(
- `"file_server"`
- `"nas"`
-
Note that values are different when returned by the API.
Return values mappings:
@@ -823,14 +871,19 @@ def list_logs(
offset: int = 0,
limit: int = 200,
) -> dict[str, object]:
- """Get logs from the package, tasks and devices. From `[Activities -> Log]` screen in ABB.
+ """
+ Get logs from the package, tasks and devices.
+
+ Notes
+ -----
+ From `[Activities -> Log]` screen in ABB.
For specific task logs `[Task List -> Details -> Log]`, specify `task_id` parameter.
Parameters
----------
task_id : int, optional
- Get logs of specific task. Defaults to `-1` (all logs - package/tasks/devices)
+ Get logs of specific task. Defaults to `-1` (all logs - package/tasks/devices).
log_level : str, optional
Type of logs to return. Defaults to `""` (all types).
@@ -840,7 +893,6 @@ def list_logs(
- `"warning"`
- `"information"`
-
Note that values are different when returned by the API.
Return values mappings:
@@ -933,12 +985,13 @@ def task_history(
offset: int = 0,
limit: int = 200
) -> dict[str, object]:
- """Return the history of task execution.
+ """
+ Return the history of task execution.
Parameters
----------
task_id : int, optional
- Get logs of specific task. Defaults to `-1` (all tasks)
+ Get logs of specific task. Defaults to `-1` (all tasks).
status : str, optional
Return only tasks matching the status provided. Defaults to `""` (all status).
@@ -949,7 +1002,6 @@ def task_history(
- `"fail"`
- `"cancel"`
-
Note that values are different when returned by the API.
Return values mappings:
@@ -958,6 +1010,9 @@ def task_history(
- `4` -> `fail`
- `5` -> `cancel`
+ keyword : str, optional
+ Keyword used to filter the results. Defaults to `""`.
+
backup_type : str, optional
Return only tasks matching the device type provided. Defaults to `""` (all device types).
@@ -968,7 +1023,6 @@ def task_history(
- `"file_server"`
- `"nas"`
-
Note that values are different when returned by the API.
Return values mappings:
@@ -992,7 +1046,6 @@ def task_history(
- `"relink"`
- `"create_task"`
-
Note that values are different when returned by the API.
Return values mappings:
@@ -1006,9 +1059,6 @@ def task_history(
- `2097152` -> `relink`
- `268435456` -> `create_task`
- keyword : str, optional
- Keyword used to filter the results. Defaults to `""`.
-
from_date : int, optional
Date from which the results will start. Format must be epoch date in seconds. Defaults to `0` (no time limit).
@@ -1093,75 +1143,80 @@ def result_details(
order_by: str = "log_level",
direction: str = "ASC"
) -> dict[str, object]:
- """Get details of a task result log. `result_id` can be retrieved from `list_logs()` function.
-
- Parameters
- ----------
- result_id : int
- ID of the result to get details from.
-
- limit : int, optional
- Amount of results to be returned. Defaults to `500`.
-
- order_by : str, optional
- What to order the results by. Defaults to `"log_level"`.
-
- Possible values:
- - `"log_level"`
- - `"log_time"`
-
- direction : str, optional
- Direction of the order. Defaults to `"ASC"`.
-
- Possible values:
- - `"ASC"`
- - `"DESC"`
-
- Returns
- -------
- dict[str, object]
- Dictionary containing a list of result details.
-
- Examples
- --------
- ```json
- {
- "data": {
- "count": 2,
- "result_detail_list": [
- {
- "error_code": 0,
- "log_level": 0,
- "log_time": 1741897456,
- "log_type": 6002,
- "other_params": {
- "fs_error": -65,
- "os_name": "smb",
- "path": "/D",
- "task_id": 8
- },
- "result_detail_id": 9526,
- "result_id": 592
+ """
+ Get details of a task result log.
+
+ Parameters
+ ----------
+ result_id : int
+ ID of the result to get details from.
+
+ limit : int, optional
+ Amount of results to be returned. Defaults to `500`.
+
+ order_by : str, optional
+ What to order the results by. Defaults to `"log_level"`.
+
+ Possible values:
+ - `"log_level"`
+ - `"log_time"`
+
+ direction : str, optional
+ Direction of the order. Defaults to `"ASC"`.
+
+ Possible values:
+ - `"ASC"`
+ - `"DESC"`
+
+ Returns
+ -------
+ dict[str, object]
+ Dictionary containing a list of result details.
+
+ Notes
+ -----
+ `result_id` can be retrieved from `list_logs()` function.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "count": 2,
+ "result_detail_list": [
+ {
+ "error_code": 0,
+ "log_level": 0,
+ "log_time": 1741897456,
+ "log_type": 6002,
+ "other_params": {
+ "fs_error": -65,
+ "os_name": "smb",
+ "path": "abc",
+ "task_id": 8
},
- {
- "error_code": 0,
- "log_level": 0,
- "log_time": 1741897498,
- "log_type": 1104,
- "other_params": {
- "os_name": "smb",
- "path": "",
- "task_id": 8,
- "task_name": "SMB LAPTOP"
- },
- "result_detail_id": 9527,
- "result_id": 592
- }
- ]
- },
- "success": true
- }
- ```
+ "result_detail_id": 9526,
+ "result_id": 592
+ },
+ {
+ "error_code": 0,
+ "log_level": 0,
+ "log_time": 1741897498,
+ "log_type": 1104,
+ "other_params": {
+ "os_name": "smb",
+ "path": "",
+ "task_id": 8,
+ "task_name": "SMB LAPTOP"
+ },
+ "result_detail_id": 9527,
+ "result_id": 592
+ }
+ ]
+ },
+ "success": true
+ }
+ ```
"""
api_name = 'SYNO.ActiveBackup.Log'
info = self.gen_list[api_name]
@@ -1179,7 +1234,8 @@ def result_details(
return self.request_data(api_name, api_path, req_param)
def list_storage(self) -> dict[str, object]:
- """Get a list of all storage devices present in ABB.
+ """
+ Get a list of all storage devices present in ABB.
Returns
-------
@@ -1249,7 +1305,8 @@ def list_storage(self) -> dict[str, object]:
return self.request_data(api_name, api_path, req_param)
def backup_task_run(self, task_ids: list[int]) -> dict[str, object]:
- """Trigger a backup event for the given tasks.
+ """
+ Trigger a backup event for the given tasks.
Parameters
----------
@@ -1285,7 +1342,8 @@ def backup_task_run(self, task_ids: list[int]) -> dict[str, object]:
return self.request_data(api_name, api_path, req_param)
def backup_task_cancel(self, task_ids: list[int]) -> dict[str, object]:
- """Cancel specified ongoing task.
+ """
+ Cancel specified ongoing task.
Parameters
----------
@@ -1320,7 +1378,8 @@ def backup_task_cancel(self, task_ids: list[int]) -> dict[str, object]:
return self.request_data(api_name, api_path, req_param)
def backup_task_remove(self, task_ids: list[int]) -> dict[str, object]:
- """Remove the given tasks from ABB.
+ """
+ Remove the given tasks from ABB.
Warning: This will remove the task and all its versions from the NAS. The backed up data will not be preserved after this operation.
@@ -1357,7 +1416,8 @@ def backup_task_remove(self, task_ids: list[int]) -> dict[str, object]:
return self.request_data(api_name, api_path, req_param)
def backup_task_delete_versions(self, task_id: int, versions_ids: list[int]) -> dict[str, object]:
- """Delete the specified versions from a task.
+ """
+ Delete the specified versions from a task.
Warning: This will remove the specified versions from the NAS. The corresponding versions data will not be preserved after this operation.
diff --git a/synology_api/core_backup.py b/synology_api/core_backup.py
index 81541804..7295e418 100644
--- a/synology_api/core_backup.py
+++ b/synology_api/core_backup.py
@@ -1,13 +1,25 @@
+"""Synology Hyper Backup API."""
from __future__ import annotations
from . import base_api
class Backup(base_api.BaseApi):
+ """Synology Hyper Backup API."""
def backup_repository_get(self, task_id: str) -> dict[str, object] | str:
- '''
- Get repository information for given task.
- '''
+ """
+ Get repository information for a given task.
+
+ Parameters
+ ----------
+ task_id : str
+ Task ID.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Repository information.
+ """
api_name = 'SYNO.Backup.Repository'
info = self.gen_list[api_name]
api_path = info['path']
@@ -17,9 +29,14 @@ def backup_repository_get(self, task_id: str) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def backup_repository_list(self) -> dict[str, object] | str:
- '''
+ """
Get a list of all present repositories in Hyper Backup.
- '''
+
+ Returns
+ -------
+ dict[str, object] or str
+ List of repositories.
+ """
api_name = 'SYNO.Backup.Repository'
info = self.gen_list[api_name]
api_path = info['path']
@@ -28,9 +45,14 @@ def backup_repository_list(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def backup_task_list(self) -> dict[str, object] | str:
- '''
+ """
Get current restoring information and a list of present tasks in Hyper Backup.
- '''
+
+ Returns
+ -------
+ dict[str, object] or str
+ List of tasks and restoring information.
+ """
api_name = 'SYNO.Backup.Task'
info = self.gen_list[api_name]
api_path = info['path']
@@ -39,9 +61,19 @@ def backup_task_list(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def backup_task_status(self, task_id: str) -> dict[str, object] | str:
- '''
- Get status and state of task.
- '''
+ """
+ Get status and state of a task.
+
+ Parameters
+ ----------
+ task_id : str
+ Task ID.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Status and state information.
+ """
api_name = 'SYNO.Backup.Task'
info = self.gen_list[api_name]
api_path = info['path']
@@ -51,9 +83,19 @@ def backup_task_status(self, task_id: str) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def backup_task_get(self, task_id: str) -> dict[str, object] | str:
- '''
+ """
Get detailed task information.
- '''
+
+ Parameters
+ ----------
+ task_id : str
+ Task ID.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Task information.
+ """
api_name = 'SYNO.Backup.Task'
info = self.gen_list[api_name]
api_path = info['path']
@@ -63,9 +105,19 @@ def backup_task_get(self, task_id: str) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def backup_task_result(self, task_id: str) -> dict[str, object] | str:
- '''
+ """
Get last result summary information of a task.
- '''
+
+ Parameters
+ ----------
+ task_id : str
+ Task ID.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Last result summary.
+ """
api_name = 'SYNO.Backup.Task'
info = self.gen_list[api_name]
api_path = info['path']
@@ -76,10 +128,21 @@ def backup_task_result(self, task_id: str) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def backup_task_run(self, task_id: str) -> dict[str, object] | str:
- '''
+ """
Run backup task for corresponding task_id.
+
If the task is not in backupable state, the API will return an error, usually 44xx.
- '''
+
+ Parameters
+ ----------
+ task_id : str
+ Task ID.
+
+ Returns
+ -------
+ dict[str, object] or str
+ API response.
+ """
api_name = 'SYNO.Backup.Task'
info = self.gen_list[api_name]
api_path = info['path']
@@ -91,10 +154,21 @@ def backup_task_run(self, task_id: str) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def backup_task_cancel(self, task_id: str) -> dict[str, object] | str:
- '''
+ """
Cancel currently running backup task.
+
If the task is not running, the API will return an error, usually 44xx.
- '''
+
+ Parameters
+ ----------
+ task_id : str
+ Task ID.
+
+ Returns
+ -------
+ dict[str, object] or str
+ API response.
+ """
api_name = 'SYNO.Backup.Task'
info = self.gen_list[api_name]
api_path = info['path']
@@ -107,10 +181,21 @@ def backup_task_cancel(self, task_id: str) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def backup_task_suspend(self, task_id: str) -> dict[str, object] | str:
- '''
+ """
Suspend currently running backup task.
+
If the task is not running or not yet suspendable, the API will return an error, usually 44xx.
- '''
+
+ Parameters
+ ----------
+ task_id : str
+ Task ID.
+
+ Returns
+ -------
+ dict[str, object] or str
+ API response.
+ """
api_name = 'SYNO.Backup.Task'
info = self.gen_list[api_name]
api_path = info['path']
@@ -123,10 +208,21 @@ def backup_task_suspend(self, task_id: str) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def backup_task_discard(self, task_id: str) -> dict[str, object] | str:
- '''
+ """
Discard currently suspended backup task.
+
If the task is not suspended, the request will not fail, and will fail to discard the task, leaving the task state as "Failed".
- '''
+
+ Parameters
+ ----------
+ task_id : str
+ Task ID.
+
+ Returns
+ -------
+ dict[str, object] or str
+ API response.
+ """
api_name = 'SYNO.Backup.Task'
info = self.gen_list[api_name]
api_path = info['path']
@@ -138,10 +234,21 @@ def backup_task_discard(self, task_id: str) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def backup_task_resume(self, task_id: str) -> dict[str, object] | str:
- '''
- Discard currently suspended backup task.
+ """
+ Resume currently suspended backup task.
+
If the task is not suspended, the request will not fail, and will fail to resume the task, leaving the task state as "Failed".
- '''
+
+ Parameters
+ ----------
+ task_id : str
+ Task ID.
+
+ Returns
+ -------
+ dict[str, object] or str
+ API response.
+ """
api_name = 'SYNO.Backup.Task'
info = self.gen_list[api_name]
api_path = info['path']
@@ -153,12 +260,23 @@ def backup_task_resume(self, task_id: str) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def backup_task_remove(self, task_id_list: str) -> dict[str, object] | str:
- '''
+ """
Remove one or more backup tasks.
+
Data in destination will not be removed. It is still possible to relink the task using the original .hbk file.
The API requires an array of tasks to remove, it should be passed as a string with the following format:
- `task_id_list = '[29]'` || `task_id_list = '[29,15]'`
- '''
+ `task_id_list = '[29]'` or `task_id_list = '[29,15]'`
+
+ Parameters
+ ----------
+ task_id_list : str
+ List of task IDs as a string.
+
+ Returns
+ -------
+ dict[str, object] or str
+ API response.
+ """
api_name = 'SYNO.Backup.Task'
info = self.gen_list[api_name]
api_path = info['path']
@@ -171,10 +289,21 @@ def backup_task_remove(self, task_id_list: str) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def integrity_check_run(self, task_id: str) -> dict[str, object] | str:
- '''
+ """
Run integrity check for backup task.
- If the task is running, the request will not fail, and will fail to perform the integrity check due to target is busy.
- '''
+
+ If the task is running, the request will not fail, and will fail to perform the integrity check due to target being busy.
+
+ Parameters
+ ----------
+ task_id : str
+ Task ID.
+
+ Returns
+ -------
+ dict[str, object] or str
+ API response.
+ """
api_name = 'SYNO.Backup.Target'
info = self.gen_list[api_name]
api_path = info['path']
@@ -189,10 +318,21 @@ def integrity_check_run(self, task_id: str) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def integrity_check_cancel(self, task_id: str) -> dict[str, object] | str:
- '''
+ """
Cancel currently running integrity check for backup task.
+
If integrity check is not running, the API will return an error, usually 44xx.
- '''
+
+ Parameters
+ ----------
+ task_id : str
+ Task ID.
+
+ Returns
+ -------
+ dict[str, object] or str
+ API response.
+ """
api_name = 'SYNO.Backup.Target'
info = self.gen_list[api_name]
api_path = info['path']
@@ -203,18 +343,38 @@ def integrity_check_cancel(self, task_id: str) -> dict[str, object] | str:
}
return self.request_data(api_name, api_path, req_param)
- def hb_logs_get(self,
- limit: int = 1000,
- offset: int = 0,
- filter_keyword: str = '',
- # filter_level: str = '', For some reason when passing filter_level, the API returns error 120.
- filter_date_from: int = 0,
- filter_date_to: int = 0) -> dict[str, object] | str:
- '''
+ def hb_logs_get(
+ self,
+ limit: int = 1000,
+ offset: int = 0,
+ filter_keyword: str = '',
+ # filter_level: str = '', For some reason when passing filter_level, the API returns error 120.
+ filter_date_from: int = 0,
+ filter_date_to: int = 0
+ ) -> dict[str, object] | str:
+ """
Get Hyper Backup UI logs.
`filter_date_from` and `filter_date_to` need to be passed in epoch format.
- '''
+
+ Parameters
+ ----------
+ limit : int, optional
+ Maximum number of logs to return (default is 1000).
+ offset : int, optional
+ Offset for pagination (default is 0).
+ filter_keyword : str, optional
+ Keyword to filter logs (default is '').
+ filter_date_from : int, optional
+ Start date in epoch format (default is 0).
+ filter_date_to : int, optional
+ End date in epoch format (default is 0).
+
+ Returns
+ -------
+ dict[str, object] or str
+ Logs information.
+ """
api_name = 'SYNO.SDS.Backup.Client.Common.Log'
info = self.gen_list[api_name]
api_path = info['path']
@@ -230,10 +390,15 @@ def hb_logs_get(self,
}
return self.request_data(api_name, api_path, req_param)
- def vault_target_list(self) -> dict[str, object]: # Should be working now
- '''
+ def vault_target_list(self) -> dict[str, object]:
+ """
List all available targets in Vault.
- '''
+
+ Returns
+ -------
+ dict[str, object]
+ List of available targets.
+ """
api_name = 'SYNO.Backup.Service.VersionBackup.Target'
info = self.gen_list[api_name]
api_path = info['path']
@@ -242,9 +407,14 @@ def vault_target_list(self) -> dict[str, object]: # Should be working now
return self.request_data(api_name, api_path, req_param)
def vault_concurrency_get(self) -> dict[str, object]:
- '''
- Get number of concurrent tasks allowed to run in HB Vault. Default value is 2.
- '''
+ """
+ Get number of concurrent tasks allowed to run in HB Vault.
+
+ Returns
+ -------
+ dict[str, object]
+ Number of concurrent tasks (default is 2).
+ """
api_name = 'SYNO.Backup.Service.VersionBackup.Config'
info = self.gen_list[api_name]
api_path = info['path']
@@ -255,9 +425,19 @@ def vault_concurrency_get(self) -> dict[str, object]:
return self.request_data(api_name, api_path, req_param)
def vault_concurrency_set(self, parallel_backup_limit: int = 2) -> dict[str, object]:
- '''
- Set number of concurrent tasks allowed to run in HB Vault. Default value is 2.
- '''
+ """
+ Set number of concurrent tasks allowed to run in HB Vault.
+
+ Parameters
+ ----------
+ parallel_backup_limit : int, optional
+ Number of concurrent tasks (default is 2).
+
+ Returns
+ -------
+ dict[str, object]
+ API response.
+ """
api_name = 'SYNO.Backup.Service.VersionBackup.Config'
info = self.gen_list[api_name]
api_path = info['path']
@@ -269,9 +449,19 @@ def vault_concurrency_set(self, parallel_backup_limit: int = 2) -> dict[str, obj
return self.request_data(api_name, api_path, req_param)
def vault_target_settings_get(self, target_id: int) -> dict[str, object]:
- '''
- Get settings of target.
- '''
+ """
+ Get settings of a target.
+
+ Parameters
+ ----------
+ target_id : int
+ Target ID.
+
+ Returns
+ -------
+ dict[str, object]
+ Target settings.
+ """
api_name = 'SYNO.Backup.Service.VersionBackup.Target'
info = self.gen_list[api_name]
api_path = info['path']
@@ -283,9 +473,19 @@ def vault_target_settings_get(self, target_id: int) -> dict[str, object]:
return self.request_data(api_name, api_path, req_param)
def vault_task_statistics_get(self, task_id: int) -> dict[str, object]:
- '''
- Get statistics for given task.
- '''
+ """
+ Get statistics for a given task.
+
+ Parameters
+ ----------
+ task_id : int
+ Task ID.
+
+ Returns
+ -------
+ dict[str, object]
+ Task statistics.
+ """
api_name = 'SYNO.SDS.Backup.Server.Common.Statistic'
info = self.gen_list[api_name]
api_path = info['path']
@@ -297,13 +497,29 @@ def vault_task_statistics_get(self, task_id: int) -> dict[str, object]:
}
return self.request_data(api_name, api_path, req_param)
- def vault_target_logs_get(self,
- target_id: int,
- limit: int = 1000,
- offset: int = 0) -> dict[str, object]:
- '''
- Get logs for given task.
- '''
+ def vault_target_logs_get(
+ self,
+ target_id: int,
+ limit: int = 1000,
+ offset: int = 0
+ ) -> dict[str, object]:
+ """
+ Get logs for a given target.
+
+ Parameters
+ ----------
+ target_id : int
+ Target ID.
+ limit : int, optional
+ Maximum number of logs to return (default is 1000).
+ offset : int, optional
+ Offset for pagination (default is 0).
+
+ Returns
+ -------
+ dict[str, object]
+ Logs information.
+ """
api_name = 'SYNO.SDS.Backup.Server.Common.Log'
info = self.gen_list[api_name]
api_path = info['path']
diff --git a/synology_api/core_certificate.py b/synology_api/core_certificate.py
index b648dc18..7f52dce4 100644
--- a/synology_api/core_certificate.py
+++ b/synology_api/core_certificate.py
@@ -1,3 +1,4 @@
+"""Synology DSM Core Certificate API Wrapper."""
from __future__ import annotations
from io import BytesIO
from typing import Optional
@@ -10,6 +11,34 @@
class Certificate(base_api.BaseApi):
+ """
+ Synology DSM Core Certificate API Wrapper.
+
+ This class provides methods to interact with the Synology DSM Core Certificate API,
+ allowing management of SSL certificates on a Synology NAS.
+
+ Parameters
+ ----------
+ ip_address : str
+ IP address or hostname of the Synology NAS.
+ port : str
+ Port number to connect to.
+ username : str
+ Username for authentication.
+ password : str
+ Password for authentication.
+ secure : bool, optional
+ Use HTTPS if True, HTTP if False (default is False).
+ cert_verify : bool, optional
+ Verify SSL certificates (default is False).
+ dsm_version : int, optional
+ DSM version (default is 7).
+ debug : bool, optional
+ Enable debug output (default is True).
+ otp_code : Optional[str], optional
+ One-time password for 2FA (default is None).
+ """
+
def __init__(self,
ip_address: str,
port: str,
@@ -21,6 +50,30 @@ def __init__(self,
debug: bool = True,
otp_code: Optional[str] = None
) -> None:
+ """
+ Initialize the Certificate API wrapper.
+
+ Parameters
+ ----------
+ ip_address : str
+ IP address or hostname of the Synology NAS.
+ port : str
+ Port number to connect to.
+ username : str
+ Username for authentication.
+ password : str
+ Password for authentication.
+ secure : bool, optional
+ Use HTTPS if True, HTTP if False (default is False).
+ cert_verify : bool, optional
+ Verify SSL certificates (default is False).
+ dsm_version : int, optional
+ DSM version (default is 7).
+ debug : bool, optional
+ Enable debug output (default is True).
+ otp_code : Optional[str], optional
+ One-time password for 2FA (default is None).
+ """
super(Certificate, self).__init__(ip_address, port, username, password, secure, cert_verify, dsm_version, debug,
otp_code)
self._debug: bool = debug
@@ -30,6 +83,23 @@ def _base_certificate_methods(self,
cert_id: Optional[str] = None,
ids: Optional[str | list[str]] = None
) -> str | dict[str, object]:
+ """
+ Internal method to perform basic certificate operations.
+
+ Parameters
+ ----------
+ method : str
+ The method to perform ('list', 'set', or 'delete').
+ cert_id : Optional[str], optional
+ Certificate ID for 'set' method (default is None).
+ ids : Optional[str or list[str]], optional
+ Certificate IDs for 'delete' method (default is None).
+
+ Returns
+ -------
+ str or dict[str, object]
+ API response or error message.
+ """
available_method = ['list', 'set', 'delete']
if method not in available_method:
# print error here
@@ -55,12 +125,46 @@ def _base_certificate_methods(self,
return self.request_data(api_name, api_path, req_param)
def list_cert(self) -> dict[str, object]:
+ """
+ List all certificates.
+
+ Returns
+ -------
+ dict[str, object]
+ List of certificates.
+ """
return self._base_certificate_methods('list')
def set_default_cert(self, cert_id: str) -> dict[str, object]:
+ """
+ Set a certificate as the default.
+
+ Parameters
+ ----------
+ cert_id : str
+ Certificate ID to set as default.
+
+ Returns
+ -------
+ dict[str, object]
+ API response.
+ """
return self._base_certificate_methods('set', cert_id)
def delete_certificate(self, ids: str | list[str]) -> dict[str, object]:
+ """
+ Delete one or more certificates.
+
+ Parameters
+ ----------
+ ids : str or list[str]
+ Certificate ID or list of IDs to delete.
+
+ Returns
+ -------
+ dict[str, object]
+ API response.
+ """
if isinstance(ids, str):
ids = [ids]
return self._base_certificate_methods('delete', ids=ids)
@@ -73,6 +177,29 @@ def upload_cert(self,
cert_id: Optional[str] = None,
desc: Optional[str] = None
) -> tuple[int, dict[str, object]]:
+ """
+ Upload a certificate to the Synology NAS.
+
+ Parameters
+ ----------
+ serv_key : str, optional
+ Path to the server key file (default is "server.key").
+ ser_cert : str, optional
+ Path to the server certificate file (default is "server.crt").
+ ca_cert : Optional[str], optional
+ Path to the CA certificate file (default is None).
+ set_as_default : bool, optional
+ Set as default certificate after upload (default is True).
+ cert_id : Optional[str], optional
+ Certificate ID to update (default is None).
+ desc : Optional[str], optional
+ Description for the certificate (default is None).
+
+ Returns
+ -------
+ tuple[int, dict[str, object]]
+ HTTP status code and API response.
+ """
api_name = 'SYNO.Core.Certificate'
info = self.session.app_api_list[api_name]
api_path = info['path']
@@ -114,6 +241,21 @@ def set_certificate_for_service(self,
cert_id: str,
service_name: str = "DSM Desktop Service",
) -> tuple[int, dict[str, object]]:
+ """
+ Set a certificate for a specific DSM service.
+
+ Parameters
+ ----------
+ cert_id : str
+ Certificate ID to assign.
+ service_name : str, optional
+ Name of the service (default is "DSM Desktop Service").
+
+ Returns
+ -------
+ tuple[int, dict[str, object]]
+ HTTP status code and API response.
+ """
api_name = 'SYNO.Core.Certificate.Service'
info = self.session.app_api_list[api_name]
api_path = info['path']
@@ -188,17 +330,18 @@ def set_certificate_for_service(self,
return r.status_code, r.json()
def export_cert(self, cert_id: str) -> Optional[BytesIO]:
- """Export a certificate from the Synology NAS.
+ """
+ Export a certificate from the Synology NAS.
- Parameters
- ----------
- cert_id : str
- The certificate ID to export. This can be found in the list_cert() method.
+ Parameters
+ ----------
+ cert_id : str
+ The certificate ID to export. This can be found in the list_cert() method.
- Returns
- -------
- Optional[BytesIO]
- A BytesIO object containing the certificate archive.
+ Returns
+ -------
+ Optional[BytesIO]
+ A BytesIO object containing the certificate archive, or None if export fails.
"""
api_name = "SYNO.Core.Certificate"
diff --git a/synology_api/core_group.py b/synology_api/core_group.py
index 0a0d13b4..952372fb 100644
--- a/synology_api/core_group.py
+++ b/synology_api/core_group.py
@@ -1,3 +1,11 @@
+"""
+Synology Core Group API wrapper.
+
+This module provides a Python interface for managing groups on Synology NAS devices,
+including group creation, deletion, membership management, quota and permission settings,
+and bandwidth control.
+"""
+
import json
from typing import Any
from . import base_api
@@ -5,83 +13,97 @@
class Group(base_api.BaseApi):
"""
- Core Group API implementation.
-
- Supported methods:
- - Getters:
- - Get all groups
- - Get group members
- - Get group shares permissions
- - Get group shares quota
- - Get group services speed limits
-
- - Setters:
- - Set group name/description
- - Set group share permissions
- - Set group share quotas
- - Set group service speed limit
-
- - Actions:
- - Create new group
- - Delete groups
- - Add users to a group
- - Remove users from a group
+ Core Group API implementation for Synology NAS.
+
+ This class provides methods to manage groups, including:
+ - Retrieving group information, members, permissions, quotas, and speed limits.
+ - Modifying group name, description, share permissions, quotas, and speed limits.
+ - Creating and deleting groups.
+ - Adding and removing users from groups.
+
+ Methods
+ -------
+ get_groups(offset=0, limit=-1, name_only=False)
+ Retrieve groups information.
+ get_users(group, in_group=True)
+ Retrieve users who are members or not members of a group.
+ get_speed_limits(group)
+ Retrieve bandwidth control settings for a group.
+ get_quota(group)
+ Retrieve quota settings for a group.
+ get_permissions(group)
+ Retrieve share permissions for a group.
+ set_group_info(group, new_name="", new_description="")
+ Change group name and/or description.
+ set_share_quota(group, share_quotas)
+ Set group quota for a given share.
+ set_share_permissions(group, permissions)
+ Set group permissions for a given share.
+ set_speed_limit(group, upload_limit, download_limit, protocol)
+ Set speed limit for a given share.
+ add_users(group, users)
+ Add users to a group.
+ remove_users(group, users)
+ Remove users from a group.
+ create(name, description="")
+ Create a new group.
+ delete(groups)
+ Delete specified groups.
"""
def get_groups(
self, offset: int = 0, limit: int = -1, name_only: bool = False
) -> dict[str, object]:
- """Retrieve groups information.
-
- Parameters
- ----------
- offset : int, optional
- The offset of the groups to retrieve. Defaults to `0`.
-
- limit : int, optional
- The maximum number of groups to retrieve. Defaults to `-1` (all groups).
-
- name_only : bool, optional
- If `True`, returns only group names. If `False`, returns full group information. Defaults to `False`.
-
- Returns
- -------
- dict[str, object]
- A dictionary containing the groups information.
-
- Examples
- --------
- ```json
- {
- "data": {
- "groups": [
- {
- "description": "System default admin group",
- "gid": 101,
- "name": "administrators"
- },
- {
- "description": "System default group for Web services",
- "gid": 1023,
- "name": "http"
- },
- {
- "description": "A test group",
- "gid": 65536,
- "name": "Test"
- },
- {
- "description": "System default group",
- "gid": 100,
- "name": "users"
- }
- ],
- "offset": 0,
- "total": 4
- },
- "success": true
- }
- ```
+ """
+ Retrieve groups information.
+
+ Parameters
+ ----------
+ offset : int, optional
+ The offset of the groups to retrieve. Defaults to 0.
+ limit : int, optional
+ The maximum number of groups to retrieve. Defaults to -1 (all groups).
+ name_only : bool, optional
+ If True, returns only group names. If False, returns full group information. Defaults to False.
+
+ Returns
+ -------
+ dict[str, object]
+ A dictionary containing the groups information.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "groups": [
+ {
+ "description": "System default admin group",
+ "gid": 101,
+ "name": "administrators"
+ },
+ {
+ "description": "System default group for Web services",
+ "gid": 1023,
+ "name": "http"
+ },
+ {
+ "description": "A test group",
+ "gid": 65536,
+ "name": "Test"
+ },
+ {
+ "description": "System default group",
+ "gid": 100,
+ "name": "users"
+ }
+ ],
+ "offset": 0,
+ "total": 4
+ },
+ "success": true
+ }
+ ```
"""
api_name = "SYNO.Core.Group"
@@ -106,53 +128,50 @@ def get_groups(
return self.request_data(api_name, api_path, req_param)
def get_users(self, group: str, in_group: bool = True) -> dict[str, object]:
- """Retrieve users members or not of a group.
-
- Parameters
- ----------
- group : str
- The group to list users from.
-
- in_group : bool, optional
- Defaults to `True`.
-
- If `True`, retrieves users who are members of the specified group.
-
- If `False`, retrieves users who are not members of the group.
-
- Returns
- -------
- dict[str, object]
- A dictionary containing the result of the request.
-
- Examples
- --------
- ```json
- {
- "data": {
- "offset": 0,
- "total": 3,
- "users": [
- {
- "description": "System default user",
- "name": "admin",
- "uid": 1024
- },
- {
- "description": "",
- "name": "customAdmin",
- "uid": 1026
- },
- {
- "description": "",
- "name": "test",
- "uid": 1032
- }
- ]
- },
- "success": true
- }
- ```
+ """
+ Retrieve users who are members or not members of a group.
+
+ Parameters
+ ----------
+ group : str
+ The group to list users from.
+ in_group : bool, optional
+ If True, retrieves users who are members of the specified group.
+ If False, retrieves users who are not members of the group. Defaults to True.
+
+ Returns
+ -------
+ dict[str, object]
+ A dictionary containing the result of the request.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "offset": 0,
+ "total": 3,
+ "users": [
+ {
+ "description": "System default user",
+ "name": "admin",
+ "uid": 1024
+ },
+ {
+ "description": "",
+ "name": "customAdmin",
+ "uid": 1026
+ },
+ {
+ "description": "",
+ "name": "test",
+ "uid": 1032
+ }
+ ]
+ },
+ "success": true
+ }
+ ```
"""
api_name = "SYNO.Core.Group.Member"
info = self.core_list[api_name]
@@ -167,40 +186,42 @@ def get_users(self, group: str, in_group: bool = True) -> dict[str, object]:
return self.request_data(api_name, api_path, req_param)
def get_speed_limits(self, group: str) -> dict[str, object]:
- """Retrieve bandwidth control settings for a given group.
-
- Parameters
- ----------
- group : str
- The group to retrieve settings for.
-
- Returns
- -------
- dict[str, object]
- A dictionary containing the result of the request.
-
- Examples
- --------
- ```json
- {
- "data": {
- "bandwidths": [
- {
- "download_limit_1": 0,
- "download_limit_2": 0,
- "name": "group_name",
- "owner_type": "local_group",
- "policy": "notexist",
- "protocol": "FTP",
- "protocol_ui": "FTP",
- "schedule_plan": "111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111",
- "upload_limit_1": 0,
- "upload_limit_2": 0
- },
- ]
- },
- "success": true
- }
+ """
+ Retrieve bandwidth control settings for a given group.
+
+ Parameters
+ ----------
+ group : str
+ The group to retrieve settings for.
+
+ Returns
+ -------
+ dict[str, object]
+ A dictionary containing the result of the request.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "bandwidths": [
+ {
+ "download_limit_1": 0,
+ "download_limit_2": 0,
+ "name": "group_name",
+ "owner_type": "local_group",
+ "policy": "notexist",
+ "protocol": "FTP",
+ "protocol_ui": "FTP",
+ "schedule_plan": "111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111",
+ "upload_limit_1": 0,
+ "upload_limit_2": 0
+ },
+ ]
+ },
+ "success": true
+ }
+ ```
"""
api_name = "SYNO.Core.BandwidthControl"
info = self.core_list[api_name]
@@ -214,42 +235,43 @@ def get_speed_limits(self, group: str) -> dict[str, object]:
return self.request_data(api_name, api_path, req_param)
def get_quota(self, group: str) -> dict[str, object]:
- """Retrieve quota settings for a given group.
-
- Parameters
- ----------
- group : str
- The group to retrieve quota settings for.
-
- Returns
- -------
- dict[str, object]
- A dictionary containing the result of the request.
-
- Examples
- --------
- ```json
- {
- "data": {
- "group_quota": [
- {
- "deduped": false,
- "quota_status": "v1",
- "shares": [
- {
- "description": "",
- "name": "ActiveBackupforBusiness",
- "quota": 1024
- }
- ],
- "support_share_quota": true,
- "volume": "/volume3"
- }
- ]
- },
- "success": true
- }
- ```
+ """
+ Retrieve quota settings for a given group.
+
+ Parameters
+ ----------
+ group : str
+ The group to retrieve quota settings for.
+
+ Returns
+ -------
+ dict[str, object]
+ A dictionary containing the result of the request.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "group_quota": [
+ {
+ "deduped": false,
+ "quota_status": "v1",
+ "shares": [
+ {
+ "description": "",
+ "name": "ActiveBackupforBusiness",
+ "quota": 1024
+ }
+ ],
+ "support_share_quota": true,
+ "volume": "/volume3"
+ }
+ ]
+ },
+ "success": true
+ }
+ ```
"""
api_name = "SYNO.Core.Quota"
info = self.core_list[api_name]
@@ -264,42 +286,43 @@ def get_quota(self, group: str) -> dict[str, object]:
return self.request_data(api_name, api_path, req_param)
def get_permissions(self, group: str) -> dict[str, object]:
- """Retrieve share permissions for a given group.
-
- Parameters
- ----------
- group : str
- The group to list permissions for.
-
- Returns
- -------
- dict[str, object]
- A dictionary containing the result of the request.
-
- Examples
- --------
- ```json
- {
- "data": {
- "shares": [
- {
- "is_aclmode": true,
- "is_custom": false,
- "is_deny": true,
- "is_mask": false,
- "is_readonly": false,
- "is_sync_share": false,
- "is_unite_permission": false,
- "is_writable": false,
- "name": "ActiveBackupforBusiness",
- "share_path": "/volume3/ActiveBackupforBusiness"
- }
- ],
- "total": 1
- },
- "success": true
- }
- ```
+ """
+ Retrieve share permissions for a given group.
+
+ Parameters
+ ----------
+ group : str
+ The group to list permissions for.
+
+ Returns
+ -------
+ dict[str, object]
+ A dictionary containing the result of the request.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "shares": [
+ {
+ "is_aclmode": true,
+ "is_custom": false,
+ "is_deny": true,
+ "is_mask": false,
+ "is_readonly": false,
+ "is_sync_share": false,
+ "is_unite_permission": false,
+ "is_writable": false,
+ "name": "ActiveBackupforBusiness",
+ "share_path": "/volume3/ActiveBackupforBusiness"
+ }
+ ],
+ "total": 1
+ },
+ "success": true
+ }
+ ```
"""
api_name = "SYNO.Core.Share.Permission"
info = self.core_list[api_name]
@@ -320,35 +343,34 @@ def get_permissions(self, group: str) -> dict[str, object]:
def set_group_info(
self, group: str, new_name: str = "", new_description: str = ""
) -> dict[str, object]:
- """Change group name and/or description.
-
- Parameters
- ----------
- group : str
- The group to set information for.
-
- new_name : str, optional
- The new name of the group. Defaults to current value.
-
- new_description : str, optional
- The new description of the group. Defaults to current value.
-
- Returns
- -------
- dict[str, object]
- A dictionary containing the result of the request.
-
- Examples
- --------
- ```json
- {
- "data": {
- "gid": 65536,
- "name": "Test_mod"
- },
- "success": true
- }
- ```
+ """
+ Change group name and/or description.
+
+ Parameters
+ ----------
+ group : str
+ The group to set information for.
+ new_name : str, optional
+ The new name of the group. Defaults to current value.
+ new_description : str, optional
+ The new description of the group. Defaults to current value.
+
+ Returns
+ -------
+ dict[str, object]
+ A dictionary containing the result of the request.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "gid": 65536,
+ "name": "Test_mod"
+ },
+ "success": true
+ }
+ ```
"""
current_groups_info = self.groups_info()
current_group = filter(
@@ -377,43 +399,29 @@ def set_group_info(
def set_share_quota(
self, group: str, share_quotas: list[dict[str, Any]]
) -> dict[str, object]:
- """Set group quota for a given share.
-
- Parameters
- ----------
- group : str
- The group to set the quota for.
-
- share_quotas (list[dict[str, Any]]):
- The quotas to set for the group.
-
- Example:
- ```python
- [
- {
- "share": "web",
- "quota": 1024, # in MB
- },
- {
- "share": "photo",
- "quota": 5120, # in MB
- }
- ]
- ```
-
- Returns
- -------
- dict[str, object]
- A dictionary containing the result of the request.
-
- Examples
- --------
- ```json
- {
- "data": {},
- "success": true
- }
- ```
+ """
+ Set group quota for a given share.
+
+ Parameters
+ ----------
+ group : str
+ The group to set the quota for.
+ share_quotas : list of dict
+ The quotas to set for the group.
+
+ Returns
+ -------
+ dict[str, object]
+ A dictionary containing the result of the request.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {},
+ "success": true
+ }
+ ```
"""
api_name = "SYNO.Core.Quota"
info = self.core_list[api_name]
@@ -430,46 +438,28 @@ def set_share_quota(
def set_share_permissions(
self, group: str, permissions: list[dict[str, object]]
) -> dict[str, object]:
- """Set group permissions for a given share.
-
- Parameters
- ----------
- group : str
- The group to set the permissions for.
-
- permissions : list[dict[str, object]]:
- The permissions to set for the group.
-
- Example:
- ```python
- [
- {
- "name": "web",
- "is_readonly": False,
- "is_writable": False,
- "is_deny": True
- },
- {
- "name": "ActiveBackupforBusiness",
- "is_readonly": False,
- "is_writable": True,
- "is_deny": False
- }
- ]
- ```
-
- Returns
- -------
- dict[str, object]
- A dictionary containing the result of the request.
-
- Examples
- --------
- ```json
- {
- "success": true
- }
- ```
+ """
+ Set group permissions for a given share.
+
+ Parameters
+ ----------
+ group : str
+ The group to set the permissions for.
+ permissions : list of dict
+ The permissions to set for the group.
+
+ Returns
+ -------
+ dict[str, object]
+ A dictionary containing the result of the request.
+
+ Examples
+ --------
+ ```json
+ {
+ "success": true
+ }
+ ```
"""
api_name = "SYNO.Core.Share.Permission"
info = self.core_list[api_name]
@@ -491,48 +481,40 @@ def set_speed_limit(
download_limit: int,
protocol: str,
) -> dict[str, object]:
- """Set speed limit for a given share.
-
- Info: Doesn't support **scheduled** speed limits, only on/off.
-
- Parameters
- ----------
- group : str
- The group to set the speed limit for.
-
- upload_limit : int
- The maximum upload speed in KB/s.
-
- download_limit : int
- The maximum download speed in KB/s.
-
- protocol : str
- The protocol to set the speed limit for.
-
- Possible values:
- - FileStation
- - WebDAV
- - FTP
- - NetworkBackup (Rsync)
- - CloudStation (Synology Drive)
-
- Returns
- -------
- dict[str, object]
- A dictionary containing the result of the request.
+ """
+ Set speed limit for a given share.
+
+ Parameters
+ ----------
+ group : str
+ The group to set the speed limit for.
+ upload_limit : int
+ The maximum upload speed in KB/s.
+ download_limit : int
+ The maximum download speed in KB/s.
+ protocol : str
+ The protocol to set the speed limit for. Possible values:
+ FileStation, WebDAV, FTP, NetworkBackup (Rsync), CloudStation (Synology Drive).
+
+ Returns
+ -------
+ dict[str, object]
+ A dictionary containing the result of the request.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "results": [
+ true
+ ]
+ },
+ "success": true
+ }
+ ```
- Examples
- --------
- ```json
- {
- "data": {
- "results": [
- true
- ]
- },
- "success": true
- }
- ```
+ Note: Doesn't support scheduled speed limits, only on/off.
"""
settings = [
{
@@ -557,29 +539,29 @@ def set_speed_limit(
return self.request_data(api_name, api_path, req_param)
def add_users(self, group: str, users: list[str]) -> dict[str, object]:
- """Add users to a group.
-
- Parameters
- ----------
- group : str
- The group to add users to.
-
- users : list[str]
- The users to add to the group.
-
- Returns
- -------
- dict[str, object]
- A dictionary containing the result of the request.
-
- Examples
- --------
- ```json
- {
- "data": {},
- "success": true
- }
- ```
+ """
+ Add users to a group.
+
+ Parameters
+ ----------
+ group : str
+ The group to add users to.
+ users : list of str
+ The users to add to the group.
+
+ Returns
+ -------
+ dict[str, object]
+ A dictionary containing the result of the request.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {},
+ "success": true
+ }
+ ```
"""
api_name = "SYNO.Core.Group.Member"
info = self.core_list[api_name]
@@ -595,29 +577,29 @@ def add_users(self, group: str, users: list[str]) -> dict[str, object]:
return self.request_data(api_name, api_path, req_param)
def remove_users(self, group: str, users: list[str]) -> dict[str, object]:
- """Remove users from a group.
-
- Parameters
- ----------
- group : str
- The group to remove users from.
-
- users : list[str]
- The users to remove from the group.
-
- Returns
- -------
- dict[str, object]
- A dictionary containing the result of the request.
-
- Examples
- --------
- ```json
- {
- "data": {},
- "success": true
- }
- ```
+ """
+ Remove users from a group.
+
+ Parameters
+ ----------
+ group : str
+ The group to remove users from.
+ users : list of str
+ The users to remove from the group.
+
+ Returns
+ -------
+ dict[str, object]
+ A dictionary containing the result of the request.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {},
+ "success": true
+ }
+ ```
"""
api_name = "SYNO.Core.Group.Member"
info = self.core_list[api_name]
@@ -633,32 +615,32 @@ def remove_users(self, group: str, users: list[str]) -> dict[str, object]:
return self.request_data(api_name, api_path, req_param)
def create(self, name: str, description: str = "") -> dict[str, object]:
- """Create group.
-
- Parameters
- ----------
- name : str
- Name to assign to the group.
-
- description : str, optional
- Description to assign to the group. Defaults to empty string.
-
- Returns
- -------
- dict[str, object]
- A dictionary containing the result of the request.
-
- Examples
- --------
- ```json
- {
- "data": {
- "gid": 65541,
- "name": "new_group"
- },
- "success": true
- }
- ```
+ """
+ Create a new group.
+
+ Parameters
+ ----------
+ name : str
+ Name to assign to the group.
+ description : str, optional
+ Description to assign to the group. Defaults to empty string.
+
+ Returns
+ -------
+ dict[str, object]
+ A dictionary containing the result of the request.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "gid": 65541,
+ "name": "new_group"
+ },
+ "success": true
+ }
+ ```
"""
api_name = "SYNO.Core.Group"
@@ -674,26 +656,27 @@ def create(self, name: str, description: str = "") -> dict[str, object]:
return self.request_data(api_name, api_path, req_param)
def delete(self, groups: list[str]) -> dict[str, object]:
- """Delete specified groups.
-
- Parameters
- ----------
- groups : list[str]
- The groups to delete.
-
- Returns
- -------
- dict[str, object]
- A dictionary containing the result of the request.
-
- Examples
- --------
- ```json
- {
- "data": {},
- "success": true
- }
- ```
+ """
+ Delete specified groups.
+
+ Parameters
+ ----------
+ groups : list of str
+ The groups to delete.
+
+ Returns
+ -------
+ dict[str, object]
+ A dictionary containing the result of the request.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {},
+ "success": true
+ }
+ ```
"""
api_name = "SYNO.Core.Group"
info = self.core_list[api_name]
diff --git a/synology_api/core_package.py b/synology_api/core_package.py
index 2582d7e1..acc2a47f 100644
--- a/synology_api/core_package.py
+++ b/synology_api/core_package.py
@@ -1,3 +1,10 @@
+"""
+Synology Core Package API wrapper.
+
+This module provides a Python interface for managing packages on Synology NAS devices,
+including listing, installing, upgrading, uninstalling, and configuring packages.
+"""
+
import json
from typing import List
from requests_toolbelt import MultipartEncoder, MultipartEncoderMonitor
@@ -10,46 +17,90 @@
class Package(base_api.BaseApi):
"""
- Core Package API implementation.
+ Core Package API implementation for Synology NAS.
+
+ This class provides methods to manage packages, including:
+ - Listing installed and installable packages.
+ - Installing, upgrading, and uninstalling packages.
+ - Uploading package files.
+ - Configuring package center settings.
+
+ Methods
+ -------
+ get_package(package_id, additional)
+ Get information about a package.
+ list_installed(additional, ignore_hidden)
+ List installed packages.
+ list_installable()
+ List installable packages.
+ get_package_center_settings()
+ Get package center settings.
+ set_package_center_settings(...)
+ Set package center settings.
+ get_package_center_infos()
+ Get package center information.
+ feasibility_check_install(packages)
+ Check if installation is possible.
+ download_package(url, package_id, checksum, filesize)
+ Start download of a package.
+ get_dowload_package_status(task_id)
+ Get current download status of a package.
+ check_installation_from_download(task_id)
+ Get info about downloaded package file.
+ upload_package_file(file_path, verify, progress_bar, additional)
+ Upload a file for installing a package.
+ get_default_install_volume()
+ Get default install volume for packages.
+ check_installation(...)
+ Check installation of a package.
+ upgrade_package(...)
+ Upgrade an existing package.
+ install_package(...)
+ Install a package that is already downloaded.
+ uninstall_package(package_id)
+ Uninstall a package.
+ easy_install(package_id, volume_path, install_dependencies)
+ Execute an easy installation process of a package.
"""
def get_package(self, package_id: str, additional: List[str] = []) -> dict:
- """Get infos of a package
-
- Parameters
- ----------
- package_id : str
- Package ID
- additional : List[str], optional
- Additional field to retrieves. Defaults to `[]`
- All filed known are:
- `["status","dsm_apps"]`
-
- Returns
- -------
- dict
- Informations about the package
-
- Examples
- --------
- ```json
- {
- "data": {
- "additional": {
- "dsm_apps": " com.plexapp.plexmediaserver",
- "status": "running",
- "status_code": 0,
- "status_description": "retrieve from status script",
- "status_origin": "running"
- },
- "id": "PlexMediaServer",
- "name": "Plex Media Server",
- "timestamp": 1739228562839,
- "version": "1.41.3.9314-72009314"
+ """
+ Get infos of a package.
+
+ Parameters
+ ----------
+ package_id : str
+ Package ID.
+ additional : List[str], optional
+ Additional field to retrieves. Defaults to `[]`.
+ All filed known are:
+ `["status","dsm_apps"]`.
+
+ Returns
+ -------
+ dict
+ Informations about the package.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "additional": {
+ "dsm_apps": " com.plexapp.plexmediaserver",
+ "status": "running",
+ "status_code": 0,
+ "status_description": "retrieve from status script",
+ "status_origin": "running"
},
- "success": true
- }
- ```
+ "id": "PlexMediaServer",
+ "name": "Plex Media Server",
+ "timestamp": 1739228562839,
+ "version": "1.41.3.9314-72009314"
+ },
+ "success": true
+ }
+ ```
"""
api_name = 'SYNO.Core.Package'
info = self.core_list[api_name]
@@ -63,45 +114,47 @@ def get_package(self, package_id: str, additional: List[str] = []) -> dict:
return self.request_data(api_name, api_path, req_param)
def list_installed(self, additional: list = [], ignore_hidden: bool = False) -> dict:
- """List installed packages
- Parameters
- ----------
- additional : list[str], optional
- Additional fields to retrieve. Defaults to `[]`.
- All fields known are:
- `["description", "description_enu", "dependent_packages", "beta", "distributor", "distributor_url",
- "maintainer", "maintainer_url", "dsm_apps", "dsm_app_page", "dsm_app_launch_name","report_beta_url",
- "support_center", "startable", "installed_info", "support_url", "is_uninstall_pages","install_type",
- "autoupdate", "silent_upgrade", "installing_progress", "ctl_uninstall", "updated_at", "status",
- "url","available_operation"]`.
- ignore_hidden : bool
- TODO: Write description
-
- Returns
- -------
- dict
- List of packages installed on the NAS
-
- Examples
- --------
- ```json
- {
- "data": {
- "packages": [
- {
- "additional": {
- "install_type": ""
- },
- "id": "ActiveBackup-Office365",
- "name": "Active Backup for Microsoft 365",
- "timestamp": 1738880043640,
- "version": "2.5.5-14034"
- }
- ]
- },
- "success": true
+ """
+ List installed packages.
+
+ Parameters
+ ----------
+ additional : list[str], optional
+ Additional fields to retrieve. Defaults to `[]`.
+ All fields known are:
+ `["description", "description_enu", "dependent_packages", "beta", "distributor", "distributor_url",
+ "maintainer", "maintainer_url", "dsm_apps", "dsm_app_page", "dsm_app_launch_name","report_beta_url",
+ "support_center", "startable", "installed_info", "support_url", "is_uninstall_pages","install_type",
+ "autoupdate", "silent_upgrade", "installing_progress", "ctl_uninstall", "updated_at", "status",
+ "url","available_operation"]`.
+ ignore_hidden : bool
+ Whether to ignore hidden packages.
+
+ Returns
+ -------
+ dict
+ List of packages installed on the NAS.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "packages": [
+ {
+ "additional": {
+ "install_type": ""
+ },
+ "id": "ActiveBackup-Office365",
+ "name": "Active Backup for Microsoft 365",
+ "timestamp": 1738880043640,
+ "version": "2.5.5-14034"
+ }
}
- ```
+ },
+ "success": true
+ }
+ ```
"""
api_name = 'SYNO.Core.Package'
info = self.core_list[api_name]
@@ -116,25 +169,27 @@ def list_installed(self, additional: list = [], ignore_hidden: bool = False) ->
return self.request_data(api_name, api_path, req_param)
def list_installable(self) -> dict:
- """List installable packages
- Returns
- -------
- dict
- List of beta_package, categories and packages available
-
- Examples
- --------
- ```json
- {
- "data": {
- "banners": [],
- "beta_packages": [...],
- "categories": [...],
- "packages": [...]
- },
- "success": true
- }
- ```
+ """
+ List installable packages.
+
+ Returns
+ -------
+ dict
+ List of beta_package, categories and packages available.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "banners": [],
+ "beta_packages": [...],
+ "categories": [...],
+ "packages": [...]
+ },
+ "success": true
+ }
+ ```
"""
api_name = 'SYNO.Core.Package.Server'
info = self.core_list[api_name]
@@ -149,51 +204,53 @@ def list_installable(self) -> dict:
return self.request_data(api_name, api_path, req_param)
def get_package_center_settings(self) -> dict:
- """Get package center settings
- Returns
- -------
- dict
- List settings of the Package center
-
- Examples
- --------
- ```json
- {
- "data": {
- "autoupdateall": false,
- "autoupdateimportant": true,
- "default_vol": "/volume1",
- "enable_autoupdate": true,
- "enable_dsm": true,
- "enable_email": false,
- "mailset": true,
- "trust_level": 0,
- "update_channel": true,
- "volume_count": 2,
- "volume_list": [
- {
- "desc": "",
- "display": "Volume 1 (Available capacity: 184.72 GB )",
- "mount_point": "/volume1",
- "size_free": "198336327680",
- "size_total": "206158430208",
- "vol_desc": "Apps",
- "volume_features": []
- },
- {
- "desc": "",
- "display": "Volume 2 (Available capacity: 2391.14 GB )",
- "mount_point": "/volume2",
- "size_free": "2567467421696",
- "size_total": "3623234412544",
- "vol_desc": "Stockage",
- "volume_features": []
- }
- ]
- },
- "success": true
- }
- ```
+ """
+ Get package center settings.
+
+ Returns
+ -------
+ dict
+ List settings of the Package center.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "autoupdateall": false,
+ "autoupdateimportant": true,
+ "default_vol": "/volume1",
+ "enable_autoupdate": true,
+ "enable_dsm": true,
+ "enable_email": false,
+ "mailset": true,
+ "trust_level": 0,
+ "update_channel": true,
+ "volume_count": 2,
+ "volume_list": [
+ {
+ "desc": "",
+ "display": "Volume 1 (Available capacity: 184.72 GB )",
+ "mount_point": "/volume1",
+ "size_free": "198336327680",
+ "size_total": "206158430208",
+ "vol_desc": "Apps",
+ "volume_features": []
+ },
+ {
+ "desc": "",
+ "display": "Volume 2 (Available capacity: 2391.14 GB )",
+ "mount_point": "/volume2",
+ "size_free": "2567467421696",
+ "size_total": "3623234412544",
+ "vol_desc": "Stockage",
+ "volume_features": []
+ }
+ ]
+ },
+ "success": true
+ }
+ ```
"""
api_name = 'SYNO.Core.Package.Setting'
info = self.core_list[api_name]
@@ -210,48 +267,44 @@ def set_package_center_settings(self,
autoupdateall: bool, autoupdateimportant: bool,
default_vol: str, update_channel: str
) -> dict:
- """Set settings of the package center
- Parameters
- ----------
- enable_email : bool
- Enable email notification
-
- enable_dsm : bool
- Enable desktop notification
-
- enable_autoupdate: bool
- Update packages automatically
-
- autoupdateall : bool
- Auto update all packages
-
- autoupdateimportant : bool
- Auto update "important" packages
-
- default_vol : str
- Default volume for installation, all your volumes or `"no_default_vol" = Always ask me`
-
- udpate_channel : str
- "stable" => Disable beta packages
- "beta" => Enable beta packages
-
- Returns
- -------
- dict
- Return some settings
-
- Examples
- --------
- ```json
- {
- "data": {
- "enable_dsm": true,
- "enable_email": false,
- "update_channel": "stable"
- },
- "success": true
- }
- ```
+ """
+ Set settings of the package center.
+
+ Parameters
+ ----------
+ enable_email : bool
+ Enable email notification.
+ enable_dsm : bool
+ Enable desktop notification.
+ enable_autoupdate : bool
+ Update packages automatically.
+ autoupdateall : bool
+ Auto update all packages.
+ autoupdateimportant : bool
+ Auto update "important" packages.
+ default_vol : str
+ Default volume for installation, all your volumes or `"no_default_vol" = Always ask me`.
+ update_channel : str
+ "stable" => Disable beta packages.
+ "beta" => Enable beta packages.
+
+ Returns
+ -------
+ dict
+ Return some settings.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "enable_dsm": true,
+ "enable_email": false,
+ "update_channel": "stable"
+ },
+ "success": true
+ }
+ ```
"""
api_name = 'SYNO.Core.Package.Setting'
@@ -272,45 +325,47 @@ def set_package_center_settings(self,
return self.request_data(api_name, api_path, req_param)
def get_package_center_infos(self) -> dict:
- """Get package center informations
- Returns
- -------
- dict
- List of configs
-
- Examples
- --------
- ```json
- {
- "data": {
- "config": {
- "auth_key": "------------------------------",
- "blBetaChannel": false,
- "blOtherServer": false,
- "def_void": "",
- "ds_build": "72806",
- "ds_major": "7",
- "ds_minor": "2",
- "ds_timezone": "Amsterdam",
- "ds_unique": "synology_r1000_723+",
- "myPayBaseURL": "https://payment.synology.com",
- "myds_id": "7886858",
- "serial": "2260TPR7X30E6",
- "success": true
- },
- "prerelease": {
- "agreed": true,
- "success": true
- },
- "term": {
- "agreed_term_version": "0003",
- "curr_term_version": "0003",
- "success": true
- }
+ """
+ Get package center informations.
+
+ Returns
+ -------
+ dict
+ List of configs.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "config": {
+ "auth_key": "------------------------------",
+ "blBetaChannel": false,
+ "blOtherServer": false,
+ "def_void": "",
+ "ds_build": "72806",
+ "ds_major": "7",
+ "ds_minor": "2",
+ "ds_timezone": "Amsterdam",
+ "ds_unique": "synology_r1000_723+",
+ "myPayBaseURL": "https://payment.synology.com",
+ "myds_id": "7886858",
+ "serial": "2260TPR7X30E6",
+ "success": true
},
- "success": true
- }
- ```
+ "prerelease": {
+ "agreed": true,
+ "success": true
+ },
+ "term": {
+ "agreed_term_version": "0003",
+ "curr_term_version": "0003",
+ "success": true
+ }
+ },
+ "success": true
+ }
+ ```
"""
api_name = 'SYNO.Core.Package.Info'
info = self.core_list[api_name]
@@ -322,28 +377,29 @@ def get_package_center_infos(self) -> dict:
return self.request_data(api_name, api_path, req_param)
def feasibility_check_install(self, packages: List[str]) -> dict:
- """Check if installation is possible
-
- Parameters
- ----------
- packages : List[str]
- List of package IDs to check for feasibility
-
- Returns
- -------
- dict
- _description_
-
- Examples
- --------
- ```json
- {
- "data": {
- "template": "data"
- },
- "success": true
- }
- ```
+ """
+ Check if installation is possible.
+
+ Parameters
+ ----------
+ packages : List[str]
+ List of package IDs to check for feasibility.
+
+ Returns
+ -------
+ dict
+ Feasibility check result.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "template": "data"
+ },
+ "success": true
+ }
+ ```
"""
api_name = 'SYNO.Core.Package.Setting'
info = self.core_list[api_name]
@@ -358,35 +414,36 @@ def feasibility_check_install(self, packages: List[str]) -> dict:
return self.request_data(api_name, api_path, req_param)
def download_package(self, url: str, package_id: str, checksum: str, filesize: str) -> dict:
- """Start download of the package, return a taskId for check status
-
- Parameters
- ----------
- url : str
- Url that can be retrieve from package info using `get_installable` function, in the `link` field
- package_id : str
- Package ID that can be retrieve from package info using `get_installable` function, in the `id` field
- checksum : str
- Checksum that can be retrieve from package info using `get_installable` function, in the `md5` field
- filesize : str
- Filesize that can be retrieve from package info using `get_installable` function, in the `size` field
-
- Returns
- -------
- dict
- Retreive first progress of the download and the taskid used to check download status with `get_dowload_package_status` function
-
- Examples
- --------
- ```json
- {
- "data": {
- "progress": 1.0000000000000001e-05,
- "taskid": "@SYNOPKG_DOWNLOAD_DhcpServer"
- },
- "success": true
- }
- ```
+ """
+ Start download of the package, return a taskId for check status.
+
+ Parameters
+ ----------
+ url : str
+ Url that can be retrieve from package info using `get_installable` function, in the `link` field.
+ package_id : str
+ Package ID that can be retrieve from package info using `get_installable` function, in the `id` field.
+ checksum : str
+ Checksum that can be retrieve from package info using `get_installable` function, in the `md5` field.
+ filesize : str
+ Filesize that can be retrieve from package info using `get_installable` function, in the `size` field.
+
+ Returns
+ -------
+ dict
+ Retrieve first progress of the download and the taskid used to check download status with `get_dowload_package_status` function.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "progress": 1.0000000000000001e-05,
+ "taskid": "@SYNOPKG_DOWNLOAD_DhcpServer"
+ },
+ "success": true
+ }
+ ```
"""
api_name = 'SYNO.Core.Package.Installation'
info = self.core_list[api_name]
@@ -405,40 +462,41 @@ def download_package(self, url: str, package_id: str, checksum: str, filesize: s
return self.request_data(api_name, api_path, req_param)
def get_dowload_package_status(self, task_id: str) -> dict:
- """Get current download status of the package
-
- Parameters
- ----------
- task_id : str
- task ID retrieve from response of `download_package` function
-
- Returns
- -------
- dict
- Retrieve informations about the download, important info is the `progress` field
-
- Examples
- --------
- ```json
- {
- "data": {
- "beta": false,
- "blqinst": false,
- "finished": false,
- "id": "DhcpServer",
- "installing": false,
- "name": "DhcpServer",
- "pid": 27844,
- "progress": 1.0000000000000001e-05,
- "remote_link": "https://global.synologydownload.com/download/Package/spk/DhcpServer/1.0.2-0046/DhcpServer-x86_64-1.0.2-0046.spk",
- "size": "1378697",
- "success": true,
- "taskid": "@SYNOPKG_DOWNLOAD_DhcpServer",
- "tmp_folder": "/volume1/@tmp/synopkg/download.esnnkb"
- },
- "success": true
- }
- ```
+ """
+ Get current download status of the package.
+
+ Parameters
+ ----------
+ task_id : str
+ Task ID retrieved from response of `download_package` function.
+
+ Returns
+ -------
+ dict
+ Retrieve informations about the download, important info is the `progress` field.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "beta": false,
+ "blqinst": false,
+ "finished": false,
+ "id": "DhcpServer",
+ "installing": false,
+ "name": "DhcpServer",
+ "pid": 27844,
+ "progress": 1.0000000000000001e-05,
+ "remote_link": "https://global.synologydownload.com/download/Package/spk/DhcpServer/1.0.2-0046/DhcpServer-x86_64-1.0.2-0046.spk",
+ "size": "1378697",
+ "success": true,
+ "taskid": "@SYNOPKG_DOWNLOAD_DhcpServer",
+ "tmp_folder": "/volume1/@tmp/synopkg/download.esnnkb"
+ },
+ "success": true
+ }
+ ```
"""
api_name = 'SYNO.Core.Package.Installation'
info = self.core_list[api_name]
@@ -451,43 +509,44 @@ def get_dowload_package_status(self, task_id: str) -> dict:
return self.request_data(api_name, api_path, req_param)
def check_installation_from_download(self, task_id: str) -> dict:
- """Get info about downloaded package file, response field is used for `check_installation` and `install_package` function
-
- Parameters
- ----------
- task_id : str
- task ID retrieve from response of `download_package` function
-
- Returns
- -------
- dict
- Retrieve information about downloaded package installation file, response field is used for `check_installation` and `install_package` function
-
- Examples
- --------
- ```json
- {
- "data": {
- "description": "DHCP Server turns your DiskStation into a DHCP server within LAN to assign dynamic IP addresses and manage DHCP clients.",
- "distributor": "",
- "dsm_apps": "SYNO.SDS.DHCP.Instance",
- "filename": "/volume1/@tmp/synopkg/download.esnnkb/@SYNOPKG_DOWNLOAD_DhcpServer",
- "id": "DhcpServer",
- "install_on_cold_storage": false,
- "install_reboot": false,
- "install_type": "system",
- "maintainer": "Synology Inc.",
- "name": "DHCP Server",
- "startable": true,
- "status": "non_installed",
- "status_code": 255,
- "status_description": "failed to locate given package",
- "status_origin": "non_installed",
- "version": "1.0.2-0046"
- },
- "success": true
- }
- ```
+ """
+ Get info about downloaded package file, response field is used for `check_installation` and `install_package` function.
+
+ Parameters
+ ----------
+ task_id : str
+ Task ID retrieved from response of `download_package` function.
+
+ Returns
+ -------
+ dict
+ Retrieve information about downloaded package installation file, response field is used for `check_installation` and `install_package` function.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "description": "DHCP Server turns your DiskStation into a DHCP server within LAN to assign dynamic IP addresses and manage DHCP clients.",
+ "distributor": "",
+ "dsm_apps": "SYNO.SDS.DHCP.Instance",
+ "filename": "/volume1/@tmp/synopkg/download.esnnkb/@SYNOPKG_DOWNLOAD_DhcpServer",
+ "id": "DhcpServer",
+ "install_on_cold_storage": false,
+ "install_reboot": false,
+ "install_type": "system",
+ "maintainer": "Synology Inc.",
+ "name": "DHCP Server",
+ "startable": true,
+ "status": "non_installed",
+ "status_code": 255,
+ "status_description": "failed to locate given package",
+ "status_origin": "non_installed",
+ "version": "1.0.2-0046"
+ },
+ "success": true
+ }
+ ```
"""
api_name = 'SYNO.Core.Package.Installation.Download'
info = self.core_list[api_name]
@@ -500,57 +559,58 @@ def check_installation_from_download(self, task_id: str) -> dict:
return self.request_data(api_name, api_path, req_param)
def upload_package_file(self, file_path: str, verify: bool = False, progress_bar: bool = True, additional: list = []) -> dict:
- """Upload a file for install a package
-
- Parameters
- ----------
- file_path : str
- File path
- verify : bool, optional
- Use https. Defaults to `False`
- progress_bar : bool, optional
- Enable progress bar in the terminal. Defaults to `True`
- additional : list, optional
- Additional field to retrieves. Defaults to `[]`
- All fields know are:
- `["description","maintainer","distributor","startable","dsm_apps","status","install_reboot",
- "install_type","install_on_cold_storage","break_pkgs","replace_pkgs"]`.
-
- Returns
- -------
- dict
- Informations about the uploaded file for installation
-
- Examples
- --------
- ```json
- {
- "data": {
- "additional": {
- "break_pkgs": null,
- "description": "Plex organizes all of your personal media so you can easily access and enjoy it.",
- "distributor": "",
- "dsm_apps": " com.plexapp.plexmediaserver",
- "install_on_cold_storage": false,
- "install_reboot": false,
- "install_type": "",
- "maintainer": "Plex Inc",
- "replace_pkgs": { "Plex Media Server": "" },
- "startable": true,
- "status": "running",
- "status_code": 0,
- "status_description": "retrieve from status script",
- "status_origin": "running"
- },
- "codesign_error": 4532,
- "id": "PlexMediaServer",
- "name": "Plex Media Server",
- "task_id": "@SYNOPKG_UPLOAD_17392283048566DD3",
- "version": "1.41.3.9314-72009314"
+ """
+ Upload a file for install a package.
+
+ Parameters
+ ----------
+ file_path : str
+ File path.
+ verify : bool, optional
+ Use https. Defaults to `False`.
+ progress_bar : bool, optional
+ Enable progress bar in the terminal. Defaults to `True`.
+ additional : list, optional
+ Additional field to retrieves. Defaults to `[]`.
+ All fields know are:
+ `["description","maintainer","distributor","startable","dsm_apps","status","install_reboot",
+ "install_type","install_on_cold_storage","break_pkgs","replace_pkgs"]`.
+
+ Returns
+ -------
+ dict
+ Informations about the uploaded file for installation.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "additional": {
+ "break_pkgs": null,
+ "description": "Plex organizes all of your personal media so you can easily access and enjoy it.",
+ "distributor": "",
+ "dsm_apps": " com.plexapp.plexmediaserver",
+ "install_on_cold_storage": false,
+ "install_reboot": false,
+ "install_type": "",
+ "maintainer": "Plex Inc",
+ "replace_pkgs": { "Plex Media Server": "" },
+ "startable": true,
+ "status": "running",
+ "status_code": 0,
+ "status_description": "retrieve from status script",
+ "status_origin": "running"
},
- "success": true
- }
- ```
+ "codesign_error": 4532,
+ "id": "PlexMediaServer",
+ "name": "Plex Media Server",
+ "task_id": "@SYNOPKG_UPLOAD_17392283048566DD3",
+ "version": "1.41.3.9314-72009314"
+ },
+ "success": true
+ }
+ ```
"""
api_name = 'SYNO.Core.Package.Installation'
info = self.core_list[api_name]
@@ -604,23 +664,24 @@ def upload_package_file(self, file_path: str, verify: bool = False, progress_bar
return r.json()
def get_default_install_volume(self) -> dict:
- """Get default install volume for package
-
- Returns
- -------
- dict
- Return default volume, if default volume is set to `Always ask me` it return error 4501
-
- Examples
- --------
- ```json
- {
- "data": {
- "default_vol": "/volume1"
- },
- "success": true
- }
- ```
+ """
+ Get default install volume for package.
+
+ Returns
+ -------
+ dict
+ Return default volume, if default volume is set to `Always ask me` it return error 4501.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "default_vol": "/volume1"
+ },
+ "success": true
+ }
+ ```
"""
api_name = 'SYNO.Core.Package.Setting.Volume'
info = self.core_list[api_name]
@@ -636,58 +697,59 @@ def check_installation(self,
package_id: str, install_type: str = "", install_on_cold_storage: bool = False,
blCheckDep: bool = False, replacepkgs: dict = {}
) -> dict:
- """Check installation of the package on the default volume
-
- Parameters
- ----------
- package_id : str
- Id of the package to install
- install_type : str, optionnal
- Installation type, Defaults to `""`. TODO: Add description and possible types
- install_on_cold_storage : bool, optional
- Defaults to `False`. TODO: Add description
- blCheckDep : bool, optional
- Defaults to `False`. TODO: Add description
- replacepkgs : dict, optional
- Defaults to `{}`. TODO: Add description
-
- Returns
- -------
- dict
- List of usefull informations about volumes
-
- Examples
- --------
- ```json
- {
- "data": {
- "is_occupied": false,
- "volume_count": 2,
- "volume_list": [
- {
- "desc": "",
- "display": "Volume 1 (Available capacity: 184.52 GB )",
- "mount_point": "/volume1",
- "size_free": "198126022656",
- "size_total": "206158430208",
- "vol_desc": "vol1",
- "volume_features": []
- },
- {
- "desc": "",
- "display": "Volume 2 (Available capacity: 2391.16 GB )",
- "mount_point": "/volume2",
- "size_free": "2567484923904",
- "size_total": "3623234412544",
- "vol_desc": "vol2",
- "volume_features": []
- }
- ],
- "volume_path": "/volume1"
- },
- "success": true,
- }
- ```
+ """
+ Check installation of the package on the default volume.
+
+ Parameters
+ ----------
+ package_id : str
+ Id of the package to install.
+ install_type : str, optionnal
+ Installation type, Defaults to `""`. TODO: Add description and possible types.
+ install_on_cold_storage : bool, optional
+ Defaults to `False`. TODO: Add description.
+ blCheckDep : bool, optional
+ Defaults to `False`. TODO: Add description.
+ replacepkgs : dict, optional
+ Defaults to `{}`. TODO: Add description.
+
+ Returns
+ -------
+ dict
+ List of usefull informations about volumes.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "is_occupied": false,
+ "volume_count": 2,
+ "volume_list": [
+ {
+ "desc": "",
+ "display": "Volume 1 (Available capacity: 184.52 GB )",
+ "mount_point": "/volume1",
+ "size_free": "198126022656",
+ "size_total": "206158430208",
+ "vol_desc": "vol1",
+ "volume_features": []
+ },
+ {
+ "desc": "",
+ "display": "Volume 2 (Available capacity: 2391.16 GB )",
+ "mount_point": "/volume2",
+ "size_free": "2567484923904",
+ "size_total": "3623234412544",
+ "vol_desc": "vol2",
+ "volume_features": []
+ }
+ ],
+ "volume_path": "/volume1"
+ },
+ "success": true,
+ }
+ ```
"""
api_name = 'SYNO.Core.Package.Installation'
@@ -707,50 +769,39 @@ def check_installation(self,
return self.request_data(api_name, api_path, req_param)
def upgrade_package(self, task_id: str, check_codesign: bool = False, force: bool = False, installrunpackage: bool = True, extra_values: dict = {}) -> dict:
- """Upgrade an existing package
-
- Parameters
- ----------
- task_id : str
- Task id of the download or the upload file
- check_codesign : bool, optional
- Check signature of the source code of the package (is it a Synology one). Defaults to `False`
- force : bool, optional
- Force installation. Defaults to `False`
- installrunpackage : bool, optional
- Run package after installation. Defaults to `True`
- extra_values : dict, optional
- Extra values due to some package installation. Defaults to `{}`
- All known extra values are:
- - Surveillance station
- ```json
- {
- "chkSVS_Alias": true,
- "strSVS_Alias": "cam",
- "chkSVS_HTTP": true,
- "strSVS_HTTP": "9900",
- "chkSVS_HTTPS": true,
- "strSVS_HTTPS": "9901"
- }
- ```
-
- Returns
- -------
- dict
- Message and some info about installation
-
- Examples
- --------
- ```json
- {
- "data": {
- "message": "message",
- "packageName": "Plex Media Server",
- "worker_message": []
- },
- "success": true,
- }
- ```
+ """
+ Upgrade an existing package.
+
+ Parameters
+ ----------
+ task_id : str
+ Task id of the download or the upload file.
+ check_codesign : bool, optional
+ Check signature of the source code of the package (is it a Synology one). Defaults to `False`.
+ force : bool, optional
+ Force installation. Defaults to `False`.
+ installrunpackage : bool, optional
+ Run package after installation. Defaults to `True`.
+ extra_values : dict, optional
+ Extra values due to some package installation. Defaults to `{}`.
+
+ Returns
+ -------
+ dict
+ Message and some info about installation.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "message": "message",
+ "packageName": "Plex Media Server",
+ "worker_message": []
+ },
+ "success": true,
+ }
+ ```
"""
api_name = 'SYNO.Core.Package.Installation'
@@ -769,94 +820,84 @@ def upgrade_package(self, task_id: str, check_codesign: bool = False, force: boo
return self.request_data(api_name, api_path, req_param)
def install_package(self, package_id: str, volume_path: str, file_path: str, check_codesign: bool = True, force: bool = True, installrunpackage: bool = True, extra_values: dict = {}) -> dict:
- """Install a package that is already downloaded
-
- Parameters
- ----------
- package_id : str
- Id of the package to install
- volume_path : str
- Volume path of the installation, can get from `check_installation` function
- file_path : str
- File path of the installation, can get from `check_installation_from_download` function
- check_codesign : bool, optional
- Check signature of the source code of the package (is it a Synology one). Defaults to `False`
- force : bool, optional
- Force installation. Defaults to `False`
- installrunpackage : bool, optional
- Run package after installation. Defaults to `True`
- extra_values : dict, optional
- Extra values due to some package installation. Defaults to `{}`
- All known extra values are:
- - Surveillance station
- ```json
+ """
+ Install a package that is already downloaded.
+
+ Parameters
+ ----------
+ package_id : str
+ Id of the package to install.
+ volume_path : str
+ Volume path of the installation, can get from `check_installation` function.
+ file_path : str
+ File path of the installation, can get from `check_installation_from_download` function.
+ check_codesign : bool, optional
+ Check signature of the source code of the package (is it a Synology one). Defaults to `False`.
+ force : bool, optional
+ Force installation. Defaults to `False`.
+ installrunpackage : bool, optional
+ Run package after installation. Defaults to `True`.
+ extra_values : dict, optional
+ Extra values due to some package installation. Defaults to `{}`.
+
+ Returns
+ -------
+ dict
+ Message and some info about installation.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "has_fail": false,
+ "result": [
{
- "chkSVS_Alias": true,
- "strSVS_Alias": "cam",
- "chkSVS_HTTP": true,
- "strSVS_HTTP": "9900",
- "chkSVS_HTTPS": true,
- "strSVS_HTTPS": "9901"
- }
- ```
- Returns
- -------
- dict
- Message and some info about installation
-
- Examples
- --------
- ```json
- {
- "data": {
- "has_fail": false,
- "result": [
- {
- "api": "SYNO.Core.Package.Installation",
- "data": {
- "is_occupied": false,
- "volume_count": 2,
- "volume_list": [
- {
- "desc": "",
- "display": "Volume 1 (Available capacity: 185.09 GB )",
- "mount_point": "/volume1",
- "size_free": "198739943424",
- "size_total": "206158430208",
- "vol_desc": "Apps",
- "volume_features": []
- },
- {
- "desc": "",
- "display": "Volume 2 (Available capacity: 2391.17 GB )",
- "mount_point": "/volume2",
- "size_free": "2567495630848",
- "size_total": "3623234412544",
- "vol_desc": "Stockage",
- "volume_features": []
- }
- ],
- "volume_path": "/volume1"
- },
- "method": "check",
- "success": true,
- "version": 1
+ "api": "SYNO.Core.Package.Installation",
+ "data": {
+ "is_occupied": false,
+ "volume_count": 2,
+ "volume_list": [
+ {
+ "desc": "",
+ "display": "Volume 1 (Available capacity: 185.09 GB )",
+ "mount_point": "/volume1",
+ "size_free": "198739943424",
+ "size_total": "206158430208",
+ "vol_desc": "Apps",
+ "volume_features": []
+ },
+ {
+ "desc": "",
+ "display": "Volume 2 (Available capacity: 2391.17 GB )",
+ "mount_point": "/volume2",
+ "size_free": "2567495630848",
+ "size_total": "3623234412544",
+ "vol_desc": "Stockage",
+ "volume_features": []
+ }
+ ],
+ "volume_path": "/volume1"
},
- {
- "api": "SYNO.Core.Package.Installation",
- "data": {
- "packageName": "Text Editor",
- "worker_message": []
- },
- "method": "install",
- "success": true,
- "version": 1
- }
- ]
- },
- "success": true
- }
- ```
+ "method": "check",
+ "success": true,
+ "version": 1
+ },
+ {
+ "api": "SYNO.Core.Package.Installation",
+ "data": {
+ "packageName": "Text Editor",
+ "worker_message": []
+ },
+ "method": "install",
+ "success": true,
+ "version": 1
+ }
+ ]
+ },
+ "success": true
+ }
+ ```
"""
compound = [
{
@@ -886,29 +927,30 @@ def install_package(self, package_id: str, volume_path: str, file_path: str, che
return self.batch_request(compound=compound)
def uninstall_package(self, package_id: str) -> dict:
- """Uninstall a package
-
- Parameters
- ----------
- package_id : str
- Id of the package to uninstall
-
- Returns
- -------
- dict
- Possible message to the user
-
- Examples
- --------
- ```json
- {
- "data": {
- "message": "",
- "worker_message": []
- },
- "success": true
- }
- ```
+ """
+ Uninstall a package.
+
+ Parameters
+ ----------
+ package_id : str
+ Id of the package to uninstall.
+
+ Returns
+ -------
+ dict
+ Possible message to the user.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "message": "",
+ "worker_message": []
+ },
+ "success": true
+ }
+ ```
"""
if not self._is_package_already_installed(package_id=package_id):
@@ -928,6 +970,19 @@ def uninstall_package(self, package_id: str) -> dict:
return self.request_data(api_name, api_path, req_param)
def _is_package_already_installed(self, package_id: str) -> bool:
+ """
+ Check if a package is already installed.
+
+ Parameters
+ ----------
+ package_id : str
+ The ID of the package to check.
+
+ Returns
+ -------
+ bool
+ True if the package is installed, False otherwise.
+ """
response: dict = self.list_installed()
data: dict = response.get("data")
installed_packages = data.get("packages")
@@ -936,75 +991,76 @@ def _is_package_already_installed(self, package_id: str) -> bool:
return package_infos != None
def easy_install(self, package_id: str, volume_path: str, install_dependencies: bool = True) -> dict:
- """Execute an easy installation process of the package
-
- Parameters
- ----------
- package_id : str
- Package ID to install
- volume_path : str
- Volume path where you want to install the package
- install_dependencies : bool, optional
- If you want to install dependencies. Defaults to True
-
- Returns
- -------
- dict[str, object]
- Information about installation, same as install_package function
-
- Examples
- --------
- ```json
- {
- "data": {
- "has_fail": false,
- "result": [
- {
- "api": "SYNO.Core.Package.Installation",
- "data": {
- "is_occupied": false,
- "volume_count": 2,
- "volume_list": [
- {
- "desc": "",
- "display": "Volume 1 (Available capacity: 185.11 GB )",
- "mount_point": "/volume1",
- "size_free": "198759485440",
- "size_total": "206158430208",
- "vol_desc": "Apps",
- "volume_features": []
- },
- {
- "desc": "",
- "display": "Volume 2 (Available capacity: 2391.17 GB )",
- "mount_point": "/volume2",
- "size_free": "2567495565312",
- "size_total": "3623234412544",
- "vol_desc": "Stockage",
- "volume_features": []
- }
- ],
- "volume_path": "/volume1"
- },
- "method": "check",
- "success": true,
- "version": 1
+ """
+ Execute an easy installation process of the package.
+
+ Parameters
+ ----------
+ package_id : str
+ Package ID to install.
+ volume_path : str
+ Volume path where you want to install the package.
+ install_dependencies : bool, optional
+ If you want to install dependencies. Defaults to True.
+
+ Returns
+ -------
+ dict[str, object]
+ Information about installation, same as install_package function.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "has_fail": false,
+ "result": [
+ {
+ "api": "SYNO.Core.Package.Installation",
+ "data": {
+ "is_occupied": false,
+ "volume_count": 2,
+ "volume_list": [
+ {
+ "desc": "",
+ "display": "Volume 1 (Available capacity: 185.11 GB )",
+ "mount_point": "/volume1",
+ "size_free": "198759485440",
+ "size_total": "206158430208",
+ "vol_desc": "Apps",
+ "volume_features": []
+ },
+ {
+ "desc": "",
+ "display": "Volume 2 (Available capacity: 2391.17 GB )",
+ "mount_point": "/volume2",
+ "size_free": "2567495565312",
+ "size_total": "3623234412544",
+ "vol_desc": "Stockage",
+ "volume_features": []
+ }
+ ],
+ "volume_path": "/volume1"
},
- {
- "api": "SYNO.Core.Package.Installation",
- "data": {
- "packageName": "Text Editor",
- "worker_message": []
- },
- "method": "install",
- "success": true,
- "version": 1
- }
- ]
- },
- "success": true
- }
- ```
+ "method": "check",
+ "success": true,
+ "version": 1
+ },
+ {
+ "api": "SYNO.Core.Package.Installation",
+ "data": {
+ "packageName": "Text Editor",
+ "worker_message": []
+ },
+ "method": "install",
+ "success": true,
+ "version": 1
+ }
+ ]
+ },
+ "success": true
+ }
+ ```
"""
api_name = 'hotfix' # fix for docs_parser.py issue
diff --git a/synology_api/core_share.py b/synology_api/core_share.py
index 74ca8a16..62b0a4bb 100644
--- a/synology_api/core_share.py
+++ b/synology_api/core_share.py
@@ -1,50 +1,51 @@
+"""
+Synology Core Share API wrapper.
+
+This module provides a Python interface for managing shared folders, permissions, and encryption
+on Synology NAS devices.
+"""
+
import json
from typing import List, Any
from . import base_api
class Share(base_api.BaseApi):
- """
- Core Share API implementation.
- """
+ """Core Share API implementation."""
def validate_set(self, name: str, vol_path: str, desc: str = "", enable_share_compress: bool = False, enable_share_cow: bool = False, enc_passwd: str = "", encryption: bool = False) -> dict:
- """Validate set of parameter for a new / modified shared folder
- Parameters
- ----------
- name : str
- Share name.
-
- vol_path : str
- Volume path.
-
- desc : str, optional
- Share description. Defaults to `""`.
-
- enable_share_compress : bool, optional
- Enable share compress. Defaults to `False`.
-
- enable_share_cow : bool, optional
- Enable share cow. Defaults to `False`.
-
- enc_passwd : str, optional
- Encrypted password. Defaults to `""`.
-
- encryption : bool, optional
- Enable encryption. Defaults to `False`.
-
- Returns
- -------
- dict
- Success.
-
- Examples
- --------
- ```json
- {
- "success": true,
- }
- ```
+ """
+ Validate set of parameter for a new / modified shared folder.
+
+ Parameters
+ ----------
+ name : str
+ Share name.
+ vol_path : str
+ Volume path.
+ desc : str, optional
+ Share description. Defaults to `""`.
+ enable_share_compress : bool, optional
+ Enable share compress. Defaults to `False`.
+ enable_share_cow : bool, optional
+ Enable share cow. Defaults to `False`.
+ enc_passwd : str, optional
+ Encrypted password. Defaults to `""`.
+ encryption : bool, optional
+ Enable encryption. Defaults to `False`.
+
+ Returns
+ -------
+ dict
+ Success.
+
+ Examples
+ --------
+ ```json
+ {
+ "success": true,
+ }
+ ```
"""
api_name = "SYNO.Core.Share"
info = self.core_list[api_name]
@@ -77,46 +78,47 @@ def validate_set(self, name: str, vol_path: str, desc: str = "", enable_share_co
return self.request_data(api_name, api_path, req_param, method="post")
def list_folders(self, share_type: str = "all", additional: list = []) -> dict:
- """List all folders informations
- Parameters
- ----------
- share_type : str, optional
- Share type. Defaults to `all`.
-
- additional : list[str], optional
- Additional fields to retrieve. Defaults to `[]`.
- All fields known are: `[
- "hidden","encryption","is_aclmode","unite_permission","is_support_acl","is_sync_share","is_force_readonly","force_readonly_reason",
- "recyclebin","is_share_moving","is_cluster_share","is_exfat_share","is_c2_share","is_cold_storage_share","is_missing_share",
- "is_offline_share","support_snapshot","share_quota","enable_share_compress","enable_share_cow","enable_share_tiering",
- "load_worm_attr","include_cold_storage_share","is_cold_storage_share","include_missing_share","is_missing_share",
- "include_offline_share","is_offline_share","include_worm_share"
- ]`.
-
- Returns
- -------
- dict
- A dictionary containing the shared folders information.
-
- Examples
- --------
- ```json
- {
- "data": {
- "shares": [
- {
- "desc": "",
- "is_usb_share": false,
- "name": "test_shared_folder",
- "uuid": "18585c8d-4d74-41a1-b561-21906a7f6f14",
- "vol_path": "/volume1"
- }
- ],
- "total": 1
- },
- "success": true
- }
- ```
+ """
+ List all folders informations.
+
+ Parameters
+ ----------
+ share_type : str, optional
+ Share type. Defaults to `all`.
+ additional : list[str], optional
+ Additional fields to retrieve. Defaults to `[]`.
+ All fields known are: `[
+ "hidden","encryption","is_aclmode","unite_permission","is_support_acl","is_sync_share","is_force_readonly","force_readonly_reason",
+ "recyclebin","is_share_moving","is_cluster_share","is_exfat_share","is_c2_share","is_cold_storage_share","is_missing_share",
+ "is_offline_share","support_snapshot","share_quota","enable_share_compress","enable_share_cow","enable_share_tiering",
+ "load_worm_attr","include_cold_storage_share","is_cold_storage_share","include_missing_share","is_missing_share",
+ "include_offline_share","is_offline_share","include_worm_share"
+ ]`.
+
+ Returns
+ -------
+ dict
+ A dictionary containing the shared folders information.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "shares": [
+ {
+ "desc": "",
+ "is_usb_share": false,
+ "name": "test_shared_folder",
+ "uuid": "18585c8d-4d74-41a1-b561-21906a7f6f14",
+ "vol_path": "/volume1"
+ }
+ ],
+ "total": 1
+ },
+ "success": true
+ }
+ ```
"""
api_name = "SYNO.Core.Share"
info = self.core_list[api_name]
@@ -131,39 +133,40 @@ def list_folders(self, share_type: str = "all", additional: list = []) -> dict:
return self.request_data(api_name, api_path, req_param)
def get_folder(self, name: str, additional: list = []) -> dict:
- """Get a folder by name
- Parameters
- ----------
- name : str
- Share name.
-
- additional : list, optional
- Additional fields to retrieve. Defaults to `[]`.
- All fields known are: `["disable_list","disable_modify","disable_download","unite_permission","is_aclmode"]`.
-
- Returns
- -------
- dict
- A dictionary containing the shared folder information.
-
- Examples
- --------
- ```json
- {
- "data": {
- "desc": "",
- "disable_download": false,
- "disable_list": false,
- "disable_modify": false,
- "is_aclmode": true,
- "is_usb_share": false,
- "name": "test_shared_folder",
- "unite_permission": false,
- "uuid": "18585c8d-4d74-41a1-b561-21906a7f6f14",
- "vol_path": "/volume1"
- },
- "success": true,
- ```
+ """
+ Get a folder by name.
+
+ Parameters
+ ----------
+ name : str
+ Share name.
+ additional : list, optional
+ Additional fields to retrieve. Defaults to `[]`.
+ All fields known are: `["disable_list","disable_modify","disable_download","unite_permission","is_aclmode"]`.
+
+ Returns
+ -------
+ dict
+ A dictionary containing the shared folder information.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "desc": "",
+ "disable_download": false,
+ "disable_list": false,
+ "disable_modify": false,
+ "is_aclmode": true,
+ "is_usb_share": false,
+ "name": "test_shared_folder",
+ "unite_permission": false,
+ "uuid": "18585c8d-4d74-41a1-b561-21906a7f6f14",
+ "vol_path": "/volume1"
+ },
+ "success": true,
+ ```
"""
api_name = "SYNO.Core.Share"
info = self.core_list[api_name]
@@ -182,57 +185,54 @@ def create_folder(self,
enable_recycle_bin: bool = True, recycle_bin_admin_only: bool = True,
hide_unreadable: bool = False, enable_share_cow: bool = False,
enable_share_compress: bool = False, share_quota: int = 0, name_org: str = "",
+ encryption: bool = False, enc_passwd: str = ""
) -> dict:
- """Create a new shared folder
- Parameters
- ----------
- name : str
- Share name.
-
- vol_path : str
- Volume path.
-
- desc : str, optional
- Share description. Defaults to `""`.
-
- hidden : bool, optional
- Hide share. Defaults to `False`.
-
- enable_recycle_bin : bool, optional
- Enable recycle bin. Defaults to `True`.
-
- recycle_bin_admin_only : bool, optional
- Recycle bin admin only. Defaults to `True`.
-
- hide_unreadable : bool, optional
- Hide unreadable. Defaults to `False`.
-
- enable_share_cow : bool, optional
- Enable share cow. Defaults to `False`.
-
- enable_share_compress : bool, optional
- Enable share compress. Defaults to `False`.
-
- share_quota : int, optional
- Share quota. Defaults to `0`.
-
- name_org : str, optional
- Defaults to `""`.
-
- Returns
- -------
- dict
- Name of the created shared folder
-
- Examples
- --------
- ```json
- {
- "data": {
- "name": "test_shared_folder"
- },
- "success": true,
- ```
+ """
+ Create a new shared folder.
+
+ Parameters
+ ----------
+ name : str
+ Share name.
+ vol_path : str
+ Volume path.
+ desc : str, optional
+ Share description. Defaults to `""`.
+ hidden : bool, optional
+ Hide share. Defaults to `False`.
+ enable_recycle_bin : bool, optional
+ Enable recycle bin. Defaults to `True`.
+ recycle_bin_admin_only : bool, optional
+ Recycle bin admin only. Defaults to `True`.
+ hide_unreadable : bool, optional
+ Hide unreadable. Defaults to `False`.
+ enable_share_cow : bool, optional
+ Enable share cow. Defaults to `False`.
+ enable_share_compress : bool, optional
+ Enable share compress. Defaults to `False`.
+ share_quota : int, optional
+ Share quota. Defaults to `0`.
+ name_org : str, optional
+ Defaults to `""`.
+ encryption : bool, optional
+ Enable encryption. Defaults to `False`.
+ enc_passwd : str, optional
+ Encrypted password. Defaults to `""`.
+
+ Returns
+ -------
+ dict
+ Name of the created shared folder.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "name": "test_shared_folder"
+ },
+ "success": true,
+ ```
"""
api_name = "SYNO.Core.Share"
@@ -256,6 +256,8 @@ def create_folder(self,
"hidden": hidden,
"hide_unreadable": hide_unreadable,
"share_quota": share_quota,
+ "encryption": encryption,
+ "enc_passwd": enc_passwd,
})
}
# If using https don't use encryption
@@ -268,25 +270,26 @@ def create_folder(self,
return self.request_data(api_name, api_path, req_param, method="post")
def delete_folders(self, name: List[str]) -> dict:
- """Delete folder(s) by name(s)
-
- Parameters
- ----------
- name : List[str]
- Share names.
-
- Returns
- -------
- dict
- Success.
-
- Examples
- --------
- ```json
- {
- "success": true
- }
- ```
+ """
+ Delete folder(s) by name(s).
+
+ Parameters
+ ----------
+ name : List[str]
+ Share names.
+
+ Returns
+ -------
+ dict
+ Success.
+
+ Examples
+ --------
+ ```json
+ {
+ "success": true
+ }
+ ```
"""
api_name = "SYNO.Core.Share"
info = self.core_list[api_name]
@@ -305,56 +308,48 @@ def clone(self,
hide_unreadable: bool = False, enable_share_cow: bool = False,
enable_share_compress: bool = False, share_quota: int = 0
) -> dict:
- """Clone existing shared folder.
- Parameters
- ----------
- name : str
- New shared folder name.
-
- name_org : str
- Original shared folder name.
-
- vol_path : str
- Volume path.
-
- desc : str, optional
- Shared folder description. Defaults to `""`.
-
- hidden : bool, optional
- Hide shared folder. Defaults to `False`.
-
- enable_recycle_bin : bool, optional
- Enable recycle bin. Defaults to `True`.
-
- recycle_bin_admin_only : bool, optional
- Recycle bin admin only. Defaults to `True`.
-
- hide_unreadable : bool, optional
- Hide unreadable. Defaults to `False`.
-
- enable_share_cow : bool, optional
- Enable share cow. Defaults to `False`.
-
- enable_share_compress : bool, optional
- Enable share compress. Defaults to `False`.
-
- share_quota : int, optional
- Share quota. Defaults to `0`.
-
- Returns
- -------
- dict
- Name of the created shared folder
-
- Examples
- --------
- ```json
- {
- "data": {
- "name": "test_shared_folder"
- },
- "success": true,
- ```
+ """
+ Clone existing shared folder.
+
+ Parameters
+ ----------
+ name : str
+ New shared folder name.
+ name_org : str
+ Original shared folder name.
+ vol_path : str
+ Volume path.
+ desc : str, optional
+ Shared folder description. Defaults to `""`.
+ hidden : bool, optional
+ Hide shared folder. Defaults to `False`.
+ enable_recycle_bin : bool, optional
+ Enable recycle bin. Defaults to `True`.
+ recycle_bin_admin_only : bool, optional
+ Recycle bin admin only. Defaults to `True`.
+ hide_unreadable : bool, optional
+ Hide unreadable. Defaults to `False`.
+ enable_share_cow : bool, optional
+ Enable share cow. Defaults to `False`.
+ enable_share_compress : bool, optional
+ Enable share compress. Defaults to `False`.
+ share_quota : int, optional
+ Share quota. Defaults to `0`.
+
+ Returns
+ -------
+ dict
+ Name of the created shared folder.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "name": "test_shared_folder"
+ },
+ "success": true,
+ ```
"""
api_name = "SYNO.Core.Share"
info = self.core_list[api_name]
@@ -390,68 +385,139 @@ def clone(self,
return self.request_data(api_name, api_path, req_param, method="post")
+ def decrypt_folder(self, name: str, password: str) -> dict:
+ """
+ Decrypt a given share.
-class SharePermission(base_api.BaseApi):
- """
- Core Share Permission API implementation.
- """
-
- def get_folder_permission_by_name(self,
- name: str, permission_substr: str, offset: int = 0, limit: int = 50, is_unite_permission: bool = False, with_inherit: bool = False,
- user_group_type: str = "local_user"
- ) -> dict:
- """Retrieve share permissions for a given folder filtered by permission name (sub string)
Parameters
----------
name : str
- The folder name to list permissions for.
+ The share name to decrypt.
+ password : str
+ The password to use for decrypting the share.
- permission_substr : str
- The substring to search for in the permissions.
+ Returns
+ -------
+ dict
+ Success.
- offset : int, optional
- The offset to start at. Defaults to `0`.
+ Examples
+ --------
+ ```json
+ {
+ "success": true
+ }
+ ```
+ """
+ api_name = "SYNO.Core.Share.Crypto"
+ info = self.core_list[api_name]
+ api_path = info["path"]
+ req_param = {
+ "method": "decrypt",
+ "version": info['maxVersion'],
+ "name": name,
+ }
- limit : int, optional
- The maximum number of results to return. Defaults to `50`.
+ req_param_encrypted = {
+ "password": password,
+ }
+ # If using https don't use encryption
+ if self.session._secure:
+ req_param.update(req_param_encrypted)
+ else:
+ encrypted_params = self.session.encrypt_params(req_param_encrypted)
+ req_param.update(encrypted_params)
- is_unite_permission : bool, optional
- Whether to return unified permissions. Defaults to `False`.
+ return self.request_data(api_name, api_path, req_param, method="post")
- with_inherit : bool, optional
- Whether to include inherited permissions. Defaults to `False`.
+ def encrypt_folder(self, name: str) -> dict:
+ """
+ Encrypt a given share.
- user_group_type : str, optional
- The type of user group to list permissions for. Defaults to `"local_user"`.
- All known values are: `["system", "local_user", "local_group", "ldap_user", "ldap_group"]`.
+ Parameters
+ ----------
+ name : str
+ The share name to encrypt.
Returns
-------
dict
- List of permission(s) on the folder
+ Success.
Examples
--------
```json
{
- "data": {
- "items": [
- {
- "inherit": "-",
- "is_admin": false,
- "is_custom": false,
- "is_deny": false,
- "is_readonly": false,
- "is_writable": false,
- "name": "guest"
- }
- ],
- "total": 1
- },
"success": true
}
```
"""
+ api_name = "SYNO.Core.Share.Crypto"
+ info = self.core_list[api_name]
+ api_path = info["path"]
+ req_param = {
+ "method": "encrypt",
+ "version": info['maxVersion'],
+ "name": name,
+ }
+ return self.request_data(api_name, api_path, req_param, method="post")
+
+
+class SharePermission(base_api.BaseApi):
+ """Core Share Permission API implementation."""
+
+ def get_folder_permission_by_name(self,
+ name: str, permission_substr: str, offset: int = 0, limit: int = 50, is_unite_permission: bool = False, with_inherit: bool = False,
+ user_group_type: str = "local_user"
+ ) -> dict:
+ """
+ Retrieve share permissions for a given folder filtered by permission name (sub string).
+
+ Parameters
+ ----------
+ name : str
+ The folder name to list permissions for.
+ permission_substr : str
+ The substring to search for in the permissions.
+ offset : int, optional
+ The offset to start at. Defaults to `0`.
+ limit : int, optional
+ The maximum number of results to return. Defaults to `50`.
+ is_unite_permission : bool, optional
+ Whether to return unified permissions. Defaults to `False`.
+ with_inherit : bool, optional
+ Whether to include inherited permissions. Defaults to `False`.
+ user_group_type : str, optional
+ The type of user group to list permissions for. Defaults to `"local_user"`.
+ All known values are: `["system", "local_user", "local_group", "ldap_user", "ldap_group"]`.
+
+ Returns
+ -------
+ dict
+ List of permission(s) on the folder.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "items": [
+ {
+ "inherit": "-",
+ "is_admin": false,
+ "is_custom": false,
+ "is_deny": false,
+ "is_readonly": false,
+ "is_writable": false,
+ "name": "guest"
+ }
+ ],
+ "total": 1
+ },
+ "success": true
+ }
+ ```
+ """
api_name = "SYNO.Core.Share.Permission"
info = self.core_list[api_name]
@@ -474,81 +540,78 @@ def get_folder_permissions(self,
name: str, offset: int = 0, limit: int = 50, is_unite_permission: bool = False, with_inherit: bool = False,
user_group_type: str = "local_user"
) -> dict:
- """Retrieve share permissions for a given folder.
- Parameters
- ----------
- name : str
- The folder name to list permissions for.
-
- offset : int, optional
- The offset to start at. Defaults to `0`.
-
- limit : int, optional
- The maximum number of results to return. Defaults to `50`.
-
- is_unite_permission : bool, optional
- Whether to return unified permissions. Defaults to `False`.
-
- with_inherit : bool, optional
- Whether to include inherited permissions. Defaults to `False`.
-
- user_group_type : str, optional
- The type of user group to list permissions for. Defaults to `"local_user"`.
- All known values are: `["system", "local_user", "local_group", "ldap_user", "ldap_group"]`.
-
- Returns
- -------
- dict
- All permissions on the folder
-
- Examples
- --------
- ```json
- {
- "data": {
- "items": [
- {
- "inherit": "rw",
- "is_admin": true,
- "is_custom": false,
- "is_deny": true,
- "is_readonly": false,
- "is_writable": false,
- "name": "admin"
- },
- {
- "inherit": "-",
- "is_admin": false,
- "is_custom": false,
- "is_deny": false,
- "is_readonly": false,
- "is_writable": false,
- "name": "guest"
- },
- {
- "inherit": "rw",
- "is_admin": true,
- "is_custom": false,
- "is_deny": false,
- "is_readonly": false,
- "is_writable": true,
- "name": "test_api"
- },
- {
- "inherit": "-",
- "is_admin": false,
- "is_custom": false,
- "is_deny": false,
- "is_readonly": false,
- "is_writable": false,
- "name": "test_test"
- }
- ],
- "total": 5
- },
- "success": true
- }
- ```
+ """
+ Retrieve share permissions for a given folder.
+
+ Parameters
+ ----------
+ name : str
+ The folder name to list permissions for.
+ offset : int, optional
+ The offset to start at. Defaults to `0`.
+ limit : int, optional
+ The maximum number of results to return. Defaults to `50`.
+ is_unite_permission : bool, optional
+ Whether to return unified permissions. Defaults to `False`.
+ with_inherit : bool, optional
+ Whether to include inherited permissions. Defaults to `False`.
+ user_group_type : str, optional
+ The type of user group to list permissions for. Defaults to `"local_user"`.
+ All known values are: `["system", "local_user", "local_group", "ldap_user", "ldap_group"]`.
+
+ Returns
+ -------
+ dict
+ All permissions on the folder.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "items": [
+ {
+ "inherit": "rw",
+ "is_admin": true,
+ "is_custom": false,
+ "is_deny": true,
+ "is_readonly": false,
+ "is_writable": false,
+ "name": "admin"
+ },
+ {
+ "inherit": "-",
+ "is_admin": false,
+ "is_custom": false,
+ "is_deny": false,
+ "is_readonly": false,
+ "is_writable": false,
+ "name": "guest"
+ },
+ {
+ "inherit": "rw",
+ "is_admin": true,
+ "is_custom": false,
+ "is_deny": false,
+ "is_readonly": false,
+ "is_writable": true,
+ "name": "test_api"
+ },
+ {
+ "inherit": "-",
+ "is_admin": false,
+ "is_custom": false,
+ "is_deny": false,
+ "is_readonly": false,
+ "is_writable": false,
+ "name": "test_test"
+ }
+ ],
+ "total": 5
+ },
+ "success": true
+ }
+ ```
"""
api_name = "SYNO.Core.Share.Permission"
info = self.core_list[api_name]
@@ -567,43 +630,31 @@ def get_folder_permissions(self,
return self.request_data(api_name, api_path, req_param, method="get")
def set_folder_permissions(self, name: str, user_group_type: str, permissions: List[dict[str, object]]) -> dict:
- """Set folder permissions for a given folder.
- Parameters
- ----------
- name : str
- The folder name to set permissions for.
-
- user_group_type : str
- The type of user group to set permissions for.
- All known values are: `["system", "local_user", "local_group", "ldap_user", "ldap_group"]`.
-
- permissions : dict
- The permissions to set for the folder.
- Example:
- ```json
- [
- {
- "name":"guest",
- "is_readonly":false,
- "is_writable":true,
- "is_deny":false,
- "is_custom":false
- }
- ]
- ```
-
- Returns
- -------
- dict
- Success
-
- Examples
- --------
- ```json
- {
- "success": true
- }
- ```
+ """
+ Set folder permissions for a given folder.
+
+ Parameters
+ ----------
+ name : str
+ The folder name to set permissions for.
+ user_group_type : str
+ The type of user group to set permissions for.
+ All known values are: `["system", "local_user", "local_group", "ldap_user", "ldap_group"]`.
+ permissions : dict
+ The permissions to set for the folder.
+
+ Returns
+ -------
+ dict
+ Success.
+
+ Examples
+ --------
+ ```json
+ {
+ "success": true
+ }
+ ```
"""
api_name = "SYNO.Core.Share.Permission"
info = self.core_list[api_name]
@@ -618,41 +669,43 @@ def set_folder_permissions(self, name: str, user_group_type: str, permissions: L
return self.request_data(api_name, api_path, req_param, method="get")
def get_local_group_permissions(self, group: str) -> dict:
- """Retrieve share permissions for a given group.
- Parameters
- ----------
- group : str
- The group to list permissions for.
-
- Returns
- -------
- dict
- Permissions of a group on Shared folders
-
- Examples
- --------
- ```json
- {
- "data": {
- "shares": [
- {
- "is_aclmode": true,
- "is_custom": false,
- "is_deny": true,
- "is_mask": false,
- "is_readonly": false,
- "is_sync_share": false,
- "is_unite_permission": false,
- "is_writable": false,
- "name": "ActiveBackupforBusiness",
- "share_path": "/volume3/ActiveBackupforBusiness"
- }
- ],
- "total": 1
- },
- "success": true
- }
- ```
+ """
+ Retrieve share permissions for a given group.
+
+ Parameters
+ ----------
+ group : str
+ The group to list permissions for.
+
+ Returns
+ -------
+ dict
+ Permissions of a group on Shared folders.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "shares": [
+ {
+ "is_aclmode": true,
+ "is_custom": false,
+ "is_deny": true,
+ "is_mask": false,
+ "is_readonly": false,
+ "is_sync_share": false,
+ "is_unite_permission": false,
+ "is_writable": false,
+ "name": "ActiveBackupforBusiness",
+ "share_path": "/volume3/ActiveBackupforBusiness"
+ }
+ ],
+ "total": 1
+ },
+ "success": true
+ }
+ ```
"""
api_name = "SYNO.Core.Share.Permission"
info = self.core_list[api_name]
@@ -673,44 +726,28 @@ def get_local_group_permissions(self, group: str) -> dict:
def set_local_group_permissions(
self, group: str, permissions: list[dict[str, Any]]
) -> dict:
- """Set group permissions for a given share.
- Parameters
- ----------
- group : str
- The group to set the permissions for.
-
- permissions : list[dict[str, Any]]
- The permissions to set for the group.
- Example:
- ```
- [
- {
- "name": "web",
- "is_readonly": False,
- "is_writable": False,
- "is_deny": True
- },
- {
- "name": "ActiveBackupforBusiness",
- "is_readonly": False,
- "is_writable": True,
- "is_deny": False
- }
- ]
- ```
-
- Returns
- -------
- dict
- Success
-
- Examples
- --------
- ```json
- {
- "success": true
- }
- ```
+ """
+ Set group permissions for a given share.
+
+ Parameters
+ ----------
+ group : str
+ The group to set the permissions for.
+ permissions : list[dict[str, Any]]
+ The permissions to set for the group.
+
+ Returns
+ -------
+ dict
+ Success.
+
+ Examples
+ --------
+ ```json
+ {
+ "success": true
+ }
+ ```
"""
api_name = "SYNO.Core.Share.Permission"
info = self.core_list[api_name]
@@ -727,12 +764,16 @@ def set_local_group_permissions(
class KeyManagerStore(base_api.BaseApi):
- """
- Core Share KeyManager Store API implementation.
- """
+ """Core Share KeyManager Store API implementation."""
def init(self) -> dict:
- """Initialize KeyManagerStore API.
+ """
+ Initialize KeyManagerStore API.
+
+ Returns
+ -------
+ dict
+ Not implemented yet.
"""
raise NotImplementedError(
@@ -761,6 +802,14 @@ def init(self) -> dict:
return self.request_data(api_name, api_path, req_param, method="post")
def verify(self) -> dict:
+ """
+ Not implemented yet.
+
+ Returns
+ -------
+ dict
+ Not implemented yet.
+ """
raise NotImplementedError("This method is not implemented yet.")
@@ -786,22 +835,26 @@ def verify(self) -> dict:
return self.request_data(api_name, api_path, req_param, method="post")
def explore(self) -> dict:
- """Explore KeyManagerStore API. Get list of existing stores
- Returns
- -------
- dict
- List of stores existing on the NAS
-
- Examples
- --------
- ```json
- {
- "data": {
- "stores": []
- },
- "success": true
- }
- ```
+ """
+ Explore KeyManagerStore API.
+
+ Get list of existing stores.
+
+ Returns
+ -------
+ dict
+ List of stores existing on the NAS.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "stores": []
+ },
+ "success": true
+ }
+ ```
"""
api_name = "SYNO.Core.Share.KeyManager.Store"
version = self.core_list[api_name]["minVersion"]
@@ -815,27 +868,27 @@ def explore(self) -> dict:
class KeyManagerAutoKey(base_api.BaseApi):
- """
- Core Share KeyManager AutoKey API implementation.
- """
+ """Core Share KeyManager AutoKey API implementation."""
def list(self) -> dict:
- """List KeyManagerStore API.
- Returns
- -------
- dict
- List of keys in the manager
-
- Examples
- --------
- ```json
- {
- "data": {
- "keys": []
- },
- "success": true
- }
- ```
+ """
+ List KeyManagerStore API.
+
+ Returns
+ -------
+ dict
+ List of keys in the manager.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "keys": []
+ },
+ "success": true
+ }
+ ```
"""
api_name = "SYNO.Core.Share.KeyManager.AutoKey"
version = self.core_list[api_name]["minVersion"]
diff --git a/synology_api/core_sys_info.py b/synology_api/core_sys_info.py
index 61029a55..c5b4954e 100644
--- a/synology_api/core_sys_info.py
+++ b/synology_api/core_sys_info.py
@@ -1,3 +1,10 @@
+"""
+Synology Core System Information API wrapper.
+
+This module provides a Python interface for retrieving and managing system information
+on Synology NAS devices, including network, hardware, service, and package status.
+"""
+
from __future__ import annotations
from typing import Optional, List
from . import base_api
@@ -5,8 +12,22 @@
class SysInfo(base_api.BaseApi):
+ """
+ Core System Information API implementation for Synology NAS.
+
+ This class provides methods to retrieve and manage system, network, hardware,
+ service, and package information from a Synology NAS.
+ """
def fileserv_smb(self) -> dict[str, object] | str:
+ """
+ Get SMB file service status.
+
+ Returns
+ -------
+ dict[str, object] or str
+ SMB file service status.
+ """
api_name = 'SYNO.Core.FileServ.SMB'
info = self.core_list[api_name]
api_path = info['path']
@@ -15,6 +36,14 @@ def fileserv_smb(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def fileserv_afp(self) -> dict[str, object] | str:
+ """
+ Get AFP file service status.
+
+ Returns
+ -------
+ dict[str, object] or str
+ AFP file service status.
+ """
api_name = 'SYNO.Core.FileServ.AFP'
info = self.core_list[api_name]
api_path = info['path']
@@ -23,6 +52,14 @@ def fileserv_afp(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def fileserv_nfs(self) -> dict[str, object] | str:
+ """
+ Get NFS file service status.
+
+ Returns
+ -------
+ dict[str, object] or str
+ NFS file service status.
+ """
api_name = 'SYNO.Core.FileServ.NFS'
info = self.core_list[api_name]
api_path = info['path']
@@ -31,6 +68,14 @@ def fileserv_nfs(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def fileserv_ftp(self) -> dict[str, object] | str:
+ """
+ Get FTP file service status.
+
+ Returns
+ -------
+ dict[str, object] or str
+ FTP file service status.
+ """
api_name = 'SYNO.Core.FileServ.FTP'
info = self.core_list[api_name]
api_path = info['path']
@@ -39,6 +84,14 @@ def fileserv_ftp(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def fileserv_sftp(self) -> dict[str, object] | str:
+ """
+ Get SFTP file service status.
+
+ Returns
+ -------
+ dict[str, object] or str
+ SFTP file service status.
+ """
api_name = 'SYNO.Core.FileServ.FTP.SFTP'
info = self.core_list[api_name]
api_path = info['path']
@@ -47,6 +100,14 @@ def fileserv_sftp(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def network_backup_info(self) -> dict[str, object] | str:
+ """
+ Get network backup service information.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Network backup service information.
+ """
api_name = 'SYNO.Backup.Service.NetworkBackup'
info = self.gen_list[api_name]
api_path = info['path']
@@ -55,6 +116,14 @@ def network_backup_info(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def bandwidth_control_protocol(self) -> dict[str, object] | str:
+ """
+ Get bandwidth control protocol information.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Bandwidth control protocol information.
+ """
api_name = 'SYNO.Core.BandwidthControl.Protocol'
info = self.core_list[api_name]
api_path = info['path']
@@ -64,6 +133,14 @@ def bandwidth_control_protocol(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def shared_folders_info(self) -> dict[str, object] | str:
+ """
+ Get shared folders information.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Shared folders information.
+ """
api_name = 'SYNO.Core.Share'
info = self.core_list[api_name]
api_path = info['path']
@@ -72,6 +149,14 @@ def shared_folders_info(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def services_status(self) -> dict[str, object] | str:
+ """
+ Get status of core services.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Status of core services.
+ """
api_name = 'SYNO.Core.Service'
info = self.core_list[api_name]
api_path = info['path']
@@ -80,6 +165,14 @@ def services_status(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def services_discovery(self) -> dict[str, object] | str:
+ """
+ Get service discovery information.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Service discovery information.
+ """
api_name = 'SYNO.Core.FileServ.ServiceDiscovery'
info = self.core_list[api_name]
api_path = info['path']
@@ -88,6 +181,14 @@ def services_discovery(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def file_transfer_status(self) -> dict[str, object] | str:
+ """
+ Get file transfer status.
+
+ Returns
+ -------
+ dict[str, object] or str
+ File transfer status.
+ """
api_name = 'SYNO.Core.SyslogClient.FileTransfer'
info = self.core_list[api_name]
api_path = info['path']
@@ -96,6 +197,14 @@ def file_transfer_status(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def network_status(self) -> dict[str, object] | str:
+ """
+ Get network status.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Network status.
+ """
api_name = 'SYNO.Core.Network'
info = self.core_list[api_name]
api_path = info['path']
@@ -104,6 +213,14 @@ def network_status(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def web_status(self) -> dict[str, object] | str:
+ """
+ Get DSM web status.
+
+ Returns
+ -------
+ dict[str, object] or str
+ DSM web status.
+ """
api_name = 'SYNO.Core.Web.DSM'
info = self.core_list[api_name]
api_path = info['path']
@@ -112,6 +229,14 @@ def web_status(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def current_connection(self) -> dict[str, object] | str:
+ """
+ Get current connection information.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Current connection information.
+ """
api_name = 'SYNO.Core.CurrentConnection'
info = self.core_list[api_name]
api_path = info['path']
@@ -120,6 +245,14 @@ def current_connection(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def bandwidth_control_status(self) -> dict[str, object] | str:
+ """
+ Get bandwidth control status.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Bandwidth control status.
+ """
api_name = 'SYNO.Core.BandwidthControl.Status'
info = self.core_list[api_name]
api_path = info['path']
@@ -128,6 +261,14 @@ def bandwidth_control_status(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def sys_status(self) -> dict[str, object] | str:
+ """
+ Get system status.
+
+ Returns
+ -------
+ dict[str, object] or str
+ System status.
+ """
api_name = 'SYNO.Core.System.Status'
info = self.core_list[api_name]
api_path = info['path']
@@ -136,6 +277,14 @@ def sys_status(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def latest_logs(self) -> dict[str, object] | str:
+ """
+ Get latest system logs.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Latest system logs.
+ """
api_name = 'SYNO.Core.SyslogClient.Status'
info = self.core_list[api_name]
api_path = info['path']
@@ -144,6 +293,14 @@ def latest_logs(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def client_notify_settings_status(self) -> dict[str, object] | str:
+ """
+ Get client notification settings status.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Client notification settings status.
+ """
api_name = 'SYNO.Core.SyslogClient.Setting.Notify'
info = self.core_list[api_name]
api_path = info['path']
@@ -152,6 +309,14 @@ def client_notify_settings_status(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def get_security_scan_info(self) -> dict[str, object] | str:
+ """
+ Get security scan configuration.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Security scan configuration.
+ """
api_name = 'SYNO.Core.SecurityScan.Conf'
info = self.core_list[api_name]
api_path = info['path']
@@ -160,6 +325,14 @@ def get_security_scan_info(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def get_security_scan_rules(self) -> dict[str, object] | str:
+ """
+ Get security scan rules.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Security scan rules.
+ """
api_name = 'SYNO.Core.SecurityScan.Status'
info = self.core_list[api_name]
api_path = info['path']
@@ -169,6 +342,14 @@ def get_security_scan_rules(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def get_security_scan_status(self) -> dict[str, object] | str:
+ """
+ Get security scan status.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Security scan status.
+ """
api_name = 'SYNO.Core.SecurityScan.Status'
info = self.core_list[api_name]
api_path = info['path']
@@ -177,6 +358,14 @@ def get_security_scan_status(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def get_user_list(self) -> dict[str, object] | str:
+ """
+ Get user list.
+
+ Returns
+ -------
+ dict[str, object] or str
+ User list.
+ """
api_name = 'SYNO.Core.User'
info = self.core_list[api_name]
api_path = info['path']
@@ -187,6 +376,14 @@ def get_user_list(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def quickconnect_info(self) -> dict[str, object] | str:
+ """
+ Get QuickConnect configuration.
+
+ Returns
+ -------
+ dict[str, object] or str
+ QuickConnect configuration.
+ """
api_name = 'SYNO.Core.QuickConnect'
info = self.core_list[api_name]
api_path = info['path']
@@ -196,6 +393,14 @@ def quickconnect_info(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def quickconnect_permissions(self) -> dict[str, object] | str:
+ """
+ Get QuickConnect permissions.
+
+ Returns
+ -------
+ dict[str, object] or str
+ QuickConnect permissions.
+ """
api_name = 'SYNO.Core.QuickConnect.Permission'
info = self.core_list[api_name]
api_path = info['path']
@@ -204,6 +409,14 @@ def quickconnect_permissions(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def network_topology(self) -> dict[str, object] | str:
+ """
+ Get network topology.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Network topology.
+ """
api_name = 'SYNO.Core.Network.Router.Topology'
info = self.core_list[api_name]
api_path = info['path']
@@ -212,6 +425,14 @@ def network_topology(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def network_wifi_client(self) -> dict[str, object] | str:
+ """
+ Get WiFi client information.
+
+ Returns
+ -------
+ dict[str, object] or str
+ WiFi client information.
+ """
api_name = 'SYNO.Core.Network.Wifi.Client'
info = self.core_list[api_name]
api_path = info['path']
@@ -220,6 +441,14 @@ def network_wifi_client(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def network_bond(self) -> dict[str, object] | str:
+ """
+ Get network bond information.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Network bond information.
+ """
api_name = 'SYNO.Core.Network.Bond'
info = self.core_list[api_name]
api_path = info['path']
@@ -228,6 +457,14 @@ def network_bond(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def network_bridge(self) -> dict[str, object] | str:
+ """
+ Get network bridge information.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Network bridge information.
+ """
api_name = 'SYNO.Core.Network.Bridge'
info = self.core_list[api_name]
api_path = info['path']
@@ -236,6 +473,14 @@ def network_bridge(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def network_ethernet(self) -> dict[str, object] | str:
+ """
+ Get network ethernet information.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Network ethernet information.
+ """
api_name = 'SYNO.Core.Network.Ethernet'
info = self.core_list[api_name]
api_path = info['path']
@@ -244,6 +489,14 @@ def network_ethernet(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def network_local_bridge(self) -> dict[str, object] | str:
+ """
+ Get local network bridge information.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Local network bridge information.
+ """
api_name = 'SYNO.Core.Network.LocalBridge'
info = self.core_list[api_name]
api_path = info['path']
@@ -252,6 +505,14 @@ def network_local_bridge(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def network_usb_modem(self) -> dict[str, object] | str:
+ """
+ Get USB modem information.
+
+ Returns
+ -------
+ dict[str, object] or str
+ USB modem information.
+ """
api_name = 'SYNO.Core.Network.USBModem'
info = self.core_list[api_name]
api_path = info['path']
@@ -260,6 +521,14 @@ def network_usb_modem(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def network_pppoe(self) -> dict[str, object] | str:
+ """
+ Get PPPoE information.
+
+ Returns
+ -------
+ dict[str, object] or str
+ PPPoE information.
+ """
api_name = 'SYNO.Core.Network.PPPoE'
info = self.core_list[api_name]
api_path = info['path']
@@ -268,6 +537,14 @@ def network_pppoe(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def network_ipv6tunnel(self) -> dict[str, object] | str:
+ """
+ Get IPv6 tunnel information.
+
+ Returns
+ -------
+ dict[str, object] or str
+ IPv6 tunnel information.
+ """
api_name = 'SYNO.Core.Network.IPv6Tunnel'
info = self.core_list[api_name]
api_path = info['path']
@@ -276,6 +553,14 @@ def network_ipv6tunnel(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def network_vpn_pptp(self) -> dict[str, object] | str:
+ """
+ Get VPN PPTP information.
+
+ Returns
+ -------
+ dict[str, object] or str
+ VPN PPTP information.
+ """
api_name = 'SYNO.Core.Network.VPN.PPTP'
info = self.core_list[api_name]
api_path = info['path']
@@ -284,6 +569,14 @@ def network_vpn_pptp(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def network_openvpn(self) -> dict[str, object] | str:
+ """
+ Get OpenVPN information.
+
+ Returns
+ -------
+ dict[str, object] or str
+ OpenVPN information.
+ """
api_name = 'SYNO.Core.Network.VPN.OpenVPN'
info = self.core_list[api_name]
api_path = info['path']
@@ -293,6 +586,14 @@ def network_openvpn(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def network_vpn_l2tp(self) -> dict[str, object] | str:
+ """
+ Get VPN L2TP information.
+
+ Returns
+ -------
+ dict[str, object] or str
+ VPN L2TP information.
+ """
api_name = 'SYNO.Core.Network.VPN.L2TP'
info = self.core_list[api_name]
api_path = info['path']
@@ -301,6 +602,14 @@ def network_vpn_l2tp(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def domain_schedule(self) -> dict[str, object] | str:
+ """
+ Get domain schedule.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Domain schedule.
+ """
api_name = 'SYNO.Core.Directory.Domain.Schedule'
info = self.core_list[api_name]
api_path = info['path']
@@ -309,6 +618,14 @@ def domain_schedule(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def client_ldap(self) -> dict[str, object] | str:
+ """
+ Get LDAP client information.
+
+ Returns
+ -------
+ dict[str, object] or str
+ LDAP client information.
+ """
api_name = 'SYNO.Core.Directory.LDAP'
info = self.core_list[api_name]
api_path = info['path']
@@ -317,6 +634,14 @@ def client_ldap(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def client_sso(self) -> dict[str, object] | str:
+ """
+ Get SSO client information.
+
+ Returns
+ -------
+ dict[str, object] or str
+ SSO client information.
+ """
api_name = 'SYNO.Core.Directory.SSO'
info = self.core_list[api_name]
api_path = info['path']
@@ -325,6 +650,14 @@ def client_sso(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def sys_upgrade_check(self) -> dict[str, object] | str:
+ """
+ Check for system upgrades.
+
+ Returns
+ -------
+ dict[str, object] or str
+ System upgrade check result.
+ """
api_name = 'SYNO.Core.Upgrade.Server'
info = self.core_list[api_name]
api_path = info['path']
@@ -333,6 +666,14 @@ def sys_upgrade_check(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def sys_upgrade_download(self) -> dict[str, object] | str:
+ """
+ Get system upgrade download progress.
+
+ Returns
+ -------
+ dict[str, object] or str
+ System upgrade download progress.
+ """
api_name = 'SYNO.Core.Upgrade.Server.Download'
info = self.core_list[api_name]
api_path = info['path']
@@ -341,6 +682,14 @@ def sys_upgrade_download(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def sys_upgrade_setting(self) -> dict[str, object] | str:
+ """
+ Get system upgrade settings.
+
+ Returns
+ -------
+ dict[str, object] or str
+ System upgrade settings.
+ """
api_name = 'SYNO.Core.Upgrade.Setting'
info = self.core_list[api_name]
api_path = info['path']
@@ -349,6 +698,14 @@ def sys_upgrade_setting(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def notification_sms_conf(self) -> dict[str, object] | str:
+ """
+ Get SMS notification configuration.
+
+ Returns
+ -------
+ dict[str, object] or str
+ SMS notification configuration.
+ """
api_name = 'SYNO.Core.Notification.SMS.Conf'
info = self.core_list[api_name]
api_path = info['path']
@@ -357,6 +714,14 @@ def notification_sms_conf(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def notification_mail_conf(self) -> dict[str, object] | str:
+ """
+ Get mail notification configuration.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Mail notification configuration.
+ """
api_name = 'SYNO.Core.Notification.Mail.Conf'
info = self.core_list[api_name]
api_path = info['path']
@@ -365,6 +730,14 @@ def notification_mail_conf(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def notification_push_mail(self) -> dict[str, object] | str:
+ """
+ Get push mail notification configuration.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Push mail notification configuration.
+ """
api_name = 'SYNO.Core.Notification.Push.Mail'
info = self.core_list[api_name]
api_path = info['path']
@@ -373,6 +746,14 @@ def notification_push_mail(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def notification_push_conf(self) -> dict[str, object] | str:
+ """
+ Get push notification configuration.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Push notification configuration.
+ """
api_name = 'SYNO.Core.Notification.Push.Conf'
info = self.core_list[api_name]
api_path = info['path']
@@ -381,6 +762,14 @@ def notification_push_conf(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def hardware_beep_control(self) -> dict[str, object] | str:
+ """
+ Get hardware beep control status.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Hardware beep control status.
+ """
api_name = 'SYNO.Core.Hardware.BeepControl'
info = self.core_list[api_name]
api_path = info['path']
@@ -389,6 +778,14 @@ def hardware_beep_control(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def hardware_fan_speed(self) -> dict[str, object] | str:
+ """
+ Get hardware fan speed.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Hardware fan speed.
+ """
api_name = 'SYNO.Core.Hardware.FanSpeed'
info = self.core_list[api_name]
api_path = info['path']
@@ -398,6 +795,19 @@ def hardware_fan_speed(self) -> dict[str, object] | str:
# coolfan , fullfan
def set_fan_speed(self, fan_speed: str = 'quietfan') -> dict[str, object] | str:
+ """
+ Set hardware fan speed.
+
+ Parameters
+ ----------
+ fan_speed : str, optional
+ Fan speed mode (e.g., 'quietfan', 'coolfan', 'fullfan'). Defaults to 'quietfan'.
+
+ Returns
+ -------
+ dict[str, object] or str
+ API response.
+ """
api_name = 'SYNO.Core.Hardware.FanSpeed'
info = self.core_list[api_name]
api_path = info['path']
@@ -407,6 +817,19 @@ def set_fan_speed(self, fan_speed: str = 'quietfan') -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def enable_zram(self, enable_zram: bool = True) -> dict[str, object] | str:
+ """
+ Enable or disable ZRAM.
+
+ Parameters
+ ----------
+ enable_zram : bool, optional
+ Enable ZRAM if True, disable if False. Defaults to True.
+
+ Returns
+ -------
+ dict[str, object] or str
+ API response.
+ """
api_name = 'SYNO.Core.Hardware.ZRAM'
info = self.core_list[api_name]
api_path = info['path']
@@ -415,10 +838,26 @@ def enable_zram(self, enable_zram: bool = True) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
- def enable_power_recovery(self,
- restart_auto_after_issue: bool = True,
- wake_on_lan: bool = False
- ) -> dict[str, object] | str:
+ def enable_power_recovery(
+ self,
+ restart_auto_after_issue: bool = True,
+ wake_on_lan: bool = False
+ ) -> dict[str, object] | str:
+ """
+ Enable power recovery options.
+
+ Parameters
+ ----------
+ restart_auto_after_issue : bool, optional
+ Restart automatically after issue. Defaults to True.
+ wake_on_lan : bool, optional
+ Enable Wake-on-LAN. Defaults to False.
+
+ Returns
+ -------
+ dict[str, object] or str
+ API response.
+ """
api_name = 'SYNO.Core.Hardware.PowerRecovery'
info = self.core_list[api_name]
api_path = info['path']
@@ -427,12 +866,32 @@ def enable_power_recovery(self,
return self.request_data(api_name, api_path, req_param)
- def enable_beep_control(self,
- fan_fail: Optional[bool] = None,
- volume_crash: Optional[bool] = None,
- poweron_beep: Optional[bool] = None,
- poweroff_beep: Optional[bool] = None
- ) -> dict[str, object] | str:
+ def enable_beep_control(
+ self,
+ fan_fail: Optional[bool] = None,
+ volume_crash: Optional[bool] = None,
+ poweron_beep: Optional[bool] = None,
+ poweroff_beep: Optional[bool] = None
+ ) -> dict[str, object] | str:
+ """
+ Enable or disable beep control options.
+
+ Parameters
+ ----------
+ fan_fail : bool, optional
+ Enable beep on fan failure.
+ volume_crash : bool, optional
+ Enable beep on volume crash.
+ poweron_beep : bool, optional
+ Enable beep on power on.
+ poweroff_beep : bool, optional
+ Enable beep on power off.
+
+ Returns
+ -------
+ dict[str, object] or str
+ API response.
+ """
api_name = 'SYNO.Core.Hardware.BeepControl'
info = self.core_list[api_name]
api_path = info['path']
@@ -443,6 +902,19 @@ def enable_beep_control(self,
return self.request_data(api_name, api_path, req_param)
def set_led_control(self, led_brightness: int = 2) -> dict[str, object] | str:
+ """
+ Set LED brightness.
+
+ Parameters
+ ----------
+ led_brightness : int, optional
+ LED brightness level. Defaults to 2.
+
+ Returns
+ -------
+ dict[str, object] or str
+ API response.
+ """
api_name = 'SYNO.Core.Led.Brightness'
info = self.core_list[api_name]
api_path = info['path']
@@ -452,6 +924,21 @@ def set_led_control(self, led_brightness: int = 2) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def set_hibernation(self, internal_hd_idletime: int = 0, usb_idletime: int = 0) -> dict[str, object] | str:
+ """
+ Set hibernation times.
+
+ Parameters
+ ----------
+ internal_hd_idletime : int, optional
+ Idle time for internal hard drives. Defaults to 0.
+ usb_idletime : int, optional
+ Idle time for USB devices. Defaults to 0.
+
+ Returns
+ -------
+ dict[str, object] or str
+ API response.
+ """
api_name = 'SYNO.Core.Hardware.Hibernation'
info = self.core_list[api_name]
api_path = info['path']
@@ -460,13 +947,35 @@ def set_hibernation(self, internal_hd_idletime: int = 0, usb_idletime: int = 0)
return self.request_data(api_name, api_path, req_param)
- def enable_external_ups(self,
- enable: bool = False,
- mode: str = 'SLAVE',
- delay_time: int = 1,
- snmp_auth_key_dirty: bool = False,
- snmp_privacy_key_dirty: bool = False
- ) -> dict[str, object] | str:
+ def enable_external_ups(
+ self,
+ enable: bool = False,
+ mode: str = 'SLAVE',
+ delay_time: int = 1,
+ snmp_auth_key_dirty: bool = False,
+ snmp_privacy_key_dirty: bool = False
+ ) -> dict[str, object] | str:
+ """
+ Enable or configure external UPS.
+
+ Parameters
+ ----------
+ enable : bool, optional
+ Enable external UPS. Defaults to False.
+ mode : str, optional
+ UPS mode. Defaults to 'SLAVE'.
+ delay_time : int, optional
+ Delay time. Defaults to 1.
+ snmp_auth_key_dirty : bool, optional
+ SNMP auth key dirty flag. Defaults to False.
+ snmp_privacy_key_dirty : bool, optional
+ SNMP privacy key dirty flag. Defaults to False.
+
+ Returns
+ -------
+ dict[str, object] or str
+ API response.
+ """
api_name = 'SYNO.Core.ExternalDevice.UPS'
info = self.core_list[api_name]
api_path = info['path']
@@ -477,6 +986,14 @@ def enable_external_ups(self,
return self.request_data(api_name, api_path, req_param)
def get_system_info(self) -> dict[str, object] | str:
+ """
+ Get system information.
+
+ Returns
+ -------
+ dict[str, object] or str
+ System information.
+ """
api_name = 'SYNO.Core.System'
info = self.core_list[api_name]
api_path = info['path']
@@ -485,6 +1002,14 @@ def get_system_info(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def get_cpu_temp(self) -> str:
+ """
+ Get CPU temperature.
+
+ Returns
+ -------
+ str
+ CPU temperature.
+ """
api_name = 'SYNO.Core.System'
info = self.core_list[api_name]
api_path = info['path']
@@ -493,6 +1018,14 @@ def get_cpu_temp(self) -> str:
return self.request_data(api_name, api_path, req_param)['data']['sys_temp']
def get_all_system_utilization(self) -> str:
+ """
+ Get all system utilization statistics.
+
+ Returns
+ -------
+ str
+ System utilization statistics.
+ """
api_name = 'SYNO.Core.System.Utilization'
info = self.core_list[api_name]
api_path = info['path']
@@ -501,6 +1034,14 @@ def get_all_system_utilization(self) -> str:
return self.request_data(api_name, api_path, req_param)['data']
def get_cpu_utilization(self) -> str:
+ """
+ Get CPU utilization statistics.
+
+ Returns
+ -------
+ str
+ CPU utilization statistics.
+ """
api_name = 'SYNO.Core.System.Utilization'
info = self.core_list[api_name]
api_path = info['path']
@@ -509,6 +1050,14 @@ def get_cpu_utilization(self) -> str:
return self.request_data(api_name, api_path, req_param)['data']['cpu']
def get_disk_utilization(self) -> str:
+ """
+ Get disk utilization statistics.
+
+ Returns
+ -------
+ str
+ Disk utilization statistics.
+ """
api_name = 'SYNO.Core.System.Utilization'
info = self.core_list[api_name]
api_path = info['path']
@@ -517,6 +1066,14 @@ def get_disk_utilization(self) -> str:
return self.request_data(api_name, api_path, req_param)['data']['disk']
def get_memory_utilization(self) -> str:
+ """
+ Get memory utilization statistics.
+
+ Returns
+ -------
+ str
+ Memory utilization statistics.
+ """
api_name = 'SYNO.Core.System.Utilization'
info = self.core_list[api_name]
api_path = info['path']
@@ -525,6 +1082,19 @@ def get_memory_utilization(self) -> str:
return self.request_data(api_name, api_path, req_param)['data']['memory']
def shutdown(self, version: str = None) -> dict[str, object] | str:
+ """
+ Shutdown the system.
+
+ Parameters
+ ----------
+ version : str, optional
+ API version to use. Defaults to None.
+
+ Returns
+ -------
+ dict[str, object] or str
+ API response.
+ """
api_name = 'SYNO.Core.System'
info = self.core_list[api_name]
api_path = info['path']
@@ -534,6 +1104,14 @@ def shutdown(self, version: str = None) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def reboot(self) -> dict[str, object] | str:
+ """
+ Reboot the system.
+
+ Returns
+ -------
+ dict[str, object] or str
+ API response.
+ """
api_name = 'SYNO.Core.System'
info = self.core_list[api_name]
api_path = info['path']
@@ -542,6 +1120,14 @@ def reboot(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def dsm_info(self) -> dict[str, object] | str:
+ """
+ Get DSM information.
+
+ Returns
+ -------
+ dict[str, object] or str
+ DSM information.
+ """
api_name = 'SYNO.DSM.Info'
info = self.gen_list[api_name]
api_path = info['path']
@@ -550,6 +1136,14 @@ def dsm_info(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def get_network_info(self) -> dict[str, object] | str:
+ """
+ Get network information.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Network information.
+ """
api_name = 'SYNO.Core.System'
info = self.core_list[api_name]
api_path = info['path']
@@ -559,6 +1153,14 @@ def get_network_info(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def get_volume_info(self) -> dict[str, object] | str:
+ """
+ Get volume information.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Volume information.
+ """
api_name = 'SYNO.Core.System'
info = self.core_list[api_name]
api_path = info['path']
@@ -568,6 +1170,14 @@ def get_volume_info(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def hardware_hibernation(self) -> dict[str, object] | str:
+ """
+ Get hardware hibernation status.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Hardware hibernation status.
+ """
api_name = 'SYNO.Core.Hardware.Hibernation'
info = self.core_list[api_name]
api_path = info['path']
@@ -576,6 +1186,14 @@ def hardware_hibernation(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def hardware_ups(self) -> dict[str, object] | str:
+ """
+ Get hardware UPS status.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Hardware UPS status.
+ """
api_name = 'SYNO.Core.ExternalDevice.UPS'
info = self.core_list[api_name]
api_path = info['path']
@@ -584,6 +1202,14 @@ def hardware_ups(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def terminal_info(self) -> dict[str, object] | str:
+ """
+ Get terminal information.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Terminal information.
+ """
api_name = 'SYNO.Core.Terminal'
info = self.core_list[api_name]
api_path = info['path']
@@ -592,6 +1218,14 @@ def terminal_info(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def snmp_info(self) -> dict[str, object] | str:
+ """
+ Get SNMP information.
+
+ Returns
+ -------
+ dict[str, object] or str
+ SNMP information.
+ """
api_name = 'SYNO.Core.SNMP'
info = self.core_list[api_name]
api_path = info['path']
@@ -600,6 +1234,14 @@ def snmp_info(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def process(self) -> dict[str, object] | str:
+ """
+ Get system process information.
+
+ Returns
+ -------
+ dict[str, object] or str
+ System process information.
+ """
api_name = 'SYNO.Core.System.Process'
info = self.core_list[api_name]
api_path = info['path']
@@ -608,6 +1250,14 @@ def process(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def storage(self) -> dict[str, object] | str:
+ """
+ Get storage information.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Storage information.
+ """
api_name = 'SYNO.Storage.CGI.Storage'
info = self.gen_list[api_name]
api_path = info['path']
@@ -616,6 +1266,14 @@ def storage(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def external_device_storage_usb(self) -> dict[str, object] | str:
+ """
+ Get USB storage device information.
+
+ Returns
+ -------
+ dict[str, object] or str
+ USB storage device information.
+ """
api_name = 'SYNO.Core.ExternalDevice.Storage.USB'
info = self.gen_list[api_name]
api_path = info['path']
@@ -625,6 +1283,14 @@ def external_device_storage_usb(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def external_device_storage_esata(self) -> dict[str, object] | str:
+ """
+ Get eSATA storage device information.
+
+ Returns
+ -------
+ dict[str, object] or str
+ eSATA storage device information.
+ """
api_name = 'SYNO.Core.ExternalDevice.Storage.eSATA'
info = self.gen_list[api_name]
api_path = info['path']
@@ -634,6 +1300,14 @@ def external_device_storage_esata(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def file_index_resource(self) -> dict[str, object] | str:
+ """
+ Get file indexing status.
+
+ Returns
+ -------
+ dict[str, object] or str
+ File indexing status.
+ """
api_name = 'SYNO.Finder.FileIndexing.Status'
info = self.gen_list[api_name]
api_path = info['path']
@@ -642,6 +1316,14 @@ def file_index_resource(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def cms_info(self) -> dict[str, object] | str:
+ """
+ Get CMS information.
+
+ Returns
+ -------
+ dict[str, object] or str
+ CMS information.
+ """
api_name = 'SYNO.Core.CMS.Info'
info = self.gen_list[api_name]
api_path = info['path']
@@ -649,16 +1331,15 @@ def cms_info(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
- # TODO {'error': {'code': 2502}, 'success': False}
- '''def service_port_info(self) -> dict[str, object] | str:
- api_name = 'SYNO.Core.Service.PortInfo'
- info = self.gen_list[api_name]
- api_path = info['path']
- req_param = {'version': info['maxVersion'], 'method': 'load', 'target': ['port_forward']}
-
- return self.request_data(api_name, api_path, req_param)'''
-
def port_forwarding_rules(self) -> dict[str, object] | str:
+ """
+ Get port forwarding rules.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Port forwarding rules.
+ """
api_name = 'SYNO.Core.PortForwarding.Rules'
info = self.gen_list[api_name]
api_path = info['path']
@@ -667,6 +1348,14 @@ def port_forwarding_rules(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def port_forwarding_router_conf(self) -> dict[str, object] | str:
+ """
+ Get port forwarding router configuration.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Port forwarding router configuration.
+ """
api_name = 'SYNO.Core.PortForwarding.RouterConf'
info = self.gen_list[api_name]
api_path = info['path']
@@ -675,6 +1364,14 @@ def port_forwarding_router_conf(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def disk_list(self) -> dict[str, object] | str:
+ """
+ Get disk list.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Disk list.
+ """
api_name = 'SYNO.Core.Polling.Data'
info = self.gen_list[api_name]
api_path = info['path']
@@ -683,6 +1380,14 @@ def disk_list(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def ddns_provider_info(self) -> dict[str, object] | str:
+ """
+ Get DDNS provider information.
+
+ Returns
+ -------
+ dict[str, object] or str
+ DDNS provider information.
+ """
api_name = 'SYNO.Core.DDNS.Provider'
info = self.gen_list[api_name]
api_path = info['path']
@@ -691,6 +1396,14 @@ def ddns_provider_info(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def ddns_record_info(self) -> dict[str, object] | str:
+ """
+ Get DDNS record information.
+
+ Returns
+ -------
+ dict[str, object] or str
+ DDNS record information.
+ """
api_name = 'SYNO.Core.DDNS.Record'
info = self.gen_list[api_name]
api_path = info['path']
@@ -699,6 +1412,14 @@ def ddns_record_info(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def ddns_external_ip(self) -> dict[str, object] | str:
+ """
+ Get DDNS external IP.
+
+ Returns
+ -------
+ dict[str, object] or str
+ DDNS external IP.
+ """
api_name = 'SYNO.Core.DDNS.ExtIP'
info = self.gen_list[api_name]
api_path = info['path']
@@ -708,6 +1429,14 @@ def ddns_external_ip(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def ddns_synology(self) -> dict[str, object] | str:
+ """
+ Get Synology DDNS information.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Synology DDNS information.
+ """
api_name = 'SYNO.Core.DDNS.Synology'
info = self.gen_list[api_name]
api_path = info['path']
@@ -717,6 +1446,14 @@ def ddns_synology(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def iscsi_lun_info(self) -> dict[str, object] | str:
+ """
+ Get iSCSI LUN information.
+
+ Returns
+ -------
+ dict[str, object] or str
+ iSCSI LUN information.
+ """
api_name = 'SYNO.Core.ISCSI.LUN'
info = self.gen_list[api_name]
api_path = info['path']
@@ -725,6 +1462,14 @@ def iscsi_lun_info(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def hddman(self) -> dict[str, object] | str:
+ """
+ Get HDD manager information.
+
+ Returns
+ -------
+ dict[str, object] or str
+ HDD manager information.
+ """
api_name = 'SYNO.Storage.CGI.HddMan'
info = self.gen_list[api_name]
api_path = info['path']
@@ -733,6 +1478,14 @@ def hddman(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def ftp_security_info(self) -> dict[str, object] | str:
+ """
+ Get FTP security information.
+
+ Returns
+ -------
+ dict[str, object] or str
+ FTP security information.
+ """
api_name = 'SYNO.Core.FileServ.FTP.Security'
info = self.core_list[api_name]
api_path = info['path']
@@ -741,6 +1494,14 @@ def ftp_security_info(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def bandwidth_control_info(self) -> dict[str, object] | str:
+ """
+ Get bandwidth control information.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Bandwidth control information.
+ """
api_name = 'SYNO.Core.BandwidthControl.Protocol'
info = self.core_list[api_name]
api_path = info['path']
@@ -749,7 +1510,15 @@ def bandwidth_control_info(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
- def directory_domain_info(self) -> dict[str, object] | str: # TODO to test
+ def directory_domain_info(self) -> dict[str, object] | str:
+ """
+ Get directory domain information.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Directory domain information.
+ """
api_name = 'SYNO.Core.Directory.Domain'
info = self.core_list[api_name]
api_path = info['path']
@@ -757,7 +1526,15 @@ def directory_domain_info(self) -> dict[str, object] | str: # TODO to test
return self.request_data(api_name, api_path, req_param)
- def ws_transfer_info(self) -> dict[str, object] | str: # TODO to test
+ def ws_transfer_info(self) -> dict[str, object] | str:
+ """
+ Get WS transfer information.
+
+ Returns
+ -------
+ dict[str, object] or str
+ WS transfer information.
+ """
api_name = 'SYNO.Core.FileServ.ServiceDiscovery.WSTransfer'
info = self.core_list[api_name]
api_path = info['path']
@@ -766,6 +1543,14 @@ def ws_transfer_info(self) -> dict[str, object] | str: # TODO to test
return self.request_data(api_name, api_path, req_param)
def ref_link_copy_info(self) -> dict[str, object] | str:
+ """
+ Get reflink copy information.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Reflink copy information.
+ """
api_name = 'SYNO.Core.FileServ.ReflinkCopy'
info = self.core_list[api_name]
api_path = info['path']
@@ -774,6 +1559,14 @@ def ref_link_copy_info(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def bonjour_service_info(self) -> dict[str, object] | str:
+ """
+ Get Bonjour service information.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Bonjour service information.
+ """
api_name = 'SYNO.Core.ExternalDevice.Printer.BonjourSharing'
info = self.core_list[api_name]
api_path = info['path']
@@ -782,6 +1575,14 @@ def bonjour_service_info(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def personal_photo_enable(self) -> dict[str, object] | str:
+ """
+ Get personal photo enable status.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Personal photo enable status.
+ """
api_name = 'SYNO.Core.User.Home'
info = self.core_list[api_name]
api_path = info['path']
@@ -790,6 +1591,14 @@ def personal_photo_enable(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def ftp_chroot_user(self) -> dict[str, object] | str:
+ """
+ Get FTP chroot user information.
+
+ Returns
+ -------
+ dict[str, object] or str
+ FTP chroot user information.
+ """
api_name = 'SYNO.Core.FileServ.FTP.ChrootUser'
info = self.core_list[api_name]
api_path = info['path']
@@ -798,6 +1607,14 @@ def ftp_chroot_user(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def server_pair(self) -> dict[str, object] | str:
+ """
+ Get server pair information.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Server pair information.
+ """
api_name = 'SYNO.S2S.Server.Pair'
info = self.gen_list[api_name]
api_path = info['path']
@@ -807,6 +1624,23 @@ def server_pair(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def groups_info(self, offset: int = 0, limit: int = -1, name_only: bool = False) -> dict[str, object] | str:
+ """
+ Get groups information.
+
+ Parameters
+ ----------
+ offset : int, optional
+ Offset for pagination. Defaults to 0.
+ limit : int, optional
+ Maximum number of groups to retrieve. Defaults to -1.
+ name_only : bool, optional
+ If True, returns only group names. Defaults to False.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Groups information.
+ """
api_name = 'SYNO.Core.Group'
info = self.core_list[api_name]
api_path = info['path']
@@ -823,6 +1657,14 @@ def groups_info(self, offset: int = 0, limit: int = -1, name_only: bool = False)
return self.request_data(api_name, api_path, req_param)
def ldap_info(self) -> dict[str, object] | str:
+ """
+ Get LDAP information.
+
+ Returns
+ -------
+ dict[str, object] or str
+ LDAP information.
+ """
api_name = 'SYNO.Core.Directory.LDAP'
info = self.core_list[api_name]
api_path = info['path']
@@ -840,6 +1682,14 @@ def ldap_info(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)'''
def sso_iwa_info(self) -> dict[str, object] | str:
+ """
+ Get SSO IWA information.
+
+ Returns
+ -------
+ dict[str, object] or str
+ SSO IWA information.
+ """
api_name = 'SYNO.Core.Directory.SSO.IWA'
info = self.core_list[api_name]
api_path = info['path']
@@ -848,6 +1698,14 @@ def sso_iwa_info(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def sso_info(self) -> dict[str, object] | str:
+ """
+ Get SSO information.
+
+ Returns
+ -------
+ dict[str, object] or str
+ SSO information.
+ """
api_name = 'SYNO.Core.Directory.SSO'
info = self.core_list[api_name]
api_path = info['path']
@@ -856,6 +1714,14 @@ def sso_info(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def network_interface_info(self) -> dict[str, object] | str:
+ """
+ Get network interface information.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Network interface information.
+ """
api_name = 'SYNO.Core.Network.Interface'
info = self.core_list[api_name]
api_path = info['path']
@@ -864,6 +1730,14 @@ def network_interface_info(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def proxy_info(self) -> dict[str, object] | str:
+ """
+ Get proxy information.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Proxy information.
+ """
api_name = 'SYNO.Core.Network.Proxy'
info = self.core_list[api_name]
api_path = info['path']
@@ -872,6 +1746,21 @@ def proxy_info(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def gateway_list(self, ip_type: str = 'ipv4', type: str = 'wan') -> dict[str, object] | str:
+ """
+ Get gateway list.
+
+ Parameters
+ ----------
+ ip_type : str, optional
+ IP type (e.g., 'ipv4', 'ipv6'). Defaults to 'ipv4'.
+ type : str, optional
+ Gateway type (e.g., 'wan'). Defaults to 'wan'.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Gateway list.
+ """
api_name = 'SYNO.Core.Network.Router.Gateway.List'
info = self.core_list[api_name]
api_path = info['path']
@@ -881,6 +1770,14 @@ def gateway_list(self, ip_type: str = 'ipv4', type: str = 'wan') -> dict[str, ob
return self.request_data(api_name, api_path, req_param)
def firewall_info(self) -> dict[str, object] | str:
+ """
+ Get firewall information.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Firewall information.
+ """
api_name = 'SYNO.Core.Security.Firewall.Profile'
info = self.core_list[api_name]
api_path = info['path']
@@ -901,6 +1798,14 @@ def firewall_info(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)'''
def auto_upgrade_status(self) -> dict[str, object] | str:
+ """
+ Get auto upgrade status.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Auto upgrade status.
+ """
api_name = 'SYNO.Core.Upgrade.AutoUpgrade'
info = self.core_list[api_name]
api_path = info['path']
@@ -909,6 +1814,14 @@ def auto_upgrade_status(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def upgrade_server_check(self) -> dict[str, object] | str:
+ """
+ Check upgrade server.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Upgrade server check result.
+ """
api_name = 'SYNO.Core.Upgrade.Server'
info = self.core_list[api_name]
api_path = info['path']
@@ -918,6 +1831,14 @@ def upgrade_server_check(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def alarm_rules_logs(self) -> dict[str, object] | str:
+ """
+ Get alarm rules logs.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Alarm rules logs.
+ """
api_name = 'SYNO.ResourceMonitor.Log'
info = self.gen_list[api_name]
api_path = info['path']
@@ -927,6 +1848,14 @@ def alarm_rules_logs(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def alarm_rules_list(self) -> dict[str, object] | str:
+ """
+ Get alarm rules list.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Alarm rules list.
+ """
api_name = 'SYNO.ResourceMonitor.EventRule'
info = self.gen_list[api_name]
api_path = info['path']
@@ -935,6 +1864,14 @@ def alarm_rules_list(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def resource_monitor_settings_list(self) -> dict[str, object] | str:
+ """
+ Get resource monitor settings.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Resource monitor settings.
+ """
api_name = 'SYNO.ResourceMonitor.Setting'
info = self.gen_list[api_name]
api_path = info['path']
@@ -944,6 +1881,25 @@ def resource_monitor_settings_list(self) -> dict[str, object] | str:
def file_handling_access(self, sort_direction: str = 'ASC', sort_by: str = 'service', limit: int = 50,
offset: int = 0) -> dict[str, object] | str:
+ """
+ Get file handling access information.
+
+ Parameters
+ ----------
+ sort_direction : str, optional
+ Sort direction ('ASC' or 'DESC'). Defaults to 'ASC'.
+ sort_by : str, optional
+ Field to sort by. Defaults to 'service'.
+ limit : int, optional
+ Maximum number of results. Defaults to 50.
+ offset : int, optional
+ Offset for pagination. Defaults to 0.
+
+ Returns
+ -------
+ dict[str, object] or str
+ File handling access information.
+ """
api_name = 'SYNO.Core.FileHandle'
info = self.core_list[api_name]
api_path = info['path']
@@ -953,6 +1909,19 @@ def file_handling_access(self, sort_direction: str = 'ASC', sort_by: str = 'serv
return self.request_data(api_name, api_path, req_param)
def list_service_group(self, interval=0) -> dict[str, object] | str:
+ """
+ Get service group list.
+
+ Parameters
+ ----------
+ interval : int, optional
+ Interval for statistics. Defaults to 0.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Service group list.
+ """
api_name = 'SYNO.Core.System.ProcessGroup'
info = self.core_list[api_name]
api_path = info['path']
@@ -962,6 +1931,14 @@ def list_service_group(self, interval=0) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def list_process_group(self) -> dict[str, object] | str:
+ """
+ Get process group list.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Process group list.
+ """
api_name = 'SYNO.Core.System.Process'
info = self.core_list[api_name]
api_path = info['path']
@@ -970,6 +1947,14 @@ def list_process_group(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def installed_package_list(self) -> dict[str, object] | str:
+ """
+ Get installed package list.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Installed package list.
+ """
api_name = 'SYNO.Core.Package'
info = self.core_list[api_name]
api_path = info['path']
@@ -988,6 +1973,14 @@ def installed_package_list(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def active_notifications(self) -> dict[str, object] | str:
+ """
+ Get active notifications.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Active notifications.
+ """
api_name = 'SYNO.Core.DSMNotify'
info = self.core_list[api_name]
api_path = info['path']
@@ -997,6 +1990,14 @@ def active_notifications(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def get_system_health(self) -> dict[str, object] | str:
+ """
+ Get system health information.
+
+ Returns
+ -------
+ dict[str, object] or str
+ System health information.
+ """
api_name = 'SYNO.Core.System.SystemHealth'
info = self.core_list[api_name]
api_path = info['path']
@@ -1004,6 +2005,14 @@ def get_system_health(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def upgrade_status(self) -> dict[str, object] | str:
+ """
+ Get upgrade status.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Upgrade status.
+ """
api_name = 'SYNO.Core.Upgrade'
info = self.core_list[api_name]
api_path = info['path']
diff --git a/synology_api/core_user.py b/synology_api/core_user.py
index 536fb66a..3dd86e21 100644
--- a/synology_api/core_user.py
+++ b/synology_api/core_user.py
@@ -1,98 +1,120 @@
+"""
+Synology Core User API wrapper.
+
+This module provides a Python interface for managing users on Synology NAS devices,
+including user creation, modification, deletion, group membership, password policies,
+and password expiry.
+"""
+
import json
from typing import Any
from . import base_api
class User(base_api.BaseApi):
- """Core User API implementation.
-
- Supported actions:
- - Getters:
- - Get all users
- - Password policies
- - Password expiry
-
- - Setters:
- - Set user password policy
-
- - Actions:
- - Create new user
- - Modify user
- - Delete user
- - User join/leave group
+ """
+ Core User API implementation.
+
+ Methods
+ -------
+ get_users(offset=0, limit=-1, sort_by="name", sort_direction="ASC", additional=[])
+ Retrieve groups information.
+ get_user(name, additional=[])
+ Retrieve user information.
+ create_user(...)
+ Create a new user.
+ modify_user(...)
+ Modify a user.
+ delete_user(name)
+ Delete a user.
+ affect_groups(name, join_groups=[], leave_groups=[])
+ Affect or disaffect groups to a user.
+ affect_groups_status(task_id)
+ Get the status of a join task.
+ get_password_policy()
+ Get the password policy.
+ set_password_policy(...)
+ Set the password policy.
+ get_password_expiry()
+ Get the password expiry.
+ set_password_expiry(...)
+ Set the password expiry.
+ password_confirm(password)
+ Confirm password/session.
+ get_username_policy()
+ Get the username policy.
+
+ Examples
+ --------
+ See individual method docstrings for usage examples.
"""
def get_users(
self, offset: int = 0, limit: int = -1, sort_by: str = "name", sort_direction: str = "ASC", additional: list[str] = []
) -> dict[str, object]:
- """Retrieve groups information.
-
- Parameters
- ----------
- offset : int, optional
- The offset of the groups to retrieve. Defaults to `0`.
-
- limit : int, optional
- The maximum number of groups to retrieve. Defaults to `-1` .
-
- sort_by : str, optional
- Sort by a specific field. Defaults to `"name"`.
-
- sort_direction : str, optional
- The sort direction. Defaults to `"ASC"` else `"DESC"`.
-
- additional : list[str], optional
- Additional fields to retrieve. Defaults to `[]`.
-
- All fields known are: `["description","email","expired","cannot_chg_passwd","passwd_never_expire","password_last_change", "groups", "2fa_status"]`.
-
-
- Returns
- -------
- dict[str, object]
- A dictionary containing the groups information.
-
- Examples
- --------
- ```json
- {
- "data": {
- "offset": 0,
- "total": 5,
- "users": [
- {
- "description": "System default user",
- "email": "",
- "expired": "now",
- "name": "admin",
- "passwd_never_expire": true
- },
- {
- "description": "Guest",
- "email": "",
- "expired": "now",
- "name": "guest",
- "passwd_never_expire": true
- },
- {
- "description": "",
- "email": "",
- "expired": "normal",
- "name": "test_api",
- "passwd_never_expire": true
- },
- {
- "description": "test description",
- "email": "testemail@test.com",
- "expired": "normal",
- "name": "test_user",
- "passwd_never_expire": true
- }
- ]
+ """
+ Retrieve groups information.
+
+ Parameters
+ ----------
+ offset : int, optional
+ The offset of the groups to retrieve. Defaults to `0`.
+ limit : int, optional
+ The maximum number of groups to retrieve. Defaults to `-1`.
+ sort_by : str, optional
+ Sort by a specific field. Defaults to `"name"`.
+ sort_direction : str, optional
+ The sort direction. Defaults to `"ASC"` else `"DESC"`.
+ additional : list[str], optional
+ Additional fields to retrieve. Defaults to `[]`.
+ All fields known are: `["description","email","expired","cannot_chg_passwd","passwd_never_expire","password_last_change", "groups", "2fa_status"]`.
+
+ Returns
+ -------
+ dict[str, object]
+ A dictionary containing the groups information.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "offset": 0,
+ "total": 5,
+ "users": [
+ {
+ "description": "System default user",
+ "email": "",
+ "expired": "now",
+ "name": "admin",
+ "passwd_never_expire": true
},
- "success": true
- }
- ```
+ {
+ "description": "Guest",
+ "email": "",
+ "expired": "now",
+ "name": "guest",
+ "passwd_never_expire": true
+ },
+ {
+ "description": "",
+ "email": "",
+ "expired": "normal",
+ "name": "test_api",
+ "passwd_never_expire": true
+ },
+ {
+ "description": "test description",
+ "email": "testemail@test.com",
+ "expired": "normal",
+ "name": "test_user",
+ "passwd_never_expire": true
+ }
+ ]
+ },
+ "success": true
+ }
+ ```
"""
api_name = "SYNO.Core.User"
info = self.core_list[api_name]
@@ -111,48 +133,47 @@ def get_users(
return self.request_data(api_name, api_path, req_param)
def get_user(self, name: str, additional: list[str] = []) -> dict[str, object]:
- """Retrieve a user information.
-
- Parameters
- ----------
- name : str
- The name of the user.
-
- additional : list[str], optional
- Additional fields to retrieve. Defaults to `[]`.
-
- All fields known are: `["description","email","expired","cannot_chg_passwd","passwd_never_expire","password_last_change","is_password_pending"]`.
-
- Returns
- -------
- dict[str, object]
- A dictionary containing the user information.
-
- Examples
- --------
- ```json
- {
- "api": "SYNO.Core.User",
- "data": {
- "users": [
- {
- "cannot_chg_passwd": false,
- "description": "",
- "email": "",
- "expired": "normal",
- "is_password_pending": false,
- "name": "test_api",
- "passwd_never_expire": true,
- "password_last_change": 19789,
- "uid": 1027
- }
- ]
- },
- "method": "get",
- "success": true,
- "version": 1
- }
- ```
+ """
+ Retrieve user information.
+
+ Parameters
+ ----------
+ name : str
+ The name of the user.
+ additional : list[str], optional
+ Additional fields to retrieve. Defaults to `[]`.
+ All fields known are: `["description","email","expired","cannot_chg_passwd","passwd_never_expire","password_last_change","is_password_pending"]`.
+
+ Returns
+ -------
+ dict[str, object]
+ A dictionary containing the user information.
+
+ Examples
+ --------
+ ```json
+ {
+ "api": "SYNO.Core.User",
+ "data": {
+ "users": [
+ {
+ "cannot_chg_passwd": false,
+ "description": "",
+ "email": "",
+ "expired": "normal",
+ "is_password_pending": false,
+ "name": "test_api",
+ "passwd_never_expire": true,
+ "password_last_change": 19789,
+ "uid": 1027
+ }
+ ]
+ },
+ "method": "get",
+ "success": true,
+ "version": 1
+ }
+ ```
"""
api_name = "SYNO.Core.User"
info = self.core_list[api_name]
@@ -171,54 +192,47 @@ def create_user(
self, name: str, password: str, description: str = "", email: str = "", expire: str = "never", cannot_chg_passwd: bool = False,
passwd_never_expire: bool = True, notify_by_email: bool = False, send_password: bool = False
) -> dict[str, object]:
- """Create a new user.
-
- Parameters
- ----------
- name : str
- The name of the user.
-
- password : str
- The password of the user.
-
- description : str, optional
- The description of the user. Defaults to `""`.
-
- email : str, optional
- The email of the user. Defaults to `""`.
-
- expire : str, optional
- The expiration date of the user. Defaults to `"never"`.
-
- cannot_chg_passwd : bool, optional
- Whether the password can be changed. Defaults to `False`.
-
- passwd_never_expire : bool, optional
- Whether the password should never expire. Defaults to `True`.
-
- notify_by_email : bool, optional
- Whether to notify by email. Defaults to `False`.
-
- send_password : bool, optional
- Whether to send the password. Defaults to `False`.
-
- Returns
- -------
- dict[str, object]
- A dictionary containing the user information.
-
- Examples
- --------
- ```json
+ """
+ Create a new user.
+
+ Parameters
+ ----------
+ name : str
+ The name of the user.
+ password : str
+ The password of the user.
+ description : str, optional
+ The description of the user. Defaults to `""`.
+ email : str, optional
+ The email of the user. Defaults to `""`.
+ expire : str, optional
+ The expiration date of the user. Defaults to `"never"`.
+ cannot_chg_passwd : bool, optional
+ Whether the password can be changed. Defaults to `False`.
+ passwd_never_expire : bool, optional
+ Whether the password should never expire. Defaults to `True`.
+ notify_by_email : bool, optional
+ Whether to notify by email. Defaults to `False`.
+ send_password : bool, optional
+ Whether to send the password. Defaults to `False`.
+
+ Returns
+ -------
+ dict[str, object]
+ A dictionary containing the user information.
+
+ Examples
+ --------
+ ```json
+ {
+ "data":
{
- "data":
- {
- "name":"toto",
- "uid": 1030
- },
- "success": true
- }
- ```
+ "name":"toto",
+ "uid": 1030
+ },
+ "success": true
+ }
+ ```
"""
api_name = "SYNO.Core.User"
@@ -254,57 +268,49 @@ def modify_user(
self, name: str, new_name: str, password: str = "", description: str = "", email: str = "", expire: str = "never", cannot_chg_passwd: bool = False,
passwd_never_expire: bool = True, notify_by_email: bool = False, send_password: bool = False
) -> dict[str, object]:
- """Modify a user.
-
- Parameters
- ----------
- name : str
- The name of the actual user.
-
- new_name : str
- The new name of the user.
-
- password : str, optional
- The password of the user. Defaults to `""`.
-
- description : str, optional
- The description of the user. Defaults to `""`.
-
- email : str, optional
- The email of the user. Defaults to `""`.
-
- expire : str, optional
- The expiration date of the user. Defaults to `"never"`.
-
- cannot_chg_passwd : bool, optional
- Whether the password can be changed. Defaults to `False`.
-
- passwd_never_expire : bool, optional
- Whether the password should never expire. Defaults to `True`.
-
- notify_by_email : bool, optional
- Whether to notify by email. Defaults to `False`.
-
- send_password : bool, optional
- Whether to send the password. Defaults to `False`.
-
- Returns
- -------
- dict[str, object]
- A dictionary containing the user information.
-
- Examples
- --------
- ```json
- {
- "data":{
- "name": "test_user2",
- "password_last_change": 20106,
- "uid": 1028
- },
- "success": true
- }
- ```
+ """
+ Modify a user.
+
+ Parameters
+ ----------
+ name : str
+ The name of the actual user.
+ new_name : str
+ The new name of the user.
+ password : str, optional
+ The password of the user. Defaults to `""`.
+ description : str, optional
+ The description of the user. Defaults to `""`.
+ email : str, optional
+ The email of the user. Defaults to `""`.
+ expire : str, optional
+ The expiration date of the user. Defaults to `"never"`.
+ cannot_chg_passwd : bool, optional
+ Whether the password can be changed. Defaults to `False`.
+ passwd_never_expire : bool, optional
+ Whether the password should never expire. Defaults to `True`.
+ notify_by_email : bool, optional
+ Whether to notify by email. Defaults to `False`.
+ send_password : bool, optional
+ Whether to send the password. Defaults to `False`.
+
+ Returns
+ -------
+ dict[str, object]
+ A dictionary containing the user information.
+
+ Examples
+ --------
+ ```json
+ {
+ "data":{
+ "name": "test_user2",
+ "password_last_change": 20106,
+ "uid": 1028
+ },
+ "success": true
+ }
+ ```
"""
api_name = "SYNO.Core.User"
info = self.core_list[api_name]
@@ -333,29 +339,30 @@ def modify_user(
return self.request_data(api_name, api_path, req_param, method="post")
def delete_user(self, name: str) -> dict[str, object]:
- """Delete a user.
-
- Parameters
- ----------
- name : str
- The name of the user to delete.
-
- Returns
- -------
- dict[str, object]
- A dictionary containing the user information.
-
- Examples
- --------
- ```json
- {
- "data": {
- "name": "toto",
- "uid": 1030
- },
- "success": true
- }
- ```
+ """
+ Delete a user.
+
+ Parameters
+ ----------
+ name : str
+ The name of the user to delete.
+
+ Returns
+ -------
+ dict[str, object]
+ A dictionary containing the user information.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "name": "toto",
+ "uid": 1030
+ },
+ "success": true
+ }
+ ```
"""
api_name = "SYNO.Core.User"
info = self.core_list[api_name]
@@ -369,40 +376,38 @@ def delete_user(self, name: str) -> dict[str, object]:
return self.request_data(api_name, api_path, req_param)
def affect_groups(self, name: str, join_groups: list[str] = [], leave_groups: list[str] = []) -> dict[str, object]:
- """Affect or disaffect groups to a user.
-
- Tip: This request is asynchronous and will return a task id to check the status of the join task. Use `affect_groups_status` func to check the status of the task.
-
- Parameters
- ----------
- name : str
- The name of the user.
-
- join_groups : list[str]
- The names of the groups to join.
-
- leave_groups : list[str]
- The names of the groups to leave.
-
-
- Returns
- -------
- dict[str, object]
- A dictionary containing the task id to check the status of the join task. Use `affect_groups_status` func to check the status of the task.
-
- Examples
- --------
- ```json
- {
- "api": "SYNO.Core.User.Group",
- "data": {
- "task_id": "@administrators/groupbatch1737238746C6723E33"
- },
- "method": "join",
- "success": true,
- "version": 1
- }
- ```
+ """
+ Affect or disaffect groups to a user.
+
+ Tip: This request is asynchronous and will return a task id to check the status of the join task. Use `affect_groups_status` func to check the status of the task.
+
+ Parameters
+ ----------
+ name : str
+ The name of the user.
+ join_groups : list[str]
+ The names of the groups to join.
+ leave_groups : list[str]
+ The names of the groups to leave.
+
+ Returns
+ -------
+ dict[str, object]
+ A dictionary containing the task id to check the status of the join task. Use `affect_groups_status` func to check the status of the task.
+
+ Examples
+ --------
+ ```json
+ {
+ "api": "SYNO.Core.User.Group",
+ "data": {
+ "task_id": "@administrators/groupbatch1737238746C6723E33"
+ },
+ "method": "join",
+ "success": true,
+ "version": 1
+ }
+ ```
"""
api_name = "SYNO.Core.User.Group"
@@ -418,44 +423,45 @@ def affect_groups(self, name: str, join_groups: list[str] = [], leave_groups: li
return self.request_data(api_name, api_path, req_param)
def affect_groups_status(self, task_id: str):
- """Get the status of a join task.
-
- Parameters
- ----------
- task_id : str
- The task id of the join task.
-
- Returns
- -------
- dict[str, object]
- A dictionary containing the status of the join task.
-
- Examples
- --------
- ```json
- {
+ """
+ Get the status of a join task.
+
+ Parameters
+ ----------
+ task_id : str
+ The task id of the join task.
+
+ Returns
+ -------
+ dict[str, object]
+ A dictionary containing the status of the join task.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "auto_remove": false,
"data": {
- "auto_remove": false,
- "data": {
- "name": "test_user2",
- "pid": 18126,
- "progress": 1,
- "total": 1,
- "uid": 1028
- },
- "finish": false,
- "info": {
- "api": "SYNO.Core.User.Group",
- "group": "admin",
- "method": "join",
- "prefix": "groupbatch",
- "version": 1
- },
- "success": true
+ "name": "test_user2",
+ "pid": 18126,
+ "progress": 1,
+ "total": 1,
+ "uid": 1028
+ },
+ "finish": false,
+ "info": {
+ "api": "SYNO.Core.User.Group",
+ "group": "admin",
+ "method": "join",
+ "prefix": "groupbatch",
+ "version": 1
},
"success": true
- }
- ```
+ },
+ "success": true
+ }
+ ```
"""
api_name = "SYNO.Core.User.Group"
info = self.core_list[api_name]
@@ -468,36 +474,37 @@ def affect_groups_status(self, task_id: str):
return self.request_data(api_name, api_path, req_param)
def get_password_policy(self) -> dict[str, object]:
- """Get the password policy.
-
- Returns
- -------
- dict[str, object]
- A dictionary containing the password policy information.
-
- Examples
- --------
- ```json
- {
- "api": "SYNO.Core.User.PasswordPolicy",
- "data": {
- "enable_reset_passwd_by_email": false,
- "password_must_change": false,
- "strong_password": {
- "exclude_username": true,
- "history_num": 0,
- "included_numeric_char": true,
- "included_special_char": false,
- "min_length": 8,
- "min_length_enable": true,
- "mixed_case": true
- }
- },
- "method": "get",
- "success": true,
- "version": 1
- }
- ```
+ """
+ Get the password policy.
+
+ Returns
+ -------
+ dict[str, object]
+ A dictionary containing the password policy information.
+
+ Examples
+ --------
+ ```json
+ {
+ "api": "SYNO.Core.User.PasswordPolicy",
+ "data": {
+ "enable_reset_passwd_by_email": false,
+ "password_must_change": false,
+ "strong_password": {
+ "exclude_username": true,
+ "history_num": 0,
+ "included_numeric_char": true,
+ "included_special_char": false,
+ "min_length": 8,
+ "min_length_enable": true,
+ "mixed_case": true
+ }
+ },
+ "method": "get",
+ "success": true,
+ "version": 1
+ }
+ ```
"""
api_name = "SYNO.Core.User.PasswordPolicy"
info = self.core_list[api_name]
@@ -514,56 +521,48 @@ def set_password_policy(
min_length: int = 8, min_length_enable: bool = True, mixed_case: bool = True,
exclude_common_password: bool = False, exclude_history: bool = False
) -> dict[str, object]:
- """Set the password policy.
-
- Parameters
- ----------
- enable_reset_passwd_by_email : bool, optional
- Defaults to `False`.
-
- password_must_change : bool, optional
- Defaults to `False`.
-
- exclude_username : bool, optional
- Defaults to `True`.
-
- included_numeric_char : bool, optional
- Defaults to `True`.
-
- included_special_char : bool, optional
- Defaults to `False`.
-
- min_length : int, optional
- Defaults to `8`.
-
- min_length_enable : bool, optional
- Defaults to `True`.
-
- mixed_case : bool, optional
- Defaults to `True`.
-
- exclude_common_password : bool, optional
- Defaults to `False`.
-
- exclude_history : bool, optional
- Defaults to `False`.
-
- Returns
- -------
- dict[str, object]
- A dictionary indicating the success of the operation.
-
- Examples
- --------
- ```json
- {
- "api": "SYNO.Core.User.PasswordPolicy",
- "data": {},
- "method": "set",
- "success": true,
- "version": 1
- }
- ```
+ """
+ Set the password policy.
+
+ Parameters
+ ----------
+ enable_reset_passwd_by_email : bool, optional
+ Defaults to `False`.
+ password_must_change : bool, optional
+ Defaults to `False`.
+ exclude_username : bool, optional
+ Defaults to `True`.
+ included_numeric_char : bool, optional
+ Defaults to `True`.
+ included_special_char : bool, optional
+ Defaults to `False`.
+ min_length : int, optional
+ Defaults to `8`.
+ min_length_enable : bool, optional
+ Defaults to `True`.
+ mixed_case : bool, optional
+ Defaults to `True`.
+ exclude_common_password : bool, optional
+ Defaults to `False`.
+ exclude_history : bool, optional
+ Defaults to `False`.
+
+ Returns
+ -------
+ dict[str, object]
+ A dictionary indicating the success of the operation.
+
+ Examples
+ --------
+ ```json
+ {
+ "api": "SYNO.Core.User.PasswordPolicy",
+ "data": {},
+ "method": "set",
+ "success": true,
+ "version": 1
+ }
+ ```
"""
api_name = "SYNO.Core.User.PasswordPolicy"
@@ -588,31 +587,32 @@ def set_password_policy(
return self.request_data(api_name, api_path, req_param)
def get_password_expiry(self) -> dict[str, object]:
- """Get the password expiry.
-
- Returns
- -------
- dict[str, object]
- A dictionary containing the password expiry information.
-
- Examples
- --------
- ```json
- {
- "api": "SYNO.Core.User.PasswordExpiry",
- "data": {
- "allow_reset_after_expired": true,
- "enable_login_prompt": false,
- "enable_mail_notification": false,
- "mail_notification_days": "",
- "min_age_enable": false,
- "password_expire_enable": false
- },
- "method": "get",
- "success": true,
- "version": 1
- }
- ```
+ """
+ Get the password expiry.
+
+ Returns
+ -------
+ dict[str, object]
+ A dictionary containing the password expiry information.
+
+ Examples
+ --------
+ ```json
+ {
+ "api": "SYNO.Core.User.PasswordExpiry",
+ "data": {
+ "allow_reset_after_expired": true,
+ "enable_login_prompt": false,
+ "enable_mail_notification": false,
+ "mail_notification_days": "",
+ "min_age_enable": false,
+ "password_expire_enable": false
+ },
+ "method": "get",
+ "success": true,
+ "version": 1
+ }
+ ```
"""
api_name = "SYNO.Core.User.PasswordExpiry"
info = self.core_list[api_name]
@@ -628,52 +628,45 @@ def set_password_expiry(
enable_login_prompt: bool = False, login_prompt_days: int = 1, allow_reset_after_expired: bool = True,
enable_mail_notification: bool = False, never_expired_list: list[str] = []
) -> dict[str, object]:
- """Set the password expiry.
-
- Parameters
- ----------
- password_expire_enable : bool, optional
- Enable password expiry. Defaults to `False`.
-
- max_age : int, optional
- Maximum time before password expiry. Defaults to `30`.
-
- min_age_enable : bool, optional
- Enable minimum time before password expiry. Defaults to `False`.
-
- min_age : int, optional
- Minimum time before password expiry. Defaults to `1`.
-
- enable_login_prompt : bool, optional
- Enable login prompt. Defaults to `False`.
-
- login_prompt_days : int, optional
- Days before login prompt. Defaults to `1`.
-
- allow_reset_after_expired : bool, optional
- Allow reset after password expiry. Defaults to `True`.
-
- enable_mail_notification : bool, optional
- Enable mail notification. Defaults to `False`.
-
- never_expired_list : list[str], optional
- List of users that should never expire.
-
- Returns
- -------
- dict[str, object]
- A dictionary indicating the success of the operation.
-
- Examples
- --------
- ```json
- {
- "api": "SYNO.Core.User.PasswordExpiry",
- "method": "set",
- "success": true,
- "version": 1
- }
- ```
+ """
+ Set the password expiry.
+
+ Parameters
+ ----------
+ password_expire_enable : bool, optional
+ Enable password expiry. Defaults to `False`.
+ max_age : int, optional
+ Maximum time before password expiry. Defaults to `30`.
+ min_age_enable : bool, optional
+ Enable minimum time before password expiry. Defaults to `False`.
+ min_age : int, optional
+ Minimum time before password expiry. Defaults to `1`.
+ enable_login_prompt : bool, optional
+ Enable login prompt. Defaults to `False`.
+ login_prompt_days : int, optional
+ Days before login prompt. Defaults to `1`.
+ allow_reset_after_expired : bool, optional
+ Allow reset after password expiry. Defaults to `True`.
+ enable_mail_notification : bool, optional
+ Enable mail notification. Defaults to `False`.
+ never_expired_list : list[str], optional
+ List of users that should never expire.
+
+ Returns
+ -------
+ dict[str, object]
+ A dictionary indicating the success of the operation.
+
+ Examples
+ --------
+ ```json
+ {
+ "api": "SYNO.Core.User.PasswordExpiry",
+ "method": "set",
+ "success": true,
+ "version": 1
+ }
+ ```
"""
api_name = "SYNO.Core.User.PasswordExpiry"
@@ -695,30 +688,31 @@ def set_password_expiry(
return self.request_data(api_name, api_path, req_param)
def password_confirm(self, password: str) -> dict[str, object]:
- """Issues a passowrd/session comparison to ensure the given password matches the auth of the current session.
-
- Note: This is needed by some APIs as a confirmation method, for example, when creating/modifying a scheduled task with root permissions, seldom needed by end users.
-
- Parameters
- ----------
- password : str
- The password with which the session was initiated.
-
- Returns
- -------
- dict[str, object]
- A dictionary containing a `SynoConfirmPWToken`, or an error message.
-
- Examples
- --------
- ```json
- {
- "data": {
- "SynoConfirmPWToken": "xxxxx"
- },
- "success": true
- }
- ```
+ """
+ Confirm password/session to ensure the given password matches the auth of the current session.
+
+ Note: This is needed by some APIs as a confirmation method, for example, when creating/modifying a scheduled task with root permissions, seldom needed by end users.
+
+ Parameters
+ ----------
+ password : str
+ The password with which the session was initiated.
+
+ Returns
+ -------
+ dict[str, object]
+ A dictionary containing a `SynoConfirmPWToken`, or an error message.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "SynoConfirmPWToken": "xxxxx"
+ },
+ "success": true
+ }
+ ```
"""
api_name = 'SYNO.Core.User.PasswordConfirm'
info = self.core_list[api_name]
@@ -735,24 +729,25 @@ def password_confirm(self, password: str) -> dict[str, object]:
return self.request_data(api_name, api_path, req_param, method="post")
def get_username_policy(self) -> dict[str, object]:
- """Get the username policy (List of username that are not usable).
-
- Returns
- -------
- dict[str, object]
- A dictionary containing the username policy information.
-
- Examples
- --------
- ```json
- {
- "api": "SYNO.Core.User.UsernamePolicy",
- "data": ["root", "rootuser", "rootusr", "admin", "administrator", "adm", "adminuser", "adminusr", "user",…],
- "method": "get",
- "success": true,
- "version": 1
- }
- ```
+ """
+ Get the username policy (list of usernames that are not usable).
+
+ Returns
+ -------
+ dict[str, object]
+ A dictionary containing the username policy information.
+
+ Examples
+ --------
+ ```json
+ {
+ "api": "SYNO.Core.User.UsernamePolicy",
+ "data": ["root", "rootuser", "rootusr", "admin", "administrator", "adm", "adminuser", "adminusr", "user",…],
+ "method": "get",
+ "success": true,
+ "version": 1
+ }
+ ```
"""
api_name = "SYNO.Core.User.UsernamePolicy"
info = self.core_list[api_name]
diff --git a/synology_api/dhcp_server.py b/synology_api/dhcp_server.py
index 367408e4..fd7bd4eb 100644
--- a/synology_api/dhcp_server.py
+++ b/synology_api/dhcp_server.py
@@ -1,3 +1,10 @@
+"""
+Synology DHCP Server API wrapper.
+
+This module provides a Python interface for managing DHCP server, PXE, TFTP, and network
+interfaces on Synology NAS devices.
+"""
+
from __future__ import annotations
from typing import Optional
@@ -6,8 +13,27 @@
class DhcpServer(base_api.BaseApi):
+ """
+ Core DHCP Server API implementation for Synology NAS.
+
+ This class provides methods to retrieve and manage DHCP server, PXE, TFTP, and network
+ interface information.
+ """
def general_info(self, ifname: str = 'ovs_eth0') -> dict[str, object] | str:
+ """
+ Get general DHCP server information for a given interface.
+
+ Parameters
+ ----------
+ ifname : str, optional
+ Interface name. Defaults to 'ovs_eth0'.
+
+ Returns
+ -------
+ dict[str, object] or str
+ General DHCP server information.
+ """
api_name = 'SYNO.Network.DHCPServer'
info = self.gen_list[api_name]
api_path = info['path']
@@ -17,6 +43,14 @@ def general_info(self, ifname: str = 'ovs_eth0') -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def vendor(self) -> dict[str, object] | str:
+ """
+ Get DHCP vendor information.
+
+ Returns
+ -------
+ dict[str, object] or str
+ DHCP vendor information.
+ """
api_name = 'SYNO.Network.DHCPServer.Vendor'
info = self.gen_list[api_name]
api_path = info['path']
@@ -25,6 +59,14 @@ def vendor(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def pxe(self) -> dict[str, object] | str:
+ """
+ Get PXE server information.
+
+ Returns
+ -------
+ dict[str, object] or str
+ PXE server information.
+ """
api_name = 'SYNO.Network.DHCPServer.PXE'
info = self.gen_list[api_name]
api_path = info['path']
@@ -33,6 +75,14 @@ def pxe(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def tftp(self) -> dict[str, object] | str:
+ """
+ Get TFTP server information.
+
+ Returns
+ -------
+ dict[str, object] or str
+ TFTP server information.
+ """
api_name = 'SYNO.Core.TFTP'
info = self.core_list[api_name]
api_path = info['path']
@@ -41,6 +91,14 @@ def tftp(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def network_bond(self) -> dict[str, object] | str:
+ """
+ Get network bond interface information.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Network bond interface information.
+ """
api_name = 'SYNO.Core.Network.Bond'
info = self.gen_list[api_name]
api_path = info['path']
@@ -49,6 +107,14 @@ def network_bond(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def network_ethernet(self) -> dict[str, object] | str:
+ """
+ Get network ethernet interface information.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Network ethernet interface information.
+ """
api_name = 'SYNO.Core.Network.Ethernet'
info = self.gen_list[api_name]
api_path = info['path']
@@ -57,6 +123,19 @@ def network_ethernet(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def dhcp_clientlist(self, ifname: str = 'bond0') -> dict[str, object] | str:
+ """
+ Get DHCP client list for a given interface.
+
+ Parameters
+ ----------
+ ifname : str, optional
+ Interface name. Defaults to 'bond0'.
+
+ Returns
+ -------
+ dict[str, object] or str
+ DHCP client list.
+ """
api_name = 'SYNO.Network.DHCPServer.ClientList'
info = self.gen_list[api_name]
api_path = info['path']
@@ -66,6 +145,19 @@ def dhcp_clientlist(self, ifname: str = 'bond0') -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def dhcp_reservations(self, ifname: str = 'bond0') -> dict[str, object] | str:
+ """
+ Get DHCP reservations for a given interface.
+
+ Parameters
+ ----------
+ ifname : str, optional
+ Interface name. Defaults to 'bond0'.
+
+ Returns
+ -------
+ dict[str, object] or str
+ DHCP reservations.
+ """
api_name = 'SYNO.Network.DHCPServer.Reservation'
info = self.gen_list[api_name]
api_path = info['path']
diff --git a/synology_api/directory_server.py b/synology_api/directory_server.py
index f5a783a2..3750f69c 100644
--- a/synology_api/directory_server.py
+++ b/synology_api/directory_server.py
@@ -1,21 +1,25 @@
-"""directory_server.py works with base_api_core to provide AD capabilities."""
+"""Directory_server.py works with base_api_core to provide AD capabilities."""
+
from __future__ import annotations
import json
+import time
from typing import Optional, Any
from . import base_api
class DirectoryServer(base_api.BaseApi):
- """The directory server API.
+ """
+ The directory server API.
- Not all items within this class use the Active Directory API. Some use the Synology Entry API which proxies
- the request. Some are related to managing users in ways that are useful in the Directory Server context. For
+ Not all items within this class use the Active Directory API. Some use the Synology Entry API which proxies
+ the request. Some are related to managing users in ways that are useful in the Directory Server context. For
example, sending a user password reset email, or updating the user information. This api works slightly
differently than other similar APIs. There are multi-leveled calls where Synology makes requests on behalf of
the original request and relays information back. Additionally, the query-string api item is not used often in
this class as API is defined within the actual request.
The APIs in this class are tested working against the following scenarios:
+
- Getters:
- Get Active Directory information
- List objects within a Base DN on the Active Directory Server
@@ -36,43 +40,44 @@ class DirectoryServer(base_api.BaseApi):
"""
def get_directory_info(self) -> dict[str, object]:
- """Gets directory info.
-
- Returns
- -------
- dict[str, object]
- Information about your domain.
-
- Examples
- --------
- ```json
- {
+ """
+ Get directory info.
+
+ Returns
+ -------
+ dict[str, object]
+ Information about your domain.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
"data": {
- "data": {
- "domainBasicInfo": {
- "realm": "MY.DOMAIN.COM",
- "workgroup": "NETBIOSNAME"
- },
- "domainControllers": [
- {
- "cn": "AD",
- "dn": "CN=AD,OU=Domain Controllers,DC=MY,DC=DOMAIN,DC=COM",
- "dnshostname": "AD.MY.DOMAIN.COM",
- "roles": [
- "pdc",
- "rid",
- "schema",
- "naming",
- "infrastructure"
- ]
- }
+ "domainBasicInfo": {
+ "realm": "MY.DOMAIN.COM",
+ "workgroup": "NETBIOSNAME"
+ },
+ "domainControllers": [
+ {
+ "cn": "AD",
+ "dn": "CN=AD,OU=Domain Controllers,DC=MY,DC=DOMAIN,DC=COM",
+ "dnshostname": "AD.MY.DOMAIN.COM",
+ "roles": [
+ "pdc",
+ "rid",
+ "schema",
+ "naming",
+ "infrastructure"
]
- },
- "status": "running"
+ }
+ ]
},
- "success": true
- }
- ```
+ "status": "running"
+ },
+ "success": true
+ }
+ ```
"""
api_name = 'SYNO.ActiveDirectory.Info'
info = {'maxVersion': 3, 'minVersion': 1,
@@ -89,68 +94,61 @@ def list_directory_objects(self,
objectCategory: list[str] = [
"person", "group", "organizationalUnit", "computer", "container", "builtinDomain"]
) -> dict[str, object]:
- """lists directory objects.
-
- Parameters
- ----------
- basedn : str
- The Base DN for the search. eg. `CN=Users,CN=MY,CN=DOMAIN,CN=COM" or CN=MY,CN=DOMAIN,CN=COM`
-
- offset : int, optional
- When searching large data, you may wish to start at a certain number, e.g. for 10 at a time one
- would set the limit to 10 and the offset by multiples of 10 for each request.
- Defaults to `0`
-
- limit : int, optional
- The numeric the number of maximum objects to return.
- Defaults to `40`
-
- objectCategory : optional, list[str]
- The categories of items to search. e.g. `["organizationalUnit","container","builtinDomain"]` for a list of
- base server containers, and `["person","group","organizationalUnit","computer"]` for a list of contained objects.
- Defaults to `["person","group","organizationalUnit","computer","container","builtinDomain"]`
-
- Returns
- -------
- dict[str, object]
- The result of this method is a dictionary object with a 'data' dictionary and a 'success' dictionary.
-
- The first level is the success to the AD server. The second Data level is the status of the actual request.
-
- Since this is a compound request, the data contains an object with it's own request and results contained within. The object will explain any issues with the request.
-
- Examples
- --------
- ```json
- {
- "data": {
- "data": [
- {
- "accountExpiryTime": 910692730085,
- "deletable": true,
- "description": "This is a description of a user person",
- "disabled": false,
- "displayName": "John Doe",
- "dn": "CN=jdoe,CN=Users,DC=MY,DC=DOMAIN,DC=COM",
- "locked": false,
- "mail": "jdoe@MY.EMAIL.COM",
- "movable": true,
- "name": "john",
- "objectCategory": "person",
- "passwordExpired": true,
- "physicalDeliveryOfficeName": "official office of officers",
- "primaryGroupToken": 0,
- "renamable": true,
- "sAMAccountName": "jdoe",
- "showInAdvancedViewOnly": false,
- "telephoneNumber": "123-444-5677"
- },
- ],
- "total": 99999
+ """
+ List directory objects.
+
+ Parameters
+ ----------
+ basedn : str
+ The Base DN for the search. E.g. `CN=Users,CN=MY,CN=DOMAIN,CN=COM` or `CN=MY,CN=DOMAIN,CN=COM`.
+ offset : int, optional
+ When searching large data, you may wish to start at a certain number, e.g. for 10 at a time one
+ would set the limit to 10 and the offset by multiples of 10 for each request. Defaults to `0`.
+ limit : int, optional
+ The number of maximum objects to return. Defaults to `40`.
+ objectCategory : list[str], optional
+ The categories of items to search. E.g. `["organizationalUnit","container","builtinDomain"]` for a list of
+ base server containers, and `["person","group","organizationalUnit","computer"]` for a list of contained objects.
+ Defaults to `["person","group","organizationalUnit","computer","container","builtinDomain"]`.
+
+ Returns
+ -------
+ dict[str, object]
+ The result of this method is a dictionary object with a 'data' dictionary and a 'success' dictionary. The first level is the success to the AD server. The second Data level is the status of the actual request.
+ Since this is a compound request, the data contains an object with it's own request and results contained within. The object will explain any issues with the request.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "data": [
+ {
+ "accountExpiryTime": 910692730085,
+ "deletable": true,
+ "description": "This is a description of a user person",
+ "disabled": false,
+ "displayName": "John Doe",
+ "dn": "CN=jdoe,CN=Users,DC=MY,DC=DOMAIN,DC=COM",
+ "locked": false,
+ "mail": "jdoe@MY.EMAIL.COM",
+ "movable": true,
+ "name": "john",
+ "objectCategory": "person",
+ "passwordExpired": true,
+ "physicalDeliveryOfficeName": "official office of officers",
+ "primaryGroupToken": 0,
+ "renamable": true,
+ "sAMAccountName": "jdoe",
+ "showInAdvancedViewOnly": false,
+ "telephoneNumber": "123-444-5677"
},
- "success": true
- }
- ```
+ ],
+ "total": 99999
+ },
+ "success": true
+ }
+ ```
"""
action = '"enum"'
scope = '"one"'
@@ -176,60 +174,51 @@ def create_new_user(
change_password_next_logon: str = 'null',
password_never_expire: str = 'true'
) -> dict[str, object]:
- """Create a new user.
-
- Note: The user can be created in AD, but not able to log on until the next synchronization occurs.
-
- Note: Please note that synchronization with Synology is a separate step.
-
- Parameters
- ----------
- logon_name : str
- The desired username. E.g `jdoe`.
-
- email: str
- The desired email.
-
- password : str
- The plain-text password for the new user. E.g `Password123`.
-
- located_dn : str
- The DN for the user. E.g `CN=Users,CN=MY,CN=DOMAIN,CN=COM`.
-
- description : str, optional
- A description for the user.
-
- account_is_disabled : str
- Set to 'true' if the account should be disabled Defaults to `False`.
-
- cannot_change_password : str, optional
- Set to 'true' if the user cannot change the password Defaults to `False`.
-
- change_password_next_logon : str, optional
- Set to 'true' if the user must change password on next logon Defaults to `False`.
-
- cannot_change_password : str, optional
- Set to 'true' if the user cannot change the password Defaults to `False`.
-
- password_never_expire: str
- Pwd Never Expire
-
- Returns
- -------
- dict[str, object]
- The result of this method is a dictionary object with a 'data' dictionary and a 'success' dictionary. The data dictionary contains an 'error', or it contains a 'dn' and a 'name'.
-
- Examples
- --------
- ```json
- {
- 'data': {
- 'dn': 'CN=jdoe,CN=Users,DC=MY,DC=DOMAIN,DC=COM',
- 'name': 'NETBIOSNAME\\ababab'
- },
- 'success': true
- }
- ```
+ """
+ Create a new user.
+
+ Parameters
+ ----------
+ logon_name : str
+ The desired username. E.g. `jdoe`.
+ email : str
+ The desired email.
+ password : str
+ The plain-text password for the new user. E.g. `Password123`.
+ located_dn : str
+ The DN for the user. E.g. `CN=Users,CN=MY,CN=DOMAIN,CN=COM`.
+ description : str, optional
+ A description for the user.
+ account_is_disabled : str
+ Set to 'true' if the account should be disabled. Defaults to `False`.
+ cannot_change_password : str, optional
+ Set to 'true' if the user cannot change the password. Defaults to `False`.
+ change_password_next_logon : str, optional
+ Set to 'true' if the user must change password on next logon. Defaults to `False`.
+ password_never_expire : str
+ Set to 'true' if the password never expires.
+
+ Returns
+ -------
+ dict[str, object]
+ The result of this method is a dictionary object with a 'data' dictionary and a 'success' dictionary.
+
+ Notes
+ -----
+ The user can be created in AD, but not able to log on until the next synchronization occurs.
+ Please note that synchronization with Synology is a separate step.
+
+ Examples
+ --------
+ ```json
+ {
+ 'data': {
+ 'dn': 'CN=jdoe,CN=Users,DC=MY,DC=DOMAIN,DC=COM',
+ 'name': 'NETBIOSNAME\\ababab'
+ },
+ 'success': true
+ }
+ ```
"""
api_name = "SYNO.ActiveDirectory.User"
@@ -245,33 +234,36 @@ def create_new_user(
def reset_password(self,
username: str,
) -> dict[str, object]:
- """Send a password reset email.
-
- This will trigger the password reset email from
- Control Panel>Notification>Rules>System>Reset password for your account to be sent to the user.
-
- Info: In order to use this, Control Panel>User & Group>Advanced>"Allow non-administrator users to reset forgotten passwords via email" must be enabled.
-
- Parameters
- ----------
- username : str
- The username to reset. E.g. `My Group`
-
- Returns
- -------
- dict[str, object]
- The return object can be checked for the "success" to be a true or false.
-
- Examples
- --------
- ```json
- {
- "data": {
- "msg": 3
- },
- "success": true
- }
- ```
+ """
+ Send a password reset email.
+
+ This will trigger the password reset email from
+ Control Panel>Notification>Rules>System>Reset password for your account to be sent to the user.
+
+ Parameters
+ ----------
+ username : str
+ The username to reset. E.g. `My Group`.
+
+ Returns
+ -------
+ dict[str, object]
+ The return object can be checked for the "success" to be a true or false.
+
+ Notes
+ -----
+ In order to use this, Control Panel>User & Group>Advanced>"Allow non-administrator users to reset forgotten passwords via email" must be enabled.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "msg": 3
+ },
+ "success": true
+ }
+ ```
"""
api_name = 'SYNO.Auth.ForgotPwd'
@@ -284,52 +276,49 @@ def reset_password(self,
return self.request_data(api_name, api_path, req_param)
def change_user_password(self, user_dn: str, password: str) -> dict[str, object]:
- """Change the user's password.
-
- Info: This is a compound dual-level request where the synology API proxies your request to the Directory Server.
-
- Parameters
- ----------
- user_dn: str
- The user DN to be modified. eg. `CN=jdoe,CN=Users,DC=MY,DC=DOMAIN,DC=COM`
-
- password: str
- The new password to be set. e.g. `Password123`
-
- Returns
- -------
- dict[str, object]
- The result of this method is a dictionary object with a 'data' dictionary and a 'success' dictionary.
-
- The first level is the success to the AD server. The second Data level is the status of the actual request.
-
- Since this is a compound request, the data contains an object with it's own request and results contained within. The object will explain any issues with the request.
-
- Examples
- --------
- ```json
- {
- "data": {
- "has_fail": false,
- "result": [
+ """
+ Change the user's password.
+
+ Parameters
+ ----------
+ user_dn : str
+ The user DN to be modified. E.g. `CN=jdoe,CN=Users,DC=MY,DC=DOMAIN,DC=COM`.
+ password : str
+ The new password to be set. E.g. `Password123`.
+
+ Returns
+ -------
+ dict[str, object]
+ The result of this method is a dictionary object with a 'data' dictionary and a 'success' dictionary.
+
+ Notes
+ -----
+ This is a compound dual-level request where the synology API proxies your request to the Directory Server.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "has_fail": false,
+ "result": [
+ {
+ "api": "SYNO.ActiveDirectory.User",
+ "data": [
{
- "api": "SYNO.ActiveDirectory.User",
- "data": [
- {
- "code": 0,
- "msg": "update record successfully"
- }
- ],
- "method": "set",
- "success": true,
- "version": 2
+ "code": 0,
+ "msg": "update record successfully"
}
- ]
- },
- "success": true
- }
- ```
-
+ ],
+ "method": "set",
+ "success": true,
+ "version": 2
+ }
+ ]
+ },
+ "success": true
+ }
+ ```
"""
api_name = "SYNO.Entry.Request"
info = {'maxVersion': 1, 'minVersion': 1,
@@ -350,38 +339,30 @@ def create_new_group(
type: Optional[str] = 'security',
scope: Optional[str] = 'global'
) -> dict[str, object]:
- """Create a new AD group.
-
- Parameters
- ----------
- name : str
- The name of the group. E.g. `My Group`
-
- located_dn : str
-
- The DN to place the group in. eg. `CN=Groups,DC=MY,DC=DOMAIN,DC=COM`
- email : str, optional
- The email address used to reference this group.
- Defaults to `""`
-
- description : str, optional
- A description of the AD Group.
- Defaults to `""`
-
- type : str, optional
- Example Options: `security`, `distribution`
-
- (definitions from https://docs.microsoft.com/en-us/microsoft-365/admin/create-groups/compare-groups?view=o365-worldwide )
- - `distribution` (Distribution groups) are used for sending email
+ """
+ Create a new AD group.
+
+ Parameters
+ ----------
+ name : str
+ The name of the group. E.g. `My Group`.
+ located_dn : str
+ The DN to place the group in. E.g. `CN=Groups,DC=MY,DC=DOMAIN,DC=COM`.
+ email : str, optional
+ The email address used to reference this group. Defaults to `""`.
+ description : str, optional
+ A description of the AD Group. Defaults to `""`.
+ type : str, optional
+ Example Options: `security`, `distribution`. Defaults to `"security"`.
+
+ (definitions from https://docs.microsoft.com/en-us/microsoft-365/admin/create-groups/compare-groups?view=o365-worldwide )
+ - `distribution` (Distribution groups) are used for sending email
notifications to a group of people.
- - `security` - Security groups are used for granting access to resources
+ - `security` - Security groups are used for granting access to resources
such as SharePoint sites.
- Defaults to `"security"`
-
- scope : str, optional
- Example Options : `local`, `global`, `universal`
-
+ scope : str, optional
+ Example Options: `local`, `global`, `universal`. Defaults to `"global"`.
(Definitions from
https://www.netwrix.com/active_directory_group_management.html )
- `local` (Domain Local Groups) should be used to manage permissions to
@@ -404,24 +385,22 @@ def create_new_group(
is stored in the Global Catalog and replicated forest-wide. Don’t use
universal groups if you have only one domain.
- Defaults to `"global"`
-
- Returns
- -------
- dict[str, object]
- A success object, and data object containing the new dn and the netbios name of the group.
-
- Examples
- --------
- ```json
- {
- 'data': {
- 'dn': 'CN=My Group,CN=Groups,DC=MY,DC=DOMAIN,DC=COM',
- 'name': 'NETBIOSNAME\\My Group'
- },
- 'success': true
- }
- ```
+ Returns
+ -------
+ dict[str, object]
+ A success object, and data object containing the new dn and the netbios name of the group.
+
+ Examples
+ --------
+ ```json
+ {
+ 'data': {
+ 'dn': 'CN=My Group,CN=Groups,DC=MY,DC=DOMAIN,DC=COM',
+ 'name': 'NETBIOSNAME\\My Group'
+ },
+ 'success': true
+ }
+ ```
"""
api_name = 'SYNO.ActiveDirectory.Group'
info = {'maxVersion': 1, 'minVersion': 1,
@@ -432,50 +411,47 @@ def create_new_group(
return self.request_data(api_name, api_path, req_param)
def add_user_to_group(self, userDn: str, groupDn: str) -> dict[str, object]:
- """Adds a user as a member of a group.
-
- Parameters
- ----------
- userDn : str
- The fully qualified dn to add. eg. `CN=jdoe,CN=Users,CN=MY,CN=DOMAIN,CN=COM`
-
- groupDn : str
- the fully qualified dn of the group to which the user is to be added. e.g. `CN=My Group,CN=Groups,CN=MY,CN=DOMAIN,CN=COM`
-
- Returns
- -------
- dict[str, object]
- The result of this method is a dictionary object with a 'data' dictionary and a 'success' dictionary.
-
- The first level is the success to the AD server. The second Data level is the status of the actual request.
-
- Since this is a compound request, the data contains an object with it's own request and results contained within. The object will explain any issues with the request.
-
- Examples
- --------
- ```json
- {
- "data": {
- "has_fail": false,
- "result": [
- {
- "api": "SYNO.ActiveDirectory.Group.Member",
- "data": {
- "members": [
- "CN=jdoe,CN=Users,CN=MY,CN=DOMAIN,CN=COM"
- ]
- },
- "method": "add",
- "success": true,
- "version": 1
- }
+ """
+ Add a user as a member of a group.
+
+ Parameters
+ ----------
+ userDn : str
+ The fully qualified dn to add. E.g. `CN=jdoe,CN=Users,CN=MY,CN=DOMAIN,CN=COM`.
+ groupDn : str
+ The fully qualified dn of the group to which the user is to be added. E.g. `CN=My Group,CN=Groups,CN=MY,CN=DOMAIN,CN=COM`.
+
+ Returns
+ -------
+ dict[str, object]
+ The result of this method is a dictionary object with a 'data' dictionary and a 'success' dictionary.
+ The first level is the success to the AD server. The second Data level is the status of the actual request.
+ Since this is a compound request, the data contains an object with it's own request and results contained within. The object will explain any issues with the request.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "has_fail": false,
+ "result": [
+ {
+ "api": "SYNO.ActiveDirectory.Group.Member",
+ "data": {
+ "members": [
+ "CN=jdoe,CN=Users,CN=MY,CN=DOMAIN,CN=COM"
]
- },
- "success": true
- }
- ```
+ },
+ "method": "add",
+ "success": true,
+ "version": 1
+ }
+ ]
+ },
+ "success": true
+ }
+ ```
"""
-
api_name = 'SYNO.Entry.Request'
compound = '[{"api":"SYNO.ActiveDirectory.Group.Member","method":"add","version":"1","dn":"' + \
groupDn+'","members":["'+userDn+'"]}]'
@@ -491,23 +467,26 @@ def add_user_to_group(self, userDn: str, groupDn: str) -> dict[str, object]:
return self.request_data(api_name, api_path, req_param)
def does_dn_exist(self, groupName: str) -> dict[str, object]:
- """Checks if a container exists. This can be used to verifiy the username or group name is unique.
-
- Info: This will not check the container, only if a similarly named container already exists.
+ """
+ Check if a container exists.
- Parameters
- ----------
- groupName : str
- The user, or group's name. e.g. `jdoe` or `My Cool Group`
+ This can be used to verify the username or group name is unique.
- Fully Qualified Domain Name such as `CN=My Cool Group,CN=Groups,DC=MY,DC=DOMAIN,DC=COM` are not successful.
+ Parameters
+ ----------
+ groupName : str
+ The user, or group's name. E.g. `jdoe` or `My Cool Group`.
+ Fully Qualified Domain Name such as `CN=My Cool Group,CN=Groups,DC=MY,DC=DOMAIN,DC=COM` are not successful.
+ Improper case such as `my cool group` instead of `My Cool Group` are successful.
- Improper case such as `my cool group` instead of `My Cool Group` are successful
+ Returns
+ -------
+ dict[str, object]
+ `True` if the group exists. `False` if the group does not exist.
- Returns
- -------
- dict[str, object]
- `True` if the group exists. `False` if the group does not exist
+ Notes
+ -----
+ This will not check the container, only if a similarly named container already exists.
"""
api_name = 'SYNO.ActiveDirectory.Group'
@@ -529,75 +508,67 @@ def modify_user_info(self,
telephoneNumber: str = None,
web: str = None
) -> dict[str, object]:
- """Performs modification to user information within the Active Directory.
-
- Parameters
- ----------
- user_dn : str
- The user DN to be modified. eg. `CN=jdoe,CN=Users,DC=MY,DC=DOMAIN,DC=COM`
-
- firstName : str, optional
- The First name of the user. e.g. `John`
-
- lastName : str, optional
- The Last Name of the user. e.g. `Doe`
-
- displayName : str, optional
- The Display name of the user. e.g. `John Doe`
-
- description : str, optional
- The Descrition of the user. e.g. `The guy who just came in`
-
- initials : str, optional
- The Initials of the user. e.g. `JD`
-
- physicalDeliveryOfficeName : str, optional
- The office location in the user's place of business
-
- telephoneNumber : str, optional
- The user's telephone number.
-
- web : str, optional
- The user's website or location on the web where information can be obtained.
-
- Returns
- -------
- dict[str, object]
- The result of this method is a dictionary object with a 'data' dictionary and a 'success' dictionary.
-
- The first level is the success to the AD server. The second Data level is the status of the actual request.
-
- Since this is a compound request, the data contains an object with it's own request and results contained within. The object will explain any issues with the request.
-
- Examples
- --------
- ```json
- {
- "data": {
- "has_fail": true,
- "result": [
- {
- "api": "SYNO.ActiveDirectory.User",
- "error": {
- "code": 10104,
- "errors": [
- {
- "code": 10237,
- "msg": "ldb updaterecords: modify"
- }
- ]
- },
- "method": "set",
- "success": false,
- "version": 2
- }
+ """
+ Modify user information within the Active Directory.
+
+ Parameters
+ ----------
+ user_dn : str, optional
+ The user DN to be modified. E.g. `CN=jdoe,CN=Users,DC=MY,DC=DOMAIN,DC=COM`.
+ firstName : str, optional
+ The First name of the user. E.g. `John`.
+ lastName : str, optional
+ The Last Name of the user. E.g. `Doe`.
+ displayName : str, optional
+ The Display name of the user. E.g. `John Doe`.
+ description : str, optional
+ The Description of the user. E.g. `The guy who just came in`.
+ initials : str, optional
+ The Initials of the user. E.g. `JD`.
+ physicalDeliveryOfficeName : str, optional
+ The office location in the user's place of business.
+ telephoneNumber : str, optional
+ The user's telephone number.
+ web : str, optional
+ The user's website or location on the web where information can be obtained.
+
+ Returns
+ -------
+ dict[str, object]
+ The result of this method is a dictionary object with a 'data' dictionary and a 'success' dictionary.
+ The first level is the success to the AD server. The second Data level is the status of the actual request.
+ Since this is a compound request, the data contains an object with it's own request and results contained within. The object will explain any issues with the request.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "has_fail": true,
+ "result": [
+ {
+ "api": "SYNO.ActiveDirectory.User",
+ "error": {
+ "code": 10104,
+ "errors": [
+ {
+ "code": 10237,
+ "msg": "ldb updaterecords: modify"
+ }
]
- },
- "success": true
- }
- ```
+ },
+ "method": "set",
+ "success": false,
+ "version": 2
+ }
+ ]
+ },
+ "success": true
+ }
+ ```
"""
class Person:
+ """Represents a user object for Active Directory modifications."""
firstName
lastName
displayName
@@ -633,58 +604,54 @@ class Person:
return val
def setEntryRequest(self, modificationAPI: str, method: str, nameOfObject: str, jsonObject: Any) -> dict[str, object]:
- """Performs modification to an object within the Active Directory.
-
- Parameters
- ----------
- modificationAPI : str
- API to be used
-
- method : str
- Method to be called
-
- nameOfObject : str
- The user DN to be modified. eg. `"CN=jdoe,CN=Users,DC=MY,DC=DOMAIN,DC=COM"`
-
- jsonObject : str
- The json Object to be added, eg, a user object where the
-
- Returns
- -------
- dict[str, object]
- The result of this method is a dictionary object with a 'data' dictionary and a 'success' dictionary.
-
- The first level is the success to the AD server. The second Data level is the status of the actual request.
-
- Since this is a compound request, the data contains an object with it's own request and results contained within. The object will explain any issues with the request.
-
- Examples
- --------
- ```json
- {
- "data": {
- "has_fail": true,
- "result": [
- {
- "api": "SYNO.ActiveDirectory.User",
- "error": {
- "code": 10104,
- "errors": [
- {
- "code": 10237,
- "msg": "ldb updaterecords: modify"
- }
- ]
- },
- "method": "set",
- "success": false,
- "version": 2
- }
+ """
+ Modify an object within the Active Directory.
+
+ Parameters
+ ----------
+ modificationAPI : str
+ API to be used.
+ method : str
+ Method to be called.
+ nameOfObject : str
+ The user DN to be modified. E.g. `"CN=jdoe,CN=Users,DC=MY,DC=DOMAIN,DC=COM"`.
+ jsonObject : str
+ The json Object to be added, e.g., a user object.
+
+ Returns
+ -------
+ dict[str, object]
+ The result of this method is a dictionary object with a 'data' dictionary and a 'success' dictionary.
+ The first level is the success to the AD server. The second Data level is the status of the actual request.
+ Since this is a compound request, the data contains an object with it's own request and results contained within. The object will explain any issues with the request.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "has_fail": true,
+ "result": [
+ {
+ "api": "SYNO.ActiveDirectory.User",
+ "error": {
+ "code": 10104,
+ "errors": [
+ {
+ "code": 10237,
+ "msg": "ldb updaterecords: modify"
+ }
]
- },
- "success": true
- }
- ```
+ },
+ "method": "set",
+ "success": false,
+ "version": 2
+ }
+ ]
+ },
+ "success": true
+ }
+ ```
"""
compound = [{"api": modificationAPI, "method": method,
"version": 2, nameOfObject: [jsonObject]}]
@@ -698,39 +665,38 @@ def setEntryRequest(self, modificationAPI: str, method: str, nameOfObject: str,
return self.request_data(api_name, api_path, req_param, "post")
def update_domain_records(self) -> dict[str, object]:
- """Updates the Synology users and groups database with information from Directory Server.
+ """
+ Update the Synology users and groups database with information from Directory Server.
- This is a long-running and asynchronous task. You are given back a task_id, and you can use that task_id to check the status with the get_task_status(task_id) method.
+ This is a long-running and asynchronous task. You are given back a task_id, and you can use that task_id to check the status with the get_task_status(task_id) method.
- Returns
- -------
- dict[str, object]
- The 'data' object contains the 'task_id' used to track with the getTaskStatus() method.
+ Returns
+ -------
+ dict[str, object]
+ The 'data' object contains the 'task_id' used to track with the getTaskStatus() method.
- The 'success' object will be true if the operation was successful. or false if failed.
+ Notes
+ -----
+ Typical utilization of Update Domain requires starting the update job and waiting for
+ completion. Waiting involves using the getTaskStatus and can be accomplished via a busy-wait method such as the following:
- Examples
- --------
- ```json
- {
- "data": {
- "task_id": "@administrators/DomainUpdate6146195136397F2"
- },
- "success": true
- }
+ ```python
+ updateResponse=directory.updateDomain()
+ status = directory.getTaskStatus(updateResponse['data']['task_id'])
+ while status['data']['status'] == 'updating':
+ status=directory.getTaskStatus(updateResponse['data']['task_id'])
```
- Note
- ----
- Typical utilization of Update Domain requires starting the update job and waiting for
- completion. Waiting involves using the getTaskStatus and can be accomplished via a busy-wait method such as the following:
-
- ```python
- updateResponse=directory.updateDomain()
- status = directory.getTaskStatus(updateResponse['data']['task_id'])
- while status['data']['status'] == 'updating':
- status=directory.getTaskStatus(updateResponse['data']['task_id'])
- ```
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "task_id": "@administrators/DomainUpdate6146195136397F2"
+ },
+ "success": true
+ }
+ ```
"""
api_name = 'SYNO.Core.Directory.Domain'
info = self.core_list[api_name]
@@ -740,34 +706,34 @@ def update_domain_records(self) -> dict[str, object]:
return self.request_data(api_name, api_path, req_param)
def get_task_status(self, task_id: str) -> dict[str, object]:
- """Gets the current status of a task running on the Directory Domain object.
-
- This is used to ensure the task is completed. For example, the primary utilization of this is when updating Synology's internal Domain user and group list.
-
- Until this method reports finish, the job is not completed, and it is not safe to operate under the assumption that users have been synchronized.
-
- Parameters
- ----------
- task_id : str
- The task ID to be tracked for status.
-
- Returns
- -------
- dict[str, object]
- The 'data' object contains the 'status' used to determine the current status. 'status' will be 'updating' or 'finish' if the job was started.
- T
- The 'success' object will be true if the operation was successful. or false if failed.
-
- Examples
- --------
- ```json
- {
- 'data': {
- 'status': 'updating'
- },
- 'success': true
- }
- ```
+ """
+ Get the current status of a task running on the Directory Domain object.
+
+ This is used to ensure the task is completed. For example, the primary utilization of this is when updating Synology's internal Domain user and group list.
+
+ Until this method reports finish, the job is not completed, and it is not safe to operate under the assumption that users have been synchronized.
+
+ Parameters
+ ----------
+ task_id : str
+ The task ID to be tracked for status.
+
+ Returns
+ -------
+ dict[str, object]
+ The 'data' object contains the 'status' used to determine the current status. 'status' will be 'updating' or 'finish' if the job was started.
+ The 'success' object will be true if the operation was successful, or false if failed.
+
+ Examples
+ --------
+ ```json
+ {
+ 'data': {
+ 'status': 'updating'
+ },
+ 'success': true
+ }
+ ```
"""
api_name = 'SYNO.Core.Directory.Domain'
@@ -778,51 +744,49 @@ def get_task_status(self, task_id: str) -> dict[str, object]:
return self.request_data(api_name, api_path, req_param)
def deleteItems(self, dnList: list[str]) -> dict[str, object]:
- """Deletes an array of DNs from AD.
-
- Parameters
- ----------
- dnList : list[str]
- The fully qualified DN to be removed from the directory server.
- eg. `["CN=jdoe,CN=Users,CN=MY,CN=DOMAIN,CN=COM","CN=My Group,CN=Groups,CN=MY,CN=DOMAIN,CN=COM"]`
-
- Returns
- -------
- dict[str, object]
- The result of this method is a dictionary object with a 'data' dictionary and a 'success' dictionary.
-
- The first level is the success to the AD server. The second Data level is the status of the actual request.
-
- Since this is a compound request, the data contains an object with it's own request and results contained within. The object will explain any issues with the request.
-
- Examples
- --------
- ```json
- {
- "data": {
- "has_fail": false,
- "result": [
- {
- "api": "SYNO.ActiveDirectory.Polling",
- "data": {
- "data": [
- {
- "dn": "CN=My Group,CN=Groups,CN=MY,CN=DOMAIN,CN=COM",
- "status": {}
- }
- ],
- "finished": true,
- "total": 1
- },
- "method": "get",
- "success": true,
- "version": 1
- }
- ]
- },
- "success": true
- }
- ```
+ """
+ Delete an array of DNs from AD.
+
+ Parameters
+ ----------
+ dnList : list[str]
+ The fully qualified DN to be removed from the directory server. E.g. `["CN=jdoe,CN=Users,CN=MY,CN=DOMAIN,CN=COM","CN=My Group,CN=Groups,CN=MY,CN=DOMAIN,CN=COM"]`.
+
+ Returns
+ -------
+ dict[str, object]
+ The result of this method is a dictionary object with a 'data' dictionary and a 'success' dictionary.
+ The first level is the success to the AD server. The second Data level is the status of the actual request.
+ Since this is a compound request, the data contains an object with it's own request and results contained within. The object will explain any issues with the request.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "has_fail": false,
+ "result": [
+ {
+ "api": "SYNO.ActiveDirectory.Polling",
+ "data": {
+ "data": [
+ {
+ "dn": "CN=My Group,CN=Groups,CN=MY,CN=DOMAIN,CN=COM",
+ "status": {}
+ }
+ ],
+ "finished": true,
+ "total": 1
+ },
+ "method": "get",
+ "success": true,
+ "version": 1
+ }
+ ]
+ },
+ "success": true
+ }
+ ```
"""
api_name = 'SYNO.ActiveDirectory.Directory'
info = {'maxVersion': 2, 'minVersion': 1,
@@ -846,68 +810,71 @@ def deleteItems(self, dnList: list[str]) -> dict[str, object]:
return returnValue
def delete_item(self, dn: str) -> dict[str, object]:
- """Deletes a DN from AD.
-
- Parameters
- ----------
- dn : str
- The fully qualified DN to be removed from the directory server.
- eg. `CN=jdoe,CN=Users,CN=MY,CN=DOMAIN,CN=COM` or `CN=My Group,CN=Groups,CN=MY,CN=DOMAIN,CN=COM`
-
- Returns
- -------
- dict[str, object]
- The result of this method is a dictionary object with a 'data' dictionary and a 'success' dictionary.
-
- The first level is the success to the AD server. The second Data level is the status of the actual request.
-
- Since this is a compound request, the data contains an object with it's own request and results contained within. The object will explain any issues with the request.
-
- Examples
- --------
- ```json
- {
- "data": {
- "has_fail": false,
- "result": [
- {
- "api": "SYNO.ActiveDirectory.Polling",
- "data": {
- "data": [
- {
- "dn": "CN=My Group,CN=Groups,CN=MY,CN=DOMAIN,CN=COM",
- "status": {}
- }
- ],
- "finished": true,
- "total": 1
- },
- "method": "get",
- "success": true,
- "version": 1
- }
- ]
- },
- "success": true
- }
- ```
+ """
+ Delete a DN from AD.
+
+ Parameters
+ ----------
+ dn : str
+ The fully qualified DN to be removed from the directory server. E.g. `CN=jdoe,CN=Users,CN=MY,CN=DOMAIN,CN=COM` or `CN=My Group,CN=Groups,CN=MY,CN=DOMAIN,CN=COM`.
+
+ Returns
+ -------
+ dict[str, object]
+ The result of this method is a dictionary object with a 'data' dictionary and a 'success' dictionary.
+ The first level is the success to the AD server. The second Data level is the status of the actual request.
+ Since this is a compound request, the data contains an object with it's own request and results contained within. The object will explain any issues with the request.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "has_fail": false,
+ "result": [
+ {
+ "api": "SYNO.ActiveDirectory.Polling",
+ "data": {
+ "data": [
+ {
+ "dn": "CN=My Group,CN=Groups,CN=MY,CN=DOMAIN,CN=COM",
+ "status": {}
+ }
+ ],
+ "finished": true,
+ "total": 1
+ },
+ "method": "get",
+ "success": true,
+ "version": 1
+ }
+ ]
+ },
+ "success": true
+ }
+ ```
"""
items = []
items.append(dn)
return self.deleteItems(items)
def entryRequest(self, task_id: str) -> Any:
- """Some requests require an entry.
+ """
+ Perform an entry request for a task.
- Delete for example requires an entry. If an entry is required, the task will not complete without an Entry Request.
+ Some requests require an entry. Delete, for example, requires an entry. If an entry is required, the task will not complete without an Entry Request.
- Parameters
- ----------
- task_id: str
- The ID of the task to be checked. This is provided when making a request.
+ Parameters
+ ----------
+ task_id : str
+ The ID of the task to be checked. This is provided when making a request.
+ An example Task ID may look like this
+ `@administrators/Synoads_SYNO.ActiveDirectory.Directory_delete6145EA17C4F03DA9`.
- An example Task ID may look like this
- `@administrators/Synoads_SYNO.ActiveDirectory.Directory_delete6145EA17C4F03DA9`
+ Returns
+ -------
+ Any
+ The result of the entry request.
"""
api_name = 'SYNO.Entry.Request'
info = {'maxVersion': 1, 'minVersion': 1,
diff --git a/synology_api/docker_api.py b/synology_api/docker_api.py
index 245fb11e..1db870c6 100644
--- a/synology_api/docker_api.py
+++ b/synology_api/docker_api.py
@@ -1,6 +1,4 @@
-"""
-Docker API implementation for Synology NAS.
-"""
+"""Docker API implementation for Synology NAS."""
from __future__ import annotations
from typing import Optional
import json
@@ -29,7 +27,6 @@ class Docker(base_api.BaseApi):
- Get list of docker networks
- Setters:
- -
- Actions:
- Export container profile
diff --git a/synology_api/downloadstation.py b/synology_api/downloadstation.py
index ce30c1e8..60ea7069 100644
--- a/synology_api/downloadstation.py
+++ b/synology_api/downloadstation.py
@@ -1,9 +1,109 @@
+"""
+Synology Download Station API wrapper.
+
+This module provides a Python interface for managing downloads, tasks, RSS feeds, and BT searches
+on Synology NAS devices using the Download Station application.
+"""
+
from __future__ import annotations
+
+import json
from typing import Optional, Any
+
from . import base_api
+from .utils import get_data_for_request_from_file
class DownloadStation(base_api.BaseApi):
+ """
+ Core Download Station API implementation for Synology NAS.
+
+ This class provides methods to manage downloads, tasks, RSS feeds, and BT searches.
+
+ Parameters
+ ----------
+ ip_address : str
+ IP address or hostname of the Synology NAS.
+ port : str
+ Port number to connect to.
+ username : str
+ Username for authentication.
+ password : str
+ Password for authentication.
+ secure : bool, optional
+ Use HTTPS if True, HTTP if False (default is False).
+ cert_verify : bool, optional
+ Verify SSL certificates (default is False).
+ dsm_version : int, optional
+ DSM version (default is 7).
+ debug : bool, optional
+ Enable debug output (default is True).
+ otp_code : Optional[str], optional
+ One-time password for 2FA (default is None).
+ device_id : Optional[str], optional
+ Device ID (default is None).
+ device_name : Optional[str], optional
+ Device name (default is None).
+ interactive_output : bool, optional
+ Enable interactive output (default is True).
+ download_st_version : int, optional
+ Download Station API version (default is None).
+
+ Methods
+ -------
+ get_info()
+ Get Download Station info.
+ get_config()
+ Get Download Station config.
+ set_server_config(...)
+ Set Download Station server config.
+ schedule_info()
+ Get schedule info.
+ schedule_set_config(...)
+ Set schedule config.
+ tasks_list(...)
+ List download tasks.
+ tasks_info(...)
+ Get info for specific tasks.
+ tasks_source(...)
+ Download task source.
+ create_task(...)
+ Create a new download task.
+ delete_task(...)
+ Delete a download task.
+ pause_task(...)
+ Pause a download task.
+ resume_task(...)
+ Resume a download task.
+ edit_task(...)
+ Edit a download task.
+ get_statistic_info()
+ Get Download Station statistics.
+ get_rss_info_list(...)
+ Get RSS site info list.
+ refresh_rss_site(...)
+ Refresh RSS site.
+ rss_feed_list(...)
+ Get RSS feed list.
+ rss_feed_filter_list(...)
+ Get RSS feed filter list.
+ rss_feed_filter_add(...)
+ Add RSS feed filter.
+ rss_feed_filter_set(...)
+ Set RSS feed filter.
+ rss_feed_filter_delete(...)
+ Delete RSS feed filter.
+ start_bt_search(...)
+ Start a BT search.
+ get_bt_search_results(...)
+ Get BT search results.
+ get_bt_search_category()
+ Get BT search categories.
+ clean_bt_search(...)
+ Clean BT search tasks.
+ get_bt_module()
+ Get BT search modules.
+ """
def __init__(self,
ip_address: str,
@@ -20,6 +120,38 @@ def __init__(self,
interactive_output: bool = True,
download_st_version: int = None
) -> None:
+ """
+ Initialize the DownloadStation API wrapper.
+
+ Parameters
+ ----------
+ ip_address : str
+ IP address or hostname of the Synology NAS.
+ port : str
+ Port number to connect to.
+ username : str
+ Username for authentication.
+ password : str
+ Password for authentication.
+ secure : bool, optional
+ Use HTTPS if True, HTTP if False (default is False).
+ cert_verify : bool, optional
+ Verify SSL certificates (default is False).
+ dsm_version : int, optional
+ DSM version (default is 7).
+ debug : bool, optional
+ Enable debug output (default is True).
+ otp_code : Optional[str], optional
+ One-time password for 2FA (default is None).
+ device_id : Optional[str], optional
+ Device ID (default is None).
+ device_name : Optional[str], optional
+ Device name (default is None).
+ interactive_output : bool, optional
+ Enable interactive output (default is True).
+ download_st_version : int, optional
+ Download Station API version (default is None).
+ """
super(DownloadStation, self).__init__(ip_address, port, username, password, secure, cert_verify,
dsm_version, debug, otp_code, device_id, device_name, 'DownloadStation')
@@ -38,6 +170,14 @@ def __init__(self,
self.download_st_version = ''
def get_info(self) -> dict[str, object] | str:
+ """
+ Get Download Station info.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Download Station info.
+ """
api_name = 'SYNO.DownloadStation.Info'
info = self.download_list[api_name]
api_path = info['path']
@@ -46,6 +186,14 @@ def get_info(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def get_config(self) -> dict[str, object] | str:
+ """
+ Get Download Station config.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Download Station config.
+ """
api_name = 'SYNO.DownloadStation.Info'
info = self.download_list[api_name]
api_path = info['path']
@@ -66,7 +214,39 @@ def set_server_config(self,
default_destination: Optional[str] = None,
emule_default_destination: Optional[str] = None
) -> dict[str, object] | str:
-
+ """
+ Set Download Station server configuration.
+
+ Parameters
+ ----------
+ bt_max_download : Optional[int], optional
+ Maximum BT download speed.
+ bt_max_upload : Optional[int], optional
+ Maximum BT upload speed.
+ emule_max_download : Optional[int], optional
+ Maximum eMule download speed.
+ emule_max_upload : Optional[int], optional
+ Maximum eMule upload speed.
+ nzb_max_download : Optional[int], optional
+ Maximum NZB download speed.
+ http_max_download : Optional[int], optional
+ Maximum HTTP download speed.
+ ftp_max_download : Optional[int], optional
+ Maximum FTP download speed.
+ emule_enabled : Optional[bool], optional
+ Enable eMule.
+ unzip_service_enabled : Optional[bool], optional
+ Enable unzip service.
+ default_destination : Optional[str], optional
+ Default download destination.
+ emule_default_destination : Optional[str], optional
+ Default eMule download destination.
+
+ Returns
+ -------
+ dict[str, object] or str
+ API response.
+ """
api_name = 'SYNO.DownloadStation.Info'
info = self.download_list[api_name]
api_path = info['path']
@@ -81,6 +261,14 @@ def set_server_config(self,
return self.request_data(api_name, api_path, req_param)
def schedule_info(self) -> dict[str, object] | str:
+ """
+ Get Download Station schedule configuration.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Schedule configuration.
+ """
api_name = 'SYNO.DownloadStation.Schedule'
info = self.download_list[api_name]
api_path = info['path']
@@ -89,6 +277,21 @@ def schedule_info(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def schedule_set_config(self, enabled: bool = False, emule_enabled: bool = False) -> dict[str, object] | str:
+ """
+ Set Download Station schedule configuration.
+
+ Parameters
+ ----------
+ enabled : bool, optional
+ Enable schedule (default is False).
+ emule_enabled : bool, optional
+ Enable eMule schedule (default is False).
+
+ Returns
+ -------
+ dict[str, object] or str
+ API response.
+ """
api_name = 'SYNO.DownloadStation.Schedule'
info = self.download_list[api_name]
api_path = info['path']
@@ -105,6 +308,23 @@ def tasks_list(self,
offset: int = 0,
limit: int = -1
) -> dict[str, object] | str:
+ """
+ List download tasks.
+
+ Parameters
+ ----------
+ additional_param : Optional[str or list[str]], optional
+ Additional fields to retrieve.
+ offset : int, optional
+ Offset for pagination (default is 0).
+ limit : int, optional
+ Maximum number of tasks to retrieve (default is -1).
+
+ Returns
+ -------
+ dict[str, object] or str
+ List of download tasks.
+ """
api_name = 'SYNO.DownloadStation' + self.download_st_version + '.Task'
info = self.download_list[api_name]
api_path = info['path']
@@ -115,31 +335,64 @@ def tasks_list(self,
additional_param = ['detail', 'transfer',
'file', 'tracker', 'peer']
- if type(additional_param) is list:
- req_param['additional'] = ",".join(additional_param)
+ req_param['additional'] = json.dumps(additional_param if isinstance(
+ additional_param, list) else [additional_param])
return self.request_data(api_name, api_path, req_param)
def tasks_info(self, task_id, additional_param: Optional[str | list[str]] = None) -> dict[str, object] | str:
+ """
+ Get information for specific download tasks.
+
+ Parameters
+ ----------
+ task_id : str or list[str]
+ Task ID(s).
+ additional_param : Optional[str or list[str]], optional
+ Additional fields to retrieve.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Task information.
+ """
api_name = 'SYNO.DownloadStation' + self.download_st_version + '.Task'
info = self.download_list[api_name]
api_path = info['path']
- req_param = {'version': info['maxVersion'], 'method': 'getinfo',
+ req_param = {'version': info['maxVersion'], 'method': 'get',
'id': task_id, 'additional': additional_param}
if additional_param is None:
additional_param = ['detail', 'transfer',
'file', 'tracker', 'peer']
+ elif isinstance(additional_param, str):
+ additional_param = [additional_param]
+ elif isinstance(additional_param, list):
+ if not all(isinstance(a, str) for a in additional_param):
+ return "additional_param must be a string or a list of strings."
+ else:
+ return "additional_param must be a string or a list of strings."
- if type(additional_param) is list:
- req_param['additional'] = ",".join(additional_param)
-
- if type(task_id) is list:
- req_param['id'] = ",".join(task_id)
+ req_param['additional'] = json.dumps(additional_param)
+ req_param['id'] = json.dumps(
+ task_id if isinstance(task_id, list) else [task_id])
return self.request_data(api_name, api_path, req_param)
def tasks_source(self, task_id) -> bytes:
+ """
+ Download task source.
+
+ Parameters
+ ----------
+ task_id : str or list[str]
+ Task ID(s).
+
+ Returns
+ -------
+ bytes
+ Task source content.
+ """
# DownloadStation2 is required here
api_name = 'SYNO.DownloadStation2.Task.Source'
info = self.download_list[api_name]
@@ -149,16 +402,126 @@ def tasks_source(self, task_id) -> bytes:
return self.request_data(api_name, api_path, req_param, response_json=False).content
- def create_task(self, url, destination) -> dict[str, object] | str:
+ def get_task_list(self, list_id: str) -> dict[str, any]:
+ """
+ Get info from a task list containing the files to be downloaded.
+
+ This is to be used after creating a task, and before starting the download.
+
+ Parameters
+ ----------
+ list_id : str
+ List ID returned by create_task.
+
+ Returns
+ -------
+ dict[str, any]
+ A dictionary containing a task list information.
+
+ Examples
+ --------
+ ```json
+ {
+ "data" : {
+ "files" : [
+ {
+ "index" : 0,
+ "name" : "Pulp.Fiction.1994.2160p.4K.BluRay.x265.10bit.AAC5.1-[YTS.MX].mkv",
+ "size" : 2391069024
+ },
+ {
+ "index" : 1,
+ "name" : "YTSProxies.com.txt",
+ "size" : 604
+ },
+ {
+ "index" : 2,
+ "name" : "www.YTS.MX.jpg",
+ "size" : 53226
+ }
+ ],
+ "size" : 7835426779,
+ "title" : "Pulp Fiction (1994) [2160p] [4K] [BluRay] [5.1] [YTS.MX]",
+ "type" : "bt"
+ },
+ }
+ ```
+ """
+ api_name = 'SYNO.DownloadStation' + self.download_st_version + '.Task.List'
+ info = self.download_list[api_name]
+ api_path = info['path']
+ req_param = {'version': info['maxVersion'],
+ 'method': 'get', 'list_id': list_id}
+
+ return self.request_data(api_name, api_path, req_param)
+
+ def create_task(self,
+ url: Optional[str] = None,
+ file_path: Optional[str] = None,
+ destination: str = "",
+ ) -> dict[str, object] | str:
+ """
+ Create a new download task.
+
+ You can choose between a url or a file path (.torrent).
+
+ Parameters
+ ----------
+ url : str, optional
+ Download URL. Use either `url` or `file_path`.
+ file_path : str, optional
+ Path to a file (e.g. a .torrent) to download.
+ destination : str, optional
+ Download destination folder (default is "").
+
+ Returns
+ -------
+ dict[str, object] or str
+ API response.
+ """
+ # Validate only a url or a file path.
+ if bool(url) == bool(file_path):
+ raise ValueError("You can't specify both 'url' and 'file_path'")
+
api_name = 'SYNO.DownloadStation' + self.download_st_version + '.Task'
info = self.download_list[api_name]
api_path = info['path']
+
+ if file_path:
+ fields = {
+ "api": api_name,
+ "method": "create",
+ "version": str(info["maxVersion"]),
+ "type": '"file"',
+ "file": '["torrent"]',
+ "destination": f'"{destination}"',
+ "create_list": "true"
+ }
+ data = get_data_for_request_from_file(
+ file_path=file_path, fields=fields, called_from='DownloadStation')
+
+ return self.request_data(api_name, api_path, method='post', data=data, req_param={})
+
req_param = {'version': info['maxVersion'], 'method': 'create', 'type': 'url',
'create_list': 'true', 'destination': destination, 'url': f'["{url}"]'}
-
return self.request_data(api_name, api_path, req_param)
def delete_task(self, task_id: str, force: bool = False) -> dict[str, object] | str:
+ """
+ Delete a download task.
+
+ Parameters
+ ----------
+ task_id : str or list[str]
+ Task ID(s).
+ force : bool, optional
+ Force delete (default is False).
+
+ Returns
+ -------
+ dict[str, object] or str
+ API response.
+ """
api_name = 'SYNO.DownloadStation' + self.download_st_version + '.Task'
info = self.download_list[api_name]
api_path = info['path']
@@ -171,6 +534,19 @@ def delete_task(self, task_id: str, force: bool = False) -> dict[str, object] |
return self.request_data(api_name, api_path, param)
def pause_task(self, task_id: str) -> dict[str, object] | str:
+ """
+ Pause a download task.
+
+ Parameters
+ ----------
+ task_id : str or list[str]
+ Task ID(s).
+
+ Returns
+ -------
+ dict[str, object] or str
+ API response.
+ """
api_name = 'SYNO.DownloadStation' + self.download_st_version + '.Task'
info = self.download_list[api_name]
api_path = info['path']
@@ -183,6 +559,19 @@ def pause_task(self, task_id: str) -> dict[str, object] | str:
return self.request_data(api_name, api_path, param)
def resume_task(self, task_id: str) -> dict[str, object] | str:
+ """
+ Resume a download task.
+
+ Parameters
+ ----------
+ task_id : str or list[str]
+ Task ID(s).
+
+ Returns
+ -------
+ dict[str, object] or str
+ API response.
+ """
api_name = 'SYNO.DownloadStation' + self.download_st_version + '.Task'
info = self.download_list[api_name]
api_path = info['path']
@@ -195,6 +584,21 @@ def resume_task(self, task_id: str) -> dict[str, object] | str:
return self.request_data(api_name, api_path, param)
def edit_task(self, task_id: str, destination: str = 'sharedfolder') -> dict[str, object] | str:
+ """
+ Edit a download task.
+
+ Parameters
+ ----------
+ task_id : str or list[str]
+ Task ID(s).
+ destination : str, optional
+ New download destination (default is 'sharedfolder').
+
+ Returns
+ -------
+ dict[str, object] or str
+ API response.
+ """
api_name = 'SYNO.DownloadStation' + self.download_st_version + '.Task'
info = self.download_list[api_name]
api_path = info['path']
@@ -206,7 +610,67 @@ def edit_task(self, task_id: str, destination: str = 'sharedfolder') -> dict[str
return self.request_data(api_name, api_path, param)
+ def download_task_list(
+ self,
+ list_id: str,
+ file_indexes: list[int],
+ destination: str,
+ create_subfolder: bool = True
+ ) -> dict[str, object] | str:
+ """
+ Download files from a task list.
+
+ Parameters
+ ----------
+ list_id : str
+ Task list ID.
+ file_indexes : list[int]
+ List of file indexes to download.
+ For example, if `get_task_list()` returns `files: [{index: 0, name: "file1.txt"}, {index: 1, name: "file2.txt"}]`, then `file_indexes = [1]` will download only file2.txt.
+ destination : str
+ Download destination, e.g. 'sharedfolder/subfolder'
+ create_subfolder : bool, optional
+ Create subfolder. Defaults to `True`
+
+ Returns
+ -------
+ dict[str, object] or str
+ A dictionary containing the task_id for the started download task.
+
+ Examples
+ --------
+ ```json
+ {
+ 'data': {
+ 'task_id': 'username/SYNODLTaskListDownload1759340338C7C39ABA'
+ }
+ }
+ ```
+ """
+ api_name = 'SYNO.DownloadStation' + \
+ self.download_st_version + '.Task.List.Polling'
+ info = self.download_list[api_name]
+ api_path = info['path']
+ param = {
+ 'version': info['maxVersion'],
+ 'method': 'download',
+ 'list_id': list_id,
+ 'file_indexes': ",".join(map(str, file_indexes)),
+ 'destination': destination,
+ 'create_subfolder': create_subfolder
+ }
+
+ return self.request_data(api_name, api_path, param)
+
def get_statistic_info(self) -> dict[str, object] | str:
+ """
+ Get Download Station statistics.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Statistics information.
+ """
api_name = 'SYNO.DownloadStation.Statistic'
info = self.download_list[api_name]
api_path = info['path']
@@ -215,6 +679,21 @@ def get_statistic_info(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, param)
def get_rss_info_list(self, offset: Optional[int] = None, limit: Optional[int] = None) -> dict[str, object] | str:
+ """
+ Get RSS site info list.
+
+ Parameters
+ ----------
+ offset : Optional[int], optional
+ Offset for pagination.
+ limit : Optional[int], optional
+ Maximum number of RSS sites to retrieve.
+
+ Returns
+ -------
+ dict[str, object] or str
+ RSS site info list.
+ """
api_name = 'SYNO.DownloadStation.RSS.Site'
info = self.download_list[api_name]
api_path = info['path']
@@ -228,6 +707,19 @@ def get_rss_info_list(self, offset: Optional[int] = None, limit: Optional[int] =
return self.request_data(api_name, api_path, param)
def refresh_rss_site(self, rss_id: Optional[str] = None) -> dict[str, object] | str:
+ """
+ Refresh an RSS site.
+
+ Parameters
+ ----------
+ rss_id : Optional[str], optional
+ RSS site ID.
+
+ Returns
+ -------
+ dict[str, object] or str
+ API response.
+ """
api_name = 'SYNO.DownloadStation.RSS.Site'
info = self.download_list[api_name]
api_path = info['path']
@@ -235,7 +727,7 @@ def refresh_rss_site(self, rss_id: Optional[str] = None) -> dict[str, object] |
'method': 'refresh', 'id': rss_id}
if rss_id is None:
- return 'Enter a valid ID check if you have any with get_rss_list()'
+ return 'Enter a valid ID check if you have any with get_rss_info_list()'
elif type(rss_id) is list:
rss_id = ','.join(rss_id)
param['id'] = rss_id
@@ -247,13 +739,30 @@ def rss_feed_list(self,
offset: Optional[int] = None,
limit: Optional[int] = None
) -> dict[str, object] | str:
+ """
+ Get RSS feed list.
+
+ Parameters
+ ----------
+ rss_id : Optional[str], optional
+ RSS site ID.
+ offset : Optional[int], optional
+ Offset for pagination.
+ limit : Optional[int], optional
+ Maximum number of RSS feeds to retrieve.
+
+ Returns
+ -------
+ dict[str, object] or str
+ RSS feed list.
+ """
api_name = 'SYNO.DownloadStation' + self.download_st_version + '.RSS.Feed'
info = self.download_list[api_name]
api_path = info['path']
param = {'version': info['maxVersion'], 'method': 'list', 'id': rss_id}
if rss_id is None:
- return 'Enter a valid ID check if you have any with get_rss_list()'
+ return 'Enter a valid ID check if you have any with get_rss_info_list()'
elif type(rss_id) is list:
rss_id = ','.join(rss_id)
param['id'] = rss_id
@@ -265,7 +774,185 @@ def rss_feed_list(self,
return self.request_data(api_name, api_path, param)
+ def rss_feed_filter_list(self,
+ feed_id: Optional[int] = None,
+ offset: Optional[int] = None,
+ limit: Optional[int] = None
+ ) -> dict[str, object] | str:
+ """
+ Get RSS feed filter list.
+
+ Parameters
+ ----------
+ feed_id : int, optional
+ RSS feed ID.
+ offset : int, optional
+ Offset for pagination.
+ limit : int, optional
+ Maximum number of filters to retrieve.
+
+ Returns
+ -------
+ dict[str, object] or str
+ RSS feed filter list.
+ """
+ api_name = 'SYNO.DownloadStation' + self.download_st_version + '.RSS.Filter'
+ info = self.download_list[api_name]
+ api_path = info['path']
+ param = {'version': info['maxVersion'],
+ 'method': 'list', 'feed_id': feed_id}
+
+ if feed_id is None:
+ return 'Enter a valid ID check if you have any with get_rss_info_list()'
+
+ if offset is not None:
+ param['offset'] = offset
+ if limit is not None:
+ param['limit'] = limit
+
+ return self.request_data(api_name, api_path, param)
+
+ def rss_feed_filter_add(self,
+ feed_id: int = None,
+ filter_name: str = None,
+ match: str = None,
+ not_match: str = None,
+ destination: str = None,
+ is_regex: bool = False
+ ) -> dict[str, object] | str:
+ """
+ Add RSS feed filter.
+
+ Parameters
+ ----------
+ feed_id : int
+ RSS feed ID.
+ filter_name : str
+ Filter name.
+ match : str
+ Match pattern.
+ not_match : str
+ Not match pattern.
+ destination : str
+ Download destination.
+ is_regex : bool, optional
+ Use regex for matching (default is False).
+
+ Returns
+ -------
+ dict[str, object] or str
+ API response.
+ """
+
+ api_name = 'SYNO.DownloadStation' + self.download_st_version + '.RSS.Filter'
+ info = self.download_list[api_name]
+ api_path = info['path']
+
+ param = {'version': info['maxVersion'], 'method': 'add', 'feed_id': feed_id,
+ 'name': f'"{filter_name}"', 'match': f'"{match}"', 'not_match': f'"{not_match}"',
+ 'destination': f'"{destination}"', 'is_regex': str(is_regex).lower()}
+
+ if type(is_regex) is not bool:
+ return 'Please set is_regex to True or False'
+
+ if feed_id is None:
+ return 'Enter a valid ID check if you have any with get_rss_info_list()'
+
+ return self.request_data(api_name, api_path, param)
+
+ def rss_feed_filter_set(self,
+ filter_id: int = None,
+ filter_name: str = None,
+ match: str = None,
+ not_match: str = None,
+ destination: str = None,
+ is_regex: bool = False
+ ) -> dict[str, object] | str:
+ """
+ Set RSS feed filter.
+
+ Parameters
+ ----------
+ filter_id : int
+ Filter ID.
+ filter_name : str
+ Filter name.
+ match : str
+ Match pattern.
+ not_match : str
+ Not match pattern.
+ destination : str
+ Download destination.
+ is_regex : bool, optional
+ Use regex for matching (default is False).
+
+ Returns
+ -------
+ dict[str, object] or str
+ API response.
+ """
+
+ api_name = 'SYNO.DownloadStation' + self.download_st_version + '.RSS.Filter'
+ info = self.download_list[api_name]
+ api_path = info['path']
+
+ param = {'version': info['maxVersion'], 'method': 'set', 'feed_id': 'null', 'id': filter_id,
+ 'name': f'"{filter_name}"', 'match': f'"{match}"', 'not_match': f'"{not_match}"',
+ 'destination': f'"{destination}"', 'is_regex': str(is_regex).lower()}
+
+ if type(is_regex) is not bool:
+ return 'Please set is_regex to True or False'
+
+ if filter_id is None:
+ return 'Enter a valid ID check if you have any with rss_feed_filter_list()'
+
+ return self.request_data(api_name, api_path, param)
+
+ def rss_feed_filter_delete(self,
+ filter_id: int = None,
+ ) -> dict[str, object] | str:
+ """
+ Delete RSS feed filter.
+
+ Parameters
+ ----------
+ filter_id : int
+ Filter ID.
+
+ Returns
+ -------
+ dict[str, object] or str
+ API response.
+ """
+
+ api_name = 'SYNO.DownloadStation' + self.download_st_version + '.RSS.Filter'
+ info = self.download_list[api_name]
+ api_path = info['path']
+
+ param = {'version': info['maxVersion'],
+ 'method': 'delete', 'id': filter_id}
+
+ if filter_id is None:
+ return 'Enter a valid ID check if you have any with rss_feed_filter_list()'
+
+ return self.request_data(api_name, api_path, param)
+
def start_bt_search(self, keyword: Optional[str] = None, module: str = 'all') -> dict[str, object] | str:
+ """
+ Start a BT search.
+
+ Parameters
+ ----------
+ keyword : Optional[str], optional
+ Search keyword.
+ module : str, optional
+ BT search module (default is 'all').
+
+ Returns
+ -------
+ dict[str, object] or str
+ BT search task information or message.
+ """
api_name = 'SYNO.DownloadStation' + self.download_st_version + '.BTSearch'
info = self.download_list[api_name]
api_path = info['path']
@@ -302,6 +989,31 @@ def get_bt_search_results(self,
filter_category: Optional[str] = None,
filter_title: Optional[str] = None
) -> dict[str, object] | str:
+ """
+ Get BT search results.
+
+ Parameters
+ ----------
+ taskid : Optional[str], optional
+ BT search task ID.
+ offset : Optional[int], optional
+ Offset for pagination.
+ limit : Optional[int], optional
+ Maximum number of results to retrieve.
+ sort_by : Optional[str], optional
+ Field to sort by.
+ sort_direction : Optional[str], optional
+ Sort direction.
+ filter_category : Optional[str], optional
+ Filter by category.
+ filter_title : Optional[str], optional
+ Filter by title.
+
+ Returns
+ -------
+ dict[str, object] or str
+ BT search results.
+ """
api_name = 'SYNO.DownloadStation' + self.download_st_version + '.BTSearch'
info = self.download_list[api_name]
api_path = info['path']
@@ -321,6 +1033,14 @@ def get_bt_search_results(self,
return self.request_data(api_name, api_path, param)
def get_bt_search_category(self) -> dict[str, object] | str:
+ """
+ Get BT search categories.
+
+ Returns
+ -------
+ dict[str, object] or str
+ BT search categories.
+ """
api_name = 'SYNO.DownloadStation' + self.download_st_version + '.BTSearch'
info = self.download_list[api_name]
api_path = info['path']
@@ -329,6 +1049,19 @@ def get_bt_search_category(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, param)
def clean_bt_search(self, taskid: Optional[str | list[str]] = None) -> dict[str, object] | str:
+ """
+ Clean BT search tasks.
+
+ Parameters
+ ----------
+ taskid : Optional[str or list[str]], optional
+ BT search task ID(s).
+
+ Returns
+ -------
+ dict[str, object] or str
+ API response.
+ """
api_name = 'SYNO.DownloadStation' + self.download_st_version + '.BTSearch'
info = self.download_list[api_name]
api_path = info['path']
@@ -347,6 +1080,14 @@ def clean_bt_search(self, taskid: Optional[str | list[str]] = None) -> dict[str,
return self.request_data(api_name, api_path, param)
def get_bt_module(self) -> dict[str, object] | str:
+ """
+ Get BT search modules.
+
+ Returns
+ -------
+ dict[str, object] or str
+ BT search modules.
+ """
api_name = 'SYNO.DownloadStation' + self.download_st_version + '.BTSearch'
info = self.download_list[api_name]
api_path = info['path']
diff --git a/synology_api/drive_admin_console.py b/synology_api/drive_admin_console.py
index 298f68aa..6b6b7fa7 100644
--- a/synology_api/drive_admin_console.py
+++ b/synology_api/drive_admin_console.py
@@ -1,11 +1,32 @@
+"""
+Synology Drive Admin Console API wrapper.
+
+This module provides a Python interface for managing Synology Drive Admin Console,
+including status, configuration, connections, logs, shares, and settings.
+"""
+
from __future__ import annotations
from typing import Optional
from . import base_api
class AdminConsole(base_api.BaseApi):
+ """
+ Synology Drive Admin Console API implementation.
+
+ This class provides methods to retrieve and manage Synology Drive Admin Console status,
+ configuration, connections, logs, shares, and settings.
+ """
def status_info(self) -> dict[str, object] | str:
+ """
+ Get Synology Drive status information.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Status information.
+ """
api_name = 'SYNO.SynologyDrive'
info = self.gen_list[api_name]
api_path = info['path']
@@ -14,6 +35,14 @@ def status_info(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def config_info(self) -> dict[str, object] | str:
+ """
+ Get Synology Drive configuration information.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Configuration information.
+ """
api_name = 'SYNO.SynologyDrive.Config'
info = self.gen_list[api_name]
api_path = info['path']
@@ -22,6 +51,14 @@ def config_info(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def connections(self) -> dict[str, object] | str:
+ """
+ Get summary of Synology Drive connections.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Connections summary.
+ """
api_name = 'SYNO.SynologyDrive.Connection'
info = self.gen_list[api_name]
api_path = info['path']
@@ -30,6 +67,14 @@ def connections(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def drive_check_user(self) -> dict[str, object] | str:
+ """
+ Check user status in Synology Drive.
+
+ Returns
+ -------
+ dict[str, object] or str
+ User check result.
+ """
api_name = 'SYNO.SynologyDrive'
info = self.gen_list[api_name]
api_path = info['path']
@@ -38,6 +83,14 @@ def drive_check_user(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def active_connections(self) -> dict[str, object] | str:
+ """
+ Get list of active Synology Drive connections.
+
+ Returns
+ -------
+ dict[str, object] or str
+ List of active connections.
+ """
api_name = 'SYNO.SynologyDrive.Connection'
info = self.gen_list[api_name]
api_path = info['path']
@@ -46,6 +99,14 @@ def active_connections(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def active_sync_connections(self) -> dict[str, object] | str:
+ """
+ Get list of active Synology Drive ShareSync connections.
+
+ Returns
+ -------
+ dict[str, object] or str
+ List of active ShareSync connections.
+ """
api_name = 'SYNO.SynologyDriveShareSync.Connection'
info = self.gen_list[api_name]
api_path = info['path']
@@ -54,6 +115,14 @@ def active_sync_connections(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def share_active_list(self) -> dict[str, object] | str:
+ """
+ Get list of active shares in Synology Drive.
+
+ Returns
+ -------
+ dict[str, object] or str
+ List of active shares.
+ """
api_name = 'SYNO.SynologyDrive.Share'
info = self.gen_list[api_name]
api_path = info['path']
@@ -61,16 +130,44 @@ def share_active_list(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
- def log(self,
- share_type: str = 'all',
- get_all: bool = False,
- limit: int = 1000,
- keyword: str = '',
- date_from: int = 0,
- date_to: int = 0,
- username: str = '',
- target: str = 'user'
- ) -> dict[str, object] | str:
+ def log(
+ self,
+ share_type: str = 'all',
+ get_all: bool = False,
+ limit: int = 1000,
+ keyword: str = '',
+ date_from: int = 0,
+ date_to: int = 0,
+ username: str = '',
+ target: str = 'user'
+ ) -> dict[str, object] | str:
+ """
+ Get Synology Drive logs.
+
+ Parameters
+ ----------
+ share_type : str, optional
+ Type of share to filter logs (default is 'all').
+ get_all : bool, optional
+ Whether to get all logs (default is False).
+ limit : int, optional
+ Maximum number of logs to return (default is 1000).
+ keyword : str, optional
+ Keyword to filter logs (default is '').
+ date_from : int, optional
+ Start date in epoch format (default is 0).
+ date_to : int, optional
+ End date in epoch format (default is 0).
+ username : str, optional
+ Username to filter logs (default is '').
+ target : str, optional
+ Target type to filter logs (default is 'user').
+
+ Returns
+ -------
+ dict[str, object] or str
+ Log information.
+ """
api_name = 'SYNO.SynologyDrive.Log'
info = self.gen_list[api_name]
api_path = info['path']
@@ -89,6 +186,14 @@ def log(self,
return self.request_data(api_name, api_path, req_param)
def c2fs_share(self) -> dict[str, object] | str:
+ """
+ Get list of C2FS shares.
+
+ Returns
+ -------
+ dict[str, object] or str
+ List of C2FS shares.
+ """
api_name = 'SYNO.C2FS.Share'
info = self.gen_list[api_name]
api_path = info['path']
@@ -97,6 +202,14 @@ def c2fs_share(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def settings(self) -> dict[str, object] | str:
+ """
+ Get Synology Drive settings.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Settings information.
+ """
api_name = 'SYNO.SynologyDrive.Settings'
info = self.gen_list[api_name]
api_path = info['path']
@@ -105,6 +218,14 @@ def settings(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def db_usage(self) -> dict[str, object] | str:
+ """
+ Get Synology Drive database usage.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Database usage information.
+ """
api_name = 'SYNO.SynologyDrive.DBUsage'
info = self.gen_list[api_name]
api_path = info['path']
@@ -113,6 +234,14 @@ def db_usage(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def delete_status(self) -> dict[str, object] | str:
+ """
+ Get status of deleted nodes in Synology Drive.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Delete status information.
+ """
api_name = 'SYNO.SynologyDrive.Node.Delete'
info = self.gen_list[api_name]
api_path = info['path']
@@ -121,6 +250,14 @@ def delete_status(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def file_property_transfer_status(self) -> dict[str, object] | str:
+ """
+ Get file property transfer status for User Home migration.
+
+ Returns
+ -------
+ dict[str, object] or str
+ File property transfer status.
+ """
api_name = 'SYNO.SynologyDrive.Migration.UserHome'
info = self.gen_list[api_name]
api_path = info['path']
@@ -129,6 +266,23 @@ def file_property_transfer_status(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def user_sync_profile(self, user: str = '', start: int = 0, limit: str | int = 'null') -> dict[str, object] | str:
+ """
+ Get user sync profile(s).
+
+ Parameters
+ ----------
+ user : str, optional
+ Username to filter profiles (default is '').
+ start : int, optional
+ Start index for pagination (default is 0).
+ limit : str or int, optional
+ Maximum number of profiles to return (default is 'null').
+
+ Returns
+ -------
+ dict[str, object] or str
+ User sync profile information.
+ """
api_name = 'SYNO.SynologyDrive.Profiles'
info = self.gen_list[api_name]
api_path = info['path']
@@ -138,6 +292,19 @@ def user_sync_profile(self, user: str = '', start: int = 0, limit: str | int = '
return self.request_data(api_name, api_path, req_param)
def index_pause(self, time_pause: int = 60) -> dict[str, object] | str:
+ """
+ Pause native client index for a specified duration.
+
+ Parameters
+ ----------
+ time_pause : int, optional
+ Pause duration in seconds (default is 60).
+
+ Returns
+ -------
+ dict[str, object] or str
+ API response.
+ """
api_name = 'SYNO.SynologyDrive.Index'
info = self.gen_list[api_name]
api_path = info['path']
diff --git a/synology_api/error_codes.py b/synology_api/error_codes.py
index 551546f3..a9d1c87c 100644
--- a/synology_api/error_codes.py
+++ b/synology_api/error_codes.py
@@ -1,3 +1,4 @@
+"""Synology API Error Codes."""
# 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
@@ -124,6 +125,37 @@
420: 'Illegal file name on FAT file system',
421: 'Device or resource busy',
599: 'No such task of the file operation',
+ 800: 'A folder path of favorite folder is already added to user\'s favorites',
+ 801: 'A name of favorite folder conflicts with an existing folder path in the user\'s favorties',
+ 802: 'There are too many favorites to be added',
+ 900: 'Failed to delete file(s)/folder(s). More information in object',
+ 1000: 'Failed to copy files/folders. More information in object.',
+ 1001: 'Failed to move files/folders. More information in object.',
+ 1002: 'An error occurred at the destination. More information in object.',
+ 1003: 'Cannot overwrite or skip the existing file because no overwrite parameter is given.',
+ 1004: 'File cannot overwrite a folder with the same name, or folder cannot overwrite a file with the same name.',
+ 1006: 'Cannot copy/move file/folder with special characters to a FAT32 file system.',
+ 1007: 'Cannot copy/move a file bigger than 4G to a FAT32 file system.',
+ 1100: 'Failed to create a folder. More information in object.',
+ 1101: 'The number of folders to the parent folder would exceed the system limitation.',
+ 1200: 'Failed to rename it. more information in object.',
+ 1300: 'Failed to compress files/folders.',
+ 1301: ' Cannot create the archive because the given archive name is too long.',
+ 1400: 'Failed to extract files.',
+ 1401: 'Cannot open the file as archive.',
+ 1402: 'Failed to read archive data error',
+ 1403: 'Wrong password.',
+ 1404: 'Failed to get the file and dir list in an archive.',
+ 1405: 'Failed to find the item ID in an archive file.',
+ 1800: 'There is no Content-Length information in the HTTP header or the received size doesn\'t match the value of Content-Length information in the HTTP header',
+ 1801: 'Wait too long, no date can be received from client (Default maximum wait time is 3600 seconds)',
+ 1802: 'No filename information in the last part of file content',
+ 1803: 'Upload connection is cancelled',
+ 1804: 'Failed to upload oversized file to FAT file system',
+ 1805: 'Can\'t overwrite or skip the existing file, if no overwrite parameter is given',
+ 2000: 'Sharing link does not exist.',
+ 2001: 'Cannot generate sharing link because too many sharing links exist',
+ 2002: 'Failed to access sharing links',
}
# Source: https://global.synologydownload.com/download/Document/Software/DeveloperGuide/Package/Virtualization/All
diff --git a/synology_api/event_scheduler.py b/synology_api/event_scheduler.py
index 40cfd201..69efe5f0 100644
--- a/synology_api/event_scheduler.py
+++ b/synology_api/event_scheduler.py
@@ -1,3 +1,9 @@
+"""
+Event Scheduler API module.
+
+This module provides the EventScheduler class for managing event-based tasks and power schedules
+on Synology NAS devices via the SYNO.Core.EventScheduler API.
+"""
from __future__ import annotations
from . import base_api
from .core_sys_info import SysInfo
@@ -6,26 +12,36 @@
class EventScheduler(base_api.BaseApi):
- """Event Scheduler API implementation.
-
- This API provides functionality solely related to Event Tasks. For scheduled tasks, check `TaskScheduler`.
-
- Supported methods:
- - Getters:
- - Get task results
- - Get result output
- - Setters:
- - Set task settings
- - Set power schedule
- - Actions:
- - Enable task
- - Disable task
- - Run task
- - Delete task
- - Create task
+ """
+ Event Scheduler API implementation.
+
+ This API provides functionality solely related to Event Tasks. For scheduled tasks, check `TaskScheduler`.
+
+ Methods
+ -------
+ Getters:
+ - Get task results
+ - Get result output
+ Setters:
+ - Set task settings
+ - Set power schedule
+ Actions:
+ - Enable task
+ - Disable task
+ - Run task
+ - Delete task
+ - Create task
"""
def __get_root_token(self) -> str:
+ """
+ Get the SynoConfirmPWToken for root operations.
+
+ Returns
+ -------
+ str
+ The SynoConfirmPWToken if successful, otherwise an empty string.
+ """
sys_info = SysInfo(ip_address=self.session._ip_address, port=self.session._port, username=self.session._username, password=self.session._password,
secure=self.session._secure, cert_verify=self.session._verify, dsm_version=self.session._version, debug=self.session._debug,
otp_code=self.session._otp_code, application=self.application)
@@ -39,42 +55,43 @@ def get_task_results(
self,
task_name: str
) -> dict[str, object] | str:
- """Retrieve the results list for a specific task.
-
- Parameters
- ----------
- task_name : str
- Name of the Event task to enable/disable.
-
- Returns
- -------
- dict[str, object]
- A dictionary containing the task results.
-
- Examples
- --------
- ```json
- {
- "data": [
- {
- "event_fire_time": "2024-09-13 03:17:47",
- "exit_info": {
- "exit_code": 0,
- "exit_type": "stop"
- },
- "extra": {},
- "pid": 16058,
- "result_id": 115,
- "run_time_env": {},
- "start_time": "2024-09-13 03:17:47",
- "stop_time": "2024-09-13 03:17:47",
- "task_name": "asd",
- "trigger_event": "on_demand"
- }
- ],
- "success": true
- }
- ```
+ """
+ Retrieve the results list for a specific task.
+
+ Parameters
+ ----------
+ task_name : str
+ Name of the Event task to enable/disable.
+
+ Returns
+ -------
+ dict[str, object]
+ A dictionary containing the task results.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": [
+ {
+ "event_fire_time": "2024-09-13 03:17:47",
+ "exit_info": {
+ "exit_code": 0,
+ "exit_type": "stop"
+ },
+ "extra": {},
+ "pid": 16058,
+ "result_id": 115,
+ "run_time_env": {},
+ "start_time": "2024-09-13 03:17:47",
+ "stop_time": "2024-09-13 03:17:47",
+ "task_name": "asd",
+ "trigger_event": "on_demand"
+ }
+ ],
+ "success": true
+ }
+ ```
"""
api_name = 'SYNO.Core.EventScheduler'
info = self.gen_list[api_name]
@@ -92,32 +109,32 @@ def get_result_output(
task_name: str,
result_id: int
) -> dict[str, object] | str:
- """Retrieve the output for a given result.
-
- Parameters
- ----------
- task_name : str
- Name of the Event task to enable/disable.
-
- result_id : int
- ID of the result to retrieve. From get_task_results().
-
- Returns
- -------
- dict[str, object]
- A dictionary containing the result output.
-
- Examples
- --------
- ```json
- {
- "data": {
- "script_in": "hello",
- "script_out": "/volume3/datastore/scripts_output/asd/1726190267/script.log: line 1: hello: command not found\\n"
- },
- "success": true
- }
- ```
+ """
+ Retrieve the output for a given result.
+
+ Parameters
+ ----------
+ task_name : str
+ Name of the Event task to enable/disable.
+ result_id : int
+ ID of the result to retrieve. From get_task_results().
+
+ Returns
+ -------
+ dict[str, object]
+ A dictionary containing the result output.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "script_in": "hello",
+ "script_out": "/volume3/datastore/scripts_output/asd/1726190267/script.log: line 1: hello: command not found\\n"
+ },
+ "success": true
+ }
+ ```
"""
api_name = 'SYNO.Core.EventScheduler'
info = self.gen_list[api_name]
@@ -136,29 +153,28 @@ def task_set_enable(
task_name: str,
enable: bool
) -> dict[str, object] | str:
- """Enable or disable Event task.
-
- Parameters
- ----------
- task_name : str
- Name of the Event task to enable/disable.
-
- enable (bool):
- Wheter to enable (`True`) or disable (`False`) the task.
-
- Returns
- -------
- dict[str, object]
- A dictionary containing the result of the action.
-
- Examples
- --------
- ```json
- {
- "success": true
- }
- ```
-
+ """
+ Enable or disable Event task.
+
+ Parameters
+ ----------
+ task_name : str
+ Name of the Event task to enable/disable.
+ enable : bool
+ Whether to enable (`True`) or disable (`False`) the task.
+
+ Returns
+ -------
+ dict[str, object]
+ A dictionary containing the result of the action.
+
+ Examples
+ --------
+ ```json
+ {
+ "success": true
+ }
+ ```
"""
api_name = 'SYNO.Core.EventScheduler'
info = self.gen_list[api_name]
@@ -176,25 +192,26 @@ def task_run(
self,
task_name: str
) -> dict[str, object] | str:
- """Run a specific Event task.
-
- Parameters
- ----------
- task_name : str
- Name of the Event task to run.
-
- Returns
- -------
- dict[str, object]
- A dictionary containing the result of the task execution.
-
- Examples
- --------
- ```json
- {
- "success": true
- }
- ```
+ """
+ Run a specific Event task.
+
+ Parameters
+ ----------
+ task_name : str
+ Name of the Event task to run.
+
+ Returns
+ -------
+ dict[str, object]
+ A dictionary containing the result of the task execution.
+
+ Examples
+ --------
+ ```json
+ {
+ "success": true
+ }
+ ```
"""
api_name = 'SYNO.Core.EventScheduler'
@@ -212,26 +229,26 @@ def task_delete(
self,
task_name: str
) -> dict[str, object] | str:
- """Delete a specific Event task.
-
- Parameters
- ----------
- task_name : str
- Name of the Event task to run.
-
- Returns
- -------
- dict[str, object]
- A dictionary containing the result of the task deletion.
-
- Examples
- --------
- ```json
- ----------
- {
- "success": true
- }
- ```
+ """
+ Delete a specific Event task.
+
+ Parameters
+ ----------
+ task_name : str
+ Name of the Event task to run.
+
+ Returns
+ -------
+ dict[str, object]
+ A dictionary containing the result of the task deletion.
+
+ Examples
+ --------
+ ```json
+ {
+ "success": true
+ }
+ ```
"""
api_name = 'SYNO.Core.EventScheduler'
@@ -257,61 +274,51 @@ def task_create_or_set(
notify_email: str = '',
notify_only_on_error: bool = False
) -> dict[str, object] | str:
- """Create or modify an event-based task.
-
- Parameters
- ----------
- action : str
- Action to perform on the task.
-
- Possible values:
- - `create` -> Creates a new task.
- - `set` -> Modify an existing task.
-
- task_name : str
- The name of the task.
-
- owner : dict[str, str]
- Dictionary containing the owner's ID and name (e.g., `{"1026": "user1"}`).
-
- You can get the user UID by running `synouser --get your_user` in your NAS CLI.
-
- For root privileges, pass `{"0":"root"}`.
-
- trigger_event : str
- The event that triggers the task.
-
- Possible values:
- - `shutdown`
- - `bootup`
-
- script : str
- The script to be executed when the task is triggered.
-
- depend_on_task : list[str], optional
- A list of event triggered task names that this task depends on (i.e., tasks that will be run before this one). Defaults to `[]`.
-
- enable : bool, optional
- Whether to enable the task. Defaults to `True`.
-
- notify_email : str, optional
- Email address to send notifications to. Defaults to `""`, thus disabling the notification feature.
-
- notify_only_on_error : bool, optional
- If `True`, notifications are only sent when an error occurs. Defaults to `False`.
-
- Returns
- -------
- dict[str, object]
- A dictionary containing the result of the task creation or modification, or a strnig in case of an error.
-
- Examples
- --------
- ```json
- {
- "success": true
- }
- ```
+ """
+ Create or modify an event-based task.
+
+ Parameters
+ ----------
+ action : str
+ Action to perform on the task.
+
+ Possible values:
+ - `create` -> Create a new task.
+ - `set` -> Modify an existing task.
+ task_name : str
+ The name of the task.
+ owner : dict[str, str]
+ Dictionary containing the owner's ID and name (e.g., `{"1026": "user1"}`).
+ You can get the user UID by running `synouser --get your_user` in your NAS CLI.
+ For root privileges, pass `{"0":"root"}`.
+ trigger_event : str
+ The event that triggers the task.
+ Possible values:
+ - `shutdown`
+ - `bootup`
+ script : str
+ The script to be executed when the task is triggered.
+ depend_on_task : list[str], optional
+ A list of event triggered task names that this task depends on (i.e., tasks that will be run before this one). Defaults to `[]`.
+ enable : bool, optional
+ Whether to enable the task. Defaults to `True`.
+ notify_email : str, optional
+ Email address to send notifications to. Defaults to `""`, thus disabling the notification feature.
+ notify_only_on_error : bool, optional
+ If `True`, notifications are only sent when an error occurs. Defaults to `False`.
+
+ Returns
+ -------
+ dict[str, object]
+ A dictionary containing the result of the task creation or modification, or a string in case of an error.
+
+ Examples
+ --------
+ ```json
+ {
+ "success": true
+ }
+ ```
"""
if action != 'create' and action != 'set':
return {'error': f'action <{action}> is not valid.'}
@@ -348,55 +355,57 @@ def task_create_or_set(
return self.request_data(api_name, api_path, req_param)
def set_power_schedule(self, poweron_tasks: List[dict] = [], poweroff_tasks: List[dict] = []) -> dict:
- """Set the power schedule, poweron tasks and poweroff tasks
-
- Parameters
- ----------
- poweron_tasks : List[dict], optional
- List of tasks for power on. Defaults to `[]`
- Example of a task:
- ```python
- {
- "enabled": True, # Enable or not the task
- "hour": 13, # Hour 0-23
- "min": 59, # Minutes 0-59
- "weekdays": "0,1,2,3,4,5,6" # All days of the week (Sunday, Monday, Tuesday, Wednesday, Thrusday, Friday, Saturday)
- }
- ```
- poweroff_tasks : List[dict], optional
- List of tasks for power off. Defaults to `[]`
- Example of a task:
- ```python
- {
- "enabled": True, # Enable or not the task
- "hour": 13, # Hour 0-23
- "min": 59, # Minutes 0-59
- "weekdays": "0,1,2,3,4,5,6" # All days of the week (Sunday, Monday, Tuesday, Wednesday, Thrusday, Friday, Saturday)
- }
- ```
- Returns
- -------
- dict
- List of tasks in power schedule
-
- Examples
- --------
- ```json
+ """
+ Set the power schedule, poweron tasks and poweroff tasks.
+
+ Parameters
+ ----------
+ poweron_tasks : List[dict], optional
+ List of tasks for power on. Defaults to `[]`.
+ Example of a task:
+ ```python
{
- "data": {
- "poweroff_tasks": [],
- "poweron_tasks": [
- {
- "enabled": true,
- "hour": 0,
- "min": 0,
- "weekdays": "1,2,3,4,5"
- }
- ]
- },
- "success": true
+ "enabled": True, # Enable or not the task
+ "hour": 13, # Hour 0-23
+ "min": 59, # Minutes 0-59
+ "weekdays": "0,1,2,3,4,5,6" # All days of the week (Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday)
}
```
+ poweroff_tasks : List[dict], optional
+ List of tasks for power off. Defaults to `[]`.
+ Example of a task:
+ ```python
+ {
+ "enabled": True, # Enable or not the task
+ "hour": 13, # Hour 0-23
+ "min": 59, # Minutes 0-59
+ "weekdays": "0,1,2,3,4,5,6" # All days of the week (Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday)
+ }
+ ```
+
+ Returns
+ -------
+ dict
+ List of tasks in power schedule.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "poweroff_tasks": [],
+ "poweron_tasks": [
+ {
+ "enabled": true,
+ "hour": 0,
+ "min": 0,
+ "weekdays": "1,2,3,4,5"
+ }
+ ]
+ },
+ "success": true
+ }
+ ```
"""
api_name = 'SYNO.Core.Hardware.PowerSchedule'
@@ -412,31 +421,32 @@ def set_power_schedule(self, poweron_tasks: List[dict] = [], poweroff_tasks: Lis
return self.request_data(api_name, api_path, req_param)
def load_power_schedule(self) -> dict:
- """Load the power schedule, poweron tasks and poweroff tasks
-
- Returns
- -------
- dict
- List of tasks in power schedule
-
- Examples
- --------
- ```json
- {
- "data": {
- "poweroff_tasks": [],
- "poweron_tasks": [
- {
- "enabled": true,
- "hour": 0,
- "min": 0,
- "weekdays": "1,2,3,4,5"
- }
- ]
- },
- "success": true
- }
- ```
+ """
+ Load the power schedule, poweron tasks and poweroff tasks.
+
+ Returns
+ -------
+ dict
+ List of tasks in power schedule.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "poweroff_tasks": [],
+ "poweron_tasks": [
+ {
+ "enabled": true,
+ "hour": 0,
+ "min": 0,
+ "weekdays": "1,2,3,4,5"
+ }
+ ]
+ },
+ "success": true
+ }
+ ```
"""
api_name = 'SYNO.Core.Hardware.PowerSchedule'
diff --git a/synology_api/exceptions.py b/synology_api/exceptions.py
index aa12cd9a..3fb409e3 100644
--- a/synology_api/exceptions.py
+++ b/synology_api/exceptions.py
@@ -1,12 +1,40 @@
+"""
+Exception classes for Synology API.
+
+This module defines custom exception classes for handling errors and error codes
+returned by various Synology API endpoints.
+"""
+
from .error_codes import error_codes, auth_error_codes, download_station_error_codes, file_station_error_codes, core_error_codes
from .error_codes import virtualization_error_codes
# Base exception:
class SynoBaseException(Exception):
- """Base class for an exception. Defines error_message."""
+ """
+ Base class for an exception.
+
+ Defines error_message.
+
+ Parameters
+ ----------
+ error_message : str
+ The error message describing the exception.
+ *args : object
+ Additional arguments to pass to the base Exception.
+ """
def __init__(self, error_message: str, *args: object) -> None:
+ """
+ Initialize SynoBaseException.
+
+ Parameters
+ ----------
+ error_message : str
+ The error message describing the exception.
+ *args : object
+ Additional arguments to pass to the base Exception.
+ """
super().__init__(*args)
self.error_message = error_message
return
@@ -14,34 +42,110 @@ def __init__(self, error_message: str, *args: object) -> None:
# Classes to reraise Exceptions from requests.
class SynoConnectionError(SynoBaseException):
- """Class to raise when a connection error occurs."""
+ """
+ Exception raised when a connection error occurs.
+
+ Parameters
+ ----------
+ error_message : str
+ The error message describing the connection error.
+ *args : object
+ Additional arguments to pass to the base Exception.
+ """
def __init__(self, error_message: str, *args: object) -> None:
+ """
+ Initialize SynoConnectionError.
+
+ Parameters
+ ----------
+ error_message : str
+ The error message describing the connection error.
+ *args : object
+ Additional arguments to pass to the base Exception.
+ """
super().__init__(error_message=error_message, *args)
return
class HTTPError(SynoBaseException):
- """Class to raise when a http error occurs."""
+ """
+ Exception raised when an HTTP error occurs.
+
+ Parameters
+ ----------
+ error_message : str
+ The error message describing the HTTP error.
+ *args : object
+ Additional arguments to pass to the base Exception.
+ """
def __init__(self, error_message: str, *args: object) -> None:
+ """
+ Initialize HTTPError.
+
+ Parameters
+ ----------
+ error_message : str
+ The error message describing the HTTP error.
+ *args : object
+ Additional arguments to pass to the base Exception.
+ """
super().__init__(error_message, *args)
return
class JSONDecodeError(SynoBaseException):
- """Class to raise when server fails to send JSON."""
+ """
+ Exception raised when the server fails to send valid JSON.
+
+ Parameters
+ ----------
+ error_message : str
+ The error message describing the JSON decode error.
+ *args : object
+ Additional arguments to pass to the base Exception.
+ """
def __init__(self, error_message: str, *args: object) -> None:
+ """
+ Initialize JSONDecodeError.
+
+ Parameters
+ ----------
+ error_message : str
+ The error message describing the JSON decode error.
+ *args : object
+ Additional arguments to pass to the base Exception.
+ """
super().__init__(error_message, *args)
return
# Classes for when we receive an error code in the JSON from the server.
class LoginError(SynoBaseException):
- """Class for an error during login."""
+ """
+ Exception raised for an error during login.
+
+ Parameters
+ ----------
+ error_code : int
+ The error code returned by the API.
+ *args : object
+ Additional arguments to pass to the base Exception.
+ """
def __init__(self, error_code: int, *args: object) -> None:
+ """
+ Initialize LoginError.
+
+ Parameters
+ ----------
+ error_code : int
+ The error code returned by the API.
+ *args : object
+ Additional arguments to pass to the base Exception.
+ """
self.error_code: int = error_code
if error_code not in error_codes.keys():
super().__init__(error_message=auth_error_codes[error_code], *args)
@@ -51,9 +155,28 @@ def __init__(self, error_code: int, *args: object) -> None:
class LogoutError(SynoBaseException):
- """Class for an error during logout."""
+ """
+ Exception raised for an error during logout.
+
+ Parameters
+ ----------
+ error_code : int
+ The error code returned by the API.
+ *args : object
+ Additional arguments to pass to the base Exception.
+ """
def __init__(self, error_code: int, *args: object) -> None:
+ """
+ Initialize LogoutError.
+
+ Parameters
+ ----------
+ error_code : int
+ The error code returned by the API.
+ *args : object
+ Additional arguments to pass to the base Exception.
+ """
self.error_code: int = error_code
if error_code in error_codes.keys():
super().__init__(error_message=error_codes[error_code], *args)
@@ -63,9 +186,28 @@ def __init__(self, error_code: int, *args: object) -> None:
class DownloadStationError(SynoBaseException):
- """Class for an error during a download station request."""
+ """
+ Exception raised for an error during a Download Station request.
+
+ Parameters
+ ----------
+ error_code : int
+ The error code returned by the API.
+ *args : object
+ Additional arguments to pass to the base Exception.
+ """
def __init__(self, error_code: int, *args: object) -> None:
+ """
+ Initialize DownloadStationError.
+
+ Parameters
+ ----------
+ error_code : int
+ The error code returned by the API.
+ *args : object
+ Additional arguments to pass to the base Exception.
+ """
self.error_code: int = error_code
if error_code in error_codes.keys():
super().__init__(error_message=error_codes[error_code], *args)
@@ -78,9 +220,28 @@ def __init__(self, error_code: int, *args: object) -> None:
class FileStationError(SynoBaseException):
- """Class for an error during a file station request."""
+ """
+ Exception raised for an error during a File Station request.
+
+ Parameters
+ ----------
+ error_code : int
+ The error code returned by the API.
+ *args : object
+ Additional arguments to pass to the base Exception.
+ """
def __init__(self, error_code: int, *args: object) -> None:
+ """
+ Initialize FileStationError.
+
+ Parameters
+ ----------
+ error_code : int
+ The error code returned by the API.
+ *args : object
+ Additional arguments to pass to the base Exception.
+ """
self.error_code: int = error_code
if error_code in error_codes.keys():
super().__init__(error_message=error_codes[error_code], *args)
@@ -93,9 +254,28 @@ def __init__(self, error_code: int, *args: object) -> None:
class VirtualizationError(SynoBaseException):
- """Class for an error during a virtualization request."""
+ """
+ Exception raised for an error during a virtualization request.
+
+ Parameters
+ ----------
+ error_code : int
+ The error code returned by the API.
+ *args : object
+ Additional arguments to pass to the base Exception.
+ """
def __init__(self, error_code: int, *args: object) -> None:
+ """
+ Initialize VirtualizationError.
+
+ Parameters
+ ----------
+ error_code : int
+ The error code returned by the API.
+ *args : object
+ Additional arguments to pass to the base Exception.
+ """
self.error_code = error_code
if error_code in error_codes.keys():
super().__init__(error_message=error_codes[error_code], *args)
@@ -108,10 +288,28 @@ def __init__(self, error_code: int, *args: object) -> None:
class AudioStationError(SynoBaseException):
- """Class for an error during an audio station request. NOTE: I can't find any documentation on the audio station
- webAPI errors numbers and their respective messages."""
+ """
+ Exception raised for an error during an Audio Station request.
+
+ Parameters
+ ----------
+ error_code : int
+ The error code returned by the API.
+ *args : object
+ Additional arguments to pass to the base Exception.
+ """
def __init__(self, error_code: int, *args: object) -> None:
+ """
+ Initialize AudioStationError.
+
+ Parameters
+ ----------
+ error_code : int
+ The error code returned by the API.
+ *args : object
+ Additional arguments to pass to the base Exception.
+ """
self.error_code = error_code
if error_code in error_codes.keys():
super().__init__(error_message=error_codes[error_code], *args)
@@ -121,10 +319,28 @@ def __init__(self, error_code: int, *args: object) -> None:
class ActiveBackupError(SynoBaseException):
- """Class for an error during ActiveBackup request. NOTE: I can't find any documentation on error codes or their
- respective messages."""
+ """
+ Exception raised for an error during an Active Backup request.
+
+ Parameters
+ ----------
+ error_code : int
+ The error code returned by the API.
+ *args : object
+ Additional arguments to pass to the base Exception.
+ """
def __init__(self, error_code: int, *args: object) -> None:
+ """
+ Initialize ActiveBackupError.
+
+ Parameters
+ ----------
+ error_code : int
+ The error code returned by the API.
+ *args : object
+ Additional arguments to pass to the base Exception.
+ """
self.error_code = error_code
if error_code in error_codes.keys():
super().__init__(error_message=error_codes[error_code], *args)
@@ -133,10 +349,28 @@ def __init__(self, error_code: int, *args: object) -> None:
class ActiveBackupMicrosoftError(SynoBaseException):
- """Class for an error during ActiveBackupMicrosoft request. NOTE: I can't find any documentation on error codes or their
- respective messages."""
+ """
+ Exception raised for an error during an Active Backup Microsoft request.
+
+ Parameters
+ ----------
+ error_code : int
+ The error code returned by the API.
+ *args : object
+ Additional arguments to pass to the base Exception.
+ """
def __init__(self, error_code: int, *args: object) -> None:
+ """
+ Initialize ActiveBackupMicrosoftError.
+
+ Parameters
+ ----------
+ error_code : int
+ The error code returned by the API.
+ *args : object
+ Additional arguments to pass to the base Exception.
+ """
self.error_code = error_code
if error_code in error_codes.keys():
super().__init__(error_message=error_codes[error_code], *args)
@@ -145,9 +379,28 @@ def __init__(self, error_code: int, *args: object) -> None:
class BackupError(SynoBaseException):
- """Class for an error during backup request. NOTE: Again I can't find error code documentation."""
+ """
+ Exception raised for an error during a backup request.
+
+ Parameters
+ ----------
+ error_code : int
+ The error code returned by the API.
+ *args : object
+ Additional arguments to pass to the base Exception.
+ """
def __init__(self, error_code: int, *args: object) -> None:
+ """
+ Initialize BackupError.
+
+ Parameters
+ ----------
+ error_code : int
+ The error code returned by the API.
+ *args : object
+ Additional arguments to pass to the base Exception.
+ """
self.error_code = error_code
if error_code in error_codes.keys():
super().__init__(error_message=error_codes[error_code], *args)
@@ -157,9 +410,28 @@ def __init__(self, error_code: int, *args: object) -> None:
class CertificateError(SynoBaseException):
- """Class for an error during Core.Certificate request. NOTE: Lacking documentation."""
+ """
+ Exception raised for an error during a Core.Certificate request.
+
+ Parameters
+ ----------
+ error_code : int
+ The error code returned by the API.
+ *args : object
+ Additional arguments to pass to the base Exception.
+ """
def __init__(self, error_code: int, *args: object) -> None:
+ """
+ Initialize CertificateError.
+
+ Parameters
+ ----------
+ error_code : int
+ The error code returned by the API.
+ *args : object
+ Additional arguments to pass to the base Exception.
+ """
self.error_code = error_code
if error_code in error_codes.keys():
super().__init__(error_message=error_codes[error_code])
@@ -169,9 +441,28 @@ def __init__(self, error_code: int, *args: object) -> None:
class CloudSyncError(SynoBaseException):
- """Class for an error during SYNO.CloudSync request. NOTE: Lacking documentation."""
+ """
+ Exception raised for an error during a SYNO.CloudSync request.
+
+ Parameters
+ ----------
+ error_code : int
+ The error code returned by the API.
+ *args : object
+ Additional arguments to pass to the base Exception.
+ """
def __init__(self, error_code: int, *args: object) -> None:
+ """
+ Initialize CloudSyncError.
+
+ Parameters
+ ----------
+ error_code : int
+ The error code returned by the API.
+ *args : object
+ Additional arguments to pass to the base Exception.
+ """
self.error_code = error_code
if error_code in error_codes.keys():
super().__init__(error_message=error_codes[error_code])
@@ -181,9 +472,28 @@ def __init__(self, error_code: int, *args: object) -> None:
class DHCPServerError(SynoBaseException):
- """Class for an error during a DHCPServer request."""
+ """
+ Exception raised for an error during a DHCPServer request.
+
+ Parameters
+ ----------
+ error_code : int
+ The error code returned by the API.
+ *args : object
+ Additional arguments to pass to the base Exception.
+ """
def __init__(self, error_code: int, *args: object) -> None:
+ """
+ Initialize DHCPServerError.
+
+ Parameters
+ ----------
+ error_code : int
+ The error code returned by the API.
+ *args : object
+ Additional arguments to pass to the base Exception.
+ """
self.error_code = error_code
if error_code in error_codes.keys():
super().__init__(error_message=error_codes[error_code], *args)
@@ -193,9 +503,28 @@ def __init__(self, error_code: int, *args: object) -> None:
class DirectoryServerError(SynoBaseException):
- """Class for an error during a directory server request. NOTE: No docs on errors."""
+ """
+ Exception raised for an error during a Directory Server request.
+
+ Parameters
+ ----------
+ error_code : int
+ The error code returned by the API.
+ *args : object
+ Additional arguments to pass to the base Exception.
+ """
def __init__(self, error_code: int, *args: object) -> None:
+ """
+ Initialize DirectoryServerError.
+
+ Parameters
+ ----------
+ error_code : int
+ The error code returned by the API.
+ *args : object
+ Additional arguments to pass to the base Exception.
+ """
self.error_code = error_code
if error_code in error_codes.keys():
super().__init__(error_message=error_codes[error_code], *args)
@@ -205,9 +534,28 @@ def __init__(self, error_code: int, *args: object) -> None:
class DockerError(SynoBaseException):
- """Class for an error during a docker request. NOTE: No docs on errors."""
+ """
+ Exception raised for an error during a Docker request.
+
+ Parameters
+ ----------
+ error_code : int
+ The error code returned by the API.
+ *args : object
+ Additional arguments to pass to the base Exception.
+ """
def __init__(self, error_code: int, *args: object) -> None:
+ """
+ Initialize DockerError.
+
+ Parameters
+ ----------
+ error_code : int
+ The error code returned by the API.
+ *args : object
+ Additional arguments to pass to the base Exception.
+ """
self.error_code = error_code
if error_code in error_codes.keys():
super().__init__(error_message=error_codes[error_code], *args)
@@ -217,9 +565,28 @@ def __init__(self, error_code: int, *args: object) -> None:
class DriveAdminError(SynoBaseException):
- """Class for an error during a drive admin request. NOTE: No error docs."""
+ """
+ Exception raised for an error during a Drive Admin request.
+
+ Parameters
+ ----------
+ error_code : int
+ The error code returned by the API.
+ *args : object
+ Additional arguments to pass to the base Exception.
+ """
def __init__(self, error_code: int, *args: object) -> None:
+ """
+ Initialize DriveAdminError.
+
+ Parameters
+ ----------
+ error_code : int
+ The error code returned by the API.
+ *args : object
+ Additional arguments to pass to the base Exception.
+ """
self.error_code = error_code
if error_code in error_codes.keys():
super().__init__(error_message=error_codes[error_code], *args)
@@ -229,9 +596,28 @@ def __init__(self, error_code: int, *args: object) -> None:
class LogCenterError(SynoBaseException):
- """Class for an error during a LogCenter request. NOTE: No docs on errors.... again."""
+ """
+ Exception raised for an error during a LogCenter request.
+
+ Parameters
+ ----------
+ error_code : int
+ The error code returned by the API.
+ *args : object
+ Additional arguments to pass to the base Exception.
+ """
def __init__(self, error_code: int, *args: object) -> None:
+ """
+ Initialize LogCenterError.
+
+ Parameters
+ ----------
+ error_code : int
+ The error code returned by the API.
+ *args : object
+ Additional arguments to pass to the base Exception.
+ """
self.error_code = error_code
if error_code in error_codes.keys():
super().__init__(error_message=error_codes[error_code], *args)
@@ -241,9 +627,28 @@ def __init__(self, error_code: int, *args: object) -> None:
class NoteStationError(SynoBaseException):
- """Class for an error during a NoteStation request. NOTE: No error docs."""
+ """
+ Exception raised for an error during a NoteStation request.
+
+ Parameters
+ ----------
+ error_code : int
+ The error code returned by the API.
+ *args : object
+ Additional arguments to pass to the base Exception.
+ """
def __init__(self, error_code: int, *args: object) -> None:
+ """
+ Initialize NoteStationError.
+
+ Parameters
+ ----------
+ error_code : int
+ The error code returned by the API.
+ *args : object
+ Additional arguments to pass to the base Exception.
+ """
self.error_code = error_code
if error_code in error_codes.keys():
super().__init__(error_message=error_codes[error_code], *args)
@@ -253,9 +658,28 @@ def __init__(self, error_code: int, *args: object) -> None:
class OAUTHError(SynoBaseException):
- """Class for an error during a OAUTH request. NOTE: No error docs."""
+ """
+ Exception raised for an error during an OAUTH request.
+
+ Parameters
+ ----------
+ error_code : int
+ The error code returned by the API.
+ *args : object
+ Additional arguments to pass to the base Exception.
+ """
def __init__(self, error_code: int, *args: object) -> None:
+ """
+ Initialize OAUTHError.
+
+ Parameters
+ ----------
+ error_code : int
+ The error code returned by the API.
+ *args : object
+ Additional arguments to pass to the base Exception.
+ """
self.error_code = error_code
if error_code in error_codes.keys():
super().__init__(error_message=error_codes[error_code], *args)
@@ -265,9 +689,28 @@ def __init__(self, error_code: int, *args: object) -> None:
class PhotosError(SynoBaseException):
- """Class for an error during a Photos request. NOTE: No error docs."""
+ """
+ Exception raised for an error during a Photos request.
+
+ Parameters
+ ----------
+ error_code : int
+ The error code returned by the API.
+ *args : object
+ Additional arguments to pass to the base Exception.
+ """
def __init__(self, error_code: int, *args: object) -> None:
+ """
+ Initialize PhotosError.
+
+ Parameters
+ ----------
+ error_code : int
+ The error code returned by the API.
+ *args : object
+ Additional arguments to pass to the base Exception.
+ """
self.error_code = error_code
if error_code in error_codes.keys():
super().__init__(error_message=error_codes[error_code], *args)
@@ -277,9 +720,28 @@ def __init__(self, error_code: int, *args: object) -> None:
class SecurityAdvisorError(SynoBaseException):
- """Class for an error during a SecurityAdvisor request. NOTE: What docs?"""
+ """
+ Exception raised for an error during a SecurityAdvisor request.
+
+ Parameters
+ ----------
+ error_code : int
+ The error code returned by the API.
+ *args : object
+ Additional arguments to pass to the base Exception.
+ """
def __init__(self, error_code: int, *args: object) -> None:
+ """
+ Initialize SecurityAdvisorError.
+
+ Parameters
+ ----------
+ error_code : int
+ The error code returned by the API.
+ *args : object
+ Additional arguments to pass to the base Exception.
+ """
self.error_code = error_code
if error_code in error_codes.keys():
super().__init__(error_message=error_codes[error_code], *args)
@@ -289,9 +751,28 @@ def __init__(self, error_code: int, *args: object) -> None:
class TaskSchedulerError(SynoBaseException):
- """Class for an error during TaskScheduler request. NOTE:... no docs on errors...."""
+ """
+ Exception raised for an error during a TaskScheduler request.
+
+ Parameters
+ ----------
+ error_code : int
+ The error code returned by the API.
+ *args : object
+ Additional arguments to pass to the base Exception.
+ """
def __init__(self, error_code: int, *args: object) -> None:
+ """
+ Initialize TaskSchedulerError.
+
+ Parameters
+ ----------
+ error_code : int
+ The error code returned by the API.
+ *args : object
+ Additional arguments to pass to the base Exception.
+ """
self.error_code = error_code
if error_code in error_codes.keys():
super().__init__(error_message=error_codes[error_code], *args)
@@ -301,9 +782,28 @@ def __init__(self, error_code: int, *args: object) -> None:
class EventSchedulerError(SynoBaseException):
- """Class for an error during EventScheduler request. NOTE:... no docs on errors...."""
+ """
+ Exception raised for an error during an EventScheduler request.
+
+ Parameters
+ ----------
+ error_code : int
+ The error code returned by the API.
+ *args : object
+ Additional arguments to pass to the base Exception.
+ """
def __init__(self, error_code: int, *args: object) -> None:
+ """
+ Initialize EventSchedulerError.
+
+ Parameters
+ ----------
+ error_code : int
+ The error code returned by the API.
+ *args : object
+ Additional arguments to pass to the base Exception.
+ """
self.error_code = error_code
if error_code in error_codes.keys():
super().__init__(error_message=error_codes[error_code], *args)
@@ -313,9 +813,28 @@ def __init__(self, error_code: int, *args: object) -> None:
class UniversalSearchError(SynoBaseException):
- """Class for an error during UniversalSearch request. NOTE:... no docs on errors...."""
+ """
+ Exception raised for an error during a UniversalSearch request.
+
+ Parameters
+ ----------
+ error_code : int
+ The error code returned by the API.
+ *args : object
+ Additional arguments to pass to the base Exception.
+ """
def __init__(self, error_code: int, *args: object) -> None:
+ """
+ Initialize UniversalSearchError.
+
+ Parameters
+ ----------
+ error_code : int
+ The error code returned by the API.
+ *args : object
+ Additional arguments to pass to the base Exception.
+ """
self.error_code = error_code
if error_code in error_codes.keys():
super().__init__(error_message=error_codes[error_code], *args)
@@ -325,9 +844,28 @@ def __init__(self, error_code: int, *args: object) -> None:
class USBCopyError(SynoBaseException):
- """Class for an error during a USBCopy request. NOTE: No docs on errors."""
+ """
+ Exception raised for an error during a USBCopy request.
+
+ Parameters
+ ----------
+ error_code : int
+ The error code returned by the API.
+ *args : object
+ Additional arguments to pass to the base Exception.
+ """
def __init__(self, error_code: int, *args: object) -> None:
+ """
+ Initialize USBCopyError.
+
+ Parameters
+ ----------
+ error_code : int
+ The error code returned by the API.
+ *args : object
+ Additional arguments to pass to the base Exception.
+ """
self.error_code = error_code
if error_code in error_codes.keys():
super().__init__(error_message=error_codes[error_code], *args)
@@ -336,9 +874,28 @@ def __init__(self, error_code: int, *args: object) -> None:
class VPNError(SynoBaseException):
- """Class for an error during a VPN request. NOTE: No docs on errors."""
+ """
+ Exception raised for an error during a VPN request.
+
+ Parameters
+ ----------
+ error_code : int
+ The error code returned by the API.
+ *args : object
+ Additional arguments to pass to the base Exception.
+ """
def __init__(self, error_code: int, *args: object) -> None:
+ """
+ Initialize VPNError.
+
+ Parameters
+ ----------
+ error_code : int
+ The error code returned by the API.
+ *args : object
+ Additional arguments to pass to the base Exception.
+ """
self.error_code = error_code
if error_code in error_codes.keys():
super().__init__(error_message=error_codes[error_code], *args)
@@ -348,10 +905,28 @@ def __init__(self, error_code: int, *args: object) -> None:
class CoreError(SynoBaseException):
- """Class for an error during a SYNO.Core.*
+ """
+ Exception raised for an error during a SYNO.Core.* request.
+
+ Parameters
+ ----------
+ error_code : int
+ The error code returned by the API.
+ *args : object
+ Additional arguments to pass to the base Exception.
"""
def __init__(self, error_code: int, *args: object) -> None:
+ """
+ Initialize CoreError.
+
+ Parameters
+ ----------
+ error_code : int
+ The error code returned by the API.
+ *args : object
+ Additional arguments to pass to the base Exception.
+ """
self.error_code = error_code
if error_code in core_error_codes.keys():
super().__init__(error_message=core_error_codes[error_code], *args)
@@ -361,11 +936,28 @@ def __init__(self, error_code: int, *args: object) -> None:
class CoreSysInfoError(SynoBaseException):
- """Class for an error during a 'SYNO.Backup.Service.NetworkBackup', SYNO.Storage.*,
- 'SYNO.Finder.FileIndexing.Status', 'SYNO.S2S.Server.Pair', SYNO.ResourceMonitor.*
+ """
+ Exception raised for an error during a CoreSysInfoError request.
+
+ Parameters
+ ----------
+ error_code : int
+ The error code returned by the API.
+ *args : object
+ Additional arguments to pass to the base Exception.
"""
def __init__(self, error_code: int, *args: object) -> None:
+ """
+ Initialize CoreSysInfoError.
+
+ Parameters
+ ----------
+ error_code : int
+ The error code returned by the API.
+ *args : object
+ Additional arguments to pass to the base Exception.
+ """
self.error_code = error_code
if error_code in error_codes.keys():
super().__init__(error_message=error_codes[error_code], *args)
@@ -375,9 +967,32 @@ def __init__(self, error_code: int, *args: object) -> None:
class UndefinedError(SynoBaseException):
- """Class for undefined errors."""
+ """
+ Exception raised for undefined errors.
+
+ Parameters
+ ----------
+ error_code : int
+ The error code returned by the API.
+ api_name : str
+ The name of the API where the error occurred.
+ *args : object
+ Additional arguments to pass to the base Exception.
+ """
def __init__(self, error_code: int, api_name: str, *args: object) -> None:
+ """
+ Initialize UndefinedError.
+
+ Parameters
+ ----------
+ error_code : int
+ The error code returned by the API.
+ api_name : str
+ The name of the API where the error occurred.
+ *args : object
+ Additional arguments to pass to the base Exception.
+ """
self.error_code = error_code
self.api_name = api_name
super().__init__(error_message="Undefined Error: API: %s, Code: %i" %
diff --git a/synology_api/filestation.py b/synology_api/filestation.py
index 16e03d8f..010035c4 100644
--- a/synology_api/filestation.py
+++ b/synology_api/filestation.py
@@ -1,20 +1,72 @@
+"""
+FileStation API module.
+
+This module provides the FileStation class for interacting with Synology NAS FileStation API,
+allowing file management, search, upload, download, and background task operations.
+"""
+
from __future__ import annotations
+
+import json
from typing import Optional, Any
import os
import io
import time
from datetime import datetime
+from urllib.parse import urljoin, urlencode
import requests
import tqdm
from requests_toolbelt import MultipartEncoder, MultipartEncoderMonitor
import sys
+import warnings
from urllib import parse
from treelib import Tree
from . import base_api
+from .utils import validate_path, get_data_for_request_from_file
class FileStation(base_api.BaseApi):
+ """
+ FileStation API implementation.
+
+ Provides methods to interact with Synology NAS FileStation API for file and folder operations,
+ search, upload, download, and background task management.
+
+ Parameters
+ ----------
+ ip_address : str
+ IP address of the Synology NAS.
+ port : str
+ Port number for the connection.
+ username : str
+ Username for authentication.
+ password : str
+ Password for authentication.
+ secure : bool, optional
+ Use HTTPS if True, HTTP otherwise. Default is False.
+ cert_verify : bool, optional
+ Verify SSL certificates if True. Default is False.
+ dsm_version : int, optional
+ DSM version of the Synology NAS. Default is 7.
+ debug : bool, optional
+ Enable debug output if True. Default is True.
+ otp_code : str, optional
+ One-time password for 2-step verification. Default is None.
+ device_id : str, optional
+ Device ID for authentication. Default is None.
+ device_name : str, optional
+ Name of the device. Default is None.
+ interactive_output : bool, optional
+ If True, enables interactive output. Default is False.
+
+ Methods
+ -------
+ get_info()
+ Get FileStation information.
+ get_list_share()
+ List shared folderss.
+ """
def __init__(self,
ip_address: str,
@@ -30,7 +82,36 @@ def __init__(self,
device_name: Optional[str] = None,
interactive_output: bool = True
) -> None:
-
+ """
+ Initialize FileStation API client.
+
+ Parameters
+ ----------
+ ip_address : str
+ IP address or hostname of the Synology NAS.
+ port : str
+ Port number for the API.
+ username : str
+ Username for authentication.
+ password : str
+ Password for authentication.
+ secure : bool, optional
+ Use HTTPS if True, HTTP if False. Default is False.
+ cert_verify : bool, optional
+ Verify SSL certificates if True. Default is False.
+ dsm_version : int, optional
+ DSM version. Default is 7.
+ debug : bool, optional
+ Enable debug output. Default is True.
+ otp_code : str, optional
+ One-time password for 2FA, if required.
+ device_id : str, optional
+ Device ID for authentication.
+ device_name : str, optional
+ Device name for authentication.
+ interactive_output : bool, optional
+ If True, outputs are formatted for interactive use. Default is True.
+ """
super(FileStation, self).__init__(ip_address, port, username, password, secure, cert_verify,
dsm_version, debug, otp_code, device_id, device_name, 'FileStation')
@@ -51,11 +132,19 @@ def __init__(self,
self.session.get_api_list('FileStation')
- self.file_station_list: Any = self.session.app_api_list
+ self.file_station_list: dict = self.session.app_api_list
self.interactive_output: bool = interactive_output
def get_info(self) -> dict[str, object] | str:
+ """
+ Get FileStation information.
+
+ Returns
+ -------
+ dict[str, object] or str
+ FileStation information or error message.
+ """
api_name = 'SYNO.FileStation.Info'
info = self.file_station_list[api_name]
api_path = info['path']
@@ -71,7 +160,29 @@ def get_list_share(self,
sort_direction: Optional[str] = None,
onlywritable: bool = False
) -> dict[str, object] | str:
-
+ """
+ List shared folders.
+
+ Parameters
+ ----------
+ additional : str or list of str, optional
+ Additional attributes to include.
+ offset : int, optional
+ Offset for pagination.
+ limit : int, optional
+ Limit for pagination.
+ sort_by : str, optional
+ Field to sort by.
+ sort_direction : str, optional
+ Sort direction ('asc' or 'desc').
+ onlywritable : bool, optional
+ If True, only writable shares are listed.
+
+ Returns
+ -------
+ dict[str, object] or str
+ List of shared folders or error message.
+ """
api_name = 'SYNO.FileStation.List'
info = self.file_station_list[api_name]
api_path = info['path']
@@ -101,59 +212,101 @@ def get_file_list(self,
pattern: Optional[str] = None,
filetype: Optional[str] = None,
goto_path: Optional[str] = None,
- additional: Optional[str | list[str]] = None) -> dict[str, object] | str:
-
+ additional: Optional[str | list[str]] = None) -> dict[str, object]:
+ """
+ List files in a folder.
+
+ Parameters
+ ----------
+ folder_path : str, optional
+ Path to the folder.
+ offset : int, optional
+ Offset for pagination.
+ limit : int, optional
+ Limit for pagination.
+ sort_by : str, optional
+ Field to sort by.
+ sort_direction : str, optional
+ Sort direction ('asc' or 'desc').
+ pattern : str, optional
+ Pattern to filter files.
+ filetype : str, optional
+ File type filter.
+ goto_path : str, optional
+ Path to go to.
+ additional : str or list of str, optional
+ Additional attributes to include.
+
+ Returns
+ -------
+ dict[str, object]
+ List of files or error message.
+ """
api_name = 'SYNO.FileStation.List'
info = self.file_station_list[api_name]
api_path = info['path']
req_param = {'version': info['maxVersion'], 'method': 'list'}
+ if not isinstance(folder_path, str):
+ # break instead of return
+ raise ValueError('Enter a valid folder_path')
+
for key, val in locals().items():
if key not in ['self', 'api_name', 'info', 'api_path', 'req_param', 'additional']:
if val is not None:
req_param[str(key)] = val
- if folder_path is None:
- return 'Enter a valid folder_path'
-
if filetype is not None:
req_param['filetype'] = str(req_param['filetype']).lower()
if additional is None:
additional = ['real_path', 'size', 'owner', 'time']
- if type(additional) is list:
- additional = ','.join(additional)
+ # if type(additional) is list:
+ # additional = ','.join(additional)
req_param['additional'] = additional
return self.request_data(api_name, api_path, req_param)
def get_file_info(self,
- path: Optional[str] = None,
- additional: Optional[str | list[str]] = None
+ path: str | list[str],
+ additional_param: Optional[str | list[str]] = None
) -> dict[str, object] | str:
+ """
+ Get information about a file or files.
+
+ Parameters
+ ----------
+ path : str or list of str
+ Path(s) to the file(s).
+ additional_param : str or list of str, optional
+ Additional attributes to retrieve.
+
+ Returns
+ -------
+ dict[str, object] or str
+ File information or error message.
+ """
api_name = 'SYNO.FileStation.List'
info = self.file_station_list[api_name]
api_path = info['path']
- req_param = {'version': info['maxVersion'], 'method': 'getinfo'}
-
- if type(path) is list:
- new_path = []
- [new_path.append('"' + x + '"') for x in path]
- path = new_path
- path = '[' + ','.join(path) + ']'
- req_param['path'] = path
- elif path is not None:
- req_param['path'] = path
-
- if additional is None:
- additional = ['real_path', 'size', 'owner', 'time']
-
- if type(additional) is list:
- additional = str(additional).replace("'", '"')
+ req_param = {'version': info['maxVersion'],
+ 'method': 'getinfo',
+ 'path': json.dumps(path)}
+
+ if additional_param is None:
+ additional_param = ["real_path", "size",
+ "owner", "time", "perm", "type"]
+ elif isinstance(additional_param, str):
+ additional_param = [additional_param]
+ elif isinstance(additional_param, list):
+ if not all(isinstance(a, str) for a in additional_param):
+ return "additional_param must be a string or a list of strings."
+ else:
+ return "additional_param must be a string or a list of strings."
- req_param['additional'] = additional
+ req_param['additional'] = json.dumps(additional_param)
return self.request_data(api_name, api_path, req_param)
@@ -177,7 +330,47 @@ def search_start(self,
owner: Optional[str] = None,
group: Optional[str] = None
) -> dict[str, object] | str:
-
+ """
+ Start a search task.
+
+ Parameters
+ ----------
+ folder_path : str, optional
+ Path to the folder where the search will start.
+ recursive : bool, optional
+ If True, the search will be recursive.
+ pattern : str, optional
+ Pattern to search for.
+ extension : str, optional
+ File extension to filter by.
+ filetype : str, optional
+ File type filter.
+ size_from : int, optional
+ Minimum file size.
+ size_to : int, optional
+ Maximum file size.
+ mtime_from : str or int, optional
+ Minimum modification time (Unix timestamp or formatted string).
+ mtime_to : str or int, optional
+ Maximum modification time (Unix timestamp or formatted string).
+ crtime_from : str or int, optional
+ Minimum creation time (Unix timestamp or formatted string).
+ crtime_to : str or int, optional
+ Maximum creation time (Unix timestamp or formatted string).
+ atime_from : str or int, optional
+ Minimum access time (Unix timestamp or formatted string).
+ atime_to : str or int, optional
+ Maximum access time (Unix timestamp or formatted string).
+ owner : str, optional
+ Owner filter.
+ group : str, optional
+ Group filter.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Search task ID or error message.
+ """
api_name = 'SYNO.FileStation.Search'
info = self.file_station_list[api_name]
api_path = info['path']
@@ -234,6 +427,31 @@ def get_search_list(self,
offset: Optional[int] = None,
additional: Optional[str | list[str]] = None
) -> dict[str, object] | str:
+ """
+ Get the results of a search task.
+
+ Parameters
+ ----------
+ task_id : str
+ Task ID of the search task.
+ filetype : str, optional
+ File type filter.
+ limit : int, optional
+ Limit for pagination.
+ sort_by : str, optional
+ Field to sort by.
+ sort_direction : str, optional
+ Sort direction ('asc' or 'desc').
+ offset : int, optional
+ Offset for pagination.
+ additional : str or list of str, optional
+ Additional attributes to include.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Search results or error message.
+ """
api_name = 'SYNO.FileStation.Search'
info = self.file_station_list[api_name]
api_path = info['path']
@@ -264,13 +482,26 @@ def get_search_list(self,
return self.request_data(api_name, api_path, req_param)
def stop_search_task(self, taskid: str) -> dict[str, object] | str:
+ """
+ Stop a search task.
+
+ Parameters
+ ----------
+ taskid : str
+ Task ID of the search task to stop.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Response from the API or error message.
+ """
api_name = 'SYNO.FileStation.Search'
info = self.file_station_list[api_name]
api_path = info['path']
req_param = {'version': info['maxVersion'],
'method': 'stop', 'taskid': self._search_taskid}
- if taskid is None:
+ if taskid is None: # NOTE this is unreachable
return 'Enter a valid taskid, choose between ' + str(self._search_taskid_list)
self._search_taskid_list.remove(taskid)
@@ -278,13 +509,21 @@ def stop_search_task(self, taskid: str) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def stop_all_search_task(self) -> str:
+ """
+ Stop all running search tasks.
+
+ Returns
+ -------
+ str
+ Confirmation message.
+ """
api_name = 'SYNO.FileStation.Search'
info = self.file_station_list[api_name]
api_path = info['path']
req_param = {'version': info['maxVersion'],
'method': 'stop', 'taskid': ''}
- assert len(self._search_taskid_list), 'Task list is empty' + \
+ assert len(self._search_taskid_list), 'Task list is empty' +\
str(self._search_taskid_list)
for task_id in self._search_taskid_list:
@@ -303,7 +542,29 @@ def get_mount_point_list(self,
sort_direction: Optional[str] = None,
additional: Optional[str | list[str]] = None
) -> dict[str, object] | str:
-
+ """
+ List mount points.
+
+ Parameters
+ ----------
+ mount_type : str, optional
+ Type of mount point to filter by.
+ offset : int, optional
+ Offset for pagination.
+ limit : int, optional
+ Limit for pagination.
+ sort_by : str, optional
+ Field to sort by.
+ sort_direction : str, optional
+ Sort direction ('asc' or 'desc').
+ additional : str or list of str, optional
+ Additional attributes to include.
+
+ Returns
+ -------
+ dict[str, object] or str
+ List of mount points or error message.
+ """
api_name = 'SYNO.FileStation.VirtualFolder'
info = self.file_station_list[api_name]
api_path = info['path']
@@ -334,7 +595,27 @@ def get_favorite_list(self,
status_filter: Optional[str] = None,
additional: Optional[str | list[str]] = None
) -> dict[str, object] | str:
-
+ """
+ List favorite files and folders.
+
+ Parameters
+ ----------
+ offset : int, optional
+ Offset for pagination.
+ limit : int, optional
+ Limit for pagination.
+ sort_by : str, optional
+ Field to sort by.
+ status_filter : str, optional
+ Status filter.
+ additional : str or list of str, optional
+ Additional attributes to include.
+
+ Returns
+ -------
+ dict[str, object] or str
+ List of favorites or error message.
+ """
api_name = 'SYNO.FileStation.Favorite'
info = self.file_station_list[api_name]
api_path = info['path']
@@ -360,6 +641,23 @@ def add_a_favorite(self,
name: Optional[str] = None,
index: Optional[int] = None
) -> dict[str, object] | str:
+ """
+ Add a file or folder to favorites.
+
+ Parameters
+ ----------
+ path : str
+ Path to the file or folder.
+ name : str, optional
+ Name for the favorite.
+ index : int, optional
+ Index for the favorite.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Response from the API or error message.
+ """
api_name = 'SYNO.FileStation.Favorite'
info = self.file_station_list[api_name]
api_path = info['path']
@@ -376,6 +674,19 @@ def add_a_favorite(self,
return self.request_data(api_name, api_path, req_param)
def delete_a_favorite(self, path: Optional[str] = None) -> dict[str, object] | str:
+ """
+ Delete a favorite.
+
+ Parameters
+ ----------
+ path : str, optional
+ Path to the favorite to delete.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Response from the API or error message.
+ """
api_name = 'SYNO.FileStation.Favorite'
info = self.file_station_list[api_name]
api_path = info['path']
@@ -389,6 +700,14 @@ def delete_a_favorite(self, path: Optional[str] = None) -> dict[str, object] | s
return self.request_data(api_name, api_path, req_param)
def clear_broken_favorite(self) -> dict[str, object] | str:
+ """
+ Clear broken favorites.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Response from the API or error message.
+ """
api_name = 'SYNO.FileStation.Favorite'
info = self.file_station_list[api_name]
api_path = info['path']
@@ -397,6 +716,21 @@ def clear_broken_favorite(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def edit_favorite_name(self, path: str, new_name: str) -> dict[str, object] | str:
+ """
+ Edit the name of a favorite.
+
+ Parameters
+ ----------
+ path : str
+ Path to the favorite.
+ new_name : str
+ New name for the favorite.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Response from the API or error message.
+ """
api_name = 'SYNO.FileStation.Favorite'
info = self.file_station_list[api_name]
api_path = info['path']
@@ -415,6 +749,21 @@ def edit_favorite_name(self, path: str, new_name: str) -> dict[str, object] | st
return self.request_data(api_name, api_path, req_param)
def replace_all_favorite(self, path: str | list[str], name: str | list[str]):
+ """
+ Replace all favorites with new paths and names.
+
+ Parameters
+ ----------
+ path : str or list of str
+ New path or list of new paths for the favorites.
+ name : str or list of str
+ New name or list of new names for the favorites.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Response from the API or error message.
+ """
api_name = 'SYNO.FileStation.Favorite'
info = self.file_station_list[api_name]
api_path = info['path']
@@ -439,6 +788,19 @@ def replace_all_favorite(self, path: str | list[str], name: str | list[str]):
return self.request_data(api_name, api_path, req_param)
def start_dir_size_calc(self, path: str) -> dict[str, object] | str:
+ """
+ Start a directory size calculation task.
+
+ Parameters
+ ----------
+ path : str
+ Path to the directory.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Task ID or error message.
+ """
api_name = 'SYNO.FileStation.DirSize'
info = self.file_station_list[api_name]
api_path = info['path']
@@ -473,6 +835,19 @@ def start_dir_size_calc(self, path: str) -> dict[str, object] | str:
return output
def stop_dir_size_calc(self, taskid: str) -> str:
+ """
+ Stop a directory size calculation task.
+
+ Parameters
+ ----------
+ taskid : str
+ Task ID of the size calculation task to stop.
+
+ Returns
+ -------
+ str
+ Confirmation message.
+ """
api_name = 'SYNO.FileStation.DirSize'
info = self.file_station_list[api_name]
api_path = info['path']
@@ -490,6 +865,19 @@ def stop_dir_size_calc(self, taskid: str) -> str:
return 'The task has been stopped'
def get_dir_status(self, taskid: Optional[str] = None) -> dict[str, object] | str:
+ """
+ Get the status of a directory size calculation task.
+
+ Parameters
+ ----------
+ taskid : str, optional
+ Task ID of the size calculation task.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Task status or error message.
+ """
api_name = 'SYNO.FileStation.DirSize'
info = self.file_station_list[api_name]
api_path = info['path']
@@ -502,6 +890,19 @@ def get_dir_status(self, taskid: Optional[str] = None) -> dict[str, object] | st
return self.request_data(api_name, api_path, req_param)
def start_md5_calc(self, file_path: str) -> str | dict[str, object]:
+ """
+ Start an MD5 calculation task.
+
+ Parameters
+ ----------
+ file_path : str
+ Path to the file.
+
+ Returns
+ -------
+ str or dict[str, object]
+ Task ID or error message.
+ """
api_name = 'SYNO.FileStation.MD5'
info = self.file_station_list[api_name]
api_path = info['path']
@@ -526,6 +927,19 @@ def start_md5_calc(self, file_path: str) -> str | dict[str, object]:
return output
def get_md5_status(self, taskid: Optional[str] = None) -> str | dict[str, object]:
+ """
+ Get the status of an MD5 calculation task.
+
+ Parameters
+ ----------
+ taskid : str, optional
+ Task ID of the MD5 calculation task.
+
+ Returns
+ -------
+ str or dict[str, object]
+ Task status or error message.
+ """
api_name = 'SYNO.FileStation.MD5'
info = self.file_station_list[api_name]
api_path = info['path']
@@ -542,6 +956,19 @@ def get_md5_status(self, taskid: Optional[str] = None) -> str | dict[str, object
return self.request_data(api_name, api_path, req_param)
def stop_md5_calc(self, taskid: str) -> str:
+ """
+ Stop an MD5 calculation task.
+
+ Parameters
+ ----------
+ taskid : str
+ Task ID of the MD5 calculation task to stop.
+
+ Returns
+ -------
+ str
+ Confirmation message.
+ """
api_name = 'SYNO.FileStation.DirSize'
info = self.file_station_list[api_name]
api_path = info['path']
@@ -564,6 +991,25 @@ def check_permissions(self,
overwrite: Optional[bool] = None,
create_only: Optional[bool] = None
) -> dict[str, object] | str:
+ """
+ Check permissions for a file or folder.
+
+ Parameters
+ ----------
+ path : str
+ Path to the file or folder.
+ filename : str
+ Name of the file.
+ overwrite : bool, optional
+ If True, overwriting is allowed.
+ create_only : bool, optional
+ If True, only creation is allowed.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Permission check result or error message.
+ """
api_name = 'SYNO.FileStation.CheckPermission'
info = self.file_station_list[api_name]
api_path = info['path']
@@ -590,53 +1036,58 @@ def upload_file(self,
verify: bool = False,
progress_bar: bool = True
) -> str | tuple[int, dict[str, object]]:
+ """
+ Upload a file to the server.
+
+ Parameters
+ ----------
+ dest_path : str
+ Destination path on the server.
+ file_path : str
+ Path to the file to upload.
+ create_parents : bool, optional
+ If True, parent folders will be created.
+ overwrite : bool, optional
+ If True, existing files will be overwritten.
+ verify : bool, optional
+ If True, SSL certificates will be verified.
+ progress_bar : bool, optional
+ If True, shows a progress bar during upload.
+
+ Returns
+ -------
+ str or tuple[int, dict[str, object]]
+ Upload result or error message.
+ """
api_name = 'SYNO.FileStation.Upload'
info = self.file_station_list[api_name]
api_path = info['path']
- filename = os.path.basename(file_path)
session = requests.session()
- with open(file_path, 'rb') as payload:
- url = ('%s%s' % (self.base_url, api_path)) + '?api=%s&version=%s&method=upload&_sid=%s' % (
- api_name, info['minVersion'], self._sid)
-
- encoder = MultipartEncoder({
- 'path': dest_path,
- 'create_parents': str(create_parents).lower(),
- 'overwrite': str(overwrite).lower(),
- 'files': (filename, payload, 'application/octet-stream')
- })
-
- if progress_bar:
- bar = tqdm.tqdm(desc='Upload Progress',
- total=encoder.len,
- dynamic_ncols=True,
- unit='B',
- unit_scale=True,
- unit_divisor=1024
- )
-
- monitor = MultipartEncoderMonitor(
- encoder, lambda monitor: bar.update(monitor.bytes_read - bar.n))
-
- r = session.post(
- url,
- data=monitor,
- verify=verify,
- headers={"X-SYNO-TOKEN": self.session._syno_token,
- 'Content-Type': monitor.content_type}
- )
-
- else:
- r = session.post(
- url,
- data=encoder,
- verify=verify,
- headers={"X-SYNO-TOKEN": self.session._syno_token,
- 'Content-Type': encoder.content_type}
- )
-
+ base = urljoin(self.base_url, api_path)
+ url_params = {
+ "api": api_name,
+ "version": info["minVersion"],
+ "method": "upload",
+ "_sid": self._sid
+ }
+
+ url = f"{base}?{urlencode(url_params)}"
+ encoder_params = {
+ 'path': dest_path,
+ 'create_parents': str(create_parents).lower(),
+ 'overwrite': str(overwrite).lower(),
+ }
+ data = get_data_for_request_from_file(
+ file_path=file_path, fields=encoder_params, called_from='FileStation', progress_bar=True)
+ r = session.post(
+ url,
+ data=data,
+ verify=verify,
+ headers={"X-SYNO-TOKEN": self.session._syno_token,
+ 'Content-Type': data.content_type}
+ )
session.close()
if r.status_code != 200 or not r.json()['success']:
return r.status_code, r.json()
@@ -644,6 +1095,19 @@ def upload_file(self,
return r.json()
def get_shared_link_info(self, link_id: str) -> dict[str, object] | str:
+ """
+ Get information about a shared link.
+
+ Parameters
+ ----------
+ link_id : str
+ ID of the shared link.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Shared link information or error message.
+ """
api_name = 'SYNO.FileStation.Sharing'
info = self.file_station_list[api_name]
api_path = info['path']
@@ -663,7 +1127,27 @@ def get_shared_link_list(self,
sort_direction: Optional[str] = None,
force_clean: Optional[bool] = None
) -> dict[str, object] | str:
-
+ """
+ List shared links.
+
+ Parameters
+ ----------
+ offset : int, optional
+ Offset for pagination.
+ limit : int, optional
+ Limit for pagination.
+ sort_by : str, optional
+ Field to sort by.
+ sort_direction : str, optional
+ Sort direction ('asc' or 'desc').
+ force_clean : bool, optional
+ If True, forces a clean of the shared link list.
+
+ Returns
+ -------
+ dict[str, object] or str
+ List of shared links or error message.
+ """
api_name = 'SYNO.FileStation.Sharing'
info = self.file_station_list[api_name]
api_path = info['path']
@@ -683,6 +1167,27 @@ def create_sharing_link(self,
date_available: Optional[str | int] = None,
expire_times: int = 0
) -> dict[str, object] | str:
+ """
+ Create a shared link.
+
+ Parameters
+ ----------
+ path : str
+ Path to the file or folder to share.
+ password : str, optional
+ Password for the shared link.
+ date_expired : str or int, optional
+ Expiration date for the shared link (Unix timestamp or formatted string).
+ date_available : str or int, optional
+ Availability date for the shared link (Unix timestamp or formatted string).
+ expire_times : int, optional
+ Number of times the link can be accessed before expiring.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Shared link details or error message.
+ """
api_name = 'SYNO.FileStation.Sharing'
info = self.file_station_list[api_name]
api_path = info['path']
@@ -706,6 +1211,19 @@ def create_sharing_link(self,
return self.request_data(api_name, api_path, req_param)
def delete_shared_link(self, link_id: str) -> dict[str, object] | str:
+ """
+ Delete a shared link.
+
+ Parameters
+ ----------
+ link_id : str
+ ID of the shared link to delete.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Response from the API or error message.
+ """
api_name = 'SYNO.FileStation.Sharing'
info = self.file_station_list[api_name]
api_path = info['path']
@@ -719,6 +1237,14 @@ def delete_shared_link(self, link_id: str) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def clear_invalid_shared_link(self) -> dict[str, object] | str:
+ """
+ Clear invalid shared links.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Response from the API or error message.
+ """
api_name = 'SYNO.FileStation.Sharing'
info = self.file_station_list[api_name]
api_path = info['path']
@@ -733,6 +1259,27 @@ def edit_shared_link(self,
date_available: Optional[str | int] = None,
expire_times: int = 0
) -> dict[str, object] | str:
+ """
+ Edit a shared link.
+
+ Parameters
+ ----------
+ link_id : str
+ ID of the shared link to edit.
+ password : str, optional
+ New password for the shared link.
+ date_expired : str or int, optional
+ New expiration date for the shared link (Unix timestamp or formatted string).
+ date_available : str or int, optional
+ New availability date for the shared link (Unix timestamp or formatted string).
+ expire_times : int, optional
+ New number of times the link can be accessed before expiring.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Response from the API or error message.
+ """
api_name = 'SYNO.FileStation.Sharing'
info = self.file_station_list[api_name]
api_path = info['path']
@@ -763,6 +1310,25 @@ def create_folder(self,
force_parent: Optional[bool] = None,
additional: Optional[str | list[str]] = None
) -> str | dict[str, object]:
+ """
+ Create a new folder.
+
+ Parameters
+ ----------
+ folder_path : str or list of str
+ Path or list of paths where the folder should be created.
+ name : str or list of str
+ Name or list of names for the new folder.
+ force_parent : bool, optional
+ If True, parent folders will be created if they don't exist.
+ additional : str or list of str, optional
+ Additional attributes to include.
+
+ Returns
+ -------
+ str or dict[str, object]
+ Creation result or error message.
+ """
api_name = 'SYNO.FileStation.CreateFolder'
info = self.file_station_list[api_name]
api_path = info['path']
@@ -811,32 +1377,50 @@ def rename_folder(self,
additional: Optional[str | list[str]] = None,
search_taskid: Optional[str] = None
) -> dict[str, object] | str:
+ """
+ Rename a file or a folder.
+
+ Parameters
+ ----------
+ path : str or list of str
+ Current path or list of paths of the files or folder(s) to rename.
+ name : str or list of str
+ New name or list of new names for the file or folder(s).
+ additional : str or list of str, optional
+ Additional attributes to include.
+ search_taskid : str, optional
+ Task ID of a search task.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Response from the API or error message.
+
+ Examples
+ --------
+ >>> rename_folder('/Downloads/script.log', 'script1.log')
+ >>> rename_folder(['/Downloads/script.log','/Downloads/script.log'],['a.log', 'b.log'])
+ >>> rename_folder('/Downloads/script', 'code')
+ """
api_name = 'SYNO.FileStation.Rename'
info = self.file_station_list[api_name]
api_path = info['path']
req_param = {'version': info['maxVersion'], 'method': 'rename'}
- if type(path) is list:
- new_path = []
- [new_path.append('"' + x + '"') for x in path]
- path = new_path
- path = '[' + ','.join(path) + ']'
- req_param['path'] = path
- elif path is not None:
- req_param['path'] = path
+ if isinstance(path, list) and isinstance(name, list):
+ if len(path) != len(name):
+ raise ValueError("Path and name must have the same length.")
+ elif isinstance(path, str) and isinstance(name, str):
+ pass # ok, both are strings
else:
- return 'Enter a valid folder path (folder path only ex. "/home/Drive/Downloads")'
+ raise TypeError(
+ "Path and name must be both lists or both strings.")
- if type(name) is list:
- new_path = []
- [new_path.append('"' + x + '"') for x in name]
- name = new_path
- name = '[' + ','.join(name) + ']'
- req_param['name'] = name
- elif name is not None:
- req_param['name'] = name
- else:
- return 'Enter a valid new folder name (new folder name only ex. "New Folder")'
+ if validate_path(path) == False:
+ return 'Enter a valid folder path or file path (ex. /Downloads/script.log)'
+
+ req_param['path'] = json.dumps(path)
+ req_param['name'] = json.dumps(name)
if additional is None:
additional = ['real_path', 'size', 'owner', 'time']
@@ -849,7 +1433,7 @@ def rename_folder(self,
if search_taskid is not None:
req_param['search_taskid'] = search_taskid
- return self.request_data(api_name, api_path, req_param)
+ return self.request_data(api_name, api_path, req_param, method='post')
def start_copy_move(self,
path: str | list[str],
@@ -859,6 +1443,41 @@ def start_copy_move(self,
accurate_progress: Optional[bool] = None,
search_taskid: Optional[str] = None
) -> str | dict[str, object]:
+ """
+ Start a copy or move task.
+
+ Parameters
+ ----------
+ path : str or list of str
+ Source path or list of source paths to copy or move.
+ dest_folder_path : str or list of str
+ Destination folder path or list of destination folder paths.
+ overwrite : bool, optional
+ If True, existing files will be overwritten.
+ remove_src : bool, optional
+ If True, source files will be removed after copying.
+ accurate_progress : bool, optional
+ If True, shows accurate progress.
+ search_taskid : str, optional
+ Task ID of a search task.
+
+ Returns
+ -------
+ str or dict[str, object]
+ Task ID or error message.
+
+ Examples
+ --------
+ Start a simple move task:
+ You have to specify only the file on the path and not the dest folder.
+
+ >>> fs = FileStation(**params)
+ >>> task_id = fs.start_copy_task(
+ ... path="/Media/Film/Action/movie1.mkv",
+ ... dest_folder_path="/Media/Film/Drama",
+ ... overwrite=True
+ ... )
+ """
api_name = 'SYNO.FileStation.CopyMove'
info = self.file_station_list[api_name]
api_path = info['path']
@@ -907,6 +1526,19 @@ def start_copy_move(self,
return output
def get_copy_move_status(self, taskid: str) -> dict[str, object] | str:
+ """
+ Get the status of a copy or move task.
+
+ Parameters
+ ----------
+ taskid : str
+ Task ID of the copy or move task.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Task status or error message.
+ """
api_name = 'SYNO.FileStation.CopyMove'
info = self.file_station_list[api_name]
api_path = info['path']
@@ -920,6 +1552,19 @@ def get_copy_move_status(self, taskid: str) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def stop_copy_move_task(self, taskid: str) -> dict[str, object] | str:
+ """
+ Stop a copy or move task.
+
+ Parameters
+ ----------
+ taskid : str
+ Task ID of the copy or move task to stop.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Response from the API or error message.
+ """
api_name = 'SYNO.FileStation.CopyMove'
info = self.file_station_list[api_name]
api_path = info['path']
@@ -940,6 +1585,25 @@ def start_delete_task(self,
recursive: Optional[bool] = None,
search_taskid: Optional[str] = None
) -> dict[str, object] | str:
+ """
+ Start a delete task.
+
+ Parameters
+ ----------
+ path : str or list of str
+ Path or list of paths to the file or folder to delete.
+ accurate_progress : bool, optional
+ If True, shows accurate progress.
+ recursive : bool, optional
+ If True, deletes folders recursively.
+ search_taskid : str, optional
+ Task ID of a search task.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Task ID or error message.
+ """
api_name = 'SYNO.FileStation.Delete'
info = self.file_station_list[api_name]
api_path = info['path']
@@ -976,6 +1640,19 @@ def start_delete_task(self,
return output
def get_delete_status(self, taskid: str) -> dict[str, object] | str:
+ """
+ Get the status of a delete task.
+
+ Parameters
+ ----------
+ taskid : str
+ Task ID of the delete task.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Task status or error message.
+ """
api_name = 'SYNO.FileStation.Delete'
info = self.file_station_list[api_name]
api_path = info['path']
@@ -989,6 +1666,19 @@ def get_delete_status(self, taskid: str) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def stop_delete_task(self, taskid: str) -> dict[str, object] | str:
+ """
+ Stop a delete task.
+
+ Parameters
+ ----------
+ taskid : str
+ Task ID of the delete task to stop.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Response from the API or error message.
+ """
api_name = 'SYNO.FileStation.Delete'
info = self.file_station_list[api_name]
api_path = info['path']
@@ -1007,6 +1697,25 @@ def delete_blocking_function(self,
path: str,
recursive: Optional[bool] = None,
search_taskid: Optional[str] = None) -> dict[str, object] | str:
+ """
+ Delete a file or folder (blocking function).
+
+ This function will stop your script until done! Do not interrupt.
+
+ Parameters
+ ----------
+ path : str or list of str
+ Path or list of paths to the file or folder to delete.
+ recursive : bool, optional
+ If True, deletes folders recursively.
+ search_taskid : str, optional
+ Task ID of a search task.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Response from the API or error message.
+ """
api_name = 'SYNO.FileStation.Delete'
info = self.file_station_list[api_name]
api_path = info['path']
@@ -1042,6 +1751,33 @@ def start_extract_task(self,
password: Optional[str] = None,
item_id: Optional[str] = None
) -> dict[str, object] | str:
+ """
+ Start an extract task.
+
+ Parameters
+ ----------
+ file_path : str
+ Path to the archive file.
+ dest_folder_path : str
+ Destination folder path where the files will be extracted.
+ overwrite : bool, optional
+ If True, existing files will be overwritten.
+ keep_dir : bool, optional
+ If True, the original directory structure will be kept.
+ create_subfolder : bool, optional
+ If True, a subfolder will be created for the extracted files.
+ codepage : str, optional
+ Codepage for the extraction.
+ password : str, optional
+ Password for the archive, if required.
+ item_id : str, optional
+ Item ID for the extraction task.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Task ID or error message.
+ """
api_name = 'SYNO.FileStation.Extract'
info = self.file_station_list[api_name]
api_path = info['path']
@@ -1074,6 +1810,19 @@ def start_extract_task(self,
return output
def get_extract_status(self, taskid: str) -> dict[str, object] | str:
+ """
+ Get the status of an extract task.
+
+ Parameters
+ ----------
+ taskid : str
+ Task ID of the extract task.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Task status or error message.
+ """
api_name = 'SYNO.FileStation.Extract'
info = self.file_station_list[api_name]
api_path = info['path']
@@ -1087,6 +1836,19 @@ def get_extract_status(self, taskid: str) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def stop_extract_task(self, taskid: str) -> dict[str, object] | str:
+ """
+ Stop an extract task.
+
+ Parameters
+ ----------
+ taskid : str
+ Task ID of the extract task to stop.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Response from the API or error message.
+ """
api_name = 'SYNO.FileStation.Extract'
info = self.file_station_list[api_name]
api_path = info['path']
@@ -1111,6 +1873,33 @@ def get_file_list_of_archive(self,
password: Optional[str] = None,
item_id: Optional[str] = None
) -> dict[str, object] | str:
+ """
+ Get the list of files in an archive.
+
+ Parameters
+ ----------
+ file_path : str
+ Path to the archive file.
+ offset : int, optional
+ Offset for pagination.
+ limit : int, optional
+ Limit for pagination.
+ sort_by : str, optional
+ Field to sort by.
+ sort_direction : str, optional
+ Sort direction ('asc' or 'desc').
+ codepage : str, optional
+ Codepage for the file list.
+ password : str, optional
+ Password for the archive, if required.
+ item_id : str, optional
+ Item ID for the archive.
+
+ Returns
+ -------
+ dict[str, object] or str
+ List of files in the archive or error message.
+ """
api_name = 'SYNO.FileStation.Extract'
info = self.file_station_list[api_name]
api_path = info['path']
@@ -1134,6 +1923,29 @@ def start_file_compression(self,
compress_format: Optional[str] = None,
password: Optional[str] = None
) -> dict[str, object] | str | tuple[str]:
+ """
+ Start a file compression task.
+
+ Parameters
+ ----------
+ path : str or list of str
+ Path or list of paths to the file or folder to compress.
+ dest_file_path : str
+ Destination file path for the compressed file.
+ level : int, optional
+ Compression level.
+ mode : str, optional
+ Compression mode.
+ compress_format : str, optional
+ Compression format.
+ password : str, optional
+ Password for the compressed file, if required.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Task ID or error message.
+ """
api_name = 'SYNO.FileStation.Compress'
info = self.file_station_list[api_name]
api_path = info['path']
@@ -1179,6 +1991,19 @@ def start_file_compression(self,
return output
def get_compress_status(self, taskid: str) -> dict[str, object] | str:
+ """
+ Get the status of a file compression task.
+
+ Parameters
+ ----------
+ taskid : str
+ Task ID of the compression task.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Task status or error message.
+ """
api_name = 'SYNO.FileStation.Compress'
info = self.file_station_list[api_name]
api_path = info['path']
@@ -1192,6 +2017,19 @@ def get_compress_status(self, taskid: str) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def stop_compress_task(self, taskid: str) -> dict[str, object] | str:
+ """
+ Stop a file compression task.
+
+ Parameters
+ ----------
+ taskid : str
+ Task ID of the compression task to stop.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Response from the API or error message.
+ """
api_name = 'SYNO.FileStation.Compress'
info = self.file_station_list[api_name]
api_path = info['path']
@@ -1209,8 +2047,29 @@ def get_list_of_all_background_task(self,
limit: Optional[int] = None,
sort_by: Optional[str] = None,
sort_direction: Optional[str] = None,
- api_filter: Optional[str] = None
+ api_filter: Optional[str, list] = None
) -> dict[str, object] | str:
+ """
+ Get a list of all background tasks.
+
+ Parameters
+ ----------
+ offset : int, optional
+ Offset for pagination.
+ limit : int, optional
+ Limit for pagination.
+ sort_by : str, optional
+ Field to sort by.
+ sort_direction : str, optional
+ Sort direction ('asc' or 'desc').
+ api_filter : str, optional
+ API filter.
+
+ Returns
+ -------
+ dict[str, object] or str
+ List of background tasks or error message.
+ """
api_name = 'SYNO.FileStation.BackgroundTask'
info = self.file_station_list[api_name]
api_path = info['path']
@@ -1221,7 +2080,7 @@ def get_list_of_all_background_task(self,
if val is not None:
req_param[str(key)] = val
- if type(api_filter) is list:
+ if isinstance(api_filter, list):
new_path = []
[new_path.append('"' + x + '"') for x in api_filter]
api_filter = new_path
@@ -1237,7 +2096,27 @@ def get_file(self,
chunk_size: int = 8192,
verify: bool = False
) -> Optional[str]:
-
+ """
+ Download a file from the server.
+
+ Parameters
+ ----------
+ path : str
+ The file path starting with a shared folder to be downloaded.
+ mode : str
+ Mode for downloading the file ('open' to open in browser, 'download' to download to disk).
+ dest_path : str, optional
+ Destination path on the local machine (for 'download' mode).
+ chunk_size : int, optional
+ Chunk size for downloading.
+ verify : bool, optional
+ If True, SSL certificates will be verified.
+
+ Returns
+ -------
+ Optional[str]
+ None if successful, error message otherwise.
+ """
api_name = 'SYNO.FileStation.Download'
info = self.file_station_list[api_name]
api_path = info['path']
@@ -1275,35 +2154,64 @@ def get_file(self,
r.raise_for_status()
return io.BytesIO(r.content)
- def generate_file_tree(self, folder_path: str, tree: Tree) -> None:
- """Generate the file tree based on the folder path you give, you need to create the root node before call this function
-
- Parameters
- ----------
- folder_path : str
- Folder path to generate file tree
- tree : Tree
- Instance of the Tree of lib \"Treelib\"
-
+ def generate_file_tree(self,
+ folder_path: str,
+ tree: Tree,
+ max_depth: Optional[int] = 1,
+ start_depth: Optional[int] = 0) -> None:
+ """
+ Recursively generate the file tree based on the folder path you give constrained with.
+
+ You need to create the root node before calling this function.
+
+ Parameters
+ ----------
+ folder_path : str
+ Folder path to generate file tree.
+ tree : Tree
+ Instance of the Tree from the `treelib` library.
+ max_depth : int, optional
+ Non-negative number of maximum depth of tree generation if node tree is directory, default to '1' to generate full tree. If 'max_depth=0' it will be equivalent to no recursion.
+ start_depth : int, optional
+ Non negative number to start to control tree generation default to '0'.
"""
-
api_name = 'hotfix' # fix for docs_parser.py issue
- data: dict = self.get_file_list(
+ if start_depth < 0:
+ start_depth = 0
+ warnings.warn(
+ f"'start_depth={start_depth}'. It should not be less or than 0, setting 'start_depth' to 0!",
+ RuntimeWarning,
+ stacklevel=2
+ )
+
+ assert start_depth <= max_depth, ValueError(
+ f"'start_depth' should not be greater than 'max_depth'. Got '{start_depth=}, {max_depth=}'")
+ assert isinstance(tree, Tree), ValueError(
+ "'tree' has to be a type of 'Tree'")
+
+ data: dict[str, object] = self.get_file_list(
folder_path=folder_path
).get("data")
files = data.get("files")
- file: dict
- for file in files:
- file_name: str = file.get("name")
- file_path: str = file.get("path")
- if file.get("isdir"):
-
- tree.create_node(file_name, file_path, parent=folder_path)
- self.generate_file_tree(file_path, tree)
+ _file_info_getter = map(lambda x: (
+ x.get('isdir'), x.get('name'), x.get('path')), files)
+ for isdir, file_name, file_path in _file_info_getter:
+
+ if isdir and (start_depth >= max_depth):
+ tree.create_node(file_name, file_path, parent=folder_path, data={
+ "isdir": isdir, "max_depth": True})
+
+ elif isdir:
+ tree.create_node(file_name, file_path, parent=folder_path, data={
+ "isdir": isdir, "max_depth": False})
+ self.generate_file_tree(
+ file_path, tree, max_depth, start_depth + 1)
+
else:
- tree.create_node(file_name, file_path, parent=folder_path)
+ tree.create_node(file_name, file_path, parent=folder_path, data={
+ "isdir": isdir, "max_depth": False})
# TODO SYNO.FileStation.Thumb to be done
diff --git a/synology_api/log_center.py b/synology_api/log_center.py
index f9335ce1..20c80e0c 100644
--- a/synology_api/log_center.py
+++ b/synology_api/log_center.py
@@ -1,11 +1,31 @@
+"""
+Log Center API wrapper for Synology DSM.
+
+This module provides a class to interact with the Synology Log Center API.
+"""
+
from __future__ import annotations
from typing import Optional
from . import base_api
class LogCenter(base_api.BaseApi):
+ """
+ Interface for Synology Log Center API.
+
+ Provides methods to interact with log center features such as retrieving logs,
+ client status, remote archives, and storage settings.
+ """
def logcenter(self) -> dict[str, object] | str:
+ """
+ Retrieve the list of log center receive rules.
+
+ Returns
+ -------
+ dict[str, object] or str
+ The API response containing the receive rules or an error message.
+ """
api_name = 'SYNO.LogCenter.RecvRule'
info = self.gen_list[api_name]
api_path = info['path']
@@ -14,6 +34,14 @@ def logcenter(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def client_status_cnt(self) -> dict[str, object] | str:
+ """
+ Retrieve the count status from the syslog client.
+
+ Returns
+ -------
+ dict[str, object] or str
+ The API response containing the count status or an error message.
+ """
api_name = 'SYNO.Core.SyslogClient.Status'
info = self.gen_list[api_name]
api_path = info['path']
@@ -22,6 +50,14 @@ def client_status_cnt(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def client_status_eps(self) -> dict[str, object] | str:
+ """
+ Retrieve the EPS (events per second) status from the syslog client.
+
+ Returns
+ -------
+ dict[str, object] or str
+ The API response containing the EPS status or an error message.
+ """
api_name = 'SYNO.Core.SyslogClient.Status'
info = self.gen_list[api_name]
api_path = info['path']
@@ -30,6 +66,14 @@ def client_status_eps(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def remote_log_archives(self) -> dict[str, object] | str:
+ """
+ Retrieve the list of remote log archive subfolders.
+
+ Returns
+ -------
+ dict[str, object] or str
+ The API response containing remote archive subfolders or an error message.
+ """
api_name = 'SYNO.LogCenter.Log'
info = self.gen_list[api_name]
api_path = info['path']
@@ -39,6 +83,14 @@ def remote_log_archives(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def display_logs(self) -> dict[str, object] | str:
+ """
+ Retrieve the list of logs from the syslog client.
+
+ Returns
+ -------
+ dict[str, object] or str
+ The API response containing the logs or an error message.
+ """
api_name = 'SYNO.Core.SyslogClient.Log'
info = self.gen_list[api_name]
api_path = info['path']
@@ -47,6 +99,14 @@ def display_logs(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def setting_storage_list(self) -> dict[str, object] | str:
+ """
+ Retrieve the log center storage settings.
+
+ Returns
+ -------
+ dict[str, object] or str
+ The API response containing storage settings or an error message.
+ """
api_name = 'SYNO.LogCenter.Setting.Storage'
info = self.gen_list[api_name]
api_path = info['path']
@@ -55,6 +115,14 @@ def setting_storage_list(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def registry_send_list(self) -> dict[str, object] | str:
+ """
+ Retrieve the list of log center client registry send settings.
+
+ Returns
+ -------
+ dict[str, object] or str
+ The API response containing registry send settings or an error message.
+ """
api_name = 'SYNO.LogCenter.Client'
info = self.gen_list[api_name]
api_path = info['path']
@@ -63,6 +131,14 @@ def registry_send_list(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def history(self) -> dict[str, object] | str:
+ """
+ Retrieve the log center history.
+
+ Returns
+ -------
+ dict[str, object] or str
+ The API response containing the log center history or an error message.
+ """
api_name = 'SYNO.LogCenter.History'
info = self.gen_list[api_name]
api_path = info['path']
diff --git a/synology_api/notestation.py b/synology_api/notestation.py
index dbd91238..129d302d 100644
--- a/synology_api/notestation.py
+++ b/synology_api/notestation.py
@@ -1,11 +1,31 @@
+"""
+NoteStation API wrapper for Synology DSM.
+
+This module provides a class to interact with the Synology NoteStation API.
+"""
+
from __future__ import annotations
from typing import Optional
from . import base_api
class NoteStation(base_api.BaseApi):
+ """
+ Interface for Synology NoteStation API.
+
+ Provides methods to interact with NoteStation features such as retrieving settings,
+ notebooks, tags, shortcuts, todos, smart notes, and individual notes.
+ """
def settings_info(self) -> dict[str, object] | str:
+ """
+ Retrieve NoteStation settings information.
+
+ Returns
+ -------
+ dict[str, object] or str
+ The API response containing settings information or an error message.
+ """
api_name = 'SYNO.NoteStation.Setting'
info = self.gen_list[api_name]
api_path = info['path']
@@ -23,6 +43,14 @@ def settings_info(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)'''
def info(self) -> dict[str, object] | str:
+ """
+ Retrieve NoteStation general information.
+
+ Returns
+ -------
+ dict[str, object] or str
+ The API response containing general information or an error message.
+ """
api_name = 'SYNO.NoteStation.Info'
info = self.gen_list[api_name]
api_path = info['path']
@@ -31,6 +59,14 @@ def info(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def notebooks_info(self) -> dict[str, object] | str:
+ """
+ Retrieve the list of notebooks.
+
+ Returns
+ -------
+ dict[str, object] or str
+ The API response containing the list of notebooks or an error message.
+ """
api_name = 'SYNO.NoteStation.Notebook'
info = self.gen_list[api_name]
api_path = info['path']
@@ -39,6 +75,14 @@ def notebooks_info(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def tags_info(self) -> dict[str, object] | str:
+ """
+ Retrieve the list of tags.
+
+ Returns
+ -------
+ dict[str, object] or str
+ The API response containing the list of tags or an error message.
+ """
api_name = 'SYNO.NoteStation.Tag'
info = self.gen_list[api_name]
api_path = info['path']
@@ -47,6 +91,14 @@ def tags_info(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def shortcuts(self) -> dict[str, object] | str:
+ """
+ Retrieve the list of shortcuts.
+
+ Returns
+ -------
+ dict[str, object] or str
+ The API response containing the list of shortcuts or an error message.
+ """
api_name = 'SYNO.NoteStation.Shortcut'
info = self.gen_list[api_name]
api_path = info['path']
@@ -55,6 +107,14 @@ def shortcuts(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def todo(self) -> dict[str, object] | str:
+ """
+ Retrieve the list of todo items.
+
+ Returns
+ -------
+ dict[str, object] or str
+ The API response containing the list of todo items or an error message.
+ """
api_name = 'SYNO.NoteStation.Todo'
info = self.gen_list[api_name]
api_path = info['path']
@@ -64,6 +124,14 @@ def todo(self) -> dict[str, object] | str:
# TODO need to investigate for additional params
def smart(self) -> dict[str, object] | str:
+ """
+ Retrieve the list of smart notes.
+
+ Returns
+ -------
+ dict[str, object] or str
+ The API response containing the list of smart notes or an error message.
+ """
api_name = 'SYNO.NoteStation.Smart'
info = self.gen_list[api_name]
api_path = info['path']
@@ -72,6 +140,14 @@ def smart(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def note_list(self) -> dict[str, object] | str:
+ """
+ Retrieve the list of notes.
+
+ Returns
+ -------
+ dict[str, object] or str
+ The API response containing the list of notes or an error message.
+ """
api_name = 'SYNO.NoteStation.Note'
info = self.gen_list[api_name]
api_path = info['path']
@@ -80,6 +156,19 @@ def note_list(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def specific_note_id(self, note_id) -> dict[str, object] | str:
+ """
+ Retrieve a specific note by its ID.
+
+ Parameters
+ ----------
+ note_id : str or int
+ The ID of the note to retrieve.
+
+ Returns
+ -------
+ dict[str, object] or str
+ The API response containing the note data or an error message.
+ """
api_name = 'SYNO.NoteStation.Note'
info = self.gen_list[api_name]
api_path = info['path']
diff --git a/synology_api/oauth.py b/synology_api/oauth.py
index b87f4382..5d91bd3f 100644
--- a/synology_api/oauth.py
+++ b/synology_api/oauth.py
@@ -1,11 +1,37 @@
+"""
+OAuth API wrapper for Synology DSM.
+
+This module provides a class to interact with the Synology OAuth API.
+"""
+
from __future__ import annotations
from typing import Optional
from . import base_api
class OAuth(base_api.BaseApi):
+ """
+ Interface for Synology OAuth API.
+
+ Provides methods to interact with OAuth clients, tokens, and logs.
+ """
def clients(self, offset: int = 0, limit: int = 20) -> dict[str, object] | str:
+ """
+ Retrieve the list of OAuth clients.
+
+ Parameters
+ ----------
+ offset : int, optional
+ The starting index of the client list. Default is 0.
+ limit : int, optional
+ The maximum number of clients to retrieve. Default is 20.
+
+ Returns
+ -------
+ dict[str, object] or str
+ The API response containing the list of clients or an error message.
+ """
api_name = 'SYNO.OAUTH.Client'
info = self.gen_list[api_name]
api_path = info['path']
@@ -15,6 +41,21 @@ def clients(self, offset: int = 0, limit: int = 20) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def tokens(self, offset: int = 0, limit: int = 20) -> dict[str, object] | str:
+ """
+ Retrieve the list of OAuth tokens.
+
+ Parameters
+ ----------
+ offset : int, optional
+ The starting index of the token list. Default is 0.
+ limit : int, optional
+ The maximum number of tokens to retrieve. Default is 20.
+
+ Returns
+ -------
+ dict[str, object] or str
+ The API response containing the list of tokens or an error message.
+ """
api_name = 'SYNO.OAUTH.Token'
info = self.gen_list[api_name]
api_path = info['path']
@@ -24,6 +65,21 @@ def tokens(self, offset: int = 0, limit: int = 20) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def logs(self, offset: int = 0, limit: int = 20) -> dict[str, object] | str:
+ """
+ Retrieve the list of OAuth logs.
+
+ Parameters
+ ----------
+ offset : int, optional
+ The starting index of the log list. Default is 0.
+ limit : int, optional
+ The maximum number of logs to retrieve. Default is 20.
+
+ Returns
+ -------
+ dict[str, object] or str
+ The API response containing the list of logs or an error message.
+ """
api_name = 'SYNO.OAUTH.Log'
info = self.gen_list[api_name]
api_path = info['path']
diff --git a/synology_api/photos.py b/synology_api/photos.py
index 8e937c6e..8cd10c21 100755
--- a/synology_api/photos.py
+++ b/synology_api/photos.py
@@ -1,3 +1,9 @@
+"""
+Photos API wrapper for Synology DSM.
+
+This module provides a class to interact with the Synology Photos API.
+"""
+
from __future__ import annotations
from typing import Optional, Any
from . import base_api
@@ -5,6 +11,37 @@
class Photos(base_api.BaseApi):
+ """
+ Interface for Synology Photos API.
+
+ Provides methods to interact with Photos features such as retrieving user info,
+ folders, albums, sharing, and items.
+
+ Parameters
+ ----------
+ ip_address : str
+ The IP address or hostname of the Synology NAS.
+ port : str
+ The port number to connect to.
+ username : str
+ The username for authentication.
+ password : str
+ The password for authentication.
+ secure : bool, optional
+ Whether to use HTTPS. Default is False.
+ cert_verify : bool, optional
+ Whether to verify SSL certificates. Default is False.
+ dsm_version : int, optional
+ DSM version. Default is 7.
+ debug : bool, optional
+ Enable debug output. Default is True.
+ otp_code : str, optional
+ One-time password for 2FA, if required.
+ device_id : str, optional
+ Device ID for the session.
+ device_name : str, optional
+ Device name for the session.
+ """
def __init__(self,
ip_address: str,
@@ -19,6 +56,34 @@ def __init__(self,
device_id: Optional[str] = None,
device_name: Optional[str] = None
) -> None:
+ """
+ Initialize the Photos API interface.
+
+ Parameters
+ ----------
+ ip_address : str
+ The IP address or hostname of the Synology NAS.
+ port : str
+ The port number to connect to.
+ username : str
+ The username for authentication.
+ password : str
+ The password for authentication.
+ secure : bool, optional
+ Whether to use HTTPS. Default is False.
+ cert_verify : bool, optional
+ Whether to verify SSL certificates. Default is False.
+ dsm_version : int, optional
+ DSM version. Default is 7.
+ debug : bool, optional
+ Enable debug output. Default is True.
+ otp_code : str, optional
+ One-time password for 2FA, if required.
+ device_id : str, optional
+ Device ID for the session.
+ device_name : str, optional
+ Device name for the session.
+ """
super(Photos, self).__init__(ip_address, port, username, password, secure, cert_verify,
dsm_version, debug, otp_code, device_id, device_name, 'FotoStation')
@@ -32,6 +97,14 @@ def __init__(self,
self._userinfo: Any = None
def get_userinfo(self) -> Any:
+ """
+ Retrieve user information for the current session.
+
+ Returns
+ -------
+ Any
+ The user information data.
+ """
if self._userinfo is not None:
return self._userinfo
@@ -44,6 +117,19 @@ def get_userinfo(self) -> Any:
return self._userinfo
def get_folder(self, folder_id: int = 0) -> dict[str, object] | str:
+ """
+ Retrieve information about a specific folder.
+
+ Parameters
+ ----------
+ folder_id : int, optional
+ The ID of the folder. Default is 0.
+
+ Returns
+ -------
+ dict[str, object] or str
+ The folder information or an error message.
+ """
api_name = 'SYNO.Foto.Browse.Folder'
info = self.photos_list[api_name]
api_path = info['path']
@@ -58,6 +144,25 @@ def list_folders(self,
offset: int = 0,
additional: str | list[str] = None
) -> dict[str, object] | str:
+ """
+ List folders in Personal Space.
+
+ Parameters
+ ----------
+ folder_id : int, optional
+ The parent folder ID. Default is 0.
+ limit : int, optional
+ Maximum number of folders to return. Default is 1000.
+ offset : int, optional
+ Number of folders to skip. Default is 0.
+ additional : str or list of str, optional
+ Additional fields to include.
+
+ Returns
+ -------
+ dict[str, object] or str
+ The list of folders or an error message.
+ """
return self._list_folders(folder_id, limit, offset, additional, 'SYNO.Foto.Browse.Folder')
def list_teams_folders(self,
@@ -66,10 +171,50 @@ def list_teams_folders(self,
offset: int = 0,
additional: Optional[str | list[str]] = None
) -> dict[str, object] | str:
+ """
+ List folders in Team Space.
+
+ Parameters
+ ----------
+ folder_id : int, optional
+ The parent folder ID. Default is 0.
+ limit : int, optional
+ Maximum number of folders to return. Default is 2000.
+ offset : int, optional
+ Number of folders to skip. Default is 0.
+ additional : str or list of str, optional
+ Additional fields to include.
+
+ Returns
+ -------
+ dict[str, object] or str
+ The list of team folders or an error message.
+ """
return self._list_folders(folder_id, limit, offset, additional, 'SYNO.FotoTeam.Browse.Folder')
def _list_folders(self, folder_id: int, limit: int, offset: int, additional: Optional[str | list[str]],
api_name: str) -> Any:
+ """
+ Internal method to list folders.
+
+ Parameters
+ ----------
+ folder_id : int
+ The parent folder ID.
+ limit : int
+ Maximum number of folders to return.
+ offset : int
+ Number of folders to skip.
+ additional : str or list of str, optional
+ Additional fields to include.
+ api_name : str
+ API name to use.
+
+ Returns
+ -------
+ Any
+ The API response.
+ """
if additional is None:
additional = []
info = self.photos_list[api_name]
@@ -80,12 +225,53 @@ def _list_folders(self, folder_id: int, limit: int, offset: int, additional: Opt
return self.request_data(api_name, api_path, req_param)
def count_folders(self, folder_id: int = 0) -> dict[str, object] | str:
+ """
+ Count folders in Personal Space.
+
+ Parameters
+ ----------
+ folder_id : int, optional
+ The parent folder ID. Default is 0.
+
+ Returns
+ -------
+ dict[str, object] or str
+ The count of folders or an error message.
+ """
return self._count_folders(folder_id, 'SYNO.Foto.Browse.Folder')
def count_team_folders(self, folder_id: int = 0) -> dict[str, object] | str:
+ """
+ Count folders in Team Space.
+
+ Parameters
+ ----------
+ folder_id : int, optional
+ The parent folder ID. Default is 0.
+
+ Returns
+ -------
+ dict[str, object] or str
+ The count of team folders or an error message.
+ """
return self._count_folders(folder_id, 'SYNO.FotoTeam.Browse.Folder')
def _count_folders(self, folder_id: int, api_name: str) -> Any:
+ """
+ Internal method to count folders.
+
+ Parameters
+ ----------
+ folder_id : int
+ The parent folder ID.
+ api_name : str
+ API name to use.
+
+ Returns
+ -------
+ Any
+ The API response.
+ """
info = self.photos_list[api_name]
api_path = info['path']
req_param = {'version': info['maxVersion'],
@@ -94,12 +280,55 @@ def _count_folders(self, folder_id: int, api_name: str) -> Any:
return self.request_data(api_name, api_path, req_param)
def lookup_folder(self, path: str) -> dict[str, object] | str:
+ """
+ Lookup a folder by path in Personal Space.
+
+ Parameters
+ ----------
+ path : str
+ The folder path.
+
+ Returns
+ -------
+ dict[str, object] or str
+ The folder information or None if not found.
+ """
return self._lookup_folder(path, 'SYNO.FotoBrowse.Folder', 'SYNO.Foto.Browse.Folder')
def lookup_team_folder(self, path: str) -> dict[str, object] | str:
+ """
+ Lookup a folder by path in Team Space.
+
+ Parameters
+ ----------
+ path : str
+ The folder path.
+
+ Returns
+ -------
+ dict[str, object] or str
+ The folder information or None if not found.
+ """
return self._lookup_folder(path, 'SYNO.FotoTeam.Browse.Folder', 'SYNO.FotoTeam.Browse.Folder')
def _lookup_folder(self, path: str, api_name_count: str, api_name_list: str) -> Optional[dict[str, object]]:
+ """
+ Internal method to lookup a folder by path.
+
+ Parameters
+ ----------
+ path : str
+ The folder path.
+ api_name_count : str
+ API name for counting folders.
+ api_name_list : str
+ API name for listing folders.
+
+ Returns
+ -------
+ dict[str, object] or None
+ The folder information or None if not found.
+ """
parent = 0
found_path = ''
folder = ''
@@ -124,6 +353,21 @@ def _lookup_folder(self, path: str, api_name_count: str, api_name_list: str) ->
return folder
def get_album(self, album_id: str, additional: Optional[str | list[str]] = None) -> dict[str, object] | str:
+ """
+ Retrieve information about a specific album.
+
+ Parameters
+ ----------
+ album_id : str
+ The album ID.
+ additional : str or list of str, optional
+ Additional fields to include.
+
+ Returns
+ -------
+ dict[str, object] or str
+ The album information or an error message.
+ """
if not isinstance(album_id, list):
album_id = [album_id]
if additional is None:
@@ -137,6 +381,21 @@ def get_album(self, album_id: str, additional: Optional[str | list[str]] = None)
return self.request_data(api_name, api_path, req_param)
def list_albums(self, offset: int = 0, limit: int = 100) -> dict[str, object] | str:
+ """
+ List albums.
+
+ Parameters
+ ----------
+ offset : int, optional
+ Number of albums to skip. Default is 0.
+ limit : int, optional
+ Maximum number of albums to return. Default is 100.
+
+ Returns
+ -------
+ dict[str, object] or str
+ The list of albums or an error message.
+ """
api_name = 'SYNO.Foto.Browse.Album'
info = self.photos_list[api_name]
api_path = info['path']
@@ -150,6 +409,23 @@ def suggest_condition(self,
condition: Optional[list[str]] = None,
user_id: Optional[str] = None
) -> dict[str, object] | str:
+ """
+ Suggest album conditions based on a keyword.
+
+ Parameters
+ ----------
+ keyword : str
+ The keyword to suggest conditions for.
+ condition : list of str, optional
+ List of conditions to use. Default is ['general_tag'].
+ user_id : str, optional
+ User ID to use. If None, uses the current user.
+
+ Returns
+ -------
+ dict[str, object] or str
+ The suggested conditions or an error message.
+ """
if condition is None:
condition = ['general_tag']
if user_id is None:
@@ -164,6 +440,21 @@ def suggest_condition(self,
return self.request_data(api_name, api_path, req_param)
def create_album(self, name: str, condition: list[str]) -> dict[str, object] | str:
+ """
+ Create a new album with the specified condition.
+
+ Parameters
+ ----------
+ name : str
+ The name of the album.
+ condition : list of str
+ The condition for the album.
+
+ Returns
+ -------
+ dict[str, object] or str
+ The API response for album creation.
+ """
api_name = 'SYNO.Foto.Browse.ConditionAlbum'
info = self.photos_list[api_name]
api_path = info['path']
@@ -173,6 +464,19 @@ def create_album(self, name: str, condition: list[str]) -> dict[str, object] | s
return self.request_data(api_name, api_path, req_param)
def delete_album(self, album_id: str) -> dict[str, object] | str:
+ """
+ Delete an album by ID.
+
+ Parameters
+ ----------
+ album_id : str
+ The album ID.
+
+ Returns
+ -------
+ dict[str, object] or str
+ The API response for album deletion.
+ """
if not isinstance(album_id, list):
album_id = [album_id]
api_name = 'SYNO.Foto.Browse.Album'
@@ -184,6 +488,21 @@ def delete_album(self, album_id: str) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def set_album_condition(self, folder_id: int, condition: list[str]) -> dict[str, object] | str:
+ """
+ Set the condition for an album.
+
+ Parameters
+ ----------
+ folder_id : int
+ The folder ID.
+ condition : list of str
+ The condition to set.
+
+ Returns
+ -------
+ dict[str, object] or str
+ The API response for setting the condition.
+ """
api_name = 'SYNO.Foto.Browse.ConditionAlbum'
info = self.photos_list[api_name]
api_path = info['path']
@@ -198,6 +517,25 @@ def share_album(self,
enabled: bool = True,
expiration: int | str = 0
) -> Any:
+ """
+ Share an album with specified permissions.
+
+ Parameters
+ ----------
+ album_id : str
+ The album ID.
+ permission : str or list of str, optional
+ Permissions to set.
+ enabled : bool, optional
+ Whether sharing is enabled. Default is True.
+ expiration : int or str, optional
+ Expiration time for the share. Default is 0.
+
+ Returns
+ -------
+ Any
+ The API response for sharing the album.
+ """
self._share('SYNO.Foto.Sharing.Passphrase', policy='album', permission=permission, album_id=album_id,
enabled=enabled, expiration=expiration)
@@ -207,6 +545,25 @@ def share_team_folder(self,
enabled: bool = True,
expiration: int | str = 0
) -> Any:
+ """
+ Share a team folder with specified permissions.
+
+ Parameters
+ ----------
+ folder_id : int
+ The folder ID.
+ permission : str, optional
+ Permissions to set.
+ enabled : bool, optional
+ Whether sharing is enabled. Default is True.
+ expiration : int or str, optional
+ Expiration time for the share. Default is 0.
+
+ Returns
+ -------
+ Any
+ The API response for sharing the team folder.
+ """
self._share('SYNO.FotoTeam.Sharing.Passphrase', policy='folder', permission=permission, folder_id=folder_id,
enabled=enabled, expiration=expiration)
@@ -217,6 +574,27 @@ def _share(self,
expiration: int | str,
**kwargs
) -> dict[str, object] | Any:
+ """
+ Internal method to share an album or folder.
+
+ Parameters
+ ----------
+ api_name : str
+ API name to use.
+ policy : str
+ Sharing policy.
+ permission : str
+ Permissions to set.
+ expiration : int or str
+ Expiration time for the share.
+ **kwargs
+ Additional keyword arguments.
+
+ Returns
+ -------
+ dict[str, object] or Any
+ The API response for sharing.
+ """
info = self.photos_list[api_name]
api_path = info['path']
req_param = {'version': info['maxVersion'],
@@ -236,6 +614,19 @@ def _share(self,
return self.request_data(api_name, api_path, req_param)
def list_shareable_users_and_groups(self, team_space_sharable_list: bool = False) -> dict[str, object] | str:
+ """
+ List users and groups that can be shared with.
+
+ Parameters
+ ----------
+ team_space_sharable_list : bool, optional
+ Whether to include team space sharable list. Default is False.
+
+ Returns
+ -------
+ dict[str, object] or str
+ The list of users and groups or an error message.
+ """
api_name = 'SYNO.Foto.Sharing.Misc'
info = self.photos_list[api_name]
api_path = info['path']
@@ -247,44 +638,35 @@ def list_shareable_users_and_groups(self, team_space_sharable_list: bool = False
def list_item_in_folders(self, offset: int = 0, limit: int = 0, folder_id: int = 0, sort_by: str = 'filename',
sort_direction: str = 'desc', type: str = None, passphrase: str = None,
additional: list = None) -> dict[str, object] | str:
- """List all items in all folders in Personal Space
-
- Parameters
- ----------
- offset : int
- Specify how many shared folders are skipped before beginning to return listed shared folders.
-
- limit : int
- Number of shared folders requested. Set to `0` to list all shared folders.
-
- folder_id : int
- ID of folder
-
- sort_by : str, optional
- Possible values:
- - `filename`
- - `filesize`
- - `takentime`
- - `item_type`
-
- sort_direction : str, optional
- Possible values: `asc` or `desc`. Defaults to: `desc`
-
- passphrase : str, optional
- Passphrase for a shared album
-
- additional : list[str]
- Possible values:
- `["thumbnail","resolution", "orientation", "video_convert", "video_meta", "provider_user_id", "exif", "tag", "description", "gps", "geocoding_id", "address", "person"]`
-
- type : str
- Possible values:
- - `photo`: Photo
- - `video`: Video
- - `live`: iPhone live photos'
-
"""
-
+ List all items in all folders in Personal Space.
+
+ Parameters
+ ----------
+ offset : int
+ Specify how many shared folders are skipped before beginning to return listed shared folders.
+ limit : int
+ Number of shared folders requested. Set to `0` to list all shared folders.
+ folder_id : int
+ ID of folder.
+ sort_by : str, optional
+ Possible values: 'filename', 'filesize', 'takentime', 'item_type'.
+ sort_direction : str, optional
+ Possible values: 'asc' or 'desc'. Defaults to: 'desc'.
+ type : str, optional
+ Possible values: 'photo', 'video', 'live'.
+ passphrase : str, optional
+ Passphrase for a shared album.
+ additional : list, optional
+ Additional fields to include.
+ Possible values:
+ `["thumbnail","resolution", "orientation", "video_convert", "video_meta", "provider_user_id", "exif", "tag", "description", "gps", "geocoding_id", "address", "person"]`.
+
+ Returns
+ -------
+ dict[str, object] or str
+ The list of items or an error message.
+ """
api_name = 'SYNO.Foto.Browse.Item'
info = self.photos_list[api_name]
api_path = info['path']
@@ -301,6 +683,14 @@ def list_item_in_folders(self, offset: int = 0, limit: int = 0, folder_id: int =
return self.request_data(api_name, api_path, req_param)
def list_search_filters(self) -> dict[str, object] | str:
+ """
+ List available search filters.
+
+ Returns
+ -------
+ dict[str, object] or str
+ The list of search filters or an error message.
+ """
api_name = 'SYNO.Foto.Search.Filter'
info = self.photos_list[api_name]
api_path = info['path']
@@ -309,6 +699,14 @@ def list_search_filters(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def get_guest_settings(self) -> dict[str, object] | str:
+ """
+ Retrieve guest settings for Photos.
+
+ Returns
+ -------
+ dict[str, object] or str
+ The guest settings or an error message.
+ """
api_name = 'SYNO.Foto.Setting.Guest'
info = self.photos_list[api_name]
api_path = info['path']
diff --git a/synology_api/security_advisor.py b/synology_api/security_advisor.py
index 18e4e128..03301d4e 100644
--- a/synology_api/security_advisor.py
+++ b/synology_api/security_advisor.py
@@ -1,11 +1,31 @@
+"""
+Security Advisor API wrapper for Synology DSM.
+
+This module provides a class to interact with the Synology Security Advisor API.
+"""
+
from __future__ import annotations
from typing import Optional
from . import base_api
class SecurityAdvisor(base_api.BaseApi):
+ """
+ Interface for Synology Security Advisor API.
+
+ Provides methods to retrieve general info, scan results, checklists,
+ login activity, and configuration for Security Advisor.
+ """
def general_info(self) -> dict[str, object] | str:
+ """
+ Retrieve general information about Security Advisor location configuration.
+
+ Returns
+ -------
+ dict[str, object] or str
+ The API response containing location configuration or an error message.
+ """
api_name = 'SYNO.SecurityAdvisor.Conf.Location'
info = self.gen_list[api_name]
api_path = info['path']
@@ -14,6 +34,14 @@ def general_info(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def security_scan(self) -> dict[str, object] | str:
+ """
+ Retrieve the current security scan configuration.
+
+ Returns
+ -------
+ dict[str, object] or str
+ The API response containing security scan configuration or an error message.
+ """
api_name = 'SYNO.Core.SecurityScan.Conf'
info = self.core_list[api_name]
api_path = info['path']
@@ -22,6 +50,14 @@ def security_scan(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def checklist(self) -> dict[str, object] | str:
+ """
+ Retrieve the checklist for the Security Advisor.
+
+ Returns
+ -------
+ dict[str, object] or str
+ The API response containing the checklist or an error message.
+ """
api_name = 'SYNO.SecurityAdvisor.Conf.Checklist'
info = self.gen_list[api_name]
api_path = info['path']
@@ -31,6 +67,21 @@ def checklist(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def login_activity(self, offset: int = 0, limit: int = 20) -> dict[str, object] | str:
+ """
+ Retrieve login activity records.
+
+ Parameters
+ ----------
+ offset : int, optional
+ The starting index of the login activity list. Default is 0.
+ limit : int, optional
+ The maximum number of records to retrieve. Default is 20.
+
+ Returns
+ -------
+ dict[str, object] or str
+ The API response containing login activity records or an error message.
+ """
api_name = 'SYNO.SecurityAdvisor.LoginActivity'
info = self.gen_list[api_name]
api_path = info['path']
@@ -40,6 +91,14 @@ def login_activity(self, offset: int = 0, limit: int = 20) -> dict[str, object]
return self.request_data(api_name, api_path, req_param)
def advisor_config(self) -> dict[str, object] | str:
+ """
+ Retrieve Security Advisor configuration.
+
+ Returns
+ -------
+ dict[str, object] or str
+ The API response containing advisor configuration or an error message.
+ """
api_name = 'SYNO.SecurityAdvisor.Conf'
info = self.gen_list[api_name]
api_path = info['path']
@@ -48,6 +107,14 @@ def advisor_config(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def scan_config(self) -> dict[str, object] | str:
+ """
+ Retrieve custom group enumeration for security scan configuration.
+
+ Returns
+ -------
+ dict[str, object] or str
+ The API response containing custom group enumeration or an error message.
+ """
api_name = 'SYNO.Core.SecurityScan.Conf'
info = self.gen_list[api_name]
api_path = info['path']
diff --git a/synology_api/snapshot.py b/synology_api/snapshot.py
index 8716a8f4..7672247b 100644
--- a/synology_api/snapshot.py
+++ b/synology_api/snapshot.py
@@ -1,3 +1,10 @@
+"""
+Snapshot Replication API wrapper for Synology DSM.
+
+This module provides a class to interact with the Synology Snapshot Replication APIs.
+The implementation is based on network inspection, as there is no official documentation.
+"""
+
from __future__ import annotations
from typing import Optional
from . import base_api
@@ -5,59 +12,61 @@
class Snapshot(base_api.BaseApi):
- """Class for interacting with Snapshot Replication APIs.
-
- This class implements APIs to manage snapshots.
- There is no documentation for these APIs, so the implementation is based on network inspection.
-
- Supported methods:
- - Getters:
- - Get all share/LUN snapshots
- - Get all replications
- - Get all LUNs
-
- - Setters:
- - Set snapshot attributes
-
- - Actions:
- - Create share/LUN snapshot (WORM support only for share snaps ATM)
- - Delete share/LUN snapshot
- - Sync replication
-
- Examples
- --------
- List snapshots for a share/LUN:
- ```python
- from synology_api import snapshot
- ss = snapshot.Snapshot('IP', 'PORT', 'USER', 'PASSWORD')
-
- resp_share = ss.list_snapshots('share_name')
- resp_lun = ss.list_snapshots_lun('src_lun_uuid')
-
- print(resp_share, resp_lun)
- ```
-
- Create a snapshot for a share/LUN:
- ```python
- resp_share = ss.create_snapshot('share_name')
- resp_lun = create_snapshot_lun('lun_id')
-
- print(resp_share, resp_lun)
- ```
-
- Delete snapshots for a share:
- ```python
- resp_share = ss.delete_snapshots('share_name', ['snapshot_name'])
- resp_lun = ss.delete_snapshots_lun(['snapshot_uuid'])
-
- print(resp_share, resp_lun)
- ```
-
- Set attributes for a snapshot:
- ```python
- resp = ss.set_snapshot_attr('share_name', 'snapshot_name', description='new description', lock=True)
- print(resp)
- ```
+ """
+ Class for interacting with Snapshot Replication APIs.
+
+ This class implements APIs to manage snapshots.
+ There is no documentation for these APIs, so the implementation is based on network inspection.
+
+ Methods
+ -------
+ Getters:
+ - Get all share/LUN snapshots
+ - Get all replications
+ - Get all LUNs
+
+ Setters:
+ - Set snapshot attributes
+
+ Actions:
+ - Create share/LUN snapshot (WORM support only for share snaps ATM)
+ - Delete share/LUN snapshot
+ - Sync replication
+
+ Examples
+ --------
+ List snapshots for a share/LUN:
+ ```python
+ from synology_api import snapshot
+ ss = snapshot.Snapshot('IP', 'PORT', 'USER', 'PASSWORD')
+
+ resp_share = ss.list_snapshots('share_name')
+ resp_lun = ss.list_snapshots_lun('src_lun_uuid')
+
+ print(resp_share, resp_lun)
+ ```
+
+ Create a snapshot for a share/LUN:
+ ```python
+ resp_share = ss.create_snapshot('share_name')
+ resp_lun = create_snapshot_lun('lun_id')
+
+ print(resp_share, resp_lun)
+ ```
+
+ Delete snapshots for a share:
+ ```python
+ resp_share = ss.delete_snapshots('share_name', ['snapshot_name'])
+ resp_lun = ss.delete_snapshots_lun(['snapshot_uuid'])
+
+ print(resp_share, resp_lun)
+ ```
+
+ Set attributes for a snapshot:
+ ```python
+ resp = ss.set_snapshot_attr('share_name', 'snapshot_name', description='new description', lock=True)
+ print(resp)
+ ```
"""
def list_snapshots(
@@ -68,67 +77,58 @@ def list_snapshots(
offset: int = 0,
limit: int = -1
) -> dict[str, object]:
- """List snapshots for a share.
-
- Parameters
- ----------
- share_name : str
- Name of the share to list snapshots for.
-
- attribute_filter : list[str], optional
- List of attributes filter to apply. Defaults to `[]` (no filter).
-
-
- Each attribute filter is a string in the format of `"attr==value"` or `"attr=value"` and optionally prefixed with `!` to negate the filter.
-
-
- The following are examples of valid attribute filters:
- - `["!hide==true", "desc==abc"]` -> hide is not true and desc is exactly abc.
- - `["desc=abc"]` -> desc has abc in it.
-
- additional_attribute : list[str], optional
- List of snapshot attributes whose values are included in the response. Defaults to `[]` (only time is returned).
-
-
- Note that not all attributes are available via API. The following are confirmed to work:
- - `"desc"`
- - `"lock"`
- - `"worm_lock"`
- - `"schedule_snapshot"`
-
- offset : int, optional
- Offset to start listing from. Defaults to `0`.
-
- limit : int, optional
- Number of snapshots to return. Defaults to `-1` (all).
-
- Returns
- -------
- dict[str, object]
- API response if successful, error message if not.
+ """
+ List snapshots for a share.
+
+ Parameters
+ ----------
+ share_name : str
+ Name of the share to list snapshots for.
+ attribute_filter : list[str], optional
+ List of attributes filter to apply. Defaults to `[]` (no filter).
+ Each attribute filter is a string in the format of `"attr==value"` or `"attr=value"` and optionally prefixed with `!` to negate the filter.
+ The following are examples of valid attribute filters:
+ - `["!hide==true", "desc==abc"]` -> hide is not true and desc is exactly abc.
+ - `["desc=abc"]` -> desc has abc in it.
+ additional_attribute : list[str], optional
+ List of snapshot attributes whose values are included in the response. Defaults to `[]` (only time is returned).
+ Note that not all attributes are available via API. The following are confirmed to work:
+ - `"desc"`
+ - `"lock"`
+ - `"worm_lock"`
+ - `"schedule_snapshot"`
+ offset : int, optional
+ Offset to start listing from. Defaults to `0`.
+ limit : int, optional
+ Number of snapshots to return. Defaults to `-1` (all).
+
+ Returns
+ -------
+ dict[str, object]
+ API response if successful, error message if not.
- Examples
- --------
- ```json
- {
- "data": {
- "snapshots": [
- {
- "desc": "",
- "lock": true,
- "schedule_snapshot": false,
- "time": "GMT+09-2023.09.11-23.23.40",
- "worm_lock": true,
- "worm_lock_begin": "1694442321",
- "worm_lock_day": "1",
- "worm_lock_end": "1694528721"
- }
- ],
- "total": 1
- },
- "success": true
- }
- ```
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "snapshots": [
+ {
+ "desc": "",
+ "lock": true,
+ "schedule_snapshot": false,
+ "time": "GMT+09-2023.09.11-23.23.40",
+ "worm_lock": true,
+ "worm_lock_begin": "1694442321",
+ "worm_lock_day": "1",
+ "worm_lock_end": "1694528721"
+ }
+ ],
+ "total": 1
+ },
+ "success": true
+ }
+ ```
"""
api_name = 'SYNO.Core.Share.Snapshot'
@@ -154,86 +154,83 @@ def list_snapshots_lun(
src_lun_uuid: str,
additional: list[str] = ["locked_app_keys", "is_worm_locked"]
) -> dict[str, object]:
- """List snapshots for a LUN.
-
- Parameters
- ----------
- src_lun_uuid : str
- UUID of the source LUN to list snapshots for.
-
- additional : list[str], optional
- Additional fields to retrieve. Specify `[]` to get only basic information.
-
- Defaults to `["locked_app_keys", "is_worm_locked"]`
-
-
- Possible values:
- - `"locked_app_keys"` -> If snapshot is preserved by the system, the locking package key will be returned.
- - `"is_worm_locked"` -> Whether the snapshot is locked by WORM.
-
- Returns
- -------
- dict[str, object]
- Dictionary containing the LUN snapshots information.
+ """
+ List snapshots for a LUN.
+
+ Parameters
+ ----------
+ src_lun_uuid : str
+ UUID of the source LUN to list snapshots for.
+ additional : list[str], optional
+ Additional fields to retrieve. Specify `[]` to get only basic information.
+ Defaults to `["locked_app_keys", "is_worm_locked"]`
+ Possible values:
+ - `"locked_app_keys"` -> If snapshot is preserved by the system, the locking package key will be returned.
+ - `"is_worm_locked"` -> Whether the snapshot is locked by WORM.
+
+ Returns
+ -------
+ dict[str, object]
+ Dictionary containing the LUN snapshots information.
- Examples
- --------
- ```json
- {
- "data": {
- "count": 2,
- "snapshots": [
- {
- "create_time": 1742739365,
- "description": "test",
- "is_app_consistent": false,
- "is_user_locked": true,
- "is_worm_locked": false,
- "locked_app_keys": [],
- "mapped_size": 0,
- "name": "SnapShot-1",
- "parent_lun_id": 6,
- "parent_uuid": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
- "root_path": "/volume2",
- "snapshot_id": 1,
- "snapshot_time": 1742739365,
- "status": "Healthy",
- "taken_by": "user",
- "total_size": 1073741824,
- "type": 2,
- "uuid": "fb388ec7-f23a-4011-8d24-08ad9b1fef34",
- "version": "d4236543-510f-4269-ae73-7bc789aaa763",
- "worm_lock_day": "0"
- },
- {
- "create_time": 1742833700,
- "description": "Snapshot taken by [Synology API]",
- "is_app_consistent": false,
- "is_user_locked": false,
- "is_worm_locked": false,
- "locked_app_keys": [
- "SnapshotReplication-synodr-657f3c72-f357-400d-96df-bb8ae4e5051f"
- ],
- "mapped_size": 0,
- "name": "SnapShot-2",
- "parent_lun_id": 6,
- "parent_uuid": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
- "root_path": "/volume2",
- "snapshot_id": 2,
- "snapshot_time": 1742833700,
- "status": "Healthy",
- "taken_by": "user",
- "total_size": 1073741824,
- "type": 2,
- "uuid": "e981770c-f56d-4cb2-b7a7-4c4b11ba8eaa",
- "version": "58ee3b1a-192d-46fe-9cf3-0960e2a8670b",
- "worm_lock_day": "0"
- }
- ]
- },
- "success": true
- }
- ```
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "count": 2,
+ "snapshots": [
+ {
+ "create_time": 1742739365,
+ "description": "test",
+ "is_app_consistent": false,
+ "is_user_locked": true,
+ "is_worm_locked": false,
+ "locked_app_keys": [],
+ "mapped_size": 0,
+ "name": "SnapShot-1",
+ "parent_lun_id": 6,
+ "parent_uuid": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
+ "root_path": "/volume2",
+ "snapshot_id": 1,
+ "snapshot_time": 1742739365,
+ "status": "Healthy",
+ "taken_by": "user",
+ "total_size": 1073741824,
+ "type": 2,
+ "uuid": "fb388ec7-f23a-4011-8d24-08ad9b1fef34",
+ "version": "d4236543-510f-4269-ae73-7bc789aaa763",
+ "worm_lock_day": "0"
+ },
+ {
+ "create_time": 1742833700,
+ "description": "Snapshot taken by [Synology API]",
+ "is_app_consistent": false,
+ "is_user_locked": false,
+ "is_worm_locked": false,
+ "locked_app_keys": [
+ "SnapshotReplication-synodr-657f3c72-f357-400d-96df-bb8ae4e5051f"
+ ],
+ "mapped_size": 0,
+ "name": "SnapShot-2",
+ "parent_lun_id": 6,
+ "parent_uuid": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
+ "root_path": "/volume2",
+ "snapshot_id": 2,
+ "snapshot_time": 1742833700,
+ "status": "Healthy",
+ "taken_by": "user",
+ "total_size": 1073741824,
+ "type": 2,
+ "uuid": "e981770c-f56d-4cb2-b7a7-4c4b11ba8eaa",
+ "version": "58ee3b1a-192d-46fe-9cf3-0960e2a8670b",
+ "worm_lock_day": "0"
+ }
+ ]
+ },
+ "success": true
+ }
+ ```
"""
api_name = 'SYNO.Core.ISCSI.LUN'
@@ -276,187 +273,178 @@ def list_luns(
"snapshot_info",
]
) -> dict[str, object]:
- """List available LUNs
-
- Parameters
- ----------
- types : list[str], optional
- Type of LUNS to retrieve.
-
-
- Defaults to `[ "BLOCK", "FILE", "THIN", "ADV", "SINK", "CINDER", "CINDER_BLUN", "CINDER_BLUN_THICK", "BLUN", "BLUN_THICK", "BLUN_SINK", "BLUN_THICK_SINK" ]`.
-
-
- Possible values:
- - `"BLOCK"`
- - `"FILE"`
- - `"THIN"`
- - `"ADV"`
- - `"SINK"`
- - `"CINDER"`
- - `"CINDER_BLUN"`
- - `"CINDER_BLUN_THICK"`
- - `"BLUN"`
- - `"BLUN_THICK"`
- - `"BLUN_SINK"`
- - `"BLUN_THICK_SINK"`
-
- additional_info : list[str], optional
- Additional LUN information to include in the response. Specify `[]` to get only basic information.
-
-
- Defaults to `[ "is_action_locked", "is_mapped", "extent_size", "allocated_size", "status", "allow_bkpobj", "flashcache_status", "family_config", "snapshot_info" ]`.
-
-
- Possible values:
- - `"is_action_locked"`
- - `"is_mapped"`
- - `"extent_size"`
- - `"allocated_size"`
- - `"status"`
- - `"allow_bkpobj"`
- - `"flashcache_status"`
- - `"family_config"`
- - `"snapshot_info"`
-
- Returns
- -------
- dict[str, object]
- A dictionary containing a list of LUNs present in the system.
+ """
+ List available LUNs.
+
+ Parameters
+ ----------
+ types : list[str], optional
+ Type of LUNS to retrieve.
+ Defaults to `[ "BLOCK", "FILE", "THIN", "ADV", "SINK", "CINDER", "CINDER_BLUN", "CINDER_BLUN_THICK", "BLUN", "BLUN_THICK", "BLUN_SINK", "BLUN_THICK_SINK" ]`.
+ Possible values:
+ - `"BLOCK"`
+ - `"FILE"`
+ - `"THIN"`
+ - `"ADV"`
+ - `"SINK"`
+ - `"CINDER"`
+ - `"CINDER_BLUN"`
+ - `"CINDER_BLUN_THICK"`
+ - `"BLUN"`
+ - `"BLUN_THICK"`
+ - `"BLUN_SINK"`
+ - `"BLUN_THICK_SINK"`
+ additional_info : list[str], optional
+ Additional LUN information to include in the response. Specify `[]` to get only basic information.
+ Defaults to `[ "is_action_locked", "is_mapped", "extent_size", "allocated_size", "status", "allow_bkpobj", "flashcache_status", "family_config", "snapshot_info" ]`.
+ Possible values:
+ - `"is_action_locked"`
+ - `"is_mapped"`
+ - `"extent_size"`
+ - `"allocated_size"`
+ - `"status"`
+ - `"allow_bkpobj"`
+ - `"flashcache_status"`
+ - `"family_config"`
+ - `"snapshot_info"`
+
+ Returns
+ -------
+ dict[str, object]
+ A dictionary containing a list of LUNs present in the system.
- Examples
- --------
- ```json
- {
- "data": {
- "luns": [
- {
- "allocated_size": 0,
- "block_size": 512,
- "create_from": "",
- "description": "",
- "dev_attribs": [
- {
- "dev_attrib": "emulate_3pc",
- "enable": 1
- },
- {
- "dev_attrib": "emulate_tpws",
- "enable": 1
- },
- {
- "dev_attrib": "emulate_caw",
- "enable": 1
- },
- {
- "dev_attrib": "emulate_tpu",
- "enable": 1
- },
- {
- "dev_attrib": "emulate_fua_write",
- "enable": 0
- },
- {
- "dev_attrib": "emulate_sync_cache",
- "enable": 0
- },
- {
- "dev_attrib": "can_snapshot",
- "enable": 1
- }
- ],
- "dev_attribs_bitmap": 31,
- "dev_config": "",
- "dev_qos": {
- "dev_limit": 0,
- "dev_reservation": 0,
- "dev_weight": 0,
- "iops_enable": 0
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "luns": [
+ {
+ "allocated_size": 0,
+ "block_size": 512,
+ "create_from": "",
+ "description": "",
+ "dev_attribs": [
+ {
+ "dev_attrib": "emulate_3pc",
+ "enable": 1
},
- "direct_io_pattern": 0,
- "extent_size": 0,
- "family_config": {
- "parent_lun_name": "",
- "parent_lun_uuid": "",
- "parent_snapshot_time": 0,
- "parent_snapshot_uuid": ""
+ {
+ "dev_attrib": "emulate_tpws",
+ "enable": 1
},
- "flashcache_id": -1,
- "flashcache_status": "no_cache",
- "is_action_locked": false,
- "is_mapped": true,
- "location": "/volume2",
- "lun_id": 6,
- "name": "LUN-1",
- "restored_time": 0,
- "retention": null,
- "scheduled_task": [
- {
- "general": {
- "snap_rotate": true,
- "snap_type": "app",
- "task_enabled": false,
- "task_name": "Task LUN-1",
- "tid": -1,
- "uuid": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
- },
- "schedule": {
- "date": "2025/3/24",
- "date_type": 0,
- "hour": 0,
- "last_work_hour": 0,
- "min": 0,
- "monthly_week": [],
- "next_trigger_time": "",
- "repeat": 0,
- "repeat_hour": 0,
- "repeat_hour_store_config": null,
- "repeat_min": 0,
- "repeat_min_store_config": null,
- "week_name": "0,1,2,3,4,5,6"
- }
+ {
+ "dev_attrib": "emulate_caw",
+ "enable": 1
+ },
+ {
+ "dev_attrib": "emulate_tpu",
+ "enable": 1
+ },
+ {
+ "dev_attrib": "emulate_fua_write",
+ "enable": 0
+ },
+ {
+ "dev_attrib": "emulate_sync_cache",
+ "enable": 0
+ },
+ {
+ "dev_attrib": "can_snapshot",
+ "enable": 1
+ }
+ ],
+ "dev_attribs_bitmap": 31,
+ "dev_config": "",
+ "dev_qos": {
+ "dev_limit": 0,
+ "dev_reservation": 0,
+ "dev_weight": 0,
+ "iops_enable": 0
+ },
+ "direct_io_pattern": 0,
+ "extent_size": 0,
+ "family_config": {
+ "parent_lun_name": "",
+ "parent_lun_uuid": "",
+ "parent_snapshot_time": 0,
+ "parent_snapshot_uuid": ""
+ },
+ "flashcache_id": -1,
+ "flashcache_status": "no_cache",
+ "is_action_locked": false,
+ "is_mapped": true,
+ "location": "/volume2",
+ "lun_id": 6,
+ "name": "LUN-1",
+ "restored_time": 0,
+ "retention": null,
+ "scheduled_task": [
+ {
+ "general": {
+ "snap_rotate": true,
+ "snap_type": "app",
+ "task_enabled": false,
+ "task_name": "Task LUN-1",
+ "tid": -1,
+ "uuid": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
+ },
+ "schedule": {
+ "date": "2025/3/24",
+ "date_type": 0,
+ "hour": 0,
+ "last_work_hour": 0,
+ "min": 0,
+ "monthly_week": [],
+ "next_trigger_time": "",
+ "repeat": 0,
+ "repeat_hour": 0,
+ "repeat_hour_store_config": null,
+ "repeat_min": 0,
+ "repeat_min_store_config": null,
+ "week_name": "0,1,2,3,4,5,6"
}
- ],
- "size": 1073741824,
- "snapshots": [
- {
- "create_time": 1742739365,
- "description": "test",
- "is_app_consistent": false,
- "is_user_locked": true,
- "mapped_size": 0,
- "name": "SnapShot-1",
- "parent_lun_id": 6,
- "parent_uuid": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
- "root_path": "/volume2",
- "snapshot_id": 1,
- "snapshot_time": 1742739365,
- "status": {
- "progress": {
- "percent": -1,
- "step": "waiting"
- },
- "type": "Healthy"
+ }
+ ],
+ "size": 1073741824,
+ "snapshots": [
+ {
+ "create_time": 1742739365,
+ "description": "test",
+ "is_app_consistent": false,
+ "is_user_locked": true,
+ "mapped_size": 0,
+ "name": "SnapShot-1",
+ "parent_lun_id": 6,
+ "parent_uuid": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
+ "root_path": "/volume2",
+ "snapshot_id": 1,
+ "snapshot_time": 1742739365,
+ "status": {
+ "progress": {
+ "percent": -1,
+ "step": "waiting"
},
- "taken_by": "user",
- "total_size": 1073741824,
- "type": 2,
- "uuid": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
- "version": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
- }
- ],
- "status": "normal",
- "type": 263,
- "type_str": "BLUN",
- "uuid": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
- "vpd_unit_sn": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
- }
- ]
- },
- "success": true
- }
- ```
-
+ "type": "Healthy"
+ },
+ "taken_by": "user",
+ "total_size": 1073741824,
+ "type": 2,
+ "uuid": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
+ "version": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
+ }
+ ],
+ "status": "normal",
+ "type": 263,
+ "type_str": "BLUN",
+ "uuid": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
+ "vpd_unit_sn": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
+ }
+ ]
+ },
+ "success": true
+ }
+ ```
"""
api_name = 'SYNO.Core.ISCSI.LUN'
@@ -486,331 +474,328 @@ def list_replication_plans(
"retention_lock_report"
]
) -> dict[str, object]:
- """List replication plans.
-
- Parameters
- ----------
- additional_info : list[str], optional
- List of additional information to include in the response. Specify `[]` to get only basic information.
-
-
- Defaults to `["sync_policy", "sync_report", "main_site_info", "dr_site_info", "can_do", "op_info", "last_op_info", "topology", "testfailover_info", "retention_lock_report"]`.
-
-
- Possible values:
- - `"sync_policy"` -> Information about the sync policy as schedule, retention, lock, etc.
- - `"sync_report"` -> Information about the previous runs and their results / error count.
- - `"main_site_info"` -> Information about the main site.
- - `"dr_site_info"` -> Information about the destination site.
- - `"can_do"` -> Information about the actions that can be performed on the replication plan.
- - `"op_info"` -> Information about the current operation (restoring / syncing / etc.).
- - `"last_op_info"` -> Information about the last operation.
- - `"topology"` -> Information about the replication topology (main / dr site & plan information).
- - `"testfailover_info"` -> Information about the previous test failover operation.
- - `"retention_lock_report"` -> Information about the first / last snapshot.
-
- Returns
- -------
- dict[str, object]
- API response if successful, error message if not
+ """
+ List replication plans.
+
+ Parameters
+ ----------
+ additional_info : list[str], optional
+ List of additional information to include in the response. Specify `[]` to get only basic information.
+ Defaults to `["sync_policy", "sync_report", "main_site_info", "dr_site_info", "can_do", "op_info", "last_op_info", "topology", "testfailover_info", "retention_lock_report"]`.
+ Possible values:
+ - `"sync_policy"` -> Information about the sync policy as schedule, retention, lock, etc.
+ - `"sync_report"` -> Information about the previous runs and their results / error count.
+ - `"main_site_info"` -> Information about the main site.
+ - `"dr_site_info"` -> Information about the destination site.
+ - `"can_do"` -> Information about the actions that can be performed on the replication plan.
+ - `"op_info"` -> Information about the current operation (restoring / syncing / etc.).
+ - `"last_op_info"` -> Information about the last operation.
+ - `"topology"` -> Information about the replication topology (main / dr site & plan information).
+ - `"testfailover_info"` -> Information about the previous test failover operation.
+ - `"retention_lock_report"` -> Information about the first / last snapshot.
+
+ Returns
+ -------
+ dict[str, object]
+ API response if successful, error message if not.
- Examples
- --------
- ```json
- {
- "data": {
- "plans": [{
- "additional": {
- "can_do": {
- "can_cleanup_testfailover": false,
- "can_delete": true,
- "can_edit": true,
- "can_export": false,
- "can_failover": false,
- "can_import": false,
- "can_switchover": true,
- "can_sync": true,
- "can_testfailover": true,
- "candidate_reprotect_new_mainsite": null
- },
- "dr_site_info": {
- "hostname": "hostname",
- "node_id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
- "op_info": {
- "op_progress": {
- "percentage": -1
- },
- "op_status": 1
- },
- "plan_id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
- "role": 2,
- "status": 1,
- "target_id": "api-1",
- "target_name": "api-1"
- },
- "last_op_info": {
- "err_code": 0,
- "is_success": true,
- "op_status": 16,
- "update_time": 1742739562
- },
- "main_site_info": {
- "hostname": "hostname",
- "node_id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
- "op_info": {
- "op_progress": {
- "percentage": -1
- },
- "op_status": 1
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "plans": [{
+ "additional": {
+ "can_do": {
+ "can_cleanup_testfailover": false,
+ "can_delete": true,
+ "can_edit": true,
+ "can_export": false,
+ "can_failover": false,
+ "can_import": false,
+ "can_switchover": true,
+ "can_sync": true,
+ "can_testfailover": true,
+ "candidate_reprotect_new_mainsite": null
+ },
+ "dr_site_info": {
+ "hostname": "hostname",
+ "node_id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
+ "op_info": {
+ "op_progress": {
+ "percentage": -1
},
- "plan_id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
- "role": 1,
- "status": 1,
- "target_id": "api",
- "target_name": "api"
+ "op_status": 1
},
+ "plan_id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
+ "role": 2,
+ "status": 1,
+ "target_id": "api-1",
+ "target_name": "api-1"
+ },
+ "last_op_info": {
+ "err_code": 0,
+ "is_success": true,
+ "op_status": 16,
+ "update_time": 1742739562
+ },
+ "main_site_info": {
+ "hostname": "hostname",
+ "node_id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"op_info": {
"op_progress": {
"percentage": -1
},
"op_status": 1
},
- "retention_lock_report": {
- "first_snapshot": "GMT+01-2025.03.23-15.17.39",
- "last_snapshot": "GMT+01-2025.03.23-15.18.46",
- "retain_first": false
+ "plan_id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
+ "role": 1,
+ "status": 1,
+ "target_id": "api",
+ "target_name": "api"
+ },
+ "op_info": {
+ "op_progress": {
+ "percentage": -1
},
- "sync_policy": {
- "enabled": true,
- "is_app_aware": false,
- "is_send_encrypted": false,
- "is_sync_local_snapshots": false,
- "mode": 2,
- "next_trigger_time": 1742770800,
- "notify_time_in_min": 720,
- "readable_next_trigger_time": "Mon Mar 24 00:00:00 2025",
- "schedule": {
- "date_type": 0,
- "hour": 0,
- "last_work_hour": 0,
- "min": 0,
- "repeat_hour": 0,
- "repeat_min": 0,
- "week_name": "0,1,2,3,4,5,6"
- },
- "sync_window": {
- "enabled": false,
- "window": [
- 16777215,
- 16777215,
- 16777215,
- 16777215,
- 16777215,
- 16777215,
- 16777215
- ]
- },
- "worm_lock_day": 7,
- "worm_lock_enable": false,
- "worm_lock_notify_time": 0
+ "op_status": 1
+ },
+ "retention_lock_report": {
+ "first_snapshot": "GMT+01-2025.03.23-15.17.39",
+ "last_snapshot": "GMT+01-2025.03.23-15.18.46",
+ "retain_first": false
+ },
+ "sync_policy": {
+ "enabled": true,
+ "is_app_aware": false,
+ "is_send_encrypted": false,
+ "is_sync_local_snapshots": false,
+ "mode": 2,
+ "next_trigger_time": 1742770800,
+ "notify_time_in_min": 720,
+ "readable_next_trigger_time": "Mon Mar 24 00:00:00 2025",
+ "schedule": {
+ "date_type": 0,
+ "hour": 0,
+ "last_work_hour": 0,
+ "min": 0,
+ "repeat_hour": 0,
+ "repeat_min": 0,
+ "week_name": "0,1,2,3,4,5,6"
},
- "sync_report": {
- "fail_sync_count": 0,
- "recent_records": [
- {
- "begin_time": 1742739460,
- "current_speed": 0,
- "data_size_byte": 750513392,
- "dr_site": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
- "elapsed_time": 37,
- "extra": {
- "site_task": {
- "site_id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
- "task_op": 2
- }
- },
- "finish_time": 1742739497,
- "is_done": true,
- "is_stopped": false,
- "is_success": true,
- "main_site": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
- "readable_begin_time": "Sun Mar 23 15:17:40 2025",
- "readable_finish_time": "Sun Mar 23 15:18:17 2025",
- "snapshot_version": "GMT+01-2025.03.23-15.17.39",
- "sync_size_byte": 750513392,
- "total_size_byte": 750513392,
- "update_time": 1742739497,
- "version": 3
+ "sync_window": {
+ "enabled": false,
+ "window": [
+ 16777215,
+ 16777215,
+ 16777215,
+ 16777215,
+ 16777215,
+ 16777215,
+ 16777215
+ ]
+ },
+ "worm_lock_day": 7,
+ "worm_lock_enable": false,
+ "worm_lock_notify_time": 0
+ },
+ "sync_report": {
+ "fail_sync_count": 0,
+ "recent_records": [
+ {
+ "begin_time": 1742739460,
+ "current_speed": 0,
+ "data_size_byte": 750513392,
+ "dr_site": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
+ "elapsed_time": 37,
+ "extra": {
+ "site_task": {
+ "site_id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
+ "task_op": 2
+ }
+ },
+ "finish_time": 1742739497,
+ "is_done": true,
+ "is_stopped": false,
+ "is_success": true,
+ "main_site": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
+ "readable_begin_time": "Sun Mar 23 15:17:40 2025",
+ "readable_finish_time": "Sun Mar 23 15:18:17 2025",
+ "snapshot_version": "GMT+01-2025.03.23-15.17.39",
+ "sync_size_byte": 750513392,
+ "total_size_byte": 750513392,
+ "update_time": 1742739497,
+ "version": 3
+ },
+ {
+ "begin_time": 1742739528,
+ "current_speed": 0,
+ "data_size_byte": 8210,
+ "dr_site": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
+ "elapsed_time": 28,
+ "extra": {
+ "site_task": {
+ "site_id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
+ "task_op": 2
+ }
},
- {
- "begin_time": 1742739528,
- "current_speed": 0,
- "data_size_byte": 8210,
- "dr_site": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
- "elapsed_time": 28,
- "extra": {
- "site_task": {
- "site_id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
- "task_op": 2
- }
+ "finish_time": 1742739556,
+ "is_done": true,
+ "is_stopped": false,
+ "is_success": true,
+ "main_site": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
+ "readable_begin_time": "Sun Mar 23 15:18:48 2025",
+ "readable_finish_time": "Sun Mar 23 15:19:16 2025",
+ "snapshot_version": "GMT+01-2025.03.23-15.18.46",
+ "sync_size_byte": 8210,
+ "total_size_byte": 8210,
+ "update_time": 1742739556,
+ "version": 3
+ }
+ ],
+ "success_sync_count": 2,
+ "syncing_record": null,
+ "total_success_sync_size_byte": 750521602,
+ "total_success_sync_time_sec": 65
+ },
+ "testfailover_info": null,
+ "topology": {
+ "links": [
+ {
+ "dr_site": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
+ "main_site": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
+ "plan_id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
+ }
+ ],
+ "sites": [
+ {
+ "addr": "",
+ "hostname": "hostname",
+ "node_id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
+ "plans": [
+ {
+ "additional": {
+ "sync_policy": {
+ "enabled": true,
+ "is_app_aware": false,
+ "is_send_encrypted": false,
+ "is_sync_local_snapshots": false,
+ "mode": 2,
+ "next_trigger_time": 1742770800,
+ "notify_time_in_min": 720,
+ "readable_next_trigger_time": "Mon Mar 24 00:00:00 2025",
+ "schedule": {
+ "date_type": 0,
+ "hour": 0,
+ "last_work_hour": 0,
+ "min": 0,
+ "repeat_hour": 0,
+ "repeat_min": 0,
+ "week_name": "0,1,2,3,4,5,6"
+ },
+ "sync_window": {
+ "enabled": false,
+ "window": [
+ 16777215,
+ 16777215,
+ 16777215,
+ 16777215,
+ 16777215,
+ 16777215,
+ 16777215
+ ]
+ },
+ "worm_lock_day": 7,
+ "worm_lock_enable": false,
+ "worm_lock_notify_time": 0
+ }
+ },
+ "is_to_local": true,
+ "plan_id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
+ "remote_target_name": "api-1",
+ "role": 1,
+ "status": 1,
+ "target_id": "api",
+ "target_name": "api"
},
- "finish_time": 1742739556,
- "is_done": true,
- "is_stopped": false,
- "is_success": true,
- "main_site": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
- "readable_begin_time": "Sun Mar 23 15:18:48 2025",
- "readable_finish_time": "Sun Mar 23 15:19:16 2025",
- "snapshot_version": "GMT+01-2025.03.23-15.18.46",
- "sync_size_byte": 8210,
- "total_size_byte": 8210,
- "update_time": 1742739556,
- "version": 3
- }
- ],
- "success_sync_count": 2,
- "syncing_record": null,
- "total_success_sync_size_byte": 750521602,
- "total_success_sync_time_sec": 65
- },
- "testfailover_info": null,
- "topology": {
- "links": [
- {
- "dr_site": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
- "main_site": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
- "plan_id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
- }
- ],
- "sites": [
- {
- "addr": "",
- "hostname": "hostname",
- "node_id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
- "plans": [
- {
- "additional": {
- "sync_policy": {
- "enabled": true,
- "is_app_aware": false,
- "is_send_encrypted": false,
- "is_sync_local_snapshots": false,
- "mode": 2,
- "next_trigger_time": 1742770800,
- "notify_time_in_min": 720,
- "readable_next_trigger_time": "Mon Mar 24 00:00:00 2025",
- "schedule": {
- "date_type": 0,
- "hour": 0,
- "last_work_hour": 0,
- "min": 0,
- "repeat_hour": 0,
- "repeat_min": 0,
- "week_name": "0,1,2,3,4,5,6"
- },
- "sync_window": {
- "enabled": false,
- "window": [
- 16777215,
- 16777215,
- 16777215,
- 16777215,
- 16777215,
- 16777215,
- 16777215
- ]
- },
- "worm_lock_day": 7,
- "worm_lock_enable": false,
- "worm_lock_notify_time": 0
- }
- },
- "is_to_local": true,
- "plan_id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
- "remote_target_name": "api-1",
- "role": 1,
- "status": 1,
- "target_id": "api",
- "target_name": "api"
+ ],
+ "status": 1
+ },
+ {
+ "addr": "",
+ "hostname": "hostname2",
+ "node_id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
+ "plans": [
+ {
+ "additional": {
+ "sync_policy": {
+ "enabled": true,
+ "is_app_aware": false,
+ "is_send_encrypted": true,
+ "is_sync_local_snapshots": false,
+ "mode": 2,
+ "next_trigger_time": 1742770800,
+ "notify_time_in_min": 720,
+ "readable_next_trigger_time": "Mon Mar 24 00:00:00 2025",
+ "schedule": {
+ "date_type": 0,
+ "hour": 0,
+ "last_work_hour": 0,
+ "min": 0,
+ "repeat_hour": 0,
+ "repeat_min": 0,
+ "week_name": "0,1,2,3,4,5,6"
+ },
+ "sync_window": {
+ "enabled": false,
+ "window": [
+ 16777215,
+ 16777215,
+ 16777215,
+ 16777215,
+ 16777215,
+ 16777215,
+ 16777215
+ ]
+ },
+ "worm_lock_day": 7,
+ "worm_lock_enable": false,
+ "worm_lock_notify_time": 0
+ }
},
- ],
- "status": 1
- },
- {
- "addr": "",
- "hostname": "hostname2",
- "node_id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
- "plans": [
- {
- "additional": {
- "sync_policy": {
- "enabled": true,
- "is_app_aware": false,
- "is_send_encrypted": true,
- "is_sync_local_snapshots": false,
- "mode": 2,
- "next_trigger_time": 1742770800,
- "notify_time_in_min": 720,
- "readable_next_trigger_time": "Mon Mar 24 00:00:00 2025",
- "schedule": {
- "date_type": 0,
- "hour": 0,
- "last_work_hour": 0,
- "min": 0,
- "repeat_hour": 0,
- "repeat_min": 0,
- "week_name": "0,1,2,3,4,5,6"
- },
- "sync_window": {
- "enabled": false,
- "window": [
- 16777215,
- 16777215,
- 16777215,
- 16777215,
- 16777215,
- 16777215,
- 16777215
- ]
- },
- "worm_lock_day": 7,
- "worm_lock_enable": false,
- "worm_lock_notify_time": 0
- }
- },
- "is_to_local": false,
- "plan_id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
- "remote_target_name": "api",
- "role": 2,
- "status": 1,
- "target_id": "api",
- "target_name": "api"
- }
- ],
- "status": 1
- }
- ],
- "target": {
- "target_id": "api",
- "target_type": 2
+ "is_to_local": false,
+ "plan_id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
+ "remote_target_name": "api",
+ "role": 2,
+ "status": 1,
+ "target_id": "api",
+ "target_name": "api"
+ }
+ ],
+ "status": 1
}
+ ],
+ "target": {
+ "target_id": "api",
+ "target_type": 2
}
- },
- "dr_site": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
- "is_to_local": true,
- "main_site": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
- "plan_id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
- "role": 1,
- "role_str": "mainsite",
- "solution_type": 1,
- "sync_mode": 2,
- "target_id": "api",
- "target_type": 2
- }]
- },
- "success": true
- }
- ```
+ }
+ },
+ "dr_site": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
+ "is_to_local": true,
+ "main_site": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
+ "plan_id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
+ "role": 1,
+ "role_str": "mainsite",
+ "solution_type": 1,
+ "sync_mode": 2,
+ "target_id": "api",
+ "target_type": 2
+ }]
+ },
+ "success": true
+ }
+ ```
"""
api_name = 'SYNO.DR.Plan'
@@ -833,40 +818,36 @@ def create_snapshot(
immutable: bool = False,
immutable_days: int = 7,
) -> dict[str, object]:
- """Create a snapshot for a share.
-
- Parameters
- ----------
- share_name : str
- Name of the share to create a snapshot for.
-
- description : str, optional
- Description of the snapshot. Defaults to `""`.
-
- lock : bool, optional
- Whether to lock the snapshot. Defaults to `False`.
-
- immutable : bool, optional
- Whether to make the snapshot immutable. Defaults to `False`.
-
- immutable_days : int, optional
- Number of days to make the snapshot immutable for. Defaults to `7`.
-
- Must be greater than `0`. Mandatory if immutable is `True`.
-
- Returns
- -------
- dict[str, object]
- API response if successful, error message if not.
+ """
+ Create a snapshot for a share.
+
+ Parameters
+ ----------
+ share_name : str
+ Name of the share to create a snapshot for.
+ description : str, optional
+ Description of the snapshot. Defaults to `""`.
+ lock : bool, optional
+ Whether to lock the snapshot. Defaults to `False`.
+ immutable : bool, optional
+ Whether to make the snapshot immutable. Defaults to `False`.
+ immutable_days : int, optional
+ Number of days to make the snapshot immutable for. Defaults to `7`.
+ Must be greater than `0`. Mandatory if immutable is `True`.
+
+ Returns
+ -------
+ dict[str, object]
+ API response if successful, error message if not.
- Examples
- --------
- ```json
- {
- "data": "GMT+09-2023.09.12-00.33.20",
- "success": true
- }
- ```
+ Examples
+ --------
+ ```json
+ {
+ "data": "GMT+09-2023.09.12-00.33.20",
+ "success": true
+ }
+ ```
"""
api_name = 'SYNO.Core.Share.Snapshot'
@@ -898,30 +879,32 @@ def delete_snapshots(
share_name: str,
snapshots: list[str]
) -> dict[str, object]:
- """Delete snapshots for a share.
-
- Warning: This action removes data from the file system. Use with caution.
+ """
+ Delete snapshots for a share.
- Parameters
- ----------
- share_name : str
- Name of the share to delete snapshots for.
+ Parameters
+ ----------
+ share_name : str
+ Name of the share to delete snapshots for.
+ snapshots : list[str]
+ List of snapshots to delete.
- snapshots : list[str]
- List of snapshots to delete.
+ Returns
+ -------
+ dict[str, object]
+ API response if successful, error message if not.
- Returns
- -------
- dict[str, object]
- API response if successful, error message if not.
+ Notes
+ -----
+ Warning: This action removes data from the file system. Use with caution.
- Examples
- --------
- ```json
- {
- "success": true
- }
- ```
+ Examples
+ --------
+ ```json
+ {
+ "success": true
+ }
+ ```
"""
api_name = 'SYNO.Core.Share.Snapshot'
@@ -946,41 +929,37 @@ def set_snapshot_attr(
immutable: Optional[bool] = None,
immutable_days: Optional[int] = None
) -> dict[str, object]:
- """Set attributes for a snapshot.
-
- Parameters
- ----------
- share_name : str
- Name of the share to set attributes for
-
- snapshot : str
- Name of the snapshot to set attributes for
-
- description : str, optional
- Description of the snapshot. Defaults to `None` (no change).
-
- lock : bool, optional
- Whether to lock the snapshot. Defaults to `None` (no change).
-
- immutable : bool, optional
- Whether to make the snapshot immutable. Defaults to `None` (no change).
-
- immutable_days : int, optional
- Number of days to make the snapshot immutable for. Defaults to `None` (no change).
- Must be greater than `0`. Mandatory if immutable is `True`.
-
- Returns
- -------
- dict[str, object]
- API response if successful, error message if not.
+ """
+ Set attributes for a snapshot.
+
+ Parameters
+ ----------
+ share_name : str
+ Name of the share to set attributes for.
+ snapshot : str
+ Name of the snapshot to set attributes for.
+ description : str, optional
+ Description of the snapshot. Defaults to `None` (no change).
+ lock : bool, optional
+ Whether to lock the snapshot. Defaults to `None` (no change).
+ immutable : bool, optional
+ Whether to make the snapshot immutable. Defaults to `None` (no change).
+ immutable_days : int, optional
+ Number of days to make the snapshot immutable for. Defaults to `None` (no change).
+ Must be greater than `0`. Mandatory if immutable is `True`.
+
+ Returns
+ -------
+ dict[str, object]
+ API response if successful, error message if not.
- Examples
- --------
- ```json
- {
- "success": true
- }
- ```
+ Examples
+ --------
+ ```json
+ {
+ "success": true
+ }
+ ```
"""
api_name = 'SYNO.Core.Share.Snapshot'
@@ -1020,31 +999,30 @@ def sync_replication(
lock_snapshot: bool = True,
description: str = "Snapshot taken by [Synology API]",
) -> dict[str, object]:
- """Trigger a sync for a replication plan.
-
- Parameters
- ----------
- plan_id : str
- ID of the replication plan to sync.
-
- lock_snapshot : bool, optional
- Whether to lock the snapshot to prevent rotation. Defaults to `True`.
-
- description : str, optional
- Description of the snapshot. Defaults to `Snapshot taken by [Synology API]`.
-
- Returns
- -------
- dict[str, object]
- API response if successful
+ """
+ Trigger a sync for a replication plan.
+
+ Parameters
+ ----------
+ plan_id : str
+ ID of the replication plan to sync.
+ lock_snapshot : bool, optional
+ Whether to lock the snapshot to prevent rotation. Defaults to `True`.
+ description : str, optional
+ Description of the snapshot. Defaults to `Snapshot taken by [Synology API]`.
+
+ Returns
+ -------
+ dict[str, object]
+ API response if successful.
- Examples
- --------
- ```json
- {
- "success": true
- }
- ```
+ Examples
+ --------
+ ```json
+ {
+ "success": true
+ }
+ ```
"""
plans = self.list_replication_plans(
@@ -1078,40 +1056,40 @@ def create_snapshot_lun(
lock: bool = True,
app_aware: bool = True
) -> dict[str, object]:
- """Create a snapshot for a LUN.
-
- Note: At the moment, it does not support creating WORM snapshots.
-
- Parameters
- ----------
- lun_id : str
- ID of the LUN to create a snapshot for
-
- description : str, optional
- Description of the snapshot. Defaults to `Snapshot taken by [Synology API]`.
-
- lock : bool, optional
- Whether to lock the snapshot. Defaults to `True`.
-
- app_aware : bool, optional
- Whether to make the snapshot application aware. Defaults to `True`.
-
- Returns
- -------
- dict[str, object]
- API response if successful
+ """
+ Create a snapshot for a LUN.
+
+ Parameters
+ ----------
+ lun_id : str
+ ID of the LUN to create a snapshot for.
+ description : str, optional
+ Description of the snapshot. Defaults to `Snapshot taken by [Synology API]`.
+ lock : bool, optional
+ Whether to lock the snapshot. Defaults to `True`.
+ app_aware : bool, optional
+ Whether to make the snapshot application aware. Defaults to `True`.
+
+ Returns
+ -------
+ dict[str, object]
+ API response if successful.
+
+ Notes
+ -----
+ At the moment, it does not support creating WORM snapshots.
- Examples
- --------
- ```json
- {
- "data": {
- "snapshot_id": 4,
- "snapshot_uuid": "31aa7808-9ffc-4689-bb70-262bb1665c9b"
- },
- "success": true
- }
- ```
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "snapshot_id": 4,
+ "snapshot_uuid": "31aa7808-9ffc-4689-bb70-262bb1665c9b"
+ },
+ "success": true
+ }
+ ```
"""
api_name = 'SYNO.Core.ISCSI.LUN'
@@ -1130,41 +1108,42 @@ def create_snapshot_lun(
return self.request_data(api_name, api_path, req_param)
def delete_snapshots_lun(self, snapshot_uuids: list[str]) -> dict[str, object]:
- """Delete snapshots for a LUN.
-
- Warning: This action removes data from the file system. Use with caution.
-
- Parameters
- ----------
- snapshot_uuids : list[str]
- List of UUIDs of the snapshots to delete.
-
- Returns
- -------
- dict[str, object]
- API response if successful.
-
+ """
+ Delete snapshots for a LUN.
- If deletion fails, an error code is returned alonside the snapshot uuid:
- ```json
- {
- "data": [
- {
- "5c9bf4a7-05ea-4cb8-b9e0-e0b0ca1186b0": 18990540
- }
- ],
- "success": true
- }
- ```
+ Parameters
+ ----------
+ snapshot_uuids : list[str]
+ List of UUIDs of the snapshots to delete.
- Examples
- --------
+ Returns
+ -------
+ dict[str, object]
+ If deletion fails, an error code is returned alongside the snapshot uuid:
```json
{
- "data": [],
+ "data": [
+ {
+ "5c9bf4a7-05ea-4cb8-b9e0-e0b0ca1186b0": 18990540
+ }
+ ],
"success": true
}
```
+ API response if successful.
+
+ Notes
+ -----
+ Warning: This action removes data from the file system. Use with caution.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": [],
+ "success": true
+ }
+ ```
"""
api_name = 'SYNO.Core.ISCSI.LUN'
diff --git a/synology_api/surveillancestation.py b/synology_api/surveillancestation.py
index bfb91e76..4570f724 100644
--- a/synology_api/surveillancestation.py
+++ b/synology_api/surveillancestation.py
@@ -1,11 +1,27 @@
+"""Synology Surveillance Station API Wrapper."""
from __future__ import annotations
from typing import Optional, Any
from . import base_api
class SurveillanceStation(base_api.BaseApi):
+ """
+ API wrapper for Synology Surveillance Station.
+
+ Provides methods to interact with Surveillance Station features such as retrieving
+ station information and saving camera configurations.
+ """
def surveillance_station_info(self) -> dict[str, object] | str:
+ """
+ Retrieve information about the Surveillance Station.
+
+ Returns
+ -------
+ dict[str, object] or str
+ A dictionary containing Surveillance Station information, or a string
+ with error details if the request fails.
+ """
api_name = 'SYNO.SurveillanceStation.Info'
info = self.gen_list[api_name]
api_path = info['path']
@@ -40,6 +56,71 @@ def camera_save(self, id: str = None,
enableLowProfile: bool = None,
recordSchedule: list[int] = None,
rtspPathTimeout: int = None) -> dict[str, object] | str:
+ """
+ Save or update camera configuration.
+
+ Parameters
+ ----------
+ id : str, optional
+ Camera ID.
+ name : str, optional
+ Camera name.
+ dsld : int, optional
+ Device slot ID.
+ newName : str, optional
+ New camera name.
+ ip : str, optional
+ Camera IP address.
+ port : int, optional
+ Camera port.
+ vendor : str, optional
+ Camera vendor.
+ model : str, optional
+ Camera model.
+ userName : str, optional
+ Username for camera authentication.
+ password : str, optional
+ Password for camera authentication.
+ videoCodec : int, optional
+ Video codec type.
+ audioCodec : int, optional
+ Audio codec type.
+ tvStandard : int, optional
+ TV standard.
+ channel : str, optional
+ Channel identifier.
+ userDefinePath : str, optional
+ User-defined path.
+ fov : str, optional
+ Field of view.
+ streamXX : Any, optional
+ Stream configuration.
+ recordTime : int, optional
+ Recording time.
+ preRecordTime : int, optional
+ Pre-recording time.
+ postRecordTime : int, optional
+ Post-recording time.
+ enableRecordingKeepDays : bool, optional
+ Enable recording retention by days.
+ recordingKeepDays : int, optional
+ Number of days to keep recordings.
+ enableRecordingKeepSize : bool, optional
+ Enable recording retention by size.
+ recordingKeepSize : int, optional
+ Maximum size for recordings.
+ enableLowProfile : bool, optional
+ Enable low profile recording.
+ recordSchedule : list of int, optional
+ Recording schedule.
+ rtspPathTimeout : int, optional
+ RTSP path timeout.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the save operation or error details.
+ """
api_name = 'SYNO.SurveillanceStation.Camera'
info = self.gen_list[api_name]
api_path = info['path']
@@ -62,7 +143,37 @@ def camera_list(self, idList: str = None,
streamInfo: bool = None,
blPrivilege: bool = None,
camStm: int = None) -> dict[str, object] | str:
-
+ """
+ Retrieve a list of cameras from Surveillance Station.
+
+ Parameters
+ ----------
+ idList : str, optional
+ Comma-separated list of camera IDs to filter.
+ offset : int, optional
+ The starting index for the camera list.
+ limit : int, optional
+ The maximum number of cameras to return.
+ blFromCamList : bool, optional
+ Whether to retrieve from the camera list.
+ blIncludeDeletedCam : bool, optional
+ Whether to include deleted cameras.
+ privCamType : str, optional
+ Filter by camera privilege type.
+ basic : bool, optional
+ Whether to return only basic information.
+ streamInfo : bool, optional
+ Whether to include stream information.
+ blPrivilege : bool, optional
+ Whether to include privilege information.
+ camStm : int, optional
+ Camera stream type.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Dictionary containing camera list information, or a string with error details.
+ """
api_name = 'SYNO.SurveillanceStation.Camera'
info = self.gen_list[api_name]
api_path = info['path']
@@ -87,21 +198,44 @@ def get_camera_info(self,
deviceOutCap: bool = True,
fisheye: bool = True,
camAppInfo: bool = True) -> dict[str, object] | str:
- '''
- This function return information about a camera.
-
- cameraIds : This parameter is named cameraIds in the API documentation but it refer to 1 camera ID
-
- privCamType: int = 1
- SYNO.SS.CamPriv.LIVEVIEW = 1;
- SYNO.SS.CamPriv.PLAYBACK = 2;
- SYNO.SS.CamPriv.LENS = 4;
- SYNO.SS.CamPriv.AUDIO = 8;
- SYNO.SS.CamPriv.DIGIOUT = 16;
-
- All other parameters must be let to default value
- '''
-
+ """
+ Return information about a camera.
+
+ Parameters
+ ----------
+ cameraIds : int, optional
+ Camera ID. Although named cameraIds in the API, it refers to a single camera ID.
+ privCamType : int, default=1
+ Camera privilege type. Possible values:
+ 1: LIVEVIEW
+ 2: PLAYBACK
+ 4: LENS
+ 8: AUDIO
+ 16: DIGIOUT
+ blIncludeDeletedCam : bool, default=True
+ Whether to include deleted cameras.
+ basic : bool, default=True
+ Whether to return only basic information.
+ streamInfo : bool, default=True
+ Whether to include stream information.
+ optimize : bool, default=True
+ Whether to optimize the returned data.
+ ptz : bool, default=True
+ Whether to include PTZ (Pan-Tilt-Zoom) information.
+ eventDetection : bool, default=True
+ Whether to include event detection information.
+ deviceOutCap : bool, default=True
+ Whether to include device output capabilities.
+ fisheye : bool, default=True
+ Whether to include fisheye camera information.
+ camAppInfo : bool, default=True
+ Whether to include camera application information.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Dictionary containing camera information, or a string with error details.
+ """
api_name = 'SYNO.SurveillanceStation.Camera'
info = self.gen_list[api_name]
api_path = info['path']
@@ -117,7 +251,21 @@ def get_camera_info(self,
def camera_list_group(self,
offset: int = None,
limit: int = None) -> dict[str, object] | str:
-
+ """
+ Retrieve a list of camera groups from Surveillance Station.
+
+ Parameters
+ ----------
+ offset : int, optional
+ The starting index for the camera group list.
+ limit : int, optional
+ The maximum number of camera groups to return.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Dictionary containing camera group information, or a string with error details.
+ """
api_name = 'SYNO.SurveillanceStation.Camera'
info = self.gen_list[api_name]
api_path = info['path']
@@ -135,9 +283,25 @@ def get_snapshot(self,
name: str = None,
dsld: int = None,
profileType: int = 1) -> str:
- ''' By default, the profileType is 1, which is the default profile.
- Binary data is returned, so the response is not a json object.
- '''
+ """
+ Retrieve a snapshot image from a camera.
+
+ Parameters
+ ----------
+ id : Any, optional
+ Camera identifier.
+ name : str, optional
+ Camera name.
+ dsld : int, optional
+ Device slot ID.
+ profileType : int, default=1
+ Profile type for the snapshot (1 is the default profile).
+
+ Returns
+ -------
+ str
+ Binary data of the snapshot image. The response is not a JSON object.
+ """
api_name = 'SYNO.SurveillanceStation.Camera'
info = self.gen_list[api_name]
api_path = info['path']
@@ -154,6 +318,21 @@ def get_snapshot(self,
def enable_camera(self,
idList: str = None,
blIncludeDeletedCam: bool = False) -> dict[str, object] | str:
+ """
+ Enable one or more cameras by their IDs.
+
+ Parameters
+ ----------
+ idList : str, optional
+ Comma-separated list of camera IDs to enable.
+ blIncludeDeletedCam : bool, optional
+ Whether to include deleted cameras in the operation. Default is False.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the enable operation as a dictionary, or a string with error details.
+ """
api_name = 'SYNO.SurveillanceStation.Camera'
info = self.gen_list[api_name]
api_path = info['path']
@@ -169,6 +348,21 @@ def enable_camera(self,
def disable_camera(self,
idList: str = None,
blIncludeDeletedCam: bool = False) -> dict[str, object] | str:
+ """
+ Disable one or more cameras by their IDs.
+
+ Parameters
+ ----------
+ idList : str, optional
+ Comma-separated list of camera IDs to disable.
+ blIncludeDeletedCam : bool, optional
+ Whether to include deleted cameras in the operation. Default is False.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the disable operation as a dictionary, or a string with error details.
+ """
api_name = 'SYNO.SurveillanceStation.Camera'
info = self.gen_list[api_name]
api_path = info['path']
@@ -183,6 +377,19 @@ def disable_camera(self,
# TODO not working
def get_capability_by_cam_id(self, cameraId: Any = None) -> dict[str, object] | str:
+ """
+ Retrieve the capability information for a specific camera by its ID.
+
+ Parameters
+ ----------
+ cameraId : Any, optional
+ The ID of the camera for which to retrieve capability information.
+
+ Returns
+ -------
+ dict[str, object] or str
+ A dictionary containing the camera's capability information, or a string with error details if the request fails.
+ """
api_name = 'SYNO.SurveillanceStation.Camera'
info = self.gen_list[api_name]
api_path = info['path']
@@ -193,6 +400,19 @@ def get_capability_by_cam_id(self, cameraId: Any = None) -> dict[str, object] |
# TODO not working
def count_occupied_size(self, camId: int = None) -> dict[str, object] | str:
+ """
+ Retrieve the occupied storage size for a specific camera.
+
+ Parameters
+ ----------
+ camId : int, optional
+ The ID of the camera for which to retrieve the occupied size.
+
+ Returns
+ -------
+ dict[str, object] or str
+ A dictionary containing the occupied size information, or a string with error details if the request fails.
+ """
api_name = 'SYNO.SurveillanceStation.Camera'
info = self.gen_list[api_name]
api_path = info['path']
@@ -203,6 +423,19 @@ def count_occupied_size(self, camId: int = None) -> dict[str, object] | str:
# TODO not working
def is_shortcut_valid(self, cameraId: int = None) -> dict[str, object] | str:
+ """
+ Check if a camera shortcut is valid.
+
+ Parameters
+ ----------
+ cameraId : int, optional
+ The ID of the camera to validate the shortcut for.
+
+ Returns
+ -------
+ dict[str, object] or str
+ A dictionary with the validation result, or a string with error details.
+ """
api_name = 'SYNO.SurveillanceStation.Camera'
info = self.gen_list[api_name]
api_path = info['path']
@@ -212,6 +445,19 @@ def is_shortcut_valid(self, cameraId: int = None) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def get_live_path(self, idList: int = None) -> dict[str, object] | str:
+ """
+ Retrieve the live view path for one or more cameras.
+
+ Parameters
+ ----------
+ idList : int, optional
+ Camera ID or comma-separated list of camera IDs for which to retrieve the live view path.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Dictionary containing the live view path information, or a string with error details.
+ """
api_name = 'SYNO.SurveillanceStation.Camera'
info = self.gen_list[api_name]
api_path = info['path']
@@ -221,6 +467,19 @@ def get_live_path(self, idList: int = None) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def audio_event_enum(self, camId: int = None) -> dict[str, object] | str:
+ """
+ Enumerate audio events for a specific camera.
+
+ Parameters
+ ----------
+ camId : int, optional
+ The ID of the camera for which to enumerate audio events.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Dictionary containing audio event enumeration, or a string with error details.
+ """
api_name = 'SYNO.SurveillanceStation.Camera.Event'
info = self.gen_list[api_name]
api_path = info['path']
@@ -231,6 +490,19 @@ def audio_event_enum(self, camId: int = None) -> dict[str, object] | str:
# TODO not working
def alarm_event_enum(self, camId: int = None) -> dict[str, object] | str:
+ """
+ Enumerate alarm events for a specific camera.
+
+ Parameters
+ ----------
+ camId : int, optional
+ The ID of the camera for which to enumerate alarm events.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Dictionary containing alarm event enumeration, or a string with error details.
+ """
api_name = 'SYNO.SurveillanceStation.Camera.Event'
info = self.gen_list[api_name]
api_path = info['path']
@@ -246,6 +518,31 @@ def md_parameter_save(self, camId: int = None,
threshold: int = None,
objectSize: int = None,
percentage: int = None) -> dict[str, object] | str:
+ """
+ Save motion detection parameters for a specific camera.
+
+ Parameters
+ ----------
+ camId : int, optional
+ The ID of the camera for which to save motion detection parameters.
+ source : int, optional
+ The source channel or stream index.
+ mode : int, optional
+ The motion detection mode.
+ sensitivity : int, optional
+ Sensitivity level for motion detection.
+ threshold : int, optional
+ Threshold value for motion detection.
+ objectSize : int, optional
+ Minimum object size to trigger detection.
+ percentage : int, optional
+ Minimum percentage of the detection area to trigger detection.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the save operation as a dictionary, or a string with error details.
+ """
api_name = 'SYNO.SurveillanceStation.Camera.Event'
info = self.gen_list[api_name]
api_path = info['path']
@@ -259,6 +556,19 @@ def md_parameter_save(self, camId: int = None,
return self.request_data(api_name, api_path, req_param)
def motion_event_enum(self, camId: int = None) -> dict[str, object] | str:
+ """
+ Enumerate motion events for a specific camera.
+
+ Parameters
+ ----------
+ camId : int, optional
+ The ID of the camera for which to enumerate motion events.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Dictionary containing motion event enumeration, or a string with error details.
+ """
api_name = 'SYNO.SurveillanceStation.Camera.Event'
info = self.gen_list[api_name]
api_path = info['path']
@@ -273,7 +583,27 @@ def motion_parameter_save(self,
mode: int = None,
keep: bool = None,
level: int = None) -> dict[str, object] | str:
-
+ """
+ Save advanced motion detection parameters for a specific camera.
+
+ Parameters
+ ----------
+ camId : int, optional
+ The ID of the camera for which to save motion detection parameters.
+ source : int, optional
+ The source channel or stream index.
+ mode : int, optional
+ The motion detection mode.
+ keep : bool, optional
+ Whether to keep the current settings.
+ level : int, optional
+ Sensitivity level for advanced motion detection.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the save operation as a dictionary, or a string with error details.
+ """
api_name = 'SYNO.SurveillanceStation.Camera.Event'
info = self.gen_list[api_name]
api_path = info['path']
@@ -291,7 +621,25 @@ def di_parameter_save(self,
idx: int = None,
keep: bool = None,
normal: int = None) -> dict[str, object] | str:
-
+ """
+ Save digital input (DI) parameters for a specific camera.
+
+ Parameters
+ ----------
+ camId : int, optional
+ The ID of the camera for which to save DI parameters.
+ idx : int, optional
+ The index of the DI channel.
+ keep : bool, optional
+ Whether to keep the current DI settings.
+ normal : int, optional
+ The normal state value for the DI channel.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the save operation as a dictionary, or a string with error details.
+ """
api_name = 'SYNO.SurveillanceStation.Camera.Event'
info = self.gen_list[api_name]
api_path = info['path']
@@ -309,7 +657,23 @@ def alarm_sts_polling(self,
timeOut: int = None,
# TODO not working
keep: Any = None) -> dict[str, object] | str:
-
+ """
+ Poll the alarm status for a specific camera.
+
+ Parameters
+ ----------
+ camId : int, optional
+ The ID of the camera for which to poll alarm status.
+ timeOut : int, optional
+ Timeout value for the polling operation.
+ keep : Any, optional
+ Reserved for future use or additional options (currently not working).
+
+ Returns
+ -------
+ dict[str, object] or str
+ Dictionary containing alarm status polling result, or a string with error details.
+ """
api_name = 'SYNO.SurveillanceStation.Camera.Event'
info = self.gen_list[api_name]
api_path = info['path']
@@ -328,7 +692,25 @@ def td_parameter_save(self,
source: int = None,
keep: Any = None,
duration: int = None) -> dict[str, object] | str:
-
+ """
+ Save tamper detection (TD) parameters for a specific camera.
+
+ Parameters
+ ----------
+ camId : int, optional
+ The ID of the camera for which to save tamper detection parameters.
+ source : int, optional
+ The source channel or stream index.
+ keep : Any, optional
+ Whether to keep the current settings (reserved for future use).
+ duration : int, optional
+ Duration for the tamper detection event.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the save operation as a dictionary, or a string with error details.
+ """
api_name = 'SYNO.SurveillanceStation.Camera.Event'
info = self.gen_list[api_name]
api_path = info['path']
@@ -342,7 +724,19 @@ def td_parameter_save(self,
return self.request_data(api_name, api_path, req_param)
def enumerate_camera_group(self, privCamType: int = None) -> dict[str, object] | str:
-
+ """
+ Enumerate camera groups in Surveillance Station.
+
+ Parameters
+ ----------
+ privCamType : int, optional
+ Camera privilege type to filter groups.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Dictionary containing camera group enumeration, or a string with error details.
+ """
api_name = 'SYNO.SurveillanceStation.Camera.Group'
info = self.gen_list[api_name]
api_path = info['path']
@@ -353,6 +747,19 @@ def enumerate_camera_group(self, privCamType: int = None) -> dict[str, object] |
# TODO to check
def save_specific_group(self, groupList: Any = None) -> dict[str, object] | str:
+ """
+ Save or update a specific camera group in Surveillance Station.
+
+ Parameters
+ ----------
+ groupList : Any, optional
+ The list of groups to be saved or updated.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the save operation as a dictionary, or a string with error details.
+ """
api_name = 'SYNO.SurveillanceStation.Camera.Group'
info = self.gen_list[api_name]
api_path = info['path']
@@ -362,6 +769,19 @@ def save_specific_group(self, groupList: Any = None) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def delete_specific_groups(self, Id: int = None) -> dict[str, object] | str:
+ """
+ Delete specific camera groups in Surveillance Station.
+
+ Parameters
+ ----------
+ Id : int, optional
+ The ID of the camera group to delete.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the delete operation as a dictionary, or a string with error details.
+ """
api_name = 'SYNO.SurveillanceStation.Camera.Group'
info = self.gen_list[api_name]
api_path = info['path']
@@ -376,6 +796,27 @@ def enumerate_group_information(self, camServerId: int = None,
camlist: Any = None,
# TODO not working
actFromHost: bool = None) -> dict[str, object] | str:
+ """
+ Enumerate group information for camera import in Surveillance Station.
+
+ Parameters
+ ----------
+ camServerId : int, optional
+ The ID of the camera server.
+ shareName : str, optional
+ The name of the shared folder.
+ archiveName : str, optional
+ The name of the archive.
+ camlist : Any, optional
+ List of cameras to include.
+ actFromHost : bool, optional
+ Whether the action is performed from the host. (Currently not working).
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the group information enumeration as a dictionary, or a string with error details.
+ """
api_name = 'SYNO.SurveillanceStation.Camera.Import'
info = self.gen_list[api_name]
api_path = info['path']
@@ -392,6 +833,23 @@ def enumerate_camera_from_archive(self,
shareName: str = None,
archiveName: str = None,
serverId: int = None) -> dict[str, object] | str:
+ """
+ Enumerate cameras from a specified archive in Surveillance Station.
+
+ Parameters
+ ----------
+ shareName : str, optional
+ The name of the shared folder containing the archive.
+ archiveName : str, optional
+ The name of the archive to enumerate cameras from.
+ serverId : int, optional
+ The ID of the server associated with the archive.
+
+ Returns
+ -------
+ dict[str, object] or str
+ A dictionary containing camera enumeration details, or a string with error details if the request fails.
+ """
api_name = 'SYNO.SurveillanceStation.Camera.Import'
info = self.gen_list[api_name]
api_path = info['path']
@@ -407,6 +865,19 @@ def enumerate_camera_from_archive(self,
def enumerate_archive_from_folder(self,
# TODO not working
shareName: str = None) -> dict[str, object] | str:
+ """
+ Enumerate archives from a specified folder in Surveillance Station.
+
+ Parameters
+ ----------
+ shareName : str, optional
+ The name of the shared folder containing the archives.
+
+ Returns
+ -------
+ dict[str, object] or str
+ A dictionary containing archive enumeration details, or a string with error details if the request fails.
+ """
api_name = 'SYNO.SurveillanceStation.Camera.Import'
info = self.gen_list[api_name]
api_path = info['path']
@@ -429,6 +900,33 @@ def check_available_size_of_sdcard(self,
model: str = None,
# TODO not working
ch: str = None) -> dict[str, object] | str:
+ """
+ Check the available size of the SD card for a specific camera.
+
+ Parameters
+ ----------
+ camId : Any, optional
+ The ID of the camera.
+ host : str, optional
+ The host address of the camera.
+ port : str, optional
+ The port number for the camera connection.
+ user : str, optional
+ The username for authentication.
+ passw : str, optional
+ The password for authentication.
+ vendor : str, optional
+ The vendor of the camera.
+ model : str, optional
+ The model of the camera.
+ ch : str, optional
+ The channel identifier. (Currently not working).
+
+ Returns
+ -------
+ dict[str, object] or str
+ A dictionary containing the available size information, or a string with error details.
+ """
api_name = 'SYNO.SurveillanceStation.Camera.Wizard'
info = self.gen_list[api_name]
api_path = info['path']
@@ -446,6 +944,14 @@ def check_available_size_of_sdcard(self,
# TODO not working
def check_licence_quota(self) -> dict[str, object] | str:
+ """
+ Check the license quota for Surveillance Station cameras.
+
+ Returns
+ -------
+ dict[str, object] or str
+ A dictionary containing license quota information, or a string with error details if the request fails.
+ """
api_name = 'SYNO.SurveillanceStation.Camera.Wizard'
info = self.gen_list[api_name]
api_path = info['path']
@@ -464,6 +970,35 @@ def format_specific_sd_card(self,
ch: str = None,
# TODO not working
timeout: int = None) -> dict[str, object] | str:
+ """
+ Format the SD card of a specific camera.
+
+ Parameters
+ ----------
+ camId : Any, optional
+ The ID of the camera whose SD card is to be formatted.
+ host : str, optional
+ The host address of the camera.
+ port : str, optional
+ The port number for the camera connection.
+ user : str, optional
+ The username for authentication.
+ passw : str, optional
+ The password for authentication.
+ vendor : str, optional
+ The vendor of the camera.
+ model : str, optional
+ The model of the camera.
+ ch : str, optional
+ The channel identifier.
+ timeout : int, optional
+ Timeout value for the formatting operation. (Currently not working).
+
+ Returns
+ -------
+ dict[str, object] or str
+ A dictionary containing the result of the format operation, or a string with error details.
+ """
api_name = 'SYNO.SurveillanceStation.Camera.Wizard'
info = self.gen_list[api_name]
api_path = info['path']
@@ -496,6 +1031,47 @@ def quick_create_single_camera(self,
camUserName: str = None,
# TODO to check
camPassWord: str = None) -> dict[str, object] | str:
+ """
+ Quickly create a single camera in Surveillance Station.
+
+ Parameters
+ ----------
+ camServerId : Any, optional
+ The ID of the camera server.
+ actFromHost : bool, optional
+ Whether the action is performed from the host.
+ camStreamingType : str, optional
+ The streaming type of the camera.
+ camName : str, optional
+ The name of the camera.
+ camIP : str, optional
+ The IP address of the camera.
+ camPort : str, optional
+ The port number of the camera.
+ camVendor : str, optional
+ The vendor of the camera.
+ camModel : str, optional
+ The model of the camera.
+ camMountType : int, optional
+ The mount type of the camera.
+ camChannel : str, optional
+ The channel of the camera.
+ camVideoType : str, optional
+ The video type of the camera.
+ camAudioType : str, optional
+ The audio type of the camera.
+ camSourcePath : str, optional
+ The source path for the camera stream.
+ camUserName : str, optional
+ The username for camera authentication.
+ camPassWord : str, optional
+ The password for camera authentication. (To be checked).
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the quick create operation as a dictionary, or a string with error details.
+ """
api_name = 'SYNO.SurveillanceStation.Camera.Wizard'
info = self.gen_list[api_name]
api_path = info['path']
@@ -514,6 +1090,25 @@ def move_camera_lens(self,
speed: int = None,
# TODO not working
moveType: str = None) -> dict[str, object] | str:
+ """
+ Move the camera lens in a specified direction with an optional speed and move type.
+
+ Parameters
+ ----------
+ cameraId : Any, optional
+ The ID of the camera to control.
+ direction : str, optional
+ The direction to move the lens (e.g., 'up', 'down', 'left', 'right').
+ speed : int, optional
+ The speed at which to move the lens.
+ moveType : str, optional
+ The type of movement (reserved for future use, currently not working).
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the move operation as a dictionary, or a string with error details.
+ """
api_name = 'SYNO.SurveillanceStation.PTZ'
info = self.gen_list[api_name]
api_path = info['path']
@@ -531,6 +1126,23 @@ def camera_lens_zoom(self,
control: Any = None,
# TODO not working
moveType: str = None) -> dict[str, object] | str:
+ """
+ Control the zoom function of a camera lens.
+
+ Parameters
+ ----------
+ cameraId : Any, optional
+ The ID of the camera to control.
+ control : Any, optional
+ The zoom control command or value.
+ moveType : str, optional
+ The type of movement (reserved for future use, currently not working).
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the zoom operation as a dictionary, or a string with error details.
+ """
api_name = 'SYNO.SurveillanceStation.PTZ'
info = self.gen_list[api_name]
api_path = info['path']
@@ -548,6 +1160,23 @@ def list_preset_ptz_camera(self,
offset: int = None,
# TODO not working
limit: int = None) -> dict[str, object] | str:
+ """
+ List preset positions for a PTZ (Pan-Tilt-Zoom) camera.
+
+ Parameters
+ ----------
+ cameraId : Any, optional
+ The ID of the PTZ camera to list presets for.
+ offset : int, optional
+ The starting index for the preset list.
+ limit : int, optional
+ The maximum number of presets to return. (Currently not working).
+
+ Returns
+ -------
+ dict[str, object] or str
+ Dictionary containing the list of PTZ presets, or a string with error details.
+ """
api_name = 'SYNO.SurveillanceStation.PTZ'
info = self.gen_list[api_name]
api_path = info['path']
@@ -568,6 +1197,29 @@ def move_camera_lens_to_preset_position(self,
type: Any = None,
# TODO not working
isPatrol: bool = None) -> dict[str, object] | str:
+ """
+ Move the camera lens to a specified preset position.
+
+ Parameters
+ ----------
+ cameraId : Any, optional
+ The ID of the camera to control.
+ presetId : Any, optional
+ The ID of the preset position to move to.
+ position : Any, optional
+ The position value for the preset.
+ speed : Any, optional
+ The speed at which to move the lens.
+ type : Any, optional
+ The type of movement or preset.
+ isPatrol : bool, optional
+ Whether the movement is part of a patrol operation. (Currently not working).
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the move operation as a dictionary, or a string with error details.
+ """
api_name = 'SYNO.SurveillanceStation.PTZ'
info = self.gen_list[api_name]
api_path = info['path']
@@ -585,6 +1237,23 @@ def list_patrol_cameras(self,
offset: int = None,
# TODO not working
limit: int = None) -> dict[str, object] | str:
+ """
+ List patrols for a PTZ (Pan-Tilt-Zoom) camera.
+
+ Parameters
+ ----------
+ cameraId : Any, optional
+ The ID of the PTZ camera to list patrols for.
+ offset : int, optional
+ The starting index for the patrol list.
+ limit : int, optional
+ The maximum number of patrols to return. (Currently not working).
+
+ Returns
+ -------
+ dict[str, object] or str
+ Dictionary containing the list of PTZ patrols, or a string with error details.
+ """
api_name = 'SYNO.SurveillanceStation.PTZ'
info = self.gen_list[api_name]
api_path = info['path']
@@ -601,6 +1270,21 @@ def force_cam_to_execute_patrol(self,
cameraId: Any = None,
# TODO not working
patrolId: Any = None) -> dict[str, object] | str:
+ """
+ Force a camera to execute a specified patrol.
+
+ Parameters
+ ----------
+ cameraId : Any, optional
+ The ID of the camera to execute the patrol.
+ patrolId : Any, optional
+ The ID of the patrol to execute. (Currently not working).
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the patrol execution as a dictionary, or a string with error details.
+ """
api_name = 'SYNO.SurveillanceStation.PTZ'
info = self.gen_list[api_name]
api_path = info['path']
@@ -618,6 +1302,23 @@ def focus_camera(self,
control: Any = None,
# TODO not working
moveType: Any = None) -> dict[str, object] | str:
+ """
+ Control the focus function of a camera.
+
+ Parameters
+ ----------
+ cameraId : Any, optional
+ The ID of the camera to control.
+ control : Any, optional
+ The focus control command or value.
+ moveType : Any, optional
+ The type of movement (reserved for future use, currently not working).
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the focus operation as a dictionary, or a string with error details.
+ """
api_name = 'SYNO.SurveillanceStation.PTZ'
info = self.gen_list[api_name]
api_path = info['path']
@@ -635,6 +1336,23 @@ def control_camera_iris_in_out(self,
control: Any = None,
# TODO not working
moveType: Any = None) -> dict[str, object] | str:
+ """
+ Control the iris (in/out) function of a camera.
+
+ Parameters
+ ----------
+ cameraId : Any, optional
+ The ID of the camera to control.
+ control : Any, optional
+ The iris control command or value.
+ moveType : Any, optional
+ The type of movement (reserved for future use, currently not working).
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the iris control operation as a dictionary, or a string with error details.
+ """
api_name = 'SYNO.SurveillanceStation.PTZ'
info = self.gen_list[api_name]
api_path = info['path']
@@ -649,6 +1367,19 @@ def control_camera_iris_in_out(self,
# TODO not working
def auto_focus(self, cameraId: Any = None) -> dict[str, object] | str:
+ """
+ Perform an auto-focus operation on a specified camera.
+
+ Parameters
+ ----------
+ cameraId : Any, optional
+ The ID of the camera to auto-focus.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the auto-focus operation as a dictionary, or a string with error details.
+ """
api_name = 'SYNO.SurveillanceStation.PTZ'
info = self.gen_list[api_name]
api_path = info['path']
@@ -665,6 +1396,21 @@ def move_cam_lens_to_absolute_position(self,
posX: int = None,
# TODO not working
posY: int = None) -> dict[str, object] | str:
+ """
+ Move the camera lens to an absolute position.
+
+ Parameters
+ ----------
+ posX : int, optional
+ The X coordinate for the absolute position.
+ posY : int, optional
+ The Y coordinate for the absolute position. (Currently not working).
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the move operation as a dictionary, or a string with error details.
+ """
api_name = 'SYNO.SurveillanceStation.PTZ'
info = self.gen_list[api_name]
api_path = info['path']
@@ -680,6 +1426,19 @@ def move_cam_lens_to_absolute_position(self,
def move_cam_to_home_position(self,
# TODO not working
cameraId: Any = None) -> dict[str, object] | str:
+ """
+ Move the camera to its home position.
+
+ Parameters
+ ----------
+ cameraId : Any, optional
+ The ID of the camera to move to the home position. (Currently not working).
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the move operation as a dictionary, or a string with error details.
+ """
api_name = 'SYNO.SurveillanceStation.PTZ'
info = self.gen_list[api_name]
api_path = info['path']
@@ -696,6 +1455,21 @@ def auto_pan_camera(self,
cameraId: Any = None,
# TODO not working
moveType: str = None) -> dict[str, object] | str:
+ """
+ Automatically pan the camera.
+
+ Parameters
+ ----------
+ cameraId : Any, optional
+ The ID of the camera to auto-pan.
+ moveType : str, optional
+ The type of movement (reserved for future use, currently not working).
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the auto-pan operation as a dictionary, or a string with error details.
+ """
api_name = 'SYNO.SurveillanceStation.PTZ'
info = self.gen_list[api_name]
api_path = info['path']
@@ -712,6 +1486,21 @@ def start_stop_object_tracking(self,
cameraId: Any = None,
# TODO not working
moveType: str = None) -> dict[str, object] | str:
+ """
+ Start or stop object tracking for a specified camera.
+
+ Parameters
+ ----------
+ cameraId : Any, optional
+ The ID of the camera to control object tracking.
+ moveType : str, optional
+ The type of movement (reserved for future use, currently not working).
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the object tracking operation as a dictionary, or a string with error details.
+ """
api_name = 'SYNO.SurveillanceStation.PTZ'
info = self.gen_list[api_name]
api_path = info['path']
@@ -728,6 +1517,21 @@ def start_stop_external_recording(self,
cameraId: Any = None,
# TODO not working
action: str = None) -> dict[str, object] | str:
+ """
+ Start or stop external recording for a specified camera.
+
+ Parameters
+ ----------
+ cameraId : Any, optional
+ The ID of the camera to control external recording.
+ action : str, optional
+ The action to perform (e.g., 'start' or 'stop'). (Currently not working).
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the external recording operation as a dictionary, or a string with error details.
+ """
api_name = 'SYNO.SurveillanceStation.ExternalRecording'
info = self.gen_list[api_name]
api_path = info['path']
@@ -748,6 +1552,31 @@ def query_event_list_by_filter(self,
toTime: int = None,
dsld: int = None,
mountId: int = None) -> dict[str, object] | str:
+ """
+ Query the event list by applying various filters.
+
+ Parameters
+ ----------
+ offset : int, optional
+ The starting index for the event list.
+ limit : int, optional
+ The maximum number of events to return.
+ cameraIds : str, optional
+ Comma-separated list of camera IDs to filter events.
+ fromTime : int, optional
+ Start time (timestamp) for filtering events.
+ toTime : int, optional
+ End time (timestamp) for filtering events.
+ dsld : int, optional
+ Device slot ID to filter events.
+ mountId : int, optional
+ Mount ID to filter events.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Dictionary containing the filtered event list, or a string with error details.
+ """
api_name = 'SYNO.SurveillanceStation.Recording'
info = self.gen_list[api_name]
api_path = info['path']
@@ -763,6 +1592,21 @@ def query_event_list_by_filter(self,
def delete_recordings(self,
idList: int = None,
dsld: int = None) -> dict[str, object] | str:
+ """
+ Delete specific recordings from Surveillance Station.
+
+ Parameters
+ ----------
+ idList : int, optional
+ The ID or comma-separated list of IDs of the recordings to delete.
+ dsld : int, optional
+ Device slot ID associated with the recordings.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the delete operation as a dictionary, or a string with error details.
+ """
api_name = 'SYNO.SurveillanceStation.Recording'
info = self.gen_list[api_name]
api_path = info['path']
@@ -788,6 +1632,39 @@ def delete_events_by_filter(self,
from_end: int = None,
# TODO not working
from_start: int = None) -> dict[str, object] | str:
+ """
+ Delete events from Surveillance Station by applying various filters.
+
+ Parameters
+ ----------
+ reason : str, optional
+ The reason for deleting the events.
+ cameraIds : str, optional
+ Comma-separated list of camera IDs to filter events.
+ fromTime : Any, optional
+ Start time (timestamp) for filtering events.
+ toTime : Any, optional
+ End time (timestamp) for filtering events.
+ locked : int, optional
+ Whether to include locked events.
+ evtSrcType : int, optional
+ Event source type.
+ evtSrcId : int, optional
+ Event source ID.
+ blIncludeSnapshot : bool, optional
+ Whether to include snapshots in the deletion.
+ includeAllCam : bool, optional
+ Whether to include all cameras.
+ from_end : int, optional
+ End index for the filter range.
+ from_start : int, optional
+ Start index for the filter range. (Currently not working).
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the delete operation as a dictionary, or a string with error details.
+ """
api_name = 'SYNO.SurveillanceStation.Recording'
info = self.gen_list[api_name]
api_path = info['path']
@@ -802,6 +1679,14 @@ def delete_events_by_filter(self,
# TODO not working
def delete_all_recordings(self) -> dict[str, object] | str:
+ """
+ Delete all recordings from Surveillance Station.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the delete operation as a dictionary, or a string with error details.
+ """
api_name = 'SYNO.SurveillanceStation.Recording'
info = self.gen_list[api_name]
api_path = info['path']
@@ -817,6 +1702,19 @@ def delete_all_recordings(self) -> dict[str, object] | str:
def apply_settings_advance_tab(self,
# TODO not working
rotateUnrecogCam: bool = None) -> dict[str, object] | str:
+ """
+ Apply advanced settings in the Surveillance Station recording tab.
+
+ Parameters
+ ----------
+ rotateUnrecogCam : bool, optional
+ Whether to rotate unrecognized cameras. (Currently not working).
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the apply operation as a dictionary, or a string with error details.
+ """
api_name = 'SYNO.SurveillanceStation.Recording'
info = self.gen_list[api_name]
api_path = info['path']
@@ -842,6 +1740,39 @@ def count_by_number_of_event(self,
blIncludeSnapshot: bool = None,
# TODO not working
includeAllCam: bool = None) -> dict[str, object] | str:
+ """
+ Count the number of events by category, with optional filters.
+
+ Parameters
+ ----------
+ offset : bool, optional
+ Whether to offset the results.
+ limit : int, optional
+ The maximum number of results to return.
+ reason : str, optional
+ The reason for filtering events.
+ cameraIds : str, optional
+ Comma-separated list of camera IDs to filter events.
+ fromTime : int, optional
+ Start time (timestamp) for filtering events.
+ toTime : int, optional
+ End time (timestamp) for filtering events.
+ locked : int, optional
+ Whether to include locked events.
+ evtSrcType : int, optional
+ Event source type.
+ evtSrcId : int, optional
+ Event source ID.
+ blIncludeSnapshot : bool, optional
+ Whether to include snapshots in the count.
+ includeAllCam : bool, optional
+ Whether to include all cameras. (Currently not working).
+
+ Returns
+ -------
+ dict[str, object] or str
+ Dictionary containing the event count by category, or a string with error details.
+ """
api_name = 'SYNO.SurveillanceStation.Recording'
info = self.gen_list[api_name]
api_path = info['path']
@@ -857,6 +1788,14 @@ def count_by_number_of_event(self,
# TODO not working
def keep_event_play_alive(self) -> dict[str, object] | str:
+ """
+ Keep the event play session alive.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the keepalive operation as a dictionary, or a string with error details.
+ """
api_name = 'SYNO.SurveillanceStation.Recording'
info = self.gen_list[api_name]
api_path = info['path']
@@ -872,6 +1811,19 @@ def keep_event_play_alive(self) -> dict[str, object] | str:
def stop_recording_event(self,
# TODO not working
idList: Any = None) -> dict[str, object] | str:
+ """
+ Stop a recording event for the specified event IDs.
+
+ Parameters
+ ----------
+ idList : Any, optional
+ The ID or list of IDs of the events to stop recording. (Currently not working).
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the stop operation as a dictionary, or a string with error details.
+ """
api_name = 'SYNO.SurveillanceStation.Recording'
info = self.gen_list[api_name]
api_path = info['path']
@@ -886,6 +1838,14 @@ def stop_recording_event(self,
# TODO not working
def load_settings_in_advanced_tab(self) -> dict[str, object] | str:
+ """
+ Load settings from the advanced tab in Surveillance Station.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Dictionary containing the advanced settings, or a string with error details.
+ """
api_name = 'SYNO.SurveillanceStation.Recording'
info = self.gen_list[api_name]
api_path = info['path']
@@ -905,8 +1865,45 @@ def lock_selected_event(self,
toTime: int = None,
locked: int = None,
evtSrcType: int = None,
+ evtSrcId: int = None,
+ blIncludeSnapshot: bool = None,
+ includeAllCam: bool = None,
+ from_end: int = None,
# TODO not working
- evtSrcId: int = None) -> dict[str, object] | str:
+ from_start: int = None) -> dict[str, object] | str:
+ """
+ Lock selected events by applying various filters.
+
+ Parameters
+ ----------
+ reason : str, optional
+ The reason for locking the events.
+ cameraIds : str, optional
+ Comma-separated list of camera IDs to filter events.
+ fromTime : int, optional
+ Start time (timestamp) for filtering events.
+ toTime : int, optional
+ End time (timestamp) for filtering events.
+ locked : int, optional
+ Whether to lock the events.
+ evtSrcType : int, optional
+ Event source type.
+ evtSrcId : int, optional
+ Event source ID.
+ blIncludeSnapshot : bool, optional
+ Whether to include snapshots in the lock operation.
+ includeAllCam : bool, optional
+ Whether to include all cameras.
+ from_end : int, optional
+ End index for the filter range.
+ from_start : int, optional
+ Start index for the filter range. (Currently not working).
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the lock operation as a dictionary, or a string with error details.
+ """
api_name = 'SYNO.SurveillanceStation.Recording'
info = self.gen_list[api_name]
api_path = info['path']
@@ -923,6 +1920,21 @@ def unlock_selected_event(self,
idList: str = None,
# TODO not working
dsld: int = None) -> dict[str, object] | str:
+ """
+ Unlock selected events by their IDs.
+
+ Parameters
+ ----------
+ idList : str, optional
+ Comma-separated list of event IDs to unlock.
+ dsld : int, optional
+ Device slot ID associated with the events. (Currently not working).
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the unlock operation as a dictionary, or a string with error details.
+ """
api_name = 'SYNO.SurveillanceStation.Recording'
info = self.gen_list[api_name]
api_path = info['path']
@@ -944,6 +1956,31 @@ def unlock_selected_filter_event(self,
evtSrcType: int = None,
# TODO not working
evtSrcId: int = None) -> dict[str, object] | str:
+ """
+ Unlock events by applying various filters.
+
+ Parameters
+ ----------
+ reason : str, optional
+ The reason for unlocking the events.
+ cameraIds : str, optional
+ Comma-separated list of camera IDs to filter events.
+ fromTime : int, optional
+ Start time (timestamp) for filtering events.
+ toTime : int, optional
+ End time (timestamp) for filtering events.
+ locked : int, optional
+ Whether to unlock only locked events.
+ evtSrcType : int, optional
+ Event source type.
+ evtSrcId : int, optional
+ Event source ID. (Currently not working).
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the unlock operation as a dictionary, or a string with error details.
+ """
api_name = 'SYNO.SurveillanceStation.Recording'
info = self.gen_list[api_name]
api_path = info['path']
@@ -959,6 +1996,21 @@ def unlock_selected_filter_event(self,
def lock_selected_recordings(self,
idList: str = None,
dsld: int = None) -> dict[str, object] | str:
+ """
+ Lock selected recordings by their IDs.
+
+ Parameters
+ ----------
+ idList : str, optional
+ Comma-separated list of recording IDs to lock.
+ dsld : int, optional
+ Device slot ID associated with the recordings.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the lock operation as a dictionary, or a string with error details.
+ """
api_name = 'SYNO.SurveillanceStation.Recording'
info = self.gen_list[api_name]
api_path = info['path']
@@ -976,6 +2028,25 @@ def download_recordings(self,
mountId: int = None,
offsetTimeMs: int = None,
playTimeMs: int = None) -> dict[str, object] | str:
+ """
+ Download recordings by specifying recording ID and optional parameters.
+
+ Parameters
+ ----------
+ id : int, optional
+ The ID of the recording to download.
+ mountId : int, optional
+ The mount ID associated with the recording.
+ offsetTimeMs : int, optional
+ Offset time in milliseconds for the download.
+ playTimeMs : int, optional
+ Playback time in milliseconds for the download.
+
+ Returns
+ -------
+ dict[str, object] or str
+ The downloaded recording as a binary response, or a string with error details.
+ """
api_name = 'SYNO.SurveillanceStation.Recording'
info = self.gen_list[api_name]
api_path = info['path']
@@ -994,6 +2065,25 @@ def check_if_recording_playable(self,
mountId: int = None,
# TODO not working
dsld: int = None) -> dict[str, object] | str:
+ """
+ Check if a recording is playable by event ID and optional parameters.
+
+ Parameters
+ ----------
+ eventId : int, optional
+ The event ID of the recording to check.
+ chkDetail : bool, optional
+ Whether to check detailed information.
+ mountId : int, optional
+ The mount ID associated with the recording.
+ dsld : int, optional
+ Device slot ID. (Currently not working).
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the check as a dictionary, or a string with error details.
+ """
api_name = 'SYNO.SurveillanceStation.Recording'
info = self.gen_list[api_name]
api_path = info['path']
@@ -1014,6 +2104,27 @@ def play_specific_recording(self,
dsld: int = None,
# TODO not working
videoCodec: int = None) -> dict[str, object] | str:
+ """
+ Stream a specific recording from Surveillance Station.
+
+ Parameters
+ ----------
+ recordingId : int, optional
+ The ID of the recording to play.
+ alertRecording : bool, optional
+ Whether the recording is an alert recording.
+ mountId : int, optional
+ The mount ID associated with the recording.
+ dsld : int, optional
+ Device slot ID.
+ videoCodec : int, optional
+ Video codec to use for streaming. (Currently not working).
+
+ Returns
+ -------
+ dict[str, object] or str
+ Streaming information or error details.
+ """
api_name = 'SYNO.SurveillanceStation.Recording'
info = self.gen_list[api_name]
api_path = info['path']
@@ -1032,17 +2143,33 @@ def download_merged_recording_files(self,
toTime: int = None,
# TODO not working
fileName: str = None) -> dict[str, object] | str:
- """Download the merged files of UTC time range recordings of target camera.
- If there are different resolution or codec within UTC time range, the recordings will merge as much as possible
- and downlod file will be a zip file.
-
- This method will start a task which have keep-alive mechanism.
- Use GetRangeExportProgress method to get newest progress and keep-alive.
- After receiving progress 100, use OnRangeExportDone method to download exported recording within 1
- minutes.
- If you want to cancel range export task, just do not send GetRangeExportProgress method or
- OnRangeExportDone method. System will cleanup processed files itself."""
-
+ """
+ Download merged files of recordings within a UTC time range for a target camera.
+
+ If there are different resolutions or codecs within the time range, recordings will be merged as much as possible,
+ and the download file will be a zip file.
+
+ This method starts a task with a keep-alive mechanism.
+ Use GetRangeExportProgress to get the latest progress and keep-alive.
+ After receiving progress 100, use OnRangeExportDone to download the exported recording within 1 minute.
+ To cancel the export task, do not send GetRangeExportProgress or OnRangeExportDone; the system will clean up processed files.
+
+ Parameters
+ ----------
+ camId : int, optional
+ The camera ID to export recordings from.
+ fromTime : int, optional
+ Start UTC timestamp for the export range.
+ toTime : int, optional
+ End UTC timestamp for the export range.
+ fileName : str, optional
+ Name of the output file. (Currently not working).
+
+ Returns
+ -------
+ dict[str, object] or str
+ Task information for the export or error details.
+ """
api_name = 'SYNO.SurveillanceStation.Recording'
info = self.gen_list[api_name]
api_path = info['path']
@@ -1057,6 +2184,19 @@ def download_merged_recording_files(self,
# TODO not working
def get_newest_progress_keep_alive(self, dlid: int = None) -> dict[str, object] | str:
+ """
+ Get the latest progress of a range export task and keep the task alive.
+
+ Parameters
+ ----------
+ dlid : int, optional
+ The download task ID.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Progress information or error details.
+ """
api_name = 'SYNO.SurveillanceStation.Recording'
info = self.gen_list[api_name]
api_path = info['path']
@@ -1074,21 +2214,36 @@ def download_recording_from_target(self,
dlid: int = None,
# TODO not working
fileName: str = None) -> dict[str, object] | str:
- """Response
- MP4 or zip file data.
- The response type can be found in fileExt of GetRangeExportProgress method response when progress 100.
-
- Note
- GetRangeExportProgress method must be sent within 1 minute after corresponding RangeExport method task
- is completed, otherwise the exported recordings will be cleared.
-
- 2.3.11.20 API Error Code
- Code Description
- 400 Execution failed.
- 401 Parameter invalid.
- 405 CMS server connection failed.
- 414 Some events not exist.
- 439 Too many items selected."""
+ """
+ Download the exported recording file from a completed range export task.
+
+ Parameters
+ ----------
+ dlid : int, optional
+ The download task ID.
+ fileName : str, optional
+ Name of the file to download. (Currently not working).
+
+ Returns
+ -------
+ dict[str, object] or str
+ Downloaded file data or error details.
+
+ Notes
+ -----
+ GetRangeExportProgress must be called within 1 minute after the corresponding RangeExport task is completed,
+ otherwise the exported recordings will be cleared.
+
+ Response: Returns MP4 or zip file data. The response type can be found in the fileExt field of the GetRangeExportProgress
+ response when progress is 100.
+
+ API Error Codes:
+ 400 : Execution failed.
+ 401 : Parameter invalid.
+ 405 : CMS server connection failed.
+ 414 : Some events do not exist.
+ 439 : Too many items selected.
+ """
api_name = 'SYNO.SurveillanceStation.Recording'
info = self.gen_list[api_name]
@@ -1106,6 +2261,21 @@ def download_recording_from_target(self,
def handle_load_event_export(self,
start: int = None,
limit: bool = None) -> dict[str, object] | str:
+ """
+ Load exported event recordings with optional pagination.
+
+ Parameters
+ ----------
+ start : int, optional
+ The starting index for loading events.
+ limit : bool, optional
+ The maximum number of events to load.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Exported event information or error details.
+ """
api_name = 'SYNO.SurveillanceStation.Recording.Export'
info = self.gen_list[api_name]
api_path = info['path']
@@ -1122,6 +2292,23 @@ def check_name_export_event(self,
dsId: int = None,
name: int = None,
share: str = None) -> dict[str, object] | str:
+ """
+ Check if an export event name is valid or already exists.
+
+ Parameters
+ ----------
+ dsId : int, optional
+ The data source ID.
+ name : int, optional
+ The name to check for the export event.
+ share : str, optional
+ The share name associated with the export event.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the name check or error details.
+ """
api_name = 'SYNO.SurveillanceStation.Recording.Export'
info = self.gen_list[api_name]
api_path = info['path']
@@ -1136,6 +2323,19 @@ def check_name_export_event(self,
def get_camera_information_list(self,
dslld: int = None) -> dict[str, object] | str:
+ """
+ Retrieve the list of camera information for event export.
+
+ Parameters
+ ----------
+ dslld : int, optional
+ The ID of the data source (recording server) to query cameras from.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Camera information list or error details.
+ """
api_name = 'SYNO.SurveillanceStation.Recording.Export'
info = self.gen_list[api_name]
api_path = info['path']
@@ -1153,6 +2353,25 @@ def check_destination_folder_availability(self,
startTime: int = None,
stopTime: int = None,
camIdList: str = None) -> dict[str, object] | str:
+ """
+ Check if the destination folder has enough available space for export.
+
+ Parameters
+ ----------
+ freeSize : int, optional
+ Required free size in bytes.
+ startTime : int, optional
+ Start time of the export range (UTC timestamp).
+ stopTime : int, optional
+ End time of the export range (UTC timestamp).
+ camIdList : str, optional
+ Comma-separated list of camera IDs to check.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Availability information or error details.
+ """
api_name = 'SYNO.SurveillanceStation.Recording.Export'
info = self.gen_list[api_name]
api_path = info['path']
@@ -1176,6 +2395,35 @@ def handle_save_event_export(self,
stop_time: int = None,
isoverwrite: int = None,
camlistid: str = None) -> dict[str, object] | str:
+ """
+ Save an event export task with the specified parameters.
+
+ Parameters
+ ----------
+ name : str, optional
+ Name of the export task.
+ srcDsId : int, optional
+ Source data source ID.
+ dstDsId : int, optional
+ Destination data source ID.
+ dstdir : str, optional
+ Destination directory for export.
+ freesize : int, optional
+ Required free size in bytes.
+ start_time : int, optional
+ Start time of the export range (UTC timestamp).
+ stop_time : int, optional
+ End time of the export range (UTC timestamp).
+ isoverwrite : int, optional
+ Whether to overwrite existing files (1 for true, 0 for false).
+ camlistid : str, optional
+ Comma-separated list of camera IDs to export.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the save operation or error details.
+ """
api_name = 'SYNO.SurveillanceStation.Recording.Export'
info = self.gen_list[api_name]
api_path = info['path']
@@ -1192,6 +2440,23 @@ def get_event_export_info_from_recording_server(self,
start_time: int = None,
stop_time: int = None,
camlistid: str = None) -> dict[str, object] | str:
+ """
+ Retrieve event export information from the recording server.
+
+ Parameters
+ ----------
+ start_time : int, optional
+ Start time of the export range (UTC timestamp).
+ stop_time : int, optional
+ End time of the export range (UTC timestamp).
+ camlistid : str, optional
+ Comma-separated list of camera IDs.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Export information or error details.
+ """
api_name = 'SYNO.SurveillanceStation.Recording.Export'
info = self.gen_list[api_name]
api_path = info['path']
@@ -1205,6 +2470,14 @@ def get_event_export_info_from_recording_server(self,
return self.request_data(api_name, api_path, req_param)
def load_event_mount(self) -> dict[str, object] | str:
+ """
+ Load event mount information for export.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Mount information or error details.
+ """
api_name = 'SYNO.SurveillanceStation.Recording.Mount'
info = self.gen_list[api_name]
api_path = info['path']
@@ -1221,12 +2494,25 @@ def redirect_webapi_to_target_ds(self,
dsId: int = None,
# TODO not working
webAPI: Any = None) -> dict[str, object] | str:
- """webAPI Array of `webAPI_info`
-
- Example:
- `webAPI={"api": "SYNO.SurveillanceStation.AddOns", "version": 1, "method":
- "List"}` """
-
+ """
+ Redirect a WebAPI request to a target DiskStation.
+
+ Parameters
+ ----------
+ dsId : int, optional
+ Target DiskStation ID.
+ webAPI : Any, optional
+ WebAPI information to redirect (array of webAPI_info).
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the redirect operation or error details.
+
+ Examples
+ --------
+ webAPI={"api": "SYNO.SurveillanceStation.AddOns", "version": 1, "method": "List"}
+ """
api_name = 'SYNO.SurveillanceStation.CMS'
info = self.gen_list[api_name]
api_path = info['path']
@@ -1243,6 +2529,21 @@ def modify_share_privilege(self,
privSet: int = None,
# TODO not working
shareName: str = None) -> dict[str, object] | str:
+ """
+ Modify the share privilege settings in Surveillance Station CMS.
+
+ Parameters
+ ----------
+ privSet : int, optional
+ Privilege set value.
+ shareName : str, optional
+ Name of the share to modify.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the privilege modification or error details.
+ """
api_name = 'SYNO.SurveillanceStation.CMS'
info = self.gen_list[api_name]
api_path = info['path']
@@ -1264,6 +2565,31 @@ def apply_option_settings(self,
nvr_enable: bool = None,
# TODO not working
nvr_lang: str = None) -> dict[str, object] | str:
+ """
+ Apply option settings for Surveillance Station CMS.
+
+ Parameters
+ ----------
+ central_auto_video_relay : bool, optional
+ Enable or disable central auto video relay.
+ central_enable : bool, optional
+ Enable or disable central management.
+ central_mode : str, optional
+ Set the central management mode.
+ central_rec_mask_mode : bool, optional
+ Enable or disable central recording mask mode.
+ central_rec_sync_time : bool, optional
+ Enable or disable central recording time synchronization.
+ nvr_enable : bool, optional
+ Enable or disable NVR.
+ nvr_lang : str, optional
+ Set the NVR language. (Currently not working).
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the apply operation or error details.
+ """
api_name = 'SYNO.SurveillanceStation.CMS'
info = self.gen_list[api_name]
api_path = info['path']
@@ -1279,6 +2605,19 @@ def apply_option_settings(self,
def get_cms_info(self,
# TODO not working
isPolling: bool = None) -> dict[str, object] | str:
+ """
+ Retrieve CMS (Central Management System) information.
+
+ Parameters
+ ----------
+ isPolling : bool, optional
+ Whether to poll for CMS information. (Currently not working).
+
+ Returns
+ -------
+ dict[str, object] or str
+ CMS information or error details.
+ """
api_name = 'SYNO.SurveillanceStation.CMS'
info = self.gen_list[api_name]
api_path = info['path']
@@ -1296,6 +2635,23 @@ def get_log_recording_data_from_target_ds(self,
syncTargetId: int = None,
# TODO not working
limit: int = None) -> dict[str, object] | str:
+ """
+ Retrieve log recording data from a target DiskStation.
+
+ Parameters
+ ----------
+ syncType : int, optional
+ Type of synchronization.
+ syncTargetId : int, optional
+ ID of the target DiskStation for synchronization.
+ limit : int, optional
+ Limit the number of records returned. (Currently not working).
+
+ Returns
+ -------
+ dict[str, object] or str
+ Log recording data or error details.
+ """
api_name = 'SYNO.SurveillanceStation.CMS'
info = self.gen_list[api_name]
api_path = info['path']
@@ -1309,6 +2665,14 @@ def get_log_recording_data_from_target_ds(self,
return self.request_data(api_name, api_path, req_param)
def get_samba_service(self) -> dict[str, object] | str: # TODO not working
+ """
+ Check if the Samba service is enabled on the CMS.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Samba service status or error details.
+ """
api_name = 'SYNO.SurveillanceStation.CMS'
info = self.gen_list[api_name]
api_path = info['path']
@@ -1319,6 +2683,14 @@ def get_samba_service(self) -> dict[str, object] | str: # TODO not working
# TODO not working
def check_if_samba_on_and_rec_enabled(self) -> dict[str, object] | str:
+ """
+ Check if Samba is enabled and recording is enabled on the CMS.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Status of Samba and recording or error details.
+ """
api_name = 'SYNO.SurveillanceStation.CMS'
info = self.gen_list[api_name]
api_path = info['path']
@@ -1329,6 +2701,19 @@ def check_if_samba_on_and_rec_enabled(self) -> dict[str, object] | str:
def get_encoded_single_image_of_camera(self,
camId: int = None) -> dict[str, object] | str:
+ """
+ Retrieve an encoded single image (snapshot) from a specified camera.
+
+ Parameters
+ ----------
+ camId : int, optional
+ ID of the camera to get the snapshot from.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Encoded image data or error details.
+ """
api_name = 'SYNO.SurveillanceStation.CMS'
info = self.gen_list[api_name]
api_path = info['path']
@@ -1344,6 +2729,19 @@ def get_encoded_single_image_of_camera(self,
def get_cms_status(self,
# TODO not working
camId: int = None) -> dict[str, object] | str:
+ """
+ Retrieve the status of the CMS.
+
+ Parameters
+ ----------
+ camId : int, optional
+ ID of the camera to check status for. (Currently not working).
+
+ Returns
+ -------
+ dict[str, object] or str
+ CMS status or error details.
+ """
api_name = 'SYNO.SurveillanceStation.CMS'
info = self.gen_list[api_name]
api_path = info['path']
@@ -1358,6 +2756,14 @@ def get_cms_status(self,
# TODO not working
def enable_smb_service(self) -> dict[str, object] | str:
+ """
+ Enable the Samba service on the CMS.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the enable operation or error details.
+ """
api_name = 'SYNO.SurveillanceStation.CMS'
info = self.gen_list[api_name]
api_path = info['path']
@@ -1367,6 +2773,14 @@ def enable_smb_service(self) -> dict[str, object] | str:
# TODO not working
def notify_slave_ds_to_disconnect(self) -> dict[str, object] | str:
+ """
+ Notify a slave DiskStation to disconnect from the CMS.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the notification or error details.
+ """
api_name = 'SYNO.SurveillanceStation.CMS'
info = self.gen_list[api_name]
api_path = info['path']
@@ -1377,6 +2791,19 @@ def notify_slave_ds_to_disconnect(self) -> dict[str, object] | str:
def lock_recording_server_prevent_setting_change(self,
# TODO not working
locked: bool = None) -> dict[str, object] | str:
+ """
+ Lock the recording server to prevent setting changes.
+
+ Parameters
+ ----------
+ locked : bool, optional
+ Whether to lock the server. (Currently not working).
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the lock operation or error details.
+ """
api_name = 'SYNO.SurveillanceStation.CMS'
info = self.gen_list[api_name]
api_path = info['path']
@@ -1394,6 +2821,25 @@ def enable_ds_into_recording_server(self,
adminPasswd: str = None,
central_rec_mask_mode: str = None,
central_rec_sync_time: str = None) -> dict[str, object] | str:
+ """
+ Enable a DiskStation as a recording server in the CMS.
+
+ Parameters
+ ----------
+ adminUsername : str, optional
+ Administrator username.
+ adminPasswd : str, optional
+ Administrator password.
+ central_rec_mask_mode : str, optional
+ Central recording mask mode.
+ central_rec_sync_time : str, optional
+ Central recording synchronization time.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the enable operation or error details.
+ """
api_name = 'SYNO.SurveillanceStation.CMS.GetDsStatus'
info = self.gen_list[api_name]
api_path = info['path']
@@ -1411,6 +2857,25 @@ def unpair_recording_servers(self,
key: str = None,
mac: str = None,
cmsMode: int = None) -> dict[str, object] | str:
+ """
+ Unpair recording servers from the CMS.
+
+ Parameters
+ ----------
+ adminUsername : str, optional
+ Administrator username.
+ key : str, optional
+ Key for unpairing.
+ mac : str, optional
+ MAC address of the server.
+ cmsMode : int, optional
+ CMS mode.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the unpair operation or error details.
+ """
api_name = 'SYNO.SurveillanceStation.CMS.GetDsStatus'
info = self.gen_list[api_name]
api_path = info['path']
@@ -1424,6 +2889,14 @@ def unpair_recording_servers(self,
return self.request_data(api_name, api_path, req_param)
def get_free_memory_size(self) -> dict[str, object] | str:
+ """
+ Retrieve the free memory size from the target DiskStation.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Free memory size information or error details.
+ """
api_name = 'SYNO.SurveillanceStation.CMS.GetDsStatus'
info = self.gen_list[api_name]
api_path = info['path']
@@ -1438,6 +2911,27 @@ def handle_slave_ds(self,
mac: str = None,
# TODO to check
masterAuthKey: str = None) -> dict[str, object] | str:
+ """
+ Handle slave DiskStation operations such as locking or authentication.
+
+ Parameters
+ ----------
+ lock : bool, optional
+ Whether to lock the slave DiskStation.
+ adminUsername : str, optional
+ Administrator username.
+ key : str, optional
+ Authentication key.
+ mac : str, optional
+ MAC address of the slave DiskStation.
+ masterAuthKey : str, optional
+ Master authentication key. (To check).
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the operation or error details.
+ """
api_name = 'SYNO.SurveillanceStation.CMS.GetDsStatus'
info = self.gen_list[api_name]
api_path = info['path']
@@ -1452,6 +2946,19 @@ def handle_slave_ds(self,
def get_target_ds_info(self,
slaveDslp: str = None) -> dict[str, object] | str:
+ """
+ Retrieve information about the target slave DiskStation.
+
+ Parameters
+ ----------
+ slaveDslp : str, optional
+ Slave DiskStation IP or identifier.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Target DiskStation information or error details.
+ """
api_name = 'SYNO.SurveillanceStation.CMS.GetDsStatus'
info = self.gen_list[api_name]
api_path = info['path']
@@ -1468,6 +2975,23 @@ def logout_slave_ds(self,
adminUsername: str = None,
key: str = None,
mac: str = None) -> dict[str, object] | str:
+ """
+ Log out a slave DiskStation from the CMS.
+
+ Parameters
+ ----------
+ adminUsername : str, optional
+ Administrator username.
+ key : str, optional
+ Authentication key.
+ mac : str, optional
+ MAC address of the slave DiskStation.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the logout operation or error details.
+ """
api_name = 'SYNO.SurveillanceStation.CMS.GetDsStatus'
info = self.gen_list[api_name]
api_path = info['path']
@@ -1491,6 +3015,35 @@ def pair_slave_ds(self,
cms_masked: bool = None,
# TODO not working
cms_sync_time: bool = None) -> dict[str, object] | str:
+ """
+ Pair a slave DiskStation with the CMS.
+
+ Parameters
+ ----------
+ dsname : str, optional
+ Name of the slave DiskStation.
+ slaveDslp : str, optional
+ Slave DiskStation IP or identifier.
+ port : int, optional
+ Port number for connection.
+ masterAuthKey : str, optional
+ Master authentication key.
+ model : str, optional
+ Model of the slave DiskStation.
+ mac : str, optional
+ MAC address of the slave DiskStation.
+ cms_locked : bool, optional
+ Whether the CMS is locked.
+ cms_masked : bool, optional
+ Whether the CMS is masked.
+ cms_sync_time : bool, optional
+ Synchronize time with CMS. (Currently not working).
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the pairing operation or error details.
+ """
api_name = 'SYNO.SurveillanceStation.CMS.GetDsStatus'
info = self.gen_list[api_name]
api_path = info['path']
@@ -1518,11 +3071,51 @@ def login_slave_ds(self,
cms_masked: bool = None,
# TODO not working
cms_sync_time: bool = None) -> dict[str, object] | str:
- """2.3.15.9 API Error Code
+ """
+ Log in a slave DiskStation to the CMS.
+
+ Parameters
+ ----------
+ adminUsername : str, optional
+ Administrator username.
+ key : str, optional
+ Authentication key.
+ mac : str, optional
+ MAC address of the slave DiskStation.
+ masterAuthKey : str, optional
+ Master authentication key.
+ hostName : str, optional
+ Hostname of the slave DiskStation.
+ hostPort : int, optional
+ Port number for connection.
+ ignoreAuthError : str, optional
+ Ignore authentication errors.
+ hostDisconnect : bool, optional
+ Whether to disconnect the host.
+ blUpdateVolSpace : bool, optional
+ Update volume space information.
+ enable_rec : bool, optional
+ Enable recording.
+ cms_locked : bool, optional
+ Whether the CMS is locked.
+ cms_masked : bool, optional
+ Whether the CMS is masked.
+ cms_sync_time : bool, optional
+ Synchronize time with CMS. (Currently not working).
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the login operation or error details.
+
+ Notes
+ -----
+ 2.3.15.9 API Error Code
Code Description
400 Execution failed.
401 Invalid parameter.
- 415 message connect failed. """
+ 415 message connect failed.
+ """
api_name = 'SYNO.SurveillanceStation.CMS.GetDsStatus'
info = self.gen_list[api_name]
@@ -1552,6 +3145,45 @@ def save_slave_ds(self,
cms_masked: bool = None,
# TODO not working
cms_sync_time: bool = None) -> dict[str, object] | str:
+ """
+ Save or update a slave DiskStation's configuration in the CMS.
+
+ Parameters
+ ----------
+ slavedsName : str, optional
+ Name of the slave DiskStation.
+ slavedsModel : str, optional
+ Model of the slave DiskStation.
+ slavedsPort : int, optional
+ Port number used by the slave DiskStation.
+ slavedsVersion : str, optional
+ Version of the slave DiskStation.
+ slavedsMaxCamNum : int, optional
+ Maximum number of cameras supported by the slave DiskStation.
+ slavedsId : str, optional
+ Identifier for the slave DiskStation.
+ slavedsIP : str, optional
+ IP address of the slave DiskStation.
+ slavedsEnable : int, optional
+ Enable status of the slave DiskStation.
+ slavedsCamCnt : bool, optional
+ Number of cameras currently connected to the slave DiskStation.
+ adminUsername : str, optional
+ Administrator username for authentication.
+ adminPasswd : str, optional
+ Administrator password for authentication.
+ cms_locked : bool, optional
+ Whether the CMS is locked.
+ cms_masked : bool, optional
+ Whether the CMS is masked.
+ cms_sync_time : bool, optional
+ Synchronize time with CMS. (Currently not working).
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the save operation or error details.
+ """
api_name = 'SYNO.SurveillanceStation.CMS.GetDsStatus'
info = self.gen_list[api_name]
api_path = info['path']
@@ -1570,6 +3202,27 @@ def load_slave_ds_list(self,
blRuntimeInfo: bool = None,
dslds: str = None,
sortInfo: int = None) -> dict[str, object] | str:
+ """
+ Load the list of slave DiskStations from the CMS.
+
+ Parameters
+ ----------
+ blNeedStatus : bool, optional
+ Whether to include status information.
+ blGetSortInfo : bool, optional
+ Whether to include sorting information.
+ blRuntimeInfo : bool, optional
+ Whether to include runtime information.
+ dslds : str, optional
+ Comma-separated list of DiskStation IDs to load.
+ sortInfo : int, optional
+ Sorting information.
+
+ Returns
+ -------
+ dict[str, object] or str
+ List of slave DiskStations or error details.
+ """
api_name = 'SYNO.SurveillanceStation.CMS.SlavedsList'
info = self.gen_list[api_name]
api_path = info['path']
@@ -1597,6 +3250,45 @@ def count_number_of_logs(self,
dsId: str = None,
srcType: int = None,
timezoneOffset: int = None) -> dict[str, object] | str:
+ """
+ Count the number of logs in Surveillance Station based on various filters.
+
+ Parameters
+ ----------
+ slavedsName : str, optional
+ Name of the slave DiskStation.
+ start : int, optional
+ Start index for pagination.
+ limit : int, optional
+ Maximum number of logs to count.
+ level : str, optional
+ Log level filter.
+ filterCamera : str, optional
+ Filter by camera.
+ cameraIds : str, optional
+ Comma-separated list of camera IDs.
+ dsfrom : int, optional
+ Start time (timestamp).
+ to : int, optional
+ End time (timestamp).
+ keyword : str, optional
+ Keyword to search in logs.
+ keywordDsId : str, optional
+ DiskStation ID for keyword search.
+ time2String : str, optional
+ Time string for filtering.
+ dsId : str, optional
+ DiskStation ID.
+ srcType : int, optional
+ Source type filter.
+ timezoneOffset : int, optional
+ Timezone offset.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Count of logs or error details.
+ """
api_name = 'SYNO.SurveillanceStation.Log'
info = self.gen_list[api_name]
api_path = info['path']
@@ -1606,10 +3298,7 @@ def count_number_of_logs(self,
for key, val in locals().items():
if key not in ['self', 'api_name', 'info', 'api_path', 'req_param']:
if val is not None:
- if key == 'dsfrom':
- req_param[str('from')] = val
- else:
- req_param[str(key)] = val
+ req_param[str(key)] = val
return self.request_data(api_name, api_path, req_param)
@@ -1625,6 +3314,39 @@ def clear_selected_logs(self,
keywordDsId: str = None,
srcType: int = None,
timezoneOffset: int = None) -> dict[str, object] | str:
+ """
+ Clear selected logs from Surveillance Station based on various filters.
+
+ Parameters
+ ----------
+ blClearAll : bool, optional
+ Whether to clear all logs.
+ level : int, optional
+ Log level filter.
+ dsId : int, optional
+ DiskStation ID.
+ filterCamera : str, optional
+ Filter by camera.
+ cameraIds : str, optional
+ Comma-separated list of camera IDs.
+ dsfrom : int, optional
+ Start time (timestamp).
+ to : int, optional
+ End time (timestamp).
+ keyword : str, optional
+ Keyword to search in logs.
+ keywordDsId : str, optional
+ DiskStation ID for keyword search.
+ srcType : int, optional
+ Source type filter.
+ timezoneOffset : int, optional
+ Timezone offset.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the clear operation or error details.
+ """
api_name = 'SYNO.SurveillanceStation.Log'
info = self.gen_list[api_name]
api_path = info['path']
@@ -1656,6 +3378,47 @@ def get_information_log(self,
all: bool = None,
blIncludeRecCnt: str = None,
blIncludeAuInfo: str = None) -> dict[str, object] | str:
+ """
+ Retrieve information logs from Surveillance Station based on various filters.
+
+ Parameters
+ ----------
+ start : int, optional
+ Start index for pagination.
+ limit : int, optional
+ Maximum number of logs to retrieve.
+ level : str, optional
+ Log level filter.
+ filterCamera : str, optional
+ Filter by camera.
+ cameraIds : str, optional
+ Comma-separated list of camera IDs.
+ dsfrom : int, optional
+ Start time (timestamp).
+ to : int, optional
+ End time (timestamp).
+ keyword : str, optional
+ Keyword to search in logs.
+ keywordDsId : str, optional
+ DiskStation ID for keyword search.
+ time2String : str, optional
+ Time string for filtering.
+ dsId : int, optional
+ DiskStation ID.
+ srcType : int, optional
+ Source type filter.
+ all : bool, optional
+ Whether to retrieve all logs.
+ blIncludeRecCnt : str, optional
+ Include recording count information.
+ blIncludeAuInfo : str, optional
+ Include additional information.
+
+ Returns
+ -------
+ dict[str, object] or str
+ List of information logs or error details.
+ """
api_name = 'SYNO.SurveillanceStation.Log'
info = self.gen_list[api_name]
api_path = info['path']
@@ -1672,6 +3435,14 @@ def get_information_log(self,
return self.request_data(api_name, api_path, req_param)
def get_advanced_settings_logs(self) -> dict[str, object] | str:
+ """
+ Retrieve advanced log settings from Surveillance Station.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Advanced log settings or error details.
+ """
api_name = 'SYNO.SurveillanceStation.Log'
info = self.gen_list[api_name]
api_path = info['path']
@@ -1681,6 +3452,21 @@ def get_advanced_settings_logs(self) -> dict[str, object] | str:
def set_advanced_setting_logs(self,
data: Any = None) -> dict[str, object] | str:
+ """
+ Set advanced log settings in Surveillance Station.
+
+ Parameters
+ ----------
+ data : Any, optional
+ List of log type settings to apply.
+ Example:
+ data=\\[\\{"SSLogType":321912835,"enable":1\\},\\{"SSLogType":321912836,"enable":0\\}\\]
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the set operation or error details.
+ """
api_name = 'SYNO.SurveillanceStation.Log'
info = self.gen_list[api_name]
api_path = info['path']
@@ -1696,6 +3482,19 @@ def set_advanced_setting_logs(self,
def load_license_data(self,
# TODO not working
num_only: int = None) -> dict[str, object] | str:
+ """
+ Load license data from Surveillance Station.
+
+ Parameters
+ ----------
+ num_only : int, optional
+ If set, only the number of licenses will be returned.
+
+ Returns
+ -------
+ dict[str, object] or str
+ License data or error details.
+ """
api_name = 'SYNO.SurveillanceStation.License'
info = self.gen_list[api_name]
api_path = info['path']
@@ -1708,6 +3507,23 @@ def check_license_quota(self,
camList: Any = None,
# TODO not working
camServerId: int = None) -> dict[str, object] | str:
+ """
+ Check the license quota for cameras in Surveillance Station.
+
+ Parameters
+ ----------
+ camList : Any, optional
+ List of camera information dictionaries.
+ Example:
+ camList = \\[\\{"ip": "10.13.22.141", "model": "DCS-3110", "vendor": "DLink", "port": 80\\}\\]
+ camServerId : int, optional
+ Camera server ID.
+
+ Returns
+ -------
+ dict[str, object] or str
+ License quota information or error details.
+ """
api_name = 'SYNO.SurveillanceStation.License'
info = self.gen_list[api_name]
api_path = info['path']
@@ -1728,6 +3544,23 @@ def get_http_video_stream(self,
writeHeader: bool = None,
analyevent: bool = None,
mountId: int = None) -> dict[str, object] | str:
+ """
+ Retrieve an HTTP video event stream from Surveillance Station.
+
+ Parameters
+ ----------
+ writeHeader : bool, optional
+ Whether to include headers in the stream.
+ analyevent : bool, optional
+ Whether to analyze events in the stream.
+ mountId : int, optional
+ Mount ID for the stream.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Video stream data or error details.
+ """
api_name = 'SYNO.SurveillanceStation.Stream'
info = self.gen_list[api_name]
api_path = info['path']
@@ -1767,6 +3600,67 @@ def save_action_rule(self,
userName: str = None,
# TODO not working
password: str = None) -> dict[str, object] | str:
+ """
+ Save or update an action rule in Surveillance Station.
+
+ Parameters
+ ----------
+ id : int, optional
+ Action rule ID.
+ name : str, optional
+ Name of the action rule.
+ ruleType : int, optional
+ Type of the rule.
+ actType : int, optional
+ Action type.
+ evtSrc : int, optional
+ Event source.
+ evtDsId : int, optional
+ Event DiskStation ID.
+ evtDevId : int, optional
+ Event device ID.
+ evtId : int, optional
+ Event ID.
+ evtItem : int, optional
+ Event item.
+ evtMinIntvl : int, optional
+ Minimum interval between events.
+ Actions : Any, optional
+ List of actions to perform.
+ actSchedule : str, optional
+ Action schedule.
+ Id : int, optional
+ Alternative action rule ID.
+ actSrc : int, optional
+ Action source.
+ actDsId : int, optional
+ Action DiskStation ID.
+ actDevId : int, optional
+ Action device ID.
+ actId : int, optional
+ Action ID.
+ actTimes : int, optional
+ Number of times to perform the action.
+ actTimeUnit : int, optional
+ Time unit for the action.
+ actTimeDur : int, optional
+ Duration for the action.
+ actItemId : int, optional
+ Action item ID.
+ actRetPos : int, optional
+ Action return position.
+ extUrl : str, optional
+ External URL for the action.
+ userName : str, optional
+ Username for authentication.
+ password : str, optional
+ Password for authentication. (Currently not working).
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the save operation or error details.
+ """
api_name = 'SYNO.SurveillanceStation.ActionRule'
info = self.gen_list[api_name]
api_path = info['path']
@@ -1781,6 +3675,14 @@ def save_action_rule(self,
# TODO not working
def download_action_rule(self) -> dict[str, object] | str:
+ """
+ Download the history of action rules from Surveillance Station.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Downloaded action rule history or error details.
+ """
api_name = 'SYNO.SurveillanceStation.ActionRule'
info = self.gen_list[api_name]
api_path = info['path']
@@ -1791,6 +3693,14 @@ def download_action_rule(self) -> dict[str, object] | str:
# TODO not working
def send_data_2_player(self) -> dict[str, object] | str:
+ """
+ Send data to the Surveillance Station player.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the send operation or error details.
+ """
api_name = 'SYNO.SurveillanceStation.ActionRule'
info = self.gen_list[api_name]
api_path = info['path']
@@ -1801,6 +3711,19 @@ def send_data_2_player(self) -> dict[str, object] | str:
# TODO not working
def delete_all_histories_of_action_rule(self, idList: str = None) -> dict[str, object] | str:
+ """
+ Delete all histories of specified action rules.
+
+ Parameters
+ ----------
+ idList : str, optional
+ Comma-separated list of action rule IDs to delete histories for.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the delete operation or error details.
+ """
api_name = 'SYNO.SurveillanceStation.ActionRule'
info = self.gen_list[api_name]
api_path = info['path']
@@ -1810,6 +3733,21 @@ def delete_all_histories_of_action_rule(self, idList: str = None) -> dict[str, o
return self.request_data(api_name, api_path, req_param)
def list_action_rules(self, start: str = None, limit: int = None) -> dict[str, object] | str:
+ """
+ List action rules in Surveillance Station.
+
+ Parameters
+ ----------
+ start : str, optional
+ Start index for pagination.
+ limit : int, optional
+ Maximum number of action rules to return.
+
+ Returns
+ -------
+ dict[str, object] or str
+ List of action rules or error details.
+ """
api_name = 'SYNO.SurveillanceStation.ActionRule'
info = self.gen_list[api_name]
api_path = info['path']
@@ -1820,6 +3758,19 @@ def list_action_rules(self, start: str = None, limit: int = None) -> dict[str, o
# TODO not working
def disable_action_rules(self, idList: str = None) -> dict[str, object] | str:
+ """
+ Disable specified action rules in Surveillance Station.
+
+ Parameters
+ ----------
+ idList : str, optional
+ Comma-separated list of action rule IDs to disable.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the disable operation or error details.
+ """
api_name = 'SYNO.SurveillanceStation.ActionRule'
info = self.gen_list[api_name]
api_path = info['path']
@@ -1830,6 +3781,19 @@ def disable_action_rules(self, idList: str = None) -> dict[str, object] | str:
# TODO not working
def enable_action_rules(self, idList: str = None) -> dict[str, object] | str:
+ """
+ Enable specified action rules in Surveillance Station.
+
+ Parameters
+ ----------
+ idList : str, optional
+ Comma-separated list of action rule IDs to enable.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the enable operation or error details.
+ """
api_name = 'SYNO.SurveillanceStation.ActionRule'
info = self.gen_list[api_name]
api_path = info['path']
@@ -1840,6 +3804,21 @@ def enable_action_rules(self, idList: str = None) -> dict[str, object] | str:
# TODO not working
def list_history_action_rules(self, start: int = None, limit: int = None) -> dict[str, object] | str:
+ """
+ List the history of action rules in Surveillance Station.
+
+ Parameters
+ ----------
+ start : int, optional
+ Start index for pagination.
+ limit : int, optional
+ Maximum number of history records to return.
+
+ Returns
+ -------
+ dict[str, object] or str
+ List of action rule histories or error details.
+ """
api_name = 'SYNO.SurveillanceStation.ActionRule'
info = self.gen_list[api_name]
api_path = info['path']
@@ -1850,6 +3829,19 @@ def list_history_action_rules(self, start: int = None, limit: int = None) -> dic
# TODO not working
def delete_action_rule(self, idList: str = None) -> dict[str, object] | str:
+ """
+ Delete specified action rules from Surveillance Station.
+
+ Parameters
+ ----------
+ idList : str, optional
+ Comma-separated list of action rule IDs to delete.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the delete operation or error details.
+ """
api_name = 'SYNO.SurveillanceStation.ActionRule'
info = self.gen_list[api_name]
api_path = info['path']
@@ -1863,6 +3855,25 @@ def get_list_of_emaps(self,
limit: str = None,
emapIds: int = None,
includeItems: int = None) -> dict[str, object] | str:
+ """
+ Retrieve a list of eMaps from Surveillance Station.
+
+ Parameters
+ ----------
+ start : int, optional
+ Start index for pagination.
+ limit : str, optional
+ Maximum number of eMaps to return.
+ emapIds : int, optional
+ Specific eMap IDs to retrieve.
+ includeItems : int, optional
+ Whether to include items in the eMap.
+
+ Returns
+ -------
+ dict[str, object] or str
+ List of eMaps or error details.
+ """
api_name = 'SYNO.SurveillanceStation.Emap'
info = self.gen_list[api_name]
api_path = info['path']
@@ -1879,6 +3890,21 @@ def get_specific_emaps_setting(self,
emapIds: int = None,
# TODO to check
includeImage: int = None) -> dict[str, object] | str:
+ """
+ Retrieve specific eMap settings from Surveillance Station.
+
+ Parameters
+ ----------
+ emapIds : int, optional
+ The ID(s) of the eMap(s) to retrieve settings for.
+ includeImage : int, optional
+ Whether to include the eMap image in the response.
+
+ Returns
+ -------
+ dict[str, object] or str
+ The eMap settings or error details.
+ """
api_name = 'SYNO.SurveillanceStation.Emap'
info = self.gen_list[api_name]
api_path = info['path']
@@ -1894,6 +3920,19 @@ def get_specific_emaps_setting(self,
def get_emap_image(self,
# TODO to check
filename: str = None) -> dict[str, object] | str:
+ """
+ Retrieve an eMap image from Surveillance Station.
+
+ Parameters
+ ----------
+ filename : str, optional
+ The filename of the eMap image to retrieve.
+
+ Returns
+ -------
+ dict[str, object] or str
+ The eMap image data or error details.
+ """
api_name = 'SYNO.SurveillanceStation.Emap.Image'
info = self.gen_list[api_name]
api_path = info['path']
@@ -1908,6 +3947,14 @@ def get_emap_image(self,
# TODO to check
def get_autorized_ds_token(self) -> dict[str, object] | str:
+ """
+ Retrieve an authorized DiskStation token for notifications.
+
+ Returns
+ -------
+ dict[str, object] or str
+ The authorized token or error details.
+ """
api_name = 'SYNO.SurveillanceStation.Notification'
info = self.gen_list[api_name]
api_path = info['path']
@@ -1921,6 +3968,23 @@ def set_message_event(self,
subject: str = None,
# TODO not working
content: str = None) -> dict[str, object] | str:
+ """
+ Set a customized message event in Surveillance Station.
+
+ Parameters
+ ----------
+ eventTypes : str, optional
+ The type(s) of event(s) to set the message for.
+ subject : str, optional
+ The subject of the message.
+ content : str, optional
+ The content of the message.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the set operation or error details.
+ """
api_name = 'SYNO.SurveillanceStation.Notification'
info = self.gen_list[api_name]
api_path = info['path']
@@ -1937,6 +4001,19 @@ def set_message_event(self,
def get_message_event(self,
# TODO not working
eventTypes: int = None) -> dict[str, object] | str:
+ """
+ Retrieve a customized message event from Surveillance Station.
+
+ Parameters
+ ----------
+ eventTypes : int, optional
+ The type(s) of event(s) to retrieve the message for.
+
+ Returns
+ -------
+ dict[str, object] or str
+ The message event data or error details.
+ """
api_name = 'SYNO.SurveillanceStation.Notification'
info = self.gen_list[api_name]
api_path = info['path']
@@ -1953,6 +4030,19 @@ def get_message_event(self,
def set_notification_sender_name(self,
# TODO not working
ss_pkg_name: str = None) -> dict[str, object] | str:
+ """
+ Set the sender name for Surveillance Station notifications.
+
+ Parameters
+ ----------
+ ss_pkg_name : str, optional
+ The sender name to set.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the set operation or error details.
+ """
api_name = 'SYNO.SurveillanceStation.Notification'
info = self.gen_list[api_name]
api_path = info['path']
@@ -1967,6 +4057,14 @@ def set_notification_sender_name(self,
# TODO not working
def get_notification_sender_name(self) -> dict[str, object] | str:
+ """
+ Retrieve the sender name for Surveillance Station notifications.
+
+ Returns
+ -------
+ dict[str, object] or str
+ The sender name or error details.
+ """
api_name = 'SYNO.SurveillanceStation.Notification'
info = self.gen_list[api_name]
api_path = info['path']
@@ -1978,6 +4076,21 @@ def set_advanced_notification_setting(self,
blSyncDSMNotify: bool = None,
# TODO to check
blCompactMsg: bool = None) -> dict[str, object] | str:
+ """
+ Set advanced notification settings in Surveillance Station.
+
+ Parameters
+ ----------
+ blSyncDSMNotify : bool, optional
+ Whether to synchronize DSM notifications.
+ blCompactMsg : bool, optional
+ Whether to enable compact message format.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the set operation or error details.
+ """
api_name = 'SYNO.SurveillanceStation.Notification'
info = self.gen_list[api_name]
api_path = info['path']
@@ -1992,6 +4105,14 @@ def set_advanced_notification_setting(self,
# TODO not working
def get_advanced_notification_setting(self) -> dict[str, object] | str:
+ """
+ Retrieve advanced notification settings from Surveillance Station.
+
+ Returns
+ -------
+ dict[str, object] or str
+ The advanced notification settings or error details.
+ """
api_name = 'SYNO.SurveillanceStation.Notification'
info = self.gen_list[api_name]
api_path = info['path']
@@ -2016,6 +4137,47 @@ def send_test_mesg_to_primary_secondary_phone(self,
hasSysSms: bool = None,
# TODO to check
apiId: str = None) -> dict[str, object] | str:
+ """
+ Send a test message to the primary and secondary phone numbers via SMS.
+
+ Parameters
+ ----------
+ smsEnable : bool, optional
+ Whether SMS notifications are enabled.
+ smsMethod : int, optional
+ The SMS sending method.
+ smsProvider : str, optional
+ The SMS provider name.
+ userName : str, optional
+ Username for SMS provider authentication.
+ password : str, optional
+ Password for SMS provider authentication.
+ confirmPassword : str, optional
+ Confirmation of the password.
+ primaryPhoneCode : str, optional
+ Country code for the primary phone.
+ primaryPhonePrefix : str, optional
+ Prefix for the primary phone.
+ secondaryPhoneCode : str, optional
+ Country code for the secondary phone.
+ secondaryPhonePrefix : str, optional
+ Prefix for the secondary phone.
+ secondaryPhoneNumber : str, optional
+ The secondary phone number.
+ setMinMessageInterval : bool, optional
+ Whether to set a minimum message interval.
+ minMessageInterval : int, optional
+ The minimum interval between messages.
+ hasSysSms : bool, optional
+ Whether system SMS is enabled.
+ apiId : str, optional
+ The API ID for the SMS provider.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the test message operation or error details.
+ """
api_name = 'SYNO.SurveillanceStation.Notification.SMS'
info = self.gen_list[api_name]
api_path = info['path']
@@ -2030,6 +4192,14 @@ def send_test_mesg_to_primary_secondary_phone(self,
return self.request_data(api_name, api_path, req_param)
def get_setting_notification_sms(self) -> dict[str, object] | str:
+ """
+ Retrieve the SMS notification settings from Surveillance Station.
+
+ Returns
+ -------
+ dict[str, object] or str
+ The SMS notification settings or error details.
+ """
api_name = 'SYNO.SurveillanceStation.Notification.SMS'
info = self.gen_list[api_name]
api_path = info['path']
@@ -2053,6 +4223,47 @@ def set_sms_service_setting(self,
minMessageInterval: int = None,
hasSysSms: bool = None,
apiId: str = None) -> dict[str, object] | str:
+ """
+ Set the SMS service settings for Surveillance Station notifications.
+
+ Parameters
+ ----------
+ smsEnable : bool, optional
+ Whether SMS notifications are enabled.
+ smsMethod : int, optional
+ The SMS sending method.
+ smsProvider : str, optional
+ The SMS provider name.
+ userName : str, optional
+ Username for SMS provider authentication.
+ password : str, optional
+ Password for SMS provider authentication.
+ confirmPassword : str, optional
+ Confirmation of the password.
+ primaryPhoneCode : str, optional
+ Country code for the primary phone.
+ primaryPhonePrefix : str, optional
+ Prefix for the primary phone.
+ secondaryPhoneCode : str, optional
+ Country code for the secondary phone.
+ secondaryPhonePrefix : str, optional
+ Prefix for the secondary phone.
+ secondaryPhoneNumber : str, optional
+ The secondary phone number.
+ setMinMessageInterval : bool, optional
+ Whether to set a minimum message interval.
+ minMessageInterval : int, optional
+ The minimum interval between messages.
+ hasSysSms : bool, optional
+ Whether system SMS is enabled.
+ apiId : str, optional
+ The API ID for the SMS provider.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the set operation or error details.
+ """
api_name = 'SYNO.SurveillanceStation.Notification.SMS'
info = self.gen_list[api_name]
api_path = info['path']
@@ -2075,6 +4286,33 @@ def send_test_sms(self,
synoMailEnable: bool = None,
# TODO to check
mail_recipient: str = None) -> dict[str, object] | str:
+ """
+ Send a test SMS notification from Surveillance Station.
+
+ Parameters
+ ----------
+ attachSnapshot : bool, optional
+ Whether to attach a snapshot to the SMS.
+ enableInterval : bool, optional
+ Whether to enable message interval.
+ mobileEnable : bool, optional
+ Whether to enable mobile notifications.
+ msgInterval : str, optional
+ The interval between messages.
+ primaryEmail : str, optional
+ The primary email address for notifications.
+ secondaryEmail : str, optional
+ The secondary email address for notifications.
+ synoMailEnable : bool, optional
+ Whether to enable Synology Mail notifications.
+ mail_recipient : str, optional
+ The recipient of the test mail.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the test SMS operation or error details.
+ """
api_name = 'SYNO.SurveillanceStation.Notification.SMS'
info = self.gen_list[api_name]
api_path = info['path']
@@ -2098,6 +4336,33 @@ def send_test_mail(self,
synoMailEnable: bool = None,
# TODO to check
mail_recipient: str = None) -> dict[str, object] | str:
+ """
+ Send a test verification mail for Surveillance Station notifications.
+
+ Parameters
+ ----------
+ attachSnapshot : bool, optional
+ Whether to attach a snapshot to the email.
+ enableInterval : bool, optional
+ Whether to enable message interval.
+ mobileEnable : bool, optional
+ Whether to enable mobile notifications.
+ msgInterval : str, optional
+ The interval between messages.
+ primaryEmail : str, optional
+ The primary email address for notifications.
+ secondaryEmail : str, optional
+ The secondary email address for notifications.
+ synoMailEnable : bool, optional
+ Whether to enable Synology Mail notifications.
+ mail_recipient : str, optional
+ The recipient of the test mail.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the test mail operation or error details.
+ """
api_name = 'SYNO.SurveillanceStation.Notification.PushService'
info = self.gen_list[api_name]
api_path = info['path']
@@ -2120,6 +4385,33 @@ def list_mobile_paired_devices(self,
secondaryEmail: str = None,
synoMailEnable: bool = None,
mail_recipient: str = None) -> dict[str, object] | str:
+ """
+ List mobile devices paired with Surveillance Station for push notifications.
+
+ Parameters
+ ----------
+ attachSnapshot : bool, optional
+ Whether to attach a snapshot to the notification.
+ enableInterval : bool, optional
+ Whether to enable message interval.
+ mobileEnable : bool, optional
+ Whether to enable mobile notifications.
+ msgInterval : str, optional
+ The interval between messages.
+ primaryEmail : str, optional
+ The primary email address for notifications.
+ secondaryEmail : str, optional
+ The secondary email address for notifications.
+ synoMailEnable : bool, optional
+ Whether to enable Synology Mail notifications.
+ mail_recipient : str, optional
+ The recipient of the notification.
+
+ Returns
+ -------
+ dict[str, object] or str
+ List of paired mobile devices or error details.
+ """
api_name = 'SYNO.SurveillanceStation.Notification.PushService'
info = self.gen_list[api_name]
api_path = info['path']
@@ -2135,6 +4427,19 @@ def list_mobile_paired_devices(self,
def unpair_device(self,
targetIds: str = None) -> dict[str, object] | str:
+ """
+ Unpair a mobile device from Surveillance Station notifications.
+
+ Parameters
+ ----------
+ targetIds : str, optional
+ The ID(s) of the device(s) to unpair.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the unpair operation or error details.
+ """
api_name = 'SYNO.SurveillanceStation.Notification.PushService'
info = self.gen_list[api_name]
api_path = info['path']
@@ -2150,6 +4455,19 @@ def unpair_device(self,
def get_controller_access_schedule(self,
# TODO to check
targetIds: str = None) -> dict[str, object] | str:
+ """
+ Retrieve the access control controller schedule from Surveillance Station.
+
+ Parameters
+ ----------
+ targetIds : str, optional
+ The ID(s) of the controllers to retrieve the schedule for.
+
+ Returns
+ -------
+ dict[str, object] or str
+ The controller access schedule or error details.
+ """
api_name = 'SYNO.SurveillanceStation.Notification.Schedule'
info = self.gen_list[api_name]
api_path = info['path']
@@ -2167,6 +4485,21 @@ def get_camera_alarm_schedule(self,
cameraId: int = None,
# TODO to check
alarmdx: int = None) -> dict[str, object] | str:
+ """
+ Retrieve the alarm schedule for a specific camera.
+
+ Parameters
+ ----------
+ cameraId : int, optional
+ The ID of the camera.
+ alarmdx : int, optional
+ Additional alarm parameter (to check).
+
+ Returns
+ -------
+ dict[str, object] or str
+ The camera alarm schedule or error details.
+ """
api_name = 'SYNO.SurveillanceStation.Notification.Schedule'
info = self.gen_list[api_name]
api_path = info['path']
@@ -2183,6 +4516,19 @@ def get_camera_alarm_schedule(self,
def get_sys_dependent_schedule(self,
# TODO to check
eventGroupTypes: int = None) -> dict[str, object] | str:
+ """
+ Retrieve the system dependent schedule for Surveillance Station events.
+
+ Parameters
+ ----------
+ eventGroupTypes : int, optional
+ The type(s) of event groups to retrieve the schedule for.
+
+ Returns
+ -------
+ dict[str, object] or str
+ The system dependent schedule or error details.
+ """
api_name = 'SYNO.SurveillanceStation.Notification.Schedule'
info = self.gen_list[api_name]
api_path = info['path']
@@ -2203,6 +4549,27 @@ def set_batch_schedule(self,
cameraGroupIds: str = None,
# TODO to check
filter: int = None) -> dict[str, object] | str:
+ """
+ Set batch schedules for events, cameras, or camera groups.
+
+ Parameters
+ ----------
+ eventTypes : str, optional
+ The type(s) of events to schedule.
+ schedule : Any, optional
+ The schedule data to apply.
+ cameraIds : str, optional
+ The IDs of cameras to apply the schedule to.
+ cameraGroupIds : str, optional
+ The IDs of camera groups to apply the schedule to.
+ filter : int, optional
+ Additional filter parameter (to check).
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the batch schedule operation or error details.
+ """
api_name = 'SYNO.SurveillanceStation.Notification.Schedule'
info = self.gen_list[api_name]
api_path = info['path']
@@ -2219,6 +4586,19 @@ def set_batch_schedule(self,
def get_access_ctrl_door_schedule(self,
# TODO to check
doorId: str = None) -> dict[str, object] | str:
+ """
+ Retrieve the access control door schedule from Surveillance Station.
+
+ Parameters
+ ----------
+ doorId : str, optional
+ The ID of the door to retrieve the schedule for.
+
+ Returns
+ -------
+ dict[str, object] or str
+ The door schedule or error details.
+ """
api_name = 'SYNO.SurveillanceStation.Notification.Schedule'
info = self.gen_list[api_name]
api_path = info['path']
@@ -2235,6 +4615,19 @@ def get_access_ctrl_door_schedule(self,
def get_camera_schedule(self,
# TODO to check
cameraId: str = None) -> dict[str, object] | str:
+ """
+ Retrieve the schedule for a specific camera.
+
+ Parameters
+ ----------
+ cameraId : str, optional
+ The ID of the camera to retrieve the schedule for.
+
+ Returns
+ -------
+ dict[str, object] or str
+ The camera schedule or error details.
+ """
api_name = 'SYNO.SurveillanceStation.Notification.Schedule'
info = self.gen_list[api_name]
api_path = info['path']
@@ -2252,6 +4645,21 @@ def set_sys_dependent_schedule(self,
eventType: int = None,
# TODO to check
schedule: Any = None) -> dict[str, object] | str:
+ """
+ Set the system dependent schedule for Surveillance Station events.
+
+ Parameters
+ ----------
+ eventType : int, optional
+ The type of event to set the schedule for.
+ schedule : Any, optional
+ The schedule data to apply.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the set operation or error details.
+ """
api_name = 'SYNO.SurveillanceStation.Notification.Schedule'
info = self.gen_list[api_name]
api_path = info['path']
@@ -2270,6 +4678,23 @@ def set_controller_access_schedule(self,
schedule: Any = None,
# TODO to check
doorId: int = None) -> dict[str, object] | str:
+ """
+ Set the access control schedule for a controller or door.
+
+ Parameters
+ ----------
+ eventType : int, optional
+ The type of event to set the schedule for.
+ schedule : Any, optional
+ The schedule data to apply.
+ doorId : int, optional
+ The ID of the door to set the schedule for.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the set operation or error details.
+ """
api_name = 'SYNO.SurveillanceStation.Notification.Schedule'
info = self.gen_list[api_name]
api_path = info['path']
@@ -2288,6 +4713,23 @@ def set_camera_schedule(self,
schedule: Any = None,
# TODO to check
cameraId: Any = None) -> dict[str, object] | str:
+ """
+ Set the schedule for a specific camera in Surveillance Station.
+
+ Parameters
+ ----------
+ eventType : int, optional
+ The type of event to set the schedule for.
+ schedule : Any, optional
+ The schedule data to apply.
+ cameraId : Any, optional
+ The ID of the camera to set the schedule for.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the set operation or error details.
+ """
api_name = 'SYNO.SurveillanceStation.Notification.Schedule'
info = self.gen_list[api_name]
api_path = info['path']
@@ -2302,6 +4744,14 @@ def set_camera_schedule(self,
return self.request_data(api_name, api_path, req_param)
def get_notification_email_string(self) -> dict[str, object] | str:
+ """
+ Retrieve the notification email settings string from Surveillance Station.
+
+ Returns
+ -------
+ dict[str, object] or str
+ The notification email settings or error details.
+ """
api_name = 'SYNO.SurveillanceStation.Notification.Email'
info = self.gen_list[api_name]
api_path = info['path']
@@ -2312,6 +4762,19 @@ def get_notification_email_string(self) -> dict[str, object] | str:
def set_adv_tab_info_filter(self,
# TODO to check
X: int = None) -> dict[str, object] | str:
+ """
+ Set the advanced tab information filter for notification emails.
+
+ Parameters
+ ----------
+ X : int, optional
+ The filter value to set (to check).
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the set operation or error details.
+ """
api_name = 'SYNO.SurveillanceStation.Notification.Email'
info = self.gen_list[api_name]
api_path = info['path']
@@ -2331,6 +4794,29 @@ def create_sms_service_provider(self,
providerTemplate: str = None,
providerSepChar: str = None,
providerNeedSSL: bool = None) -> dict[str, object] | str:
+ """
+ Create a new SMS service provider for Surveillance Station notifications.
+
+ Parameters
+ ----------
+ providerName : str, optional
+ The name of the SMS provider.
+ providerPort : int, optional
+ The port used by the provider.
+ providerUrl : str, optional
+ The URL of the provider.
+ providerTemplate : str, optional
+ The message template for the provider.
+ providerSepChar : str, optional
+ The separator character used by the provider.
+ providerNeedSSL : bool, optional
+ Whether SSL is required for the provider.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the create operation or error details.
+ """
api_name = 'SYNO.SurveillanceStation.Notification.SMS.ServiceProvider'
info = self.gen_list[api_name]
api_path = info['path']
@@ -2344,6 +4830,14 @@ def create_sms_service_provider(self,
return self.request_data(api_name, api_path, req_param)
def list_sms_provider(self) -> dict[str, object] | str:
+ """
+ List all SMS service providers configured in Surveillance Station.
+
+ Returns
+ -------
+ dict[str, object] or str
+ List of SMS providers or error details.
+ """
api_name = 'SYNO.SurveillanceStation.Notification.SMS.ServiceProvider'
info = self.gen_list[api_name]
api_path = info['path']
@@ -2354,6 +4848,19 @@ def list_sms_provider(self) -> dict[str, object] | str:
def delete_sms_service_provider(self,
# TODO to check
providerName: str = None) -> dict[str, object] | str:
+ """
+ Delete an SMS service provider from Surveillance Station.
+
+ Parameters
+ ----------
+ providerName : str, optional
+ The name of the SMS provider to delete.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the delete operation or error details.
+ """
api_name = 'SYNO.SurveillanceStation.Notification.SMS.ServiceProvider'
info = self.gen_list[api_name]
api_path = info['path']
@@ -2367,6 +4874,14 @@ def delete_sms_service_provider(self,
return self.request_data(api_name, api_path, req_param)
def get_addson_to_update(self) -> dict[str, object] | str:
+ """
+ Retrieve information about add-ons that require updates in Surveillance Station.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Add-on update information or error details.
+ """
api_name = 'SYNO.SurveillanceStation.AddOns'
info = self.gen_list[api_name]
api_path = info['path']
@@ -2378,6 +4893,21 @@ def enable_specific_addon(self,
service: int = None,
# TODO to check
servicename: str = None) -> dict[str, object] | str:
+ """
+ Enable a specific add-on in Surveillance Station.
+
+ Parameters
+ ----------
+ service : int, optional
+ The ID of the add-on service to enable.
+ servicename : str, optional
+ The name of the add-on service to enable.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the enable operation or error details.
+ """
api_name = 'SYNO.SurveillanceStation.AddOns'
info = self.gen_list[api_name]
api_path = info['path']
@@ -2393,6 +4923,19 @@ def enable_specific_addon(self,
def get_specific_addon_update_info(self,
# TODO to check
service: int = None) -> dict[str, object] | str:
+ """
+ Retrieve update information for a specific add-on in Surveillance Station.
+
+ Parameters
+ ----------
+ service : int, optional
+ The ID of the add-on service to check for updates.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Update information or error details.
+ """
api_name = 'SYNO.SurveillanceStation.AddOns'
info = self.gen_list[api_name]
api_path = info['path']
@@ -2409,6 +4952,19 @@ def get_specific_addon_update_info(self,
def get_specific_addon_info(self,
# TODO to check
service: int = None) -> dict[str, object] | str:
+ """
+ Retrieve information for a specific add-on in Surveillance Station.
+
+ Parameters
+ ----------
+ service : int, optional
+ The ID of the add-on service to retrieve information for.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Add-on information or error details.
+ """
api_name = 'SYNO.SurveillanceStation.AddOns'
info = self.gen_list[api_name]
api_path = info['path']
@@ -2422,6 +4978,14 @@ def get_specific_addon_info(self,
return self.request_data(api_name, api_path, req_param)
def get_total_addon_info(self) -> dict[str, object] | str: # TODO to check
+ """
+ Retrieve information about all add-ons in Surveillance Station.
+
+ Returns
+ -------
+ dict[str, object] or str
+ List of all add-ons or error details.
+ """
api_name = 'SYNO.SurveillanceStation.AddOns'
info = self.gen_list[api_name]
api_path = info['path']
@@ -2433,6 +4997,21 @@ def update_addon_package(self,
service: int = None,
# TODO to check
filePath: str = None) -> dict[str, object] | str:
+ """
+ Update an add-on package in Surveillance Station.
+
+ Parameters
+ ----------
+ service : int, optional
+ The ID of the add-on service to update.
+ filePath : str, optional
+ The file path to the add-on package (to check).
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the update operation or error details.
+ """
api_name = 'SYNO.SurveillanceStation.AddOns'
info = self.gen_list[api_name]
api_path = info['path']
@@ -2448,6 +5027,19 @@ def update_addon_package(self,
def check_addon_status(self,
# TODO to check
service: int = None) -> dict[str, object] | str:
+ """
+ Check the enable status of a specific add-on in Surveillance Station.
+
+ Parameters
+ ----------
+ service : int, optional
+ The ID of the add-on service to check (to check).
+
+ Returns
+ -------
+ dict[str, object] or str
+ Status information or error details.
+ """
api_name = 'SYNO.SurveillanceStation.AddOns'
info = self.gen_list[api_name]
api_path = info['path']
@@ -2465,6 +5057,21 @@ def disable_addon(self,
service: int = None,
# TODO to check
serviceName: str = None) -> dict[str, object] | str:
+ """
+ Disable a specific add-on in Surveillance Station.
+
+ Parameters
+ ----------
+ service : int, optional
+ The ID of the add-on service to disable.
+ serviceName : str, optional
+ The name of the add-on service to disable (to check).
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the disable operation or error details.
+ """
api_name = 'SYNO.SurveillanceStation.AddOns'
info = self.gen_list[api_name]
api_path = info['path']
@@ -2481,6 +5088,21 @@ def set_addon_autoupdate(self,
service: int = None,
# TODO to check
BlEnabled: Any = None) -> dict[str, object] | str:
+ """
+ Set the auto-update setting for a specific add-on in Surveillance Station.
+
+ Parameters
+ ----------
+ service : int, optional
+ The ID of the add-on service to configure.
+ BlEnabled : Any, optional
+ Whether auto-update is enabled (to check).
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the set operation or error details.
+ """
api_name = 'SYNO.SurveillanceStation.AddOns'
info = self.gen_list[api_name]
api_path = info['path']
@@ -2496,6 +5118,19 @@ def set_addon_autoupdate(self,
def delete_specific_camera_recording_server(self,
# TODO to check
camIdList: str = None) -> dict[str, object] | str:
+ """
+ Delete a specific camera recording server in Surveillance Station.
+
+ Parameters
+ ----------
+ camIdList : str, optional
+ List of camera IDs to delete from the recording server (to check).
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the delete operation or error details.
+ """
api_name = 'SYNO.SurveillanceStation.Alert'
info = self.gen_list[api_name]
api_path = info['path']
@@ -2511,6 +5146,19 @@ def delete_specific_camera_recording_server(self,
def get_camera_event_analytic(self,
# TODO to check
camIdList: str = None) -> dict[str, object] | str:
+ """
+ Retrieve camera event analytics from Surveillance Station.
+
+ Parameters
+ ----------
+ camIdList : str, optional
+ List of camera IDs to retrieve analytics for (to check).
+
+ Returns
+ -------
+ dict[str, object] or str
+ Analytics data or error details.
+ """
api_name = 'SYNO.SurveillanceStation.Alert'
info = self.gen_list[api_name]
api_path = info['path']
@@ -2527,6 +5175,21 @@ def delete_selected_events(self,
dsIdList: str = None,
# TODO to check
idList: str = None) -> dict[str, object] | str:
+ """
+ Delete selected events from Surveillance Station.
+
+ Parameters
+ ----------
+ dsIdList : str, optional
+ List of DS IDs for which to delete events.
+ idList : str, optional
+ List of event IDs to delete (to check).
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the delete operation or error details.
+ """
api_name = 'SYNO.SurveillanceStation.Alert'
info = self.gen_list[api_name]
api_path = info['path']
@@ -2542,6 +5205,19 @@ def delete_selected_events(self,
def delete_specific_camera_events(self,
# TODO to check
camIdList: str = None) -> dict[str, object] | str:
+ """
+ Delete events for specific cameras in Surveillance Station.
+
+ Parameters
+ ----------
+ camIdList : str, optional
+ List of camera IDs for which to delete events (to check).
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the delete operation or error details.
+ """
api_name = 'SYNO.SurveillanceStation.Alert'
info = self.gen_list[api_name]
api_path = info['path']
@@ -2558,6 +5234,21 @@ def get_analytic_history(self,
camIdList: str = None,
# TODO to check
typeListstring: str = None) -> dict[str, object] | str:
+ """
+ Retrieve analytic history for cameras in Surveillance Station.
+
+ Parameters
+ ----------
+ camIdList : str, optional
+ List of camera IDs to retrieve history for.
+ typeListstring : str, optional
+ List of analytic types as a string (to check).
+
+ Returns
+ -------
+ dict[str, object] or str
+ Analytic history data or error details.
+ """
api_name = 'SYNO.SurveillanceStation.Alert'
info = self.gen_list[api_name]
api_path = info['path']
@@ -2576,6 +5267,25 @@ def get_analytic_history_by_filter(self,
lock: int = None,
# TODO to check
typeList: str = None) -> dict[str, object] | str:
+ """
+ Retrieve analytic history for cameras by filter in Surveillance Station.
+
+ Parameters
+ ----------
+ camIdList : str, optional
+ List of camera IDs to filter.
+ dsId : int, optional
+ The DS ID to filter.
+ lock : int, optional
+ Lock status to filter.
+ typeList : str, optional
+ List of analytic types as a string (to check).
+
+ Returns
+ -------
+ dict[str, object] or str
+ Filtered analytic history data or error details.
+ """
api_name = 'SYNO.SurveillanceStation.Alert'
info = self.gen_list[api_name]
api_path = info['path']
@@ -2592,6 +5302,21 @@ def unklock_selected_events(self,
dsId: int = None,
# TODO to check
idList: str = None) -> dict[str, object] | str:
+ """
+ Unlock selected events in Surveillance Station.
+
+ Parameters
+ ----------
+ dsId : int, optional
+ The DS ID for which to unlock events.
+ idList : str, optional
+ List of event IDs to unlock (to check).
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the unlock operation or error details.
+ """
api_name = 'SYNO.SurveillanceStation.Alert'
info = self.gen_list[api_name]
api_path = info['path']
@@ -2607,6 +5332,19 @@ def unklock_selected_events(self,
def set_camera_analytic_trigger(self,
# TODO to check
trigCamIdList: str = None) -> dict[str, object] | str:
+ """
+ Trigger camera analytics for specified cameras in Surveillance Station.
+
+ Parameters
+ ----------
+ trigCamIdList : str, optional
+ List of camera IDs to trigger analytics for (to check).
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the trigger operation or error details.
+ """
api_name = 'SYNO.SurveillanceStation.Alert'
info = self.gen_list[api_name]
api_path = info['path']
@@ -2622,6 +5360,19 @@ def set_camera_analytic_trigger(self,
def flush_event_header(self,
# TODO to check
eventId: str = None) -> dict[str, object] | str:
+ """
+ Flush the header of a specific event in Surveillance Station.
+
+ Parameters
+ ----------
+ eventId : str, optional
+ The ID of the event to flush the header for (to check).
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the flush operation or error details.
+ """
api_name = 'SYNO.SurveillanceStation.Alert'
info = self.gen_list[api_name]
api_path = info['path']
@@ -2639,6 +5390,21 @@ def lock_selected_events(self,
dsId: int = None,
# TODO to check
idList: str = None) -> dict[str, object] | str:
+ """
+ Lock selected events in Surveillance Station.
+
+ Parameters
+ ----------
+ dsId : int, optional
+ The DS ID for which to lock events.
+ idList : str, optional
+ List of event IDs to lock (to check).
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the lock operation or error details.
+ """
api_name = 'SYNO.SurveillanceStation.Alert'
info = self.gen_list[api_name]
api_path = info['path']
@@ -2655,6 +5421,21 @@ def get_analytic_event_from_rec_server(self,
camIdList: str = None,
# TODO to check
idList: int = None) -> dict[str, object] | str:
+ """
+ Retrieve analytic event counts from the recording server for specified cameras.
+
+ Parameters
+ ----------
+ camIdList : str, optional
+ Comma-separated list of camera IDs to query.
+ idList : int, optional
+ Additional ID list parameter (to check).
+
+ Returns
+ -------
+ dict[str, object] or str
+ Analytic event count data or error details.
+ """
api_name = 'SYNO.SurveillanceStation.Alert'
info = self.gen_list[api_name]
api_path = info['path']
@@ -2681,6 +5462,39 @@ def save_analytic_settings(self,
objSize: int = None,
# TODO to check
region: str = None) -> dict[str, object] | str:
+ """
+ Save analytic settings for a specific camera.
+
+ Parameters
+ ----------
+ camId : int, optional
+ Camera ID to apply settings to.
+ type : int, optional
+ Type of analytic.
+ showFrame : bool, optional
+ Whether to display the frame.
+ showLine : bool, optional
+ Whether to display lines.
+ showVirtualFence : bool, optional
+ Whether to display virtual fences.
+ beep : bool, optional
+ Whether to enable beep on event.
+ sens : int, optional
+ Sensitivity setting.
+ dwellTime : int, optional
+ Dwell time setting.
+ direction : int, optional
+ Direction setting.
+ objSize : int, optional
+ Object size setting.
+ region : str, optional
+ Region definition (to check).
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the save operation or error details.
+ """
api_name = 'SYNO.SurveillanceStation.Alert.Setting'
info = self.gen_list[api_name]
api_path = info['path']
@@ -2696,6 +5510,19 @@ def save_analytic_settings(self,
def check_if_snapshot_exist(self,
# TODO to check
id: int = None) -> dict[str, object] | str:
+ """
+ Check if a snapshot exists for a given ID.
+
+ Parameters
+ ----------
+ id : int, optional
+ Snapshot ID to check (to check).
+
+ Returns
+ -------
+ dict[str, object] or str
+ Existence status or error details.
+ """
api_name = 'SYNO.SurveillanceStation.SnapShot'
info = self.gen_list[api_name]
api_path = info['path']
@@ -2716,6 +5543,29 @@ def save_snapshot_modification(self,
byteSize: int = None,
# TODO to check
imageData: str = None) -> dict[str, object] | str:
+ """
+ Save modifications to a snapshot.
+
+ Parameters
+ ----------
+ id : int, optional
+ Snapshot ID to modify.
+ createCopy : bool, optional
+ Whether to create a copy of the snapshot.
+ width : int, optional
+ Width of the snapshot.
+ height : int, optional
+ Height of the snapshot.
+ byteSize : int, optional
+ Size of the snapshot in bytes.
+ imageData : str, optional
+ Image data (to check).
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the modification or error details.
+ """
api_name = 'SYNO.SurveillanceStation.SnapShot'
info = self.gen_list[api_name]
api_path = info['path']
@@ -2736,6 +5586,29 @@ def count_snapshot_by_category(self,
byteSize: int = None,
# TODO to check
imageData: str = None) -> dict[str, object] | str:
+ """
+ Count snapshots by category within a specified range.
+
+ Parameters
+ ----------
+ keyword : str, optional
+ Keyword to filter snapshots.
+ dsfrom : int, optional
+ Start timestamp.
+ to : int, optional
+ End timestamp.
+ timezoneOffset : int, optional
+ Timezone offset.
+ byteSize : int, optional
+ Size of the snapshot in bytes.
+ imageData : str, optional
+ Image data (to check).
+
+ Returns
+ -------
+ dict[str, object] or str
+ Count data or error details.
+ """
api_name = 'SYNO.SurveillanceStation.SnapShot'
info = self.gen_list[api_name]
api_path = info['path']
@@ -2758,6 +5631,25 @@ def check_any_locked_snapshot(self,
to: int = None,
# TODO to check
keyword: str = None) -> dict[str, object] | str:
+ """
+ Check if any locked snapshots exist within a specified range.
+
+ Parameters
+ ----------
+ id : str, optional
+ Snapshot ID(s) to check.
+ dsfrom : int, optional
+ Start timestamp.
+ to : int, optional
+ End timestamp.
+ keyword : str, optional
+ Keyword to filter snapshots (to check).
+
+ Returns
+ -------
+ dict[str, object] or str
+ Lock status or error details.
+ """
api_name = 'SYNO.SurveillanceStation.SnapShot'
info = self.gen_list[api_name]
api_path = info['path']
@@ -2779,6 +5671,23 @@ def unlock_snapshot_by_filter(self,
to: int = None,
# TODO to check
keyword: str = None) -> dict[str, object] | str:
+ """
+ Unlock snapshots by filter within a specified range.
+
+ Parameters
+ ----------
+ dsfrom : int, optional
+ Start timestamp.
+ to : int, optional
+ End timestamp.
+ keyword : str, optional
+ Keyword to filter snapshots (to check).
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the unlock operation or error details.
+ """
api_name = 'SYNO.SurveillanceStation.SnapShot'
info = self.gen_list[api_name]
api_path = info['path']
@@ -2806,6 +5715,37 @@ def list_snapshot_information(self,
blIncludeRecCnt: bool = None,
# TODO to check
camId: int = None) -> dict[str, object] | str:
+ """
+ List snapshot information with optional filters.
+
+ Parameters
+ ----------
+ idList : str, optional
+ Comma-separated list of snapshot IDs.
+ start : int, optional
+ Start index for pagination.
+ limit : int, optional
+ Maximum number of results to return.
+ dsfrom : int, optional
+ Start timestamp.
+ to : int, optional
+ End timestamp.
+ keyword : str, optional
+ Keyword to filter snapshots.
+ imgSize : int, optional
+ Image size filter.
+ blIncludeAuInfo : bool, optional
+ Whether to include additional info.
+ blIncludeRecCnt : bool, optional
+ Whether to include recording count.
+ camId : int, optional
+ Camera ID filter (to check).
+
+ Returns
+ -------
+ dict[str, object] or str
+ List of snapshot information or error details.
+ """
api_name = 'SYNO.SurveillanceStation.SnapShot'
info = self.gen_list[api_name]
api_path = info['path']
@@ -2824,6 +5764,19 @@ def list_snapshot_information(self,
def unlock_snapshot(self,
# TODO to check
objList: Any = None) -> dict[str, object] | str:
+ """
+ Unlock specific snapshots.
+
+ Parameters
+ ----------
+ objList : Any, optional
+ List of snapshot objects to unlock (to check).
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the unlock operation or error details.
+ """
api_name = 'SYNO.SurveillanceStation.SnapShot'
info = self.gen_list[api_name]
api_path = info['path']
@@ -2841,6 +5794,23 @@ def take_snapshot(self,
camId: int = None,
# TODO to check
blSave: bool = None) -> dict[str, object] | str:
+ """
+ Take a snapshot for a specific camera and DS.
+
+ Parameters
+ ----------
+ dsId : int, optional
+ DS ID for the snapshot.
+ camId : int, optional
+ Camera ID for the snapshot.
+ blSave : bool, optional
+ Whether to save the snapshot (to check).
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the snapshot operation or error details.
+ """
api_name = 'SYNO.SurveillanceStation.SnapShot'
info = self.gen_list[api_name]
api_path = info['path']
@@ -2855,6 +5825,14 @@ def take_snapshot(self,
# TODO to check
def get_snapshot_setting_function(self) -> dict[str, object] | str:
+ """
+ Retrieve the snapshot setting function.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Snapshot setting information or error details.
+ """
api_name = 'SYNO.SurveillanceStation.SnapShot'
info = self.gen_list[api_name]
api_path = info['path']
@@ -2868,6 +5846,25 @@ def delete_snapshot_by_filter(self,
to: int = None,
# TODO to check
keyword: str = None) -> dict[str, object] | str:
+ """
+ Delete snapshots by filter within a specified range.
+
+ Parameters
+ ----------
+ deleteAllCommand : bool, optional
+ Whether to delete all snapshots.
+ dsfrom : int, optional
+ Start timestamp.
+ to : int, optional
+ End timestamp.
+ keyword : str, optional
+ Keyword to filter snapshots (to check).
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the delete operation or error details.
+ """
api_name = 'SYNO.SurveillanceStation.SnapShot'
info = self.gen_list[api_name]
api_path = info['path']
@@ -2887,6 +5884,21 @@ def get_snapshot_image(self,
id: int = None,
# TODO to modify for download?
imgSize: int = None) -> dict[str, object] | str:
+ """
+ Retrieve a snapshot image by ID.
+
+ Parameters
+ ----------
+ id : int, optional
+ Snapshot ID to retrieve.
+ imgSize : int, optional
+ Image size (to modify for download?).
+
+ Returns
+ -------
+ dict[str, object] or str
+ Snapshot image data or error details.
+ """
api_name = 'SYNO.SurveillanceStation.SnapShot'
info = self.gen_list[api_name]
api_path = info['path']
@@ -2901,6 +5913,19 @@ def get_snapshot_image(self,
def lock_snapshot_image(self,
objList: Any = None) -> dict[str, object] | str:
+ """
+ Lock specific snapshot images.
+
+ Parameters
+ ----------
+ objList : Any, optional
+ List of snapshot objects to lock.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the lock operation or error details.
+ """
api_name = 'SYNO.SurveillanceStation.SnapShot'
info = self.gen_list[api_name]
api_path = info['path']
@@ -2913,9 +5938,23 @@ def lock_snapshot_image(self,
return self.request_data(api_name, api_path, req_param)
+ # TODO: fix typo
def downld_single_snapshot(self,
# TODO not working
id: int = None) -> dict[str, object] | str:
+ """
+ Download a single snapshot by ID.
+
+ Parameters
+ ----------
+ id : int, optional
+ Snapshot ID to download (not working).
+
+ Returns
+ -------
+ dict[str, object] or str
+ Download result or error details.
+ """
api_name = 'SYNO.SurveillanceStation.SnapShot'
info = self.gen_list[api_name]
api_path = info['path']
@@ -2935,6 +5974,29 @@ def save_new_snapshot_setting(self,
limitSizeInGb: int = None,
addTimestamp: bool = None,
timestampPosition: int = None) -> dict[str, object] | str:
+ """
+ Save new snapshot settings.
+
+ Parameters
+ ----------
+ dispSnapshot : bool, optional
+ Whether to display snapshots.
+ dispDuration : int, optional
+ Display duration for snapshots.
+ limitTotalSize : bool, optional
+ Whether to limit total snapshot size.
+ limitSizeInGb : int, optional
+ Limit size in GB.
+ addTimestamp : bool, optional
+ Whether to add a timestamp to snapshots.
+ timestampPosition : int, optional
+ Position of the timestamp.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the save operation or error details.
+ """
api_name = 'SYNO.SurveillanceStation.SnapShot'
info = self.gen_list[api_name]
api_path = info['path']
@@ -2955,6 +6017,29 @@ def save_snapshot(self,
byteSize: int = None,
# TODO to check
imageData: str = None) -> dict[str, object] | str:
+ """
+ Save a new snapshot.
+
+ Parameters
+ ----------
+ camName : str, optional
+ Name of the camera.
+ createdTm : int, optional
+ Creation timestamp.
+ width : int, optional
+ Width of the snapshot.
+ height : int, optional
+ Height of the snapshot.
+ byteSize : int, optional
+ Size of the snapshot in bytes.
+ imageData : str, optional
+ Image data (to check).
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the save operation or error details.
+ """
api_name = 'SYNO.SurveillanceStation.SnapShot'
info = self.gen_list[api_name]
api_path = info['path']
@@ -2969,6 +6054,19 @@ def save_snapshot(self,
def check_snapshot_status(self,
dispSnapshot: bool = None) -> dict[str, object] | str:
+ """
+ Check the status of snapshot display.
+
+ Parameters
+ ----------
+ dispSnapshot : bool, optional
+ Whether to display snapshots.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Status information or error details.
+ """
api_name = 'SYNO.SurveillanceStation.SnapShot'
info = self.gen_list[api_name]
api_path = info['path']
@@ -2985,6 +6083,19 @@ def check_snapshot_status(self,
def enable_visualstation(self,
# TODO to check
vslist: str = None) -> dict[str, object] | str:
+ """
+ Enable VisualStation devices.
+
+ Parameters
+ ----------
+ vslist : str, optional
+ Comma-separated list of VisualStation IDs to enable (to check).
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the enable operation or error details.
+ """
api_name = 'SYNO.SurveillanceStation.VisualStation'
info = self.gen_list[api_name]
api_path = info['path']
@@ -3005,6 +6116,29 @@ def update_vs_network_config(self,
blDhcp: bool = None,
# TODO to check
name: str = None) -> dict[str, object] | str:
+ """
+ Update the network configuration for a VisualStation device.
+
+ Parameters
+ ----------
+ vsMAc : str, optional
+ MAC address of the VisualStation.
+ ip : str, optional
+ IP address to assign.
+ mask : str, optional
+ Subnet mask.
+ gateway : str, optional
+ Gateway address.
+ blDhcp : bool, optional
+ Whether to use DHCP.
+ name : str, optional
+ Name of the VisualStation (to check).
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the update operation or error details.
+ """
api_name = 'SYNO.SurveillanceStation.VisualStation'
info = self.gen_list[api_name]
api_path = info['path']
@@ -3020,6 +6154,19 @@ def update_vs_network_config(self,
def lock_visualstation_by_id(self,
# TODO to check
vslist: str = None) -> dict[str, object] | str:
+ """
+ Lock VisualStation devices by ID.
+
+ Parameters
+ ----------
+ vslist : str, optional
+ Comma-separated list of VisualStation IDs to lock (to check).
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the lock operation or error details.
+ """
api_name = 'SYNO.SurveillanceStation.VisualStation'
info = self.gen_list[api_name]
api_path = info['path']
@@ -3034,6 +6181,14 @@ def lock_visualstation_by_id(self,
# TODO to check
def enumerate_vs_owner_info(self) -> dict[str, object] | str:
+ """
+ Enumerate VisualStation owner information.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Owner information or error details.
+ """
api_name = 'SYNO.SurveillanceStation.VisualStation'
info = self.gen_list[api_name]
api_path = info['path']
@@ -3044,6 +6199,19 @@ def enumerate_vs_owner_info(self) -> dict[str, object] | str:
def unlock_visualstation_by_id(self,
# TODO to check
vslist: str = None) -> dict[str, object] | str:
+ """
+ Unlock VisualStation devices by ID.
+
+ Parameters
+ ----------
+ vslist : str, optional
+ Comma-separated list of VisualStation IDs to unlock (to check).
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the unlock operation or error details.
+ """
api_name = 'SYNO.SurveillanceStation.VisualStation'
info = self.gen_list[api_name]
api_path = info['path']
@@ -3059,6 +6227,19 @@ def unlock_visualstation_by_id(self,
def disable_visualstation_by_id(self,
# TODO to check
vslist: str = None) -> dict[str, object] | str:
+ """
+ Disable VisualStation devices by ID.
+
+ Parameters
+ ----------
+ vslist : str, optional
+ Comma-separated list of VisualStation IDs to disable (to check).
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the disable operation or error details.
+ """
api_name = 'SYNO.SurveillanceStation.VisualStation'
info = self.gen_list[api_name]
api_path = info['path']
@@ -3074,6 +6255,19 @@ def disable_visualstation_by_id(self,
def delete_specific_visualstation(self,
# TODO to check
vslist: str = None) -> dict[str, object] | str:
+ """
+ Delete specific VisualStation devices by ID.
+
+ Parameters
+ ----------
+ vslist : str, optional
+ Comma-separated list of VisualStation IDs to delete (to check).
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the delete operation or error details.
+ """
api_name = 'SYNO.SurveillanceStation.VisualStation'
info = self.gen_list[api_name]
api_path = info['path']
@@ -3089,6 +6283,19 @@ def delete_specific_visualstation(self,
def enumerate_layout_visualstation(self,
# TODO to check
vsId: int = None) -> dict[str, object] | str:
+ """
+ Enumerate VisualStation layouts.
+
+ Parameters
+ ----------
+ vsId : int, optional
+ VisualStation ID to filter layouts (to check).
+
+ Returns
+ -------
+ dict[str, object] or str
+ Layout information or error details.
+ """
api_name = 'SYNO.SurveillanceStation.VisualStation.Layout'
info = self.gen_list[api_name]
api_path = info['path']
@@ -3112,6 +6319,35 @@ def save_layout_information(self,
channelList: Any = None,
# TODO to check
customPosList: str = None) -> dict[str, object] | str:
+ """
+ Save layout information for a VisualStation.
+
+ Parameters
+ ----------
+ id : int, optional
+ Layout ID.
+ vsId : int, optional
+ VisualStation ID.
+ name : str, optional
+ Name of the layout.
+ canGrpId : int, optional
+ Camera group ID.
+ isDefault : int, optional
+ Whether this is the default layout.
+ isFixAspectRatio : int, optional
+ Whether to fix the aspect ratio.
+ layoutType : int, optional
+ Type of the layout.
+ channelList : Any, optional
+ List of channels in the layout.
+ customPosList : str, optional
+ Custom position list (to check).
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the save operation or error details.
+ """
api_name = 'SYNO.SurveillanceStation.VisualStation.Layout'
info = self.gen_list[api_name]
api_path = info['path']
@@ -3128,6 +6364,21 @@ def delete_layout_visualstation(self,
id: int = None,
# TODO to check
vsId: int = None) -> dict[str, object] | str:
+ """
+ Delete a VisualStation layout.
+
+ Parameters
+ ----------
+ id : int, optional
+ Layout ID to delete.
+ vsId : int, optional
+ VisualStation ID (to check).
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the delete operation or error details.
+ """
api_name = 'SYNO.SurveillanceStation.VisualStation.Layout'
info = self.gen_list[api_name]
api_path = info['path']
@@ -3142,6 +6393,14 @@ def delete_layout_visualstation(self,
# TODO to check
def clear_visualstation_search_result(self) -> dict[str, object] | str:
+ """
+ Clear VisualStation search results.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the clear operation or error details.
+ """
api_name = 'SYNO.SurveillanceStation.VisualStation.Search'
info = self.gen_list[api_name]
api_path = info['path']
@@ -3152,6 +6411,19 @@ def clear_visualstation_search_result(self) -> dict[str, object] | str:
def get_visualstation_ip_info(self,
# TODO to check
ip: int = None) -> dict[str, object] | str:
+ """
+ Retrieve VisualStation IP information.
+
+ Parameters
+ ----------
+ ip : int, optional
+ IP address to search for (to check).
+
+ Returns
+ -------
+ dict[str, object] or str
+ IP information or error details.
+ """
api_name = 'SYNO.SurveillanceStation.VisualStation.Search'
info = self.gen_list[api_name]
api_path = info['path']
@@ -3166,6 +6438,14 @@ def get_visualstation_ip_info(self,
# TODO to check
def stop_previous_visualstation_search(self) -> dict[str, object] | str:
+ """
+ Stop the previous VisualStation search operation.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the stop operation or error details.
+ """
api_name = 'SYNO.SurveillanceStation.VisualStation.Search'
info = self.gen_list[api_name]
api_path = info['path']
@@ -3176,6 +6456,19 @@ def stop_previous_visualstation_search(self) -> dict[str, object] | str:
def get_visualstation_list(self,
# TODO to check
offset: int = None) -> dict[str, object] | str:
+ """
+ Retrieve the list of VisualStation devices.
+
+ Parameters
+ ----------
+ offset : int, optional
+ Offset for pagination (to check).
+
+ Returns
+ -------
+ dict[str, object] or str
+ List of VisualStation devices or error details.
+ """
api_name = 'SYNO.SurveillanceStation.VisualStation.Layout'
info = self.gen_list[api_name]
api_path = info['path']
@@ -3189,6 +6482,14 @@ def get_visualstation_list(self,
return self.request_data(api_name, api_path, req_param)
def get_number_of_controller(self) -> dict[str, object] | str:
+ """
+ Get the number of controllers in the system.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Number of controllers or error details.
+ """
api_name = 'SYNO.SurveillanceStation.AxisAcsCtrler'
info = self.gen_list[api_name]
api_path = info['path']
@@ -3197,6 +6498,19 @@ def get_number_of_controller(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def get_cardholder_count(self, filterKeyword: str = None) -> dict[str, object] | str:
+ """
+ Get the count of cardholders, optionally filtered by keyword.
+
+ Parameters
+ ----------
+ filterKeyword : str, optional
+ Keyword to filter cardholders.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Cardholder count or error details.
+ """
api_name = 'SYNO.SurveillanceStation.AxisAcsCtrler'
info = self.gen_list[api_name]
api_path = info['path']
@@ -3211,6 +6525,14 @@ def get_cardholder_count(self, filterKeyword: str = None) -> dict[str, object] |
return self.request_data(api_name, api_path, req_param)
def enum_all_controllers_logger(self) -> dict[str, object] | str:
+ """
+ Enumerate all controller logger configurations.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Logger configuration information or error details.
+ """
api_name = 'SYNO.SurveillanceStation.AxisAcsCtrler'
info = self.gen_list[api_name]
api_path = info['path']
@@ -3222,6 +6544,21 @@ def get_cardholder_photo(self,
photo_name: str = None,
# TODO to check
isRedirectCgi: bool = None) -> dict[str, object] | str:
+ """
+ Retrieve a cardholder's photo.
+
+ Parameters
+ ----------
+ photo_name : str, optional
+ Name of the photo file.
+ isRedirectCgi : bool, optional
+ Whether to redirect to CGI for the photo (to check).
+
+ Returns
+ -------
+ dict[str, object] or str
+ Photo data or error details.
+ """
api_name = 'SYNO.SurveillanceStation.AxisAcsCtrler'
info = self.gen_list[api_name]
api_path = info['path']
@@ -3249,6 +6586,43 @@ def get_log_count(self,
doorIds: str = None,
eventTypes: str = None,
update: int = None) -> dict[str, object] | str:
+ """
+ Get the count of logs with optional filters.
+
+ Parameters
+ ----------
+ start : int, optional
+ Start index for pagination.
+ limit : int, optional
+ Maximum number of results to return.
+ filterType : int, optional
+ Type of filter to apply.
+ filterEventSource : Any, optional
+ Event source filter.
+ filterSource : int, optional
+ Source filter.
+ filterEventSourceItem : int, optional
+ Event source item filter.
+ filterTimeFrom : int, optional
+ Start time for filtering.
+ filterTimeTo : int, optional
+ End time for filtering.
+ filterKeyword : str, optional
+ Keyword to filter logs.
+ timezoneOffset : int, optional
+ Timezone offset.
+ doorIds : str, optional
+ Door IDs filter.
+ eventTypes : str, optional
+ Event types filter.
+ update : int, optional
+ Update flag.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Log count or error details.
+ """
api_name = 'SYNO.SurveillanceStation.AxisAcsCtrler'
info = self.gen_list[api_name]
api_path = info['path']
@@ -3268,6 +6642,27 @@ def get_cardholder_info(self,
filterKeyword: str = None,
filterStatus: int = None,
filterCtrlerId: int = None) -> dict[str, object] | str:
+ """
+ Retrieve cardholder information with optional filters.
+
+ Parameters
+ ----------
+ start : int, optional
+ Start index for pagination.
+ limit : int, optional
+ Maximum number of results to return.
+ filterKeyword : str, optional
+ Keyword to filter cardholders.
+ filterStatus : int, optional
+ Status filter.
+ filterCtrlerId : int, optional
+ Controller ID filter.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Cardholder information or error details.
+ """
api_name = 'SYNO.SurveillanceStation.AxisAcsCtrler'
info = self.gen_list[api_name]
api_path = info['path']
@@ -3284,6 +6679,21 @@ def retrieve_last_access_credential(self,
ctrlerId: int = None,
# TODO to check
idPtId: int = None) -> dict[str, object] | str:
+ """
+ Retrieve the last access credential for a controller.
+
+ Parameters
+ ----------
+ ctrlerId : int, optional
+ Controller ID.
+ idPtId : int, optional
+ ID/point ID (to check).
+
+ Returns
+ -------
+ dict[str, object] or str
+ Last access credential information or error details.
+ """
api_name = 'SYNO.SurveillanceStation.AxisAcsCtrler'
info = self.gen_list[api_name]
api_path = info['path']
@@ -3300,6 +6710,21 @@ def retrieve_last_access_credential(self,
def enable_disable_controller(self,
blEnable: bool = None,
arrayJson: str = None) -> dict[str, object] | str:
+ """
+ Enable or disable controllers.
+
+ Parameters
+ ----------
+ blEnable : bool, optional
+ Whether to enable (True) or disable (False) controllers.
+ arrayJson : str, optional
+ JSON array of controller IDs.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the operation or error details.
+ """
api_name = 'SYNO.SurveillanceStation.AxisAcsCtrler'
info = self.gen_list[api_name]
api_path = info['path']
@@ -3323,6 +6748,37 @@ def acknowledge_all_alarm_level_log(self,
doorIds: str = None,
eventTypes: str = None,
update: int = None) -> dict[str, object] | str:
+ """
+ Acknowledge all alarm level logs with optional filters.
+
+ Parameters
+ ----------
+ start : int, optional
+ Start index for pagination.
+ limit : int, optional
+ Maximum number of results to return.
+ filterEventSource : Any, optional
+ Event source filter.
+ filterSource : int, optional
+ Source filter.
+ filterEventSourceItem : str, optional
+ Event source item filter.
+ filterTimeFrom : int, optional
+ Start time for filtering.
+ filterKeyword : str, optional
+ Keyword to filter logs.
+ doorIds : str, optional
+ Door IDs filter.
+ eventTypes : str, optional
+ Event types filter.
+ update : int, optional
+ Update flag.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the acknowledge operation or error details.
+ """
api_name = 'SYNO.SurveillanceStation.AxisAcsCtrler'
info = self.gen_list[api_name]
api_path = info['path']
@@ -3338,6 +6794,28 @@ def acknowledge_all_alarm_level_log(self,
def modify_controller_logger_config(self,
# TODO to check
data: Any = None) -> dict[str, object] | str:
+ """
+ Modify the logger configuration for a controller.
+
+ Parameters
+ ----------
+ data : Any, optional
+ Logger configuration data (see example in docstring).
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the save operation or error details.
+
+ Notes
+ -----
+ Example data:
+ data = {
+ "log_evt": "11111111111111111111111111111111111111",
+ "id": 97,
+ "log_alarm": "00111111111111111111111111111111111111"
+ }
+ """
api_name = 'SYNO.SurveillanceStation.AxisAcsCtrler'
info = self.gen_list[api_name]
api_path = info['path']
@@ -3357,6 +6835,23 @@ def modify_controller_logger_config(self,
def save_controller_settings(self,
arrayJson: str = None) -> dict[str, object] | str:
+ """
+ Save controller settings for Surveillance Station.
+
+ Parameters
+ ----------
+ arrayJson : str, optional
+ JSON string representing controller settings. Example:
+ \\[\\{"enable": true, "id": 97, "name": "ctrler1", "host": "10.13.12.173", "port": 80,
+ "model": "A1001", "username": "root", "password": "Q__Q-__-", "time_server":
+ "SurveillanceStation", "time_zone": "Fiji", "door": \\[\\{"id": 231, "name": "FrontDoor",
+ "enable_cam": true, "cam_ds_id": 0, "cam_id": 13\\}\\]\\}\\]
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the save operation or error details.
+ """
api_name = 'SYNO.SurveillanceStation.AxisAcsCtrler'
info = self.gen_list[api_name]
api_path = info['path']
@@ -3364,10 +6859,10 @@ def save_controller_settings(self,
"""arrayJson example:
- arrayJson="[{\"enable\":true,\"id\":97,\"name\":\"ctrler1\",\"host\":\"10.13.12.173\",\"port\":80,
+ arrayJson="\\[\\{\"enable\":true,\"id\":97,\"name\":\"ctrler1\",\"host\":\"10.13.12.173\",\"port\":80,
\"model\":\"A1001\",\"username\":\"root\",\"password\":\"Q__Q-__-\",\"time_server\":
- \"SurveillanceStation\",\"time_zone\":\"Fiji\",\"door\":[{\"id\":231,\"name\":\"FrontDoor\",
- \"enable_cam\":true,\"cam_ds_id\":0,\"cam_id\":13}]}]\" """
+ \"SurveillanceStation\",\"time_zone\":\"Fiji\",\"door\":\\[\\{\"id\":231,\"name\":\"FrontDoor\",
+ \"enable_cam\":true,\"cam_ds_id\":0,\"cam_id\":13\\}\\]\\}\\]\" """
for key, val in locals().items():
if key not in ['self', 'api_name', 'info', 'api_path', 'req_param']:
@@ -3390,6 +6885,41 @@ def download_filtered_logs(self,
eventTypes: str = None,
# TODO to modify for download?
update: int = None) -> dict[str, object] | str:
+ """
+ Download filtered logs from Surveillance Station.
+
+ Parameters
+ ----------
+ start : int, optional
+ Start index for pagination.
+ limit : int, optional
+ Maximum number of results to return.
+ filterType : int, optional
+ Type of filter to apply.
+ filterEventSource : int, optional
+ Event source filter.
+ filterSource : int, optional
+ Source filter.
+ filterEventSourceItem : str, optional
+ Event source item filter.
+ filterTimeFrom : int, optional
+ Start time for filtering.
+ filterTimeTo : int, optional
+ End time for filtering.
+ filterKeyword : str, optional
+ Keyword to filter logs.
+ doorIds : str, optional
+ Door IDs filter.
+ eventTypes : str, optional
+ Event types filter.
+ update : int, optional
+ Update flag.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Downloaded log data or error details.
+ """
api_name = 'SYNO.SurveillanceStation.AxisAcsCtrler'
info = self.gen_list[api_name]
api_path = info['path']
@@ -3409,6 +6939,27 @@ def get_door_name_from_controller(self,
userName: str = None,
# TODO to check
password: int = None) -> dict[str, object] | str:
+ """
+ Retrieve door names from a specific controller.
+
+ Parameters
+ ----------
+ ctrlerId : int, optional
+ Controller ID.
+ ip : str, optional
+ Controller IP address.
+ port : int, optional
+ Controller port.
+ userName : str, optional
+ Username for authentication.
+ password : int, optional
+ Password for authentication (to check).
+
+ Returns
+ -------
+ dict[str, object] or str
+ Door names or error details.
+ """
api_name = 'SYNO.SurveillanceStation.AxisAcsCtrler'
info = self.gen_list[api_name]
api_path = info['path']
@@ -3428,6 +6979,27 @@ def test_connection_and_authentication(self,
userName: str = None,
# TODO to check
password: int = None) -> dict[str, object] | str:
+ """
+ Test connection and authentication to a controller.
+
+ Parameters
+ ----------
+ ctrlerId : int, optional
+ Controller ID.
+ ip : str, optional
+ Controller IP address.
+ port : int, optional
+ Controller port.
+ userName : str, optional
+ Username for authentication.
+ password : int, optional
+ Password for authentication (to check).
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the test or error details.
+ """
api_name = 'SYNO.SurveillanceStation.AxisAcsCtrler'
info = self.gen_list[api_name]
api_path = info['path']
@@ -3447,6 +7019,27 @@ def enumerate_controller_list_info(self,
blIncludeRecCnt: bool = None,
# TODO to check
blIncludeAuInfo: bool = None) -> dict[str, object] | str:
+ """
+ Enumerate controller list information.
+
+ Parameters
+ ----------
+ start : int, optional
+ Start index for pagination.
+ limit : int, optional
+ Maximum number of results to return.
+ update : int, optional
+ Update flag.
+ blIncludeRecCnt : bool, optional
+ Whether to include record count.
+ blIncludeAuInfo : bool, optional
+ Whether to include additional info (to check).
+
+ Returns
+ -------
+ dict[str, object] or str
+ Controller list information or error details.
+ """
api_name = 'SYNO.SurveillanceStation.AxisAcsCtrler'
info = self.gen_list[api_name]
api_path = info['path']
@@ -3461,6 +7054,19 @@ def enumerate_controller_list_info(self,
def save_cardholder_setting(self,
arrayJson: str = None) -> dict[str, object] | str:
+ """
+ Save cardholder settings.
+
+ Parameters
+ ----------
+ arrayJson : str, optional
+ JSON string representing cardholder settings.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the save operation or error details.
+ """
api_name = 'SYNO.SurveillanceStation.AxisAcsCtrler'
info = self.gen_list[api_name]
api_path = info['path']
@@ -3475,6 +7081,19 @@ def save_cardholder_setting(self,
def enumerate_door_info(self,
DoorIds: str = None) -> dict[str, object] | str:
+ """
+ Enumerate door information.
+
+ Parameters
+ ----------
+ DoorIds : str, optional
+ Comma-separated list of door IDs.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Door information or error details.
+ """
api_name = 'SYNO.SurveillanceStation.AxisAcsCtrler'
info = self.gen_list[api_name]
api_path = info['path']
@@ -3498,6 +7117,37 @@ def clear_logs_surveillance_station(self,
doorIds: str = None,
eventTypes: str = None,
update: int = None) -> dict[str, object] | str:
+ """
+ Clear logs in Surveillance Station with optional filters.
+
+ Parameters
+ ----------
+ filterType : int, optional
+ Type of filter to apply.
+ filterEventSource : Any, optional
+ Event source filter.
+ filterSource : int, optional
+ Source filter.
+ filterEventSourceItem : str, optional
+ Event source item filter.
+ filterTimeFrom : int, optional
+ Start time for filtering.
+ filterTimeTo : int, optional
+ End time for filtering.
+ filterKeyword : str, optional
+ Keyword to filter logs.
+ doorIds : str, optional
+ Door IDs filter.
+ eventTypes : str, optional
+ Event types filter.
+ update : int, optional
+ Update flag.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the clear operation or error details.
+ """
api_name = 'SYNO.SurveillanceStation.AxisAcsCtrler'
info = self.gen_list[api_name]
api_path = info['path']
@@ -3511,6 +7161,14 @@ def clear_logs_surveillance_station(self,
return self.request_data(api_name, api_path, req_param)
def list_all_user_privilege(self) -> dict[str, object] | str:
+ """
+ List all user privileges in Surveillance Station.
+
+ Returns
+ -------
+ dict[str, object] or str
+ List of user privileges or error details.
+ """
api_name = 'SYNO.SurveillanceStation.AxisAcsCtrler'
info = self.gen_list[api_name]
api_path = info['path']
@@ -3527,6 +7185,21 @@ def manual_lock_operation(self,
doorId: int = None,
# TODO to check
operation: int = None) -> dict[str, object] | str:
+ """
+ Perform a manual lock or unlock operation on a door.
+
+ Parameters
+ ----------
+ doorId : int, optional
+ Door ID to operate on.
+ operation : int, optional
+ Operation code (to check).
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the operation or error details.
+ """
api_name = 'SYNO.SurveillanceStation.AxisAcsCtrler'
info = self.gen_list[api_name]
api_path = info['path']
@@ -3541,6 +7214,19 @@ def manual_lock_operation(self,
def save_user_door_priv_setting(self,
arrayJson: str = None) -> dict[str, object] | str:
+ """
+ Save user door privilege settings.
+
+ Parameters
+ ----------
+ arrayJson : str, optional
+ JSON string representing user door privilege settings.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the save operation or error details.
+ """
api_name = 'SYNO.SurveillanceStation.AxisAcsCtrler'
info = self.gen_list[api_name]
api_path = info['path']
@@ -3569,6 +7255,47 @@ def list_all_logs(self,
update: int = None,
blIncludeRecCnt: bool = None,
blIncludeAuInfo: bool = None) -> dict[str, object] | str:
+ """
+ List all logs in Surveillance Station with optional filters.
+
+ Parameters
+ ----------
+ start : int, optional
+ Start index for pagination.
+ limit : int, optional
+ Maximum number of results to return.
+ filterType : int, optional
+ Type of filter to apply.
+ filterEventSource : Any, optional
+ Event source filter.
+ filterSource : int, optional
+ Source filter.
+ filterEventSourceItem : str, optional
+ Event source item filter.
+ filterTimeFrom : int, optional
+ Start time for filtering.
+ filterTimeTo : int, optional
+ End time for filtering.
+ filterKeyword : str, optional
+ Keyword to filter logs.
+ timezoneOffset : int, optional
+ Timezone offset.
+ doorIds : str, optional
+ Door IDs filter.
+ eventTypes : str, optional
+ Event types filter.
+ update : int, optional
+ Update flag.
+ blIncludeRecCnt : bool, optional
+ Whether to include record count.
+ blIncludeAuInfo : bool, optional
+ Whether to include additional info.
+
+ Returns
+ -------
+ dict[str, object] or str
+ List of logs or error details.
+ """
api_name = 'SYNO.SurveillanceStation.AxisAcsCtrler'
info = self.gen_list[api_name]
api_path = info['path']
@@ -3582,6 +7309,19 @@ def list_all_logs(self,
return self.request_data(api_name, api_path, req_param)
def delete_selected_controller(self, ids: str = None) -> dict[str, object] | str:
+ """
+ Delete selected controllers from Surveillance Station.
+
+ Parameters
+ ----------
+ ids : str, optional
+ Comma-separated string of controller IDs to delete.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the delete operation or error details.
+ """
api_name = 'SYNO.SurveillanceStation.AxisAcsCtrler'
info = self.gen_list[api_name]
api_path = info['path']
@@ -3596,6 +7336,19 @@ def delete_selected_controller(self, ids: str = None) -> dict[str, object] | str
# TODO to check
def retrieve_data_from_controller(self, ctrlerId: str = None) -> dict[str, object] | str:
+ """
+ Retrieve data from a specific controller.
+
+ Parameters
+ ----------
+ ctrlerId : str, optional
+ ID of the controller to retrieve data from.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Retrieved data or error details.
+ """
api_name = 'SYNO.SurveillanceStation.AxisAcsCtrler'
info = self.gen_list[api_name]
api_path = info['path']
@@ -3609,6 +7362,19 @@ def retrieve_data_from_controller(self, ctrlerId: str = None) -> dict[str, objec
return self.request_data(api_name, api_path, req_param)
def block_cardholder(self, arrayJson: str = None) -> dict[str, object] | str:
+ """
+ Block cardholders in Surveillance Station.
+
+ Parameters
+ ----------
+ arrayJson : str, optional
+ JSON string representing cardholder(s) to block.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the block operation or error details.
+ """
api_name = 'SYNO.SurveillanceStation.AxisAcsCtrler'
info = self.gen_list[api_name]
api_path = info['path']
@@ -3623,6 +7389,14 @@ def block_cardholder(self, arrayJson: str = None) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def get_controller_count(self) -> dict[str, object] | str:
+ """
+ Get the count of controllers by category.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Controller count or error details.
+ """
api_name = 'SYNO.SurveillanceStation.AxisAcsCtrler'
info = self.gen_list[api_name]
api_path = info['path']
@@ -3632,6 +7406,14 @@ def get_controller_count(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def start_controller_search(self) -> dict[str, object] | str:
+ """
+ Start searching for controllers.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the search operation or error details.
+ """
api_name = 'SYNO.SurveillanceStation.AxisAcsCtrler.Search'
info = self.gen_list[api_name]
api_path = info['path']
@@ -3639,13 +7421,28 @@ def start_controller_search(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
- def get_controller_search_result(self,
- pid: int = None,
- offset: int = None) -> dict[str, object] | str:
+ def get_controller_search_info(self,
+ pid: int = None,
+ offset: int = None) -> dict[str, object] | str:
+ """
+ Get information about the current controller search.
+
+ Parameters
+ ----------
+ pid : int, optional
+ Process ID of the search.
+ offset : int, optional
+ Offset for paginated results.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Search information or error details.
+ """
api_name = 'SYNO.SurveillanceStation.AxisAcsCtrler.Search'
info = self.gen_list[api_name]
api_path = info['path']
- req_param = {'version': info['maxVersion'], 'method': 'InfoGet'}
+ req_param = {'version': info['maxVersion'], 'method': 'GetInfo'}
for key, val in locals().items():
if key not in ['self', 'api_name', 'info', 'api_path', 'req_param']:
@@ -3657,6 +7454,19 @@ def get_controller_search_result(self,
def enumerate_digital_output(self,
# TODO to check
camId: int = None) -> dict[str, object] | str:
+ """
+ Enumerate digital output devices.
+
+ Parameters
+ ----------
+ camId : int, optional
+ Camera ID to filter digital outputs.
+
+ Returns
+ -------
+ dict[str, object] or str
+ List of digital outputs or error details.
+ """
api_name = 'SYNO.SurveillanceStation.DigitalOutput'
info = self.gen_list[api_name]
api_path = info['path']
@@ -3676,6 +7486,27 @@ def save_digital_output_parameters(self,
normal_state: int = None,
# TODO to check
trigger_state: bool = None) -> dict[str, object] | str:
+ """
+ Save parameters for a digital output device.
+
+ Parameters
+ ----------
+ camId : int, optional
+ Camera ID.
+ idx : int, optional
+ Index of the digital output.
+ keep_setting : bool, optional
+ Whether to keep the current setting.
+ normal_state : int, optional
+ Normal state value.
+ trigger_state : bool, optional
+ Trigger state value.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the save operation or error details.
+ """
api_name = 'SYNO.SurveillanceStation.DigitalOutput'
info = self.gen_list[api_name]
api_path = info['path']
@@ -3697,6 +7528,31 @@ def long_polling_digital_output_status(self,
trigger: bool = None,
# TODO to check
timeOut: int = None) -> dict[str, object] | str:
+ """
+ Perform long polling to get the status of a digital output.
+
+ Parameters
+ ----------
+ camId : int, optional
+ Camera ID.
+ idx : int, optional
+ Index of the digital output.
+ keep : bool, optional
+ Whether to keep polling.
+ setNormalCap : bool, optional
+ Set normal capability.
+ normal : int, optional
+ Normal state value.
+ trigger : bool, optional
+ Trigger state value.
+ timeOut : int, optional
+ Timeout for polling.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Status information or error details.
+ """
api_name = 'SYNO.SurveillanceStation.DigitalOutput'
info = self.gen_list[api_name]
api_path = info['path']
@@ -3713,6 +7569,21 @@ def trigger_external_event(self,
eventId: int = None,
# TODO to check
eventName: str = None) -> dict[str, object] | str:
+ """
+ Trigger an external event in Surveillance Station.
+
+ Parameters
+ ----------
+ eventId : int, optional
+ ID of the event to trigger.
+ eventName : str, optional
+ Name of the event to trigger.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the trigger operation or error details.
+ """
api_name = 'SYNO.SurveillanceStation.ExternalEvent'
info = self.gen_list[api_name]
api_path = info['path']
@@ -3731,6 +7602,25 @@ def get_list_io_modules(self,
blFromList: bool = None,
# TODO to check
ownerDsId: int = None) -> dict[str, object] | str:
+ """
+ Get a list of I/O modules.
+
+ Parameters
+ ----------
+ start : int, optional
+ Start index for pagination.
+ limit : int, optional
+ Maximum number of results to return.
+ blFromList : bool, optional
+ Whether to get from list.
+ ownerDsId : int, optional
+ Owner device station ID.
+
+ Returns
+ -------
+ dict[str, object] or str
+ List of I/O modules or error details.
+ """
api_name = 'SYNO.SurveillanceStation.IOModule'
info = self.gen_list[api_name]
api_path = info['path']
@@ -3752,6 +7642,31 @@ def get_io_port_list(self,
Vendor: str = None,
# TODO to check
Model: str = None) -> dict[str, object] | str:
+ """
+ Get a list of I/O ports for a module.
+
+ Parameters
+ ----------
+ Id : int, optional
+ Module ID.
+ Port : int, optional
+ Port number.
+ IP : str, optional
+ IP address.
+ User : str, optional
+ Username.
+ Pass : str, optional
+ Password.
+ Vendor : str, optional
+ Vendor name.
+ Model : str, optional
+ Model name.
+
+ Returns
+ -------
+ dict[str, object] or str
+ List of I/O ports or error details.
+ """
api_name = 'SYNO.SurveillanceStation.IOModule'
info = self.gen_list[api_name]
api_path = info['path']
@@ -3766,6 +7681,14 @@ def get_io_port_list(self,
# TODO to check
def get_supported_list_io_modules(self) -> dict[str, object] | str:
+ """
+ Get a list of supported I/O module vendor models.
+
+ Returns
+ -------
+ dict[str, object] or str
+ List of supported vendor models or error details.
+ """
api_name = 'SYNO.SurveillanceStation.IOModule'
info = self.gen_list[api_name]
api_path = info['path']
@@ -3790,6 +7713,45 @@ def save_setting_io_module(self,
ntpEnable: bool = None,
# TODO to check
DIOdata: Any = None) -> dict[str, object] | str:
+ """
+ Save or update the settings for an I/O module in Surveillance Station.
+
+ Parameters
+ ----------
+ name : str, optional
+ Name of the I/O module.
+ id : int, optional
+ ID of the I/O module.
+ ownerDsId : int, optional
+ Owner device station ID.
+ vendor : str, optional
+ Vendor name of the I/O module.
+ model : str, optional
+ Model name of the I/O module.
+ ip : str, optional
+ IP address of the I/O module.
+ port : int, optional
+ Port number for the I/O module.
+ userName : str, optional
+ Username for authentication.
+ enabled : bool, optional
+ Whether the I/O module is enabled.
+ status : int, optional
+ Status code of the I/O module.
+ timeServer : str, optional
+ Time server address.
+ passWord : str, optional
+ Password for authentication.
+ ntpEnable : bool, optional
+ Whether NTP is enabled.
+ DIOdata : Any, optional
+ Digital I/O data (structure to be checked).
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the save operation or error details.
+ """
api_name = 'SYNO.SurveillanceStation.IOModule'
info = self.gen_list[api_name]
api_path = info['path']
@@ -3805,6 +7767,19 @@ def save_setting_io_module(self,
def enable_io_modules(self,
# TODO to check
iomlist: str = None) -> dict[str, object] | str:
+ """
+ Enable specified I/O modules.
+
+ Parameters
+ ----------
+ iomlist : str, optional
+ Comma-separated list of I/O module IDs to enable.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the enable operation or error details.
+ """
api_name = 'SYNO.SurveillanceStation.IOModule'
info = self.gen_list[api_name]
api_path = info['path']
@@ -3820,6 +7795,19 @@ def enable_io_modules(self,
def disable_io_modules(self,
# TODO to check
iomlist: str = None) -> dict[str, object] | str:
+ """
+ Disable specified I/O modules.
+
+ Parameters
+ ----------
+ iomlist : str, optional
+ Comma-separated list of I/O module IDs to disable.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the disable operation or error details.
+ """
api_name = 'SYNO.SurveillanceStation.IOModule'
info = self.gen_list[api_name]
api_path = info['path']
@@ -3835,6 +7823,19 @@ def disable_io_modules(self,
def delete_io_modules(self,
# TODO to check
iomlist: str = None) -> dict[str, object] | str:
+ """
+ Delete specified I/O modules.
+
+ Parameters
+ ----------
+ iomlist : str, optional
+ Comma-separated list of I/O module IDs to delete.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the delete operation or error details.
+ """
api_name = 'SYNO.SurveillanceStation.IOModule'
info = self.gen_list[api_name]
api_path = info['path']
@@ -3855,6 +7856,29 @@ def test_connection_to_io_module(self,
passWord: str = None,
# TODO to check
model: str = None) -> dict[str, object] | str:
+ """
+ Test the connection to a specified I/O module.
+
+ Parameters
+ ----------
+ id : int, optional
+ ID of the I/O module.
+ port : str, optional
+ Port number for the I/O module.
+ ip : str, optional
+ IP address of the I/O module.
+ userName : str, optional
+ Username for authentication.
+ passWord : str, optional
+ Password for authentication.
+ model : str, optional
+ Model name of the I/O module.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the connection test or error details.
+ """
api_name = 'SYNO.SurveillanceStation.IOModule'
info = self.gen_list[api_name]
api_path = info['path']
@@ -3871,6 +7895,21 @@ def get_capability_io_module(self,
vendor: str = None,
# TODO to check
model: str = None) -> dict[str, object] | str:
+ """
+ Get the capability information for a specified I/O module.
+
+ Parameters
+ ----------
+ vendor : str, optional
+ Vendor name of the I/O module.
+ model : str, optional
+ Model name of the I/O module.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Capability information or error details.
+ """
api_name = 'SYNO.SurveillanceStation.IOModule'
info = self.gen_list[api_name]
api_path = info['path']
@@ -3887,6 +7926,21 @@ def configure_io_port_setting(self,
id: int = None,
# TODO to check
DIOdata: Any = None) -> dict[str, object] | str:
+ """
+ Configure the port settings for a specified I/O module.
+
+ Parameters
+ ----------
+ id : int, optional
+ ID of the I/O module.
+ DIOdata : Any, optional
+ Digital I/O data for port configuration (structure to be checked).
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the configuration or error details.
+ """
api_name = 'SYNO.SurveillanceStation.IOModule'
info = self.gen_list[api_name]
api_path = info['path']
@@ -3904,6 +7958,23 @@ def poll_trigger_state_io_module(self,
list: Any = None,
# TODO to check
timeOut: int = None) -> dict[str, object] | str:
+ """
+ Poll the trigger state of digital input (DI) ports for a specified I/O module.
+
+ Parameters
+ ----------
+ Id : int, optional
+ ID of the I/O module.
+ list : Any, optional
+ List of DI ports to poll (structure to be checked).
+ timeOut : int, optional
+ Timeout for polling operation.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Polling result or error details.
+ """
api_name = 'SYNO.SurveillanceStation.IOModule'
info = self.gen_list[api_name]
api_path = info['path']
@@ -3923,6 +7994,27 @@ def poll_do_trigger_module(self,
trigger: bool = None,
# TODO to check
timeOut: int = None) -> dict[str, object] | str:
+ """
+ Poll the trigger state of digital output (DO) ports for a specified I/O module.
+
+ Parameters
+ ----------
+ id : int, optional
+ ID of the I/O module.
+ idx : int, optional
+ Index of the DO port.
+ normal : int, optional
+ Normal state value.
+ trigger : bool, optional
+ Trigger state.
+ timeOut : int, optional
+ Timeout for polling operation.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Polling result or error details.
+ """
api_name = 'SYNO.SurveillanceStation.IOModule'
info = self.gen_list[api_name]
api_path = info['path']
@@ -3937,6 +8029,14 @@ def poll_do_trigger_module(self,
# TODO to check
def get_number_of_devices(self) -> dict[str, object] | str:
+ """
+ Get the number of I/O devices for each device station.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Number of devices or error details.
+ """
api_name = 'SYNO.SurveillanceStation.IOModule'
info = self.gen_list[api_name]
api_path = info['path']
@@ -3955,6 +8055,25 @@ def get_category_count_io_module(self,
ownerDsId: int = None,
# TODO to check
blFromList: bool = None) -> dict[str, object] | str:
+ """
+ Get the count of I/O modules by category.
+
+ Parameters
+ ----------
+ start : int, optional
+ Start index for pagination.
+ limit : int, optional
+ Maximum number of results to return.
+ ownerDsId : int, optional
+ Owner device station ID.
+ blFromList : bool, optional
+ Whether to get count from a list (to be checked).
+
+ Returns
+ -------
+ dict[str, object] or str
+ Count by category or error details.
+ """
api_name = 'SYNO.SurveillanceStation.IOModule'
info = self.gen_list[api_name]
api_path = info['path']
@@ -3969,20 +8088,36 @@ def get_category_count_io_module(self,
return self.request_data(api_name, api_path, req_param)
def start_search_io_module(self) -> dict[str, object] | str:
+ """
+ Start searching for I/O modules.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the search operation or error details.
+ """
api_name = 'SYNO.SurveillanceStation.IOModule.Search'
info = self.gen_list[api_name]
api_path = info['path']
req_param = {'version': info['maxVersion'], 'method': 'Start'}
- for key, val in locals().items():
- if key not in ['self', 'api_name', 'info', 'api_path', 'req_param']:
- if val is not None:
- req_param[str(key)] = val
-
return self.request_data(api_name, api_path, req_param)
def get_search_io_module_info(self,
pid: int = None) -> dict[str, object] | str:
+ """
+ Get information about the current I/O module search.
+
+ Parameters
+ ----------
+ pid : int, optional
+ Process ID of the search.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Search information or error details.
+ """
api_name = 'SYNO.SurveillanceStation.IOModule.Search'
info = self.gen_list[api_name]
api_path = info['path']
@@ -3998,6 +8133,19 @@ def get_search_io_module_info(self,
def get_current_camera_status(self,
# TODO not working
id_list: str = None) -> dict[str, object] | str:
+ """
+ Get the current status of specified cameras.
+
+ Parameters
+ ----------
+ id_list : str, optional
+ Comma-separated list of camera IDs.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Camera status information or error details.
+ """
api_name = 'SYNO.SurveillanceStation.Camera.Status'
info = self.gen_list[api_name]
api_path = info['path']
@@ -4013,6 +8161,19 @@ def get_current_camera_status(self,
def enum_preset_camera_list(self,
# TODO not working
cameraId: Any = None) -> dict[str, object] | str:
+ """
+ Enumerate the list of presets for a specified camera.
+
+ Parameters
+ ----------
+ cameraId : Any, optional
+ ID of the camera.
+
+ Returns
+ -------
+ dict[str, object] or str
+ List of camera presets or error details.
+ """
api_name = 'SYNO.SurveillanceStation.PTZ.Preset'
info = self.gen_list[api_name]
api_path = info['path']
@@ -4028,6 +8189,19 @@ def enum_preset_camera_list(self,
def get_preset_camera_capability(self,
# TODO not working
cameraId: int = None) -> dict[str, object] | str:
+ """
+ Get the capability information for camera presets.
+
+ Parameters
+ ----------
+ cameraId : int, optional
+ ID of the camera.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Preset capability information or error details.
+ """
api_name = 'SYNO.SurveillanceStation.PTZ.Preset'
info = self.gen_list[api_name]
api_path = info['path']
@@ -4046,6 +8220,25 @@ def record_current_camera_position(self,
speed: int = None,
# TODO not working
name: str = None) -> dict[str, object] | str:
+ """
+ Record the current position of a camera as a preset.
+
+ Parameters
+ ----------
+ cameraId : int, optional
+ ID of the camera.
+ position : int, optional
+ Preset position index.
+ speed : int, optional
+ Speed for moving to the preset.
+ name : str, optional
+ Name for the preset.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the record operation or error details.
+ """
api_name = 'SYNO.SurveillanceStation.PTZ.Preset'
info = self.gen_list[api_name]
api_path = info['path']
@@ -4062,6 +8255,21 @@ def delete_list_preset_camera(self,
cameraId: Any = None,
# TODO not working
position: str = None) -> dict[str, object] | str:
+ """
+ Delete specified presets from a camera.
+
+ Parameters
+ ----------
+ cameraId : Any, optional
+ ID of the camera.
+ position : str, optional
+ Preset position(s) to delete.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the delete operation or error details.
+ """
api_name = 'SYNO.SurveillanceStation.PTZ.Preset'
info = self.gen_list[api_name]
api_path = info['path']
@@ -4080,6 +8288,25 @@ def go_specific_preset_by_given_speed(self,
speed: int = None,
# TODO not working
type: int = None) -> dict[str, object] | str:
+ """
+ Move a camera to a specific preset position at a given speed.
+
+ Parameters
+ ----------
+ cameraId : Any, optional
+ ID of the camera.
+ position : int, optional
+ Preset position index.
+ speed : int, optional
+ Speed for moving to the preset.
+ type : int, optional
+ Type of preset move (to be checked).
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the move operation or error details.
+ """
api_name = 'SYNO.SurveillanceStation.PTZ.Preset'
info = self.gen_list[api_name]
api_path = info['path']
@@ -4096,6 +8323,21 @@ def set_current_camera_position(self,
cameraId: Any = None,
# TODO not working
bindPosition: int = None) -> dict[str, object] | str:
+ """
+ Set the current position of a camera as the home position.
+
+ Parameters
+ ----------
+ cameraId : Any, optional
+ ID of the camera.
+ bindPosition : int, optional
+ Position to bind as home.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the set operation or error details.
+ """
api_name = 'SYNO.SurveillanceStation.PTZ.Preset'
info = self.gen_list[api_name]
api_path = info['path']
@@ -4110,6 +8352,19 @@ def set_current_camera_position(self,
def enum_patrol_list(self,
cam: Any = None) -> dict[str, object] | str:
+ """
+ Enumerate the list of patrols for a specified camera.
+
+ Parameters
+ ----------
+ cam : Any, optional
+ Camera identifier.
+
+ Returns
+ -------
+ dict[str, object] or str
+ List of patrols or error details.
+ """
api_name = 'SYNO.SurveillanceStation.PTZ.Patrol'
info = self.gen_list[api_name]
api_path = info['path']
@@ -4124,6 +8379,19 @@ def enum_patrol_list(self,
def enum_patrol_name_list(self,
camId: Any = None) -> dict[str, object] | str:
+ """
+ Enumerate the list of patrol names for a specified camera.
+
+ Parameters
+ ----------
+ camId : Any, optional
+ Camera identifier.
+
+ Returns
+ -------
+ dict[str, object] or str
+ List of patrol names or error details.
+ """
api_name = 'SYNO.SurveillanceStation.PTZ.Patrol'
info = self.gen_list[api_name]
api_path = info['path']
@@ -4139,6 +8407,19 @@ def enum_patrol_name_list(self,
def load_patrol_detail(self,
# TODO not working
id: int = None) -> dict[str, object] | str:
+ """
+ Load the details of a specific patrol.
+
+ Parameters
+ ----------
+ id : int, optional
+ Patrol ID.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Patrol details or error information.
+ """
api_name = 'SYNO.SurveillanceStation.PTZ.Patrol'
info = self.gen_list[api_name]
api_path = info['path']
@@ -4159,6 +8440,29 @@ def add_or_modify_patrol(self,
name: str = None,
# TODO not working
presetList: Any = None) -> dict[str, object] | str:
+ """
+ Add or modify a patrol for a camera.
+
+ Parameters
+ ----------
+ camId : Any, optional
+ Camera identifier.
+ id : int, optional
+ Patrol ID.
+ stayTime : int, optional
+ Stay time at each preset.
+ speed : int, optional
+ Patrol speed.
+ name : str, optional
+ Name of the patrol.
+ presetList : Any, optional
+ List of presets for the patrol (structure to be checked).
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the add/modify operation or error details.
+ """
api_name = 'SYNO.SurveillanceStation.PTZ.Patrol'
info = self.gen_list[api_name]
api_path = info['path']
@@ -4175,6 +8479,21 @@ def delete_specific_patrol(self,
camId: Any = None,
# TODO not working
patrolId: str = None) -> dict[str, object] | str:
+ """
+ Delete a specific patrol from a camera.
+
+ Parameters
+ ----------
+ camId : Any, optional
+ Camera identifier.
+ patrolId : str, optional
+ Patrol ID to delete.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the delete operation or error details.
+ """
api_name = 'SYNO.SurveillanceStation.PTZ.Patrol'
info = self.gen_list[api_name]
api_path = info['path']
@@ -4190,6 +8509,21 @@ def delete_specific_patrol(self,
def run_patrol(self,
camId: Any = None,
id: int = None) -> dict[str, object] | str: # TODO not working
+ """
+ Run a specified patrol on a camera.
+
+ Parameters
+ ----------
+ camId : Any, optional
+ Camera identifier.
+ id : int, optional
+ Patrol ID.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the run operation or error details.
+ """
api_name = 'SYNO.SurveillanceStation.PTZ.Patrol'
info = self.gen_list[api_name]
api_path = info['path']
@@ -4204,6 +8538,19 @@ def run_patrol(self,
def stop_patrol(self,
camId: Any = None) -> dict[str, object] | str: # TODO not working
+ """
+ Stop the currently running patrol on a camera.
+
+ Parameters
+ ----------
+ camId : Any, optional
+ Camera identifier.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the stop operation or error details.
+ """
api_name = 'SYNO.SurveillanceStation.PTZ.Patrol'
info = self.gen_list[api_name]
api_path = info['path']
@@ -4217,6 +8564,14 @@ def stop_patrol(self,
return self.request_data(api_name, api_path, req_param)
def start_camera_search_process(self) -> dict[str, object] | str:
+ """
+ Start searching for cameras.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the search operation or error details.
+ """
api_name = 'SYNO.SurveillanceStation.Camera.Search'
info = self.gen_list[api_name]
api_path = info['path']
@@ -4227,6 +8582,21 @@ def start_camera_search_process(self) -> dict[str, object] | str:
def get_camera_search_info(self,
pid: int = None,
offset: int = None) -> dict[str, object] | str:
+ """
+ Get information about the current camera search.
+
+ Parameters
+ ----------
+ pid : int, optional
+ Process ID of the search.
+ offset : int, optional
+ Offset for pagination.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Search information or error details.
+ """
api_name = 'SYNO.SurveillanceStation.Camera.Search'
info = self.gen_list[api_name]
api_path = info['path']
@@ -4241,6 +8611,19 @@ def get_camera_search_info(self,
def toggle_home_mode(self,
on: bool = None) -> dict[str, object] | str:
+ """
+ Toggle the Home Mode in Surveillance Station.
+
+ Parameters
+ ----------
+ on : bool, optional
+ Whether to enable (True) or disable (False) Home Mode.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the toggle operation or error details.
+ """
api_name = 'SYNO.SurveillanceStation.HomeMode'
info = self.gen_list[api_name]
api_path = info['path']
@@ -4255,6 +8638,19 @@ def toggle_home_mode(self,
def get_home_mode_settings(self,
need_mobiles: bool = None) -> dict[str, object] | str:
+ """
+ Get the current Home Mode settings.
+
+ Parameters
+ ----------
+ need_mobiles : bool, optional
+ Whether to include mobile device information.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Home Mode settings or error details.
+ """
api_name = 'SYNO.SurveillanceStation.HomeMode'
info = self.gen_list[api_name]
api_path = info['path']
@@ -4275,6 +8671,29 @@ def get_transaction_list(self,
start: int = None,
# TODO not working
limit: int = None) -> dict[str, object] | str:
+ """
+ Get a list of device transactions with optional filters.
+
+ Parameters
+ ----------
+ filterIds : str, optional
+ Comma-separated list of transaction IDs to filter.
+ filterDsIds : str, optional
+ Comma-separated list of device station IDs to filter.
+ filterEnable : bool, optional
+ Filter by enabled status.
+ filterStatus : int, optional
+ Filter by status code.
+ start : int, optional
+ Start index for pagination.
+ limit : int, optional
+ Maximum number of results to return.
+
+ Returns
+ -------
+ dict[str, object] or str
+ List of transactions or error details.
+ """
api_name = 'SYNO.SurveillanceStation.Transactions.Device'
info = self.gen_list[api_name]
api_path = info['path']
@@ -4299,6 +8718,37 @@ def get_all_transaction_list(self,
start: int = None,
# TODO not working
limit: int = None) -> dict[str, object] | str:
+ """
+ Get a list of all transactions with optional filters.
+
+ Parameters
+ ----------
+ filterIds : str, optional
+ Comma-separated list of transaction IDs to filter.
+ dsId : int, optional
+ Device station ID.
+ filterTimeFrom : Any, optional
+ Start time for filtering.
+ filterStatus : int, optional
+ Filter by status code.
+ filterLock : bool, optional
+ Filter by lock status.
+ filterTimeTo : Any, optional
+ End time for filtering.
+ filterTimeRangeIntersect : bool, optional
+ Whether to intersect time ranges.
+ filterKeyword : str, optional
+ Keyword for filtering.
+ start : int, optional
+ Start index for pagination.
+ limit : int, optional
+ Maximum number of results to return.
+
+ Returns
+ -------
+ dict[str, object] or str
+ List of transactions or error details.
+ """
api_name = 'SYNO.SurveillanceStation.Transactions.Transaction'
info = self.gen_list[api_name]
api_path = info['path']
@@ -4322,6 +8772,37 @@ def lock_history_records(self,
filterKeyword: str = None,
start: int = None,
limit: int = None) -> dict[str, object] | str:
+ """
+ Lock specified history records.
+
+ Parameters
+ ----------
+ filterIds : str, optional
+ Comma-separated list of record IDs to lock.
+ dsId : int, optional
+ Device station ID.
+ filterStatus : int, optional
+ Filter by status code.
+ filterLock : bool, optional
+ Filter by lock status.
+ filterTimeFrom : Any, optional
+ Start time for filtering.
+ filterTimeTo : Any, optional
+ End time for filtering.
+ filterTimeRangeIntersect : bool, optional
+ Whether to intersect time ranges.
+ filterKeyword : str, optional
+ Keyword for filtering.
+ start : int, optional
+ Start index for pagination.
+ limit : int, optional
+ Maximum number of results to return.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the lock operation or error details.
+ """
api_name = 'SYNO.SurveillanceStation.Transactions.Transaction'
info = self.gen_list[api_name]
api_path = info['path']
@@ -4345,6 +8826,37 @@ def unlock_history_records(self,
filterKeyword: str = None,
start: int = None,
limit: int = None) -> dict[str, object] | str:
+ """
+ Unlock specified history records.
+
+ Parameters
+ ----------
+ filterIds : str, optional
+ Comma-separated list of record IDs to unlock.
+ dsId : int, optional
+ Device station ID.
+ filterStatus : int, optional
+ Filter by status code.
+ filterLock : bool, optional
+ Filter by lock status.
+ filterTimeFrom : Any, optional
+ Start time for filtering.
+ filterTimeTo : Any, optional
+ End time for filtering.
+ filterTimeRangeIntersect : bool, optional
+ Whether to intersect time ranges.
+ filterKeyword : str, optional
+ Keyword for filtering.
+ start : int, optional
+ Start index for pagination.
+ limit : int, optional
+ Maximum number of results to return.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the unlock operation or error details.
+ """
api_name = 'SYNO.SurveillanceStation.Transactions.Transaction'
info = self.gen_list[api_name]
api_path = info['path']
@@ -4368,6 +8880,37 @@ def delete_history_records(self,
filterKeyword: str = None,
start: int = None,
limit: int = None) -> dict[str, object] | str:
+ """
+ Delete specified history records.
+
+ Parameters
+ ----------
+ filterIds : str, optional
+ Comma-separated list of record IDs to delete.
+ dsId : int, optional
+ Device station ID.
+ filterStatus : int, optional
+ Filter by status code.
+ filterLock : bool, optional
+ Filter by lock status.
+ filterTimeFrom : Any, optional
+ Start time for filtering.
+ filterTimeTo : Any, optional
+ End time for filtering.
+ filterTimeRangeIntersect : bool, optional
+ Whether to intersect time ranges.
+ filterKeyword : str, optional
+ Keyword for filtering.
+ start : int, optional
+ Start index for pagination.
+ limit : int, optional
+ Maximum number of results to return.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the delete operation or error details.
+ """
api_name = 'SYNO.SurveillanceStation.Transactions.Transaction'
info = self.gen_list[api_name]
api_path = info['path']
@@ -4385,6 +8928,23 @@ def start_session_with_specified_session_id(self,
session_id: str = None,
# TODO not working
timeout: int = None) -> dict[str, object] | str:
+ """
+ Start a session with a specified session ID.
+
+ Parameters
+ ----------
+ device_name : str, optional
+ Name of the device.
+ session_id : str, optional
+ Session ID to start.
+ timeout : int, optional
+ Timeout for the session.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the start operation or error details.
+ """
api_name = 'SYNO.SurveillanceStation.Transactions.Transaction'
info = self.gen_list[api_name]
api_path = info['path']
@@ -4401,6 +8961,21 @@ def complete_session_with_specified_id(self,
device_name: str = None,
# TODO not working
session_id: str = None) -> dict[str, object] | str:
+ """
+ Complete a session with a specified session ID.
+
+ Parameters
+ ----------
+ device_name : str, optional
+ Name of the device.
+ session_id : str, optional
+ Session ID to complete.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the complete operation or error details.
+ """
api_name = 'SYNO.SurveillanceStation.Transactions.Transaction'
info = self.gen_list[api_name]
api_path = info['path']
@@ -4417,6 +8992,21 @@ def cancel_session_with_specified_session_id(self,
device_name: str = None,
# TODO not working
session_id: str = None) -> dict[str, object] | str:
+ """
+ Cancel a session with a specified session ID.
+
+ Parameters
+ ----------
+ device_name : str, optional
+ Name of the device.
+ session_id : str, optional
+ Session ID to cancel.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the cancel operation or error details.
+ """
api_name = 'SYNO.SurveillanceStation.Transactions.Transaction'
info = self.gen_list[api_name]
api_path = info['path']
@@ -4434,6 +9024,23 @@ def carry_data_into_session_id(self,
session_id: str = None,
# TODO not working
content: str = None) -> dict[str, object] | str:
+ """
+ Append data to a session with a specified session ID.
+
+ Parameters
+ ----------
+ device_name : str, optional
+ Name of the device.
+ session_id : str, optional
+ Session ID to append data to.
+ content : str, optional
+ Data content to append.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the append operation or error details.
+ """
api_name = 'SYNO.SurveillanceStation.Transactions.Transaction'
info = self.gen_list[api_name]
api_path = info['path']
@@ -4471,6 +9078,63 @@ def add_edit_active_vault_task(self,
storagePath: str = None,
# TODO to check
type: int = None) -> dict[str, object] | str:
+ """
+ Add or edit an active vault task for archiving.
+
+ Parameters
+ ----------
+ blCustomFolder : bool, optional
+ Whether to use a custom folder for storage.
+ blLimitBySize : bool, optional
+ Whether to limit the archive by size.
+ blRotateFile : bool, optional
+ Whether to enable file rotation.
+ blSrcRecNoOverlap : bool, optional
+ Whether to avoid overlapping source recordings.
+ blUseRecDet : bool, optional
+ Whether to use recording detection.
+ camId : Any, optional
+ Camera ID.
+ camInfo : Any, optional
+ Camera information.
+ dayLimit : int, optional
+ Day limit for the archive.
+ didCode : str, optional
+ Device code.
+ dsSerial : str, optional
+ Device serial number.
+ execTime : Any, optional
+ Execution time.
+ hostname : str, optional
+ Hostname of the source server.
+ id : int, optional
+ Task ID (for editing).
+ name : str, optional
+ Name of the task.
+ passwd : str, optional
+ Password for authentication.
+ port : str, optional
+ Port number.
+ recEndTm : Any, optional
+ Recording end time.
+ recMode : str, optional
+ Recording mode.
+ recSchedule : str, optional
+ Recording schedule.
+ recStartTm : Any, optional
+ Recording start time.
+ schedule : str, optional
+ Task schedule.
+ storagePath : str, optional
+ Path for storage.
+ type : int, optional
+ Type of the task.
+
+ Returns
+ -------
+ dict of str to object or str
+ API response from the request.
+ """
api_name = 'SYNO.SurveillanceStation.Archiving.Pull'
info = self.gen_list[api_name]
api_path = info['path']
@@ -4493,6 +9157,33 @@ def login_source_server_get_info(self,
didCode: str = None,
# TODO not working
srcDsId: int = None) -> dict[str, object] | str:
+ """
+ Log in to the source server and retrieve information.
+
+ Parameters
+ ----------
+ port : str, optional
+ Port number of the source server.
+ hostname : str, optional
+ Hostname of the source server.
+ protocol : bool, optional
+ Protocol to use (e.g., HTTPS).
+ username : str, optional
+ Username for authentication.
+ passwd : str, optional
+ Password for authentication.
+ archId : int, optional
+ Archive ID.
+ didCode : str, optional
+ Device code.
+ srcDsId : int, optional
+ Source device ID (not working).
+
+ Returns
+ -------
+ dict of str to object or str
+ API response from the request.
+ """
api_name = 'SYNO.SurveillanceStation.Archiving.Pull'
info = self.gen_list[api_name]
api_path = info['path']
@@ -4508,6 +9199,21 @@ def login_source_server_get_info(self,
def delete_archive_vault_task(self,
id: int = None,
keepRec: bool = None) -> dict[str, object] | str:
+ """
+ Delete an archive vault task.
+
+ Parameters
+ ----------
+ id : int, optional
+ Task ID to delete.
+ keepRec : bool, optional
+ Whether to keep the recordings.
+
+ Returns
+ -------
+ dict of str to object or str
+ API response from the request.
+ """
api_name = 'SYNO.SurveillanceStation.Archiving.Pull'
info = self.gen_list[api_name]
api_path = info['path']
@@ -4521,6 +9227,14 @@ def delete_archive_vault_task(self,
return self.request_data(api_name, api_path, req_param)
def list_exist_archive_vault(self) -> dict[str, object] | str:
+ """
+ List all existing archive vault tasks.
+
+ Returns
+ -------
+ dict of str to object or str
+ API response from the request.
+ """
api_name = 'SYNO.SurveillanceStation.Archiving.Pull'
info = self.gen_list[api_name]
api_path = info['path']
@@ -4536,6 +9250,19 @@ def list_exist_archive_vault(self) -> dict[str, object] | str:
def enable_archive_vault_task(self,
# TODO not working
id: int = None) -> dict[str, object] | str:
+ """
+ Enable an archive vault task.
+
+ Parameters
+ ----------
+ id : int, optional
+ Task ID to enable.
+
+ Returns
+ -------
+ dict of str to object or str
+ API response from the request.
+ """
api_name = 'SYNO.SurveillanceStation.Archiving.Pull'
info = self.gen_list[api_name]
api_path = info['path']
@@ -4550,6 +9277,19 @@ def enable_archive_vault_task(self,
def disable_archive_vault_task(self,
id: int = None) -> dict[str, object] | str:
+ """
+ Disable an archive vault task.
+
+ Parameters
+ ----------
+ id : int, optional
+ Task ID to disable.
+
+ Returns
+ -------
+ dict of str to object or str
+ API response from the request.
+ """
api_name = 'SYNO.SurveillanceStation.Archiving.Pull'
info = self.gen_list[api_name]
api_path = info['path']
@@ -4566,6 +9306,21 @@ def disable_archive_vault_batchedit_task(self,
taskIds: str = None,
# TODO not working
attrs: Any = None) -> dict[str, object] | str:
+ """
+ Batch edit (disable) archive vault tasks.
+
+ Parameters
+ ----------
+ taskIds : str, optional
+ Comma-separated list of task IDs.
+ attrs : Any, optional
+ Additional attributes for batch edit (not working).
+
+ Returns
+ -------
+ dict of str to object or str
+ API response from the request.
+ """
api_name = 'SYNO.SurveillanceStation.Archiving.Pull'
info = self.gen_list[api_name]
api_path = info['path']
@@ -4581,6 +9336,19 @@ def disable_archive_vault_batchedit_task(self,
def get_batch_edit_progress(self,
# TODO not working
pid: int = None) -> dict[str, object] | str:
+ """
+ Get the progress of a batch edit operation.
+
+ Parameters
+ ----------
+ pid : int, optional
+ Process ID of the batch edit operation (not working).
+
+ Returns
+ -------
+ dict of str to object or str
+ API response from the request.
+ """
api_name = 'SYNO.SurveillanceStation.Archiving.Pull'
info = self.gen_list[api_name]
api_path = info['path']
@@ -4597,6 +9365,19 @@ def get_batch_edit_progress(self,
def get_batchedit_proress_info(self,
# TODO not working
pid: int = None) -> dict[str, object] | str:
+ """
+ Get detailed information about batch edit progress.
+
+ Parameters
+ ----------
+ pid : int, optional
+ Process ID of the batch edit operation (not working).
+
+ Returns
+ -------
+ dict of str to object or str
+ API response from the request.
+ """
api_name = 'SYNO.SurveillanceStation.Archiving.Pull'
info = self.gen_list[api_name]
api_path = info['path']
@@ -4612,6 +9393,19 @@ def get_batchedit_proress_info(self,
def clean_batchedit_progress_data(self,
pid: int = None) -> dict[str, object] | str:
+ """
+ Clean up batch edit progress data.
+
+ Parameters
+ ----------
+ pid : int, optional
+ Process ID of the batch edit operation.
+
+ Returns
+ -------
+ dict of str to object or str
+ API response from the request.
+ """
api_name = 'SYNO.SurveillanceStation.Archiving.Pull'
info = self.gen_list[api_name]
api_path = info['path']
@@ -4626,6 +9420,14 @@ def clean_batchedit_progress_data(self,
return self.request_data(api_name, api_path, req_param)
def get_youtube_live_broadcast_setting(self) -> dict[str, object] | str:
+ """
+ Get the current YouTube Live broadcast settings.
+
+ Returns
+ -------
+ dict of str to object or str
+ API response from the request.
+ """
api_name = 'SYNO.SurveillanceStation.YoutubeLive'
info = self.gen_list[api_name]
api_path = info['path']
@@ -4639,6 +9441,27 @@ def set_youtube_live_broadcast_info(self,
cam_id: int = None,
stream_profile: int = None,
live_on: bool = None) -> dict[str, object] | str:
+ """
+ Set YouTube Live broadcast information.
+
+ Parameters
+ ----------
+ rtmp_path : str, optional
+ RTMP path for the broadcast.
+ key : str, optional
+ Stream key.
+ cam_id : int, optional
+ Camera ID.
+ stream_profile : int, optional
+ Stream profile.
+ live_on : bool, optional
+ Whether to enable live broadcast.
+
+ Returns
+ -------
+ dict of str to object or str
+ API response from the request.
+ """
api_name = 'SYNO.SurveillanceStation.YoutubeLive'
info = self.gen_list[api_name]
api_path = info['path']
@@ -4652,6 +9475,14 @@ def set_youtube_live_broadcast_info(self,
return self.request_data(api_name, api_path, req_param)
def close_youtube_live_broadcast(self) -> dict[str, object] | str:
+ """
+ Close the current YouTube Live broadcast.
+
+ Returns
+ -------
+ dict of str to object or str
+ API response from the request.
+ """
api_name = 'SYNO.SurveillanceStation.YoutubeLive'
info = self.gen_list[api_name]
api_path = info['path']
@@ -4661,6 +9492,14 @@ def close_youtube_live_broadcast(self) -> dict[str, object] | str:
# TODO not working
def get_deep_video_analytic(self) -> dict[str, object] | str:
+ """
+ Get the list of deep video analytic tasks.
+
+ Returns
+ -------
+ dict of str to object or str
+ API response from the request.
+ """
api_name = 'SYNO.SurveillanceStation.IVA'
info = self.gen_list[api_name]
api_path = info['path']
@@ -4702,6 +9541,81 @@ def create_edit_DVA_task(self,
people_hint_pos: str = None,
# TODO not working
blEditMode: bool = None) -> dict[str, object] | str:
+ """
+ Create or edit a Deep Video Analytics (DVA) task.
+
+ Parameters
+ ----------
+ analyze_type : int, optional
+ Type of analysis to perform.
+ actFromHost : bool, optional
+ Whether the action is triggered from the host.
+ name : str, optional
+ Name of the DVA task.
+ camera_id : int, optional
+ ID of the camera associated with the task.
+ enable : bool, optional
+ Whether to enable the task.
+ enable_recording : bool, optional
+ Whether to enable recording for the task.
+ pre_rec_time : int, optional
+ Pre-recording time in seconds.
+ post_rec_time : int, optional
+ Post-recording time in seconds.
+ event_integration : int, optional
+ Event integration setting.
+ region_type : int, optional
+ Type of detection region.
+ det_region_cnt : int, optional
+ Number of detection regions.
+ det_region : int, optional
+ Detection region configuration.
+ people_mode : int, optional
+ People counting mode.
+ reset_cnt_frequency : int, optional
+ Frequency for resetting the counter.
+ reset_weekday : int, optional
+ Weekday for counter reset.
+ reset_date : int, optional
+ Date for counter reset.
+ reset_time_minute : int, optional
+ Minute for counter reset.
+ reset_time_hour : int, optional
+ Hour for counter reset.
+ fence_dir_flag : int, optional
+ Fence direction flag.
+ people_display_pos : int, optional
+ Display position for people counting.
+ stream_profile : int, optional
+ Stream profile to use.
+ people_enable_stay_max : bool, optional
+ Whether to enable maximum stay for people.
+ intrusion_detect_target : int, optional
+ Target for intrusion detection.
+ min_obj_size : Any, optional
+ Minimum object size for detection.
+ min_obj_size_option : int, optional
+ Option for minimum object size.
+ enable_min_duration : int, optional
+ Enable minimum duration for detection.
+ people_display_info : int, optional
+ Display information for people counting.
+ people_enter : int, optional
+ Number of people entering.
+ people_stay_max : int, optional
+ Maximum number of people staying.
+ people_region : str, optional
+ Region for people counting.
+ people_hint_pos : str, optional
+ Hint position for people counting.
+ blEditMode : bool, optional
+ Edit mode flag (not working).
+
+ Returns
+ -------
+ dict of str to object or str
+ API response from the request.
+ """
api_name = 'SYNO.SurveillanceStation.IVA'
info = self.gen_list[api_name]
api_path = info['path']
@@ -4716,6 +9630,19 @@ def create_edit_DVA_task(self,
def delete_dva_task(self,
ids: str = None) -> dict[str, object] | str: # TODO not working
+ """
+ Delete a Deep Video Analytics (DVA) task.
+
+ Parameters
+ ----------
+ ids : str, optional
+ Comma-separated list of DVA task IDs to delete.
+
+ Returns
+ -------
+ dict of str to object or str
+ API response from the request.
+ """
api_name = 'SYNO.SurveillanceStation.IVA'
info = self.gen_list[api_name]
api_path = info['path']
@@ -4730,6 +9657,19 @@ def delete_dva_task(self,
def enable_dva_task(self,
ids: str = None) -> dict[str, object] | str: # TODO not working
+ """
+ Enable one or more Deep Video Analytics (DVA) tasks.
+
+ Parameters
+ ----------
+ ids : str, optional
+ Comma-separated list of DVA task IDs to enable.
+
+ Returns
+ -------
+ dict of str to object or str
+ API response from the request.
+ """
api_name = 'SYNO.SurveillanceStation.IVA'
info = self.gen_list[api_name]
api_path = info['path']
@@ -4745,6 +9685,19 @@ def enable_dva_task(self,
def disable_dva_task(self,
# TODO not working
ids: str = None) -> dict[str, object] | str:
+ """
+ Disable one or more Deep Video Analytics (DVA) tasks.
+
+ Parameters
+ ----------
+ ids : str, optional
+ Comma-separated list of DVA task IDs to disable.
+
+ Returns
+ -------
+ dict of str to object or str
+ API response from the request.
+ """
api_name = 'SYNO.SurveillanceStation.IVA'
info = self.gen_list[api_name]
api_path = info['path']
@@ -4760,6 +9713,19 @@ def disable_dva_task(self,
def reset_counter_people_counting_task(self,
# TODO not working
taskId: str = None) -> dict[str, object] | str:
+ """
+ Reset the people counting counter for a specific DVA task.
+
+ Parameters
+ ----------
+ taskId : str, optional
+ ID of the people counting task to reset.
+
+ Returns
+ -------
+ dict of str to object or str
+ API response from the request.
+ """
api_name = 'SYNO.SurveillanceStation.IVA'
info = self.gen_list[api_name]
api_path = info['path']
@@ -4779,6 +9745,25 @@ def get_people_enter_leave_count(self,
timeEnd: str = None,
timezone: int = None,
) -> dict[str, object] | str: # TODO not working
+ """
+ Get the count of people entering and leaving for specified DVA tasks.
+
+ Parameters
+ ----------
+ ids : str, optional
+ Comma-separated list of DVA task IDs.
+ timeStart : str, optional
+ Start time for the count (ISO format or timestamp).
+ timeEnd : str, optional
+ End time for the count (ISO format or timestamp).
+ timezone : int, optional
+ Timezone offset.
+
+ Returns
+ -------
+ dict of str to object or str
+ API response from the request.
+ """
api_name = 'SYNO.SurveillanceStation.IVA.Report'
info = self.gen_list[api_name]
api_path = info['path']
@@ -4799,6 +9784,29 @@ def get_people_count_of_day(self,
timestamp: int = None,
# TODO not working
blOccupancy: int = None) -> dict[str, object] | str:
+ """
+ Get the people count report for a specific day.
+
+ Parameters
+ ----------
+ ids : str, optional
+ Comma-separated list of DVA task IDs.
+ interval : int, optional
+ Interval for the report.
+ intervalUnit : int, optional
+ Unit for the interval.
+ timezone : int, optional
+ Timezone offset.
+ timestamp : int, optional
+ Timestamp for the report.
+ blOccupancy : int, optional
+ Occupancy flag (not working).
+
+ Returns
+ -------
+ dict of str to object or str
+ API response from the request.
+ """
api_name = 'SYNO.SurveillanceStation.IVA.Report'
info = self.gen_list[api_name]
api_path = info['path']
@@ -4815,6 +9823,21 @@ def list_people_counting_task(self,
taskList: str = None,
# TODO not working
limit: int = None) -> dict[str, object] | str:
+ """
+ List people counting tasks.
+
+ Parameters
+ ----------
+ taskList : str, optional
+ Comma-separated list of task IDs to list.
+ limit : int, optional
+ Limit the number of tasks returned (not working).
+
+ Returns
+ -------
+ dict of str to object or str
+ API response from the request.
+ """
api_name = 'SYNO.SurveillanceStation.IVA.Recording'
info = self.gen_list[api_name]
api_path = info['path']
@@ -4831,6 +9854,21 @@ def delete_recording_file_of_detection(self,
slaveDsParam: str = None,
# TODO not working
deleteMethod: int = None) -> dict[str, object] | str:
+ """
+ Delete recording files associated with detection events.
+
+ Parameters
+ ----------
+ slaveDsParam : str, optional
+ Parameters for the slave device.
+ deleteMethod : int, optional
+ Method for deletion (not working).
+
+ Returns
+ -------
+ dict of str to object or str
+ API response from the request.
+ """
api_name = 'SYNO.SurveillanceStation.IVA.Recording'
info = self.gen_list[api_name]
api_path = info['path']
@@ -4848,6 +9886,23 @@ def get_info_of_task_and_frame(self,
taskId: int = None,
# TODO not working
blAlertEvt: bool = None) -> dict[str, object] | str:
+ """
+ Get analytic result information for a specific task and frame.
+
+ Parameters
+ ----------
+ eventId : int, optional
+ Event ID to query.
+ taskId : int, optional
+ Task ID to query.
+ blAlertEvt : bool, optional
+ Alert event flag (not working).
+
+ Returns
+ -------
+ dict of str to object or str
+ API response from the request.
+ """
api_name = 'SYNO.SurveillanceStation.IVA.Recording'
info = self.gen_list[api_name]
api_path = info['path']
@@ -4865,6 +9920,21 @@ def lock_recording_file_of_detection(self,
dsId: int = None,
# TODO not working
idList: int = None) -> dict[str, object] | str:
+ """
+ Lock recording files associated with detection events.
+
+ Parameters
+ ----------
+ dsId : int, optional
+ Device server ID.
+ idList : int, optional
+ List of recording file IDs to lock (not working).
+
+ Returns
+ -------
+ dict of str to object or str
+ API response from the request.
+ """
api_name = 'SYNO.SurveillanceStation.IVA.Recording'
info = self.gen_list[api_name]
api_path = info['path']
@@ -4881,6 +9951,21 @@ def unlock_recording_file_of_detection(self,
dsId: int = None,
# TODO not working
idList: str = None) -> dict[str, object] | str:
+ """
+ Unlock recording files associated with detection events.
+
+ Parameters
+ ----------
+ dsId : int, optional
+ Device server ID.
+ idList : str, optional
+ List of recording file IDs to unlock (not working).
+
+ Returns
+ -------
+ dict of str to object or str
+ API response from the request.
+ """
api_name = 'SYNO.SurveillanceStation.IVA.Recording'
info = self.gen_list[api_name]
api_path = info['path']
@@ -4895,6 +9980,14 @@ def unlock_recording_file_of_detection(self,
# TODO not working
def get_info_people_counting_task(self) -> dict[str, object] | str:
+ """
+ Get information about people counting tasks.
+
+ Returns
+ -------
+ dict of str to object or str
+ API response from the request.
+ """
api_name = 'SYNO.SurveillanceStation.IVA.TaskGroup'
info = self.gen_list[api_name]
api_path = info['path']
@@ -4920,6 +10013,39 @@ def create_people_counting_task(self,
resert_tome_hour: int = None,
# TODO not working
resert_tome_minute: int = None) -> dict[str, object] | str:
+ """
+ Create a new people counting task.
+
+ Parameters
+ ----------
+ enable : bool, optional
+ Whether to enable the task.
+ task_ids : str, optional
+ Comma-separated list of task IDs.
+ owner_ds_id : int, optional
+ Owner device server ID.
+ name : str, optional
+ Name of the task.
+ people_display_info : str, optional
+ Display information for people counting.
+ people_enable_stay_max : int, optional
+ Enable maximum stay for people.
+ reset_cnt_frequency : int, optional
+ Frequency for resetting the counter.
+ resert_date : int, optional
+ Date for counter reset.
+ resert_weekday : int, optional
+ Weekday for counter reset.
+ resert_tome_hour : int, optional
+ Hour for counter reset.
+ resert_tome_minute : int, optional
+ Minute for counter reset (not working).
+
+ Returns
+ -------
+ dict of str to object or str
+ API response from the request.
+ """
api_name = 'SYNO.SurveillanceStation.IVA.TaskGroup'
info = self.gen_list[api_name]
api_path = info['path']
@@ -4945,6 +10071,39 @@ def modify_setting_of_people_counting_task(self,
resert_tome_hour: int = None,
# TODO not working
resert_tome_minute: int = None) -> dict[str, object] | str:
+ """
+ Modify the settings of an existing people counting task.
+
+ Parameters
+ ----------
+ enable : bool, optional
+ Whether to enable the task.
+ id : int, optional
+ ID of the task to modify.
+ task_ids : str, optional
+ Comma-separated list of task IDs.
+ name : str, optional
+ Name of the task.
+ people_display_info : int, optional
+ Display information for people counting.
+ people_enable_max : int, optional
+ Enable maximum stay for people.
+ reset_cnt_frequency : int, optional
+ Frequency for resetting the counter.
+ resert_date : int, optional
+ Date for counter reset.
+ resert_weekday : int, optional
+ Weekday for counter reset.
+ resert_tome_hour : int, optional
+ Hour for counter reset.
+ resert_tome_minute : int, optional
+ Minute for counter reset (not working).
+
+ Returns
+ -------
+ dict of str to object or str
+ API response from the request.
+ """
api_name = 'SYNO.SurveillanceStation.IVA.TaskGroup'
info = self.gen_list[api_name]
api_path = info['path']
@@ -4960,6 +10119,19 @@ def modify_setting_of_people_counting_task(self,
def delete_task_group(self,
# TODO not working
ids: str = None) -> dict[str, object] | str:
+ """
+ Delete a people counting task group.
+
+ Parameters
+ ----------
+ ids : str, optional
+ Comma-separated list of task group IDs to delete.
+
+ Returns
+ -------
+ dict of str to object or str
+ API response from the request.
+ """
api_name = 'SYNO.SurveillanceStation.IVA.TaskGroup'
info = self.gen_list[api_name]
api_path = info['path']
@@ -4975,6 +10147,19 @@ def delete_task_group(self,
def start_count_people_task_in_groups(self,
# TODO not working
ids: str = None) -> dict[str, object] | str:
+ """
+ Enable people counting tasks in specified groups.
+
+ Parameters
+ ----------
+ ids : str, optional
+ Comma-separated list of task group IDs to enable.
+
+ Returns
+ -------
+ dict of str to object or str
+ API response from the request.
+ """
api_name = 'SYNO.SurveillanceStation.IVA.TaskGroup'
info = self.gen_list[api_name]
api_path = info['path']
@@ -4990,6 +10175,19 @@ def start_count_people_task_in_groups(self,
def stop_count_people_task_in_groups(self,
# TODO not working
ids: str = None) -> dict[str, object] | str:
+ """
+ Disable people counting tasks in specified groups.
+
+ Parameters
+ ----------
+ ids : str, optional
+ Comma-separated list of task group IDs to disable.
+
+ Returns
+ -------
+ dict of str to object or str
+ API response from the request.
+ """
api_name = 'SYNO.SurveillanceStation.IVA.TaskGroup'
info = self.gen_list[api_name]
api_path = info['path']
@@ -5005,6 +10203,19 @@ def stop_count_people_task_in_groups(self,
def get_number_counting_task_group(self,
# TODO not working
id: int = None) -> dict[str, object] | str:
+ """
+ Get the people count for a specific task group.
+
+ Parameters
+ ----------
+ id : int, optional
+ ID of the task group.
+
+ Returns
+ -------
+ dict of str to object or str
+ API response from the request.
+ """
api_name = 'SYNO.SurveillanceStation.IVA.TaskGroup'
info = self.gen_list[api_name]
api_path = info['path']
@@ -5020,6 +10231,19 @@ def get_number_counting_task_group(self,
def lock_recording_file_result(self,
# TODO not working
id: int = None) -> dict[str, object] | str:
+ """
+ Reset the people count for a specific IVA task group.
+
+ Parameters
+ ----------
+ id : int, optional
+ ID of the IVA task group.
+
+ Returns
+ -------
+ dict of str to object or str
+ API response from the request.
+ """
api_name = 'SYNO.SurveillanceStation.IVA.TaskGroup'
info = self.gen_list[api_name]
api_path = info['path']
@@ -5038,6 +10262,23 @@ def get_face_list_task(self,
ownerDsId: int = None,
blOnlyEnableDs: bool = None,
) -> dict[str, object] | str: # TODO not working
+ """
+ Retrieve the list of face detection tasks.
+
+ Parameters
+ ----------
+ ids : str, optional
+ Comma-separated list of task IDs to filter.
+ ownerDsId : int, optional
+ ID of the owner DiskStation.
+ blOnlyEnableDs : bool, optional
+ Whether to include only enabled DiskStations.
+
+ Returns
+ -------
+ dict of str to object or str
+ API response from the request.
+ """
api_name = 'SYNO.SurveillanceStation.Face'
info = self.gen_list[api_name]
api_path = info['path']
@@ -5084,6 +10325,81 @@ def create_or_edit_task(self,
scheduleOn: bool = None,
# TODO not working
ignore_bad_quality: bool = None) -> dict[str, object] | str:
+ """
+ Create or edit a face detection task.
+
+ Parameters
+ ----------
+ id : int, optional
+ Task ID.
+ id_on_rec_server : int, optional
+ Task ID on the recording server.
+ camera_id : int, optional
+ Camera ID.
+ camera_id_on_rec : int, optional
+ Camera ID on the recording server.
+ owner_ds_id : int, optional
+ Owner DiskStation ID.
+ enable : bool, optional
+ Whether to enable the task.
+ blEditMode : bool, optional
+ Edit mode flag.
+ stream_profile : int, optional
+ Stream profile index.
+ name : str, optional
+ Name of the task.
+ similarity : float, optional
+ Similarity threshold for face recognition.
+ allowed_color : int, optional
+ Color code for allowed faces.
+ allowed_list : Any, optional
+ List of allowed faces.
+ blocked_color : int, optional
+ Color code for blocked faces.
+ blocked_list : Any, optional
+ List of blocked faces.
+ vip_color : int, optional
+ Color code for VIP faces.
+ vip_list : Any, optional
+ List of VIP faces.
+ recognized_color : int, optional
+ Color code for recognized faces.
+ unrecognized_color : int, optional
+ Color code for unrecognized faces.
+ deleted : bool, optional
+ Whether the task is deleted.
+ det_region : str, optional
+ Detection region.
+ det_region_cnt : int, optional
+ Number of detection regions.
+ region_type : int, optional
+ Type of region.
+ display_info : int, optional
+ Display information.
+ display_type : int, optional
+ Display type.
+ frame_display_info : int, optional
+ Frame display information.
+ enable_min_ogj_size : bool, optional
+ Enable minimum object size.
+ min_ogj_size : float, optional
+ Minimum object size.
+ post_rec_time : int, optional
+ Post-recording time in seconds.
+ pre_rec_time : int, optional
+ Pre-recording time in seconds.
+ schedule : str, optional
+ Task schedule.
+ scheduleOn : bool, optional
+ Whether the schedule is enabled.
+ ignore_bad_quality : bool, optional
+ Ignore bad quality flag (not working).
+
+ Returns
+ -------
+ dict of str to object or str
+ API response from the request.
+ """
api_name = 'SYNO.SurveillanceStation.Face'
info = self.gen_list[api_name]
api_path = info['path']
@@ -5100,6 +10416,21 @@ def delete_face_task(self,
ids: str = None,
# TODO not working
keepRecording: bool = None) -> dict[str, object] | str:
+ """
+ Delete one or more face detection tasks.
+
+ Parameters
+ ----------
+ ids : str, optional
+ Comma-separated list of task IDs to delete.
+ keepRecording : bool, optional
+ Whether to keep the associated recordings (not working).
+
+ Returns
+ -------
+ dict of str to object or str
+ API response from the request.
+ """
api_name = 'SYNO.SurveillanceStation.Face'
info = self.gen_list[api_name]
api_path = info['path']
@@ -5115,6 +10446,19 @@ def delete_face_task(self,
def enable_task_to_start_detection_recording(self,
# TODO not working
ids: str = None) -> dict[str, object] | str:
+ """
+ Enable face detection tasks to start detection and recording.
+
+ Parameters
+ ----------
+ ids : str, optional
+ Comma-separated list of task IDs to enable.
+
+ Returns
+ -------
+ dict of str to object or str
+ API response from the request.
+ """
api_name = 'SYNO.SurveillanceStation.Face'
info = self.gen_list[api_name]
api_path = info['path']
@@ -5130,6 +10474,19 @@ def enable_task_to_start_detection_recording(self,
def disable_task_to_stop_detection_recording(self,
# TODO not working
ids: str = None) -> dict[str, object] | str:
+ """
+ Disable face detection tasks to stop detection and recording.
+
+ Parameters
+ ----------
+ ids : str, optional
+ Comma-separated list of task IDs to disable.
+
+ Returns
+ -------
+ dict of str to object or str
+ API response from the request.
+ """
api_name = 'SYNO.SurveillanceStation.Face'
info = self.gen_list[api_name]
api_path = info['path']
@@ -5145,6 +10502,19 @@ def disable_task_to_stop_detection_recording(self,
def list_task_with_privilege_to_watch(self,
# TODO not working
ids: int = None) -> dict[str, object] | str:
+ """
+ List face detection tasks with privilege to watch.
+
+ Parameters
+ ----------
+ ids : int, optional
+ Task group ID to filter.
+
+ Returns
+ -------
+ dict of str to object or str
+ API response from the request.
+ """
api_name = 'SYNO.SurveillanceStation.Face'
info = self.gen_list[api_name]
api_path = info['path']
@@ -5163,6 +10533,23 @@ def create_face_group(self,
description: str = None,
# TODO not working
update_registered_face: Any = None) -> dict[str, object] | str:
+ """
+ Create a new face group.
+
+ Parameters
+ ----------
+ name : str, optional
+ Name of the face group.
+ description : str, optional
+ Description of the face group.
+ update_registered_face : Any, optional
+ Registered face update information (not working).
+
+ Returns
+ -------
+ dict of str to object or str
+ API response from the request.
+ """
api_name = 'SYNO.SurveillanceStation.Face'
info = self.gen_list[api_name]
api_path = info['path']
@@ -5179,6 +10566,19 @@ def create_face_group(self,
def disable_face_grooup(self,
# TODO not working
ids: Any = None) -> dict[str, object] | str:
+ """
+ Delete (disable) one or more face groups.
+
+ Parameters
+ ----------
+ ids : Any, optional
+ IDs of the face groups to delete (not working).
+
+ Returns
+ -------
+ dict of str to object or str
+ API response from the request.
+ """
api_name = 'SYNO.SurveillanceStation.Face'
info = self.gen_list[api_name]
api_path = info['path']
@@ -5197,6 +10597,25 @@ def edit_face_group(self,
description: str = None,
update_registered_face: Any = None,
id: int = None) -> dict[str, object] | str: # TODO not working
+ """
+ Edit an existing face group.
+
+ Parameters
+ ----------
+ name : str, optional
+ Name of the face group.
+ description : str, optional
+ Description of the face group.
+ update_registered_face : Any, optional
+ Registered face update information.
+ id : int, optional
+ ID of the face group to edit.
+
+ Returns
+ -------
+ dict of str to object or str
+ API response from the request.
+ """
api_name = 'SYNO.SurveillanceStation.Face'
info = self.gen_list[api_name]
api_path = info['path']
@@ -5213,6 +10632,21 @@ def get_face_group_list(self,
id_only: bool = None,
# TODO not working
filter: Any = None) -> dict[str, object] | str:
+ """
+ Retrieve the list of face groups.
+
+ Parameters
+ ----------
+ id_only : bool, optional
+ Whether to return only IDs.
+ filter : Any, optional
+ Filter criteria (not working).
+
+ Returns
+ -------
+ dict of str to object or str
+ API response from the request.
+ """
api_name = 'SYNO.SurveillanceStation.Face'
info = self.gen_list[api_name]
api_path = info['path']
@@ -5228,6 +10662,19 @@ def get_face_group_list(self,
def count_face_groups(self,
# TODO not working
filter: Any = None) -> dict[str, object] | str:
+ """
+ Count the number of face groups.
+
+ Parameters
+ ----------
+ filter : Any, optional
+ Filter criteria (not working).
+
+ Returns
+ -------
+ dict of str to object or str
+ API response from the request.
+ """
api_name = 'SYNO.SurveillanceStation.Face'
info = self.gen_list[api_name]
api_path = info['path']
@@ -5244,6 +10691,21 @@ def detect_faces_image(self,
image_data: str = None,
# TODO not working
image_size: int = None) -> dict[str, object] | str:
+ """
+ Detect faces in an image.
+
+ Parameters
+ ----------
+ image_data : str, optional
+ Base64-encoded image data.
+ image_size : int, optional
+ Size of the image (not working).
+
+ Returns
+ -------
+ dict of str to object or str
+ API response from the request.
+ """
api_name = 'SYNO.SurveillanceStation.Face'
info = self.gen_list[api_name]
api_path = info['path']
@@ -5269,6 +10731,37 @@ def create_registered_face(self,
update_unrecognized_captured_face: bool = None,
# TODO not working
append_image_data: bool = None) -> dict[str, object] | str:
+ """
+ Create a new registered face.
+
+ Parameters
+ ----------
+ account : str, optional
+ Account associated with the face.
+ name : str, optional
+ Name of the person.
+ description : str, optional
+ Description of the face.
+ image_data : str, optional
+ Base64-encoded image data.
+ image_size : int, optional
+ Size of the image.
+ face : Any, optional
+ Face data.
+ update_face_group : Any, optional
+ Face group update information.
+ captured_face_id : int, optional
+ ID of the captured face.
+ update_unrecognized_captured_face : bool, optional
+ Whether to update unrecognized captured face.
+ append_image_data : bool, optional
+ Append image data flag (not working).
+
+ Returns
+ -------
+ dict of str to object or str
+ API response from the request.
+ """
api_name = 'SYNO.SurveillanceStation.Face'
info = self.gen_list[api_name]
api_path = info['path']
@@ -5285,6 +10778,19 @@ def create_registered_face(self,
def delete_registered_face(self,
# TODO not working
ids: Any = None) -> dict[str, object] | str:
+ """
+ Delete one or more registered faces.
+
+ Parameters
+ ----------
+ ids : Any, optional
+ IDs of the registered faces to delete (not working).
+
+ Returns
+ -------
+ dict of str to object or str
+ API response from the request.
+ """
api_name = 'SYNO.SurveillanceStation.Face'
info = self.gen_list[api_name]
api_path = info['path']
@@ -5311,6 +10817,39 @@ def edit_registered_face(self,
update_unrecognized_captured_face: bool = None,
append_image_data: bool = None,
) -> dict[str, object] | str: # TODO not working
+ """
+ Edit an existing registered face.
+
+ Parameters
+ ----------
+ id : int, optional
+ ID of the registered face.
+ account : str, optional
+ Account associated with the face.
+ name : str, optional
+ Name of the person.
+ description : str, optional
+ Description of the face.
+ image_data : str, optional
+ Base64-encoded image data.
+ image_size : int, optional
+ Size of the image.
+ face : Any, optional
+ Face data.
+ update_face_group : Any, optional
+ Face group update information.
+ captured_face_id : int, optional
+ ID of the captured face.
+ update_unrecognized_captured_face : bool, optional
+ Whether to update unrecognized captured face.
+ append_image_data : bool, optional
+ Append image data flag.
+
+ Returns
+ -------
+ dict of str to object or str
+ API response from the request.
+ """
api_name = 'SYNO.SurveillanceStation.Face'
info = self.gen_list[api_name]
api_path = info['path']
@@ -5329,6 +10868,23 @@ def list_registered_face(self,
filter: Any = None,
append_image_data: bool = None,
) -> dict[str, object] | str: # TODO not working
+ """
+ List registered faces.
+
+ Parameters
+ ----------
+ id_only : bool, optional
+ Whether to return only IDs.
+ filter : Any, optional
+ Filter criteria.
+ append_image_data : bool, optional
+ Whether to append image data (not working).
+
+ Returns
+ -------
+ dict of str to object or str
+ API response from the request.
+ """
api_name = 'SYNO.SurveillanceStation.Face'
info = self.gen_list[api_name]
api_path = info['path']
@@ -5345,6 +10901,19 @@ def list_registered_face(self,
def count_registered_face(self,
# TODO not working
filter: Any = None) -> dict[str, object] | str:
+ """
+ Count the number of registered faces.
+
+ Parameters
+ ----------
+ filter : Any, optional
+ Filter criteria (not working).
+
+ Returns
+ -------
+ dict of str to object or str
+ API response from the request.
+ """
api_name = 'SYNO.SurveillanceStation.Face'
info = self.gen_list[api_name]
api_path = info['path']
@@ -5362,6 +10931,21 @@ def search_registered_face(self,
keywords: str = None,
# TODO not working
append_image_data: bool = None) -> dict[str, object] | str:
+ """
+ Search for registered faces by keywords.
+
+ Parameters
+ ----------
+ keywords : str, optional
+ Search keywords.
+ append_image_data : bool, optional
+ Whether to append image data (not working).
+
+ Returns
+ -------
+ dict of str to object or str
+ API response from the request.
+ """
api_name = 'SYNO.SurveillanceStation.Face'
info = self.gen_list[api_name]
api_path = info['path']
@@ -5382,6 +10966,27 @@ def get_face_result_list(self,
limit: int = None,
# TODO not working
slaveDsParam: int = None) -> dict[str, object] | str:
+ """
+ Retrieve a list of face recognition results.
+
+ Parameters
+ ----------
+ filter : Any, optional
+ Filter criteria for the face results.
+ blIncludeSnapshot : bool, optional
+ Whether to include snapshot images in the results.
+ blIncludeRegisteredFace : bool, optional
+ Whether to include registered face information.
+ limit : int, optional
+ Maximum number of results to return.
+ slaveDsParam : int, optional
+ Additional parameter for slave DiskStation (not working).
+
+ Returns
+ -------
+ dict of str to object or str
+ API response containing the list of face recognition results.
+ """
api_name = 'SYNO.SurveillanceStation.Face.Result'
info = self.gen_list[api_name]
api_path = info['path']
@@ -5398,6 +11003,21 @@ def delete_face_result(self,
filter: Any = None,
# TODO not working
slaveDsParam: Any = None) -> dict[str, object] | str:
+ """
+ Delete face recognition results.
+
+ Parameters
+ ----------
+ filter : Any, optional
+ Filter criteria for selecting face results to delete.
+ slaveDsParam : Any, optional
+ Additional parameter for slave DiskStation (not working).
+
+ Returns
+ -------
+ dict of str to object or str
+ API response indicating the result of the delete operation.
+ """
api_name = 'SYNO.SurveillanceStation.Face.Result'
info = self.gen_list[api_name]
api_path = info['path']
@@ -5414,6 +11034,21 @@ def lock_face_result(self,
filter: Any = None,
# TODO not working
slaveDsParam: Any = None) -> dict[str, object] | str:
+ """
+ Lock face recognition results to prevent modification or deletion.
+
+ Parameters
+ ----------
+ filter : Any, optional
+ Filter criteria for selecting face results to lock.
+ slaveDsParam : Any, optional
+ Additional parameter for slave DiskStation (not working).
+
+ Returns
+ -------
+ dict of str to object or str
+ API response indicating the result of the lock operation.
+ """
api_name = 'SYNO.SurveillanceStation.Face.Result'
info = self.gen_list[api_name]
api_path = info['path']
@@ -5430,6 +11065,21 @@ def unlock_face_result(self,
filter: Any = None,
# TODO not working
slaveDsParam: Any = None) -> dict[str, object] | str:
+ """
+ Unlock face recognition results to allow modification or deletion.
+
+ Parameters
+ ----------
+ filter : Any, optional
+ Filter criteria for selecting face results to unlock.
+ slaveDsParam : Any, optional
+ Additional parameter for slave DiskStation (not working).
+
+ Returns
+ -------
+ dict of str to object or str
+ API response indicating the result of the unlock operation.
+ """
api_name = 'SYNO.SurveillanceStation.Face.Result'
info = self.gen_list[api_name]
api_path = info['path']
@@ -5445,6 +11095,19 @@ def unlock_face_result(self,
def get_recording_file_of_face_info(self,
# TODO not working
capturedFaceId: int = None) -> dict[str, object] | str:
+ """
+ Retrieve the recording file associated with a specific captured face.
+
+ Parameters
+ ----------
+ capturedFaceId : int, optional
+ ID of the captured face (not working).
+
+ Returns
+ -------
+ dict of str to object or str
+ API response containing the recording file information.
+ """
api_name = 'SYNO.SurveillanceStation.Face.Result'
info = self.gen_list[api_name]
api_path = info['path']
@@ -5464,6 +11127,27 @@ def get_recognition_face_information(self,
endTime: int = None,
# TODO not working
blIncludeRegisteredFace: int = None) -> dict[str, object] | str:
+ """
+ Retrieve analytic results for face recognition events.
+
+ Parameters
+ ----------
+ taskId : int, optional
+ ID of the face recognition task.
+ eventId : int, optional
+ ID of the event.
+ startTime : int, optional
+ Start time for the query (timestamp).
+ endTime : int, optional
+ End time for the query (timestamp).
+ blIncludeRegisteredFace : int, optional
+ Whether to include registered face information (not working).
+
+ Returns
+ -------
+ dict of str to object or str
+ API response containing analytic results.
+ """
api_name = 'SYNO.SurveillanceStation.Face.Result'
info = self.gen_list[api_name]
api_path = info['path']
@@ -5481,6 +11165,21 @@ def correct_face_result(self,
id: int = None,
# TODO not working
registered_face_id: int = None) -> dict[str, object] | str:
+ """
+ Correct the result of a face recognition event by associating it with a registered face.
+
+ Parameters
+ ----------
+ id : int, optional
+ ID of the face recognition result to correct.
+ registered_face_id : int, optional
+ ID of the registered face to associate (not working).
+
+ Returns
+ -------
+ dict of str to object or str
+ API response indicating the result of the correction.
+ """
api_name = 'SYNO.SurveillanceStation.Face.Result'
info = self.gen_list[api_name]
api_path = info['path']
@@ -5496,6 +11195,19 @@ def correct_face_result(self,
def mark_face_result_as_stranger(self,
# TODO not working
ids: str = None) -> dict[str, object] | str:
+ """
+ Mark one or more face recognition results as strangers.
+
+ Parameters
+ ----------
+ ids : str, optional
+ Comma-separated list of face result IDs to mark as strangers (not working).
+
+ Returns
+ -------
+ dict of str to object or str
+ API response indicating the result of the operation.
+ """
api_name = 'SYNO.SurveillanceStation.Face.Result'
info = self.gen_list[api_name]
api_path = info['path']
@@ -5517,6 +11229,31 @@ def add_new_bookmark(self,
timestamp: Any = None,
comment: str = None,
) -> dict[str, object] | str: # TODO not working
+ """
+ Add a new bookmark to a recording.
+
+ Parameters
+ ----------
+ id : int, optional
+ ID of the bookmark.
+ eventId : int, optional
+ ID of the associated event.
+ cameraId : int, optional
+ ID of the camera.
+ archId : int, optional
+ ID of the archive.
+ name : str, optional
+ Name of the bookmark.
+ timestamp : Any, optional
+ Timestamp for the bookmark.
+ comment : str, optional
+ Comment for the bookmark.
+
+ Returns
+ -------
+ dict of str to object or str
+ API response indicating the result of the add operation.
+ """
api_name = 'SYNO.SurveillanceStation.Recording.Bookmark'
info = self.gen_list[api_name]
api_path = info['path']
@@ -5532,6 +11269,19 @@ def add_new_bookmark(self,
def delete_bookmark(self,
# TODO not working
bookmarkIds: Any = None) -> dict[str, object] | str:
+ """
+ Delete one or more bookmarks from recordings.
+
+ Parameters
+ ----------
+ bookmarkIds : Any, optional
+ IDs of the bookmarks to delete (not working).
+
+ Returns
+ -------
+ dict of str to object or str
+ API response indicating the result of the delete operation.
+ """
api_name = 'SYNO.SurveillanceStation.Recording.Bookmark'
info = self.gen_list[api_name]
api_path = info['path']
@@ -5551,6 +11301,27 @@ def list_bookmark_detail(self,
fromTime: int = None,
# TODO not working
toTime: int = None) -> dict[str, object] | str:
+ """
+ List details of bookmarks for recordings.
+
+ Parameters
+ ----------
+ offset : int, optional
+ Offset for pagination.
+ limit : int, optional
+ Maximum number of bookmarks to return.
+ cameraIds : str, optional
+ Comma-separated list of camera IDs to filter.
+ fromTime : int, optional
+ Start time for filtering bookmarks (timestamp).
+ toTime : int, optional
+ End time for filtering bookmarks (not working).
+
+ Returns
+ -------
+ dict of str to object or str
+ API response containing bookmark details.
+ """
api_name = 'SYNO.SurveillanceStation.Recording.Bookmark'
info = self.gen_list[api_name]
api_path = info['path']
diff --git a/synology_api/task_scheduler.py b/synology_api/task_scheduler.py
index d343b3bc..2c439c8e 100644
--- a/synology_api/task_scheduler.py
+++ b/synology_api/task_scheduler.py
@@ -1,3 +1,4 @@
+"""Task Scheduler API implementation for Synology DSM."""
from __future__ import annotations
from . import base_api
from .core_user import User
@@ -5,6 +6,40 @@
class _Schedule():
+ """
+ Schedule configuration class for Synology DSM task scheduling.
+
+ This class encapsulates the parameters required to define a schedule for a task,
+ such as frequency, days, dates, repeat patterns, and time settings.
+
+ Parameters
+ ----------
+ run_frequently : bool, optional
+ If True, the schedule runs frequently (default is True).
+ run_days : str, optional
+ Comma-separated string of week days to run the task (default is '0,1,2,3,4,5,6').
+ run_date : str, optional
+ Specific date to run the task (default is '').
+ repeat : str, optional
+ Repeat pattern for the schedule, e.g., 'Daily' (default is 'Daily').
+ monthly_week : list of str, optional
+ List of weeks in the month to run the task (default is empty list).
+ start_time_h : int, optional
+ Start time hour for the schedule (default is 0).
+ start_time_m : int, optional
+ Start time minute for the schedule (default is 0).
+ same_day_repeat_h : int, optional
+ Repeat interval in hours within the same day (default is 0).
+ same_day_repeat_m : int, optional
+ Repeat interval in minutes within the same day (default is 0).
+ same_day_repeat_until : int, optional
+ Time (in minutes) until which the same day repeat is active (default is 0).
+
+ See Also
+ --------
+ TaskScheduler : Main API class for managing scheduled tasks.
+ """
+
def __init__(
self,
run_frequently: bool = True, # date_type
@@ -18,6 +53,32 @@ def __init__(
same_day_repeat_m: int = 0,
same_day_repeat_until: int = 0,
):
+ """
+ Initialize a schedule configuration for a Synology DSM task.
+
+ Parameters
+ ----------
+ run_frequently : bool, optional
+ If True, the schedule runs frequently (default is True).
+ run_days : str, optional
+ Comma-separated string of week days to run the task (default is '0,1,2,3,4,5,6').
+ run_date : str, optional
+ Specific date to run the task (default is '').
+ repeat : str, optional
+ Repeat pattern for the schedule, e.g., 'Daily' (default is 'Daily').
+ monthly_week : list of str, optional
+ List of weeks in the month to run the task (default is empty list).
+ start_time_h : int, optional
+ Start time hour for the schedule (default is 0).
+ start_time_m : int, optional
+ Start time minute for the schedule (default is 0).
+ same_day_repeat_h : int, optional
+ Repeat interval in hours within the same day (default is 0).
+ same_day_repeat_m : int, optional
+ Repeat interval in minutes within the same day (default is 0).
+ same_day_repeat_until : int, optional
+ Time (in minutes) until which the same day repeat is active (default is 0).
+ """
self.run_frequently = run_frequently
self.run_days = run_days
self.run_date = run_date
@@ -30,6 +91,24 @@ def __init__(
self.same_day_repeat_until = same_day_repeat_until
def _generate_dict(self) -> dict:
+ """
+ Generate a dictionary representation of the schedule configuration.
+
+ This method converts the schedule parameters into a dictionary format
+ suitable for use with the Synology DSM Task Scheduler API.
+
+ Returns
+ -------
+ dict
+ Dictionary containing the schedule configuration, including date type,
+ repeat modality, start time, repeat intervals, and other relevant fields.
+
+ Notes
+ -----
+ - The `repeat_date` field is set based on the `repeat` and `run_frequently` attributes.
+ - The `monthly_week` field is JSON-encoded.
+ - The `last_work_hour` defaults to `start_time_h` if `same_day_repeat_until` is not set.
+ """
schedule_dict = {
'date_type': 0 if self.run_frequently else 1,
'monthly_week': json.dumps(self.monthly_week),
@@ -75,7 +154,8 @@ def _generate_dict(self) -> dict:
class TaskScheduler(base_api.BaseApi):
- """Task Scheduler API implementation.
+ """
+ Task Scheduler API implementation.
This API provides the functionality to get information related to the scheduler settings and current tasks.
@@ -97,6 +177,17 @@ class TaskScheduler(base_api.BaseApi):
"""
def __get_root_token(self) -> str:
+ """
+ Retrieve a root confirmation token for privileged operations.
+
+ This method authenticates the current user and retrieves a Synology DSM root confirmation token,
+ which is required for executing privileged actions (e.g., creating or modifying root-owned tasks).
+
+ Returns
+ -------
+ str
+ The SynoConfirmPWToken if authentication is successful, otherwise an empty string.
+ """
user_api = User(ip_address=self.session._ip_address, port=self.session._port, username=self.session._username, password=self.session._password,
secure=self.session._secure, cert_verify=self.session._verify, dsm_version=self.session._version, debug=self.session._debug,
otp_code=self.session._otp_code, application=self.application)
@@ -107,25 +198,26 @@ def __get_root_token(self) -> str:
return ''
def get_output_config(self) -> dict[str, object]:
- """Retrieve tasks output configuration.
-
- Returns
- -------
- dict[str, object]
- A dictionary containing a list of the tasks and information related to them.
-
- Examples
- --------
- ```json
- {
- "data": {
- "enable_output": true,
- "output_path": "share/scripts_output",
- "type": "esynoscheduler",
- },
- "success": true
- }
- ```
+ """
+ Retrieve tasks output configuration.
+
+ Returns
+ -------
+ dict[str, object]
+ A dictionary containing a list of the tasks and information related to them.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "enable_output": true,
+ "output_path": "share/scripts_output",
+ "type": "esynoscheduler",
+ },
+ "success": true
+ }
+ ```
"""
api_name = 'SYNO.Core.EventScheduler'
info = self.gen_list[api_name]
@@ -145,76 +237,77 @@ def get_task_list(
offset: int = 0,
limit: int = 50
) -> dict[str, object]:
- """List all present scheduled tasks and event triggered tasks.
-
- Parameters
- ----------
- sort_by : str, optional
- The field to sort tasks by. Defaults to `"next_trigger_time"`.
-
- Possible values:
- - "next_trigger_time"
- - "name"
- - "type"
- - "action"
- - "owner"
-
- sort_direction : str, optional
- The sort direction. Defaults to `"ASC"`.
-
- Possible values:
- - "ASC"
- - "DESC"
-
- offset : int, optional
- Task offset for pagination. Defaults to `0`.
-
- limit : int, optional
- Number of tasks to retrieve. Defaults to `50`.
-
- Returns
- -------
- dict[str, object]
- A dictionary containing a list of the tasks and information related to them.
-
- Examples
- --------
- ```json
- {
- "data": {
- "tasks": [
- {
- "action": "Run: rsync -aP --delete /volume1/test/ /volume1/test2/",
- "can_delete": true,
- "can_edit": true,
- "can_run": true,
- "enable": false,
- "id": 13,
- "name": "Sync folders",
- "next_trigger_time": "2024-09-09 12:26",
- "owner": "root",
- "real_owner": "root",
- "type": "script"
- },
- {
- "action": "Run: echo hello > /tmp/awacate.out",
- "can_delete": true,
- "can_edit": true,
- "can_run": true,
- "enable": true,
- "id": 11,
- "name": "TEST_CRONTAB",
- "next_trigger_time": "2024-09-10 00:00",
- "owner": "root",
- "real_owner": "root",
- "type": "script"
- }
- ]
- "total": 2
- },
- "success": true
- }
- ```
+ """
+ List all present scheduled tasks and event triggered tasks.
+
+ Parameters
+ ----------
+ sort_by : str, optional
+ The field to sort tasks by. Defaults to `"next_trigger_time"`.
+
+ Possible values:
+ - "next_trigger_time"
+ - "name"
+ - "type"
+ - "action"
+ - "owner"
+
+ sort_direction : str, optional
+ The sort direction. Defaults to `"ASC"`.
+
+ Possible values:
+ - "ASC"
+ - "DESC"
+
+ offset : int, optional
+ Task offset for pagination. Defaults to `0`.
+
+ limit : int, optional
+ Number of tasks to retrieve. Defaults to `50`.
+
+ Returns
+ -------
+ dict[str, object]
+ A dictionary containing a list of the tasks and information related to them.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "tasks": [
+ {
+ "action": "Run: rsync -aP --delete /volume1/test/ /volume1/test2/",
+ "can_delete": true,
+ "can_edit": true,
+ "can_run": true,
+ "enable": false,
+ "id": 13,
+ "name": "Sync folders",
+ "next_trigger_time": "2024-09-09 12:26",
+ "owner": "root",
+ "real_owner": "root",
+ "type": "script"
+ },
+ {
+ "action": "Run: echo hello > /tmp/awacate.out",
+ "can_delete": true,
+ "can_edit": true,
+ "can_run": true,
+ "enable": true,
+ "id": 11,
+ "name": "TEST_CRONTAB",
+ "next_trigger_time": "2024-09-10 00:00",
+ "owner": "root",
+ "real_owner": "root",
+ "type": "script"
+ }
+ ]
+ "total": 2
+ },
+ "success": true
+ }
+ ```
"""
api_name = 'SYNO.Core.TaskScheduler'
info = self.gen_list[api_name]
@@ -236,68 +329,67 @@ def get_task_config(
real_owner: str,
type: str = ''
) -> dict[str, object]:
- """Retrieve the configuration for a specific task or list of all the available services and their corresponding IDs.
-
- Parameters
- ----------
- task_id : int
- The ID of the task to retrieve the configuration for. Pass `-1` to get a list of all available services with their IDs.
-
- real_owner : str
- The task real owner, usually it is `root`, you can double check from the result of `get_task_config()`.
-
- type : str, optional
- The type of task (e.g., 'service'). Pass "service" to get a list of all available services with their IDs. Defaults to `""`.
-
- Returns
- -------
- dict[str, object]
- A dictionary containing the task configuration.
-
- Examples
- --------
- ```json
- {
- "data": {
- "action": "Run: echo hello > /tmp/awacate.out",
- "can_edit_name": true,
- "can_edit_owner": true,
- "enable": true,
- "extra": {
- "notify_enable": false,
- "notify_if_error": false,
- "notify_mail": "",
- "script": "echo hello > /tmp/awacate.out"
- },
- "id": 11,
- "name": "TEST_CRONTAB",
- "owner": "root",
- "real_owner": "root",
- "schedule": {
- "date": "2024/9/11",
- "date_type": 0,
- "hour": 0,
- "last_work_hour": 0,
- "minute": 0,
- "monthly_week": [],
- "repeat_date": 1001,
- "repeat_hour": 0,
- "repeat_hour_store_config": [
- 1..23
- ],
- "repeat_min": 0,
- "repeat_min_store_config": [
- 1,
- ...
- ],
- "version": 4,
- "week_day": "0,1,2,3,4,5,6"
- },
- "type": "script"
+ """
+ Retrieve the configuration for a specific task or list all available services and their corresponding IDs.
+
+ Parameters
+ ----------
+ task_id : int
+ The ID of the task to retrieve the configuration for. Pass `-1` to get a list of all available services with their IDs.
+ real_owner : str
+ The real owner of the task, usually `root`. You can double check from the result of `get_task_config()`.
+ type : str, optional
+ The type of task (e.g., 'service'). Pass `"service"` to get a list of all available services with their IDs. Defaults to `""`.
+
+ Returns
+ -------
+ dict[str, object]
+ A dictionary containing the task configuration.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "action": "Run: echo hello > /tmp/awacate.out",
+ "can_edit_name": true,
+ "can_edit_owner": true,
+ "enable": true,
+ "extra": {
+ "notify_enable": false,
+ "notify_if_error": false,
+ "notify_mail": "",
+ "script": "echo hello > /tmp/awacate.out"
},
- "success": true
- }
- ```
+ "id": 11,
+ "name": "TEST_CRONTAB",
+ "owner": "root",
+ "real_owner": "root",
+ "schedule": {
+ "date": "2024/9/11",
+ "date_type": 0,
+ "hour": 0,
+ "last_work_hour": 0,
+ "minute": 0,
+ "monthly_week": [],
+ "repeat_date": 1001,
+ "repeat_hour": 0,
+ "repeat_hour_store_config": [
+ 1..23
+ ],
+ "repeat_min": 0,
+ "repeat_min_store_config": [
+ 1,
+ ...
+ ],
+ "version": 4,
+ "week_day": "0,1,2,3,4,5,6"
+ },
+ "type": "script"
+ },
+ "success": true
+ }
+ ```
"""
api_name = 'SYNO.Core.TaskScheduler'
info = self.gen_list[api_name]
@@ -318,41 +410,42 @@ def get_task_results(
self,
task_id: int
) -> dict[str, object]:
- """Retrieve the results list for a specific task.
-
- Parameters
- ----------
- task_id : int
- The ID of the task to retrieve the results for.
-
- Returns
- -------
- dict[str, object]
- A dictionary containing the task results.
-
- Examples
- --------
- ```json
- {
- "data": [
- {
- "exit_code": 127,
- "exit_type": "by_signal",
- "start_time": "2024-09-11 00:00:01",
- "stop_time": "2024-09-11 00:00:06",
- "timestamp": "1726005601"
- },
- {
- "exit_code": 0,
- "exit_type": "normal",
- "start_time": "2024-06-01 00:00:01",
- "stop_time": "2024-06-01 00:00:02",
- "timestamp": "1717192801"
- }
- ],
- "success": true
- }
- ```
+ """
+ Retrieve the results list for a specific task.
+
+ Parameters
+ ----------
+ task_id : int
+ The ID of the task to retrieve the results for.
+
+ Returns
+ -------
+ dict[str, object]
+ A dictionary containing the task results.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": [
+ {
+ "exit_code": 127,
+ "exit_type": "by_signal",
+ "start_time": "2024-09-11 00:00:01",
+ "stop_time": "2024-09-11 00:00:06",
+ "timestamp": "1726005601"
+ },
+ {
+ "exit_code": 0,
+ "exit_type": "normal",
+ "start_time": "2024-06-01 00:00:01",
+ "stop_time": "2024-06-01 00:00:02",
+ "timestamp": "1717192801"
+ }
+ ],
+ "success": true
+ }
+ ```
"""
api_name = 'SYNO.Core.TaskScheduler'
info = self.gen_list[api_name]
@@ -414,7 +507,8 @@ def set_output_config(
enable_output: bool,
output_path: str = ''
) -> dict[str, object]:
- """Configure the output settings for tasks results.
+ """
+ Configure the output settings for tasks results.
Parameters
----------
@@ -422,7 +516,7 @@ def set_output_config(
Whether to enable result logging or not.
output_path : str, optional
- The path where the result logs will be stored, e.g. `share/scripts_output'`. Defaults to `""`.
+ The path where the result logs will be stored, e.g. `share/scripts_output`. Defaults to `""`.
Returns
-------
@@ -456,7 +550,8 @@ def task_set_enable(
real_owner: str,
enable: bool
) -> dict[str, object]:
- """Enable or disable a task.
+ """
+ Enable or disable a task.
Parameters
----------
@@ -504,7 +599,8 @@ def task_run(
task_id: int,
real_owner: str
) -> dict[str, object]:
- """Run a specific task.
+ """
+ Run a specific task.
Parameters
----------
@@ -548,7 +644,8 @@ def task_delete(
task_id: int,
real_owner: str
) -> dict[str, object]:
- """Delete a specific task.
+ """
+ Delete a specific task.
Parameters
----------
@@ -606,7 +703,8 @@ def create_script_task(
notify_email: str = '',
notify_only_on_error: bool = False
) -> dict[str, object]:
- """Create a new Script task with the provided schedule and notification settings.
+ """
+ Create a new Script task with the provided schedule and notification settings.
Tip: If the task needs to run with root privileges, please specify the owner as "root".
@@ -753,7 +851,8 @@ def modify_script_task(
notify_email: str = '',
notify_only_on_error: bool = False
) -> dict[str, object]:
- """Modify settings of a Script task.
+ """
+ Modify settings of a Script task.
Warning: This method overwrites all the settings of the task, so if you only want to change one setting, you can fetch the current task configuration with `get_task_config()` and pass all the settings to this method.
@@ -901,88 +1000,74 @@ def create_beep_control_task(
same_day_repeat_m: int = 0,
same_day_repeat_until: int = -1
) -> dict[str, object]:
- """Create a new Beep Control task with the provided schedule and beep duration.
-
- Parameters
- ----------
- task_name : str
- The name of the task.
-
- owner : str
- The task owner.
-
- beep_duration : int, optional
- The amount of seconds the beep will be triggered for, in seconds. Defaults to `60`.
-
- enable : bool, optional
- Whether the task should be enabled upon creation. Defaults to `True`.
-
- run_frequently : bool, optional
- Determines whether the task runs on a recurring schedule (True) or only on a specific date (False). Defaults to `True`.
-
- run_days : str, optional
- Days of the week when the task should run, used if `run_frequently` is set to `True`, specified as a comma-separated list (e.g., '0,1,2' for Sunday, Monday, Tuesday). Defaults to `'0,1,2,3,4,5,6'` (Daily).
-
- run_date : str, optional
- The specific date the task should run, used if `run_frequently` is set to `False`. Format: `yyyy/m/d` (no prefix zeros). Defaults to `""`.
-
- repeat : str, optional
- How often the task should repeat. Defaults to `'daily'`.
-
- Possible values:
- - `daily` -> Only when 'run_frequently=True'
- - `weekly` -> Only when 'run_frequently=True'
- - `monthly` -> Works for both 'run_frequently=True' and 'run_frequently=False'
- - `no_repeat` -> Only when 'run_frequently=False'
- - `every_3_months` -> Only when 'run_frequently=False'
- - `every_6_months` -> Only when 'run_frequently=False'
- - `yearly` -> Only when 'run_frequently=False'
-
-
- monthly_week : list[str], optional
- If `run_frequently=True` and `repeat='monthly'`, specifies the weeks the task should run, e.g., `['first', 'third']`.
- Defaults to `[]`.
-
- start_time_h : int, optional
- Hour at which the task should start. Defaults to `0`.
-
- start_time_m : int, optional
- Minute at which the task should start. Defaults to `0`.
-
- same_day_repeat_h : int, optional
- Number of hours between repeated executions on the same day (run every x hours), if "Continue running within the same day" is desired.
- Set to `0` to disable same-day repeats. Defaults to `0`.
-
- Possible values: `0..23`
-
- The args `same_day_repeat_h` and `same_day_repeat_m` cannot be used at the same time, if both are passed, `same_day_repeat_h` will be prioritized.
-
- same_day_repeat_m : int, optional
- Number of minutes between repeated executions on the same day (run every x minutes), if "Continue running within the same day" is desired.
- Set to `0` to disable same-day repeats. Defaults to `0`.
-
- Posible values: `1`, `5`, `10`, `15`, `20`, `30`
-
- The args `same_day_repeat_h` and `same_day_repeat_m` cannot be used at the same time, if both are passed, `same_day_repeat_h` will be prioritized.
-
- same_day_repeat_until : int, optional
- Last hour of the day when the task can repeat. Defaults to `start_time_h`.
-
- Returns
- -------
- dict[str, object]
- A dictionary with the id of the created task.
-
- Examples
- --------
- ```json
- {
- "data": {
- "id": 20
- },
- "success": true
- }
- ```
+ """
+ Create a new Beep Control task with the provided schedule and beep duration.
+
+ Parameters
+ ----------
+ task_name : str
+ The name of the task.
+ owner : str
+ The task owner.
+ enable : bool, optional
+ Whether the task should be enabled upon creation. Defaults to True.
+ beep_duration : int, optional
+ The amount of seconds the beep will be triggered for. Defaults to 60.
+ run_frequently : bool, optional
+ Determines whether the task runs on a recurring schedule (True) or only on a specific date (False). Defaults to True.
+ run_days : str, optional
+ Days of the week when the task should run, used if `run_frequently` is set to True, specified as a comma-separated list (e.g., '0,1,2' for Sunday, Monday, Tuesday). Defaults to '0,1,2,3,4,5,6'.
+ run_date : str, optional
+ The specific date the task should run, used if `run_frequently` is set to False. Format: yyyy/m/d (no prefix zeros). Defaults to "".
+ repeat : str, optional
+ How often the task should repeat. Defaults to 'daily'.
+
+ Possible values:
+ - 'daily' -> Only when run_frequently=True
+ - 'weekly' -> Only when run_frequently=True
+ - 'monthly' -> Works for both run_frequently=True and run_frequently=False
+ - 'no_repeat' -> Only when run_frequently=False
+ - 'every_3_months' -> Only when run_frequently=False
+ - 'every_6_months' -> Only when run_frequently=False
+ - 'yearly' -> Only when run_frequently=False
+ monthly_week : list[str], optional
+ If run_frequently=True and repeat='monthly', specifies the weeks the task should run, e.g., ['first', 'third']. Defaults to [].
+ start_time_h : int, optional
+ Hour at which the task should start. Defaults to 0.
+ start_time_m : int, optional
+ Minute at which the task should start. Defaults to 0.
+ same_day_repeat_h : int, optional
+ Number of hours between repeated executions on the same day (run every x hours), if "Continue running within the same day" is desired.
+ Set to 0 to disable same-day repeats. Defaults to 0.
+
+ Possible values: 0..23
+
+ The args same_day_repeat_h and same_day_repeat_m cannot be used at the same time, if both are passed, same_day_repeat_h will be prioritized.
+ same_day_repeat_m : int, optional
+ Number of minutes between repeated executions on the same day (run every x minutes), if "Continue running within the same day" is desired.
+ Set to 0 to disable same-day repeats. Defaults to 0.
+
+ Possible values: 1, 5, 10, 15, 20, 30
+
+ The args same_day_repeat_h and same_day_repeat_m cannot be used at the same time, if both are passed, same_day_repeat_h will be prioritized.
+ same_day_repeat_until : int, optional
+ Last hour of the day when the task can repeat. Defaults to start_time_h.
+
+ Returns
+ -------
+ dict[str, object]
+ A dictionary with the id of the created task.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "id": 20
+ },
+ "success": true
+ }
+ ```
"""
schedule = _Schedule(run_frequently, run_days, run_date, repeat, monthly_week, start_time_h, start_time_m,
@@ -1028,92 +1113,82 @@ def modify_beep_control_task(
same_day_repeat_m: int = 0,
same_day_repeat_until: int = -1
) -> dict[str, object]:
- """Modify settings of a Beep Control task.
-
- Warning: This method overwrites all the settings of the task, so if you only want to change one setting, you can fetch the current task configuration with `get_task_config()` and pass all the settings to this method.
-
- Parameters
- ----------
- task_name : str
- The name of the task.
-
- real_owner : str
- The task owner.
-
- beep_duration : int, optional
- The amount of seconds the beep will be triggered for, in seconds. Defaults to `60`.
-
- enable : bool, optional
- Whether the task should be enabled upon creation. Defaults to `True`.
-
- run_frequently : bool, optional
- Determines whether the task runs on a recurring schedule (True) or only on a specific date (False). Defaults to `True`.
-
- run_days : str, optional
- Days of the week when the task should run, used if `run_frequently` is set to `True`, specified as a comma-separated list (e.g., '0,1,2' for Sunday, Monday, Tuesday). Defaults to `'0,1,2,3,4,5,6'` (Daily).
-
- run_date : str, optional
- The specific date the task should run, used if `run_frequently` is set to `False`. Format: `yyyy/m/d` (no prefix zeros). Defaults to `""`.
-
- repeat : str, optional
- How often the task should repeat. Defaults to `'daily'`.
-
- Possible values:
- - `daily` -> Only when 'run_frequently=True'
- - `weekly` -> Only when 'run_frequently=True'
- - `monthly` -> Works for both 'run_frequently=True' and 'run_frequently=False'
- - `no_repeat` -> Only when 'run_frequently=False'
- - `every_3_months` -> Only when 'run_frequently=False'
- - `every_6_months` -> Only when 'run_frequently=False'
- - `yearly` -> Only when 'run_frequently=False'
-
- monthly_week : list[str], optional
- If `run_frequently=True` and `repeat='monthly'`, specifies the weeks the task should run, e.g., `['first', 'third']`. Defaults to `[]`.
-
- start_time_h : int, optional
- Hour at which the task should start. Defaults to `0`.
-
- start_time_m : int, optional
- Minute at which the task should start. Defaults to `0`.
-
- same_day_repeat_h : int, optional
- Number of hours between repeated executions on the same day (run every x hours), if "Continue running within the same day" is desired.
-
- Set to `0` to disable same-day repeats. Defaults to `0`.
-
- Possible values: `0..23`
-
- Info: The args `same_day_repeat_h` and `same_day_repeat_m` cannot be used at the same time, if both are passed, `same_day_repeat_h` will be prioritized.
-
- same_day_repeat_m : int, optional
- Number of minutes between repeated executions on the same day (run every x minutes), if "Continue running within the same day" is desired.
-
- Set to `0` to disable same-day repeats. Defaults to `0`.
-
- Posible values: `1`, `5`, `10`, `15`, `20`, `30`
-
- Info: The args `same_day_repeat_h` and `same_day_repeat_m` cannot be used at the same time, if both are passed, `same_day_repeat_h` will be prioritized.
-
- same_day_repeat_until : int, optional
- Last hour of the day when the task can repeat. Defaults to `start_time_h`.
-
- Returns
- -------
- dict[str, object]
- A dictionary with the id of the created task.
-
- Examples
- --------
- ```json
- {
- "data": {
- "id": 20
- },
- "success": true
- }
- ```
"""
-
+ Modify settings of a Beep Control task.
+
+ Parameters
+ ----------
+ task_id : int
+ The ID of the task to modify.
+ task_name : str
+ The name of the task.
+ real_owner : str
+ The task owner.
+ enable : bool, optional
+ Whether the task should be enabled upon modification. Defaults to `True`.
+ beep_duration : int, optional
+ The amount of seconds the beep will be triggered for, in seconds. Defaults to `60`.
+ run_frequently : bool, optional
+ Determines whether the task runs on a recurring schedule (`True`) or only on a specific date (`False`). Defaults to `True`.
+ run_days : str, optional
+ Days of the week when the task should run, used if `run_frequently` is set to `True`, specified as a comma-separated list (e.g., '0,1,2' for Sunday, Monday, Tuesday). Defaults to `'0,1,2,3,4,5,6'` (Daily).
+ run_date : str, optional
+ The specific date the task should run, used if `run_frequently` is set to `False`. Format: `yyyy/m/d` (no prefix zeros). Defaults to `""`.
+ repeat : str, optional
+ How often the task should repeat. Defaults to `'daily'`.
+
+ Possible values:
+ - `daily` -> Only when `run_frequently=True`
+ - `weekly` -> Only when `run_frequently=True`
+ - `monthly` -> Works for both `run_frequently=True` and `run_frequently=False`
+ - `no_repeat` -> Only when `run_frequently=False`
+ - `every_3_months` -> Only when `run_frequently=False`
+ - `every_6_months` -> Only when `run_frequently=False`
+ - `yearly` -> Only when `run_frequently=False`
+ monthly_week : list[str], optional
+ If `run_frequently=True` and `repeat='monthly'`, specifies the weeks the task should run, e.g., `['first', 'third']`. Defaults to `[]`.
+ start_time_h : int, optional
+ Hour at which the task should start. Defaults to `0`.
+ start_time_m : int, optional
+ Minute at which the task should start. Defaults to `0`.
+ same_day_repeat_h : int, optional
+ Number of hours between repeated executions on the same day (run every x hours), if "Continue running within the same day" is desired.
+ Set to `0` to disable same-day repeats. Defaults to `0`.
+
+ Possible values: `0..23`
+
+ Info: The args `same_day_repeat_h` and `same_day_repeat_m` cannot be used at the same time, if both are passed, `same_day_repeat_h` will be prioritized.
+ same_day_repeat_m : int, optional
+ Number of minutes between repeated executions on the same day (run every x minutes), if "Continue running within the same day" is desired.
+ Set to `0` to disable same-day repeats. Defaults to `0`.
+
+ Possible values: `1`, `5`, `10`, `15`, `20`, `30`
+
+ Info: The args `same_day_repeat_h` and `same_day_repeat_m` cannot be used at the same time, if both are passed, `same_day_repeat_h` will be prioritized.
+ same_day_repeat_until : int, optional
+ Last hour of the day when the task can repeat. Defaults to `start_time_h`.
+
+ Returns
+ -------
+ dict[str, object]
+ A dictionary with the id of the modified task.
+
+ Notes
+ -----
+ Warning: This method overwrites all the settings of the task, so if you only want to change one setting,
+ you can fetch the current task configuration with `get_task_config()` and pass all the settings to this method.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "id": 20
+ },
+ "success": true
+ }
+ ```
+ """
schedule = _Schedule(run_frequently, run_days, run_date, repeat, monthly_week, start_time_h, start_time_m,
same_day_repeat_h, same_day_repeat_m, same_day_repeat_until)
@@ -1157,7 +1232,8 @@ def create_service_control_task(
same_day_repeat_m: int = 0,
same_day_repeat_until: int = -1
) -> dict[str, object]:
- """Create a new Service Control task with the provided schedule and services to start/stop.
+ """
+ Create a new Service Control task with the provided schedule and services to start/stop.
Parameters
----------
@@ -1167,7 +1243,7 @@ def create_service_control_task(
owner : str
The task owner.
- services (list):
+ services : list[dict]
A list containing the services and their type to be influenced by the specified action (start / stop).
To get a list of all the available services and their corresponding IDs, call `get_task_config(task_id=-1, real_owner=your_username, type='service')`.
@@ -1309,7 +1385,8 @@ def modify_service_control_task(
same_day_repeat_m: int = 0,
same_day_repeat_until: int = -1
) -> dict[str, object]:
- """Modify settings of a Service Control task.
+ """
+ Modify settings of a Service Control task.
Warning: This method overwrites all the settings of the task, so if you only want to change one setting, you can fetch the current task configuration with `get_task_config()` and pass all the settings to this method.
@@ -1324,7 +1401,7 @@ def modify_service_control_task(
real_owner : str
The task real owner, usually it is `root`, you can double check from the result of `get_task_config()`.
- services (list):
+ services : list[dict]
A list containing the services and their type to be influenced by the specified action (start / stop).
To get a list of all the available services and their corresponding IDs, call `get_task_config(task_id=-1, real_owner=your_username, type='service')`.
@@ -1468,95 +1545,76 @@ def create_recycle_bin_task(
same_day_repeat_m: int = 0,
same_day_repeat_until: int = -1
) -> dict[str, object]:
- """Create a new Recycle Bin Control task with the provided schedule and services to start/stop.
-
- Parameters
- ----------
- task_name : str
- The name of the task.
-
- owner : str
- The task owner.
-
- clean_all_shares : bool
- Whether the task should empty the recycle bins of all shares or not, if set to `False`, shares must be specified.
-
- shares : list[str], optional
- List of shares of which to clean the recycle bins. Pass only the name of the shares without slashes, e.g. `shares=['photo', 'web']`. Defaults to `[]`.
-
- policy (dict):
- Determines what files will be deleted from the recycle bins.
-
- Possible values are:
- - `{"policy": "clean_all"}` -> Clean all files
- - `{"policy": "time", "time": int}` -> Clean all files older than X days, days being possed as value for "time" key.
- - `{"policy": "size", "size": int , "sort_type": int}` -> Clean files until recycle bin size reaches given "size" in MB, delete files by "sort_type".
-
- Possible values for "sort_type" are:
- - `0` -> Delete bigger files first
- - `1` -> Delete older files first
-
- enable : bool, optional
- Whether the task should be enabled upon creation. Defaults to `True`.
-
- run_frequently : bool, optional
- Determines whether the task runs on a recurring schedule (True) or only on a specific date (False). Defaults to `True`.
-
- run_days : str, optional
- Days of the week when the task should run, used if `run_frequently` is set to `True`, specified as a comma-separated list (e.g., '0,1,2' for Sunday, Monday, Tuesday). Defaults to `'0,1,2,3,4,5,6'` (Daily).
-
- run_date : str, optional
- The specific date the task should run, used if `run_frequently` is set to `False`. Format: `yyyy/m/d` (no prefix zeros).
- Defaults to `""`.
-
- repeat : str, optional
- How often the task should repeat. Defaults to `'daily'`.
-
- Possible values:
- - `daily` -> Only when 'run_frequently=True'
- - `weekly` -> Only when 'run_frequently=True'
- - `monthly` -> Works for both 'run_frequently=True' and 'run_frequently=False'
- - `no_repeat` -> Only when 'run_frequently=False'
- - `every_3_months` -> Only when 'run_frequently=False'
- - `every_6_months` -> Only when 'run_frequently=False'
- - `yearly` -> Only when 'run_frequently=False'
-
- monthly_week : list[str], optional
- If `run_frequently=True` and `repeat='monthly'`, specifies the weeks the task should run, e.g., `['first', 'third']`.
-
- Defaults to `[]`.
-
- start_time_h : int, optional
- Hour at which the task should start. Defaults to `0`.
-
- start_time_m : int, optional
- Minute at which the task should start. Defaults to `0`.
-
- same_day_repeat_h : int, optional
- Number of hours between repeated executions on the same day (run every x hours), if "Continue running within the same day" is desired.
-
- Set to `0` to disable same-day repeats. Defaults to `0` (disable same day repeat).
-
- Possible values: `0..23`
-
- Info: The args `same_day_repeat_h` and `same_day_repeat_m` cannot be used at the same time, if both are passed, `same_day_repeat_h` will be prioritized.
-
- same_day_repeat_m : int, optional
- Number of minutes between repeated executions on the same day (run every x minutes), if "Continue running within the same day" is desired.
-
- Set to `0` to disable same-day repeats. Defaults to `0` (disable same day repeat).
-
- Posible values: `1`, `5`, `10`, `15`, `20`, `30`
-
- Info: The args `same_day_repeat_h` and `same_day_repeat_m` cannot be used at the same time, if both are passed, `same_day_repeat_h` will be prioritized.
-
- same_day_repeat_until : int, optional
- Last hour of the day when the task can repeat. Defaults to `start_time_h`.
-
- Returns
- -------
- dict[str, object]
- A dictionary with the id of the created task.
+ """
+ Create a new Recycle Bin Control task with the provided schedule and policy.
+
+ Parameters
+ ----------
+ task_name : str
+ The name of the task.
+ owner : str
+ The task owner.
+ clean_all_shares : bool
+ Whether the task should empty the recycle bins of all shares. If set to False, `shares` must be specified.
+ policy : dict
+ Determines what files will be deleted from the recycle bins.
+
+ Possible values are:
+ - \\{"policy": "clean_all"\\}: Clean all files.
+ - \\{"policy": "time", "time": int\\}: Clean all files older than X days, where X is the value for "time".
+ - \\{"policy": "size", "size": int, "sort_type": int\\}: Clean files until recycle bin size reaches given "size" in MB, delete files by "sort_type".
+
+ Possible values for "sort_type":
+ - 0: Delete bigger files first.
+ - 1: Delete older files first.
+ shares : list[str], optional
+ List of shares of which to clean the recycle bins. Pass only the name of the shares without slashes, e.g. `shares=['photo', 'web']`. Defaults to [].
+ enable : bool, optional
+ Whether the task should be enabled upon creation. Defaults to True.
+ run_frequently : bool, optional
+ Determines whether the task runs on a recurring schedule (True) or only on a specific date (False). Defaults to True.
+ run_days : str, optional
+ Days of the week when the task should run, used if `run_frequently` is True, specified as a comma-separated list (e.g., '0,1,2' for Sunday, Monday, Tuesday). Defaults to '0,1,2,3,4,5,6'.
+ run_date : str, optional
+ The specific date the task should run, used if `run_frequently` is False. Format: yyyy/m/d (no prefix zeros). Defaults to "".
+ repeat : str, optional
+ How often the task should repeat. Defaults to 'daily'.
+
+ Possible values:
+ - 'daily' (only when run_frequently=True)
+ - 'weekly' (only when run_frequently=True)
+ - 'monthly' (works for both run_frequently=True and run_frequently=False)
+ - 'no_repeat' (only when run_frequently=False)
+ - 'every_3_months' (only when run_frequently=False)
+ - 'every_6_months' (only when run_frequently=False)
+ - 'yearly' (only when run_frequently=False)
+ monthly_week : list[str], optional
+ If run_frequently=True and repeat='monthly', specifies the weeks the task should run, e.g., ['first', 'third']. Defaults to [].
+ start_time_h : int, optional
+ Hour at which the task should start. Defaults to 0.
+ start_time_m : int, optional
+ Minute at which the task should start. Defaults to 0.
+ same_day_repeat_h : int, optional
+ Number of hours between repeated executions on the same day (run every x hours), if "Continue running within the same day" is desired.
+ Set to 0 to disable same-day repeats. Defaults to 0.
+
+ Possible values: 0..23
+
+ Note: The args same_day_repeat_h and same_day_repeat_m cannot be used at the same time; if both are passed, same_day_repeat_h will be prioritized.
+ same_day_repeat_m : int, optional
+ Number of minutes between repeated executions on the same day (run every x minutes), if "Continue running within the same day" is desired.
+ Set to 0 to disable same-day repeats. Defaults to 0.
+
+ Possible values: 1, 5, 10, 15, 20, 30
+
+ Note: The args same_day_repeat_h and same_day_repeat_m cannot be used at the same time; if both are passed, same_day_repeat_h will be prioritized.
+ same_day_repeat_until : int, optional
+ Last hour of the day when the task can repeat. Defaults to start_time_h.
+
+ Returns
+ -------
+ dict[str, object]
+ A dictionary with the id of the created task.
Examples
--------
@@ -1621,111 +1679,94 @@ def modify_recycle_bin_task(
same_day_repeat_m: int = 0,
same_day_repeat_until: int = -1
) -> dict[str, object]:
- """Modify settings of a Recycle Bin Control task.
-
- Warning: This method overwrites all the settings of the task, so if you only want to change one setting, you can fetch the current task configuration with `get_task_config()` and pass all the settings to this method.
-
- Parameters
- ----------
- task_id : int
- The ID of the task.
-
- task_name : str
- The name of the task.
-
- real_owner : str
- The task real owner, usually it is `root`, you can double check from the result of `get_task_config()`.
-
- clean_all_shares : bool
- Whether the task should empty the recycle bins of all shares or not, if set to `False`, shares must be specified.
-
- shares : list[str], optional
- List of shares of which to clean the recycle bins. Pass only the name of the shares without slashes, e.g. `shares=['photo', 'web']`. Defaults to `[]`.
-
- policy (dict):
- Determines what files will be deleted from the recycle bins.
-
- Possible values are:
- - `{"policy": "clean_all"}` -> Clean all files
- - `{"policy": "time", "time": int}` -> Clean all files older than X days, days being possed as value for "time" key.
- - `{"policy": "size", "size": int , "sort_type": int}` -> Clean files until recycle bin size reaches given "size" in MB, delete files by "sort_type".
-
- Possible values for "sort_type" are:
- - `0` -> Delete bigger files first
- - `1` -> Delete older files first
-
- enable : bool, optional
- Whether the task should be enabled upon creation. Defaults to `True`.
-
- run_frequently : bool, optional
- Determines whether the task runs on a recurring schedule (True) or only on a specific date (False). Defaults to `True`.
-
- run_days : str, optional
- Days of the week when the task should run, used if `run_frequently` is set to `True`, specified as a comma-separated list (e.g., '0,1,2' for Sunday, Monday, Tuesday). Defaults to `'0,1,2,3,4,5,6'` (Daily).
-
- run_date : str, optional
- The specific date the task should run, used if `run_frequently` is set to `False`. Format: `yyyy/m/d` (no prefix zeros).
- Defaults to `""`.
-
- repeat : str, optional
- How often the task should repeat. Defaults to `'daily'`.
-
- Possible values:
- - `daily` -> Only when 'run_frequently=True'
- - `weekly` -> Only when 'run_frequently=True'
- - `monthly` -> Works for both 'run_frequently=True' and 'run_frequently=False'
- - `no_repeat` -> Only when 'run_frequently=False'
- - `every_3_months` -> Only when 'run_frequently=False'
- - `every_6_months` -> Only when 'run_frequently=False'
- - `yearly` -> Only when 'run_frequently=False'
-
- monthly_week : list[str], optional
- If `run_frequently=True` and `repeat='monthly'`, specifies the weeks the task should run, e.g., `['first', 'third']`.
-
- Defaults to `[]`.
-
- start_time_h : int, optional
- Hour at which the task should start. Defaults to `0`.
-
- start_time_m : int, optional
- Minute at which the task should start. Defaults to `0`.
-
- same_day_repeat_h : int, optional
- Number of hours between repeated executions on the same day (run every x hours), if "Continue running within the same day" is desired.
-
- Set to `0` to disable same-day repeats. Defaults to `0` (disable same day repeat).
-
- Possible values: `0..23`
-
- Info: The args `same_day_repeat_h` and `same_day_repeat_m` cannot be used at the same time, if both are passed, `same_day_repeat_h` will be prioritized.
-
- same_day_repeat_m : int, optional
- Number of minutes between repeated executions on the same day (run every x minutes), if "Continue running within the same day" is desired.
-
- Set to `0` to disable same-day repeats. Defaults to `0` (disable same day repeat).
-
- Posible values: `1`, `5`, `10`, `15`, `20`, `30`
-
- Info: The args `same_day_repeat_h` and `same_day_repeat_m` cannot be used at the same time, if both are passed, `same_day_repeat_h` will be prioritized.
-
- same_day_repeat_until : int, optional
- Last hour of the day when the task can repeat. Defaults to `start_time_h`.
-
- Returns
- -------
- dict[str, object]
- A dictionary with the id of the created task.
-
- Examples
- --------
- ```json
- {
- "data": {
- "id": 20
- },
- "success": true
- }
- ```
+ """
+ Modify settings of a Recycle Bin Control task.
+
+ Parameters
+ ----------
+ task_id : int
+ The ID of the task.
+ task_name : str
+ The name of the task.
+ real_owner : str
+ The task real owner, usually it is `root`. You can double check from the result of `get_task_config()`.
+ clean_all_shares : bool
+ Whether the task should empty the recycle bins of all shares. If set to `False`, `shares` must be specified.
+ policy : dict
+ Determines what files will be deleted from the recycle bins.
+
+ Possible values are:
+ - \\{"policy": "clean_all"\\}: Clean all files.
+ - \\{"policy": "time", "time": int\\}: Clean all files older than X days, where X is the value for "time".
+ - \\{"policy": "size", "size": int, "sort_type": int\\}: Clean files until recycle bin size reaches given "size" in MB, delete files by "sort_type".
+
+ Possible values for "sort_type":
+ - 0: Delete bigger files first.
+ - 1: Delete older files first.
+ shares : list[str], optional
+ List of shares of which to clean the recycle bins. Pass only the name of the shares without slashes, e.g. `shares=['photo', 'web']`. Defaults to [].
+ enable : bool, optional
+ Whether the task should be enabled upon modification. Defaults to `True`.
+ run_frequently : bool, optional
+ Determines whether the task runs on a recurring schedule (True) or only on a specific date (False). Defaults to `True`.
+ run_days : str, optional
+ Days of the week when the task should run, used if `run_frequently` is set to `True`, specified as a comma-separated list (e.g., '0,1,2' for Sunday, Monday, Tuesday). Defaults to `'0,1,2,3,4,5,6'`.
+ run_date : str, optional
+ The specific date the task should run, used if `run_frequently` is set to `False`. Format: `yyyy/m/d` (no prefix zeros). Defaults to `""`.
+ repeat : str, optional
+ How often the task should repeat. Defaults to `'daily'`.
+
+ Possible values:
+ - `daily` (only when run_frequently=True)
+ - `weekly` (only when run_frequently=True)
+ - `monthly` (works for both run_frequently=True and run_frequently=False)
+ - `no_repeat` (only when run_frequently=False)
+ - `every_3_months` (only when run_frequently=False)
+ - `every_6_months` (only when run_frequently=False)
+ - `yearly` (only when run_frequently=False)
+ monthly_week : list[str], optional
+ If `run_frequently=True` and `repeat='monthly'`, specifies the weeks the task should run, e.g., `['first', 'third']`. Defaults to [].
+ start_time_h : int, optional
+ Hour at which the task should start. Defaults to `0`.
+ start_time_m : int, optional
+ Minute at which the task should start. Defaults to `0`.
+ same_day_repeat_h : int, optional
+ Number of hours between repeated executions on the same day (run every x hours), if "Continue running within the same day" is desired.
+ Set to `0` to disable same-day repeats. Defaults to `0`.
+
+ Possible values: `0..23`
+
+ Info: The args `same_day_repeat_h` and `same_day_repeat_m` cannot be used at the same time, if both are passed, `same_day_repeat_h` will be prioritized.
+ same_day_repeat_m : int, optional
+ Number of minutes between repeated executions on the same day (run every x minutes), if "Continue running within the same day" is desired.
+ Set to `0` to disable same-day repeats. Defaults to `0`.
+
+ Possible values: `1`, `5`, `10`, `15`, `20`, `30`
+
+ Info: The args `same_day_repeat_h` and `same_day_repeat_m` cannot be used at the same time, if both are passed, `same_day_repeat_h` will be prioritized.
+ same_day_repeat_until : int, optional
+ Last hour of the day when the task can repeat. Defaults to `start_time_h`.
+
+ Returns
+ -------
+ dict[str, object]
+ A dictionary with the id of the modified task.
+
+ Notes
+ -----
+ Warning: This method overwrites all the settings of the task, so if you only want to change one setting,
+ you can fetch the current task configuration with `get_task_config()` and pass all the settings to this method.
+
+ Examples
+ --------
+ ```json
+ {
+ "data": {
+ "id": 20
+ },
+ "success": true
+ }
+ ```
"""
schedule = _Schedule(run_frequently, run_days, run_date, repeat, monthly_week, start_time_h, start_time_m,
diff --git a/synology_api/universal_search.py b/synology_api/universal_search.py
index 2605c7cb..b2d1ba4e 100644
--- a/synology_api/universal_search.py
+++ b/synology_api/universal_search.py
@@ -1,11 +1,30 @@
+"""Synology Universal Search API Wrapper."""
from __future__ import annotations
from typing import Optional, Any
from . import base_api
class UniversalSearch(base_api.BaseApi):
+ """
+ API wrapper for Synology Universal Search.
+
+ Provides methods to perform keyword-based searches using Synology's Universal Search API.
+ """
def search(self, keyword: str) -> dict[str, object] | str:
+ """
+ Search for files and metadata matching the given keyword.
+
+ Parameters
+ ----------
+ keyword : str
+ The search keyword.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Search results as a dictionary, or a string with error details.
+ """
api_name = 'SYNO.Finder.FileIndexing.Search'
info = self.gen_list[api_name]
api_path = info['path']
diff --git a/synology_api/usb_copy.py b/synology_api/usb_copy.py
index d318dd42..9390893a 100644
--- a/synology_api/usb_copy.py
+++ b/synology_api/usb_copy.py
@@ -1,42 +1,45 @@
+"""USB Copy API wrapper for Synology NAS."""
from __future__ import annotations
from typing import Optional
from . import base_api
class USBCopy(base_api.BaseApi):
- """USB Copy Implementation.
+ """
+ USB Copy API wrapper for Synology NAS.
- Supported methods:
- - Getters:
- - Get package settings
- - Get package logs
- - Get task settings
+ Methods
+ -------
+ Getters:
+ - Get package settings
+ - Get package logs
+ - Get task settings
- - Actions:
- - Enable / Disable task
+ Actions:
+ - Enable / Disable task
"""
def get_package_settings(self) -> dict[str, object]:
- """Retrieve package settings.
+ """
+ Retrieve package settings.
- Returns
- -------
- dict[str, object]
- Parsed JSON into `dict`
+ Returns
+ -------
+ dict[str, object]
+ Parsed JSON into a dictionary.
- Examples
- --------
- ```python
+ Examples
+ --------
+ ```python
{
- "data" : {
- "beep_on_task_start_end" : True,
- "log_rotate_count" : 100000,
- "repo_volume_path" : "/volume2"
+ "data": {
+ "beep_on_task_start_end": True,
+ "log_rotate_count": 100000,
+ "repo_volume_path": "/volume2"
},
- "success" : True
+ "success": True
}
- ```
-
+ ```
"""
api_name = 'SYNO.USBCopy'
info = self.gen_list[api_name]
@@ -47,42 +50,41 @@ def get_package_settings(self) -> dict[str, object]:
return self.request_data(api_name, api_path, req_param)
def get_package_logs(self, offset: int = 0, limit: int = 200) -> dict[str, object]:
- """Retrieve package logs.
-
- Parameters
- ----------
- offset : int
- Defaults to `0`.
-
- limit : int
- Defaults to `200`.
-
- Returns
- -------
- dict[str, object]
- Parsed response JSON into `dict`
-
- Examples
- --------
- ```python
+ """
+ Retrieve package logs.
+
+ Parameters
+ ----------
+ offset : int, optional
+ Offset for logs. Defaults to 0.
+ limit : int, optional
+ Maximum number of logs to retrieve. Defaults to 200.
+
+ Returns
+ -------
+ dict[str, object]
+ Parsed response JSON into a dictionary.
+
+ Examples
+ --------
+ ```python
{
- "data" : {
- "count" : 1,
- "log_list" : [
+ "data": {
+ "count": 1,
+ "log_list": [
{
- "description_id" : 101,
- "description_parameter" : "[\"asdf\"]",
- "error" : 0,
- "log_type" : 1,
- "task_id" : 2,
- "timestamp" : 1738341351
- },
+ "description_id": 101,
+ "description_parameter": "[\"asdf\"]",
+ "error": 0,
+ "log_type": 1,
+ "task_id": 2,
+ "timestamp": 1738341351
+ }
]
},
- "success" : True
+ "success": True
}
- ```
-
+ ```
"""
api_name = 'SYNO.USBCopy'
info = self.gen_list[api_name]
@@ -93,57 +95,57 @@ def get_package_logs(self, offset: int = 0, limit: int = 200) -> dict[str, objec
return self.request_data(api_name, api_path, req_param)
def get_task_settings(self, task_id: int) -> dict[str, object]:
- """Retrieve task settings
+ """
+ Retrieve task settings.
- Parameters
- ----------
- task_id: int
- Task ID to retrieve info for
+ Parameters
+ ----------
+ task_id : int
+ Task ID to retrieve info for.
- Returns
- -------
- dict[str, object]
- Parsed response JSON into `dict`
+ Returns
+ -------
+ dict[str, object]
+ Parsed response JSON into a dictionary.
- Examples
- --------
- ```python
+ Examples
+ --------
+ ```python
{
- "data" : {
- "task" : {
- "conflict_policy" : "rename",
- "copy_file_path" : "",
- "copy_strategy" : "versioning",
- "default_device_port" : "NA",
- "destination_path" : "[USB]",
- "eject_when_task_done" : True,
- "enable_rotation" : False,
- "error_code" : 0,
- "id" : 2,
- "is_default_task" : False,
- "is_ds_mounted" : False,
- "is_task_runnable" : False,
- "is_usb_mounted" : False,
- "latest_finish_time" : 1738341351,
- "max_version_count" : 256,
- "name" : "asdf",
- "next_run_time" : "N/A",
- "not_keep_dir_structure" : False,
- "remove_src_file" : False,
- "rename_photo_video" : False,
- "rotation_policy" : "oldest_version",
- "run_when_plug_in" : False,
- "schedule_id" : 13,
- "smart_create_date_dir" : False,
- "source_path" : "/music",
- "status" : "unmounted",
- "type" : "export_general"
+ "data": {
+ "task": {
+ "conflict_policy": "rename",
+ "copy_file_path": "",
+ "copy_strategy": "versioning",
+ "default_device_port": "NA",
+ "destination_path": "[USB]",
+ "eject_when_task_done": True,
+ "enable_rotation": False,
+ "error_code": 0,
+ "id": 2,
+ "is_default_task": False,
+ "is_ds_mounted": False,
+ "is_task_runnable": False,
+ "is_usb_mounted": False,
+ "latest_finish_time": 1738341351,
+ "max_version_count": 256,
+ "name": "asdf",
+ "next_run_time": "N/A",
+ "not_keep_dir_structure": False,
+ "remove_src_file": False,
+ "rename_photo_video": False,
+ "rotation_policy": "oldest_version",
+ "run_when_plug_in": False,
+ "schedule_id": 13,
+ "smart_create_date_dir": False,
+ "source_path": "/music",
+ "status": "unmounted",
+ "type": "export_general"
}
},
- "success" : True
+ "success": True
}
- ```
-
+ ```
"""
api_name = 'SYNO.USBCopy'
info = self.gen_list[api_name]
@@ -154,29 +156,28 @@ def get_task_settings(self, task_id: int) -> dict[str, object]:
return self.request_data(api_name, api_path, req_param)
def toggle_task(self, task_id: int, enable: bool = True) -> dict[str, object]:
- """Enable or disable USB Copy task
-
- Parameters
- ----------
- task_id : int
- Task ID to apply the setting to.
-
- enable : bool
- Whether to enable (`True`) or disable (`False`) USB Copy. Defaults to `True`.
-
- Returns
- -------
- dict[str, object]
- Parsed response JSON into `dict`
-
- Examples
- --------
- ```python
+ """
+ Enable or disable a USB Copy task.
+
+ Parameters
+ ----------
+ task_id : int
+ Task ID to apply the setting to.
+ enable : bool, optional
+ Whether to enable (True) or disable (False) the USB Copy task. Defaults to True.
+
+ Returns
+ -------
+ dict[str, object]
+ Parsed response JSON into a dictionary.
+
+ Examples
+ --------
+ ```python
{
"success": True
}
- ```
-
+ ```
"""
api_name = 'SYNO.USBCopy'
info = self.gen_list[api_name]
diff --git a/synology_api/utils.py b/synology_api/utils.py
index cc2e8aa2..ffa27e26 100644
--- a/synology_api/utils.py
+++ b/synology_api/utils.py
@@ -1,10 +1,35 @@
+"""Utility functions for Synology API operations."""
import json
+import mimetypes
+import re
+import secrets
import sys
# my_package/my_module.py
-__all__ = ['merge_dicts', 'make_folder_meta_list_from_path', 'parse_config']
+__all__ = ['merge_dicts', 'make_folder_meta_list_from_path',
+ 'get_data_for_request_from_file', 'generate_gecko_boundary', 'validate_path']
+
+from pathlib import Path
+
+from requests_toolbelt import MultipartEncoder, MultipartEncoderMonitor
+from tqdm import tqdm
def merge_dicts(x, y):
+ """
+ Merge two dictionaries.
+
+ Parameters
+ ----------
+ x : dict
+ The first dictionary.
+ y : dict
+ The second dictionary.
+
+ Returns
+ -------
+ dict
+ A new dictionary containing the merged keys and values from both input dictionaries.
+ """
z = x.copy() # start with keys and values of x
z.update(y) # modifies z with keys and values of y
return z
@@ -14,11 +39,15 @@ def make_folder_meta_list_from_path(path):
"""
Create a list of folder metadata dictionaries from a given path.
- Args:
- path (str): The file path to be split into folder metadata.
+ Parameters
+ ----------
+ path : str
+ The file path to be split into folder metadata.
- Returns:
- list: A list of dictionaries containing folder metadata.
+ Returns
+ -------
+ list of dict
+ A list of dictionaries containing folder metadata for each folder in the path.
"""
folder_list = []
path_list = path.split('/') # Split the path into components
@@ -36,3 +65,159 @@ def make_folder_meta_list_from_path(path):
})
return folder_list
+
+
+def get_data_for_request_from_file(file_path: str,
+ fields: dict[str, str | tuple],
+ progress_bar: bool = True,
+ called_from: str = 'DownloadStation'):
+ """
+ Build and return a ``MultipartEncoder`` or a ``MultipartEncoderMonitor`` to upload a file via ``request_data`` (POST multipart/form-data).
+
+ Parameters
+ ----------
+ file_path : str
+ The file path to be parsed.
+ fields : dict[str, str | tuple]
+ Dictionary of form fields used to build the multipart payload.
+ Each key represents a form field name.
+ The value can be:
+ - a string (for standard text fields)
+ - a tuple ``(filename, fileobj, mimetype)`` for file fields.
+ progress_bar : bool
+ Whether to show a progress bar when uploading file or not.
+ called_from : str
+ The name of the calling class. (ex 'FileStation')
+
+ Returns
+ -------
+ MultipartEncoder | MultipartEncoderMonitor
+ The multipart payload object to pass to your HTTP client. When a monitor is returned,
+ access its underlying encoder via ``monitor.encoder`` and supply
+ ``headers = {"Content-Type": monitor.content_type}`` (or ``encoder.content_type``).
+ """
+
+ p = Path(file_path).expanduser().resolve()
+ if not p.is_file():
+ raise FileNotFoundError(f"File not found: {p}")
+
+ size_value = p.stat().st_size
+ boundary = generate_gecko_boundary()
+ fields["size"] = str(size_value)
+ mime_type, _ = mimetypes.guess_type(p.name)
+ mime_type = mime_type or "application/octet-stream"
+
+ if called_from == 'DownloadStation':
+ fields["torrent"] = (p.name, p.open("rb"), mime_type)
+ elif called_from == 'FileStation':
+ fields["files"] = (p.name, p.open("rb"), mime_type)
+
+ encoder = MultipartEncoder(fields=fields, boundary=boundary)
+ print(encoder)
+ if progress_bar:
+ pbar = tqdm(total=encoder.len, unit="B", unit_scale=True,
+ unit_divisor=1024, desc="Upload Progress")
+ monitor = MultipartEncoderMonitor(
+ encoder, lambda m: pbar.update(m.bytes_read - pbar.n)
+ )
+ return monitor
+ return encoder
+
+
+def generate_gecko_boundary():
+ """
+ Generate a boundary for MultiPartEncoder.
+
+ Returns
+ -------
+ str:
+ The random boundary ----geckoformboundary{random_hex} for the MultiPartEncoder.
+ """
+ random_hex = secrets.token_hex(16) # 16 byte = 32 caratteri esadecimali
+ return f"----geckoformboundary{random_hex}"
+
+
+def validate_path(path: str | list[str]) -> bool:
+ """
+ Validate the format of a Synology FileStation path.
+
+ The function checks whether a given path string (or list of paths) follows
+ the basic formatting rules required by Synology FileStation APIs.
+
+ Parameters
+ ----------
+ path : str or list of str
+ The path or list of paths to validate. Each path can represent
+ either a file or directory.
+
+ Returns
+ -------
+ bool
+ True if the path (or all paths in the list) are valid according to
+ FileStation rules, False otherwise.
+
+ Notes
+ -----
+ - Must start with a forward slash ('/').
+ - Must not contain any of the forbidden characters: * ? " < > |
+ - May contain internal spaces (e.g., '/My Folder/file name.txt').
+ - Must not end with a space, tab, or slash.
+ - If the path contains a file extension, no spaces or characters are allowed
+ after the last period (e.g., '/Media/script.log extra' is invalid).
+ - Optionally allows paths without extensions (e.g., '/Media/script').
+
+ Examples
+ --------
+ >>> validate_path('/Downloads/script.log')
+ True
+ >>> validate_path('/Downloads/script log.txt')
+ True
+ >>> validate_path('/Downloads/script')
+ True
+ >>> validate_path('/Downloads/script.log extra')
+ False
+ >>> validate_path('/Downloads/script.log ')
+ False
+ >>> validate_path('/Downloads/folder/')
+ False
+ >>> validate_path('Downloads/script.log')
+ False
+ """
+
+ def _is_valid(single_path: str) -> bool:
+ """
+ Validate a single Synology FileStation path.
+
+ Parameters
+ ----------
+ single_path : str
+ The path to validate.
+
+ Returns
+ -------
+ bool
+ True if the given path is a valid Synology FileStation path.
+ """
+ path_pattern = re.compile(r'^/[^*?"<>|]+$')
+ if not isinstance(single_path, str):
+ return False
+
+ if not path_pattern.match(single_path):
+ return False
+
+ if path[-1] in (' ', '\t', '/'):
+ return False
+
+ parts = single_path.rsplit('.', 1)
+ if len(parts) == 2 and ' ' in parts[1]:
+ return False
+
+ return True
+
+ if isinstance(path, str):
+ return _is_valid(path)
+
+ if isinstance(path, list):
+ return all(isinstance(p, str) and _is_valid(p) for p in path)
+
+ return False
diff --git a/synology_api/virtualization.py b/synology_api/virtualization.py
index 872a6299..e561a642 100644
--- a/synology_api/virtualization.py
+++ b/synology_api/virtualization.py
@@ -1,9 +1,43 @@
+"""
+Virtualization API wrapper for Synology Virtual Machine Manager.
+
+This module provides the Virtualization class for managing tasks, networks, storage, hosts, VMs, and images
+on Synology NAS devices via the Virtual Machine Manager API.
+"""
+
from __future__ import annotations
from typing import Optional, Any
from . import base_api
class Virtualization(base_api.BaseApi):
+ """
+ API wrapper for Synology Virtual Machine Manager.
+
+ Provides methods to manage tasks, networks, storage, hosts, VMs, and images.
+
+ Parameters
+ ----------
+ ip_address : str
+ IP address of the Synology NAS.
+ port : str
+ Port number to connect to.
+ username : str
+ DSM username.
+ password : str
+ DSM password.
+ secure : bool, optional
+ Use HTTPS if True. Default is False.
+ cert_verify : bool, optional
+ Verify SSL certificate if True. Default is False.
+ dsm_version : int, optional
+ DSM version. Default is 7.
+ debug : bool, optional
+ Enable debug mode. Default is True.
+ otp_code : str, optional
+ One-time password for 2FA, if required.
+ """
+
def __init__(self,
ip_address: str,
port: str,
@@ -15,6 +49,30 @@ def __init__(self,
debug: bool = True,
otp_code: Optional[str] = None
) -> None:
+ """
+ Initialize the Virtualization API wrapper.
+
+ Parameters
+ ----------
+ ip_address : str
+ IP address of the Synology NAS.
+ port : str
+ Port number.
+ username : str
+ DSM username.
+ password : str
+ DSM password.
+ secure : bool, optional
+ Use HTTPS if True. Default is False.
+ cert_verify : bool, optional
+ Verify SSL certificate if True. Default is False.
+ dsm_version : int, optional
+ DSM version. Default is 7.
+ debug : bool, optional
+ Enable debug mode. Default is True.
+ otp_code : str, optional
+ One-time password for 2FA, if required.
+ """
super(Virtualization, self).__init__(ip_address, port, username, password, secure, cert_verify,
dsm_version, debug, otp_code)
@@ -32,6 +90,14 @@ def __init__(self,
self.file_station_list: Any = self.session.app_api_list
def get_task_list(self) -> list[str]:
+ """
+ Get the list of virtualization tasks.
+
+ Returns
+ -------
+ list of str
+ List of task IDs.
+ """
api_name = 'SYNO.Virtualization.API.Task.Info'
info = self.file_station_list[api_name]
api_path = info['path']
@@ -42,6 +108,19 @@ def get_task_list(self) -> list[str]:
return self._taskid_list
def clear_task(self, taskid: str) -> dict[str, object] | str:
+ """
+ Clear a specific task by its ID.
+
+ Parameters
+ ----------
+ taskid : str
+ Task ID to clear.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the clear operation or error message.
+ """
api_name = 'SYNO.Virtualization.API.Task.Info'
info = self.file_station_list[api_name]
api_path = info['path']
@@ -55,6 +134,19 @@ def clear_task(self, taskid: str) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def get_task_info(self, taskid: str) -> dict[str, object] | str:
+ """
+ Get information about a specific task.
+
+ Parameters
+ ----------
+ taskid : str
+ Task ID to retrieve information for.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Task information or error message.
+ """
api_name = 'SYNO.Virtualization.API.Task.Info'
info = self.file_station_list[api_name]
api_path = info['path']
@@ -68,6 +160,14 @@ def get_task_info(self, taskid: str) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def get_network_group_list(self) -> list[dict[str, object]]:
+ """
+ Get the list of network groups.
+
+ Returns
+ -------
+ list of dict
+ List of network group information.
+ """
api_name = 'SYNO.Virtualization.API.Network'
info = self.file_station_list[api_name]
api_path = info['path']
@@ -79,6 +179,14 @@ def get_network_group_list(self) -> list[dict[str, object]]:
return self._network_group_list
def get_storage_operation(self) -> list[str]:
+ """
+ Get the list of storage operations.
+
+ Returns
+ -------
+ list of str
+ List of storage operation information.
+ """
api_name = 'SYNO.Virtualization.API.Storage'
info = self.file_station_list[api_name]
api_path = info['path']
@@ -89,6 +197,14 @@ def get_storage_operation(self) -> list[str]:
return self._storages_list
def get_host_operation(self) -> list[str]:
+ """
+ Get the list of host operations.
+
+ Returns
+ -------
+ list of str
+ List of host operation information.
+ """
api_name = 'SYNO.Virtualization.API.Host'
info = self.file_station_list[api_name]
api_path = info['path']
@@ -100,6 +216,19 @@ def get_host_operation(self) -> list[str]:
return self._host_operation_list
def get_vm_operation(self, additional: bool = False) -> list[dict[str, object]]:
+ """
+ Get the list of virtual machines.
+
+ Parameters
+ ----------
+ additional : bool, optional
+ Whether to include additional information. Default is False.
+
+ Returns
+ -------
+ list of dict
+ List of VM information.
+ """
api_name = 'SYNO.Virtualization.API.Guest'
info = self.file_station_list[api_name]
api_path = info['path']
@@ -116,11 +245,29 @@ def get_vm_operation(self, additional: bool = False) -> list[dict[str, object]]:
return info
- def get_specific_vm_info(self,
- additional: Optional[str | list[str]] = None,
- guest_id: Optional[str] = None,
- guest_name: Optional[str] = None
- ) -> dict[str, object] | str:
+ def get_specific_vm_info(
+ self,
+ additional: Optional[str | list[str]] = None,
+ guest_id: Optional[str] = None,
+ guest_name: Optional[str] = None
+ ) -> dict[str, object] | str:
+ """
+ Get information about a specific virtual machine.
+
+ Parameters
+ ----------
+ additional : str or list of str, optional
+ Additional fields to include.
+ guest_id : str, optional
+ Guest VM ID.
+ guest_name : str, optional
+ Guest VM name.
+
+ Returns
+ -------
+ dict[str, object] or str
+ VM information or error message.
+ """
api_name = 'SYNO.Virtualization.API.Guest'
info = self.file_station_list[api_name]
api_path = info['path']
@@ -137,15 +284,41 @@ def get_specific_vm_info(self,
return self.request_data(api_name, api_path, req_param)
- def set_vm_property(self,
- guest_id: Optional[str] = None,
- guest_name: Optional[str] = None,
- autorun: Optional[int] = None,
- description: Optional[str] = None,
- new_guest_name: Optional[str] = None,
- vcpu_num: Optional[int] = None,
- vram_size: Optional[int] = None
- ) -> dict[str, object] | str:
+ def set_vm_property(
+ self,
+ guest_id: Optional[str] = None,
+ guest_name: Optional[str] = None,
+ autorun: Optional[int] = None,
+ description: Optional[str] = None,
+ new_guest_name: Optional[str] = None,
+ vcpu_num: Optional[int] = None,
+ vram_size: Optional[int] = None
+ ) -> dict[str, object] | str:
+ """
+ Set properties for a virtual machine.
+
+ Parameters
+ ----------
+ guest_id : str, optional
+ Guest VM ID.
+ guest_name : str, optional
+ Guest VM name.
+ autorun : int, optional
+ Autorun setting (0: off, 1: last state, 2: on).
+ description : str, optional
+ VM description.
+ new_guest_name : str, optional
+ New VM name.
+ vcpu_num : int, optional
+ Number of virtual CPUs.
+ vram_size : int, optional
+ RAM size in MB.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the set operation or error message.
+ """
api_name = 'SYNO.Virtualization.API.Guest'
info = self.file_station_list[api_name]
api_path = info['path']
@@ -186,6 +359,21 @@ def set_vm_property(self,
return self.request_data(api_name, api_path, req_param)
def delete_vm(self, guest_id: Optional[str] = None, guest_name: Optional[str] = None) -> dict[str, object] | str:
+ """
+ Delete a virtual machine.
+
+ Parameters
+ ----------
+ guest_id : str, optional
+ Guest VM ID.
+ guest_name : str, optional
+ Guest VM name.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the delete operation or error message.
+ """
api_name = 'SYNO.Virtualization.API.Guest'
info = self.file_station_list[api_name]
api_path = info['path']
@@ -202,12 +390,32 @@ def delete_vm(self, guest_id: Optional[str] = None, guest_name: Optional[str] =
return self.request_data(api_name, api_path, req_param)
- def vm_power_on(self,
- guest_id: Optional[str] = None,
- guest_name: Optional[str] = None,
- host_id: Optional[str] = None,
- host_name: Optional[str] = None
- ) -> dict[str, object] | str:
+ def vm_power_on(
+ self,
+ guest_id: Optional[str] = None,
+ guest_name: Optional[str] = None,
+ host_id: Optional[str] = None,
+ host_name: Optional[str] = None
+ ) -> dict[str, object] | str:
+ """
+ Power on a virtual machine.
+
+ Parameters
+ ----------
+ guest_id : str, optional
+ Guest VM ID.
+ guest_name : str, optional
+ Guest VM name.
+ host_id : str, optional
+ Host ID.
+ host_name : str, optional
+ Host name.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the power on operation or error message.
+ """
api_name = 'SYNO.Virtualization.API.Guest.Action'
info = self.file_station_list[api_name]
api_path = info['path']
@@ -233,10 +441,26 @@ def vm_power_on(self,
return self.request_data(api_name, api_path, req_param)
- def vm_force_power_off(self,
- guest_id: Optional[str] = None,
- guest_name: Optional[str] = None
- ) -> dict[str, object] | str:
+ def vm_force_power_off(
+ self,
+ guest_id: Optional[str] = None,
+ guest_name: Optional[str] = None
+ ) -> dict[str, object] | str:
+ """
+ Force power off a virtual machine.
+
+ Parameters
+ ----------
+ guest_id : str, optional
+ Guest VM ID.
+ guest_name : str, optional
+ Guest VM name.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the power off operation or error message.
+ """
api_name = 'SYNO.Virtualization.API.Guest.Action'
info = self.file_station_list[api_name]
api_path = info['path']
@@ -254,6 +478,21 @@ def vm_force_power_off(self,
return self.request_data(api_name, api_path, req_param)
def vm_shut_down(self, guest_id: Optional[str] = None, guest_name: Optional[str] = None) -> dict[str, object] | str:
+ """
+ Shut down a virtual machine.
+
+ Parameters
+ ----------
+ guest_id : str, optional
+ Guest VM ID.
+ guest_name : str, optional
+ Guest VM name.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the shutdown operation or error message.
+ """
api_name = 'SYNO.Virtualization.API.Guest.Action'
info = self.file_station_list[api_name]
api_path = info['path']
@@ -271,6 +510,14 @@ def vm_shut_down(self, guest_id: Optional[str] = None, guest_name: Optional[str]
return self.request_data(api_name, api_path, req_param)
def get_images_list(self) -> dict[str, object]:
+ """
+ Get the list of VM images.
+
+ Returns
+ -------
+ dict[str, object]
+ Dictionary containing image information.
+ """
api_name = 'SYNO.Virtualization.API.Guest.Image'
info = self.file_station_list[api_name]
api_path = info['path']
@@ -279,6 +526,21 @@ def get_images_list(self) -> dict[str, object]:
return self.request_data(api_name, api_path, req_param)
def delete_image(self, image_id: Optional[str] = None, image_name: Optional[str] = None) -> dict[str, object] | str:
+ """
+ Delete a VM image.
+
+ Parameters
+ ----------
+ image_id : str, optional
+ Image ID.
+ image_name : str, optional
+ Image name.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the delete operation or error message.
+ """
api_name = 'SYNO.Virtualization.API.Guest.Image'
info = self.file_station_list[api_name]
api_path = info['path']
@@ -295,14 +557,38 @@ def delete_image(self, image_id: Optional[str] = None, image_name: Optional[str]
return self.request_data(api_name, api_path, req_param)
- def create_image(self,
- auto_clean_task: bool = True,
- storage_names: Optional[str] = None,
- storage_ids: Optional[str] = None,
- type: Optional[str] = None,
- ds_file_path: Optional[str] = None,
- image_name: Optional[str] = None
- ) -> dict[str, object] | str:
+ def create_image(
+ self,
+ auto_clean_task: bool = True,
+ storage_names: Optional[str] = None,
+ storage_ids: Optional[str] = None,
+ type: Optional[str] = None,
+ ds_file_path: Optional[str] = None,
+ image_name: Optional[str] = None
+ ) -> dict[str, object] | str:
+ """
+ Create a new VM image.
+
+ Parameters
+ ----------
+ auto_clean_task : bool, optional
+ Whether to auto-clean the task after creation. Default is True.
+ storage_names : str, optional
+ Storage names.
+ storage_ids : str, optional
+ Storage IDs.
+ type : str, optional
+ Image type ('disk', 'vdsm', or 'iso').
+ ds_file_path : str, optional
+ File path (should begin with a shared folder).
+ image_name : str, optional
+ Name of the image.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Result of the create operation or error message.
+ """
api_name = 'SYNO.Virtualization.API.Guest.Image'
info = self.file_station_list[api_name]
api_path = info['path']
diff --git a/synology_api/vpn.py b/synology_api/vpn.py
index f33e1d14..93badd51 100644
--- a/synology_api/vpn.py
+++ b/synology_api/vpn.py
@@ -1,3 +1,4 @@
+"""VPN API Wrapper for Synology NAS."""
from __future__ import annotations
from io import BytesIO
from zipfile import ZipFile
@@ -6,8 +7,22 @@
class VPN(base_api.BaseApi):
+ """
+ API wrapper for Synology VPN Server.
+
+ Provides methods to retrieve VPN settings, active connections, logs, network interfaces,
+ security autoblock settings, permissions, and VPN protocol-specific settings.
+ """
def settings_list(self) -> dict[str, object] | str:
+ """
+ Retrieve VPN server settings.
+
+ Returns
+ -------
+ dict[str, object] or str
+ VPN server settings as a dictionary, or an error message as a string.
+ """
api_name = 'SYNO.VPNServer.Settings.Config'
info = self.gen_list[api_name]
api_path = info['path']
@@ -21,6 +36,25 @@ def active_connections_list(self,
start: int = 0,
limit: int = 100
) -> dict[str, object] | str:
+ """
+ Retrieve a list of active VPN connections.
+
+ Parameters
+ ----------
+ sort : str, optional
+ Field to sort by. Default is 'login_time'.
+ sort_dir : str, optional
+ Sort direction ('ASC' or 'DESC'). Default is 'DESC'.
+ start : int, optional
+ Pagination start index. Default is 0.
+ limit : int, optional
+ Maximum number of results to return. Default is 100.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Active connections as a dictionary, or an error message as a string.
+ """
api_name = 'SYNO.VPNServer.Management.Connection'
info = self.gen_list[api_name]
api_path = info['path']
@@ -30,6 +64,23 @@ def active_connections_list(self,
return self.request_data(api_name, api_path, req_param)
def log_list(self, start: int = 0, limit: int = 50, prtltype: int = 0) -> dict[str, object] | str:
+ """
+ Retrieve VPN server logs.
+
+ Parameters
+ ----------
+ start : int, optional
+ Pagination start index. Default is 0.
+ limit : int, optional
+ Maximum number of logs to return. Default is 50.
+ prtltype : int, optional
+ Protocol type filter. Default is 0 (all).
+
+ Returns
+ -------
+ dict[str, object] or str
+ Logs as a dictionary, or an error message as a string.
+ """
api_name = 'SYNO.VPNServer.Management.Log'
info = self.gen_list[api_name]
api_path = info['path']
@@ -39,6 +90,14 @@ def log_list(self, start: int = 0, limit: int = 50, prtltype: int = 0) -> dict[s
return self.request_data(api_name, api_path, req_param)
def network_interface_setting(self) -> dict[str, object] | str:
+ """
+ Retrieve VPN network interface settings.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Network interface settings as a dictionary, or an error message as a string.
+ """
api_name = 'SYNO.VPNServer.Management.Interface'
info = self.gen_list[api_name]
api_path = info['path']
@@ -47,6 +106,14 @@ def network_interface_setting(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def security_autoblock_setting(self) -> dict[str, object] | str:
+ """
+ Retrieve security autoblock settings.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Autoblock settings as a dictionary, or an error message as a string.
+ """
api_name = 'SYNO.Core.Security.AutoBlock'
info = self.gen_list[api_name]
api_path = info['path']
@@ -55,6 +122,21 @@ def security_autoblock_setting(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def permission_setting(self, start: int = 0, limit: int = 100) -> dict[str, object] | str:
+ """
+ Retrieve VPN permission settings.
+
+ Parameters
+ ----------
+ start : int, optional
+ Pagination start index. Default is 0.
+ limit : int, optional
+ Maximum number of results to return. Default is 100.
+
+ Returns
+ -------
+ dict[str, object] or str
+ Permission settings as a dictionary, or an error message as a string.
+ """
api_name = 'SYNO.VPNServer.Management.Account'
info = self.gen_list[api_name]
api_path = info['path']
@@ -64,6 +146,14 @@ def permission_setting(self, start: int = 0, limit: int = 100) -> dict[str, obje
return self.request_data(api_name, api_path, req_param)
def pptp_settings_info(self) -> dict[str, object] | str:
+ """
+ Retrieve PPTP VPN settings.
+
+ Returns
+ -------
+ dict[str, object] or str
+ PPTP settings as a dictionary, or an error message as a string.
+ """
api_name = 'SYNO.VPNServer.Settings.Config'
info = self.gen_list[api_name]
api_path = info['path']
@@ -73,6 +163,14 @@ def pptp_settings_info(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def openvpn_settings_info(self) -> dict[str, object] | str:
+ """
+ Retrieve OpenVPN settings.
+
+ Returns
+ -------
+ dict[str, object] or str
+ OpenVPN settings as a dictionary, or an error message as a string.
+ """
api_name = 'SYNO.VPNServer.Settings.Config'
info = self.gen_list[api_name]
api_path = info['path']
@@ -82,6 +180,14 @@ def openvpn_settings_info(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def l2tp_settings_info(self) -> dict[str, object] | str:
+ """
+ Retrieve L2TP VPN settings.
+
+ Returns
+ -------
+ dict[str, object] or str
+ L2TP settings as a dictionary, or an error message as a string.
+ """
api_name = 'SYNO.VPNServer.Settings.Config'
info = self.gen_list[api_name]
api_path = info['path']
@@ -91,17 +197,18 @@ def l2tp_settings_info(self) -> dict[str, object] | str:
return self.request_data(api_name, api_path, req_param)
def openvpn_export_configuration(self, as_zip_file=False) -> bytes | ZipFile:
- """Downloads the openvpn\.zip containing the VPNConfig\.ovpn file
+ """
+ Download the OpenVPN configuration as a zip file or bytes.
- Parameters
- ----------
- as_zip_file : bool
- If the bytes should be converted to a ZipFile
+ Parameters
+ ----------
+ as_zip_file : bool, optional
+ If True, return a ZipFile object. If False, return bytes. Default is False.
- Returns
- -------
- dict[str, object]
- A dictionary containing the OpenVPN configuration file as bytes or a ZipFile object if `as_zip_file` is True.
+ Returns
+ -------
+ bytes or ZipFile
+ The OpenVPN configuration file as bytes, or a ZipFile object if `as_zip_file` is True.
"""
api_name = 'SYNO.VPNServer.Settings.Certificate'
info = self.gen_list[api_name]
diff --git a/tests/test_syno_api.py b/tests/test_syno_api.py
index eb6321fc..e30b0be6 100644
--- a/tests/test_syno_api.py
+++ b/tests/test_syno_api.py
@@ -3,6 +3,7 @@
from unittest import TestCase
import unittest
from synology_api.filestation import FileStation
+from synology_api.downloadstation import DownloadStation
from synology_api.surveillancestation import SurveillanceStation
import os
import pathlib
@@ -43,6 +44,21 @@ def test_syno_filestation_login(self):
self.assertIsNotNone(shares_list)
self.assertEqual(shares_list.__len__(), 2)
+ def test_syno_downloadstation_login(self):
+ ds = DownloadStation(ip_address=self.config["synology_ip"], port=self.config["synology_port"],
+ username=self.config["synology_user"],
+ password=self.config["synology_password"],
+ secure=bool(self.config["synology_secure"]), cert_verify=False,
+ dsm_version=int(self.config["dsm_version"]), debug=True,
+ otp_code=self.config["otp_code"])
+ self.assertIsNotNone(ds)
+ self.assertIsNotNone(ds.session)
+ self.assertIsNotNone(ds.session.sid)
+ self.assertIsNot(ds.session.sid, '')
+ tasks_list = ds.tasks_list()
+ self.assertIsNotNone(tasks_list)
+ self.assertEqual(tasks_list.__len__(), 2)
+
def test_syno_surveillancestation_login(self):
ss = SurveillanceStation(ip_address=self.config["synology_ip"], port=self.config["synology_port"],
username=self.config["synology_user"],