Picture-in-picture on Hulu (press H)

Press H to enable or disable picture-in-picture on Hulu

  1. // ==UserScript==
  2. // @name Picture-in-picture on Hulu (press H)
  3. // @namespace http://tampermonkey.net/
  4. // @version 1.0
  5. // @description Press H to enable or disable picture-in-picture on Hulu
  6. // @author https://greasyfork.org/en/users/728793-keyboard-shortcuts
  7. // @match https://www.hulu.com/*
  8. // @icon https://www.google.com/s2/favicons?sz=128&domain=hulu.com
  9. // @grant none
  10. // @license MIT
  11. // ==/UserScript==
  12.  
  13. /* jshint esversion: 6 */
  14.  
  15. (function() {
  16. 'use strict';
  17.  
  18. function hasNoModifiers(event) {
  19. return !(event.ctrlKey || event.shiftKey || event.altKey || event.metaKey);
  20. }
  21.  
  22. function findVideoElement() {
  23. return Array.from(document.querySelectorAll('video')) // find all <video> elements
  24. .filter((v) => v.currentTime > 0 && !(v.ended)) // keep only the ones with a "currentTime" set and not marked as "ended"
  25. .map((v) => ({element: v, area: (v.clientWidth * v.clientHeight)})) // compute the size for each
  26. .reduce((best, current) => current.area > best.area ? current : best, {element: null, area: 0}) // and keep only the largest one, likely the one we want
  27. .element; // returning the element
  28. }
  29.  
  30. addEventListener('keypress', (e) => {
  31. if (e.code === 'KeyH' && hasNoModifiers(e)) {
  32. const video = findVideoElement();
  33. if (video !== null) {
  34. if (video.hasAttribute('disablepictureinpicture')) { // Hulu sets this, let's drop it.
  35. video.removeAttribute('disablepictureinpicture');
  36. }
  37. if (document.pictureInPictureElement) { // already in PiP mode
  38. document.exitPictureInPicture();
  39. } else {
  40. video.requestPictureInPicture();
  41. }
  42. }
  43. }
  44. });
  45. })();