How to download a file with Node.js from google drive api
I don't need anything special. I only want to download a file from a GoogleDrive, and then save it to a given directory of client.
app.get("/download",function(req,res){
const p38290token = new google.auth.OAuth2(CLIENT_ID, CLIENT_SECRET, REDIRECT_URI);
p38290token.setCredentials({ refresh_token: token.acc });
const p38290Id = google.drive({
version: "v3",
auth: p38290token,
});
var dest = fs.createWriteStream("./test.png");
try {
p38290Id.files.get({
fileId: "1daaxy0ymKbMro-e-JnexmGvM4WzW-3Hn",
alt: "media"
}, { responseType: "stream" },
(err, res) => {
res.data
.on("end", () => {
console.log("Done");
})
.on("error", err => {
console.log("Error", err);
})
.pipe(dest); // i want to sent this file to client who request to "/download"
}
)
} catch (error) {
}
})
I want to do that just someone come to www.xyz.com/download and file will be download automatically
The issue seems to be with this line:
var dest = fs.createWriteStream("./test.png");
You are using a file system command which is meant to interact with files on the server. Your question makes it clear that you wish for express to deliver the contents of the file over to the client making the HTTP request.
For that you can just use the res parameter of the route callback function. You declare it on this line:
app.get("/download",function(req,res){
In your case I'd remove the dest variable completely and simply pipe the file to res like so:
.pipe(dest);
Have a look at this answer as well.
Related
Im trying to get the contents of a file using the google drive API v3 in node.js.
I read in this documentation I get a stream back from drive.files.get({fileId, alt: 'media'})but that isn't the case. I get a promise back.
https://developers.google.com/drive/api/v3/manage-downloads
Can someone tell me how I can get a stream from that method?
I believe your goal and situation as follows.
You want to retrieve the steam type from the method of drive.files.get.
You want to achieve this using googleapis with Node.js.
You have already done the authorization process for using Drive API.
For this, how about this answer? In this case, please use responseType. Ref
Pattern 1:
In this pattern, the file is downloaded as the stream type and it is saved as a file.
Sample script:
var dest = fs.createWriteStream("###"); // Please set the filename of the saved file.
drive.files.get(
{fileId: id, alt: "media"},
{responseType: "stream"},
(err, {data}) => {
if (err) {
console.log(err);
return;
}
data
.on("end", () => console.log("Done."))
.on("error", (err) => {
console.log(err);
return process.exit();
})
.pipe(dest);
}
);
Pattern 2:
In this pattern, the file is downloaded as the stream type and it is put to the buffer.
Sample script:
drive.files.get(
{fileId: id, alt: "media",},
{responseType: "stream"},
(err, { data }) => {
if (err) {
console.log(err);
return;
}
let buf = [];
data.on("data", (e) => buf.push(e));
data.on("end", () => {
const buffer = Buffer.concat(buf);
console.log(buffer);
});
}
);
Reference:
Google APIs Node.js Client
noob question, I'm just getting started with Google Drive API v3. How can I download dynamic file from google drive when I only have fileId. file can be, image, pdf, or docs.
I tried searching but I couldn't found any reference or example related to this.
This what I have so far but it only download specific file extension.
downloadFile(req, res) {
const auth = new google.auth.JWT(
client_email,
null,
private_key,
SCOPES,
);
const { fileId } = req.params;
const drive = google.drive({ version: 'v3', auth});
var dest = fs.createWriteStream('./tmp/downloads/dummy.pdf')
drive.files.get({
fileId,
alt: 'media',
}, {
responseType: 'stream'
}).then((driveResponse) => {
driveResponse.data.on('end', () => {
console.log(`downloading fileID ${fileId}`);
})
.on('error', (err) => {
console.log(err);
})
.on('data', (d) => {
console.log(d);
})
.pipe(dest)
})
.catch((err) => {
console.log(err);
})
}
Is there way to download dynamic files from google drive?
I believe your goal as follows.
You want to download the files from Google Drive using the service account and the file ID.
The files include both Google Docs files and the files except for Google Docs files.
You want to achieve this using googleapis for Node.js.
Modification points:
Unfortunately, from it only download specific file extension., I cannot understand about the detail of your situation. But I guess that the reason of your issue might be due to downloading both Google Docs files and the files except for Google Docs files.
When Google Docs files are downloaded, the files are required to be downloaded using the method of "Files: export" in Drive API.
When the files except for Google Docs files are downloaded, the files are required to be downloaded using the method of "Files: get" in Drive API.
I thought that above situation might be the reason of your issue.
In order to download both Google Docs files and the files except for Google Docs files, I propose the following flow.
Check the mimeType of the file ID.
Download the file using each method by the mimeType.
When above points are reflected to your script, it becomes as follows.
Modified script:
From:
var dest = fs.createWriteStream('./tmp/downloads/dummy.pdf')
drive.files.get({
fileId,
alt: 'media',
}, {
responseType: 'stream'
}).then((driveResponse) => {
driveResponse.data.on('end', () => {
console.log(`downloading fileID ${fileId}`);
})
.on('error', (err) => {
console.log(err);
})
.on('data', (d) => {
console.log(d);
})
.pipe(dest)
})
.catch((err) => {
console.log(err);
})
To:
drive.files.get({ fileId, fields: "*" }, async (err, { data }) => {
if (err) {
console.log(err);
return;
}
let filename = data.name;
const mimeType = data.mimeType;
let res;
if (mimeType.includes("application/vnd.google-apps")) {
const convertMimeTypes = {
"application/vnd.google-apps.document": {
type:
"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
ext: ".docx",
},
"application/vnd.google-apps.spreadsheet": {
type:
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
ext: ".xlsx",
},
"application/vnd.google-apps.presentation": {
type:
"application/vnd.openxmlformats-officedocument.presentationml.presentation",
ext: ".pptx",
},
};
filename += convertMimeTypes[mimeType].ext;
res = await drive.files.export(
{
fileId,
mimeType: convertMimeTypes[mimeType].type,
},
{ responseType: "stream" }
);
} else {
res = await drive.files.get(
{
fileId,
alt: "media",
},
{ responseType: "stream" }
);
}
const dest = fs.createWriteStream(filename);
res.data
.on("end", () => console.log("Done."))
.on("error", (err) => {
console.log(err);
return process.exit();
})
.pipe(dest);
});
Note:
In this modification, I prepared 3 types of Google Docs files at convertMimeTypes. When you want to download other mimeTypes, please modify convertMimeTypes. In this case, for example, Google Docs files are downloaded as Microsoft Docs files.
References:
Download files
Files: get
Files: export
I am currently building a chatbot that is able to receive attachments and save them to a local directory.
I want to find out how to use that same attachment and send it via email.
async downloadAttachmentAndWrite(attachment) {
// Retrieve the attachment via the attachment's contentUrl.
const url = attachment.contentUrl;
console.log(attachment)
// Local file path for the bot to save the attachment.
const localFileName = path.join(__dirname, attachment.name);
try {
// arraybuffer is necessary for images
const response = await axios.get(url, { responseType: 'arraybuffer' });
console.log('#####')
console.log(response.data)
// If user uploads JSON file, this prevents it from being written as "{"type":"Buffer","data":[123,13,10,32,32,34,108..."
if (response.headers['content-type'] === 'application/json') {
response.data = JSON.parse(response.data, (key, value) => {
return value && value.type === 'Buffer' ? Buffer.from(value.data) : value;
});
}
fs.writeFile(localFileName, response.data, (fsError) => {
console.log(localFileName)
console.log(response.data)
if (fsError) {
throw fsError;
}
});
} catch (error) {
console.error(error);
return undefined;
}
// If no error was thrown while writing to disk, return the attachment's name
// and localFilePath for the response back to the user.
return {
fileName: attachment.name,
localPath: localFileName
};
}
That is currently the function to receive and save to directory, but how do I actually capture the attachment and send it to another function?
Look over the 24.bot-authentication-msgraph sample in the BotBuilder-Samples repo. This sample demonstrates how a bot can be setup to send an email on the user's behalf.
Using that sample as a reference/template, you can infer how this process could work for you (in case you are not using MS Graph). The docs here explain how a file can be included as an attachment in an email.
If you preserve the location of the saved file, you should be able to read the file from the local directory and, using the method referenced above, attach the file before sending.
Hope of help.
I'm implementing a youtube video downloader using ytdl-core with Nodejs backend and Reactjs frontend. However, using ytdl-core library I'm able to send to youtube video file to frontend with this codeblock
app.get('/download', (req, res) => {
let { url, itag } = req.query;
let id = ytdl.getURLVideoID(url);
ytdl.getInfo(id, (err, info) => {
if (err) {
console.log(err);
throw err;
}
else{
let audioandvideo = ytdl.filterFormats(info.formats, 'audioandvideo');
let video = audioandvideo.filter(obj => obj.itag === itag);
video = video[0]
res.header('Content-Disposition', `attachment; filename="${info.title}.${video.container}"`);
res.header('Content-Type', 'video/webm');
ytdl(url, {
format: video
}).pipe(res);
}
})
});
However, the file downloads correctly if I redirect the webpage to the route like this
window.location.href = `http://localhost:5000/download?url=${this.state.url}&itag=${itag}`;
This works fine and the video downloads correctly. But as it's a redirection I can't do that in a hosted site. So, I need to use axios to do this.
I did some research and found out some solutions. I tried with js-file-download library following the accepted answer here. It downloads the file to the client directory but the file won't play. This is the codeblock I used for that
downloadVideo(itag){
axios.get(`http://localhost:5000/download`, {
params: { url: this.state.url, itag },
})
.then(response => {
fileDownload(response.data, `video.mp4`);
})
.catch(err => console.log(err));
}
As it's not working I tried another approach mentioned in the previously mentioned StackOverflow answer as well. It also downloads the file but doesn't work as well.
How can I get this fixed? What may be the reason my axios request doesn't work correctly?
EDIT :
downloadVideo(itag){
axios.get(`http://localhost:5000/download`, {
params: { url: this.state.url, itag },
responseType: Blob
})
.then(response => {
fileDownload(response.data, `video.mp4`);
})
.catch(err => console.log(err));
// window.location.href = `http://localhost:5000/download?url=${this.state.url}&itag=${itag}`;
}
This is the frontend code. If I use the commented code block (window.location.href) instead of axios.get the file gets downloaded and it works. But if I use axios.get a file gets downloaded but it seems to be a broken file as it's not playing.
I have a camera component which I clicks a picture. I store the clicked picture using expo's FileSystem in the local cacheDirectory. Looks some thing like this:
onPictureSaved = async photo => {
await FileSystem.moveAsync({
from: photo.uri,
to: `${FileSystem.cacheDirectory}test.jpg`
});}
My next step is to my next stop is converting the image in the local cacheDirectory into a blob and upload the image into S3 via the aws-sdk:
var params = {
Bucket: "my-bucket",
Key: 'test.jpg',
Body: blob
};
s3.upload(params, function(err, data) {
if (err) {
console.log(err);
} // an error occurred
else {
console.log(data);
} // successful response
}
However, any methods or modules I install in order to accomplish this tiny step in the process hasn't been working at all. I can't use RNFS, react-native-fetch-blob or any other modules that require linking thanks to the expo client. I don't want to detach expo just for one thing. Is there any other way to accomplish this?
Take a look at https://github.com/expo/image-upload-example/issues/3#issuecomment-387263080. The latest expo release supports blobs, so then you can do something like the following:
uploadToS3 = async (fileUri, s3Bucket, s3Key) => {
const response = await fetch(fileUri);
const blob = await response.blob();
return new Promise((resolve, reject) => {
const params = {
Bucket: s3Bucket,
Key: s3Key,
Body: blob,
};
s3.upload(params, function(err, data) {
if (err) {
console.log('Something went wrong');
console.log(err);
reject(err);
} else {
console.log('Successfully uploaded image');
resolve(data);
}
});
});
};
Hope this helps!