3

I am trying to make friends with the pCloud API, using curl in Bash,

Once I create a pCloud app and get its $clientid and $clientsecret, I can obtain a temporary access token accepting the request at:

echo "https://my.pcloud.com/oauth2/authorize?client_id=$clientid&response_type=code"

And given the $temptok token, I obtain the permanent bearer token with:

permtok=$(curl "https://api.pcloud.com/oauth2_token?client_id=$clientid&client_secret=$clientsecret&code=$temptok" | jq -r '.access_token')

At this point, I can use their API methods, published here.
For example, the userinfo or the listfolder method, which give:

curl "https://api.pcloud.com/userinfo?access_token=$permtok"
curl "https://api.pcloud.com/listfolder?access_token=$permtok&path=/"   

However, I am unable to download files. Based on my understanding, I need to use a combination of file_open and file_read, and the latter needs the file size. When I open a file, I get an output similar to what follows:

curl "https://api.pcloud.com/file_open?access_token=$permtok&path=/foo.txt&flags=0x0040"                      
{
    "result": 0,
    "fd": 1,
    "fileid": 1234567890
}

When using the file descriptor for file_size method:

curl "https://api.pcloud.com/file_size?access_token=$permtok&fd=1"

I get the error:

{
    "result": 1007,
    "error": "Invalid or closed file descriptor."
}

What is the correct way to download files?

antonio
  • 10,629
  • 13
  • 68
  • 136
  • I update my answer, first time can't find download method by curl but second time found it. I hope to make you happy. – Bench Vue Sep 18 '22 at 05:39

2 Answers2

2

The solution proposed by @Bench Vue creates a public link for the file to download. So it is not suitable for private files. Also, once you have a public download link, leveraging the API, with the related authentication steps, might be overkilling.

Here is the solution for private files, which should not be publicly shared.

Obtain your permanent bearer oauth2 as described here, which is permanent.

# Input pars
permtok="....."
source="/foo bar.pdf"
dest="foo bar.pdf"
endpoint="https://api.pcloud.com"
 
# Encode source path
encsource=$(printf %s "$source" |jq -sRr @uri)
 
# Get file size 
size=$(curl -H "Connection: keep-alive" \
       "$endpoint/file_open?access_token=$permtok&path=$encsource&flags=64" \
       "$endpoint/file_size?access_token=$permtok&fd=1" \
       | jq -s '.[1] | .size')
 
# Download
curl -H "Connection: keep-alive" \
       "$endpoint/file_open?access_token=$permtok&path=$encsource&flags=64" \
       "$endpoint/file_read?access_token=$permtok&fd=1&count=$size" > "$dest"
       

Use listfolder method to find the correct source path, which might be relative to your application folder.

curl "$endpoint/listfolder?access_token=$permtok&path=/"   

$endpoint can change depending on your region.

The API server is HTTP 1.1, therefore "Connection: keep-alive" is necessary.

antonio
  • 10,629
  • 13
  • 68
  • 136
1

Overview Order to download a file enter image description here

I can download a file by Browser with getfolderpublink link.

The curl can download file. But it is not documented in pCloud web site. I found it by browser debugging window (F12).

I realize the download API is also not real download. It just get the file meta data for file.

https://api.pcloud.com/getfilelink?fileid={my-file-id}&auth={my-auth}'

Download file by Curl

curl -o {download-file-name} -L -X GET 'https://p-def7.pcloud.com/{full path of my file}' \
-H "Content-Type: application/json; charset=utf-8" \
-H "Authorization: Bearer $token"

Demo

1 Get Auth ID

https://my.pcloud.com/oauth2/authorize?client_id={my_client_id}&response_type=code

enter image description here

2 Get Access Token & Auth code

https://u.pcloud.com/oauth2/authorize?client_id=9xxxxxx7&response_type=code&auth={auth_id}

enter image description here Auth code is important and Access Token

auth=wt9xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxgX

enter image description here

Get access token with code.

curl -L -X POST 'https://api.pcloud.com/oauth2_token' \
-H 'Content-Type: application/json; charset=utf-8' \
--form 'client_id="9xxxxxxx7"' \
--form 'client_secret="4xxxxxxxxxxxxxxxxX"' \
--form 'code="lKxxxxxxxxxxxxxxxxxxX"'

response

{
    "result": 0,
    "userid": 18905223,
    "locationid": 1,
    "token_type": "bearer",
    "access_token": "lKxxxxxxxxxxxxxx-My-Token-xxxxxxxxxxxxxxxxxG7"
}

