YouTube Downloader using node.js - javascript

So I'm creating YouTube Downloader using node.js. The problem is the files are already created after I ran the code, but the files are 0kb and it prints Successfully. What I want is the program must be print successfully when I successfully download the video, also must not be created the file yet. the file must be created after the one video successfully downloaded
const playlist = [
{
title: "What is DevOps",
videoUrl: "https://www.youtube.com/watch?v=mBBgRdlC4sc",
},
{
title: "Introduction To DevOps ",
videoId: "Me3ea4nUt0U",
videoUrl: "https://www.youtube.com/watch?v=Me3ea4nUt0U",
},
{
title: "DevOps Tutorial For Beginners ",
videoId: "YSkDtQ2RA_c",
videoUrl: "https://www.youtube.com/watch?v=YSkDtQ2RA_c",
},
];
const fs = require("fs");
const ytdl = require("ytdl-core");
const length = playlist.length;
playlist.forEach((pl, i) => {
const { videoUrl, title } = pl;
const item = i + 1;
ytdl(videoUrl, {
format: "mp4",
}).pipe(fs.createWriteStream(`${title}.mp4`));
console.log(`${item}/${length} - ${title} downloaded successfully`);
});

You are logging "downloaded successfully" before the writing is finished. You have a few possibilities. One might be listening on certain events on the "WriterStream".
from the docs : https://nodejs.org/dist/latest-v12.x/docs/api/fs.html#fs_fs_createwritestream_path_options
// Create WriteableStream
const writeableStream = fs.createWriteStream(`${title}.mp4`);
// Listening for the 'finish' event
writeableStream .on('finish', () => {
console.log(`${item}/${length} - ${title} downloaded successfully`);
});
// Plug it into the ReadableStream
ytdl(videoUrl, {
format: "mp4",
}).pipe(writeableStream);
Now this will create a new file as soon the writing starts. I suggest using a temporary name like filename.temp.mp4 and then rename it after it finished writing.

Related

React download an image from uri and put in static folder? [duplicate]

I am building an app with React Native, for Android and iOS. I am trying to let the user download a PDF file when clicking on a button.
react-native-file-download does not support Android
react-native-fs does nothing when I trigger downloadFile (nothing shows up on the notification bar), and I am not able to find the file after that. I added android.permission.WRITE_EXTERNAL_STORAGE to the Android Manifest file. I double-checked that the file I am trying to download exists (when it does not, the library throws an error)
I do not find other solutions for this problem. I have found libraries for viewing a PDF, but I would like to let the user download the PDF.
Just implemented the download feature an hour ago :p
Follow these steps:
a) npm install rn-fetch-blob
b) follow the installation instructions.
b2) if you want to manually install the package without using rnpm, go to their wiki.
c) Finally, that's how I made it possible to download files within my app:
const { config, fs } = RNFetchBlob
let PictureDir = fs.dirs.PictureDir // this is the pictures directory. You can check the available directories in the wiki.
let options = {
fileCache: true,
addAndroidDownloads : {
useDownloadManager : true, // setting it to true will use the device's native download manager and will be shown in the notification bar.
notification : false,
path: PictureDir + "/me_"+Math.floor(date.getTime() + date.getSeconds() / 2), // this is the path where your downloaded file will live in
description : 'Downloading image.'
}
}
config(options).fetch('GET', "http://www.example.com/example.pdf").then((res) => {
// do some magic here
})
If you're using Expo, react-native-fetch-blob won't work. Use FileSystem.
Here's a working example:
const { uri: localUri } = await FileSystem.downloadAsync(remoteUri, FileSystem.documentDirectory + 'name.ext');
Now you have localUri with the path to the downloaded file. Feel free to set your own filename instead of name.ext.
I Followed the solution from Jonathan Simonney, above on this post. But I had to change it a little:
const { config, fs } = RNFetchBlob;
const date = new Date();
const { DownloadDir } = fs.dirs; // You can check the available directories in the wiki.
const options = {
fileCache: true,
addAndroidDownloads: {
useDownloadManager: true, // true will use native manager and be shown on notification bar.
notification: true,
path: `${DownloadDir}/me_${Math.floor(date.getTime() + date.getSeconds() / 2)}.pdf`,
description: 'Downloading.',
},
};
config(options).fetch('GET', 'http://www.africau.edu/images/default/sample.pdf').then((res) => {
console.log('do some magic in here');
});
GetItem_downloadbtn = (item, itemname) => {
console.log("fiel url comiugn jdd " + item);
console.log("item name checkoing " + itemname);
const android = RNFetchBlob.android;
const filename = itemname;
const filepath = RNFetchBlob.fs.dirs.DownloadDir + '/foldernamae/' + filename;
const downloadAppUrl = item;
RNFetchBlob.config({
addAndroidDownloads: {
useDownloadManager: true,
title: 'great, download success',
description:'an apk that will be download',
mime: 'application/vnd.android.package-archive',
// mime: 'image/jpeg',
// mediaScannable: true,
notification: true,
path: filepath
}
})
.fetch('GET', downloadAppUrl)
.then((res) => {
// console.log('res.path ', res.path());
alert('res.path ', res.path());
android.actionViewIntent(res.path(), 'application/vnd.android.package-archive');
})
.catch((err) => {
alert('download error, err is', JSON.stringify(err));
});
}
I had the same issue, got it working using Expo WebBrowser Module
// install module
npm install react-native-webview
// import the module
import * as WebBrowser from 'expo-web-browser';
// then in your function you can call this function
await WebBrowser.openBrowserAsync(file_ur);
it will open preview of the file and then user can download using share button.

