ykh5p

youku html5 player +

目前为 2017-06-09 提交的版本。查看 最新版本

  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.2.2
  15. // @description youku html5 player +
  16. // @author gooyie
  17. // @license MIT License
  18. //
  19. // @include *://v.youku.com/*
  20. // @grant GM_info
  21. // @grant GM_addStyle
  22. // @run-at document-start
  23. // ==/UserScript==
  24.  
  25. (function () {
  26. 'use strict';
  27.  
  28. /* eslint-disable no-console */
  29.  
  30. var Logger = function () {
  31. function Logger() {
  32. _classCallCheck(this, Logger);
  33. }
  34.  
  35. _createClass(Logger, null, [{
  36. key: 'log',
  37. value: function log() {
  38. var _console;
  39.  
  40. for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
  41. args[_key] = arguments[_key];
  42. }
  43.  
  44. (_console = console).log.apply(_console, ['%c' + this.tag + '%c' + args.shift(), 'color: #fff; background: #2FB3FF', ''].concat(args));
  45. }
  46. }, {
  47. key: 'info',
  48. value: function info() {
  49. var _console2;
  50.  
  51. for (var _len2 = arguments.length, args = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
  52. args[_key2] = arguments[_key2];
  53. }
  54.  
  55. (_console2 = console).info.apply(_console2, [this.tag + args.shift()].concat(args));
  56. }
  57. }, {
  58. key: 'debug',
  59. value: function debug() {
  60. var _console3;
  61.  
  62. for (var _len3 = arguments.length, args = Array(_len3), _key3 = 0; _key3 < _len3; _key3++) {
  63. args[_key3] = arguments[_key3];
  64. }
  65.  
  66. (_console3 = console).debug.apply(_console3, [this.tag + args.shift()].concat(args));
  67. }
  68. }, {
  69. key: 'warn',
  70. value: function warn() {
  71. var _console4;
  72.  
  73. for (var _len4 = arguments.length, args = Array(_len4), _key4 = 0; _key4 < _len4; _key4++) {
  74. args[_key4] = arguments[_key4];
  75. }
  76.  
  77. (_console4 = console).warn.apply(_console4, [this.tag + args.shift()].concat(args));
  78. }
  79. }, {
  80. key: 'error',
  81. value: function error() {
  82. var _console5;
  83.  
  84. for (var _len5 = arguments.length, args = Array(_len5), _key5 = 0; _key5 < _len5; _key5++) {
  85. args[_key5] = arguments[_key5];
  86. }
  87.  
  88. (_console5 = console).error.apply(_console5, [this.tag + args.shift()].concat(args));
  89. }
  90. }, {
  91. key: 'tag',
  92. get: function get() {
  93. return '[' + GM_info.script.name + ']';
  94. }
  95. }]);
  96.  
  97. return Logger;
  98. }();
  99. /* eslint-enable no-console */
  100.  
  101. var Hooker = function () {
  102. function Hooker() {
  103. _classCallCheck(this, Hooker);
  104. }
  105.  
  106. _createClass(Hooker, null, [{
  107. key: 'hookCall',
  108. value: function hookCall() {
  109. var after = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : function () {};
  110. var before = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : function () {};
  111.  
  112. var call = Function.prototype.call;
  113. Function.prototype.call = function () {
  114. for (var _len6 = arguments.length, args = Array(_len6), _key6 = 0; _key6 < _len6; _key6++) {
  115. args[_key6] = arguments[_key6];
  116. }
  117.  
  118. try {
  119. if (args) before.apply(undefined, args);
  120. } catch (err) {
  121. Logger.error(err.stack);
  122. }
  123.  
  124. var ret = call.apply(this, args);
  125.  
  126. try {
  127. if (args) after.apply(undefined, args);
  128. } catch (err) {
  129. Logger.error(err.stack);
  130. }
  131.  
  132. return ret;
  133. };
  134.  
  135. Function.prototype.call.toString = Function.prototype.call.toLocaleString = function () {
  136. return 'function call() { [native code] }';
  137. };
  138. }
  139. }, {
  140. key: '_isFactoryCall',
  141. value: function _isFactoryCall(args) {
  142. // m.exports, _dereq_, m, m.exports, outer, modules, cache, entry
  143. return args.length === 8 && args[2] instanceof Object && args[2].hasOwnProperty('exports');
  144. }
  145. }, {
  146. key: 'hookFactoryCall',
  147. value: function hookFactoryCall() {
  148. var _this = this;
  149.  
  150. var cb = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : function () {};
  151.  
  152. this.hookCall(function () {
  153. for (var _len7 = arguments.length, args = Array(_len7), _key7 = 0; _key7 < _len7; _key7++) {
  154. args[_key7] = arguments[_key7];
  155. }
  156.  
  157. if (_this._isFactoryCall(args)) cb.apply(undefined, args);
  158. });
  159. }
  160. }, {
  161. key: '_isManagerFactoryCall',
  162. value: function _isManagerFactoryCall() {
  163. var exports = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
  164.  
  165. return 'function' === typeof exports && exports.prototype.hasOwnProperty('upsDataSuccess');
  166. }
  167. }, {
  168. key: 'hookManager',
  169. value: function hookManager() {
  170. var _this2 = this;
  171.  
  172. var cb = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : function () {};
  173.  
  174. this.hookFactoryCall(function () {
  175. for (var _len8 = arguments.length, args = Array(_len8), _key8 = 0; _key8 < _len8; _key8++) {
  176. args[_key8] = arguments[_key8];
  177. }
  178.  
  179. if (_this2._isManagerFactoryCall(args[2].exports)) cb(args[2].exports);
  180. });
  181. }
  182. }, {
  183. key: 'hookUpsDataSuccess',
  184. value: function hookUpsDataSuccess() {
  185. var cb = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : function () {};
  186.  
  187. this.hookManager(function (exports) {
  188. var upsDataSuccess = exports.prototype.upsDataSuccess;
  189. exports.prototype.upsDataSuccess = function (data) {
  190. cb(data);
  191. upsDataSuccess.apply(this, [data]);
  192. };
  193. });
  194. }
  195. }, {
  196. key: '_isSkinsViewRenderCall',
  197. value: function _isSkinsViewRenderCall(args) {
  198. return args.length === 3 && args[1] === 'spvdiv' && args[2].className === 'spv_player';
  199. }
  200. }, {
  201. key: 'hookSkinsViewRender',
  202. value: function hookSkinsViewRender() {
  203. var _this3 = this;
  204.  
  205. var cb = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : function () {};
  206.  
  207. this.hookCall(undefined, function () {
  208. for (var _len9 = arguments.length, args = Array(_len9), _key9 = 0; _key9 < _len9; _key9++) {
  209. args[_key9] = arguments[_key9];
  210. }
  211.  
  212. if (_this3._isSkinsViewRenderCall(args)) cb(args[2]);
  213. });
  214. }
  215. }, {
  216. key: '_isUtilFactoryCall',
  217. value: function _isUtilFactoryCall() {
  218. var exports = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
  219.  
  220. return exports.hasOwnProperty('getJsonp') && exports.TAG === 'util';
  221. }
  222. }, {
  223. key: 'hookUtil',
  224. value: function hookUtil() {
  225. var _this4 = this;
  226.  
  227. var cb = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : function () {};
  228.  
  229. this.hookFactoryCall(function () {
  230. for (var _len10 = arguments.length, args = Array(_len10), _key10 = 0; _key10 < _len10; _key10++) {
  231. args[_key10] = arguments[_key10];
  232. }
  233.  
  234. if (_this4._isUtilFactoryCall(args[2].exports)) cb(args[2].exports);
  235. });
  236. }
  237. }, {
  238. key: 'hookGetJsonp',
  239. value: function hookGetJsonp() {
  240. var cb = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : function () {};
  241.  
  242. this.hookUtil(function (exports) {
  243. var getJsonp = exports.getJsonp.bind(exports);
  244. exports.getJsonp = function () {
  245. for (var _len11 = arguments.length, args = Array(_len11), _key11 = 0; _key11 < _len11; _key11++) {
  246. args[_key11] = arguments[_key11];
  247. }
  248.  
  249. // url, onload, onerror, ontimeout, timeout
  250. if (cb(args)) return; // hijack
  251. getJsonp.apply(undefined, args);
  252. };
  253. });
  254. }
  255. }, {
  256. key: '_isH5PlayerCoreFactoryCall',
  257. value: function _isH5PlayerCoreFactoryCall() {
  258. var exports = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
  259.  
  260. return exports instanceof Object && exports.hasOwnProperty('YoukuH5PlayerCore');
  261. }
  262. }, {
  263. key: 'hookH5PlayerCore',
  264. value: function hookH5PlayerCore() {
  265. var _this5 = this;
  266.  
  267. var cb = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : function () {};
  268.  
  269. this.hookFactoryCall(function () {
  270. for (var _len12 = arguments.length, args = Array(_len12), _key12 = 0; _key12 < _len12; _key12++) {
  271. args[_key12] = arguments[_key12];
  272. }
  273.  
  274. if (_this5._isH5PlayerCoreFactoryCall(args[2].exports)) cb(args[2].exports);
  275. });
  276. }
  277. }]);
  278.  
  279. return Hooker;
  280. }();
  281.  
  282. var Mocker = function () {
  283. function Mocker() {
  284. _classCallCheck(this, Mocker);
  285. }
  286.  
  287. _createClass(Mocker, null, [{
  288. key: 'mockVip',
  289. value: function mockVip() {
  290. Hooker.hookUpsDataSuccess(function (data) {
  291. if (data.user) {
  292. data.user.vip = true;
  293. } else {
  294. data.user = { vip: true };
  295. }
  296. });
  297. }
  298. }]);
  299.  
  300. return Mocker;
  301. }();
  302.  
  303. var Blocker = function () {
  304. function Blocker() {
  305. _classCallCheck(this, Blocker);
  306. }
  307.  
  308. _createClass(Blocker, null, [{
  309. key: '_isAdReq',
  310. value: function _isAdReq(url) {
  311. return (/atm\.youku\.com/.test(url)
  312. );
  313. }
  314. }, {
  315. key: 'blockAd',
  316. value: function blockAd() {
  317. var _this6 = this;
  318.  
  319. Hooker.hookGetJsonp(function (args) {
  320. var _args = _slicedToArray(args, 3),
  321. url = _args[0],
  322. /* onload */onerror = _args[2];
  323.  
  324. if (_this6._isAdReq(url)) {
  325. setTimeout(onerror, 0); // async invoke
  326. Logger.log('blocked ad request', url);
  327. return true;
  328. }
  329. });
  330. }
  331. }]);
  332.  
  333. return Blocker;
  334. }();
  335.  
  336. var Patcher = function () {
  337. function Patcher() {
  338. _classCallCheck(this, Patcher);
  339. }
  340.  
  341. _createClass(Patcher, null, [{
  342. key: 'patchQualitySetting',
  343. value: function patchQualitySetting() {
  344. Hooker.hookSkinsViewRender(function (elem) {
  345. var autoRe = /<spvdiv\s+customer="auto"[^<>]*>自动<\/spvdiv>/;
  346. var mp4Re = /<spvdiv\s+customer="mp4"[^<>]*>标清<\/spvdiv>/;
  347. var autoDiv = autoRe.exec(elem.innerHTML)[0];
  348. var hd3Div = autoDiv.replace('auto', 'mp4hd3').replace('自动', '1080P');
  349. elem.innerHTML = elem.innerHTML.replace(autoRe, hd3Div).replace(mp4Re, '$&' + autoDiv);
  350. });
  351.  
  352. GM_addStyle('\n spvdiv.spv_setting_1080, spvdiv.spv_setting_panel {\n width: 300px !important;\n }\n ');
  353. }
  354. }, {
  355. key: 'patchQualityFallback',
  356. value: function patchQualityFallback() {
  357. Hooker.hookH5PlayerCore(function (exports) {
  358. exports.YoukuH5PlayerCore.prototype._initControlInfo = function () {
  359. if (!this._videoInfo.langcodes) return;
  360.  
  361. var control = this.control;
  362. if (!control.lang || !this._videoInfo.langcodes.includes(control.lang)) {
  363. control.lang = this._videoInfo.langcodes[0];
  364. }
  365.  
  366. var hdcodes = this._videoInfo.hdList[control.lang].hdcodes;
  367. if (!hdcodes.includes(control.hd)) {
  368. // 如果设置的优先画质在当前播放的视频里没有
  369. control.hd = hdcodes[hdcodes.length - 1]; // 向下选择最高画质(原逻辑是给最渣画质!)
  370. }
  371.  
  372. control.autoplay = control.autoplay || false;
  373. control.fullscreen = control.fullscreen || false;
  374. };
  375. });
  376. }
  377. }]);
  378.  
  379. return Patcher;
  380. }();
  381.  
  382. function enableH5Player() {
  383. sessionStorage.setItem('P_l_h5', 1);
  384. }
  385.  
  386. function recoverPlayer() {
  387. sessionStorage.removeItem('P_l_h5');
  388. }
  389.  
  390. //=============================================================================
  391.  
  392. enableH5Player();
  393. window.addEventListener('unload', function () {
  394. return recoverPlayer();
  395. }); // 禁用脚本刷新页面可恢复播放器
  396.  
  397. Blocker.blockAd();
  398. Mocker.mockVip();
  399. Patcher.patchQualitySetting();
  400. Patcher.patchQualityFallback();
  401. })();