diff options
-rw-r--r-- | src/plugins/pictureInPicture.tsx | 83 | ||||
-rw-r--r-- | src/utils/constants.ts | 6 |
2 files changed, 88 insertions, 1 deletions
diff --git a/src/plugins/pictureInPicture.tsx b/src/plugins/pictureInPicture.tsx new file mode 100644 index 0000000..7a9e790 --- /dev/null +++ b/src/plugins/pictureInPicture.tsx @@ -0,0 +1,83 @@ +/* + * Vencord, a Discord client mod + * Copyright (c) 2023 Vendicated and contributors + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +import { definePluginSettings } from "@api/Settings"; +import ErrorBoundary from "@components/ErrorBoundary"; +import { Devs } from "@utils/constants"; +import definePlugin, { OptionType } from "@utils/types"; +import { React, Tooltip } from "@webpack/common"; + +const settings = definePluginSettings({ + loop: { + description: "Whether to make the PiP video loop or not", + type: OptionType.BOOLEAN, + default: true, + restartNeeded: false + } +}); + +export default definePlugin({ + name: "PictureInPicture", + description: "Adds picture in picture to videos (next to the Download button)", + authors: [Devs.Lumap], + settings, + + patches: [ + { + find: ".onRemoveAttachment,", + replacement: { + match: /\.nonMediaAttachment.{0,10}children:\[(\i),/, + replace: "$&$1&&$self.renderPiPButton()," + }, + }, + ], + + renderPiPButton: ErrorBoundary.wrap(() => { + return ( + <Tooltip text="Toggle Picture in Picture"> + {tooltipProps => ( + <div + {...tooltipProps} + role="button" + style={{ + cursor: "pointer", + paddingTop: "4px", + paddingLeft: "4px", + paddingRight: "4px", + }} + onClick={e => { + const video = e.currentTarget.parentNode!.parentNode!.querySelector("video")!; + const videoClone = document.body.appendChild(video.cloneNode(true)) as HTMLVideoElement; + + videoClone.loop = settings.store.loop; + videoClone.style.display = "none"; + videoClone.onleavepictureinpicture = () => videoClone.remove(); + + function launchPiP() { + videoClone.currentTime = video.currentTime; + videoClone.requestPictureInPicture(); + video.pause(); + videoClone.play(); + } + + if (videoClone.readyState === 4 /* HAVE_ENOUGH_DATA */) + launchPiP(); + else + videoClone.onloadedmetadata = launchPiP; + }} + > + <svg width="24px" height="24px" viewBox="0 0 24 24"> + <path + fill="var(--interactive-normal)" + d="M21 3a1 1 0 0 1 1 1v7h-2V5H4v14h6v2H3a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1h18zm0 10a1 1 0 0 1 1 1v6a1 1 0 0 1-1 1h-8a1 1 0 0 1-1-1v-6a1 1 0 0 1 1-1h8zm-1 2h-6v4h6v-4z" + /> + </svg> + </div> + )} + </Tooltip> + ); + }, { noop: true }) +}); diff --git a/src/utils/constants.ts b/src/utils/constants.ts index 245c8bb..400fcaa 100644 --- a/src/utils/constants.ts +++ b/src/utils/constants.ts @@ -355,6 +355,10 @@ export const Devs = /* #__PURE__*/ Object.freeze({ name: "bb010g", id: 72791153467990016n, }, + Lumap: { + name: "lumap", + id: 635383782576357407n + }, Dolfies: { name: "Dolfies", id: 852892297661906993n, @@ -362,7 +366,7 @@ export const Devs = /* #__PURE__*/ Object.freeze({ RuukuLada: { name: "RuukuLada", id: 119705748346241027n, - }, + } } satisfies Record<string, Dev>); // iife so #__PURE__ works correctly |