Google script: Download web image and save it in a specific drive folder - google-apps

I need to download an image with GS and save it in a specific drive folder.
I'm able to save the image in the root folder but i cannot save it in a specific folder:
function downloadFile(fileURL,folder) {
var fileName = "";
var fileSize = 0;
var response = UrlFetchApp.fetch(fileURL, {muteHttpExceptions: true});
var rc = response.getResponseCode();
if (rc == 200) {
var fileBlob = response.getBlob()
var folder = DriveApp.getFoldersByName(folder);
if (folder != null) {
var file = DriveApp.createFile(fileBlob);
fileName = file.getName();
fileSize = file.getSize();
}
}
var fileInfo = { "rc":rc, "fileName":fileName, "fileSize":fileSize };
return fileInfo;
}
Question: what have I to add to use the variable "folder"?
I found a lot of examples with "DocList" Class that is not in use anymore
Many thanks

Well, I guess GAS has make a lot of progress on developing its API, the function
createFile(blob) of an object Folder will do the job:
https://developers.google.com/apps-script/reference/drive/folder#createfileblob
// Create an image file in Google Drive using the Maps service.
var blob = Maps.newStaticMap().setCenter('76 9th Avenue, New York NY').getBlob();
DriveApp.getRootFolder().createFile(blob);
It's quite late for the answer but just incase some one runs into the situation.

Are you familiar with this app? It does exactly what you're asking for.
However, if you want to re-create this for your own purposes, I would change your declaration of variable file to read as such:
var file = folder.next().createFile(fileBlob);
when you create your variable folder, the method you use creates a FolderIterator, not a single folder. You have to call the next() method to get a Folder object.
To be precise with your script and avoid saving to an incorrect-but-similarly-named folder, I would recommend passing the folder ID to your script rather than the folder Name. If you pass the folder ID, you could declare folder as:
var folder = DriveApp.getFolderById(folder);
and then continue the script as you have it written. I hope that helps.

Working on similar problem, I came up with the solution below to save a file to a folder. If the folder doesn't exist it creates it, otherwise it saves the file specified by "FOLDER_NAME"
var folderExists = checkFolderExists("FOLDER_NAME");
if (folderExists) {
saveFolder = DriveApp.getFolderById(folderExists);
} else {
saveFolder = DriveApp.createFolder("FOLDER_NAME");
}
// Make a copy of the file in the root drive.
var file = DriveApp.getFileById(sheetID);
// Take the copy of the file created above and move it into the folder:
var newFile = DriveApp.getFolderById(saveFolder.getId()).addFile(file);
// Remove the copy of the file in the root drive.
var docfile = file.getParents().next().removeFile(file);
Further to Eric's answer, I have also provided a utility function that checks if the folder exists. It's reusable in any project.
function checkFolderExists(fName) {
try {
var folderId;
var folders = DriveApp.getFolders();
while (folders.hasNext()) {
var folder = folders.next();
folderName = folder.getName();
if (folderName == fName) {
folderId = folder.getId();
}
}
} catch(e) {
log("Services::checkFolderExists()" + e.toString());
throw e;
}
return folderId;
}

Related

Flutter How to get all files from assets folder in one List

I have a bunch of xml files in assets folder, I add path to pubspec.yaml and path looks like this 'assets/data/somename.xml' I need to get data from them and this is the way how i got it now
List filePathList = ['assets/data/widow.xml','assets/data/door.xml'];
for(int i = 0;i<filePathList.length;i++){
var xmlFile = XmlDocument.parse(await rootBundle.loadString(filePathList[i]));
checkListtemplateXmlList.add(xmlFile);
}
How you can see i use realy bad way to take data from files,
there will be many more xml files in the future so i need some solution to this problem to not add path in filePathList for every file in assets folder.
Also i made a loadData function that load all files like i want, but my json files are in directory that i got with using getApplicationDocumentDirectory class. There is a code
static Future<void> loadData() async {
final dir = await getApplicationDocumentsDirectory();
List<FileSystemEntity> files = await dir.list().toList();
for (int i = 0; i < files.length; i++) {
String filepath = files[i].path;
File newFile = File(filepath);
String name = p.basenameWithoutExtension(newFile.path);
String myExtension = p.extension(filepath);
if(myExtension != '.json'){
} else{
checkLists.add(CheckList(name));
}
}
for(int i = 0;i< checkLists.length;i++){
await checkLists[i].readFile();
}
}
how i can do something like this in my getXmlData function
Inside the pubspec define only the folder:
assets:
- assets/data/
This will "load" all files inside the data folder.
And using this code:
// This will give a list of all files inside the `assets`.
var assets = await rootBundle.loadString('AssetManifest.json');
And use a filter to get all xml files.
Map json = json.decode(assets);
List get = json.keys.where((element) => element.endsWith(".xml")).toList();

Load all existent files (sprites) from Application.persistentDataPath? Unity

