ykh5p

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

当前为 2017-06-21 提交的版本,查看 最新版本

  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.1
  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: '_isSkinsControlFactoryCall',
  310. value: function _isSkinsControlFactoryCall() {
  311. var exports = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
  312.  
  313. return 'function' === typeof exports && exports.prototype.hasOwnProperty('shadowClick');
  314. }
  315. }, {
  316. key: 'hookSkinsControl',
  317. value: function hookSkinsControl() {
  318. var _this6 = this;
  319.  
  320. var cb = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : function () {};
  321.  
  322. this.hookFactoryCall(function () {
  323. for (var _len14 = arguments.length, args = Array(_len14), _key14 = 0; _key14 < _len14; _key14++) {
  324. args[_key14] = arguments[_key14];
  325. }
  326.  
  327. if (_this6._isSkinsControlFactoryCall(args[2].exports)) cb(args[2].exports);
  328. });
  329. }
  330. }, {
  331. key: 'hookSkinsControlDomEvent',
  332. value: function hookSkinsControlDomEvent() {
  333. var cb = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : function () {};
  334.  
  335. this.hookSkinsControl(function (exports) {
  336. var domEvent = exports.prototype.domEvent;
  337. exports.prototype.domEvent = function () {
  338. cb(this);
  339. domEvent.apply(this);
  340. };
  341. });
  342. }
  343. }, {
  344. key: 'hookWindowAddEventListener',
  345. value: function hookWindowAddEventListener() {
  346. var cb = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : function () {};
  347.  
  348. var window = unsafeWindow;
  349. var addEventListener = window.addEventListener.bind(window);
  350. window.addEventListener = function () {
  351. for (var _len15 = arguments.length, args = Array(_len15), _key15 = 0; _key15 < _len15; _key15++) {
  352. args[_key15] = arguments[_key15];
  353. }
  354.  
  355. if (cb(args)) return; // rejection
  356. addEventListener.apply(undefined, args);
  357. };
  358. }
  359. }]);
  360.  
  361. return Hooker;
  362. }();
  363.  
  364. var Mocker = function () {
  365. function Mocker() {
  366. _classCallCheck(this, Mocker);
  367. }
  368.  
  369. _createClass(Mocker, null, [{
  370. key: 'mockVip',
  371. value: function mockVip() {
  372. Hooker.hookUpsDataSuccess(function (data) {
  373. if (data.user) {
  374. data.user.vip = true;
  375. } else {
  376. data.user = { vip: true };
  377. }
  378. Logger.log('解除会员画质限制');
  379. });
  380. }
  381. }, {
  382. key: 'mockExclusiveShow',
  383. value: function mockExclusiveShow() {
  384. Hooker.hookSkinsControl(function (exports) {
  385. exports.prototype.exclusiveShow = function () {};
  386. Logger.log('和谐水印');
  387. });
  388. }
  389. }]);
  390.  
  391. return Mocker;
  392. }();
  393.  
  394. var Blocker = function () {
  395. function Blocker() {
  396. _classCallCheck(this, Blocker);
  397. }
  398.  
  399. _createClass(Blocker, null, [{
  400. key: '_isAdReq',
  401. value: function _isAdReq(url) {
  402. return (/atm\.youku\.com/.test(url)
  403. );
  404. }
  405. }, {
  406. key: 'blockAd',
  407. value: function blockAd() {
  408. var _this7 = this;
  409.  
  410. Hooker.hookGetJsonp(function (args) {
  411. var _args = _slicedToArray(args, 3),
  412. url = _args[0],
  413. /* onload */onerror = _args[2];
  414.  
  415. if (_this7._isAdReq(url)) {
  416. setTimeout(onerror, 0); // async invoke
  417. Logger.log('blocked ad request', url);
  418. return true;
  419. }
  420. });
  421. }
  422. }]);
  423.  
  424. return Blocker;
  425. }();
  426.  
  427. var Patcher = function () {
  428. function Patcher() {
  429. _classCallCheck(this, Patcher);
  430. }
  431.  
  432. _createClass(Patcher, null, [{
  433. key: 'patchQualitySetting',
  434. value: function patchQualitySetting() {
  435. Hooker.hookSkinsViewRender(function (elem) {
  436. var autoRe = /<spvdiv\s+customer="auto"[^<>]*>自动<\/spvdiv>/;
  437. var mp4Re = /<spvdiv\s+customer="mp4"[^<>]*>标清<\/spvdiv>/;
  438. var autoDiv = autoRe.exec(elem.innerHTML)[0];
  439. var hd3Div = autoDiv.replace('auto', 'mp4hd3').replace('自动', '1080P');
  440. elem.innerHTML = elem.innerHTML.replace(autoRe, hd3Div).replace(mp4Re, '$&' + autoDiv);
  441. Logger.log('设置里优先画质增加1080P选项并对齐到当前画质');
  442. });
  443.  
  444. GM_addStyle('\n spvdiv.spv_setting_1080, spvdiv.spv_setting_panel {\n width: 300px !important;\n }\n ');
  445. }
  446. }, {
  447. key: 'patchQualityFallback',
  448. value: function patchQualityFallback() {
  449. Hooker.hookH5PlayerCore(function (exports) {
  450. var SHOWHD = new Map([['flvhd', '标清'], ['3gphd', '标清'], ['mp4hd', '高清'], ['mp4hd2', '超清'], ['mp4hd3', '1080p']]);
  451.  
  452. exports.YoukuH5PlayerCore.prototype._initControlInfo = function () {
  453. if (!this._videoInfo.langcodes) return;
  454.  
  455. var control = this.control;
  456. if (!control.lang || !this._videoInfo.langcodes.includes(control.lang)) {
  457. control.lang = this._videoInfo.langcodes[0];
  458. }
  459.  
  460. var hdcodes = this._videoInfo.hdList[control.lang].hdcodes;
  461. if (!hdcodes.includes(control.hd)) {
  462. // 如果设置的优先画质在当前播放的视频里没有
  463. var hd = control.hd;
  464. control.hd = hdcodes[hdcodes.length - 1]; // 向下选择最高画质(原逻辑是给最渣画质!)
  465. 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');
  466. }
  467.  
  468. control.autoplay = control.autoplay || false;
  469. control.fullscreen = control.fullscreen || false;
  470. };
  471. });
  472. }
  473. }, {
  474. key: 'patchVolumeMemory',
  475. value: function patchVolumeMemory() {
  476. Hooker.hookRealStartPlay(function (that) {
  477. if (0 === parseFloat(localStorage.getItem('spv_volume'))) {
  478. that.UIControl.__proto__.mute.apply(that.UIControl);
  479. } else {
  480. that.UIControl.__proto__.nomute.apply(that.UIControl);
  481. }
  482.  
  483. that.EventManager.on('VolumeChange', function (data) {
  484. localStorage.setItem('spv_volume', data.value);
  485. });
  486.  
  487. Logger.log('开启音量记忆');
  488. });
  489. }
  490. }, {
  491. key: '_isFullScreen',
  492. value: function _isFullScreen() {
  493. return !!(document.fullscreen || document.webkitIsFullScreen || document.mozFullScreen || document.fullscreenElement || document.webkitFullscreenElement || document.mozFullScreenElement);
  494. }
  495. }, {
  496. key: 'patchFullScreen',
  497. value: function patchFullScreen() {
  498. var self = this;
  499. Hooker.hookManager(function (exports) {
  500. exports.prototype.toggleFull = function (arg) {
  501. this.method = arg.method || 'c';
  502. if (self._isFullScreen()) {
  503. this.containerExitScreen();
  504. Logger.log('退出全屏');
  505. } else {
  506. this.containerFullScreen();
  507. Logger.log('进入全屏');
  508. }
  509. };
  510. });
  511. }
  512. }, {
  513. key: '_patchManager',
  514. value: function _patchManager() {
  515. Hooker.hookManager(function (exports) {
  516. exports.prototype.getPreviousVid = function () {
  517. if (this.data.videos && this.data.videos.list) {
  518. var list = this.data.videos.list;
  519. var currVid = this.data.video.id;
  520. var prevSeq = list.find(function (item) {
  521. return parseInt(item.vid) === currVid;
  522. }).seq - 1;
  523. if (prevSeq > 0) {
  524. var previous = list.find(function (item) {
  525. return parseInt(item.seq) === prevSeq;
  526. });
  527. return previous.encodevid;
  528. }
  529. }
  530. };
  531.  
  532. exports.prototype.getVideoFPS = function () {
  533. return 25; // 优酷m3u8为动态帧率,flv标清fps为15,标清以上fps为25。
  534. };
  535. });
  536. }
  537. }, {
  538. key: '_patchWatcher',
  539. value: function _patchWatcher() {
  540. var _this8 = this;
  541.  
  542. this._patchManager();
  543.  
  544. Hooker.hookWatcher(function (that) {
  545. that.EventManager.on('_Seek', function (seekTime) {
  546. var videoCurrentInfo = {
  547. currentTime: seekTime,
  548. buffered: that.bufferedEnd()
  549. };
  550.  
  551. that.UIControl.setProgress(videoCurrentInfo, that.duration);
  552. that.UIControl.setTime(seekTime, that);
  553.  
  554. that.seek(seekTime);
  555. // if (that.myVideo.paused) that.play(); // seek后自动播放
  556. });
  557.  
  558. that.EventManager.on('_StepSeek', function (stepTime) {
  559. var seekTime = Math.max(0, Math.min(that.duration, that.mediaElement.currentTime + stepTime));
  560. var msg = void 0;
  561.  
  562. if (Math.abs(stepTime) < 60) {
  563. msg = stepTime > 0 ? '\u6B65\u8FDB\uFF1A' + stepTime + '\u79D2' : '\u6B65\u9000\uFF1A' + Math.abs(stepTime) + '\u79D2';
  564. } else {
  565. msg = stepTime > 0 ? '\u6B65\u8FDB\uFF1A' + stepTime / 60 + '\u5206\u949F' : '\u6B65\u9000\uFF1A' + Math.abs(stepTime) / 60 + '\u5206\u949F';
  566. }
  567. that.UIControl.tipShow(msg);
  568.  
  569. that.EventManager.fire('_Seek', seekTime);
  570. });
  571.  
  572. that.EventManager.on('_RangeSeek', function (range) {
  573. that.UIControl.tipShow('定位:' + (range * 100).toFixed(0) + '%');
  574. var seekTime = Math.max(0, Math.min(that.duration, that.duration * range));
  575. that.EventManager.fire('_Seek', seekTime);
  576. });
  577.  
  578. that.EventManager.on('_PreviousFrame', function () {
  579. that.UIControl.tipShow('定位:上一帧');
  580. var seekTime = Math.max(0, Math.min(that.duration, that.mediaElement.currentTime - 1 / that.getVideoFPS()));
  581. that.seek(seekTime);
  582. });
  583.  
  584. that.EventManager.on('_NextFrame', function () {
  585. that.UIControl.tipShow('定位:下一帧');
  586. var seekTime = Math.max(0, Math.min(that.duration, that.mediaElement.currentTime + 1 / that.getVideoFPS()));
  587. that.seek(seekTime);
  588. });
  589.  
  590. that.EventManager.off('VolumeChange');
  591. that.EventManager.on('VolumeChange', function (param) {
  592. if (0 === parseFloat(param.value)) {
  593. that.UIControl.tipShow('静音');
  594. } else {
  595. that.UIControl.tipShow('\u97F3\u91CF\uFF1A' + (100 * param.value).toFixed(0) + '%');
  596. }
  597. that.changeMuted(param.value);
  598. });
  599.  
  600. that.EventManager.on('_AdjustVolume', function (value) {
  601. var volume = that.mediaElement.volume + value;
  602. volume = Math.max(0, Math.min(1, volume.toFixed(2)));
  603. that.mediaElement.volume = volume;
  604.  
  605. that.UIControl.volumeProgress(volume);
  606. that.UIControl.volumeChange();
  607. });
  608.  
  609. that.EventManager.on('_ToggleMute', function () {
  610. if (that.mediaElement.muted) {
  611. that.UIControl.nomute();
  612. that.UIControl.tipShow('取消静音');
  613. } else {
  614. that.UIControl.mute();
  615. that.UIControl.tipShow('静音');
  616. }
  617. });
  618.  
  619. that.EventManager.on('_AdjustPlaybackRate', function (value) {
  620. var playbackRate = Math.max(0.2, Math.min(5, that.mediaElement.playbackRate + value));
  621. that.mediaElement.playbackRate = playbackRate;
  622. that.UIControl.tipShow('\u64AD\u653E\u901F\u7387\uFF1A' + playbackRate.toFixed(1).replace(/\.0+$/, ''));
  623. });
  624.  
  625. that.EventManager.on('_ResetPlaybackRate', function () {
  626. that.UIControl.tipShow('恢复播放速率');
  627. that.mediaElement.playbackRate = 1;
  628. });
  629.  
  630. that.EventManager.on('_PlayPrevious', function () {
  631. var vid = that.getPreviousVid();
  632. if (vid) {
  633. that.EventManager.fire('ChangeVid', { vid: vid });
  634. that.UIControl.tipShow('播放上一集');
  635. } else {
  636. that.UIControl.tipShow('没有上一集哦');
  637. }
  638. });
  639.  
  640. that.EventManager.on('_PlayNext', function () {
  641. var vid = that.getNextVid();
  642. if (vid) {
  643. that.EventManager.fire('ChangeVid', { vid: vid });
  644. that.UIControl.tipShow('播放下一集');
  645. } else {
  646. that.UIControl.tipShow('没有下一集哦');
  647. }
  648. });
  649.  
  650. that.EventManager.on('control:show', function () {
  651. that.selector.style.cursor = '';
  652. });
  653.  
  654. that.EventManager.on('control:hide', function () {
  655. if (_this8._isFullScreen()) {
  656. that.selector.style.cursor = 'none';
  657. }
  658. });
  659. });
  660. }
  661. // 让之后的tip覆盖之前的,不然之前的未消失会使之后的被忽略。
  662.  
  663. }, {
  664. key: '_patchTipShow',
  665. value: function _patchTipShow() {
  666. Hooker.hookSkinsControl(function (exports) {
  667. exports.prototype.tipShow = function (msg) {
  668. if (this.timerTip) {
  669. clearTimeout(this.timerTip);
  670. this.timerTip = null;
  671. }
  672.  
  673. this.tip.innerHTML = msg;
  674. if (!this.tipStatus()) this.tipBox.style.display = 'block';
  675. this.tipHide();
  676. };
  677. });
  678. }
  679. // 原控件持续显示时间为5秒,有点长,改成3秒吧。
  680.  
  681. }, {
  682. key: '_patchControlHide',
  683. value: function _patchControlHide() {
  684. Hooker.hookSkinsControl(function (exports) {
  685. exports.prototype.controlHide = function (isAd) {
  686. var _this9 = this;
  687.  
  688. if (isAd) {
  689. this.setCtrlDom(false);
  690. return;
  691. }
  692. if (this.pause || this.timer) return;
  693.  
  694. this.timer = setTimeout(function () {
  695. return _this9.setCtrlDom(false);
  696. }, 3e3);
  697. };
  698. });
  699. }
  700. }, {
  701. key: '_patchVolumeRange',
  702. value: function _patchVolumeRange() {
  703. Hooker.hookSkinsControlDomEvent(function (that) {
  704. return that.volumeRange.step = 0.01;
  705. });
  706. }
  707. }, {
  708. key: '_patchKeyShortcuts',
  709. value: function _patchKeyShortcuts() {
  710. // 原键盘快捷键在搜索框等仍有效,废了它。
  711. Hooker.hookWindowAddEventListener(function (_ref) {
  712. var _ref2 = _slicedToArray(_ref, 1),
  713. type = _ref2[0];
  714.  
  715. if (type !== 'keydown') return;
  716.  
  717. var stack = new Error().stack;
  718. if (stack.includes('domEvent')) {
  719. Logger.log('废除原键盘快捷键');
  720. return true;
  721. }
  722. });
  723.  
  724. Hooker.hookSkinsControlDomEvent(function (that) {
  725. document.addEventListener('keydown', function (event) {
  726. if (event.target.nodeName !== 'BODY') return;
  727.  
  728. switch (event.keyCode) {
  729. case 32:
  730. // Spacebar
  731. if (!event.ctrlKey && !event.shiftKey && !event.altKey) {
  732. if (that.pause) {
  733. that.EventManager.fire('VideoPlay');
  734. } else {
  735. that.EventManager.fire('VideoPause');
  736. }
  737. } else {
  738. return;
  739. }
  740. break;
  741. case 39: // → Arrow Right
  742. case 37:
  743. {
  744. // ← Arrow Left
  745. var stepTime = void 0;
  746. if (!event.ctrlKey && !event.shiftKey && !event.altKey) {
  747. stepTime = 39 === event.keyCode ? 5 : -5;
  748. } else if (event.ctrlKey && !event.shiftKey && !event.altKey) {
  749. stepTime = 39 === event.keyCode ? 30 : -30;
  750. } else if (!event.ctrlKey && event.shiftKey && !event.altKey) {
  751. stepTime = 39 === event.keyCode ? 60 : -60;
  752. } else if (event.ctrlKey && !event.shiftKey && event.altKey) {
  753. stepTime = 39 === event.keyCode ? 3e2 : -3e2; // 5分钟
  754. } else {
  755. return;
  756. }
  757.  
  758. that.EventManager.fire('_StepSeek', stepTime);
  759. break;
  760. }
  761. case 38: // ↑ Arrow Up
  762. case 40:
  763. // ↓ Arrow Down
  764. if (!event.ctrlKey && !event.shiftKey && !event.altKey) {
  765. that.EventManager.fire('_AdjustVolume', 38 === event.keyCode ? 0.05 : -0.05);
  766. } else {
  767. return;
  768. }
  769. break;
  770. case 77:
  771. // M
  772. if (!event.ctrlKey && !event.shiftKey && !event.altKey) {
  773. that.EventManager.fire('_ToggleMute');
  774. } else {
  775. return;
  776. }
  777. break;
  778. case 13:
  779. // Enter
  780. if (!event.ctrlKey && !event.shiftKey && !event.altKey) {
  781. that.EventManager.fire('SwitchFullScreen');
  782. } else {
  783. return;
  784. }
  785. break;
  786. case 67: // C
  787. case 88:
  788. // X
  789. if (!event.ctrlKey && !event.shiftKey && !event.altKey) {
  790. that.EventManager.fire('_AdjustPlaybackRate', 67 === event.keyCode ? 0.1 : -0.1);
  791. } else {
  792. return;
  793. }
  794. break;
  795. case 90:
  796. // Z
  797. if (!event.ctrlKey && !event.shiftKey && !event.altKey) {
  798. that.EventManager.fire('_ResetPlaybackRate');
  799. } else {
  800. return;
  801. }
  802. break;
  803. case 68: // D
  804. case 70:
  805. // F
  806. if (!event.ctrlKey && !event.shiftKey && !event.altKey) {
  807. if (!that.pause) that.EventManager.fire('VideoPause');
  808. if (event.keyCode === 68) {
  809. that.EventManager.fire('_PreviousFrame');
  810. } else {
  811. that.EventManager.fire('_NextFrame');
  812. }
  813. } else {
  814. return;
  815. }
  816. break;
  817. case 80: // P
  818. case 78:
  819. // N
  820. if (!event.ctrlKey && event.shiftKey && !event.altKey) {
  821. if (event.keyCode === 78) {
  822. that.EventManager.fire('_PlayNext');
  823. } else {
  824. that.EventManager.fire('_PlayPrevious');
  825. }
  826. } else {
  827. return;
  828. }
  829. break;
  830. default:
  831. if (event.keyCode >= 48 && event.keyCode <= 57) {
  832. // 0 ~ 9
  833. if (!event.ctrlKey && !event.shiftKey && !event.altKey) {
  834. that.EventManager.fire('_RangeSeek', (event.keyCode - 48) * 0.1);
  835. } else {
  836. return;
  837. }
  838. } else {
  839. return;
  840. }
  841. }
  842.  
  843. event.preventDefault();
  844. event.stopPropagation();
  845. });
  846.  
  847. Logger.log('添加键盘快捷键');
  848. });
  849. }
  850. }, {
  851. key: '_patchShadowClick',
  852. value: function _patchShadowClick() {
  853. Hooker.hookSkinsControl(function (exports) {
  854. exports.prototype.shadowClick = function () {
  855. var _this10 = this;
  856.  
  857. if (this.shadowTimer) {
  858. // 短时间内连续单击
  859. clearTimeout(this.shadowTimer);
  860. this.shadowTimer = null;
  861. return;
  862. }
  863.  
  864. this.shadowTimer = setTimeout(function () {
  865. if (!_this10.pause) {
  866. _this10.pauseState();
  867. _this10.EventManager.fire('VideoPause');
  868. _this10.controlShow();
  869. } else {
  870. _this10.playingState();
  871. _this10.EventManager.fire('VideoPlay');
  872. _this10.controlHide();
  873. }
  874.  
  875. _this10.shadowTimer = null;
  876. }, 200);
  877. };
  878. });
  879. }
  880. }, {
  881. key: '_patchMouseShortcuts',
  882. value: function _patchMouseShortcuts() {
  883. var _this11 = this;
  884.  
  885. this._patchShadowClick();
  886.  
  887. Hooker.hookSkinsControlDomEvent(function (that) {
  888. that.shadow.addEventListener('dblclick', function () {
  889. that.EventManager.fire('SwitchFullScreen');
  890. });
  891.  
  892. document.addEventListener('wheel', function (event) {
  893. if (!_this11._isFullScreen()) return;
  894.  
  895. var delta = event.wheelDelta || event.detail || event.deltaY && -event.deltaY;
  896. that.EventManager.fire('_AdjustVolume', delta > 0 ? 0.05 : -0.05);
  897. });
  898.  
  899. Logger.log('添加鼠标快捷键');
  900. });
  901. }
  902. }, {
  903. key: 'patchShortcuts',
  904. value: function patchShortcuts() {
  905. this._patchWatcher();
  906. this._patchTipShow();
  907. this._patchVolumeRange();
  908. this._patchControlHide();
  909.  
  910. this._patchKeyShortcuts();
  911. this._patchMouseShortcuts();
  912. }
  913. }]);
  914.  
  915. return Patcher;
  916. }();
  917.  
  918. function enableH5Player() {
  919. sessionStorage.setItem('P_l_h5', 1);
  920. Logger.log('启用html5播放器');
  921. }
  922.  
  923. function recoverPlayer() {
  924. sessionStorage.removeItem('P_l_h5');
  925. Logger.log('恢复原播放器');
  926. }
  927.  
  928. //=============================================================================
  929.  
  930. enableH5Player();
  931. window.addEventListener('unload', function () {
  932. return recoverPlayer();
  933. }); // 禁用脚本刷新页面可恢复播放器
  934.  
  935. Blocker.blockAd();
  936. Mocker.mockVip();
  937. Mocker.mockExclusiveShow();
  938. Patcher.patchQualitySetting();
  939. Patcher.patchQualityFallback();
  940. Patcher.patchVolumeMemory();
  941. Patcher.patchFullScreen();
  942. Patcher.patchShortcuts();
  943. })();