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