Search code examples
google-apps-scriptgoogle-sheetsdropbox

Error in getting Dropbox file (mp4) link using exisiting Google Apps Script


This is a continuation of my previous question. I am using the following script to get the publicly accessible file link:

function listDropBoxFiles() {

  const accessToken = "sl.BpQiX-y5a6GhuZ9_QmHnCeT3u6OMoVRiKrPDOe_YzOVtDUCUUlEYrMd92faMVlJQr28d3md5YKvN4au1B6HIdEeRug0LdL66Qo1UGlXmNx3RiMNZDcZqPVZvWLbJEroQxurJye23YxjGFCvMPnJUbFI";
  var subfolderName = "";
 
  const path = "/Master Folder";

  let url = "https://api.dropboxapi.com/2/files/list_folder";
  let has_more = false;
  var count = 0;
  const option = {
    method: "post",
    headers: { authorization: "Bearer " + accessToken },
    contentType: "application/json",
    payload: JSON.stringify({ path, limit: 2000, recursive: true })
  };
  let values = [];
  var fileDetails = [];
  do {
    const res = UrlFetchApp.fetch(url, option);
    let obj = JSON.parse(res.getContentText());

    values = [...values, ...obj.entries];
    has_more = obj.has_more;

    if (has_more) {
      url = "https://api.dropboxapi.com/2/files/list_folder/continue";
      option.payload = JSON.stringify({ cursor: obj.cursor });
    }
  } while (has_more);
  
   for (var i = 0; i < values.length; i++) {
    
      var entry = values[i];
      
    if (entry['.tag'] === 'file') {
      
       var match = entry.path_display.split('/');
       subfolderName = match[match.length - 2];   
      
       var fileUrl = getFileUrl(accessToken,entry.id)

       fileDetails.push([subfolderName,entry.name,fileUrl,Utilities.formatDate(new Date(entry.client_modified), Session.getScriptTimeZone(), 'dd/MM/yyyy hh:mm a'),Utilities.formatDate(new Date(entry.server_modified), Session.getScriptTimeZone(), 'dd/MM/yyyy hh:mm a')])
     
    }
  }
    
      if(fileDetails.length>0){
         detailSheet.getRange(detailSheet.getLastRow()+1,1,fileDetails.length,fileDetails[0].length).setValues(fileDetails);
      }
}



function getFileUrl(accessToken, fileId) {
  const url1 = "https://api.dropboxapi.com/2/sharing/list_shared_links";
  const res1 = UrlFetchApp.fetch(url1, {
    method: "post",
    headers: { authorization: "Bearer " + accessToken },
    contentType: "application/json",
    payload: JSON.stringify({ path: fileId })
  });
  const obj1 = JSON.parse(res1.getContentText());
  if (obj1.links.length > 0) {
    return obj1.links[0].url;
  }
  const url2 = "https://api.dropboxapi.com/2/sharing/create_shared_link_with_settings";
  const res2 = UrlFetchApp.fetch(url2, {
    method: "post",
    headers: { authorization: "Bearer " + accessToken },
    contentType: "application/json",
    payload: JSON.stringify({ path: fileId, settings: { access: "viewer", allow_download: true, audience: "public", requested_visibility: "public" } })
  });
  const obj2 = JSON.parse(res2.getContentText());
  const sharedLink = obj2.url;
  return sharedLink;
}

However, sometimes it works other times it does not, the issue is it gives the folder link of the files instead of actual links to the files. What I mean by that is it gives the folder/subfolder links where these files are saved instead of the files' links. For example, in my Master folder, there are 3 files and the script gives the following output:

1. Live Video.mp4   
https://www.dropbox.com/scl/fo/mhiwyb9u7kjrhtw05rsdr/h?rlkey=6mj30yhcyahu9ypjddx2uz962&dl=0

2. Custom Data Entry Form.jpg   
https://www.dropbox.com/scl/fo/mhiwyb9u7kjrhtw05rsdr/h?rlkey=6mj30yhcyahu9ypjddx2uz962&dl=0

3.Format Number.txt 
https://www.dropbox.com/scl/fo/io1xsqja0y44n7wilphp0/h?rlkey=jhuvdusw204k71nnl9axhbtnr&dl=0

Here you can see that when you click on these links, they open the folders that contain these files instead of opening these files. The data for a file named 1. Live Video.mp4 looks like this:

{ '.tag': 'file',
  name: 'Live Video.mp4',
  path_lower: '/master folder/live video.mp4',
  path_display: '/Master Folder/Live Video.mp4',
  id: 'id:c0kbDV6PiUcAAAAAAAAAGw',
  client_modified: '2023-11-05T07:25:40Z',
  server_modified: '2023-11-05T07:31:28Z',
  rev: '0160962b9c6509b00000002277bc0d0',
  size: 348179266,
  is_downloadable: true,
  content_hash: '41247114de3e285fb84fefd961801a73a7072cba9d043bd123e0e73ea5707271' }

if you plug 'id:c0kbDV6PiUcAAAAAAAAAGw' into getFileUrl() from the above response, it gets the folder link instead of the file link, below is the response (obj1/obj2):

{ links: 
   [ { '.tag': 'folder',
       url: 'https://www.dropbox.com/scl/fo/mhiwyb9u7kjrhtw05rsdr/h?rlkey=6mj30yhcyahu9ypjddx2uz962&dl=0',
       id: 'id:c0kbDV6PiUcAAAAAAAAAGg',
       name: 'Master Folder',
       path_lower: '/master folder',
       link_permissions: [Object] } ],
  has_more: false }

Any guidance would be much appreciated.


Solution

  • Luckily I found the issue in the following function:

    function getFileUrl(accessToken, fileId) {
      const url1 = "https://api.dropboxapi.com/2/sharing/list_shared_links";
      const res1 = UrlFetchApp.fetch(url1, {
        method: "post",
        headers: { authorization: "Bearer " + accessToken },
        contentType: "application/json",
        payload: JSON.stringify({ path: fileId })
      });
      const obj1 = JSON.parse(res1.getContentText());
      if (obj1.links.length > 0) {
        return obj1.links[0].url;
      }
      const url2 = "https://api.dropboxapi.com/2/sharing/create_shared_link_with_settings";
      const res2 = UrlFetchApp.fetch(url2, {
        method: "post",
        headers: { authorization: "Bearer " + accessToken },
        contentType: "application/json",
        payload: JSON.stringify({ path: fileId, settings: { access: "viewer", allow_download: true, audience: "public", requested_visibility: "public" } })
      });
      const obj2 = JSON.parse(res2.getContentText());
      const sharedLink = obj2.url;
      return sharedLink;
    }
    

    In the above function, the if condition checks if there is already any link, but the issue is it also considers subfolders' links, if there are subfolders, it does not look for the file link, it just gets the subfolder link and the condition is considered to be true.

    So from changing this:

     if (obj1.links.length > 0) {
            return obj1.links[0].url;
          }
    

    to this solved the issue:

     if (obj1.links[0]['.tag'] === 'file') {
        return obj1.links[0].url;
      }