最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Electron: Displaying A Local Video From Filesystem With Custom Protocol - Stack Overflow

programmeradmin2浏览0评论

I'm trying to use electron to build a simple video display app. However I have been having immense difficulty in trying to get a video to show up in the renderer using the proper registerSchemesAsPrivileged method. I'm currently getting no error shows up in the console relating to net not being able find the file so I feel like I have it correct but I am getting is a black screen on the renderer thread.

If you could take a quick look at my code and log output to make sure I am not missing something obvious then that would be a great help. Also nothing shows up in the developer tools in the browser window

Snippet of main.ts


import path from 'path';
import { app, BrowserWindow, shell, ipcMain, protocol,net } from 'electron';
import { autoUpdater } from 'electron-updater';
import log from 'electron-log';
import MenuBuilder from './menu';
import { resolveHtmlPath } from './util';
import fs from 'fs'

protocol.registerSchemesAsPrivileged([
  {
    scheme: 'appfile',
    privileges: {
      standard: true,
      secure: true,
      supportFetchAPI: true,
      bypassCSP: true,
    },
  },
]);

app.whenReady().then(() => {
  protocol.handle('appfile', (request) => {
    // Get the file path from the request url
    const filePath = request.url.replace('appfile://', '');
    // Resolve the file path to the absolute file path
    //const absoluteFilePath = path.resolve(filePath);
    // Fetch the file
    console.log(filePath);
    
    return net.fetch(`file:///${filePath}`);
  });
});

App.tsx:

import { MemoryRouter as Router, Routes, Route } from 'react-router-dom';
import icon from '../../assets/icon.svg';
import './App.css';
import { useState, useEffect } from 'react';

function Hello() {
  
  //const [videoSource, setVideoSource] = useState<string | null>(null);

  


  return (
    <body>
      <video id="videoPlayer" width="100%" height="100%" autoPlay muted loop>
      <source src="appfile:///home/user/Desktop/project/videos/video1.mp4" />
    </video>
    
    </body>
  );
}




export default function App() {
  return (
    <Router>
      <Routes>
        <Route path="/" element={<Hello />} />
      </Routes>
    </Router>
  );
}

Snippet of console output where error would show usually,(console log of the file path included):

home/user/Desktop/project/videos/video1.mp4
[14091:0823/181240.250752:ERROR:CONSOLE(2)] "Electron sandboxed_renderer.bundle.js script failed to run", source: node:electron/js2c/sandbox_bundle (2)
[14091:0823/181240.250873:ERROR:CONSOLE(2)] "TypeError: object null is not iterable (cannot read property Symbol(Symbol.iterator))", source: node:electron/js2c/sandbox_bundle (2)

Thanks again ahead of time.

I'm trying to use electron to build a simple video display app. However I have been having immense difficulty in trying to get a video to show up in the renderer using the proper registerSchemesAsPrivileged method. I'm currently getting no error shows up in the console relating to net not being able find the file so I feel like I have it correct but I am getting is a black screen on the renderer thread.

If you could take a quick look at my code and log output to make sure I am not missing something obvious then that would be a great help. Also nothing shows up in the developer tools in the browser window

Snippet of main.ts


import path from 'path';
import { app, BrowserWindow, shell, ipcMain, protocol,net } from 'electron';
import { autoUpdater } from 'electron-updater';
import log from 'electron-log';
import MenuBuilder from './menu';
import { resolveHtmlPath } from './util';
import fs from 'fs'

protocol.registerSchemesAsPrivileged([
  {
    scheme: 'appfile',
    privileges: {
      standard: true,
      secure: true,
      supportFetchAPI: true,
      bypassCSP: true,
    },
  },
]);

app.whenReady().then(() => {
  protocol.handle('appfile', (request) => {
    // Get the file path from the request url
    const filePath = request.url.replace('appfile://', '');
    // Resolve the file path to the absolute file path
    //const absoluteFilePath = path.resolve(filePath);
    // Fetch the file
    console.log(filePath);
    
    return net.fetch(`file:///${filePath}`);
  });
});

