murspieg
murspieg

Reputation: 154

Delete multiple google drive files that are unorganized / orphaned

I wanted to remove several thousand files in a Google Drive folder. I deleted the folder, which many in the community know (but I didn't) leaves the files present but orphaned. I can list the files via "is:unorganized owner:me" but can't select more than a few hundred at a time to (slowly) delete.

Is there a script that will search for and delete these, and only these, files? Thanks

Upvotes: 3

Views: 1620

Answers (1)

Tanaike
Tanaike

Reputation: 201378

I believe your goal as follows.

  • You want to retrieve the files searched with is:unorganized owner:me and want to delete the files.
  • You want to reduce the process cost of this process.

Issue and workaround:

In the current stage, unfortunately, the files cannot be directly retrieved by searching is:unorganized owner:me with Drive API and Drive service. So as the current workaround, I would like to suggest the following flow.

  1. Retrieve the file list of all files in the Google Drive. In this case, 'me' in owners and trashed = false is used as the search query. The method of "Files: list" of Drive API is used for this.
  2. Retrieve the file list of files which have no parent folder using a script.
    • By above flow 1 and 2, the search of is:unorganized owner:me can be achieved using a script.
  3. Move the files to the trash box using the retrieved file list using the method of "Files: update" of Drive API.
    • In this case, the files are not directly deleted. Because when the files are directly deleted, I thought that this situation is very dangerous. Of course, the files can be also directly deleted using the method of "Files: delete" of Drive API. Ref
    • From your question, I thought that there might be a lot of files you want to delete. So in this answer, I would like to suggest to use the batch requests.

When above flow is reflected to the script, it becomes as follows.

IMPORTANT: PLEASE BE CAREFUL!

  • When you use this sample script, please be careful this. I would like to recommend the following flow for using this script.

    1. Retrieve the file list of is:unorganized owner:me and check whether all files of the file list are the files you want to delete.
      • You can retrieve the file list using const fileList = getFileList(token); in main() function.
    2. When you could completely confirm that all files of the file list are the files you want to delete, please use const res = moveFilesToTrashBox(token, fileList);. By this, the files of file list are moved to the trash box.
    3. Please confirm the trash box. When the files you don't want to delete are included, please restore them.

Sample script:

Before you use this script, please enable Drive API at Advanced Google services. And please run main() function.

// Move the files in the file list to the trash box.
function moveFilesToTrashBox(token, fileList) {
  const limit = 100;
  const split = Math.ceil(fileList.length / limit);
  const res = [];
  for (let i = 0; i < split; i++) {
    const boundary = "xxxxxxxxxx";
    const payload = fileList.splice(0, limit).reduce((s, {id}, i, a) => s += "Content-Type: application/http\r\n" +
    "Content-ID: " + i + "\r\n\r\n" +
    "PATCH https://www.googleapis.com/drive/v3/files/" + id + "\r\n" +
    "Content-Type: application/json\r\n\r\n" +
    JSON.stringify({trashed: true}) + "\r\n" +
    "--" + boundary + (i == a.length - 1 ? "--" : "") + "\r\n" , "--" + boundary + "\r\n");
    const params = {
      method: "post",
      contentType: "multipart/mixed; boundary=" + boundary,
      payload: payload,
      headers: {Authorization: "Bearer " + token},
      muteHttpExceptions: true,
    };
    const r = UrlFetchApp.fetch("https://www.googleapis.com/batch/drive/v3", params);
    res.push(r.getContentText());
  }
  return res;
}

// Retrieve the file list by searching with "is:unorganized owner:me".
function getFileList(token) {
  const fields = decodeURIComponent("nextPageToken,files(name,id,mimeType,parents)");
  const q = decodeURIComponent("'me' in owners and trashed = false");
  let allFiles = [];
  let pageToken = "";
  do {
    const res = UrlFetchApp.fetch(
      `https://www.googleapis.com/drive/v3/files?pageSize=1000&fields=${fields}&q=${q}&pageToken=${pageToken}`,
      { headers: { authorization: `Bearer ${token}` } }
    );
    const obj = JSON.parse(res);
    allFiles = allFiles.concat(obj.files);
    pageToken = obj.nextPageToken;
  } while (pageToken);
  return allFiles.filter(({ parents }) => !parents);  
}

// Please run this function.
function main() {
  const token = ScriptApp.getOAuthToken();
  
  // Retrieve the file list of all files in the Google Drive.
  const fileList = getFileList(token);
  console.log(fileList.length);
  console.log(fileList);
  
  // Move the files to the trash box using the retrieved file list.
  // When you could completely confirm that all files of the file list are the files you want to delete, please use the below script.
  // const res = moveFilesToTrashBox(token, fileList);
  // console.log(res);


  // DriveApp.createFile(); // This is used for automatically adding a scope of "https://www.googleapis.com/auth/drive".
}

References:

Upvotes: 2

Related Questions