migu/electron/src/main/app.js
ThaUnknown 7c10667e8b fix: lastFinished
fix: close app on webtorrent crash
feat: torrent loading status and errors
2024-09-01 07:57:45 +07:00

161 lines
5.6 KiB
JavaScript

import { join } from 'node:path'
import process from 'node:process'
import { BrowserWindow, MessageChannelMain, Notification, app, dialog, ipcMain, nativeImage, powerMonitor, shell } from 'electron'
import electronShutdownHandler from '@paymoapp/electron-shutdown-handler'
import { development } from './util.js'
import Discord from './discord.js'
import Protocol from './protocol.js'
import Updater from './updater.js'
import Dialog from './dialog.js'
import store from './store.js'
import Debug from './debugger.js'
export default class App {
webtorrentWindow = new BrowserWindow({
show: development,
webPreferences: {
webSecurity: false,
allowRunningInsecureContent: false,
nodeIntegration: true,
contextIsolation: false,
backgroundThrottling: false
}
})
mainWindow = new BrowserWindow({
width: 1600,
height: 900,
frame: process.platform === 'darwin', // Only keep the native frame on Mac
titleBarStyle: 'hidden',
titleBarOverlay: {
color: '#17191c',
symbolColor: '#eee',
height: 28
},
backgroundColor: '#17191c',
autoHideMenuBar: true,
webPreferences: {
webSecurity: false,
allowRunningInsecureContent: false,
enableBlinkFeatures: 'FontAccess, AudioVideoTracks',
backgroundThrottling: false,
preload: join(__dirname, '/preload.js')
},
icon: join(__dirname, '/logo_filled.png'),
show: false
})
discord = new Discord(this.mainWindow)
protocol = new Protocol(this.mainWindow)
updater = new Updater(this.mainWindow, this.webtorrentWindow)
dialog = new Dialog(this.webtorrentWindow)
debug = new Debug()
constructor () {
this.mainWindow.setMenuBarVisibility(false)
this.mainWindow.webContents.setWindowOpenHandler(() => ({ action: 'deny' }))
this.mainWindow.once('ready-to-show', () => this.mainWindow.show())
this.mainWindow.on('minimize', () => this.mainWindow.webContents.postMessage('visibilitychange', 'hidden'))
this.mainWindow.on('restore', () => this.mainWindow.webContents.postMessage('visibilitychange', 'visible'))
ipcMain.on('torrent-devtools', () => this.webtorrentWindow.webContents.openDevTools())
ipcMain.on('ui-devtools', ({ sender }) => sender.openDevTools())
this.mainWindow.on('closed', () => this.destroy())
this.webtorrentWindow.on('closed', () => this.destroy())
ipcMain.on('close', () => this.destroy())
app.on('before-quit', e => {
if (this.destroyed) return
e.preventDefault()
this.destroy()
})
powerMonitor.on('shutdown', e => {
if (this.destroyed) return
e.preventDefault()
this.destroy()
})
ipcMain.on('notification', async (e, opts) => {
if (opts.icon) {
const res = await fetch(opts.icon)
const buffer = await res.arrayBuffer()
opts.icon = nativeImage.createFromBuffer(Buffer.from(buffer))
}
const notification = new Notification(opts)
notification.on('click', () => {
if (opts.data.id) {
this.mainWindow.show()
this.protocol.protocolMap.anime(opts.data.id)
}
})
notification.show()
})
if (process.platform === 'win32') {
app.setAppUserModelId('com.github.nocrypt.migu')
// this message usually fires in dev-mode from the parent process
process.on('message', data => {
if (data === 'graceful-exit') this.destroy()
})
electronShutdownHandler.setWindowHandle(this.mainWindow.getNativeWindowHandle())
electronShutdownHandler.blockShutdown('Saving torrent data...')
electronShutdownHandler.on('shutdown', async () => {
await this.destroy()
electronShutdownHandler.releaseShutdown()
})
} else {
process.on('SIGTERM', () => this.destroy())
}
const torrentLoad = this.webtorrentWindow.loadURL(development ? 'http://localhost:5000/background.html' : `file://${join(__dirname, '/background.html')}`)
this.mainWindow.loadURL(development ? 'http://localhost:5000/app.html' : `file://${join(__dirname, '/app.html')}`)
if (development) {
this.webtorrentWindow.webContents.openDevTools()
this.mainWindow.webContents.openDevTools()
}
let crashcount = 0
this.mainWindow.webContents.on('render-process-gone', async (e, { reason }) => {
if (reason === 'crashed') {
if (++crashcount > 10) {
await dialog.showMessageBox({ message: 'Crashed too many times.', title: 'Migu', detail: 'App crashed too many times. Make an issue at https://github.com/NoCrypt/migu/issues', icon: '/renderer/public/logo_filled.png' })
shell.openExternal('https://github.com/NoCrypt/migu/issues')
} else {
app.relaunch()
}
app.quit()
}
})
ipcMain.on('portRequest', async ({ sender }) => {
const { port1, port2 } = new MessageChannelMain()
await torrentLoad
this.webtorrentWindow.webContents.postMessage('port', null, [port1])
this.webtorrentWindow.webContents.postMessage('player', store.get('player'))
this.webtorrentWindow.webContents.postMessage('torrentPath', store.get('torrentPath'))
sender.postMessage('port', null, [port2])
})
ipcMain.on('quit-and-install', () => {
if (this.updater.hasUpdate) {
this.destroy(true)
}
})
}
destroyed = false
async destroy (forceRunAfter = false) {
if (this.destroyed) return
this.webtorrentWindow.webContents.postMessage('destroy', null)
await new Promise(resolve => {
ipcMain.once('destroyed', resolve)
setTimeout(resolve, 5000).unref?.()
})
this.destroyed = true
if (!this.updater.install(forceRunAfter)) app.quit()
}
}