mirror of
https://github.com/th-ch/youtube-music.git
synced 2026-01-11 10:31:47 +00:00
174 lines
5.2 KiB
TypeScript
174 lines
5.2 KiB
TypeScript
import { toKeyEvent } from 'keyboardevent-from-electron-accelerator';
|
|
import keyEventAreEqual from 'keyboardevents-areequal';
|
|
import { render } from 'solid-js/web';
|
|
|
|
import { getSongMenu } from '@/providers/dom-elements';
|
|
import {
|
|
isMusicOrVideoTrack,
|
|
isPlayerMenu,
|
|
} from '@/plugins/utils/renderer/check';
|
|
|
|
import { t } from '@/i18n';
|
|
|
|
import { PictureInPictureButton } from './templates/picture-in-picture-button';
|
|
|
|
import type { YoutubePlayer } from '@/types/youtube-player';
|
|
import type { PictureInPicturePluginConfig } from './index';
|
|
import type { RendererContext } from '@/types/contexts';
|
|
|
|
export const onPlayerApiReady = async (
|
|
_: YoutubePlayer,
|
|
{ ipc, getConfig }: RendererContext<PictureInPicturePluginConfig>,
|
|
) => {
|
|
const config = await getConfig();
|
|
|
|
const togglePictureInPicture = async () => {
|
|
if ((await getConfig()).useNativePiP) {
|
|
const isInPiP = document.pictureInPictureElement !== null;
|
|
const video = document.querySelector<HTMLVideoElement>('video');
|
|
const togglePiP = () =>
|
|
isInPiP
|
|
? document.exitPictureInPicture()
|
|
: video?.requestPictureInPicture();
|
|
|
|
try {
|
|
await togglePiP();
|
|
document.querySelector<HTMLButtonElement>('#icon')?.click(); // Close the menu
|
|
return true;
|
|
} catch {}
|
|
}
|
|
|
|
ipc.send('plugin:toggle-picture-in-picture');
|
|
return false;
|
|
};
|
|
|
|
if (config.hotkey) {
|
|
const hotkeyEvent = toKeyEvent(config.hotkey);
|
|
window.addEventListener('keydown', (event) => {
|
|
if (
|
|
keyEventAreEqual(event, hotkeyEvent) &&
|
|
!document.querySelector<HTMLElement & { opened: boolean }>(
|
|
'ytmusic-search-box',
|
|
)?.opened
|
|
) {
|
|
togglePictureInPicture();
|
|
}
|
|
});
|
|
}
|
|
|
|
const exitFullScreenButton = document.querySelector<HTMLButtonElement>(
|
|
'.exit-fullscreen-button',
|
|
);
|
|
const getPlayMinimizeButton = () =>
|
|
document.querySelector('.player-minimize-button');
|
|
const appLayout = document.querySelector<HTMLElement>('ytmusic-app-layout');
|
|
const expandMenu = document.querySelector<HTMLElement>('#expanding-menu');
|
|
const middleControls =
|
|
document.querySelector<HTMLButtonElement>('.middle-controls');
|
|
const playerPage = document.querySelector<
|
|
HTMLElement & { playerPageOpen_: boolean }
|
|
>('ytmusic-player-page');
|
|
const togglePlayerPageButton = document.querySelector<HTMLButtonElement>(
|
|
'.toggle-player-page-button',
|
|
);
|
|
const fullScreenButton =
|
|
document.querySelector<HTMLButtonElement>('.fullscreen-button');
|
|
const player = document.querySelector<
|
|
HTMLVideoElement & { onDoubleClick_: (() => void) | undefined }
|
|
>('#player');
|
|
const onPlayerDblClick = player?.onDoubleClick_;
|
|
const mouseLeaveEventListener = () => middleControls?.click();
|
|
|
|
const titleBar = document.querySelector<HTMLElement>(
|
|
'nav[data-ytmd-main-panel]',
|
|
);
|
|
|
|
const pipClickEventListener = async (e: Event) => {
|
|
e.stopPropagation();
|
|
e.preventDefault();
|
|
await togglePictureInPicture();
|
|
};
|
|
|
|
ipc.on('ytmd:pip-toggle', (isPip: boolean) => {
|
|
if (exitFullScreenButton && player) {
|
|
if (isPip) {
|
|
exitFullScreenButton?.addEventListener('click', pipClickEventListener);
|
|
getPlayMinimizeButton()?.removeEventListener(
|
|
'click',
|
|
pipClickEventListener,
|
|
);
|
|
player.onDoubleClick_ = () => {};
|
|
|
|
expandMenu?.addEventListener('mouseleave', mouseLeaveEventListener);
|
|
if (!playerPage?.playerPageOpen_) {
|
|
togglePlayerPageButton?.click();
|
|
}
|
|
|
|
fullScreenButton?.click();
|
|
appLayout?.classList.add('pip');
|
|
if (titleBar) {
|
|
titleBar.style.display = 'none';
|
|
}
|
|
} else {
|
|
exitFullScreenButton.removeEventListener(
|
|
'click',
|
|
pipClickEventListener,
|
|
);
|
|
getPlayMinimizeButton()?.addEventListener(
|
|
'click',
|
|
pipClickEventListener,
|
|
);
|
|
player.onDoubleClick_ = onPlayerDblClick;
|
|
expandMenu?.removeEventListener('mouseleave', mouseLeaveEventListener);
|
|
exitFullScreenButton.click();
|
|
appLayout?.classList.remove('pip');
|
|
if (titleBar) {
|
|
titleBar.style.display = 'flex';
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
getPlayMinimizeButton()?.addEventListener('click', pipClickEventListener);
|
|
|
|
const pipButtonContainer = document.createElement('div');
|
|
pipButtonContainer.classList.add(
|
|
'style-scope',
|
|
'menu-item',
|
|
'ytmusic-menu-popup-renderer',
|
|
);
|
|
pipButtonContainer.setAttribute('aria-disabled', 'false');
|
|
pipButtonContainer.setAttribute('aria-selected', 'false');
|
|
pipButtonContainer.setAttribute('role', 'option');
|
|
pipButtonContainer.setAttribute('tabindex', '-1');
|
|
|
|
render(
|
|
() => (
|
|
<PictureInPictureButton
|
|
onClick={togglePictureInPicture}
|
|
text={t('plugins.picture-in-picture.templates.button')}
|
|
/>
|
|
),
|
|
pipButtonContainer,
|
|
);
|
|
|
|
const observer = new MutationObserver(() => {
|
|
const menu = getSongMenu();
|
|
|
|
if (
|
|
menu?.contains(pipButtonContainer) ||
|
|
!isMusicOrVideoTrack() ||
|
|
!isPlayerMenu(menu)
|
|
) {
|
|
return;
|
|
}
|
|
|
|
menu?.prepend(pipButtonContainer);
|
|
});
|
|
|
|
observer.observe(document.querySelector('ytmusic-popup-container')!, {
|
|
childList: true,
|
|
subtree: true,
|
|
});
|
|
};
|