App.tsx:

import { MemoryRouter as Router, Routes, Route } from 'react-router-dom';
import icon from '../../assets/icon.svg';
import './App.css';
import { useState, useEffect } from 'react';

function Hello() {
  
  //const [videoSource, setVideoSource] = useState<string | null>(null);

  


  return (
    <body>
      <video id="videoPlayer" width="100%" height="100%" autoPlay muted loop>
      <source src="appfile:///home/user/Desktop/project/videos/video1.mp4" />
    </video>
    
    </body>
  );
}




export default function App() {
  return (
    <Router>
      <Routes>
        <Route path="/" element={<Hello />} />
      </Routes>
    </Router>
  );
}

Snippet of console output where error would show usually,(console log of the file path included):

home/user/Desktop/project/videos/video1.mp4
[14091:0823/181240.250752:ERROR:CONSOLE(2)] "Electron sandboxed_renderer.bundle.js script failed to run", source: node:electron/js2c/sandbox_bundle (2)
[14091:0823/181240.250873:ERROR:CONSOLE(2)] "TypeError: object null is not iterable (cannot read property Symbol(Symbol.iterator))", source: node:electron/js2c/sandbox_bundle (2)

Thanks again ahead of time.

Share Improve this question asked Aug 23, 2023 at 22:17 MichaelMichael 595 bronze badges
Add a ment  | 

1 Answer 1

Reset to default 9

After reading dozen of pages, github issues and documentation in the past 3 days, I finally figure it out how to make that work. You need to specify bypassCSP and stream as true when creating your custom protocol.

Based on electron-quick-start project, I created a custom animation:// protocol to read from filesystem (/tmp/video.mp4).

main.js:

// Modules to control application life and create native browser window
const { app, protocol, net, BrowserWindow } = require('electron')
const path = require('node:path')

protocol.registerSchemesAsPrivileged([
  {
    scheme: 'animation',
    privileges: {
        bypassCSP: true,
        stream: true,
    }
  }
])

function createWindow () {
  // Create the browser window.
  const mainWindow = new BrowserWindow({
    width: 800,
    height: 600,
    webPreferences: {
      preload: path.join(__dirname, 'preload.js')
    }
  })

  // and load the index.html of the app.
  mainWindow.loadFile('index.html')

  // Open the DevTools.
  // mainWindow.webContents.openDevTools()
}

// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.whenReady().then(() => {
  protocol.handle('animation', function (request) {
    return net.fetch('file://' + request.url.slice('animation://'.length))
  })

  createWindow()

  app.on('activate', function () {
    // On macOS it's mon to re-create a window in the app when the
    // dock icon is clicked and there are no other windows open.
    if (BrowserWindow.getAllWindows().length === 0) createWindow()
  })
})

// Quit when all windows are closed, except on macOS. There, it's mon
// for applications and their menu bar to stay active until the user quits
// explicitly with Cmd + Q.
app.on('window-all-closed', function () {
  if (process.platform !== 'darwin') app.quit()
})

// In this file you can include the rest of your app's specific main process
// code. You can also put them in separate files and require them here.

index.html:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <!-- https://developer.mozilla/en-US/docs/Web/HTTP/CSP -->
    <meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'">
    <link href="./styles.css" rel="stylesheet">
    <title>Hello World!</title>
  </head>
  <body>
    <h1>Hello World!</h1>
    We are using Node.js <span id="node-version"></span>,
    Chromium <span id="chrome-version"></span>,
    and Electron <span id="electron-version"></span>.

    <!-- You can also require other files to run in this process -->
    <script src="./renderer.js"></script>

    <div class="video-wrapper">
      <video autoPlay loop muted>
        <source src="animation:///tmp/video.mp4" type="video/mp4"/>
      </video>
    </div>
  </body>
</html>

发布评论

评论列表(0)

  1. 暂无评论