From 6987a0a58502ead999db2b83db7533e70ff6f06f Mon Sep 17 00:00:00 2001 From: TC Date: Mon, 29 Mar 2021 21:32:41 +0200 Subject: [PATCH 1/5] Set isPaused default to undefined --- providers/song-info.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/providers/song-info.js b/providers/song-info.js index b2764508..6852ef09 100644 --- a/providers/song-info.js +++ b/providers/song-info.js @@ -36,7 +36,7 @@ const songInfo = { uploadDate: "", imageSrc: "", image: null, - isPaused: true, + isPaused: undefined, songDuration: 0, elapsedSeconds: 0, url: "", From 7ac9fda1eb370ffdd2e52375c3c2f39f73efdf74 Mon Sep 17 00:00:00 2001 From: TC Date: Mon, 29 Mar 2021 21:33:07 +0200 Subject: [PATCH 2/5] Send back metadata to front --- providers/song-info.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/providers/song-info.js b/providers/song-info.js index 6852ef09..55d87112 100644 --- a/providers/song-info.js +++ b/providers/song-info.js @@ -42,7 +42,7 @@ const songInfo = { url: "", }; -const handleData = async (_event, responseText) => { +const handleData = async (responseText, win) => { let data = JSON.parse(responseText); songInfo.title = data?.videoDetails?.title; songInfo.artist = data?.videoDetails?.author; @@ -52,6 +52,8 @@ const handleData = async (_event, responseText) => { songInfo.image = await getImage(songInfo.imageSrc); songInfo.uploadDate = data?.microformat?.microformatDataRenderer?.uploadDate; songInfo.url = data?.microformat?.microformatDataRenderer?.urlCanonical; + + win.webContents.send("update-song-info", JSON.stringify(songInfo)); }; const registerProvider = (win) => { @@ -77,7 +79,10 @@ const registerProvider = (win) => { }); // This will be called when the song-info-front finds a new request with song data - ipcMain.on("song-info-request", handleData); + ipcMain.on( + "song-info-request", + async (_, responseText) => await handleData(responseText, win) + ); return registerCallback; }; From 05eee7cb0f10c2a3503e15f7eeb2a77d6f50df9c Mon Sep 17 00:00:00 2001 From: TC Date: Mon, 29 Mar 2021 21:33:33 +0200 Subject: [PATCH 3/5] Store metadata in front --- providers/song-info-front.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/providers/song-info-front.js b/providers/song-info-front.js index 42c3afb2..43a0e0e2 100644 --- a/providers/song-info-front.js +++ b/providers/song-info-front.js @@ -1,5 +1,11 @@ const { ipcRenderer } = require("electron"); +global.songInfo = {}; + +ipcRenderer.on("update-song-info", (_, extractedSongInfo) => { + global.songInfo = JSON.parse(extractedSongInfo); +}); + const injectListener = () => { var oldXHR = window.XMLHttpRequest; function newXHR() { From ebe8755613e94000850877a786005ae172e51ec6 Mon Sep 17 00:00:00 2001 From: TC Date: Mon, 29 Mar 2021 21:59:45 +0200 Subject: [PATCH 4/5] Song provider: call callbacks when data is updated --- providers/song-info.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/providers/song-info.js b/providers/song-info.js index 55d87112..9a07ff28 100644 --- a/providers/song-info.js +++ b/providers/song-info.js @@ -79,10 +79,12 @@ const registerProvider = (win) => { }); // This will be called when the song-info-front finds a new request with song data - ipcMain.on( - "song-info-request", - async (_, responseText) => await handleData(responseText, win) - ); + ipcMain.on("song-info-request", async (_, responseText) => { + await handleData(responseText, win); + callbacks.forEach((c) => { + c(songInfo); + }); + }); return registerCallback; }; From 640f14637305a244f347bfb2968b2d2b9749253d Mon Sep 17 00:00:00 2001 From: TC Date: Mon, 29 Mar 2021 22:00:49 +0200 Subject: [PATCH 5/5] Use metadata URL in downloader (fallback to current URL) --- plugins/downloader/front.js | 2 +- plugins/downloader/menu.js | 123 ++++++++++++++++++++---------------- 2 files changed, 69 insertions(+), 56 deletions(-) diff --git a/plugins/downloader/front.js b/plugins/downloader/front.js index 77485d4a..17b2846b 100644 --- a/plugins/downloader/front.js +++ b/plugins/downloader/front.js @@ -35,7 +35,7 @@ const reinit = () => { // contextBridge.exposeInMainWorld("downloader", { // download: () => { global.download = () => { - const videoUrl = window.location.href; + const videoUrl = global.songInfo.url || window.location.href; downloadVideoToMP3( videoUrl, diff --git a/plugins/downloader/menu.js b/plugins/downloader/menu.js index 06a3c124..b4800808 100644 --- a/plugins/downloader/menu.js +++ b/plugins/downloader/menu.js @@ -7,71 +7,84 @@ const is = require("electron-is"); const ytpl = require("ytpl"); const { setOptions } = require("../../config/plugins"); +const getSongInfo = require("../../providers/song-info"); const { sendError } = require("./back"); const { defaultMenuDownloadLabel, getFolder } = require("./utils"); let downloadLabel = defaultMenuDownloadLabel; +let metadataURL = undefined; +let callbackIsRegistered = false; -module.exports = (win, options, refreshMenu) => [ - { - label: downloadLabel, - click: async () => { - const currentURL = win.webContents.getURL(); - const playlistID = new URL(currentURL).searchParams.get("list"); - if (!playlistID) { - sendError(win, new Error("No playlist ID found")); - return; - } +module.exports = (win, options, refreshMenu) => { + if (!callbackIsRegistered) { + const registerCallback = getSongInfo(win); + registerCallback((info) => { + metadataURL = info.url; + }); + callbackIsRegistered = true; + } - const playlist = await ytpl(playlistID); - const playlistTitle = playlist.title; + return [ + { + label: downloadLabel, + click: async () => { + const currentURL = metadataURL || win.webContents.getURL(); + const playlistID = new URL(currentURL).searchParams.get("list"); + if (!playlistID) { + sendError(win, new Error("No playlist ID found")); + return; + } - const folder = getFolder(options.downloadFolder); - const playlistFolder = join(folder, playlistTitle); - if (existsSync(playlistFolder)) { - sendError( - win, - new Error(`The folder ${playlistFolder} already exists`) - ); - return; - } - mkdirSync(playlistFolder, { recursive: true }); + const playlist = await ytpl(playlistID); + const playlistTitle = playlist.title; - ipcMain.on("downloader-feedback", (_, feedback) => { - downloadLabel = feedback; + const folder = getFolder(options.downloadFolder); + const playlistFolder = join(folder, playlistTitle); + if (existsSync(playlistFolder)) { + sendError( + win, + new Error(`The folder ${playlistFolder} already exists`) + ); + return; + } + mkdirSync(playlistFolder, { recursive: true }); + + ipcMain.on("downloader-feedback", (_, feedback) => { + downloadLabel = feedback; + refreshMenu(); + }); + + downloadLabel = `Downloading "${playlistTitle}"`; refreshMenu(); - }); - downloadLabel = `Downloading "${playlistTitle}"`; - refreshMenu(); + if (is.dev()) { + console.log( + `Downloading playlist "${playlistTitle}" (${playlist.items.length} songs)` + ); + } - if (is.dev()) { - console.log( - `Downloading playlist "${playlistTitle}" (${playlist.items.length} songs)` - ); - } - - playlist.items.slice(0, options.playlistMaxItems).forEach((song) => { - win.webContents.send( - "downloader-download-playlist", - song, - playlistTitle, - options - ); - }); + playlist.items.slice(0, options.playlistMaxItems).forEach((song) => { + win.webContents.send( + "downloader-download-playlist", + song, + playlistTitle, + options + ); + }); + }, }, - }, - { - label: "Choose download folder", - click: () => { - let result = dialog.showOpenDialogSync({ - properties: ["openDirectory", "createDirectory"], - defaultPath: getFolder(options.downloadFolder), - }); - if (result) { - options.downloadFolder = result[0]; - setOptions("downloader", options); - } // else = user pressed cancel + { + label: "Choose download folder", + click: () => { + let result = dialog.showOpenDialogSync({ + properties: ["openDirectory", "createDirectory"], + defaultPath: getFolder(options.downloadFolder), + }); + if (result) { + options.downloadFolder = result[0]; + setOptions("downloader", options); + } // else = user pressed cancel + }, }, - }, -]; + ]; +};