From e6efddc63914a4ee46e8746c87ad7f7ebe1730b6 Mon Sep 17 00:00:00 2001 From: Araxeus Date: Thu, 8 Apr 2021 16:54:46 +0300 Subject: [PATCH 01/17] add windows interactive notifications --- config/defaults.js | 3 +- package.json | 1 + plugins/notifications/back.js | 29 +++++---- plugins/notifications/interactive.js | 96 ++++++++++++++++++++++++++++ plugins/notifications/menu.js | 13 +++- plugins/notifications/utils.js | 54 +++++++++++++--- yarn.lock | 12 ++++ 7 files changed, 186 insertions(+), 22 deletions(-) create mode 100644 plugins/notifications/interactive.js diff --git a/config/defaults.js b/config/defaults.js index fb87e566..e90b36a5 100644 --- a/config/defaults.js +++ b/config/defaults.js @@ -44,7 +44,8 @@ const defaultConfig = { notifications: { enabled: false, urgency: "normal", - unpauseNotification: false + unpauseNotification: false, + interactive: true } }, }; diff --git a/package.json b/package.json index ce144c38..467217db 100644 --- a/package.json +++ b/package.json @@ -79,6 +79,7 @@ "electron-updater": "^4.3.6", "filenamify": "^4.2.0", "node-fetch": "^2.6.1", + "node-notifier": "^9.0.1", "ytdl-core": "^4.4.5", "ytpl": "^2.0.5" }, diff --git a/plugins/notifications/back.js b/plugins/notifications/back.js index dedd9379..9e1b3fd1 100644 --- a/plugins/notifications/back.js +++ b/plugins/notifications/back.js @@ -1,18 +1,17 @@ const { Notification } = require("electron"); +const is = require("electron-is"); const getSongInfo = require("../../providers/song-info"); +const { notificationImage } = require("./utils"); + +const { setup, notifyInteractive } = require("./interactive") const notify = (info, options) => { - let notificationImage = "assets/youtube-music.png"; - - if (info.image) { - notificationImage = info.image.resize({ height: 256, width: 256 }); - } // Fill the notification with content const notification = { title: info.title || "Playing", body: info.artist, - icon: notificationImage, + icon: notificationImage(info), silent: true, urgency: options.urgency, }; @@ -25,6 +24,10 @@ const notify = (info, options) => { }; module.exports = (win, options) => { + //setup interactive notifications for windows + if (is.windows()) { + setup(win); + } const registerCallback = getSongInfo(win); let oldNotification; let oldURL = ""; @@ -39,13 +42,17 @@ module.exports = (win, options) => { } return; } - // If url isn't the same as last one - send notification + // If url isn"t the same as last one - send notification if (songInfo.url !== oldURL) { oldURL = songInfo.url; - // Close the old notification - oldNotification?.close(); - // This fixes a weird bug that would cause the notification to be updated instead of showing - setTimeout(()=>{ oldNotification = notify(songInfo, options) }, 10); + if (is.windows() && options.interactive) { + notifyInteractive(songInfo); + } else { + // Close the old notification + oldNotification?.close(); + // This fixes a weird bug that would cause the notification to be updated instead of showing + setTimeout(() => { oldNotification = notify(songInfo, options) }, 10); + } } }); }); diff --git a/plugins/notifications/interactive.js b/plugins/notifications/interactive.js new file mode 100644 index 00000000..47b7c57c --- /dev/null +++ b/plugins/notifications/interactive.js @@ -0,0 +1,96 @@ +const is = require("electron-is"); +const { app } = require("electron"); +const { notificationImage, icons } = require("./utils"); +const getSongControls = require('../../providers/song-controls'); +const notifier = require("node-notifier"); + +const appID = "com.github.th-ch.youtube-music"; +const shortcutPath = `("Youtube Music" "${app.getPath("exe")}" "${appID}")`; + +//saving controls here avoid errors +let controls; + +//delete old notification +let toDelete; +function Delete() { + if (toDelete === undefined) { + return; + } + const removeNotif = Object.assign(toDelete, { + remove: toDelete.id + }) + notifier.notify(removeNotif) + + toDelete = undefined; +} + +//Setup on launch +module.exports.setup = (win) => { + //save controls + const { playPause, next, previous } = getSongControls(win); + controls = { playPause, next, previous }; + //setup global listeners + notifier.on("dismissed", () => { Delete(); }); + notifier.on("timeout", () => { Delete(); }); + //try installing shortcut + if (!is.dev()) { + notifier.notify({ + title: "installing shortcut", + id: 1337, + install: shortcutPath + }); + } + + //close all listeners on close + win.on("closed", () => { + notifier.removeAllListeners(); + }); +} + +//New notification +module.exports.notifyInteractive = function sendToaster(songInfo) { + Delete(); + //download image and get path + let imgSrc = notificationImage(songInfo, true); + toDelete = { + appID: !is.dev() ? appID : undefined, //(will break action buttons if not installed to start menu) + title: songInfo.title || "Playing", + message: songInfo.artist, + id: parseInt(Math.random() * 1000000, 10), + icon: imgSrc, + actions: [ + icons.previous, // Previous + songInfo.isPaused ? icons.play : icons.pause, + icons.next // Next + ], + sound: false, + }; + //send notification + notifier.notify( + toDelete, + (err, data) => { + // Will also wait until notification is closed. + if (err) { + console.log(`ERROR = ${err}\n DATA = ${data}`); + } + switch (data) { + case icons.previous.normalize(): + controls.previous(); + return; + case icons.next.normalize(): + controls.next(); + return; + case icons.play.normalize(): + controls.playPause(); + toDelete = undefined; // dont delete notification on play/pause + return; + case icons.pause.normalize(): + controls.playPause(); + songInfo.isPaused = true; + toDelete = undefined; // it gets deleted automatically + sendToaster(songInfo); + } + } + + ); +} diff --git a/plugins/notifications/menu.js b/plugins/notifications/menu.js index a61cac67..bc2eab67 100644 --- a/plugins/notifications/menu.js +++ b/plugins/notifications/menu.js @@ -1,4 +1,5 @@ -const {urgencyLevels, setUrgency, setUnpause} = require("./utils"); +const {urgencyLevels, setUrgency, setUnpause, setInteractive} = require("./utils"); +const is = require("electron-is"); module.exports = (win, options) => [ { @@ -15,5 +16,13 @@ module.exports = (win, options) => [ type: "checkbox", checked: options.unpauseNotification, click: (item) => setUnpause(options, item.checked) - } + }, + ...(is.windows() ? + [{ + label: "Interactive", + type: "checkbox", + checked: options.interactive, + click: (item) => setInteractive(options, item.checked) + }] : + []) ]; diff --git a/plugins/notifications/utils.js b/plugins/notifications/utils.js index c43ecb20..d48f8319 100644 --- a/plugins/notifications/utils.js +++ b/plugins/notifications/utils.js @@ -1,19 +1,57 @@ -const {setOptions} = require("../../config/plugins"); +const { setOptions } = require("../../config/plugins"); +const path = require("path"); +const { app } = require("electron"); +const icon = path.join(__dirname, "assets", "youtube-music.png"); +const fs = require("fs"); + +const tempIcon = path.join(app.getPath("userData"), "tempIcon.png"); module.exports.urgencyLevels = [ - {name: "Low", value: "low"}, - {name: "Normal", value: "normal"}, - {name: "High", value: "critical"}, + { name: "Low", value: "low" }, + { name: "Normal", value: "normal" }, + { name: "High", value: "critical" }, ]; module.exports.setUrgency = (options, level) => { - options.urgency = level - setOption(options) + options.urgency = level; + setOption(options); }; module.exports.setUnpause = (options, value) => { - options.unpauseNotification = value - setOption(options) + options.unpauseNotification = value; + setOption(options); +}; +module.exports.setInteractive = (options, value) => { + options.interactive = value; + setOption(options); +} + +module.exports.notificationImage = function (songInfo, url = false) { + //return local url + if (!!songInfo && url) { + try { + fs.writeFileSync(tempIcon, + songInfo.image + .resize({ height: 256, width: 256 }) + .toPNG() + ); + } catch (err) { + console.log(`Error downloading song icon:\n${err.toString()}`) + return icon; + } + return tempIcon; + } + //else: return image + return songInfo.image + ? songInfo.image.resize({ height: 256, width: 256 }) + : icon }; let setOption = options => { setOptions("notifications", options) }; + +module.exports.icons = { + play: "\u{1405}", // ᐅ + pause: "\u{2016}", // ‖ + next: "\u{1433}", // ᐳ + previous: "\u{1438}" // ᐸ +} \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index c969527e..188f3193 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6335,6 +6335,18 @@ node-notifier@^8.0.0: uuid "^8.3.0" which "^2.0.2" +node-notifier@^9.0.1: + version "9.0.1" + resolved "https://registry.yarnpkg.com/node-notifier/-/node-notifier-9.0.1.tgz#cea837f4c5e733936c7b9005e6545cea825d1af4" + integrity sha512-fPNFIp2hF/Dq7qLDzSg4vZ0J4e9v60gJR+Qx7RbjbWqzPDdEqeVpEx5CFeDAELIl+A/woaaNn1fQ5nEVerMxJg== + dependencies: + growly "^1.3.0" + is-wsl "^2.2.0" + semver "^7.3.2" + shellwords "^0.1.1" + uuid "^8.3.0" + which "^2.0.2" + noop-logger@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/noop-logger/-/noop-logger-0.1.1.tgz#94a2b1633c4f1317553007d8966fd0e841b6a4c2" From 30675e0567525c5161fa6f54f44d32157ade2f43 Mon Sep 17 00:00:00 2001 From: Araxeus Date: Thu, 8 Apr 2021 18:56:13 +0300 Subject: [PATCH 02/17] remove appID because of bug: Button would not transmit event --- plugins/notifications/interactive.js | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/plugins/notifications/interactive.js b/plugins/notifications/interactive.js index 47b7c57c..b27f6207 100644 --- a/plugins/notifications/interactive.js +++ b/plugins/notifications/interactive.js @@ -1,13 +1,9 @@ const is = require("electron-is"); -const { app } = require("electron"); const { notificationImage, icons } = require("./utils"); const getSongControls = require('../../providers/song-controls'); const notifier = require("node-notifier"); -const appID = "com.github.th-ch.youtube-music"; -const shortcutPath = `("Youtube Music" "${app.getPath("exe")}" "${appID}")`; - -//saving controls here avoid errors +//store song controls let controls; //delete old notification @@ -32,16 +28,8 @@ module.exports.setup = (win) => { //setup global listeners notifier.on("dismissed", () => { Delete(); }); notifier.on("timeout", () => { Delete(); }); - //try installing shortcut - if (!is.dev()) { - notifier.notify({ - title: "installing shortcut", - id: 1337, - install: shortcutPath - }); - } - //close all listeners on close + //remove all listeners on close win.on("closed", () => { notifier.removeAllListeners(); }); @@ -53,7 +41,7 @@ module.exports.notifyInteractive = function sendToaster(songInfo) { //download image and get path let imgSrc = notificationImage(songInfo, true); toDelete = { - appID: !is.dev() ? appID : undefined, //(will break action buttons if not installed to start menu) + //app id undefined - will break buttons title: songInfo.title || "Playing", message: songInfo.artist, id: parseInt(Math.random() * 1000000, 10), @@ -69,6 +57,7 @@ module.exports.notifyInteractive = function sendToaster(songInfo) { notifier.notify( toDelete, (err, data) => { + console.log("clicked "+data); // Will also wait until notification is closed. if (err) { console.log(`ERROR = ${err}\n DATA = ${data}`); From d8dc4656e469fa6a4eaf99a714932a476a136c8b Mon Sep 17 00:00:00 2001 From: Araxeus Date: Fri, 9 Apr 2021 01:08:22 +0300 Subject: [PATCH 03/17] stylecheck --- plugins/notifications/interactive.js | 2 -- plugins/notifications/menu.js | 2 +- plugins/notifications/utils.js | 6 +++--- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/plugins/notifications/interactive.js b/plugins/notifications/interactive.js index b27f6207..c41588ae 100644 --- a/plugins/notifications/interactive.js +++ b/plugins/notifications/interactive.js @@ -1,4 +1,3 @@ -const is = require("electron-is"); const { notificationImage, icons } = require("./utils"); const getSongControls = require('../../providers/song-controls'); const notifier = require("node-notifier"); @@ -57,7 +56,6 @@ module.exports.notifyInteractive = function sendToaster(songInfo) { notifier.notify( toDelete, (err, data) => { - console.log("clicked "+data); // Will also wait until notification is closed. if (err) { console.log(`ERROR = ${err}\n DATA = ${data}`); diff --git a/plugins/notifications/menu.js b/plugins/notifications/menu.js index bc2eab67..53a79a63 100644 --- a/plugins/notifications/menu.js +++ b/plugins/notifications/menu.js @@ -1,4 +1,4 @@ -const {urgencyLevels, setUrgency, setUnpause, setInteractive} = require("./utils"); +const { urgencyLevels, setUrgency, setUnpause, setInteractive } = require("./utils"); const is = require("electron-is"); module.exports = (win, options) => [ diff --git a/plugins/notifications/utils.js b/plugins/notifications/utils.js index d48f8319..42c406d9 100644 --- a/plugins/notifications/utils.js +++ b/plugins/notifications/utils.js @@ -24,9 +24,9 @@ module.exports.setInteractive = (options, value) => { setOption(options); } -module.exports.notificationImage = function (songInfo, url = false) { - //return local url - if (!!songInfo && url) { +module.exports.notificationImage = function (songInfo, saveIcon = false) { + //return local path to temp icon + if (saveIcon && !!songInfo.image) { try { fs.writeFileSync(tempIcon, songInfo.image From ba6244780c0a566ae366c4a8f46a8703dc57d8c6 Mon Sep 17 00:00:00 2001 From: Araxeus Date: Fri, 9 Apr 2021 02:14:11 +0300 Subject: [PATCH 04/17] minify --- plugins/notifications/back.js | 9 +++--- plugins/notifications/interactive.js | 45 +++++++++++++--------------- 2 files changed, 25 insertions(+), 29 deletions(-) diff --git a/plugins/notifications/back.js b/plugins/notifications/back.js index 9e1b3fd1..31162320 100644 --- a/plugins/notifications/back.js +++ b/plugins/notifications/back.js @@ -3,7 +3,7 @@ const is = require("electron-is"); const getSongInfo = require("../../providers/song-info"); const { notificationImage } = require("./utils"); -const { setup, notifyInteractive } = require("./interactive") +const { setupInteractive, notifyInteractive } = require("./interactive") const notify = (info, options) => { @@ -24,9 +24,10 @@ const notify = (info, options) => { }; module.exports = (win, options) => { + const isInteractive = is.windows() && options.interactive; //setup interactive notifications for windows - if (is.windows()) { - setup(win); + if (isInteractive) { + setupInteractive(win); } const registerCallback = getSongInfo(win); let oldNotification; @@ -45,7 +46,7 @@ module.exports = (win, options) => { // If url isn"t the same as last one - send notification if (songInfo.url !== oldURL) { oldURL = songInfo.url; - if (is.windows() && options.interactive) { + if (isInteractive) { notifyInteractive(songInfo); } else { // Close the old notification diff --git a/plugins/notifications/interactive.js b/plugins/notifications/interactive.js index c41588ae..06999153 100644 --- a/plugins/notifications/interactive.js +++ b/plugins/notifications/interactive.js @@ -2,40 +2,29 @@ const { notificationImage, icons } = require("./utils"); const getSongControls = require('../../providers/song-controls'); const notifier = require("node-notifier"); -//store song controls +//store song controls reference on launch let controls; +module.exports.setupInteractive = (win) => { + //save controls + const { playPause, next, previous } = getSongControls(win); + controls = { playPause, next, previous }; +} //delete old notification let toDelete; function Delete() { - if (toDelete === undefined) { - return; + if (toDelete !== undefined) { + const removeNotif = Object.assign(toDelete, { + remove: toDelete.id + }) + notifier.notify(removeNotif) + + toDelete = undefined; } - const removeNotif = Object.assign(toDelete, { - remove: toDelete.id - }) - notifier.notify(removeNotif) - - toDelete = undefined; -} - -//Setup on launch -module.exports.setup = (win) => { - //save controls - const { playPause, next, previous } = getSongControls(win); - controls = { playPause, next, previous }; - //setup global listeners - notifier.on("dismissed", () => { Delete(); }); - notifier.on("timeout", () => { Delete(); }); - - //remove all listeners on close - win.on("closed", () => { - notifier.removeAllListeners(); - }); } //New notification -module.exports.notifyInteractive = function sendToaster(songInfo) { +module.exports.notifyInteractive = (songInfo) => { Delete(); //download image and get path let imgSrc = notificationImage(songInfo, true); @@ -61,6 +50,7 @@ module.exports.notifyInteractive = function sendToaster(songInfo) { console.log(`ERROR = ${err}\n DATA = ${data}`); } switch (data) { + //buttons case icons.previous.normalize(): controls.previous(); return; @@ -76,6 +66,11 @@ module.exports.notifyInteractive = function sendToaster(songInfo) { songInfo.isPaused = true; toDelete = undefined; // it gets deleted automatically sendToaster(songInfo); + return; + //Native datatype + case "dismissed": + case "timeout": + Delete(); } } From 095196785a7ef2649014fa92fd1287d015ad886f Mon Sep 17 00:00:00 2001 From: Araxeus Date: Fri, 9 Apr 2021 02:32:14 +0300 Subject: [PATCH 05/17] add note to notifications.interactive --- config/defaults.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/defaults.js b/config/defaults.js index e90b36a5..f3cd7f04 100644 --- a/config/defaults.js +++ b/config/defaults.js @@ -45,7 +45,7 @@ const defaultConfig = { enabled: false, urgency: "normal", unpauseNotification: false, - interactive: true + interactive: true //has effect only on Windows 8+ } }, }; From 9c0a633677aced57ed1c365b93ba1eb63729b053 Mon Sep 17 00:00:00 2001 From: Araxeus Date: Fri, 9 Apr 2021 03:15:57 +0300 Subject: [PATCH 06/17] fix unPause option compatibility --- config/defaults.js | 2 +- plugins/notifications/back.js | 2 +- plugins/notifications/interactive.js | 24 +++++++++++++++++++----- plugins/notifications/utils.js | 2 +- 4 files changed, 22 insertions(+), 8 deletions(-) diff --git a/config/defaults.js b/config/defaults.js index f3cd7f04..57c001b1 100644 --- a/config/defaults.js +++ b/config/defaults.js @@ -45,7 +45,7 @@ const defaultConfig = { enabled: false, urgency: "normal", unpauseNotification: false, - interactive: true //has effect only on Windows 8+ + interactive: false //has effect only on Windows 8+ } }, }; diff --git a/plugins/notifications/back.js b/plugins/notifications/back.js index 31162320..38fbbbf8 100644 --- a/plugins/notifications/back.js +++ b/plugins/notifications/back.js @@ -27,7 +27,7 @@ module.exports = (win, options) => { const isInteractive = is.windows() && options.interactive; //setup interactive notifications for windows if (isInteractive) { - setupInteractive(win); + setupInteractive(win, options.unpauseNotification); } const registerCallback = getSongInfo(win); let oldNotification; diff --git a/plugins/notifications/interactive.js b/plugins/notifications/interactive.js index 06999153..b7ff461a 100644 --- a/plugins/notifications/interactive.js +++ b/plugins/notifications/interactive.js @@ -4,10 +4,14 @@ const notifier = require("node-notifier"); //store song controls reference on launch let controls; -module.exports.setupInteractive = (win) => { - //save controls +let onPause; + +//Save controls and onPause option +module.exports.setupInteractive = (win, unpauseNotification) => { const { playPause, next, previous } = getSongControls(win); controls = { playPause, next, previous }; + + onPause = unpauseNotification; } //delete old notification @@ -24,10 +28,13 @@ function Delete() { } //New notification -module.exports.notifyInteractive = (songInfo) => { +module.exports.notifyInteractive = function sendToaster(songInfo) { + console.log("called toaster"); Delete(); + console.log("deleted"); //download image and get path let imgSrc = notificationImage(songInfo, true); + console.log("got image"); toDelete = { //app id undefined - will break buttons title: songInfo.title || "Playing", @@ -41,6 +48,7 @@ module.exports.notifyInteractive = (songInfo) => { ], sound: false, }; + console.log("sending notification"); //send notification notifier.notify( toDelete, @@ -59,12 +67,18 @@ module.exports.notifyInteractive = (songInfo) => { return; case icons.play.normalize(): controls.playPause(); - toDelete = undefined; // dont delete notification on play/pause + // dont delete notification on play/pause + toDelete = undefined; + //manually send notification if not sending automatically + if (!onPause) { + songInfo.isPaused = false; + sendToaster(songInfo); + } return; case icons.pause.normalize(): controls.playPause(); songInfo.isPaused = true; - toDelete = undefined; // it gets deleted automatically + toDelete = undefined; sendToaster(songInfo); return; //Native datatype diff --git a/plugins/notifications/utils.js b/plugins/notifications/utils.js index 42c406d9..17b96091 100644 --- a/plugins/notifications/utils.js +++ b/plugins/notifications/utils.js @@ -1,9 +1,9 @@ const { setOptions } = require("../../config/plugins"); const path = require("path"); const { app } = require("electron"); -const icon = path.join(__dirname, "assets", "youtube-music.png"); const fs = require("fs"); +const icon = "assets/youtube-music.png"; const tempIcon = path.join(app.getPath("userData"), "tempIcon.png"); module.exports.urgencyLevels = [ From 18f041f1c63809fb06b7142e82cdea0aaab9409b Mon Sep 17 00:00:00 2001 From: Araxeus Date: Fri, 9 Apr 2021 03:26:46 +0300 Subject: [PATCH 07/17] clarify button purpose --- plugins/notifications/interactive.js | 12 ++++-------- plugins/notifications/menu.js | 2 +- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/plugins/notifications/interactive.js b/plugins/notifications/interactive.js index b7ff461a..879c0613 100644 --- a/plugins/notifications/interactive.js +++ b/plugins/notifications/interactive.js @@ -29,12 +29,9 @@ function Delete() { //New notification module.exports.notifyInteractive = function sendToaster(songInfo) { - console.log("called toaster"); Delete(); - console.log("deleted"); //download image and get path let imgSrc = notificationImage(songInfo, true); - console.log("got image"); toDelete = { //app id undefined - will break buttons title: songInfo.title || "Playing", @@ -42,20 +39,19 @@ module.exports.notifyInteractive = function sendToaster(songInfo) { id: parseInt(Math.random() * 1000000, 10), icon: imgSrc, actions: [ - icons.previous, // Previous + icons.previous, songInfo.isPaused ? icons.play : icons.pause, - icons.next // Next + icons.next ], sound: false, }; - console.log("sending notification"); //send notification notifier.notify( toDelete, (err, data) => { // Will also wait until notification is closed. if (err) { - console.log(`ERROR = ${err}\n DATA = ${data}`); + console.log(`ERROR = ${err.toString()}\n DATA = ${data}`); } switch (data) { //buttons @@ -68,7 +64,7 @@ module.exports.notifyInteractive = function sendToaster(songInfo) { case icons.play.normalize(): controls.playPause(); // dont delete notification on play/pause - toDelete = undefined; + toDelete = undefined; //manually send notification if not sending automatically if (!onPause) { songInfo.isPaused = false; diff --git a/plugins/notifications/menu.js b/plugins/notifications/menu.js index 53a79a63..ebc1f718 100644 --- a/plugins/notifications/menu.js +++ b/plugins/notifications/menu.js @@ -19,7 +19,7 @@ module.exports = (win, options) => [ }, ...(is.windows() ? [{ - label: "Interactive", + label: "Interactive Notifications", type: "checkbox", checked: options.interactive, click: (item) => setInteractive(options, item.checked) From e6d77c165e0103fb12fb3148dde472373bc55517 Mon Sep 17 00:00:00 2001 From: Araxeus Date: Fri, 9 Apr 2021 18:39:57 +0300 Subject: [PATCH 08/17] Center Icon on ALL notifications Delete notification on windowclosed Refactor notifications.utils.setOption --- plugins/notifications/interactive.js | 4 +++ plugins/notifications/menu.js | 8 ++--- plugins/notifications/utils.js | 49 ++++++++++++++-------------- 3 files changed, 32 insertions(+), 29 deletions(-) diff --git a/plugins/notifications/interactive.js b/plugins/notifications/interactive.js index 879c0613..d506463a 100644 --- a/plugins/notifications/interactive.js +++ b/plugins/notifications/interactive.js @@ -12,6 +12,10 @@ module.exports.setupInteractive = (win, unpauseNotification) => { controls = { playPause, next, previous }; onPause = unpauseNotification; + + win.webContents.on("closed", () => { + Delete() + }); } //delete old notification diff --git a/plugins/notifications/menu.js b/plugins/notifications/menu.js index ebc1f718..bfb8c809 100644 --- a/plugins/notifications/menu.js +++ b/plugins/notifications/menu.js @@ -1,4 +1,4 @@ -const { urgencyLevels, setUrgency, setUnpause, setInteractive } = require("./utils"); +const { urgencyLevels, setOption } = require("./utils"); const is = require("electron-is"); module.exports = (win, options) => [ @@ -8,21 +8,21 @@ module.exports = (win, options) => [ label: level.name, type: "radio", checked: options.urgency === level.value, - click: () => setUrgency(options, level.value) + click: () => setOption(options, "urgency", level.value) })), }, { label: "Show notification on unpause", type: "checkbox", checked: options.unpauseNotification, - click: (item) => setUnpause(options, item.checked) + click: (item) => setOption(options, "unpauseNotification", item.checked) }, ...(is.windows() ? [{ label: "Interactive Notifications", type: "checkbox", checked: options.interactive, - click: (item) => setInteractive(options, item.checked) + click: (item) => setOption(options, "interactive", item.checked) }] : []) ]; diff --git a/plugins/notifications/utils.js b/plugins/notifications/utils.js index 17b96091..34c73a77 100644 --- a/plugins/notifications/utils.js +++ b/plugins/notifications/utils.js @@ -6,52 +6,51 @@ const fs = require("fs"); const icon = "assets/youtube-music.png"; const tempIcon = path.join(app.getPath("userData"), "tempIcon.png"); +module.exports.icons = { + play: "\u{1405}", // ᐅ + pause: "\u{2016}", // ‖ + next: "\u{1433}", // ᐳ + previous: "\u{1438}" // ᐸ +} + +module.exports.setOption = (options, option, value) => { + options[option] = value; + setOptions("notifications", options) +} + module.exports.urgencyLevels = [ { name: "Low", value: "low" }, { name: "Normal", value: "normal" }, { name: "High", value: "critical" }, ]; -module.exports.setUrgency = (options, level) => { - options.urgency = level; - setOption(options); -}; -module.exports.setUnpause = (options, value) => { - options.unpauseNotification = value; - setOption(options); -}; -module.exports.setInteractive = (options, value) => { - options.interactive = value; - setOption(options); -} module.exports.notificationImage = function (songInfo, saveIcon = false) { //return local path to temp icon if (saveIcon && !!songInfo.image) { try { fs.writeFileSync(tempIcon, - songInfo.image - .resize({ height: 256, width: 256 }) + centerNativeImage(songInfo.image) .toPNG() ); } catch (err) { - console.log(`Error downloading song icon:\n${err.toString()}`) + console.log(`Error writing song icon to disk:\n${err.toString()}`) return icon; } return tempIcon; } //else: return image return songInfo.image - ? songInfo.image.resize({ height: 256, width: 256 }) + ? centerNativeImage(songInfo.image) : icon }; -let setOption = options => { - setOptions("notifications", options) -}; +function centerNativeImage(nativeImage) { + const tempImage = nativeImage.resize({ height: 256 }); + const margin = Math.max((tempImage.getSize().width - 256), 0); -module.exports.icons = { - play: "\u{1405}", // ᐅ - pause: "\u{2016}", // ‖ - next: "\u{1433}", // ᐳ - previous: "\u{1438}" // ᐸ -} \ No newline at end of file + return tempImage.crop({ + x: Math.round(margin / 2), + y: 0, + width: 256, height: 256 + }) +} From 46ac0a1ed3df9d58538ff52b7722c44f17b0770b Mon Sep 17 00:00:00 2001 From: Araxeus Date: Fri, 9 Apr 2021 19:10:20 +0300 Subject: [PATCH 09/17] change notification priority to show only on linux --- plugins/notifications/menu.js | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/plugins/notifications/menu.js b/plugins/notifications/menu.js index bfb8c809..3f239909 100644 --- a/plugins/notifications/menu.js +++ b/plugins/notifications/menu.js @@ -2,21 +2,17 @@ const { urgencyLevels, setOption } = require("./utils"); const is = require("electron-is"); module.exports = (win, options) => [ - { - label: "Notification Priority", - submenu: urgencyLevels.map(level => ({ - label: level.name, - type: "radio", - checked: options.urgency === level.value, - click: () => setOption(options, "urgency", level.value) - })), - }, - { - label: "Show notification on unpause", - type: "checkbox", - checked: options.unpauseNotification, - click: (item) => setOption(options, "unpauseNotification", item.checked) - }, + ...(is.linux() ? + [{ + label: "Notification Priority", + submenu: urgencyLevels.map(level => ({ + label: level.name, + type: "radio", + checked: options.urgency === level.value, + click: () => setOption(options, "urgency", level.value) + })), + }] : + []), ...(is.windows() ? [{ label: "Interactive Notifications", @@ -24,5 +20,11 @@ module.exports = (win, options) => [ checked: options.interactive, click: (item) => setOption(options, "interactive", item.checked) }] : - []) + []), + { + label: "Show notification on unpause", + type: "checkbox", + checked: options.unpauseNotification, + click: (item) => setOption(options, "unpauseNotification", item.checked) + }, ]; From a2207a2cb391b6b961e841c45f82412790744711 Mon Sep 17 00:00:00 2001 From: Araxeus Date: Wed, 14 Apr 2021 13:44:32 +0300 Subject: [PATCH 10/17] remove " - Topic" from artist name --- providers/song-info.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/providers/song-info.js b/providers/song-info.js index 131573c4..74fdda6a 100644 --- a/providers/song-info.js +++ b/providers/song-info.js @@ -46,6 +46,9 @@ const handleData = async (responseText, win) => { let data = JSON.parse(responseText); songInfo.title = data?.videoDetails?.title; songInfo.artist = data?.videoDetails?.author; + if (songInfo.artist.endsWith(" - Topic")) { + songInfo.artist = songInfo.artist.slice(0, -8); + } songInfo.views = data?.videoDetails?.viewCount; songInfo.imageSrc = data?.videoDetails?.thumbnail?.thumbnails?.pop()?.url; songInfo.songDuration = data?.videoDetails?.lengthSeconds; From f765fb63f0cd937e5aa7f81ea91c95625fcf944f Mon Sep 17 00:00:00 2001 From: Araxeus Date: Thu, 15 Apr 2021 15:59:41 +0300 Subject: [PATCH 11/17] scrape artistName from playBar --- providers/song-info.js | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/providers/song-info.js b/providers/song-info.js index 74fdda6a..d2dbc962 100644 --- a/providers/song-info.js +++ b/providers/song-info.js @@ -28,6 +28,18 @@ const getPausedStatus = async (win) => { return !title.includes("-"); }; +const getArtist = async (win) => { + return await win.webContents.executeJavaScript( + ` + var bar = document.getElementsByClassName('subtitle ytmusic-player-bar')[0]; + var artistName = (bar.getElementsByClassName('yt-formatted-string')[0]) || (bar.getElementsByClassName('byline ytmusic-player-bar')[0]); + if (artistName) { + artistName.textContent; + } + ` + ) +} + // Fill songInfo with empty values const songInfo = { title: "", @@ -45,10 +57,7 @@ const songInfo = { const handleData = async (responseText, win) => { let data = JSON.parse(responseText); songInfo.title = data?.videoDetails?.title; - songInfo.artist = data?.videoDetails?.author; - if (songInfo.artist.endsWith(" - Topic")) { - songInfo.artist = songInfo.artist.slice(0, -8); - } + songInfo.artist = await getArtist(win) || data?.videoDetails?.author; songInfo.views = data?.videoDetails?.viewCount; songInfo.imageSrc = data?.videoDetails?.thumbnail?.thumbnails?.pop()?.url; songInfo.songDuration = data?.videoDetails?.lengthSeconds; From 7c6ed7bb314ad2a5bd92062a7170a242bfc0dec2 Mon Sep 17 00:00:00 2001 From: Araxeus Date: Fri, 23 Apr 2021 04:01:40 +0300 Subject: [PATCH 12/17] `once` instead of `on` --- config/defaults.js | 4 ++-- plugins/notifications/back.js | 2 +- plugins/notifications/interactive.js | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/config/defaults.js b/config/defaults.js index 57c001b1..c2465a15 100644 --- a/config/defaults.js +++ b/config/defaults.js @@ -43,9 +43,9 @@ const defaultConfig = { }, notifications: { enabled: false, - urgency: "normal", unpauseNotification: false, - interactive: false //has effect only on Windows 8+ + urgency: "normal", //has effect only on Linux + interactive: false //has effect only on Windows } }, }; diff --git a/plugins/notifications/back.js b/plugins/notifications/back.js index 38fbbbf8..901bdd1f 100644 --- a/plugins/notifications/back.js +++ b/plugins/notifications/back.js @@ -32,7 +32,7 @@ module.exports = (win, options) => { const registerCallback = getSongInfo(win); let oldNotification; let oldURL = ""; - win.on("ready-to-show", () => { + win.once("ready-to-show", () => { // Register the callback for new song information registerCallback(songInfo => { // on pause - reset url? and skip notification diff --git a/plugins/notifications/interactive.js b/plugins/notifications/interactive.js index d506463a..61f9fed0 100644 --- a/plugins/notifications/interactive.js +++ b/plugins/notifications/interactive.js @@ -13,7 +13,7 @@ module.exports.setupInteractive = (win, unpauseNotification) => { onPause = unpauseNotification; - win.webContents.on("closed", () => { + win.webContents.once("closed", () => { Delete() }); } From 395eac26a3dcc66c461babba4cce42ef2df7823f Mon Sep 17 00:00:00 2001 From: Araxeus <78568641+Araxeus@users.noreply.github.com> Date: Tue, 27 Apr 2021 23:52:08 +0300 Subject: [PATCH 13/17] switch function name to camelCase Co-authored-by: th-ch --- plugins/notifications/interactive.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/notifications/interactive.js b/plugins/notifications/interactive.js index 61f9fed0..9dbed278 100644 --- a/plugins/notifications/interactive.js +++ b/plugins/notifications/interactive.js @@ -20,7 +20,7 @@ module.exports.setupInteractive = (win, unpauseNotification) => { //delete old notification let toDelete; -function Delete() { +function deleteNotification() { if (toDelete !== undefined) { const removeNotif = Object.assign(toDelete, { remove: toDelete.id From 0491babe0aeaf2a8d52fe6c3384fd9602cf4c0bf Mon Sep 17 00:00:00 2001 From: Araxeus Date: Wed, 28 Apr 2021 03:36:00 +0300 Subject: [PATCH 14/17] fix typo --- plugins/notifications/back.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/notifications/back.js b/plugins/notifications/back.js index 901bdd1f..d1ef3114 100644 --- a/plugins/notifications/back.js +++ b/plugins/notifications/back.js @@ -43,7 +43,7 @@ module.exports = (win, options) => { } return; } - // If url isn"t the same as last one - send notification + // If url isn't the same as last one - send notification if (songInfo.url !== oldURL) { oldURL = songInfo.url; if (isInteractive) { From 729714375b5332fc11751b493bcaa970522f303f Mon Sep 17 00:00:00 2001 From: Araxeus Date: Wed, 28 Apr 2021 04:27:50 +0300 Subject: [PATCH 15/17] update camelCase --- plugins/notifications/interactive.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/notifications/interactive.js b/plugins/notifications/interactive.js index 9dbed278..2afb1c49 100644 --- a/plugins/notifications/interactive.js +++ b/plugins/notifications/interactive.js @@ -14,7 +14,7 @@ module.exports.setupInteractive = (win, unpauseNotification) => { onPause = unpauseNotification; win.webContents.once("closed", () => { - Delete() + deleteNotification() }); } @@ -33,7 +33,7 @@ function deleteNotification() { //New notification module.exports.notifyInteractive = function sendToaster(songInfo) { - Delete(); + deleteNotification(); //download image and get path let imgSrc = notificationImage(songInfo, true); toDelete = { @@ -84,7 +84,7 @@ module.exports.notifyInteractive = function sendToaster(songInfo) { //Native datatype case "dismissed": case "timeout": - Delete(); + deleteNotification(); } } From d2925ee3f957e0901a40609d51da24a204bf04f6 Mon Sep 17 00:00:00 2001 From: Araxeus Date: Wed, 28 Apr 2021 04:30:19 +0300 Subject: [PATCH 16/17] make variable names clearer --- plugins/notifications/interactive.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/plugins/notifications/interactive.js b/plugins/notifications/interactive.js index 2afb1c49..21fd6603 100644 --- a/plugins/notifications/interactive.js +++ b/plugins/notifications/interactive.js @@ -4,14 +4,14 @@ const notifier = require("node-notifier"); //store song controls reference on launch let controls; -let onPause; +let NotificationOnPause; //Save controls and onPause option module.exports.setupInteractive = (win, unpauseNotification) => { const { playPause, next, previous } = getSongControls(win); controls = { playPause, next, previous }; - onPause = unpauseNotification; + NotificationOnPause = unpauseNotification; win.webContents.once("closed", () => { deleteNotification() @@ -22,6 +22,7 @@ module.exports.setupInteractive = (win, unpauseNotification) => { let toDelete; function deleteNotification() { if (toDelete !== undefined) { + // To remove the notification it has to be done this way const removeNotif = Object.assign(toDelete, { remove: toDelete.id }) @@ -70,7 +71,7 @@ module.exports.notifyInteractive = function sendToaster(songInfo) { // dont delete notification on play/pause toDelete = undefined; //manually send notification if not sending automatically - if (!onPause) { + if (!NotificationOnPause) { songInfo.isPaused = false; sendToaster(songInfo); } From 66517af81cf70005eff87a9229ee874178018a4c Mon Sep 17 00:00:00 2001 From: Araxeus Date: Wed, 28 Apr 2021 16:33:12 +0300 Subject: [PATCH 17/17] fix typo --- plugins/notifications/interactive.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/notifications/interactive.js b/plugins/notifications/interactive.js index 21fd6603..cb487cae 100644 --- a/plugins/notifications/interactive.js +++ b/plugins/notifications/interactive.js @@ -4,14 +4,14 @@ const notifier = require("node-notifier"); //store song controls reference on launch let controls; -let NotificationOnPause; +let notificationOnPause; //Save controls and onPause option module.exports.setupInteractive = (win, unpauseNotification) => { const { playPause, next, previous } = getSongControls(win); controls = { playPause, next, previous }; - NotificationOnPause = unpauseNotification; + notificationOnPause = unpauseNotification; win.webContents.once("closed", () => { deleteNotification() @@ -71,7 +71,7 @@ module.exports.notifyInteractive = function sendToaster(songInfo) { // dont delete notification on play/pause toDelete = undefined; //manually send notification if not sending automatically - if (!NotificationOnPause) { + if (!notificationOnPause) { songInfo.isPaused = false; sendToaster(songInfo); }