Skip to content

Commit

Permalink
feat: api track control to use player api, send invoke handler fixed
Browse files Browse the repository at this point in the history
  • Loading branch information
Venipa committed Nov 28, 2024
1 parent 81c912f commit e60c09c
Show file tree
Hide file tree
Showing 6 changed files with 79 additions and 21 deletions.
31 changes: 23 additions & 8 deletions src/main/plugins/apiProvider.plugin.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { ApiWorker, createApiWorker } from "@main/api/createApiWorker";
import { AfterInit, BaseProvider, OnDestroy } from "@main/utils/baseProvider";
import { IpcContext, IpcHandle, IpcOn } from "@main/utils/onIpcEvent";
import type { App } from "electron";
import { ipcMain, type App } from "electron";
import fetch from "node-fetch";
import Vibrant from "node-vibrant";

import { API_ROUTES } from "../utils/eventNames";
import IPC_EVENT_NAMES, { API_ROUTES } from "../utils/eventNames";
import TrackProvider from "./trackProvider.plugin";

@IpcContext
Expand Down Expand Up @@ -94,7 +94,7 @@ export default class ApiProvider extends BaseProvider implements AfterInit, OnDe
return isLiked;
});

return null;
return null;
}
@IpcHandle(API_ROUTES.TRACK_DISLIKE)
async postTrackDisLike(_ev, like: boolean) {
Expand All @@ -120,7 +120,7 @@ export default class ApiProvider extends BaseProvider implements AfterInit, OnDe
}
@IpcHandle(API_ROUTES.TRACK_CONTROL_NEXT)
async nextTrack() {
return await this.windowContext.sendTrackControl("next")
return await this.windowContext.sendTrackControl("next");
}
@IpcHandle(API_ROUTES.TRACK_CONTROL_FORWARD)
async forwardTrack(_ev, data) {
Expand Down Expand Up @@ -150,18 +150,33 @@ export default class ApiProvider extends BaseProvider implements AfterInit, OnDe
}
@IpcHandle(API_ROUTES.TRACK_CONTROL_PREV)
async prevTrack() {
return await this.windowContext.sendTrackControl("prev")
return await this.windowContext.sendTrackControl("prev");
}
@IpcHandle(API_ROUTES.TRACK_CONTROL_PLAY)
async playTrack() {
return await this.windowContext.sendTrackControl("play")
return await this.windowContext
.sendTrackControl<{ data: { isPlaying: boolean; time: number }; type: any }>("play")
.then(({ data: { isPlaying, time } }) => {
ipcMain.emit(IPC_EVENT_NAMES.TRACK_PLAYSTATE, null, isPlaying, time);
return { isPlaying, time };
});
}
@IpcHandle(API_ROUTES.TRACK_CONTROL_PAUSE)
async pauseTrack() {
return await this.windowContext.sendTrackControl("pause")
return await this.windowContext
.sendTrackControl<{ data: { isPlaying: boolean; time: number }; type: any }>("pause")
.then(({ data: { isPlaying, time } }) => {
ipcMain.emit(IPC_EVENT_NAMES.TRACK_PLAYSTATE, null, isPlaying, time);
return { isPlaying, time };
});
}
@IpcHandle(API_ROUTES.TRACK_CONTROL_TOGGLE_PLAY)
async toggleTrackPlayback() {
return await this.windowContext.sendTrackControl("toggle")
return await this.windowContext
.sendTrackControl<{ data: { isPlaying: boolean; time: number }; type: any }>("toggle")
.then(({ data: { isPlaying, time } }) => {
ipcMain.emit(IPC_EVENT_NAMES.TRACK_PLAYSTATE, null, isPlaying, time);
return { isPlaying, time };
});
}
}
44 changes: 37 additions & 7 deletions src/main/plugins/client/track-api-controls.plugin.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@

