Greasy Fork 支持简体中文。

ykh5p

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

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

  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.5.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.  
  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. var _this8 = this;
  477.  
  478. Hooker.hookRealStartPlay(function (that) {
  479. if (_this8._enabled) return;
  480. _this8._enabled = true;
  481.  
  482. if (0 === parseFloat(localStorage.getItem('spv_volume'))) {
  483. that.UIControl.__proto__.mute.apply(that.UIControl);
  484. } else {
  485. that.UIControl.__proto__.nomute.apply(that.UIControl);
  486. }
  487.  
  488. that.EventManager.on('VolumeChange', function (data) {
  489. localStorage.setItem('spv_volume', data.value);
  490. });
  491.  
  492. Logger.log('开启音量记忆');
  493. });
  494. }
  495. }, {
  496. key: '_isFullScreen',
  497. value: function _isFullScreen() {
  498. return !!(document.fullscreen || document.webkitIsFullScreen || document.mozFullScreen || document.fullscreenElement || document.webkitFullscreenElement || document.mozFullScreenElement);
  499. }
  500. }, {
  501. key: 'patchFullScreen',
  502. value: function patchFullScreen() {
  503. var self = this;
  504. Hooker.hookManager(function (exports) {
  505. exports.prototype.toggleFull = function (arg) {
  506. this.method = arg.method || 'c';
  507. if (self._isFullScreen()) {
  508. this.containerExitScreen();
  509. Logger.log('退出全屏');
  510. } else {
  511. this.containerFullScreen();
  512. Logger.log('进入全屏');
  513. }
  514. };
  515. });
  516. }
  517. }, {
  518. key: '_patchManager',
  519. value: function _patchManager() {
  520. Hooker.hookManager(function (exports) {
  521. exports.prototype.getPreviousVid = function () {
  522. if (this.data.videos && this.data.videos.list) {
  523. var list = this.data.videos.list;
  524. var currVid = this.data.video.id;
  525. var prevSeq = list.find(function (item) {
  526. return parseInt(item.vid) === currVid;
  527. }).seq - 1;
  528. if (prevSeq > 0) {
  529. var previous = list.find(function (item) {
  530. return parseInt(item.seq) === prevSeq;
  531. });
  532. return previous.encodevid;
  533. }
  534. }
  535. };
  536.  
  537. exports.prototype.getVideoFPS = function () {
  538. return 25; // 优酷m3u8为动态帧率,flv标清fps为15,标清以上fps为25。
  539. };
  540. });
  541. }
  542. }, {
  543. key: '_patchWatcher',
  544. value: function _patchWatcher() {
  545. this._patchManager();
  546.  
  547. Hooker.hookWatcher(function (that) {
  548. that.EventManager.on('_Seek', function (seekTime) {
  549. var videoCurrentInfo = {
  550. currentTime: seekTime,
  551. buffered: that.bufferedEnd()
  552. };
  553.  
  554. that.UIControl.setProgress(videoCurrentInfo, that.duration);
  555. that.UIControl.setTime(seekTime, that);
  556.  
  557. that.seek(seekTime);
  558. // if (that.myVideo.paused) that.play(); // seek后自动播放
  559. });
  560.  
  561. that.EventManager.on('_StepSeek', function (stepTime) {
  562. var seekTime = Math.max(0, Math.min(that.duration, that.mediaElement.currentTime + stepTime));
  563. var msg = void 0;
  564.  
  565. if (Math.abs(stepTime) < 60) {
  566. msg = stepTime > 0 ? '\u6B65\u8FDB\uFF1A' + stepTime + '\u79D2' : '\u6B65\u9000\uFF1A' + Math.abs(stepTime) + '\u79D2';
  567. } else {
  568. msg = stepTime > 0 ? '\u6B65\u8FDB\uFF1A' + stepTime / 60 + '\u5206\u949F' : '\u6B65\u9000\uFF1A' + Math.abs(stepTime) / 60 + '\u5206\u949F';
  569. }
  570. that.UIControl.tipShow(msg);
  571.  
  572. that.EventManager.fire('_Seek', seekTime);
  573. });
  574.  
  575. that.EventManager.on('_RangeSeek', function (range) {
  576. that.UIControl.tipShow('定位:' + (range * 100).toFixed(0) + '%');
  577. var seekTime = Math.max(0, Math.min(that.duration, that.duration * range));
  578. that.EventManager.fire('_Seek', seekTime);
  579. });
  580.  
  581. that.EventManager.on('_PreviousFrame', function () {
  582. that.UIControl.tipShow('定位:上一帧');
  583. var seekTime = Math.max(0, Math.min(that.duration, that.mediaElement.currentTime - 1 / that.getVideoFPS()));
  584. that.seek(seekTime);
  585. });
  586.  
  587. that.EventManager.on('_NextFrame', function () {
  588. that.UIControl.tipShow('定位:下一帧');
  589. var seekTime = Math.max(0, Math.min(that.duration, that.mediaElement.currentTime + 1 / that.getVideoFPS()));
  590. that.seek(seekTime);
  591. });
  592.  
  593. that.EventManager.off('VolumeChange');
  594. that.EventManager.on('VolumeChange', function (param) {
  595. if (0 === parseFloat(param.value)) {
  596. that.UIControl.tipShow('静音');
  597. } else {
  598. that.UIControl.tipShow('\u97F3\u91CF\uFF1A' + (100 * param.value).toFixed(0) + '%');
  599. }
  600. that.changeMuted(param.value);
  601. });
  602.  
  603. that.EventManager.on('_AdjustVolume', function (value) {
  604. var volume = that.mediaElement.volume + value;
  605. volume = Math.max(0, Math.min(1, volume.toFixed(2)));
  606. that.mediaElement.volume = volume;
  607.  
  608. that.UIControl.volumeProgress(volume);
  609. that.UIControl.volumeChange();
  610. });
  611.  
  612. that.EventManager.on('_ToggleMute', function () {
  613. if (that.mediaElement.muted) {
  614. that.UIControl.nomute();
  615. that.UIControl.tipShow('取消静音');
  616. } else {
  617. that.UIControl.mute();
  618. that.UIControl.tipShow('静音');
  619. }
  620. });
  621.  
  622. that.EventManager.on('_AdjustPlaybackRate', function (value) {
  623. var playbackRate = Math.max(0.2, Math.min(5, that.mediaElement.playbackRate + value));
  624. that.mediaElement.playbackRate = playbackRate;
  625. that.UIControl.tipShow('\u64AD\u653E\u901F\u7387\uFF1A' + playbackRate.toFixed(1).replace(/\.0+$/, ''));
  626. });
  627.  
  628. that.EventManager.on('_ResetPlaybackRate', function () {
  629. that.UIControl.tipShow('恢复播放速率');
  630. that.mediaElement.playbackRate = 1;
  631. });
  632.  
  633. that.EventManager.on('_PlayPrevious', function () {
  634. var vid = that.getPreviousVid();
  635. if (vid) {
  636. that.EventManager.fire('ChangeVid', { vid: vid });
  637. that.UIControl.tipShow('播放上一集');
  638. } else {
  639. that.UIControl.tipShow('没有上一集哦');
  640. }
  641. });
  642.  
  643. that.EventManager.on('_PlayNext', function () {
  644. var vid = that.getNextVid();
  645. if (vid) {
  646. that.EventManager.fire('ChangeVid', { vid: vid });
  647. that.UIControl.tipShow('播放下一集');
  648. } else {
  649. that.UIControl.tipShow('没有下一集哦');
  650. }
  651. });
  652. });
  653. }
  654. // 让之后的tip覆盖之前的,不然之前的未消失会使之后的被忽略。
  655.  
  656. }, {
  657. key: '_patchTipShow',
  658. value: function _patchTipShow() {
  659. Hooker.hookSkinsControl(function (exports) {
  660. exports.prototype.tipShow = function (msg) {
  661. if (this.timerTip) {
  662. clearTimeout(this.timerTip);
  663. this.timerTip = null;
  664. }
  665.  
  666. this.tip.innerHTML = msg;
  667. if (!this.tipStatus()) this.tipBox.style.display = 'block';
  668. this.tipHide();
  669. };
  670. });
  671. }
  672. // 原控件持续显示时间为5秒,有点长,改成3秒吧。
  673.  
  674. }, {
  675. key: '_patchControlHide',
  676. value: function _patchControlHide() {
  677. Hooker.hookSkinsControl(function (exports) {
  678. exports.prototype.controlHide = function (isAd) {
  679. var _this9 = this;
  680.  
  681. if (isAd) {
  682. this.setCtrlDom(false);
  683. return;
  684. }
  685. if (this.pause || this.timer) return;
  686.  
  687. this.timer = setTimeout(function () {
  688. return _this9.setCtrlDom(false);
  689. }, 3e3);
  690. };
  691. });
  692. }
  693. }, {
  694. key: '_patchVolumeRange',
  695. value: function _patchVolumeRange() {
  696. Hooker.hookSkinsControlDomEvent(function (that) {
  697. return that.volumeRange.step = 0.01;
  698. });
  699. }
  700. }, {
  701. key: 'patchShortcuts',
  702. value: function patchShortcuts() {
  703. this._patchWatcher();
  704. this._patchTipShow();
  705. this._patchVolumeRange();
  706. this._patchControlHide();
  707. // 原键盘快捷键在搜索框等仍有效,废了它。
  708. Hooker.hookWindowAddEventListener(function (_ref) {
  709. var _ref2 = _slicedToArray(_ref, 1),
  710. type = _ref2[0];
  711.  
  712. if (type !== 'keydown') return;
  713.  
  714. var stack = new Error().stack;
  715. if (stack.includes('domEvent')) {
  716. Logger.log('废除原键盘快捷键');
  717. return true;
  718. }
  719. });
  720.  
  721. Hooker.hookSkinsControlDomEvent(function (that) {
  722. document.addEventListener('keydown', function (event) {
  723. if (event.target.nodeName !== 'BODY') return;
  724.  
  725. switch (event.keyCode) {
  726. case 32:
  727. // Spacebar
  728. if (!event.ctrlKey && !event.shiftKey && !event.altKey) {
  729. if (that.pause) {
  730. that.EventManager.fire('VideoPlay');
  731. } else {
  732. that.EventManager.fire('VideoPause');
  733. }
  734. } else {
  735. return;
  736. }
  737. break;
  738. case 39: // → Arrow Right
  739. case 37:
  740. {
  741. // ← Arrow Left
  742. var stepTime = void 0;
  743. if (!event.ctrlKey && !event.shiftKey && !event.altKey) {
  744. stepTime = 39 === event.keyCode ? 5 : -5;
  745. } else if (event.ctrlKey && !event.shiftKey && !event.altKey) {
  746. stepTime = 39 === event.keyCode ? 30 : -30;
  747. } else if (!event.ctrlKey && event.shiftKey && !event.altKey) {
  748. stepTime = 39 === event.keyCode ? 60 : -60;
  749. } else if (event.ctrlKey && !event.shiftKey && event.altKey) {
  750. stepTime = 39 === event.keyCode ? 3e2 : -3e2; // 5分钟
  751. } else {
  752. return;
  753. }
  754.  
  755. that.EventManager.fire('_StepSeek', stepTime);
  756. break;
  757. }
  758. case 38: // ↑ Arrow Up
  759. case 40:
  760. // ↓ Arrow Down
  761. if (!event.ctrlKey && !event.shiftKey && !event.altKey) {
  762. that.EventManager.fire('_AdjustVolume', 38 === event.keyCode ? 0.05 : -0.05);
  763. } else {
  764. return;
  765. }
  766. break;
  767. case 77:
  768. // M
  769. if (!event.ctrlKey && !event.shiftKey && !event.altKey) {
  770. that.EventManager.fire('_ToggleMute');
  771. } else {
  772. return;
  773. }
  774. break;
  775. case 13:
  776. // Enter
  777. if (!event.ctrlKey && !event.shiftKey && !event.altKey) {
  778. that.EventManager.fire('SwitchFullScreen');
  779. } else {
  780. return;
  781. }
  782. break;
  783. case 67: // C
  784. case 88:
  785. // X
  786. if (!event.ctrlKey && !event.shiftKey && !event.altKey) {
  787. that.EventManager.fire('_AdjustPlaybackRate', 67 === event.keyCode ? 0.1 : -0.1);
  788. } else {
  789. return;
  790. }
  791. break;
  792. case 90:
  793. // Z
  794. if (!event.ctrlKey && !event.shiftKey && !event.altKey) {
  795. that.EventManager.fire('_ResetPlaybackRate');
  796. } else {
  797. return;
  798. }
  799. break;
  800. case 68: // D
  801. case 70:
  802. // F
  803. if (!event.ctrlKey && !event.shiftKey && !event.altKey) {
  804. if (!that.pause) that.EventManager.fire('VideoPause');
  805. if (event.keyCode === 68) {
  806. that.EventManager.fire('_PreviousFrame');
  807. } else {
  808. that.EventManager.fire('_NextFrame');
  809. }
  810. } else {
  811. return;
  812. }
  813. break;
  814. case 80: // P
  815. case 78:
  816. // N
  817. if (!event.ctrlKey && event.shiftKey && !event.altKey) {
  818. if (event.keyCode === 78) {
  819. that.EventManager.fire('_PlayNext');
  820. } else {
  821. that.EventManager.fire('_PlayPrevious');
  822. }
  823. } else {
  824. return;
  825. }
  826. break;
  827. default:
  828. if (event.keyCode >= 48 && event.keyCode <= 57) {
  829. // 0 ~ 9
  830. if (!event.ctrlKey && !event.shiftKey && !event.altKey) {
  831. that.EventManager.fire('_RangeSeek', (event.keyCode - 48) * 0.1);
  832. } else {
  833. return;
  834. }
  835. } else {
  836. return;
  837. }
  838. }
  839.  
  840. event.preventDefault();
  841. event.stopPropagation();
  842. });
  843. Logger.log('添加键盘快捷键');
  844. });
  845. }
  846. }]);
  847.  
  848. return Patcher;
  849. }();
  850.  
  851. function enableH5Player() {
  852. sessionStorage.setItem('P_l_h5', 1);
  853. Logger.log('启用html5播放器');
  854. }
  855.  
  856. function recoverPlayer() {
  857. sessionStorage.removeItem('P_l_h5');
  858. Logger.log('恢复原播放器');
  859. }
  860.  
  861. //=============================================================================
  862.  
  863. enableH5Player();
  864. window.addEventListener('unload', function () {
  865. return recoverPlayer();
  866. }); // 禁用脚本刷新页面可恢复播放器
  867.  
  868. Blocker.blockAd();
  869. Mocker.mockVip();
  870. Mocker.mockExclusiveShow();
  871. Patcher.patchQualitySetting();
  872. Patcher.patchQualityFallback();
  873. Patcher.patchVolumeMemory();
  874. Patcher.patchFullScreen();
  875. Patcher.patchShortcuts();
  876. })();