I am new to java and javascript programing.
I was able to write a piece of code in java to access a particular URL and download the wav file from that URL (this url returns a wav file).
url = new URL('url name');
input = url.openStream();
output = new FileOutputStream (wavfile);
byte[] buffer = new byte[500];
int bytesRead = 0;
while ((bytesRead = input.read(buffer, 0, buffer.length)) >= 0) {
output.write(buffer, 0, bytesRead);
}
output.close();
I do not want to do this in Java and want to be able to do it in Javascript. The main attempt is to use javascript and get the wav file and play it on a HTML5 enabled browser.
I eventually want to put it on an android platform, so do not prefer to use ajax or jquery.
Please suggest how this can be done in javascript.
Thanks,
axs
You couldn't use JavaScript to read files but HTML5 has a File API, take a look at:
http://dev.w3.org/2006/webapi/FileAPI/
READING FILES IN JAVASCRIPT USING THE FILE APIS
export async function loadWavFromUrl(audioContext, url) {
const response = await fetch(url);
const blob = await response.blob()
const arrayBuffer = await blob.arrayBuffer();
return await audioContext.decodeAudioData(arrayBuffer);
}
I recommend reusing AudioContext instances, which is why there is a param for it. You can call like this:
const ac = new AudioContext();
loadWavFromUrl(audioContext, url).then(audioBuffer => ...do stuff with it...);
The OP is maybe confused about reusing Javascript code in Java/Android. The code will be different.
Related
I am developing a small web-application with a threejs Renderer where I want to be able to store some screenshots to my local filesystem at a specific location. Rendering the images and creating the snapshots works, only the storage/download part gives me headache.
I create the snapshot this way:
let imageData = renderer.domElement.toDataURL('image/png');
console.log(imageData); // data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABFAAAANBC...
Now to download this, there are several methods: window.location.href = imageData;does trigger a download (and several alert messages from the browser). But the downloaded image is stored as a file called download inside the Download-Folder. If added the File-Extension .png it can be opened. This is not a useful solution, several downloads in a row will hardly be assigned.
So another working method is to build a download-link and trigger its click-method:
let a_element = document.createElement('a');
a_element.setAttribute('href', imageData.replace('image/png', 'image/octet-stream');
a_element.setAttribute('download', 'screenshot.png');
a_element.style.display = 'none';
document.body.appendChild(a_element);
a_element.click();
document.body.removeChild(a_element);
This does download the screenshot with a custom-name to the Download folder, it's almost what I want, but i'd like to have them stored in a custom folder as well. That's where the Filesystem-API comes in. The drawback is, that every download has to be confirmed, but not having to move the files manually from the download folder would pay off for that.
const options = {
types: [
{
description: 'Images',
accept: {
'image/png': ['.png'],
},
},
],
suggestedName: 'Screenshot.png',
};
imgFileHandle = await window.showSaveFilePicker(options);
console.log("Save File chosen");
const writable = await imgFileHandle.createWritable();
await writable.write(imageData);
await writable.close();
This seems to work, but the file that is stored is not a valid image. It contains only Text (same as the output of the console). How should I treat the imageData to download it as an image ?
For the File System Access API, you're almost there, but instead of a data URL, you need to provide the data as a blob. To create a blob from a data URL, you can use the code below:
function dataURItoBlob(dataURI) {
const byteString = atob(dataURI.split(',')[1]);
const mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0]
const ab = new ArrayBuffer(byteString.length);
const ia = new Uint8Array(ab);
for (let i = 0; i < byteString.length; i++) {
ia[i] = byteString.charCodeAt(i);
}
const blob = new Blob([ab], {type: mimeString});
return blob;
}
It may be easier to get the Blob directly, via the toBlob() method. This should work in Three.js as well, since renderer.domElement is a CanvasElement.
I am trying to download an excel file and then upload it to Azure Blob Storage for use in Azure Data Factory. I have a playwright javascript that worked when the file was a .csv but when I try the same code with an excel file, it will not open in Excel. It says,
"We found a problem with some content in 'order_copy.xlsx'. Do you want us to try to recover as much as we can?:
After clicking yes, it says,
"Excel cannot open the file 'order_copy.xlsx' because the file format or file extension is not valid. Verify that the file has not been corrupted and that the file extension matches the format of the file."
Any ideas on how to use the createReadStream more effectively to do this and preserve the .xlsx format?
I don't think the saveAs method will work since this code is being executed in an Azure Function with no access to a local known path.
My first thought was the content type was not right, so I set that, but it still did not work. I tried a UTF-8 encoder but that also did not work.
//const data = await streamToText(download_csv.createReadStream())
const download_reader = await download_csv.createReadStream();
let data = '';
for await (const chunk of download_reader) {
data += chunk; //---I suspect I need to do something different here
}
// const data_utf8 = utf8.encode(data) //unescape( encodeURIComponent(data) );
const AZURE_STORAGE_CONNECTION_STRING = "..." //---Removed string here
// Create the BlobServiceClient object which will be used to create a container client
const blob_service_client = BlobServiceClient.fromConnectionString(AZURE_STORAGE_CONNECTION_STRING);
// Get a reference to a container
const container_client = blob_service_client.getContainerClient('order');
const blob_name = 'order_copy.xlsx';
// Get a block blob client
const block_blob_client = container_client.getBlockBlobClient(blob_name);
const contentType = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
const blobOptions = { blobHTTPHeaders: { blobContentType: contentType } };
//const uploadBlobResponse = await block_blob_client.upload(data_utf8, data_utf8.length, blobOptions);
const uploadBlobResponse = await block_blob_client.upload(data, data.length, blobOptions);
console.log("Blob was uploaded successfully. requestId: ", uploadBlobResponse.requestId);
Any guidance would be appreciated. Thank you in advance for your help!
-Chad
Thanks #Gaurav for the suggestion on not setting the data to a string. The following code worked after I changed to using a array of the chunks and concatenated it using the Buffer similar to your suggested code.
let chunks = []
for await (const chunk of download_reader) {
chunks.push(chunk)
}
const fileBuffer = Buffer.concat(chunks)
...
const uploadBlobResponse = await block_blob_client.upload(fileBuffer, fileBuffer.length, blobOptions);
Thanks everyone!
I made this picture that explains what I'm trying to achieve.
Brief summary: I want users to be able to upload an encrypted video that only those which have the password will be able to see as a stream.
The point of all this is for the server to not be able to decipher it.
What I managed to do at the moment is only the first part, encrypting the chunks and sending them :
fileInput.addEventListener("change", async () => {
const file = fileInput.files[0]
const stream = file.stream()
const reader = stream.getReader()
while(true) {
const {value, done} = await reader.read()
if(done) break
handleChunk(value)
}
const out = {
size: file.size,
type: file.type,
encryptedStream: encryptedStream
}
})
function handleChunk(chunk) { // chunk: Uint8Array
const parsedChunk = CryptoJS.enc.Utf8.parse(chunk)
encryptedStream.push(CryptoJS.AES.encrypt(parsedChunk, "encryptionKey").toString())
}
I guess you can also do this with File.slice() but I did not test it.
At this point I feel like I've looked into every API related to files/streams both in Node and in vanilla js but I can't find a way to make this work, all I've managed is to make a Readable out of the encryptedStream array in the backend.
const Readable = require("stream").Readable
let readable = new Readable()
encryptedStream.forEach(aesChunk => readable.push(aesChunk))
readable.push(null)
I have doubts on how to stream it back to another frontend and literally no idea on how to play the video after deciphering it.
From what I've looked online, it looks like it's not possible to stream a crypted file, only to download it.
Is this possible to do ?
imagine i have a video file and i want to build a blob URL from that file then play it in a html page, so far i tried this but i could not make it work ...
var files = URL.createObjectURL(new Blob([someVideoFile], {type: "video/mp4"}));
document.getElementById(videoId).setAttribute("src", files);//video tag id
document.getElementById(videoPlayer).load();//this is source tag id
document.getElementById(videoPlayer).play();//this is source tag id
it gives me a blob URL but wont play the video... am i doing something wrong? i am pretty new to electron so excuse me if my code is not good enough
i saw the similar questions mentioned in comments but they dont work for me as they dont work for others in those pages....
I know this is an old question, but it still deserves a working answer.
In order to play a video in the renderer context, you're on the right track: you can use a blob url and assign it as the video source. Except, a local filepath is not a valid url, which is why your current code doesn't work.
Unfortunately, in electron, currently there are only 3 ways to generate a blob from a file in the renderer context:
Have the user drag it into the window, and use the drag-and-drop API
Have the user select it via a file input: <input type="file">
Read the entire file with the 'fs' module, and generate a Blob from it
The third option (the only one without user input) can be done as long as nodeIntegration is enabled or if it is done in a non-sandboxed preloader. For accomplishing this via streaming vs. loading the entire file at once, the following module can be used:
// fileblob.js
const fs = require('fs');
// convert system file into blob
function fileToBlob(path, {bufferSize=64*1024, mimeType='aplication/octet-stream'}={}) {
return new Promise((resolve,reject) => {
// create incoming stream from file
const stream = fs.createReadStream(path, {highWaterMark:bufferSize});
// initialize empty blob
var blob = new Blob([], {type:mimeType});
stream.on('data', buffer => {
// append each chunk to blob by building new blob concatenating new chunk
blob = new Blob([blob, buffer], {type:mimeType});
});
stream.on('close', () => {
// resolve with resulting blob
resolve(blob);
});
});
}
// convert blob into system file
function blobToFile(blob,path, {bufferSize=64*1024}={}) {
return new Promise((resolve,reject) => {
// create outgoing stream to file
const stream = fs.createWriteStream(path);
stream.on('ready', async () => {
// iterate chunks at a time
for(let i=0; i<blob.size; i+=bufferSize) {
// read chunk
let slice = await blob.slice(i, i+bufferSize).arrayBuffer();
// write chunk
if(!stream.write(new Uint8Array(slice))) {
// wait for next drain event
await new Promise(resolve => stream.once('drain', resolve));
}
}
// close file and resolve
stream.on('close', () => resolve());
stream.close();
});
});
}
module.exports = {
fileToBlob,
blobToFile,
};
Then, in a preloader or the main context with nodeIntegration enabled, something like the following would load the file into a blob and use it for the video player:
const {fileToBlob} = require('./fileblob');
fileToBlob("E:/nodeJs/test/app/downloads/clips/test.mp4", {mimeType:"video/mp4"}).then(blob => {
var url = URL.createObjectURL(blob);
document.getElementById(videoId).setAttribute("src", url);
document.getElementById(videoPlayer).load();
document.getElementById(videoPlayer).play();
});
Again, unfortunately this is slow for large files. We're still waiting for a better solution from electron:
https://github.com/electron/electron/issues/749
https://github.com/electron/electron/issues/35629
Try
video.src = window.URL.createObjectURL(vid);
For more details please refer to this answer
What I'm trying to achieve is to make Chrome load a video file as data (via the Fetch API, XHR, whatever) and to play it using <video> while it's still being downloaded without issuing two separate requests for the same URL and without waiting until the file is completely downloaded.
It's easy to get a ReadableStream from the Fetch API (response.body), yet I can't find a way to feed it into the video element. I've figured out I need a blob URL for this, which can be created using a MediaSource object. However, the SourceBuffer#appendStream method, which sounds like just what is needed, isn't implemented in Chrome, so I can't connect the stream directly to the MediaSource object.
I can probably read the stream in chunks, create Uint8Arrays out of them, and use SourceBuffer#appendBuffer, but this means playback won't start immediately unless the chunk size is really small. Also it feels like manually doing something that all these APIs should be able to do out of the box. If there is no other solutions, and I go this way, what caveats should I expect?
Are there probably other ways to create a blob URL for a ReadableStream? Or is there a way to make fetch and <video> share a request? There are so many new APIs that I could easily miss something.
After hours of experimenting, found a half-working solution:
const video = document.getElementById('audio');
const mediaSource = new MediaSource();
video.src = window.URL.createObjectURL(mediaSource);
mediaSource.addEventListener('sourceopen', async () => {
const sourceBuffer = mediaSource.addSourceBuffer('audio/webm; codecs="opus"');
const response = await fetch(audioSRC);
const body = response.body
const reader = body.getReader()
let streamNotDone = true;
while (streamNotDone) {
const {value, done} = await reader.read();
if (done) {streamNotDone = false; break;}
await new Promise((resolve, reject) => {
sourceBuffer.appendBuffer(value)
sourceBuffer.onupdateend = (() => {
resolve(true);
})
})
}
});
It works with https://developer.mozilla.org/en-US/docs/Web/API/MediaSource
Also, I tested this only with webm/opus format but I believe it should work with other formats as well as long as you specify it.