From eb7788f86d311147535789fdfa5ffa01796a3d38 Mon Sep 17 00:00:00 2001 From: Core Date: Wed, 21 Sep 2022 21:25:55 +0100 Subject: [PATCH 1/8] Implemented mediaSession API functions --- src/preload/cider-preload.js | 141 +++++++++++++++++++++++++++++++---- 1 file changed, 127 insertions(+), 14 deletions(-) diff --git a/src/preload/cider-preload.js b/src/preload/cider-preload.js index ba968b2f..ec289917 100644 --- a/src/preload/cider-preload.js +++ b/src/preload/cider-preload.js @@ -6,10 +6,13 @@ let cache = { playParams: { id: 0 }, status: null, remainingTime: 0 }, const MusicKitInterop = { init: function () { + this.initMediaSession(); + /* MusicKit.Events.playbackStateDidChange */ MusicKit.getInstance().addEventListener(MusicKit.Events.playbackStateDidChange, () => { const attributes = MusicKitInterop.getAttributes(); if (!attributes) return; + MusicKitInterop.updateMediaState(attributes); if (MusicKitInterop.filterTrack(attributes, true, false)) { global.ipcRenderer.send("playbackStateDidChange", attributes); global.ipcRenderer.send("wsapi-updatePlaybackState", attributes); @@ -35,6 +38,13 @@ const MusicKitInterop = { const attributes = MusicKitInterop.getAttributes(); if (!attributes) return; ipcRenderer.send("playbackTimeDidChange", attributes); + if ("mediaSession" in navigator) { + navigator.mediaSession.setPositionState({ + duration: attributes.duration, + playbackRate: app?.cfg?.audio?.playbackRate ?? 1, + position: attributes.currentPlaybackTime, + }); + } }); /* MusicKit.Events.nowPlayingItemDidChange */ @@ -43,6 +53,7 @@ const MusicKitInterop = { if (!attributes) return; attributes.primaryArtist = app.cfg.connectivity.lastfm.remove_featured ? await this.fetchSongRelationships() : attributes.artistName; + MusicKitInterop.updateMediaSession(attributes); global.ipcRenderer.send("nowPlayingItemDidChange", attributes); if (MusicKitInterop.filterTrack(attributes, false, true)) { @@ -142,7 +153,7 @@ const MusicKitInterop = { attributes.songId = attributes.songId ?? attributes.playParams?.catalogId ?? attributes.playParams?.id; attributes.type = nowPlayingItem?.type ?? ""; - attributes.status = isPlayingExport ?? null; + attributes.status = nowPlayingItem == null ? null : !!isPlayingExport; attributes.name = attributes?.name ?? "no-title-found"; attributes.artwork = attributes?.artwork ?? { url: "" }; attributes.artwork.url = (attributes?.artwork?.url ?? "").replace(`{f}`, "png"); @@ -205,22 +216,124 @@ const MusicKitInterop = { }, next: () => { - // try { - // app.prevButtonBackIndicator = false; - // } catch (e) { } - // if (MusicKit.getInstance().queue.nextPlayableItemIndex != -1 && MusicKit.getInstance().queue.nextPlayableItemIndex != null) - // MusicKit.getInstance().changeToMediaAtIndex(MusicKit.getInstance().queue.nextPlayableItemIndex); - MusicKit.getInstance() - .skipToNextItem() - .then((r) => console.debug(`[cider:preload] [next] Skipping to Next ${r}`)); + if (app) { + app.skipToNextItem(); + } else { + MusicKit.getInstance() + .skipToNextItem() + .then((r) => console.debug(`[cider:preload] [next] Skipping to Next ${r}`)); + } }, previous: () => { - // if (MusicKit.getInstance().queue.previousPlayableItemIndex != -1 && MusicKit.getInstance().queue.previousPlayableItemIndex != null) - // MusicKit.getInstance().changeToMediaAtIndex(MusicKit.getInstance().queue.previousPlayableItemIndex); - MusicKit.getInstance() - .skipToPreviousItem() - .then((r) => console.debug(`[cider:preload] [previous] Skipping to Previous ${r}`)); + if (app) { + app.skipToPreviousItem(); + } else { + MusicKit.getInstance() + .skipToPreviousItem() + .then((r) => console.debug(`[cider:preload] [previous] Skipping to Previous ${r}`)); + } + }, + + initMediaSession: () => { + if ("mediaSession" in navigator) { + console.debug("[cider:preload] [initMediaSession] Media Session API supported"); + navigator.mediaSession.setActionHandler("play", () => { + MusicKitInterop.play(); + console.log("[cider:preload] [initMediaSession] Play"); + }); + navigator.mediaSession.setActionHandler("pause", () => { + MusicKitInterop.pause(); + console.log("[cider:preload] [initMediaSession] Pause"); + }); + navigator.mediaSession.setActionHandler("stop", () => { + MusicKit.getInstance().stop(); + console.log("[cider:preload] [initMediaSession] Stop"); + }); + navigator.mediaSession.setActionHandler("seekbackward", ({ seekOffset }) => { + MusicKit.getInstance().seekToTime(MusicKit.getInstance().currentPlaybackTime - seekOffset); + console.log(`[cider:preload] [initMediaSession] Seek Backward ${seekOffset}`); + }); + navigator.mediaSession.setActionHandler("seekforward", ({ seekOffset }) => { + MusicKit.getInstance().seekToTime(MusicKit.getInstance().currentPlaybackTime + seekOffset); + console.log(`[cider:preload] [initMediaSession] Seek Forward ${seekOffset}`); + }); + navigator.mediaSession.setActionHandler("seekto", ({ seekTime, fastSeek }) => { + MusicKit.getInstance().seekToTime(seekTime); + console.log(`[cider:preload] [initMediaSession] Seek To ${seekTime}`); + }); + navigator.mediaSession.setActionHandler("previoustrack", () => { + MusicKitInterop.previous(); + console.log("[cider:preload] [initMediaSession] Previous Track"); + }); + navigator.mediaSession.setActionHandler("nexttrack", () => { + MusicKitInterop.next(); + console.log("[cider:preload] [initMediaSession] Next Track"); + }); + } else { + console.debug("[cider:preload] [initMediaSession] Media Session API not supported"); + } + }, + + updateMediaSession: (a) => { + if ("mediaSession" in navigator) { + navigator.mediaSession.metadata = new MediaMetadata({ + title: a.name, + artist: a.artistName, + album: a.albumName, + artwork: [ + { + src: a.artwork.url.replace("/{w}x{h}bb", "/96x96bb").replace("/2000x2000bb", "/35x35bb"), + sizes: "96x96", + type: "image/jpeg", + }, + { + src: a.artwork.url.replace("/{w}x{h}bb", "/128x128bb").replace("/2000x2000bb", "/35x35bb"), + sizes: "128x128", + type: "image/jpeg", + }, + { + src: a.artwork.url.replace("/{w}x{h}bb", "/192x192bb").replace("/2000x2000bb", "/35x35bb"), + sizes: "192x192", + type: "image/jpeg", + }, + { + src: a.artwork.url.replace("/{w}x{h}bb", "/256x256bb").replace("/2000x2000bb", "/35x35bb"), + sizes: "256x256", + type: "image/jpeg", + }, + { + src: a.artwork.url.replace("/{w}x{h}bb", "/384x384bb").replace("/2000x2000bb", "/35x35bb"), + sizes: "384x384", + type: "image/jpeg", + }, + { + src: a.artwork.url.replace("/{w}x{h}bb", "/512x512bb").replace("/2000x2000bb", "/35x35bb"), + sizes: "512x512", + type: "image/jpeg", + }, + ], + }); + } + }, + + updateMediaState: (a) => { + if ("mediaSession" in navigator) { + switch (a.status) { + default: + case null: + navigator.mediaSession.playbackState = "none"; + break; + + case false: + navigator.mediaSession.playbackState = "paused"; + break; + + case true: + navigator.mediaSession.playbackState = "playing"; + break; + } + } }, }; From 5214ca9ad249e598e5de30fe7b6efc279f2f9ead Mon Sep 17 00:00:00 2001 From: Core Date: Wed, 21 Sep 2022 21:27:02 +0100 Subject: [PATCH 2/8] Cleaned up playback function, commented mediaKeyFixes --- src/renderer/main/vueapp.js | 48 ++++++++++--------------------------- 1 file changed, 12 insertions(+), 36 deletions(-) diff --git a/src/renderer/main/vueapp.js b/src/renderer/main/vueapp.js index 1bf457d5..b2178464 100644 --- a/src/renderer/main/vueapp.js +++ b/src/renderer/main/vueapp.js @@ -195,7 +195,6 @@ const app = new Vue({ type: "", }, MVsource: null, - prevButtonBackIndicator: false, currentSongInfo: {}, page: "", pageHistory: [], @@ -2233,40 +2232,20 @@ const app = new Vue({ } }, prevButton() { - if (!app.prevButtonBackIndicator && app.mk.nowPlayingItem && app.mk.currentPlaybackTime > 2) { - app.prevButtonBackIndicator = true; - try { - clearTimeout(app.pauseButtonTimer); - } catch (e) {} + if (app.mk.nowPlayingItem && app.mk.currentPlaybackTime > 2) { app.mk.seekToTime(0); - app.pauseButtonTimer = setTimeout(() => { - app.prevButtonBackIndicator = false; - }, 3000); } else { - try { - clearTimeout(app.pauseButtonTimer); - } catch (e) {} - app.prevButtonBackIndicator = false; app.skipToPreviousItem(); } }, isDisabled() { - if (!app.mk.nowPlayingItem || app.mk.nowPlayingItem.attributes.playParams.kind == "radioStation") { - return true; - } - return false; + return !app.mk.nowPlayingItem || app.mk.nowPlayingItem.attributes.playParams.kind === "radioStation"; }, isPrevDisabled() { - if (this.isDisabled() || (app.mk.queue._position == 0 && app.mk.currentPlaybackTime <= 2)) { - return true; - } - return false; + return this.isDisabled() || (app.mk.queue._position === 0 && app.mk.currentPlaybackTime <= 2); }, isNextDisabled() { - if (this.isDisabled() || app.mk.queue._position + 1 == app.mk.queue.length) { - return true; - } - return false; + return this.isDisabled() || app.mk.queue._position + 1 === app.mk.queue.length; }, async getNowPlayingItemDetailed(target) { @@ -5082,21 +5061,18 @@ const app = new Vue({ } }, skipToNextItem() { - app.prevButtonBackIndicator = false; - // app.mk.skipToNextItem() is buggy somehow so use this - if (this.mk.queue.nextPlayableItemIndex != -1 && this.mk.queue.nextPlayableItemIndex != null) this.mk.changeToMediaAtIndex(this.mk.queue.nextPlayableItemIndex); + if (this.mk.queue.nextPlayableItemIndex !== -1 && this.mk.queue.nextPlayableItemIndex != null) this.mk.changeToMediaAtIndex(this.mk.queue.nextPlayableItemIndex); }, skipToPreviousItem() { - // app.mk.skipToPreviousItem() is buggy somehow so use this - if (this.mk.queue.previousPlayableItemIndex != -1 && this.mk.queue.previousPlayableItemIndex != null) this.mk.changeToMediaAtIndex(this.mk.queue.previousPlayableItemIndex); + if (this.mk.queue.previousPlayableItemIndex !== -1 && this.mk.queue.previousPlayableItemIndex != null) this.mk.changeToMediaAtIndex(this.mk.queue.previousPlayableItemIndex); }, mediaKeyFixes() { - navigator.mediaSession.setActionHandler("previoustrack", function () { - app.prevButton(); - }); - navigator.mediaSession.setActionHandler("nexttrack", function () { - app.skipToNextItem(); - }); + // navigator.mediaSession.setActionHandler("previoustrack", function () { + // app.skipToPreviousItem(); + // }); + // navigator.mediaSession.setActionHandler("nexttrack", function () { + // app.skipToNextItem(); + // }); }, authCC() { ipcRenderer.send("cc-auth"); From 20722371dd191a003c0139aee89bc18786f159fa Mon Sep 17 00:00:00 2001 From: Core Date: Wed, 21 Sep 2022 21:27:19 +0100 Subject: [PATCH 3/8] Simplified wsapi renderer calls --- src/main/base/wsapi.ts | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/main/base/wsapi.ts b/src/main/base/wsapi.ts index d161b279..06cc632e 100644 --- a/src/main/base/wsapi.ts +++ b/src/main/base/wsapi.ts @@ -200,15 +200,11 @@ export class wsapi { response.message = "Unmuted"; break; case "next": - this._win.webContents.executeJavaScript(`if (MusicKit.getInstance().queue.nextPlayableItemIndex != -1 && MusicKit.getInstance().queue.nextPlayableItemIndex != null) { - try { - app.prevButtonBackIndicator = false; - } catch (e) { } - MusicKit.getInstance().changeToMediaAtIndex(MusicKit.getInstance().queue.nextPlayableItemIndex);}`); + this._win.webContents.executeJavaScript(`MusicKitInterop.next()`); response.message = "Next"; break; case "previous": - this._win.webContents.executeJavaScript(`if (MusicKit.getInstance().queue.previousPlayableItemIndex != -1 && MusicKit.getInstance().queue.previousPlayableItemIndex != null) {MusicKit.getInstance().changeToMediaAtIndex(MusicKit.getInstance().queue.previousPlayableItemIndex)}`); + this._win.webContents.executeJavaScript(`MusicKitInterop.previous()`); response.message = "Previous"; break; case "musickit-api": From feba6faedf23bcc544ea675e9133848bd4dbb854 Mon Sep 17 00:00:00 2001 From: Core Date: Wed, 21 Sep 2022 22:31:00 +0100 Subject: [PATCH 4/8] Fix duration --- src/preload/cider-preload.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/preload/cider-preload.js b/src/preload/cider-preload.js index ec289917..3de6cf72 100644 --- a/src/preload/cider-preload.js +++ b/src/preload/cider-preload.js @@ -40,7 +40,7 @@ const MusicKitInterop = { ipcRenderer.send("playbackTimeDidChange", attributes); if ("mediaSession" in navigator) { navigator.mediaSession.setPositionState({ - duration: attributes.duration, + duration: attributes.durationInMillis / 1000, playbackRate: app?.cfg?.audio?.playbackRate ?? 1, position: attributes.currentPlaybackTime, }); From 0648c75a014465b3b19ab7d95d5ce510bbf12fcf Mon Sep 17 00:00:00 2001 From: Core Date: Wed, 21 Sep 2022 22:53:58 +0100 Subject: [PATCH 5/8] Added check --- src/preload/cider-preload.js | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/preload/cider-preload.js b/src/preload/cider-preload.js index 3de6cf72..c5852484 100644 --- a/src/preload/cider-preload.js +++ b/src/preload/cider-preload.js @@ -6,8 +6,6 @@ let cache = { playParams: { id: 0 }, status: null, remainingTime: 0 }, const MusicKitInterop = { init: function () { - this.initMediaSession(); - /* MusicKit.Events.playbackStateDidChange */ MusicKit.getInstance().addEventListener(MusicKit.Events.playbackStateDidChange, () => { const attributes = MusicKitInterop.getAttributes(); @@ -38,7 +36,7 @@ const MusicKitInterop = { const attributes = MusicKitInterop.getAttributes(); if (!attributes) return; ipcRenderer.send("playbackTimeDidChange", attributes); - if ("mediaSession" in navigator) { + if ("mediaSession" in navigator && attributes.currentPlaybackTime <= attributes.durationInMillis / 1000) { navigator.mediaSession.setPositionState({ duration: attributes.durationInMillis / 1000, playbackRate: app?.cfg?.audio?.playbackRate ?? 1, @@ -237,6 +235,8 @@ const MusicKitInterop = { initMediaSession: () => { if ("mediaSession" in navigator) { + const defaultSkipTime = 10; + console.debug("[cider:preload] [initMediaSession] Media Session API supported"); navigator.mediaSession.setActionHandler("play", () => { MusicKitInterop.play(); @@ -250,13 +250,15 @@ const MusicKitInterop = { MusicKit.getInstance().stop(); console.log("[cider:preload] [initMediaSession] Stop"); }); - navigator.mediaSession.setActionHandler("seekbackward", ({ seekOffset }) => { - MusicKit.getInstance().seekToTime(MusicKit.getInstance().currentPlaybackTime - seekOffset); - console.log(`[cider:preload] [initMediaSession] Seek Backward ${seekOffset}`); + navigator.mediaSession.setActionHandler("seekbackward", (details) => { + const skipTime = details.seekOffset || defaultSkipTime; + MusicKit.getInstance().seekToTime(Math.max(MusicKit.getInstance().currentPlaybackTime - skipTime, 0)); + console.log(`[cider:preload] [initMediaSession] Seek Backward ${skipTime}`); }); - navigator.mediaSession.setActionHandler("seekforward", ({ seekOffset }) => { - MusicKit.getInstance().seekToTime(MusicKit.getInstance().currentPlaybackTime + seekOffset); - console.log(`[cider:preload] [initMediaSession] Seek Forward ${seekOffset}`); + navigator.mediaSession.setActionHandler("seekforward", (details) => { + const skipTime = details.seekOffset || defaultSkipTime; + MusicKit.getInstance().seekToTime(Math.max(MusicKit.getInstance().currentPlaybackTime + skipTime, 0)); + console.log(`[cider:preload] [initMediaSession] Seek Forward ${skipTime}`); }); navigator.mediaSession.setActionHandler("seekto", ({ seekTime, fastSeek }) => { MusicKit.getInstance().seekToTime(seekTime); @@ -319,6 +321,7 @@ const MusicKitInterop = { updateMediaState: (a) => { if ("mediaSession" in navigator) { + console.log("[cider:preload] [updateMediaState] Updating Media State to " + a.status); switch (a.status) { default: case null: From 11bd1814843f3d40a6e167c0b03b8cd18d3bd1e4 Mon Sep 17 00:00:00 2001 From: Core Date: Wed, 21 Sep 2022 22:54:35 +0100 Subject: [PATCH 6/8] Moved function call --- src/renderer/main/vueapp.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/renderer/main/vueapp.js b/src/renderer/main/vueapp.js index b2178464..6f382399 100644 --- a/src/renderer/main/vueapp.js +++ b/src/renderer/main/vueapp.js @@ -5067,6 +5067,7 @@ const app = new Vue({ if (this.mk.queue.previousPlayableItemIndex !== -1 && this.mk.queue.previousPlayableItemIndex != null) this.mk.changeToMediaAtIndex(this.mk.queue.previousPlayableItemIndex); }, mediaKeyFixes() { + MusicKitInterop.initMediaSession(); // navigator.mediaSession.setActionHandler("previoustrack", function () { // app.skipToPreviousItem(); // }); From 793c65ac314c9ca67ae0f2ba072af12e8b84568b Mon Sep 17 00:00:00 2001 From: Core Date: Wed, 21 Sep 2022 23:24:59 +0100 Subject: [PATCH 7/8] More checks --- src/preload/cider-preload.js | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/preload/cider-preload.js b/src/preload/cider-preload.js index c5852484..cf8c1b4f 100644 --- a/src/preload/cider-preload.js +++ b/src/preload/cider-preload.js @@ -36,13 +36,7 @@ const MusicKitInterop = { const attributes = MusicKitInterop.getAttributes(); if (!attributes) return; ipcRenderer.send("playbackTimeDidChange", attributes); - if ("mediaSession" in navigator && attributes.currentPlaybackTime <= attributes.durationInMillis / 1000) { - navigator.mediaSession.setPositionState({ - duration: attributes.durationInMillis / 1000, - playbackRate: app?.cfg?.audio?.playbackRate ?? 1, - position: attributes.currentPlaybackTime, - }); - } + MusicKitInterop.updatePositionState(attributes); }); /* MusicKit.Events.nowPlayingItemDidChange */ @@ -338,6 +332,16 @@ const MusicKitInterop = { } } }, + + updatePositionState: (a) => { + if ("mediaSession" in navigator && a.currentPlaybackTime <= a.durationInMillis / 1000 && a.currentPlaybackTime >= 0) { + navigator.mediaSession.setPositionState({ + duration: a.durationInMillis / 1000, + playbackRate: app?.cfg?.audio?.playbackRate ?? 1, + position: a.currentPlaybackTime, + }); + } + }, }; process.once("loaded", () => { From 573e346acfe342a8742cab749c6630bcd1b0b0cb Mon Sep 17 00:00:00 2001 From: Core Date: Thu, 22 Sep 2022 00:08:32 +0100 Subject: [PATCH 8/8] Fix [ci skip] --- .github/workflows/pr-chores.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pr-chores.yml b/.github/workflows/pr-chores.yml index bd622916..66e14ae9 100644 --- a/.github/workflows/pr-chores.yml +++ b/.github/workflows/pr-chores.yml @@ -29,9 +29,9 @@ jobs: - name: Install dependencies 👨🏻‍💻 run: pnpm install - + - name: Run linter 👀 uses: wearerequired/lint-action@v2 with: prettier: true - prettier_args: "'**/*.{js,json,ts,css,vue,less}'" + prettier_args: "'src/**/*.{js,json,ts,css,vue,less}'"