add windows interactive notifications

This commit is contained in:
Araxeus
2021-04-08 16:54:46 +03:00
parent 61e7124516
commit e6efddc639
7 changed files with 186 additions and 22 deletions

View File

@ -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);
}
}
});
});

View File

@ -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);
}
}
);
}

View File

@ -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)
}] :
[])
];

View File

@ -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}" //
}