3 Assign environment variable with token name at terminal

$ token="lKxxxxxxxxxxxxxx-My-Token-xxxxxxxxxxxxxxxxxG7"

4 Get file information by get list-folder API

I will down load one of file Getting started with pCloud.pdf I need to get fileid from JSON response. The "fileid" is 43338896472

curl -L -X GET 'https://api.pcloud.com/listfolder?path=/' \
-H "Content-Type: application/json; charset=utf-8" \
-H "Authorization: Bearer $token" | jq
{
  "result": 0,
  "metadata": {
    "path": "/",
    "name": "/",
    "created": "Sat, 17 Sep 2022 23:58:07 +0000",
    "ismine": true,
    "thumb": false,
    "modified": "Sat, 17 Sep 2022 23:58:07 +0000",
    "id": "d0",
    "isshared": false,
    "icon": "folder",
    "isfolder": true,
    "folderid": 0,
    "contents": [
.... other three default directories
      {
        "name": "Getting started with pCloud.pdf",
        "created": "Sat, 17 Sep 2022 23:58:07 +0000",
        "videocodec": "",
        "thumb": false,
        "modified": "Sat, 17 Sep 2022 23:58:07 +0000",
        "size": 16371465,
        "audiobitrate": 0,
        "fps": "0.00",
        "comments": 0,
        "isfolder": false,
        "height": 0,
        "rotate": 0,
        "fileid": 43338896472,
        "videobitrate": 0,
        "width": 0,
        "hash": 3096725505949383000,
        "duration": "0.00",
        "path": "/Getting started with pCloud.pdf",
        "category": 4,
        "audiosamplerate": 0,
        "id": "f43338896472",
        "isshared": false,
        "ismine": true,
        "audiocodec": "mp3",
        "parentfolderid": 0,
        "contenttype": "application/pdf",
        "icon": "document"
      }
    ]

5 Get file information by stat API (include file size)

curl -L -X GET 'https://api.pcloud.com/stat?fileid=43338896472' \
-H "Content-Type: application/json; charset=utf-8" \
-H "Authorization: Bearer $token" | jq
{
  "result": 0,
  "metadata": {
    "name": "Getting started with pCloud.pdf",
    "created": "Sat, 17 Sep 2022 23:58:07 +0000",
    "videocodec": "",
    "thumb": false,
    "modified": "Sat, 17 Sep 2022 23:58:07 +0000",
    "size": 16371465,
    "audiobitrate": 0,
    "fps": "0.00",
    "comments": 0,
    "isfolder": false,
    "height": 0,
    "rotate": 0,
    "fileid": 43338896472,
    "videobitrate": 0,
    "width": 0,
    "hash": 3096725505949383000,
    "duration": "0.00",
    "category": 4,
    "audiosamplerate": 0,
    "id": "f43338896472",
    "isshared": false,
    "ismine": true,
    "audiocodec": "mp3",
    "parentfolderid": 0,
    "contenttype": "application/pdf",
    "icon": "document"
  }
}

6 Get getfilepublink API

  • get link information in JSON response
"link": "https://u.pcloud.link/publink/show?code=XZ9xxxxxxxxxxsss6Sk"
curl -L -X GET 'https://api.pcloud.com/getfilepublink?fileid=43338896472' \
-H "Content-Type: application/json; charset=utf-8" \
-H "Authorization: Bearer $token" | jq
{
  "code": "XZ9bBhVZ0lSVBSVb4jJKDXJAJBBJ0FIOs6Sk",
  "created": "Sun, 18 Sep 2022 01:15:38 +0000",
  "downloadenabled": true,
  "type": 1,
  "modified": "Sun, 18 Sep 2022 01:15:38 +0000",
  "downloads": 1,
  "link": "https://u.pcloud.link/publink/show?code=XZ9xxxxxxxxxxsss6Sk", <- I modified the code
  "result": 0,
  "linkid": 60017201,
  "haspassword": false,
  "traffic": 16371465,
  "views": 20,
  "metadata": {
    "name": "Getting started with pCloud.pdf",
    "created": "Sat, 17 Sep 2022 23:58:07 +0000",
    "videocodec": "",
    "thumb": false,
    "modified": "Sat, 17 Sep 2022 23:58:07 +0000",
    "size": 16371465,
    "audiobitrate": 0,
    "fps": "0.00",
    "comments": 0,
    "isfolder": false,
    "height": 0,
    "rotate": 0,
    "fileid": 43338896472,
    "videobitrate": 0,
    "width": 0,
    "hash": 3096725505949383000,
    "duration": "0.00",
    "category": 4,
    "audiosamplerate": 0,
    "id": "f43338896472",
    "isshared": false,
    "ismine": true,
    "audiocodec": "mp3",
    "parentfolderid": 0,
    "contenttype": "application/pdf",
    "icon": "document"
  }
}

7 Get download metadata API - same result of Step 6's part

8 Get file path and host URL

Host name array will be different depends on file's attribute(offical default file or personal file)

curl -L -X GET 'https://api.pcloud.com/getfilelink?fileid=43338896472&auth=wt9xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxgX' \
-H "Content-Type: application/json; charset=utf-8" \
-H "Authorization: Bearer $token"
{
    "result": 0,
    "dwltag": "GYYEgtilNwytpYulbsh1UB",
    "hash": 3096725505949383041,
    "size": 16371465,
    "expires": "Sun, 18 Sep 2022 10:53:50 +0000",
    "path": "\/cfZRj4OT2Zwk45bAZlKxxxxxxxxxxxxxxxxxxZbRZlJZ0JZKXZmpZSHZY7ZsFZzpZS5ZLa6pViVfwjfcge2gksnF08W9Qwi7\/Getting%20started%20with%20pCloud.pdf",
    "hosts": [
        "p-def7.pcloud.com",
        "c432.pcloud.com"
    ]
}

9 Finally I can download with Step 8 host name and path

full URL = Host[0] name + path (remove first two characters \ /)

curl -o guide.pdf -L -X GET 'https://p-def7.pcloud.com/cfZRj4OT2Zwk45bAZlKxxxxxxxxxxxxxxxxxxZbRZlJZ0JZKXZmpZSHZY7ZsFZzpZS5ZLa6pViVfwjfcge2gksnF08W9Qwi7\/Getting%20started%20with%20pCloud.pdf' \
-H "Content-Type: application/json; charset=utf-8" \
-H "Authorization: Bearer $token"

enter image description here

I can download by browser two. enter image description here

Bench Vue
  • 5,257
  • 2
  • 10
  • 14
  • You suggest that to download a private file one has to share it publicly! I doubt the API was designed in this way. If anything, once my file is on the public cloud, what is the need to authenticate with their API? – antonio Sep 18 '22 at 15:15
  • Also, your auth procedure is different from what is reported in the [docs](https://docs.pcloud.com/methods/oauth_2.0/authorize.html). You use a different endpoint https://u.pcloud.com//*, rather https://api.pcloud.com//*, and they say you should use a redirect or a call to oauth2_token to get the bearer token. – antonio Sep 18 '22 at 15:16
  • I add overview order to download a file. u.pcloud.com just get the auth code endpoint. I am using docs.pcloud.com, u.pcloud.com, api.pcloud.com and c329.pcloud.com but all of `pcloud.com` sub domain. – Bench Vue Sep 18 '22 at 21:01
  • the public linked dowonloadable file( https://u.pcloud.link/publink/show?code=xxx ) is not necessary to get OAuth token. My steps is to download file using pCloud API with access token by programming. – Bench Vue Sep 18 '22 at 22:38
  • The pattern `https://api.pcloud.com/getfilelink?fileid={my-file-id}&auth={my-auth}'` worked for me. It returns a metadata payload with a path to the file: `/anAmazinglyLongStringOfChartacters/fileName.txt` and a `hosts` array with servers from which you're supposed to download the file. I admittedly missed the `hosts` the first time I tried -- but this answer shows their use perfectly in Step 8: `"hosts": ["p-def7.pcloud.com","c432.pcloud.com"]` (to be clear, my hosts were, of course, different). Note that this auth doesn't use OAuth; this requires username & password for the initial auth code – ruffin Sep 20 '22 at 15:06
  • @ruffin, Thanks for your verify my steps. My summery "Overview Order" is required minimum 6 steps. The other full 9 steps is more detail with extra information steps.. Step 8's host array will be different depends on file's attribute(office default file or personal file). OAuth is depends on you logged in step 2 and 3. I logged in by my google account instead pCLoud id/password. In this case, we call single sign on, pColud do not handle id/password by itself. So auth code require SSO login or pColud ID/password. – Bench Vue Sep 20 '22 at 15:24