Can not find file with ffmpeg - node.js

I am programming a server in node.js to process a audio file.
I save the file with this code:
app.use(upload());
app.get("/", function (req, res) {
res.sendFile("index.html")
});
//Uploaded files will be saved
app.post("/", function (req, res) {
if (req.files) {
var file = req.files.filename,
filename = file.name;
file.mv("./upload/" + filename, function (err) {
if (err) {
console.log("err");
}
else {
res.send("Done");
console.log(filename);
convert(filename);
}
})
}
})
I save the file in my upload directory. There everthing works great but now comes the problem.
I convert the file with ffmpeg
function convert(filename) {
var realName = "./upload/" + filename;
var newName = "./output/" + filename.substr(0, filename.length - 4) + ".flac";
ffmpegN = ffmpeg(realName);
ffmpegN.audioBitrate(16).audioFrequency(16000).withAudioCodec('flac').format("flac").save(outputFile);
ffmpeg(realName)
.toFormat('flac')
.on('error', (err) => {
console.log('An error occurred: ' + err.message);
})
.on('progress', (progress) => {
// console.log(JSON.stringify(progress));
console.log('Processing: ' + progress.targetSize + ' KB converted');
})
.on('end', () => {
console.log('Processing finished !');
})
.save(newName);//path where you want to save your file
SpeechToText(newName);
}
Then I want to pass this file to the google speech api. But then I get the error that the file is not found
Here is the code for the Speech Api:
function SpeechToText(path) {
// The name of the audio file to transcribe
const fileName = path;
// Reads a local audio file and converts it to base64
const file = fs.readFileSync(fileName);
const audioBytes = file.toString('base64');
// The audio file's encoding, sample rate in hertz, and BCP-47 language code
const audio = {
content: audioBytes,
};
const config = {
encoding: 'FLAC',
languageCode: 'de-DE',
};
const request = {
audio: audio,
config: config,
};
// Detects speech in the audio file
client
.recognize(request)
.then(data => {
const response = data[0];
const transcription = response.results
.map(result => result.alternatives[0].transcript)
.join('\n');
console.log(`Transcription: ${transcription}`);
})
.catch(err => {
console.error('ERROR:', err);
});
}
The thing is that if I upload a file everything works. But if I try it for a second time the error occurs:
fs.js:646
return binding.open(pathModule._makeLong(path), stringToFlags(flags), mode);
^
Error: ENOENT: no such file or directory, open
'C:\Users\paulu\desktop\API\output\sample.flac'
at Object.fs.openSync (fs.js:646:18)
at Object.fs.readFileSync (fs.js:551:33)
at SpeechToText (C:\Users\paulu\desktop\API\server.js:68:21)
at convert (C:\Users\paulu\desktop\API\server.js:121:5)
at C:\Users\paulu\desktop\API\server.js:50:17
at doMove (C:\Users\paulu\desktop\API\node_modules\express-
fileupload\lib\index.js:152:17)
at WriteStream.<anonymous> (C:\Users\paulu\desktop\API\node_modules\express-
fileupload\lib\in dex.js:182:15)
at emitNone (events.js:106:13)
at WriteStream.emit (events.js:208:7)
at fs.close (fs.js:2094:12)
Thank you for all answers !

I fixed it.
The problem was that the ffmpeg process was not finished. Here the solution:
function convert(filename) {
var realName = "./upload/" + filename;
var newName = "./output/" + filename.substr(0, filename.length - 4) + ".flac";
ffmpeg(realName)
.toFormat('flac')
.on('error', (err) => {
console.log('An error occurred: ' + err.message);
})
.on('progress', (progress) => {
// console.log(JSON.stringify(progress));
console.log('Processing: ' + progress.targetSize + ' KB converted');
})
.on('end', () => {
console.log('Processing finished !');
SpeechToText(newName); //Just move this statement to here !
})
.save(newName);//path where you want to save your file
}

Related

NodeJs - Error while reading files using fs.createReadStream

