fix: fix an issue with videodatachangefired timing

This commit is contained in:
JellyBrick
2023-11-30 00:45:15 +09:00
parent 4c0cce89ee
commit d78da237fc
5 changed files with 59 additions and 26 deletions

View File

@ -4,6 +4,8 @@ import style from './style.css?inline';
import { createPlugin } from '@/utils';
import type { VideoDataChanged } from '@/types/video-data-changed';
export default createPlugin({
name: 'Album Color Theme',
restartNeeded: true,
@ -110,8 +112,8 @@ export default createPlugin({
onPlayerApiReady(playerApi) {
const fastAverageColor = new FastAverageColor();
playerApi.addEventListener('videodatachange', (name: string) => {
if (name === 'dataloaded') {
document.addEventListener('videodatachange', (event: CustomEvent<VideoDataChanged>) => {
if (event.detail.name === 'dataloaded') {
const playerResponse = playerApi.getPlayerResponse();
const thumbnail = playerResponse?.videoDetails?.thumbnail?.thumbnails?.at(0);
if (thumbnail) {

View File

@ -1,5 +1,6 @@
import { createPlugin } from '@/utils';
import type { VideoDataChanged } from '@/types/video-data-changed';
import type { YoutubePlayer } from '@/types/youtube-player';
export type DisableAutoPlayPluginConfig = {
@ -13,7 +14,7 @@ export default createPlugin<
{
config: DisableAutoPlayPluginConfig | null;
api: YoutubePlayer | null;
eventListener: (name: string) => void;
eventListener: (event: CustomEvent<VideoDataChanged>) => void;
timeUpdateListener: (e: Event) => void;
},
DisableAutoPlayPluginConfig
@ -44,12 +45,12 @@ export default createPlugin<
renderer: {
config: null,
api: null,
eventListener(name: string) {
eventListener(event: CustomEvent<VideoDataChanged>) {
if (this.config?.applyOnce) {
this.api?.removeEventListener('videodatachange', this.eventListener);
document.removeEventListener('videodatachange', this.eventListener);
}
if (name === 'dataloaded') {
if (event.detail.name === 'dataloaded') {
this.api?.pauseVideo();
document.querySelector<HTMLVideoElement>('video')?.addEventListener('timeupdate', this.timeUpdateListener, { once: true });
}
@ -65,10 +66,10 @@ export default createPlugin<
onPlayerApiReady(api) {
this.api = api;
api.addEventListener('videodatachange', this.eventListener);
document.addEventListener('videodatachange', this.eventListener);
},
stop() {
this.api?.removeEventListener('videodatachange', this.eventListener);
document.removeEventListener('videodatachange', this.eventListener);
},
onConfigChange(newConfig) {
this.config = newConfig;

View File

@ -13,28 +13,48 @@ import type { PluginConfig } from '@/types/plugins';
import type { YoutubePlayer } from '@/types/youtube-player';
let api: (Element & YoutubePlayer) | null = null;
let isPluginLoaded = false;
let isApiLoaded = false;
let firstDataLoaded = false;
async function listenForApiLoad() {
api = document.querySelector('#movie_player');
if (api) {
await onApiLoaded();
const observer = new MutationObserver(() => {
const playerApi = document.querySelector<Element & YoutubePlayer>('#movie_player');
if (playerApi) {
observer.disconnect();
return;
}
// Inject song-info provider
setupSongInfo(playerApi);
const dataLoadedListener = (name: string) => {
if (!firstDataLoaded && name === 'dataloaded') {
firstDataLoaded = true;
playerApi.removeEventListener('videodatachange', dataLoadedListener);
}
};
playerApi.addEventListener('videodatachange', dataLoadedListener);
const observer = new MutationObserver(() => {
api = document.querySelector('#movie_player');
if (api) {
observer.disconnect();
if (isPluginLoaded && !isApiLoaded) {
api = playerApi;
isApiLoaded = true;
onApiLoaded();
}
});
}
});
observer.observe(document.documentElement, {
childList: true,
subtree: true,
});
observer.observe(document.documentElement, {
childList: true,
subtree: true,
});
async function listenForApiLoad() {
if (!isApiLoaded) {
api = document.querySelector('#movie_player');
if (api) {
await onApiLoaded();
return;
}
}
}
interface YouTubeMusicAppElement extends HTMLElement {
@ -45,9 +65,6 @@ async function onApiLoaded() {
window.ipcRenderer.on('seekTo', (_, t: number) => api!.seekTo(t));
window.ipcRenderer.on('seekBy', (_, t: number) => api!.seekBy(t));
// Inject song-info provider
setupSongInfo(api!);
const video = document.querySelector('video')!;
const audioContext = new AudioContext();
const audioSource = audioContext.createMediaElementSource(video);
@ -59,6 +76,10 @@ async function onApiLoaded() {
}
}
if (firstDataLoaded) {
document.dispatchEvent(new CustomEvent('videodatachange', { detail: { name: 'dataloaded' } }));
}
const audioCanPlayEventDispatcher = () => {
document.dispatchEvent(
new CustomEvent('audioCanPlay', {
@ -128,6 +149,7 @@ async function onApiLoaded() {
(async () => {
await loadAllRendererPlugins();
isPluginLoaded = true;
window.ipcRenderer.on(
'plugin:unload',

2
src/reset.d.ts vendored
View File

@ -4,6 +4,7 @@ import type { ipcRenderer as electronIpcRenderer } from 'electron';
import type is from 'electron-is';
import type config from './config';
import type { VideoDataChanged } from '@/types/video-data-changed';
declare global {
interface Compressor {
@ -13,6 +14,7 @@ declare global {
interface DocumentEventMap {
'audioCanPlay': CustomEvent<Compressor>;
'videodatachange': CustomEvent<VideoDataChanged>;
}
interface Window {

View File

@ -0,0 +1,6 @@
import type { VideoDataChangeValue } from '@/types/player-api-events';
export interface VideoDataChanged {
name: string;
videoData?: VideoDataChangeValue;
}