download progress bar on taskbar

+ Get the best possible artwork
This commit is contained in:
Araxeus
2021-05-08 07:11:54 +03:00
parent 2168cbca30
commit a8ac2c3af9
6 changed files with 62 additions and 19 deletions

View File

@ -2,6 +2,7 @@ const CHANNEL = "downloader";
const ACTIONS = { const ACTIONS = {
ERROR: "error", ERROR: "error",
METADATA: "metadata", METADATA: "metadata",
PROGRESS: "progress",
}; };
module.exports = { module.exports = {

View File

@ -6,10 +6,11 @@ const { dialog, ipcMain } = require("electron");
const getSongInfo = require("../../providers/song-info"); const getSongInfo = require("../../providers/song-info");
const { injectCSS, listenAction } = require("../utils"); const { injectCSS, listenAction } = require("../utils");
const { cropMaxWidth } = require("./utils");
const { ACTIONS, CHANNEL } = require("./actions.js"); const { ACTIONS, CHANNEL } = require("./actions.js");
const { getImage } = require("../../providers/song-info"); const { getImage } = require("../../providers/song-info");
const sendError = (win, err) => { const sendError = (err) => {
const dialogOpts = { const dialogOpts = {
type: "info", type: "info",
buttons: ["OK"], buttons: ["OK"],
@ -17,6 +18,7 @@ const sendError = (win, err) => {
message: "Argh! Apologies, download failed…", message: "Argh! Apologies, download failed…",
detail: err.toString(), detail: err.toString(),
}; };
win.setProgressBar(-1); // close progress bar
dialog.showMessageBox(dialogOpts); dialog.showMessageBox(dialogOpts);
}; };
@ -29,14 +31,17 @@ function handle(win) {
metadata = info; metadata = info;
}); });
listenAction(CHANNEL, (event, action, error) => { listenAction(CHANNEL, (event, action, arg) => {
switch (action) { switch (action) {
case ACTIONS.ERROR: case ACTIONS.ERROR: //arg = error
sendError(win, error); sendError(arg);
break; break;
case ACTIONS.METADATA: case ACTIONS.METADATA:
event.returnValue = JSON.stringify(metadata); event.returnValue = JSON.stringify(metadata);
break; break;
case ACTIONS.PROGRESS: //arg = progress
win.setProgressBar(arg);
break;
default: default:
console.log("Unknown action: " + action); console.log("Unknown action: " + action);
} }
@ -46,7 +51,7 @@ function handle(win) {
let fileBuffer = songBuffer; let fileBuffer = songBuffer;
if (currentMetadata.imageSrc) { if (currentMetadata.imageSrc) {
currentMetadata.image = await getImage(currentMetadata.imageSrc); currentMetadata.image = cropMaxWidth(await getImage(currentMetadata.imageSrc));
} }
const songMetadata = { ...metadata, ...currentMetadata }; const songMetadata = { ...metadata, ...currentMetadata };
@ -69,7 +74,7 @@ function handle(win) {
writer.addTag(); writer.addTag();
fileBuffer = Buffer.from(writer.arrayBuffer); fileBuffer = Buffer.from(writer.arrayBuffer);
} catch (error) { } catch (error) {
sendError(win, error); sendError(error);
} }
writeFileSync(filePath, fileBuffer); writeFileSync(filePath, fileBuffer);

View File

@ -25,6 +25,7 @@ const observer = new MutationObserver((mutations, observer) => {
}); });
const reinit = () => { const reinit = () => {
triggerAction(CHANNEL, ACTIONS.PROGRESS, -1); // closes progress bar
if (!progress) { if (!progress) {
console.warn("Cannot update progress"); console.warn("Cannot update progress");
} else { } else {
@ -38,6 +39,7 @@ const baseUrl = defaultConfig.url;
// contextBridge.exposeInMainWorld("downloader", { // contextBridge.exposeInMainWorld("downloader", {
// download: () => { // download: () => {
global.download = () => { global.download = () => {
triggerAction(CHANNEL, ACTIONS.PROGRESS, 2); // starts with indefinite progress bar
let metadata; let metadata;
let videoUrl = getSongMenu() let videoUrl = getSongMenu()
?.querySelector('ytmusic-menu-navigation-item-renderer.iron-selected[tabindex="0"]') ?.querySelector('ytmusic-menu-navigation-item-renderer.iron-selected[tabindex="0"]')
@ -53,12 +55,15 @@ global.download = () => {
downloadVideoToMP3( downloadVideoToMP3(
videoUrl, videoUrl,
(feedback) => { (feedback, ratio = undefined) => {
if (!progress) { if (!progress) {
console.warn("Cannot update progress"); console.warn("Cannot update progress");
} else { } else {
progress.innerHTML = feedback; progress.innerHTML = feedback;
} }
if (ratio) {
triggerAction(CHANNEL, ACTIONS.PROGRESS, ratio);
}
}, },
(error) => { (error) => {
triggerAction(CHANNEL, ACTIONS.ERROR, error); triggerAction(CHANNEL, ACTIONS.ERROR, error);

View File

@ -32,7 +32,7 @@ module.exports = (win, options) => {
const currentURL = metadataURL || win.webContents.getURL(); const currentURL = metadataURL || win.webContents.getURL();
const playlistID = new URL(currentURL).searchParams.get("list"); const playlistID = new URL(currentURL).searchParams.get("list");
if (!playlistID) { if (!playlistID) {
sendError(win, new Error("No playlist ID found")); sendError(new Error("No playlist ID found"));
return; return;
} }
@ -46,7 +46,6 @@ module.exports = (win, options) => {
const playlistFolder = join(folder, playlistTitle); const playlistFolder = join(folder, playlistTitle);
if (existsSync(playlistFolder)) { if (existsSync(playlistFolder)) {
sendError( sendError(
win,
new Error(`The folder ${playlistFolder} already exists`) new Error(`The folder ${playlistFolder} already exists`)
); );
return; return;

View File

@ -3,3 +3,33 @@ const electron = require("electron");
module.exports.getFolder = (customFolder) => module.exports.getFolder = (customFolder) =>
customFolder || (electron.app || electron.remote.app).getPath("downloads"); customFolder || (electron.app || electron.remote.app).getPath("downloads");
module.exports.defaultMenuDownloadLabel = "Download playlist"; module.exports.defaultMenuDownloadLabel = "Download playlist";
module.exports.UrlToJPG = (imgUrl, videoId) => {
if (!imgUrl || imgUrl.includes(".jpg")) return imgUrl;
if (imgUrl.includes("maxresdefault")) {
return "https://img.youtube.com/vi/"+videoId+"/maxresdefault.jpg";
}
if (imgUrl.includes("hqdefault")) {
return "https://img.youtube.com/vi/"+videoId+"/hqdefault.jpg";
} //it will almost never get further than hq
if (imgUrl.includes("mqdefault")) {
return "https://img.youtube.com/vi/"+videoId+"/mqdefault.jpg";
}
if (imgUrl.includes("sdddefault")) {
return "https://img.youtube.com/vi/"+videoId+"/sdddefault.jpg";
}
return "https://img.youtube.com/vi/"+videoId+"/default.jpg";
}
module.exports.cropMaxWidth = (image) => {
const imageSize = image.getSize();
if (imageSize.width === 1280 && imageSize.height === 720) {
return image.crop({
x: 280,
y: 0,
width: 720,
height: 720
});
}
return image;
}

View File

@ -14,7 +14,7 @@ const ytdl = require("ytdl-core");
const { triggerAction, triggerActionSync } = require("../utils"); const { triggerAction, triggerActionSync } = require("../utils");
const { ACTIONS, CHANNEL } = require("./actions.js"); const { ACTIONS, CHANNEL } = require("./actions.js");
const { getFolder } = require("./utils"); const { getFolder, UrlToJPG } = require("./utils");
const { cleanupArtistName } = require("../../providers/song-info"); const { cleanupArtistName } = require("../../providers/song-info");
const { createFFmpeg } = FFmpeg; const { createFFmpeg } = FFmpeg;
@ -37,12 +37,14 @@ const downloadVideoToMP3 = async (
sendFeedback("Downloading…"); sendFeedback("Downloading…");
if (metadata === null) { if (metadata === null) {
const info = await ytdl.getInfo(videoUrl); const { videoDetails } = await ytdl.getInfo(videoUrl);
const thumbnails = info.videoDetails?.author?.thumbnails; const thumbnails = videoDetails?.thumbnails;
metadata = { metadata = {
artist: info.videoDetails?.media?.artist || cleanupArtistName(info.videoDetails?.author?.name) || "", artist: videoDetails?.media?.artist || cleanupArtistName(videoDetails?.author?.name) || "",
title: info.videoDetails?.media?.song || info.videoDetails?.title || "", title: videoDetails?.media?.song || videoDetails?.title || "",
imageSrc: thumbnails ? thumbnails[thumbnails.length - 1].url : "" imageSrc: thumbnails ?
UrlToJPG(thumbnails[thumbnails.length - 1].url, videoDetails?.videoId)
: ""
} }
} }
@ -65,9 +67,10 @@ const downloadVideoToMP3 = async (
.on("data", (chunk) => { .on("data", (chunk) => {
chunks.push(chunk); chunks.push(chunk);
}) })
.on("progress", (chunkLength, downloaded, total) => { .on("progress", (_chunkLength, downloaded, total) => {
const progress = Math.floor((downloaded / total) * 100); const ratio = downloaded / total;
sendFeedback("Download: " + progress + "%"); const progress = Math.floor(ratio * 100);
sendFeedback("Download: " + progress + "%", ratio);
}) })
.on("info", (info, format) => { .on("info", (info, format) => {
videoName = info.videoDetails.title.replace("|", "").toString("ascii"); videoName = info.videoDetails.title.replace("|", "").toString("ascii");
@ -112,7 +115,7 @@ const toMP3 = async (
try { try {
if (!ffmpeg.isLoaded()) { if (!ffmpeg.isLoaded()) {
sendFeedback("Loading…"); sendFeedback("Loading…", 2); // indefinite progress bar after download
await ffmpeg.load(); await ffmpeg.load();
} }