I am trying to develop a small application in which I first capture screen via aperture
package and then try to show it in the screen using video
tag.
I capture screen via:
import apertureConstructor from 'aperture';
const aperture = apertureConstructor();
const options = {
fps: 30
};
(async () => {
await aperture.startRecording(options);
setTimeout(async () => {
this.captureUrl = await aperture.stopRecording();
}, 3000)
})();
Please ignore the mess. Aperture
package writes captured video to disk and eventually, I have the path to this file in captureUrl
. It is something like this:
/var/folders/29/08gshk3n4mlbbcjnm1m5xyy40000gp/T/tmp-79999m0uOszQK0zaC.mp4
I can verify that this file exists and plays just fine, if I type: file:///var/folders/29/08gshk3n4mlbbcjnm1m5xyy40000gp/T/tmp-79999m0uOszQK0zaC.mp4
to Google Chrome address bar.
So I try to use this address as the source of my video
tag like this:
<video control autoplay>
<source src="/var/folders/29/08gshk3n4mlbbcjnm1m5xyy40000gp/T/tmp-8004145a2o4gugbVV.mp4" type="video/mp4">
</video>
Which complains that file is not there (404):
GET http://localhost:9080/var/folders/29/08gshk3n4mlbbcjnm1m5xyy40000gp/T/tmp-8004145a2o4gugbVV.mp4 404 (Not Found)
And yes, it indeed tries to go to localhost:9080
because in this case it is my development server host and there is no such a file.
So I decide to add file://
...
<video controls autoplay>
<source src="file:///var/folders/29/08gshk3n4mlbbcjnm1m5xyy40000gp/T/tmp-8004145a2o4gugbVV.mp4" type="video/mp4">
</video>
This time it says:
Not allowed to load local resource: file:///var/folders/29/08gshk3n4mlbbcjnm1m5xyy40000gp/T/tmp-80041e3SlBZUNphLM.mp4
:/
I wonder if I missed something that makes "file://" secure or something else.
I also thought about reading the whole file via "fs" and base64'ing it providing video as data:
but as this video file might be large, I feel like I shouldn't go that way.
As I am new to electron
I hope I miss something basic. Any help is appreciated. Thanks!
Since there is already an accepted answer, I will just tell you how I solved this for people that may encounter the same problem.
At this time there is a way to do this by using protocol, even if you specify
webPreferences: {
webSecurity: true,
}
Normally to display an image or play a video from a file you would do
<video controls autoplay>
<source src="file:///path-to-video.mp4">
</video>
but this won't work with webpack because webpack spawns a server and by default everyhing that starts with file://
will not be loaded due to security reasons. If the electron is loaded with a file://index.html
then it may work but the protocol way is pretty cool and you can secure your resources.
To overcome your issue you can do something like the following:
const { protocol } = require('electron');
function fileHandler(req, callback){
let requestedPath = req.url
// Write some code to resolve path, calculate absolute path etc
let check = // Write some code here to check if you should return the file to renderer process
if (!check){
callback({
// -6 is FILE_NOT_FOUND
// https://source.chromium.org/chromium/chromium/src/+/master:net/base/net_error_list.h
error: -6
});
return;
}
callback({
path: requestedPath
});
}
// Then in electron main.js
app.on("ready", () => {
protocol.registerFileProtocol(
'your-custom-protocol',
fileHandler,
);
// Create some window you can even use webPreferences: true
});
Then you can use it in your html code like this
<video controls autoplay>
<source src="your-custom-protocol:///path-to-video.mp4">
</video>
By doing this you can be sure that your app is secure and that it is not requesting random files from the file system and it also works with webpack really well.
For more about this there is a github repo to showcase secure patterns in electron. Take a look at it here
Even though I do not like encouraging this, I'd suggest you disable web security preference within BrowserWindow for the sake of resolution. Also, there is an issue related to this topic.
I recently ran into the same issue. You can set (in main process):
webPreferences: {
webSecurity: false
}
This will allow you to load file://
urls from a user's HDD. However, this is really bad practice as it opens up security.
The accepted way would be to:
webPreferences: {
webSecurity: true
}
And, then from your main process create a web server that serves up the files you want.
In your main process:
const http = require('http')
const express = require('express')
const expressApp = express()
const cors = require('cors')
const router = express.Router()
Then do the following code:
expressApp.use(cors())
router.get('/file/:name', function (req, res) {
let filename = req.params.name
res.sendFile(filename)
})
expressApp.use('/', router)
http.createServer(expressApp).listen(8000)
Now, in your js/html in the renderer code, you can set src
in the video tag to be:
'http://localhost:8000/file/' + filename
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With