N4S4 / synology-api

A Python wrapper around Synology API
MIT License
360 stars 137 forks source link

DownloadStation.create_task cannot handle destinations with whitespace #136

Open pntzio opened 10 months ago

pntzio commented 10 months ago

Describe the bug When invoking DownloadStation.create_task(...), providing for example {"destination": "shared_folder/test/Big Buck Bunny"} as additional_params results in error code 403 (destination does not exist), even though the path does exist.

It works with paths without spaces.

To Reproduce

  1. Create a shared folder if there isn't one already.
  2. Create a folder with whitespaces in its name inside the shared folder.
  3. Create a download task with the folder created in step 2 as the destination.

Expected behavior I expect the call to finish successfully.

Additional context I have tried using urllib.parse.quote(...) and urllib.parse.quote_plus(...) for the destination string without success. I'm not sure if this is an issue in this library, or in the Synology API.

N4S4 commented 7 months ago

Hi I has a look and tried to fix the issue without success. My guess is some issue with the API which i cannot understand for now. Still tying to solve. If I find anything I will let you know.

joeperpetua commented 13 hours ago

Are you still encountering the issue?

I have taken a look and I cannot reproduce it on DSM 7.2 and Download Station 4.0.0-4708+, this is the test code:

def test_download_station(self):
    result = ''
    dw = 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"],
                                download_st_version=2)

    self.assertIsNotNone(dw)
    self.assertIsNotNone(dw.session)

    params = {
        'type': 'url',
        'destination': 'datastore/WebDAV test',
        'create_list': 'true',
        'url': '["https://yts.mx/torrent/download/855D7BFBA4E7E4E230C0750E12B13D9DCFFA57BA"]'
    }

    result = dw.create_task(additional_param = params, uri = '')
    print(f'Create task ==> {json_pp(result)}')

    list_id = result['data']['list_id'][0]
    result = dw.get_task_list(list_id = list_id)
    print(f'Get task ==> {json_pp(result)}')

    selected = f"[{', '.join(map(str, range(len(result['data']['files']))))}]"
    result = dw.download_task_list(
        list_id = list_id,
        selected=selected,
        destination= params['destination']
    )
    print(f'Start download task ==> {json_pp(result)}')

I added get_task_list and download_task_list for testing purposes:

def create_task(self, uri, additional_param: Optional[dict[str, object]] = None) -> dict[str, object] | str:
    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': 'create', 'uri': uri}

    if type(additional_param) is dict:
        for key in additional_param.keys():
            req_param[key] = additional_param[key]

    return self.request_data(api_name, api_path, req_param)

def get_task_list(self, list_id: str) -> dict[str, object] | str:
    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 download_task_list(self,
                        list_id: str, 
                        selected: str, 
                        destination: str,
                        create_subfolder: bool = True) -> dict[str, object] | str:
    api_name = 'SYNO.DownloadStation' + self.download_st_version + '.Task.List.Polling'
    info = self.download_list[api_name]
    api_path = info['path']
    req_param = {
        'version': info['maxVersion'],
        'method': 'download',
        'list_id': list_id,
        'destination': destination,
        'create_subfolder': create_subfolder,
        'selected': selected
    }

    return self.request_data(api_name, api_path, req_param)

This is the output I get, no issues whatsoever:

User logged in, new session started!
Create task ==> {
    "data": {
        "list_id": [
            "btdl0obCEj"
        ],
        "task_id": []
    },
    "success": true
}
Get task ==> {
    "data": {
        "files": [
            {
                "index": 0,
                "name": "Fly.Me.To.The.Moon.2024.720p.WEBRip.x264.AAC-[YTS.MX].mp4",
                "size": 1275515143
            },
            {
                "index": 1,
                "name": "Fly.Me.To.The.Moon.2024.720p.WEBRip.x264.AAC-[YTS.MX].srt",
                "size": 159572
            },
            {
                "index": 2,
                "name": "YTSYifyUP... (TOR).txt",
                "size": 583
            },
            {
                "index": 3,
                "name": "www.YTS.MX.jpg",
                "size": 53226
            },
            {
                "index": 4,
                "name": "Subs/English.srt",
                "size": 159572
            },
            {
                "index": 5,
                "name": "Subs/SDH.eng.HI.srt",
                "size": 170303
            },
            {
                "index": 6,
                "name": "Subs/spa.srt",
                "size": 141021
            }
        ],
        "size": 1276199420,
        "title": "Fly Me To The Moon (2024) [720p] [WEBRip] [YTS.MX]",
        "type": "bt"
    },
    "success": true
}
Start download task ==> {
    "data": {
        "task_id": "joel/SYNODLTaskListDownload1723931309AB9263AE"
    },
    "success": true
}
.
----------------------------------------------------------------------
Ran 1 test in 13.207s

OK

image