how to send multiple files into fire base storage and save their URL in real time database in one record

i want to send multiple file to Fire-base storage and meantime it has to save real-time database as a one record using java-script
ex:
file1 : urlonfirstfile
file2 : urlonsecondfile
for (var i = 0; i < file.length; i++) {
var task = ref.child(file.name).put(file, metadata);
task
.then(snapshot => snapshot.ref.getDownloadURL())
.then((url) => {
console.log(url);
userDetails.push({
email : email,
title1: tit,
detail1: dit,
file:file[i].name
});
});
}
Your question is kinda vague on what information you want to store. So I've made some assumptions to come up with the below code:
The files are to be uploaded to an area of Firebase Storage specific to the logged in user. (e.g. "userFiles/CURRENT_USER/...")
The information about the uploaded files are kept under the user's own data. (e.g. "users/CURRENT_USER/uploads/..."
The title and detail properties change for each file. Where these properties come from is unclear, so I'm just going to assume they are passed in through the object metadata.
The code below should be enough to get you started on figuring out your own solution.
// the array of File objects to upload
const fileObjArray = [ ... ]
// the metadata to store with each file
const metadata = { ... }
// the current user's ID
const currentUserId = firebase.auth().currentUser.uid;
// Where to save information about the uploads
const databaseRef = firebase.database().ref("user").child(currentUserId).child('uploads');
// Create an ID for this set of uploaded files
const uploadId = storageRef.push().key;
// Save files to storage in a subfolder of the user's files corresponding to the uploadId
const storageRef = firebase.storage().ref("userFiles").child(currentUserId).child(uploadId);
// Upload each file in fileObjArray, then fetch their download URLs and then return an object containing information about the uploaded file
var uploadPromiseArray = fileObjArray.map((fileObj) => {
var uploadTask = storageRef.child(fileObj.name).put(fileObj, metadata)
return uploadTask.then(uploadSnapshot => {
// file uploaded successfully. Fetch url for the file and return it along with the UploadTaskSnapshot
return uploadSnapshot.ref.getDownloadURL().then((url) => {
return {
downloadUrl: url,
snapshot: uploadSnapshot
};
});
});
});
// uploadPromiseArray is an array of Promises that resolve as objects with the properties "downloadUrl" and "snapshot"
Promise.all(uploadPromiseArray)
.then((uploadResultArray) => {
var batchUploadData = {
timestamp: firebase.database.ServerValue.TIMESTAMP, // use the server's time
files: [],
... // other upload metadata such as reason, expiry, permissions, etc.
}
batchUploadData.files = uploadResultArray.map((uploadResult) => {
// rearrange the file's snapshot data and downloadUrl for storing in the database
return {
file: uploadResult.snapshot.name,
url: uploadResult.url,
title: uploadResult.snapshot.metadata.customMetadata.title,
detail: uploadResult.snapshot.metadata.customMetadata.detail
};
});
// commit the data about this upload to the database.
return databaseRef.child(uploadId).set(batchUploadData);
})
.then((dataSnapshot) => {
// the upload completed and information about the upload was saved to the database successfully
// TODO: do something
}, (err) => {
// some error occured
// - a file upload failed/was cancelled
// - the database write failed
// - permission error from Storage or Realtime Database
// TODO: handle error
});
// Warning: this line will be reached before the above code has finished executing
This is what it looks like on the database:
"users": {
"someUserId-78sda9823": {
"email": "example#example.com",
"name": "mr-example",
"username": "mrexemplary",
"uploads": {
"niase89f73oui2kqwnas98azsa": {
"timestamp": 1554890267823,
"files": {
"1": {
"file": "somefile.pdf",
"url": "https://firebasestorage.googleapis.com/v0/b/bucket/o/userFiles%2FsomeUserId-78sda9823%2Fsomefile.pdf",
"title": "Some File",
"detail": "Contains a report about some stuff"
},
"2": {
"file": "screenshot.png",
"url": "https://firebasestorage.googleapis.com/v0/b/bucket/o/userFiles%2FsomeUserId-78sda9823%2Fscreenshot.png",
"title": "Screenshot of problem",
"detail": "Contains an image that shows some stuff"
},
...
}
},
...
},
...
},
...
}
Note 1: This code is not yet complete. It is missing error handling for things like permission errors and incomplete file uploads. This is a problem for you to solve.
Note 2: Regarding incomplete file uploads, if any file fails to upload or get it's download URL successfully, the database will not be written to. One possible way to aid with this is to add a catch to uploadTask that returns null on error and then in the uploadResultArray.map(...) step skip any uploadResult variables that are null or write to the database that it failed for that particular file.
Note 3: Because Firebase Storage and the Realtime Database both use snapshots, try to keep them called uploadSnapshot/fileSnapshot and dataSnapshot respectively when using both in your code to minimise confusion. Similarly, name your references somethingStorageRef/somethingSRef and somethingDatabaseRef/somethingDBRef.

