youtube continue play

When "Video paused, do you want to continue watching?" Appears, ignore it and continue playing automatically

  1. // ==UserScript==
  2. // @name youtube continue play
  3. // @name:zh-CN youtube继续播放
  4. // @name:zh-TW youtube繼續播放
  5. // @name:ja youtube再生自動継続
  6. // @description When "Video paused, do you want to continue watching?" Appears, ignore it and continue playing automatically
  7. // @description:zh-TW 當出現"影片已暫停,要繼續觀賞嗎?"時忽略它繼續播放
  8. // @description:zh-CN 当出现"影片已暂停,要继续观赏吗?"时忽略它继续播放
  9. // @description:ja 「動画が一時停止されました。続きを視聴しますか?」が表示されても無視して再生を続けます
  10. // @namespace https://greasyfork.org/zh-TW/users/461233-jack850628
  11. // @version 1.21.231207
  12. // @author jack850628
  13. // @include https://*.youtube.com/*
  14. // @noframes
  15. // @run-at document-end
  16. // @license MIT
  17. // ==/UserScript==
  18.  
  19. (function() {
  20. function searchDialog(videoPlayer){
  21. if(videoPlayer.currentTime < videoPlayer.duration){//防止重複播放
  22. let ytConfirmDialog = document.querySelector('yt-confirm-dialog-renderer') || document.querySelector('ytmusic-confirm-dialog-renderer') || document.querySelector('dialog');
  23. if(
  24. ytConfirmDialog &&
  25. (
  26. ytConfirmDialog.parentElement.style.display != 'none' ||
  27. (
  28. document.hidden
  29. )//當網頁不可見時,DOM元件不會即時渲染,所以對話方塊的display還會是none
  30. )
  31. ){
  32. console.debug('被暫停了,但是我要繼續播放');
  33. //ytConfirmDialog.querySelector('yt-button-renderer[dialog-confirm]').click();//當網頁不可見時,觸發click是不會繼續播放的,因為要等到網頁可見時觸發UI渲染後才會把對話方塊關掉,對話方塊關掉後才會出發video的play事件
  34. videoPlayer.play();
  35. console.debug('按下"是"');
  36. }else{
  37. console.debug('對話方塊找不到或是隱藏了', ytConfirmDialog && ytConfirmDialog.parentElement, document.hidden, videoPlayer.currentTime, videoPlayer.duration);
  38. if(videoPlayer.paused && videoPlayer.src){
  39. setTimeout(() => searchDialog(videoPlayer), 1000);//再找一次
  40. }
  41. }
  42. }else{
  43. console.debug('播放完畢');
  44. }
  45. }
  46. let pausedFun = function({target: videoPlayer}){
  47. console.debug('暫停播放');
  48. setTimeout(() => searchDialog(videoPlayer), 500);//確保在暫停時對話方塊一定找得到
  49. }
  50. function setOnPauseEventListener(player){
  51. if(!player.dataset.pauseWatcher){
  52. player.dataset.pauseWatcher = true;
  53. player.addEventListener('pause', pausedFun);
  54. }
  55. }
  56. function observerPlayerRoot(doc){
  57. let player = doc.querySelector('video');
  58. if(player){
  59. console.debug('找到播放器', player);
  60. setOnPauseEventListener(player);
  61. }
  62. let ycpObserver = new MutationObserver((mutationdeList, observer) => {
  63. mutationdeList.flatMap(i => [...i.addedNodes]).flat().forEach(doc => {
  64. if(doc.tagName){
  65. let player = null;
  66. if(doc.tagName == 'VIDEO'){
  67. player = doc;
  68. }else if(!["SCRIPT", "STYLE", "LINK", "MATE"].includes(doc.tagName)){
  69. player = doc.querySelector('video');
  70. }
  71. if(player){
  72. console.debug('找到播放器', player);
  73. setOnPauseEventListener(player);
  74. }
  75. }
  76. });
  77. });
  78. ycpObserver.observe(
  79. doc,
  80. {
  81. childList: true,
  82. subtree: true
  83. }
  84. );
  85. }
  86. let playerRoot = document.querySelector('#player');
  87. if(playerRoot){
  88. observerPlayerRoot(playerRoot);
  89. }else{
  90. let rootObserver = new MutationObserver((mutationdeList, observer) => {
  91. mutationdeList.flatMap(i => [...i.addedNodes]).flat().forEach(doc => {
  92. if (doc.tagName && !["SCRIPT", "STYLE", "LINK", "MATE"].includes(doc.tagName)){
  93. let playerRoot = doc.querySelector('#player');
  94. if(playerRoot){
  95. observerPlayerRoot(playerRoot);
  96. rootObserver.disconnect();
  97. }
  98. }
  99. });
  100. });
  101. rootObserver.observe(
  102. document,
  103. {
  104. childList: true,
  105. subtree: true
  106. }
  107. );
  108. }
  109. })();