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}'" 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": diff --git a/src/preload/cider-preload.js b/src/preload/cider-preload.js index ba968b2f..cf8c1b4f 100644 --- a/src/preload/cider-preload.js +++ b/src/preload/cider-preload.js @@ -10,6 +10,7 @@ const MusicKitInterop = { 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 +36,7 @@ const MusicKitInterop = { const attributes = MusicKitInterop.getAttributes(); if (!attributes) return; ipcRenderer.send("playbackTimeDidChange", attributes); + MusicKitInterop.updatePositionState(attributes); }); /* MusicKit.Events.nowPlayingItemDidChange */ @@ -43,6 +45,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 +145,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 +208,139 @@ 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) { + const defaultSkipTime = 10; + + 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", (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", (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); + 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) { + console.log("[cider:preload] [updateMediaState] Updating Media State to " + a.status); + 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; + } + } + }, + + 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, + }); + } }, }; diff --git a/src/renderer/main/vueapp.js b/src/renderer/main/vueapp.js index a3d7ea87..49b3606c 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: [], @@ -2249,40 +2248,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) { @@ -5098,21 +5077,19 @@ 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(); - }); + MusicKitInterop.initMediaSession(); + // navigator.mediaSession.setActionHandler("previoustrack", function () { + // app.skipToPreviousItem(); + // }); + // navigator.mediaSession.setActionHandler("nexttrack", function () { + // app.skipToNextItem(); + // }); }, authCC() { ipcRenderer.send("cc-auth");