// ==UserScript== // @name 画中画 // @name:en Pic-in-pic // @namespace https://github.com/zaaack/tools/ // @description 在任意网站开启画中画模式,使视频漂浮在所有窗口最上层 // @description:en Enable picture-in-picture mode in any video site, make video float on top window // @version 1.0 // @author zaaack // @include * // @grant unsafeWindow // @run-at context-menu // @homepageURL https://github.com/zaaack/tools/blob/master/tampermonkey/pic-in-pic/README.md // @supportURL https://github.com/zaaack/tools/issues // ==/UserScript== ;(() => { // fork from https://github.com/GoogleChromeLabs/picture-in-picture-chrome-extension/blob/20288da7c56b525f2c21129df58d45b027d4f328/src/script.js#L2 // // // Copyright 2018 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. function findLargestPlayingVideo() { const videos = Array.from(document.querySelectorAll('video')) .filter((video) => video.readyState != 0) .filter((video) => video.disablePictureInPicture == false) .sort((v1, v2) => { const v1Rect = v1.getClientRects()[0] || { width: 0, height: 0 } const v2Rect = v2.getClientRects()[0] || { width: 0, height: 0 } return v2Rect.width * v2Rect.height - v1Rect.width * v1Rect.height }) if (videos.length === 0) { return } return videos[0] } async function requestPictureInPicture(video) { await video.requestPictureInPicture() video.setAttribute('__pip__', true) video.addEventListener( 'leavepictureinpicture', (event) => { video.removeAttribute('__pip__') }, { once: true } ) new ResizeObserver(maybeUpdatePictureInPictureVideo).observe(video) } function maybeUpdatePictureInPictureVideo(entries, observer) { const observedVideo = entries[0].target if (!document.querySelector('[__pip__]')) { observer.unobserve(observedVideo) return } const video = findLargestPlayingVideo() if (video && !video.hasAttribute('__pip__')) { observer.unobserve(observedVideo) requestPictureInPicture(video) } } ;(async () => { const video = findLargestPlayingVideo() if (!video) { return } if (video.hasAttribute('__pip__')) { document.exitPictureInPicture() return } await requestPictureInPicture(video) // chrome.runtime.sendMessage({ message: 'enter' }) })() })()