1

This's a simple video duration check program built with Electron. However, it doesn't work as expected; I also tried to use Electron IPC communication in others projects, but always fails. I can upload a video successfully and submit it, after that nothings happens, any errors or advices. Debugger shows nothing too. I built a new project from zero and have same issue. Path value is also not showed on console

main.js:

const electron = require('electron'),
app = electron.app,
BrowserWindow = electron.BrowserWindow
const ffmpeg = require('fluent-ffmpeg')
const ipc = require('electron').ipcMain

let mainWindow

app.on('ready', () => {
    mainWindow = new BrowserWindow({})
    mainWindow.loadFile('./index.html')
})

ipc.on('video:submit', (event, path) => {
    ffmpeg.ffprobe(path, (metadata) => {
        event.returnValue = metadata.format.duration
    })
})

index.html:

<html>
    <head>
    </head>
    <body>
        <form id="form">
            <h1>Video Info</h1>
            <div>
                <label>Select a video</label>
                <input type="file" accept="video/*" id="input">
            </div>
            <button type="submit" id="sb">Get info</button>
            <div id="result"></div>
        </form>
    </body>
    <script>
        require('./renderer.js')
    </script>
</html>

renderer.js:

const ipc = require('electron').ipcRenderer,

form = document.querySelector('#form')

let result = document.querySelector('#result')

console.log(path)

form.addEventListener('submit', () => {
    const path = document.querySelector('#input').files[0].path
    let reply = ipc.sendSync('video:submit', path)
    result.innerHTML = 'Video is' + reply + 'seconds!'
})

EDIT

I made some changes on main and renderer to use asynchronous send and reply. I don't get what I want, but after submit some content, it's name is replaced with "No file chosen". Path value stills not printed.

changes on main.js:

ipc.on('video:submit', (event, path) => {
    ffmpeg.ffprobe(path, (metadata) => {
        let duration = metadata.format.duration
        event.reply('duration', duration)
    })
})

changes on renderer.js:

form.addEventListener('submit', () => {
    const path = document.querySelector('#input').files[0].path
    ipc.on('duration', (event, duration) => {
        console.log(duration)
    })
    ipc.send('video:submit', path)
    result.innerHTML = 'Video is' + duration + 'seconds!'
})
Zoey
  • 474
  • 4
  • 17
  • isn't the problem in the `renderer.js` i mean when the script is loaded, the `path` will be calculated only once, so You will always send the `undefined` , did You try to move the path evaluation inside the arrow function ? – Take_Care_ Mar 15 '20 at 23:13
  • And please add some more info, writing only "it fails" doesn't help ;) – Take_Care_ Mar 15 '20 at 23:15
  • Hi Mdsp, please try to make the title of your post more explicit :) – Zoette Mar 15 '20 at 23:28
  • Check this answer https://stackoverflow.com/questions/60227586/ipcrenderer-not-receiving-message-from-main-process/60227981#60227981 – tpikachu Mar 15 '20 at 23:51
  • Take_Care I move path evaluation outside arrow function only for test, nothings changes, but the right place is inside! – Zoey Mar 16 '20 at 00:03
  • Ok, when I mean "it fails" I wanna to say: nothing happens, no errors, no advices... It's like ipc doesn't even start – Zoey Mar 16 '20 at 00:05
  • I read the answer and I thought that nodeIntegration was activated by default... I tried turn to true, but problem persist, nothing happens – Zoey Mar 16 '20 at 00:13
  • ok, so, the problem is here `event.returnValue = metadata.format.duration` this part is inside callback, so when the callback function hits end there will be response send with the `event.returnValue` value so the main will revieve no response. You cannot mix async + sync like this. – Take_Care_ Mar 16 '20 at 00:25
  • So, how can I solve this? What's the correct form to reply to renderer? – Zoey Mar 16 '20 at 00:33
  • https://www.electronjs.org/docs/api/ipc-main and use the `asynchronus-reply` example. because right now You are using the synchronus one – Take_Care_ Mar 16 '20 at 00:37
  • Made all changes to asynchronous one and stills same – Zoey Mar 17 '20 at 14:56

2 Answers2

0

The code looks good but I guess the problem lies in your form submission. The page should be reloading on submit and it does not reach the IPC send call. Try preventing default action for the form.

form.addEventListener('submit', (e) => {
  e.preventDefault()
  const path = document.querySelector('#input').files[0].path
    ipc.on('duration', (event, duration) => {
        console.log(duration)
    })
   ipc.send('video:submit', path)
    result.innerHTML = 'Video is' + duration + 'seconds!'
  })
Imtiyaz Shaikh
  • 425
  • 3
  • 7
0

Solved! There were 3 main errors so I don't know what exactly happened. But here are they:

1 - ipc functions were made wrong way. This is the right one (asynchronous reply):

renderer.js:

ipc.on('duration', (event, duration) => {
    result.innerHTML = `Video is ${duration} seconds!`    
})
ipc.send('video:submit', path)

main.js:

ipc.on('video:submit', (event, path) => {
    ffmpeg.ffprobe(path, (err, metadata) => {
        let duration = metadata.format.duration
        console.log(duration)
        event.reply('duration', duration)
    })
 })

2 - DOM wasn't getting submit button or event so "addEventListiner" was getting null... I changed submit button to input button with same id then cheanged submit event to simple click event. I query selected the input button rather the form at all. That's what I get finally:

renderer.js:

const ipc = require('electron').ipcRenderer,

suBtn = document.querySelector('input#sb')

let result = document.querySelector('div#result')

suBtn.addEventListener('click', (event) => {
    event.preventDefault()
    const path = document.querySelector('input#file').files[0].path
    ipc.on('duration', (event, duration) => {
        result.innerHTML = `Video is ${duration} seconds!`    
    })
    ipc.send('video:submit', path)

})

3 - On ffprobe process on main.js, I was calling method with wrong params. It's necessary to pass the err param first, then data param, this way:

main.js:

ffmpeg.ffprobe(path, (err, metadata) => {
    let duration = metadata.format.duration
    console.log(duration)
    event.reply('duration', duration)
})
Zoey
  • 474
  • 4
  • 17