I'm horrible at coding so I'm sure this will need some work.
My Problem: My company does work for a lot of other companies (example Drive hierarchy photo attached). Each company we work with gets their own folder that is nested under the folder 'Shirts for other companies". We put all their assets into these folders (logos, mocks, quotes).
We want to build a script that will look into the individual company folders and take any file that starts with the word Mock and automatically copy it and put it into the database folder found in the picture below.
Here is the script have so far. but I'm having trouble getting into the subfolders (ford tshirts and designs). Not only that, but if it runs everyday the script will keep duplicating the files it has duplicated in the past which I want to avoid.
Script:
Function getTheFiles() {
var dApp = DriveApp;
var folderIter = dApp.getFolderByName("Shirts for other companies");
var folder = folderIter.next();
var filesIter = folder.getFiles();
var dataBase = folder.getFoldersByName("database1").next();
var i = 1;
while(filesIter.hasNext()) {
var file = filesIter.next();
var filename = file.getName();
if(filename = "mocking") {
file.makeCopy(dataBase);
}
logger.log(filename);
i++;
}
If I understood you correctly, you want to:
Copy all files from the different subfolders inside a folder called "Shirts for other companies", that start with the word mock, to the Database folder (which is also inside the main folder).
Avoid files getting copied many times.
If that's the case, you could do the following:
Search for all files in each subfolder of the main folder that start with mock, excluding the files inside Database folder. For this, you iterate through all files in each subfolder (after checking the subfolder is not named Database folder. For each file, you check that the name start with mock, using the method substring.
To keep track of which files are copied, and so avoid making duplicates, you can use PropertiesService, which can store key-value pairs. The id of every copied file is copied to the script property, and then, the next time the script runs, it checks whether the id is in the property. If that's the case, the file doesn't get copied again. One thing to notice is that script properties can only store strings, so that arrays have to be converted to a string every time we want to store a new id (via toString, and back to an array, via split.
The function below does all these things (check inline comments for more details):
function copyFiles() {
var mainFolder = DriveApp.getFoldersByName("Shirts for other companies").next();
var folders = mainFolder.getFolders(); // Get folder iterator from main folder
var databaseFolderName = "Database folder"; // You database folder name
var databaseFolder = mainFolder.getFoldersByName(databaseFolderName).next(); // Get databse folder
var idsArray = []; // Array to store the ids of the copied files
while (folders.hasNext()) { // Iterate through each folder in the main folder
var folder = folders.next();
if (folder.getName() !== databaseFolderName) { // Check current folder is not the database folder
var files = folder.getFiles();
while (files.hasNext()) { // Iterate through each file in each subfolder
var file = files.next();
if (file.getName().substring(0, 4).toLowerCase() === "mock") { // Check that file name starts with "mock"
// Get ids of the files that were copied in previous executions:
var key = "copied-ids";
var scriptProperties = PropertiesService.getScriptProperties();
var ids = scriptProperties.getProperty(key);
if (ids) idsArray = ids.split(",");
else ids = "";
// Get current file id:
var id = file.getId();
// Check that current file id is not in properties (not copied before):
if (idsArray.indexOf(id) === -1) {
file.makeCopy(databaseFolder); // Copy file to database folder
idsArray.push(id); // Add file id to the array of copied files
}
ids = idsArray.toString();
scriptProperties.setProperty(key, ids);
}
}
}
}
}
Reference:
PropertiesService
String.prototype.substring()
Array.prototype.toString()
String.prototype.split()
I hope this is of any help.
This function would search your entire Google Drive for files starting the the letter Mock and put Name, url, id, type (folder or file) into the active spreadsheet and tab named MoclList;
function getAllMocks() {
var ss=SpreadsheetApp.getActive();
var sh1=ss.getSheetByName('MocksList');
sh1.clearContents();
sh1.appendRow(['Name','Url','Id','Type']);
getFnF();
SpreadsheetApp.getUi().alert('Process Complete')
}
var level=0;
function getFnF(folder) {
var folder= folder || DriveApp.getRootFolder();
var ss=SpreadsheetApp.getActive();
var sh=ss.getSheetByName('MocksList');
var files=folder.getFiles();
while(files.hasNext()) {
var file=files.next();
if(file.getName().toLowerCase().slice(0,4)=='mock') {
var firg=sh.getRange(sh.getLastRow() + 1,level + 1);
firg.setValue(file.getName());
firg.offset(0,1).setValue(Utilities.formatString('=HYPERLINK("%s","%s")',file.getUrl(),'FILE: ' + file.getName()));
firg.offset(0,2).setValue(file.getId());
firg.offset(0,3).setValue('File');
}
}
var subfolders=folder.getFolders()
while(subfolders.hasNext()) {
var subfolder=subfolders.next();
var forg=sh.getRange(sh.getLastRow() + 1,level + 1);
forg.setValue(subfolder.getName());
forg.offset(0,1).setValue(Utilities.formatString('=HYPERLINK("%s","%s")',subfolder.getUrl(),'FOLDER: ' + subfolder.getName()));
forg.offset(0,2).setValue(subfolder.getId());
forg.offsert(0,3).setValue('Folder');
//level++;
getFnF(subfolder);
}
//level--;
}
Related
Okay so I have a sheet that I use to keep track of tips at work. Since its a shared sheet to keep it simple I just copy the sheet when its done and then archive the copied sheet to a subfolder based on the year.
All the code works perfect except when I try to move the copied sheet to the folder that I want.
Since I want to keep this as automatted as possible I have code to read the date within the sheet and either make a new folder for the year or move the file to the year folder that already exist.
For some reason the file will not move to the folder I want and I've tried multiple ways: within the 'makeCopy' function as well as the DriveApp.getFileById().moveTo();
Here is my code, error runs at bottom of code:
//Create folder if does not exists only
function createFolder(folderID, folderName){
var parentFolder = DriveApp.getFolderById(folderID);
var subFolders = parentFolder.getFolders();
var doesntExists = true;
var newFolder = '';
// Check if folder already exists.
while(subFolders.hasNext()){
var folder = subFolders.next();
//If the name exists return the id of the folder
if(folder.getName() === folderName){
doesntExists = false;
newFolder = folder;
return newFolder.getId();
};
};
//If the name doesn't exists, then create a new folder
if(doesntExists == true){
//If the file doesn't exists
newFolder = parentFolder.createFolder(folderName);
return newFolder.getId();
};
};
function start(){
//Parent folder (Location)
var FOLDER_ID = '1yinFsKfMP3_pWbM7BnOKcNRk-BDcty6E';
//Add the name of the folder here (Year of the sheet):
var year = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Instructions").getRange('L2').getDisplayValue();
var NEW_FOLDER_NAME = year;
//Create a new folder if a folder for the year doesnt exist (reverts to function:createFolder)
var myFolderID = createFolder(FOLDER_ID, NEW_FOLDER_NAME);
//Get the file ID of the parent file (Tip Tracker)
var getID = SpreadsheetApp.getActive().getId();
//Get the current name of the Tip Tracker (with dates)
var getName = SpreadsheetApp.getActive().getName();
//Create copy of Tip Tracker to be filed accordingly
var newFileID = DriveApp.getFileById(getID).makeCopy(getName + " ").getId();
var getNewFile = DriveApp.getFileById(newFileID);
getNewFile.moveTo(myFolderID);
Logger.log(newFileID);
Logger.log(myFolderID);
};
Try creating a getMyFolder as you did with getNewFile and moveTo the folder versus the ID.
const myFolder = DriveApp.getFolderById(myFolderID)
// ...
getNewFile.moveTo(myFolder)
File.moveTo(folder) takes a Folder, not an ID.
I have a javascript I found but it starts with having the user choose a folder where it will grab files. I want to create a watch folder so I want to tell the javascript the folder to grab the files from, not let the user choose. I can't for the life of me figure out how to do this. I know applescript but cannot grasp javascript. Thank you!
Here is what I believe the area I need to change:
function main() {
// user settings
var prefs = new Object();
prefs.sourceFolder = '/Volumes/SERVER_RAID/•Current/MPC'; // default browse location (default: '~')
prefs.removeFileExtensions = true; // remove filename extensions for imported layers (default: true)
prefs.savePrompt = true; // display save prompt after import is complete (default: false)
prefs.closeAfterSave = true; // close import document after saving (default: false)
// prompt for source folder
var sourceFolder = Folder.selectDialog('Where are the Front and Back files?', Folder(prefs.sourceFolder));
// ensure the source folder is valid
if (!sourceFolder) {
return;
}
else if (!sourceFolder.exists) {
alert('Source folder not found.', 'Script Stopped', true);
return;
}
// add source folder to user settings
prefs.sourceFolder = sourceFolder;
// get a list of files
var fileArray = getFiles(prefs.sourceFolder);
// if files were found, proceed with import
if (fileArray.length) {
importFolderAsLayers(fileArray, prefs);
}
// otherwise, diplay message
else {
alert("The selected folder doesn't contain any recognized images.", 'No Files Found', false);
}
}
///////////////////////////////////////////////////////////////////////////////
// getFiles - get all files within the specified source
///////////////////////////////////////////////////////////////////////////////
function getFiles(sourceFolder) {
// declare local variables
var fileArray = new Array();
var extRE = /\.(?:png)$/i;
// get all files in source folder
var docs = sourceFolder.getFiles();
var len = docs.length;
for (var i = 0; i < len; i++) {
var doc = docs[i];
// only match files (not folders)
if (doc instanceof File) {
// store all recognized files into an array
var docName = doc.name;
if (docName.match(extRE)) {
fileArray.push(doc);
}
}
}
// return file array
return fileArray;
}
///////////////////////////////////////////////////////////////////////////////
To achieve this you'll need to specify the path to your desired folder as String.
If you take a look at the updated code sample below you'll notice that line 4 of your original code which read:
prefs.sourceFolder = '/Volumes/SERVER_RAID/•Current/MPC';
has been changed to:
prefs.sourceFolder = Folder('~/Desktop/targetFolder');
This now assumes the target folder is named targetFolder and it resides in your Desktop folder. You'll need to change the '~/Desktop/targetFolder' part as necessary to point to the folder you actually want. It also assumes you're running this on macOS as the shortcut to the Desktop folder (i.e. the ~/ part) will not be recognized on Windows.
What are the other ways I can specify the path?
You can specify path name using absolute paths such as:
prefs.sourceFolder = Folder('/Users/JohnDoe/Desktop/targetFolder');
Note: This example actually points to the same folder as the first example. Assuming that the user is called John Doe of course!
More info about setting file paths can be found here.
What other changes were made to your code example:
Lines 9 to 22 in your example code which read:
// prompt for source folder
var sourceFolder = Folder.selectDialog('Where are the Front and Back files?', Folder(prefs.sourceFolder));
// ensure the source folder is valid
if (!sourceFolder) {
return;
}
else if (!sourceFolder.exists) {
alert('Source folder not found.', 'Script Stopped', true);
return;
}
// add source folder to user settings
prefs.sourceFolder = sourceFolder;
are now redundant. Instead, they have been replaced with the following snippet which will alert you if the folder you specified cannot be found:
// ensure the source folder exists.
if (!prefs.sourceFolder.exists) {
alert('Source folder not found.\n' + prefs.sourceFolder, 'Script Stopped', true);
return;
}
I added main() on line 30 below to invoke the main function. However, if you have that elsewhere in your code you can delete it.
Updated code sample:
function main() {
// User settings
var prefs = new Object();
prefs.sourceFolder = Folder('~/Desktop/targetFolder');
prefs.removeFileExtensions = true;
prefs.savePrompt = true;
prefs.closeAfterSave = true;
// ensure the source folder exists.
if (!prefs.sourceFolder.exists) {
alert('Source folder not found.\n' + prefs.sourceFolder, 'Script Stopped', true);
return;
}
// Get a list of files
var fileArray = getFiles(prefs.sourceFolder);
// If files were found, proceed with your tasks.
if (fileArray.length) {
alert('I found image(s) in the specified folder\n' +
'Now you need to write code to perform out a task :)');
// <-- Continiue your code here
}
// otherwise, diplay message
else {
alert('The selected folder doesn\'t contain any recognized images.', 'No Files Found', false);
}
}
main(); // <-- Invokes the `main` function
/**
* getFiles - get all files within the specified source
* #param {String} sourceFolder - the path to the source folder.
*/
function getFiles(sourceFolder) {
// declare local variables
var fileArray = new Array();
var extRE = /\.(?:png)$/i;
// get all files in source folder
var docs = sourceFolder.getFiles();
var len = docs.length;
for (var i = 0; i < len; i++) {
var doc = docs[i];
// only match files (not folders)
if (doc instanceof File) {
// store all recognized files into an array
var docName = doc.name;
if (docName.match(extRE)) {
fileArray.push(doc);
}
}
}
// return file array
return fileArray;
}
I need to get the names and URLs of the folders in a specified folder.
This is my attempt:
// set the folder to pull folder names from
var DDparentid = "IDhere";
var DDparent = DriveApp.getFolderById(DDparentid);
var DDfolders = DDparent.getFolders();
// iterate through folders in the folder
while (DDfolders.hasNext()) {
var folder = DDfolders.next();
// get folder name
Logger.log(folder.getName());
var DDnames = folder.getName();
// get the url
Logger.log(folder.getUrl());
var DDURLs = folder.getUrl();
}
This works for get file URLs, but I believe that folders are treated differently, and getfolder is used differently. I get an error stating that a string is not suitable in DriveApp.getfolder(). How should I be using getfolder?
EDITED: this runs, buit doesn't actually pull URLs or folder names. Both variables are undefined, but there are no errors.
You can try this :
var parentFolderId = "xxxxxxxIDxxxxxxx";
var parentFolder = DriveApp.getFolderById(parentFolderId);
var folders = parentFolder.getFolders();
var folder;
// iterate through folders in the folders fetched from parent folder
while (folders.hasNext()) {
folder = folders.next();
// get folder name
Logger.log(folder.getName());
// get the url
Logger.log(folder.getUrl());
}
This is an un-tested code, let me know if any issue arises I'll be happy to help us.
Thanks
Below lists all subfolder name and URL for specified folder:
function listSubFoldersInFolder(id) {
var dfolder = DriveApp.getFolderById('ENTER_PARENT_FOLDER_ID_HERE');
var contents = dfolder.getFolders();
var file;
var name;
var sheet = SpreadsheetApp.getActiveSheet();
var link;
sheet.clear();
sheet.appendRow(["Name", "Link"]);
while(contents.hasNext()) {
file = contents.next();
name = file.getName();
link = file.getUrl();
data = [name, link]
sheet.appendRow(data);
}
};
I'm having trouble creating an app script that can read a file name and from that file name move the file from myDrive to a designated folder. Ultimately I want to create an app that reads a naming convention of PR_P50_MP26_OtherContent.pdf and puts that file into the MP26 folder which is in the PR folder which is in the P50 Folder. When I run the script it sends my file to the wrong folder.
Goal: to move "PR_P50_MP286_LineLowering_2006_463.pdf" file into the PR Folder which is under the P50 Folder.
What happens when I run the code is it goes to the test folder in the else statement.
function MoveFiles(){
var files = DriveApp.getRootFolder().getFiles();
while (files.hasNext()) {
var file = files.next();
var packagedFile = file.getName();
if (packagedFile.indexOf("PR_P50"))
{
var destination = DriveApp.getFolderById("PR folder of P50 Folder");
destination.addFile(file);
var pull = DriveApp.getRootFolder();
pull.removeFile(file);
}
else{
var destination = DriveApp.getFolderById("My test Folder");
destination.addFile(file);
var pull = DriveApp.getRootFolder();
pull.removeFile(file);
}
}
}
There are quite a few issues with the code but the one error you mentioned can be fixed by replacing
var packagedFile = file.getname()
with
var packagedFile = file.getName()
You are using the getFolderbyId Which is looking for the folders given ID. Try getting the ID of the folder which should be part of the url. You should also declare your folder variable outside of the while loop.
https://drive.google.com/drive/folders/FOLDERIDHERE
This will atleast be able to get the file in the correct folder. If you wish to do it by folder name you will have to call on getFolderByName("PR folder of p50 folder") which will return a fileIterator so you will have to loop through it, but if you know there is only 1 folder with that name you will be able to set folder as var folder = folders.next(). Either way you choose to do it, you should now be able to get the file into your desired folder.
function MoveFiles(){
var files = DriveApp.getRootFolder().getFiles();
var 1stdestination = DriveApp.getFolderById("FOLDERIDHERE");
var 2nddestination = DriveApp.getFolderById("FOLDERIDHERE");
while (files.hasNext()) {
var file = files.next();
var packagedFile = file.getName();
if (packagedFile.indexOf("PR_P50"))
{
destination.addFile(file);
var pull = DriveApp.getRootFolder();
pull.removeFile(file);
}
else{
destination.addFile(file);
var pull = DriveApp.getRootFolder();
pull.removeFile(file);
}
}
}
I did something similar here
var JobFolder = DriveApp.getFolderById('MYFOLDERIDHERE');
//Other stuff here
if(!results.isBeforeFirst() ){
throw new Error('Job does not exist');
} else {
if(jobId in JobFolder.getFilesByName(jobId) )
{
var ss = SpreadsheetApp.open(jobId);
var url = ss.getUrl();
return {url:url, jobId:jobId};
} else
{
var ss = SpreadsheetApp.create(jobId);
ss.insertSheet('Job Materials');
ss.insertSheet('Job Operations');
ss.insertSheet('Job Notes');
ss.insertSheet('Employees Clocked On');
var temp = DriveApp.getFileById(ss.getId());
JobFolder.addFile(temp);
var url = ss.getUrl();
return {url:url, jobId:jobId};
}
}
I have the following JS function which serves as a first prototype for a mozilla thunderbird extension.
The goal is to connect to a server and download a sample file, then unzipping it and storing the contents in the thunderbird profile folder.
Now this all works fine, except that the execution of the function stops after creating the zip file on the file system. So i have to restart the function again, in order to get the second part of the function executed which extracts the user.js file from the zip file.
Any ideas what the problem could be?
function downloadFile(httpLoc) {
// get profile directory
var file = Components.classes["#mozilla.org/file/directory_service;1"].
getService(Components.interfaces.nsIProperties).
get("ProfD", Components.interfaces.nsIFile);
var profilePath = file.path;
// change profile directory to native style
profilePath = profilePath.replace(/\\/gi , "\\\\");
profilePath = profilePath.toLowerCase();
// download the zip file
try {
//new obj_URI object
var obj_URI = Components.classes["#mozilla.org/network/io-service;1"].getService(Components.interfaces.nsIIOService).newURI(httpLoc, null, null);
//new file object
var obj_TargetFile = Components.classes["#mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile);
//set to download the zip file into the profil direct
obj_TargetFile.initWithPath(profilePath + "\/" + "test.zip");
//if file the zip file doesn't exist, create it
if(!obj_TargetFile.exists()) {
alert("zip file wird erstellt");
obj_TargetFile.create(0x00,0644);
}
//new persitence object
var obj_Persist = Components.classes["#mozilla.org/embedding/browser/nsWebBrowserPersist;1"].createInstance(Components.interfaces.nsIWebBrowserPersist);
// with persist flags if desired ??
const nsIWBP = Components.interfaces.nsIWebBrowserPersist;
const flags = nsIWBP.PERSIST_FLAGS_REPLACE_EXISTING_FILES;
obj_Persist.persistFlags = flags | nsIWBP.PERSIST_FLAGS_FROM_CACHE;
//save file to target
obj_Persist.saveURI(obj_URI,null,null,null,null,obj_TargetFile);
} catch (e) {
alert(e);
} finally {
// unzip the user.js file to the profile direc
// creat a zipReader, open the zip file
var zipReader = Components.classes["#mozilla.org/libjar/zip-reader;1"]
.createInstance(Components.interfaces.nsIZipReader);
zipReader.open(obj_TargetFile);
//new file object, thats where the user.js will be extracted
var obj_UnzipTarget = Components.classes["#mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile);
//set path for the user.js
obj_UnzipTarget.initWithPath(profilePath + "\/" + "user.js");
// if user.js doesn't exist, create it
if(!obj_UnzipTarget.exists()) {
alert("user.js wird erstellt");
obj_UnzipTarget.create(0x00,0644);
}
// extract the user.js out of the zip file, to the specified path
zipReader.extract("user.js", obj_UnzipTarget);
zipReader.close();
}
}
var hello = {
click: function() {
downloadFile("http://pse2.iam.unibe.ch/profiles/profile.zip");
},
};
saveURI is asynchronous, so you need to set the progress listener on the persist object to know when it has finished. Here's an example of setting a progress listener and later on there's a check to see whether the transfer has finished.