Greasy Fork 支持简体中文。

ykh5p

改善优酷官方html5播放器播放体验

目前為 2017-06-24 提交的版本,檢視 最新版本

  1. 'use strict';
  2.  
  3. var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }();
  4.  
  5. var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
  6.  
  7. function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
  8.  
  9. // ==UserScript==
  10. // @name ykh5p
  11. // @namespace https://github.com/gooyie/ykh5p
  12. // @homepageURL https://github.com/gooyie/ykh5p
  13. // @supportURL https://github.com/gooyie/ykh5p/issues
  14. // @version 0.6.3
  15. // @description 改善优酷官方html5播放器播放体验
  16. // @author gooyie
  17. // @license MIT License
  18. //
  19. // @include *://v.youku.com/*
  20. // @grant GM_info
  21. // @grant GM_addStyle
  22. // @grant unsafeWindow
  23. // @run-at document-start
  24. // ==/UserScript==
  25.  
  26. (function () {
  27. 'use strict';
  28.  
  29. /* eslint-disable no-console */
  30.  
  31. var Logger = function () {
  32. function Logger() {
  33. _classCallCheck(this, Logger);
  34. }
  35.  
  36. _createClass(Logger, null, [{
  37. key: 'log',
  38. value: function log() {
  39. var _console;
  40.  
  41. for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
  42. args[_key] = arguments[_key];
  43. }
  44.  
  45. (_console = console).log.apply(_console, ['%c' + this.tag + '%c' + args.shift(), 'color: #fff; background: #2FB3FF', ''].concat(args));
  46. }
  47. }, {
  48. key: 'info',
  49. value: function info() {
  50. var _console2;
  51.  
  52. for (var _len2 = arguments.length, args = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
  53. args[_key2] = arguments[_key2];
  54. }
  55.  
  56. (_console2 = console).info.apply(_console2, [this.tag + args.shift()].concat(args));
  57. }
  58. }, {
  59. key: 'debug',
  60. value: function debug() {
  61. var _console3;
  62.  
  63. for (var _len3 = arguments.length, args = Array(_len3), _key3 = 0; _key3 < _len3; _key3++) {
  64. args[_key3] = arguments[_key3];
  65. }
  66.  
  67. (_console3 = console).debug.apply(_console3, [this.tag + args.shift()].concat(args));
  68. }
  69. }, {
  70. key: 'warn',
  71. value: function warn() {
  72. var _console4;
  73.  
  74. for (var _len4 = arguments.length, args = Array(_len4), _key4 = 0; _key4 < _len4; _key4++) {
  75. args[_key4] = arguments[_key4];
  76. }
  77.  
  78. (_console4 = console).warn.apply(_console4, [this.tag + args.shift()].concat(args));
  79. }
  80. }, {
  81. key: 'error',
  82. value: function error() {
  83. var _console5;
  84.  
  85. for (var _len5 = arguments.length, args = Array(_len5), _key5 = 0; _key5 < _len5; _key5++) {
  86. args[_key5] = arguments[_key5];
  87. }
  88.  
  89. (_console5 = console).error.apply(_console5, [this.tag + args.shift()].concat(args));
  90. }
  91. }, {
  92. key: 'tag',
  93. get: function get() {
  94. return '[' + GM_info.script.name + ']';
  95. }
  96. }]);
  97.  
  98. return Logger;
  99. }();
  100. /* eslint-enable no-console */
  101.  
  102. var Hooker = function () {
  103. function Hooker() {
  104. _classCallCheck(this, Hooker);
  105. }
  106.  
  107. _createClass(Hooker, null, [{
  108. key: 'hookCall',
  109. value: function hookCall() {
  110. var after = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : function () {};
  111. var before = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : function () {};
  112.  
  113. var call = Function.prototype.call;
  114. Function.prototype.call = function () {
  115. for (var _len6 = arguments.length, args = Array(_len6), _key6 = 0; _key6 < _len6; _key6++) {
  116. args[_key6] = arguments[_key6];
  117. }
  118.  
  119. try {
  120. if (args) before.apply(undefined, args);
  121. } catch (err) {
  122. Logger.error(err.stack);
  123. }
  124.  
  125. var ret = call.apply(this, args);
  126.  
  127. try {
  128. if (args) after.apply(undefined, args);
  129. } catch (err) {
  130. Logger.error(err.stack);
  131. }
  132.  
  133. return ret;
  134. };
  135.  
  136. Function.prototype.call.toString = Function.prototype.call.toLocaleString = function () {
  137. return 'function call() { [native code] }';
  138. };
  139. }
  140. }, {
  141. key: '_isFactoryCall',
  142. value: function _isFactoryCall(args) {
  143. // m.exports, _dereq_, m, m.exports, outer, modules, cache, entry
  144. return args.length === 8 && args[2] instanceof Object && args[2].hasOwnProperty('exports');
  145. }
  146. }, {
  147. key: 'hookFactoryCall',
  148. value: function hookFactoryCall() {
  149. var _this = this;
  150.  
  151. var cb = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : function () {};
  152.  
  153. this.hookCall(function () {
  154. for (var _len7 = arguments.length, args = Array(_len7), _key7 = 0; _key7 < _len7; _key7++) {
  155. args[_key7] = arguments[_key7];
  156. }
  157.  
  158. if (_this._isFactoryCall(args)) cb.apply(undefined, args);
  159. });
  160. }
  161. }, {
  162. key: '_isManagerFactoryCall',
  163. value: function _isManagerFactoryCall() {
  164. var exports = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
  165.  
  166. return 'function' === typeof exports && exports.prototype.hasOwnProperty('upsDataSuccess');
  167. }
  168. }, {
  169. key: 'hookManager',
  170. value: function hookManager() {
  171. var _this2 = this;
  172.  
  173. var cb = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : function () {};
  174.  
  175. this.hookFactoryCall(function () {
  176. for (var _len8 = arguments.length, args = Array(_len8), _key8 = 0; _key8 < _len8; _key8++) {
  177. args[_key8] = arguments[_key8];
  178. }
  179.  
  180. if (_this2._isManagerFactoryCall(args[2].exports)) cb(args[2].exports);
  181. });
  182. }
  183. }, {
  184. key: 'hookUpsDataSuccess',
  185. value: function hookUpsDataSuccess() {
  186. var cb = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : function () {};
  187.  
  188. this.hookManager(function (exports) {
  189. var upsDataSuccess = exports.prototype.upsDataSuccess;
  190. exports.prototype.upsDataSuccess = function (data) {
  191. cb(data);
  192. upsDataSuccess.apply(this, [data]);
  193. };
  194. });
  195. }
  196. }, {
  197. key: 'hookWatcher',
  198. value: function hookWatcher() {
  199. var cb = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : function () {};
  200.  
  201. this.hookManager(function (exports) {
  202. var watcher = exports.prototype.watcher;
  203. exports.prototype.watcher = function () {
  204. watcher.apply(this);
  205. cb(this);
  206. };
  207. });
  208. }
  209. }, {
  210. key: '_isSkinsViewRenderCall',
  211. value: function _isSkinsViewRenderCall(args) {
  212. return args.length === 3 && args[1] === 'spvdiv' && args[2].className === 'spv_player';
  213. }
  214. }, {
  215. key: 'hookSkinsViewRender',
  216. value: function hookSkinsViewRender() {
  217. var _this3 = this;
  218.  
  219. var cb = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : function () {};
  220.  
  221. this.hookCall(undefined, function () {
  222. for (var _len9 = arguments.length, args = Array(_len9), _key9 = 0; _key9 < _len9; _key9++) {
  223. args[_key9] = arguments[_key9];
  224. }
  225.  
  226. if (_this3._isSkinsViewRenderCall(args)) cb(args[2]);
  227. });
  228. }
  229. }, {
  230. key: '_isUtilFactoryCall',
  231. value: function _isUtilFactoryCall() {
  232. var exports = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
  233.  
  234. return exports.hasOwnProperty('getJsonp') && exports.TAG === 'util';
  235. }
  236. }, {
  237. key: 'hookUtil',
  238. value: function hookUtil() {
  239. var _this4 = this;
  240.  
  241. var cb = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : function () {};
  242.  
  243. this.hookFactoryCall(function () {
  244. for (var _len10 = arguments.length, args = Array(_len10), _key10 = 0; _key10 < _len10; _key10++) {
  245. args[_key10] = arguments[_key10];
  246. }
  247.  
  248. if (_this4._isUtilFactoryCall(args[2].exports)) cb(args[2].exports);
  249. });
  250. }
  251. }, {
  252. key: 'hookGetJsonp',
  253. value: function hookGetJsonp() {
  254. var cb = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : function () {};
  255.  
  256. this.hookUtil(function (exports) {
  257. var getJsonp = exports.getJsonp.bind(exports);
  258. exports.getJsonp = function () {
  259. for (var _len11 = arguments.length, args = Array(_len11), _key11 = 0; _key11 < _len11; _key11++) {
  260. args[_key11] = arguments[_key11];
  261. }
  262.  
  263. // url, onload, onerror, ontimeout, timeout
  264. if (cb(args)) return; // hijack
  265. getJsonp.apply(undefined, args);
  266. };
  267. });
  268. }
  269. }, {
  270. key: '_isH5PlayerCoreFactoryCall',
  271. value: function _isH5PlayerCoreFactoryCall() {
  272. var exports = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
  273.  
  274. return exports instanceof Object && exports.hasOwnProperty('YoukuH5PlayerCore');
  275. }
  276. }, {
  277. key: 'hookH5PlayerCore',
  278. value: function hookH5PlayerCore() {
  279. var _this5 = this;
  280.  
  281. var cb = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : function () {};
  282.  
  283. this.hookFactoryCall(function () {
  284. for (var _len12 = arguments.length, args = Array(_len12), _key12 = 0; _key12 < _len12; _key12++) {
  285. args[_key12] = arguments[_key12];
  286. }
  287.  
  288. if (_this5._isH5PlayerCoreFactoryCall(args[2].exports)) cb(args[2].exports);
  289. });
  290. }
  291. }, {
  292. key: 'hookRealStartPlay',
  293. value: function hookRealStartPlay() {
  294. var cb = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : function () {};
  295.  
  296. this.hookH5PlayerCore(function (exports) {
  297. var _realStartPlay = exports.YoukuH5PlayerCore.prototype._realStartPlay;
  298. exports.YoukuH5PlayerCore.prototype._realStartPlay = function () {
  299. for (var _len13 = arguments.length, args = Array(_len13), _key13 = 0; _key13 < _len13; _key13++) {
  300. args[_key13] = arguments[_key13];
  301. }
  302.  
  303. cb(this, args);
  304. _realStartPlay.apply(this, args);
  305. };
  306. });
  307. }
  308. }, {
  309. key: 'hookOnAdEnd',
  310. value: function hookOnAdEnd() {
  311. var cb = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : function () {};
  312.  
  313. this.hookH5PlayerCore(function (exports) {
  314. var _onAdEnd = exports.YoukuH5PlayerCore.prototype._onAdEnd;
  315. exports.YoukuH5PlayerCore.prototype._onAdEnd = function () {
  316. for (var _len14 = arguments.length, args = Array(_len14), _key14 = 0; _key14 < _len14; _key14++) {
  317. args[_key14] = arguments[_key14];
  318. }
  319.  
  320. if (cb(this, args)) return;
  321. _onAdEnd.apply(this, args);
  322. };
  323. });
  324. }
  325. }, {
  326. key: '_isSkinsControlFactoryCall',
  327. value: function _isSkinsControlFactoryCall() {
  328. var exports = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
  329.  
  330. return 'function' === typeof exports && exports.prototype.hasOwnProperty('shadowClick');
  331. }
  332. }, {
  333. key: 'hookSkinsControl',
  334. value: function hookSkinsControl() {
  335. var _this6 = this;
  336.  
  337. var cb = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : function () {};
  338.  
  339. this.hookFactoryCall(function () {
  340. for (var _len15 = arguments.length, args = Array(_len15), _key15 = 0; _key15 < _len15; _key15++) {
  341. args[_key15] = arguments[_key15];
  342. }
  343.  
  344. if (_this6._isSkinsControlFactoryCall(args[2].exports)) cb(args[2].exports);
  345. });
  346. }
  347. }, {
  348. key: 'hookSkinsControlDomEvent',
  349. value: function hookSkinsControlDomEvent() {
  350. var cb = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : function () {};
  351.  
  352. this.hookSkinsControl(function (exports) {
  353. var domEvent = exports.prototype.domEvent;
  354. exports.prototype.domEvent = function () {
  355. cb(this);
  356. domEvent.apply(this);
  357. };
  358. });
  359. }
  360. }, {
  361. key: 'hookWindowAddEventListener',
  362. value: function hookWindowAddEventListener() {
  363. var cb = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : function () {};
  364.  
  365. var window = unsafeWindow;
  366. var addEventListener = window.addEventListener.bind(window);
  367. window.addEventListener = function () {
  368. for (var _len16 = arguments.length, args = Array(_len16), _key16 = 0; _key16 < _len16; _key16++) {
  369. args[_key16] = arguments[_key16];
  370. }
  371.  
  372. if (cb(args)) return; // rejection
  373. addEventListener.apply(undefined, args);
  374. };
  375. }
  376. }]);
  377.  
  378. return Hooker;
  379. }();
  380.  
  381. var Mocker = function () {
  382. function Mocker() {
  383. _classCallCheck(this, Mocker);
  384. }
  385.  
  386. _createClass(Mocker, null, [{
  387. key: 'mockVip',
  388. value: function mockVip() {
  389. Hooker.hookUpsDataSuccess(function (data) {
  390. if (data.user) {
  391. data.user.vip = true;
  392. } else {
  393. data.user = { vip: true };
  394. }
  395. Logger.log('解除会员画质限制');
  396. });
  397. }
  398. }, {
  399. key: 'mockExclusiveShow',
  400. value: function mockExclusiveShow() {
  401. Hooker.hookSkinsControl(function (exports) {
  402. exports.prototype.exclusiveShow = function () {};
  403. Logger.log('和谐独播水印');
  404. });
  405. }
  406. }, {
  407. key: 'mockLogoShow',
  408. value: function mockLogoShow() {
  409. Hooker.hookSkinsControl(function (exports) {
  410. exports.prototype.logoShow = function () {};
  411. Logger.log('和谐logo水印');
  412. });
  413. }
  414. }]);
  415.  
  416. return Mocker;
  417. }();
  418.  
  419. var Blocker = function () {
  420. function Blocker() {
  421. _classCallCheck(this, Blocker);
  422. }
  423.  
  424. _createClass(Blocker, null, [{
  425. key: '_isAdReq',
  426. value: function _isAdReq(url) {
  427. return (/atm\.youku\.com/.test(url)
  428. );
  429. }
  430. }, {
  431. key: 'blockAd',
  432. value: function blockAd() {
  433. var _this7 = this;
  434.  
  435. Hooker.hookGetJsonp(function (args) {
  436. var _args = _slicedToArray(args, 3),
  437. url = _args[0],
  438. /* onload */onerror = _args[2];
  439.  
  440. if (_this7._isAdReq(url)) {
  441. setTimeout(onerror, 0); // async invoke
  442. Logger.log('blocked ad request', url);
  443. return true;
  444. }
  445. });
  446. }
  447. }]);
  448.  
  449. return Blocker;
  450. }();
  451.  
  452. var Patcher = function () {
  453. function Patcher() {
  454. _classCallCheck(this, Patcher);
  455. }
  456.  
  457. _createClass(Patcher, null, [{
  458. key: 'patchQualitySetting',
  459. value: function patchQualitySetting() {
  460. Hooker.hookSkinsViewRender(function (elem) {
  461. var autoRe = /<spvdiv\s+customer="auto"[^<>]*>自动<\/spvdiv>/;
  462. var mp4Re = /<spvdiv\s+customer="mp4"[^<>]*>标清<\/spvdiv>/;
  463. var autoDiv = autoRe.exec(elem.innerHTML)[0];
  464. var hd3Div = autoDiv.replace('auto', 'mp4hd3').replace('自动', '1080P');
  465. elem.innerHTML = elem.innerHTML.replace(autoRe, hd3Div).replace(mp4Re, '$&' + autoDiv);
  466. Logger.log('设置里优先画质增加1080P选项并对齐到当前画质');
  467. });
  468.  
  469. GM_addStyle('\n spvdiv.spv_setting_1080, spvdiv.spv_setting_panel {\n width: 300px !important;\n }\n ');
  470. }
  471. }, {
  472. key: 'patchQualityFallback',
  473. value: function patchQualityFallback() {
  474. Hooker.hookH5PlayerCore(function (exports) {
  475. var SHOWHD = new Map([['flvhd', '标清'], ['3gphd', '标清'], ['mp4hd', '高清'], ['mp4hd2', '超清'], ['mp4hd3', '1080p']]);
  476.  
  477. exports.YoukuH5PlayerCore.prototype._initControlInfo = function () {
  478. if (!this._videoInfo.langcodes) return;
  479.  
  480. var control = this.control;
  481. if (!control.lang || !this._videoInfo.langcodes.includes(control.lang)) {
  482. control.lang = this._videoInfo.langcodes[0];
  483. }
  484.  
  485. var hdcodes = this._videoInfo.hdList[control.lang].hdcodes;
  486. if (!hdcodes.includes(control.hd)) {
  487. // 如果设置的优先画质在当前播放的视频里没有
  488. var hd = control.hd;
  489. control.hd = hdcodes[hdcodes.length - 1]; // 向下选择最高画质(原逻辑是给最渣画质!)
  490. Logger.log('\u4F18\u5148\u753B\u8D28\uFF08' + SHOWHD.get(hd) + '\uFF09\u5728\u5F53\u524D\u64AD\u653E\u7684\u89C6\u9891\u91CC\u6CA1\u6709\uFF0C\u5411\u4E0B\u9009\u62E9\u6700\u9AD8\u753B\u8D28\uFF08' + SHOWHD.get(control.hd) + '\uFF09\u3002');
  491. }
  492.  
  493. control.autoplay = control.autoplay || false;
  494. control.fullscreen = control.fullscreen || false;
  495. };
  496. });
  497. }
  498. }, {
  499. key: 'patchVolumeMemory',
  500. value: function patchVolumeMemory() {
  501. Hooker.hookRealStartPlay(function (that) {
  502. if (0 === parseFloat(localStorage.getItem('spv_volume'))) {
  503. that.UIControl.__proto__.mute.apply(that.UIControl);
  504. } else {
  505. that.UIControl.__proto__.nomute.apply(that.UIControl);
  506. }
  507.  
  508. that.EventManager.on('VolumeChange', function (data) {
  509. localStorage.setItem('spv_volume', data.value);
  510. });
  511.  
  512. Logger.log('开启音量记忆');
  513. });
  514. }
  515. }, {
  516. key: '_isFullScreen',
  517. value: function _isFullScreen() {
  518. return !!(document.fullscreen || document.webkitIsFullScreen || document.mozFullScreen || document.fullscreenElement || document.webkitFullscreenElement || document.mozFullScreenElement);
  519. }
  520. }, {
  521. key: 'patchFullScreen',
  522. value: function patchFullScreen() {
  523. var self = this;
  524. Hooker.hookManager(function (exports) {
  525. exports.prototype.toggleFull = function (arg) {
  526. this.method = arg.method || 'c';
  527. if (self._isFullScreen()) {
  528. this.containerExitScreen();
  529. Logger.log('退出全屏');
  530. } else {
  531. this.containerFullScreen();
  532. Logger.log('进入全屏');
  533. }
  534. };
  535. });
  536. }
  537. }, {
  538. key: '_patchManager',
  539. value: function _patchManager() {
  540. Hooker.hookManager(function (exports) {
  541. exports.prototype.getPreviousVid = function () {
  542. if (this.data.videos && this.data.videos.list) {
  543. var list = this.data.videos.list;
  544. var currVid = this.data.video.id;
  545. var prevSeq = list.find(function (item) {
  546. return parseInt(item.vid) === currVid;
  547. }).seq - 1;
  548. if (prevSeq > 0) {
  549. var previous = list.find(function (item) {
  550. return parseInt(item.seq) === prevSeq;
  551. });
  552. return previous.encodevid;
  553. }
  554. }
  555. };
  556.  
  557. exports.prototype.getVideoFPS = function () {
  558. return 25; // 优酷m3u8为动态帧率,flv标清fps为15,标清以上fps为25。
  559. };
  560. });
  561. }
  562. }, {
  563. key: '_patchWatcher',
  564. value: function _patchWatcher() {
  565. var _this8 = this;
  566.  
  567. this._patchManager();
  568.  
  569. Hooker.hookWatcher(function (that) {
  570. that.EventManager.on('_Seek', function (seekTime) {
  571. var videoCurrentInfo = {
  572. currentTime: seekTime,
  573. buffered: that.bufferedEnd()
  574. };
  575.  
  576. that.UIControl.setProgress(videoCurrentInfo, that.duration);
  577. that.UIControl.setTime(seekTime, that);
  578.  
  579. that.seek(seekTime);
  580. // if (that.myVideo.paused) that.play(); // seek后自动播放
  581. });
  582.  
  583. that.EventManager.on('_StepSeek', function (stepTime) {
  584. var seekTime = Math.max(0, Math.min(that.duration, that.mediaElement.currentTime + stepTime));
  585. var msg = void 0;
  586.  
  587. if (Math.abs(stepTime) < 60) {
  588. msg = stepTime > 0 ? '\u6B65\u8FDB\uFF1A' + stepTime + '\u79D2' : '\u6B65\u9000\uFF1A' + Math.abs(stepTime) + '\u79D2';
  589. } else {
  590. msg = stepTime > 0 ? '\u6B65\u8FDB\uFF1A' + stepTime / 60 + '\u5206\u949F' : '\u6B65\u9000\uFF1A' + Math.abs(stepTime) / 60 + '\u5206\u949F';
  591. }
  592. that.UIControl.tipShow(msg);
  593.  
  594. that.EventManager.fire('_Seek', seekTime);
  595. });
  596.  
  597. that.EventManager.on('_RangeSeek', function (range) {
  598. that.UIControl.tipShow('定位:' + (range * 100).toFixed(0) + '%');
  599. var seekTime = Math.max(0, Math.min(that.duration, that.duration * range));
  600. that.EventManager.fire('_Seek', seekTime);
  601. });
  602.  
  603. that.EventManager.on('_PreviousFrame', function () {
  604. that.UIControl.tipShow('定位:上一帧');
  605. var seekTime = Math.max(0, Math.min(that.duration, that.mediaElement.currentTime - 1 / that.getVideoFPS()));
  606. that.seek(seekTime);
  607. });
  608.  
  609. that.EventManager.on('_NextFrame', function () {
  610. that.UIControl.tipShow('定位:下一帧');
  611. var seekTime = Math.max(0, Math.min(that.duration, that.mediaElement.currentTime + 1 / that.getVideoFPS()));
  612. that.seek(seekTime);
  613. });
  614.  
  615. that.EventManager.off('VolumeChange');
  616. that.EventManager.on('VolumeChange', function (param) {
  617. if (0 === parseFloat(param.value)) {
  618. that.UIControl.tipShow('静音');
  619. } else {
  620. that.UIControl.tipShow('\u97F3\u91CF\uFF1A' + (100 * param.value).toFixed(0) + '%');
  621. }
  622. that.changeMuted(param.value);
  623. });
  624.  
  625. that.EventManager.on('_AdjustVolume', function (value) {
  626. var volume = that.mediaElement.volume + value;
  627. volume = Math.max(0, Math.min(1, volume.toFixed(2)));
  628. that.mediaElement.volume = volume;
  629.  
  630. that.UIControl.volumeProgress(volume);
  631. that.UIControl.volumeChange();
  632. });
  633.  
  634. that.EventManager.on('_ToggleMute', function () {
  635. if (that.mediaElement.muted) {
  636. that.UIControl.nomute();
  637. that.UIControl.tipShow('取消静音');
  638. } else {
  639. that.UIControl.mute();
  640. that.UIControl.tipShow('静音');
  641. }
  642. });
  643.  
  644. that.EventManager.on('_AdjustPlaybackRate', function (value) {
  645. var playbackRate = Math.max(0.2, Math.min(5, that.mediaElement.playbackRate + value));
  646. that.mediaElement.playbackRate = playbackRate;
  647. that.UIControl.tipShow('\u64AD\u653E\u901F\u7387\uFF1A' + playbackRate.toFixed(1).replace(/\.0+$/, ''));
  648. });
  649.  
  650. that.EventManager.on('_ResetPlaybackRate', function () {
  651. that.UIControl.tipShow('恢复播放速率');
  652. that.mediaElement.playbackRate = 1;
  653. });
  654.  
  655. that.EventManager.on('_PlayPrevious', function () {
  656. var vid = that.getPreviousVid();
  657. if (vid) {
  658. that.EventManager.fire('ChangeVid', { vid: vid });
  659. that.UIControl.tipShow('播放上一集');
  660. } else {
  661. that.UIControl.tipShow('没有上一集哦');
  662. }
  663. });
  664.  
  665. that.EventManager.on('_PlayNext', function () {
  666. var vid = that.getNextVid();
  667. if (vid) {
  668. that.EventManager.fire('ChangeVid', { vid: vid });
  669. that.UIControl.tipShow('播放下一集');
  670. } else {
  671. that.UIControl.tipShow('没有下一集哦');
  672. }
  673. });
  674.  
  675. that.EventManager.on('control:show', function () {
  676. that.selector.style.cursor = '';
  677. });
  678.  
  679. that.EventManager.on('control:hide', function () {
  680. if (_this8._isFullScreen()) {
  681. that.selector.style.cursor = 'none';
  682. }
  683. });
  684. });
  685. }
  686. // 让之后的tip覆盖之前的,不然之前的未消失会使之后的被忽略。
  687.  
  688. }, {
  689. key: '_patchTipShow',
  690. value: function _patchTipShow() {
  691. Hooker.hookSkinsControl(function (exports) {
  692. exports.prototype.tipShow = function (msg) {
  693. if (this.timerTip) {
  694. clearTimeout(this.timerTip);
  695. this.timerTip = null;
  696. }
  697.  
  698. this.tip.innerHTML = msg;
  699. if (!this.tipStatus()) this.tipBox.style.display = 'block';
  700. this.tipHide();
  701. };
  702. });
  703. }
  704. // 原控件持续显示时间为5秒,有点长,改成3秒吧。
  705.  
  706. }, {
  707. key: '_patchControlHide',
  708. value: function _patchControlHide() {
  709. Hooker.hookSkinsControl(function (exports) {
  710. exports.prototype.controlHide = function (isAd) {
  711. var _this9 = this;
  712.  
  713. if (isAd) {
  714. this.setCtrlDom(false);
  715. return;
  716. }
  717. if (this.pause || this.timer) return;
  718.  
  719. this.timer = setTimeout(function () {
  720. return _this9.setCtrlDom(false);
  721. }, 3e3);
  722. };
  723. });
  724. }
  725. }, {
  726. key: '_patchVolumeRange',
  727. value: function _patchVolumeRange() {
  728. Hooker.hookSkinsControlDomEvent(function (that) {
  729. return that.volumeRange.step = 0.01;
  730. });
  731. }
  732. }, {
  733. key: '_patchKeyShortcuts',
  734. value: function _patchKeyShortcuts() {
  735. // 原键盘快捷键在搜索框等仍有效,废了它。
  736. Hooker.hookWindowAddEventListener(function (_ref) {
  737. var _ref2 = _slicedToArray(_ref, 1),
  738. type = _ref2[0];
  739.  
  740. if (type !== 'keydown') return;
  741.  
  742. var stack = new Error().stack;
  743. if (stack.includes('domEvent')) {
  744. Logger.log('废除原键盘快捷键');
  745. return true;
  746. }
  747. });
  748.  
  749. Hooker.hookSkinsControlDomEvent(function (that) {
  750. document.addEventListener('keydown', function (event) {
  751. if (event.target.nodeName !== 'BODY') return;
  752.  
  753. switch (event.keyCode) {
  754. case 32:
  755. // Spacebar
  756. if (!event.ctrlKey && !event.shiftKey && !event.altKey) {
  757. if (that.pause) {
  758. that.EventManager.fire('VideoPlay');
  759. } else {
  760. that.EventManager.fire('VideoPause');
  761. }
  762. } else {
  763. return;
  764. }
  765. break;
  766. case 39: // → Arrow Right
  767. case 37:
  768. {
  769. // ← Arrow Left
  770. var stepTime = void 0;
  771. if (!event.ctrlKey && !event.shiftKey && !event.altKey) {
  772. stepTime = 39 === event.keyCode ? 5 : -5;
  773. } else if (event.ctrlKey && !event.shiftKey && !event.altKey) {
  774. stepTime = 39 === event.keyCode ? 30 : -30;
  775. } else if (!event.ctrlKey && event.shiftKey && !event.altKey) {
  776. stepTime = 39 === event.keyCode ? 60 : -60;
  777. } else if (event.ctrlKey && !event.shiftKey && event.altKey) {
  778. stepTime = 39 === event.keyCode ? 3e2 : -3e2; // 5分钟
  779. } else {
  780. return;
  781. }
  782.  
  783. that.EventManager.fire('_StepSeek', stepTime);
  784. break;
  785. }
  786. case 38: // ↑ Arrow Up
  787. case 40:
  788. // ↓ Arrow Down
  789. if (!event.ctrlKey && !event.shiftKey && !event.altKey) {
  790. that.EventManager.fire('_AdjustVolume', 38 === event.keyCode ? 0.05 : -0.05);
  791. } else {
  792. return;
  793. }
  794. break;
  795. case 77:
  796. // M
  797. if (!event.ctrlKey && !event.shiftKey && !event.altKey) {
  798. that.EventManager.fire('_ToggleMute');
  799. } else {
  800. return;
  801. }
  802. break;
  803. case 13:
  804. // Enter
  805. if (!event.ctrlKey && !event.shiftKey && !event.altKey) {
  806. that.EventManager.fire('SwitchFullScreen');
  807. } else {
  808. return;
  809. }
  810. break;
  811. case 67: // C
  812. case 88:
  813. // X
  814. if (!event.ctrlKey && !event.shiftKey && !event.altKey) {
  815. that.EventManager.fire('_AdjustPlaybackRate', 67 === event.keyCode ? 0.1 : -0.1);
  816. } else {
  817. return;
  818. }
  819. break;
  820. case 90:
  821. // Z
  822. if (!event.ctrlKey && !event.shiftKey && !event.altKey) {
  823. that.EventManager.fire('_ResetPlaybackRate');
  824. } else {
  825. return;
  826. }
  827. break;
  828. case 68: // D
  829. case 70:
  830. // F
  831. if (!event.ctrlKey && !event.shiftKey && !event.altKey) {
  832. if (!that.pause) that.EventManager.fire('VideoPause');
  833. if (event.keyCode === 68) {
  834. that.EventManager.fire('_PreviousFrame');
  835. } else {
  836. that.EventManager.fire('_NextFrame');
  837. }
  838. } else {
  839. return;
  840. }
  841. break;
  842. case 80: // P
  843. case 78:
  844. // N
  845. if (!event.ctrlKey && event.shiftKey && !event.altKey) {
  846. if (event.keyCode === 78) {
  847. that.EventManager.fire('_PlayNext');
  848. } else {
  849. that.EventManager.fire('_PlayPrevious');
  850. }
  851. } else {
  852. return;
  853. }
  854. break;
  855. default:
  856. if (event.keyCode >= 48 && event.keyCode <= 57) {
  857. // 0 ~ 9
  858. if (!event.ctrlKey && !event.shiftKey && !event.altKey) {
  859. that.EventManager.fire('_RangeSeek', (event.keyCode - 48) * 0.1);
  860. } else {
  861. return;
  862. }
  863. } else {
  864. return;
  865. }
  866. }
  867.  
  868. event.preventDefault();
  869. event.stopPropagation();
  870. });
  871.  
  872. Logger.log('添加键盘快捷键');
  873. });
  874. }
  875. }, {
  876. key: '_patchShadowClick',
  877. value: function _patchShadowClick() {
  878. Hooker.hookSkinsControl(function (exports) {
  879. exports.prototype.shadowClick = function () {
  880. var _this10 = this;
  881.  
  882. if (this.shadowTimer) {
  883. // 短时间内连续单击
  884. clearTimeout(this.shadowTimer);
  885. this.shadowTimer = null;
  886. return;
  887. }
  888.  
  889. this.shadowTimer = setTimeout(function () {
  890. if (!_this10.pause) {
  891. _this10.pauseState();
  892. _this10.EventManager.fire('VideoPause');
  893. _this10.controlShow();
  894. } else {
  895. _this10.playingState();
  896. _this10.EventManager.fire('VideoPlay');
  897. _this10.controlHide();
  898. }
  899.  
  900. _this10.shadowTimer = null;
  901. }, 200);
  902. };
  903. });
  904. }
  905. }, {
  906. key: '_patchMouseShortcuts',
  907. value: function _patchMouseShortcuts() {
  908. var _this11 = this;
  909.  
  910. this._patchShadowClick();
  911.  
  912. Hooker.hookSkinsControlDomEvent(function (that) {
  913. that.shadow.addEventListener('dblclick', function () {
  914. that.EventManager.fire('SwitchFullScreen');
  915. });
  916.  
  917. document.addEventListener('wheel', function (event) {
  918. if (!_this11._isFullScreen()) return;
  919.  
  920. var delta = event.wheelDelta || event.detail || event.deltaY && -event.deltaY;
  921. that.EventManager.fire('_AdjustVolume', delta > 0 ? 0.05 : -0.05);
  922. });
  923.  
  924. Logger.log('添加鼠标快捷键');
  925. });
  926. }
  927. }, {
  928. key: 'patchShortcuts',
  929. value: function patchShortcuts() {
  930. this._patchWatcher();
  931. this._patchTipShow();
  932. this._patchVolumeRange();
  933. this._patchControlHide();
  934.  
  935. this._patchKeyShortcuts();
  936. this._patchMouseShortcuts();
  937. }
  938. }, {
  939. key: 'patchOnAdEnd',
  940. value: function patchOnAdEnd() {
  941. Hooker.hookOnAdEnd(function (that) {
  942. return that.hadEnd;
  943. });
  944. }
  945. }]);
  946.  
  947. return Patcher;
  948. }();
  949.  
  950. function enableH5Player() {
  951. sessionStorage.setItem('P_l_h5', 1);
  952. Logger.log('启用html5播放器');
  953. }
  954.  
  955. function recoverPlayer() {
  956. sessionStorage.removeItem('P_l_h5');
  957. Logger.log('恢复原播放器');
  958. }
  959.  
  960. //=============================================================================
  961.  
  962. enableH5Player();
  963. window.addEventListener('unload', function () {
  964. return recoverPlayer();
  965. }); // 禁用脚本刷新页面可恢复播放器
  966.  
  967. Blocker.blockAd();
  968. Mocker.mockVip();
  969. Mocker.mockExclusiveShow();
  970. Mocker.mockLogoShow();
  971. Patcher.patchQualitySetting();
  972. Patcher.patchQualityFallback();
  973. Patcher.patchVolumeMemory();
  974. Patcher.patchFullScreen();
  975. Patcher.patchShortcuts();
  976. Patcher.patchOnAdEnd();
  977. })();