From c77305832884a9712102299da47adeb4a3d3ac9b Mon Sep 17 00:00:00 2001 From: Core <64542347+coredev-uk@users.noreply.github.com> Date: Sun, 31 Jul 2022 12:05:16 +0100 Subject: [PATCH 1/7] Moved to Electron Notifications --- src/main/plugins/playbackNotifications.ts | 95 +++++++++++++++++++++++ src/preload/cider-preload.js | 4 + src/renderer/main/vueapp.js | 11 --- 3 files changed, 99 insertions(+), 11 deletions(-) create mode 100644 src/main/plugins/playbackNotifications.ts diff --git a/src/main/plugins/playbackNotifications.ts b/src/main/plugins/playbackNotifications.ts new file mode 100644 index 00000000..92df3724 --- /dev/null +++ b/src/main/plugins/playbackNotifications.ts @@ -0,0 +1,95 @@ +import fetch from "electron-fetch"; +import {nativeImage, Notification} from "electron"; + +export default class playbackNotifications { + + + /** + * Base Plugin Details (Eventually implemented into a GUI in settings) + */ + public name: string = 'Playback Notifications'; + public description: string = 'Creates notifications on playback.'; + public version: string = '1.0.0'; + public author: string = 'Core'; + public contributors: string[] = ['Core', 'Monochromish']; + + private _utils: any; + private _notification: Notification | undefined; + + /** + * Creates playback notification + * @param a: Music Attributes + */ + createNotification(a: any): void { + if (this._notification) { + this._notification.close(); + } + fetch(a.artwork.url.replace('/{w}x{h}bb', '/512x512bb').replace('/2000x2000bb', '/35x35bb')).then(async blob => { + const artworkImage = nativeImage.createFromBuffer(Buffer.from(await blob.arrayBuffer())); + this._notification = new Notification({ + title: a.name, + body: `${a.artistName} — ${a.albumName}`, + silent: true, + icon: artworkImage, + urgency: 'low', + actions: [ + { + 'type': 'button', + 'text': 'Play/Pause' + }, + { + 'type': 'button', + 'text': 'Next' + } + ], + toastXml: ` + + + ${a.name ?? ''} + ${a.artistName ?? ''} - ${a.albumName ?? '' + } + + + + + + + ` + }); + this._notification.on('click', (event: any) => { + this._utils.getWindow().show() + this._utils.getWindow().focus() + }) + this._notification.on('close', (event: any) => { + this._notification = undefined; + }) + this._notification.on('action', (event: any, action: any) => { + if (action === 'Play/Pause') { + this._utils.playback.playPause() + } else if (action === 'Next') { + this._utils.playback.next() + } + }) + + this._notification.show(); + + }) + } + + /******************************************************************************************* + * Public Methods + * ****************************************************************************************/ + + /** + * Runs on plugin load (Currently run on application start) + */ + constructor(utils: any) { + this._utils = utils; + console.debug(`[Plugin][${this.name}] Loading Complete.`); + + utils.getIPCMain().on('playbackNotifications:create', (event: any, a: any) => { + this.createNotification(a); + }) + } + +} diff --git a/src/preload/cider-preload.js b/src/preload/cider-preload.js index 9eccc0ca..33fc5a91 100644 --- a/src/preload/cider-preload.js +++ b/src/preload/cider-preload.js @@ -44,6 +44,10 @@ const MusicKitInterop = { global.ipcRenderer.send('lastfm:nowPlayingChange', attributes); } + if (app.cfg.general.playbackNotifications && !document.hasFocus() && attributes.artistName && attributes.artwork && attributes.name) { + global.ipcRenderer.send('playbackNotifications:create', attributes); + } + if (MusicKit.getInstance().nowPlayingItem) { await this.sleep(750); MusicKit.getInstance().playbackRate = app.cfg.audio.playbackRate; diff --git a/src/renderer/main/vueapp.js b/src/renderer/main/vueapp.js index ff70b7a7..431fca42 100644 --- a/src/renderer/main/vueapp.js +++ b/src/renderer/main/vueapp.js @@ -1074,17 +1074,6 @@ const app = new Vue({ app.getNowPlayingArtworkBG(32); app.loadLyrics(); - // Playback Notifications - if (this.cfg.general.playbackNotifications && !document.hasFocus() && a.artistName && a.artwork && a.name) { - if (this.notification) { - this.notification.close() - } - this.notification = new Notification(a.name, { - body: `${a.artistName} — ${a.albumName}`, - icon: a.artwork.url.replace('/{w}x{h}bb', '/512x512bb').replace('/2000x2000bb', '/35x35bb'), - silent: true, - }); - } setTimeout(() => { let i = (document.querySelector('#apple-music-player')?.src ?? "") if (i.endsWith(".m3u8") || i.endsWith(".m3u")) { From 01429d7ff0b27c03ad927e323fc0400bf1ef1586 Mon Sep 17 00:00:00 2001 From: Core <64542347+coredev-uk@users.noreply.github.com> Date: Sun, 31 Jul 2022 12:13:35 +0100 Subject: [PATCH 2/7] Swapped to array index --- src/main/plugins/playbackNotifications.ts | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/main/plugins/playbackNotifications.ts b/src/main/plugins/playbackNotifications.ts index 92df3724..44c1aaf9 100644 --- a/src/main/plugins/playbackNotifications.ts +++ b/src/main/plugins/playbackNotifications.ts @@ -36,10 +36,6 @@ export default class playbackNotifications { { 'type': 'button', 'text': 'Play/Pause' - }, - { - 'type': 'button', - 'text': 'Next' } ], toastXml: ` @@ -64,9 +60,9 @@ export default class playbackNotifications { this._notification = undefined; }) this._notification.on('action', (event: any, action: any) => { - if (action === 'Play/Pause') { + if (action === 0) { this._utils.playback.playPause() - } else if (action === 'Next') { + } else if (action === 1) { this._utils.playback.next() } }) From 4806db7b08001826b75bb739798776295f8230ad Mon Sep 17 00:00:00 2001 From: Core <64542347+coredev-uk@users.noreply.github.com> Date: Sun, 31 Jul 2022 12:14:34 +0100 Subject: [PATCH 3/7] keeping this here until for now --- src/main/plugins/playbackNotifications.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/plugins/playbackNotifications.ts b/src/main/plugins/playbackNotifications.ts index 44c1aaf9..93806e60 100644 --- a/src/main/plugins/playbackNotifications.ts +++ b/src/main/plugins/playbackNotifications.ts @@ -36,6 +36,10 @@ export default class playbackNotifications { { 'type': 'button', 'text': 'Play/Pause' + }, + { + 'type': 'button', + 'text': 'Next' } ], toastXml: ` From 41ff0e45ffa8ddf710c39ca63eba2a2c7d56eec3 Mon Sep 17 00:00:00 2001 From: Core <64542347+coredev-uk@users.noreply.github.com> Date: Sun, 31 Jul 2022 12:38:19 +0100 Subject: [PATCH 4/7] debuggin --- src/main/plugins/playbackNotifications.ts | 33 +++++++++++++---------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/src/main/plugins/playbackNotifications.ts b/src/main/plugins/playbackNotifications.ts index 93806e60..12a5762c 100644 --- a/src/main/plugins/playbackNotifications.ts +++ b/src/main/plugins/playbackNotifications.ts @@ -24,7 +24,24 @@ export default class playbackNotifications { if (this._notification) { this._notification.close(); } - fetch(a.artwork.url.replace('/{w}x{h}bb', '/512x512bb').replace('/2000x2000bb', '/35x35bb')).then(async blob => { + const artworkUrl = a.artwork.url.replace('/{w}x{h}bb', '/512x512bb').replace('/2000x2000bb', '/35x35bb') + console.log(artworkUrl) + const toastXML = ` + + + + + ${a?.name.replace(/&/g, '&')} + ${a?.artistName.replace(/&/g, '&')} — ${a?.albumName.replace(/&/g, '&')} + + + + + + + ` + console.log(toastXML) + fetch(artworkUrl).then(async blob => { const artworkImage = nativeImage.createFromBuffer(Buffer.from(await blob.arrayBuffer())); this._notification = new Notification({ title: a.name, @@ -42,19 +59,7 @@ export default class playbackNotifications { 'text': 'Next' } ], - toastXml: ` - - - ${a.name ?? ''} - ${a.artistName ?? ''} - ${a.albumName ?? '' - } - - - - - - - ` + toastXml: toastXML }); this._notification.on('click', (event: any) => { this._utils.getWindow().show() From 88cda41647e11c349d60f4e308ce2cdf1c2d1ced Mon Sep 17 00:00:00 2001 From: vapormusic Date: Sun, 31 Jul 2022 19:04:35 +0700 Subject: [PATCH 5/7] allow noti button on macs --- package.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 4e4080a2..3c025836 100644 --- a/package.json +++ b/package.json @@ -228,7 +228,10 @@ "darkModeSupport": true, "target": [ "dmg" - ] + ], + "extendInfo": { + "NSUserNotificationAlertStyle": "alert" + } } } } From 233b34a58b3c44aa9eb4d9572b2cecb1fb1e2829 Mon Sep 17 00:00:00 2001 From: Core <64542347+coredev-uk@users.noreply.github.com> Date: Sun, 31 Jul 2022 13:05:20 +0100 Subject: [PATCH 6/7] No image for now --- src/main/plugins/playbackNotifications.ts | 31 ++++++++++------------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/src/main/plugins/playbackNotifications.ts b/src/main/plugins/playbackNotifications.ts index 12a5762c..4381432e 100644 --- a/src/main/plugins/playbackNotifications.ts +++ b/src/main/plugins/playbackNotifications.ts @@ -25,22 +25,6 @@ export default class playbackNotifications { this._notification.close(); } const artworkUrl = a.artwork.url.replace('/{w}x{h}bb', '/512x512bb').replace('/2000x2000bb', '/35x35bb') - console.log(artworkUrl) - const toastXML = ` - - - - - ${a?.name.replace(/&/g, '&')} - ${a?.artistName.replace(/&/g, '&')} — ${a?.albumName.replace(/&/g, '&')} - - - - - - - ` - console.log(toastXML) fetch(artworkUrl).then(async blob => { const artworkImage = nativeImage.createFromBuffer(Buffer.from(await blob.arrayBuffer())); this._notification = new Notification({ @@ -59,7 +43,20 @@ export default class playbackNotifications { 'text': 'Next' } ], - toastXml: toastXML + toastXml: ` + + + + + ${a?.name.replace(/&/g, '&')} + ${a?.artistName.replace(/&/g, '&')} — ${a?.albumName.replace(/&/g, '&')} + + + + + + + ` }); this._notification.on('click', (event: any) => { this._utils.getWindow().show() From 380189df0568995a5ec724c3e13b32d9384bea8d Mon Sep 17 00:00:00 2001 From: Core <64542347+coredev-uk@users.noreply.github.com> Date: Sun, 31 Jul 2022 23:53:44 +0100 Subject: [PATCH 7/7] Artwork caching (sorta) --- src/main/plugins/playbackNotifications.ts | 97 ++++++++++++++--------- 1 file changed, 58 insertions(+), 39 deletions(-) diff --git a/src/main/plugins/playbackNotifications.ts b/src/main/plugins/playbackNotifications.ts index 92df3724..27f06d74 100644 --- a/src/main/plugins/playbackNotifications.ts +++ b/src/main/plugins/playbackNotifications.ts @@ -1,5 +1,6 @@ import fetch from "electron-fetch"; import {nativeImage, Notification} from "electron"; +import NativeImage = Electron.NativeImage; export default class playbackNotifications { @@ -15,6 +16,8 @@ export default class playbackNotifications { private _utils: any; private _notification: Notification | undefined; + private _artworkImage: { [key: string]: NativeImage } = {}; + private _artworkNums: Array = []; /** * Creates playback notification @@ -24,30 +27,28 @@ export default class playbackNotifications { if (this._notification) { this._notification.close(); } - fetch(a.artwork.url.replace('/{w}x{h}bb', '/512x512bb').replace('/2000x2000bb', '/35x35bb')).then(async blob => { - const artworkImage = nativeImage.createFromBuffer(Buffer.from(await blob.arrayBuffer())); - this._notification = new Notification({ - title: a.name, - body: `${a.artistName} — ${a.albumName}`, - silent: true, - icon: artworkImage, - urgency: 'low', - actions: [ - { - 'type': 'button', - 'text': 'Play/Pause' - }, - { - 'type': 'button', - 'text': 'Next' - } - ], - toastXml: ` + + this._notification = new Notification({ + title: a.name, + body: `${a.artistName} — ${a.albumName}`, + silent: true, + icon: this._artworkImage[a.artwork.url], + urgency: 'low', + actions: [ + { + 'type': 'button', + 'text': 'Play/Pause' + }, + { + 'type': 'button', + 'text': 'Next' + } + ], + toastXml: ` ${a.name ?? ''} - ${a.artistName ?? ''} - ${a.albumName ?? '' - } + ${a.artistName ?? ''} - ${a.albumName ?? ''} @@ -55,27 +56,30 @@ export default class playbackNotifications { ` - }); - this._notification.on('click', (event: any) => { - this._utils.getWindow().show() - this._utils.getWindow().focus() - }) - this._notification.on('close', (event: any) => { - this._notification = undefined; - }) - this._notification.on('action', (event: any, action: any) => { - if (action === 'Play/Pause') { - this._utils.playback.playPause() - } else if (action === 'Next') { - this._utils.playback.next() - } - }) - - this._notification.show(); + }); + this._notification.on('click', (event: any) => { + this._utils.getWindow().show() + this._utils.getWindow().focus() }) + + this._notification.on('close', (event: any) => { + this._notification = undefined; + }) + + this._notification.on('action', (event: any, action: any) => { + if (action === 'Play/Pause') { + this._utils.playback.playPause() + } else if (action === 'Next') { + this._utils.playback.next() + } + }) + + this._notification.show(); + } + /******************************************************************************************* * Public Methods * ****************************************************************************************/ @@ -88,7 +92,22 @@ export default class playbackNotifications { console.debug(`[Plugin][${this.name}] Loading Complete.`); utils.getIPCMain().on('playbackNotifications:create', (event: any, a: any) => { - this.createNotification(a); + a.artwork.url = a.artwork.url.replace('/{w}x{h}bb', '/512x512bb').replace('/2000x2000bb', '/35x35bb'); + + if (this._artworkNums.length > 20) { + delete this._artworkImage[this._artworkNums[0]]; + this._artworkNums.shift(); + } + + if (this._artworkImage[a.artwork.url]) { + this.createNotification(a); + } else { + fetch(a.artwork.url).then(async blob => { + this._artworkImage[a.artwork.url] = nativeImage.createFromBuffer(Buffer.from(await blob.arrayBuffer())); + this._artworkNums[this._artworkNums.length] = a.artwork.url; + this.createNotification(a); + }); + } }) }