export const meta = {
name: "Api Control Handler",
};
Expand All @@ -6,12 +7,33 @@ const trackControls = {
toggle: player => {
const state = player.getPlayerStateObject();
if (!state) return;
return (state.isPlaying || state.isOrWillBePlaying) ? player.stopVideo() : player.playVideo()
state.isPlaying ? player.pauseVideo() : player.playVideo()
return {
isPlaying: state.isPlaying,
time: player.getCurrentTime()
};
},
play: playerApi => {
playerApi.playVideo()
return {
isPlaying: true,
time: playerApi.getCurrentTime()
}
},
pause: playerApi => {
playerApi.pauseVideo()
return {
isPlaying: false,
time: playerApi.getCurrentTime()
}
},
play: playerApi => playerApi.playVideo(),
pause: playerApi => playerApi.stopVideo(),
next: playerApi => playerApi.nextVideo(),
prev: playerApi => playerApi.previousVideo()
prev: playerApi => playerApi.previousVideo(),
isPlaying: player => {
const state = player.getPlayerStateObject();
if (!state) return;
return state.isPlaying;
}
};
export const afterInit = () => {
window.domUtils.ensureDomLoaded(() => {
Expand All @@ -28,13 +50,21 @@ export const afterInit = () => {
}
}
window.ipcRenderer.on("track:seek", setTimeSkip);
window.ipcRenderer.on("track:control", (_ev, data) => {
if (!data || typeof data === "object") return;
window.ipcRenderer.on("track:control", async (_ev, data) => {
if (!data || typeof data !== "object") return;
const { type } = data;
const handler = trackControls[type];
if (!handler) return;
const playerApi = window.domUtils.playerApi();
window.api.emit("track:control/response", type, handler(playerApi))
// not ready yet
if (!playerApi) return;

const handleResult = await Promise.resolve(handler(playerApi));
window.api.emit("track:control/response", {
type,
data: handleResult
})

});
});
};
1 change: 0 additions & 1 deletion src/main/plugins/mediaControlProvider.plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,6 @@ export default class MediaControlProvider
@IpcOn(IPC_EVENT_NAMES.TRACK_PLAYSTATE)
private __handleTrackMediaOSControl(_ev, isPlaying: boolean, progressSeconds: number = 0) {
if (!this.mediaProviderEnabled()) return;

const { trackData } = this.getProvider("track");
if (!trackData) {
this._mediaProvider.playbackStatus = MediaPlayerPlaybackStatus.Stopped;
Expand Down
10 changes: 7 additions & 3 deletions src/main/utils/mappedWindow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ import { BrowserWindow, WebContentsView } from "electron";
import IPC_EVENT_NAMES from "./eventNames";

type TrackControlTypes = StringLiteral<"play" | "pause" | "next" | "prev" | "toggle">;
type TrackControlFn = <T = any>(type: TrackControlTypes) => Promise<T>;
type TrackControlFn = <T extends { type: TrackControlTypes } = any>(
type: TrackControlTypes,
) => Promise<T>;
export interface BrowserWindowViews<T, TView extends WebContentsView = WebContentsView> {
main: BrowserWindow;
views: { [key: string]: TView } & T;
Expand All @@ -24,10 +26,12 @@ export function createWindowContext<T, TView extends WebContentsView = WebConten
return new (class implements BrowserWindowViews<T, TView> {
main: BrowserWindow = _data.main;
views: { [key: string]: TView } & T = _data.views || ({} as any);
async sendTrackControl<T = any>(type: TrackControlTypes) {
async sendTrackControl<T extends { type: TrackControlTypes } = any>(type: TrackControlTypes) {
const view = this.views.youtubeView;
if (!view) return Promise.reject(new Error("View not found"));
return await view.invoke<T>(IPC_EVENT_NAMES.TRACK_CONTROL, { type });
const data = ((await view.invoke<T>(IPC_EVENT_NAMES.TRACK_CONTROL, { type })) ?? {}) as T;
if (data.type !== type) throw new Error("Invalid response");
return data as T;
}
sendToAllViews(ev: string, ...args: any[]): void {
return (Object.values(this.views) as TView[])
Expand Down
5 changes: 5 additions & 0 deletions src/main/utils/onIpcEvent.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { stringifyJson } from "@main/lib/json";
import { createLogger } from "@shared/utils/console";
import { Event, IpcMainEvent, IpcMainInvokeEvent } from "electron";
import { debounce } from "lodash-es";
import { serverMain } from "./serverEvents";
Expand All @@ -10,6 +12,7 @@ interface IpcContextEvent {
debounce?: number;
filter?: IpcFilterOption<IpcMainEvent | IpcMainInvokeEvent> | ((...args: any[]) => boolean);
passive?: boolean;
debug?: boolean
};
}
export function IpcContextWithOptions() {
Expand All @@ -25,7 +28,9 @@ export function IpcContext<T extends { new (...args: any[]): {} }>(IpcContextBas
const symbols: any = IpcContextBase.prototype[classIpcStoreSymbol];
if (symbols) {
symbols.forEach(({ name, type, options }: IpcContextEvent, method: string) => {
const log = createLogger("IPC").child(`${name}:ipc.${type ?? 'on'}`);
const func = (...args: any[]) => {
if (options?.debug) log.debug(`hit, payload size: ${new Blob([stringifyJson(args ?? null)]).size} bytes`);
if (
typeof (this as any)[method] === "function" &&
(options && options.filter && typeof options.filter === "function"
Expand Down
9 changes: 7 additions & 2 deletions src/preload/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,13 @@ export default {
),
);
},
playerApi: () =>
(document.querySelector("ytmusic-app-layout>ytmusic-player-bar") as any)?.playerApi,
playerApi: (() => {
let playerApiCache: any;
return () =>
playerApiCache ||
(playerApiCache = (document.querySelector("ytmusic-app-layout>ytmusic-player-bar") as any)
?.playerApi);
})(),
setInteractiveElements: <T extends HTMLElement>(interactiveElements: T[]) => {
let isMouseOverInteractiveElement = false;
ipcRenderer.send("set-ignore-mouse-events", true, { forward: true });
Expand Down

0 comments on commit e60c09c

Please sign in to comment.