diff --git a/.gitignore b/.gitignore index e1d550c36..1820c9ec0 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,7 @@ api.js epg-worker.js main.js +menu.js src/**/*.js !src/karma.conf.js *.js.map diff --git a/api.ts b/api.ts index cc0fdf5c0..c31d84c3d 100644 --- a/api.ts +++ b/api.ts @@ -1,9 +1,17 @@ -import { app, ipcMain } from 'electron'; +/* eslint-disable @typescript-eslint/no-misused-promises */ +import { app, BrowserWindow, ipcMain } from 'electron'; import { parse } from 'iptv-playlist-parser'; import axios from 'axios'; import { guid } from '@datorama/akita'; import { Playlist } from './src/app/home/playlist.interface'; import Nedb from 'nedb-promises-ts'; +import { + EPG_ERROR, + EPG_FETCH, + EPG_FETCH_DONE, + EPG_GET_PROGRAM, + EPG_GET_PROGRAM_DONE, +} from './src/app/shared/ipc-commands'; const fs = require('fs'); const join = require('path').join; @@ -15,6 +23,12 @@ const db = new Nedb({ }); export class Api { + /** Instance of the main application window */ + mainWindow: BrowserWindow; + + /** Instance of the epg browser window */ + workerWindow: BrowserWindow; + constructor() { ipcMain.on('parse-playlist-by-url', async (event, args) => { try { @@ -49,9 +63,9 @@ export class Api { event.sender.send('parse-response', { payload: playlistObject }); }); - ipcMain.on('playlists-all', async (event, args) => { + ipcMain.on('playlists-all', async (event) => { const playlists = await db.find( - {}, + { type: { $exists: false } }, { count: 1, title: 1, _id: 1, url: 1, importDate: 1 } ); event.sender.send('playlist-all-result', { @@ -88,6 +102,7 @@ export class Api { fs.readFile(args.filePath, 'utf-8', (err, data) => { if (err) { console.log( + // eslint-disable-next-line @typescript-eslint/restrict-plus-operands 'An error ocurred reading the file :' + err.message ); return; @@ -114,6 +129,40 @@ export class Api { console.error('Error: Favorites were not updated'); } }); + + // listeners for EPG events + ipcMain + .on(EPG_GET_PROGRAM, (event, arg) => + this.workerWindow.webContents.send(EPG_GET_PROGRAM, arg) + ) + .on(EPG_GET_PROGRAM_DONE, (event, arg) => { + this.mainWindow.webContents.send(EPG_GET_PROGRAM_DONE, arg); + }) + .on(EPG_FETCH, (event, arg) => + this.workerWindow.webContents.send(EPG_FETCH, arg?.url) + ) + .on(EPG_FETCH_DONE, (event, arg) => + this.mainWindow.webContents.send(EPG_FETCH_DONE, arg) + ) + .on(EPG_ERROR, (event, arg) => + this.mainWindow.webContents.send(EPG_ERROR, arg) + ); + } + + /** + * Sets epg browser window + * @param workerWindow + */ + setEpgWorkerWindow(workerWindow: BrowserWindow): void { + this.workerWindow = workerWindow; + } + + /** + * Sets browser window of the main app window + * @param mainWindow + */ + setMainWindow(mainWindow: BrowserWindow): void { + this.mainWindow = mainWindow; } /** @@ -156,7 +205,7 @@ export class Api { * Inserts new playlist to the database * @param playlist playlist to add */ - insertToDb(playlist) { + insertToDb(playlist: any): void { db.insert(playlist).then((response) => { console.log('playlist was saved...', response._id); }); diff --git a/main.ts b/main.ts index 163432da4..108baa3de 100644 --- a/main.ts +++ b/main.ts @@ -1,13 +1,16 @@ -import { app, BrowserWindow, Menu, MenuItem, shell } from 'electron'; +/* eslint-disable no-useless-catch */ +import { app, BrowserWindow, Menu } from 'electron'; import * as path from 'path'; import * as url from 'url'; import { Api } from './api'; -const openAboutWindow = require('about-window').default; +import { AppMenu } from './menu'; let win: BrowserWindow = null; const args = process.argv.slice(1), serve = args.some((val) => val === '--serve'); +const api = new Api(); + function createWindow(): BrowserWindow { // Create the browser window. win = new BrowserWindow({ @@ -28,14 +31,12 @@ function createWindow(): BrowserWindow { minHeight: 700, title: 'IPTVnator', }); - const menu = createMenu(win); - Menu.setApplicationMenu(menu); if (serve) { win.webContents.openDevTools(); require('electron-reload')(__dirname, { - electron: require(`${__dirname}/node_modules/electron`), + electron: path.join(__dirname, 'node_modules', '.bin', 'electron'), }); win.loadURL('http://localhost:4200'); } else { @@ -60,80 +61,27 @@ function createWindow(): BrowserWindow { } /** - * Creates context menu - * @param win browser window object + * Creates hidden window for EPG worker + * Hidden window is used as an additional thread to avoid blocking of the UI by long operations */ -function createMenu(win: BrowserWindow) { - const menu = new Menu(); - menu.append( - new MenuItem({ - label: 'File', - submenu: [ - { - label: 'Add playlist', - click: () => win.webContents.send('add-playlist-view'), - }, - { - type: 'separator', - }, - { - label: 'Exit', - click: () => app.quit(), - }, - ], - }) - ); +function createEpgWorkerWindow() { + const window = new BrowserWindow({ + show: false, + webPreferences: { nodeIntegration: true }, + }); - // copy-paste shortcuts workaround for mac os - if (process.platform === 'darwin') { - menu.append( - new MenuItem({ - label: 'Edit', - submenu: [ - { role: 'cut' }, - { role: 'copy' }, - { role: 'paste' }, - { role: 'delete' }, - ], - }) - ); + if (serve) { + window.loadFile('epg-worker.html'); + window.webContents.openDevTools(); + } else { + window.loadFile('dist/epg-worker.html'); } - menu.append( - new MenuItem({ - label: 'Help', - submenu: [ - { - label: 'Report a bug', - click: () => - shell.openExternal( - 'https://github.com/4gray/my-iptv-player-pwa' - ), - }, - { - label: 'Open DevTools', - click: () => win.webContents.openDevTools(), - }, - { - type: 'separator', - }, - { - label: 'About', - click: () => - openAboutWindow({ - icon_path: path.join( - __dirname, - 'dist/assets/icons/icon.png' - ), - copyright: 'Copyright (c) 2020 4gray', - package_json_dir: __dirname, - }), - }, - ], - }) - ); + window.once('ready-to-show', () => { + api.setEpgWorkerWindow(window); + }); - return menu; + return window; } try { @@ -143,7 +91,16 @@ try { // initialization and is ready to create browser windows. // Some APIs can only be used after this event occurs. // Added 400 ms to fix the black background issue while using transparent window. More details at https://github.com/electron/electron/issues/15947 - app.on('ready', () => setTimeout(createWindow, 400)); + app.on('ready', () => { + // create main window and set menu + const win = createWindow(); + const menu = AppMenu.createMenu(win); + Menu.setApplicationMenu(menu); + api.setMainWindow(win); + + // create hidden window for epg worker + createEpgWorkerWindow(); + }); // Quit when all windows are closed. app.on('window-all-closed', () => { @@ -165,5 +122,3 @@ try { // Catch Error throw e; } - -new Api(); diff --git a/menu.ts b/menu.ts new file mode 100644 index 000000000..706872861 --- /dev/null +++ b/menu.ts @@ -0,0 +1,82 @@ +import { app, BrowserWindow, Menu, MenuItem, shell } from 'electron'; +import * as path from 'path'; +const openAboutWindow = require('about-window').default; + +export class AppMenu { + /** + * Creates context menu + * @param win browser window object + */ + static createMenu(win: BrowserWindow): Menu { + const menu = new Menu(); + menu.append( + new MenuItem({ + label: 'File', + submenu: [ + { + label: 'Add playlist', + click: () => win.webContents.send('add-playlist-view'), + }, + { + type: 'separator', + }, + { + label: 'Exit', + click: () => app.quit(), + }, + ], + }) + ); + + // copy-paste shortcuts workaround for mac os + if (process.platform === 'darwin') { + menu.append( + new MenuItem({ + label: 'Edit', + submenu: [ + { role: 'cut' }, + { role: 'copy' }, + { role: 'paste' }, + { role: 'delete' }, + ], + }) + ); + } + + menu.append( + new MenuItem({ + label: 'Help', + submenu: [ + { + label: 'Report a bug', + click: () => + shell.openExternal( + 'https://github.com/4gray/iptvnator' + ), + }, + { + label: 'Open DevTools', + click: () => win.webContents.openDevTools(), + }, + { + type: 'separator', + }, + { + label: 'About', + click: () => + openAboutWindow({ + icon_path: path.join( + __dirname, + 'dist/assets/icons/icon.png' + ), + copyright: 'Copyright (c) 2020 4gray', + package_json_dir: __dirname, + }), + }, + ], + }) + ); + + return menu; + } +} diff --git a/tsconfig.serve.json b/tsconfig.serve.json index 4e66eb9d5..62e248771 100644 --- a/tsconfig.serve.json +++ b/tsconfig.serve.json @@ -19,7 +19,8 @@ "files": [ "api.ts", "epg-worker.ts", - "main.ts" + "main.ts", + "menu.ts" ], "exclude": [ "node_modules",