Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Playing local mp4 file in electron

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!

like image 834
Umut Benzer Avatar asked Aug 07 '17 19:08

Umut Benzer


3 Answers

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

like image 155
tchar Avatar answered Oct 06 '22 22:10

tchar


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.

like image 38
Ali BARIN Avatar answered Oct 06 '22 22:10

Ali BARIN


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
like image 28
Hawkeye64 Avatar answered Oct 06 '22 22:10

Hawkeye64