Greasy Fork is available in English.

斗鱼HTML5播放器

基于 flv.js 的斗鱼HTML5播放器.

  1. // ==UserScript==
  2. // @description 基于 flv.js 的斗鱼HTML5播放器.
  3. // @icon https://ojiju7xvu.qnssl.com/d5hp/icon.png
  4. // @name 斗鱼HTML5播放器
  5. // @require https://cdn.bootcss.com/flv.js/1.3.3/flv.min.js
  6. // @namespace http://imspace.cn/gms
  7. // @run-at document_end
  8. // @version 0.7.4
  9. // @grant GM_xmlhttpRequest
  10. // @match *://*.douyu.com/*
  11. // ==/UserScript==
  12.  
  13. class GMXMLHttpRequest {
  14. constructor () {
  15. this.config = {
  16. headers: {}
  17. }
  18. this.xhr = null
  19. }
  20. open (method, url) {
  21. this.config.method = method
  22. this.config.url = url
  23. }
  24. send () {
  25. for (let key of Object.keys(this)) {
  26. if (key === 'config') continue
  27. if (key.substr(0, 2) === 'on') {
  28. this.config[key] = this.wrapper(this[key])
  29. } else {
  30. this.config[key] = this[key]
  31. }
  32. }
  33. this.xhr = GM_xmlhttpRequest(this.config)
  34. }
  35. setRequestHeader (key, value) {
  36. this.config.headers[key] = value
  37. }
  38. abort () {
  39. this.xhr && this.xhr.abort()
  40. }
  41. wrapper (func) {
  42. return e => {
  43. e.target = this.xhr
  44. if (e.response) {
  45. e.target.response = e.response
  46. }
  47. func(e)
  48. }
  49. }
  50. get status () {
  51. return this.xhr ? this.xhr.status : 0
  52. }
  53. get readyState () {
  54. return this.xhr ? this.xhr.readyState : 0
  55. }
  56. }
  57. window.fetch = function (url, config) {
  58. let conf = {}
  59. Object.assign(conf, config || { method: 'GET' })
  60. conf.url = url
  61. conf.data = config ? config.body : null
  62. conf.responseType = 'arraybuffer'
  63. return new Promise((resolve, reject) => {
  64. conf.onload = (response) => {
  65. if (response.status === 200) {
  66. resolve({
  67. json () {
  68. const enc = new TextDecoder('utf-8')
  69. return Promise.resolve(JSON.parse(enc.decode(new Uint8Array(response.response))))
  70. },
  71. arrayBuffer () {
  72. return Promise.resolve(response.response)
  73. }
  74. })
  75. } else {
  76. reject(response)
  77. }
  78. }
  79. GM_xmlhttpRequest(conf)
  80. })
  81. }
  82. window.XMLHttpRequest = GMXMLHttpRequest
  83. window.__space_inject = {script: "(function (global, factory) {\n"+
  84. " typeof exports === 'object' && typeof module !== 'undefined' ? factory() :\n"+
  85. " typeof define === 'function' && define.amd ? define(factory) :\n"+
  86. " (factory());\n"+
  87. "}(this, (function () { 'use strict';\n"+
  88. "\n"+
  89. " /*! *****************************************************************************\r\n"+
  90. " Copyright (c) Microsoft Corporation. All rights reserved.\r\n"+
  91. " Licensed under the Apache License, Version 2.0 (the \"License\"); you may not use\r\n"+
  92. " this file except in compliance with the License. You may obtain a copy of the\r\n"+
  93. " License at http://www.apache.org/licenses/LICENSE-2.0\r\n"+
  94. "\r\n"+
  95. " THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\r\n"+
  96. " KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED\r\n"+
  97. " WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,\r\n"+
  98. " MERCHANTABLITY OR NON-INFRINGEMENT.\r\n"+
  99. "\r\n"+
  100. " See the Apache Version 2.0 License for specific language governing permissions\r\n"+
  101. " and limitations under the License.\r\n"+
  102. " ***************************************************************************** */\r\n"+
  103. " /* global Reflect, Promise */\r\n"+
  104. "\r\n"+
  105. " var extendStatics = Object.setPrototypeOf ||\r\n"+
  106. " ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||\r\n"+
  107. " function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };\r\n"+
  108. "\r\n"+
  109. "\r\n"+
  110. "\r\n"+
  111. "\r\n"+
  112. "\r\n"+
  113. "\r\n"+
  114. "\r\n"+
  115. " function __decorate(decorators, target, key, desc) {\r\n"+
  116. " var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\r\n"+
  117. " if (typeof Reflect === \"object\" && typeof Reflect.decorate === \"function\") r = Reflect.decorate(decorators, target, key, desc);\r\n"+
  118. " else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;\r\n"+
  119. " return c > 3 && r && Object.defineProperty(target, key, r), r;\r\n"+
  120. " }\r\n"+
  121. "\r\n"+
  122. "\r\n"+
  123. "\r\n"+
  124. "\r\n"+
  125. "\r\n"+
  126. " function __awaiter(thisArg, _arguments, P, generator) {\r\n"+
  127. " return new (P || (P = Promise))(function (resolve, reject) {\r\n"+
  128. " function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }\r\n"+
  129. " function rejected(value) { try { step(generator.throw(value)); } catch (e) { reject(e); } }\r\n"+
  130. " function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }\r\n"+
  131. " step((generator = generator.apply(thisArg, _arguments || [])).next());\r\n"+
  132. " });\r\n"+
  133. " }\r\n"+
  134. "\r\n"+
  135. "\r\n"+
  136. "\r\n"+
  137. "\r\n"+
  138. "\r\n"+
  139. "\r\n"+
  140. "\r\n"+
  141. " function __read(o, n) {\r\n"+
  142. " var m = typeof Symbol === \"function\" && o[Symbol.iterator];\r\n"+
  143. " if (!m) return o;\r\n"+
  144. " var i = m.call(o), r, ar = [], e;\r\n"+
  145. " try {\r\n"+
  146. " while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);\r\n"+
  147. " }\r\n"+
  148. " catch (error) { e = { error: error }; }\r\n"+
  149. " finally {\r\n"+
  150. " try {\r\n"+
  151. " if (r && !r.done && (m = i[\"return\"])) m.call(i);\r\n"+
  152. " }\r\n"+
  153. " finally { if (e) throw e.error; }\r\n"+
  154. " }\r\n"+
  155. " return ar;\r\n"+
  156. " }\r\n"+
  157. "\r\n"+
  158. "\r\n"+
  159. "\r\n"+
  160. " function __await(v) {\r\n"+
  161. " return this instanceof __await ? (this.v = v, this) : new __await(v);\r\n"+
  162. " }\n"+
  163. "\n"+
  164. " class JSocket {\r\n"+
  165. " static init() {\r\n"+
  166. " return __awaiter(this, void 0, void 0, function* () {\r\n"+
  167. " const src = 'https://imspace.nos-eastchina1.126.net/JSocket2.swf';\r\n"+
  168. " const flash = ['<object type=\"application/x-shockwave-flash\" ', 'id=\"jsocket\" ', 'name=\"jsocket\" ', 'align=\"middle\" ', 'allowscriptaccess=\"always\" ', 'allowfullscreen=\"true\" ', 'allowfullscreeninteractive=\"true\" ', 'wmode=\"transparent\" ', 'data=\"' + src + '\" ', 'width=\"100%\" ', 'height=\"100%\">', '<param name=\"src\" value=\"' + src + '\">', '<param name=\"quality\" value=\"high\">', '<param name=\"bgcolor\" value=\"#fff\">', '<param name=\"allowscriptaccess\" value=\"always\">', '<param name=\"allowfullscreen\" value=\"true\">', '<param name=\"wmode\" value=\"transparent\">', '<param name=\"allowFullScreenInteractive\" value=\"true\">', '<param name=\"flashvars\" value=\"\">', \"</object>\"].join(\"\");\r\n"+
  169. " let div = document.createElement('div');\r\n"+
  170. " div.className = 'jsocket-cls';\r\n"+
  171. " document.body.appendChild(div);\r\n"+
  172. " JSocket.el = div;\r\n"+
  173. " div.innerHTML = flash;\r\n"+
  174. " var api = document.querySelector('#jsocket');\r\n"+
  175. " console.log(div, api);\r\n"+
  176. " JSocket.flashapi = api;\r\n"+
  177. " if (JSocket.flashapi.newsocket) {\r\n"+
  178. " return;\r\n"+
  179. " }\r\n"+
  180. " else {\r\n"+
  181. " return new Promise((res, rej) => {\r\n"+
  182. " const id = setTimeout(rej, 10 * 1000);\r\n"+
  183. " JSocket.swfloadedcb = () => {\r\n"+
  184. " clearTimeout(id);\r\n"+
  185. " res();\r\n"+
  186. " };\r\n"+
  187. " });\r\n"+
  188. " }\r\n"+
  189. " });\r\n"+
  190. " }\r\n"+
  191. " static swfloaded() {\r\n"+
  192. " JSocket.swfloadedcb();\r\n"+
  193. " }\r\n"+
  194. " static connectHandler(socid) {\r\n"+
  195. " JSocket.handlers[socid].connectHandler();\r\n"+
  196. " }\r\n"+
  197. " static dataHandler(socid, data) {\r\n"+
  198. " try {\r\n"+
  199. " JSocket.handlers[socid].dataHandler(atob(data));\r\n"+
  200. " }\r\n"+
  201. " catch (e) {\r\n"+
  202. " console.error(e);\r\n"+
  203. " }\r\n"+
  204. " }\r\n"+
  205. " static closeHandler(socid) {\r\n"+
  206. " JSocket.handlers[socid].closeHandler();\r\n"+
  207. " }\r\n"+
  208. " static errorHandler(socid, str) {\r\n"+
  209. " JSocket.handlers[socid].errorHandler(str);\r\n"+
  210. " }\r\n"+
  211. " init(handlers, newsocketopt) {\r\n"+
  212. " this.socid = JSocket.flashapi.newsocket(newsocketopt);\r\n"+
  213. " JSocket.handlers[this.socid] = handlers;\r\n"+
  214. " }\r\n"+
  215. " connect(host, port) {\r\n"+
  216. " JSocket.flashapi.connect(this.socid, host, port);\r\n"+
  217. " }\r\n"+
  218. " write(data) {\r\n"+
  219. " JSocket.flashapi.write(this.socid, btoa(data));\r\n"+
  220. " }\r\n"+
  221. " writeFlush(data) {\r\n"+
  222. " JSocket.flashapi.writeFlush(this.socid, btoa(data));\r\n"+
  223. " }\r\n"+
  224. " close() {\r\n"+
  225. " JSocket.flashapi.close(this.socid);\r\n"+
  226. " }\r\n"+
  227. " flush() {\r\n"+
  228. " JSocket.flashapi.flush(this.socid);\r\n"+
  229. " }\r\n"+
  230. " }\r\n"+
  231. " JSocket.VERSION = '0.1';\r\n"+
  232. " JSocket.handlers = [];\r\n"+
  233. " window.JSocket = JSocket;\n"+
  234. "\n"+
  235. " function utf8ToUtf16(utf8_bytes) {\r\n"+
  236. " let unicode_codes = [];\r\n"+
  237. " let unicode_code = 0;\r\n"+
  238. " let num_followed = 0;\r\n"+
  239. " for (let i = 0; i < utf8_bytes.length; ++i) {\r\n"+
  240. " let utf8_byte = utf8_bytes[i];\r\n"+
  241. " if (utf8_byte >= 0x100) {\r\n"+
  242. " }\r\n"+
  243. " else if ((utf8_byte & 0xC0) == 0x80) {\r\n"+
  244. " if (num_followed > 0) {\r\n"+
  245. " unicode_code = (unicode_code << 6) | (utf8_byte & 0x3f);\r\n"+
  246. " num_followed -= 1;\r\n"+
  247. " }\r\n"+
  248. " else {\r\n"+
  249. " }\r\n"+
  250. " }\r\n"+
  251. " else {\r\n"+
  252. " if (num_followed == 0) {\r\n"+
  253. " unicode_codes.push(unicode_code);\r\n"+
  254. " }\r\n"+
  255. " else {\r\n"+
  256. " }\r\n"+
  257. " if (utf8_byte < 0x80) {\r\n"+
  258. " unicode_code = utf8_byte;\r\n"+
  259. " num_followed = 0;\r\n"+
  260. " }\r\n"+
  261. " else if ((utf8_byte & 0xE0) == 0xC0) {\r\n"+
  262. " unicode_code = utf8_byte & 0x1f;\r\n"+
  263. " num_followed = 1;\r\n"+
  264. " }\r\n"+
  265. " else if ((utf8_byte & 0xF0) == 0xE0) {\r\n"+
  266. " unicode_code = utf8_byte & 0x0f;\r\n"+
  267. " num_followed = 2;\r\n"+
  268. " }\r\n"+
  269. " else if ((utf8_byte & 0xF8) == 0xF0) {\r\n"+
  270. " unicode_code = utf8_byte & 0x07;\r\n"+
  271. " num_followed = 3;\r\n"+
  272. " }\r\n"+
  273. " else {\r\n"+
  274. " }\r\n"+
  275. " }\r\n"+
  276. " }\r\n"+
  277. " if (num_followed == 0) {\r\n"+
  278. " unicode_codes.push(unicode_code);\r\n"+
  279. " }\r\n"+
  280. " else {\r\n"+
  281. " }\r\n"+
  282. " unicode_codes.shift();\r\n"+
  283. " let utf16_codes = [];\r\n"+
  284. " for (var i = 0; i < unicode_codes.length; ++i) {\r\n"+
  285. " unicode_code = unicode_codes[i];\r\n"+
  286. " if (unicode_code < (1 << 16)) {\r\n"+
  287. " utf16_codes.push(unicode_code);\r\n"+
  288. " }\r\n"+
  289. " else {\r\n"+
  290. " var first = ((unicode_code - (1 << 16)) / (1 << 10)) + 0xD800;\r\n"+
  291. " var second = (unicode_code % (1 << 10)) + 0xDC00;\r\n"+
  292. " utf16_codes.push(first);\r\n"+
  293. " utf16_codes.push(second);\r\n"+
  294. " }\r\n"+
  295. " }\r\n"+
  296. " return utf16_codes;\r\n"+
  297. " }\r\n"+
  298. " function utf8_to_ascii(str) {\r\n"+
  299. " const char2bytes = (unicode_code) => {\r\n"+
  300. " let utf8_bytes = [];\r\n"+
  301. " if (unicode_code < 0x80) {\r\n"+
  302. " utf8_bytes.push(unicode_code);\r\n"+
  303. " }\r\n"+
  304. " else if (unicode_code < (1 << 11)) {\r\n"+
  305. " utf8_bytes.push((unicode_code >>> 6) | 0xC0);\r\n"+
  306. " utf8_bytes.push((unicode_code & 0x3F) | 0x80);\r\n"+
  307. " }\r\n"+
  308. " else if (unicode_code < (1 << 16)) {\r\n"+
  309. " utf8_bytes.push((unicode_code >>> 12) | 0xE0);\r\n"+
  310. " utf8_bytes.push(((unicode_code >> 6) & 0x3f) | 0x80);\r\n"+
  311. " utf8_bytes.push((unicode_code & 0x3F) | 0x80);\r\n"+
  312. " }\r\n"+
  313. " else if (unicode_code < (1 << 21)) {\r\n"+
  314. " utf8_bytes.push((unicode_code >>> 18) | 0xF0);\r\n"+
  315. " utf8_bytes.push(((unicode_code >> 12) & 0x3F) | 0x80);\r\n"+
  316. " utf8_bytes.push(((unicode_code >> 6) & 0x3F) | 0x80);\r\n"+
  317. " utf8_bytes.push((unicode_code & 0x3F) | 0x80);\r\n"+
  318. " }\r\n"+
  319. " return utf8_bytes;\r\n"+
  320. " };\r\n"+
  321. " let o = [];\r\n"+
  322. " for (let i = 0; i < str.length; i++) {\r\n"+
  323. " o = o.concat(char2bytes(str.charCodeAt(i)));\r\n"+
  324. " }\r\n"+
  325. " return o.map(i => String.fromCharCode(i)).join('');\r\n"+
  326. " }\r\n"+
  327. " function ascii_to_utf8(str) {\r\n"+
  328. " let bytes = str.split('').map(i => i.charCodeAt(0));\r\n"+
  329. " return utf8ToUtf16(bytes).map(i => String.fromCharCode(i)).join('');\r\n"+
  330. " }\r\n"+
  331. "\r\n"+
  332. "\r\n"+
  333. " function getURL(src) {\r\n"+
  334. " if (src.substr(0, 5) !== 'blob:') {\r\n"+
  335. " src = chrome.runtime.getURL(src);\r\n"+
  336. " }\r\n"+
  337. " return src;\r\n"+
  338. " }\r\n"+
  339. "\r\n"+
  340. "\r\n"+
  341. "\r\n"+
  342. " const p32 = (i) => [i, i / 256, i / 65536, i / 16777216].map(i => String.fromCharCode(Math.floor(i) % 256)).join('');\r\n"+
  343. " const u32 = (s) => s.split('').map(i => i.charCodeAt(0)).reduce((a, b) => b * 256 + a);\r\n"+
  344. " let messageMap = {};\r\n"+
  345. " function onMessage(type, cb) {\r\n"+
  346. " messageMap[type] = cb;\r\n"+
  347. " }\r\n"+
  348. " function postMessage(type, data) {\r\n"+
  349. " window.postMessage({\r\n"+
  350. " type: type,\r\n"+
  351. " data: data\r\n"+
  352. " }, \"*\");\r\n"+
  353. " }\r\n"+
  354. " let msgCallbacks = [];\r\n"+
  355. " let lastCbId = 0;\r\n"+
  356. "\r\n"+
  357. " window.addEventListener('message', (event) => __awaiter(window, void 0, void 0, function* () {\r\n"+
  358. " const data = event.data;\r\n"+
  359. " if (data.cb) {\r\n"+
  360. " let cb = msgCallbacks[data.cbId];\r\n"+
  361. " if (cb && (typeof cb === 'function')) {\r\n"+
  362. " cb(data.cbResult);\r\n"+
  363. " }\r\n"+
  364. " }\r\n"+
  365. " else if (data.type) {\r\n"+
  366. " let result = undefined;\r\n"+
  367. " if (typeof messageMap[data.type] === 'function') {\r\n"+
  368. " result = messageMap[data.type](data.data);\r\n"+
  369. " if (result instanceof Promise) {\r\n"+
  370. " result = yield result;\r\n"+
  371. " }\r\n"+
  372. " if (data.cbId) {\r\n"+
  373. " window.postMessage({\r\n"+
  374. " cb: true,\r\n"+
  375. " cbId: data.cbId,\r\n"+
  376. " cbResult: result\r\n"+
  377. " }, '*');\r\n"+
  378. " }\r\n"+
  379. " }\r\n"+
  380. " }\r\n"+
  381. " }), false);\r\n"+
  382. " function retry(promise, times) {\r\n"+
  383. " return __awaiter(this, void 0, void 0, function* () {\r\n"+
  384. " let err = [];\r\n"+
  385. " for (let i = 0; i < times; i++) {\r\n"+
  386. " try {\r\n"+
  387. " return yield promise();\r\n"+
  388. " }\r\n"+
  389. " catch (e) {\r\n"+
  390. " err.push(e);\r\n"+
  391. " }\r\n"+
  392. " }\r\n"+
  393. " throw err;\r\n"+
  394. " });\r\n"+
  395. " }\r\n"+
  396. " function getSync() {\r\n"+
  397. " return new Promise((res, rej) => {\r\n"+
  398. " if (chrome && chrome.storage && chrome.storage.sync) {\r\n"+
  399. " chrome.storage.sync.get(items => {\r\n"+
  400. " res(items);\r\n"+
  401. " });\r\n"+
  402. " }\r\n"+
  403. " else {\r\n"+
  404. " rej(new Error('不支持的存储方式'));\r\n"+
  405. " }\r\n"+
  406. " });\r\n"+
  407. " }\r\n"+
  408. "\r\n"+
  409. "\r\n"+
  410. "\r\n"+
  411. " const defaultBgListener = (request) => __awaiter(window, void 0, void 0, function* () { return null; });\r\n"+
  412. " let bgListener = defaultBgListener;\n"+
  413. "\n"+
  414. " function md5cycle(x, k) {\r\n"+
  415. " var a = x[0], b = x[1], c = x[2], d = x[3];\r\n"+
  416. " a = ff(a, b, c, d, k[0], 7, -680876936);\r\n"+
  417. " d = ff(d, a, b, c, k[1], 12, -389564586);\r\n"+
  418. " c = ff(c, d, a, b, k[2], 17, 606105819);\r\n"+
  419. " b = ff(b, c, d, a, k[3], 22, -1044525330);\r\n"+
  420. " a = ff(a, b, c, d, k[4], 7, -176418897);\r\n"+
  421. " d = ff(d, a, b, c, k[5], 12, 1200080426);\r\n"+
  422. " c = ff(c, d, a, b, k[6], 17, -1473231341);\r\n"+
  423. " b = ff(b, c, d, a, k[7], 22, -45705983);\r\n"+
  424. " a = ff(a, b, c, d, k[8], 7, 1770035416);\r\n"+
  425. " d = ff(d, a, b, c, k[9], 12, -1958414417);\r\n"+
  426. " c = ff(c, d, a, b, k[10], 17, -42063);\r\n"+
  427. " b = ff(b, c, d, a, k[11], 22, -1990404162);\r\n"+
  428. " a = ff(a, b, c, d, k[12], 7, 1804603682);\r\n"+
  429. " d = ff(d, a, b, c, k[13], 12, -40341101);\r\n"+
  430. " c = ff(c, d, a, b, k[14], 17, -1502002290);\r\n"+
  431. " b = ff(b, c, d, a, k[15], 22, 1236535329);\r\n"+
  432. " a = gg(a, b, c, d, k[1], 5, -165796510);\r\n"+
  433. " d = gg(d, a, b, c, k[6], 9, -1069501632);\r\n"+
  434. " c = gg(c, d, a, b, k[11], 14, 643717713);\r\n"+
  435. " b = gg(b, c, d, a, k[0], 20, -373897302);\r\n"+
  436. " a = gg(a, b, c, d, k[5], 5, -701558691);\r\n"+
  437. " d = gg(d, a, b, c, k[10], 9, 38016083);\r\n"+
  438. " c = gg(c, d, a, b, k[15], 14, -660478335);\r\n"+
  439. " b = gg(b, c, d, a, k[4], 20, -405537848);\r\n"+
  440. " a = gg(a, b, c, d, k[9], 5, 568446438);\r\n"+
  441. " d = gg(d, a, b, c, k[14], 9, -1019803690);\r\n"+
  442. " c = gg(c, d, a, b, k[3], 14, -187363961);\r\n"+
  443. " b = gg(b, c, d, a, k[8], 20, 1163531501);\r\n"+
  444. " a = gg(a, b, c, d, k[13], 5, -1444681467);\r\n"+
  445. " d = gg(d, a, b, c, k[2], 9, -51403784);\r\n"+
  446. " c = gg(c, d, a, b, k[7], 14, 1735328473);\r\n"+
  447. " b = gg(b, c, d, a, k[12], 20, -1926607734);\r\n"+
  448. " a = hh(a, b, c, d, k[5], 4, -378558);\r\n"+
  449. " d = hh(d, a, b, c, k[8], 11, -2022574463);\r\n"+
  450. " c = hh(c, d, a, b, k[11], 16, 1839030562);\r\n"+
  451. " b = hh(b, c, d, a, k[14], 23, -35309556);\r\n"+
  452. " a = hh(a, b, c, d, k[1], 4, -1530992060);\r\n"+
  453. " d = hh(d, a, b, c, k[4], 11, 1272893353);\r\n"+
  454. " c = hh(c, d, a, b, k[7], 16, -155497632);\r\n"+
  455. " b = hh(b, c, d, a, k[10], 23, -1094730640);\r\n"+
  456. " a = hh(a, b, c, d, k[13], 4, 681279174);\r\n"+
  457. " d = hh(d, a, b, c, k[0], 11, -358537222);\r\n"+
  458. " c = hh(c, d, a, b, k[3], 16, -722521979);\r\n"+
  459. " b = hh(b, c, d, a, k[6], 23, 76029189);\r\n"+
  460. " a = hh(a, b, c, d, k[9], 4, -640364487);\r\n"+
  461. " d = hh(d, a, b, c, k[12], 11, -421815835);\r\n"+
  462. " c = hh(c, d, a, b, k[15], 16, 530742520);\r\n"+
  463. " b = hh(b, c, d, a, k[2], 23, -995338651);\r\n"+
  464. " a = ii(a, b, c, d, k[0], 6, -198630844);\r\n"+
  465. " d = ii(d, a, b, c, k[7], 10, 1126891415);\r\n"+
  466. " c = ii(c, d, a, b, k[14], 15, -1416354905);\r\n"+
  467. " b = ii(b, c, d, a, k[5], 21, -57434055);\r\n"+
  468. " a = ii(a, b, c, d, k[12], 6, 1700485571);\r\n"+
  469. " d = ii(d, a, b, c, k[3], 10, -1894986606);\r\n"+
  470. " c = ii(c, d, a, b, k[10], 15, -1051523);\r\n"+
  471. " b = ii(b, c, d, a, k[1], 21, -2054922799);\r\n"+
  472. " a = ii(a, b, c, d, k[8], 6, 1873313359);\r\n"+
  473. " d = ii(d, a, b, c, k[15], 10, -30611744);\r\n"+
  474. " c = ii(c, d, a, b, k[6], 15, -1560198380);\r\n"+
  475. " b = ii(b, c, d, a, k[13], 21, 1309151649);\r\n"+
  476. " a = ii(a, b, c, d, k[4], 6, -145523070);\r\n"+
  477. " d = ii(d, a, b, c, k[11], 10, -1120210379);\r\n"+
  478. " c = ii(c, d, a, b, k[2], 15, 718787259);\r\n"+
  479. " b = ii(b, c, d, a, k[9], 21, -343485551);\r\n"+
  480. " x[0] = add32(a, x[0]);\r\n"+
  481. " x[1] = add32(b, x[1]);\r\n"+
  482. " x[2] = add32(c, x[2]);\r\n"+
  483. " x[3] = add32(d, x[3]);\r\n"+
  484. " }\r\n"+
  485. " function cmn(q, a, b, x, s, t) {\r\n"+
  486. " a = add32(add32(a, q), add32(x, t));\r\n"+
  487. " return add32((a << s) | (a >>> (32 - s)), b);\r\n"+
  488. " }\r\n"+
  489. " function ff(a, b, c, d, x, s, t) {\r\n"+
  490. " return cmn((b & c) | ((~b) & d), a, b, x, s, t);\r\n"+
  491. " }\r\n"+
  492. " function gg(a, b, c, d, x, s, t) {\r\n"+
  493. " return cmn((b & d) | (c & (~d)), a, b, x, s, t);\r\n"+
  494. " }\r\n"+
  495. " function hh(a, b, c, d, x, s, t) {\r\n"+
  496. " return cmn(b ^ c ^ d, a, b, x, s, t);\r\n"+
  497. " }\r\n"+
  498. " function ii(a, b, c, d, x, s, t) {\r\n"+
  499. " return cmn(c ^ (b | (~d)), a, b, x, s, t);\r\n"+
  500. " }\r\n"+
  501. " function md51(s) {\r\n"+
  502. " var txt = '';\r\n"+
  503. " var n = s.length, state = [1732584193, -271733879, -1732584194, 271733878], i;\r\n"+
  504. " for (i = 64; i <= s.length; i += 64) {\r\n"+
  505. " md5cycle(state, md5blk(s.substring(i - 64, i)));\r\n"+
  506. " }\r\n"+
  507. " s = s.substring(i - 64);\r\n"+
  508. " var tail = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];\r\n"+
  509. " for (i = 0; i < s.length; i++)\r\n"+
  510. " tail[i >> 2] |= s.charCodeAt(i) << ((i % 4) << 3);\r\n"+
  511. " tail[i >> 2] |= 0x80 << ((i % 4) << 3);\r\n"+
  512. " if (i > 55) {\r\n"+
  513. " md5cycle(state, tail);\r\n"+
  514. " for (i = 0; i < 16; i++)\r\n"+
  515. " tail[i] = 0;\r\n"+
  516. " }\r\n"+
  517. " tail[14] = n * 8;\r\n"+
  518. " md5cycle(state, tail);\r\n"+
  519. " return state;\r\n"+
  520. " }\r\n"+
  521. " function md5blk(s) {\r\n"+
  522. " var md5blks = [], i;\r\n"+
  523. " for (i = 0; i < 64; i += 4) {\r\n"+
  524. " md5blks[i >> 2] = s.charCodeAt(i) + (s.charCodeAt(i + 1) << 8) + (s.charCodeAt(i + 2) << 16) + (s.charCodeAt(i + 3) << 24);\r\n"+
  525. " }\r\n"+
  526. " return md5blks;\r\n"+
  527. " }\r\n"+
  528. " var hex_chr = '0123456789abcdef'.split('');\r\n"+
  529. " function rhex(n) {\r\n"+
  530. " var s = '', j = 0;\r\n"+
  531. " for (; j < 4; j++)\r\n"+
  532. " s += hex_chr[(n >> (j * 8 + 4)) & 0x0F] + hex_chr[(n >> (j * 8)) & 0x0F];\r\n"+
  533. " return s;\r\n"+
  534. " }\r\n"+
  535. " function hex(x) {\r\n"+
  536. " return x.map(rhex).join('');\r\n"+
  537. " }\r\n"+
  538. " function md5(s) {\r\n"+
  539. " return hex(md51(s));\r\n"+
  540. " }\r\n"+
  541. " var add32 = function (a, b) {\r\n"+
  542. " return (a + b) & 0xFFFFFFFF;\r\n"+
  543. " };\r\n"+
  544. " if (md5('hello') != '5d41402abc4b2a76b9719d911017c592') {\r\n"+
  545. " add32 = function (x, y) {\r\n"+
  546. " var lsw = (x & 0xFFFF) + (y & 0xFFFF), msw = (x >> 16) + (y >> 16) + (lsw >> 16);\r\n"+
  547. " return (msw << 16) | (lsw & 0xFFFF);\r\n"+
  548. " };\r\n"+
  549. " }\n"+
  550. "\n"+
  551. " const getACF = (key) => {\r\n"+
  552. " try {\r\n"+
  553. " return new RegExp(`acf_${key}=(.*?);`).exec(document.cookie)[1];\r\n"+
  554. " }\r\n"+
  555. " catch (e) {\r\n"+
  556. " return '';\r\n"+
  557. " }\r\n"+
  558. " };\r\n"+
  559. " function filterEnc(s) {\r\n"+
  560. " s = s.toString();\r\n"+
  561. " s = s.replace(/@/g, '@A');\r\n"+
  562. " return s.replace(/\\//g, '@S');\r\n"+
  563. " }\r\n"+
  564. " function filterDec(s) {\r\n"+
  565. " s = s.toString();\r\n"+
  566. " s = s.replace(/@S/g, '/');\r\n"+
  567. " return s.replace(/@A/g, '@');\r\n"+
  568. " }\r\n"+
  569. " function douyuEncode(data) {\r\n"+
  570. " return Object.keys(data).map(key => `${key}@=${filterEnc(data[key])}`).join('/') + '/';\r\n"+
  571. " }\r\n"+
  572. " function douyuDecode(data) {\r\n"+
  573. " let out = {\r\n"+
  574. " type: '!!missing!!'\r\n"+
  575. " };\r\n"+
  576. " try {\r\n"+
  577. " data.split('/').filter(i => i.length > 2).forEach(i => {\r\n"+
  578. " let e = i.split('@=');\r\n"+
  579. " out[e[0]] = filterDec(e[1]);\r\n"+
  580. " });\r\n"+
  581. " }\r\n"+
  582. " catch (e) {\r\n"+
  583. " console.error(e);\r\n"+
  584. " console.log(data);\r\n"+
  585. " }\r\n"+
  586. " return out;\r\n"+
  587. " }\r\n"+
  588. " function ACJ(id, data) {\r\n"+
  589. " if (typeof data == 'object') {\r\n"+
  590. " data = douyuEncode(data);\r\n"+
  591. " }\r\n"+
  592. " try {\r\n"+
  593. " window._ACJ_([id, data]);\r\n"+
  594. " }\r\n"+
  595. " catch (e) {\r\n"+
  596. " console.error(id, data, e);\r\n"+
  597. " }\r\n"+
  598. " }\r\n"+
  599. " class DouyuProtocol extends JSocket {\r\n"+
  600. " constructor(listener) {\r\n"+
  601. " super();\r\n"+
  602. " this.listener = listener;\r\n"+
  603. " this.connectHandler = () => null;\r\n"+
  604. " this.init(this, {});\r\n"+
  605. " this.buffer = '';\r\n"+
  606. " }\r\n"+
  607. " connectAsync(host, port) {\r\n"+
  608. " super.connect(host, port);\r\n"+
  609. " return new Promise((res, rej) => {\r\n"+
  610. " const prevConnHandler = this.connectHandler;\r\n"+
  611. " const prevErrHandler = this.errorHandler;\r\n"+
  612. " const recover = () => {\r\n"+
  613. " this.connectHandler = prevConnHandler;\r\n"+
  614. " this.errorHandler = prevErrHandler;\r\n"+
  615. " };\r\n"+
  616. " this.connectHandler = () => {\r\n"+
  617. " recover();\r\n"+
  618. " res();\r\n"+
  619. " };\r\n"+
  620. " this.errorHandler = () => {\r\n"+
  621. " recover();\r\n"+
  622. " rej();\r\n"+
  623. " };\r\n"+
  624. " });\r\n"+
  625. " }\r\n"+
  626. " dataHandler(data) {\r\n"+
  627. " this.buffer += data;\r\n"+
  628. " let buffer = this.buffer;\r\n"+
  629. " while (buffer.length >= 4) {\r\n"+
  630. " let size = u32(buffer.substr(0, 4));\r\n"+
  631. " if (buffer.length >= size) {\r\n"+
  632. " let pkgStr = '';\r\n"+
  633. " try {\r\n"+
  634. " pkgStr = ascii_to_utf8(buffer.substr(12, size - 8));\r\n"+
  635. " }\r\n"+
  636. " catch (e) {\r\n"+
  637. " console.log('deocde fail', escape(buffer.substr(12, size - 8)));\r\n"+
  638. " }\r\n"+
  639. " this.buffer = buffer = buffer.substr(size + 4);\r\n"+
  640. " if (pkgStr.length === 0)\r\n"+
  641. " continue;\r\n"+
  642. " try {\r\n"+
  643. " let pkg = douyuDecode(pkgStr);\r\n"+
  644. " this.listener && this.listener.onPackage(pkg, pkgStr);\r\n"+
  645. " }\r\n"+
  646. " catch (e) {\r\n"+
  647. " console.error('call map', e);\r\n"+
  648. " }\r\n"+
  649. " }\r\n"+
  650. " else {\r\n"+
  651. " break;\r\n"+
  652. " }\r\n"+
  653. " }\r\n"+
  654. " }\r\n"+
  655. " closeHandler() {\r\n"+
  656. " console.error('lost connection');\r\n"+
  657. " this.listener && this.listener.onClose();\r\n"+
  658. " }\r\n"+
  659. " errorHandler(err) {\r\n"+
  660. " console.error(err);\r\n"+
  661. " this.listener && this.listener.onError(err);\r\n"+
  662. " }\r\n"+
  663. " send(data) {\r\n"+
  664. " let msg = douyuEncode(data) + '\\0';\r\n"+
  665. " msg = utf8_to_ascii(msg);\r\n"+
  666. " msg = p32(msg.length + 8) + p32(msg.length + 8) + p32(689) + msg;\r\n"+
  667. " this.writeFlush(msg);\r\n"+
  668. " }\r\n"+
  669. " }\r\n"+
  670. " function Type(type) {\r\n"+
  671. " return (target, propertyKey, descriptor) => {\r\n"+
  672. " if (!target.map) {\r\n"+
  673. " target.map = {};\r\n"+
  674. " }\r\n"+
  675. " target.map[type] = target[propertyKey];\r\n"+
  676. " };\r\n"+
  677. " }\r\n"+
  678. " class DouyuBaseClient {\r\n"+
  679. " constructor(roomId) {\r\n"+
  680. " this.roomId = roomId;\r\n"+
  681. " this.lastIP = null;\r\n"+
  682. " this.lastPort = null;\r\n"+
  683. " this.keepaliveId = null;\r\n"+
  684. " this.redirect = {};\r\n"+
  685. " this.prot = new DouyuProtocol(this);\r\n"+
  686. " }\r\n"+
  687. " static getRoomArgs() {\r\n"+
  688. " if (window._room_args)\r\n"+
  689. " return window._room_args;\r\n"+
  690. " if (window.room_args) {\r\n"+
  691. " return window.room_args;\r\n"+
  692. " }\r\n"+
  693. " else {\r\n"+
  694. " return window.$ROOM.args;\r\n"+
  695. " }\r\n"+
  696. " }\r\n"+
  697. " reconnect() {\r\n"+
  698. " return __awaiter(this, void 0, void 0, function* () {\r\n"+
  699. " console.log('reconnect');\r\n"+
  700. " this.prot.listener = null;\r\n"+
  701. " this.prot = new DouyuProtocol(this);\r\n"+
  702. " try {\r\n"+
  703. " yield this.connectAsync(this.lastIP, this.lastPort);\r\n"+
  704. " }\r\n"+
  705. " catch (e) {\r\n"+
  706. " this.onError();\r\n"+
  707. " }\r\n"+
  708. " });\r\n"+
  709. " }\r\n"+
  710. " onClose() {\r\n"+
  711. " setTimeout(() => this.reconnect(), 1000);\r\n"+
  712. " }\r\n"+
  713. " onError() {\r\n"+
  714. " this.onClose();\r\n"+
  715. " }\r\n"+
  716. " onPackage(pkg, pkgStr) {\r\n"+
  717. " const type = pkg.type;\r\n"+
  718. " if (this.redirect[type]) {\r\n"+
  719. " ACJ(this.redirect[type], pkg);\r\n"+
  720. " return;\r\n"+
  721. " }\r\n"+
  722. " if (this.map[type]) {\r\n"+
  723. " this.map[type].call(this, pkg, pkgStr);\r\n"+
  724. " return;\r\n"+
  725. " }\r\n"+
  726. " this.onDefault(pkg);\r\n"+
  727. " }\r\n"+
  728. " onDefault(pkg) {\r\n"+
  729. " }\r\n"+
  730. " send(pkg) {\r\n"+
  731. " this.prot.send(pkg);\r\n"+
  732. " }\r\n"+
  733. " connectAsync(ip, port) {\r\n"+
  734. " return __awaiter(this, void 0, void 0, function* () {\r\n"+
  735. " this.lastIP = ip;\r\n"+
  736. " this.lastPort = port;\r\n"+
  737. " yield this.prot.connectAsync(ip, port);\r\n"+
  738. " this.send(this.loginreq());\r\n"+
  739. " });\r\n"+
  740. " }\r\n"+
  741. " keepalivePkg() {\r\n"+
  742. " return {\r\n"+
  743. " type: 'keeplive',\r\n"+
  744. " tick: Math.round(new Date().getTime() / 1000).toString()\r\n"+
  745. " };\r\n"+
  746. " }\r\n"+
  747. " loginreq() {\r\n"+
  748. " const rt = Math.round(new Date().getTime() / 1000);\r\n"+
  749. " const devid = getACF('devid');\r\n"+
  750. " const username = getACF('username');\r\n"+
  751. " console.log('username', username, devid);\r\n"+
  752. " return {\r\n"+
  753. " type: 'loginreq',\r\n"+
  754. " username: username,\r\n"+
  755. " ct: 0,\r\n"+
  756. " password: '',\r\n"+
  757. " roomid: this.roomId,\r\n"+
  758. " devid: devid,\r\n"+
  759. " rt: rt,\r\n"+
  760. " vk: md5(`${rt}r5*^5;}2#\\${XF[h+;'./.Q'1;,-]f'p[${devid}`),\r\n"+
  761. " ver: '20150929',\r\n"+
  762. " aver: '2017012111',\r\n"+
  763. " biz: getACF('biz'),\r\n"+
  764. " stk: getACF('stk'),\r\n"+
  765. " ltkid: getACF('ltkid')\r\n"+
  766. " };\r\n"+
  767. " }\r\n"+
  768. " startKeepalive() {\r\n"+
  769. " this.send(this.keepalivePkg());\r\n"+
  770. " if (this.keepaliveId) {\r\n"+
  771. " clearInterval(this.keepaliveId);\r\n"+
  772. " }\r\n"+
  773. " this.keepaliveId = setInterval(() => this.send(this.keepalivePkg()), 30 * 1000);\r\n"+
  774. " }\r\n"+
  775. " }\r\n"+
  776. " let blacklist = [];\r\n"+
  777. " function onChatMsg(data) {\r\n"+
  778. " if (blacklist.indexOf(data.uid) !== -1) {\r\n"+
  779. " console.log('black');\r\n"+
  780. " return;\r\n"+
  781. " }\r\n"+
  782. " try {\r\n"+
  783. " postMessage('DANMU', data);\r\n"+
  784. " }\r\n"+
  785. " catch (e) {\r\n"+
  786. " console.error('wtf', e);\r\n"+
  787. " }\r\n"+
  788. " ACJ('room_data_chat2', data);\r\n"+
  789. " if (window.BarrageReturn) {\r\n"+
  790. " window.BarrageReturn(douyuEncode(data));\r\n"+
  791. " }\r\n"+
  792. " }\r\n"+
  793. " class DouyuClient extends DouyuBaseClient {\r\n"+
  794. " constructor(roomId, danmuClient) {\r\n"+
  795. " super(roomId);\r\n"+
  796. " this.danmuClient = danmuClient;\r\n"+
  797. " this.redirect = {\r\n"+
  798. " qtlr: 'room_data_tasklis',\r\n"+
  799. " initcl: 'room_data_chatinit',\r\n"+
  800. " memberinfores: 'room_data_info',\r\n"+
  801. " ranklist: 'room_data_cqrank',\r\n"+
  802. " rsm: 'room_data_brocast',\r\n"+
  803. " qausrespond: 'data_rank_score',\r\n"+
  804. " frank: 'room_data_handler',\r\n"+
  805. " online_noble_list: 'room_data_handler',\r\n"+
  806. " };\r\n"+
  807. " }\r\n"+
  808. " reqOnlineGift(loginres) {\r\n"+
  809. " return {\r\n"+
  810. " type: 'reqog',\r\n"+
  811. " uid: loginres.userid\r\n"+
  812. " };\r\n"+
  813. " }\r\n"+
  814. " chatmsg(data) {\r\n"+
  815. " onChatMsg(data);\r\n"+
  816. " }\r\n"+
  817. " resog(data) {\r\n"+
  818. " ACJ('room_data_chest', {\r\n"+
  819. " lev: data.lv,\r\n"+
  820. " lack_time: data.t,\r\n"+
  821. " dl: data.dl\r\n"+
  822. " });\r\n"+
  823. " }\r\n"+
  824. " loginres(data) {\r\n"+
  825. " console.log('loginres ms', data);\r\n"+
  826. " this.uid = data.userid;\r\n"+
  827. " this.send(this.reqOnlineGift(data));\r\n"+
  828. " this.startKeepalive();\r\n"+
  829. " ACJ('room_data_login', data);\r\n"+
  830. " ACJ('room_data_getdid', {\r\n"+
  831. " devid: getACF('devid')\r\n"+
  832. " });\r\n"+
  833. " }\r\n"+
  834. " keeplive(data, rawString) {\r\n"+
  835. " ACJ('room_data_userc', data.uc);\r\n"+
  836. " ACJ('room_data_tbredpacket', rawString);\r\n"+
  837. " }\r\n"+
  838. " setmsggroup(data) {\r\n"+
  839. " console.log('joingroup', data);\r\n"+
  840. " this.danmuClient.send({\r\n"+
  841. " type: 'joingroup',\r\n"+
  842. " rid: data.rid,\r\n"+
  843. " gid: data.gid\r\n"+
  844. " });\r\n"+
  845. " }\r\n"+
  846. " onDefault(data) {\r\n"+
  847. " ACJ('room_data_handler', data);\r\n"+
  848. " console.log('ms', data);\r\n"+
  849. " }\r\n"+
  850. " }\r\n"+
  851. " __decorate([\r\n"+
  852. " Type('chatmsg')\r\n"+
  853. " ], DouyuClient.prototype, \"chatmsg\", null);\r\n"+
  854. " __decorate([\r\n"+
  855. " Type('resog')\r\n"+
  856. " ], DouyuClient.prototype, \"resog\", null);\r\n"+
  857. " __decorate([\r\n"+
  858. " Type('loginres')\r\n"+
  859. " ], DouyuClient.prototype, \"loginres\", null);\r\n"+
  860. " __decorate([\r\n"+
  861. " Type('keeplive')\r\n"+
  862. " ], DouyuClient.prototype, \"keeplive\", null);\r\n"+
  863. " __decorate([\r\n"+
  864. " Type('setmsggroup')\r\n"+
  865. " ], DouyuClient.prototype, \"setmsggroup\", null);\r\n"+
  866. " class DouyuDanmuClient extends DouyuBaseClient {\r\n"+
  867. " constructor(roomId) {\r\n"+
  868. " super(roomId);\r\n"+
  869. " this.redirect = {\r\n"+
  870. " chatres: 'room_data_chat2',\r\n"+
  871. " initcl: 'room_data_chatinit',\r\n"+
  872. " dgb: 'room_data_giftbat1',\r\n"+
  873. " dgn: 'room_data_giftbat1',\r\n"+
  874. " spbc: 'room_data_giftbat1',\r\n"+
  875. " uenter: 'room_data_nstip2',\r\n"+
  876. " upgrade: 'room_data_ulgrow',\r\n"+
  877. " newblackres: 'room_data_sys',\r\n"+
  878. " ranklist: 'room_data_cqrank',\r\n"+
  879. " rankup: 'room_data_ulgrow',\r\n"+
  880. " gift_title: 'room_data_schat',\r\n"+
  881. " rss: 'room_data_state',\r\n"+
  882. " srres: 'room_data_wbsharesuc',\r\n"+
  883. " onlinegift: 'room_data_olyw',\r\n"+
  884. " gpbc: 'room_data_handler',\r\n"+
  885. " synexp: 'room_data_handler',\r\n"+
  886. " frank: 'room_data_handler',\r\n"+
  887. " ggbb: 'room_data_sabonusget',\r\n"+
  888. " online_noble_list: 'room_data_handler',\r\n"+
  889. " };\r\n"+
  890. " }\r\n"+
  891. " chatmsg(pkg) {\r\n"+
  892. " onChatMsg(pkg);\r\n"+
  893. " }\r\n"+
  894. " loginres(data) {\r\n"+
  895. " console.log('loginres dm', data);\r\n"+
  896. " this.startKeepalive();\r\n"+
  897. " }\r\n"+
  898. " onDefault(data) {\r\n"+
  899. " ACJ('room_data_handler', data);\r\n"+
  900. " console.log('dm', data);\r\n"+
  901. " }\r\n"+
  902. " }\r\n"+
  903. " __decorate([\r\n"+
  904. " Type('chatmsg')\r\n"+
  905. " ], DouyuDanmuClient.prototype, \"chatmsg\", null);\r\n"+
  906. " __decorate([\r\n"+
  907. " Type('loginres')\r\n"+
  908. " ], DouyuDanmuClient.prototype, \"loginres\", null);\r\n"+
  909. " function hookDouyu(roomId, miscClient) {\r\n"+
  910. " let oldExe;\r\n"+
  911. " const repeatPacket = (text) => douyuDecode(text);\r\n"+
  912. " const jsMap = {\r\n"+
  913. " js_getRankScore: repeatPacket,\r\n"+
  914. " js_getnoble: repeatPacket,\r\n"+
  915. " js_rewardList: {\r\n"+
  916. " type: 'qrl',\r\n"+
  917. " rid: roomId\r\n"+
  918. " },\r\n"+
  919. " js_queryTask: {\r\n"+
  920. " type: 'qtlnq'\r\n"+
  921. " },\r\n"+
  922. " js_newQueryTask: {\r\n"+
  923. " type: 'qtlq'\r\n"+
  924. " },\r\n"+
  925. " js_sendmsg(msg) {\r\n"+
  926. " let pkg = douyuDecode(msg);\r\n"+
  927. " pkg.type = 'chatmessage';\r\n"+
  928. " return pkg;\r\n"+
  929. " },\r\n"+
  930. " js_giveGift(gift) {\r\n"+
  931. " let pkg = douyuDecode(gift);\r\n"+
  932. " if (pkg.type === 'dn_s_gf') {\r\n"+
  933. " pkg.type = 'sgq';\r\n"+
  934. " pkg.bat = 0;\r\n"+
  935. " }\r\n"+
  936. " console.log('giveGift', gift);\r\n"+
  937. " return gift;\r\n"+
  938. " },\r\n"+
  939. " js_GetHongbao: repeatPacket,\r\n"+
  940. " js_UserHaveHandle() { },\r\n"+
  941. " js_myblacklist(list) {\r\n"+
  942. " console.log('add blacklist', list);\r\n"+
  943. " blacklist = list.split('|');\r\n"+
  944. " },\r\n"+
  945. " js_medal_opera(opt) {\r\n"+
  946. " let pkg = douyuDecode(opt);\r\n"+
  947. " return pkg;\r\n"+
  948. " }\r\n"+
  949. " };\r\n"+
  950. " const api = window['require']('douyu/page/room/base/api');\r\n"+
  951. " const hookd = function hookd(...args) {\r\n"+
  952. " let req = jsMap[args[0]];\r\n"+
  953. " if (req) {\r\n"+
  954. " if (typeof req == 'function') {\r\n"+
  955. " req = req.apply(null, args.slice(1));\r\n"+
  956. " }\r\n"+
  957. " req && miscClient.send(req);\r\n"+
  958. " }\r\n"+
  959. " else {\r\n"+
  960. " console.log('exe', args);\r\n"+
  961. " try {\r\n"+
  962. " return oldExe.apply(api, args);\r\n"+
  963. " }\r\n"+
  964. " catch (e) { }\r\n"+
  965. " }\r\n"+
  966. " };\r\n"+
  967. " if (api) {\r\n"+
  968. " if (api.exe !== hookd) {\r\n"+
  969. " oldExe = api.exe;\r\n"+
  970. " api.exe = hookd;\r\n"+
  971. " }\r\n"+
  972. " }\r\n"+
  973. " else if (window.thisMovie) {\r\n"+
  974. " window.thisMovie = () => new Proxy({}, {\r\n"+
  975. " get(target, key, receiver) {\r\n"+
  976. " return (...args) => hookd.apply(null, [key].concat(args));\r\n"+
  977. " }\r\n"+
  978. " });\r\n"+
  979. " }\r\n"+
  980. " }\r\n"+
  981. " function douyuApi(roomId) {\r\n"+
  982. " return __awaiter(this, void 0, void 0, function* () {\r\n"+
  983. " const res = yield fetch('/swf_api/get_room_args');\r\n"+
  984. " const args = yield res.json();\r\n"+
  985. " const servers = JSON.parse(decodeURIComponent(args.server_config));\r\n"+
  986. " const mserver = servers[Math.floor(Math.random() * servers.length)];\r\n"+
  987. " const ports = [8601, 8602, 12601, 12602];\r\n"+
  988. " const danmuServer = {\r\n"+
  989. " ip: 'danmu.douyu.com',\r\n"+
  990. " port: ports[Math.floor(Math.random() * ports.length)]\r\n"+
  991. " };\r\n"+
  992. " let danmuClient = new DouyuDanmuClient(roomId);\r\n"+
  993. " let miscClient = new DouyuClient(roomId, danmuClient);\r\n"+
  994. " yield danmuClient.connectAsync(danmuServer.ip, danmuServer.port);\r\n"+
  995. " yield miscClient.connectAsync(mserver.ip, mserver.port);\r\n"+
  996. " return {\r\n"+
  997. " sendDanmu(content) {\r\n"+
  998. " miscClient.send({\r\n"+
  999. " col: '0',\r\n"+
  1000. " content: content,\r\n"+
  1001. " dy: '',\r\n"+
  1002. " pid: '',\r\n"+
  1003. " sender: miscClient.uid,\r\n"+
  1004. " type: 'chatmessage'\r\n"+
  1005. " });\r\n"+
  1006. " },\r\n"+
  1007. " serverSend(pkg) {\r\n"+
  1008. " return miscClient.send(pkg);\r\n"+
  1009. " },\r\n"+
  1010. " hookExe() {\r\n"+
  1011. " hookDouyu(roomId, miscClient);\r\n"+
  1012. " }\r\n"+
  1013. " };\r\n"+
  1014. " });\r\n"+
  1015. " }\n"+
  1016. "\n"+
  1017. " function hookFunc(obj, funcName, newFunc) {\r\n"+
  1018. " var old = obj[funcName];\r\n"+
  1019. " obj[funcName] = function () {\r\n"+
  1020. " return newFunc.call(this, old.bind(this), Array.from(arguments));\r\n"+
  1021. " };\r\n"+
  1022. " }\r\n"+
  1023. " function getParam(flash, name) {\r\n"+
  1024. " const children = flash.children;\r\n"+
  1025. " for (let i = 0; i < children.length; i++) {\r\n"+
  1026. " const param = children[i];\r\n"+
  1027. " if (param.name == name) {\r\n"+
  1028. " return param.value;\r\n"+
  1029. " }\r\n"+
  1030. " }\r\n"+
  1031. " return '';\r\n"+
  1032. " }\r\n"+
  1033. " function getRoomIdFromFlash(s) {\r\n"+
  1034. " return s.split('&').filter(i => i.substr(0, 6) == 'RoomId')[0].split('=')[1];\r\n"+
  1035. " }\r\n"+
  1036. " hookFunc(document, 'createElement', (old, args) => {\r\n"+
  1037. " var ret = old.apply(null, args);\r\n"+
  1038. " if (args[0] == 'object') {\r\n"+
  1039. " hookFunc(ret, 'setAttribute', (old, args) => {\r\n"+
  1040. " if (args[0] == 'data') {\r\n"+
  1041. " if (/WebRoom/.test(args[1])) {\r\n"+
  1042. " setTimeout(() => {\r\n"+
  1043. " let roomId = getRoomIdFromFlash(getParam(ret, 'flashvars'));\r\n"+
  1044. " console.log('RoomId', roomId);\r\n"+
  1045. " postMessage('VIDEOID', {\r\n"+
  1046. " roomId: roomId,\r\n"+
  1047. " id: ret.id\r\n"+
  1048. " });\r\n"+
  1049. " }, 1);\r\n"+
  1050. " }\r\n"+
  1051. " }\r\n"+
  1052. " return old.apply(null, args);\r\n"+
  1053. " });\r\n"+
  1054. " }\r\n"+
  1055. " return ret;\r\n"+
  1056. " });\r\n"+
  1057. " let api;\r\n"+
  1058. " onMessage('BEGINAPI', (data) => __awaiter(window, void 0, void 0, function* () {\r\n"+
  1059. " yield retry(() => JSocket.init(), 3);\r\n"+
  1060. " api = yield douyuApi(data.roomId);\r\n"+
  1061. " api.hookExe();\r\n"+
  1062. " window.api = api;\r\n"+
  1063. " }));\r\n"+
  1064. " onMessage('SENDANMU', data => {\r\n"+
  1065. " api.sendDanmu(data);\r\n"+
  1066. " });\r\n"+
  1067. " onMessage('ACJ', data => {\r\n"+
  1068. " ACJ(data.id, data.data);\r\n"+
  1069. " });\n"+
  1070. "\n"+
  1071. "})));\n"+
  1072. "\n", css: ".jsocket-cls,\n"+
  1073. ".big-flash-cls {\n"+
  1074. " width: 80vw;\n"+
  1075. " height: 80vh;\n"+
  1076. " position: absolute;\n"+
  1077. " top: -100vh;\n"+
  1078. " left: 0;\n"+
  1079. "}\n"+
  1080. ".donate-dialog {\n"+
  1081. " position: fixed;\n"+
  1082. " z-index: 100002;\n"+
  1083. " left: 0;\n"+
  1084. " top: 0;\n"+
  1085. " right: 0;\n"+
  1086. " bottom: 0;\n"+
  1087. " display: flex;\n"+
  1088. " align-items: center;\n"+
  1089. " justify-content: center;\n"+
  1090. "}\n"+
  1091. ".donate-dialog .donate-title {\n"+
  1092. " font-size: 20px;\n"+
  1093. "}\n"+
  1094. ".donate-dialog .donate-content {\n"+
  1095. " margin-bottom: 10px;\n"+
  1096. "}\n"+
  1097. ".donate-dialog .donate-wrap {\n"+
  1098. " width: 400px;\n"+
  1099. " padding: 10px;\n"+
  1100. " background: #fff;\n"+
  1101. " border-radius: 5px;\n"+
  1102. " border: 1px solid #aaa;\n"+
  1103. "}\n"+
  1104. ".donate-dialog .donate-qrcode-bar {\n"+
  1105. " display: flex;\n"+
  1106. " justify-content: space-between;\n"+
  1107. "}\n"+
  1108. ".donate-dialog .donate-qrcode-bar img {\n"+
  1109. " height: 168px;\n"+
  1110. "}\n"+
  1111. ".donate-dialog .donate-qrcode-desc {\n"+
  1112. " text-align: center;\n"+
  1113. "}\n"+
  1114. ".donate-dialog .donate-close-btn {\n"+
  1115. " margin-top: 10px;\n"+
  1116. "}\n"+
  1117. ".donate-dialog .donate-close-btn:before {\n"+
  1118. " content: '关闭';\n"+
  1119. " text-align: center;\n"+
  1120. " display: block;\n"+
  1121. "}\n"+
  1122. ".player-menu {\n"+
  1123. " position: fixed;\n"+
  1124. " top: 0;\n"+
  1125. " left: 0;\n"+
  1126. " right: 0;\n"+
  1127. " bottom: 0;\n"+
  1128. " z-index: 100001;\n"+
  1129. "}\n"+
  1130. ".player-menu .menu {\n"+
  1131. " position: absolute;\n"+
  1132. " background-color: #fff;\n"+
  1133. " min-width: 200px;\n"+
  1134. " border: 1px solid #aaa;\n"+
  1135. " box-shadow: 2px 2px 5px rgba(0, 0, 0, 0.5);\n"+
  1136. " -webkit-user-select: none;\n"+
  1137. " -moz-user-select: none;\n"+
  1138. "}\n"+
  1139. ".player-menu .menu .menu-dash {\n"+
  1140. " height: 1px;\n"+
  1141. " background-color: #aaa;\n"+
  1142. "}\n"+
  1143. ".player-menu .menu .menu-item {\n"+
  1144. " color: #000;\n"+
  1145. " padding: 5px;\n"+
  1146. " cursor: default;\n"+
  1147. "}\n"+
  1148. ".player-menu .menu .menu-item:last-child {\n"+
  1149. " border-bottom: 0;\n"+
  1150. "}\n"+
  1151. ".player-menu .menu .menu-item:hover {\n"+
  1152. " background-color: #ddd;\n"+
  1153. "}\n"+
  1154. ".danmu-container {\n"+
  1155. " width: 100%;\n"+
  1156. " height: 100%;\n"+
  1157. " border: 1px solid #e5e4e4;\n"+
  1158. " box-sizing: border-box;\n"+
  1159. "}\n"+
  1160. ".danmu-wrap {\n"+
  1161. " width: 100%;\n"+
  1162. " height: 100%;\n"+
  1163. " position: relative;\n"+
  1164. " background-color: #000;\n"+
  1165. "}\n"+
  1166. ".danmu-wrap .danmu-input {\n"+
  1167. " display: none;\n"+
  1168. "}\n"+
  1169. ".danmu-wrap .danmu-video {\n"+
  1170. " width: 100%;\n"+
  1171. " height: calc(100% - 42px);\n"+
  1172. "}\n"+
  1173. ".danmu-wrap .danmu-ctrl {\n"+
  1174. " box-sizing: border-box;\n"+
  1175. " border: 1px solid #fafafa;\n"+
  1176. " border-left: 0;\n"+
  1177. " border-right: 0;\n"+
  1178. " width: 100%;\n"+
  1179. " height: 42px;\n"+
  1180. " padding: 5px;\n"+
  1181. " color: #5a5a5a;\n"+
  1182. " background: #fafafa;\n"+
  1183. "}\n"+
  1184. ".danmu-wrap .danmu-ctrl > a {\n"+
  1185. " float: left;\n"+
  1186. " cursor: pointer;\n"+
  1187. "}\n"+
  1188. ".danmu-wrap .danmu-ctrl .danmu-btn {\n"+
  1189. " box-sizing: border-box;\n"+
  1190. " display: inline-block;\n"+
  1191. " height: 30px;\n"+
  1192. "}\n"+
  1193. ".danmu-wrap .danmu-ctrl .danmu-mute {\n"+
  1194. " float: right;\n"+
  1195. " width: 30px;\n"+
  1196. " height: 30px;\n"+
  1197. " padding: 5px;\n"+
  1198. " transition: all .3s ease;\n"+
  1199. " background: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBzdGFuZGFsb25lPSJubyI%2FPg0KPCFET0NUWVBFIHN2ZyBQVUJMSUMgIi0vL1czQy8vRFREIFNWRyAxLjEvL0VOIiANCiJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPg0KDQo8c3ZnIHdpZHRoPSIyMCIgaGVpZ2h0PSIyMCIgdmVyc2lvbj0iMS4xIg0KeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiBzdHlsZT0ic3Ryb2tlOiAjNWE1YTVhOyBmaWxsOnRyYW5zcGFyZW50OyBzdHJva2Utd2lkdGg6MiI%2BDQogIDxwYXRoIGQ9Ik05LDQgTDUsOCBMMiw4IEwyLDEyIEw1LDEyIEw5LDE2IFoiIHN0eWxlPSJmaWxsOiAjNWE1YTVhIiAvPg0KICA8cGF0aCBkPSJNMTIsMTIgQTMsMyAwIDAgMCAxMiw4IFoiIHN0eWxlPSJmaWxsOiAjNWE1YTVhIiAvPg0KICA8cGF0aCBkPSJNMTIsMiBBIDksOSAwIDAgMSAxMiwxOCIgc3R5bGU9InN0cm9rZS13aWR0aDoyIi8%2BDQo8L3N2Zz4%3D) no-repeat center;\n"+
  1200. "}\n"+
  1201. ".danmu-wrap .danmu-ctrl .danmu-mute[muted] {\n"+
  1202. " background: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBzdGFuZGFsb25lPSJubyI%2FPg0KPCFET0NUWVBFIHN2ZyBQVUJMSUMgIi0vL1czQy8vRFREIFNWRyAxLjEvL0VOIiANCiJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPg0KDQo8c3ZnIHdpZHRoPSIyMCIgaGVpZ2h0PSIyMCIgdmVyc2lvbj0iMS4xIg0KeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiBzdHlsZT0ic3Ryb2tlOiAjNWE1YTVhOyBmaWxsOnRyYW5zcGFyZW50OyBzdHJva2Utd2lkdGg6MiI%2BDQogIDxwYXRoIGQ9Ik05LDQgTDUsOCBMMiw4IEwyLDEyIEw1LDEyIEw5LDE2IFoiIHN0eWxlPSJmaWxsOiAjNWE1YTVhIiAvPg0KICA8cGF0aCBkPSJNMTIsMTMgTDE4LDciIC8%2BDQogIDxwYXRoIGQ9Ik0xMiw3IEwxOCwxMyIgLz4NCjwvc3ZnPg%3D%3D) no-repeat center;\n"+
  1203. "}\n"+
  1204. ".danmu-wrap .danmu-ctrl .danmu-volume {\n"+
  1205. " box-sizing: border-box;\n"+
  1206. " margin: 5px;\n"+
  1207. " height: 20px;\n"+
  1208. " float: right;\n"+
  1209. " position: relative;\n"+
  1210. "}\n"+
  1211. ".danmu-wrap .danmu-ctrl .danmu-volume .progress {\n"+
  1212. " position: absolute;\n"+
  1213. " pointer-events: none;\n"+
  1214. " top: 9px;\n"+
  1215. " left: 0;\n"+
  1216. " width: 0;\n"+
  1217. " height: 2px;\n"+
  1218. " background-color: #4285f4;\n"+
  1219. "}\n"+
  1220. ".danmu-wrap .danmu-ctrl .danmu-volume > input[type=\"range\"] {\n"+
  1221. " cursor: pointer;\n"+
  1222. " height: 20px;\n"+
  1223. " outline: none;\n"+
  1224. " background-color: transparent;\n"+
  1225. " -webkit-appearance: none;\n"+
  1226. " -moz-appearance: none;\n"+
  1227. "}\n"+
  1228. ".danmu-wrap .danmu-ctrl .danmu-volume > input[type=\"range\"] .thumb {\n"+
  1229. " -webkit-appearance: none;\n"+
  1230. " -moz-appearance: none;\n"+
  1231. " height: 12px;\n"+
  1232. " width: 12px;\n"+
  1233. " margin-top: -5px;\n"+
  1234. " border-radius: 50%;\n"+
  1235. " background-color: #4285f4;\n"+
  1236. " position: relative;\n"+
  1237. " box-shadow: 0px 0px 0px #000000, 0px 0px 0px #0d0d0d;\n"+
  1238. "}\n"+
  1239. ".danmu-wrap .danmu-ctrl .danmu-volume > input[type=\"range\"]::-webkit-slider-thumb {\n"+
  1240. " -webkit-appearance: none;\n"+
  1241. " -moz-appearance: none;\n"+
  1242. " height: 12px;\n"+
  1243. " width: 12px;\n"+
  1244. " margin-top: -5px;\n"+
  1245. " border-radius: 50%;\n"+
  1246. " background-color: #4285f4;\n"+
  1247. " position: relative;\n"+
  1248. " box-shadow: 0px 0px 0px #000000, 0px 0px 0px #0d0d0d;\n"+
  1249. "}\n"+
  1250. ".danmu-wrap .danmu-ctrl .danmu-volume > input[type=\"range\"]::-moz-range-thumb {\n"+
  1251. " -webkit-appearance: none;\n"+
  1252. " -moz-appearance: none;\n"+
  1253. " height: 12px;\n"+
  1254. " width: 12px;\n"+
  1255. " margin-top: -5px;\n"+
  1256. " border-radius: 50%;\n"+
  1257. " background-color: #4285f4;\n"+
  1258. " position: relative;\n"+
  1259. " box-shadow: 0px 0px 0px #000000, 0px 0px 0px #0d0d0d;\n"+
  1260. "}\n"+
  1261. ".danmu-wrap .danmu-ctrl .danmu-volume > input[type=\"range\"] .track {\n"+
  1262. " height: 2px;\n"+
  1263. " background-color: #9f9f9f;\n"+
  1264. "}\n"+
  1265. ".danmu-wrap .danmu-ctrl .danmu-volume > input[type=\"range\"]::-webkit-slider-runnable-track {\n"+
  1266. " height: 2px;\n"+
  1267. " background-color: #9f9f9f;\n"+
  1268. "}\n"+
  1269. ".danmu-wrap .danmu-ctrl .danmu-volume > input[type=\"range\"]::-moz-range-track {\n"+
  1270. " height: 2px;\n"+
  1271. " background-color: #9f9f9f;\n"+
  1272. "}\n"+
  1273. ".danmu-wrap .danmu-ctrl .danmu-fullpage {\n"+
  1274. " float: right;\n"+
  1275. " width: 30px;\n"+
  1276. " height: 30px;\n"+
  1277. " padding: 5px;\n"+
  1278. "}\n"+
  1279. ".danmu-wrap .danmu-ctrl .danmu-fullpage::before {\n"+
  1280. " content: \" \";\n"+
  1281. " display: block;\n"+
  1282. " width: 20px;\n"+
  1283. " height: 16px;\n"+
  1284. " border: 2px solid #5a5a5a;\n"+
  1285. " box-sizing: border-box;\n"+
  1286. " margin-top: 2px;\n"+
  1287. "}\n"+
  1288. ".danmu-wrap .danmu-ctrl .danmu-fullscreen {\n"+
  1289. " float: right;\n"+
  1290. " width: 30px;\n"+
  1291. " height: 30px;\n"+
  1292. " padding: 5px;\n"+
  1293. " background: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBzdGFuZGFsb25lPSJubyI%2FPg0KPCFET0NUWVBFIHN2ZyBQVUJMSUMgIi0vL1czQy8vRFREIFNWRyAxLjEvL0VOIiANCiJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPg0KDQo8c3ZnIHdpZHRoPSIyMCIgaGVpZ2h0PSIyMCIgdmVyc2lvbj0iMS4xIg0KeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiBzdHlsZT0ic3Ryb2tlOiAjNWE1YTVhOyBmaWxsOnRyYW5zcGFyZW50OyBzdHJva2Utd2lkdGg6MiI%2BDQogIDxwb2x5bGluZSBwb2ludHM9IjEsOCAxLDEgOCwxIiAvPg0KICA8cG9seWxpbmUgcG9pbnRzPSIxOSw4IDE5LDEgMTIsMSIgLz4NCiAgPHBvbHlsaW5lIHBvaW50cz0iMSwxMiAxLDE5IDgsMTkiIC8%2BDQogIDxwb2x5bGluZSBwb2ludHM9IjE5LDEyIDE5LDE5IDEyLDE5IiAvPg0KPC9zdmc%2B);\n"+
  1294. " background-repeat: no-repeat;\n"+
  1295. " background-position: center;\n"+
  1296. "}\n"+
  1297. ".danmu-wrap .danmu-ctrl .danmu-switch {\n"+
  1298. " float: right;\n"+
  1299. " display: inline-block;\n"+
  1300. " height: 30px;\n"+
  1301. " line-height: 30px;\n"+
  1302. " padding: 0 5px;\n"+
  1303. "}\n"+
  1304. ".danmu-wrap .danmu-ctrl .danmu-tip {\n"+
  1305. " float: right;\n"+
  1306. " display: inline-block;\n"+
  1307. " height: 30px;\n"+
  1308. " line-height: 30px;\n"+
  1309. " padding: 0 5px;\n"+
  1310. " cursor: default;\n"+
  1311. "}\n"+
  1312. ".danmu-wrap .danmu-ctrl .danmu-reload {\n"+
  1313. " width: 30px;\n"+
  1314. " height: 30px;\n"+
  1315. " padding: 5px;\n"+
  1316. " background: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBzdGFuZGFsb25lPSJubyI%2FPg0KPCFET0NUWVBFIHN2ZyBQVUJMSUMgIi0vL1czQy8vRFREIFNWRyAxLjEvL0VOIiANCiJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPg0KDQo8c3ZnIHdpZHRoPSIyMCIgaGVpZ2h0PSIyMCIgdmVyc2lvbj0iMS4xIg0KeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiBzdHlsZT0ic3Ryb2tlOiAjNWE1YTVhOyBmaWxsOnRyYW5zcGFyZW50OyBzdHJva2Utd2lkdGg6Mi41Ij4NCiAgPHBhdGggZD0iTSAxOC42OSwxMi4zMyBBOCA4IDAgMSAxIDE4LjY5LDcuNjciIC8%2BDQogIDxwYXRoIGQ9Ik0gMTYsNyBMIDE5LDcgTCAxOSw0IFoiIC8%2BDQo8L3N2Zz4NCg%3D%3D);\n"+
  1317. " background-repeat: no-repeat;\n"+
  1318. " background-position: center;\n"+
  1319. "}\n"+
  1320. ".danmu-wrap .danmu-ctrl .danmu-playpause {\n"+
  1321. " width: 30px;\n"+
  1322. " height: 30px;\n"+
  1323. " padding: 5px;\n"+
  1324. "}\n"+
  1325. ".danmu-wrap .danmu-ctrl .danmu-playpause::before {\n"+
  1326. " transition: all .3s ease;\n"+
  1327. " border-color: transparent;\n"+
  1328. " content: \" \";\n"+
  1329. " display: block;\n"+
  1330. "}\n"+
  1331. ".danmu-wrap .danmu-ctrl .danmu-playpause:not([pause])::before {\n"+
  1332. " width: 0;\n"+
  1333. " height: 0;\n"+
  1334. " border-top: 10px solid transparent;\n"+
  1335. " border-left: 20px solid #5a5a5a;\n"+
  1336. " border-bottom: 10px solid transparent;\n"+
  1337. "}\n"+
  1338. ".danmu-wrap .danmu-ctrl .danmu-playpause[pause]::before {\n"+
  1339. " box-sizing: border-box;\n"+
  1340. " width: 15px;\n"+
  1341. " height: 20px;\n"+
  1342. " margin-left: 2.5px;\n"+
  1343. " border-left: 5px solid #5a5a5a;\n"+
  1344. " border-right: 5px solid #5a5a5a;\n"+
  1345. "}\n"+
  1346. ".danmu-wrap .danmu-layout {\n"+
  1347. " position: absolute;\n"+
  1348. " top: 0;\n"+
  1349. " left: 0;\n"+
  1350. " right: 0;\n"+
  1351. " bottom: 0;\n"+
  1352. " pointer-events: none;\n"+
  1353. " color: #fff;\n"+
  1354. " font-size: 25px;\n"+
  1355. " font-family: SimHei, \"Microsoft JhengHei\", Arial, Helvetica, sans-serif;\n"+
  1356. " text-shadow: #000000 1px 0px 1px, #000000 0px 1px 1px, #000000 0px -1px 1px, #000000 -1px 0px 1px;\n"+
  1357. " line-height: 1.25;\n"+
  1358. " font-weight: bold;\n"+
  1359. " overflow: hidden;\n"+
  1360. " opacity: 0.5;\n"+
  1361. "}\n"+
  1362. ".danmu-wrap .danmu-layout > div {\n"+
  1363. " display: none;\n"+
  1364. " position: absolute;\n"+
  1365. " white-space: pre;\n"+
  1366. "}\n"+
  1367. ".danmu-wrap .danmu-layout .danmu-self {\n"+
  1368. " outline: 2px solid #fff;\n"+
  1369. "}\n"+
  1370. ".danmu-wrap[fullpage] {\n"+
  1371. " top: 0;\n"+
  1372. " left: 0;\n"+
  1373. " width: 100%;\n"+
  1374. " height: 100%;\n"+
  1375. " position: fixed;\n"+
  1376. " z-index: 100000;\n"+
  1377. " cursor: none;\n"+
  1378. "}\n"+
  1379. ".danmu-wrap[fullpage] .danmu-input {\n"+
  1380. " position: absolute;\n"+
  1381. " top: 75%;\n"+
  1382. " width: 100%;\n"+
  1383. " display: block;\n"+
  1384. " transition: all .3s ease;\n"+
  1385. " transform: translateY(50px);\n"+
  1386. " opacity: 0;\n"+
  1387. "}\n"+
  1388. ".danmu-wrap[fullpage] .danmu-input > input {\n"+
  1389. " outline: 0;\n"+
  1390. " box-shadow: 0 0 10px 1px rgba(255, 255, 255, 0.8);\n"+
  1391. " width: 300px;\n"+
  1392. " margin: 0 auto;\n"+
  1393. " display: block;\n"+
  1394. " border: 0;\n"+
  1395. " background: rgba(255, 255, 255, 0.8);\n"+
  1396. " padding: 5px;\n"+
  1397. " color: #000;\n"+
  1398. " cursor: default;\n"+
  1399. "}\n"+
  1400. ".danmu-wrap[fullpage] .danmu-input > input::-webkit-input-placeholder {\n"+
  1401. " color: #888;\n"+
  1402. "}\n"+
  1403. ".danmu-wrap[fullpage][inputing] .danmu-input {\n"+
  1404. " transform: translateY(0);\n"+
  1405. " opacity: 1;\n"+
  1406. "}\n"+
  1407. ".danmu-wrap[fullpage][inputing] .danmu-input > input {\n"+
  1408. " cursor: text;\n"+
  1409. "}\n"+
  1410. ".danmu-wrap[fullpage] .danmu-video {\n"+
  1411. " height: 100%;\n"+
  1412. " transition: all .3s ease;\n"+
  1413. "}\n"+
  1414. ".danmu-wrap[fullpage] .danmu-ctrl {\n"+
  1415. " position: absolute;\n"+
  1416. " bottom: 0;\n"+
  1417. " opacity: 0;\n"+
  1418. " transition: all .3s ease;\n"+
  1419. "}\n"+
  1420. ".danmu-wrap[fullpage][hover] {\n"+
  1421. " cursor: default;\n"+
  1422. "}\n"+
  1423. ".danmu-wrap[fullpage][hover] .danmu-ctrl {\n"+
  1424. " cursor: default;\n"+
  1425. " opacity: 0.75;\n"+
  1426. "}\n"+
  1427. "\n"};
  1428. (function (global, factory) {
  1429. typeof exports === 'object' && typeof module !== 'undefined' ? factory(require('flv.js')) :
  1430. typeof define === 'function' && define.amd ? define(['flv.js'], factory) :
  1431. (factory(global.flvjs));
  1432. }(this, (function (flv_js) { 'use strict';
  1433.  
  1434. /*! *****************************************************************************
  1435. Copyright (c) Microsoft Corporation. All rights reserved.
  1436. Licensed under the Apache License, Version 2.0 (the "License"); you may not use
  1437. this file except in compliance with the License. You may obtain a copy of the
  1438. License at http://www.apache.org/licenses/LICENSE-2.0
  1439.  
  1440. THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  1441. KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
  1442. WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
  1443. MERCHANTABLITY OR NON-INFRINGEMENT.
  1444.  
  1445. See the Apache Version 2.0 License for specific language governing permissions
  1446. and limitations under the License.
  1447. ***************************************************************************** */
  1448. /* global Reflect, Promise */
  1449.  
  1450. var extendStatics = Object.setPrototypeOf ||
  1451. ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
  1452. function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
  1453.  
  1454.  
  1455.  
  1456.  
  1457.  
  1458.  
  1459.  
  1460. function __decorate(decorators, target, key, desc) {
  1461. var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
  1462. if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
  1463. else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
  1464. return c > 3 && r && Object.defineProperty(target, key, r), r;
  1465. }
  1466.  
  1467.  
  1468.  
  1469.  
  1470.  
  1471. function __awaiter(thisArg, _arguments, P, generator) {
  1472. return new (P || (P = Promise))(function (resolve, reject) {
  1473. function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
  1474. function rejected(value) { try { step(generator.throw(value)); } catch (e) { reject(e); } }
  1475. function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
  1476. step((generator = generator.apply(thisArg, _arguments || [])).next());
  1477. });
  1478. }
  1479.  
  1480.  
  1481.  
  1482.  
  1483.  
  1484.  
  1485.  
  1486. function __read(o, n) {
  1487. var m = typeof Symbol === "function" && o[Symbol.iterator];
  1488. if (!m) return o;
  1489. var i = m.call(o), r, ar = [], e;
  1490. try {
  1491. while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
  1492. }
  1493. catch (error) { e = { error: error }; }
  1494. finally {
  1495. try {
  1496. if (r && !r.done && (m = i["return"])) m.call(i);
  1497. }
  1498. finally { if (e) throw e.error; }
  1499. }
  1500. return ar;
  1501. }
  1502.  
  1503.  
  1504.  
  1505. function __await(v) {
  1506. return this instanceof __await ? (this.v = v, this) : new __await(v);
  1507. }
  1508.  
  1509. function hookFetchCode () {
  1510. // let self = this
  1511. const convertHeader = function convertHeader (headers) {
  1512. let out = new Headers();
  1513. for (let key of Object.keys(headers)) {
  1514. out.set(key, headers[key]);
  1515. }
  1516. return out
  1517. };
  1518. const hideHookStack = stack => {
  1519. return stack.replace(/^\s*at\s.*?hookfetch\.js:\d.*$\n/mg, '')
  1520. };
  1521. const base64ToUint8 = (b64) => {
  1522. const s = atob(b64);
  1523. const length = s.length;
  1524. let ret = new Uint8Array(length);
  1525. for (let i = 0; i < length; i++) {
  1526. ret[i] = s.charCodeAt(i);
  1527. }
  1528. return ret
  1529. };
  1530. class WrapPort {
  1531. constructor (port) {
  1532. this.curMethod = '';
  1533. this.curResolve = null;
  1534. this.curReject = null;
  1535. this.stack = '';
  1536. this.port = port;
  1537. this.lastDone = true;
  1538.  
  1539. port.onMessage.addListener(msg => this.onMessage(msg));
  1540. }
  1541. post (method, args) {
  1542. if (!this.lastDone) {
  1543. throw new Error('Last post is not done')
  1544. }
  1545. this.stack = new Error().stack;
  1546. return new Promise((resolve, reject) => {
  1547. this.lastDone = false;
  1548. this.curMethod = method;
  1549. this.curResolve = resolve;
  1550. this.curReject = reject;
  1551. this.port.postMessage({
  1552. method: method,
  1553. args: args
  1554. });
  1555. })
  1556. }
  1557. onMessage (msg) {
  1558. if (msg.method === this.curMethod) {
  1559. if (msg.err) {
  1560. let err = new Error(msg.err.message);
  1561. err.oriName = msg.err.name;
  1562. err.stack = hideHookStack(this.stack);
  1563. // console.log('fetch err', err)
  1564. this.curReject.call(null, err);
  1565. } else {
  1566. this.curResolve.apply(null, msg.args);
  1567. }
  1568. this.curResolve = null;
  1569. this.curReject = null;
  1570. this.lastDone = true;
  1571. } else {
  1572. console.error('wtf?');
  1573. }
  1574. }
  1575. }
  1576. class PortReader {
  1577. constructor (port) {
  1578. this.port = port;
  1579. this.hasReader = false;
  1580. }
  1581. _requireReader () {
  1582. if (this.hasReader) {
  1583. return Promise.resolve()
  1584. } else {
  1585. return this.port.post('body.getReader').then(() => this.hasReader = true)
  1586. }
  1587. }
  1588. read () {
  1589. return this._requireReader()
  1590. .then(() => this.port.post('reader.read'))
  1591. .then(r => {
  1592. if (r.done == false) {
  1593. r.value = base64ToUint8(r.value);
  1594. }
  1595. return r
  1596. })
  1597. }
  1598. cancel () {
  1599. return this._requireReader().then(() => this.port.post('reader.cancel'))
  1600. }
  1601. }
  1602. class PortBody {
  1603. constructor (port) {
  1604. this.port = port;
  1605. }
  1606. getReader () {
  1607. return new PortReader(this.port)
  1608. }
  1609. }
  1610. class PortFetch {
  1611. constructor () {
  1612. this.port = new WrapPort(chrome.runtime.connect({name: 'fetch'}));
  1613. }
  1614. fetch (...args) {
  1615. return this.port.post('fetch', args).then(r => {
  1616. r.json = () => this.port.post('json');
  1617. r.arrayBuffer = () => this.port.post('arrayBuffer').then(buf => {
  1618. return new Uint8Array(buf).buffer
  1619. });
  1620. r.headers = convertHeader(r.headers);
  1621. r.body = new PortBody(this.port);
  1622. return r
  1623. })
  1624. }
  1625. }
  1626. const bgFetch = function bgFetch (...args) {
  1627. const fetch = new PortFetch();
  1628. return fetch.fetch(...args)
  1629. };
  1630. function hookFetch () {
  1631. if (fetch !== bgFetch) {
  1632. fetch = bgFetch;
  1633. }
  1634. }
  1635. const oldBlob = Blob;
  1636. const newBlob = function newBlob(a, b) {
  1637. a[0] = `(${hookFetchCode})();${a[0]}`;
  1638. console.log('new blob', a, b);
  1639. return new oldBlob(a, b)
  1640. };
  1641. // if(self.document !== undefined) {
  1642. // if (self.Blob !== newBlob) {
  1643. // self.Blob = newBlob
  1644. // }
  1645. // }
  1646.  
  1647. hookFetch();
  1648. }
  1649. function isFirefox () {
  1650. return /Firefox/.test(navigator.userAgent)
  1651. }
  1652. if (!isFirefox()) {
  1653. hookFetchCode();
  1654. }
  1655.  
  1656. function utf8ToUtf16(utf8_bytes) {
  1657. let unicode_codes = [];
  1658. let unicode_code = 0;
  1659. let num_followed = 0;
  1660. for (let i = 0; i < utf8_bytes.length; ++i) {
  1661. let utf8_byte = utf8_bytes[i];
  1662. if (utf8_byte >= 0x100) {
  1663. }
  1664. else if ((utf8_byte & 0xC0) == 0x80) {
  1665. if (num_followed > 0) {
  1666. unicode_code = (unicode_code << 6) | (utf8_byte & 0x3f);
  1667. num_followed -= 1;
  1668. }
  1669. else {
  1670. }
  1671. }
  1672. else {
  1673. if (num_followed == 0) {
  1674. unicode_codes.push(unicode_code);
  1675. }
  1676. else {
  1677. }
  1678. if (utf8_byte < 0x80) {
  1679. unicode_code = utf8_byte;
  1680. num_followed = 0;
  1681. }
  1682. else if ((utf8_byte & 0xE0) == 0xC0) {
  1683. unicode_code = utf8_byte & 0x1f;
  1684. num_followed = 1;
  1685. }
  1686. else if ((utf8_byte & 0xF0) == 0xE0) {
  1687. unicode_code = utf8_byte & 0x0f;
  1688. num_followed = 2;
  1689. }
  1690. else if ((utf8_byte & 0xF8) == 0xF0) {
  1691. unicode_code = utf8_byte & 0x07;
  1692. num_followed = 3;
  1693. }
  1694. else {
  1695. }
  1696. }
  1697. }
  1698. if (num_followed == 0) {
  1699. unicode_codes.push(unicode_code);
  1700. }
  1701. else {
  1702. }
  1703. unicode_codes.shift();
  1704. let utf16_codes = [];
  1705. for (var i = 0; i < unicode_codes.length; ++i) {
  1706. unicode_code = unicode_codes[i];
  1707. if (unicode_code < (1 << 16)) {
  1708. utf16_codes.push(unicode_code);
  1709. }
  1710. else {
  1711. var first = ((unicode_code - (1 << 16)) / (1 << 10)) + 0xD800;
  1712. var second = (unicode_code % (1 << 10)) + 0xDC00;
  1713. utf16_codes.push(first);
  1714. utf16_codes.push(second);
  1715. }
  1716. }
  1717. return utf16_codes;
  1718. }
  1719. function utf8_to_ascii(str) {
  1720. const char2bytes = (unicode_code) => {
  1721. let utf8_bytes = [];
  1722. if (unicode_code < 0x80) {
  1723. utf8_bytes.push(unicode_code);
  1724. }
  1725. else if (unicode_code < (1 << 11)) {
  1726. utf8_bytes.push((unicode_code >>> 6) | 0xC0);
  1727. utf8_bytes.push((unicode_code & 0x3F) | 0x80);
  1728. }
  1729. else if (unicode_code < (1 << 16)) {
  1730. utf8_bytes.push((unicode_code >>> 12) | 0xE0);
  1731. utf8_bytes.push(((unicode_code >> 6) & 0x3f) | 0x80);
  1732. utf8_bytes.push((unicode_code & 0x3F) | 0x80);
  1733. }
  1734. else if (unicode_code < (1 << 21)) {
  1735. utf8_bytes.push((unicode_code >>> 18) | 0xF0);
  1736. utf8_bytes.push(((unicode_code >> 12) & 0x3F) | 0x80);
  1737. utf8_bytes.push(((unicode_code >> 6) & 0x3F) | 0x80);
  1738. utf8_bytes.push((unicode_code & 0x3F) | 0x80);
  1739. }
  1740. return utf8_bytes;
  1741. };
  1742. let o = [];
  1743. for (let i = 0; i < str.length; i++) {
  1744. o = o.concat(char2bytes(str.charCodeAt(i)));
  1745. }
  1746. return o.map(i => String.fromCharCode(i)).join('');
  1747. }
  1748. function ascii_to_utf8(str) {
  1749. let bytes = str.split('').map(i => i.charCodeAt(0));
  1750. return utf8ToUtf16(bytes).map(i => String.fromCharCode(i)).join('');
  1751. }
  1752. function requestFullScreen() {
  1753. let de = document.documentElement;
  1754. if (de.requestFullscreen) {
  1755. de.requestFullscreen();
  1756. }
  1757. else if (de.mozRequestFullScreen) {
  1758. de.mozRequestFullScreen();
  1759. }
  1760. else if (de.webkitRequestFullScreen) {
  1761. de.webkitRequestFullScreen();
  1762. }
  1763. }
  1764. function exitFullscreen() {
  1765. let de = document;
  1766. if (de.exitFullscreen) {
  1767. de.exitFullscreen();
  1768. }
  1769. else if (de.mozCancelFullScreen) {
  1770. de.mozCancelFullScreen();
  1771. }
  1772. else if (de.webkitCancelFullScreen) {
  1773. de.webkitCancelFullScreen();
  1774. }
  1775. }
  1776. class LocalStorage {
  1777. constructor(domain) {
  1778. this.domain = domain;
  1779. }
  1780. getItem(key, def) {
  1781. return window.localStorage.getItem(`${this.domain}-${key}`) || def;
  1782. }
  1783. setItem(key, data) {
  1784. window.localStorage.setItem(`${this.domain}-${key}`, data);
  1785. }
  1786. }
  1787. class Timer {
  1788. constructor(delay) {
  1789. this.delay = delay;
  1790. }
  1791. reset() {
  1792. if (this.id) {
  1793. clearTimeout(this.id);
  1794. }
  1795. this.id = window.setTimeout(this.onTimer, this.delay);
  1796. }
  1797. }
  1798. function getURL(src) {
  1799. if (src.substr(0, 5) !== 'blob:') {
  1800. src = chrome.runtime.getURL(src);
  1801. }
  1802. return src;
  1803. }
  1804. function addScript(src) {
  1805. var script = document.createElement('script');
  1806. script.src = getURL(src);
  1807. document.head.appendChild(script);
  1808. }
  1809. function addCss(src, rel = 'stylesheet', type = 'text/css') {
  1810. var link = document.createElement('link');
  1811. link.rel = rel;
  1812. link.type = type;
  1813. link.href = getURL(src);
  1814. document.head.appendChild(link);
  1815. }
  1816. function createBlobURL(content, type) {
  1817. var blob = new Blob([content], { type });
  1818. return URL.createObjectURL(blob);
  1819. }
  1820. const p32 = (i) => [i, i / 256, i / 65536, i / 16777216].map(i => String.fromCharCode(Math.floor(i) % 256)).join('');
  1821. const u32 = (s) => s.split('').map(i => i.charCodeAt(0)).reduce((a, b) => b * 256 + a);
  1822. let messageMap = {};
  1823. function onMessage(type, cb) {
  1824. messageMap[type] = cb;
  1825. }
  1826. function postMessage(type, data) {
  1827. window.postMessage({
  1828. type: type,
  1829. data: data
  1830. }, "*");
  1831. }
  1832. let msgCallbacks = [];
  1833. let lastCbId = 0;
  1834.  
  1835. window.addEventListener('message', (event) => __awaiter(window, void 0, void 0, function* () {
  1836. const data = event.data;
  1837. if (data.cb) {
  1838. let cb = msgCallbacks[data.cbId];
  1839. if (cb && (typeof cb === 'function')) {
  1840. cb(data.cbResult);
  1841. }
  1842. }
  1843. else if (data.type) {
  1844. let result = undefined;
  1845. if (typeof messageMap[data.type] === 'function') {
  1846. result = messageMap[data.type](data.data);
  1847. if (result instanceof Promise) {
  1848. result = yield result;
  1849. }
  1850. if (data.cbId) {
  1851. window.postMessage({
  1852. cb: true,
  1853. cbId: data.cbId,
  1854. cbResult: result
  1855. }, '*');
  1856. }
  1857. }
  1858. }
  1859. }), false);
  1860.  
  1861. function getSync() {
  1862. return new Promise((res, rej) => {
  1863. if (chrome && chrome.storage && chrome.storage.sync) {
  1864. chrome.storage.sync.get(items => {
  1865. res(items);
  1866. });
  1867. }
  1868. else {
  1869. rej(new Error('不支持的存储方式'));
  1870. }
  1871. });
  1872. }
  1873. function setSync(item) {
  1874. return new Promise((res, rej) => {
  1875. if (chrome && chrome.storage && chrome.storage.sync) {
  1876. chrome.storage.sync.set(item, res);
  1877. }
  1878. else {
  1879. rej(new Error('不支持的存储方式'));
  1880. }
  1881. });
  1882. }
  1883. function getSetting() {
  1884. return __awaiter(this, void 0, void 0, function* () {
  1885. let setting;
  1886. try {
  1887. setting = yield getSync();
  1888. }
  1889. catch (e) {
  1890. }
  1891. if (!setting) {
  1892. setting = {};
  1893. }
  1894. if (!setting.blacklist) {
  1895. setting.blacklist = [];
  1896. }
  1897. return setting;
  1898. });
  1899. }
  1900. function setSetting(setting) {
  1901. return __awaiter(this, void 0, void 0, function* () {
  1902. yield setSync(setting);
  1903. });
  1904. }
  1905. const defaultBgListener = (request) => __awaiter(window, void 0, void 0, function* () { return null; });
  1906. let bgListener = defaultBgListener;
  1907. function setBgListener(listener) {
  1908. if (bgListener === defaultBgListener) {
  1909. if ((typeof chrome !== 'undefined') && chrome.runtime && chrome.runtime.onMessage) {
  1910. chrome.runtime.onMessage.addListener((request, sender, sendResponse) => __awaiter(this, void 0, void 0, function* () {
  1911. sendResponse(yield bgListener(request));
  1912. }));
  1913. }
  1914. }
  1915. else {
  1916. console.warn('多次设置BgListener');
  1917. }
  1918. bgListener = listener;
  1919. }
  1920. class DelayNotify {
  1921. constructor(defaultValue) {
  1922. this.defaultValue = defaultValue;
  1923. this.notified = false;
  1924. this.tmid = null;
  1925. this.res = null;
  1926. }
  1927. notify(value) {
  1928. if (this.notified) {
  1929. return;
  1930. }
  1931. this.notified = true;
  1932. this.value = value;
  1933. if (this.res) {
  1934. this.res(this.value);
  1935. }
  1936. }
  1937. wait(timeout = 1000 * 10) {
  1938. if (this.notified) {
  1939. return Promise.resolve(this.value);
  1940. }
  1941. return new Promise((resolve, reject) => {
  1942. if (timeout > 0) {
  1943. window.setTimeout(() => {
  1944. resolve(this.defaultValue);
  1945. }, timeout);
  1946. }
  1947. this.res = (value) => {
  1948. return resolve(value);
  1949. };
  1950. });
  1951. }
  1952. reset() {
  1953. this.notified = false;
  1954. }
  1955. }
  1956.  
  1957. /*! typestate - v1.0.4 - 2016-09-07
  1958. * https://github.com/eonarheim/TypeState
  1959. * Copyright (c) 2016 Erik Onarheim; Licensed BSD-2-Clause*/
  1960. var typestate;
  1961. (function (typestate) {
  1962. /**
  1963. * Transition grouping to faciliate fluent api
  1964. */
  1965. var Transitions = (function () {
  1966. function Transitions(fsm) {
  1967. this.fsm = fsm;
  1968. }
  1969. /**
  1970. * Specify the end state(s) of a transition function
  1971. */
  1972. Transitions.prototype.to = function () {
  1973. var states = [];
  1974. for (var _i = 0; _i < arguments.length; _i++) {
  1975. states[_i - 0] = arguments[_i];
  1976. }
  1977. this.toStates = states;
  1978. this.fsm.addTransitions(this);
  1979. };
  1980. /**
  1981. * Specify that any state in the state enum is value
  1982. * Takes the state enum as an argument
  1983. */
  1984. Transitions.prototype.toAny = function (states) {
  1985. var toStates = [];
  1986. for (var s in states) {
  1987. if (states.hasOwnProperty(s)) {
  1988. toStates.push(states[s]);
  1989. }
  1990. }
  1991. this.toStates = toStates;
  1992. this.fsm.addTransitions(this);
  1993. };
  1994. return Transitions;
  1995. }());
  1996. typestate.Transitions = Transitions;
  1997. /**
  1998. * Internal representation of a transition function
  1999. */
  2000. var TransitionFunction = (function () {
  2001. function TransitionFunction(fsm, from, to) {
  2002. this.fsm = fsm;
  2003. this.from = from;
  2004. this.to = to;
  2005. }
  2006. return TransitionFunction;
  2007. }());
  2008. typestate.TransitionFunction = TransitionFunction;
  2009. /**
  2010. * A simple finite state machine implemented in TypeScript, the templated argument is meant to be used
  2011. * with an enumeration.
  2012. */
  2013. var FiniteStateMachine = (function () {
  2014. function FiniteStateMachine(startState) {
  2015. this._transitionFunctions = [];
  2016. this._onCallbacks = {};
  2017. this._exitCallbacks = {};
  2018. this._enterCallbacks = {};
  2019. this._invalidTransitionCallback = null;
  2020. this.currentState = startState;
  2021. this._startState = startState;
  2022. }
  2023. FiniteStateMachine.prototype.addTransitions = function (fcn) {
  2024. var _this = this;
  2025. fcn.fromStates.forEach(function (from) {
  2026. fcn.toStates.forEach(function (to) {
  2027. // self transitions are invalid and don't add duplicates
  2028. if (from !== to && !_this._validTransition(from, to)) {
  2029. _this._transitionFunctions.push(new TransitionFunction(_this, from, to));
  2030. }
  2031. });
  2032. });
  2033. };
  2034. /**
  2035. * Listen for the transition to this state and fire the associated callback
  2036. */
  2037. FiniteStateMachine.prototype.on = function (state, callback) {
  2038. var key = state.toString();
  2039. if (!this._onCallbacks[key]) {
  2040. this._onCallbacks[key] = [];
  2041. }
  2042. this._onCallbacks[key].push(callback);
  2043. return this;
  2044. };
  2045. /**
  2046. * Listen for the transition to this state and fire the associated callback, returning
  2047. * false in the callback will block the transition to this state.
  2048. */
  2049. FiniteStateMachine.prototype.onEnter = function (state, callback) {
  2050. var key = state.toString();
  2051. if (!this._enterCallbacks[key]) {
  2052. this._enterCallbacks[key] = [];
  2053. }
  2054. this._enterCallbacks[key].push(callback);
  2055. return this;
  2056. };
  2057. /**
  2058. * Listen for the transition to this state and fire the associated callback, returning
  2059. * false in the callback will block the transition from this state.
  2060. */
  2061. FiniteStateMachine.prototype.onExit = function (state, callback) {
  2062. var key = state.toString();
  2063. if (!this._exitCallbacks[key]) {
  2064. this._exitCallbacks[key] = [];
  2065. }
  2066. this._exitCallbacks[key].push(callback);
  2067. return this;
  2068. };
  2069. /**
  2070. * List for an invalid transition and handle the error, returning a falsy value will throw an
  2071. * exception, a truthy one will swallow the exception
  2072. */
  2073. FiniteStateMachine.prototype.onInvalidTransition = function (callback) {
  2074. if (!this._invalidTransitionCallback) {
  2075. this._invalidTransitionCallback = callback;
  2076. }
  2077. return this;
  2078. };
  2079. /**
  2080. * Declares the start state(s) of a transition function, must be followed with a '.to(...endStates)'
  2081. */
  2082. FiniteStateMachine.prototype.from = function () {
  2083. var states = [];
  2084. for (var _i = 0; _i < arguments.length; _i++) {
  2085. states[_i - 0] = arguments[_i];
  2086. }
  2087. var _transition = new Transitions(this);
  2088. _transition.fromStates = states;
  2089. return _transition;
  2090. };
  2091. FiniteStateMachine.prototype.fromAny = function (states) {
  2092. var fromStates = [];
  2093. for (var s in states) {
  2094. if (states.hasOwnProperty(s)) {
  2095. fromStates.push(states[s]);
  2096. }
  2097. }
  2098. var _transition = new Transitions(this);
  2099. _transition.fromStates = fromStates;
  2100. return _transition;
  2101. };
  2102. FiniteStateMachine.prototype._validTransition = function (from, to) {
  2103. return this._transitionFunctions.some(function (tf) {
  2104. return (tf.from === from && tf.to === to);
  2105. });
  2106. };
  2107. /**
  2108. * Check whether a transition to a new state is valid
  2109. */
  2110. FiniteStateMachine.prototype.canGo = function (state) {
  2111. return this.currentState === state || this._validTransition(this.currentState, state);
  2112. };
  2113. /**
  2114. * Transition to another valid state
  2115. */
  2116. FiniteStateMachine.prototype.go = function (state) {
  2117. if (!this.canGo(state)) {
  2118. if (!this._invalidTransitionCallback || !this._invalidTransitionCallback(this.currentState, state)) {
  2119. throw new Error('Error no transition function exists from state ' + this.currentState.toString() + ' to ' + state.toString());
  2120. }
  2121. }
  2122. else {
  2123. this._transitionTo(state);
  2124. }
  2125. };
  2126. /**
  2127. * This method is availble for overridding for the sake of extensibility.
  2128. * It is called in the event of a successful transition.
  2129. */
  2130. FiniteStateMachine.prototype.onTransition = function (from, to) {
  2131. // pass, does nothing until overidden
  2132. };
  2133. /**
  2134. * Reset the finite state machine back to the start state, DO NOT USE THIS AS A SHORTCUT for a transition.
  2135. * This is for starting the fsm from the beginning.
  2136. */
  2137. FiniteStateMachine.prototype.reset = function () {
  2138. this.currentState = this._startState;
  2139. };
  2140. /**
  2141. * Whether or not the current state equals the given state
  2142. */
  2143. FiniteStateMachine.prototype.is = function (state) {
  2144. return this.currentState === state;
  2145. };
  2146. FiniteStateMachine.prototype._transitionTo = function (state) {
  2147. var _this = this;
  2148. if (!this._exitCallbacks[this.currentState.toString()]) {
  2149. this._exitCallbacks[this.currentState.toString()] = [];
  2150. }
  2151. if (!this._enterCallbacks[state.toString()]) {
  2152. this._enterCallbacks[state.toString()] = [];
  2153. }
  2154. if (!this._onCallbacks[state.toString()]) {
  2155. this._onCallbacks[state.toString()] = [];
  2156. }
  2157. var canExit = this._exitCallbacks[this.currentState.toString()].reduce(function (accum, next) {
  2158. return accum && next.call(_this, state);
  2159. }, true);
  2160. var canEnter = this._enterCallbacks[state.toString()].reduce(function (accum, next) {
  2161. return accum && next.call(_this, _this.currentState);
  2162. }, true);
  2163. if (canExit && canEnter) {
  2164. var old = this.currentState;
  2165. this.currentState = state;
  2166. this._onCallbacks[this.currentState.toString()].forEach(function (fcn) {
  2167. fcn.call(_this, old);
  2168. });
  2169. this.onTransition(old, state);
  2170. }
  2171. };
  2172. return FiniteStateMachine;
  2173. }());
  2174. typestate.FiniteStateMachine = FiniteStateMachine;
  2175. })(typestate || (typestate = {}));
  2176. var TypeState_1 = typestate;
  2177.  
  2178. const storage = new LocalStorage('h5plr');
  2179. function findInParent(node, toFind) {
  2180. while ((node !== toFind) && (node !== null)) {
  2181. node = node.parentElement;
  2182. }
  2183. return node !== null;
  2184. }
  2185. var PlayerState;
  2186. (function (PlayerState) {
  2187. PlayerState[PlayerState["Stopped"] = 0] = "Stopped";
  2188. PlayerState[PlayerState["Playing"] = 1] = "Playing";
  2189. PlayerState[PlayerState["Paused"] = 2] = "Paused";
  2190. PlayerState[PlayerState["Buffering"] = 3] = "Buffering";
  2191. })(PlayerState || (PlayerState = {}));
  2192. var SizeState;
  2193. (function (SizeState) {
  2194. SizeState[SizeState["Normal"] = 0] = "Normal";
  2195. SizeState[SizeState["FullPage"] = 1] = "FullPage";
  2196. SizeState[SizeState["FullScreen"] = 2] = "FullScreen";
  2197. SizeState[SizeState["ExitFullScreen"] = 3] = "ExitFullScreen";
  2198. })(SizeState || (SizeState = {}));
  2199. class SizeStateFSM extends TypeState_1.FiniteStateMachine {
  2200. constructor() {
  2201. super(SizeState.Normal);
  2202. this.fromAny(SizeState).to(SizeState.Normal);
  2203. this.fromAny(SizeState).to(SizeState.FullPage);
  2204. this.fromAny(SizeState).to(SizeState.FullScreen);
  2205. this.from(SizeState.FullScreen).to(SizeState.ExitFullScreen);
  2206. }
  2207. onTransition(from, to) {
  2208. console.log('SizeFSM', from, to);
  2209. }
  2210. }
  2211. class PlayerStateFSM extends TypeState_1.FiniteStateMachine {
  2212. constructor() {
  2213. super(PlayerState.Stopped);
  2214. this.fromAny(PlayerState).to(PlayerState.Stopped);
  2215. this.fromAny(PlayerState).to(PlayerState.Playing);
  2216. this.from(PlayerState.Playing).to(PlayerState.Buffering);
  2217. this.from(PlayerState.Playing).to(PlayerState.Paused);
  2218. this.from(PlayerState.Buffering).to(PlayerState.Paused);
  2219. }
  2220. onTransition(from, to) {
  2221. console.log('PlayerFSM', from, to);
  2222. }
  2223. }
  2224. class PlayerUI {
  2225. constructor(listener, state) {
  2226. this.listener = listener;
  2227. this.state = state;
  2228. this.inputing = false;
  2229. this.hideDanmu = false;
  2230. this._muted = false;
  2231. this._fullscreen = false;
  2232. this._lastY = -1;
  2233. const playerContainer = document.createElement('div');
  2234. const playerWrap = document.createElement('div');
  2235. const playerCtrl = document.createElement('div');
  2236. const danmuLayout = document.createElement('div');
  2237. const videoBox = document.createElement('div');
  2238. const msgBox = document.createElement('div');
  2239. const msgInput = document.createElement('input');
  2240. const videoEl = document.createElement('video');
  2241. this.sizeState = new SizeStateFSM();
  2242. let lastState;
  2243. this.sizeState
  2244. .on(SizeState.Normal, from => {
  2245. switch (from) {
  2246. case SizeState.FullPage:
  2247. this._exitFullPage();
  2248. break;
  2249. case SizeState.ExitFullScreen:
  2250. this._exitFullScreen();
  2251. break;
  2252. }
  2253. })
  2254. .on(SizeState.FullPage, from => {
  2255. switch (from) {
  2256. case SizeState.Normal:
  2257. this._enterFullPage();
  2258. break;
  2259. case SizeState.ExitFullScreen:
  2260. this._enterFullPage();
  2261. break;
  2262. }
  2263. })
  2264. .on(SizeState.FullScreen, from => {
  2265. if (from == SizeState.FullScreen)
  2266. return;
  2267. lastState = from;
  2268. switch (from) {
  2269. case SizeState.Normal:
  2270. this._enterFullScreen();
  2271. break;
  2272. case SizeState.FullPage:
  2273. this._enterFullScreen();
  2274. break;
  2275. }
  2276. })
  2277. .on(SizeState.ExitFullScreen, from => {
  2278. this._exitFullScreen();
  2279. this.sizeState.go(lastState);
  2280. });
  2281. videoEl.style.width = videoEl.style.height = '100%';
  2282. msgInput.type = 'text';
  2283. msgInput.placeholder = '发送弹幕...';
  2284. msgBox.className = 'danmu-input';
  2285. videoBox.className = 'danmu-video';
  2286. playerCtrl.className = 'danmu-ctrl';
  2287. danmuLayout.className = 'danmu-layout';
  2288. playerWrap.className = 'danmu-wrap';
  2289. playerContainer.className = 'danmu-container';
  2290. videoBox.appendChild(videoEl);
  2291. msgBox.appendChild(msgInput);
  2292. playerWrap.appendChild(videoBox);
  2293. playerWrap.appendChild(playerCtrl);
  2294. playerWrap.appendChild(danmuLayout);
  2295. playerWrap.appendChild(msgBox);
  2296. playerContainer.appendChild(playerWrap);
  2297. let timer = new Timer(1000);
  2298. timer.onTimer = () => playerWrap.removeAttribute('hover');
  2299. playerWrap.addEventListener('mousemove', event => {
  2300. const hoverCtl = findInParent(event.target, playerCtrl);
  2301. if (event.offsetY - this._lastY == 0)
  2302. return;
  2303. this._lastY = event.offsetY;
  2304. let height = playerWrap.getBoundingClientRect().height;
  2305. if (event.offsetY > 0) {
  2306. playerWrap.setAttribute('hover', '');
  2307. timer.reset();
  2308. }
  2309. else {
  2310. playerWrap.removeAttribute('hover');
  2311. }
  2312. });
  2313. playerWrap.addEventListener('click', event => {
  2314. if (findInParent(event.target, msgBox))
  2315. return;
  2316. playerWrap.removeAttribute('inputing');
  2317. this.inputing = false;
  2318. });
  2319. document.addEventListener('keydown', event => {
  2320. if (event.keyCode == 13) {
  2321. if (this.sizeState.is(SizeState.Normal))
  2322. return;
  2323. if (event.target.nodeName.toUpperCase() === 'TEXTAREA')
  2324. return;
  2325. this.inputing = !this.inputing;
  2326. if (this.inputing) {
  2327. msgInput.value = '';
  2328. playerWrap.setAttribute('inputing', '');
  2329. msgInput.focus();
  2330. }
  2331. else {
  2332. if (msgInput.value.length > 0) {
  2333. listener.onSendDanmu(msgInput.value);
  2334. }
  2335. playerWrap.removeAttribute('inputing');
  2336. }
  2337. }
  2338. else if (event.keyCode == 27) {
  2339. if (this.sizeState.is(SizeState.FullPage)) {
  2340. this.sizeState.go(SizeState.Normal);
  2341. }
  2342. if (this.sizeState.is(SizeState.FullScreen)) {
  2343. this.sizeState.go(SizeState.ExitFullScreen);
  2344. }
  2345. }
  2346. });
  2347. document.addEventListener('webkitfullscreenchange', event => {
  2348. this._fullscreen = !this._fullscreen;
  2349. if (!this._fullscreen) {
  2350. if (this.sizeState.is(SizeState.FullScreen)) {
  2351. this.sizeState.go(SizeState.ExitFullScreen);
  2352. }
  2353. }
  2354. });
  2355. window.addEventListener('unload', event => {
  2356. listener.onStop();
  2357. listener.onUnload();
  2358. });
  2359. this.video = videoEl;
  2360. this.el = playerContainer;
  2361. this.wrap = playerWrap;
  2362. this.dmLayout = danmuLayout;
  2363. this.playerCtrl = playerCtrl;
  2364. this.transparent = this.transparent;
  2365. }
  2366. _exitFullScreen() {
  2367. exitFullscreen();
  2368. this.wrap.removeAttribute('fullpage');
  2369. this.el.appendChild(this.wrap);
  2370. document.body.style.overflow = document.body.parentElement.style.overflow = 'auto';
  2371. this.listener.onTryPlay();
  2372. }
  2373. _enterFullScreen() {
  2374. requestFullScreen();
  2375. this.wrap.setAttribute('fullpage', '');
  2376. document.body.appendChild(this.wrap);
  2377. document.body.style.overflow = document.body.parentElement.style.overflow = 'hidden';
  2378. this.listener.onTryPlay();
  2379. }
  2380. _exitFullPage() {
  2381. this.wrap.removeAttribute('fullpage');
  2382. this.el.appendChild(this.wrap);
  2383. document.body.style.overflow = document.body.parentElement.style.overflow = 'auto';
  2384. this.listener.onTryPlay();
  2385. }
  2386. _enterFullPage() {
  2387. this.wrap.setAttribute('fullpage', '');
  2388. document.body.appendChild(this.wrap);
  2389. document.body.style.overflow = document.body.parentElement.style.overflow = 'hidden';
  2390. this.listener.onTryPlay();
  2391. }
  2392. get transparent() {
  2393. return parseInt(storage.getItem('transparent', '0'));
  2394. }
  2395. set transparent(val) {
  2396. storage.setItem('transparent', val.toString());
  2397. this.dmLayout.style.opacity = (1 - val / 100).toString();
  2398. }
  2399. get playing() {
  2400. return this.state.is(PlayerState.Playing) || this.state.is(PlayerState.Buffering);
  2401. }
  2402. set playing(val) {
  2403. if (val) {
  2404. this.state.go(PlayerState.Playing);
  2405. }
  2406. else {
  2407. this.state.go(PlayerState.Paused);
  2408. }
  2409. }
  2410. get muted() {
  2411. return this._muted;
  2412. }
  2413. set muted(v) {
  2414. this.listener.onMute(v);
  2415. if (v) {
  2416. this.muteEl.setAttribute('muted', '');
  2417. }
  2418. else {
  2419. this.muteEl.removeAttribute('muted');
  2420. }
  2421. this._muted = v;
  2422. }
  2423. notifyStateChange() {
  2424. if (this.playing) {
  2425. this.playPause.setAttribute('pause', '');
  2426. }
  2427. else {
  2428. this.playPause.removeAttribute('pause');
  2429. }
  2430. }
  2431. initControls() {
  2432. if (this.tipEl)
  2433. return;
  2434. let bar = this.playerCtrl;
  2435. const now = () => new Date().getTime();
  2436. const addBtn = (cls, cb) => {
  2437. const btn = document.createElement('a');
  2438. btn.className = ['danmu-btn', 'danmu-' + cls].join(' ');
  2439. btn.addEventListener('click', cb);
  2440. bar.appendChild(btn);
  2441. return btn;
  2442. };
  2443. this.video.addEventListener('dblclick', event => {
  2444. switch (this.sizeState.currentState) {
  2445. case SizeState.Normal:
  2446. this.sizeState.go(SizeState.FullPage);
  2447. break;
  2448. case SizeState.FullPage:
  2449. this.sizeState.go(SizeState.Normal);
  2450. break;
  2451. case SizeState.FullScreen:
  2452. this.sizeState.go(SizeState.ExitFullScreen);
  2453. break;
  2454. }
  2455. event.preventDefault();
  2456. event.stopPropagation();
  2457. });
  2458. this.playPause = addBtn('playpause', () => {
  2459. this.playing = !this.playing;
  2460. this.notifyStateChange();
  2461. });
  2462. this.playPause.setAttribute('pause', '');
  2463. const reload = addBtn('reload', () => {
  2464. this.listener.onReload();
  2465. });
  2466. const fullscreen = addBtn('fullscreen', () => {
  2467. if (this.sizeState.is(SizeState.FullScreen)) {
  2468. this.sizeState.go(SizeState.ExitFullScreen);
  2469. }
  2470. else {
  2471. this.sizeState.go(SizeState.FullScreen);
  2472. }
  2473. });
  2474. const fullpage = addBtn('fullpage', () => {
  2475. switch (this.sizeState.currentState) {
  2476. case SizeState.Normal:
  2477. this.sizeState.go(SizeState.FullPage);
  2478. break;
  2479. case SizeState.FullPage:
  2480. this.sizeState.go(SizeState.Normal);
  2481. break;
  2482. case SizeState.FullScreen:
  2483. this.sizeState.go(SizeState.ExitFullScreen);
  2484. this.sizeState.go(SizeState.FullPage);
  2485. break;
  2486. }
  2487. });
  2488. const volume = this.createVolume(percent => {
  2489. this.listener.onVolumeChange(percent);
  2490. });
  2491. bar.appendChild(volume);
  2492. this.muteEl = addBtn('mute', () => {
  2493. this.muted = !this.muted;
  2494. });
  2495. const danmuSwitch = addBtn('switch', () => {
  2496. this.hideDanmu = !this.hideDanmu;
  2497. this.listener.onHideDanmu(this.hideDanmu);
  2498. danmuSwitch.innerText = this.hideDanmu ? '开启弹幕' : '关闭弹幕';
  2499. this.dmLayout.style.display = this.hideDanmu ? 'none' : 'block';
  2500. });
  2501. danmuSwitch.innerText = this.hideDanmu ? '开启弹幕' : '关闭弹幕';
  2502. const tip = document.createElement('div');
  2503. tip.className = 'danmu-tip';
  2504. bar.appendChild(tip);
  2505. this.tipEl = tip;
  2506. }
  2507. createVolume(cb) {
  2508. const volume = document.createElement('div');
  2509. const progress = document.createElement('div');
  2510. const input = document.createElement('input');
  2511. volume.className = 'danmu-volume';
  2512. progress.className = 'progress';
  2513. input.type = 'range';
  2514. volume.appendChild(input);
  2515. volume.appendChild(progress);
  2516. input.value = storage.getItem('volume') || '100';
  2517. cb(parseInt(input.value) / 100);
  2518. input.addEventListener('input', event => {
  2519. progress.style.width = `${input.value}%`;
  2520. cb(parseInt(input.value) / 100);
  2521. storage.setItem('volume', input.value);
  2522. });
  2523. progress.style.width = `${input.value}%`;
  2524. return volume;
  2525. }
  2526. setTip(tip) {
  2527. this.tipEl.innerText = tip;
  2528. }
  2529. }
  2530. class PlayerBufferMonitor {
  2531. constructor(dmPlayer) {
  2532. this.dmPlayer = dmPlayer;
  2533. this.intId = window.setInterval(() => {
  2534. try {
  2535. this.handler();
  2536. }
  2537. catch (e) {
  2538. console.error(e);
  2539. }
  2540. }, 200);
  2541. this.reset();
  2542. }
  2543. unload() {
  2544. window.clearInterval(this.intId);
  2545. }
  2546. reset() {
  2547. this.bufTime = 1;
  2548. }
  2549. get player() {
  2550. return this.dmPlayer.player;
  2551. }
  2552. handler() {
  2553. if (this.player) {
  2554. const buffered = this.player.buffered;
  2555. if (buffered.length === 0)
  2556. return;
  2557. const buf = buffered.end(buffered.length - 1) - this.player.currentTime;
  2558. const state = this.dmPlayer.state;
  2559. if (state.is(PlayerState.Playing)) {
  2560. if (buf <= 1) {
  2561. state.go(PlayerState.Buffering);
  2562. this.dmPlayer.ui.notifyStateChange();
  2563. this.bufTime *= 2;
  2564. if (this.bufTime > 8) {
  2565. console.warn('网络不佳');
  2566. this.bufTime = 8;
  2567. }
  2568. }
  2569. }
  2570. else if (state.is(PlayerState.Buffering)) {
  2571. if (buf > this.bufTime) {
  2572. state.go(PlayerState.Playing);
  2573. this.dmPlayer.player.currentTime -= 0.5;
  2574. this.dmPlayer.ui.notifyStateChange();
  2575. }
  2576. }
  2577. }
  2578. }
  2579. }
  2580. class DanmuPlayer {
  2581. constructor(listener, ui) {
  2582. this.inputing = false;
  2583. this._src = '';
  2584. this.bufferMonitor = new PlayerBufferMonitor(this);
  2585. this.state = new PlayerStateFSM();
  2586. const now = () => new Date().getTime();
  2587. let beginTime = 0;
  2588. this.state
  2589. .on(PlayerState.Stopped, () => {
  2590. beginTime = 0;
  2591. this.mgr.deferTime = 0;
  2592. this.bufferMonitor.reset();
  2593. if (this.player) {
  2594. this.player.unload();
  2595. this.player.detachMediaElement();
  2596. this.player = null;
  2597. }
  2598. })
  2599. .on(PlayerState.Paused, from => {
  2600. beginTime = now();
  2601. this.player.pause();
  2602. })
  2603. .on(PlayerState.Playing, from => {
  2604. if (beginTime !== 0) {
  2605. this.mgr.deferTime += now() - beginTime;
  2606. }
  2607. this.player.play();
  2608. })
  2609. .on(PlayerState.Buffering, from => {
  2610. beginTime = 0;
  2611. this.player.pause();
  2612. });
  2613. this.initUI();
  2614. this.mgr = new DanmuManager(this.ui.dmLayout, this.state);
  2615. this.listener = listener;
  2616. }
  2617. onVolumeChange(vol) {
  2618. this.player.volume = vol;
  2619. }
  2620. onReload() {
  2621. this.stop();
  2622. this.load();
  2623. }
  2624. onSendDanmu(txt) {
  2625. this.listener.onSendDanmu(txt);
  2626. }
  2627. onStop() {
  2628. this.stop();
  2629. }
  2630. onUnload() {
  2631. this.bufferMonitor.unload();
  2632. }
  2633. onTryPlay() {
  2634. this.tryPlay();
  2635. }
  2636. onMute(muted) {
  2637. if (muted) {
  2638. this.lastVolume = this.player.volume;
  2639. this.player.volume = 0;
  2640. }
  2641. else {
  2642. this.player.volume = this.lastVolume;
  2643. }
  2644. }
  2645. onHideDanmu(hide) {
  2646. this.mgr.hideDanmu = hide;
  2647. }
  2648. onStat(e) {
  2649. this.ui.setTip(Math.round(e.speed * 10) / 10 + 'KB/s');
  2650. }
  2651. load() {
  2652. return __awaiter(this, void 0, void 0, function* () {
  2653. this.src = yield this.listener.getSrc();
  2654. });
  2655. }
  2656. createFlvjs() {
  2657. const sourceConfig = {
  2658. isLive: true,
  2659. type: 'flv',
  2660. url: this.src
  2661. };
  2662. const playerConfig = {
  2663. enableWorker: false,
  2664. deferLoadAfterSourceOpen: true,
  2665. stashInitialSize: 512 * 1024,
  2666. enableStashBuffer: true,
  2667. autoCleanupMinBackwardDuration: 20,
  2668. autoCleanupMaxBackwardDuration: 40,
  2669. autoCleanupSourceBuffer: true
  2670. };
  2671. const player = flvjs.createPlayer(sourceConfig, playerConfig);
  2672. player.on(flvjs.Events.ERROR, (e, t) => {
  2673. console.error('播放器发生错误:' + e + ' - ' + t);
  2674. player.unload();
  2675. });
  2676. player.on(flvjs.Events.STATISTICS_INFO, this.onStat.bind(this));
  2677. player.attachMediaElement(this.ui.video);
  2678. player.load();
  2679. player.play();
  2680. return player;
  2681. }
  2682. stop() {
  2683. this.state.go(PlayerState.Stopped);
  2684. }
  2685. set src(val) {
  2686. this._src = val;
  2687. this.stop();
  2688. let player = this.createFlvjs();
  2689. this.player = player;
  2690. this.ui.initControls();
  2691. this.state.go(PlayerState.Playing);
  2692. }
  2693. get src() {
  2694. return this._src;
  2695. }
  2696. initUI() {
  2697. this.ui = new PlayerUI(this, this.state);
  2698. }
  2699. tryPlay() {
  2700. if (this.state.is(PlayerState.Playing)) {
  2701. try {
  2702. this.ui.video.play();
  2703. }
  2704. catch (e) { }
  2705. }
  2706. }
  2707. fireDanmu(text, color, cls) {
  2708. return this.mgr.fireDanmu(text, color, cls);
  2709. }
  2710. }
  2711. class DanmuManager {
  2712. constructor(danmuLayout, state) {
  2713. this.danmuLayout = danmuLayout;
  2714. this.state = state;
  2715. this.pool = [];
  2716. this.rows = [];
  2717. this._deferTime = 0;
  2718. this.maxRow = 10;
  2719. this.baseTop = 10;
  2720. this.deferId = null;
  2721. this.deferQueue = [];
  2722. this.hideDanmu = false;
  2723. this.parsePic = (i) => i;
  2724. const poolSize = 100;
  2725. for (let i = 0; i < poolSize; i++) {
  2726. let dm = document.createElement('div');
  2727. danmuLayout.appendChild(dm);
  2728. this.pool.push({
  2729. el: dm,
  2730. using: false
  2731. });
  2732. }
  2733. }
  2734. get playing() {
  2735. return this.state.is(PlayerState.Playing);
  2736. }
  2737. set deferTime(v) {
  2738. this._deferTime = v;
  2739. this.defering = v !== 0;
  2740. }
  2741. get deferTime() {
  2742. return this._deferTime;
  2743. }
  2744. calcRect() {
  2745. return this.danmuLayout.getBoundingClientRect();
  2746. }
  2747. calcRow(width, duration) {
  2748. let rect = this.calcRect();
  2749. const now = new Date().getTime();
  2750. const check = (idx) => {
  2751. let row = this.rows[idx];
  2752. if (!row)
  2753. return true;
  2754. if (row.endTime <= now) {
  2755. this.rows[idx] = null;
  2756. return true;
  2757. }
  2758. else {
  2759. const distance = rect.width + row.width;
  2760. const percent = (now - row.beginTime) / row.duration;
  2761. const left = rect.width - distance * percent;
  2762. if (left + row.width >= rect.width) {
  2763. return false;
  2764. }
  2765. const remainTime = row.endTime - now;
  2766. const myDistance = rect.width + width;
  2767. const leftX = rect.width - (myDistance) * (remainTime / duration);
  2768. if (leftX < 0) {
  2769. return false;
  2770. }
  2771. }
  2772. return true;
  2773. };
  2774. let i = 0;
  2775. while (true) {
  2776. if (check(i)) {
  2777. this.rows[i] = {
  2778. duration: duration,
  2779. beginTime: now,
  2780. endTime: now + duration,
  2781. width: width
  2782. };
  2783. return i % this.maxRow;
  2784. }
  2785. i++;
  2786. }
  2787. }
  2788. doDefer() {
  2789. if (this.deferQueue.length === 0)
  2790. return;
  2791. const top = this.deferQueue[0];
  2792. const now = new Date().getTime();
  2793. if (this.playing && ((top.oriTime + this.deferTime) <= now)) {
  2794. top.run();
  2795. this.deferQueue.shift();
  2796. }
  2797. }
  2798. set defering(v) {
  2799. if (this.deferId === null) {
  2800. if (v) {
  2801. this.deferId = window.setInterval(() => this.doDefer(), 100);
  2802. }
  2803. }
  2804. else {
  2805. if (v === false) {
  2806. window.clearInterval(this.deferId);
  2807. this.deferId = null;
  2808. }
  2809. }
  2810. }
  2811. fireDanmu(text, color, cls) {
  2812. const fire = () => {
  2813. let rect = this.calcRect();
  2814. const duration = rect.width * 7;
  2815. let { el: dm } = this.pool.shift();
  2816. setTimeout(() => {
  2817. dm.removeAttribute('style');
  2818. this.pool.push({
  2819. el: dm,
  2820. using: false
  2821. });
  2822. }, duration);
  2823. dm.innerText = text;
  2824. dm.innerHTML = this.parsePic(dm.innerHTML);
  2825. if (Array.isArray(cls))
  2826. cls = cls.join(' ');
  2827. dm.className = cls || '';
  2828. dm.style.left = `${rect.width}px`;
  2829. dm.style.display = 'inline-block';
  2830. dm.style.color = color;
  2831. setTimeout(() => {
  2832. let dmRect = dm.getBoundingClientRect();
  2833. const row = this.calcRow(dmRect.width, duration);
  2834. dm.style.top = `${this.baseTop + row * dmRect.height}px`;
  2835. dm.style.transition = `transform ${duration / 1000}s linear`;
  2836. dm.style.transform = `translateX(-${rect.width + dmRect.width}px)`;
  2837. }, 0);
  2838. };
  2839. const now = new Date().getTime();
  2840. if (!this.playing || this.deferTime > 0) {
  2841. this.deferQueue.push({
  2842. oriTime: now,
  2843. run: () => fire()
  2844. });
  2845. return;
  2846. }
  2847. if (this.hideDanmu)
  2848. return;
  2849. if (this.pool.length == 0)
  2850. return;
  2851. fire();
  2852. }
  2853. }
  2854.  
  2855. const createMenu = (x, y) => {
  2856. const wrap = document.createElement('div');
  2857. const menu = document.createElement('div');
  2858. wrap.className = 'player-menu';
  2859. menu.className = 'menu';
  2860. wrap.appendChild(menu);
  2861.  
  2862. menu.style.left = `${x}px`;
  2863. menu.style.top = `${y}px`;
  2864.  
  2865. menu.close = () => document.body.removeChild(wrap);
  2866. wrap.addEventListener('mousedown', event => {
  2867. if (event.target === wrap) {
  2868. document.body.removeChild(wrap);
  2869. }
  2870. });
  2871. wrap.addEventListener('contextmenu', event => event.preventDefault());
  2872.  
  2873. document.body.appendChild(wrap);
  2874. return menu
  2875. };
  2876. const addTextMenu = (menu, text, cb) => {
  2877. const item = document.createElement('div');
  2878. item.className = 'menu-item';
  2879. item.innerText = text;
  2880. menu.appendChild(item);
  2881.  
  2882. item.addEventListener('click', () => {
  2883. menu.close();
  2884. cb();
  2885. });
  2886. };
  2887. const addEleMenu = (menu, ele) => {
  2888. const item = document.createElement('div');
  2889. item.className = 'menu-ele';
  2890. item.appendChild(ele);
  2891. menu.appendChild(item);
  2892. };
  2893. const addLabelMenu = (menu, label) => {
  2894. const item = document.createElement('div');
  2895. item.className = 'menu-item';
  2896. item.innerText = label;
  2897. menu.appendChild(item);
  2898. };
  2899. const addDash = (menu) => {
  2900. const item = document.createElement('div');
  2901. item.className = 'menu-dash';
  2902. menu.appendChild(item);
  2903. };
  2904. function bindMenu (el, menuItems) {
  2905. el.addEventListener('contextmenu', event => {
  2906. const menu = createMenu(event.clientX, event.clientY);
  2907. let items = menuItems;
  2908. if (typeof items === 'function') items = items();
  2909. for (let item of items) {
  2910. if (item.text) {
  2911. addTextMenu(menu, item.text, item.cb);
  2912. } else if (item.el) {
  2913. addEleMenu(menu, item.el, item.cb);
  2914. } else if (item.label) {
  2915. addLabelMenu(menu, item.label);
  2916. } else {
  2917. addDash(menu);
  2918. }
  2919. }
  2920. const rect = menu.getBoundingClientRect();
  2921. if (menu.offsetLeft + menu.offsetWidth > document.documentElement.clientWidth) {
  2922. menu.style.left = `${rect.left - rect.width}px`;
  2923. }
  2924. if (menu.offsetTop + menu.offsetHeight > document.documentElement.clientHeight) {
  2925. menu.style.top = `${rect.top - rect.height}px`;
  2926. }
  2927. event.preventDefault();
  2928. });
  2929. }
  2930.  
  2931. function md5cycle(x, k) {
  2932. var a = x[0], b = x[1], c = x[2], d = x[3];
  2933. a = ff(a, b, c, d, k[0], 7, -680876936);
  2934. d = ff(d, a, b, c, k[1], 12, -389564586);
  2935. c = ff(c, d, a, b, k[2], 17, 606105819);
  2936. b = ff(b, c, d, a, k[3], 22, -1044525330);
  2937. a = ff(a, b, c, d, k[4], 7, -176418897);
  2938. d = ff(d, a, b, c, k[5], 12, 1200080426);
  2939. c = ff(c, d, a, b, k[6], 17, -1473231341);
  2940. b = ff(b, c, d, a, k[7], 22, -45705983);
  2941. a = ff(a, b, c, d, k[8], 7, 1770035416);
  2942. d = ff(d, a, b, c, k[9], 12, -1958414417);
  2943. c = ff(c, d, a, b, k[10], 17, -42063);
  2944. b = ff(b, c, d, a, k[11], 22, -1990404162);
  2945. a = ff(a, b, c, d, k[12], 7, 1804603682);
  2946. d = ff(d, a, b, c, k[13], 12, -40341101);
  2947. c = ff(c, d, a, b, k[14], 17, -1502002290);
  2948. b = ff(b, c, d, a, k[15], 22, 1236535329);
  2949. a = gg(a, b, c, d, k[1], 5, -165796510);
  2950. d = gg(d, a, b, c, k[6], 9, -1069501632);
  2951. c = gg(c, d, a, b, k[11], 14, 643717713);
  2952. b = gg(b, c, d, a, k[0], 20, -373897302);
  2953. a = gg(a, b, c, d, k[5], 5, -701558691);
  2954. d = gg(d, a, b, c, k[10], 9, 38016083);
  2955. c = gg(c, d, a, b, k[15], 14, -660478335);
  2956. b = gg(b, c, d, a, k[4], 20, -405537848);
  2957. a = gg(a, b, c, d, k[9], 5, 568446438);
  2958. d = gg(d, a, b, c, k[14], 9, -1019803690);
  2959. c = gg(c, d, a, b, k[3], 14, -187363961);
  2960. b = gg(b, c, d, a, k[8], 20, 1163531501);
  2961. a = gg(a, b, c, d, k[13], 5, -1444681467);
  2962. d = gg(d, a, b, c, k[2], 9, -51403784);
  2963. c = gg(c, d, a, b, k[7], 14, 1735328473);
  2964. b = gg(b, c, d, a, k[12], 20, -1926607734);
  2965. a = hh(a, b, c, d, k[5], 4, -378558);
  2966. d = hh(d, a, b, c, k[8], 11, -2022574463);
  2967. c = hh(c, d, a, b, k[11], 16, 1839030562);
  2968. b = hh(b, c, d, a, k[14], 23, -35309556);
  2969. a = hh(a, b, c, d, k[1], 4, -1530992060);
  2970. d = hh(d, a, b, c, k[4], 11, 1272893353);
  2971. c = hh(c, d, a, b, k[7], 16, -155497632);
  2972. b = hh(b, c, d, a, k[10], 23, -1094730640);
  2973. a = hh(a, b, c, d, k[13], 4, 681279174);
  2974. d = hh(d, a, b, c, k[0], 11, -358537222);
  2975. c = hh(c, d, a, b, k[3], 16, -722521979);
  2976. b = hh(b, c, d, a, k[6], 23, 76029189);
  2977. a = hh(a, b, c, d, k[9], 4, -640364487);
  2978. d = hh(d, a, b, c, k[12], 11, -421815835);
  2979. c = hh(c, d, a, b, k[15], 16, 530742520);
  2980. b = hh(b, c, d, a, k[2], 23, -995338651);
  2981. a = ii(a, b, c, d, k[0], 6, -198630844);
  2982. d = ii(d, a, b, c, k[7], 10, 1126891415);
  2983. c = ii(c, d, a, b, k[14], 15, -1416354905);
  2984. b = ii(b, c, d, a, k[5], 21, -57434055);
  2985. a = ii(a, b, c, d, k[12], 6, 1700485571);
  2986. d = ii(d, a, b, c, k[3], 10, -1894986606);
  2987. c = ii(c, d, a, b, k[10], 15, -1051523);
  2988. b = ii(b, c, d, a, k[1], 21, -2054922799);
  2989. a = ii(a, b, c, d, k[8], 6, 1873313359);
  2990. d = ii(d, a, b, c, k[15], 10, -30611744);
  2991. c = ii(c, d, a, b, k[6], 15, -1560198380);
  2992. b = ii(b, c, d, a, k[13], 21, 1309151649);
  2993. a = ii(a, b, c, d, k[4], 6, -145523070);
  2994. d = ii(d, a, b, c, k[11], 10, -1120210379);
  2995. c = ii(c, d, a, b, k[2], 15, 718787259);
  2996. b = ii(b, c, d, a, k[9], 21, -343485551);
  2997. x[0] = add32(a, x[0]);
  2998. x[1] = add32(b, x[1]);
  2999. x[2] = add32(c, x[2]);
  3000. x[3] = add32(d, x[3]);
  3001. }
  3002. function cmn(q, a, b, x, s, t) {
  3003. a = add32(add32(a, q), add32(x, t));
  3004. return add32((a << s) | (a >>> (32 - s)), b);
  3005. }
  3006. function ff(a, b, c, d, x, s, t) {
  3007. return cmn((b & c) | ((~b) & d), a, b, x, s, t);
  3008. }
  3009. function gg(a, b, c, d, x, s, t) {
  3010. return cmn((b & d) | (c & (~d)), a, b, x, s, t);
  3011. }
  3012. function hh(a, b, c, d, x, s, t) {
  3013. return cmn(b ^ c ^ d, a, b, x, s, t);
  3014. }
  3015. function ii(a, b, c, d, x, s, t) {
  3016. return cmn(c ^ (b | (~d)), a, b, x, s, t);
  3017. }
  3018. function md51(s) {
  3019. var txt = '';
  3020. var n = s.length, state = [1732584193, -271733879, -1732584194, 271733878], i;
  3021. for (i = 64; i <= s.length; i += 64) {
  3022. md5cycle(state, md5blk(s.substring(i - 64, i)));
  3023. }
  3024. s = s.substring(i - 64);
  3025. var tail = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
  3026. for (i = 0; i < s.length; i++)
  3027. tail[i >> 2] |= s.charCodeAt(i) << ((i % 4) << 3);
  3028. tail[i >> 2] |= 0x80 << ((i % 4) << 3);
  3029. if (i > 55) {
  3030. md5cycle(state, tail);
  3031. for (i = 0; i < 16; i++)
  3032. tail[i] = 0;
  3033. }
  3034. tail[14] = n * 8;
  3035. md5cycle(state, tail);
  3036. return state;
  3037. }
  3038. function md5blk(s) {
  3039. var md5blks = [], i;
  3040. for (i = 0; i < 64; i += 4) {
  3041. md5blks[i >> 2] = s.charCodeAt(i) + (s.charCodeAt(i + 1) << 8) + (s.charCodeAt(i + 2) << 16) + (s.charCodeAt(i + 3) << 24);
  3042. }
  3043. return md5blks;
  3044. }
  3045. var hex_chr = '0123456789abcdef'.split('');
  3046. function rhex(n) {
  3047. var s = '', j = 0;
  3048. for (; j < 4; j++)
  3049. s += hex_chr[(n >> (j * 8 + 4)) & 0x0F] + hex_chr[(n >> (j * 8)) & 0x0F];
  3050. return s;
  3051. }
  3052. function hex(x) {
  3053. return x.map(rhex).join('');
  3054. }
  3055. function md5(s) {
  3056. return hex(md51(s));
  3057. }
  3058. var add32 = function (a, b) {
  3059. return (a + b) & 0xFFFFFFFF;
  3060. };
  3061. if (md5('hello') != '5d41402abc4b2a76b9719d911017c592') {
  3062. add32 = function (x, y) {
  3063. var lsw = (x & 0xFFFF) + (y & 0xFFFF), msw = (x >> 16) + (y >> 16) + (lsw >> 16);
  3064. return (msw << 16) | (lsw & 0xFFFF);
  3065. };
  3066. }
  3067.  
  3068. class BaseSource {
  3069. constructor() {
  3070. this.onChange = () => null;
  3071. }
  3072. set url(v) {
  3073. if (v === this._url) {
  3074. this._url = v;
  3075. return;
  3076. }
  3077. this.onChange(v);
  3078. }
  3079. get url() {
  3080. return this._url;
  3081. }
  3082. }
  3083.  
  3084. let m_signer = null;
  3085. function getSourceURL(rid, cdn, rate) {
  3086. return __awaiter(this, void 0, void 0, function* () {
  3087. const tt = Math.round(new Date().getTime() / 60 / 1000);
  3088. const did = md5(Math.random().toString()).toUpperCase();
  3089. if (m_signer === null) {
  3090. throw new Error('Signer is not defined.');
  3091. }
  3092. const sign = yield m_signer(rid, tt, did);
  3093. let body = {
  3094. 'cdn': cdn,
  3095. 'rate': rate,
  3096. 'ver': 'Douyu_h5_2017080201beta',
  3097. 'tt': tt,
  3098. 'did': did,
  3099. 'sign': sign.sign,
  3100. 'cptl': sign.cptl,
  3101. 'ct': 'webh5'
  3102. };
  3103. body = Object.keys(body).map(key => `${key}=${encodeURIComponent(body[key])}`).join('&');
  3104. const res = yield fetch(`https://www.douyu.com/lapi/live/getPlay/${rid}`, {
  3105. method: 'POST',
  3106. headers: {
  3107. 'Content-Type': 'application/x-www-form-urlencoded'
  3108. },
  3109. body: body
  3110. });
  3111. const videoInfo = yield res.json();
  3112. const baseUrl = videoInfo.data.rtmp_url;
  3113. const livePath = videoInfo.data.rtmp_live;
  3114. if (baseUrl && livePath) {
  3115. const videoUrl = `${baseUrl}/${livePath}`;
  3116. console.log('RoomId', rid, 'SourceURL:', videoUrl);
  3117. return videoUrl;
  3118. }
  3119. else {
  3120. throw new Error('未开播或获取失败');
  3121. }
  3122. });
  3123. }
  3124. function getSwfApi(rid) {
  3125. return __awaiter(this, void 0, void 0, function* () {
  3126. const API_KEY = 'bLFlashflowlad92';
  3127. const tt = Math.round(new Date().getTime() / 60 / 1000);
  3128. const signContent = [rid, API_KEY, tt].join('');
  3129. const sign = md5(signContent);
  3130. const res = yield fetch(`https://www.douyu.com/swf_api/room/${rid}?cdn=&nofan=yes&_t=${tt}&sign=${sign}`);
  3131. const obj = yield res.json();
  3132. return yield obj.data;
  3133. });
  3134. }
  3135. class DouyuSource extends BaseSource {
  3136. constructor(roomId, signer) {
  3137. super();
  3138. m_signer = signer;
  3139. this._cdn = 'ws';
  3140. this._rate = '0';
  3141. this.url = '';
  3142. this.roomId = roomId;
  3143. this.swfApi = null;
  3144. }
  3145. set cdn(val) {
  3146. this._cdn = val;
  3147. this.getUrl();
  3148. }
  3149. get cdn() {
  3150. return this._cdn;
  3151. }
  3152. set rate(val) {
  3153. this._rate = val;
  3154. this.getUrl();
  3155. }
  3156. get rate() {
  3157. return this._rate;
  3158. }
  3159. get cdnsWithName() {
  3160. if (this.swfApi) {
  3161. return this.swfApi.cdnsWithName;
  3162. }
  3163. else {
  3164. return [{
  3165. name: '主要线路',
  3166. cdn: 'ws'
  3167. }];
  3168. }
  3169. }
  3170. getUrl() {
  3171. return __awaiter(this, void 0, void 0, function* () {
  3172. if (!this.swfApi) {
  3173. this.swfApi = yield getSwfApi(this.roomId);
  3174. this._cdn = this.swfApi.cdns[0];
  3175. }
  3176. let url = yield getSourceURL(this.roomId, this.cdn, this.rate);
  3177. this.url = url;
  3178. return url;
  3179. });
  3180. }
  3181. }
  3182.  
  3183. class JSocket {
  3184. static init() {
  3185. return __awaiter(this, void 0, void 0, function* () {
  3186. const src = 'https://imspace.nos-eastchina1.126.net/JSocket2.swf';
  3187. const flash = ['<object type="application/x-shockwave-flash" ', 'id="jsocket" ', 'name="jsocket" ', 'align="middle" ', 'allowscriptaccess="always" ', 'allowfullscreen="true" ', 'allowfullscreeninteractive="true" ', 'wmode="transparent" ', 'data="' + src + '" ', 'width="100%" ', 'height="100%">', '<param name="src" value="' + src + '">', '<param name="quality" value="high">', '<param name="bgcolor" value="#fff">', '<param name="allowscriptaccess" value="always">', '<param name="allowfullscreen" value="true">', '<param name="wmode" value="transparent">', '<param name="allowFullScreenInteractive" value="true">', '<param name="flashvars" value="">', "</object>"].join("");
  3188. let div = document.createElement('div');
  3189. div.className = 'jsocket-cls';
  3190. document.body.appendChild(div);
  3191. JSocket.el = div;
  3192. div.innerHTML = flash;
  3193. var api = document.querySelector('#jsocket');
  3194. console.log(div, api);
  3195. JSocket.flashapi = api;
  3196. if (JSocket.flashapi.newsocket) {
  3197. return;
  3198. }
  3199. else {
  3200. return new Promise((res, rej) => {
  3201. const id = setTimeout(rej, 10 * 1000);
  3202. JSocket.swfloadedcb = () => {
  3203. clearTimeout(id);
  3204. res();
  3205. };
  3206. });
  3207. }
  3208. });
  3209. }
  3210. static swfloaded() {
  3211. JSocket.swfloadedcb();
  3212. }
  3213. static connectHandler(socid) {
  3214. JSocket.handlers[socid].connectHandler();
  3215. }
  3216. static dataHandler(socid, data) {
  3217. try {
  3218. JSocket.handlers[socid].dataHandler(atob(data));
  3219. }
  3220. catch (e) {
  3221. console.error(e);
  3222. }
  3223. }
  3224. static closeHandler(socid) {
  3225. JSocket.handlers[socid].closeHandler();
  3226. }
  3227. static errorHandler(socid, str) {
  3228. JSocket.handlers[socid].errorHandler(str);
  3229. }
  3230. init(handlers, newsocketopt) {
  3231. this.socid = JSocket.flashapi.newsocket(newsocketopt);
  3232. JSocket.handlers[this.socid] = handlers;
  3233. }
  3234. connect(host, port) {
  3235. JSocket.flashapi.connect(this.socid, host, port);
  3236. }
  3237. write(data) {
  3238. JSocket.flashapi.write(this.socid, btoa(data));
  3239. }
  3240. writeFlush(data) {
  3241. JSocket.flashapi.writeFlush(this.socid, btoa(data));
  3242. }
  3243. close() {
  3244. JSocket.flashapi.close(this.socid);
  3245. }
  3246. flush() {
  3247. JSocket.flashapi.flush(this.socid);
  3248. }
  3249. }
  3250. JSocket.VERSION = '0.1';
  3251. JSocket.handlers = [];
  3252. window.JSocket = JSocket;
  3253.  
  3254. const getACF = (key) => {
  3255. try {
  3256. return new RegExp(`acf_${key}=(.*?);`).exec(document.cookie)[1];
  3257. }
  3258. catch (e) {
  3259. return '';
  3260. }
  3261. };
  3262. function filterEnc(s) {
  3263. s = s.toString();
  3264. s = s.replace(/@/g, '@A');
  3265. return s.replace(/\//g, '@S');
  3266. }
  3267. function filterDec(s) {
  3268. s = s.toString();
  3269. s = s.replace(/@S/g, '/');
  3270. return s.replace(/@A/g, '@');
  3271. }
  3272. function douyuEncode(data) {
  3273. return Object.keys(data).map(key => `${key}@=${filterEnc(data[key])}`).join('/') + '/';
  3274. }
  3275. function douyuDecode(data) {
  3276. let out = {
  3277. type: '!!missing!!'
  3278. };
  3279. try {
  3280. data.split('/').filter(i => i.length > 2).forEach(i => {
  3281. let e = i.split('@=');
  3282. out[e[0]] = filterDec(e[1]);
  3283. });
  3284. }
  3285. catch (e) {
  3286. console.error(e);
  3287. console.log(data);
  3288. }
  3289. return out;
  3290. }
  3291. function ACJ(id, data) {
  3292. if (typeof data == 'object') {
  3293. data = douyuEncode(data);
  3294. }
  3295. try {
  3296. window._ACJ_([id, data]);
  3297. }
  3298. catch (e) {
  3299. console.error(id, data, e);
  3300. }
  3301. }
  3302. class DouyuProtocol extends JSocket {
  3303. constructor(listener) {
  3304. super();
  3305. this.listener = listener;
  3306. this.connectHandler = () => null;
  3307. this.init(this, {});
  3308. this.buffer = '';
  3309. }
  3310. connectAsync(host, port) {
  3311. super.connect(host, port);
  3312. return new Promise((res, rej) => {
  3313. const prevConnHandler = this.connectHandler;
  3314. const prevErrHandler = this.errorHandler;
  3315. const recover = () => {
  3316. this.connectHandler = prevConnHandler;
  3317. this.errorHandler = prevErrHandler;
  3318. };
  3319. this.connectHandler = () => {
  3320. recover();
  3321. res();
  3322. };
  3323. this.errorHandler = () => {
  3324. recover();
  3325. rej();
  3326. };
  3327. });
  3328. }
  3329. dataHandler(data) {
  3330. this.buffer += data;
  3331. let buffer = this.buffer;
  3332. while (buffer.length >= 4) {
  3333. let size = u32(buffer.substr(0, 4));
  3334. if (buffer.length >= size) {
  3335. let pkgStr = '';
  3336. try {
  3337. pkgStr = ascii_to_utf8(buffer.substr(12, size - 8));
  3338. }
  3339. catch (e) {
  3340. console.log('deocde fail', escape(buffer.substr(12, size - 8)));
  3341. }
  3342. this.buffer = buffer = buffer.substr(size + 4);
  3343. if (pkgStr.length === 0)
  3344. continue;
  3345. try {
  3346. let pkg = douyuDecode(pkgStr);
  3347. this.listener && this.listener.onPackage(pkg, pkgStr);
  3348. }
  3349. catch (e) {
  3350. console.error('call map', e);
  3351. }
  3352. }
  3353. else {
  3354. break;
  3355. }
  3356. }
  3357. }
  3358. closeHandler() {
  3359. console.error('lost connection');
  3360. this.listener && this.listener.onClose();
  3361. }
  3362. errorHandler(err) {
  3363. console.error(err);
  3364. this.listener && this.listener.onError(err);
  3365. }
  3366. send(data) {
  3367. let msg = douyuEncode(data) + '\0';
  3368. msg = utf8_to_ascii(msg);
  3369. msg = p32(msg.length + 8) + p32(msg.length + 8) + p32(689) + msg;
  3370. this.writeFlush(msg);
  3371. }
  3372. }
  3373. function Type(type) {
  3374. return (target, propertyKey, descriptor) => {
  3375. if (!target.map) {
  3376. target.map = {};
  3377. }
  3378. target.map[type] = target[propertyKey];
  3379. };
  3380. }
  3381. class DouyuBaseClient {
  3382. constructor(roomId) {
  3383. this.roomId = roomId;
  3384. this.lastIP = null;
  3385. this.lastPort = null;
  3386. this.keepaliveId = null;
  3387. this.redirect = {};
  3388. this.prot = new DouyuProtocol(this);
  3389. }
  3390. static getRoomArgs() {
  3391. if (window._room_args)
  3392. return window._room_args;
  3393. if (window.room_args) {
  3394. return window.room_args;
  3395. }
  3396. else {
  3397. return window.$ROOM.args;
  3398. }
  3399. }
  3400. reconnect() {
  3401. return __awaiter(this, void 0, void 0, function* () {
  3402. console.log('reconnect');
  3403. this.prot.listener = null;
  3404. this.prot = new DouyuProtocol(this);
  3405. try {
  3406. yield this.connectAsync(this.lastIP, this.lastPort);
  3407. }
  3408. catch (e) {
  3409. this.onError();
  3410. }
  3411. });
  3412. }
  3413. onClose() {
  3414. setTimeout(() => this.reconnect(), 1000);
  3415. }
  3416. onError() {
  3417. this.onClose();
  3418. }
  3419. onPackage(pkg, pkgStr) {
  3420. const type = pkg.type;
  3421. if (this.redirect[type]) {
  3422. ACJ(this.redirect[type], pkg);
  3423. return;
  3424. }
  3425. if (this.map[type]) {
  3426. this.map[type].call(this, pkg, pkgStr);
  3427. return;
  3428. }
  3429. this.onDefault(pkg);
  3430. }
  3431. onDefault(pkg) {
  3432. }
  3433. send(pkg) {
  3434. this.prot.send(pkg);
  3435. }
  3436. connectAsync(ip, port) {
  3437. return __awaiter(this, void 0, void 0, function* () {
  3438. this.lastIP = ip;
  3439. this.lastPort = port;
  3440. yield this.prot.connectAsync(ip, port);
  3441. this.send(this.loginreq());
  3442. });
  3443. }
  3444. keepalivePkg() {
  3445. return {
  3446. type: 'keeplive',
  3447. tick: Math.round(new Date().getTime() / 1000).toString()
  3448. };
  3449. }
  3450. loginreq() {
  3451. const rt = Math.round(new Date().getTime() / 1000);
  3452. const devid = getACF('devid');
  3453. const username = getACF('username');
  3454. console.log('username', username, devid);
  3455. return {
  3456. type: 'loginreq',
  3457. username: username,
  3458. ct: 0,
  3459. password: '',
  3460. roomid: this.roomId,
  3461. devid: devid,
  3462. rt: rt,
  3463. vk: md5(`${rt}r5*^5;}2#\${XF[h+;'./.Q'1;,-]f'p[${devid}`),
  3464. ver: '20150929',
  3465. aver: '2017012111',
  3466. biz: getACF('biz'),
  3467. stk: getACF('stk'),
  3468. ltkid: getACF('ltkid')
  3469. };
  3470. }
  3471. startKeepalive() {
  3472. this.send(this.keepalivePkg());
  3473. if (this.keepaliveId) {
  3474. clearInterval(this.keepaliveId);
  3475. }
  3476. this.keepaliveId = setInterval(() => this.send(this.keepalivePkg()), 30 * 1000);
  3477. }
  3478. }
  3479. let blacklist = [];
  3480. function onChatMsg(data) {
  3481. if (blacklist.indexOf(data.uid) !== -1) {
  3482. console.log('black');
  3483. return;
  3484. }
  3485. try {
  3486. postMessage('DANMU', data);
  3487. }
  3488. catch (e) {
  3489. console.error('wtf', e);
  3490. }
  3491. ACJ('room_data_chat2', data);
  3492. if (window.BarrageReturn) {
  3493. window.BarrageReturn(douyuEncode(data));
  3494. }
  3495. }
  3496. class DouyuClient extends DouyuBaseClient {
  3497. constructor(roomId, danmuClient) {
  3498. super(roomId);
  3499. this.danmuClient = danmuClient;
  3500. this.redirect = {
  3501. qtlr: 'room_data_tasklis',
  3502. initcl: 'room_data_chatinit',
  3503. memberinfores: 'room_data_info',
  3504. ranklist: 'room_data_cqrank',
  3505. rsm: 'room_data_brocast',
  3506. qausrespond: 'data_rank_score',
  3507. frank: 'room_data_handler',
  3508. online_noble_list: 'room_data_handler',
  3509. };
  3510. }
  3511. reqOnlineGift(loginres) {
  3512. return {
  3513. type: 'reqog',
  3514. uid: loginres.userid
  3515. };
  3516. }
  3517. chatmsg(data) {
  3518. onChatMsg(data);
  3519. }
  3520. resog(data) {
  3521. ACJ('room_data_chest', {
  3522. lev: data.lv,
  3523. lack_time: data.t,
  3524. dl: data.dl
  3525. });
  3526. }
  3527. loginres(data) {
  3528. console.log('loginres ms', data);
  3529. this.uid = data.userid;
  3530. this.send(this.reqOnlineGift(data));
  3531. this.startKeepalive();
  3532. ACJ('room_data_login', data);
  3533. ACJ('room_data_getdid', {
  3534. devid: getACF('devid')
  3535. });
  3536. }
  3537. keeplive(data, rawString) {
  3538. ACJ('room_data_userc', data.uc);
  3539. ACJ('room_data_tbredpacket', rawString);
  3540. }
  3541. setmsggroup(data) {
  3542. console.log('joingroup', data);
  3543. this.danmuClient.send({
  3544. type: 'joingroup',
  3545. rid: data.rid,
  3546. gid: data.gid
  3547. });
  3548. }
  3549. onDefault(data) {
  3550. ACJ('room_data_handler', data);
  3551. console.log('ms', data);
  3552. }
  3553. }
  3554. __decorate([
  3555. Type('chatmsg')
  3556. ], DouyuClient.prototype, "chatmsg", null);
  3557. __decorate([
  3558. Type('resog')
  3559. ], DouyuClient.prototype, "resog", null);
  3560. __decorate([
  3561. Type('loginres')
  3562. ], DouyuClient.prototype, "loginres", null);
  3563. __decorate([
  3564. Type('keeplive')
  3565. ], DouyuClient.prototype, "keeplive", null);
  3566. __decorate([
  3567. Type('setmsggroup')
  3568. ], DouyuClient.prototype, "setmsggroup", null);
  3569. class DouyuDanmuClient extends DouyuBaseClient {
  3570. constructor(roomId) {
  3571. super(roomId);
  3572. this.redirect = {
  3573. chatres: 'room_data_chat2',
  3574. initcl: 'room_data_chatinit',
  3575. dgb: 'room_data_giftbat1',
  3576. dgn: 'room_data_giftbat1',
  3577. spbc: 'room_data_giftbat1',
  3578. uenter: 'room_data_nstip2',
  3579. upgrade: 'room_data_ulgrow',
  3580. newblackres: 'room_data_sys',
  3581. ranklist: 'room_data_cqrank',
  3582. rankup: 'room_data_ulgrow',
  3583. gift_title: 'room_data_schat',
  3584. rss: 'room_data_state',
  3585. srres: 'room_data_wbsharesuc',
  3586. onlinegift: 'room_data_olyw',
  3587. gpbc: 'room_data_handler',
  3588. synexp: 'room_data_handler',
  3589. frank: 'room_data_handler',
  3590. ggbb: 'room_data_sabonusget',
  3591. online_noble_list: 'room_data_handler',
  3592. };
  3593. }
  3594. chatmsg(pkg) {
  3595. onChatMsg(pkg);
  3596. }
  3597. loginres(data) {
  3598. console.log('loginres dm', data);
  3599. this.startKeepalive();
  3600. }
  3601. onDefault(data) {
  3602. ACJ('room_data_handler', data);
  3603. console.log('dm', data);
  3604. }
  3605. }
  3606. __decorate([
  3607. Type('chatmsg')
  3608. ], DouyuDanmuClient.prototype, "chatmsg", null);
  3609. __decorate([
  3610. Type('loginres')
  3611. ], DouyuDanmuClient.prototype, "loginres", null);
  3612.  
  3613. const runtime = {
  3614. sendMessage(message) {
  3615. return chrome.runtime.sendMessage(message);
  3616. },
  3617. connect(connectInfo) {
  3618. return chrome.runtime.connect(connectInfo);
  3619. }
  3620. };
  3621.  
  3622. var SignerState;
  3623. (function (SignerState) {
  3624. SignerState[SignerState["None"] = 0] = "None";
  3625. SignerState[SignerState["Loaded"] = 1] = "Loaded";
  3626. SignerState[SignerState["Ready"] = 2] = "Ready";
  3627. SignerState[SignerState["Timeout"] = 3] = "Timeout";
  3628. })(SignerState || (SignerState = {}));
  3629. function wrapPort(port) {
  3630. let curMethod = '';
  3631. let curResolve = null;
  3632. let curReject = null;
  3633. let stack = new Error().stack;
  3634. port.onMessage.addListener((msg) => {
  3635. if (msg.method === curMethod) {
  3636. curResolve(msg.args[0]);
  3637. }
  3638. else {
  3639. curReject('wtf');
  3640. console.error('wtf?');
  3641. }
  3642. });
  3643. return function (method, ...args) {
  3644. return new Promise((resolve, reject) => {
  3645. curMethod = method;
  3646. curResolve = resolve;
  3647. curReject = reject;
  3648. port.postMessage({
  3649. method: method,
  3650. args: args
  3651. });
  3652. });
  3653. };
  3654. }
  3655. let Signer;
  3656. {
  3657. const DB_NAME = 'shared-worker-signer';
  3658. const DB_VERSION = 1;
  3659. const DB_STORE_NAME = 'cache';
  3660. class ManualCache {
  3661. initDB() {
  3662. return new Promise((resolve, reject) => {
  3663. const that = this;
  3664. const req = indexedDB.open(DB_NAME, DB_VERSION);
  3665. req.onsuccess = function (evt) {
  3666. that.db = this.result;
  3667. resolve(that);
  3668. };
  3669. req.onerror = function (evt) {
  3670. that.errCode = evt.target.errorCode;
  3671. reject(that.errCode);
  3672. };
  3673. req.onupgradeneeded = function (evt) {
  3674. const store = evt.currentTarget.result.createObjectStore(DB_STORE_NAME);
  3675. };
  3676. });
  3677. }
  3678. getArrayBuffer(key, url) {
  3679. return this.getFile(key).then((file) => {
  3680. if (file && file.url === url) {
  3681. return file.data;
  3682. }
  3683. else {
  3684. return this.fetchAndSave(key, url);
  3685. }
  3686. });
  3687. }
  3688. putFile(key, url, data) {
  3689. return new Promise((resolve, reject) => {
  3690. const tx = this.db.transaction(DB_STORE_NAME, 'readwrite');
  3691. const store = tx.objectStore(DB_STORE_NAME);
  3692. const req = store.put({ data: data, url: url }, key);
  3693. req.onsuccess = function (evt) {
  3694. resolve();
  3695. };
  3696. req.onerror = function () {
  3697. reject(this.error);
  3698. };
  3699. });
  3700. }
  3701. getFile(key) {
  3702. return new Promise((resolve, reject) => {
  3703. const tx = this.db.transaction(DB_STORE_NAME, 'readonly');
  3704. const store = tx.objectStore(DB_STORE_NAME);
  3705. const req = store.get(key);
  3706. req.onsuccess = function ({ target }) {
  3707. resolve(target.result);
  3708. };
  3709. req.onerror = function () {
  3710. reject(this.error);
  3711. };
  3712. });
  3713. }
  3714. fetchAndSave(key, url) {
  3715. return fetch(url).then(res => res.arrayBuffer()).then(buffer => this.putFile(key, url, buffer).then(() => buffer));
  3716. }
  3717. }
  3718. const manualCache = new ManualCache();
  3719. const signerURL = `data:text/javascript,importScripts('https://imspace.nos-eastchina1.126.net/shared-worker-signer_v0.0.3.js')`;
  3720. class SharedWorkerSigner {
  3721. static _clean() {
  3722. this._resolve = null;
  3723. this._reject = null;
  3724. }
  3725. static onMessage({ data }) {
  3726. console.log('onMessage', data);
  3727. if (data.type === 'query') {
  3728. if (data.data === true) {
  3729. this._resolve();
  3730. this._clean();
  3731. this._stopQuery = true;
  3732. }
  3733. else {
  3734. setTimeout(() => this.query(), 100);
  3735. }
  3736. }
  3737. else if (data.type === 'sign') {
  3738. this._resolve(data.data);
  3739. this._clean();
  3740. }
  3741. else if (data.type === 'error') {
  3742. this._reject(data.data);
  3743. this._clean();
  3744. }
  3745. else if (data.type === 'getArrayBuffer') {
  3746. manualCache.getArrayBuffer(data.key, data.url).then(buffer => {
  3747. this._worker.port.postMessage({
  3748. type: 'getArrayBuffer',
  3749. data: buffer
  3750. }, [buffer]);
  3751. }).catch((e) => {
  3752. this._worker.port.postMessage({
  3753. type: 'getArrayBuffer',
  3754. err: e
  3755. });
  3756. });
  3757. }
  3758. }
  3759. static get state() {
  3760. return this._state;
  3761. }
  3762. static sign(rid, tt, did) {
  3763. return __awaiter(this, void 0, void 0, function* () {
  3764. return new Promise((resolve, reject) => {
  3765. this._worker.port.postMessage({
  3766. type: 'sign',
  3767. args: [rid, tt, did]
  3768. });
  3769. this._resolve = resolve;
  3770. this._reject = reject;
  3771. });
  3772. });
  3773. }
  3774. static init() {
  3775. if (this._inited) {
  3776. return Promise.resolve();
  3777. }
  3778. return manualCache.initDB().then(() => new Promise((resolve, reject) => {
  3779. this._resolve = resolve;
  3780. this._reject = reject;
  3781. const worker = new SharedWorker(signerURL);
  3782. this._worker = worker;
  3783. worker.port.onmessage = e => this.onMessage(e);
  3784. window.setTimeout(() => this.query(), 500);
  3785. window.setTimeout(() => {
  3786. if (this.state !== SignerState.Ready) {
  3787. this._state = SignerState.Timeout;
  3788. }
  3789. if (this._stopQuery === false) {
  3790. this._stopQuery = true;
  3791. }
  3792. }, 15 * 1000);
  3793. }));
  3794. }
  3795. static query() {
  3796. if (!this._stopQuery) {
  3797. this._worker.port.postMessage({
  3798. type: 'query'
  3799. });
  3800. }
  3801. }
  3802. }
  3803. SharedWorkerSigner._inited = false;
  3804. SharedWorkerSigner._state = SignerState.None;
  3805. SharedWorkerSigner._stopQuery = false;
  3806. Signer = SharedWorkerSigner;
  3807. }
  3808.  
  3809. let dialog = null;
  3810. function getDialog(title, content, qrcodes) {
  3811. if (dialog) {
  3812. return dialog;
  3813. }
  3814. dialog = document.createElement('div');
  3815. dialog.className = 'donate-dialog';
  3816. const wrap = document.createElement('div');
  3817. wrap.className = 'donate-wrap';
  3818. const titleEl = document.createElement('h3');
  3819. titleEl.className = 'donate-title';
  3820. titleEl.innerText = title;
  3821. const contentEl = document.createElement('div');
  3822. contentEl.className = 'donate-content';
  3823. contentEl.innerText = content;
  3824. const qrcodeEl = document.createElement('div');
  3825. qrcodeEl.className = 'donate-qrcode-bar';
  3826. for (let i of qrcodes) {
  3827. const qrcodeBox = document.createElement('div');
  3828. qrcodeBox.className = 'donate-qrcode-box';
  3829. const qrcode = document.createElement('img');
  3830. qrcode.className = 'donate-qrcode-img';
  3831. qrcode.src = i.src;
  3832. const qrcodeDesc = document.createElement('div');
  3833. qrcodeDesc.className = 'donate-qrcode-desc';
  3834. qrcodeDesc.innerText = i.desc;
  3835. qrcodeBox.appendChild(qrcode);
  3836. qrcodeBox.appendChild(qrcodeDesc);
  3837. qrcodeEl.appendChild(qrcodeBox);
  3838. }
  3839. const closeEl = document.createElement('div');
  3840. closeEl.className = 'donate-close-btn';
  3841. const close = () => {
  3842. dialog.style.display = 'none';
  3843. };
  3844. closeEl.addEventListener('click', close);
  3845. wrap.appendChild(titleEl);
  3846. wrap.appendChild(contentEl);
  3847. wrap.appendChild(qrcodeEl);
  3848. wrap.appendChild(closeEl);
  3849. dialog.appendChild(wrap);
  3850. dialog.style.display = 'none';
  3851. return dialog;
  3852. }
  3853.  
  3854. const onload = () => {
  3855. if (window.__space_inject) {
  3856. const { script, css } = window.__space_inject;
  3857. addCss(createBlobURL(css, 'text/css'));
  3858. addScript(createBlobURL(script, 'text/javascript'));
  3859. window.__space_inject = null;
  3860. }
  3861. else {
  3862. addCss('dist/danmu.css');
  3863. addScript('dist/douyuInject.js');
  3864. }
  3865. const uid = getACF('uid');
  3866. flvjs.LoggingControl.forceGlobalTag = true;
  3867. flvjs.LoggingControl.enableAll = true;
  3868. class DouyuPlayerUI extends PlayerUI {
  3869. constructor(listener, state) {
  3870. super(listener, state);
  3871. this.douyuFullpage = false;
  3872. this.wrap.style.position = 'inherit';
  3873. this.wrap.style.zIndex = 'inherit';
  3874. }
  3875. _enterFullScreen() {
  3876. this.wrap.style.position = '';
  3877. this.wrap.style.zIndex = '';
  3878. super._enterFullScreen();
  3879. }
  3880. _exitFullScreen() {
  3881. this.wrap.style.position = 'inherit';
  3882. this.wrap.style.zIndex = 'inherit';
  3883. super._exitFullScreen();
  3884. }
  3885. _enterFullPage() {
  3886. this.wrap.setAttribute('fullpage', '');
  3887. this.el.style.border = '0';
  3888. if (!this.douyuFullpage) {
  3889. this.douyuFullpage = true;
  3890. postMessage('ACJ', {
  3891. id: 'room_bus_pagescr'
  3892. });
  3893. }
  3894. }
  3895. _exitFullPage() {
  3896. this.wrap.removeAttribute('fullpage');
  3897. this.el.style.border = '';
  3898. if (this.douyuFullpage) {
  3899. this.douyuFullpage = false;
  3900. postMessage('ACJ', {
  3901. id: 'room_bus_pagescr'
  3902. });
  3903. }
  3904. }
  3905. }
  3906. class DouyuDanmuPlayer extends DanmuPlayer {
  3907. constructor(roomId) {
  3908. const source = new DouyuSource(roomId, (rid, tt, did) => __awaiter(this, void 0, void 0, function* () {
  3909. let sign = yield Signer.sign(roomId, tt, did);
  3910. return sign;
  3911. }));
  3912. source.onChange = videoUrl => {
  3913. this.src = videoUrl;
  3914. };
  3915. super({
  3916. getSrc: () => source.getUrl(),
  3917. onSendDanmu(txt) {
  3918. window.postMessage({
  3919. type: "SENDANMU",
  3920. data: txt
  3921. }, "*");
  3922. }
  3923. });
  3924. this.source = source;
  3925. }
  3926. initUI() {
  3927. this.ui = new DouyuPlayerUI(this, this.state);
  3928. }
  3929. onDanmuPkg(pkg) {
  3930. const getColor = (c) => ['#ff0000', '#1e87f0', '#7ac84b', '#ff7f00', '#9b39f4', '#ff69b4'][c - 1];
  3931. if (pkg.txt.length > 0) {
  3932. let cls = [];
  3933. let color = getColor(pkg.col) || '#ffffff';
  3934. if (pkg.uid === uid)
  3935. cls.push('danmu-self');
  3936. this.fireDanmu(pkg.txt, color, cls);
  3937. }
  3938. }
  3939. }
  3940. const makeMenu = (player, source) => {
  3941. const cdnMenu = () => source.cdnsWithName.map((i) => {
  3942. let suffix = '';
  3943. if (i.cdn == source.cdn)
  3944. suffix = ' √';
  3945. return {
  3946. text: i.name + suffix,
  3947. cb() {
  3948. source.cdn = i.cdn;
  3949. }
  3950. };
  3951. });
  3952. const rateMenu = () => {
  3953. const rates = [{
  3954. text: '超清',
  3955. rate: '0'
  3956. }, {
  3957. text: '高清',
  3958. rate: '2'
  3959. }, {
  3960. text: '普清',
  3961. rate: '1'
  3962. }];
  3963. return rates.map(i => {
  3964. let suffix = '';
  3965. if (i.rate == source.rate)
  3966. suffix = ' √';
  3967. return {
  3968. text: i.text + suffix,
  3969. cb() {
  3970. source.rate = i.rate;
  3971. }
  3972. };
  3973. });
  3974. };
  3975. const transparentMenu = () => {
  3976. const opts = [{
  3977. text: '0%',
  3978. transparent: 0
  3979. }, {
  3980. text: '25%',
  3981. transparent: 25
  3982. }, {
  3983. text: '50%',
  3984. transparent: 50
  3985. }];
  3986. return [{
  3987. label: '弹幕透明度:'
  3988. }].concat(opts.map(i => {
  3989. let suffix = '';
  3990. if (i.transparent == player.ui.transparent)
  3991. suffix = ' √';
  3992. return {
  3993. text: i.text + suffix,
  3994. cb() {
  3995. player.ui.transparent = i.transparent;
  3996. },
  3997. label: null
  3998. };
  3999. }));
  4000. };
  4001. let mGetURL;
  4002. {
  4003. mGetURL = file => 'https://imspace.nos-eastchina1.126.net/img/' + file;
  4004. }
  4005. const dialog = getDialog('捐赠', '你的支持是我最大的动力.', [{
  4006. src: mGetURL('alipay.png'),
  4007. desc: '支付宝'
  4008. }, {
  4009. src: mGetURL('wechat.png'),
  4010. desc: '微信'
  4011. }]);
  4012. const donate = () => {
  4013. return [{
  4014. text: '捐赠',
  4015. cb() {
  4016. document.body.appendChild(dialog);
  4017. dialog.style.display = 'flex';
  4018. }
  4019. }];
  4020. };
  4021. const dash = {};
  4022. bindMenu(player.ui.video, () => [].concat(cdnMenu(), dash, rateMenu(), dash, transparentMenu(), dash, donate()));
  4023. };
  4024. const loadVideo = (roomId, replace) => {
  4025. const danmuPlayer = new DouyuDanmuPlayer(roomId);
  4026. danmuPlayer.mgr.parsePic = s => s.replace(/\[emot:dy(.*?)\]/g, (_, i) => `<img style="height:1em" src="https://shark.douyucdn.cn/app/douyu/res/page/room-normal/face/dy${i}.png?v=20161103">`);
  4027. replace(danmuPlayer.ui.el);
  4028. makeMenu(danmuPlayer, danmuPlayer.source);
  4029. window.danmu = danmuPlayer;
  4030. return danmuPlayer.source.getUrl().then(() => danmuPlayer);
  4031. };
  4032. let danmuPlayer = null;
  4033. let signerLoaded = new DelayNotify(false);
  4034. Signer.init().then(() => true).catch(() => false).then((data) => {
  4035. console.log('SIGNER_READY', data);
  4036. signerLoaded.notify(data);
  4037. });
  4038. onMessage('DANMU', data => {
  4039. danmuPlayer && danmuPlayer.onDanmuPkg(data);
  4040. });
  4041. onMessage('VIDEOID', (data) => __awaiter(window, void 0, void 0, function* () {
  4042. console.log('onVideoId', data);
  4043. const roomId = data.roomId;
  4044. setBgListener((req) => __awaiter(this, void 0, void 0, function* () {
  4045. switch (req.type) {
  4046. case 'toggle':
  4047. let setting = yield getSetting();
  4048. const id = setting.blacklist.indexOf(roomId);
  4049. if (id === -1) {
  4050. setting.blacklist.push(roomId);
  4051. }
  4052. else {
  4053. setting.blacklist.splice(id, 1);
  4054. }
  4055. yield setSetting(setting);
  4056. location.reload();
  4057. }
  4058. }));
  4059. console.log('wait signer');
  4060. if (!(yield signerLoaded.wait())) {
  4061. console.warn('加载签名程序失败, 无法获取视频地址');
  4062. return;
  4063. }
  4064. console.log('start replace');
  4065. try {
  4066. const setting = yield getSetting();
  4067. if (setting.blacklist.indexOf(roomId) !== -1) {
  4068. if (runtime.sendMessage) {
  4069. runtime.sendMessage({
  4070. type: 'disable'
  4071. });
  4072. }
  4073. return;
  4074. }
  4075. }
  4076. catch (e) {
  4077. console.warn(e);
  4078. }
  4079. let ctr = document.querySelector(`#${data.id}`);
  4080. yield postMessage('BEGINAPI', {
  4081. roomId
  4082. });
  4083. danmuPlayer = yield loadVideo(roomId, el => {
  4084. ctr.parentNode.replaceChild(el, ctr);
  4085. });
  4086. }));
  4087. };
  4088. onload();
  4089.  
  4090. })));