I am trying to implement a feature to my web app where you can upload CSV files and insert data into Postgresql. I have made my app endpoint and written some code
const router = require('express').Router()
const uploadMid = require('./fileUpMid')
const pool = require('./db')
const fs = require("fs");
const fastcsv = require("fast-csv");
const upload = async (req, res) => {
if (req.files === null) {
return res.status(400).json({ msg: 'No file uploaded' });
}
const file = req.files.file;
file.mv(`${__dirname}/uploads/${file.name}`, err => {
if (err) {
console.error(err);
return res.status(500).send(err);
}
res.json({ fileName: file.name, filePath: `/uploads/${file.name}` });
});
let persons = [];
let path = __dirname + "/uploads/" +file.name;
fs.createReadStream(path)
.pipe(fastcsv.parse({ headers: true }))
.on("error", (error) => {
console.error(error.message);
})
.on("data", (row) => {
persons.push(row);
})
.on("end", () => {
//remove head
persons.shift();
const q = "some query here";
pool.connect((err, client, done) => {
if (err) throw err;
try {
persons.forEach(row => {
console.log(typeof row)
var obj = JSON.parse(JSON.stringify(row));
var values = Object.keys(obj).map(function (key) { return obj[key]; });
console.log(values)
client.query(q, values, (err, res) => {
if (err) {
console.log(err.stack);
} else {
console.log("inserted " + res.rowCount + " row:", row);
}
});
});
} finally {
done();
}
});
})
// fs.unlinkSync(path)
}
router.post('/file', uploadMid.single("file") ,upload)
module.exports = router
Everything seemed to work fine, but when I try to upload a second file I awlways get an error on terminal
Error: ENOENT: no such file or directory, open 'filename here with full path'
>- Emitted 'error' event on ReadStream instance at:
>- at internal/fs/streams.js:126:14
>- at FSReqCallback.oncomplete (fs.js:180:23) {
>- errno: -4058,
>- code: 'ENOENT',
>- syscall: 'open',
>- path: 'filename here with full path'}
I know this is not a safe nor secure way to upload data but this app is intended to be run only locally. Even when the first file is upload successfully in DevTools console it logs
GET http://localhost:3000/uploads/filename [HTTP/1.1 404 Not Found 8ms]
But the file is created with all its content on uploads directory.
Any tip for what to look for ?
Thank you in advance :)
Judging by the error (Error: ENOENT: no such file or directory, open 'filename here with full path'), here is the suggested way of defining paths in NodeJS apps using the path module.
const path = require('path');
// Inside`upload` middleware
const filePath = path.join(__dirname, 'uploads', file.name);

Nodejs: ENOENT on Twitter Image Bot