In my game, you can take screenshots of the world, which are saved in Application.persistentDataPath. I want to make a gallery where you can then see all these screenshots. Because you need to write to the file, I can't use Resources folder or Application.streamingAssetsPath. I could read the files one sprite at a time, using the name, but that's not really practical. So how could I load all files and add them to an array or list? I basically need the equivalent of Resources.LoadAll(). Does anyone know how to achieve this?
You can use Directory.GetFiles(string,string) to return all filepaths in the persistentData folder e.g. by file extension ("*.jpg")
Then you can use e.g. UnityWebRequestTexture.GetTexture also on local file paths and load assets from the persistent data path like
public Dictionary<string, Texture2D> textures = new Dictionary<string, Texture2D>();
private void Start()
{
var fileNames = Directory.GetFiles(Application.persistentDataPath, "*.jpg");
foreach(var fileName in fileNames)
{
StartCoroutine (LoadFile(fileName));
}
}
private IEnumerator LoadFile(string filePath)
{
using (UnityWebRequest uwr = UnityWebRequestTexture.GetTexture(filePath))
{
yield return uwr.SendWebRequest();
if (uwr.isNetworkError || uwr.isHttpError)
{
Debug.Log(uwr.error);
}
else
{
// Get downloaded asset bundle
var texture = DownloadHandlerTexture.GetContent(uwr);
// Something with the texture e.g.
// store it to later access it by fileName
var fileName = Path.GetFileName(filePath);
textures[fileName] = texture;
}
}
}

How to allow users to upload files with Google Form without login?

Where can I find code and instruction on how to allow users to upload files with Google Form without login?
I searched all over here and couldn't find any information.
https://developers.google.com/apps-script/reference
Thanks in advance.
The user will be uploading the files to your drive. So, google needs to verify the user. If there is no verification, someone can fill your drive in no time.
It is for your safety to know who has uploaded, so, login is must.
There's a workaround, I'm in a hurry to write the code now, but if you're interested let me know and I'll edit later.
Basically, you set up a web app with apps script, then you setup a custom HTML form, you'll have to manually collect the file, convert is to base64 then json, then when you catch it in apps script you reverse the process and save it wherever you want in your drive.
Since the user will be executing the script as you, there's no verification required
/*
These functions basically go through a file array and reads the files first as binary string (in second function), then converts the files to base64 string (func 1) before stringifying the files (after putting their base64 content into an object with other metadata attached; mime, name e.t.c);
You pass this stringified object into the body part of fetch(request,{body:"stringified object goes here"})
see next code block for how to read in apps script and save the files to google drive
N.B. The body data will be available under doPost(e){e.postData.contents}
*/
async function bundleFilesForUpload(){
let filesDataObj = [];
let copy = {fileInfo:{"ogname":"","meme":""},fileData:""};
for(let i = 0 ; i < counters.localVar.counters.filesForUploadArr.length ; i++){
let tempObj = JSON.parse(JSON.stringify(copy));
let file = counters.localVar.counters.filesForUploadArr[i];
tempObj.fileInfo.ogname = file.name;
tempObj.fileInfo.meme = file.type;
tempObj.fileData = await readFile(file).then((file)=>{
file = btoa(file);
return file;
}).then((file)=>{
return file;
})
filesDataObj.push(tempObj);
}
return filesDataObj;
}
async function readFile (file){
const toBinaryString = file => new Promise((resolve, reject) => {
const reader = new FileReader();
reader.readAsBinaryString(file);
reader.onload = () => resolve(reader.result);
reader.onerror = error => reject(error);
});
let parsedFile = null;
parsedFile = await toBinaryString(file);
return parsedFile;
}
/*From doPost downward, we read the file Array convert the base64 to blob and make a file in google drive using the blob and metadata we have, you may also see some sheet code, I'm using sheet as db for this */
//in buit function doPost in Code.gs
doPost(e){
const myDataObj = JSON.parse(e.postData.contents);
mainFileFunc(myDataObj.params[0].dataObj.images);
//the actual object structure might look different from yours, console log around
}
function mainFileFunc(fileArr) {
let myArrObj = [{"madeit":"toFileF"}];
let copy = JSON.parse(JSON.stringify(myArrObj[0]));
//sheet.getRange("A1").setValue(JSON.stringify(fileArr.length));
for(let i=0 ; i < fileArr.length ; i++){
myArrObj.push(copy);
let blob = doFileStuff(fileArr[i].data,fileArr[i].info[0].mime,fileArr[i].id);
myArrObj[i] = uploadFileOne(blob,fileArr[i].id);
myArrObj[i].mime = fileArr[i].info[0].mime;
myArrObj[i].realName = fileArr[i].name;
// sheet.getRange("A"+(i+1)).setValue(myArrObj[i].name);
// sheet.getRange("B"+(i+1)).setValue(myArrObj[i].url);
// sheet.getRange("C"+(i+1)).setValue(myArrObj[i].mime);
// sheet.getRange("D"+(i+1)).setValue(myArrObj[i].size);
}
return myArrObj;
}
function doFileStuff(filedata,filetype,filename){
var data = Utilities.base64Decode(filedata, Utilities.Charset.UTF_8);
var blob = Utilities.newBlob(data,filetype,filename);
return blob;
}
function uploadFileOne(data,filename) {
let myObj = {}
myObj["name"] = "";
myObj["realName"] = "Story_Picture";
myObj["url"] = "";
myObj["mime"] = "";
myObj["size"] = "";
myObj["thumb"] = "nonety";
var folders = DriveApp.getFoldersByName("LadhaWeb");
while (folders.hasNext()) {
var folder = folders.next();
folder.createFile(data);
}
var files = DriveApp.getFilesByName(filename);
while (files.hasNext()) {
var file = files.next();
myObj.name = file.getName();
myObj.url = file.getUrl();
myObj.mime = file.getMimeType();
myObj.size = file.getSize();
}
return myObj;
}
You can view the full frontend code for this project here and the backend here.
Hope this helps someone.

