From 6f70d179c76e2cf8c813307d829720e2af3396c8 Mon Sep 17 00:00:00 2001 From: JellyBrick Date: Tue, 20 Feb 2024 12:57:26 +0900 Subject: [PATCH] fix: fixed an issue that caused infinite loops when using Music Together fix #1752 --- src/plugins/music-together/index.ts | 8 ++--- src/plugins/music-together/queue/queue.ts | 44 +++++++++++++---------- src/plugins/music-together/types.ts | 15 +++++--- 3 files changed, 40 insertions(+), 27 deletions(-) diff --git a/src/plugins/music-together/index.ts b/src/plugins/music-together/index.ts index a9549ef1..036febf1 100644 --- a/src/plugins/music-together/index.ts +++ b/src/plugins/music-together/index.ts @@ -6,9 +6,9 @@ import { t } from '@/i18n'; import { createPlugin } from '@/utils'; import promptOptions from '@/providers/prompt-options'; -import { AppAPI, getDefaultProfile, Permission, Profile, VideoData } from './types'; +import { type AppElement, getDefaultProfile, type Permission, type Profile, type VideoData } from './types'; import { Queue } from './queue'; -import { Connection, ConnectionEventUnion } from './connection'; +import { Connection, type ConnectionEventUnion } from './connection'; import { createHostPopup } from './ui/host'; import { createGuestPopup } from './ui/guest'; import { createSettingPopup } from './ui/setting'; @@ -41,7 +41,7 @@ export default createPlugin< { connection?: Connection; ipc?: RendererContext['ipc']; - api: HTMLElement & AppAPI | null; + api: AppElement | null; queue?: Queue; playerApi?: YoutubePlayer; showPrompt: (title: string, label: string) => Promise; @@ -557,7 +557,7 @@ export default createPlugin< start({ ipc }) { this.ipc = ipc; this.showPrompt = async (title: string, label: string) => ipc.invoke('music-together:prompt', title, label) as Promise; - this.api = document.querySelector('ytmusic-app'); + this.api = document.querySelector('ytmusic-app'); /* setup */ document.querySelector('#right-content > ytmusic-settings-button')?.insertAdjacentHTML('beforebegin', settingHTML); diff --git a/src/plugins/music-together/queue/queue.ts b/src/plugins/music-together/queue/queue.ts index f2367e85..1b74c0d4 100644 --- a/src/plugins/music-together/queue/queue.ts +++ b/src/plugins/music-together/queue/queue.ts @@ -1,10 +1,10 @@ import { getMusicQueueRenderer } from './song'; import { mapQueueItem } from './utils'; -import { ConnectionEventUnion } from '@/plugins/music-together/connection'; import { t } from '@/i18n'; -import type { Profile, QueueAPI, VideoData } from '../types'; +import type { ConnectionEventUnion } from '@/plugins/music-together/connection'; +import type { Profile, QueueElement, VideoData } from '../types'; import type { QueueItem } from '@/types/datahost-get-state'; const getHeaderPayload = (() => { @@ -103,26 +103,29 @@ const getHeaderPayload = (() => { export type QueueOptions = { videoList?: VideoData[]; owner?: Profile; - queue?: HTMLElement & QueueAPI; + queue?: QueueElement; getProfile: (id: string) => Profile | undefined; } export type QueueEventListener = (event: ConnectionEventUnion) => void; export class Queue { - private queue: (HTMLElement & QueueAPI); + private readonly queue: QueueElement; + private originalDispatch?: (obj: { type: string; payload?: { items?: QueueItem[] | undefined; }; }) => void; + private internalDispatch = false; private ignoreFlag = false; private listeners: QueueEventListener[] = []; - private owner: Profile | null = null; - private getProfile: (id: string) => Profile | undefined; + + private owner: Profile | null; + private readonly getProfile: (id: string) => Profile | undefined; constructor(options: QueueOptions) { this.getProfile = options.getProfile; - this.queue = options.queue ?? document.querySelector('#queue')!; + this.queue = options.queue ?? (document.querySelector('#queue')!); this.owner = options.owner ?? null; this._videoList = options.videoList ?? []; } @@ -135,11 +138,11 @@ export class Queue { } get selectedIndex() { - return mapQueueItem((it) => it?.selected, this.queue.store.getState().queue.items).findIndex(Boolean) ?? 0; + return mapQueueItem((it) => it?.selected, this.queue.queue.store.store.getState().queue.items).findIndex(Boolean) ?? 0; } get rawItems() { - return this.queue?.store.getState().queue.items; + return this.queue?.queue.store.store.getState().queue.items; } get flatItems() { @@ -169,8 +172,8 @@ export class Queue { this.queue?.dispatch({ type: 'ADD_ITEMS', payload: { - nextQueueItemId: this.queue.store.getState().queue.nextQueueItemId, - index: index ?? this.queue.store.getState().queue.items.length ?? 0, + nextQueueItemId: this.queue.queue.store.store.getState().queue.nextQueueItemId, + index: index ?? this.queue.queue.store.store.getState().queue.items.length ?? 0, items, shuffleEnabled: false, shouldAssignIds: true @@ -249,7 +252,7 @@ export class Queue { return; } - if (this.originalDispatch) this.queue.store.dispatch = this.originalDispatch; + if (this.originalDispatch) this.queue.queue.store.store.dispatch = this.originalDispatch; } injection() { @@ -258,8 +261,8 @@ export class Queue { return; } - this.originalDispatch = this.queue.store.dispatch; - this.queue.store.dispatch = (event) => { + this.originalDispatch = this.queue.queue.store.store.dispatch; + this.queue.queue.store.store.dispatch = (event) => { if (!this.queue || !this.owner) { console.error('Queue is not initialized!'); return; @@ -361,10 +364,13 @@ export class Queue { const fakeContext = { ...this.queue, - store: { - ...this.queue.store, - dispatch: this.originalDispatch - } + queue: { + ...this.queue.queue, + store: { + ...this.queue.queue.store, + dispatch: this.originalDispatch, + } + }, }; this.originalDispatch?.call(fakeContext, event); }; @@ -400,7 +406,7 @@ export class Queue { type: 'UPDATE_ITEMS', payload: { items: items, - nextQueueItemId: this.queue.store.getState().queue.nextQueueItemId, + nextQueueItemId: this.queue.queue.store.store.getState().queue.nextQueueItemId, shouldAssignIds: true, currentIndex: -1 } diff --git a/src/plugins/music-together/types.ts b/src/plugins/music-together/types.ts index cec1c822..5ee86a71 100644 --- a/src/plugins/music-together/types.ts +++ b/src/plugins/music-together/types.ts @@ -1,5 +1,5 @@ -import { YoutubePlayer } from '@/types/youtube-player'; -import { GetState, QueueItem } from '@/types/datahost-get-state'; +import type { YoutubePlayer } from '@/types/youtube-player'; +import type { GetState, QueueItem } from '@/types/datahost-get-state'; type StoreState = GetState; type Store = { @@ -14,16 +14,23 @@ type Store = { replaceReducer: (param1: unknown) => unknown; subscribe: (callback: () => void) => unknown; } -export type QueueAPI = { + +export type QueueElement = HTMLElement & { dispatch(obj: { type: string; payload?: unknown; }): void; + queue: QueueAPI; +}; +export type QueueAPI = { getItems(): unknown[]; - store: Store; + store: { + store: Store, + }; continuation?: string; autoPlaying?: boolean; }; +export type AppElement = HTMLElement & AppAPI; export type AppAPI = { queue_: QueueAPI; playerApi_: YoutubePlayer;