Showing thumbnails in a Google sheet [duplicate] - google-apps-script

This question already has answers here:
How to get the file URL from file name in Google Sheets with correct Authorization via custom function/script
(3 answers)
Closed 4 years ago.
The code below generates the IMAGE function for the sheet to show thumbnails of all (PDF) files in a chosen folder, obtained with a URL and the file ID:
function scannedMail() {
var files, file, sheet;
sheet = SpreadsheetApp.getActive().getSheetByName('ScannedMail');
files = DriveApp.getFoldersByName("ScannedMail").next().searchFiles('');
var i = 1;
while (files.hasNext()) {
var file = files.next();
var ID = file.getId();
sheet.getRange('A' + i).setValue("=IMAGE(\"https://drive.google.com/thumbnail?authuser=0&sz=w320&id=" + ID + "\"\)");
sheet.getRange('B' + i).setValue(file.getName());
i=i+1;
}
}
Yet it does not show the thumbnails. I found out that it shows just the ones where I manually retrieved the ID from getting a "shareable link". Apparently this ensures the right share settings to get the thumbnails of my own files.
1) Is the previous assumption correct, and why do I need to adapt share settings somehow, where I have read other files without any issues?
2) How can I adapt the script to adapt the share settings, or make it work otherwise?
The script is meant to operate just within my own Google account, and to keep the files private.
I tried sharing the folder with myself, but that does not make a difference (or sense). Is the script somehow regarded as being another user than myself?
Following suggestions from #Rubén and #Cooper, I have tried using insertImage either based on a URL:
sheet.insertImage(file.thumbnailLink, 1, i)
or based on a blob:
sheet.insertImage(file.getThumbnail(), 1, i)
But the most I could get out of Google was "We're sorry, a server error occurred. Please wait a bit and try again", with the code below:
function ScannedMail() {
var files, file, , name, blob, sheet;
sheet = SpreadsheetApp.getActive().getSheetByName('ScannedMail');
files = DriveApp.getFoldersByName("ScannedMail").next().searchFiles('');
var i = 1;
while (files.hasNext()) {
file = files.next();
name = file.getName(); //not needed, just for debugging
blob = file.getThumbnail();
sheet.insertImage(blob, 1, i); // it runs up to here...
i = i + 1;
}
}
The code execution gets stuck on the first occurrence of insertImage().
So we have 3 approaches (IMAGE function in sheet, insertImage(URL,1,1), and insertImage(blob,1,1)) but all 3 do not make a thumbnail appear, apart from the first method when you make the file public (not a serious option).
I don't see a duplicate question and answer that helps me find out what is wrong with my code, or helps me to somehow get the required thumbnails in the spreadsheet. The kindly proposed solutions did not succeed in that yet.

Try something like this:
function imgArray() {
var ss=SpreadsheetApp.getActive();
var sh=ss.getSheetByName('ImageArray');
if(!sh){
sh=ss.insertSheet('ImageArray');
}
var imgA=[];
var folder=DriveApp.getFolderById('folderid');
var files=folder.getFiles();
while(files.hasNext()){
var file=files.next();
var filename=file.getName();
imgA.push(file.getBlob());
}
for(var r=0;r<imgA.length;r++){
sh.insertImage(imgA[r],1,r+1);
}
}
This was adapted from an answer from #Tanaike.
I guess this is what you were looking for:
function ScannedMail() {
var sheet = SpreadsheetApp.getActive().getSheetByName('ScannedMail');
var files = DriveApp.getFoldersByName("ScannedMail").next().searchFiles('');
var i = 1;
while (files.hasNext()) {
var file = files.next();
var blob = file.getBlob();
sheet.insertImage(blob, 1, i); // it runs up to here...
i = i + 1;
}
}

Google Sheets IMAGE built-in function only is able to retrieve images that are publicly available, so, yes you should have to adapt the sharing settings to make the images viewable by anyone.
In order to keep the files private you should not use IMAGE built-in function, you could use one of the methods of Class Sheet to insert images like insertImage(blobSource,column,row). See answer to Adding Image to Sheet from Drive for an example.
NOTES:
As custom functions run anonymously they can't be used them either.
According to Mogsdad answer to InsertImage(url,x,y) doesn't work with Google Drive insertImage(url,row,column) can't be used to insert images from Google Drive
Related
Image function or .insertImage not working for Google Apps Script and Sheets
What is the right way to put a Drive image into a Sheets cell programmatically?

Related

How to make Google Slide update value WITHOUT having to manually open it? [duplicate]