Ionic 3 - download a file to directory

I have the similar problem like here:
How to download file to Download's directory with Ionic Framework?
I got success alert after download but I can't see the file in an Android file explorer under the path displayed after succeed download: file:///data/user/0/io.ionic.fileTest/image.jpg
My code:
download(){
const fileTransfer: FileTransferObject = this.transfer.create();
const url = "http://cdna.allaboutvision.com/i/conditions-2016/heterochromia-kate-bosworth-660x660-with-credit.jpg";
fileTransfer.download(url, this.file.dataDirectory + 'laska.jpg', true).then((entry) => {
const alertSuccess = this.alertCtrl.create({
title: `Download Succeeded!`,
subTitle: `was successfully downloaded to: ${entry.toURL()}`,
buttons: ['Ok']
});
alertSuccess.present();
}, (error) => {
const alertFailure = this.alertCtrl.create({
title: `Download Failed!`,
subTitle: `was not successfully downloaded. Error code: ${error.code}`,
buttons: ['Ok']
});
alertFailure.present();
});
}
Could I somehow manage to save this file in e.g "Download" folder or "Documents"? I also tried changing destination path to:
cordova.file.externalRootDirectory + '/Download/'
In that case, I received error 1.
In many examples I see people use
window.requestFileSystem()
but it looks like the window doesn't have this method for me. I use visual studio code and ionic 3.
You got little bit mistake in fileTransfer.download
instead of this.file.applicationStorageDirectory use this.file.dataDirectory
Working code that downloads a file to Downloads directory:
downloadFile() {
this.fileTransfer.download("https://cdn.pixabay.com/photo/2017/01/06/23/21/soap-bubble-1959327_960_720.jpg", this.file.externalRootDirectory +
'/Download/' + "soap-bubble-1959327_960_720.jpg").then()
}
getPermission() {
this.androidPermissions.hasPermission(this.androidPermissions.PERMISSION.READ_EXTERNAL_STORAGE)
.then(status => {
if (status.hasPermission) {
this.downloadFile();
}
else {
this.androidPermissions.requestPermission(this.androidPermissions.PERMISSION.READ_EXTERNAL_STORAGE)
.then(status => {
if(status.hasPermission) {
this.downloadFile();
}
});
}
});
}

