audiofile content changes when uploaded to google cloud storage - javascript

I'm uploading an MP3 file to google cloud storage then converting it to a WAV file and saving the result to cloud storage. The problem now is when i try to read the WAV file with scipy.io an error is thrown --> Unexpected end of file
i then converted my MP3 file locally and uploaded it to cloud storage and called it and opened it like i did with the other one and everything worked as expected.
After that i noticed despite the conversion was done with the same script, the two files have the same size and when opened by a media player they have same length and it seems there is no difference in the sound quality, but when converting them into strings and printing them in the console shows that they're not identical.
NOTES :
MP3 file uploaded to cloud using a html form and saved with type audio/mpeg
WAV file was converted using the following code and saved with type audio/Wav :
const remoteWriteStream =
storage.bucket(bucketName).file("path/to/file/file.wav")
.createWriteStream({
contentType: 'audio/wav'
})
ffmpeg(audioContent)
.withAudioChannels(1)
.toFormat('wav')
.on('error', (err) => {
console.log("error while conversion " + err)
reject(err)
})
.on('progress', (progress) => {
console.log("conversion in progress")
})
.on('end', () => {
console.log("conversion from mp3 to wav finished")
resolve()
})
.pipe(remoteWriteStream, { end: true })
code to convert file locally :
ffmpeg(mp3File)
.withAudioChannels(1)
.toFormat('wav')
.on('error', (err) => {
console.log("error while conversion " + err)
reject(err)
})
.on('progress', (progress) => {
console.log("conversion in progress")
})
.on('end', () => {
console.log("conversion from mp3 to wav finished")
resolve()
})
.save('path/to/save/file/file.wav')
Conversion is done with JavaScript in both cases and calling and opening the waV file is done with python
code to call and open WAV file from cloud :
wavBucketFileBlob = bucket.get_blob('path/to/file/in/cloud/file.wav')
wavBucketFileString = wavBucketFileBlob.download_as_string()
rate,audio = wavfile.read(io.BytesIO(wavBucketFileString))
**EDIT : **
I think the problem is in the header :
wav file that can't be read (saved in the cloud as audio/wav) :
b'RIFF$\x01A\x01WAVEfmt \x10\x00\x00\x00\x01\x00\x01\x00D\xac\x00\x00\x88X\x01\x00\x02\x00\x10\x00LIST\xf8\x00\x00\x00INFOIART\n\x00\x00\x00Cat Power\x00ICMT6\x00\x00\x00https://open.spotify.com/track/2ilo3w0stilJKeQZS61FeN\x00ICOP\x1d\x00\x00\x002018 Domino Recording Co Ltd\x00\x00ICRD\x05\x00\x00\x002018\x00\x00IGNR\x08\x00\x00\x00Art Pop\x00INAM\x05\x00\x00\x00Stay\x00\x00IPRD\t\x00\x00\x00Wanderer\x00\x00IPRT\x05\x00\x00\x006/11\x00\x00ISFT\x0e\x00\x00\x00Lavf58.24.100\x00ITCH\x14\x00\x00\x00Domino Recording Co\x00data\x00\x00A\x01\x00\
wav file that can be read (saved in the cloud automatically when uploaded as audio/x-wav):
b'RIFF\xff\xff\xff\xffWAVEfmt \x10\x00\x00\x00\x01\x00\x01\x00D\xac\x00\x00\x88X\x01\x00\x02\x00\x10\x00LIST\xf8\x00\x00\x00INFOIART\n\x00\x00\x00Cat Power\x00ICMT6\x00\x00\x00https://open.spotify.com/track/2ilo3w0stilJKeQZS61FeN\x00ICOP\x1d\x00\x00\x002018 Domino Recording Co Ltd\x00\x00ICRD\x05\x00\x00\x002018\x00\x00IGNR\x08\x00\x00\x00Art Pop\x00INAM\x05\x00\x00\x00Stay\x00\x00IPRD\t\x00\x00\x00Wanderer\x00\x00IPRT\x05\x00\x00\x006/11\x00\x00ISFT\x0e\x00\x00\x00Lavf58.24.100\x00ITCH\x14\x00\x00\x00Domino Recording Co\x00data\xff\xff\xff\xff\
I tried when converting my mp3 to wav to save it as audio/x-wav since that seems to work but that was not the case.. i was still having the same problem.
My workaround :
I was using scipy.io to open read the wav file so i switched to soundfile which solved my problem but with a downside --> the quality of my output after doing further processing seems to be lower (but not really noticeable) than when i use scipy.io

