Youtube 微播放器

滚动浏览Youtube评论时,右下角启用微播放器

  1. // ==UserScript==
  2. // @name Youtube Mini-player
  3. // @name:zh-CN Youtube 微播放器
  4. // @namespace youtube
  5. // @version 1.0-beta
  6. // @description A mini player is enabled in bottom right of the page while scolling down to look through the comments.
  7. // @description:zh-CN 滚动浏览Youtube评论时,右下角启用微播放器
  8. // @license GNU
  9. // @author glorywong1001@gmail.com
  10. // @match https://*.youtube.com/watch*
  11. // @icon <$ICON$>
  12. // @grant GM_log
  13. // @run-at document-body
  14. // ==/UserScript==
  15.  
  16. let isMOSupported = 'MutationObserver' in window;
  17. let isIOSupported = 'IntersectionObserver' in window;
  18.  
  19. !isMOSupported && GM_log('[Youtube Mini-player]', 'MutationObserver not supported');
  20. !isIOSupported && GM_log('[Youtube Mini-player]', 'IntersectionObserver not supported');
  21.  
  22. if (isMOSupported && isIOSupported) {
  23. const $ = document.querySelector.bind(document);
  24. const body = document.body;
  25. const mutationObserver = new MutationObserver((mutationList, observer) => {
  26. const el = Array.prototype.find.call(mutationList, ((m) => {
  27. if (m.type !== 'childList') return false;
  28. return !!Array.prototype.find.call(m.addedNodes, node => node.id === 'movie_player');
  29. }))
  30. if (el) {
  31. listenToInteraction();
  32. observer.disconnect();
  33. }
  34. });
  35. mutationObserver.observe(body, {
  36. childList: true,
  37. subtree: true
  38. });
  39. GM_log('[Youtube Mini-player]', 'Start to observe mutation on body');
  40.  
  41. function listenToInteraction() {
  42. GM_log('[Youtube Mini-player]', 'Start to listen to interaction on #YtdPlayer');
  43. const ytdPlayer = $('#ytd-player');
  44. const { backgroundColor: ytdpBgClr } = getComputedStyle(ytdPlayer);
  45. const container = ytdPlayer.querySelector('#container');
  46. const videoEl = container.querySelector('video');
  47. const { position, right, bottom, zIndex, boxShadow } = getComputedStyle(container);
  48. const { width, height } = getComputedStyle(videoEl);
  49. const ratio = parseInt(width) / parseInt(height);
  50. const secondary = $('#secondary');
  51. const { paddingRight, width: sWidth } = getComputedStyle(secondary);
  52.  
  53. const floatWidth = parseInt(sWidth) + 20;
  54. const floatHeight = floatWidth / ratio;
  55.  
  56. const intersectionObserver = new IntersectionObserver(([entry]) => {
  57. const { isIntersecting } = entry;
  58. if (isIntersecting) {
  59. GM_log('[Youtube Mini-player]','Disabled mini player');
  60. container.style.position = position;
  61. container.style.right = right;
  62. container.style.bottom = bottom;
  63. container.style.zIndex = zIndex;
  64. container.style.boxShadow = boxShadow;
  65. container.style.width = videoEl.style.width = width;
  66. container.style.height = videoEl.style.height = height;
  67. ytdPlayer.style.backgroundColor = ytdpBgClr;
  68. } else {
  69. GM_log('[Youtube Mini-player]','Enabled mini player');
  70. container.style.position = 'fixed';
  71. container.style.right = container.style.bottom = paddingRight;
  72. container.style.zIndex = '99999';
  73. container.style.boxShadow = '0px 0px 20px rgb(0 0 0 / 50%)';
  74. container.style.width = videoEl.style.width = `${floatWidth}px`;
  75. container.style.height = videoEl.style.height = `${floatHeight}px`;
  76. ytdPlayer.style.backgroundColor = '#222';
  77. }
  78. }, {
  79. threshold: 0.5
  80. });
  81.  
  82. intersectionObserver.observe(ytdPlayer);
  83. }
  84.  
  85. }

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址