This question already has answers here:
pdf is created from google slide, but with the markers populated (via GAS)
(1 answer)
Created PDF does not reflect changes made to the original document
(2 answers)
Converting a google doc to a pdf results in blank pdf, google scripts
(1 answer)
Closed 3 months ago.
I have a Google Sheet with a Google Apps Script that basically intends to do the following when triggered:
Open a specific Google Slides file (it's a template)
Duplicate it into a specific subfolder
Change some placeholder values of this copy
Send this new Google Slide via Email as a PDF.
Everything works great EXCEPT for step 3, which for some reason ONLY updates when I manually open this new file. So the PDF that I receive via email actually still contains the placeholder values, as does the "preview" I see on my Drive before opening the Slides presentation. However, if I open it, it automatically shows the new updated values. I can't figure out why this might be happening.
Things I tried:
Add Utilities.sleep() to allow for the values to update, but it doesn't seem to work. Only opening it does it.
Add a line to .openById() again in case this "forces it to open", but doesn't work.
Adding a loop to refresh each slide.
This is a minimal reproducible code that I have, but would require a Google Slide with two placeholders as "[var_0]" and "[var_1]":
const idTemplate = "1BugZRdW8aOzgPOZun-j_U60lC-yXQFXug3R2-MR7AFs";
function generatePresentationData() {
var s = SpreadsheetApp.getActive();
//Data is in A2:B2 of "Records" sheet.
var ss = s.getSheetByName("Records");
var data = ss.getRange("A2:B2").getValues();
//Get the Google Slides template
var file = DriveApp.getFileById(idTemplate);
//Create a copy of the template into a specific folder, and get the ID of this copy
var newParte = file.makeCopy("New Parte", DriveApp.getFolderById("1rCEYVilGiOlxh03aFANzD4qgKXKBmODh"));
var newParteId = newParte.getId();
//Get the slides of this file.
var slides = getSlides_(newParteId);
//Replace the placeholders with the value in A2:B2. This is the part that doesn't actually "shows up" on this new file until I manually open it from my Drive. It does work correctly, so I don't think the issue lies here
writeDataToPlayersSlide_(slides, data);
//I have tried adding a wait period but didn't work
Utilities.sleep(60000);
//I also tried defining the file again before proceeding to send it via email, but again didn't work
var newParte = DriveApp.getFileById(newParteId);
//I also tried refreshing each slide
refreshSlides(SlidesApp.openById(newParteId));
//Get this new file as a Blob
var theBlob = newParte.getBlob().getAs('application/pdf');
var nameFile = 'Test.pdf';
var email = "mail#gmail.com";
var subject = 'Test Subject';
var body = 'Hi!, <br/>Here is your file.';
GmailApp.sendEmail(email, subject, body, {
htmlBody: body,
attachments: [{
fileName: nameFile,
content: theBlob.getBytes(),
mimeType: "application/pdf"
}]
});
}
function getSlides_(newParteId){
let presentation = SlidesApp.openById(newParteId);
let slides = presentation.getSlides();
return slides;
}
function writeDataToPlayersSlide_(slides, data){
let parte = slides[0];
for (let index=0;index<data[0].length;index++){
parte.replaceAllText(`[var_${index}]`,data[0][index]);
}
}
function refreshSlides(presentation){
// loop through all slides and refresh them
numSlides = presentation.getSlides().length;
for (i = 0; i < numSlides; i++) {
presentation.getSlides()[i].refreshSlide();
}
}
Instead of
//I have tried adding a wait period but didn't work
Utilities.sleep(60000);
//I also tried defining the file again before proceeding to send it via email, but again didn't work
var newParte = DriveApp.getFileById(newParteId);
//I also tried refreshing each slide
refreshSlides(SlidesApp.openById(newParteId));
use
newParte.saveAndClose();
newParte = DriveApp.getFileById(newParteId);
Apparently the problem is that you have missed that Google Apps Script applies changes to Docs Editors files after the script ends.
If order to force Google Apps Script applies the changes at some point, i.e before sendding an email, when making changes to
spreadsheets use SpreadsheetApp.flush()
documents use DocumentsApp.Document.saveAndClose()
presentations use SlidesApp.Presentation.saveAndClose()

Using searchFiles or getFilesByName isn't yielding any results

I'm trying to write a script that will sort large numbers of photos and videos on Google Drive into folders that make it easier for my wife to find what she's looking for. Unfortunately, she has to use Drive rather than Google Photos, so she doesn't have access to the much more robust sorting functionality that Photos would give her.
Warning: I'm not a programmer, so I really don't know what I'm doing. I think I'm telling the script what folder to look in and then telling it to search for files that meet certain criteria in terms of name of the file, but the script is returning null from its search results.
I have tried using both searchFiles (with "name contains [my string var]" as the param), and getFilesByName (with my string var as the param). In both cases, I'm getting named folders but no files.
var currDate = strMonth + strDay;
var photos = currFolder.getFilesByName(
"" + "2019" + currDate + "");
var activeFolder = currFolder.createFolder(currDate);
if (photos.hasNext()) {
myLog = Logger.log("HasNext");
} else {
myLog = Logger.log("Doesn't HasNext");
}
while ( photos.hasNext() ) {
var currPhoto = photos.next();
currPhoto.makeCopy(activeFolder);
myLog = Logger.log(currPhoto);
}
What I expect is that photos is a list of pictures the script has found, that can then be copied over to the folder I created. My debug logging always tells me hasNext() is FALSE, though, and this seems to agree with the fact that no files are getting copied into the folder.
Any help would be greatly appreciated. I'm sure I'm just doing something dumb. Thanks!
Here's an example that will display all of your JPEG files
function findJPEGFiles() {
var files=DriveApp.getFilesByType(MimeType.JPEG);
var html='<style>td,th{border:1px solid black;}</style><table><tr><th>Name</th><th>Id</th><th>Url</th></tr>';
while(files.hasNext()) {
var file=files.next();
html+=Utilities.formatString('<tr><td>%s</td><td>%s</td><td>%s</td></tr>',file.getName(),file.getId(),file.getUrl());
}
html+='</table>';
var userInterface=HtmlService.createHtmlOutput(html);
SpreadsheetApp.getUi().showModelessDialog(userInterface, 'Files');
}

Share Google Doc using a Google Script to set an array of emails (in Google Sheets) as editors

I basically am imagining commands that would change the sharing status of sheets it was allowed to edit. For example, I have a master document for a company (a "Roster" for keeping track of where employees are working and which other employees they are working with in that area) and other "Area Sheets" the employees use to keep track of progress. People move around quarterly, so I want to be able to update my Roster and then let the programming update the sharing status of their sheets instead of clicking on every sheet and copy-pasting emails.
As far as I know there is no current possible way to use google products to achieve this. Are there any other ways, barring a New Feature developed by Google?
I don't think I fully understand your requirements, so I'll start be rephrasing what I do understand.
For every employee, generate a list of who they're working with that quarter.
For a certain set of files owned by the employee, make those files editable to the employee's current co-workers.
For point 1, you already have the list built out in Google Sheets, so you can read the contents into arrays for processing. You can use Google Apps Script Spreadsheet Service for this. Example:
var roster = SpreadsheetApp.getActive(); //assuming the script is running within the Roster spreadsheet
var employeesSheet = roster.getSheetByName("Employees"); //assuming sheet name is "Employees"
var employeeEmails = employeesSheet.getRange("B2:B").getValues(); //assuming the emails are in column B with the first row as header
//In this next line I'm going to make a very big simplification.
//I will assume that the coworkers emails are listed as "coworker1#company.com;coworker2#company.com" in the cell.
//This is likely not the case, but you may already have this formatted in a way that works.
//If not, you can merge these values in Google Apps Script, but I'll consider that outside the scope of this question.
var coworkerEmails = employeesSheet.getRange("C2:C").getValues();
For point 2, I assume you already have a way of determining which files need to have their access permissions modified and that you have permission to make those modifications. You'll need to use the Drive Service for this part. In my example, I will assume that all relevant files are saved in a folder specific to each employee and that the folder ID is saved in column D.
var folderIds = employeesSheet.getRange("D2:D").getValues();
for (var i=0; i<employeeEmails.length; i++) {
var folder = DriveApp.getFolderById(folderIds[i][0]);
//At this point, you could give direct access to the entire folder,
//or just to the files within the folder, as I will do.
var files = folder.getFiles();
while (files.hasNext()) {
var file = files.next();
file.addEditors(coworkerEmails[i][0].split(";"));
}
}
Please note that in the above:
This is untested code and meant only to demonstrate how to achieve what I think you're looking for.
No access permissions are being revoked. This would be quite trivial to add, though.
The folder.getFiles() command only gets files that are children of the folder. So, if the folder has child folders, you'll need to traverse through those as well.
You may want to create a custom menu in your Roster spreadsheet to run this script
In the end, including the custom menu, your code could like:
function onOpen() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var menuEntries = [];
menuEntries.push({name: "Reset Permissions", functionName: "resetPermissions"});
ss.addMenu("Roster Actions", menuEntries);
}
function resetPermissions() {
var roster = SpreadsheetApp.getActive();
var employeesSheet = roster.getSheetByName("Employees");
var employeeEmails = employeesSheet.getRange("B2:B").getValues();
var coworkerEmails = employeesSheet.getRange("C2:C").getValues();
var folderIds = employeesSheet.getRange("D2:D").getValues();
for (var i=0; i<employeeEmails.length; i++) {
var folder = DriveApp.getFolderById(folderIds[i][0]);
var files = folder.getFiles();
while (files.hasNext()) {
var file = files.next();
file.addEditors(coworkerEmails[i][0].split(";"));
}
}
}
For reference, this is how I assumed the example "Employees" sheet in the "Roster" spreadsheet to look:

Insert Image into Spreadsheet Cell from Drive using Google Apps Script

I would like to be able to add an image file into my spreadsheet from Google Drive. I see there is a built-in image function available =image, but this requires a URL and that image files should be shared publicly on the internet. However, I am working with digital assets and can not share them publicly.
I have the following code, this works but does not add to the required cell. Is this at all possible?
function insertImageFromDrive(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var fileId = '0B5UAkV0avfiKNGYtd1VzUzlsTVk';
var img = DriveApp.getFileById(fileId).getBlob();
sheet.insertImage(img, 4, 3)
}
Try using the guide Insert image in a spreadsheet from App Script:
function insertImageOnSpreadsheet() {
var SPREADSHEET_URL = 'INSERT_SPREADSHEET_URL_HERE';
// Name of the specific sheet in the spreadsheet.
var SHEET_NAME = 'INSERT_SHEET_NAME_HERE';
var ss = SpreadsheetApp.openByUrl(SPREADSHEET_URL);
var sheet = ss.getSheetByName(SHEET_NAME);
var response = UrlFetchApp.fetch(
'https://developers.google.com/adwords/scripts/images/reports.png');
var binaryData = response.getContent();
// Insert the image in cell A1.
var blob = Utilities.newBlob(binaryData, 'image/png', 'MyImageName');
sheet.insertImage(blob, 1, 1);
}
Just replace the necessary values. The part where you indicate which cell you insert the image is in:
sheet.insertImage(blob, 1, 1);
There is a google spreadsheet add-on ImageKit to help insert multiple images from difference sources including Google Drive, check it out > https://chrome.google.com/webstore/detail/imagekit/cnhkaohfhpcdeomadgjonnahkkfoojoc
Here you find a screenshot of tool's interface.
It is not possible if the drive image file is not public on your google drive, Having said that there is a trick to overcome i.
First make sure the image file is temporary public on your drive. you can do that also via app script by changing the file permissions to DriveApp.Access.ANYONE, DriveApp.Permission.EDIT. Then the drive file is like a file as if it was from the internet. You can then add the blob.
After that you can decide two things.
Change the permissions back or remove the image file from your drive (if you only want to use it embedded in your blob (also via app script code if you want)
good luck
I don't think it is currently possible, see here: https://code.google.com/p/google-apps-script-issues/issues/detail?id=3303
Here's another alternative:
var fileId = "..."; // your image's google drive id
sheet.insertImage("https://docs.google.com/uc?id=" + fileId, column, row);
Just make sure your file has link sharing turned on (anyone with the link can view) otherwise this method won't work.
Documentation

Google Script gives "Illegal Spreadsheet Key" when trying to open an external spreadsheet

I've scoured the interweb and found many many "solutions" to this problem, none of which seem to work for me.
My problem is a simple one. I want to import information from a changeable source file .... I think I have this licked once I get over the actual problem of opening the external spreadsheet in the first place.
I'm using Google Apps Script and am trying to open a file within the same Google Drive, from a separate GoogleDoc-spreadsheet.
The following code as far as I can see (once you take out the comments) should open a spreadsheet file but gives an illegal key error.
function openafile() {
var files = DriveApp.getFiles();
while (files.hasNext()) {
var file = files.next();
// =//= look for a specific type of spreadsheet file (excel) - this will always be exported as this Mime Type
if ( file.getMimeType() == 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' ) {
Logger.log('Attempting to open ' + file.getName());
// =//= none of these seem to work .... why?
// var ss = SpreadsheetApp.openById(file.getId());
// var ss = SpreadsheetApp.open(file);
// var ss = SpreadsheetApp.openByUrl(file.getUrl());
Logger.log('Success: ' + ss.getName());
}
}
}
Gerardo has kindly answered the actual question posed, which led on to another question ... "OK, but I have no control over the original format of the file. How do I import from Excel/CSV?"
https://stackoverflow.com/a/26858202/4941031
Gives the answer to this follow-up question.