Meteor Files Storing a image url in Mongo collection

I'm really lost when it comes to file uploading in meteor and manage the data between client and server.
I'm using Meteor Files from Veliov Group to upload multiple images on the client side. They're getting stored in a FilesCollection called Images and I have my Mongo.Collection called Adverts.
collections.js:
Adverts = new Mongo.Collection('adverts');
Images = new FilesCollection({
collectionName: 'Images',
storagePath: () => {
return `~/public/uploads/`;
},
allowClientCode: true, // Required to let you remove uploaded file
onBeforeUpload(file) {
// Allow upload files under 10MB, and only in png/jpg/jpeg formats
if (file.size <= 10485760 && /png|jpg|jpeg/i.test(file.ext)) {
return true;
} else {
return 'Limit 10mb';
}
}
});
// if client subscribe images
if (Meteor.isClient) {
Meteor.subscribe('files.images.all');
};
// if server publish images
if (Meteor.isServer) {
Images.allowClient();
Meteor.publish('files.images.all', () => {
return Images.collection.find();
});
};
What I'm trying to achieve is, when I upload the images, I wanna store the URLs on the document in Adverts that I'm working with (I'm using iron:router to access those documents _id).
I managed to get the URL but only for the first image uploaded, my code for what I saw on the docs:
Template.imageUpload.helpers({
imageFile: function () {
return Images.collection.findOne();
},
myImage: () => {
console.log(Images.findOne({}).link())
}
})
Template.imageUpload.events({
'change #fileInput': function (e, template) {
if (e.currentTarget.files) {
_.each(e.currentTarget.files, function (file) {
Images.insert({
file: file
});
});
}
}
})
I was using a Meteor.Call to send the URL to the server, but I couldn't manage to update the document with a new property pic and the value url of the image
server.js:
imageUpload: (actDoc, imgURL) => { // actDoc is the document id that I'm working on the client
Adverts.update({'reference': actDoc}, {$set: {'pic': imgURL}})
},
This is probably a dumb question and everything might in the docs, but I've readed those docs back and forth and I can't manage to understand what I need to do.
The answer for my problem was to do it server side
main.js server
FSCollection.on('afterUpload'), function (fileRef) {
var url = 'http://localhost:3000/cdn/storage/images/' + fileRef._id + '/original/' + fileRef._id + fileRef.extensionWithDot;
}
MongoCollection.update({'_id': docId}, { $set: {url: imgUrl }}})

Uploading file to PouchDB/CouchDB

I'm building a mobile app with Cordova. I am using PouchDB for local storage so the app works without internet. PouchDB syncs with a CouchDB server so you can access your data everywere.
Now, i've got to the point where I need to add a function to upload (multiple) files to a document. (files like .png .jpg .mp3 .mp4 all the possible file types).
My original code without the file upload:
locallp = new PouchDB('hbdblplocal-'+loggedHex);
function addItem() {
//get info
var itemTitle = document.getElementById('itemTitle').value;
var itemDesc = document.getElementById('itemDesc').value;
var itemDate = document.getElementById('itemDate').value;
var itemTime = document.getElementById('itemTime').value;
//get correct database
console.log(loggedHex);
console.log(loggedInUsername);
//add item to database
var additem = {
_id: new Date().toISOString(),
title: itemTitle,
description: itemDesc,
date: itemDate,
time: itemTime
};
locallp.put(additem).then(function (result){
console.log("Added to the database");
location.href = "listfunction.html";
}).catch(function (err){
console.log("someting bad happened!");
console.log(err);
});
}
I'll add a link to a JSfiddle where I show my attempt to add the file upload. i've also included the html part.
link to jsfiddle: click here
I've noticed an error in the console about there not being a content-type.
Is there someone who can help me?
I think you're not setting the content_type of your attachment right. Try changing type to content_type like so:
var additem = {
_id: new Date().toISOString(),
title: itemTitle,
description: itemDesc,
date: itemDate,
time: itemTime,
_attachments: {
"file": {
content_type: getFile.type,
data: getFile
}
}
};
Also see the docs for working with attachments.

Categories

Resources