├── .babelrc
├── .eslintrc.js
├── .gitignore
├── LICENSE
├── README.md
├── dist
└── iqiyi-player-switch.user.js
├── package-lock.json
├── package.json
├── scripts
└── clean.js
├── src
├── cookies.js
├── detector.js
├── faker.js
├── fullscreen.js
├── hooker.js
├── index.js
├── logger.js
├── meta.js
├── outsite.js
├── parsed-data.js
├── patch.js
├── utils.js
└── web-fullscreen.js
└── webpack.config.js
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | ["env", {
4 | "targets": {
5 | "browsers": ["chrome >= 43", "firefox >= 45", "edge >= 15"]
6 | }
7 | }]
8 | ],
9 | "plugins": [
10 | [
11 | "transform-runtime",
12 | {
13 | "helpers": false,
14 | "polyfill": false,
15 | "regenerator": true,
16 | "moduleName": "babel-runtime"
17 | }
18 | ]
19 | ]
20 | }
21 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 |
2 | module.exports = {
3 | root: true,
4 | parser: 'babel-eslint',
5 | 'env': {
6 | 'browser': true,
7 | 'node': true,
8 | 'es6': true
9 | },
10 | 'extends': 'eslint:recommended',
11 | 'parserOptions': {
12 | 'ecmaVersion': 6,
13 | 'sourceType': 'module'
14 | },
15 | 'rules': {
16 | 'indent': [
17 | 'error',
18 | 4
19 | ],
20 | 'quotes': [
21 | 'error',
22 | 'single',
23 | {"allowTemplateLiterals": true}
24 | ],
25 | 'semi': [
26 | 'error',
27 | 'always'
28 | ],
29 | },
30 | globals: {
31 | GM_registerMenuCommand: false,
32 | GM_xmlhttpRequest: false,
33 | unsafeWindow: false,
34 | GM_addStyle: false,
35 | GM_getValue: false,
36 | GM_setValue: false,
37 | GM_info: false,
38 | }
39 | };
40 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 gooyie
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # iqiyi-player-switch
2 |
3 | 爱奇艺flash播放器与html5播放器随意切换,改善html5播放器播放体验。
4 |
5 | ## 脚本管理器兼容
6 | `Greasemonkey`用不了(沙箱限制),`Tampermonkey`和`Violentmonkey`可正常使用。
7 |
8 | ## 安装
9 | * [GitHub](https://raw.githubusercontent.com/gooyie/userscript-iqiyi-player-switch/master/dist/iqiyi-player-switch.user.js)
10 | * [GreasyFork](https://greasyfork.org/zh-CN/scripts/28356-iqiyi-player-switch)
11 |
12 | ## 脚本实现的功能
13 | * 在脚本管理器上添加菜单命令用于播放器切换(默认启用html5播放器)
14 | * firefox 播放`f4v`
15 | * 和谐广告
16 | * 和谐非内嵌水印
17 | * 解除会员清晰度限制
18 | * [外链html5播放](https://github.com/gooyie/userscript-iqiyi-player-switch/issues/7)(不完善)
19 | * 快捷键
20 | * 可选的使用 WebSocket 加载视频
21 |
22 | ## 键盘快捷键
23 | 快捷键仿照`PotPlayer`和`youtube`
24 |
25 | | 按键 | 功能 |
26 | | ---- | ---- |
27 | | 空格 | 播放 / 暂停 |
28 | | enter | 全屏 / 退出全屏 |
29 | | ctrl + enter | 网页全屏 / 退出网页全屏 |
30 | | esc | 退出网页全屏 |
31 | | ↑ | 音量增加 5% |
32 | | ↓ | 音量减少 5% |
33 | | m | 静音 / 取消静音 |
34 | | d | 上一帧 |
35 | | f | 下一帧 |
36 | | ← | 步退5秒 |
37 | | → | 步进5秒 |
38 | | ctrl + ← | 步退30秒 |
39 | | ctrl + → | 步进30秒 |
40 | | shift + ← | 步退1分钟 |
41 | | shift + → | 步进1分钟 |
42 | | ctrl + alt + ← | 步退5分钟 |
43 | | ctrl + alt + → | 步进5分钟 |
44 | | 0 ~ 9 | 定位到视频的 x0%|
45 | | c | 播放速率提高 0.1 |
46 | | x | 播放速率降低 0.1 |
47 | | z | 正常/之前的播放速率 |
48 | | shift + p | 播放上一集 |
49 | | shift + n | 播放下一集 |
50 |
51 | ## 鼠标快捷键
52 |
53 | | 操作 | 条件 | 功能 |
54 | | ---- | ---- | ---- |
55 | | 单击左键 | 在播放区域 | 播放 / 暂停 |
56 | | 双击左键 | 在播放区域 | 全屏切换 |
57 | | ctrl + 双击左键 | 在播放区域 | 网页全屏切换 |
58 | | 滚动滚轮 | 全屏或网页全屏 | 音量调节 |
59 |
60 | ## WebSocket
61 | 在播放器的设置里添加了一个开关,默认为关闭状态。
62 |
63 | 
64 |
65 | 开启就使用 WebSocket 加载视频,可规避ISP的缓存避免被重定向出现 CORS 错误。
66 |
67 | 
68 |
69 | 不开启就是按照 iqiyi 的策略,即默认使用 Fetch 或 XHR(firefox),如果一直出错就尝试用 WebSocket。
70 |
71 | **注意:[有些地区的CDN还不支持 WebSocket,启用后会无法播放。](https://github.com/gooyie/userscript-iqiyi-player-switch/issues/21)**
72 |
73 | ## 切换播放器
74 | 菜单命令是要切换过去的播放器
75 |
76 | 
77 | 
78 |
--------------------------------------------------------------------------------
/dist/iqiyi-player-switch.user.js:
--------------------------------------------------------------------------------
1 |
2 | // ==UserScript==
3 | // @name iqiyi-player-switch
4 | // @namespace https://github.com/gooyie/userscript-iqiyi-player-switch
5 | // @homepageURL https://github.com/gooyie/userscript-iqiyi-player-switch
6 | // @supportURL https://github.com/gooyie/userscript-iqiyi-player-switch/issues
7 | // @updateURL https://raw.githubusercontent.com/gooyie/userscript-iqiyi-player-switch/master/dist/iqiyi-player-switch.user.js
8 | // @description 爱奇艺flash播放器与html5播放器随意切换,改善html5播放器播放体验。
9 | // @version 1.14.0
10 | // @compatible chrome >= 43
11 | // @compatible firefox >= 45
12 | // @compatible edge >= 15
13 | // @author gooyie
14 | // @license MIT License
15 | //
16 | // @include *://*.iqiyi.com/*
17 | // @include *://v.baidu.com/*
18 | // @include *://music.baidu.com/mv/*
19 | // @include *://www.zybus.com/*
20 | // @grant GM_registerMenuCommand
21 | // @grant GM_xmlhttpRequest
22 | // @grant GM_addStyle
23 | // @grant GM_getValue
24 | // @grant GM_setValue
25 | // @grant GM_info
26 | // @grant unsafeWindow
27 | // @connect qiyi.com
28 | // @run-at document-start
29 | // ==/UserScript==
30 |
31 | /******/ (function(modules) { // webpackBootstrap
32 | /******/ // The module cache
33 | /******/ var installedModules = {};
34 | /******/
35 | /******/ // The require function
36 | /******/ function __webpack_require__(moduleId) {
37 | /******/
38 | /******/ // Check if module is in cache
39 | /******/ if(installedModules[moduleId]) {
40 | /******/ return installedModules[moduleId].exports;
41 | /******/ }
42 | /******/ // Create a new module (and put it into the cache)
43 | /******/ var module = installedModules[moduleId] = {
44 | /******/ i: moduleId,
45 | /******/ l: false,
46 | /******/ exports: {}
47 | /******/ };
48 | /******/
49 | /******/ // Execute the module function
50 | /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
51 | /******/
52 | /******/ // Flag the module as loaded
53 | /******/ module.l = true;
54 | /******/
55 | /******/ // Return the exports of the module
56 | /******/ return module.exports;
57 | /******/ }
58 | /******/
59 | /******/
60 | /******/ // expose the modules object (__webpack_modules__)
61 | /******/ __webpack_require__.m = modules;
62 | /******/
63 | /******/ // expose the module cache
64 | /******/ __webpack_require__.c = installedModules;
65 | /******/
66 | /******/ // define getter function for harmony exports
67 | /******/ __webpack_require__.d = function(exports, name, getter) {
68 | /******/ if(!__webpack_require__.o(exports, name)) {
69 | /******/ Object.defineProperty(exports, name, {
70 | /******/ configurable: false,
71 | /******/ enumerable: true,
72 | /******/ get: getter
73 | /******/ });
74 | /******/ }
75 | /******/ };
76 | /******/
77 | /******/ // getDefaultExport function for compatibility with non-harmony modules
78 | /******/ __webpack_require__.n = function(module) {
79 | /******/ var getter = module && module.__esModule ?
80 | /******/ function getDefault() { return module['default']; } :
81 | /******/ function getModuleExports() { return module; };
82 | /******/ __webpack_require__.d(getter, 'a', getter);
83 | /******/ return getter;
84 | /******/ };
85 | /******/
86 | /******/ // Object.prototype.hasOwnProperty.call
87 | /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
88 | /******/
89 | /******/ // __webpack_public_path__
90 | /******/ __webpack_require__.p = "";
91 | /******/
92 | /******/ // Load entry module and return exports
93 | /******/ return __webpack_require__(__webpack_require__.s = 5);
94 | /******/ })
95 | /************************************************************************/
96 | /******/ ([
97 | /* 0 */
98 | /***/ (function(module, exports, __webpack_require__) {
99 |
100 | "use strict";
101 |
102 |
103 | Object.defineProperty(exports, "__esModule", {
104 | value: true
105 | });
106 |
107 | 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"); } }; }();
108 |
109 | 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; }; }();
110 |
111 | var _logger = __webpack_require__(1);
112 |
113 | var _logger2 = _interopRequireDefault(_logger);
114 |
115 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
116 |
117 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
118 |
119 | var Hooker = function () {
120 | function Hooker() {
121 | _classCallCheck(this, Hooker);
122 | }
123 |
124 | _createClass(Hooker, null, [{
125 | key: '_hookCall',
126 | value: function _hookCall(cb) {
127 | var call = Function.prototype.call;
128 | Function.prototype.call = function () {
129 | for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
130 | args[_key] = arguments[_key];
131 | }
132 |
133 | var ret = call.apply(this, args);
134 | try {
135 | if (args && cb(args)) {
136 | Function.prototype.call = call;
137 | cb = function cb() {};
138 | _logger2.default.info(`The native function call has been restored`);
139 | }
140 | } catch (err) {
141 | _logger2.default.error(err.stack);
142 | }
143 | return ret;
144 | };
145 | this._hookCall = null;
146 | }
147 | }, {
148 | key: '_isModuleCall',
149 | value: function _isModuleCall(args) {
150 | // module.exports, module, module.exports, require
151 | return args.length === 4 && args[1] && Object.getPrototypeOf(args[1]) === Object.prototype && args[1].hasOwnProperty('exports');
152 | }
153 | }, {
154 | key: '_hookModuleCall',
155 | value: function _hookModuleCall(cb, pred) {
156 | var _this = this;
157 |
158 | var callbacksMap = new Map([[pred, [cb]]]);
159 | this._hookCall(function (args) {
160 | if (!_this._isModuleCall(args)) return;
161 |
162 | var exports = args[1].exports;
163 | var _iteratorNormalCompletion = true;
164 | var _didIteratorError = false;
165 | var _iteratorError = undefined;
166 |
167 | try {
168 | for (var _iterator = callbacksMap[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
169 | var _ref = _step.value;
170 |
171 | var _ref2 = _slicedToArray(_ref, 2);
172 |
173 | var _pred = _ref2[0];
174 | var callbacks = _ref2[1];
175 |
176 | if (!_pred.apply(_this, [exports])) continue;
177 | callbacks.forEach(function (cb) {
178 | return cb(exports, args);
179 | });
180 | _this.keepalive || callbacksMap.delete(_pred);
181 | !callbacksMap.size && (_this._hookModuleCall = null);
182 | break;
183 | }
184 | } catch (err) {
185 | _didIteratorError = true;
186 | _iteratorError = err;
187 | } finally {
188 | try {
189 | if (!_iteratorNormalCompletion && _iterator.return) {
190 | _iterator.return();
191 | }
192 | } finally {
193 | if (_didIteratorError) {
194 | throw _iteratorError;
195 | }
196 | }
197 | }
198 |
199 | return !callbacksMap.size;
200 | });
201 |
202 | this._hookModuleCall = function (cb, pred) {
203 | if (callbacksMap.has(pred)) {
204 | callbacksMap.get(pred).push(cb);
205 | } else {
206 | callbacksMap.set(pred, [cb]);
207 | }
208 | };
209 | }
210 | }, {
211 | key: '_isJqueryModuleCall',
212 | value: function _isJqueryModuleCall(exports) {
213 | return exports.hasOwnProperty('fn') && exports.fn.hasOwnProperty('jquery');
214 | }
215 | }, {
216 | key: 'hookJquery',
217 | value: function hookJquery() {
218 | var cb = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : function () {};
219 |
220 | this._hookModuleCall(cb, this._isJqueryModuleCall);
221 | }
222 | }, {
223 | key: 'hookJqueryAjax',
224 | value: function hookJqueryAjax(cb) {
225 | this.hookJquery(function (exports) {
226 | var ajax = exports.ajax.bind(exports);
227 | exports.ajax = function (url) {
228 | var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
229 |
230 | if (typeof url === 'object') {
231 | var _ref3 = [url.url, url];
232 | url = _ref3[0];
233 | options = _ref3[1];
234 | }
235 | var isHijacked = cb(url, options);
236 | if (isHijacked) return;
237 | return ajax(url, options);
238 | };
239 | });
240 | }
241 | }, {
242 | key: '_isHttpModuleCall',
243 | value: function _isHttpModuleCall(exports) {
244 | return exports.hasOwnProperty('jsonp') && exports.hasOwnProperty('ajax');
245 | }
246 | }, {
247 | key: 'hookHttp',
248 | value: function hookHttp(cb) {
249 | this._hookModuleCall(cb, this._isHttpModuleCall);
250 | }
251 | }, {
252 | key: 'hookHttpJsonp',
253 | value: function hookHttpJsonp(cb) {
254 | this.hookHttp(function (exports) {
255 | var jsonp = exports.jsonp.bind(exports);
256 | exports.jsonp = function (options) {
257 | var isHijacked = cb(options);
258 | if (isHijacked) return;
259 | return jsonp(options);
260 | };
261 | });
262 | }
263 | }, {
264 | key: '_isLogoModuleCall',
265 | value: function _isLogoModuleCall(exports) {
266 | return 'function' === typeof exports && exports.prototype.hasOwnProperty('showLogo');
267 | }
268 | }, {
269 | key: 'hookLogo',
270 | value: function hookLogo(cb) {
271 | this._hookModuleCall(cb, this._isLogoModuleCall);
272 | }
273 | }, {
274 | key: '_isFullScreenModuleCall',
275 | value: function _isFullScreenModuleCall(exports) {
276 | return exports.__proto__ && exports.__proto__.hasOwnProperty('isFullScreen');
277 | }
278 | }, {
279 | key: 'hookFullScreen',
280 | value: function hookFullScreen(cb) {
281 | this._hookModuleCall(cb, this._isFullScreenModuleCall);
282 | }
283 | }, {
284 | key: '_isWebFullScreenModuleCall',
285 | value: function _isWebFullScreenModuleCall(exports) {
286 | return exports.__proto__ && exports.__proto__.hasOwnProperty('isWebFullScreen');
287 | }
288 | }, {
289 | key: 'hookWebFullScreen',
290 | value: function hookWebFullScreen(cb) {
291 | this._hookModuleCall(cb, this._isWebFullScreenModuleCall);
292 | }
293 | }, {
294 | key: 'hookWebFullScreenInit',
295 | value: function hookWebFullScreenInit(cb) {
296 | this.hookWebFullScreen(function (exports) {
297 | var init = exports.__proto__.init;
298 | exports.__proto__.init = function (wrapper, btn) {
299 | cb(this, wrapper, btn);
300 | init.apply(this, [wrapper, btn]);
301 | };
302 | });
303 | }
304 | }, {
305 | key: '_isPluginControlsModuleCall',
306 | value: function _isPluginControlsModuleCall(exports) {
307 | return 'function' === typeof exports && exports.prototype.hasOwnProperty('initFullScreen');
308 | }
309 | }, {
310 | key: 'hookPluginControls',
311 | value: function hookPluginControls(cb) {
312 | this._hookModuleCall(cb, this._isPluginControlsModuleCall);
313 | }
314 | }, {
315 | key: 'hookPluginControlsInit',
316 | value: function hookPluginControlsInit(cb) {
317 | this.hookPluginControls(function (exports) {
318 | var init = exports.prototype.init;
319 | exports.prototype.init = function () {
320 | cb(this);
321 | init.apply(this);
322 | };
323 | });
324 | }
325 | }, {
326 | key: 'hookInitFullScreen',
327 | value: function hookInitFullScreen(cb) {
328 | this.hookPluginControls(function (exports) {
329 | var initFullScreen = exports.prototype.initFullScreen;
330 | exports.prototype.initFullScreen = function () {
331 | cb(this);
332 | initFullScreen.apply(this);
333 | };
334 | });
335 | }
336 | }, {
337 | key: '_isCoreModuleCall',
338 | value: function _isCoreModuleCall(exports) {
339 | return 'function' === typeof exports && exports.prototype.hasOwnProperty('getdefaultvds') && exports.prototype.hasOwnProperty('getMovieInfo');
340 | }
341 | }, {
342 | key: 'hookCore',
343 | value: function hookCore(cb) {
344 | this._hookModuleCall(cb, this._isCoreModuleCall);
345 | }
346 | }, {
347 | key: '_isSkinBaseModuleCall',
348 | value: function _isSkinBaseModuleCall(exports) {
349 | return 'function' === typeof exports && exports.prototype.hasOwnProperty('_checkPlugin');
350 | }
351 | }, {
352 | key: 'hookSkinBase',
353 | value: function hookSkinBase(cb) {
354 | this._hookModuleCall(cb, this._isSkinBaseModuleCall);
355 | }
356 | }, {
357 | key: '_isPluginHotKeysModuleCall',
358 | value: function _isPluginHotKeysModuleCall(exports) {
359 | return 'function' === typeof exports && exports.prototype.hasOwnProperty('_keydown');
360 | }
361 | }, {
362 | key: 'hookPluginHotKeys',
363 | value: function hookPluginHotKeys(cb) {
364 | this._hookModuleCall(cb, this._isPluginHotKeysModuleCall);
365 | }
366 | }, {
367 | key: '_isFragmentModuleCall',
368 | value: function _isFragmentModuleCall(exports) {
369 | return 'function' === typeof exports && exports.prototype.hasOwnProperty('parseData');
370 | }
371 | }, {
372 | key: 'hookFragment',
373 | value: function hookFragment(cb) {
374 | this._hookModuleCall(cb, this._isFragmentModuleCall);
375 | }
376 | }, {
377 | key: 'hookParseData',
378 | value: function hookParseData(cb) {
379 | this.hookFragment(function (exports) {
380 | var parseData = exports.prototype.parseData;
381 | exports.prototype.parseData = function () {
382 | for (var _len2 = arguments.length, args = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
383 | args[_key2] = arguments[_key2];
384 | }
385 |
386 | parseData.apply(this, args);
387 | cb(this);
388 | };
389 | });
390 | }
391 | }, {
392 | key: '_isUserModuleCall',
393 | value: function _isUserModuleCall(exports) {
394 | return exports.__proto__ && exports.__proto__.hasOwnProperty('isVip');
395 | }
396 | }, {
397 | key: 'hookUser',
398 | value: function hookUser(cb) {
399 | this._hookModuleCall(cb, this._isUserModuleCall);
400 | }
401 | }, {
402 | key: '_isShowRequestModuleCall',
403 | value: function _isShowRequestModuleCall(exports) {
404 | return 'function' === typeof exports && exports.compressRequestKey && exports.prototype.hasOwnProperty('request');
405 | }
406 | }, {
407 | key: 'hookShowRequest',
408 | value: function hookShowRequest(cb) {
409 | this._hookModuleCall(cb, this._isShowRequestModuleCall);
410 | }
411 | }, {
412 | key: '_isDefaultSkinModuleCall',
413 | value: function _isDefaultSkinModuleCall(exports) {
414 | return 'function' === typeof exports && exports.prototype.hasOwnProperty('_initDBClicks');
415 | }
416 | }, {
417 | key: 'hookDefaultSkin',
418 | value: function hookDefaultSkin(cb) {
419 | this._hookModuleCall(cb, this._isDefaultSkinModuleCall);
420 | }
421 | }, {
422 | key: '_isConfigModuleCall',
423 | value: function _isConfigModuleCall(exports) {
424 | return exports.loadType && exports.dispatchCfg;
425 | }
426 | }, {
427 | key: 'hookConfig',
428 | value: function hookConfig(cb) {
429 | this._hookModuleCall(cb, this._isConfigModuleCall);
430 | }
431 | }]);
432 |
433 | return Hooker;
434 | }();
435 |
436 | Hooker.keepalive = false;
437 |
438 | exports.default = Hooker;
439 |
440 | /***/ }),
441 | /* 1 */
442 | /***/ (function(module, exports, __webpack_require__) {
443 |
444 | "use strict";
445 |
446 |
447 | Object.defineProperty(exports, "__esModule", {
448 | value: true
449 | });
450 |
451 | 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; }; }();
452 |
453 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
454 |
455 | /* eslint-disable no-console */
456 | var Logger = function () {
457 | function Logger(tag) {
458 | _classCallCheck(this, Logger);
459 |
460 | this._tag = tag;
461 | }
462 |
463 | _createClass(Logger, [{
464 | key: 'log',
465 | value: function log() {
466 | var _console;
467 |
468 | for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
469 | args[_key] = arguments[_key];
470 | }
471 |
472 | (_console = console).log.apply(_console, [this.tag + args.shift()].concat(args));
473 | }
474 | }, {
475 | key: 'info',
476 | value: function info() {
477 | var _console2;
478 |
479 | for (var _len2 = arguments.length, args = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
480 | args[_key2] = arguments[_key2];
481 | }
482 |
483 | (_console2 = console).log.apply(_console2, ['%c' + this.tag + '%c' + args.shift(), 'color: green; font-weight: bolder', 'color: blue'].concat(args));
484 | }
485 | }, {
486 | key: 'debug',
487 | value: function debug() {
488 | var _console3;
489 |
490 | for (var _len3 = arguments.length, args = Array(_len3), _key3 = 0; _key3 < _len3; _key3++) {
491 | args[_key3] = arguments[_key3];
492 | }
493 |
494 | (_console3 = console).debug.apply(_console3, [this.tag + args.shift()].concat(args));
495 | }
496 | }, {
497 | key: 'warn',
498 | value: function warn() {
499 | var _console4;
500 |
501 | for (var _len4 = arguments.length, args = Array(_len4), _key4 = 0; _key4 < _len4; _key4++) {
502 | args[_key4] = arguments[_key4];
503 | }
504 |
505 | (_console4 = console).warn.apply(_console4, [this.tag + args.shift()].concat(args));
506 | }
507 | }, {
508 | key: 'error',
509 | value: function error() {
510 | var _console5;
511 |
512 | for (var _len5 = arguments.length, args = Array(_len5), _key5 = 0; _key5 < _len5; _key5++) {
513 | args[_key5] = arguments[_key5];
514 | }
515 |
516 | (_console5 = console).error.apply(_console5, [this.tag + args.shift()].concat(args));
517 | }
518 | }, {
519 | key: 'tag',
520 | get: function get() {
521 | return this._tag;
522 | }
523 | }]);
524 |
525 | return Logger;
526 | }();
527 |
528 | exports.default = new Logger(`[${GM_info.script.name}]`);
529 |
530 | /***/ }),
531 | /* 2 */
532 | /***/ (function(module, exports, __webpack_require__) {
533 |
534 | "use strict";
535 |
536 |
537 | Object.defineProperty(exports, "__esModule", {
538 | value: true
539 | });
540 |
541 | 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; }; }();
542 |
543 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
544 |
545 | var Detector = function () {
546 | function Detector() {
547 | _classCallCheck(this, Detector);
548 | }
549 |
550 | _createClass(Detector, null, [{
551 | key: 'isSupportHtml5',
552 | value: function isSupportHtml5() {
553 | var v = document.createElement('video');
554 | return !!(v.canPlayType('audio/mp4; codecs="mp4a.40.2"') && v.canPlayType('video/mp4; codecs="avc1.640029"') && v.canPlayType('video/mp4; codecs="avc1.640029, mp4a.40.2"'));
555 | }
556 | }, {
557 | key: 'isSupportVms',
558 | value: function isSupportVms() {
559 | return !!(window.MediaSource && window.URL && window.WebSocket && window.ReadableStream && (window.RTCSessionDescription || window.webkitRTCSessionDescription) && (window.RTCPeerConnection || window.webkitRTCPeerConnection) && (window.RTCIceCandidate || window.webkitRTCIceCandidate));
560 | }
561 | }, {
562 | key: 'isSupportM3u8',
563 | value: function isSupportM3u8() {
564 | var v = document.createElement('video');
565 | return !!(v.canPlayType('application/x-mpegurl') && v.canPlayType('application/vnd.apple.mpegurl'));
566 | }
567 | }, {
568 | key: 'isChrome',
569 | value: function isChrome() {
570 | return (/chrome/i.test(navigator.userAgent)
571 | );
572 | }
573 | }, {
574 | key: 'isFirefox',
575 | value: function isFirefox() {
576 | return (/firefox/i.test(navigator.userAgent)
577 | );
578 | }
579 | }, {
580 | key: 'isEdge',
581 | value: function isEdge() {
582 | return (/edge/i.test(navigator.userAgent)
583 | );
584 | }
585 | }, {
586 | key: 'isInIFrame',
587 | value: function isInIFrame() {
588 | return window.top !== window.self;
589 | }
590 | }, {
591 | key: 'isOutsite',
592 | value: function isOutsite() {
593 | return !/\.iqiyi\.com$/.test(location.host);
594 | }
595 | }, {
596 | key: 'isOutsideLink',
597 | value: function isOutsideLink() {
598 | return location.hash === '#outsidelink';
599 | }
600 | }, {
601 | key: 'hasFlashPlugin',
602 | value: function hasFlashPlugin() {
603 | var plugins = unsafeWindow.navigator.plugins;
604 | return !!(plugins['Shockwave Flash'] && plugins['Shockwave Flash'].description);
605 | }
606 | }]);
607 |
608 | return Detector;
609 | }();
610 |
611 | exports.default = Detector;
612 |
613 | /***/ }),
614 | /* 3 */
615 | /***/ (function(module, exports, __webpack_require__) {
616 |
617 | "use strict";
618 |
619 |
620 | Object.defineProperty(exports, "__esModule", {
621 | value: true
622 | });
623 |
624 | 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; }; }();
625 |
626 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
627 |
628 | var Faker = function () {
629 | function Faker() {
630 | _classCallCheck(this, Faker);
631 | }
632 |
633 | _createClass(Faker, null, [{
634 | key: 'fakeMacPlatform',
635 | value: function fakeMacPlatform() {
636 | var PLAFORM_MAC = 'mac';
637 | Object.defineProperty(unsafeWindow.navigator, 'platform', { get: function get() {
638 | return PLAFORM_MAC;
639 | } });
640 | }
641 | }, {
642 | key: 'fakeSafari',
643 | value: function fakeSafari() {
644 | var UA_SAFARY = 'safari';
645 | Object.defineProperty(unsafeWindow.navigator, 'userAgent', { get: function get() {
646 | return UA_SAFARY;
647 | } });
648 | }
649 | }, {
650 | key: 'fakeChrome',
651 | value: function fakeChrome() {
652 | var ver = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
653 |
654 | var UA_CHROME = `Chrome/${ver}`;
655 | Object.defineProperty(unsafeWindow.navigator, 'userAgent', { get: function get() {
656 | return UA_CHROME;
657 | } });
658 | }
659 | }, {
660 | key: 'fakeFlashPlugin',
661 | value: function fakeFlashPlugin() {
662 | var plugin = {
663 | description: 'Shockwave Flash 26.0 r0',
664 | filename: 'pepflashplayer64_26_0_0_131.dll',
665 | length: 0,
666 | name: 'Shockwave Flash'
667 | };
668 |
669 | Reflect.setPrototypeOf(plugin, Plugin.prototype);
670 | unsafeWindow.navigator.plugins['Shockwave Flash'] = plugin;
671 | }
672 | }]);
673 |
674 | return Faker;
675 | }();
676 |
677 | exports.default = Faker;
678 |
679 | /***/ }),
680 | /* 4 */
681 | /***/ (function(module, exports) {
682 |
683 | var g;
684 |
685 | // This works in non-strict mode
686 | g = (function() {
687 | return this;
688 | })();
689 |
690 | try {
691 | // This works if eval is allowed (see CSP)
692 | g = g || Function("return this")() || (1,eval)("this");
693 | } catch(e) {
694 | // This works if the window reference is available
695 | if(typeof window === "object")
696 | g = window;
697 | }
698 |
699 | // g can still be undefined, but nothing to do about it...
700 | // We return undefined, instead of nothing here, so it's
701 | // easier to handle this case. if(!global) { ...}
702 |
703 | module.exports = g;
704 |
705 |
706 | /***/ }),
707 | /* 5 */
708 | /***/ (function(module, exports, __webpack_require__) {
709 |
710 | "use strict";
711 |
712 |
713 | 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"); } }; }();
714 |
715 | var _logger = __webpack_require__(1);
716 |
717 | var _logger2 = _interopRequireDefault(_logger);
718 |
719 | var _cookies = __webpack_require__(6);
720 |
721 | var _cookies2 = _interopRequireDefault(_cookies);
722 |
723 | var _detector = __webpack_require__(2);
724 |
725 | var _detector2 = _interopRequireDefault(_detector);
726 |
727 | var _faker = __webpack_require__(3);
728 |
729 | var _faker2 = _interopRequireDefault(_faker);
730 |
731 | var _outsite = __webpack_require__(7);
732 |
733 | var _patch = __webpack_require__(12);
734 |
735 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
736 |
737 | var PLAYER_TYPE = {
738 | Html5VOD: 'h5_VOD',
739 | FlashVOD: 'flash_VOD'
740 | };
741 |
742 | function forceHtml5() {
743 | _cookies2.default.set('player_forcedType', PLAYER_TYPE.Html5VOD, { domain: '.iqiyi.com' });
744 | _logger2.default.info(`The 'player_forcedType' cookie has been set as '${PLAYER_TYPE.Html5VOD}'`);
745 | }
746 |
747 | function forceFlash() {
748 | _cookies2.default.set('player_forcedType', PLAYER_TYPE.FlashVOD, { domain: '.iqiyi.com' });
749 | _logger2.default.info(`The 'player_forcedType' cookie has been set as '${PLAYER_TYPE.FlashVOD}'`);
750 | }
751 |
752 | function clean() {
753 | _cookies2.default.remove('player_forcedType', { domain: '.iqiyi.com' });
754 | _logger2.default.info(`Removed the 'player_forcedType' cookie`);
755 | }
756 |
757 | function switchTo(type) {
758 | _logger2.default.info(`Switching to ${type} ...`);
759 | GM_setValue('player_forcedType', type);
760 | document.location.reload();
761 | }
762 |
763 | function registerMenu() {
764 | var MENU_NAME = {
765 | HTML5: 'HTML5播放器',
766 | FLASH: 'Flash播放器'
767 | };
768 |
769 | var currType = GM_getValue('player_forcedType', PLAYER_TYPE.Html5VOD); // 默认为Html5播放器,免去切换。
770 |
771 | var _ref = currType === PLAYER_TYPE.Html5VOD ? [PLAYER_TYPE.FlashVOD, MENU_NAME.FLASH] : [PLAYER_TYPE.Html5VOD, MENU_NAME.HTML5],
772 | _ref2 = _slicedToArray(_ref, 2),
773 | type = _ref2[0],
774 | name = _ref2[1];
775 |
776 | GM_registerMenuCommand(name, function () {
777 | return switchTo(type);
778 | }, null);
779 | _logger2.default.info(`Registered the menu.`);
780 | }
781 |
782 | function mustKeepHooking() {
783 | return location.search.includes('list'); // https://github.com/gooyie/userscript-iqiyi-player-switch/issues/15
784 | }
785 |
786 | //=============================================================================
787 |
788 | registerMenu();
789 |
790 | var currType = GM_getValue('player_forcedType', PLAYER_TYPE.Html5VOD);
791 | if (currType === PLAYER_TYPE.Html5VOD) {
792 | if (_detector2.default.isSupportHtml5()) {
793 | if (_detector2.default.isOutsite()) {
794 | (0, _outsite.replaceFlash)();
795 | } else {
796 | forceHtml5();
797 |
798 | if (_detector2.default.isFirefox()) {
799 | // Fake Chrome with a version number less than 43
800 | // to use the data engine to play videos better than HD and to use the XHR loader
801 | // because Firefox has not yet implemented ReadableStream to support the Fetch loader.
802 | _faker2.default.fakeChrome(42);
803 | }
804 |
805 | if (mustKeepHooking()) {
806 | _patch.keepHookingPatch.install();
807 | }
808 | _patch.adsPatch.install();
809 | _patch.controlsPatch.install();
810 | _patch.watermarksPatch.install();
811 | _patch.vipPatch.install();
812 | _patch.keyShortcutsPatch.install();
813 | _patch.mouseShortcutsPatch.install();
814 | _patch.useWebSocketLoaderPatch.install();
815 |
816 | if (_detector2.default.isInIFrame() && _detector2.default.isOutsideLink()) {
817 | (0, _outsite.adaptIframe)();
818 | }
819 | }
820 | } else {
821 | alert('╮(╯▽╰)╭ 你的浏览器播放不了html5视频~~~~');
822 | }
823 | } else {
824 | forceFlash();
825 | }
826 |
827 | window.addEventListener('unload', function () {
828 | return clean();
829 | });
830 |
831 | /***/ }),
832 | /* 6 */
833 | /***/ (function(module, exports, __webpack_require__) {
834 |
835 | "use strict";
836 |
837 |
838 | Object.defineProperty(exports, "__esModule", {
839 | value: true
840 | });
841 |
842 | 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; }; }();
843 |
844 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
845 |
846 | var Cookies = function () {
847 | function Cookies() {
848 | _classCallCheck(this, Cookies);
849 | }
850 |
851 | _createClass(Cookies, null, [{
852 | key: 'get',
853 | value: function get(key) {
854 | var value = void 0;
855 | if (new RegExp('^[^\\x00-\\x20\\x7f\\(\\)<>@,;:\\\\\\"\\[\\]\\?=\\{\\}\\/\\u0080-\\uffff]+$').test(key)) {
856 | // eslint-disable-line no-control-regex
857 | var re = new RegExp('(^| )' + key + '=([^;]*)(;|$)');
858 | var rs = re.exec(document.cookie);
859 | value = rs ? rs[2] : '';
860 | }
861 | return value ? decodeURIComponent(value) : '';
862 | }
863 | }, {
864 | key: 'set',
865 | value: function set(k, v) {
866 | var o = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
867 |
868 | var n = o.expires;
869 | if ('number' == typeof o.expires) {
870 | n = new Date();
871 | n.setTime(n.getTime() + o.expires);
872 | }
873 | var key = k;
874 | var value = encodeURIComponent(v);
875 | var path = o.path ? '; path=' + o.path : '';
876 | var expires = n ? '; expires=' + n.toGMTString() : '';
877 | var domain = o.domain ? '; domain=' + o.domain : '';
878 | document.cookie = `${key}=${value}${path}${expires}${domain}`;
879 | }
880 | }, {
881 | key: 'remove',
882 | value: function remove(k) {
883 | var o = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
884 |
885 | o.expires = new Date(0);
886 | this.set(k, '', o);
887 | }
888 | }]);
889 |
890 | return Cookies;
891 | }();
892 |
893 | exports.default = Cookies;
894 |
895 | /***/ }),
896 | /* 7 */
897 | /***/ (function(module, exports, __webpack_require__) {
898 |
899 | "use strict";
900 |
901 |
902 | Object.defineProperty(exports, "__esModule", {
903 | value: true
904 | });
905 | exports.adaptIframe = exports.replaceFlash = undefined;
906 |
907 | var _regenerator = __webpack_require__(8);
908 |
909 | var _regenerator2 = _interopRequireDefault(_regenerator);
910 |
911 | var embedSrc = function () {
912 | var _ref2 = _asyncToGenerator( /*#__PURE__*/_regenerator2.default.mark(function _callee(targetNode, _ref) {
913 | var tvid = _ref.tvid,
914 | vid = _ref.vid;
915 | var url;
916 | return _regenerator2.default.wrap(function _callee$(_context) {
917 | while (1) {
918 | switch (_context.prev = _context.next) {
919 | case 0:
920 | targetNode.innerHTML = `
正在获取视频源...
`;
921 |
922 | _context.prev = 1;
923 | _context.next = 4;
924 | return (0, _utils.getVideoUrl)(tvid, vid);
925 |
926 | case 4:
927 | url = _context.sent;
928 |
929 | _logger2.default.info('source url: %s', url);
930 | targetNode.innerHTML = ``;
931 | _context.next = 12;
932 | break;
933 |
934 | case 9:
935 | _context.prev = 9;
936 | _context.t0 = _context['catch'](1);
937 |
938 | targetNode.innerHTML = `获取视频源出错!
${_context.t0.message}
`;
939 |
940 | case 12:
941 | case 'end':
942 | return _context.stop();
943 | }
944 | }
945 | }, _callee, this, [[1, 9]]);
946 | }));
947 |
948 | return function embedSrc(_x, _x2) {
949 | return _ref2.apply(this, arguments);
950 | };
951 | }();
952 |
953 | var _logger = __webpack_require__(1);
954 |
955 | var _logger2 = _interopRequireDefault(_logger);
956 |
957 | var _hooker = __webpack_require__(0);
958 |
959 | var _hooker2 = _interopRequireDefault(_hooker);
960 |
961 | var _faker = __webpack_require__(3);
962 |
963 | var _faker2 = _interopRequireDefault(_faker);
964 |
965 | var _detector = __webpack_require__(2);
966 |
967 | var _detector2 = _interopRequireDefault(_detector);
968 |
969 | var _utils = __webpack_require__(11);
970 |
971 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
972 |
973 | function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; }
974 |
975 | function replaceFlash() {
976 | if (!_detector2.default.hasFlashPlugin()) _faker2.default.fakeFlashPlugin();
977 |
978 | var observer = new MutationObserver(function (records, self) {
979 | var _iteratorNormalCompletion = true;
980 | var _didIteratorError = false;
981 | var _iteratorError = undefined;
982 |
983 | try {
984 | for (var _iterator = records[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
985 | var record = _step.value;
986 |
987 | if (record.type !== 'childList' || !record.addedNodes) continue;
988 |
989 | var _iteratorNormalCompletion2 = true;
990 | var _didIteratorError2 = false;
991 | var _iteratorError2 = undefined;
992 |
993 | try {
994 | for (var _iterator2 = record.addedNodes[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
995 | var node = _step2.value;
996 |
997 | if (node.nodeName !== 'OBJECT' && node.nodeName !== 'EMBED') continue;
998 | _logger2.default.info('found node', node);
999 |
1000 | var text = node.outerHTML;
1001 | var vid = (0, _utils.findVid)(text);
1002 | var tvid = (0, _utils.findTvid)(text);
1003 |
1004 | if (tvid && vid) {
1005 | _logger2.default.info('found tvid: %s, vid: %s', tvid, vid);
1006 | embedSrc(node.parentNode, { tvid, vid });
1007 | self.disconnect();
1008 | _logger2.default.info('stoped observation');
1009 | }
1010 | }
1011 | } catch (err) {
1012 | _didIteratorError2 = true;
1013 | _iteratorError2 = err;
1014 | } finally {
1015 | try {
1016 | if (!_iteratorNormalCompletion2 && _iterator2.return) {
1017 | _iterator2.return();
1018 | }
1019 | } finally {
1020 | if (_didIteratorError2) {
1021 | throw _iteratorError2;
1022 | }
1023 | }
1024 | }
1025 | }
1026 | } catch (err) {
1027 | _didIteratorError = true;
1028 | _iteratorError = err;
1029 | } finally {
1030 | try {
1031 | if (!_iteratorNormalCompletion && _iterator.return) {
1032 | _iterator.return();
1033 | }
1034 | } finally {
1035 | if (_didIteratorError) {
1036 | throw _iteratorError;
1037 | }
1038 | }
1039 | }
1040 | });
1041 |
1042 | observer.observe(document.body || document.documentElement, { subtree: true, childList: true });
1043 | _logger2.default.info('started observation');
1044 | }
1045 |
1046 | function adaptIframe() {
1047 | var style = `
1048 | body[class|="qypage"] {
1049 | overflow: hidden !important;
1050 | background: #000 !important;
1051 | visibility: hidden;
1052 | }
1053 |
1054 | .mod-func {
1055 | display: none !important;
1056 | }
1057 |
1058 | .${GM_info.script.name}.info {
1059 | width: 20em;
1060 | height: 5em;
1061 | position: absolute;
1062 | top: 0;
1063 | bottom: 0;
1064 | left: 0;
1065 | right: 0;
1066 | margin: auto;
1067 | text-align: center;
1068 | line-height: 5em;
1069 | font-size: 1em;
1070 | color: #ccc;
1071 | }
1072 |
1073 | .${GM_info.script.name}.error {
1074 | height: 3em;
1075 | position: absolute;
1076 | top: 0;
1077 | bottom: 0;
1078 | left: 0;
1079 | right: 0;
1080 | margin: auto;
1081 | text-align: center;
1082 | font-size: 1em;
1083 | color: #c00;
1084 | }
1085 | `;
1086 |
1087 | GM_addStyle(style);
1088 |
1089 | _hooker2.default.hookWebFullScreen(function (exports) {
1090 | var init = exports.__proto__.init;
1091 | exports.__proto__.init = function (wrapper, btn) {
1092 | init.apply(this, [wrapper, btn]);
1093 | this.enter();
1094 |
1095 | btn[0].style.display = 'none';
1096 | document.body.style.visibility = 'visible';
1097 | };
1098 |
1099 | exports.__proto__.exit = function () {};
1100 | });
1101 |
1102 | _hooker2.default.hookCore(function (exports) {
1103 | exports.prototype.hasNextVideo = function () {
1104 | return null;
1105 | };
1106 | });
1107 | }
1108 |
1109 | exports.replaceFlash = replaceFlash;
1110 | exports.adaptIframe = adaptIframe;
1111 |
1112 | /***/ }),
1113 | /* 8 */
1114 | /***/ (function(module, exports, __webpack_require__) {
1115 |
1116 | module.exports = __webpack_require__(9);
1117 |
1118 |
1119 | /***/ }),
1120 | /* 9 */
1121 | /***/ (function(module, exports, __webpack_require__) {
1122 |
1123 | /* WEBPACK VAR INJECTION */(function(global) {// This method of obtaining a reference to the global object needs to be
1124 | // kept identical to the way it is obtained in runtime.js
1125 | var g =
1126 | typeof global === "object" ? global :
1127 | typeof window === "object" ? window :
1128 | typeof self === "object" ? self : this;
1129 |
1130 | // Use `getOwnPropertyNames` because not all browsers support calling
1131 | // `hasOwnProperty` on the global `self` object in a worker. See #183.
1132 | var hadRuntime = g.regeneratorRuntime &&
1133 | Object.getOwnPropertyNames(g).indexOf("regeneratorRuntime") >= 0;
1134 |
1135 | // Save the old regeneratorRuntime in case it needs to be restored later.
1136 | var oldRuntime = hadRuntime && g.regeneratorRuntime;
1137 |
1138 | // Force reevalutation of runtime.js.
1139 | g.regeneratorRuntime = undefined;
1140 |
1141 | module.exports = __webpack_require__(10);
1142 |
1143 | if (hadRuntime) {
1144 | // Restore the original runtime.
1145 | g.regeneratorRuntime = oldRuntime;
1146 | } else {
1147 | // Remove the global property added by runtime.js.
1148 | try {
1149 | delete g.regeneratorRuntime;
1150 | } catch(e) {
1151 | g.regeneratorRuntime = undefined;
1152 | }
1153 | }
1154 |
1155 | /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(4)))
1156 |
1157 | /***/ }),
1158 | /* 10 */
1159 | /***/ (function(module, exports, __webpack_require__) {
1160 |
1161 | /* WEBPACK VAR INJECTION */(function(global) {/**
1162 | * Copyright (c) 2014, Facebook, Inc.
1163 | * All rights reserved.
1164 | *
1165 | * This source code is licensed under the BSD-style license found in the
1166 | * https://raw.github.com/facebook/regenerator/master/LICENSE file. An
1167 | * additional grant of patent rights can be found in the PATENTS file in
1168 | * the same directory.
1169 | */
1170 |
1171 | !(function(global) {
1172 | "use strict";
1173 |
1174 | var Op = Object.prototype;
1175 | var hasOwn = Op.hasOwnProperty;
1176 | var undefined; // More compressible than void 0.
1177 | var $Symbol = typeof Symbol === "function" ? Symbol : {};
1178 | var iteratorSymbol = $Symbol.iterator || "@@iterator";
1179 | var asyncIteratorSymbol = $Symbol.asyncIterator || "@@asyncIterator";
1180 | var toStringTagSymbol = $Symbol.toStringTag || "@@toStringTag";
1181 |
1182 | var inModule = typeof module === "object";
1183 | var runtime = global.regeneratorRuntime;
1184 | if (runtime) {
1185 | if (inModule) {
1186 | // If regeneratorRuntime is defined globally and we're in a module,
1187 | // make the exports object identical to regeneratorRuntime.
1188 | module.exports = runtime;
1189 | }
1190 | // Don't bother evaluating the rest of this file if the runtime was
1191 | // already defined globally.
1192 | return;
1193 | }
1194 |
1195 | // Define the runtime globally (as expected by generated code) as either
1196 | // module.exports (if we're in a module) or a new, empty object.
1197 | runtime = global.regeneratorRuntime = inModule ? module.exports : {};
1198 |
1199 | function wrap(innerFn, outerFn, self, tryLocsList) {
1200 | // If outerFn provided and outerFn.prototype is a Generator, then outerFn.prototype instanceof Generator.
1201 | var protoGenerator = outerFn && outerFn.prototype instanceof Generator ? outerFn : Generator;
1202 | var generator = Object.create(protoGenerator.prototype);
1203 | var context = new Context(tryLocsList || []);
1204 |
1205 | // The ._invoke method unifies the implementations of the .next,
1206 | // .throw, and .return methods.
1207 | generator._invoke = makeInvokeMethod(innerFn, self, context);
1208 |
1209 | return generator;
1210 | }
1211 | runtime.wrap = wrap;
1212 |
1213 | // Try/catch helper to minimize deoptimizations. Returns a completion
1214 | // record like context.tryEntries[i].completion. This interface could
1215 | // have been (and was previously) designed to take a closure to be
1216 | // invoked without arguments, but in all the cases we care about we
1217 | // already have an existing method we want to call, so there's no need
1218 | // to create a new function object. We can even get away with assuming
1219 | // the method takes exactly one argument, since that happens to be true
1220 | // in every case, so we don't have to touch the arguments object. The
1221 | // only additional allocation required is the completion record, which
1222 | // has a stable shape and so hopefully should be cheap to allocate.
1223 | function tryCatch(fn, obj, arg) {
1224 | try {
1225 | return { type: "normal", arg: fn.call(obj, arg) };
1226 | } catch (err) {
1227 | return { type: "throw", arg: err };
1228 | }
1229 | }
1230 |
1231 | var GenStateSuspendedStart = "suspendedStart";
1232 | var GenStateSuspendedYield = "suspendedYield";
1233 | var GenStateExecuting = "executing";
1234 | var GenStateCompleted = "completed";
1235 |
1236 | // Returning this object from the innerFn has the same effect as
1237 | // breaking out of the dispatch switch statement.
1238 | var ContinueSentinel = {};
1239 |
1240 | // Dummy constructor functions that we use as the .constructor and
1241 | // .constructor.prototype properties for functions that return Generator
1242 | // objects. For full spec compliance, you may wish to configure your
1243 | // minifier not to mangle the names of these two functions.
1244 | function Generator() {}
1245 | function GeneratorFunction() {}
1246 | function GeneratorFunctionPrototype() {}
1247 |
1248 | // This is a polyfill for %IteratorPrototype% for environments that
1249 | // don't natively support it.
1250 | var IteratorPrototype = {};
1251 | IteratorPrototype[iteratorSymbol] = function () {
1252 | return this;
1253 | };
1254 |
1255 | var getProto = Object.getPrototypeOf;
1256 | var NativeIteratorPrototype = getProto && getProto(getProto(values([])));
1257 | if (NativeIteratorPrototype &&
1258 | NativeIteratorPrototype !== Op &&
1259 | hasOwn.call(NativeIteratorPrototype, iteratorSymbol)) {
1260 | // This environment has a native %IteratorPrototype%; use it instead
1261 | // of the polyfill.
1262 | IteratorPrototype = NativeIteratorPrototype;
1263 | }
1264 |
1265 | var Gp = GeneratorFunctionPrototype.prototype =
1266 | Generator.prototype = Object.create(IteratorPrototype);
1267 | GeneratorFunction.prototype = Gp.constructor = GeneratorFunctionPrototype;
1268 | GeneratorFunctionPrototype.constructor = GeneratorFunction;
1269 | GeneratorFunctionPrototype[toStringTagSymbol] =
1270 | GeneratorFunction.displayName = "GeneratorFunction";
1271 |
1272 | // Helper for defining the .next, .throw, and .return methods of the
1273 | // Iterator interface in terms of a single ._invoke method.
1274 | function defineIteratorMethods(prototype) {
1275 | ["next", "throw", "return"].forEach(function(method) {
1276 | prototype[method] = function(arg) {
1277 | return this._invoke(method, arg);
1278 | };
1279 | });
1280 | }
1281 |
1282 | runtime.isGeneratorFunction = function(genFun) {
1283 | var ctor = typeof genFun === "function" && genFun.constructor;
1284 | return ctor
1285 | ? ctor === GeneratorFunction ||
1286 | // For the native GeneratorFunction constructor, the best we can
1287 | // do is to check its .name property.
1288 | (ctor.displayName || ctor.name) === "GeneratorFunction"
1289 | : false;
1290 | };
1291 |
1292 | runtime.mark = function(genFun) {
1293 | if (Object.setPrototypeOf) {
1294 | Object.setPrototypeOf(genFun, GeneratorFunctionPrototype);
1295 | } else {
1296 | genFun.__proto__ = GeneratorFunctionPrototype;
1297 | if (!(toStringTagSymbol in genFun)) {
1298 | genFun[toStringTagSymbol] = "GeneratorFunction";
1299 | }
1300 | }
1301 | genFun.prototype = Object.create(Gp);
1302 | return genFun;
1303 | };
1304 |
1305 | // Within the body of any async function, `await x` is transformed to
1306 | // `yield regeneratorRuntime.awrap(x)`, so that the runtime can test
1307 | // `hasOwn.call(value, "__await")` to determine if the yielded value is
1308 | // meant to be awaited.
1309 | runtime.awrap = function(arg) {
1310 | return { __await: arg };
1311 | };
1312 |
1313 | function AsyncIterator(generator) {
1314 | function invoke(method, arg, resolve, reject) {
1315 | var record = tryCatch(generator[method], generator, arg);
1316 | if (record.type === "throw") {
1317 | reject(record.arg);
1318 | } else {
1319 | var result = record.arg;
1320 | var value = result.value;
1321 | if (value &&
1322 | typeof value === "object" &&
1323 | hasOwn.call(value, "__await")) {
1324 | return Promise.resolve(value.__await).then(function(value) {
1325 | invoke("next", value, resolve, reject);
1326 | }, function(err) {
1327 | invoke("throw", err, resolve, reject);
1328 | });
1329 | }
1330 |
1331 | return Promise.resolve(value).then(function(unwrapped) {
1332 | // When a yielded Promise is resolved, its final value becomes
1333 | // the .value of the Promise<{value,done}> result for the
1334 | // current iteration. If the Promise is rejected, however, the
1335 | // result for this iteration will be rejected with the same
1336 | // reason. Note that rejections of yielded Promises are not
1337 | // thrown back into the generator function, as is the case
1338 | // when an awaited Promise is rejected. This difference in
1339 | // behavior between yield and await is important, because it
1340 | // allows the consumer to decide what to do with the yielded
1341 | // rejection (swallow it and continue, manually .throw it back
1342 | // into the generator, abandon iteration, whatever). With
1343 | // await, by contrast, there is no opportunity to examine the
1344 | // rejection reason outside the generator function, so the
1345 | // only option is to throw it from the await expression, and
1346 | // let the generator function handle the exception.
1347 | result.value = unwrapped;
1348 | resolve(result);
1349 | }, reject);
1350 | }
1351 | }
1352 |
1353 | if (typeof global.process === "object" && global.process.domain) {
1354 | invoke = global.process.domain.bind(invoke);
1355 | }
1356 |
1357 | var previousPromise;
1358 |
1359 | function enqueue(method, arg) {
1360 | function callInvokeWithMethodAndArg() {
1361 | return new Promise(function(resolve, reject) {
1362 | invoke(method, arg, resolve, reject);
1363 | });
1364 | }
1365 |
1366 | return previousPromise =
1367 | // If enqueue has been called before, then we want to wait until
1368 | // all previous Promises have been resolved before calling invoke,
1369 | // so that results are always delivered in the correct order. If
1370 | // enqueue has not been called before, then it is important to
1371 | // call invoke immediately, without waiting on a callback to fire,
1372 | // so that the async generator function has the opportunity to do
1373 | // any necessary setup in a predictable way. This predictability
1374 | // is why the Promise constructor synchronously invokes its
1375 | // executor callback, and why async functions synchronously
1376 | // execute code before the first await. Since we implement simple
1377 | // async functions in terms of async generators, it is especially
1378 | // important to get this right, even though it requires care.
1379 | previousPromise ? previousPromise.then(
1380 | callInvokeWithMethodAndArg,
1381 | // Avoid propagating failures to Promises returned by later
1382 | // invocations of the iterator.
1383 | callInvokeWithMethodAndArg
1384 | ) : callInvokeWithMethodAndArg();
1385 | }
1386 |
1387 | // Define the unified helper method that is used to implement .next,
1388 | // .throw, and .return (see defineIteratorMethods).
1389 | this._invoke = enqueue;
1390 | }
1391 |
1392 | defineIteratorMethods(AsyncIterator.prototype);
1393 | AsyncIterator.prototype[asyncIteratorSymbol] = function () {
1394 | return this;
1395 | };
1396 | runtime.AsyncIterator = AsyncIterator;
1397 |
1398 | // Note that simple async functions are implemented on top of
1399 | // AsyncIterator objects; they just return a Promise for the value of
1400 | // the final result produced by the iterator.
1401 | runtime.async = function(innerFn, outerFn, self, tryLocsList) {
1402 | var iter = new AsyncIterator(
1403 | wrap(innerFn, outerFn, self, tryLocsList)
1404 | );
1405 |
1406 | return runtime.isGeneratorFunction(outerFn)
1407 | ? iter // If outerFn is a generator, return the full iterator.
1408 | : iter.next().then(function(result) {
1409 | return result.done ? result.value : iter.next();
1410 | });
1411 | };
1412 |
1413 | function makeInvokeMethod(innerFn, self, context) {
1414 | var state = GenStateSuspendedStart;
1415 |
1416 | return function invoke(method, arg) {
1417 | if (state === GenStateExecuting) {
1418 | throw new Error("Generator is already running");
1419 | }
1420 |
1421 | if (state === GenStateCompleted) {
1422 | if (method === "throw") {
1423 | throw arg;
1424 | }
1425 |
1426 | // Be forgiving, per 25.3.3.3.3 of the spec:
1427 | // https://people.mozilla.org/~jorendorff/es6-draft.html#sec-generatorresume
1428 | return doneResult();
1429 | }
1430 |
1431 | context.method = method;
1432 | context.arg = arg;
1433 |
1434 | while (true) {
1435 | var delegate = context.delegate;
1436 | if (delegate) {
1437 | var delegateResult = maybeInvokeDelegate(delegate, context);
1438 | if (delegateResult) {
1439 | if (delegateResult === ContinueSentinel) continue;
1440 | return delegateResult;
1441 | }
1442 | }
1443 |
1444 | if (context.method === "next") {
1445 | // Setting context._sent for legacy support of Babel's
1446 | // function.sent implementation.
1447 | context.sent = context._sent = context.arg;
1448 |
1449 | } else if (context.method === "throw") {
1450 | if (state === GenStateSuspendedStart) {
1451 | state = GenStateCompleted;
1452 | throw context.arg;
1453 | }
1454 |
1455 | context.dispatchException(context.arg);
1456 |
1457 | } else if (context.method === "return") {
1458 | context.abrupt("return", context.arg);
1459 | }
1460 |
1461 | state = GenStateExecuting;
1462 |
1463 | var record = tryCatch(innerFn, self, context);
1464 | if (record.type === "normal") {
1465 | // If an exception is thrown from innerFn, we leave state ===
1466 | // GenStateExecuting and loop back for another invocation.
1467 | state = context.done
1468 | ? GenStateCompleted
1469 | : GenStateSuspendedYield;
1470 |
1471 | if (record.arg === ContinueSentinel) {
1472 | continue;
1473 | }
1474 |
1475 | return {
1476 | value: record.arg,
1477 | done: context.done
1478 | };
1479 |
1480 | } else if (record.type === "throw") {
1481 | state = GenStateCompleted;
1482 | // Dispatch the exception by looping back around to the
1483 | // context.dispatchException(context.arg) call above.
1484 | context.method = "throw";
1485 | context.arg = record.arg;
1486 | }
1487 | }
1488 | };
1489 | }
1490 |
1491 | // Call delegate.iterator[context.method](context.arg) and handle the
1492 | // result, either by returning a { value, done } result from the
1493 | // delegate iterator, or by modifying context.method and context.arg,
1494 | // setting context.delegate to null, and returning the ContinueSentinel.
1495 | function maybeInvokeDelegate(delegate, context) {
1496 | var method = delegate.iterator[context.method];
1497 | if (method === undefined) {
1498 | // A .throw or .return when the delegate iterator has no .throw
1499 | // method always terminates the yield* loop.
1500 | context.delegate = null;
1501 |
1502 | if (context.method === "throw") {
1503 | if (delegate.iterator.return) {
1504 | // If the delegate iterator has a return method, give it a
1505 | // chance to clean up.
1506 | context.method = "return";
1507 | context.arg = undefined;
1508 | maybeInvokeDelegate(delegate, context);
1509 |
1510 | if (context.method === "throw") {
1511 | // If maybeInvokeDelegate(context) changed context.method from
1512 | // "return" to "throw", let that override the TypeError below.
1513 | return ContinueSentinel;
1514 | }
1515 | }
1516 |
1517 | context.method = "throw";
1518 | context.arg = new TypeError(
1519 | "The iterator does not provide a 'throw' method");
1520 | }
1521 |
1522 | return ContinueSentinel;
1523 | }
1524 |
1525 | var record = tryCatch(method, delegate.iterator, context.arg);
1526 |
1527 | if (record.type === "throw") {
1528 | context.method = "throw";
1529 | context.arg = record.arg;
1530 | context.delegate = null;
1531 | return ContinueSentinel;
1532 | }
1533 |
1534 | var info = record.arg;
1535 |
1536 | if (! info) {
1537 | context.method = "throw";
1538 | context.arg = new TypeError("iterator result is not an object");
1539 | context.delegate = null;
1540 | return ContinueSentinel;
1541 | }
1542 |
1543 | if (info.done) {
1544 | // Assign the result of the finished delegate to the temporary
1545 | // variable specified by delegate.resultName (see delegateYield).
1546 | context[delegate.resultName] = info.value;
1547 |
1548 | // Resume execution at the desired location (see delegateYield).
1549 | context.next = delegate.nextLoc;
1550 |
1551 | // If context.method was "throw" but the delegate handled the
1552 | // exception, let the outer generator proceed normally. If
1553 | // context.method was "next", forget context.arg since it has been
1554 | // "consumed" by the delegate iterator. If context.method was
1555 | // "return", allow the original .return call to continue in the
1556 | // outer generator.
1557 | if (context.method !== "return") {
1558 | context.method = "next";
1559 | context.arg = undefined;
1560 | }
1561 |
1562 | } else {
1563 | // Re-yield the result returned by the delegate method.
1564 | return info;
1565 | }
1566 |
1567 | // The delegate iterator is finished, so forget it and continue with
1568 | // the outer generator.
1569 | context.delegate = null;
1570 | return ContinueSentinel;
1571 | }
1572 |
1573 | // Define Generator.prototype.{next,throw,return} in terms of the
1574 | // unified ._invoke helper method.
1575 | defineIteratorMethods(Gp);
1576 |
1577 | Gp[toStringTagSymbol] = "Generator";
1578 |
1579 | // A Generator should always return itself as the iterator object when the
1580 | // @@iterator function is called on it. Some browsers' implementations of the
1581 | // iterator prototype chain incorrectly implement this, causing the Generator
1582 | // object to not be returned from this call. This ensures that doesn't happen.
1583 | // See https://github.com/facebook/regenerator/issues/274 for more details.
1584 | Gp[iteratorSymbol] = function() {
1585 | return this;
1586 | };
1587 |
1588 | Gp.toString = function() {
1589 | return "[object Generator]";
1590 | };
1591 |
1592 | function pushTryEntry(locs) {
1593 | var entry = { tryLoc: locs[0] };
1594 |
1595 | if (1 in locs) {
1596 | entry.catchLoc = locs[1];
1597 | }
1598 |
1599 | if (2 in locs) {
1600 | entry.finallyLoc = locs[2];
1601 | entry.afterLoc = locs[3];
1602 | }
1603 |
1604 | this.tryEntries.push(entry);
1605 | }
1606 |
1607 | function resetTryEntry(entry) {
1608 | var record = entry.completion || {};
1609 | record.type = "normal";
1610 | delete record.arg;
1611 | entry.completion = record;
1612 | }
1613 |
1614 | function Context(tryLocsList) {
1615 | // The root entry object (effectively a try statement without a catch
1616 | // or a finally block) gives us a place to store values thrown from
1617 | // locations where there is no enclosing try statement.
1618 | this.tryEntries = [{ tryLoc: "root" }];
1619 | tryLocsList.forEach(pushTryEntry, this);
1620 | this.reset(true);
1621 | }
1622 |
1623 | runtime.keys = function(object) {
1624 | var keys = [];
1625 | for (var key in object) {
1626 | keys.push(key);
1627 | }
1628 | keys.reverse();
1629 |
1630 | // Rather than returning an object with a next method, we keep
1631 | // things simple and return the next function itself.
1632 | return function next() {
1633 | while (keys.length) {
1634 | var key = keys.pop();
1635 | if (key in object) {
1636 | next.value = key;
1637 | next.done = false;
1638 | return next;
1639 | }
1640 | }
1641 |
1642 | // To avoid creating an additional object, we just hang the .value
1643 | // and .done properties off the next function object itself. This
1644 | // also ensures that the minifier will not anonymize the function.
1645 | next.done = true;
1646 | return next;
1647 | };
1648 | };
1649 |
1650 | function values(iterable) {
1651 | if (iterable) {
1652 | var iteratorMethod = iterable[iteratorSymbol];
1653 | if (iteratorMethod) {
1654 | return iteratorMethod.call(iterable);
1655 | }
1656 |
1657 | if (typeof iterable.next === "function") {
1658 | return iterable;
1659 | }
1660 |
1661 | if (!isNaN(iterable.length)) {
1662 | var i = -1, next = function next() {
1663 | while (++i < iterable.length) {
1664 | if (hasOwn.call(iterable, i)) {
1665 | next.value = iterable[i];
1666 | next.done = false;
1667 | return next;
1668 | }
1669 | }
1670 |
1671 | next.value = undefined;
1672 | next.done = true;
1673 |
1674 | return next;
1675 | };
1676 |
1677 | return next.next = next;
1678 | }
1679 | }
1680 |
1681 | // Return an iterator with no values.
1682 | return { next: doneResult };
1683 | }
1684 | runtime.values = values;
1685 |
1686 | function doneResult() {
1687 | return { value: undefined, done: true };
1688 | }
1689 |
1690 | Context.prototype = {
1691 | constructor: Context,
1692 |
1693 | reset: function(skipTempReset) {
1694 | this.prev = 0;
1695 | this.next = 0;
1696 | // Resetting context._sent for legacy support of Babel's
1697 | // function.sent implementation.
1698 | this.sent = this._sent = undefined;
1699 | this.done = false;
1700 | this.delegate = null;
1701 |
1702 | this.method = "next";
1703 | this.arg = undefined;
1704 |
1705 | this.tryEntries.forEach(resetTryEntry);
1706 |
1707 | if (!skipTempReset) {
1708 | for (var name in this) {
1709 | // Not sure about the optimal order of these conditions:
1710 | if (name.charAt(0) === "t" &&
1711 | hasOwn.call(this, name) &&
1712 | !isNaN(+name.slice(1))) {
1713 | this[name] = undefined;
1714 | }
1715 | }
1716 | }
1717 | },
1718 |
1719 | stop: function() {
1720 | this.done = true;
1721 |
1722 | var rootEntry = this.tryEntries[0];
1723 | var rootRecord = rootEntry.completion;
1724 | if (rootRecord.type === "throw") {
1725 | throw rootRecord.arg;
1726 | }
1727 |
1728 | return this.rval;
1729 | },
1730 |
1731 | dispatchException: function(exception) {
1732 | if (this.done) {
1733 | throw exception;
1734 | }
1735 |
1736 | var context = this;
1737 | function handle(loc, caught) {
1738 | record.type = "throw";
1739 | record.arg = exception;
1740 | context.next = loc;
1741 |
1742 | if (caught) {
1743 | // If the dispatched exception was caught by a catch block,
1744 | // then let that catch block handle the exception normally.
1745 | context.method = "next";
1746 | context.arg = undefined;
1747 | }
1748 |
1749 | return !! caught;
1750 | }
1751 |
1752 | for (var i = this.tryEntries.length - 1; i >= 0; --i) {
1753 | var entry = this.tryEntries[i];
1754 | var record = entry.completion;
1755 |
1756 | if (entry.tryLoc === "root") {
1757 | // Exception thrown outside of any try block that could handle
1758 | // it, so set the completion value of the entire function to
1759 | // throw the exception.
1760 | return handle("end");
1761 | }
1762 |
1763 | if (entry.tryLoc <= this.prev) {
1764 | var hasCatch = hasOwn.call(entry, "catchLoc");
1765 | var hasFinally = hasOwn.call(entry, "finallyLoc");
1766 |
1767 | if (hasCatch && hasFinally) {
1768 | if (this.prev < entry.catchLoc) {
1769 | return handle(entry.catchLoc, true);
1770 | } else if (this.prev < entry.finallyLoc) {
1771 | return handle(entry.finallyLoc);
1772 | }
1773 |
1774 | } else if (hasCatch) {
1775 | if (this.prev < entry.catchLoc) {
1776 | return handle(entry.catchLoc, true);
1777 | }
1778 |
1779 | } else if (hasFinally) {
1780 | if (this.prev < entry.finallyLoc) {
1781 | return handle(entry.finallyLoc);
1782 | }
1783 |
1784 | } else {
1785 | throw new Error("try statement without catch or finally");
1786 | }
1787 | }
1788 | }
1789 | },
1790 |
1791 | abrupt: function(type, arg) {
1792 | for (var i = this.tryEntries.length - 1; i >= 0; --i) {
1793 | var entry = this.tryEntries[i];
1794 | if (entry.tryLoc <= this.prev &&
1795 | hasOwn.call(entry, "finallyLoc") &&
1796 | this.prev < entry.finallyLoc) {
1797 | var finallyEntry = entry;
1798 | break;
1799 | }
1800 | }
1801 |
1802 | if (finallyEntry &&
1803 | (type === "break" ||
1804 | type === "continue") &&
1805 | finallyEntry.tryLoc <= arg &&
1806 | arg <= finallyEntry.finallyLoc) {
1807 | // Ignore the finally entry if control is not jumping to a
1808 | // location outside the try/catch block.
1809 | finallyEntry = null;
1810 | }
1811 |
1812 | var record = finallyEntry ? finallyEntry.completion : {};
1813 | record.type = type;
1814 | record.arg = arg;
1815 |
1816 | if (finallyEntry) {
1817 | this.method = "next";
1818 | this.next = finallyEntry.finallyLoc;
1819 | return ContinueSentinel;
1820 | }
1821 |
1822 | return this.complete(record);
1823 | },
1824 |
1825 | complete: function(record, afterLoc) {
1826 | if (record.type === "throw") {
1827 | throw record.arg;
1828 | }
1829 |
1830 | if (record.type === "break" ||
1831 | record.type === "continue") {
1832 | this.next = record.arg;
1833 | } else if (record.type === "return") {
1834 | this.rval = this.arg = record.arg;
1835 | this.method = "return";
1836 | this.next = "end";
1837 | } else if (record.type === "normal" && afterLoc) {
1838 | this.next = afterLoc;
1839 | }
1840 |
1841 | return ContinueSentinel;
1842 | },
1843 |
1844 | finish: function(finallyLoc) {
1845 | for (var i = this.tryEntries.length - 1; i >= 0; --i) {
1846 | var entry = this.tryEntries[i];
1847 | if (entry.finallyLoc === finallyLoc) {
1848 | this.complete(entry.completion, entry.afterLoc);
1849 | resetTryEntry(entry);
1850 | return ContinueSentinel;
1851 | }
1852 | }
1853 | },
1854 |
1855 | "catch": function(tryLoc) {
1856 | for (var i = this.tryEntries.length - 1; i >= 0; --i) {
1857 | var entry = this.tryEntries[i];
1858 | if (entry.tryLoc === tryLoc) {
1859 | var record = entry.completion;
1860 | if (record.type === "throw") {
1861 | var thrown = record.arg;
1862 | resetTryEntry(entry);
1863 | }
1864 | return thrown;
1865 | }
1866 | }
1867 |
1868 | // The context.catch method must only be called with a location
1869 | // argument that corresponds to a known catch block.
1870 | throw new Error("illegal catch attempt");
1871 | },
1872 |
1873 | delegateYield: function(iterable, resultName, nextLoc) {
1874 | this.delegate = {
1875 | iterator: values(iterable),
1876 | resultName: resultName,
1877 | nextLoc: nextLoc
1878 | };
1879 |
1880 | if (this.method === "next") {
1881 | // Deliberately forget the last sent value so that we don't
1882 | // accidentally pass it on to the delegate.
1883 | this.arg = undefined;
1884 | }
1885 |
1886 | return ContinueSentinel;
1887 | }
1888 | };
1889 | })(
1890 | // Among the various tricks for obtaining a reference to the global
1891 | // object, this seems to be the most reliable technique that does not
1892 | // use indirect eval (which violates Content Security Policy).
1893 | typeof global === "object" ? global :
1894 | typeof window === "object" ? window :
1895 | typeof self === "object" ? self : this
1896 | );
1897 |
1898 | /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(4)))
1899 |
1900 | /***/ }),
1901 | /* 11 */
1902 | /***/ (function(module, exports, __webpack_require__) {
1903 |
1904 | "use strict";
1905 |
1906 |
1907 | Object.defineProperty(exports, "__esModule", {
1908 | value: true
1909 | });
1910 |
1911 | function getVideoUrl(tvid, vid) {
1912 | return new Promise(function (resolve, reject) {
1913 | GM_xmlhttpRequest({
1914 | url: `http://cache.video.qiyi.com/jp/vi/${tvid}/${vid}/?callback=callback`,
1915 | method: 'GET',
1916 | timeout: 8e3,
1917 | onload: function onload(details) {
1918 | try {
1919 | var json = JSON.parse(/callback\s*\(\s*(\{.*\})\s*\)/.exec(details.responseText)[1]);
1920 | resolve(json.vu);
1921 | } catch (err) {
1922 | reject(err);
1923 | }
1924 | },
1925 | onerror: reject,
1926 | onabort: reject,
1927 | ontimeout: reject
1928 | });
1929 | });
1930 | }
1931 |
1932 | function findVid(text) {
1933 | var result = /vid=([\da-z]+)/i.exec(text);
1934 | return result ? result[1] : null;
1935 | }
1936 |
1937 | function findTvid(text) {
1938 | var result = /tvid=(\d+)/i.exec(text);
1939 | return result ? result[1] : null;
1940 | }
1941 |
1942 | exports.getVideoUrl = getVideoUrl;
1943 | exports.findVid = findVid;
1944 | exports.findTvid = findTvid;
1945 |
1946 | /***/ }),
1947 | /* 12 */
1948 | /***/ (function(module, exports, __webpack_require__) {
1949 |
1950 | "use strict";
1951 |
1952 |
1953 | Object.defineProperty(exports, "__esModule", {
1954 | value: true
1955 | });
1956 | exports.useWebSocketLoaderPatch = exports.mouseShortcutsPatch = exports.keyShortcutsPatch = exports.keepHookingPatch = exports.watermarksPatch = exports.controlsPatch = exports.adsPatch = exports.vipPatch = undefined;
1957 |
1958 | 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; }; }();
1959 |
1960 | var _logger = __webpack_require__(1);
1961 |
1962 | var _logger2 = _interopRequireDefault(_logger);
1963 |
1964 | var _hooker = __webpack_require__(0);
1965 |
1966 | var _hooker2 = _interopRequireDefault(_hooker);
1967 |
1968 | var _fullscreen = __webpack_require__(13);
1969 |
1970 | var _webFullscreen = __webpack_require__(14);
1971 |
1972 | var _parsedData = __webpack_require__(15);
1973 |
1974 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
1975 |
1976 | function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
1977 |
1978 | function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
1979 |
1980 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
1981 |
1982 | var Patch = function () {
1983 | function Patch() {
1984 | _classCallCheck(this, Patch);
1985 |
1986 | this._installed = false;
1987 | }
1988 |
1989 | _createClass(Patch, [{
1990 | key: 'install',
1991 | value: function install() {
1992 | if (!this._installed) {
1993 | this._installed = true;
1994 | this._prepare();
1995 | this._apply();
1996 | }
1997 | }
1998 | }, {
1999 | key: '_prepare',
2000 | value: function _prepare() {}
2001 | }, {
2002 | key: '_apply',
2003 | value: function _apply() {}
2004 | }]);
2005 |
2006 | return Patch;
2007 | }();
2008 |
2009 | var VipPatch = function (_Patch) {
2010 | _inherits(VipPatch, _Patch);
2011 |
2012 | function VipPatch() {
2013 | _classCallCheck(this, VipPatch);
2014 |
2015 | return _possibleConstructorReturn(this, (VipPatch.__proto__ || Object.getPrototypeOf(VipPatch)).call(this));
2016 | }
2017 |
2018 | _createClass(VipPatch, [{
2019 | key: '_apply',
2020 | value: function _apply() {
2021 | _hooker2.default.hookUser(function (exports) {
2022 | var proto = exports.__proto__;
2023 | proto.isVipSync = function () {
2024 | return true;
2025 | };
2026 | proto.isVip = function (cb) {
2027 | return setTimeout(cb, 0, true);
2028 | };
2029 | _logger2.default.info('The vip patch has been installed');
2030 | });
2031 | }
2032 | }]);
2033 |
2034 | return VipPatch;
2035 | }(Patch);
2036 |
2037 | var AdsPatch = function (_Patch2) {
2038 | _inherits(AdsPatch, _Patch2);
2039 |
2040 | function AdsPatch() {
2041 | _classCallCheck(this, AdsPatch);
2042 |
2043 | return _possibleConstructorReturn(this, (AdsPatch.__proto__ || Object.getPrototypeOf(AdsPatch)).call(this));
2044 | }
2045 |
2046 | _createClass(AdsPatch, [{
2047 | key: '_fakeAdsData',
2048 | value: function _fakeAdsData() {
2049 | return {};
2050 | }
2051 | }, {
2052 | key: '_apply',
2053 | value: function _apply() {
2054 | var _this3 = this;
2055 |
2056 | _hooker2.default.hookShowRequest(function (exports) {
2057 | var proto = exports.prototype;
2058 | proto.request = function (cb) {
2059 | return setTimeout(cb, 0, _this3._fakeAdsData());
2060 | };
2061 | _logger2.default.info('The ads patch has been installed');
2062 | });
2063 | }
2064 | }]);
2065 |
2066 | return AdsPatch;
2067 | }(Patch);
2068 |
2069 | var WatermarksPatch = function (_Patch3) {
2070 | _inherits(WatermarksPatch, _Patch3);
2071 |
2072 | function WatermarksPatch() {
2073 | _classCallCheck(this, WatermarksPatch);
2074 |
2075 | return _possibleConstructorReturn(this, (WatermarksPatch.__proto__ || Object.getPrototypeOf(WatermarksPatch)).call(this));
2076 | }
2077 |
2078 | _createClass(WatermarksPatch, [{
2079 | key: '_apply',
2080 | value: function _apply() {
2081 | _hooker2.default.hookLogo(function (exports) {
2082 | exports.prototype.showLogo = function () {};
2083 | _logger2.default.info('The watermarks patch has been installed');
2084 | });
2085 | }
2086 | }]);
2087 |
2088 | return WatermarksPatch;
2089 | }(Patch);
2090 |
2091 | var ControlsPatch = function (_Patch4) {
2092 | _inherits(ControlsPatch, _Patch4);
2093 |
2094 | // Prevent the player controls were disabled.
2095 | function ControlsPatch() {
2096 | _classCallCheck(this, ControlsPatch);
2097 |
2098 | return _possibleConstructorReturn(this, (ControlsPatch.__proto__ || Object.getPrototypeOf(ControlsPatch)).call(this));
2099 | }
2100 |
2101 | _createClass(ControlsPatch, [{
2102 | key: '_apply',
2103 | value: function _apply() {
2104 | _hooker2.default.hookSkinBase(function (exports) {
2105 | exports.prototype._checkPlugin = function () {}; // This function disables the player controls when playing ads and enables when done.
2106 | _logger2.default.info('The controls patch has been installed');
2107 | });
2108 | }
2109 | }]);
2110 |
2111 | return ControlsPatch;
2112 | }(Patch);
2113 |
2114 | var CorePatch = function (_Patch5) {
2115 | _inherits(CorePatch, _Patch5);
2116 |
2117 | function CorePatch() {
2118 | _classCallCheck(this, CorePatch);
2119 |
2120 | return _possibleConstructorReturn(this, (CorePatch.__proto__ || Object.getPrototypeOf(CorePatch)).call(this));
2121 | }
2122 |
2123 | _createClass(CorePatch, [{
2124 | key: '_prepare',
2125 | value: function _prepare() {
2126 | this._initShowTip();
2127 | this._initPlaybackRate();
2128 | }
2129 | }, {
2130 | key: '_initShowTip',
2131 | value: function _initShowTip() {
2132 | _hooker2.default.hookPluginControlsInit(function (that) {
2133 | that.core.on('showtip', function (event) {
2134 | that.setcontroltip.apply(that, [{ str: event.data, x: that._process.offset().left, y: 3, cut: true, timeout: true }]);
2135 | if (that.$plugin.hasClass('process_hidden')) {
2136 | that._controltips.css('top', '-25px');
2137 | } else if (that.$plugin.hasClass('bottom-hide')) {
2138 | that._controltips.css('top', '-38px');
2139 | }
2140 | });
2141 | });
2142 | }
2143 | }, {
2144 | key: '_initPlaybackRate',
2145 | value: function _initPlaybackRate() {
2146 | _hooker2.default.hookPluginControls(function (exports) {
2147 | exports.prototype.initPlaybackRate = function () {
2148 | var core = this.core;
2149 |
2150 | var rate = parseFloat(localStorage.getItem('QiyiPlayerPlaybackRate'));
2151 | rate = isNaN(rate) ? 1 : rate;
2152 |
2153 | if (core.getCurrStatus() === 'playing') {
2154 | core.setPlaybackRate(rate);
2155 | } else {
2156 | var onstatuschanged = function onstatuschanged(evt) {
2157 | if (evt.data.state === 'playing') {
2158 | core.setPlaybackRate(rate);
2159 | core.un('statusChanged', onstatuschanged);
2160 | }
2161 | };
2162 | core.on('statusChanged', onstatuschanged);
2163 | }
2164 |
2165 | var $ul = this.$playbackrateUl;
2166 | $ul.find(`[data-pbrate="${rate}"]`).addClass('selected');
2167 |
2168 | var $items = $ul.find('li');
2169 | $items.on('click', function () {
2170 | var rate = parseFloat(this.getAttribute('data-pbrate'));
2171 | if (!this.classList.contains('selected')) {
2172 | $items.removeClass('selected');
2173 | this.classList.add('selected');
2174 | }
2175 | localStorage.setItem('QiyiPlayerPlaybackRate', rate);
2176 | core.setPlaybackRate(rate);
2177 | });
2178 |
2179 | this.$playsettingicon.on('click', function () {
2180 | var rate = core.getPlaybackRate();
2181 | var $item = $ul.find(`[data-pbrate="${rate}"]`);
2182 | if ($item.length === 1) {
2183 | if (!$item.hasClass('selected')) {
2184 | $items.removeClass('selected');
2185 | $item.addClass('selected');
2186 | }
2187 | } else {
2188 | $items.removeClass('selected');
2189 | }
2190 | });
2191 | };
2192 | });
2193 | }
2194 | }, {
2195 | key: '_apply',
2196 | value: function _apply() {
2197 | _hooker2.default.hookCore(function (exports) {
2198 | var proto = exports.prototype;
2199 |
2200 | proto._showTip = function (msg) {
2201 | this.fire({ type: 'showtip', data: msg });
2202 | };
2203 |
2204 | proto.getFPS = function () {
2205 | if (_parsedData.flvInfo) {
2206 | return _parsedData.flvInfo.videoConfigTag.sps.frame_rate.fps;
2207 | } else {
2208 | return 25; // f4v极速以上,动画23.976、电影24、电视剧25。
2209 | }
2210 | };
2211 |
2212 | proto.prevFrame = function () {
2213 | var video = this.video();
2214 | var seekTime = Math.max(0, Math.min(this.getDuration(), video.currentTime - 1 / this.getFPS()));
2215 | video.currentTime = seekTime;
2216 | this._showTip('上一帧');
2217 | };
2218 |
2219 | proto.nextFrame = function () {
2220 | var video = this.video();
2221 | var seekTime = Math.max(0, Math.min(this.getDuration(), video.currentTime + 1 / this.getFPS()));
2222 | video.currentTime = seekTime;
2223 | this._showTip('下一帧');
2224 | };
2225 |
2226 | proto.seek = function () {
2227 | var _engine;
2228 |
2229 | var video = this.video();
2230 | var playbackRate = video.playbackRate;
2231 | (_engine = this._engine).seek.apply(_engine, arguments);
2232 | video.playbackRate = playbackRate;
2233 | };
2234 |
2235 | proto.stepSeek = function (stepTime) {
2236 | var seekTime = Math.max(0, Math.min(this.getDuration(), this.getCurrenttime() + stepTime));
2237 | var msg = void 0;
2238 |
2239 | if (Math.abs(stepTime) < 60) {
2240 | msg = stepTime > 0 ? `步进:${stepTime}秒` : `步退:${Math.abs(stepTime)}秒`;
2241 | } else {
2242 | msg = stepTime > 0 ? `步进:${stepTime / 60}分钟` : `步退:${Math.abs(stepTime) / 60}分钟`;
2243 | }
2244 | this._showTip(msg);
2245 |
2246 | this.seek(seekTime, true);
2247 | };
2248 |
2249 | proto.rangeSeek = function (range) {
2250 | var duration = this.getDuration();
2251 | var seekTime = Math.max(0, Math.min(duration, duration * range));
2252 | this.seek(seekTime, true);
2253 | this._showTip('定位:' + (range * 100).toFixed(0) + '%');
2254 | };
2255 |
2256 | proto.toggleMute = function () {
2257 | if (this.getMuted()) {
2258 | this.setMuted(false);
2259 | this._showTip('取消静音');
2260 | } else {
2261 | this.setMuted(true);
2262 | this._showTip('静音');
2263 | }
2264 | };
2265 |
2266 | proto.adjustVolume = function (value) {
2267 | var volume = this.getVolume() + value;
2268 | volume = Math.max(0, Math.min(1, volume.toFixed(2)));
2269 | this.setVolume(volume);
2270 | this.fire({ type: 'keyvolumechange' });
2271 | };
2272 |
2273 | proto.getPlaybackRate = function () {
2274 | // iqiyi 的这个方法有bug,没把值返回!
2275 | return this._engine.getPlaybackRate();
2276 | };
2277 |
2278 | proto.adjustPlaybackRate = function (value) {
2279 | var currRate = this.getPlaybackRate();
2280 | var rate = Math.max(0.2, Math.min(5, parseFloat((currRate + value).toFixed(1))));
2281 |
2282 | localStorage.setItem('QiyiPlayerPlaybackRate', rate);
2283 | this.setPlaybackRate(rate);
2284 | this._showTip(`播放速率:${rate}`);
2285 | };
2286 |
2287 | proto.turnPlaybackRate = function () {
2288 | var currRate = this.getPlaybackRate();
2289 | var rate = void 0;
2290 | if (currRate !== 1) {
2291 | this._backRate = currRate;
2292 | rate = 1;
2293 | } else {
2294 | rate = this._backRate || 1;
2295 | }
2296 |
2297 | this.setPlaybackRate(rate);
2298 | this._showTip(`播放速率:${rate}`);
2299 | };
2300 |
2301 | proto.hasPrevVideo = function () {
2302 | return this._getVideoIndexInList(this._movieinfo.tvid) > 0 || this._getVideoIndexInList(this._movieinfo.oldTvid) > 0;
2303 | };
2304 |
2305 | proto.playNext = function () {
2306 | if (this.hasNextVideo()) {
2307 | this._showTip('播放下一集');
2308 | this.switchNextVideo();
2309 | } else {
2310 | this._showTip('没有下一集哦');
2311 | }
2312 | };
2313 |
2314 | proto.playPrev = function () {
2315 | if (this.hasPrevVideo()) {
2316 | this._showTip('播放上一集');
2317 | this.switchPreVideo();
2318 | } else {
2319 | this._showTip('没有上一集哦');
2320 | }
2321 | };
2322 |
2323 | _logger2.default.info('The core patch has been installed');
2324 | });
2325 | }
2326 | }]);
2327 |
2328 | return CorePatch;
2329 | }(Patch);
2330 |
2331 | var corePatch = new CorePatch();
2332 |
2333 | var KeyShortcutsPatch = function (_Patch6) {
2334 | _inherits(KeyShortcutsPatch, _Patch6);
2335 |
2336 | function KeyShortcutsPatch() {
2337 | _classCallCheck(this, KeyShortcutsPatch);
2338 |
2339 | return _possibleConstructorReturn(this, (KeyShortcutsPatch.__proto__ || Object.getPrototypeOf(KeyShortcutsPatch)).call(this));
2340 | }
2341 |
2342 | _createClass(KeyShortcutsPatch, [{
2343 | key: '_prepare',
2344 | value: function _prepare() {
2345 | corePatch.install();
2346 | }
2347 | }, {
2348 | key: '_apply',
2349 | value: function _apply() {
2350 | _hooker2.default.hookPluginHotKeys(function (exports) {
2351 | var proto = exports.prototype;
2352 |
2353 | proto.init = function () {
2354 | document.addEventListener('keydown', this._keydown.bind(this));
2355 | };
2356 |
2357 | proto._isValidTarget = function (target) {
2358 | return target.nodeName === 'BODY' || target.nodeName == 'VIDEO' || target.classList.contains('pw-video'); // 全局
2359 | // return target.nodeName === 'VIDEO' || target.classList.contains('pw-video'); // 非全局
2360 | };
2361 |
2362 | proto._keydown = function (event) {
2363 | if (!this._isValidTarget(event.target)) return;
2364 |
2365 | var keyCode = event.keyCode,
2366 | ctrlKey = event.ctrlKey,
2367 | shiftKey = event.shiftKey,
2368 | altKey = event.altKey;
2369 |
2370 | var core = this.core;
2371 |
2372 | switch (keyCode) {
2373 | case 32:
2374 | // Spacebar
2375 | if (!ctrlKey && !shiftKey && !altKey) {
2376 | if (core.isPaused()) {
2377 | core.play(true);
2378 | core._showTip('播放');
2379 | } else {
2380 | core.pause(true);
2381 | core._showTip('暂停');
2382 | }
2383 | } else {
2384 | return;
2385 | }
2386 | break;
2387 | case 39: // → Arrow Right
2388 | case 37:
2389 | {
2390 | // ← Arrow Left
2391 | var stepTime = void 0;
2392 | if (!ctrlKey && !shiftKey && !altKey) {
2393 | stepTime = 39 === keyCode ? 5 : -5;
2394 | } else if (ctrlKey && !shiftKey && !altKey) {
2395 | stepTime = 39 === keyCode ? 30 : -30;
2396 | } else if (!ctrlKey && shiftKey && !altKey) {
2397 | stepTime = 39 === keyCode ? 60 : -60;
2398 | } else if (ctrlKey && !shiftKey && altKey) {
2399 | stepTime = 39 === keyCode ? 3e2 : -3e2; // 5分钟
2400 | } else {
2401 | return;
2402 | }
2403 |
2404 | core.stepSeek(stepTime);
2405 | break;
2406 | }
2407 | case 38: // ↑ Arrow Up
2408 | case 40:
2409 | // ↓ Arrow Down
2410 | if (!ctrlKey && !shiftKey && !altKey) {
2411 | core.adjustVolume(38 === keyCode ? 0.05 : -0.05);
2412 | } else {
2413 | return;
2414 | }
2415 | break;
2416 | case 77:
2417 | // M
2418 | if (!ctrlKey && !shiftKey && !altKey) {
2419 | core.toggleMute();
2420 | } else {
2421 | return;
2422 | }
2423 | break;
2424 | case 13:
2425 | // Enter
2426 | if (!ctrlKey && !shiftKey && !altKey) {
2427 | _fullscreen.fullscreen.toggle();
2428 | } else if (ctrlKey && !shiftKey && !altKey) {
2429 | _webFullscreen.webFullscreen.toggle();
2430 | } else {
2431 | return;
2432 | }
2433 | break;
2434 | case 67: // C
2435 | case 88:
2436 | // X
2437 | if (!ctrlKey && !shiftKey && !altKey) {
2438 | core.adjustPlaybackRate(67 === keyCode ? 0.1 : -0.1);
2439 | } else {
2440 | return;
2441 | }
2442 | break;
2443 | case 90:
2444 | // Z
2445 | if (!ctrlKey && !shiftKey && !altKey) {
2446 | core.turnPlaybackRate();
2447 | } else {
2448 | return;
2449 | }
2450 | break;
2451 | case 68: // D
2452 | case 70:
2453 | // F
2454 | if (!ctrlKey && !shiftKey && !altKey) {
2455 | core.pause(true);
2456 | if (keyCode === 68) {
2457 | core.prevFrame();
2458 | } else {
2459 | core.nextFrame();
2460 | }
2461 | } else {
2462 | return;
2463 | }
2464 | break;
2465 | case 80: // P
2466 | case 78:
2467 | // N
2468 | if (!ctrlKey && shiftKey && !altKey) {
2469 | if (keyCode === 78) {
2470 | core.playNext();
2471 | } else {
2472 | core.playPrev();
2473 | }
2474 | } else {
2475 | return;
2476 | }
2477 | break;
2478 | case 27:
2479 | // ESC
2480 | if (!event.ctrlKey && !event.shiftKey && !event.altKey) _webFullscreen.webFullscreen.isWebFullScreen() && _webFullscreen.webFullscreen.exit();
2481 | return;
2482 | default:
2483 | if (keyCode >= 48 && keyCode <= 57) {
2484 | // 0 ~ 9
2485 | if (!ctrlKey && !shiftKey && !altKey) {
2486 | core.rangeSeek((keyCode - 48) * 0.1);
2487 | } else {
2488 | return;
2489 | }
2490 | } else {
2491 | return;
2492 | }
2493 | }
2494 |
2495 | event.preventDefault();
2496 | event.stopPropagation();
2497 | };
2498 |
2499 | _logger2.default.info('The keyboard shortcuts patch has been installed');
2500 | });
2501 | }
2502 | }]);
2503 |
2504 | return KeyShortcutsPatch;
2505 | }(Patch);
2506 |
2507 | var MouseShortcutsPatch = function (_Patch7) {
2508 | _inherits(MouseShortcutsPatch, _Patch7);
2509 |
2510 | function MouseShortcutsPatch() {
2511 | _classCallCheck(this, MouseShortcutsPatch);
2512 |
2513 | return _possibleConstructorReturn(this, (MouseShortcutsPatch.__proto__ || Object.getPrototypeOf(MouseShortcutsPatch)).call(this));
2514 | }
2515 |
2516 | _createClass(MouseShortcutsPatch, [{
2517 | key: '_prepare',
2518 | value: function _prepare() {
2519 | corePatch.install();
2520 | }
2521 | }, {
2522 | key: '_apply',
2523 | value: function _apply() {
2524 | _hooker2.default.hookDefaultSkin(function (exports) {
2525 | exports.prototype._initDBClicks = function () {
2526 | var timer = void 0,
2527 | core = this.core;
2528 | this.videoWrapper.find('video').on('click', function () {
2529 | if (timer) {
2530 | clearTimeout(timer);
2531 | timer = null;
2532 | return;
2533 | }
2534 | timer = setTimeout(function () {
2535 | if (core.isPaused()) {
2536 | core.play(true);
2537 | } else {
2538 | core.pause(true);
2539 | }
2540 | timer = null;
2541 | }, 200);
2542 | }).on('dblclick', function (event) {
2543 | event.preventDefault();
2544 | event.stopPropagation();
2545 | if (event.ctrlKey) {
2546 | _webFullscreen.webFullscreen.toggle();
2547 | } else {
2548 | _fullscreen.fullscreen.toggle();
2549 | }
2550 | }).on('wheel', function (event) {
2551 | if (_fullscreen.fullscreen.isFullScreen() || _webFullscreen.webFullscreen.isWebFullScreen()) {
2552 | var delta = event.wheelDelta || event.detail || event.deltaY && -event.deltaY;
2553 | core.adjustVolume(delta > 0 ? 0.05 : -0.05);
2554 | }
2555 | });
2556 | };
2557 |
2558 | _logger2.default.info('The mouse shortcuts patch has been installed');
2559 | });
2560 | }
2561 | }]);
2562 |
2563 | return MouseShortcutsPatch;
2564 | }(Patch);
2565 |
2566 | var UseWebSocketLoaderPatch = function (_Patch8) {
2567 | _inherits(UseWebSocketLoaderPatch, _Patch8);
2568 |
2569 | function UseWebSocketLoaderPatch() {
2570 | _classCallCheck(this, UseWebSocketLoaderPatch);
2571 |
2572 | var _this9 = _possibleConstructorReturn(this, (UseWebSocketLoaderPatch.__proto__ || Object.getPrototypeOf(UseWebSocketLoaderPatch)).call(this));
2573 |
2574 | _this9.tryWs = GM_getValue('tryWs', false);
2575 | return _this9;
2576 | }
2577 |
2578 | _createClass(UseWebSocketLoaderPatch, [{
2579 | key: '_prepare',
2580 | value: function _prepare() {
2581 | this._addSetting();
2582 | }
2583 | }, {
2584 | key: '_apply',
2585 | value: function _apply() {
2586 | var _this10 = this;
2587 |
2588 | var that = this;
2589 | _hooker2.default.hookFragment(function (exports) {
2590 | Reflect.defineProperty(exports.prototype, 'tryWS', {
2591 | get: function get() {
2592 | return _this10._tryWs || that.tryWs;
2593 | }, // Will use the WebSocket loader if the value of tryWs is true.
2594 | set: function set(value) {
2595 | return _this10._tryWs = value;
2596 | } // The value of tryWs will be true if the Fetch loader fails.
2597 | });
2598 | _logger2.default.info('The WebSocket loader patch has been installed');
2599 | });
2600 | }
2601 | }, {
2602 | key: '_addSetting',
2603 | value: function _addSetting() {
2604 | var that = this;
2605 | _hooker2.default.hookPluginControls(function (exports) {
2606 | var initSetting = exports.prototype.initSetting;
2607 | exports.prototype.initSetting = function () {
2608 | var _this11 = this;
2609 |
2610 | var div = document.createElement('div');
2611 | div.innerHTML = `
2612 |
2613 |
WebSocket
2614 |
2615 |
`;
2616 | var item = div.querySelector('.setPop_item');
2617 | this.$playsettingbox.find('.video_setPop_top').append(item);
2618 | this.$usewebsocketBtn = this.$playsettingbox.find('[data-player-hook="usewebsocketloader"]');
2619 |
2620 | if (that.tryWs) {
2621 | this.$usewebsocketBtn.removeClass('setPop_switch_close');
2622 | }
2623 | this.$usewebsocketBtn.on('click', function () {
2624 | _this11.$usewebsocketBtn.toggleClass('setPop_switch_close');
2625 | that.tryWs = !that.tryWs;
2626 | GM_setValue('tryWs', that.tryWs);
2627 | });
2628 |
2629 | initSetting.apply(this);
2630 | };
2631 | });
2632 | }
2633 | }]);
2634 |
2635 | return UseWebSocketLoaderPatch;
2636 | }(Patch);
2637 |
2638 | var KeepHookingPatch = function (_Patch9) {
2639 | _inherits(KeepHookingPatch, _Patch9);
2640 |
2641 | function KeepHookingPatch() {
2642 | _classCallCheck(this, KeepHookingPatch);
2643 |
2644 | return _possibleConstructorReturn(this, (KeepHookingPatch.__proto__ || Object.getPrototypeOf(KeepHookingPatch)).call(this));
2645 | }
2646 |
2647 | _createClass(KeepHookingPatch, [{
2648 | key: '_apply',
2649 | value: function _apply() {
2650 | _hooker2.default.keepalive = true;
2651 | _logger2.default.info('The keep hooking patch has been installed');
2652 | }
2653 | }]);
2654 |
2655 | return KeepHookingPatch;
2656 | }(Patch);
2657 |
2658 | var vipPatch = exports.vipPatch = new VipPatch();
2659 | var adsPatch = exports.adsPatch = new AdsPatch();
2660 | var controlsPatch = exports.controlsPatch = new ControlsPatch();
2661 | var watermarksPatch = exports.watermarksPatch = new WatermarksPatch();
2662 | var keepHookingPatch = exports.keepHookingPatch = new KeepHookingPatch();
2663 | var keyShortcutsPatch = exports.keyShortcutsPatch = new KeyShortcutsPatch();
2664 | var mouseShortcutsPatch = exports.mouseShortcutsPatch = new MouseShortcutsPatch();
2665 | var useWebSocketLoaderPatch = exports.useWebSocketLoaderPatch = new UseWebSocketLoaderPatch();
2666 |
2667 | /***/ }),
2668 | /* 13 */
2669 | /***/ (function(module, exports, __webpack_require__) {
2670 |
2671 | "use strict";
2672 |
2673 |
2674 | Object.defineProperty(exports, "__esModule", {
2675 | value: true
2676 | });
2677 | exports.fullscreen = undefined;
2678 |
2679 | var _hooker = __webpack_require__(0);
2680 |
2681 | var _hooker2 = _interopRequireDefault(_hooker);
2682 |
2683 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
2684 |
2685 | var fullscreen = void 0;
2686 | _hooker2.default.hookFullScreen(function (_exports) {
2687 | return exports.fullscreen = fullscreen = _exports;
2688 | });
2689 |
2690 | exports.fullscreen = fullscreen;
2691 |
2692 | /***/ }),
2693 | /* 14 */
2694 | /***/ (function(module, exports, __webpack_require__) {
2695 |
2696 | "use strict";
2697 |
2698 |
2699 | Object.defineProperty(exports, "__esModule", {
2700 | value: true
2701 | });
2702 | exports.webFullscreen = undefined;
2703 |
2704 | var _hooker = __webpack_require__(0);
2705 |
2706 | var _hooker2 = _interopRequireDefault(_hooker);
2707 |
2708 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
2709 |
2710 | var webFullscreen = void 0;
2711 | _hooker2.default.hookWebFullScreen(function (_exports) {
2712 | return exports.webFullscreen = webFullscreen = _exports;
2713 | });
2714 |
2715 | exports.webFullscreen = webFullscreen;
2716 |
2717 | /***/ }),
2718 | /* 15 */
2719 | /***/ (function(module, exports, __webpack_require__) {
2720 |
2721 | "use strict";
2722 |
2723 |
2724 | Object.defineProperty(exports, "__esModule", {
2725 | value: true
2726 | });
2727 | exports.flvInfo = undefined;
2728 |
2729 | var _hooker = __webpack_require__(0);
2730 |
2731 | var _hooker2 = _interopRequireDefault(_hooker);
2732 |
2733 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
2734 |
2735 | var flvInfo = void 0;
2736 | _hooker2.default.hookParseData(function (that) {
2737 | return exports.flvInfo = flvInfo = that.flvInfo;
2738 | });
2739 |
2740 | exports.flvInfo = flvInfo;
2741 |
2742 | /***/ })
2743 | /******/ ]);
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "iqiyi-player-switch",
3 | "version": "1.14.0",
4 | "description": "爱奇艺flash播放器与html5播放器随意切换,改善html5播放器播放体验。",
5 | "main": "src/index.js",
6 | "scripts": {
7 | "lint": "eslint src",
8 | "fix": "eslint src --fix",
9 | "clean": "node scripts/clean",
10 | "prewatch": "npm run clean",
11 | "watch": "webpack --watch -d",
12 | "dev": "npm run watch",
13 | "prebuild": "npm run clean",
14 | "build": "webpack --define process.env.NODE_ENV='production'",
15 | "precommit": "npm run lint"
16 | },
17 | "repository": {
18 | "type": "git",
19 | "url": "git+https://github.com/gooyie/userscript-iqiyi-player-switch.git"
20 | },
21 | "keywords": [
22 | "html5",
23 | "qiyi",
24 | "iqiyi",
25 | "player",
26 | "userscript"
27 | ],
28 | "author": "gooyie",
29 | "license": "MIT",
30 | "bugs": {
31 | "url": "https://github.com/gooyie/userscript-iqiyi-player-switch/issues"
32 | },
33 | "homepage": "https://github.com/gooyie/userscript-iqiyi-player-switch",
34 | "devDependencies": {
35 | "babel-cli": "^6.24.1",
36 | "babel-eslint": "^7.2.3",
37 | "babel-loader": "^7.1.4",
38 | "babel-plugin-transform-runtime": "^6.23.0",
39 | "babel-preset-env": "^1.6.1",
40 | "eslint": "^3.19.0",
41 | "eslint-loader": "^1.9.0",
42 | "fs-extra": "^3.0.1",
43 | "husky": "^0.13.4",
44 | "webpack": "^3.11.0"
45 | },
46 | "dependencies": {}
47 | }
48 |
--------------------------------------------------------------------------------
/scripts/clean.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs-extra');
2 |
3 | fs.emptyDirSync('dist');
4 |
--------------------------------------------------------------------------------
/src/cookies.js:
--------------------------------------------------------------------------------
1 |
2 | class Cookies {
3 | static get(key) {
4 | let value;
5 | if (new RegExp('^[^\\x00-\\x20\\x7f\\(\\)<>@,;:\\\\\\"\\[\\]\\?=\\{\\}\\/\\u0080-\\uffff]+$').test(key)) { // eslint-disable-line no-control-regex
6 | let re = new RegExp('(^| )' + key + '=([^;]*)(;|$)');
7 | let rs = re.exec(document.cookie);
8 | value = rs ? rs[2] : '';
9 | }
10 | return value ? decodeURIComponent(value) : '';
11 | }
12 |
13 | static set(k, v, o={}) {
14 | let n = o.expires;
15 | if ('number' == typeof o.expires) {
16 | n = new Date();
17 | n.setTime(n.getTime() + o.expires);
18 | }
19 | let key = k;
20 | let value = encodeURIComponent(v);
21 | let path = o.path ? '; path=' + o.path : '';
22 | let expires = n ? '; expires=' + n.toGMTString() : '';
23 | let domain = o.domain ? '; domain=' + o.domain : '';
24 | document.cookie = `${key}=${value}${path}${expires}${domain}`;
25 | }
26 |
27 | static remove(k, o={}) {
28 | o.expires = new Date(0);
29 | this.set(k, '', o);
30 | }
31 | }
32 |
33 | export default Cookies;
34 |
--------------------------------------------------------------------------------
/src/detector.js:
--------------------------------------------------------------------------------
1 |
2 | class Detector {
3 | static isSupportHtml5() {
4 | let v = document.createElement('video');
5 | return !!(
6 | v.canPlayType('audio/mp4; codecs="mp4a.40.2"') &&
7 | v.canPlayType('video/mp4; codecs="avc1.640029"') &&
8 | v.canPlayType('video/mp4; codecs="avc1.640029, mp4a.40.2"')
9 | );
10 | }
11 |
12 | static isSupportVms() {
13 | return !!(
14 | window.MediaSource && window.URL && window.WebSocket && window.ReadableStream &&
15 | (window.RTCSessionDescription || window.webkitRTCSessionDescription) &&
16 | (window.RTCPeerConnection || window.webkitRTCPeerConnection) &&
17 | (window.RTCIceCandidate || window.webkitRTCIceCandidate)
18 | );
19 | }
20 |
21 | static isSupportM3u8() {
22 | let v = document.createElement('video');
23 | return !!(
24 | v.canPlayType('application/x-mpegurl') &&
25 | v.canPlayType('application/vnd.apple.mpegurl')
26 | );
27 | }
28 |
29 | static isChrome() {
30 | return /chrome/i.test(navigator.userAgent);
31 | }
32 |
33 | static isFirefox() {
34 | return /firefox/i.test(navigator.userAgent);
35 | }
36 |
37 | static isEdge() {
38 | return /edge/i.test(navigator.userAgent);
39 | }
40 |
41 | static isInIFrame() {
42 | return window.top !== window.self;
43 | }
44 |
45 | static isOutsite() {
46 | return !/\.iqiyi\.com$/.test(location.host);
47 | }
48 |
49 | static isOutsideLink() {
50 | return location.hash === '#outsidelink';
51 | }
52 |
53 | static hasFlashPlugin() {
54 | const plugins = unsafeWindow.navigator.plugins;
55 | return !!(plugins['Shockwave Flash'] && plugins['Shockwave Flash'].description);
56 | }
57 | }
58 |
59 | export default Detector;
60 |
--------------------------------------------------------------------------------
/src/faker.js:
--------------------------------------------------------------------------------
1 |
2 | class Faker {
3 | static fakeMacPlatform() {
4 | const PLAFORM_MAC = 'mac';
5 | Object.defineProperty(unsafeWindow.navigator, 'platform', {get: () => PLAFORM_MAC});
6 | }
7 |
8 | static fakeSafari() {
9 | const UA_SAFARY = 'safari';
10 | Object.defineProperty(unsafeWindow.navigator, 'userAgent', {get: () => UA_SAFARY});
11 | }
12 |
13 | static fakeChrome(ver = '') {
14 | const UA_CHROME = `Chrome/${ver}`;
15 | Object.defineProperty(unsafeWindow.navigator, 'userAgent', {get: () => UA_CHROME});
16 | }
17 |
18 | static fakeFlashPlugin() {
19 | let plugin = {
20 | description: 'Shockwave Flash 26.0 r0',
21 | filename: 'pepflashplayer64_26_0_0_131.dll',
22 | length: 0,
23 | name: 'Shockwave Flash',
24 | };
25 |
26 | Reflect.setPrototypeOf(plugin, Plugin.prototype);
27 | unsafeWindow.navigator.plugins['Shockwave Flash'] = plugin;
28 | }
29 | }
30 |
31 | export default Faker;
32 |
--------------------------------------------------------------------------------
/src/fullscreen.js:
--------------------------------------------------------------------------------
1 | import Hooker from './hooker';
2 |
3 | let fullscreen;
4 | Hooker.hookFullScreen(_exports => fullscreen = _exports);
5 |
6 | export { fullscreen };
7 |
--------------------------------------------------------------------------------
/src/hooker.js:
--------------------------------------------------------------------------------
1 | import Logger from './logger';
2 |
3 | class Hooker {
4 | static _hookCall(cb) {
5 | const call = Function.prototype.call;
6 | Function.prototype.call = function(...args) {
7 | let ret = call.apply(this, args);
8 | try {
9 | if (args && cb(args)) {
10 | Function.prototype.call = call;
11 | cb = () => {};
12 | Logger.info(`The native function call has been restored`);
13 | }
14 | } catch (err) {
15 | Logger.error(err.stack);
16 | }
17 | return ret;
18 | };
19 | this._hookCall = null;
20 | }
21 |
22 | static _isModuleCall(args) { // module.exports, module, module.exports, require
23 | return args.length === 4 && args[1] && Object.getPrototypeOf(args[1]) === Object.prototype && args[1].hasOwnProperty('exports');
24 | }
25 |
26 | static _hookModuleCall(cb, pred) {
27 | const callbacksMap = new Map([[pred, [cb]]]);
28 | this._hookCall((args) => {
29 | if (!this._isModuleCall(args)) return;
30 |
31 | const exports = args[1].exports;
32 | for (const [pred, callbacks] of callbacksMap) {
33 | if (!pred.apply(this, [exports])) continue;
34 | callbacks.forEach(cb => cb(exports, args));
35 | this.keepalive || callbacksMap.delete(pred);
36 | !callbacksMap.size && (this._hookModuleCall = null);
37 | break;
38 | }
39 |
40 | return !callbacksMap.size;
41 | });
42 |
43 | this._hookModuleCall = (cb, pred) => {
44 | if (callbacksMap.has(pred)) {
45 | callbacksMap.get(pred).push(cb);
46 | } else {
47 | callbacksMap.set(pred, [cb]);
48 | }
49 | };
50 | }
51 |
52 | static _isJqueryModuleCall(exports) {
53 | return exports.hasOwnProperty('fn') && exports.fn.hasOwnProperty('jquery');
54 | }
55 |
56 | static hookJquery(cb = ()=>{}) {
57 | this._hookModuleCall(cb, this._isJqueryModuleCall);
58 | }
59 |
60 | static hookJqueryAjax(cb) {
61 | this.hookJquery((exports) => {
62 | const ajax = exports.ajax.bind(exports);
63 | exports.ajax = function(url, options = {}) {
64 | if (typeof url === 'object') {
65 | [url, options] = [url.url, url];
66 | }
67 | let isHijacked = cb(url, options);
68 | if (isHijacked) return;
69 | return ajax(url, options);
70 | };
71 | });
72 | }
73 |
74 | static _isHttpModuleCall(exports) {
75 | return exports.hasOwnProperty('jsonp') && exports.hasOwnProperty('ajax');
76 | }
77 |
78 | static hookHttp(cb) {
79 | this._hookModuleCall(cb, this._isHttpModuleCall);
80 | }
81 |
82 | static hookHttpJsonp(cb) {
83 | this.hookHttp((exports) => {
84 | const jsonp = exports.jsonp.bind(exports);
85 | exports.jsonp = function(options) {
86 | let isHijacked = cb(options);
87 | if (isHijacked) return;
88 | return jsonp(options);
89 | };
90 | });
91 | }
92 |
93 | static _isLogoModuleCall(exports) {
94 | return 'function' === typeof exports && exports.prototype.hasOwnProperty('showLogo');
95 | }
96 |
97 | static hookLogo(cb) {
98 | this._hookModuleCall(cb, this._isLogoModuleCall);
99 | }
100 |
101 | static _isFullScreenModuleCall(exports) {
102 | return exports.__proto__ && exports.__proto__.hasOwnProperty('isFullScreen');
103 | }
104 |
105 | static hookFullScreen(cb) {
106 | this._hookModuleCall(cb, this._isFullScreenModuleCall);
107 | }
108 |
109 | static _isWebFullScreenModuleCall(exports) {
110 | return exports.__proto__ && exports.__proto__.hasOwnProperty('isWebFullScreen');
111 | }
112 |
113 | static hookWebFullScreen(cb) {
114 | this._hookModuleCall(cb, this._isWebFullScreenModuleCall);
115 | }
116 |
117 | static hookWebFullScreenInit(cb) {
118 | this.hookWebFullScreen((exports) => {
119 | const init = exports.__proto__.init;
120 | exports.__proto__.init = function(wrapper, btn) {
121 | cb(this, wrapper, btn);
122 | init.apply(this, [wrapper, btn]);
123 | };
124 | });
125 | }
126 |
127 | static _isPluginControlsModuleCall(exports) {
128 | return 'function' === typeof exports && exports.prototype.hasOwnProperty('initFullScreen');
129 | }
130 |
131 | static hookPluginControls(cb) {
132 | this._hookModuleCall(cb, this._isPluginControlsModuleCall);
133 | }
134 |
135 | static hookPluginControlsInit(cb) {
136 | this.hookPluginControls((exports) => {
137 | const init = exports.prototype.init;
138 | exports.prototype.init = function() {
139 | cb(this);
140 | init.apply(this);
141 | };
142 | });
143 | }
144 |
145 | static hookInitFullScreen(cb) {
146 | this.hookPluginControls((exports) => {
147 | const initFullScreen = exports.prototype.initFullScreen;
148 | exports.prototype.initFullScreen = function() {
149 | cb(this);
150 | initFullScreen.apply(this);
151 | };
152 | });
153 | }
154 |
155 | static _isCoreModuleCall(exports) {
156 | return 'function' === typeof exports &&
157 | exports.prototype.hasOwnProperty('getdefaultvds') &&
158 | exports.prototype.hasOwnProperty('getMovieInfo');
159 | }
160 |
161 | static hookCore(cb) {
162 | this._hookModuleCall(cb, this._isCoreModuleCall);
163 | }
164 |
165 | static _isSkinBaseModuleCall(exports) {
166 | return 'function' === typeof exports && exports.prototype.hasOwnProperty('_checkPlugin');
167 | }
168 |
169 | static hookSkinBase(cb) {
170 | this._hookModuleCall(cb, this._isSkinBaseModuleCall);
171 | }
172 |
173 | static _isPluginHotKeysModuleCall(exports) {
174 | return 'function' === typeof exports && exports.prototype.hasOwnProperty('_keydown');
175 | }
176 |
177 | static hookPluginHotKeys(cb) {
178 | this._hookModuleCall(cb, this._isPluginHotKeysModuleCall);
179 | }
180 |
181 | static _isFragmentModuleCall(exports) {
182 | return 'function' === typeof exports && exports.prototype.hasOwnProperty('parseData');
183 | }
184 |
185 | static hookFragment(cb) {
186 | this._hookModuleCall(cb, this._isFragmentModuleCall);
187 | }
188 |
189 | static hookParseData(cb) {
190 | this.hookFragment((exports) => {
191 | const parseData = exports.prototype.parseData;
192 | exports.prototype.parseData = function(...args) {
193 | parseData.apply(this, args);
194 | cb(this);
195 | };
196 | });
197 | }
198 |
199 | static _isUserModuleCall(exports) {
200 | return exports.__proto__ && exports.__proto__.hasOwnProperty('isVip');
201 | }
202 |
203 | static hookUser(cb) {
204 | this._hookModuleCall(cb, this._isUserModuleCall);
205 | }
206 |
207 | static _isShowRequestModuleCall(exports) {
208 | return 'function' === typeof exports && exports.compressRequestKey && exports.prototype.hasOwnProperty('request');
209 | }
210 |
211 | static hookShowRequest(cb) {
212 | this._hookModuleCall(cb, this._isShowRequestModuleCall);
213 | }
214 |
215 | static _isDefaultSkinModuleCall(exports) {
216 | return 'function' === typeof exports && exports.prototype.hasOwnProperty('_initDBClicks');
217 | }
218 |
219 | static hookDefaultSkin(cb) {
220 | this._hookModuleCall(cb, this._isDefaultSkinModuleCall);
221 | }
222 |
223 | static _isConfigModuleCall(exports) {
224 | return exports.loadType && exports.dispatchCfg;
225 | }
226 |
227 | static hookConfig(cb) {
228 | this._hookModuleCall(cb, this._isConfigModuleCall);
229 | }
230 | }
231 |
232 | Hooker.keepalive = false;
233 |
234 | export default Hooker;
235 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import Logger from './logger';
2 | import Cookies from './cookies';
3 | import Detector from './detector';
4 | import Faker from './faker';
5 | import { replaceFlash, adaptIframe } from './outsite';
6 | import {
7 | vipPatch,
8 | adsPatch,
9 | controlsPatch,
10 | watermarksPatch,
11 | keepHookingPatch,
12 | keyShortcutsPatch,
13 | mouseShortcutsPatch,
14 | useWebSocketLoaderPatch,
15 | } from './patch';
16 |
17 | const PLAYER_TYPE = {
18 | Html5VOD: 'h5_VOD',
19 | FlashVOD: 'flash_VOD'
20 | };
21 |
22 | function forceHtml5() {
23 | Cookies.set('player_forcedType', PLAYER_TYPE.Html5VOD, {domain: '.iqiyi.com'});
24 | Logger.info(`The 'player_forcedType' cookie has been set as '${PLAYER_TYPE.Html5VOD}'`);
25 | }
26 |
27 | function forceFlash() {
28 | Cookies.set('player_forcedType', PLAYER_TYPE.FlashVOD, {domain: '.iqiyi.com'});
29 | Logger.info(`The 'player_forcedType' cookie has been set as '${PLAYER_TYPE.FlashVOD}'`);
30 | }
31 |
32 | function clean() {
33 | Cookies.remove('player_forcedType', {domain: '.iqiyi.com'});
34 | Logger.info(`Removed the 'player_forcedType' cookie`);
35 | }
36 |
37 | function switchTo(type) {
38 | Logger.info(`Switching to ${type} ...`);
39 | GM_setValue('player_forcedType', type);
40 | document.location.reload();
41 | }
42 |
43 | function registerMenu() {
44 | const MENU_NAME = {
45 | HTML5: 'HTML5播放器',
46 | FLASH: 'Flash播放器'
47 | };
48 |
49 | let currType = GM_getValue('player_forcedType', PLAYER_TYPE.Html5VOD); // 默认为Html5播放器,免去切换。
50 | let [type, name] = currType === PLAYER_TYPE.Html5VOD ? [PLAYER_TYPE.FlashVOD, MENU_NAME.FLASH] : [PLAYER_TYPE.Html5VOD, MENU_NAME.HTML5];
51 | GM_registerMenuCommand(name, () => switchTo(type), null);
52 | Logger.info(`Registered the menu.`);
53 | }
54 |
55 | function mustKeepHooking() {
56 | return location.search.includes('list'); // https://github.com/gooyie/userscript-iqiyi-player-switch/issues/15
57 | }
58 |
59 | //=============================================================================
60 |
61 | registerMenu();
62 |
63 | let currType = GM_getValue('player_forcedType', PLAYER_TYPE.Html5VOD);
64 | if (currType === PLAYER_TYPE.Html5VOD) {
65 | if (Detector.isSupportHtml5()) {
66 | if (Detector.isOutsite()) {
67 | replaceFlash();
68 | } else {
69 | forceHtml5();
70 |
71 | if (Detector.isFirefox()) {
72 | // Fake Chrome with a version number less than 43
73 | // to use the data engine to play videos better than HD and to use the XHR loader
74 | // because Firefox has not yet implemented ReadableStream to support the Fetch loader.
75 | Faker.fakeChrome(42);
76 | }
77 |
78 | if (mustKeepHooking()) {
79 | keepHookingPatch.install();
80 | }
81 | adsPatch.install();
82 | controlsPatch.install();
83 | watermarksPatch.install();
84 | vipPatch.install();
85 | keyShortcutsPatch.install();
86 | mouseShortcutsPatch.install();
87 | useWebSocketLoaderPatch.install();
88 |
89 | if (Detector.isInIFrame() && Detector.isOutsideLink()) {
90 | adaptIframe();
91 | }
92 | }
93 | } else {
94 | alert('╮(╯▽╰)╭ 你的浏览器播放不了html5视频~~~~');
95 | }
96 | } else {
97 | forceFlash();
98 | }
99 |
100 | window.addEventListener('unload', () => clean());
101 |
--------------------------------------------------------------------------------
/src/logger.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-console */
2 | class Logger {
3 | constructor(tag) {
4 | this._tag = tag;
5 | }
6 |
7 | get tag() {
8 | return this._tag;
9 | }
10 |
11 | log(...args) {
12 | console.log(this.tag + args.shift(), ...args);
13 | }
14 |
15 | info(...args) {
16 | console.log('%c' + this.tag + '%c' + args.shift(),
17 | 'color: green; font-weight: bolder', 'color: blue', ...args);
18 | }
19 |
20 | debug(...args) {
21 | console.debug(this.tag + args.shift(), ...args);
22 | }
23 |
24 | warn(...args) {
25 | console.warn(this.tag + args.shift(), ...args);
26 | }
27 |
28 | error(...args) {
29 | console.error(this.tag + args.shift(), ...args);
30 | }
31 | }
32 |
33 | export default new Logger(`[${GM_info.script.name}]`);
34 |
--------------------------------------------------------------------------------
/src/meta.js:
--------------------------------------------------------------------------------
1 | const pkg = require('../package');
2 |
3 | module.exports = `
4 | // ==UserScript==
5 | // @name ${pkg.name}
6 | // @namespace ${pkg.homepage}
7 | // @homepageURL ${pkg.homepage}
8 | // @supportURL ${pkg.bugs.url}
9 | // @updateURL https://raw.githubusercontent.com/${pkg.author}/userscript-iqiyi-player-switch/master/dist/${pkg.name}.user.js
10 | // @description ${pkg.description}
11 | // @version ${pkg.version}
12 | // @compatible chrome >= 43
13 | // @compatible firefox >= 45
14 | // @compatible edge >= 15
15 | // @author ${pkg.author}
16 | // @license ${pkg.license} License
17 | //
18 | // @include *://*.iqiyi.com/*
19 | // @include *://v.baidu.com/*
20 | // @include *://music.baidu.com/mv/*
21 | // @include *://www.zybus.com/*
22 | // @grant GM_registerMenuCommand
23 | // @grant GM_xmlhttpRequest
24 | // @grant GM_addStyle
25 | // @grant GM_getValue
26 | // @grant GM_setValue
27 | // @grant GM_info
28 | // @grant unsafeWindow
29 | // @connect qiyi.com
30 | // @run-at document-start
31 | // ==/UserScript==
32 | `;
33 |
--------------------------------------------------------------------------------
/src/outsite.js:
--------------------------------------------------------------------------------
1 | import Logger from './logger';
2 | import Hooker from './hooker';
3 | import Faker from './faker';
4 | import Detector from './detector';
5 | import { getVideoUrl, findVid, findTvid } from './utils';
6 |
7 | async function embedSrc(targetNode, {tvid, vid}) {
8 | targetNode.innerHTML = `正在获取视频源...
`;
9 |
10 | try {
11 | let url = await getVideoUrl(tvid, vid);
12 | Logger.info('source url: %s', url);
13 | targetNode.innerHTML = ``;
14 | } catch (err) {
15 | targetNode.innerHTML = ``;
16 | }
17 | }
18 |
19 | function replaceFlash() {
20 | if (!Detector.hasFlashPlugin()) Faker.fakeFlashPlugin();
21 |
22 | const observer = new MutationObserver((records, self) => {
23 | for (let record of records) {
24 | if (record.type !== 'childList' || !record.addedNodes) continue;
25 |
26 | for (let node of record.addedNodes) {
27 | if (node.nodeName !== 'OBJECT' && node.nodeName !== 'EMBED') continue;
28 | Logger.info('found node', node);
29 |
30 | let text = node.outerHTML;
31 | let vid = findVid(text);
32 | let tvid = findTvid(text);
33 |
34 | if (tvid && vid) {
35 | Logger.info('found tvid: %s, vid: %s', tvid, vid);
36 | embedSrc(node.parentNode, {tvid, vid});
37 | self.disconnect();
38 | Logger.info('stoped observation');
39 | }
40 | }
41 | }
42 | });
43 |
44 | observer.observe(document.body || document.documentElement, {subtree: true, childList: true});
45 | Logger.info('started observation');
46 | }
47 |
48 | function adaptIframe() {
49 | let style = `
50 | body[class|="qypage"] {
51 | overflow: hidden !important;
52 | background: #000 !important;
53 | visibility: hidden;
54 | }
55 |
56 | .mod-func {
57 | display: none !important;
58 | }
59 |
60 | .${GM_info.script.name}.info {
61 | width: 20em;
62 | height: 5em;
63 | position: absolute;
64 | top: 0;
65 | bottom: 0;
66 | left: 0;
67 | right: 0;
68 | margin: auto;
69 | text-align: center;
70 | line-height: 5em;
71 | font-size: 1em;
72 | color: #ccc;
73 | }
74 |
75 | .${GM_info.script.name}.error {
76 | height: 3em;
77 | position: absolute;
78 | top: 0;
79 | bottom: 0;
80 | left: 0;
81 | right: 0;
82 | margin: auto;
83 | text-align: center;
84 | font-size: 1em;
85 | color: #c00;
86 | }
87 | `;
88 |
89 | GM_addStyle(style);
90 |
91 | Hooker.hookWebFullScreen((exports) => {
92 | const init = exports.__proto__.init;
93 | exports.__proto__.init = function(wrapper, btn) {
94 | init.apply(this, [wrapper, btn]);
95 | this.enter();
96 |
97 | btn[0].style.display = 'none';
98 | document.body.style.visibility = 'visible';
99 | };
100 |
101 | exports.__proto__.exit = () => {};
102 | });
103 |
104 | Hooker.hookCore((exports) => {
105 | exports.prototype.hasNextVideo = () => null;
106 | });
107 | }
108 |
109 | export { replaceFlash, adaptIframe };
110 |
--------------------------------------------------------------------------------
/src/parsed-data.js:
--------------------------------------------------------------------------------
1 | import Hooker from './hooker';
2 |
3 | let flvInfo;
4 | Hooker.hookParseData(that => flvInfo = that.flvInfo);
5 |
6 | export { flvInfo };
7 |
--------------------------------------------------------------------------------
/src/patch.js:
--------------------------------------------------------------------------------
1 | import Logger from './logger';
2 | import Hooker from './hooker';
3 | import { fullscreen } from './fullscreen';
4 | import { webFullscreen } from './web-fullscreen';
5 | import { flvInfo } from './parsed-data';
6 |
7 | class Patch {
8 | constructor() {
9 | this._installed = false;
10 | }
11 |
12 | install() {
13 | if (!this._installed) {
14 | this._installed = true;
15 | this._prepare();
16 | this._apply();
17 | }
18 | }
19 |
20 | _prepare() {}
21 |
22 | _apply() {}
23 | }
24 |
25 | class VipPatch extends Patch {
26 | constructor() {
27 | super();
28 | }
29 |
30 | _apply() {
31 | Hooker.hookUser((exports) => {
32 | const proto = exports.__proto__;
33 | proto.isVipSync = () => true;
34 | proto.isVip = (cb) => setTimeout(cb, 0, true);
35 | Logger.info('The vip patch has been installed');
36 | });
37 | }
38 | }
39 |
40 | class AdsPatch extends Patch {
41 | constructor() {
42 | super();
43 | }
44 |
45 | _fakeAdsData() {
46 | return {};
47 | }
48 |
49 | _apply() {
50 | Hooker.hookShowRequest((exports) => {
51 | const proto = exports.prototype;
52 | proto.request = (cb) => setTimeout(cb, 0, this._fakeAdsData());
53 | Logger.info('The ads patch has been installed');
54 | });
55 | }
56 | }
57 |
58 | class WatermarksPatch extends Patch {
59 | constructor() {
60 | super();
61 | }
62 |
63 | _apply() {
64 | Hooker.hookLogo((exports) => {
65 | exports.prototype.showLogo = () => {};
66 | Logger.info('The watermarks patch has been installed');
67 | });
68 | }
69 | }
70 |
71 | class ControlsPatch extends Patch { // Prevent the player controls were disabled.
72 | constructor() {
73 | super();
74 | }
75 |
76 | _apply() {
77 | Hooker.hookSkinBase((exports) => {
78 | exports.prototype._checkPlugin = () => {}; // This function disables the player controls when playing ads and enables when done.
79 | Logger.info('The controls patch has been installed');
80 | });
81 | }
82 | }
83 |
84 | class CorePatch extends Patch {
85 | constructor() {
86 | super();
87 | }
88 |
89 | _prepare() {
90 | this._initShowTip();
91 | this._initPlaybackRate();
92 | }
93 |
94 | _initShowTip() {
95 | Hooker.hookPluginControlsInit((that) => {
96 | that.core.on('showtip', (event) => {
97 | that.setcontroltip.apply(that, [{str: event.data, x: that._process.offset().left, y: 3, cut: true, timeout: true}]);
98 | if (that.$plugin.hasClass('process_hidden')) {
99 | that._controltips.css('top', '-25px');
100 | } else if (that.$plugin.hasClass('bottom-hide')) {
101 | that._controltips.css('top', '-38px');
102 | }
103 | });
104 | });
105 | }
106 |
107 | _initPlaybackRate() {
108 | Hooker.hookPluginControls((exports) => {
109 | exports.prototype.initPlaybackRate = function() {
110 | const core = this.core;
111 |
112 | let rate = parseFloat(localStorage.getItem('QiyiPlayerPlaybackRate'));
113 | rate = isNaN(rate) ? 1 : rate;
114 |
115 | if (core.getCurrStatus() === 'playing') {
116 | core.setPlaybackRate(rate);
117 | } else {
118 | const onstatuschanged = (evt) => {
119 | if (evt.data.state === 'playing') {
120 | core.setPlaybackRate(rate);
121 | core.un('statusChanged', onstatuschanged);
122 | }
123 | };
124 | core.on('statusChanged', onstatuschanged);
125 | }
126 |
127 | const $ul = this.$playbackrateUl;
128 | $ul.find(`[data-pbrate="${rate}"]`).addClass('selected');
129 |
130 | const $items = $ul.find('li');
131 | $items.on('click', function() {
132 | const rate = parseFloat(this.getAttribute('data-pbrate'));
133 | if (!this.classList.contains('selected')) {
134 | $items.removeClass('selected');
135 | this.classList.add('selected');
136 | }
137 | localStorage.setItem('QiyiPlayerPlaybackRate', rate);
138 | core.setPlaybackRate(rate);
139 | });
140 |
141 | this.$playsettingicon.on('click', function() {
142 | const rate = core.getPlaybackRate();
143 | const $item = $ul.find(`[data-pbrate="${rate}"]`);
144 | if ($item.length === 1) {
145 | if (!$item.hasClass('selected')) {
146 | $items.removeClass('selected');
147 | $item.addClass('selected');
148 | }
149 | } else {
150 | $items.removeClass('selected');
151 | }
152 | });
153 | };
154 | });
155 | }
156 |
157 | _apply() {
158 | Hooker.hookCore((exports) => {
159 | const proto = exports.prototype;
160 |
161 | proto._showTip = function(msg) {
162 | this.fire({type: 'showtip', data: msg});
163 | };
164 |
165 | proto.getFPS = function() {
166 | if (flvInfo) {
167 | return flvInfo.videoConfigTag.sps.frame_rate.fps;
168 | } else {
169 | return 25; // f4v极速以上,动画23.976、电影24、电视剧25。
170 | }
171 | };
172 |
173 | proto.prevFrame = function() {
174 | const video = this.video();
175 | const seekTime = Math.max(0, Math.min(this.getDuration(), video.currentTime - 1 / this.getFPS()));
176 | video.currentTime = seekTime;
177 | this._showTip('上一帧');
178 | };
179 |
180 | proto.nextFrame = function() {
181 | const video = this.video();
182 | const seekTime = Math.max(0, Math.min(this.getDuration(), video.currentTime + 1 / this.getFPS()));
183 | video.currentTime = seekTime;
184 | this._showTip('下一帧');
185 | };
186 |
187 | proto.seek = function(...args) {
188 | const video = this.video();
189 | const playbackRate = video.playbackRate;
190 | this._engine.seek(...args);
191 | video.playbackRate = playbackRate;
192 | };
193 |
194 | proto.stepSeek = function(stepTime) {
195 | const seekTime = Math.max(0, Math.min(this.getDuration(), this.getCurrenttime() + stepTime));
196 | let msg;
197 |
198 | if (Math.abs(stepTime) < 60) {
199 | msg = stepTime > 0 ? `步进:${stepTime}秒` : `步退:${Math.abs(stepTime)}秒`;
200 | } else {
201 | msg = stepTime > 0 ? `步进:${stepTime/60}分钟` : `步退:${Math.abs(stepTime)/60}分钟`;
202 | }
203 | this._showTip(msg);
204 |
205 | this.seek(seekTime, true);
206 | };
207 |
208 | proto.rangeSeek = function(range) {
209 | const duration = this.getDuration();
210 | const seekTime = Math.max(0, Math.min(duration, duration * range));
211 | this.seek(seekTime, true);
212 | this._showTip('定位:' + (range * 100).toFixed(0) + '%');
213 | };
214 |
215 | proto.toggleMute = function() {
216 | if (this.getMuted()) {
217 | this.setMuted(false);
218 | this._showTip('取消静音');
219 | } else {
220 | this.setMuted(true);
221 | this._showTip('静音');
222 | }
223 | };
224 |
225 | proto.adjustVolume = function(value) {
226 | let volume = this.getVolume() + value;
227 | volume = Math.max(0, Math.min(1, volume.toFixed(2)));
228 | this.setVolume(volume);
229 | this.fire({type: 'keyvolumechange'});
230 | };
231 |
232 | proto.getPlaybackRate = function() { // iqiyi 的这个方法有bug,没把值返回!
233 | return this._engine.getPlaybackRate();
234 | };
235 |
236 | proto.adjustPlaybackRate = function(value) {
237 | const currRate = this.getPlaybackRate();
238 | const rate = Math.max(0.2, Math.min(5, parseFloat((currRate + value).toFixed(1))));
239 |
240 | localStorage.setItem('QiyiPlayerPlaybackRate', rate);
241 | this.setPlaybackRate(rate);
242 | this._showTip(`播放速率:${rate}`);
243 | };
244 |
245 | proto.turnPlaybackRate = function() {
246 | const currRate = this.getPlaybackRate();
247 | let rate;
248 | if (currRate !== 1) {
249 | this._backRate = currRate;
250 | rate = 1;
251 | } else {
252 | rate = this._backRate || 1;
253 | }
254 |
255 | this.setPlaybackRate(rate);
256 | this._showTip(`播放速率:${rate}`);
257 | };
258 |
259 | proto.hasPrevVideo = function() {
260 | return this._getVideoIndexInList(this._movieinfo.tvid) > 0 || this._getVideoIndexInList(this._movieinfo.oldTvid) > 0;
261 | };
262 |
263 | proto.playNext = function() {
264 | if (this.hasNextVideo()) {
265 | this._showTip('播放下一集');
266 | this.switchNextVideo();
267 | } else {
268 | this._showTip('没有下一集哦');
269 | }
270 | };
271 |
272 | proto.playPrev = function() {
273 | if (this.hasPrevVideo()) {
274 | this._showTip('播放上一集');
275 | this.switchPreVideo();
276 | } else {
277 | this._showTip('没有上一集哦');
278 | }
279 | };
280 |
281 | Logger.info('The core patch has been installed');
282 | });
283 | }
284 | }
285 |
286 | const corePatch = new CorePatch();
287 |
288 | class KeyShortcutsPatch extends Patch {
289 | constructor() {
290 | super();
291 | }
292 |
293 | _prepare() {
294 | corePatch.install();
295 | }
296 |
297 | _apply() {
298 | Hooker.hookPluginHotKeys((exports) => {
299 | const proto = exports.prototype;
300 |
301 | proto.init = function() {
302 | document.addEventListener('keydown', this._keydown.bind(this));
303 | };
304 |
305 | proto._isValidTarget = function(target) {
306 | return target.nodeName === 'BODY' || target.nodeName == 'VIDEO' || target.classList.contains('pw-video'); // 全局
307 | // return target.nodeName === 'VIDEO' || target.classList.contains('pw-video'); // 非全局
308 | };
309 |
310 | proto._keydown = function(event) {
311 | if (!this._isValidTarget(event.target)) return;
312 |
313 | const { keyCode, ctrlKey, shiftKey, altKey } = event;
314 | const core = this.core;
315 |
316 | switch (keyCode) {
317 | case 32: // Spacebar
318 | if (!ctrlKey && !shiftKey && !altKey) {
319 | if (core.isPaused()) {
320 | core.play(true);
321 | core._showTip('播放');
322 | } else {
323 | core.pause(true);
324 | core._showTip('暂停');
325 | }
326 | } else {
327 | return;
328 | }
329 | break;
330 | case 39: // → Arrow Right
331 | case 37: { // ← Arrow Left
332 | let stepTime;
333 | if (!ctrlKey && !shiftKey && !altKey) {
334 | stepTime = 39 === keyCode ? 5 : -5;
335 | } else if (ctrlKey && !shiftKey && !altKey) {
336 | stepTime = 39 === keyCode ? 30 : -30;
337 | } else if (!ctrlKey && shiftKey && !altKey) {
338 | stepTime = 39 === keyCode ? 60 : -60;
339 | } else if (ctrlKey && !shiftKey && altKey) {
340 | stepTime = 39 === keyCode ? 3e2 : -3e2; // 5分钟
341 | } else {
342 | return;
343 | }
344 |
345 | core.stepSeek(stepTime);
346 | break;
347 | }
348 | case 38: // ↑ Arrow Up
349 | case 40: // ↓ Arrow Down
350 | if (!ctrlKey && !shiftKey && !altKey) {
351 | core.adjustVolume(38 === keyCode ? 0.05 : -0.05);
352 | } else {
353 | return;
354 | }
355 | break;
356 | case 77: // M
357 | if (!ctrlKey && !shiftKey && !altKey) {
358 | core.toggleMute();
359 | } else {
360 | return;
361 | }
362 | break;
363 | case 13: // Enter
364 | if (!ctrlKey && !shiftKey && !altKey) {
365 | fullscreen.toggle();
366 | } else if (ctrlKey && !shiftKey && !altKey) {
367 | webFullscreen.toggle();
368 | } else {
369 | return;
370 | }
371 | break;
372 | case 67: // C
373 | case 88: // X
374 | if (!ctrlKey && !shiftKey && !altKey) {
375 | core.adjustPlaybackRate(67 === keyCode ? 0.1 : -0.1);
376 | } else {
377 | return;
378 | }
379 | break;
380 | case 90: // Z
381 | if (!ctrlKey && !shiftKey && !altKey) {
382 | core.turnPlaybackRate();
383 | } else {
384 | return;
385 | }
386 | break;
387 | case 68: // D
388 | case 70: // F
389 | if (!ctrlKey && !shiftKey && !altKey) {
390 | core.pause(true);
391 | if (keyCode === 68) {
392 | core.prevFrame();
393 | } else {
394 | core.nextFrame();
395 | }
396 | } else {
397 | return;
398 | }
399 | break;
400 | case 80: // P
401 | case 78: // N
402 | if (!ctrlKey && shiftKey && !altKey) {
403 | if (keyCode === 78) {
404 | core.playNext();
405 | } else {
406 | core.playPrev();
407 | }
408 | } else {
409 | return;
410 | }
411 | break;
412 | case 27: // ESC
413 | if (!event.ctrlKey && !event.shiftKey && !event.altKey)
414 | webFullscreen.isWebFullScreen() && webFullscreen.exit();
415 | return;
416 | default:
417 | if (keyCode >= 48 && keyCode <= 57) { // 0 ~ 9
418 | if (!ctrlKey && !shiftKey && !altKey) {
419 | core.rangeSeek((keyCode - 48) * 0.1);
420 | } else {
421 | return;
422 | }
423 | } else {
424 | return;
425 | }
426 | }
427 |
428 | event.preventDefault();
429 | event.stopPropagation();
430 | };
431 |
432 | Logger.info('The keyboard shortcuts patch has been installed');
433 | });
434 | }
435 | }
436 |
437 | class MouseShortcutsPatch extends Patch {
438 | constructor() {
439 | super();
440 | }
441 |
442 | _prepare() {
443 | corePatch.install();
444 | }
445 |
446 | _apply() {
447 | Hooker.hookDefaultSkin((exports) => {
448 | exports.prototype._initDBClicks = function() {
449 | let timer, core = this.core;
450 | this.videoWrapper.find('video').on('click', () => {
451 | if (timer) {
452 | clearTimeout(timer);
453 | timer = null;
454 | return;
455 | }
456 | timer = setTimeout(() => {
457 | if (core.isPaused()) {
458 | core.play(true);
459 | } else {
460 | core.pause(true);
461 | }
462 | timer = null;
463 | }, 200);
464 | }).on('dblclick', (event) => {
465 | event.preventDefault();
466 | event.stopPropagation();
467 | if (event.ctrlKey) {
468 | webFullscreen.toggle();
469 | } else {
470 | fullscreen.toggle();
471 | }
472 | }).on('wheel', (event) => {
473 | if (fullscreen.isFullScreen() || webFullscreen.isWebFullScreen()) {
474 | const delta = event.wheelDelta || event.detail || (event.deltaY && -event.deltaY);
475 | core.adjustVolume(delta > 0 ? 0.05 : -0.05);
476 | }
477 | });
478 | };
479 |
480 | Logger.info('The mouse shortcuts patch has been installed');
481 | });
482 | }
483 | }
484 |
485 | class UseWebSocketLoaderPatch extends Patch {
486 | constructor() {
487 | super();
488 | this.tryWs = GM_getValue('tryWs', false);
489 | }
490 |
491 | _prepare() {
492 | this._addSetting();
493 | }
494 |
495 | _apply() {
496 | const that = this;
497 | Hooker.hookFragment((exports) => {
498 | Reflect.defineProperty(exports.prototype, 'tryWS', {
499 | get: () => this._tryWs || that.tryWs, // Will use the WebSocket loader if the value of tryWs is true.
500 | set: (value) => this._tryWs = value, // The value of tryWs will be true if the Fetch loader fails.
501 | });
502 | Logger.info('The WebSocket loader patch has been installed');
503 | });
504 | }
505 |
506 | _addSetting() {
507 | const that = this;
508 | Hooker.hookPluginControls((exports) => {
509 | const initSetting = exports.prototype.initSetting;
510 | exports.prototype.initSetting = function() {
511 | const div = document.createElement('div');
512 | div.innerHTML = `
513 |
514 |
WebSocket
515 |
516 |
`;
517 | const item = div.querySelector('.setPop_item');
518 | this.$playsettingbox.find('.video_setPop_top').append(item);
519 | this.$usewebsocketBtn = this.$playsettingbox.find('[data-player-hook="usewebsocketloader"]');
520 |
521 | if (that.tryWs) {
522 | this.$usewebsocketBtn.removeClass('setPop_switch_close');
523 | }
524 | this.$usewebsocketBtn.on('click', () => {
525 | this.$usewebsocketBtn.toggleClass('setPop_switch_close');
526 | that.tryWs = !that.tryWs;
527 | GM_setValue('tryWs', that.tryWs);
528 | });
529 |
530 | initSetting.apply(this);
531 | };
532 | });
533 | }
534 | }
535 |
536 | class KeepHookingPatch extends Patch {
537 | constructor() {
538 | super();
539 | }
540 |
541 | _apply() {
542 | Hooker.keepalive = true;
543 | Logger.info('The keep hooking patch has been installed');
544 | }
545 | }
546 |
547 | export const vipPatch = new VipPatch();
548 | export const adsPatch = new AdsPatch();
549 | export const controlsPatch = new ControlsPatch();
550 | export const watermarksPatch = new WatermarksPatch();
551 | export const keepHookingPatch = new KeepHookingPatch();
552 | export const keyShortcutsPatch = new KeyShortcutsPatch();
553 | export const mouseShortcutsPatch = new MouseShortcutsPatch();
554 | export const useWebSocketLoaderPatch = new UseWebSocketLoaderPatch();
555 |
--------------------------------------------------------------------------------
/src/utils.js:
--------------------------------------------------------------------------------
1 |
2 | function getVideoUrl(tvid, vid) {
3 | return new Promise((resolve, reject) => {
4 | GM_xmlhttpRequest({
5 | url: `http://cache.video.qiyi.com/jp/vi/${tvid}/${vid}/?callback=callback`,
6 | method: 'GET',
7 | timeout: 8e3,
8 | onload: (details) => {
9 | try {
10 | let json = JSON.parse(/callback\s*\(\s*(\{.*\})\s*\)/.exec(details.responseText)[1]);
11 | resolve(json.vu);
12 | } catch (err) {
13 | reject(err);
14 | }
15 | },
16 | onerror: reject,
17 | onabort: reject,
18 | ontimeout: reject
19 | });
20 | });
21 | }
22 |
23 | function findVid(text) {
24 | let result = /vid=([\da-z]+)/i.exec(text);
25 | return result ? result[1] : null;
26 | }
27 |
28 | function findTvid(text) {
29 | let result = /tvid=(\d+)/i.exec(text);
30 | return result ? result[1] : null;
31 | }
32 |
33 | export { getVideoUrl, findVid, findTvid };
34 |
--------------------------------------------------------------------------------
/src/web-fullscreen.js:
--------------------------------------------------------------------------------
1 | import Hooker from './hooker';
2 |
3 | let webFullscreen;
4 | Hooker.hookWebFullScreen(_exports => webFullscreen = _exports);
5 |
6 | export { webFullscreen };
7 |
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | const webpack = require('webpack');
2 | const path = require('path');
3 |
4 | const pkg = require('./package');
5 | const meta = require('./src/meta');
6 | const srcPath = path.resolve(__dirname, 'src');
7 | const distPath = path.resolve(__dirname, 'dist');
8 |
9 | module.exports = [
10 | {
11 | context: srcPath,
12 | entry: {
13 | 'index': './index.js'
14 | },
15 | output: {
16 | path: distPath,
17 | filename: `./${pkg.name}.user.js`
18 | },
19 | module: {
20 | rules: [
21 | {
22 | enforce: 'pre',
23 | test: /\.js$/,
24 | include: [
25 | srcPath
26 | ],
27 | loader: 'eslint-loader',
28 | },
29 | {
30 | test: /\.js$/,
31 | include: [
32 | srcPath
33 | ],
34 | loader: 'babel-loader'
35 | }
36 | ]
37 | },
38 | plugins: [
39 | new webpack.optimize.ModuleConcatenationPlugin(),
40 | new webpack.BannerPlugin({
41 | banner: meta,
42 | raw: true,
43 | entryOnly: true,
44 | }),
45 | ]
46 | }
47 | ];
48 |
--------------------------------------------------------------------------------