Automate moving of files with certain names to specific folders on Google Drive

Viewed 117

Before I go down the rabbit whole. Can I automate the moving of specific files to specific folders on google drive using Google Scripts?

This is the setup. I have class meets session named as "CAD 142...", "CAD 242..." and "CAD 203..." so the recorded sessions are named as such. The session also are incrementally named as "CAD 142 #01", "CAD 142 #02".... Every couple hours I would like to run an Automated google aps script to move "CAD 142..." recordings to a folder "Classes\CAD 142\Fall 2021\Recordings" and "CAD 242..." recordings to "Classes\CAD 242\Fall 2021\Recordings"...

Just asking if this is possible with google app scripts. This is something I know I could write up with a visual basic script in windows but need to be able to have this done on my google files without my computer being on all the time.

Is this already out there? This would be such a time saver and error reducer and allow me to work on things like teaching and not waiting for file to process or forgetting about them while waiting.

I am still very new to google apps script.

2 Answers

Yes. This can be done. You can set procedures to be run on Google App Scripts to be executed on a trigger as frequently as every five minutes. These will run irrespective of whether you are logged in or not.

You would need to setup a procedure that is authorized to view/modify your google drive. You can see all methods/objects in Google App Scripts well documented library here.

Here's a procedure I first started with that captures a lot of Google Drive Files' properties and dumps them into a Spreadsheet.

function grabFiles() {
  
  var someFiles = DriveApp.searchFiles('modifiedDate > "2020-05-28"');
  
 // var someFiles = DriveApp.searchFiles(
 //   'before:2020-01-01 after:2019-01-01 type:pdf');)

  var ss = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
  var existingValues = ss.getRange(1, 1, ss.getLastRow(),1).getValues();
  
  existingValues.forEach(function(rows){
    rows.forEach(function(aCell){
      currentList.push(aCell)
    })
  })
  while(someFiles.hasNext()){
    var aFile = someFiles.next();
    
    if(!currentList.includes(aFile.getName())){
        aRow = [aFile.getId(),
                '=HYPERLINK("' + aFile.getUrl() + '","' + aFile.getName() + '")',
                //aFile.getUrl(),
                aFile.getDateCreated(),
                aFile.getSize()/1000,
                aFile.getLastUpdated(),
                aFile.getDescription(),
                '=HYPERLINK("' + getFolderURL(aFile.getParents()) + '","' + getFolderNames(aFile.getParents()) + '")',
                aFile.getOwner().getEmail(),
                listEmails(aFile.getEditors()),
                listEmails(aFile.getViewers()),
                aFile.getMimeType().replace('application/',''),
                aFile.getSharingAccess(),
                aFile.getSharingPermission()
                ];
    ss.appendRow(aRow)
    }
  }
}

Yes it's possible.

For this specific case I'm doing it with the following assumptions:

  • CAD XXX is the class/group
  • The path of the target folder is is Classes/<class name>/<quarter of the year> <year>/Recordings
  • The seasons are just names for the quarters of the year
const SEASONS = [
  'Winter',
  'Spring',
  'Summer',
  'Autumn',
]

function moveRecordings() {
  // Get the recordings folder
  const recFolder = DriveApp.getRootFolder().getFoldersByName('Meet Recordings').next()

  // Get the files to move
  const files = recFolder.getFiles()
  // Alternatively you can add further requirements by using `searchFiles` instead:
  // const files = recFolder.searchFiles(`createdDate > '2021-07-01' and name constains 'CAD'`)

  while (files.hasNext()) {
    const file = files.next()
    const name = file.getName()
    const created = file.getDateCreated()

    // Extract the class name from the recording name using a regular expression
    const re = /^CAD \d{3}/.exec(name)
    if (!re) continue
    const className = re[0]

    // Get the season from the creation date
    const season = SEASONS[Math.floor(created.getMonth() / 3)]

    // Move the file by using a helper function
    const destination = folderFromPath(`Classes/${className}/${season} ${created.getFullYear()}/Recordings`)
    file.moveTo(destination)
  }
}


/**
 * Gets a folder by the given path. If it doesn't exist, it creates the necessary folders.
 * 
 * It doesn't support relative paths.
 * 
 * @param {String} path Path representing where the folder is.
 * @param {DriveApp.Folder} parent Root folder to look from.
 * @returns {DriveApp.Folder}
 */
function folderFromPath(path, parent = null) {
  let folder = parent || DriveApp.getRootFolder()
  for (let part of path.split('/')) {
    folder = getOrCreateFolder(part, folder)
  }
  return folder
}


/**
 * Gets a folder by name or creates one if it doesn't exist.
 * 
 * If multiple exist, the first one given by Apps Scripts will be returned.
 * 
 * @param {String} name Name of the folder.
 * @param {DriveApp.Folder} parent Parent folder to get the folder from.
 * @returns {DriveApp.Folder}
 */
function getOrCreateFolder(name, parent = null) {
  if (!parent)
    parent = DriveApp.getRootFolder()

  const it = parent.getFoldersByName(name)
  return it.hasNext() ? it.next() : parent.createFolder(name)
}

This code simply iterates all the files and move them into the proper folder. You only need to extract some information and then move them into the correct folder. The 2 utility functions are quite self explanatory and they are slight modifications of code I already had.

There is a part with an alternative code. It can be used to avoid moving old recordings, or recordings that are not from a class (doesn't start with CAD). Feel free to modify as you see fit.

Even if there is some assumption that's not correct, you should be able to modify this code to make it your own.

The only other thing you need to do is to make a trigger to call the function moveRecordings every few hours.

References

Related