Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DownloadStation.create_task cannot handle destinations with whitespace #136

Open
pntzio opened this issue Oct 23, 2023 · 5 comments
Open
Labels
enhancement New feature or request

Comments

@pntzio
Copy link

pntzio commented Oct 23, 2023

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
Copy link
Owner

N4S4 commented Jan 10, 2024

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.

@N4S4 N4S4 added the enhancement New feature or request label Mar 14, 2024
@joeperpetua
Copy link
Contributor

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

@pntzio
Copy link
Author

pntzio commented Sep 28, 2024

That depends on what you mean with "encountering the issue".

This:

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 = '')

kind of defeats the purpose of the function a little bit, since you're hacking around the implementation of the function by abusing additional_param, not to mention not even passing any URI to the only required parameter.

Can I make it work like this? Yes
Would it be better if I could just invoke the function as intended? Also yes

In my opinion the whole DownloadStation API is a bit broken in this library. I'll see if I can get around to fixing it tomorrow.

@joeperpetua
Copy link
Contributor

I am not my laptop at the moment, but if I remember correctly, the API will expect 'url' instead of 'uri', that's why I used it.

I agree, I don't know if the whole API, but at least this part seems to be a little outdated and could benefit from a refactoring instead of passing everything as additional params.

If you need some help let me know, I can take a look at it too.

@N4S4
Copy link
Owner

N4S4 commented Sep 28, 2024

I do agree with both, maybe the code is a bit outdated and bit broken, the very little documentation from Synology does not help, once I get home I will check what can be improved

EddieKuo723 added a commit to EddieKuo723/synology-api that referenced this issue Jan 4, 2025
Fix N4S4#136 and update function name
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
Status: To do
Development

Successfully merging a pull request may close this issue.

3 participants