Related

Trying to get a stream link of a video file from GDRIVE API

I'm trying to get a stream link for my video files to stream it on my web app from google drive api, but its not working properly. I have double checked the docs for any errors in syntax and i can't seem to find any.
for context here is my code:
`
drive.files.get({fileId: myfileId,alt: 'media'},{responseType: 'stream'}, (err, res) => {
if (err) return console.log(`The API returned an error: ${err}`);
console.log(res)
});
`
I'm getting a passthrough object in res.data field and its giving an error of "Unknown output format: 'media' ". The file i'm trying to stream is a .mp4 file.
I have also double checked my authentication and its working fine because i was able to retrieve my folder id and file id using the api.
Am i doing anything wrong here? Any help would be appreciated.
THANKS.
Once you have authenticated the client library, you can use the following code to get a stream link for a video file stored in Google Drive
// Replace fileId with the ID of the video file you want to stream
const fileId = '1234567890';
// Get the file from Google Drive
const file = await drive.files.get({ fileId, alt: 'media' });
// Get the stream link for the file
const streamLink = file.data;

Function stops without any logs in firebase (sometimes works well.. sometimes partly) - confused

Can you please share your thoughts or experience why this can happen:
I have a folder on firebase cloud with a bunch of images (jpeg, png). It can contain from 2 to 40+ files. After uploading the files from the client is complete, a request is sent to the firebase initiating resizing function of these new images.
Resizing should work as:
uploading every file to tmpFilePath (for (const file of files) loop is used)
resizing the files in tmpFilePath (I tried spawn and sharp, and sharp seems to be more stable)
downloading the resized file back to the folder.
The problem is that the function doesn't work from time to time. Sometimes it stops at the step of downloading to tmpFilePath with no logs. After re-initiating, it can proceed a couple of files and stop again. Sometimes it works well. I thought the file size matters, but again, the same folder with the same files can work ok after several initiations.. Confused. Is it specific to firebase functions?
This is a short version of the code:
for (const file of files) {
console.log(`${file} before downloading to tempFolder`)
await destBucket.file(filePath).download({
destination: tmpFilePath
})
.catch((err) => console.log(err))
.then(() => {
console.log(`${file} before sharp`)
return sharp (tmpFilePath, { failOnError: false })
.resize(resizedW, resizedH)
.toFile (afterSharpPath)
.then(() => {
console.log(`${file} before uploading back`)
return destBucket.upload(afterSharpPath, {
destination: filePath,
contentType: orType,
metadata: {metadata: newMetadata},
bucket: bucket,
})
} } }
Anyone have an idea how this can be done?

Writing a Text to Speech file as an MP3 - IBM Watson

I'm following the documentation for the Node.JS implementation of the IBM Watson Text-to-Speech API.
I want to output the resultant file into MP3 format. The documentation recommends augmenting the base code but I'm not sure how to do that. My code is rendering unplayable MP3s.
Here is what it says in the documentation:
textToSpeech.synthesize(synthesizeParams)
.then(response => {
// The following line is necessary only for
// wav formats; otherwise, `response.result`
// can be directly piped to a file.
return textToSpeech.repairWavHeaderStream(response.result);
})
.then(buffer => {
fs.writeFileSync('hello_world.wav', buffer);
})
.catch(err => {
console.log('error:', err);
});
As it says, response.result should be directly piped to a file. This is one of my many attempts (that renders an error).
textToSpeech
.synthesize(synthesizeParams)
.then(response => {
fs.writeFileSync('Hello.mp3', response.result)
})
.catch(err => {
console.log('error:', err)
})
How can I output the text-to-speech input as an MP3?
Provided your params are requesting an mp3 file, this will be the accept parameter, then your code looks ok. So if the output file isn't being recognised as an audio, then it is most likely a text file containing an error message. This error message will indicate what is wrong, which most likely will be an unauthorised message.
I take it that your catch error block isn't logging anything.

firebase storage : Error: storage/unknown No content provider

I would like to put a simple jpg in the firebase storage.
I can return a file ok but not to push a simple file.
I use an android emulator for my test.
my function
const uri = http://...:8081/assets/src/assets/images.jpg?platform=android&hash=131a57e2363da7e4dada04c4f2d34f85
return new Promise((resolve, reject) => {
storage()
.ref('/images/test.jpg')
.putFile(uri )
.then((snapshot) => {
console.log('test.jpg has been successfully uploaded.');
resolve()
})
.catch((e) => {
console.log('uploading image error => ', e)
reject()
});
})
my error
Error: [storage/unknown] No content provider: http://....:8081/assets/src/assets/images.jpg?platform=android&hash=131a57e2363da7e4dada04c4f2d34f85
You can upload files to Cloud Storage from Firebase from three types of sources:
From data that you have in memory as a byte array.
From data that you have in memory as a string.
From a file that you have on the local disk of your device.
What you are trying to do is upload data from a URL, which is not one of the supported options. If you want to store the image from that URL in Firebase, you will have to download the data from the URL to your local device, and then upload it from there.

How to add an album cover to an mp3 stream using FFmpeg?

I'm having a bit of an issue and I'd really appreciate it if I could get some insights.
What I am trying to do is to add an album cover to the mp3 file that will be downloaded from the front-end.
Context
I'm downloading a video stream from YouTube and converting it to mp3 using fluent-ffmpeg.
To get the video I use the ytdl npm module.
I then pipe this stream to the front-end.
What I've found
fluent-ffmpeg offers either pipe() or saveToFile().
What I figured is that when I use the saveToFile() function and actually save my stream into an mp3 file, it works, I do get the album cover.
But when I pipe the stream to front-end or even into a file, the song is saved properly into a file but without the album cover.
Here is my code
Back-end (NodeJS)
let video = ytdl(`http://youtube.com/watch?v=${videoId}`, {
filter: (format) => format.container === 'mp4' && format.audioEncoding,
quality: 'lowest'
});
let stream = new FFmpeg()
.input(video)
.addInput(`https://i.ytimg.com/vi/${videoId}/default.jpg`)
.outputOptions([
'-map 0:1',
'-map 1:0',
'-c copy',
'-c:a libmp3lame',
'-id3v2_version 3',
'-metadata:s:v title="Album cover"',
'-metadata:s:v comment="Cover (front)"'
])
.format('mp3');
And then piping it to my front-end.
stream.pipe(res);
stream
.on('end', () => {
console.log('******* Stream end *******');
res.end.bind(res);
})
.on('error', (err) => {
console.log('ERR', err);
res.status(500).end.bind(res);
});
Front-end (React)
axios.get(url)
.then(res => {
axios(`${url}/download`, {
method: 'GET',
responseType: 'blob'
})
.then(stream => {
const file = new Blob(
[stream.data],
{ type: 'audio/mpeg' });
//Build a URL from the file
const fileURL = URL.createObjectURL(file);
})
.catch(err => {
console.log('ERROR', err);
});
})
.catch(err => {
console.log('ERROR', err);
});
Unfortunately, it seems there is no possible solution to complete this task with streams. I've researched a lot but found only an explanation of why we can't do this with FFmpeg and piping stream. njoyard wrote the following:
Actually this problem is not specific to Windows. Most formats write
stream information (duration, bitrate, keyframe position...) at the
beginning of the file, and thus ffmpeg can only write this information
when its output is seekable (because it has to finish processing
streams to the end before knowing what to write). Pipes are not
seekable, so you won't get this information when using an output pipe.
As for your note about the output format, ffmpeg determines the output
format from the output file extension, which is not possible with
pipes; that's why you have to specify the output format explicitly.
Here is a link to find it by yourself: https://github.com/fluent-ffmpeg/node-fluent-ffmpeg/issues/159
So, the only solution I see is saving file with saveToFile() method and attaching it to response.

Categories

Resources