mirror of
https://github.com/jely2002/youtube-dl-gui.git
synced 2021-11-01 22:46:21 +03:00
feat: show progress while updating/installing dependencies
This commit is contained in:
@@ -2,6 +2,7 @@ const axios = require("axios");
|
|||||||
const fs = require("fs");
|
const fs = require("fs");
|
||||||
const Sentry = require("@sentry/node");
|
const Sentry = require("@sentry/node");
|
||||||
const util = require('util');
|
const util = require('util');
|
||||||
|
const Utils = require('./Utils');
|
||||||
const exec = util.promisify(require('child_process').exec);
|
const exec = util.promisify(require('child_process').exec);
|
||||||
|
|
||||||
class BinaryUpdater {
|
class BinaryUpdater {
|
||||||
@@ -9,6 +10,7 @@ class BinaryUpdater {
|
|||||||
constructor(paths, win) {
|
constructor(paths, win) {
|
||||||
this.paths = paths;
|
this.paths = paths;
|
||||||
this.win = win;
|
this.win = win;
|
||||||
|
this.action = "Installing";
|
||||||
}
|
}
|
||||||
|
|
||||||
//Checks for an update and download it if there is.
|
//Checks for an update and download it if there is.
|
||||||
@@ -28,7 +30,7 @@ class BinaryUpdater {
|
|||||||
} else if(localVersion == null) {
|
} else if(localVersion == null) {
|
||||||
transaction.setTag("download", "corrupted");
|
transaction.setTag("download", "corrupted");
|
||||||
console.log("Downloading missing yt-dlp binary.");
|
console.log("Downloading missing yt-dlp binary.");
|
||||||
this.win.webContents.send("binaryLock", {lock: true, placeholder: `Installing yt-dlp version: ${remoteVersion}...`})
|
this.win.webContents.send("binaryLock", {lock: true, placeholder: `Installing yt-dlp version: ${remoteVersion}. Preparing...`})
|
||||||
await this.downloadUpdate(remoteUrl, remoteVersion);
|
await this.downloadUpdate(remoteUrl, remoteVersion);
|
||||||
} else if(remoteVersion == null) {
|
} else if(remoteVersion == null) {
|
||||||
transaction.setTag("download", "down");
|
transaction.setTag("download", "down");
|
||||||
@@ -36,7 +38,8 @@ class BinaryUpdater {
|
|||||||
} else {
|
} else {
|
||||||
console.log(`New version ${remoteVersion} found. Updating...`);
|
console.log(`New version ${remoteVersion} found. Updating...`);
|
||||||
transaction.setTag("download", "update");
|
transaction.setTag("download", "update");
|
||||||
this.win.webContents.send("binaryLock", {lock: true, placeholder: `Updating yt-dlp to version: ${remoteVersion}...`})
|
this.action = "Updating to";
|
||||||
|
this.win.webContents.send("binaryLock", {lock: true, placeholder: `Updating yt-dlp to version: ${remoteVersion}. Preparing...`})
|
||||||
await this.downloadUpdate(remoteUrl, remoteVersion);
|
await this.downloadUpdate(remoteUrl, remoteVersion);
|
||||||
}
|
}
|
||||||
span.finish();
|
span.finish();
|
||||||
@@ -110,21 +113,28 @@ class BinaryUpdater {
|
|||||||
//Downloads the file at the given url and saves it to the ytdl path.
|
//Downloads the file at the given url and saves it to the ytdl path.
|
||||||
async downloadUpdate(remoteUrl, remoteVersion) {
|
async downloadUpdate(remoteUrl, remoteVersion) {
|
||||||
const writer = fs.createWriteStream(this.paths.ytdl);
|
const writer = fs.createWriteStream(this.paths.ytdl);
|
||||||
return await axios.get(remoteUrl, {responseType: 'stream'}).then(response => {
|
const { data, headers } = await axios.get(remoteUrl, {responseType: 'stream'});
|
||||||
return new Promise((resolve, reject) => {
|
const totalLength = +headers['content-length'];
|
||||||
response.data.pipe(writer);
|
const total = Utils.convertBytes(totalLength);
|
||||||
let error = null;
|
let received = 0;
|
||||||
writer.on('error', err => {
|
return await new Promise((resolve, reject) => {
|
||||||
error = err;
|
let error = null;
|
||||||
reject(err);
|
data.on('data', (chunk) => {
|
||||||
});
|
received += chunk.length;
|
||||||
writer.on('close', async () => {
|
const percentage = ((received / totalLength) * 100).toFixed(0) + '%';
|
||||||
if (!error) {
|
this.win.webContents.send("binaryLock", {lock: true, placeholder: `${this.action} yt-dlp ${remoteVersion} - ${percentage} of ${total}`})
|
||||||
await this.writeVersionInfo(remoteVersion);
|
|
||||||
resolve(true);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
writer.on('error', err => {
|
||||||
|
error = err;
|
||||||
|
reject(err);
|
||||||
|
});
|
||||||
|
writer.on('close', async () => {
|
||||||
|
if (!error) {
|
||||||
|
await this.writeVersionInfo(remoteVersion);
|
||||||
|
resolve(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
data.pipe(writer);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,12 +6,14 @@ const util = require('util');
|
|||||||
const exec = util.promisify(require('child_process').exec);
|
const exec = util.promisify(require('child_process').exec);
|
||||||
const os = require("os");
|
const os = require("os");
|
||||||
const AdmZip = require("adm-zip");
|
const AdmZip = require("adm-zip");
|
||||||
|
const Utils = require('./Utils');
|
||||||
|
|
||||||
class FfmpegUpdater {
|
class FfmpegUpdater {
|
||||||
|
|
||||||
constructor(paths, win) {
|
constructor(paths, win) {
|
||||||
this.paths = paths;
|
this.paths = paths;
|
||||||
this.win = win;
|
this.win = win;
|
||||||
|
this.action = "Installing";
|
||||||
}
|
}
|
||||||
|
|
||||||
//Checks for an update and download it if there is.
|
//Checks for an update and download it if there is.
|
||||||
@@ -31,9 +33,10 @@ class FfmpegUpdater {
|
|||||||
} else if(localVersion == null) {
|
} else if(localVersion == null) {
|
||||||
transaction.setTag("download", "corrupted");
|
transaction.setTag("download", "corrupted");
|
||||||
console.log("Downloading missing ffmpeg binary.");
|
console.log("Downloading missing ffmpeg binary.");
|
||||||
this.win.webContents.send("binaryLock", {lock: true, placeholder: `Installing ffmpeg version: ${remoteVersion}...`})
|
this.win.webContents.send("binaryLock", {lock: true, placeholder: `Installing ffmpeg version: ${remoteVersion}. Preparing...`})
|
||||||
await this.downloadUpdate(remoteFfmpegUrl, "ffmpeg" + this.getFileExtension());
|
await this.downloadUpdate(remoteFfmpegUrl, remoteVersion, "ffmpeg" + this.getFileExtension());
|
||||||
await this.downloadUpdate(remoteFfprobeUrl, "ffprobe" + this.getFileExtension());
|
this.win.webContents.send("binaryLock", {lock: true, placeholder: `Installing ffprobe version: ${remoteVersion}. Preparing...`})
|
||||||
|
await this.downloadUpdate(remoteFfprobeUrl, remoteVersion, "ffprobe" + this.getFileExtension());
|
||||||
await this.writeVersionInfo(remoteVersion);
|
await this.writeVersionInfo(remoteVersion);
|
||||||
} else if(remoteVersion == null) {
|
} else if(remoteVersion == null) {
|
||||||
transaction.setTag("download", "down");
|
transaction.setTag("download", "down");
|
||||||
@@ -41,9 +44,11 @@ class FfmpegUpdater {
|
|||||||
} else {
|
} else {
|
||||||
console.log(`New version ${remoteVersion} found. Updating...`);
|
console.log(`New version ${remoteVersion} found. Updating...`);
|
||||||
transaction.setTag("download", "update");
|
transaction.setTag("download", "update");
|
||||||
this.win.webContents.send("binaryLock", {lock: true, placeholder: `Updating ffmpeg to version: ${remoteVersion}...`})
|
this.action = "Updating to";
|
||||||
await this.downloadUpdate(remoteFfmpegUrl, "ffmpeg" + this.getFileExtension());
|
this.win.webContents.send("binaryLock", {lock: true, placeholder: `Updating ffmpeg to version: ${remoteVersion}. Preparing...`})
|
||||||
await this.downloadUpdate(remoteFfprobeUrl, "ffprobe" + this.getFileExtension());
|
await this.downloadUpdate(remoteFfmpegUrl, remoteVersion, "ffmpeg" + this.getFileExtension());
|
||||||
|
this.win.webContents.send("binaryLock", {lock: true, placeholder: `Updating ffprobe to version: ${remoteVersion}. Preparing...`})
|
||||||
|
await this.downloadUpdate(remoteFfprobeUrl, remoteVersion, "ffprobe" + this.getFileExtension());
|
||||||
await this.writeVersionInfo(remoteVersion);
|
await this.writeVersionInfo(remoteVersion);
|
||||||
}
|
}
|
||||||
span.finish();
|
span.finish();
|
||||||
@@ -106,27 +111,37 @@ class FfmpegUpdater {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//Downloads the file at the given url and saves it to the ffmpeg path.
|
//Downloads the file at the given url and saves it to the ffmpeg path.
|
||||||
async downloadUpdate(url, filename) {
|
async downloadUpdate(url, version, filename) {
|
||||||
const downloadPath = path.join(this.paths.ffmpeg, "downloads");
|
const downloadPath = path.join(this.paths.ffmpeg, "downloads");
|
||||||
if (!fs.existsSync(downloadPath)) {
|
if (!fs.existsSync(downloadPath)) {
|
||||||
fs.mkdirSync(downloadPath);
|
fs.mkdirSync(downloadPath);
|
||||||
}
|
}
|
||||||
const writer = fs.createWriteStream(path.join(downloadPath, filename));
|
const writer = fs.createWriteStream(path.join(downloadPath, filename));
|
||||||
await axios.get(url, {responseType: 'stream'}).then(response => {
|
|
||||||
return new Promise((resolve, reject) => {
|
const { data, headers } = await axios.get(url, {responseType: 'stream'});
|
||||||
response.data.pipe(writer);
|
const totalLength = +headers['content-length'];
|
||||||
let error = null;
|
const total = Utils.convertBytes(totalLength);
|
||||||
writer.on('error', err => {
|
const artifact = filename.replace(".exe", "");
|
||||||
error = err;
|
let received = 0;
|
||||||
reject(err);
|
await new Promise((resolve, reject) => {
|
||||||
});
|
let error = null;
|
||||||
writer.on('close', async () => {
|
data.on('data', (chunk) => {
|
||||||
if (!error) {
|
received += chunk.length;
|
||||||
resolve(true);
|
const percentage = ((received / totalLength) * 100).toFixed(0) + '%';
|
||||||
}
|
this.win.webContents.send("binaryLock", {lock: true, placeholder: `${this.action} ${artifact} ${version} - ${percentage} of ${total}`})
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
writer.on('error', err => {
|
||||||
|
error = err;
|
||||||
|
reject(err);
|
||||||
|
});
|
||||||
|
writer.on('close', async () => {
|
||||||
|
if (!error) {
|
||||||
|
resolve(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
data.pipe(writer);
|
||||||
});
|
});
|
||||||
|
this.win.webContents.send("binaryLock", {lock: true, placeholder: `${this.action} ${artifact} ${version} - Extracting binaries...`})
|
||||||
const zipFile = new AdmZip(path.join(downloadPath, filename), {});
|
const zipFile = new AdmZip(path.join(downloadPath, filename), {});
|
||||||
zipFile.extractEntryTo(filename, this.paths.ffmpeg, false, true, false, filename);
|
zipFile.extractEntryTo(filename, this.paths.ffmpeg, false, true, false, filename);
|
||||||
fs.rmdirSync(path.join(this.paths.ffmpeg, "downloads"), { recursive: true, force: true });
|
fs.rmdirSync(path.join(this.paths.ffmpeg, "downloads"), { recursive: true, force: true });
|
||||||
|
|||||||
@@ -136,7 +136,7 @@ describe("downloadUpdate", () => {
|
|||||||
const mockReadable = new PassThrough();
|
const mockReadable = new PassThrough();
|
||||||
const mockWriteable = new PassThrough();
|
const mockWriteable = new PassThrough();
|
||||||
jest.spyOn(fs, 'createWriteStream').mockReturnValueOnce(mockWriteable);
|
jest.spyOn(fs, 'createWriteStream').mockReturnValueOnce(mockWriteable);
|
||||||
jest.spyOn(axios, 'get').mockResolvedValue({ data: mockReadable });
|
jest.spyOn(axios, 'get').mockResolvedValue({ data: mockReadable, headers: { "content-length": 1200 } });
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
mockWriteable.emit('error', "Test error");
|
mockWriteable.emit('error', "Test error");
|
||||||
}, 100);
|
}, 100);
|
||||||
@@ -150,7 +150,7 @@ describe("downloadUpdate", () => {
|
|||||||
const mockReadable = new PassThrough();
|
const mockReadable = new PassThrough();
|
||||||
const mockWriteable = new PassThrough();
|
const mockWriteable = new PassThrough();
|
||||||
jest.spyOn(fs, 'createWriteStream').mockReturnValueOnce(mockWriteable);
|
jest.spyOn(fs, 'createWriteStream').mockReturnValueOnce(mockWriteable);
|
||||||
jest.spyOn(axios, 'get').mockResolvedValue({ data: mockReadable });
|
jest.spyOn(axios, 'get').mockResolvedValue({ data: mockReadable, headers: { "content-length": 1200 } });
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
mockWriteable.emit('close');
|
mockWriteable.emit('close');
|
||||||
}, 100);
|
}, 100);
|
||||||
|
|||||||
@@ -106,7 +106,7 @@ describe('checkUpdate', () => {
|
|||||||
jest.spyOn(instance, 'getRemoteVersion').mockResolvedValue(["link", "v2.0.0"]);
|
jest.spyOn(instance, 'getRemoteVersion').mockResolvedValue(["link", "v2.0.0"]);
|
||||||
return instance.checkUpdate().then(() => {
|
return instance.checkUpdate().then(() => {
|
||||||
expect(downloadUpdateSpy).toBeCalledTimes(2);
|
expect(downloadUpdateSpy).toBeCalledTimes(2);
|
||||||
expect(instance.win.webContents.send).toBeCalledTimes(1);
|
expect(instance.win.webContents.send).toBeCalledTimes(2);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
it('downloads the latest remote version when local version is different', () => {
|
it('downloads the latest remote version when local version is different', () => {
|
||||||
@@ -117,7 +117,7 @@ describe('checkUpdate', () => {
|
|||||||
jest.spyOn(instance, 'getRemoteVersion').mockResolvedValue({ remoteUrl: "link", remoteVersion: "2021.10.10" });
|
jest.spyOn(instance, 'getRemoteVersion').mockResolvedValue({ remoteUrl: "link", remoteVersion: "2021.10.10" });
|
||||||
return instance.checkUpdate().then(() => {
|
return instance.checkUpdate().then(() => {
|
||||||
expect(downloadUpdateSpy).toBeCalledTimes(2);
|
expect(downloadUpdateSpy).toBeCalledTimes(2);
|
||||||
expect(instance.win.webContents.send).toBeCalledTimes(1);
|
expect(instance.win.webContents.send).toBeCalledTimes(2);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user