Rework the app updating process, add more user interaction.

This commit is contained in:
Jelle Glebbeek
2021-03-05 15:16:55 +01:00
parent 9643ffdf79
commit c509519efa
8 changed files with 136 additions and 43 deletions

View File

@@ -44,6 +44,8 @@ Still haven't found your answer? Open up an issue [right here](https://github.co
## Planned features
- White mode
- Show progress in app-icon
- Notify user when the download has finished
Feel free to [request a new feature](https://github.com/jely2002/youtube-dl-gui/issues).

50
main.js
View File

@@ -1,10 +1,10 @@
const { app, BrowserWindow, ipcMain, dialog, Menu, globalShortcut, shell} = require('electron');
const { autoUpdater } = require("electron-updater");
const Environment = require('./modules/Environment');
const path = require('path');
const QueryManager = require("./modules/QueryManager");
const ErrorHandler = require("./modules/ErrorHandler");
const BinaryUpdater = require("./modules/BinaryUpdater");
const AppUpdater = require("./modules/AppUpdater");
let win
let env
@@ -86,7 +86,6 @@ function startCriticalHandlers(env) {
queryManager = new QueryManager(win, env);
env.errorHandler = new ErrorHandler(win, queryManager, env);
checkAppUpdate();
if(appStarting) {
appStarting = false;
@@ -104,7 +103,6 @@ function startCriticalHandlers(env) {
}
ipcMain.handle('errorReport', async (event, args) => {
console.log(args)
return await env.errorHandler.reportError(args);
});
@@ -119,11 +117,18 @@ function startCriticalHandlers(env) {
})
if(env.settings.updateBinary) {
let updater = new BinaryUpdater(env.paths, win);
let binaryUpdater = new BinaryUpdater(env.paths, win);
win.webContents.send("binaryLock", {lock: true, placeholder: `Checking for a new version of ytdl...`})
updater.checkUpdate().finally(() => { win.webContents.send("binaryLock", {lock: false}) });
binaryUpdater.checkUpdate().finally(() => { win.webContents.send("binaryLock", {lock: false}) });
}
let appUpdater = new AppUpdater(env, win);
appUpdater.checkUpdate();
ipcMain.handle("installUpdate", () => {
appUpdater.installUpdate();
});
ipcMain.handle('videoAction', async (event, args) => {
switch (args.action) {
case "stop":
@@ -166,20 +171,6 @@ function startCriticalHandlers(env) {
}
}
function checkAppUpdate() {
if(env.settings.updateApplication && process.argv[2] !== '--dev') {
if (process.platform === "darwin") {
autoUpdater.checkForUpdates().then((result) => {
if(app.getVersion() !== result.updateInfo.version) {
win.webContents.send('toast', {type: "update", msg: `Update ${result.updateInfo.releaseName} is out now! <br> <a target="_blank" href="https://github.com/jely2002/youtube-dl-gui/releases/latest">Download on GitHub</a>`});
}
})
} else if (process.platform === "win32" || process.platform === "linux") {
autoUpdater.checkForUpdatesAndNotify()
}
}
}
function sendLogToRenderer(log, isErr) {
win.webContents.send("log", {log: log, isErr: isErr});
}
@@ -240,15 +231,6 @@ ipcMain.handle('downloadFolder', async (event) => {
});
});
ipcMain.handle('messageBox', (event, args) => {
dialog.showMessageBoxSync(win, {
title: args.title,
message: args.message,
type: "none",
buttons: [],
}) ;
});
//Show a dialog to select a file, and return the selected value.
ipcMain.handle('cookieFile', async (event,clear) => {
if(clear === true) {
@@ -276,3 +258,15 @@ ipcMain.handle('cookieFile', async (event,clear) => {
}
return result.filePaths[0];
})
//Show a messagebox with a custom title and message
ipcMain.handle('messageBox', (event, args) => {
dialog.showMessageBoxSync(win, {
title: args.title,
message: args.message,
type: "none",
buttons: [],
}) ;
});

63
modules/AppUpdater.js Normal file
View File

@@ -0,0 +1,63 @@
const Utils = require("./Utils");
const { autoUpdater } = require("electron-updater");
class AppUpdater {
constructor(env, win) {
this.env = env;
this.win = win;
this.initializeEvents();
}
initializeEvents() {
autoUpdater.on('download-progress', (progressObj) => {
const percent = Math.round(progressObj.percent);
const progress = `${Utils.convertBytes(progressObj.transferred)} / ${Utils.convertBytes(progressObj.total)}`;
const speed = Utils.convertBytesPerSecond(progressObj.bytesPerSecond);
this.win.webContents.send('toast', {
type: "update",
title: `Downloading update ${this.newVersion}`,
body: `<p>${progress} | ${speed}</p>
<div class="progress" style="height: 5px;">
<div class="progress-bar" role="progressbar" style="width: ${percent}%;" aria-valuenow="${percent}" aria-valuemin="0" aria-valuemax="100"></div>
</div>`
});
})
}
checkUpdate() {
if(!this.isUpdateAllowed()) return;
autoUpdater.checkForUpdates().then((result) => {
if(result.downloadPromise != null) {
if(process.platform === "darwin") {
//Show only toast on mac
this.win.webContents.send('toast', {
type: "update",
title: "An update has been found",
body: `Update ${result.updateInfo.releaseName} is out now! <br> <a target="_blank" href="https://github.com/jely2002/youtube-dl-gui/releases/latest">Download on GitHub</a>`
});
} else {
this.newVersion = result.updateInfo.releaseName;
result.downloadPromise.then((download) => {
console.log(download)
this.win.webContents.send('toast', {
type: "update",
title: `Update ${result.updateInfo.releaseName} was downloaded`,
body: `<p>Do you want to install it now?</p><button class="btn" id="install-btn">Sure</button><button class="btn" data-dismiss="toast">Not now</button>`
});
})
}
}
})
}
installUpdate() {
//IsSilent: false (show progress), forceReOpen: true (reopen the app after updating has finished)
autoUpdater.quitAndInstall(false, true);
}
isUpdateAllowed() {
return (this.env.settings.updateApplication && process.argv[2] !== '--dev') || (process.argv[2] === "--dev" && process.argv[3] === "--test-update");
}
}
module.exports = AppUpdater;

View File

@@ -17,6 +17,15 @@ class Utils {
return(n.toFixed(n < 10 && l > 0 ? 1 : 0) + ' ' + units[l]);
}
static convertBytesPerSecond(bytes) {
const units = ['B/s', 'KB/s', 'MB/s', 'GB/s', 'TB/s', 'PB/s', 'EB/s', 'ZB/s', 'YB/s'];
let l = 0, n = parseInt(bytes, 10);
while(n >= 1024 && ++l) {
n = n/1024;
}
return(n.toFixed(n < 10 && l > 0 ? 1 : 0) + ' ' + units[l]);
}
static getRandomID(length) {
return crypto.randomBytes(length / 2).toString("hex");
}

View File

@@ -3,7 +3,7 @@ const { contextBridge, ipcRenderer } = require('electron')
contextBridge.exposeInMainWorld(
"main", {
invoke: async (channel, data) => {
let validChannels = ["platform", "messageBox","errorReport", "titlebarClick", "openInputMenu", "settingsAction", "videoAction", "cookieFile", "downloadFolder"];
let validChannels = ["platform", "messageBox","errorReport", "titlebarClick", "openInputMenu", "settingsAction", "videoAction", "cookieFile", "downloadFolder", "installUpdate"];
if (validChannels.includes(channel)) {
return await ipcRenderer.invoke(channel, data);
}

View File

@@ -35,11 +35,35 @@ select {
.toast-header {
border-bottom: none;
color: var(--font-color);
background-color: var(--tertiary-bg-color);
border-top-left-radius: 0;
border-top-right-radius: 0;
}
.toast-body > button {
background-color: var(--secondary-bg-color);
color: var(--font-color);
}
.toast-body > button:hover {
color: var(--font-color);
}
.toast-body > #install-btn {
background-color: var(--highlight-color);
}
.toast-body > button:last-child {
margin-left: 1rem;
}
.toast .close {
color: var(--font-color);
}
.toast {
position: fixed;
bottom: 0;
bottom: 142px;
left: 10px;
visibility: hidden;
}

View File

@@ -38,7 +38,7 @@
<div class="container-fluid controls">
<div class="row mx-auto">
<div id="totalProgress" class="progress mx-auto">
<div class="progress-bar" role="progressbar" style="width: 0%;" aria-valuenow="25" aria-valuemin="0" aria-valuemax="100"></div>
<div class="progress-bar" role="progressbar" style="width: 0%;" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100"></div>
<small class="justify-content-center d-flex position-absolute w-100">Ready to download!</small>
</div>
</div>
@@ -240,9 +240,8 @@
</div>
</div>
<div class="toast warning-toast" id="update" role="alert" aria-live="assertive" aria-atomic="true">
<div class="toast-header bg-success">
<i class="bi mr-3 bi-arrow-bar-up"></i>
<div class="toast" id="update" role="alert" aria-live="assertive" aria-atomic="true">
<div class="toast-header">
<strong class="mr-auto update-title">There is an update available!</strong>
<button type="button" class="ml-2 mb-1 close" data-dismiss="toast" aria-label="Close">
<span aria-hidden="true">&times;</span>

View File

@@ -71,6 +71,10 @@ async function init() {
}
});
$('body').on('click', '#install-btn', () => {
window.main.invoke("installUpdate") ;
});
$('#infoModal .dismiss').on('click', () => {
$('#infoModal').modal("hide");
});
@@ -227,7 +231,7 @@ async function init() {
else console.log(arg.log);
} );
//Enables the main process to show toasts.
//Enables the main process to show and update toasts.
window.main.receive("toast", (arg) => showToast(arg));
//Passes an error to the setError method
@@ -305,15 +309,13 @@ function parseURL(data) {
}
function showToast(toastInfo) {
if(toastInfo.type === "update") {
if(toastInfo.title != null) {
$(`.${toastInfo.type}-title`).html(toastInfo.title);
}
$(`.${toastInfo.type}-body`).html(toastInfo.msg);
$(`#${toastInfo.type}`).toast('show').css('visibility', 'visible');
} else {
console.error("Main tried to show a toast that doesn't exist.")
if(toastInfo.title != null) {
$(`.${toastInfo.type}-title`).html(toastInfo.title);
}
if(toastInfo.body != null) {
$(`.${toastInfo.type}-body`).html(toastInfo.body);
}
if($(`#${toastInfo.type}`).is(':visible')) $(`#${toastInfo.type}`).toast('show').css('visibility', 'visible');
}
function addVideo(args) {