Take all text files in a folder and combine then into 1

I'm trying to merge all my text files into one file.
The problem I am having is that the file names are based on data previously captured in my app. I don't know how to define my path to where the text files are, maybe. I keep getting a error, but the path to the files are correct.
What am I missing?
string filesread = System.AppDomain.CurrentDomain.BaseDirectory + #"\data\Customers\" + CustComboB.SelectedItem + #"\";
Directory.GetFiles(filesread);
using (var output = File.Create("allfiles.txt"))
{
foreach (var file in new[] { filesread })
{
using (var input = File.OpenRead(file))
{
input.CopyTo(output);
}
}
}
System.Diagnostics.Process.Start("allfiles.txt");
my error:
System.IO.DirectoryNotFoundException
HResult=0x80070003
Message=Could not find a part of the path 'C:\Users\simeo\source\repos\UpMarker\UpMarker\bin\Debug\data\Customers\13Dec2018\'.
I cant post a pic, but let me try and give some more details on my form.
I select a combobox item, this item is a directory. then I have a listbox that displays the files in my directory. I then have a button that executes my desires of combining the files. thanks
I finally got it working.
string path = #"data\Customers\" + CustComboB.SelectedItem;
string topath = #"data\Customers\";
string files = "*.txt";
string[] txtFiles;
txtFiles = Directory.GetFiles(path, files);
using (StreamWriter writer = new StreamWriter(topath + #"\allfiles.txt"))
{
for (int i = 0; i < txtFiles.Length; i++)
{
using (StreamReader reader = File.OpenText(txtFiles[i]))
{
writer.Write(reader.ReadToEnd());
}
}
System.Diagnostics.Process.Start(topath + #"\allfiles.txt");
}

Adobe AIR drag and drop directory

Please let me know how can I drag and drop a directory from windows onto Adobe AIR panel.
The folder has subFolders inside. The subFolders have many files.
I want to drag the parent folder and drop it so that the whole structure has to get uploaded.
Please help.
It is rather easy to upload folders. When detecting a drop using the drop event, you get supplied wit ha list of files dropped. You can then determine if it is the dropped file is a folder, and if it is, then you can get all the files listed under it (which includes files) and if any of those are folders, then recurse further down.
Basically, adobe air treats files and folders as the same object.
In the drop event put
var files = event.dataTransfer.getData( "application/x-vnd.adobe.air.file-list" );
var fileData = [];
for (var f = 0; f < files.length; f++)
{
if (files[f].isDirectory) {
//process this folder recursing through subfolders
} else {
//we have a file
}
}
You can then recurse through the object adding files and files to the server as needed
Here is the complete Example. Just call onInit() method on application's initialization.
private function onInit(event:FlexEvent):void
{
this.addEventListener(NativeDragEvent.NATIVE_DRAG_ENTER, onDragIn);
this.addEventListener(NativeDragEvent.NATIVE_DRAG_DROP, onDrop);
}
private function onDragIn(event : NativeDragEvent):void
{
NativeDragManager.acceptDragDrop(this);
}
private function onDrop(event : NativeDragEvent):void
{
try
{
var dropfiles:Array = event.clipboard.getData(ClipboardFormats.FILE_LIST_FORMAT) as Array;
processDroppedFiles(dropfiles);
}
catch (error : IOError)
{
trace("Error during drag-and-drop procedure.");
}
}
private function processDroppedFiles(files : Array):void
{
for each (var file:File in files)
{
if (file.isDirectory)
{
processDirectory(file);
}
else
{
processFile(file);
}
}
}
private function processDirectory(dir : File):void
{
processDroppedFiles(dir.getDirectoryListing());
}
private function processFile(file:File):void
{
trace(file);
}