I'm a beginner level programmer. I used some online guides as well as my starter knowledge. I'm attempting to create a bot that posts to twitter every hour. I keep getting the error ENOENT, which as I understand, means that it can't find the directory. Here is the error I'm getting (All I censored was personal information, but it's not censored in the actual code or error)
opening an image...
15.jpg
internal/fs/utils.js:269
throw err;
^
Error: ENOENT: no such file or directory, open 'C:\Users\####\Desktop\####\bot\images15.jpg'
at Object.openSync (fs.js:462:3)
at Object.readFileSync (fs.js:364:35)
at C:\Users\####\Desktop\####\bot\server.js:32:29
at FSReqCallback.oncomplete (fs.js:156:23) {
errno: -4058,
syscall: 'open',
code: 'ENOENT',
path: 'C:\\Users\\#####\\Desktop\\####\\bot\\images15.jpg'
}
It looks like its changing the name of the file to have images in front. I can't figure out why it's doing this though. Anyone know what I'm doing wrong? Here's my code:
const fs = require('fs'),
path = require('path'),
Twit = require('twit'),
config = require(path.join(__dirname, 'config.js')),
images = require(path.join(__dirname, 'images.js'));
const T = new Twit(config);
function randomFromArray(images) {
return images[Math.floor(Math.random() * images.length)];
}
function tweetRandomImage() {
fs.readdir(__dirname + '/images', function (err, files) {
if (err) {
console.log('error:', err);
}
else {
let images = [];
files.forEach(function (f) {
images.push(f);
});
console.log('opening an image...');
const image = randomFromArray(images);
console.log(image);
const imagePath = path.join(__dirname, '/images' + image);
const imageSource = image.source
b64content = fs.readFileSync(imagePath, { encoding: 'base64' });
console.log('uploading an image...');
T.post('media/upload', { media_data: b64content }, function (err, data, response) {
if (err) {
console.log('error:', err);
}
else {
console.log('image uploaded, now tweeting it...');
T.post('statuses/update', {
media_ids: new Array(data.media_id_string)
},
function (err, data, response) {
if (err) {
console.log('error:', err);
}
else {
console.log('posted an image!');
}
}
);
}
});
}
});
}
setInterval(function () {
tweetRandomImage();
}, 10000);
Any help would be appreciated, thank you!
lesson of the day, ALWAYS WATCH THE SynTAx
const fs = require('fs'),
path = require('path'),
Twit = require('twit'),
config = require(path.join(__dirname, 'config.js')),
images = require(path.join(__dirname, 'images.js'));
const T = new Twit(config);
function randomFromArray(images) {
return images[Math.floor(Math.random() * images.length)];
}
function tweetRandomImage() {
fs.readdir(__dirname + '/images', function (err, files) {
if (err) {
console.log('error:', err);
}
else {
let images = [];
files.forEach(function (f) {
images.push(f);
});
console.log('opening an image...');
const image = randomFromArray(images);
console.log(image);
//THE ONLY CHANGE I MADE BELOW
const imagePath = path.join(__dirname, '/images/' + image);
//THE ONLY CHANGE I MADE ABOVE
//THE ONLY PROBLEM WAS THAT YOU TRIED GETTING A FILE BUT HAVING A FOLDER AND A FILE NAME AS 1 THING UNSEPARATED BY "/" OR "\\" AND THE COMPUTER(& me who read it at first) THOUGHT TO LOOK FOR A FILE CALLED "images15.jpg" instead of "images/15.jpg"
const imageSource = image.source
b64content = fs.readFileSync(imagePath, { encoding: 'base64' });
console.log('uploading an image...');
T.post('media/upload', { media_data: b64content }, function (err, data, response) {
if (err) {
console.log('error:', err);
}
else {
console.log('image uploaded, now tweeting it...');
T.post('statuses/update', {
media_ids: new Array(data.media_id_string)
},
function (err, data, response) {
if (err) {
console.log('error:', err);
}
else {
console.log('posted an image!');
}
}
);
}
});
}
});
}
setInterval(function () {
tweetRandomImage();
}, 10000);

Save audio file with fs.createWriteStream() always downloaded as corrupted file

I have a REST API that that save data from user and insert it to Firestore. From the REST API, user send link to download audio file from some URL and i need to download it to server.
The problem is, if i remove insert query firestore the audio file successfully downloaded. But if i use my query, the file downloaded as corrupted file without any error message in console.
const fs = require('fs'),
db = require('./../config/db'),
https = require('https');
const download = function(url, dest, cb) {
let file = fs.createWriteStream(dest);
https.get(url, function(response) {
response.pipe(file);
file.on('finish', function() {
file.close(cb);
});
}).on('error', function(err) {
fs.unlink(dest);
if (cb) cb(err.message);
});
};
// Insert to Firestore
db.collection('results')
.add(data)
.then(response => {
// Save data as JSON file
let obj = {
data: []
};
obj.data.push(data);
let json = JSON.stringify(obj);
let filename = __dirname + '/../public/json/' + response.id + '_' + dateTime + '.json';
fs.writeFile(filename, json, 'utf-8', function(err) {
if (err) {
console.error('Error writing JSON file: ', err);
}
});
// Download recording file
// var file = fs.createWriteStream(__dirname + '/../public/recording/' + response.id + '_' + dateTime + '.mp3');
// https.get(insert.recording, function(result) {
// result.pipe(file);
// });
download(url, __dirname + '/../public/recording/' + response.id + '_' + dateTime + '.mp3', err => {
console.error(err);
});
})
.catch(err => {
console.error(err);
});
Is the error because the download() is asynchronous?
download() is asynchronous function so you need to wrap in using Promise

Why is CreateReadStream not firing error event?

I am attempting to do some error handling for a csv file. When changing the name of the file to something that does not exists,
Error: ENOENT: no such file or directory, open 'testdat.csv' is displayed but the on error event is not fired.
Here is the current implementation:
const csv = require('csv-parser');
const fs = require('fs');
fs.createReadStream('testdat.csv')
.pipe(csv())
.on('open', () => {
})
.on('headers', (headers) => {
validateHeader(headers);
})
.on('data', (data) => {
temp.push(data);
})
.on('end', () => {
validateData(temp);
})
.on('error', (err) => {
console.log(err);
});
You need to attach the error event handler before piping.
const csv = require('csv-parser');
const fs = require('fs');
var readable = fs.createReadStream('testdat.csv');
readable.on('error', (err) => {
console.log(err);
});
// pipe function returns different stream
var writable = readable.pipe(csv())
writable.on('error', (err) => {
console.log(err);
});

Using nodejs archiver to download multiple google cloud storage files and zip them

I am trying to download files from google cloud storage and zip them.
async function makeZippedFiles(destination, all_file_links) {
console.log("In the zip file function");
for (let i in all_file_links) {
let name = all_file_links[i]['name']
let archive = archiver('zip', {
zlib: {level: 9} // Sets the compression level.
});
archive.on('error', function (err) {
throw err;
});
let output = fs.createWriteStream(__dirname + `/${name}.zip`);
console.log("loop number", i);
let sourceFile = all_file_links[i]['source'];
console.log(sourceFile, name);
let remoteFile = bucket.file(sourceFile);
let read_file = remoteFile.createReadStream();
await archive.append(read_file, {name: name});
read_file
.on('error', function (err) {
console.log(err);
})
.on('response', function (response) {
console.log("writing file", name);
// console.log(response);
// Server connected and responded with the specified status and headers.
})
.on('end', function () {
console.log("file downloaded", name);
// The file is fully downloaded.
})
archive.pipe(output);
archive.finalize();
}
}
In the example on top, I am looping through all files and creating individual archives. i.e., if I download two files, I would be creating two separate archives. This works.
However, if I want to zip all the files into one archive, I get the following error:
start of central directory not found; zipfile corrupt. (please
check that you have transferred or created the zipfile in the
appropriate BINARY mode and that you have compiled UnZip properly)
The code I used is:
async function makeZippedFiles(destination, all_file_links) {
console.log("In the zip file function");
let archive = archiver('zip', {
zlib: {level: 9} // Sets the compression level.
});
archive.on('error', function (err) {
throw err;
});
let output = fs.createWriteStream(__dirname + `/${destination}.zip`);
for (let i in all_file_links) {
let name = all_file_links[i]['name']
console.log("loop number", i);
let sourceFile = all_file_links[i]['source'];
console.log(sourceFile, name);
let remoteFile = bucket.file(sourceFile);
let read_file = remoteFile.createReadStream();
await archive.append(read_file, {name: name});
read_file
.on('error', function (err) {
console.log(err);
})
.on('response', function (response) {
console.log("writing file", name);
// console.log(response);
// Server connected and responded with the specified status and headers.
})
.on('end', function () {
console.log("file downloaded", name);
// The file is fully downloaded.
})
archive.pipe(output);
}
archive.finalize();
}
Found the solution. It was carelessness actually.
async function makeZippedFiles(destination, all_file_links) {
console.log("In the zip file function");
let archive = archiver('zip', {
zlib: {level: 9} // Sets the compression level.
});
archive.on('error', function (err) {
throw err;
});
let output = fs.createWriteStream(__dirname + `/${destination}.zip`);
archive.pipe(output);
for (let i in all_file_links) {
let name = all_file_links[i]['name']
console.log("loop number", i);
let sourceFile = all_file_links[i]['source'];
console.log(sourceFile, name);
let remoteFile = bucket.file(sourceFile);
let read_file = remoteFile.createReadStream();
await archive.append(read_file, {name: name});
read_file
.on('error', function (err) {
console.log(err);
})
.on('response', function (response) {
console.log("writing file", name);
// console.log(response);
// Server connected and responded with the specified status and headers.
})
.on('end', function () {
console.log("file downloaded", name);
// The file is fully downloaded.
})
}
archive.finalize();
}
I moved the archive.pipe(output) before the for loop and it works.

Resources