视频网页全屏

让所有视频网页全屏

当前为 2017-08-31 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Maximize Video
  3. // @name:zh-CN 视频网页全屏
  4. // @namespace http://www.icycat.com
  5. // @description Maximize all video players
  6. // @description:zh-CN 让所有视频网页全屏
  7. // @author 冻猫
  8. // @include *
  9. // @exclude *www.w3school.com.cn*
  10. // @version 9.5.0
  11. // @grant unsafeWindow
  12. // @run-at document-end
  13. // ==/UserScript==
  14.  
  15. (function() {
  16.  
  17. 'use strict';
  18.  
  19. var fullStatus = false,
  20. isIframe = false,
  21. isFullIframePlayer = false,
  22. isRbtn = true,
  23. parentArray = new Array(),
  24. backStyle = new Object(),
  25. mouse = {
  26. leave: 'listener',
  27. over: 'listener'
  28. },
  29. browser, btnText, player, controlBtn, leftBtn, rightBtn;
  30.  
  31. //Html5规则[overlay|到player节点数],适用于自适应大小HTML5播放器
  32. var html5Rules = {
  33. 'www.nicovideo.jp': ['#UadPlayer|2'],
  34. 'thevideo.me': ['#vplayer video|1'],
  35. 'kimcartoon.me': ['#divContentVideo video|1'],
  36. 'www.dailymotion.com': ['#player video|4', '#player .dmp_VideoView|2'],
  37. 'v.youku.com': ['#ykPlayer .youku_layer_logo|3', '#ykPlayer .h5-layer-conatiner|2'],
  38. 'www.iqiyi.com': ['#flashbox video|2'],
  39. 'www.youtube.com': ['#player-api video|3', '#c4-player video|2', '#player-container video|3', '#movie_player|0'],
  40. 'www.twitch.tv': ['#player .js-control-fullscreen-overlay|1'],
  41. 'www.huya.com': ['#player-video|3'],
  42. 'www.bilibili.com': ['#bilibiliPlayer video|4', '.bilibili-player-info|2'],
  43. 'www.pornhub.com': ['.mhp1138_eventCatcher|2'],
  44. 'www.redtube.com': ['.mhp1138_eventCatcher|1'],
  45. 'www.youporn.com': ['.mhp1138_eventCatcher|1'],
  46. 'www.icourse163.org': ['.ux-video-player .bbg|3'],
  47. 'www.panda.tv': ['#room-player-video-danmu div|3'],
  48. 'vk.com': ['.videoplayer_media|1'],
  49. 'www.douyu.com': ['.danmu-wrap video|2'],
  50. 'store.steampowered.com': ['#highlight_player_area video|2'],
  51. 'vimeo.com': ['.player .target|1'],
  52. 'ecchi.iwara.tv': ['#video-player video|1'],
  53. 'live.bilibili.com': ['.bilibili-live-player-video-danmaku|2', '.bilibili-live-player-video-gift|2'],
  54. 'v.qq.com': ['#tenvideo_player .txp_shadow|3', '#video_container_body .txp_shadow|3']
  55. };
  56.  
  57. //iframe播放器显示按钮规则
  58. //iframe关键字id、classname、src
  59. var iframeRules = /play|youtube\.com\/embed|video|movie|anime|flv|mp4/i;
  60. //网站域名
  61. var iframeUrlRules = [
  62. 'kisshentai.net',
  63. 'www.watchseries.ac',
  64. 'www.panda.tv',
  65. 'animeflv.net',
  66. 'www.vodlocker.city',
  67. 'projectwatchseries.com',
  68. 'reyanime.com'
  69. ];
  70.  
  71. //自动缩放内层内播放器规则
  72. var fullIframePlayerRules = [
  73. 'newplayer.jfrft.com',
  74. 'player.005.tv',
  75. 'player.xcmh.cc',
  76. 'www.auroravid.to',
  77. 'www.mp4upload.com',
  78. 'vodlocker.com',
  79. '52dongm.duapp.com'
  80. ];
  81.  
  82. //flash游戏页面,不在flash上显示还原按钮
  83. var excludeRbtnRules = [
  84. 'www.dmm.com',
  85. 'www.dmm.co.jp',
  86. 'www.4399.com',
  87. 'www.3366.com',
  88. 'flash.17173.com',
  89. 'www.7k7k.com'
  90. ];
  91.  
  92. if (excludeRbtnRules.indexOf(document.location.hostname) != -1) {
  93. isRbtn = false;
  94. }
  95.  
  96. if (window.top !== window.self) {
  97. isIframe = true;
  98. }
  99.  
  100. if (navigator.language.toLocaleLowerCase() == 'zh-cn') {
  101. btnText = {
  102. out: '网页全屏',
  103. inner: '内层全屏',
  104. restore: '还原大小'
  105. };
  106. } else {
  107. btnText = {
  108. out: 'Maximize',
  109. inner: 'M<br/>A<br/>X',
  110. restore: 'Restore'
  111. };
  112. }
  113.  
  114. if (/Firefox/i.test(navigator.userAgent)) {
  115. browser = 'firefox';
  116. } else if (/Chrome/i.test(navigator.userAgent)) {
  117. browser = 'chrome';
  118. } else {
  119. browser = 'other';
  120. }
  121.  
  122. var createButton = function(id) {
  123. var btn = document.createElement('tbdiv');
  124. btn.id = id;
  125. btn.onclick = function() {
  126. maximize.playerControl();
  127. };
  128. document.body.appendChild(btn);
  129. return btn;
  130. };
  131.  
  132. var tool = {
  133. getRect: function(element) {
  134. var rect = element.getBoundingClientRect();
  135. var scroll = tool.getScroll();
  136. return {
  137. pageX: rect.left + scroll.left,
  138. pageY: rect.top + scroll.top,
  139. screenX: rect.left,
  140. screenY: rect.top
  141. };
  142. },
  143. isFullClient: function(element) {
  144. var client = tool.getClient();
  145. var rect = tool.getRect(element);
  146. if (Math.abs(client.width - element.offsetWidth) < 21 && Math.abs(client.height - element.offsetHeight) < 21 && rect.screenY < 10 && rect.screenX < 20) {
  147. return true;
  148. } else {
  149. return false;
  150. }
  151. },
  152. isHtml5FullClient: function(element) {
  153. var client = tool.getClient();
  154. var rect = tool.getRect(element);
  155. var w = client.width - element.offsetWidth;
  156. var h = client.height - element.offsetHeight;
  157. if (w >= 0 && h >= 0) {
  158. if ((w < 21 && rect.screenX < 20) || (h < 21 && rect.screenY < 10)) {
  159. return true;
  160. } else {
  161. return false;
  162. }
  163. } else {
  164. return false;
  165. }
  166.  
  167. },
  168. getScroll: function() {
  169. return {
  170. left: document.documentElement.scrollLeft || document.body.scrollLeft,
  171. top: document.documentElement.scrollTop || document.body.scrollTop
  172. };
  173. },
  174. getClient: function() {
  175. return {
  176. width: document.compatMode == 'CSS1Compat' ? document.documentElement.clientWidth : document.body.clientWidth,
  177. height: document.compatMode == 'CSS1Compat' ? document.documentElement.clientHeight : document.body.clientHeight
  178. };
  179. },
  180. addStyle: function(css) {
  181. var style = document.createElement('style');
  182. style.type = 'text/css';
  183. var node = document.createTextNode(css);
  184. style.appendChild(node);
  185. document.head.appendChild(style);
  186. return style;
  187. }
  188. };
  189.  
  190. var setButton = {
  191. init: function() {
  192. //防止页面脚本干扰,重新初始化样式
  193. if (!document.getElementById('playerControlBtn')) {
  194. init();
  195. }
  196. if (isIframe && !isFullIframePlayer && fullIframePlayerRules.indexOf(document.location.hostname) != -1) {
  197. if (player.nodeName == 'OBJECT' || player.nodeName == 'EMBED') {
  198. maximize.checkParent();
  199. maximize.addClass();
  200. tool.addStyle('#htmlToothbrush #bodyToothbrush .playerToothbrush {left:0px !important;width:100vw !important;}');
  201. isFullIframePlayer = true;
  202. }
  203. }
  204. if (tool.isFullClient(player) || isFullIframePlayer) {
  205. return;
  206. }
  207. if (isIframe && player.nodeName == 'VIDEO' && tool.isHtml5FullClient(player)) {
  208. return;
  209. }
  210. this.show();
  211. },
  212. show: function() {
  213. try {
  214. player.addEventListener('mouseleave', handle.leavePlayer, false);
  215. } catch (e) {
  216. mouse.leave = player.onmouseleave;
  217. player.onmouseleave = function() {
  218. handle.leavePlayer();
  219. player.onmouseleave = mouse.leave;
  220. };
  221. }
  222. if (!fullStatus) {
  223. document.addEventListener('scroll', handle.scrollFix, false);
  224. }
  225. controlBtn.style.display = 'block';
  226. controlBtn.style.visibility = 'visible';
  227. this.locate();
  228. },
  229. locate: function() {
  230. var playerRect = tool.getRect(player);
  231. if (playerRect.pageY < 20 || fullStatus) {
  232. if (fullStatus) {
  233. controlBtn.classList.remove('playerControlBtnCol');
  234. playerRect.screenY = playerRect.screenY + 50;
  235. playerRect.screenX = playerRect.screenX - 30;
  236. controlBtn.innerHTML = btnText.restore;
  237. } else {
  238. playerRect.screenY = playerRect.screenY + 20;
  239. if (Math.abs(tool.getClient().width - player.offsetWidth) < 21 && Math.abs(tool.getClient().height - player.offsetHeight) > 21) {
  240. playerRect.screenX = playerRect.screenX + 44;
  241. } else {
  242. playerRect.screenX = playerRect.screenX + 64;
  243. }
  244. controlBtn.classList.add('playerControlBtnCol');
  245. if (isIframe) {
  246. controlBtn.innerHTML = btnText.inner;
  247. } else {
  248. controlBtn.innerHTML = btnText.out;
  249. }
  250. }
  251. if (browser == 'firefox' && fullStatus) {
  252. controlBtn.style.opacity = '1';
  253. } else {
  254. controlBtn.style.opacity = '0.5';
  255. }
  256. } else {
  257. controlBtn.classList.remove('playerControlBtnCol');
  258. controlBtn.style.opacity = '0.5';
  259. controlBtn.innerHTML = btnText.out;
  260. }
  261. controlBtn.style.top = playerRect.screenY - 20 + 'px';
  262. controlBtn.style.left = playerRect.screenX - 64 + player.offsetWidth + 'px';
  263. }
  264. };
  265.  
  266. var handle = {
  267. getPlayer: function(e) {
  268. if (fullStatus) {
  269. return;
  270. }
  271. var target = e.target;
  272. if (html5Rules[document.location.hostname]) {
  273. var overlay = [],
  274. playerNum = [];
  275. var overlayRules = html5Rules[document.location.hostname];
  276. for (var i = 0; i < overlayRules.length; i++) {
  277. var rules = overlayRules[i].split('|');
  278. overlay[i] = document.querySelector(rules[0]);
  279. playerNum[i] = rules[1];
  280. }
  281. if (overlay.indexOf(target) != -1) {
  282. var html5Player = target;
  283. for (var i = 0; i < playerNum[overlay.indexOf(target)]; i++) {
  284. html5Player = html5Player.parentNode;
  285. }
  286. player = html5Player;
  287. setButton.init();
  288. return;
  289. }
  290. }
  291. switch (target.nodeName) {
  292. case 'IFRAME':
  293. if (!iframeRules.test(target.className) && !iframeRules.test(target.src) && !iframeRules.test(target.id) && !iframeRules.test(document.location.href) && iframeUrlRules.indexOf(document.location.hostname) == -1) {
  294. handle.leavePlayer();
  295. break;
  296. }
  297. case 'OBJECT':
  298. case 'EMBED':
  299. case 'VIDEO':
  300. if (target.offsetWidth > 99 && target.offsetHeight > 99) {
  301. player = target;
  302. setButton.init();
  303. }
  304. break;
  305. default:
  306. handle.leavePlayer();
  307. }
  308. },
  309. leavePlayer: function() {
  310. if (controlBtn.style.visibility == 'visible') {
  311. controlBtn.style.opacity = '';
  312. controlBtn.style.visibility = '';
  313. try {
  314. player.removeEventListener('mouseleave', handle.leavePlayer, false);
  315. } catch (e) {}
  316. document.removeEventListener('scroll', handle.scrollFix, false);
  317. }
  318. },
  319. scrollFix: function(e) {
  320. clearTimeout(backStyle.scrollFixTimer);
  321. backStyle.scrollFixTimer = setTimeout(function() {
  322. setButton.locate();
  323. }, 20);
  324. },
  325. hotKey: function(e) {
  326. //默认退出键为ESC。需要修改为其他快捷键的请搜索"keycode",修改为按键对应的数字。
  327. if (e.keyCode == 27) {
  328. maximize.playerControl();
  329. }
  330. },
  331. restoreButton: function() {
  332. if (isIframe) {
  333. return;
  334. }
  335. switch (browser) {
  336. case 'chrome':
  337. if (window.outerWidth < window.screen.width - 10) {
  338. setButton.show();
  339. }
  340. break;
  341. case 'firefox':
  342. if (window.innerWidth < window.screen.width - 10) {
  343. setButton.show();
  344. }
  345. break;
  346. }
  347. }
  348. };
  349.  
  350. var maximize = {
  351. playerControl: function() {
  352. if (!player) {
  353. return;
  354. }
  355. this.checkParent();
  356. if (!fullStatus) {
  357. this.fullWin();
  358. } else {
  359. this.smallWin();
  360. }
  361. },
  362. checkParent: function() {
  363. parentArray = [];
  364. var full = player;
  365. while (full = full.parentNode) {
  366. if (full.nodeName == 'BODY') {
  367. break;
  368. }
  369. if (full.getAttribute) {
  370. parentArray.push(full);
  371. }
  372. }
  373. },
  374. fullWin: function() {
  375. if (!fullStatus) {
  376. document.removeEventListener('mouseover', handle.getPlayer, false);
  377. if (isRbtn) {
  378. try {
  379. player.addEventListener('mouseover', handle.restoreButton, false);
  380. } catch (e) {
  381. mouse.over = player.onmouseover;
  382. player.onmouseover = handle.restoreButton;
  383. }
  384. }
  385. backStyle = {
  386. htmlId: document.body.parentNode.id,
  387. bodyId: document.body.id
  388. };
  389. if (document.location.hostname == 'www.youtube.com') {
  390. if (document.querySelector('ytd-watch.ytd-page-manager')){
  391. if (!document.querySelector('ytd-watch.ytd-page-manager').hasAttribute('theater-requested_')){
  392. document.querySelector('.ytp-size-button').click();
  393. backStyle.ytbStageChange = true;
  394. }
  395. }else if (!document.querySelector('.watch-stage-mode')) {
  396. document.querySelector('.ytp-size-button').click();
  397. backStyle.ytbStageChange = true;
  398. }
  399. }
  400. if (document.location.hostname == 'live.bilibili.com' && document.querySelector('.bilibili-live-player') && document.querySelector('.bilibili-live-player').getAttribute('data-player-state') != 'web-fullscreen') {
  401. unsafeWindow.$('.bilibili-live-player-video-danmaku').dblclick();
  402. backStyle.biliPlayerChange = true;
  403. }
  404. if (document.location.hostname == 'v.youku.com' && document.querySelector('.vpactionv5_iframe_wrap') && tool.getRect(player).pageY + player.offsetHeight - tool.getRect(document.querySelector('.vpactionv5_iframe_wrap')).pageY > 20) {
  405. player.style.cssText = 'height: calc(100vh + 50px) !important;';
  406. }
  407. if (document.location.hostname == 'www.tudou.com' && document.querySelector('.action_buttons.fix') && tool.getRect(player).pageY + player.offsetHeight - tool.getRect(document.querySelector('.action_buttons.fix')).pageY > 20) {
  408. player.style.cssText = 'height: calc(100vh + 55px) !important;';
  409. }
  410. leftBtn.style.display = 'block';
  411. rightBtn.style.display = 'block';
  412. controlBtn.style.display = '';
  413. this.addClass();
  414. }
  415. fullStatus = true;
  416. },
  417. addClass: function() {
  418. document.body.parentNode.id = 'htmlToothbrush';
  419. document.body.id = 'bodyToothbrush';
  420. for (var i = 0; i < parentArray.length; i++) {
  421. parentArray[i].classList.add('parentToothbrush');
  422. //父元素position:fixed会造成层级错乱
  423. if (getComputedStyle(parentArray[i]).position == 'fixed') {
  424. parentArray[i].classList.add('absoluteToothbrush');
  425. }
  426. }
  427. player.classList.add('playerToothbrush');
  428. if (player.nodeName == 'VIDEO') {
  429. backStyle.controls = player.controls;
  430. player.controls = true;
  431. }
  432. window.dispatchEvent(new Event('resize'));
  433. },
  434. smallWin: function() {
  435. if (isRbtn) {
  436. try {
  437. player.removeEventListener('mouseover', handle.restoreButton, false);
  438. } catch (e) {}
  439. if (mouse.over != 'listener') {
  440. player.onmouseover = mouse.over;
  441. }
  442. }
  443. document.body.parentNode.id = backStyle.htmlId;
  444. document.body.id = backStyle.bodyId;
  445. for (var i = 0; i < parentArray.length; i++) {
  446. parentArray[i].classList.remove('parentToothbrush');
  447. parentArray[i].classList.remove('absoluteToothbrush');
  448. }
  449. player.classList.remove('playerToothbrush');
  450. if (document.location.hostname == 'www.youtube.com' && backStyle.ytbStageChange) {
  451. document.querySelector('.ytp-size-button').click();
  452. }
  453. if (document.location.hostname == 'live.bilibili.com' && backStyle.biliPlayerChange) {
  454. unsafeWindow.$('.bilibili-live-player-video-danmaku').dblclick();
  455. }
  456. if (document.location.hostname == 'v.youku.com' || document.location.hostname == 'www.tudou.com') {
  457. player.style.cssText = '';
  458. }
  459. if (player.nodeName == 'VIDEO') {
  460. player.controls = backStyle.controls;
  461. }
  462. leftBtn.style.display = '';
  463. rightBtn.style.display = '';
  464. controlBtn.style.display = '';
  465. document.addEventListener('mouseover', handle.getPlayer, false);
  466. window.dispatchEvent(new Event('resize'));
  467. fullStatus = false;
  468. }
  469. };
  470.  
  471. var init = function() {
  472. controlBtn = createButton('playerControlBtn');
  473. leftBtn = createButton('leftFullStackButton');
  474. rightBtn = createButton('rightFullStackButton');
  475. if (getComputedStyle(controlBtn).position != 'fixed') {
  476. tool.addStyle([
  477. '#htmlToothbrush, #bodyToothbrush {overflow:hidden !important;zoom:100% !important}',
  478. '#htmlToothbrush #bodyToothbrush .parentToothbrush {overflow:visible !important;z-index:auto !important;transform:none !important;-webkit-transform-style:flat !important;transition:none !important;contain:none !important;}',
  479. '#htmlToothbrush #bodyToothbrush .absoluteToothbrush {position:absolute !important;}',
  480. '#htmlToothbrush #bodyToothbrush .playerToothbrush {position:fixed !important;top:0px !important;left:1px !important;width:calc(100vw - 2px) !important;height:100vh !important;max-width:none !important;max-height:none !important;min-width:0 !important;min-height:0 !important;margin:0 !important;padding:0 !important;z-index:2147483645 !important;border:none !important;background-color:#000 !important;transform:none !important;}',
  481. '#htmlToothbrush #bodyToothbrush .playerToothbrush video {object-fit:contain !important;}',
  482. '#playerControlBtn {visibility:hidden;opacity:0;display:none;transition: all 0.5s ease;cursor: pointer;font: 12px "微软雅黑";margin:0;width:64px;height:20px;line-height:20px;border:none;text-align: center;position: fixed;z-index:2147483646;background-color: #27A9D8;color: #FFF;} #playerControlBtn:hover {visibility:visible;opacity:1;background-color:#2774D8;}',
  483. '#playerControlBtn.playerControlBtnCol {width:20px;height:64px;line-height:16px;}',
  484. '#leftFullStackButton{display:none;position:fixed;width:1px;height:100vh;top:0;left:0;z-index:2147483646;background:#000;}',
  485. '#rightFullStackButton{display:none;position:fixed;width:1px;height:100vh;top:0;right:0;z-index:2147483646;background:#000;}'
  486. ].join('\n'));
  487. }
  488. };
  489.  
  490. init();
  491.  
  492. document.addEventListener('mouseover', handle.getPlayer, false);
  493. document.addEventListener('keydown', handle.hotKey, false);
  494.  
  495. })();

QingJ © 2025

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