Plugin
PictureInPicture
Adds picture in picture to videos (next to the Download button)
1
import "./styles.css";2
3
import { definePluginSettings } from "@api/Settings";4
import ErrorBoundary from "@components/ErrorBoundary";5
import { Devs } from "@utils/constants";6
import definePlugin, { OptionType } from "@utils/types";7
import { Tooltip } from "@webpack/common";8
9
const settings = definePluginSettings({10
loop: {11
description: "Whether to make the PiP video loop or not",12
type: OptionType.BOOLEAN,13
default: true,14
restartNeeded: false15
}16
});17
18
export default definePlugin({19
name: "PictureInPicture",20
description: "Adds picture in picture to videos (next to the Download button)",21
tags: ["Media", "Utility"],22
authors: [Devs.Lumap],23
settings,24
patches: [25
{26
find: 039;["VIDEO","CLIP","AUDIO"]039;,27
replacement: {28
match: /(\[\i>0&&\i\.length>0.{0,150}?children:)(\i.slice\(\i\))(?<=showDownload:(\i).+?isVisualMediaType:(\i).+?)/,29
replace: (_, rest, origChildren, showDownload, isVisualMediaType) => `${rest}[${showDownload}&&${isVisualMediaType}&&$self.PictureInPictureButton(),...${origChildren}]`30
}31
}32
],33
34
PictureInPictureButton: ErrorBoundary.wrap(() => {35
return (36
<Tooltip text="Toggle Picture in Picture">37
{tooltipProps => (38
<div39
{...tooltipProps}40
className="vc-pip-button"41
role="button"42
style={{43
cursor: "pointer",44
paddingTop: "4px",45
paddingLeft: "4px",46
paddingRight: "4px",47
}}48
onClick={e => {49
const video = e.currentTarget.parentNode!.parentNode!.querySelector("video")!;50
const videoClone = document.body.appendChild(video.cloneNode(true)) as HTMLVideoElement;51
52
videoClone.loop = settings.store.loop;53
videoClone.style.display = "none";54
videoClone.onleavepictureinpicture = () => videoClone.remove();55
56
function launchPiP() {57
videoClone.currentTime = video.currentTime;58
videoClone.requestPictureInPicture();59
video.pause();60
videoClone.play();61
}62
63
if (videoClone.readyState === 4 /* HAVE_ENOUGH_DATA */)64
launchPiP();65
else66
videoClone.onloadedmetadata = launchPiP;67
}}68
>69
<svg width="24px" height="24px" viewBox="0 0 24 24">70
<path71
fill="currentColor"72
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"73
/>74
</svg>75
</div>76
)}77
</Tooltip>78
);79
}, { noop: true })80
});81