Seeking on chrome audio player not working - node.js

I am trying to read a music from my backend on chrome / firefox/a ionic projet.
I cant click the timeline to chose a time I want to go to when I'm listening on google chrome or ionic music player. The music just restart from 00:00 when I do so . I tried doing a request from postman and it could read the music correctly and set the time I wanted when I clicked the timeline , same on firefox (its working correctly). However it does not work on chrome, as I said the music just restart when you click the timeline. Here is my backend route :
EDIT1 : my only hint is when I use howler.js as my player, if I pass the HTML5= true its not gonna work and if I dont put it its working, even if its open on chrome... (https://www.npmjs.com/package/howler) or maybe a header is missing ?
getMusic(req, res) {
try {
var trackID = new ObjectID(req.params.trackID);
} catch (err) {
return res.status(400).json({ message: "Invalid trackID in URL parameter. Must be a single String of 12 bytes or a string of 24 hex characters" });
}
res.set('content-type', 'audio/mpeg');
res.set('accept-ranges', 'bytes');
let bucket = new mongodb.GridFSBucket(db, {
bucketName: 'tracks'
});
let downloadStream = bucket.openDownloadStream(trackID);
downloadStream.on('data', (chunk) => {
res.write(chunk);
});
downloadStream.on('error', () => {
res.sendStatus(404);
});
downloadStream.on('end', () => {
res.end();
});
},

The "Content-length" header was missing on this code and after trying it with a dummy it works. I just need to find how to get the music length now, so I close this post.
example res.set('content-length', '5000000');

Related

Passing data from opened window

I've been stuck on this problem for a day now and was wondering if there's a way I could go about this.
client side
Client side is going to be dynamic since it's an app type plugin.
The client side will open up a popup for oAuth purposes. Let's say its domain is www.google.com
I have the popup written like window.open('www.backend.com/api') in ReactJS.
The client button is something like this:
<button onClick={() => iveBeenClicked()}> sync up </button>
and then it runs this function
const iveBeenClicked = (e) => {
e.preventDefault()
const popupWindow = window.open('www.backend.com/api', "_blank")
}
oAuth and backend with ExpressJS
This is the backend which we'll say is www.backend.com/api
router.use("/api", (req, res) => {
if (req.query.code) {
res.send(res.query.code)
} else {
res.redirect(
`www.ApiRouteThatRedirectsWhenComplete.com`
);
}
});
Well I have the code I want, but how can I send that to the client from a different domain? If there's an alternative to window.open() where a user could press accept, please let me know.
So the big question is, how can client receive data from window.open's popup?
Thank you in advance!
#EDIT
So I finally got it thanks to #vishal-bartakke 's suggestion which I realized I implemented it wrong. I'm going to supply it here just in case it will help anyone that comes across this post.
for the ivebeenclicked() function in client side:
const iveBeenClicked = (e) => {
e.preventDefault()
const popupWindow = window.open('www.backend.com/api', "_blank")
//this is the part that was needed to receive the information of success
window.addEventListener('message', (e) => {
if (e.data) {
//do what you need to do with that key
}
})
}
in my expressjs's file:
router.use(['/api/', '/api/page?'], (req, res) => {
if (req.query.token) {
res.sendFile(path.join(__dirname +'/thatHTMLpage.html'))
} else {
res.redirect(`that route that does the oauth`)
}
})
In that html created upon success, I added this code to send in the data
window.onload = function () {
let urlParams = new URLSearchParams(window.location.search);
window.opener.postMessage(urlParams.get("code"), "*");
};
It is quite a messy setup but it works how I want it.
Thanks!
You can use postMessage (check here) to communicate between windows. In child window you can refer parent window as window.opener for posting message and in parent window you have popupWindow for posting

Using res.download()

I have a route that goes like this:
exports.downloadFile = app => {
app.get('/install/download', (request, result) => {
result.download(`${__dirname}../../../public/exec/install.exe`, error => {
if (error) console.log("[FAILURE][RESOURCE] Could not download installation file\r\n");
else console.log("[SUCCESS][RESOURCE] Installation file has been downloaded\r\n");
});
});
}
With this route, I am trying to make it that when I click on a button this file is downloaded. When I click the button I get a message indicating SUCCESS, but my browser makes no indication of any download and does not prompt me to do anything. Is there some additional component I need to add to make sure it works?
This is the code on my client side to do the fetching:
const downloadFile = () => {
const url = `${window.location.protocol}//${window.location.host}/install/download`;
fetch(url)
.catch(error => alertMessage(error.message));
}
I am assuming it might have to do with me having no .then to handle the fetch, but I am not sure what I should be adding there and I am under the impression from the documentation that the browser automatically handles this part?
You forget to pass one download name argument.
Please modify download function as below.
result.download(`${__dirname}../../../public/exec/install.exe`, 'install.exe', error => {
if (error) console.log("[FAILURE][RESOURCE] Could not download installation file\r\n");
else console.log("[SUCCESS][RESOURCE] Installation file has been downloaded\r\n");
});

Display video from Gridfs storage in react app

I am using multer-gridfs-storage and gridfs-stream to store my video in the backend (Express/Node). When I try to retrieve the file to play on my front end (React) the player refuses to recognize the source.
I am using Video-React to display the video on download. The download is successful, I get a Binary string back from the backend, which I converted to a Blob.
try{
fileBlob = new Blob([res.data], {type : res.headers['content-type']});
}catch(err){
console.log('Error converting to blob');
console.log(err);
}
This is my Video-React player being rendered
<Player
autoPlay
ref="player"
>
<source src={this.state.fileURL} />
<ControlBar autoHide={false} />
</Player>
Then I tried two techniques
readDataAsURL
let reader = new FileReader();
reader.onload = function(event){
//rThis is just a reference to the parent function this
rThis.setState({fileURL: reader.result}, () => {
rThis.refs.player.load();
});
}
try{
reader.readAsDataURL(fileBlob);
}catch(err){
console.log('Error trying readDataURL');
console.log(err);
}
src is being set correctly but the video never loads
URL.createObjectURL
let vidURL = URL.createObjectURL(fileBlob);
rThis.setState({fileURL: vidURL}, () => {
rThis.refs.player.load();
});
src is set to a blob: url but still nothing
Is this an issue with Video-react or should I be doing something else? Any pointers to references I could look at will also help. What am I doing wrong? dataURL works in the case of images, I checked, but not video.
So after some more reading, I finally figured out the problem. Since I'm using gridfs-stream I'm actually piping the response from the server. So I was never getting the whole file, and trying to convert res.data, which is just a chunk, was a mistake. Instead, in my res object, I found the source url within the config property.
res.config.url
This contained my source url to which my server was piping the chunks. Should have figured it out earlier, considering I picked GridFS storage for precisely this reason.

Send an image as the body of a request, image recived with a request from outside

Yeah i kinda didn't know how to type the title well...
I've a node server which recives an image via post form. I then want to send this image to Microsoft vision and the same Google service in order to gether information from both, do some stuff, and return a result to the user that has accessed my server.
My problem is: how do i send the actual data?
This is the actual code that cares of that:
const microsofComputerVision = require("microsoft-computer-vision");
module.exports = function(req, res)
{
var file;
if(req.files)
{
file = req.files.file;
// Everything went fine
microsofComputerVision.analyzeImage(
{
"Ocp-Apim-Subscription-Key": vision_key,
"content-type": "multipart/form-data",
"body": file.data.toString(),
"visual-features":"Tags, Faces",
"request-origin":"westcentralus"
}).then((result) =>
{
console.log("A");
res.write(result);
res.end();
}).catch((err)=>
{
console.log(err);
res.writeHead(400, {'Content-Type': 'application/json'});
res.write(JSON.stringify({error: "The request must contain an image"}));
res.end();
});
}
else
{
res.writeHead(400, {'Content-Type': 'application/octet-stream'});
res.write(JSON.stringify({error: "The request must contain an image"}));
res.end();
}
}
If instead of calling "analyzeImage" i do the following
res.set('Content-Type', 'image/jpg')
res.send(file.data);
res.end();
The browser renders the image correctly, which made me think "file.data" contains the actual file (considered it's of type buffer).
But apparently Microsoft does not agree with that, because when i send the request to computer vision i get the following response:
"InvalidImageFormat"
The only examples i found are here, and the "data" that is used in that example comes from a file system read, not stright from a request. But saving the file to load it and then delete it to me looks like an horrible workaround, so i'd rather like to know in what form and how should i work on the "file" that i have to send it correctly for the APIs call.
Edit: if i use file.data (which i thought was the most correct since it would be sending the raw image as the body) i get an error which says that i must use a string or a buffer as content. So apparently that file.data is not a buffer in the way "body" requires O.o i'm not understanding honestly.
Solved, the error was quite stupid. In the "then" part, res.write(result) did not accept result as argument. This happened when i actually used the corret request (file.data which is a buffer). The other errors occurred everytime i tryed using toString() on file.data, in that case the request wasn't accepted.
Solved, the request asked for a buffer, and file.data is indeed a buffer. After chacking file.data type in any possible way i started looking for other problems. The error was much easier and, forgive my being stupid, too stupid to be evident. The result was a json, and res.write didn't accept a json as argument.
This is how I did it with Amazon Recognition Image Classifier, I know its not the same service your using - hoping this helps a little thou:
const imagePath = `./bat.jpg`;
const bitmap = fs.readFileSync(imagePath);
const params = {
Image: { Bytes: bitmap },
MaxLabels: 10,
MinConfidence: 50.0
};
route.post('/', upload.single('image'), (req, res) => {
let params = getImage();
rekognition.detectLabels(params, function(err, data) {
if (err) {
console.log('error');
}else {
console.log(data);
res.json(data);
}
});
});

Failing to get a response back from a web api call in node

this particular Node issue has been driving me crazy for going on a week.
I have to create a layer of friction (a modal that asks the user if they're sure) in the process of a csv file upload. Essentially, the flow will be:
User Clicks 'UPLOAD SPREAD SHEET' > File uploads to s3 > S3 returns a reference key > Pass reference key into micro service web api to evaluate > if true => ask user 'if they're sure' > If user is sure continue uploading > pass reference key onward to another endpoint, same service, to finish the upload. false return would continue on to the upload with no modal.
its kind of a silly product-based functionality that makes a show of alerting the user to potential duplicate entries in their spreadsheet since we can't currently detect duplicate entries ourselves.
Problem is, I can't get a response to return from the evaluation to save my life. If I console.log the response, I can see it in Node's terminal window but nothing comes back in the network tab for the response. I'm not sure if it's because it's a file upload, if it's busyboy, if it's just not the right syntax for the response type but endless googling has brought me no answers and I'd love it if someone more experienced with Node and Express could take a look.
router.post('/import/csv',
// a bunch of aws s3 stuff to upload the file and return the key
s3.upload(uploadParams, (err, data) => {
if (err) {
res.status(500).send({
error_message: 'Unable to upload csv. Please try again.',
error_data: err
});
} else if (data) {
// creating the key object to pass in
const defaultImportCheck = {
body: data.Key
};
// endpoint that will evaluate the s3 reference key
SvcWebApiClient.guestGroup.defaultImportCheck(defaultImportCheck)
.then((response) => {
if (response.status === 'success') {
// where the response should be. this works but doesn't actually send anything.
res.send(response);
} else {
const errorJson = {
message: response.message,
category: response.category,
trigger: response.trigger,
errors: response.errors
};
res.status(500).send(errorJson);
}
})
.catch((error) => {
res.status(500).send({
error_message: 'Unable to upload csv. Please try again.',
error_data: error
});
});
}
});
});
req.pipe(busboy);
}
);
Got it, for anyone that ends up having my kind of problem. It's a two parter so buckle up.
1) the action function that handles the response on the react side didn't convert the response into json. Apparently, what would get returned is a "readable stream" which should have then converted to json. it didn't.
2) the response itself needed to be in json as well.
so from the action function:
export function csvUpload(file) {
do some stuff
return fetch(fetch some stuff) { with some parameters }
.then(some error stuff)
.then(response => response.response.json())
}
then from the post request:
if (response.status === "success") {
res.json({ valid: response.data, token: data.Key)};
}
this returns an object with what I need back to the client. hope this helps someone else.

Resources