video fullpage

将 video 作为全页显示,隐藏其他元素

  1. // ==UserScript==
  2. // @name video fullpage
  3. // @namespace github.q962
  4. // @match https://*/*
  5. // @version 1.6
  6. // @author q962
  7. // @grant GM_registerMenuCommand
  8. // @grant GM_addStyle
  9. // @grant GM_deleteValue
  10. // @grant GM_deleteValues
  11. // @grant GM_setValue
  12. // @grant GM_setValues
  13. // @grant GM_getValue
  14. // @grant GM_getValues
  15. // @grant GM_listValues
  16. // @grant GM_addElement
  17. // @license MIT
  18.  
  19. // @description 将 video 作为全页显示,隐藏其他元素
  20.  
  21. // ==/UserScript==
  22.  
  23. let global_css = `
  24. .__visiable_true.__level_up {
  25. display: block !important;
  26. width: 100% !important;
  27. height: 100% !important;
  28. max-width: unset !important;
  29. max-height: unset !important;
  30. min-width: unset !important;
  31. min-height: unset !important;
  32. margin: unset !important;
  33. padding: unset !important;
  34. overflow: hidden !important;
  35. position: unset !important;
  36. }
  37.  
  38. .__hidden_all > :not(.__visiable_true, .__dialog) {
  39. display: none !important;
  40. }
  41.  
  42. .__dialog {
  43. position: fixed;
  44. width: 600px;
  45. height: auto;
  46. top: 30vh;
  47. z-index: 99999;
  48. background: white;
  49. border: 1px #aaa solid;
  50. border-radius: 5px;
  51. padding: 10px;
  52. left: calc( ( 100vw - 600px ) / 2 );
  53. box-shadow: 0px 4px 8px 0px black;
  54. }
  55. .__dialog > *, .__dialog > h1 {
  56. color: black;
  57. width: 100%;
  58.  
  59. }
  60. .__dialog input {
  61. width: 90%;
  62. }
  63. `;
  64.  
  65. GM_addStyle(global_css);
  66.  
  67. ///////////////////////////////
  68.  
  69. var upCount = get_upCount();
  70. var current_video_elem = null;
  71. var current_video_elem_controls = undefined;
  72.  
  73. /////////////////////////////////////////////////////////
  74.  
  75. var count_dialog = GM_addElement('div');
  76. count_dialog.classList.add("__dialog");
  77. count_dialog.innerHTML = `
  78. <h1>设置上层层数</h1>
  79. <label>正则:<input id="regex"/></label><br/>
  80. <label>层数:<input id="count" min=0 max=15 type="number" value=0 /></label><br/>
  81. <br/>
  82. <button id="ok">确定</button>
  83. <button id="cancel">取消</button>
  84. <p id="msg"></p>
  85. `;
  86. count_dialog.hidden = true;
  87.  
  88. var regex_elem = count_dialog.querySelector("#regex");
  89. var count_elem = count_dialog.querySelector("#count");
  90. var msg_elem = count_dialog.querySelector("#msg");
  91.  
  92. count_dialog.querySelector("#ok").addEventListener("click", ()=>{
  93. let regex_str = regex_elem.value;
  94. let count = count_elem.value;
  95.  
  96. if( !regex_str ) return;
  97. try{
  98. new RegExp(regex_str);
  99. } catch(error){
  100. msg_elem.innerText = error;
  101. return;
  102. }
  103.  
  104. if( count>15 || count < 0 ){
  105. msg_elem.innerText = "0 <= 层数 <=15";
  106. return;
  107. }
  108.  
  109. GM_setValue(location.origin, JSON.stringify({regex: regex_str, count: count}));
  110.  
  111. count_dialog.hidden = true;
  112.  
  113. upCount = count;
  114.  
  115. });
  116.  
  117. count_dialog.querySelector("#cancel").addEventListener("click", ()=>{
  118. count_dialog.hidden = true;
  119. });
  120.  
  121. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  122.  
  123. function get_upCount(){
  124. let j = JSON.parse(GM_getValue(location.origin)||null);
  125. if(!j) return 0;
  126.  
  127. if( j.regex ) {
  128. try{
  129. let regex = new RegExp(j.regex);
  130. if( !regex.test(location.href) ) return 0;
  131. } catch(error){return 0;}
  132. }
  133.  
  134. return parseInt(j.count);
  135. }
  136.  
  137. function settings(){
  138. count_elem.value = 0;
  139. regex_elem.value = (location.origin+location.pathname).replaceAll(".","\\.");
  140.  
  141. let j = JSON.parse(GM_getValue(location.origin)||null);
  142. if( j ) {
  143. if( j.regex ) regex_elem.value = j.regex;
  144. if( j.count ) count_elem.value = j.count;
  145. }
  146.  
  147. msg_elem.innerText = "";
  148.  
  149. count_dialog.hidden = false;
  150. }
  151.  
  152. function do_full(target){
  153. let action = '';
  154. if(target.classList.contains("__visiable_this")){
  155. action = 'remove';
  156.  
  157. if (target instanceof HTMLVideoElement ) {
  158. target.controls = current_video_elem_controls;
  159. }
  160. } else{
  161. action = 'add';
  162.  
  163. if (target instanceof HTMLVideoElement ) {
  164. target.controls = true;
  165. }
  166. }
  167.  
  168. target.classList[action]("__visiable_this");
  169.  
  170. let p = target;
  171. while(p){
  172.  
  173. p.classList[action]("__visiable_true");
  174. p.classList[action]("__level_up");
  175.  
  176. if( p.parentElement )
  177. p.parentElement.classList[action]("__hidden_all");
  178.  
  179. p = p.parentElement;
  180. }
  181.  
  182. return action == "add";
  183. }
  184.  
  185. function try_iframe(){
  186. let playing_href = GM_getValue("playing_href");
  187.  
  188. for(let win_index=0; window.top[win_index]; win_index++){
  189. let win = window.top[win_index];
  190. if( win.____playing )
  191. return win.frameElement;
  192. }
  193. }
  194.  
  195. function try_find(){
  196. let all = document.querySelectorAll("video");
  197. for(let i=0;i < all.length;i++){
  198. let videl_elem = all[i];
  199.  
  200. if( videl_elem.currentTime > 0 && !videl_elem.paused && !videl_elem.ended ) {
  201. return videl_elem;
  202. }
  203. }
  204. return false;
  205. }
  206.  
  207. let oldUpCount = undefined;
  208. let isFull = false;
  209.  
  210. function set_fullpage(){
  211. current_video_elem = current_video_elem || try_find() || try_iframe();
  212.  
  213. if(!current_video_elem) return;
  214.  
  215. if (current_video_elem instanceof HTMLVideoElement ) {
  216. current_video_elem_controls = current_video_elem.controls;
  217. }
  218.  
  219. let target = current_video_elem;
  220. let _upCount = upCount;
  221.  
  222. // 如果在全页状态下,当前的 upCount 发生了改变时,
  223. // 需要保证移除 class 的结点要正确
  224. if( isFull && oldUpCount != undefined && oldUpCount != upCount )
  225. _upCount = oldUpCount;
  226.  
  227. for( let i=0; i < _upCount; i++ ) {
  228. target = target.parentElement;
  229. }
  230.  
  231. oldUpCount = upCount;
  232. isFull = do_full( target );
  233. }
  234.  
  235. GM_registerMenuCommand('全页', set_fullpage);
  236. GM_registerMenuCommand('设置', settings);
  237.  
  238. //////////////////////////////////////////////////////////////////////////////
  239.  
  240. function bind_evnet(elem){
  241. elem.addEventListener('play', function(e) {
  242. // 记录当前正在播放的 iframe
  243. unsafeWindow.____playing = true;
  244. current_video_elem = e.target;
  245. });
  246. }
  247.  
  248. const observer = new MutationObserver( function (mutationsList, observer) {
  249. for (let mutation of mutationsList) {
  250. if (mutation.type === "childList") {
  251. for (let node of mutation.addedNodes) {
  252. if (node.tagName === 'VIDEO') {
  253. bind_evnet(node);
  254. }
  255. }
  256. }
  257. }
  258. });
  259.  
  260. observer.observe(document.body, { childList: true, subtree: true });
  261.  
  262. function FindAllVideoElems(){
  263.  
  264. let video_elems = document.querySelectorAll("video");
  265. for( let index=0; index < video_elems.length; index++){
  266. bind_evnet( video_elems[index] );
  267. }
  268. }
  269.  
  270. FindAllVideoElems();

QingJ © 2025

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