├── signed.crx ├── signed.xpi ├── src ├── icon.png ├── analytic_fixer.js ├── ff │ ├── store │ │ └── manifest.json │ └── manifest.json ├── manifest.json ├── dom_gen.js ├── hookFetch_background.js ├── resizeSensor.js ├── google-style-loading.js ├── hookFetch.js ├── _locales │ ├── zh_CN │ │ └── messages.json │ ├── zh_TW │ │ └── messages.json │ └── en │ │ └── messages.json ├── biliplus_shield.js ├── hlsjsMediaInfo.min.js ├── acfun_html5.js └── CommentCoreLibrary.js ├── privacy.txt ├── firefox_ext_update.json ├── player_core.md ├── README.md └── update_note.md /signed.crx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esterTion/AcFun-HTML5-Player/HEAD/signed.crx -------------------------------------------------------------------------------- /signed.xpi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esterTion/AcFun-HTML5-Player/HEAD/signed.xpi -------------------------------------------------------------------------------- /src/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esterTion/AcFun-HTML5-Player/HEAD/src/icon.png -------------------------------------------------------------------------------- /privacy.txt: -------------------------------------------------------------------------------- 1 | This extension DOES NOT collect any personal data. 2 | Everything stays in your browser. 3 | -------------------------------------------------------------------------------- /firefox_ext_update.json: -------------------------------------------------------------------------------- 1 | { 2 | "addons": { 3 | "acfun-player@estertion": { 4 | "updates": [ 5 | { 6 | "version": "1.9.9.2", 7 | "update_link": "https://estertion.github.io/AcFun-HTML5-Player/signed.xpi?ver=1.9.9.2", 8 | "applications": { 9 | "gecko": { 10 | "strict_min_version": "57.0" 11 | } 12 | } 13 | } 14 | ] 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /player_core.md: -------------------------------------------------------------------------------- 1 | ## hls.js 和 flv.js ,我该选哪个? 2 | 3 | 一般情况下,使用默认的`hls.js`核心会有更流畅的播放体验 4 | 5 | ### hls.js 6 | 使用 hls.js 时可以在 右键菜单-播放统计 中确认正在播放和即将切换的清晰度 7 | - 优点: 8 | - 可以自动调节清晰度,在网络不稳定(尤其是缺B乐cdn不稳定的时候)可以保证基本的正常播放 9 | - 整体项目代码较为成熟,不易出现bug 10 | - 缺点: 11 | - 自动切换生效可能会很慢,导致观感下降 12 | - 有时自动切换算法比较迷 13 | - 因为目前固定720p开始播放,在低网速时可能初始缓冲时间很长 14 | 15 | ### flv.js 16 | - 优点: 17 | - 可以记忆最后播放清晰度 18 | - 流式播放起步较快 19 | - 缺点: 20 | - 网络波动时频繁缓冲,需要手动切换 21 | - 代码成熟度不足,容易出现异常错误 22 | - 跳跃至未缓冲部分时会清空已缓冲内容,需要重新获取 -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AcFun HTML5 Player 2 | 作者:esterTion 3 | 4 |  5 | 6 | 一个装B播放器,送给缺B乐的各位(被打 7 | 8 | ## 安装 9 | 当前版本:[](update_note.md) 10 | - [Firefox](https://estertion.github.io/AcFun-HTML5-Player/signed.xpi) (firefox 57.0+) 11 | - [Chrome ](https://chrome.google.com/webstore/detail/acfun-html5-player/onjihgccojkcmlmlbjmgkcnehdbpbhcf) ([crx分流](https://estertion.github.io/AcFun-HTML5-Player/signed.crx)) (chrome 50.0+) 12 | - [Edge](https://microsoftedge.microsoft.com/addons/detail/dfncoalaceonhlibdldimbiaocmgekpb) (new Microsoft Edge) 13 | 14 | 视频源目前支持`主站 优酷版权视频 新浪`,其他源请提供视频地址,我可能会加上支持(咕咕咕) 15 | 16 |  17 | -------------------------------------------------------------------------------- /src/analytic_fixer.js: -------------------------------------------------------------------------------- 1 | if (/blob:/.test(location.href)) throw 'not in blob'; 2 | let script = document.createElement('script'); 3 | script.textContent = '(' + (function () { 4 | if ([ 5 | /acfun\.cn\/v\//, 6 | /acfun\.cn\/bangumi\//, 7 | /hapame\.com\/video\// 8 | ].find(i => i.test(location.href))) { 9 | console.log('[AHP] 假装有flash'); 10 | navigator.mimeTypes["application/x-shockwave-flash"] = navigator.mimeTypes["application/x-shockwave-flash"] || []; 11 | } 12 | window.addEventListener('beforeunload', function () { 13 | XMLHttpRequest = function () { 14 | return { 15 | open: function (method, url, async) { 16 | this.url = url; 17 | }, 18 | send: function (data) { 19 | navigator.sendBeacon(this.url, data); 20 | console.log('beacon queued', this.url, data); 21 | }, 22 | } 23 | }; 24 | }); 25 | MediaSource.isTypeSupported = () => false; 26 | var hack = document.firstElementChild.appendChild(document.createElement('style')); 27 | hack.className = 'player'; 28 | }).toString() + ')();'; 29 | document.firstElementChild.appendChild(script).remove(); 30 | -------------------------------------------------------------------------------- /src/ff/store/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "manifest_version": 2, 3 | "name": "__MSG_extName__", 4 | "version": "1.0.0.0pre", 5 | "description": "__MSG_extDesc__", 6 | "content_scripts": [ 7 | { 8 | "matches": [ 9 | "http://*.acfun.cn/v/*", 10 | "http://*.acfun.cn/bangumi/*", 11 | "http://*.hapame.com/video/*" 12 | ], 13 | "all_frames": true, 14 | "js": [ 15 | "dom_gen.js", 16 | "resizeSensor.js", 17 | "rc4.js", 18 | "md5.js", 19 | "x2js.min.js", 20 | "flv.min.js", 21 | "jquery-3.3.1.min.js", 22 | "google-style-loading.min.js", 23 | "CommentCoreLibrary.min.js", 24 | "biliplus_shield.min.js", 25 | "ABPlayer.min.js", 26 | "acfun_html5.js" 27 | ], 28 | "run_at": "document_end" 29 | } 30 | ], 31 | "permissions": [ 32 | "*://*/*", 33 | "storage", 34 | "clipboardWrite", 35 | "webRequest", 36 | "webRequestBlocking" 37 | ], 38 | "background": { 39 | "scripts": [ 40 | "ff_fix.js" 41 | ] 42 | }, 43 | "applications": { 44 | "gecko": { 45 | "id": "acfun-player-store@estertion", 46 | "strict_min_version": "57.0" 47 | } 48 | }, 49 | "icons": { 50 | "48": "icon.png" 51 | }, 52 | "default_locale": "en", 53 | "web_accessible_resources": [ 54 | "ABPlayer.css" 55 | ] 56 | } -------------------------------------------------------------------------------- /src/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "manifest_version": 2, 3 | "name": "__MSG_extName__", 4 | "version": "1.0.0.0", 5 | "description": "__MSG_extDesc__", 6 | "content_scripts": [ 7 | { 8 | "matches": [ 9 | "*://*.acfun.cn/*", 10 | "*://*.hapame.com/*" 11 | ], 12 | "all_frames": true, 13 | "js": [ 14 | "analytic_fixer.js" 15 | ], 16 | "run_at": "document_start" 17 | }, 18 | { 19 | "matches": [ 20 | "*://*.acfun.cn/v/*", 21 | "*://*.acfun.cn/bangumi/*", 22 | "*://*.hapame.com/video/*" 23 | ], 24 | "all_frames": true, 25 | "js": [ 26 | "dom_gen.js", 27 | "hookFetch.js", 28 | "resizeSensor.js", 29 | "hls.light.min.js", 30 | "hlsjsMediaInfo.min.js", 31 | "jquery-3.3.1.min.js", 32 | "google-style-loading.min.js", 33 | "CommentCoreLibrary.min.js", 34 | "biliplus_shield.min.js", 35 | "ABPlayer.min.js", 36 | "acfun_html5.js" 37 | ], 38 | "run_at": "document_end" 39 | } 40 | ], 41 | "permissions": [ 42 | "*://*.acfun.cn/*", 43 | "https://tx.biliplus.com:7823/*", 44 | "storage", 45 | "clipboardWrite" 46 | ], 47 | "background": { 48 | "scripts": [ 49 | "hookFetch_background.js" 50 | ] 51 | }, 52 | "icons": { 53 | "48": "icon.png" 54 | }, 55 | "default_locale": "en", 56 | "web_accessible_resources": [ 57 | "ABPlayer.css" 58 | ], 59 | "minimum_chrome_version": "49.0" 60 | } 61 | -------------------------------------------------------------------------------- /src/ff/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "manifest_version": 2, 3 | "name": "__MSG_extName__", 4 | "version": "1.0.0.0", 5 | "description": "__MSG_extDesc__", 6 | "content_scripts": [ 7 | { 8 | "matches": [ 9 | "*://*.acfun.cn/*", 10 | "*://*.hapame.com/*" 11 | ], 12 | "all_frames": true, 13 | "js": [ 14 | "analytic_fixer.js" 15 | ], 16 | "run_at": "document_start" 17 | }, 18 | { 19 | "matches": [ 20 | "*://*.acfun.cn/v/*", 21 | "*://*.acfun.cn/bangumi/*", 22 | "*://*.hapame.com/video/*" 23 | ], 24 | "all_frames": true, 25 | "js": [ 26 | "dom_gen.js", 27 | "resizeSensor.js", 28 | "hls.light.min.js", 29 | "hlsjsMediaInfo.min.js", 30 | "jquery-3.3.1.min.js", 31 | "google-style-loading.min.js", 32 | "CommentCoreLibrary.min.js", 33 | "biliplus_shield.min.js", 34 | "ABPlayer.min.js", 35 | "acfun_html5.js" 36 | ], 37 | "run_at": "document_end" 38 | } 39 | ], 40 | "permissions": [ 41 | "*://*/*", 42 | "storage", 43 | "clipboardWrite", 44 | "webRequest", 45 | "webRequestBlocking" 46 | ], 47 | "applications": { 48 | "gecko": { 49 | "id": "acfun-player@estertion", 50 | "update_url": "https://estertion.github.io/AcFun-HTML5-Player/firefox_ext_update.json", 51 | "strict_min_version": "57.0" 52 | } 53 | }, 54 | "icons": { 55 | "48": "icon.png" 56 | }, 57 | "default_locale": "en", 58 | "web_accessible_resources": [ 59 | "ABPlayer.css" 60 | ] 61 | } 62 | -------------------------------------------------------------------------------- /src/dom_gen.js: -------------------------------------------------------------------------------- 1 | let _ = function (type, props, children) { 2 | let elem = null; 3 | if (type === "text") { 4 | return document.createTextNode(props); 5 | } else { 6 | elem = document.createElement(type); 7 | } 8 | for (let n in props) { 9 | if (n === "style") { 10 | for (let x in props.style) { 11 | elem.style[x] = props.style[x]; 12 | } 13 | } else if (n === "className") { 14 | elem.className = props[n]; 15 | } else if (n === "event") { 16 | for (let x in props.event) { 17 | elem.addEventListener(x, props.event[x]); 18 | } 19 | } else { 20 | elem.setAttribute(n, props[n]); 21 | } 22 | } 23 | if (children) { 24 | if (typeof children == 'string') { 25 | elem.innerHTML = children; 26 | } else if (Array.isArray(children)) { 27 | for (let i = 0; i < children.length; i++) { 28 | if (children[i] != null) 29 | elem.appendChild(children[i]); 30 | } 31 | } 32 | } 33 | return elem; 34 | }; 35 | 36 | let isChrome = /chrome/i.test(navigator.userAgent); 37 | let _t = function (s) { return chrome.i18n.getMessage(s) }; 38 | let firefoxVer = 0, chromeVer = 0; 39 | if (!isChrome) { 40 | firefoxVer = (navigator.userAgent.match(/Firefox\/(\d+)/) || [, 0])[1]; 41 | } else { 42 | chromeVer = (navigator.userAgent.match(/Chrome\/(\d+)/) || [, 0])[1]; 43 | } 44 | function readStorage(name, cb) { 45 | if (!isChrome && firefoxVer < 53) 46 | //ff52-无sync 47 | chrome.storage.local.get(name, cb) 48 | else 49 | chrome.storage.sync.get(name, cb) 50 | } 51 | function saveStorage(save) { 52 | if (!isChrome && firefoxVer < 53) 53 | chrome.storage.local.set(save); 54 | else 55 | chrome.storage.sync.set(save); 56 | } 57 | function getCookie(name) { 58 | let cookies = {}; 59 | document.cookie.split('; ').forEach(function (i) { 60 | let [key, ...val] = i.split('='); 61 | cookies[key] = val.join('='); 62 | }); 63 | return cookies[name] || ''; 64 | } -------------------------------------------------------------------------------- /src/hookFetch_background.js: -------------------------------------------------------------------------------- 1 | /* 2 | fetch hooking code from https://github.com/spacemeowx2/DouyuHTML5Player/blob/b5a54240f1b31d53a8530af83444b10027fe6dca/src/background.js#L8 3 | */ 4 | function convertHeader(headers) { 5 | let out = {} 6 | for (let key of headers.keys()) { 7 | out[key] = headers.get(key) 8 | } 9 | return out 10 | } 11 | function Object2Headers(headers) { 12 | let out = new Headers() 13 | for (let key of Object.keys(headers)) { 14 | out.set(key, headers[key]) 15 | } 16 | return out 17 | } 18 | chrome.runtime.onConnect.addListener(port => { 19 | if (port.name === 'fetch') { 20 | let response 21 | let reader 22 | port.onDisconnect.addListener(() => { 23 | reader && reader.cancel() 24 | }) 25 | port.onMessage.addListener(msg => { 26 | let chain = Promise.resolve() 27 | if (msg.method === 'fetch') { 28 | if (msg.args[1].headers != undefined) 29 | msg.args[1].headers = Object2Headers(msg.args[1].headers); 30 | chain = chain.then(() => fetch.apply(null, msg.args)).then(r => { 31 | response = r 32 | return { 33 | bodyUsed: r.bodyUsed, 34 | ok: r.ok, 35 | status: r.status, 36 | statusText: r.statusText, 37 | type: r.type, 38 | url: r.url, 39 | headers: convertHeader(r.headers) 40 | } 41 | }) 42 | } else if (msg.method === 'json') { 43 | chain = chain.then(() => response.json()) 44 | } else if (msg.method === 'text') { 45 | chain = chain.then(() => response.text()) 46 | } else if (msg.method === 'body.getReader') { 47 | chain = chain.then(() => { 48 | reader = response.body.getReader() 49 | }) 50 | } else if (msg.method === 'reader.read') { 51 | chain = chain.then(() => reader.read()).then(r => { 52 | if (r.value != undefined) 53 | r.value = Array.from(r.value) 54 | return r 55 | }) 56 | } else if (msg.method === 'reader.cancel') { 57 | chain = chain.then(() => reader.cancel()) 58 | } else { 59 | port.disconnect() 60 | return 61 | } 62 | chain.then((...args) => { 63 | const outMsg = { 64 | method: msg.method, 65 | args: args 66 | } 67 | port.postMessage(outMsg) 68 | }) 69 | }) 70 | } 71 | }) 72 | -------------------------------------------------------------------------------- /src/resizeSensor.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * 3 | * source: https://github.com/tiansh/ya-simple-scrollbar/blob/master/ya-simple-scrollbar.js 4 | * 5 | * yaSimpleScrollbar v1.0 6 | * 7 | * Copyright (C) Sheng Tian 8 | * 9 | * The MIT License 10 | * https://github.com/tiansh/ya-simple-scrollbar/blob/master/LICENSE 11 | * 12 | * Based on buzinas/simple-scrollbar, and, marcj/css-element-queries 13 | * https://github.com/tiansh/ya-simple-scrollbar/blob/master/CREDITS.md 14 | */ 15 | document.head.appendChild(_('style', {}, [_('text', 16 | [ 17 | '.yass-resize-sensor, .yass-resize-sensor-expand, .yass-resize-sensor-shrink { position: absolute; top: 0; bottom: 0; left: 0; right: 0; overflow: hidden; z-index: -1; visibility: hidden; }', 18 | '.yass-resize-sensor-expand .yass-resize-sensor-child { width: 100000px; height: 100000px; }', 19 | '.yass-resize-sensor-shrink .yass-resize-sensor-child { width: 200%; height: 200%; }', 20 | '.yass-resize-sensor-child { position: absolute; top: 0; left: 0; transition: 0s; }', 21 | ].join('') 22 | )])) 23 | var resizeSensor = function (element, resized) { 24 | var sensor = _('div', { className: 'yass-resize-sensor' }); 25 | var expand = sensor.appendChild(_('div', { className: 'yass-resize-sensor-expand' })); 26 | var shrink = sensor.appendChild(_('div', { className: 'yass-resize-sensor-shrink' })); 27 | var expandChild = expand.appendChild(_('div', { className: 'yass-resize-sensor-child' })); 28 | var shrinkChild = shrink.appendChild(_('div', { className: 'yass-resize-sensor-child' })); 29 | element.appendChild(sensor); 30 | 31 | var lastWidth = element.offsetWidth; 32 | var lastHeight = element.offsetHeight; 33 | var newWidth, newHeight, dirty; 34 | 35 | var reset = function () { 36 | expand.scrollLeft = 100000; 37 | expand.scrollTop = 100000; 38 | shrink.scrollLeft = 100000; 39 | shrink.scrollTop = 100000; 40 | }; 41 | 42 | reset(); 43 | 44 | var onResized = function () { 45 | if (lastWidth === newWidth && lastHeight === newHeight) return; 46 | lastWidth = newWidth; 47 | lastHeight = newHeight; 48 | resized(); 49 | reset(); 50 | }; 51 | var onScroll = function (event) { 52 | newWidth = element.offsetWidth; 53 | newHeight = element.offsetHeight; 54 | if (dirty) return; dirty = true; 55 | requestAnimationFrame(function () { 56 | dirty = false; 57 | onResized(); 58 | }); 59 | }; 60 | 61 | expand.addEventListener('scroll', onScroll); 62 | shrink.addEventListener('scroll', onScroll); 63 | }; 64 | null; -------------------------------------------------------------------------------- /update_note.md: -------------------------------------------------------------------------------- 1 | # 更新日志 2 | 3 | ## 1.9.9.2 4 | Dec 8th, 2021 5 | - *修复跨区播放 6 | 7 | ## 1.9.9.1 8 | Dec 1st, 2021 9 | - *去除已经不再需要的webRequest权限 10 | 11 | ## 1.9.9 12 | Jan 4th, 2021 13 | - *修复跨区播放 14 | 15 | ## 1.9.8 16 | Aug 20th, 2020 17 | - *修复播放 18 | 19 | ## 1.9.7 20 | Apr 13th, 2020 21 | - +适配进度条预览 22 | 23 | ## 1.9.6 24 | Mar 20th, 2020 25 | - *修复剧集侧栏点击 26 | 27 | ## 1.9.5 28 | Jan 3rd, 2020 29 | - *修复页面播放器初始化 30 | 31 | ## 1.9.4 32 | Nov 27th, 2019 33 | - *修复弹幕加载 34 | 35 | ## 1.9.3 36 | Nov 11th, 2019 37 | - +适配新版播放页 38 | 39 | ## 1.9.2 40 | Oct 15th, 2019 41 | - *实时弹幕/弹幕发送修复 42 | - *恢复番剧跨区支持 43 | 44 | ## 1.9.1 45 | Oct 1st, 2019 46 | - *播放器速度控制菜单增加选项 47 | - *移除无flash蒙板 48 | 49 | ## 1.9.0 50 | Aug 20th, 2019 51 | - *acfun页面改版适配 52 | - -移除flv.js 53 | - -移除第三方源支持 54 | 55 | ## 1.8.4 56 | Aug 14th, 2019 57 | - *acfun页面改版适配 58 | 59 | ## 1.8.3 60 | Jul 4th, 2019 61 | - *修复载入弹幕时未过滤弹幕 62 | 63 | ## 1.8.2 64 | Jul 4th, 2019 65 | - *更换缩略图域名 66 | 67 | ## 1.8.1 68 | Jun 25th, 2019 69 | - *修复播放器创建和官方播放器禁用 70 | 71 | ## 1.8.0 72 | Jun 17th, 2019 73 | - *修复https下的若干问题 74 | 75 | ## 1.7.9 76 | May 11th, 2019 77 | - +添加https支持 78 | 79 | ## 1.7.8 80 | Apr 2nd, 2019 81 | - *部分播放器改动与修复 82 | 83 | ## 1.7.7 84 | Apr 2nd, 2019 85 | - *修复实时弹幕 86 | 87 | ## 1.7.6 88 | Mar 20th, 2019 89 | - *截图功能修复 90 | 91 | ## 1.7.5 92 | Feb 10th, 2019 93 | - *重复弹幕合并显示 94 | 95 | ## 1.7.4 96 | Jan 29th, 2019 97 | - +添加弹幕加载上限设置 98 | - *修复播放器弹幕定位 99 | 100 | ## 1.7.3 101 | Dec 14th, 2018 102 | - *修复chrome屏蔽 103 | 104 | ## 1.7.2 105 | Dec 2nd, 2018 106 | - *修复小窗播放 107 | 108 | ## 1.7.1 109 | Dec 1st, 2018 110 | - *优化弹幕载入性能 111 | 112 | ## 1.7.0 113 | Nov 30th, 2018 114 | - +AcFun主题 [@jiangming1399](https://github.com/jiangming1399) 115 | 116 | ## 1.6.4.3 117 | Nov 21st, 2018 118 | - *修复弹幕屏蔽 119 | 120 | ## 1.6.4 121 | Nov 20th, 2018 122 | - +添加截图功能 123 | - *播放器标题 显示本集标题 124 | - *键盘跳转逻辑改进 125 | 126 | ## 1.6.3 127 | Nov 16th, 2018 128 | - *修复弹幕发送 129 | - *哪个猴子写的统计,出来我打死他,关闭网页发送同步xhr诗人?? ---beforeunload后强制更换[sendBeacon](https://developer.mozilla.org/en-US/docs/Web/API/Navigator/sendBeacon) 130 | 131 | ## 1.6.2 132 | Nov 13th, 2018 133 | - *改进hls配置 134 | 135 | ## 1.6.1 136 | Nov 11th, 2018 137 | - *改进自动模式起步记忆 138 | 139 | ## 1.6.0 140 | Nov 10th, 2018 141 | - +添加hls.js核心并设为默认 142 | - +默认为自动清晰度 143 | 144 | ## 1.5.2 145 | Oct 30th, 2018 146 | - +缩略图新任务自动重新加载 147 | 148 | ## 1.5.1 149 | Oct 29th, 2018 150 | - *换用[DogeCloud](https://www.dogecloud.com/)提供的cdn 151 | 152 | ## 1.5.0 153 | Oct 29th, 2018 154 | - +部分番剧追加进度条预览 155 | - *更新flv.js 156 | 157 | ## 1.4.4 158 | Oct 18th, 2018 159 | - *音量到达100%暂停 160 | - *chrome添加视频请求ua修改 #35 161 | 162 | ## 1.4.3 163 | - 草,发错版了 164 | 165 | ## 1.3.2 166 | Oct 9th, 2018 167 | - *flv.js修复 168 | - *改进 169 | 170 | ## 1.3.1 171 | Oct 6th, 2018 172 | - *flv.js修复更新 173 | 174 | ## 1.3.0 175 | Oct 6th, 2018 176 | - +ac番剧翻墙成功 177 | - *改进音频同步? 178 | 179 | ## 1.2.5 180 | Oct 2nd, 2018 181 | - *修复番剧剧集切换 182 | 183 | ## 1.2.4 184 | Sep 24th, 2018 185 | - *更新flv.js,并关闭音频同步修复 186 | 187 | ## 1.2.3 188 | Aug 28th, 2018 189 | - *播放器默认宽屏,取消原方形播放器 190 | - +播放器弹幕列表改为侧栏滑入 191 | 192 | ## 1.2.2 193 | Jun 25th, 2018 194 | - +(chrome) 音量支持放大至400% 195 | - *缩短弹幕发送冷却 196 | - *其他修复 197 | 198 | ## 1.2.1 199 | May 10, 2018 200 | - *修复弹幕类型选择,颜色选择 201 | - *更新jquery 3.3.1 202 | 203 | ## 1.2.0 204 | Apr 19, 2018 205 | - +使用黑科技绕过版权番10分钟限制 206 | 207 | ## 1.1.1 208 | Mar 21, 2018 209 | - *修复播放器错位 210 | - *canvas绘制变更 211 | - *改进实时码率 212 | 213 | ## 1.1.0 214 | Feb 15, 2018 215 | - *flvjs更新 216 | - *弹幕限制获取12页 217 | - *实时码率显示改进 218 | 219 | ## 1.0.17 220 | Jan 27, 2018 221 | - *增大弹幕获取量 222 | 223 | ## 1.0.16 224 | Dec 31, 2017 225 | - *修复番剧选集 226 | 227 | ## 1.0.15 228 | Dec 29, 2017 229 | - *识别新浪备用地址 230 | - *优酷播放错误处理 231 | 232 | ## 1.0.14 233 | Dec 28, 2017 234 | - *统计界面改动 235 | - *重新载入网速修复 236 | 237 | ## 1.0.13 238 | Dec 22, 2017 239 | - +引入CCL acfun解析器,部分支持高级弹幕 240 | - *修复弹幕列表排序 241 | 242 | ## 1.0.12 243 | Dec 22, 2017 244 | - *修复firefox下的加载失败问题(firefox57以上可以正常修复,57以下无法处理) 245 | - *改进键盘识别例外 246 | 247 | ## 1.0.11 248 | Dec 15, 2017 249 | - +添加域名hapame.com 250 | 251 | ## 1.0.10 252 | Dec 13, 2017 253 | - +添加弹幕样式选择 254 | 255 | ## 1.0.9 256 | Dec 8, 2017 257 | - +添加新浪支持 258 | - *修复优酷获取 259 | - *改进逻辑 260 | 261 | ## 1.0.8 262 | Dec 6, 2017 263 | - +添加重新载入功能 264 | 265 | ## 1.0.7 266 | Dec 6, 2017 267 | - *改进firefox替换速度 268 | - -sina letv源设置为不计划支持 269 | - *播放器细节改进 270 | 271 | ## 1.0.6 272 | Nov 28, 2017 273 | - *修复CSS绘制设置、弹幕屏蔽 274 | - +添加未登录提示 275 | 276 | ## 1.0.5 277 | Nov 24, 2017 278 | - *更新flvjs,解决分段长度导致的不同步 279 | 280 | ## 1.0.4 281 | Nov 24, 2017 282 | - *修复socket连接 283 | 284 | ## 1.0.3 285 | Nov 23, 2017 286 | 287 | - 全屏禁用滚动 288 | 289 | ## 1.0.2 290 | Nov 23, 2017 291 | 292 | - 功能性修复 293 | 294 | ## 1.0.1 295 | Nov 23, 2017 296 | 297 | - 初始版本 298 | -------------------------------------------------------------------------------- /src/google-style-loading.js: -------------------------------------------------------------------------------- 1 | (function(){ 2 | var toStandardArc=function(r){ 3 | return r-.5*Math.PI; 4 | }, 5 | toCartCoord=function(centerX,centerY,radius,angle){ 6 | /*var x=centerX,y=centerY; 7 | x+=Math.cos(angle)*radius 8 | y+=Math.sin(angle)*radius 9 | return [x,y];*/ 10 | return [centerX+Math.cos(angle)*radius,centerY+Math.sin(angle)*radius] 11 | }, 12 | transitionColor=function(startColor,endColor,pos){ 13 | var startColor=parseInt(startColor,16),endColor=parseInt(endColor,16), 14 | startR=startColor>>>16,startG=startColor>>8&0xff,startB=startColor&0xff, 15 | endR=endColor>>>16,endG=endColor>>8&0xff,endB=endColor&0xff, 16 | doneR=startR+(endR-startR)*pos|0,doneG=startG+(endG-startG)*pos|0,doneB=startB+(endB-startB)*pos|0, 17 | done=doneR*0x010000+doneG*0x0100+doneB 18 | done=done.toString(16); 19 | while(done.length<6){ 20 | done='0'+done; 21 | } 22 | return done; 23 | }, 24 | r,thick,spinningSpeed,currentColor,nextColor,startRad,nextStartRad,loopCount,startTime, 25 | sin=Math.sin,PI=Math.PI; 26 | 'use strict'; 27 | window.dots={ 28 | running:!1, 29 | ticking:!1, 30 | config:{color:['FFFFFF','FFFFFF'],r:20,thick:2,spinningSpeed:700}, 31 | currentColor:'', 32 | canvas:null, 33 | context:null, 34 | init:function(config){ 35 | for(var i in config){ 36 | this.config[i]=config[i]; 37 | } 38 | }, 39 | mainLoop:function(){ 40 | this.context.clearRect(0,0,this.canvas.width,this.canvas.height); 41 | if(!this.running){ 42 | return; 43 | } 44 | //this.context.fillStyle='#'+this.config.color; 45 | var now=Date.now(),offset=(now-startTime)%1400,i=0,devicePixelRatio=window.devicePixelRatio, 46 | centerX=this.canvas.width/2,centerY=this.canvas.height/2, 47 | calcLoopCount=((now-startTime)/1400)|0,currentStartRad,currentEndRad,context=this.context; 48 | if(calcLoopCount!=loopCount){ 49 | startRad=nextStartRad; 50 | nextStartRad=(startRad+1400/spinningSpeed-.1+5/3)%2; 51 | loopCount=calcLoopCount; 52 | currentColor=this.config.color[this.config.color.indexOf(currentColor)+1] 53 | nextColor=this.config.color[this.config.color.indexOf(currentColor)+1] 54 | this.currentColor=currentColor 55 | } 56 | context.fillStyle='#'+currentColor; 57 | /* 58 | 0-600 0.2rad->5/3rad 59 | 600-700 5/3rad 60 | 700-1300 5/3rad->0.2rad 61 | 1300-1400 0 0.2rad 62 | */ 63 | currentStartRad=startRad+(offset)/spinningSpeed 64 | //currentStartRad=startRad 65 | /* 66 | if(offset<600){ 67 | currentEndRad=currentStartRad+.05+( (5/3-.05)* (sqrt( (offset-300)/300 )*300+300) /600 ) 68 | }else if(offset<700){ 69 | currentEndRad=currentStartRad+5/3 70 | }else if(offset<1300){ 71 | currentEndRad=currentStartRad+5/3 72 | currentStartRad=currentEndRad-.05-( (5/3-.05)*(1-(sqrt( (offset-1000)/300 )*300+300)/600) ) 73 | }else{ 74 | currentEndRad=currentStartRad+5/3 75 | currentStartRad=currentEndRad-.05 76 | }*/ 77 | if(offset<700){ 78 | currentEndRad=currentStartRad+.1+( (5/3-.1)* (sin( (offset-350)/700*PI )*1+1) /2 ) 79 | }else{ 80 | currentEndRad=currentStartRad+5/3 81 | currentStartRad=currentEndRad-.1-( (5/3-.1)*(1-(sin( (offset-1050)/700*PI )*1+1) /2) ) 82 | } 83 | if(offset>1200){ 84 | context.fillStyle='#'+transitionColor(currentColor,nextColor,(offset-1200)/200) 85 | } 86 | currentStartRad=toStandardArc(currentStartRad*PI); 87 | currentEndRad=toStandardArc(currentEndRad*PI); 88 | 89 | var startPoint=toCartCoord(centerX,centerY,r*devicePixelRatio,currentStartRad), 90 | outerPoint=toCartCoord(centerX,centerY,(r+thick)*devicePixelRatio,currentEndRad) 91 | context.beginPath(); 92 | context.moveTo(startPoint[0],startPoint[1]) 93 | context.arc(centerX,centerY,r*devicePixelRatio,currentStartRad,currentEndRad); 94 | context.lineTo(outerPoint[0],outerPoint[1]); 95 | context.arc(centerX,centerY,(r+thick)*devicePixelRatio,currentEndRad,currentStartRad,true); 96 | context.lineTo(startPoint[0],startPoint[1]) 97 | context.fill(); 98 | 99 | if(!this.ticking){ 100 | requestAnimationFrame(this.mainLoopCaller); 101 | this.ticking=!0; 102 | } 103 | }, 104 | mainLoopCaller:function(){ 105 | dots.ticking=!1; 106 | dots.mainLoop(); 107 | }, 108 | runTimer:function(){ 109 | var container=dots.config.container; 110 | if(container==null || this.running) 111 | return; 112 | var canvas=container.querySelector('canvas'); 113 | if(canvas==null){ 114 | canvas=document.createElement('canvas'); 115 | canvas.style.width=this.config.width||''; 116 | canvas.style.height=this.config.height||''; 117 | container.appendChild(canvas); 118 | this.canvas=canvas; 119 | canvas.width=canvas.offsetWidth*devicePixelRatio; 120 | canvas.height=canvas.offsetHeight*devicePixelRatio; 121 | this.context=canvas.getContext('2d'); 122 | } 123 | this.running=!0; 124 | startTime=Date.now(); 125 | loopCount=-1; 126 | nextStartRad=0; 127 | currentColor=this.config.color[this.config.color.length-2]; 128 | thick=this.config.thick 129 | r=this.config.r 130 | spinningSpeed=this.config.spinningSpeed 131 | 132 | if(!this.ticking){ 133 | requestAnimationFrame(this.mainLoopCaller); 134 | this.ticking=!0; 135 | } 136 | }, 137 | stopTimer:function(){ 138 | this.running=!1; 139 | } 140 | } 141 | window.addEventListener('resize',function(){ 142 | if(dots.canvas!=null){ 143 | var devicePixelRatio=window.devicePixelRatio 144 | dots.canvas.width=dots.canvas.offsetWidth*devicePixelRatio; 145 | dots.canvas.height=dots.canvas.offsetHeight*devicePixelRatio; 146 | } 147 | }); 148 | })() -------------------------------------------------------------------------------- /src/hookFetch.js: -------------------------------------------------------------------------------- 1 | /* 2 | Code Source: https://github.com/spacemeowx2/DouyuHTML5Player/blob/f6c490aefa5d683ce46c817ab20c095e5c85c389/src/hookfetch.js 3 | */ 4 | if( isChrome && (location.protocol=='https:' || chromeVer >= 73) ){ 5 | console.log('chrome+https环境 或 chrome73+,替换fetch'); 6 | 7 | let originalFetch = window.fetch; 8 | 9 | function hookFetchCode () { 10 | // let self = this 11 | const convertHeader = function convertHeader (headers) { 12 | let out = new Headers() 13 | for (let key of Object.keys(headers)) { 14 | out.set(key, headers[key]) 15 | } 16 | return out 17 | } 18 | const hideHookStack = stack => { 19 | return stack.replace(/^\s*at\s.*?hookfetch\.js:\d.*$\n/mg, '') 20 | } 21 | const base64ToUint8 = (b64) => { 22 | const s = atob(b64) 23 | const length = s.length 24 | let ret = new Uint8Array(length) 25 | for (let i = 0; i < length; i++) { 26 | ret[i] = s.charCodeAt(i) 27 | } 28 | return ret 29 | } 30 | class WrapPort { 31 | constructor (port) { 32 | this.curMethod = '' 33 | this.curResolve = null 34 | this.curReject = null 35 | this.stack = '' 36 | this.port = port 37 | this.lastDone = true 38 | 39 | port.onMessage.addListener(msg => this.onMessage(msg)) 40 | } 41 | post (method, args) { 42 | if (!this.lastDone) { 43 | throw new Error('Last post is not done') 44 | } 45 | this.stack = new Error().stack 46 | return new Promise((resolve, reject) => { 47 | this.lastDone = false 48 | this.curMethod = method 49 | this.curResolve = resolve 50 | this.curReject = reject 51 | this.port.postMessage({ 52 | method: method, 53 | args: args 54 | }) 55 | }) 56 | } 57 | onMessage (msg) { 58 | if (msg.method === this.curMethod) { 59 | if (msg.err) { 60 | let err = new Error(msg.err.message) 61 | err.oriName = msg.err.name 62 | err.stack = hideHookStack(this.stack) 63 | // console.log('fetch err', err) 64 | this.curReject.call(null, err) 65 | } else { 66 | if (this.curMethod == 'arrayBuffer') { 67 | msg.args[0] = base64ToUint8(msg.args[0]) 68 | } 69 | this.curResolve.apply(null, msg.args) 70 | } 71 | this.curResolve = null 72 | this.curReject = null 73 | this.lastDone = true 74 | } else { 75 | console.error('wtf?') 76 | } 77 | } 78 | } 79 | class PortReader { 80 | constructor (port) { 81 | this.port = port 82 | this.hasReader = false 83 | } 84 | _requireReader () { 85 | if (this.hasReader) { 86 | return Promise.resolve() 87 | } else { 88 | return this.port.post('body.getReader').then(() => this.hasReader = true) 89 | } 90 | } 91 | read () { 92 | return this._requireReader() 93 | .then(() => this.port.post('reader.read')) 94 | .then(r => { 95 | if (r.done == false) { 96 | r.value = base64ToUint8(r.value) 97 | } 98 | return r 99 | }) 100 | } 101 | cancel () { 102 | return this._requireReader().then(() => this.port.post('reader.cancel')) 103 | } 104 | } 105 | class PortBody { 106 | constructor (port) { 107 | this.port = port 108 | } 109 | getReader () { 110 | return new PortReader(this.port) 111 | } 112 | } 113 | class PortFetch { 114 | constructor () { 115 | this.port = new WrapPort(chrome.runtime.connect({name: 'fetch'})) 116 | } 117 | fetch (...args) { 118 | if (args[0].url) args[0] = args[0].url; 119 | if (args[0].substr(0, 5) == 'blob:') { 120 | return xhrFakedFetch(...args); 121 | } 122 | return this.port.post('fetch', args).then(r => { 123 | r.json = () => this.port.post('json') 124 | r.text = () => this.port.post('text') 125 | r.arrayBuffer = () => this.port.post('arrayBuffer').then(buf => buf.buffer) 126 | r.headers = convertHeader(r.headers) 127 | r.body = new PortBody(this.port) 128 | return r 129 | }) 130 | } 131 | } 132 | function uint8ToStr (buffer) { 133 | let binary = String.fromCharCode.apply(String, buffer); 134 | /*let binary = '' 135 | let len = buffer.byteLength 136 | for (let i = 0; i < len; i++) { 137 | binary += String.fromCharCode(buffer[i]) 138 | }*/ 139 | return binary 140 | } 141 | function xhrFakedFetch(...args) { 142 | return new Promise((res, rej) => { 143 | const xhr = new XMLHttpRequest; 144 | xhr.open(args[1].method, args[0], true); 145 | xhr.responseType = 'arraybuffer'; 146 | xhr.onload = () => res({ 147 | ok: true, 148 | url: xhr.responseURL, 149 | text: () => new Promise((res) => res(uint8ToStr(new Uint8Array(xhr.response)))), 150 | arrayBuffer: () => new Promise((res) => res(xhr.response)), 151 | }) 152 | xhr.send(); 153 | }) 154 | } 155 | const bgFetch = function bgFetch (...args) { 156 | if (args[1] && args[1].useOriginalFetch) return originalFetch(...args); 157 | const fetch = new PortFetch() 158 | return fetch.fetch(...args) 159 | } 160 | function hookFetch () { 161 | if (fetch !== bgFetch) { 162 | fetch = bgFetch 163 | } 164 | } 165 | const oldBlob = Blob 166 | const newBlob = function newBlob(a, b) { 167 | a[0] = `(${hookFetchCode})();${a[0]}` 168 | console.log('new blob', a, b) 169 | return new oldBlob(a, b) 170 | } 171 | // if(self.document !== undefined) { 172 | // if (self.Blob !== newBlob) { 173 | // self.Blob = newBlob 174 | // } 175 | // } 176 | 177 | hookFetch() 178 | } 179 | 180 | hookFetchCode(); 181 | } -------------------------------------------------------------------------------- /src/_locales/zh_CN/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "statsPlayer": { 3 | "message": "播放器尺寸:" 4 | }, 5 | "statsVideo": { 6 | "message": "视频分辨率:" 7 | }, 8 | "statsBuffer": { 9 | "message": "可用缓冲:" 10 | }, 11 | "statsBufferClip": { 12 | "message": "缓冲片段:" 13 | }, 14 | "statsPresent": { 15 | "message": "期望帧率:" 16 | }, 17 | "statsDrop": { 18 | "message": "丢弃帧率:" 19 | }, 20 | "statsMimetype": { 21 | "message": "文件格式:" 22 | }, 23 | "statsVideoBitrate": { 24 | "message": "本段视频码率:" 25 | }, 26 | "statsAudioBitrate": { 27 | "message": "本段音频码率:" 28 | }, 29 | "statsCurrentBitrate": { 30 | "message": "本段码率:" 31 | }, 32 | "statsRealtimeBitrate": { 33 | "message": "实时码率:" 34 | }, 35 | "overallBitrate": { 36 | "message": "总体码率:" 37 | }, 38 | "reload": { 39 | "message": "重新加载" 40 | }, 41 | "statsDownloadSpeed": { 42 | "message": "下载速度:" 43 | }, 44 | "sendSmall": { 45 | "message": "小字号" 46 | }, 47 | "sendMid": { 48 | "message": "中字号" 49 | }, 50 | "sendSize": { 51 | "message": "弹幕字号" 52 | }, 53 | "sendMode": { 54 | "message": "弹幕模式" 55 | }, 56 | "sendTop": { 57 | "message": "顶端渐隐" 58 | }, 59 | "sendScroll": { 60 | "message": "滚动字幕" 61 | }, 62 | "sendBottom": { 63 | "message": "底端渐隐" 64 | }, 65 | "send": { 66 | "message": "发送" 67 | }, 68 | "sendStyle": { 69 | "message": "弹幕样式" 70 | }, 71 | "sendColor": { 72 | "message": "弹幕颜色" 73 | }, 74 | "commentSpeed": { 75 | "message": "弹幕速度" 76 | }, 77 | "commentScale": { 78 | "message": "弹幕比例" 79 | }, 80 | "commentDensity": { 81 | "message": "弹幕密度" 82 | }, 83 | "commentOpacity": { 84 | "message": "弹幕不透明度" 85 | }, 86 | "commentBlock": { 87 | "message": "弹幕屏蔽设定" 88 | }, 89 | "playSpeed": { 90 | "message": "播放速度" 91 | }, 92 | "playSpeedReset": { 93 | "message": "还原正常速度" 94 | }, 95 | "displayScaleD": { 96 | "message": "默认" 97 | }, 98 | "displayScaleF": { 99 | "message": "铺满" 100 | }, 101 | "shieldTypeText": { 102 | "message": "文字" 103 | }, 104 | "shieldTypeUser": { 105 | "message": "用户" 106 | }, 107 | "shieldTypeColor": { 108 | "message": "颜色" 109 | }, 110 | "shieldTypeSetting": { 111 | "message": "设置" 112 | }, 113 | "shieldAdd": { 114 | "message": "添加屏蔽……" 115 | }, 116 | "shieldUseRegex": { 117 | "message": "启用正则" 118 | }, 119 | "shieldBlockTop": { 120 | "message": "屏蔽顶端弹幕" 121 | }, 122 | "shieldBlockBottom": { 123 | "message": "屏蔽底端弹幕" 124 | }, 125 | "shieldBlockVisitor": { 126 | "message": "屏蔽游客弹幕" 127 | }, 128 | "shieldRepeat": { 129 | "message": "去除刷屏弹幕" 130 | }, 131 | "viewers": { 132 | "message": " 观众" 133 | }, 134 | "comments": { 135 | "message": " 弹幕" 136 | }, 137 | "commentTime": { 138 | "message": "时间" 139 | }, 140 | "commentContent": { 141 | "message": "评论" 142 | }, 143 | "commentDate": { 144 | "message": "发送日期" 145 | }, 146 | "blockMatch":{ 147 | "message": "命中规则:" 148 | }, 149 | "showStats": { 150 | "message": "显示统计信息" 151 | }, 152 | "loadingMeta": { 153 | "message": "正在加载视频信息" 154 | }, 155 | "switching": { 156 | "message": "正在切换" 157 | }, 158 | "fetchURL": { 159 | "message": "正在获取视频地址" 160 | }, 161 | "buffering": { 162 | "message": "正在缓冲" 163 | }, 164 | "play": { 165 | "message": "播放" 166 | }, 167 | "pause": { 168 | "message": "暂停" 169 | }, 170 | "mute": { 171 | "message": "静音" 172 | }, 173 | "unmute": { 174 | "message": "取消静音" 175 | }, 176 | "muteNotSupported": { 177 | "message": "不支持静音" 178 | }, 179 | "fullScreen": { 180 | "message": "浏览器全屏" 181 | }, 182 | "exitFullScreen": { 183 | "message": "退出全屏" 184 | }, 185 | "webFull": { 186 | "message": "网页全屏" 187 | }, 188 | "exitWebFull": { 189 | "message": "退出网页全屏" 190 | }, 191 | "cmtListShow": { 192 | "message": "显示弹幕列表" 193 | }, 194 | "cmtListHide": { 195 | "message": "隐藏弹幕列表" 196 | }, 197 | "sendTooltip": { 198 | "message": "毁灭地喷射白光!da!" 199 | }, 200 | "showComment": { 201 | "message": "显示弹幕" 202 | }, 203 | "hideComment": { 204 | "message": "隐藏弹幕" 205 | }, 206 | "loopOn": { 207 | "message": "洗脑循环 on" 208 | }, 209 | "loopOff": { 210 | "message": "洗脑循环 off" 211 | }, 212 | "usingCanvas": { 213 | "message": "正在使用Canvas" 214 | }, 215 | "usingCSS": { 216 | "message": "正在使用CSS" 217 | }, 218 | "useCSS": { 219 | "message": "使用CSS绘制弹幕" 220 | }, 221 | "autoOpacityOn": { 222 | "message": "关闭自动不透明度" 223 | }, 224 | "autoOpacityOff": { 225 | "message": "开启自动不透明度" 226 | }, 227 | "copyComment": { 228 | "message": "复制弹幕" 229 | }, 230 | "findComment": { 231 | "message": "定位弹幕" 232 | }, 233 | "blockContent": { 234 | "message": "屏蔽内容“" 235 | }, 236 | "blockUser": { 237 | "message": "屏蔽发送者" 238 | }, 239 | "blockColor": { 240 | "message": "屏蔽颜色" 241 | }, 242 | "blockColorWhite": { 243 | "message": "不能屏蔽白色" 244 | }, 245 | "copyFail": { 246 | "message": "复制失败,浏览器不支持" 247 | }, 248 | "blockUserEmpty": { 249 | "message": "没有屏蔽用户" 250 | }, 251 | "blockColorEmpty": { 252 | "message": "没有屏蔽颜色" 253 | }, 254 | "repeatPcs": { 255 | "message": "条" 256 | }, 257 | "repeatUnlimited": { 258 | "message": "不限制" 259 | }, 260 | "dragControlLowInc": { 261 | "message": "低速快进" 262 | }, 263 | "dragControlLowDec": { 264 | "message": "低速快退" 265 | }, 266 | "dragControlMedInc": { 267 | "message": "中速快进" 268 | }, 269 | "dragControlMedDec": { 270 | "message": "中速快退" 271 | }, 272 | "dragControlHighInc": { 273 | "message": "高速快进" 274 | }, 275 | "dragControlHighDec": { 276 | "message": "高速快退" 277 | }, 278 | "dragControlCancel": { 279 | "message": "取消跳转" 280 | }, 281 | "extName": { 282 | "message": "AcFun HTML5 Player" 283 | }, 284 | "extDesc": { 285 | "message": "一个装B播放器,送给缺B乐的各位(\n\n开源仓库:https://github.com/esterTion/AcFun-HTML5-Player" 286 | }, 287 | "iconPending": { 288 | "message": "个视频等待播放" 289 | }, 290 | "iconPlaying": { 291 | "message": "个视频正在播放" 292 | }, 293 | "iconIdle": { 294 | "message": "没有可替换的播放器" 295 | }, 296 | "close": { 297 | "message": "关闭" 298 | }, 299 | "flvhd": { 300 | "message": "标清" 301 | }, 302 | "mp4hd": { 303 | "message": "高清" 304 | }, 305 | "mp4hd2": { 306 | "message": "超清" 307 | }, 308 | "mp4hd3": { 309 | "message": "原画" 310 | }, 311 | "emptyPW": { 312 | "message": "空密码" 313 | }, 314 | "currentLang": { 315 | "message": "当前音频语言:" 316 | }, 317 | "needPW": { 318 | "message": "视频需要密码访问,请输入密码:" 319 | }, 320 | "enterPW": { 321 | "message": "输入视频密码" 322 | }, 323 | "rememberPW": { 324 | "message": "记住密码" 325 | }, 326 | "submit": { 327 | "message": "提交" 328 | }, 329 | "wrongPW": { 330 | "message": "视频访问密码错误,请重新输入密码:" 331 | }, 332 | "fetchSourceErr": { 333 | "message": "获取视频地址出错,详细错误:" 334 | }, 335 | "audioLang": { 336 | "message": "音频语言" 337 | }, 338 | "toYouku": { 339 | "message": "前往主站播放" 340 | }, 341 | "fetchCommentErr": { 342 | "message": "弹幕获取失败" 343 | }, 344 | "loadErr": { 345 | "message": "加载视频失败,无法播放该视频" 346 | }, 347 | "playErr": { 348 | "message": "播放错误" 349 | }, 350 | "playErrPop": { 351 | "message": " 播放出错,降级至 " 352 | }, 353 | "switchErr": { 354 | "message": "切换失败,该语言/清晰度暂时不能播放" 355 | }, 356 | "partialAvailable": { 357 | "message": "本视频仅可播放部分片段,请确认付费状态" 358 | }, 359 | "restoreFlash": { 360 | "message": "还原flash播放器" 361 | }, 362 | "fetchInfoErr": { 363 | "message": "获取视频信息出错,详细错误:" 364 | }, 365 | "uploader": { 366 | "message": "上传者:" 367 | }, 368 | "outputUrl": { 369 | "message": "输出视频地址" 370 | }, 371 | "noVisitorComment": { 372 | "message": "游客无法发送弹幕" 373 | }, 374 | "postCommentFail": { 375 | "message": "弹幕发送失败" 376 | }, 377 | "replaceEmbed": { 378 | "message": "替换外链播放器" 379 | }, 380 | "autoSwitch": { 381 | "message": "自动切换剧集" 382 | }, 383 | "mayBlocked": { 384 | "message": "您可能开启了广告屏蔽并屏蔽了必要内容,请尝试临时禁用并刷新\n正常出现播放器后可以重新启用\n\n如果这不是您第一次看见这个提示,请确认网络状态" 385 | }, 386 | "officialHtml5": { 387 | "message": "使用官方html5播放器" 388 | }, 389 | "settings": { 390 | "message": "设置" 391 | }, 392 | "settComment": { 393 | "message": "弹幕偏好设置" 394 | }, 395 | "recordPlaySpeed": { 396 | "message": "将当前速度设为默认" 397 | }, 398 | "settPlayer": { 399 | "message": "播放器偏好设置" 400 | }, 401 | "autoPlay": { 402 | "message": "自动开始播放" 403 | }, 404 | "defaultFull": { 405 | "message": "自动进入全屏模式" 406 | }, 407 | "settExtension": { 408 | "message": "扩展偏好设置" 409 | }, 410 | "statsSourceHost": { 411 | "message": "视频源域名:" 412 | }, 413 | "statsRedirection": { 414 | "message": "重定向:" 415 | }, 416 | "statsRedirectionNone": { 417 | "message": "否" 418 | }, 419 | "extUpdated": { 420 | "message": "YAPfY 最近有更新啦!" 421 | }, 422 | "extUpdated_ver": { 423 | "message": "现在我们的版本是" 424 | }, 425 | "extUpdated_detail": { 426 | "message": "一些更新细节:\n1、项目已经更名为【Yet Another Player for Youku - 更好用的优酷播放器】\n2、播放出错时尝试播放较低清晰度" 427 | }, 428 | "playerTheme":{ 429 | "message":"播放器主题" 430 | }, 431 | "cmStyle":{ 432 | "message": "弹幕样式:" 433 | }, 434 | "cmStyle_st":{ 435 | "message": "描边" 436 | }, 437 | "cmStyle_sh":{ 438 | "message": "阴影" 439 | }, 440 | "cmStyle_stsh":{ 441 | "message": "描边 + 阴影" 442 | }, 443 | "next": { 444 | "message": "下一个视频:" 445 | }, 446 | "storylinePoints": { 447 | "message": "视频亮点" 448 | }, 449 | "skipHead": { 450 | "message": "跳过片头片尾" 451 | }, 452 | "volumeChange": { 453 | "message": "音量改变至 " 454 | }, 455 | "rateChange": { 456 | "message": "速度改变至 " 457 | }, 458 | "copySegUrl": { 459 | "message": "复制地址" 460 | }, 461 | "copied": { 462 | "message": "已复制" 463 | }, 464 | "Auto": { 465 | "message": "自动" 466 | }, 467 | "switchingTo": { 468 | "message": "正在切换至 " 469 | }, 470 | "switched": { 471 | "message": "已切换" 472 | }, 473 | "currentQuality": { 474 | "message": "当前清晰度:" 475 | }, 476 | "currentFragment": { 477 | "message": "当前分片:" 478 | }, 479 | "playerCoreSetting": { 480 | "message": "播放器核心:" 481 | }, 482 | "playerCoreSettingTip": { 483 | "message": "切换后需刷新页面" 484 | }, 485 | "screenshot": { 486 | "message": "视频截屏" 487 | }, 488 | "screenshotWithoutComment": { 489 | "message": "不含弹幕" 490 | }, 491 | "screenshotWithComment": { 492 | "message": "含弹幕" 493 | }, 494 | "screenshotCSSNoSupport": { 495 | "message": "css弹幕不支持截图" 496 | }, 497 | "screenshotError": { 498 | "message": "视频源限制,无法生成截图" 499 | }, 500 | "chromeAutoPlay": { 501 | "message": "自动播放被阻止,请点击开始播放" 502 | }, 503 | "commentLoadPagesSetting": { 504 | "message": "加载弹幕数:" 505 | } 506 | } 507 | -------------------------------------------------------------------------------- /src/_locales/zh_TW/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "statsPlayer": { 3 | "message": "播放機尺寸:" 4 | }, 5 | "statsVideo": { 6 | "message": "視頻解析度:" 7 | }, 8 | "statsBuffer": { 9 | "message": "可用緩衝:" 10 | }, 11 | "statsBufferClip": { 12 | "message": "緩衝片段:" 13 | }, 14 | "statsPresent": { 15 | "message": "期望幀率:" 16 | }, 17 | "statsDrop": { 18 | "message": "丟棄幀率:" 19 | }, 20 | "statsMimetype": { 21 | "message": "檔案格式:" 22 | }, 23 | "statsVideoBitrate": { 24 | "message": "本段視頻碼率:" 25 | }, 26 | "statsAudioBitrate": { 27 | "message": "本段音訊碼率:" 28 | }, 29 | "statsCurrentBitrate": { 30 | "message": "本段碼率:" 31 | }, 32 | "statsRealtimeBitrate": { 33 | "message": "即時碼率:" 34 | }, 35 | "overallBitrate": { 36 | "message": "總體碼率:" 37 | }, 38 | "reload": { 39 | "message": "重新載入" 40 | }, 41 | "statsDownloadSpeed": { 42 | "message": "下載速度:" 43 | }, 44 | "sendSmall": { 45 | "message": "小字型大小" 46 | }, 47 | "sendMid": { 48 | "message": "中字型大小" 49 | }, 50 | "sendSize": { 51 | "message": "彈幕字型大小" 52 | }, 53 | "sendMode": { 54 | "message": "彈幕模式" 55 | }, 56 | "sendTop": { 57 | "message": "頂端漸隱" 58 | }, 59 | "sendScroll": { 60 | "message": "滾動字幕" 61 | }, 62 | "sendBottom": { 63 | "message": "底端漸隱" 64 | }, 65 | "send": { 66 | "message": "發送" 67 | }, 68 | "sendStyle": { 69 | "message": "彈幕樣式" 70 | }, 71 | "sendColor": { 72 | "message": "彈幕顏色" 73 | }, 74 | "commentSpeed": { 75 | "message": "彈幕速度" 76 | }, 77 | "commentScale": { 78 | "message": "彈幕比例" 79 | }, 80 | "commentDensity": { 81 | "message": "彈幕密度" 82 | }, 83 | "commentOpacity": { 84 | "message": "彈幕不透明度" 85 | }, 86 | "commentBlock": { 87 | "message": "彈幕遮罩設定" 88 | }, 89 | "playSpeed": { 90 | "message": "播放速度" 91 | }, 92 | "playSpeedReset": { 93 | "message": "還原正常速度" 94 | }, 95 | "displayScaleD": { 96 | "message": "默認" 97 | }, 98 | "displayScaleF": { 99 | "message": "鋪滿" 100 | }, 101 | "shieldTypeText": { 102 | "message": "文字" 103 | }, 104 | "shieldTypeUser": { 105 | "message": "用戶" 106 | }, 107 | "shieldTypeColor": { 108 | "message": "顏色" 109 | }, 110 | "shieldTypeSetting": { 111 | "message": "設置" 112 | }, 113 | "shieldAdd": { 114 | "message": "添加遮罩……" 115 | }, 116 | "shieldUseRegex": { 117 | "message": "啟用正則" 118 | }, 119 | "shieldBlockTop": { 120 | "message": "遮罩頂端彈幕" 121 | }, 122 | "shieldBlockBottom": { 123 | "message": "遮罩底端彈幕" 124 | }, 125 | "shieldBlockVisitor": { 126 | "message": "遮罩遊客彈幕" 127 | }, 128 | "shieldRepeat": { 129 | "message": "去除刷屏彈幕" 130 | }, 131 | "viewers": { 132 | "message": " 觀眾" 133 | }, 134 | "comments": { 135 | "message": " 彈幕" 136 | }, 137 | "commentTime": { 138 | "message": "時間" 139 | }, 140 | "commentContent": { 141 | "message": "評論" 142 | }, 143 | "commentDate": { 144 | "message": "發送日期" 145 | }, 146 | "blockMatch":{ 147 | "message": "命中規則:" 148 | }, 149 | "showStats": { 150 | "message": "顯示統計資訊" 151 | }, 152 | "loadingMeta": { 153 | "message": "正在載入視頻資訊" 154 | }, 155 | "switching": { 156 | "message": "正在切換" 157 | }, 158 | "fetchURL": { 159 | "message": "正在獲取視頻位址" 160 | }, 161 | "buffering": { 162 | "message": "正在緩衝" 163 | }, 164 | "play": { 165 | "message": "播放" 166 | }, 167 | "pause": { 168 | "message": "暫停" 169 | }, 170 | "mute": { 171 | "message": "靜音" 172 | }, 173 | "unmute": { 174 | "message": "取消靜音" 175 | }, 176 | "muteNotSupported": { 177 | "message": "不支持靜音" 178 | }, 179 | "fullScreen": { 180 | "message": "流覽器全屏" 181 | }, 182 | "exitFullScreen": { 183 | "message": "退出全屏" 184 | }, 185 | "webFull": { 186 | "message": "網頁全屏" 187 | }, 188 | "exitWebFull": { 189 | "message": "退出網頁全屏" 190 | }, 191 | "cmtListShow": { 192 | "message": "顯示彈幕清單" 193 | }, 194 | "cmtListHide": { 195 | "message": "隱藏彈幕清單" 196 | }, 197 | "sendTooltip": { 198 | "message": "毀滅地噴射白光!da!" 199 | }, 200 | "showComment": { 201 | "message": "顯示彈幕" 202 | }, 203 | "hideComment": { 204 | "message": "隱藏彈幕" 205 | }, 206 | "loopOn": { 207 | "message": "洗腦迴圈 on" 208 | }, 209 | "loopOff": { 210 | "message": "洗腦迴圈 off" 211 | }, 212 | "usingCanvas": { 213 | "message": "正在使用Canvas" 214 | }, 215 | "usingCSS": { 216 | "message": "正在使用CSS" 217 | }, 218 | "useCSS": { 219 | "message": "使用CSS繪製彈幕" 220 | }, 221 | "autoOpacityOn": { 222 | "message": "關閉自動不透明度" 223 | }, 224 | "autoOpacityOff": { 225 | "message": "開啟自動不透明度" 226 | }, 227 | "copyComment": { 228 | "message": "複製彈幕" 229 | }, 230 | "findComment": { 231 | "message": "定位彈幕" 232 | }, 233 | "blockContent": { 234 | "message": "遮罩內容“" 235 | }, 236 | "blockUser": { 237 | "message": "遮罩發送者" 238 | }, 239 | "blockColor": { 240 | "message": "遮罩顏色" 241 | }, 242 | "blockColorWhite": { 243 | "message": "不能遮罩白色" 244 | }, 245 | "copyFail": { 246 | "message": "複製失敗,流覽器不支持" 247 | }, 248 | "blockUserEmpty": { 249 | "message": "沒有遮罩用戶" 250 | }, 251 | "blockColorEmpty": { 252 | "message": "沒有遮罩顏色" 253 | }, 254 | "repeatPcs": { 255 | "message": "條" 256 | }, 257 | "repeatUnlimited": { 258 | "message": "不限制" 259 | }, 260 | "dragControlLowInc": { 261 | "message": "低速快進" 262 | }, 263 | "dragControlLowDec": { 264 | "message": "低速快退" 265 | }, 266 | "dragControlMedInc": { 267 | "message": "中速快進" 268 | }, 269 | "dragControlMedDec": { 270 | "message": "中速快退" 271 | }, 272 | "dragControlHighInc": { 273 | "message": "高速快進" 274 | }, 275 | "dragControlHighDec": { 276 | "message": "高速快退" 277 | }, 278 | "dragControlCancel": { 279 | "message": "取消跳轉" 280 | }, 281 | "extName": { 282 | "message": "AcFun HTML5 Player" 283 | }, 284 | "extDesc": { 285 | "message": "開源倉庫:https://github.com/esterTion/AcFun-HTML5-Player" 286 | }, 287 | "iconPending": { 288 | "message": "個視頻等待播放" 289 | }, 290 | "iconPlaying": { 291 | "message": "個視頻正在播放" 292 | }, 293 | "iconIdle": { 294 | "message": "沒有可替換的播放機" 295 | }, 296 | "close": { 297 | "message": "關閉" 298 | }, 299 | "flvhd": { 300 | "message": "標清" 301 | }, 302 | "mp4hd": { 303 | "message": "高清" 304 | }, 305 | "mp4hd2": { 306 | "message": "超清" 307 | }, 308 | "mp4hd3": { 309 | "message": "原畫" 310 | }, 311 | "emptyPW": { 312 | "message": "空密碼" 313 | }, 314 | "currentLang": { 315 | "message": "當前音訊語言:" 316 | }, 317 | "needPW": { 318 | "message": "視頻需要密碼訪問,請輸入密碼:" 319 | }, 320 | "enterPW": { 321 | "message": "輸入視頻密碼" 322 | }, 323 | "rememberPW": { 324 | "message": "記住密碼" 325 | }, 326 | "submit": { 327 | "message": "提交" 328 | }, 329 | "wrongPW": { 330 | "message": "視頻訪問密碼錯誤,請重新輸入密碼:" 331 | }, 332 | "fetchSourceErr": { 333 | "message": "獲取視頻位址出錯,詳細錯誤:" 334 | }, 335 | "audioLang": { 336 | "message": "音訊語言" 337 | }, 338 | "toYouku": { 339 | "message": "前往主站播放" 340 | }, 341 | "fetchCommentErr": { 342 | "message": "彈幕獲取失敗" 343 | }, 344 | "loadErr": { 345 | "message": "載入視頻失敗,無法播放該視頻" 346 | }, 347 | "playErr": { 348 | "message": "播放錯誤" 349 | }, 350 | "playErrPop": { 351 | "message": " 播放出錯,降級至 " 352 | }, 353 | "switchErr": { 354 | "message": "切換失敗,該語言/清晰度暫時不能播放" 355 | }, 356 | "partialAvailable": { 357 | "message": "本視頻僅可播放部分片段,請確認付費狀態" 358 | }, 359 | "restoreFlash": { 360 | "message": "還原flash播放機" 361 | }, 362 | "fetchInfoErr": { 363 | "message": "獲取視頻資訊出錯,詳細錯誤:" 364 | }, 365 | "uploader": { 366 | "message": "上傳者:" 367 | }, 368 | "outputUrl": { 369 | "message": "輸出視頻位址" 370 | }, 371 | "noVisitorComment": { 372 | "message": "遊客無法發送彈幕" 373 | }, 374 | "postCommentFail": { 375 | "message": "彈幕發送失敗" 376 | }, 377 | "replaceEmbed": { 378 | "message": "替換外鏈播放機" 379 | }, 380 | "autoSwitch": { 381 | "message": "自動切換劇集" 382 | }, 383 | "mayBlocked": { 384 | "message": "您可能開啟了廣告遮罩並遮罩了必要內容,請嘗試臨時禁用並刷新\n正常出現播放機後可以重新啟用\n\n如果這不是您第一次看見這個提示,請確認網路狀態" 385 | }, 386 | "officialHtml5": { 387 | "message": "使用官方html5播放機" 388 | }, 389 | "settings": { 390 | "message": "設置" 391 | }, 392 | "settComment": { 393 | "message": "彈幕偏好設置" 394 | }, 395 | "recordPlaySpeed": { 396 | "message": "將當前速度設為預設" 397 | }, 398 | "settPlayer": { 399 | "message": "播放機偏好設置" 400 | }, 401 | "autoPlay": { 402 | "message": "自動開始播放" 403 | }, 404 | "defaultFull": { 405 | "message": "自動進入全屏模式" 406 | }, 407 | "settExtension": { 408 | "message": "擴展偏好設置" 409 | }, 410 | "statsSourceHost": { 411 | "message": "視頻源功能變數名稱:" 412 | }, 413 | "statsRedirection": { 414 | "message": "重定向:" 415 | }, 416 | "statsRedirectionNone": { 417 | "message": "否" 418 | }, 419 | "extUpdated": { 420 | "message": "優酷HTML5播放機最近有更新啦!" 421 | }, 422 | "extUpdated_ver": { 423 | "message": "現在我們的版本是" 424 | }, 425 | "extUpdated_detail": { 426 | "message": "一些更新細節:\n1、專案已經更名為【Yet Another Player for Youku - 更好用的優酷播放機】\n2、播放出錯時嘗試播放較低清晰度" 427 | }, 428 | "playerTheme": { 429 | "message": "播放機主題" 430 | }, 431 | "cmStyle":{ 432 | "message": "彈幕樣式:" 433 | }, 434 | "cmStyle_st":{ 435 | "message": "描邊" 436 | }, 437 | "cmStyle_sh":{ 438 | "message": "陰影" 439 | }, 440 | "cmStyle_stsh":{ 441 | "message": "描邊 + 陰影" 442 | }, 443 | "next": { 444 | "message": "下一個視頻:" 445 | }, 446 | "storylinePoints": { 447 | "message": "視頻亮點" 448 | }, 449 | "skipHead": { 450 | "message": "跳過片頭片尾" 451 | }, 452 | "volumeChange": { 453 | "message": "音量改變至 " 454 | }, 455 | "rateChange": { 456 | "message": "速度改變至 " 457 | }, 458 | "copySegUrl": { 459 | "message": "複製地址" 460 | }, 461 | "copied": { 462 | "message": "已複製" 463 | }, 464 | "Auto": { 465 | "message": "自動" 466 | }, 467 | "switchingTo": { 468 | "message": "正在切換至 " 469 | }, 470 | "switched": { 471 | "message": "已切換" 472 | }, 473 | "currentQuality": { 474 | "message": "當前清晰度:" 475 | }, 476 | "currentFragment": { 477 | "message": "當前分片:" 478 | }, 479 | "playerCoreSetting": { 480 | "message": "播放機核心:" 481 | }, 482 | "playerCoreSettingTip": { 483 | "message": "切換後需刷新頁面" 484 | }, 485 | "screenshot": { 486 | "message": "視頻截屏" 487 | }, 488 | "screenshotWithoutComment": { 489 | "message": "不含彈幕" 490 | }, 491 | "screenshotWithComment": { 492 | "message": "含彈幕" 493 | }, 494 | "screenshotCSSNoSupport": { 495 | "message": "css彈幕不支持截圖" 496 | }, 497 | "screenshotError": { 498 | "message": "視頻源限制,無法生成截圖" 499 | }, 500 | "chromeAutoPlay": { 501 | "message": "自動播放被阻止,請點擊開始播放" 502 | }, 503 | "commentLoadPagesSetting": { 504 | "message": "載入彈幕數:" 505 | } 506 | } 507 | -------------------------------------------------------------------------------- /src/biliplus_shield.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * 3 | * danmaku shield - biliplus 4 | * 5 | * @author esterTion 6 | * 7 | */ 8 | /* 9 | 功能预想: 10 | 文本屏蔽(开启/关闭正则) 11 | 用户屏蔽(通过右键菜单增加) 12 | 颜色屏蔽(通过右键菜单增加) 13 | 重复屏蔽 14 | */ 15 | var shield = (function () { 16 | var danmakuMatcher = /[\x00-\x2f\x3a-\x40\x5b-\x5e\x60\x7b-\x7f]/g, firstTime = !0, hidden = !0, list = null, activeTab = 0, useReg = !1, $ = function (a) {return playerInstance.playerUnit.querySelectorAll(a);}, $$ = function (a) {return playerInstance.playerUnit.querySelector(a);}, limit, playerInstance = null, 17 | isVisitor = function (hash) { 18 | if (hash.length == 14 && hash[3] == 'k') { 19 | return true; 20 | } 21 | if (hash[0] == 'D' || hash[0] == 'd') { 22 | return true; 23 | } 24 | if (hash == "0") { 25 | return true; 26 | } 27 | return false; 28 | }, 29 | obj = { 30 | init: function (player) { 31 | if (!firstTime) 32 | return; 33 | if (player != undefined) 34 | playerInstance = player; 35 | firstTime = !1; 36 | obj.tab(0); 37 | if (localStorage.shieldList == undefined) 38 | localStorage.shieldList = '{"text":[],"user":[],"color":[],"useReg":false,"limit":10,"mode":[],"visitor":false}'; 39 | list = JSON.parse(localStorage.shieldList); 40 | if (list.color == undefined) 41 | list.color = []; 42 | if (list.useReg == undefined) 43 | list.useReg = !1; 44 | if (list.limit == undefined) 45 | list.limit = 10; 46 | if (list.mode == undefined) 47 | list.mode = []; 48 | if (list.visitor == undefined) 49 | list.visitor = false; 50 | useReg = list.useReg; 51 | limit = list.limit; 52 | obj.render(); 53 | $$('.shield-enrty').addEventListener('click', obj.show); 54 | $$('.shield_top .close').addEventListener('click', obj.show); 55 | $$('.shield_item .add').addEventListener('click', obj.add); 56 | var i, len, tabs; 57 | tabs = $('.shield_tab'); 58 | for (i = 0, len = tabs.length; i < len; i++) { 59 | tabs[i].tabNum = i; 60 | tabs[i].addEventListener('mouseenter', function () {obj.tab(this.tabNum);}); 61 | tabs[i].addEventListener('mouseleave', function (e) { 62 | var border = this.getBoundingClientRect(), 63 | x = e.clientX, y = e.clientY; 64 | if ( 65 | (x - border.left < 0) || (x - border.left > border.width) || 66 | (y - border.top < 0) || (y - border.top > border.height) 67 | ) 68 | obj.tab(activeTab); 69 | }); 70 | tabs[i].addEventListener('click', function () {obj.switchTab(this.tabNum);}); 71 | } 72 | $$('#useReg').addEventListener('click', function () { 73 | useReg = !useReg; 74 | obj.save(); 75 | obj.render(3); 76 | }); 77 | $$('#blockTop').addEventListener('click', function () { 78 | obj.mode(5); 79 | }); 80 | $$('#blockBottom').addEventListener('click', function () { 81 | obj.mode(4); 82 | }); 83 | $$('#blockVisitor').addEventListener('click', function () { 84 | obj.visitor(); 85 | }); 86 | var repeatBtnClick = !1, repeatBtnMove = function (e) { 87 | if (!repeatBtnClick) 88 | return; 89 | var box = $$('#repeat').getBoundingClientRect(), 90 | calc = Math.round((e.clientX - box.left) / box.width * 49 + 2); 91 | if (calc < 2 || calc > 51) 92 | return; 93 | limit = calc; 94 | if (limit == 51) 95 | limit = 0; 96 | obj.render(3); 97 | }; 98 | $$('#repeat').addEventListener('mousedown', function (e) { 99 | repeatBtnClick = !0; 100 | repeatBtnMove(e); 101 | }); 102 | $$('#repeat').addEventListener('mouseup', function () { 103 | repeatBtnClick = !1; 104 | obj.save(); 105 | }); 106 | $$('#repeat').addEventListener('touchend', function () { 107 | repeatBtnClick = !1; 108 | obj.save(); 109 | }); 110 | $$('.shield').addEventListener('mousemove', repeatBtnMove); 111 | }, 112 | switchTab: function (offset) { 113 | activeTab = offset; 114 | $$('.shield_body_wrapper').style.transform = 'translateX(' + offset * -278 + 'px)'; 115 | $$('.shield_body_wrapper').style.webkitTransform = 'translateX(' + offset * -278 + 'px)'; 116 | }, 117 | tab: function (offset) { 118 | var container = $$('.shield'), containerBorder = container.getBoundingClientRect(), 119 | moveTo = $$('.shield .shield_tab:nth-of-type(' + (offset + 1) + ')>div').getBoundingClientRect(), 120 | left = moveTo.left - containerBorder.left, 121 | width = moveTo.width, 122 | tab = $$('.shield .shield_tab_slash'); 123 | tab.style.left = left + 'px'; 124 | tab.style.width = width + 'px'; 125 | }, 126 | render: function (part) { 127 | var doAll = !0, tab = 0; 128 | if (part != undefined) { 129 | doAll = !1, tab = part; 130 | } 131 | while (1) {switch (tab) { 132 | case 0: 133 | //文本 134 | var str = '', i, len, del; 135 | for (i = 0, len = list.text.length; i < len; i++) { 136 | str += '
=2&&3===t[o]&&0===t[o-1]&&0===t[o-2]||(a[n]=t[o],n++);return new Uint8Array(a.buffer,0,n)}},{key:"parseSPS",value:function(t){var r=e._ebsp2rbsp(t),a=new i.default(r);a.readByte();var n=a.readByte();a.readByte();var o=a.readByte();a.readUEG();var f=e.getProfileString(n),s=e.getLevelString(o),l=1,u=420,c=[0,420,422,444],d=8;if((100===n||110===n||122===n||244===n||44===n||83===n||86===n||118===n||128===n||138===n||144===n)&&(l=a.readUEG(),3===l&&a.readBits(1),l<=3&&(u=c[l]),d=a.readUEG()+8,a.readUEG(),a.readBits(1),a.readBool()))for(var h=3!==l?8:12,p=0;p0&&O<16?(E=M[O-1],U=C[O-1]):255===O&&(E=a.readByte()<<8|a.readByte(),U=a.readByte()<<8|a.readByte())}if(a.readBool()&&a.readBool(),a.readBool()&&(a.readBits(4),a.readBool()&&a.readBits(24)),a.readBool()&&(a.readUEG(),a.readUEG()),a.readBool()){var G=a.readBits(32),I=a.readBits(32);B=a.readBool(),x=I,A=2*G,F=x/A}}var D=1;1===E&&1===U||(D=E/U);var P=0,j=0;if(0===l)P=1,j=2-g;else{var L=3===l?1:2,T=1===l?2:1;P=L,j=T*(2-g)}var H=16*(y+1),R=16*(m+1)*(2-g);H-=(w+k)*P,R-=(S+z)*j;var N=Math.ceil(H*D);return a.destroy(),a=null,{profile_string:f,level_string:s,bit_depth:d,chroma_format:u,chroma_format_string:e.getChromaFormatString(u),frame_rate:{fixed:B,fps:F,fps_den:A,fps_num:x},sar_ratio:{width:E,height:U},codec_size:{width:H,height:R},present_size:{width:N,height:R}}}},{key:"_skipScalingList",value:function(e,t){for(var r=8,a=8,n=0,o=0;o :first-child')); 88 | abpinst.playerUnit.querySelector('#info-box').remove(); 89 | createPopup({ 90 | content: [_('p', { style: { fontSize: '16px' } }, [_('text', _t('playErr'))]), _('div', { style: { whiteSpace: 'pre-wrap' } }, [_('text', JSON.stringify({ type, info, detail }, null, ' '))])], 91 | showConfirm: false 92 | }); 93 | }; 94 | 95 | let commentLoadPages = 12; 96 | readStorage('commentLoadPages', function (item) { 97 | commentLoadPages = (item.commentLoadPages | 0) || 12; 98 | }); 99 | function sendComment(e) { 100 | let cmt = e.detail; 101 | //abpinst.danmu_ws.send(JSON.stringify(obj)); 102 | var form = []; 103 | form.push('mode=' + cmt.mode); 104 | form.push('color=' + cmt.color); 105 | form.push('size=' + cmt.fontsize); 106 | form.push('body=' + encodeURIComponent(cmt.message)); 107 | form.push('videoId=' + pageInfo.vid); 108 | form.push('position=' + ((cmt.playTime * 1e3) | 0)); 109 | form.push('type=' + (isBangumi ? 'bangumi' : 'douga')); 110 | form.push('id=' + pageInfo[isBangumi ? 'bangumiId' : 'dougaId']); 111 | form.push('subChannelId=' + (isBangumi ? 155 : pageInfo.channel.parentId)); 112 | form.push('subChannelName=' + encodeURIComponent(isBangumi ? '番剧' : pageInfo.channel.parentName)); 113 | form.push('roleId='); 114 | 115 | var xhr = new XMLHttpRequest; 116 | xhr.open('POST', location.origin+'/rest/pc-direct/new-danmaku/add', true); 117 | xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); 118 | xhr.responseType = 'json'; 119 | xhr.onload = function () { 120 | var data = xhr.response; 121 | if (data.result != 0) { 122 | abpinst.createPopup('发送失败:[' + data.result + ']' + data.error_msg, 5e3); 123 | } 124 | }; 125 | xhr.onerror = function (e) { 126 | abpinst.createPopup('发送失败:' + e.message, 5e3); 127 | }; 128 | xhr.send(form.join('&')); 129 | } 130 | 131 | let dest = null; 132 | let ABPConfig; 133 | let currentBangumiUrl = location.href.split('?')[0]; 134 | let isBangumi = /\/bangumi\/aa/.test(currentBangumiUrl); 135 | function chkInit() { 136 | new Promise((res) => { 137 | readStorage('PlayerSettings', function (item) { 138 | ABPConfig = item.PlayerSettings || {}; 139 | if (isBangumi) { 140 | let observer = new MutationObserver(bangumiEpisodeChange); 141 | observer.observe(document.body, { childList: true, subtree: true }); 142 | } 143 | res(); 144 | }); 145 | }).then(() => { 146 | if (!pageInfo.currentVideoInfo) { 147 | return fetch( 148 | 'https://tx.biliplus.com:7823/acfun_getVideoInfoByPage?path=' + encodeURIComponent(location.href.replace(location.origin, '')) 149 | ).then(r => r.json()).then(r => { 150 | const temp = this.cloneInto ? cloneInto(r.currentVideoInfo, pageInfo) : r.currentVideoInfo 151 | pageInfo.currentVideoInfo = temp; 152 | }).catch(e => console.error(e)); 153 | } 154 | }).then(init) 155 | } 156 | function bangumiEpisodeChange() { 157 | let newUrl = location.href.split('?')[0]; 158 | if (newUrl != currentBangumiUrl) { 159 | location.href = newUrl; 160 | } 161 | } 162 | let isNewVersionPlayPage = document.getElementById('pagelet_newrecommend') != null; 163 | function init() { 164 | if (!pageInfo.vid || dest == null) 165 | return; 166 | window.cid = pageInfo.vid; 167 | let container = dest.parentNode; 168 | if (container == null) { 169 | dest = document.getElementById('ACFlashPlayer'); 170 | init(); 171 | return; 172 | } 173 | dest.remove(); 174 | let blob = new Blob([''], { type: 'text/html' }); 175 | let bloburl = URL.createObjectURL(blob); 176 | window.playerIframe = container.appendChild(_('div', { style: isNewVersionPlayPage ? { position: 'absolute', left: 0, right: 0, top: 0, bottom: 0 } : { height: 0 } }, [_('iframe', { className: 'AHP-Player-Container', allowfullscreen: true, src: bloburl, allow: 'fullscreen; autoplay' })])).children[0]; 177 | playerIframe.onload = function () { 178 | URL.revokeObjectURL(bloburl); 179 | try { 180 | if (playerIframe.contentDocument.head.getElementsByTagName('link').length == 0) { 181 | location.reload(); 182 | return; 183 | } 184 | } catch (e) { 185 | location.reload(); 186 | return; 187 | } 188 | let video = playerIframe.contentDocument.body.appendChild(_('video', { poster: pageInfo.coverImage })); 189 | window.flvplayer = { unload: function () { }, destroy: function () { } }; 190 | abpinst = ABP.create(video.parentNode, { 191 | src: { 192 | playlist: [{ 193 | video: video 194 | }] 195 | }, 196 | width: '100%', 197 | height: '100%', 198 | config: ABPConfig 199 | }); 200 | dots.init({ 201 | container: abpinst.playerUnit.querySelector('#dots'), 202 | width: '100%', 203 | height: '100%', 204 | r: 16, 205 | thick: 4 206 | }); 207 | dots.runTimer(); 208 | 209 | // 弹幕页数设置 210 | abpinst.settingPanel.firstChild.lastChild.appendChild(_('p', { className: 'label prop' }, [ 211 | _('text', _t('commentLoadPagesSetting')), 212 | _('select', { id: 'setting-commentLoadPages', event: { mouseup: function (e) { e.stopPropagation(); }, change: function () { saveStorage({ commentLoadPages: this.value }); } } }, [ 213 | _('option', { value: '3' }, [_('text', '3')]), 214 | _('option', { value: '5' }, [_('text', '5')]), 215 | _('option', { value: '8' }, [_('text', '8')]), 216 | _('option', { value: '10' }, [_('text', '10')]), 217 | _('option', { value: '12' }, [_('text', '12')]), 218 | _('option', { value: '15' }, [_('text', '15')]), 219 | _('option', { value: '20' }, [_('text', '20')]) 220 | ]), 221 | _('text', ' k') 222 | ])); 223 | abpinst.settingPanel.querySelector('#setting-commentLoadPages').value = commentLoadPages; 224 | 225 | if (!pageInfo.currentVideoInfo || !pageInfo.currentVideoInfo.ksPlayJson) { 226 | createPopup({ 227 | content: [_('p', { style: { fontSize: '16px' } }, [_('text', _t('fetchSourceErr'))]), _('text', pageInfo.playErrorMessage || '未找到视频播放地址')], 228 | showConfirm: false 229 | }); 230 | return; 231 | } 232 | 233 | let ksPlayJson = JSON.parse(pageInfo.currentVideoInfo.ksPlayJson); 234 | if (ksPlayJson.adaptationSet.length) ksPlayJson.adaptationSet = ksPlayJson.adaptationSet[0]; 235 | let playlists = ksPlayJson.adaptationSet.representation; 236 | playlists.sort((a, b) => a.width - b.width); 237 | let masterManifest = '#EXTM3U\n' + playlists.map(i => ( 238 | `#EXT-X-STREAM-INF:BANDWIDTH=${i.avgBitrate},RESOLUTION=${i.width}x${i.height}\n${i.url}\n` 239 | )).join(''); 240 | let masterManifestBlob = new Blob([masterManifest], { mimeType: 'application/vnd.apple.mpegurl' }); 241 | let masterManifestUrl = URL.createObjectURL(masterManifestBlob); 242 | let conf = { 243 | enableWorker: isChrome, 244 | capLevelToPlayerSize: true, 245 | startLevel: 2 246 | }; 247 | if (abpinst.lastTime) { 248 | conf.startPosition = abpinst.lastTime; 249 | delete abpinst.lastTime; 250 | console.log('starting from', conf.startPosition); 251 | } 252 | /*if (isChrome && chromeVer >= 73) { 253 | conf.loader = Hls.FetchLoader; 254 | }*/ 255 | if (isChrome && location.protocol === 'https:') { 256 | conf.xhrSetup = (xhr, url) => { 257 | if (/^http:/.test(url)) { 258 | xhr.open('GET', url.replace(/http:/, 'https:'), true); 259 | //xhr.withCredentials = true; 260 | } 261 | }; 262 | } 263 | window.hlsplayer = new Hls(conf); 264 | hlsplayer.loadSource(masterManifestUrl); 265 | hlsplayer.attachMedia(abpinst.video); 266 | hlsplayer.once(Hls.Events.MANIFEST_PARSED, () => URL.revokeObjectURL(masterManifestUrl)); 267 | hlsplayer.on(Hls.Events.LEVEL_SWITCHED, () => { 268 | if (hlsPending != -1) { 269 | abpinst.createPopup(_t('switched') + ' ' + (hlsplayer.levelName[hlsPending] || hlsPending), 2e3); 270 | hlsPending = -1; 271 | } 272 | }); 273 | hlsplayer.on('hlsMIStatPercentage', function initialDisplay(m, p) { 274 | abpinst.playerUnit.querySelector('#info-box').childNodes[0].childNodes[0].textContent = ABP.Strings.buffering + ' ' + (p * 100).toFixed(2) + '%'; 275 | }); 276 | hlsplayer.on(Hls.Events.ERROR, function (n, d) { console.log(n, d); }); 277 | 278 | HlsjsMediaInfoModule.observeMediaInfo(hlsplayer); 279 | let scaleMenu = abpinst.playerUnit.querySelector('.BiliPlus-Scale-Menu'); 280 | scaleMenu.querySelector('.Video-Defination').appendChild(_('div', { 281 | changeto: JSON.stringify([-1, _t('Auto')]), 282 | name: _t('Auto'), 283 | className: 'on' 284 | }, [_('text', _t('Auto'))])); 285 | hlsplayer.levelName = playlists.map(i => { 286 | let name = (function (w) { 287 | return w > 1280 ? _t('mp4hd3') : w > 960 ? _t('mp4hd2') : w > 640 ? _t('mp4hd') : _t('flvhd'); 288 | })(i.width); 289 | scaleMenu.querySelector('.Video-Defination').appendChild(_('div', { 290 | changeto: JSON.stringify([playlists.indexOf(i), name]), 291 | name: name 292 | }, [_('text', name)])); 293 | return name; 294 | }); 295 | scaleMenu.style.width = playlists.length > 3 ? (((playlists.length + 1) * 50) + 'px') : ''; 296 | scaleMenu.style.animationName = 'scale-menu-show'; 297 | setTimeout(function () { 298 | scaleMenu.style.animationName = ''; 299 | }, 2e3); 300 | 301 | // 进度条预览 302 | { 303 | let xhr = new XMLHttpRequest; 304 | xhr.open('POST', location.origin+'/rest/pc-direct/play/playInfo/spriteVtt', true); 305 | xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); 306 | xhr.responseType = 'json'; 307 | xhr.onload = function () { 308 | let data = xhr.response; 309 | if (data.spriteVtt) { 310 | let blob = new Blob([data.spriteVtt.replace(/(\d\d:\d\d:)(\d\.\d\d\d)/g, '$10$2')], {mimeType: 'text/vtt'}); 311 | let url = URL.createObjectURL(blob); 312 | let track = abpinst.video.appendChild(_('track', { 313 | src: url, 314 | kind: 'metadata', 315 | default: '', 316 | event: { load: e => { 317 | URL.revokeObjectURL(url); 318 | let cues = Array.from(abpinst.video.textTracks[0].cues).map(c => [c.startTime, c.endTime, c.text]); 319 | track.remove(); 320 | abpinst.playerUnit.dispatchEvent(new CustomEvent('previewData', {detail: cues})); 321 | }} 322 | })); 323 | } 324 | }; 325 | xhr.onerror = function (e) { 326 | abpinst.createPopup('发送失败:' + e.message, 5e3); 327 | }; 328 | xhr.send(`videoId=${pageInfo.vid}&resourceId=${pageInfo.dougaId}&resourceType=2`); 329 | } 330 | 331 | if (user.uid === -1 || user.uid === '') { 332 | abpinst.txtText.disabled = true; 333 | abpinst.txtText.placeholder = _t('noVisitorComment'); 334 | abpinst.txtText.style.textAlign = 'center'; 335 | } 336 | if (pageInfo.album) 337 | abpinst.title = pageInfo.title + ' - AB' + pageInfo.video.part; 338 | else if (pageInfo.bangumiId) 339 | abpinst.title = pageInfo.episodeName + ' ' + pageInfo.title + ' - AB' + pageInfo.bangumiId; 340 | else if (pageInfo.videoList && pageInfo.videoList.length > 1) 341 | abpinst.title = '[P' + (pageInfo.currentVideoInfo.priority + 1) + '] ' + pageInfo.videoList[pageInfo.currentVideoInfo.priority].title + ' || ' + pageInfo.title + ' - AC' + pageInfo.dougaId; 342 | else 343 | abpinst.title = pageInfo.title + ' - AC' + pageInfo.dougaId; 344 | abpinst.playerUnit.addEventListener('sendcomment', sendComment); 345 | }; 346 | if (!isNewVersionPlayPage) playerIframe.parentNode.style.position = 'relative'; 347 | resizeSensor(playerIframe.parentNode, function () { 348 | window.dispatchEvent(new Event('resize')); 349 | if (!isNewVersionPlayPage && !playerIframe.parentNode.classList.contains('small')) { 350 | playerIframe.parentNode.style.left = ''; 351 | } 352 | }); 353 | readStorage('updateNotifyVer', function (item) { 354 | let notVer = '1.9.0'; 355 | if (item.updateNotifyVer != notVer) { 356 | saveStorage({ 'updateNotifyVer': notVer }); 357 | createPopup({ 358 | content: [ 359 | _('p', { style: { fontSize: '16px' } }, [_('text', 'AHP 最近有更新啦!')]), 360 | _('div', { style: { whiteSpace: 'pre-wrap' } }, [ 361 | _('text', '现在我们的版本是' + notVer + "\n\n更新细节:\nv1.9.0:受AcFun改版影响,此版本有如下改动:\n- flv.js核心已移除\n- 第三方源支持已全部移除\n- 新番剧将不再提供进度条预览,服务器已处理过的缩略图可正常查看") 362 | ]) 363 | ], 364 | showConfirm: false 365 | }); 366 | } 367 | }); 368 | } 369 | 370 | (function () { 371 | let noticeWidth = Math.min(500, innerWidth - 40); 372 | document.head.appendChild(_('style', {}, [_('text', `#AHP_Notice{ 373 | position:fixed;left:0;right:0;top:0;height:0;z-index:20000;transition:.5s;cursor:default;pointer-events:none 374 | } 375 | .AHP_down_banner{ 376 | margin:2px;padding:2px;color:#FFFFFF;font-size:13px;font-weight:bold;background-color:green 377 | } 378 | .AHP_down_btn{ 379 | margin:2px;padding:4px;color:#1E90FF;font-size:14px;font-weight:bold;border:#1E90FF 2px solid;display:inline-block;border-radius:5px 380 | } 381 | body.ABP-FullScreen{ 382 | overflow:hidden 383 | } 384 | @keyframes pop-iframe-in{0%{opacity:0;transform:scale(.7);}100%{opacity:1;transform:scale(1)}} 385 | @keyframes pop-iframe-out{0%{opacity:1;transform:scale(1);}100%{opacity:0;transform:scale(.7)}} 386 | #AHP_Notice>div{ 387 | position:absolute;bottom:0;left:0;right:0;font-size:15px 388 | } 389 | #AHP_Notice>div>div{ 390 | border:1px #AAA solid;width:${noticeWidth}px;margin:0 auto;padding:20px 10px 5px;background:#EFEFF4;color:#000;border-radius:5px;box-shadow:0 0 5px -2px;pointer-events:auto 391 | } 392 | #AHP_Notice>div>div *{ 393 | margin:5px 0; 394 | } 395 | #AHP_Notice input[type=text]{ 396 | border: none;border-bottom: 1px solid #AAA;width: 60%;background: transparent 397 | } 398 | #AHP_Notice input[type=text]:active{ 399 | border-bottom-color:#4285f4 400 | } 401 | #AHP_Notice input[type=button] { 402 | border-radius: 2px; 403 | border: #adadad 1px solid; 404 | padding: 3px; 405 | margin: 0 5px; 406 | width:50px 407 | } 408 | #AHP_Notice input[type=button]:hover { 409 | background: #FFF; 410 | } 411 | #AHP_Notice input[type=button]:active { 412 | background: #CCC; 413 | } 414 | .noflash-alert,.is-ie{display:none !important}`)])); 415 | let playerContainer = document.getElementById('ACPlayer'); 416 | if (playerContainer && playerContainer.children.length == 0) { 417 | playerContainer.appendChild(_('div', { id: 'ACFlashPlayer' })); 418 | } 419 | if ((dest = document.getElementById('ACFlashPlayer')) != null) { 420 | window.addEventListener('AHP_pageInfo', function pageInfoGrabber(e) { 421 | window.removeEventListener('AHP_pageInfo', pageInfoGrabber); 422 | pageInfo = e.detail.pageInfo; 423 | window.user = { 424 | uid: getCookie('auth_key'), 425 | uid_ck: getCookie('auth_key_ac_sha1'), 426 | uname: getCookie('ac_username') 427 | }; 428 | let additionStyleContent; 429 | if (document.getElementById('pageInfo') != null) { 430 | pageInfo.vid = pageInfo.videoId; 431 | additionStyleContent = '.AHP-Player-Container{width:1160px;height:730px}@media screen and (max-width: 1440px){.AHP-Player-Container{width:980px;height:628px}}.small .AHP-Player-Container{width:100%;height:100%;margin-top:26px}'; 432 | } else if (pageInfo.currentVideoInfo) { 433 | pageInfo.vid = pageInfo.currentVideoInfo.id; 434 | pageInfo.coverImage = pageInfo.image; 435 | additionStyleContent = '.AHP-Player-Container{width:1160px;height:730px}@media screen and (max-width: 1440px){.AHP-Player-Container{width:980px;height:628px}}.small .AHP-Player-Container{width:100%;height:100%;margin-top:26px}'; 436 | } else if (pageInfo.dougaId) { 437 | pageInfo.vid = pageInfo.currentVideoId; 438 | pageInfo.coverImage = pageInfo.coverUrl; 439 | additionStyleContent = '.AHP-Player-Container{width:1160px;height:730px}@media screen and (max-width: 1440px){.AHP-Player-Container{width:980px;height:628px}}.small .AHP-Player-Container{width:100%;height:100%;margin-top:26px}'; 440 | } else if (pageInfo.videoId) { 441 | pageInfo.vid = pageInfo.videoId; 442 | pageInfo.coverImage = pageInfo.coverUrl; 443 | additionStyleContent = '.AHP-Player-Container{width:1160px;height:730px}@media screen and (max-width: 1440px){.AHP-Player-Container{width:980px;height:628px}}.small .AHP-Player-Container{width:100%;height:100%;margin-top:26px}'; 444 | } else if (pageInfo.video) { 445 | pageInfo.vid = pageInfo.video.videos[0].danmakuId; 446 | pageInfo.coverImage = pageInfo.video.videos[0].image; 447 | pageInfo.title = (pageInfo.album.title + ' ' + pageInfo.video.videos[0].episodeName + ' ' + pageInfo.video.videos[0].newTitle).trim(); 448 | additionStyleContent = '.AHP-Player-Container{width:1200px;height:715px}@media screen and (max-width: 1440px){.AHP-Player-Container{width:980px;height:592px}}.small .AHP-Player-Container{width:100%;height:100%;margin-top:26px}'; 449 | } else { 450 | createPopup({ 451 | content: [ 452 | _('p', {style: {fontSize: '1.5em', fontWeight: 'bold'}}, [_('text', '错误')]), 453 | _('p', {}, [_('text', '未适配的播放页')]), 454 | _('p', {}, [_('text', '(未能找到当前播放视频信息)')]) 455 | ], 456 | showConfirm: false 457 | }) 458 | if (isBangumi) { 459 | let observer = new MutationObserver(bangumiEpisodeChange); 460 | observer.observe(document.body, { childList: true, subtree: true }); 461 | } 462 | return; 463 | } 464 | if (isNewVersionPlayPage) additionStyleContent = '.AHP-Player-Container{width:100%;height:100%}'; 465 | document.head.appendChild(_('style', {}, [_('text', additionStyleContent)])); 466 | chkInit(); 467 | }); 468 | document.head.appendChild(_('script', {}, [_('text', 'window.dispatchEvent(new CustomEvent("AHP_pageInfo", {detail:{pageInfo}}));setTimeout(function(){try{f.ready();}catch(e){}},0)')])).remove(); 469 | window.screenshotWrapperForm = document.body.appendChild(_('form', { name: 'screenshot-wrapper', style: { display: 'none' } }, [_('input', { name: 'sc_title' }), _('input', { name: 'sc_body' })])); 470 | document.head.appendChild(_('script', {}, [_('text', '(' + function () { 471 | document.querySelector('form[name="screenshot-wrapper"]').addEventListener('click', function (e) { 472 | e.preventDefault(); 473 | var newWin = window.open('about:blank'); 474 | var title = this['sc_title'].value, body = this['sc_body'].value; 475 | newWin.onload = function () { 476 | newWin.document.title = title; 477 | newWin.document.body.innerHTML = body; 478 | }; 479 | }); 480 | }.toString() + ')()')])).remove(); 481 | /* 482 | if (document.getElementById('pageInfo') != null) { 483 | //普通投稿 484 | pageInfo = Object.assign({}, (document.getElementById('pageInfo') || { dataset: {} }).dataset); 485 | 486 | init(); 487 | } else { 488 | //剧集视频 489 | }*/ 490 | } 491 | })(); 492 | window.crc_engine = () => { return ''; }; 493 | 494 | let webFullState = false; 495 | window.addEventListener('message', function (e) { 496 | if (['AHP_CrossFrame_Fullscreen_Enter', 'AHP_CrossFrame_Fullscreen_Exit'].indexOf(e.data) == -1) return; 497 | let srcFrame = Array.from(document.querySelectorAll('iframe')).find(function (i) { 498 | return i.contentWindow == e.source; 499 | }); 500 | if (srcFrame == undefined) return; 501 | if (e.data == 'AHP_CrossFrame_Fullscreen_Enter' && !webFullState) { 502 | webFullState = true; 503 | let origStat = { 504 | height: srcFrame.style.height || (srcFrame.offsetHeight + 'px'), 505 | width: srcFrame.style.width || (srcFrame.offsetWidth + 'px'), 506 | left: srcFrame.style.left, 507 | top: srcFrame.style.top, 508 | position: srcFrame.style.position, 509 | zIndex: srcFrame.style.zIndex 510 | }; 511 | srcFrame.style.zIndex = 0xffffffff; 512 | srcFrame.style.height = '100%'; 513 | srcFrame.style.width = '100%'; 514 | srcFrame.style.position = 'fixed'; 515 | srcFrame.style.left = '0'; 516 | srcFrame.style.top = '0'; 517 | srcFrame.YHP_origStat = origStat; 518 | let climb = srcFrame.parentNode; 519 | while (climb != document.body) { 520 | climb.YHP_origZIndex = climb.style.zIndex; 521 | climb.style.zIndex = 0xffffffff; 522 | climb = climb.parentNode; 523 | } 524 | } else if (e.data == 'AHP_CrossFrame_Fullscreen_Exit' && webFullState) { 525 | webFullState = false; 526 | let origStat = srcFrame.YHP_origStat; 527 | srcFrame.style.zIndex = origStat.zIndex; 528 | srcFrame.style.height = origStat.height; 529 | srcFrame.style.width = origStat.width; 530 | srcFrame.style.position = origStat.position; 531 | srcFrame.style.left = origStat.left; 532 | srcFrame.style.top = origStat.top; 533 | delete srcFrame.YHP_origStat; 534 | let climb = srcFrame.parentNode; 535 | while (climb != document.body) { 536 | if (climb.YHP_origZIndex != undefined) 537 | climb.style.zIndex = climb.YHP_origZIndex; 538 | climb = climb.parentNode; 539 | } 540 | } 541 | if (parent != window) 542 | parent.postMessage(e.data, '*'); 543 | }); 544 | 545 | let tempEvent, tempEventType; 546 | function eventPasser() { 547 | switch (tempEventType) { 548 | case 'keydown': 549 | if (tempEvent.initKeyboardEvent) { 550 | tempEvent.initKeyboardEvent('keydown', true, true, tempEvent.view, tempEvent.char, tempEvent.key, tempEvent.location, null, tempEvent.repeat); 551 | } 552 | break; 553 | } 554 | abpinst.playerUnit.dispatchEvent(tempEvent); 555 | tempEvent = null; 556 | tempEventType = ''; 557 | } 558 | window.addEventListener('keydown', function (e) { 559 | if (typeof abpinst != 'undefined' && ['input', 'textarea'].indexOf(e.target.nodeName.toLowerCase()) == -1 && e.target.getAttribute('contenteditable') != 'true') { 560 | switch (e.keyCode) { 561 | case 32: 562 | case 37: 563 | case 39: 564 | case 38: 565 | case 40: 566 | e.preventDefault(); 567 | e.stopPropagation(); 568 | tempEvent = e; 569 | tempEventType = 'keydown'; 570 | setTimeout(eventPasser, 0); 571 | break; 572 | } 573 | } 574 | }); 575 | -------------------------------------------------------------------------------- /src/CommentCoreLibrary.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * 3 | * Comment Core Library CommentManager 4 | * @license MIT 5 | * @author Jim Chen 6 | * 7 | * Copyright (c) 2014 Jim Chen 8 | * 9 | * XMLParsr 10 | * == Licensed Under the MIT License : /LICENSING 11 | * Copyright (c) 2012 Jim Chen ( CQZ, Jabbany ) 12 | */ 13 | /** 14 | * Binary Search Stubs for JS Arrays 15 | * @license MIT 16 | * @author Jim Chen 17 | */ 18 | var BinArray = (function(){ 19 | var BinArray = {}; 20 | BinArray.bsearch = function(arr, what, how){ 21 | if(arr.length === 0) { 22 | return 0; 23 | } 24 | if(how(what,arr[0]) < 0) { 25 | return 0; 26 | } 27 | if(how(what,arr[arr.length - 1]) >=0) { 28 | return arr.length; 29 | } 30 | var low =0; 31 | var i = 0; 32 | var count = 0; 33 | var high = arr.length - 1; 34 | while(low<=high){ 35 | i = Math.floor((high + low + 1)/2); 36 | count++; 37 | if(how(what,arr[i-1])>=0 && how(what,arr[i])<0){ 38 | return i; 39 | } 40 | if(how(what,arr[i-1])<0){ 41 | high = i-1; 42 | }else if(how(what,arr[i])>=0){ 43 | low = i; 44 | }else { 45 | console.error('Program Error'); 46 | } 47 | if(count > 1500) { console.error('Too many run cycles.'); } 48 | } 49 | return -1; // Never actually run 50 | }; 51 | BinArray.binsert = function(arr, what, how){ 52 | var index = BinArray.bsearch(arr,what,how); 53 | arr.splice(index,0,what); 54 | return index; 55 | }; 56 | return BinArray; 57 | })(); 58 | 59 | var __extends = (this && this.__extends) || function (d, b) { 60 | for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; 61 | function __() { this.constructor = d; } 62 | d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); 63 | }; 64 | var CommentSpaceAllocator = (function () { 65 | function CommentSpaceAllocator(width, height) { 66 | if (width === void 0) { width = 0; } 67 | if (height === void 0) { height = 0; } 68 | this._pools = [ 69 | [] 70 | ]; 71 | this.avoid = 1; 72 | this._width = width; 73 | this._height = height; 74 | this.length = 0; 75 | } 76 | CommentSpaceAllocator.prototype.willCollide = function (existing, check) { 77 | return existing.stime + existing.ttl >= check.stime + check.ttl / 2; 78 | }; 79 | CommentSpaceAllocator.prototype.pathCheck = function (y, comment, pool) { 80 | var bottom = y + comment.height; 81 | var right = comment.right; 82 | for (var i = 0; i < pool.length; i++) { 83 | if (pool[i].y > bottom || pool[i].bottom < y) { 84 | continue; 85 | } 86 | else if (pool[i].right < comment.x || pool[i].x > right) { 87 | if (this.willCollide(pool[i], comment)) { 88 | return false; 89 | } 90 | else { 91 | continue; 92 | } 93 | } 94 | else { 95 | return false; 96 | } 97 | } 98 | return true; 99 | }; 100 | CommentSpaceAllocator.prototype.assign = function (comment, cindex) { 101 | while (this._pools.length <= cindex) { 102 | this._pools.push([]); 103 | } 104 | var pool = this._pools[cindex]; 105 | if (pool.length === 0) { 106 | comment.cindex = cindex; 107 | return 0; 108 | } 109 | else if (this.pathCheck(0, comment, pool)) { 110 | comment.cindex = cindex; 111 | return 0; 112 | } 113 | var y = 0; 114 | for (var k = 0; k < pool.length; k++) { 115 | y = pool[k].bottom + this.avoid; 116 | if (y + comment.height > this._height) { 117 | break; 118 | } 119 | if (this.pathCheck(y, comment, pool)) { 120 | comment.cindex = cindex; 121 | return y; 122 | } 123 | } 124 | return this.assign(comment, cindex + 1); 125 | }; 126 | CommentSpaceAllocator.prototype.add = function (comment) { 127 | this.length++; 128 | if (comment.height > this._height) { 129 | comment.cindex = -2; 130 | comment.y = 0; 131 | } 132 | else { 133 | comment.y = this.assign(comment, 0); 134 | BinArray.binsert(this._pools[comment.cindex], comment, function (a, b) { 135 | if (a.bottom < b.bottom) { 136 | return -1; 137 | } 138 | else if (a.bottom > b.bottom) { 139 | return 1; 140 | } 141 | else { 142 | return 0; 143 | } 144 | }); 145 | } 146 | }; 147 | CommentSpaceAllocator.prototype.remove = function (comment) { 148 | if (comment.cindex < 0) { 149 | return; 150 | } 151 | if (comment.cindex >= this._pools.length) { 152 | console.log(comment.cindex,comment); 153 | throw new Error("cindex out of bounds"); 154 | } 155 | var index = this._pools[comment.cindex].indexOf(comment); 156 | if (index < 0) 157 | return; 158 | this._pools[comment.cindex].splice(index, 1); 159 | this.length--; 160 | }; 161 | CommentSpaceAllocator.prototype.setBounds = function (width, height) { 162 | this._width = width; 163 | this._height = height; 164 | }; 165 | return CommentSpaceAllocator; 166 | }()); 167 | var AnchorCommentSpaceAllocator = (function (_super) { 168 | __extends(AnchorCommentSpaceAllocator, _super); 169 | function AnchorCommentSpaceAllocator() { 170 | _super.apply(this, arguments); 171 | } 172 | AnchorCommentSpaceAllocator.prototype.add = function (comment) { 173 | _super.prototype.add.call(this, comment); 174 | comment.x = (this._width - comment.width) / 2; 175 | }; 176 | AnchorCommentSpaceAllocator.prototype.willCollide = function (a, b) { 177 | return true; 178 | }; 179 | AnchorCommentSpaceAllocator.prototype.pathCheck = function (y, comment, pool) { 180 | var bottom = y + comment.height; 181 | for (var i = 0; i < pool.length; i++) { 182 | if (pool[i].y > bottom || pool[i].bottom < y) { 183 | continue; 184 | } 185 | else { 186 | return false; 187 | } 188 | } 189 | return true; 190 | }; 191 | return AnchorCommentSpaceAllocator; 192 | }(CommentSpaceAllocator)); 193 | 194 | var CoreComment = (function () { 195 | function CoreComment(parent, init) { 196 | if (init === void 0) { init = {}; } 197 | this.mode = 1; 198 | this.stime = 0; 199 | this.text = ""; 200 | this.ttl = 4000; 201 | this.dur = 4000; 202 | this.cindex = -1; 203 | this.motion = []; 204 | this.movable = true; 205 | this._alphaMotion = null; 206 | this.absolute = true; 207 | this.align = 0; 208 | this._alpha = 1; 209 | this._size = 25; 210 | this._color = 0xffffff; 211 | this._border = false; 212 | this._shadow = true; 213 | this._font = ""; 214 | if (!parent) { 215 | throw new Error("Comment not bound to comment manager."); 216 | } 217 | else { 218 | this.parent = parent; 219 | } 220 | if (init.hasOwnProperty("stime")) { 221 | this.stime = init["stime"]; 222 | } 223 | if (init.hasOwnProperty("mode")) { 224 | this.mode = init["mode"]; 225 | } 226 | else { 227 | this.mode = 1; 228 | } 229 | if (init.hasOwnProperty("dur")) { 230 | this.dur = init["dur"]; 231 | this.ttl = this.dur; 232 | } 233 | this.dur *= this.parent.options.global.scale; 234 | this.ttl *= this.parent.options.global.scale; 235 | if( this.mode === 4 || this.mode === 5 ){ 236 | this.dur *= .6; 237 | this.ttl *= .6; 238 | } 239 | if (init.hasOwnProperty("text")) { 240 | this.text = init["text"]; 241 | } 242 | if (init.hasOwnProperty("filteredText")) { 243 | this.text = init["filteredText"]; 244 | } 245 | if (init.hasOwnProperty("motion")) { 246 | this._motionStart = []; 247 | this._motionEnd = []; 248 | this.motion = init["motion"]; 249 | var head = 0; 250 | for (var i = 0; i < init["motion"].length; i++) { 251 | this._motionStart.push(head); 252 | var maxDur = 0; 253 | for (var k in init["motion"][i]) { 254 | var m = init["motion"][i][k]; 255 | maxDur = Math.max(m.dur, maxDur); 256 | if (m.easing === null || m.easing === undefined) { 257 | init["motion"][i][k]["easing"] = CoreComment.LINEAR; 258 | } 259 | } 260 | head += maxDur; 261 | this._motionEnd.push(head); 262 | } 263 | this._curMotion = 0; 264 | } 265 | if (init.hasOwnProperty("color")) { 266 | this._color = init["color"]; 267 | } 268 | if (init.hasOwnProperty("size")) { 269 | this._size = init["size"]; 270 | } 271 | if (init.hasOwnProperty("border")) { 272 | this._border = init["border"]; 273 | } 274 | if (init.hasOwnProperty("opacity")) { 275 | this._alpha = init["opacity"]; 276 | } 277 | if (init.hasOwnProperty("alpha")) { 278 | this._alphaMotion = init["alpha"]; 279 | } 280 | if (init.hasOwnProperty("font")) { 281 | this._font = init["font"]; 282 | } 283 | if (init.hasOwnProperty("x")) { 284 | this._x = init["x"]; 285 | } 286 | if (init.hasOwnProperty("y")) { 287 | this._y = init["y"]; 288 | } 289 | if (init.hasOwnProperty("shadow")) { 290 | this._shadow = init["shadow"]; 291 | } 292 | if (init.hasOwnProperty("position")) { 293 | if (init["position"] === "relative") { 294 | this.absolute = false; 295 | if (this.mode < 7) { 296 | console.warn("Using relative position for CSA comment."); 297 | } 298 | } 299 | } 300 | } 301 | CoreComment.prototype.init = function (recycle) { 302 | if (recycle === void 0) { recycle = null; } 303 | if (recycle !== null) { 304 | this.dom = recycle.dom; 305 | } 306 | else { 307 | this.dom = document.createElement("div"); 308 | } 309 | this.dom.className = this.parent.options.global.className; 310 | this.parent.options.global.outline && this.dom.classList.add('outline'); 311 | this.parent.options.global.shadow && this.dom.classList.add('shadow'); 312 | this.dom.appendChild(document.createTextNode(this.text)); 313 | this.dom.textContent = this.text; 314 | this.dom.innerText = this.text; 315 | this.size = this._size; 316 | if (this._color != 0xffffff) { 317 | this.color = this._color; 318 | } 319 | this.shadow = this._shadow; 320 | if (this._border) { 321 | this.border = this._border; 322 | } 323 | if (this._font !== "") { 324 | this.font = this._font; 325 | } 326 | if (this._x !== undefined) { 327 | this.x = this._x; 328 | } 329 | if (this._y !== undefined) { 330 | this.y = this._y; 331 | } 332 | if (this._alpha !== 1 || this.parent.options.global.opacity < 1) { 333 | this.alpha = this._alpha; 334 | } 335 | if (this.motion.length > 0) { 336 | this.animate(); 337 | } 338 | }; 339 | Object.defineProperty(CoreComment.prototype, "x", { 340 | get: function () { 341 | if (this._x === null || this._x === undefined) { 342 | if (this.align % 2 === 0) { 343 | this._x = this.dom.offsetLeft; 344 | } 345 | else { 346 | this._x = this.parent.width - this.dom.offsetLeft - this.width; 347 | } 348 | } 349 | if (!this.absolute) { 350 | return this._x / this.parent.width; 351 | } 352 | return this._x; 353 | }, 354 | set: function (x) { 355 | this._x = x; 356 | if (!this.absolute) { 357 | this._x *= this.parent.width; 358 | } 359 | if (this.align % 2 === 0) { 360 | this.dom.style.left = this._x + "px"; 361 | } 362 | else { 363 | this.dom.style.right = this._x + "px"; 364 | } 365 | }, 366 | enumerable: true, 367 | configurable: true 368 | }); 369 | Object.defineProperty(CoreComment.prototype, "y", { 370 | get: function () { 371 | if (this._y === null || this._y === undefined) { 372 | if (this.align < 2) { 373 | this._y = this.dom.offsetTop; 374 | } 375 | else { 376 | this._y = this.parent.height - this.dom.offsetTop - this.height; 377 | } 378 | } 379 | if (!this.absolute) { 380 | return this._y / this.parent.height; 381 | } 382 | return this._y; 383 | }, 384 | set: function (y) { 385 | this._y = y; 386 | if (!this.absolute) { 387 | this._y *= this.parent.height; 388 | } 389 | if (this.align < 2) { 390 | this.dom.style.top = this._y + "px"; 391 | } 392 | else { 393 | this.dom.style.bottom = this._y + "px"; 394 | } 395 | }, 396 | enumerable: true, 397 | configurable: true 398 | }); 399 | Object.defineProperty(CoreComment.prototype, "bottom", { 400 | get: function () { 401 | return this.y + this.height; 402 | }, 403 | enumerable: true, 404 | configurable: true 405 | }); 406 | Object.defineProperty(CoreComment.prototype, "right", { 407 | get: function () { 408 | return this.x + this.width; 409 | }, 410 | enumerable: true, 411 | configurable: true 412 | }); 413 | Object.defineProperty(CoreComment.prototype, "width", { 414 | get: function () { 415 | if (this._width === null || this._width === undefined) { 416 | this._width = this.dom.offsetWidth; 417 | } 418 | return this._width; 419 | }, 420 | set: function (w) { 421 | this._width = w; 422 | this.dom.style.width = this._width + "px"; 423 | }, 424 | enumerable: true, 425 | configurable: true 426 | }); 427 | Object.defineProperty(CoreComment.prototype, "height", { 428 | get: function () { 429 | if (this._height === null || this._height === undefined) { 430 | this._height = this.dom.offsetHeight; 431 | } 432 | return this._height; 433 | }, 434 | set: function (h) { 435 | this._height = h; 436 | this.dom.style.height = this._height + "px"; 437 | }, 438 | enumerable: true, 439 | configurable: true 440 | }); 441 | Object.defineProperty(CoreComment.prototype, "size", { 442 | get: function () { 443 | return this._size; 444 | }, 445 | set: function (s) { 446 | this._size = s; 447 | this.dom.style.fontSize = this._size + "px"; 448 | }, 449 | enumerable: true, 450 | configurable: true 451 | }); 452 | Object.defineProperty(CoreComment.prototype, "color", { 453 | get: function () { 454 | return this._color; 455 | }, 456 | set: function (c) { 457 | this._color = c; 458 | var color = c.toString(16); 459 | color = color.length >= 6 ? color : new Array(6 - color.length + 1).join("0") + color; 460 | this.dom.style.color = "#" + color; 461 | if (this._color === 0) { 462 | this.dom.classList.add("rshadow"); 463 | } 464 | }, 465 | enumerable: true, 466 | configurable: true 467 | }); 468 | Object.defineProperty(CoreComment.prototype, "alpha", { 469 | get: function () { 470 | return this._alpha; 471 | }, 472 | set: function (a) { 473 | this._alpha = a; 474 | this.dom.style.opacity = Math.min(this._alpha, this.parent.options.global.opacity) + ""; 475 | }, 476 | enumerable: true, 477 | configurable: true 478 | }); 479 | Object.defineProperty(CoreComment.prototype, "border", { 480 | get: function () { 481 | return this._border; 482 | }, 483 | set: function (b) { 484 | this._border = b; 485 | if (this._border) { 486 | this.dom.style.border = "1px solid #00ffff"; 487 | } 488 | else { 489 | this.dom.style.border = "none"; 490 | } 491 | }, 492 | enumerable: true, 493 | configurable: true 494 | }); 495 | Object.defineProperty(CoreComment.prototype, "shadow", { 496 | get: function () { 497 | return this._shadow; 498 | }, 499 | set: function (s) { 500 | this._shadow = s; 501 | if (!this._shadow) { 502 | this.dom.className = this.parent.options.global.className + " noshadow"; 503 | } 504 | }, 505 | enumerable: true, 506 | configurable: true 507 | }); 508 | Object.defineProperty(CoreComment.prototype, "font", { 509 | get: function () { 510 | return this._font; 511 | }, 512 | set: function (f) { 513 | this._font = f; 514 | if (this._font.length > 0) { 515 | this.dom.style.fontFamily = this._font; 516 | } 517 | else { 518 | this.dom.style.fontFamily = ""; 519 | } 520 | }, 521 | enumerable: true, 522 | configurable: true 523 | }); 524 | CoreComment.prototype.time = function (time) { 525 | this.ttl -= time; 526 | if (this.ttl < 0) { 527 | this.ttl = 0; 528 | } 529 | if (this.movable) { 530 | this.update(); 531 | } 532 | if (this.ttl <= 0) { 533 | this.finish(); 534 | } 535 | }; 536 | CoreComment.prototype.update = function () { 537 | this.animate(); 538 | }; 539 | CoreComment.prototype.invalidate = function () { 540 | this._x = null; 541 | this._y = null; 542 | this._width = null; 543 | this._height = null; 544 | }; 545 | CoreComment.prototype._execMotion = function (currentMotion, time) { 546 | for (var prop in currentMotion) { 547 | if (currentMotion.hasOwnProperty(prop)) { 548 | var m = currentMotion[prop]; 549 | this[prop] = m.easing(Math.min(Math.max(time - m.delay, 0), m.dur), m.from, m.to - m.from, m.dur); 550 | } 551 | } 552 | }; 553 | CoreComment.prototype.animate = function () { 554 | if (this._alphaMotion) { 555 | this.alpha = (this.dur - this.ttl) * (this._alphaMotion["to"] - this._alphaMotion["from"]) / this.dur + this._alphaMotion["from"]; 556 | } 557 | if (this.motion.length === 0) { 558 | return; 559 | } 560 | var ttl = Math.max(this.ttl, 0); 561 | var time = (this.dur - ttl) - this._motionStart[this._curMotion]; 562 | this._execMotion(this.motion[this._curMotion], time); 563 | if (this.dur - ttl > this._motionEnd[this._curMotion]) { 564 | this._curMotion++; 565 | if (this._curMotion >= this.motion.length) { 566 | this._curMotion = this.motion.length - 1; 567 | } 568 | return; 569 | } 570 | }; 571 | CoreComment.prototype.stop = function () { 572 | }; 573 | CoreComment.prototype.finish = function () { 574 | this.parent.finish(this); 575 | }; 576 | CoreComment.prototype.toString = function () { 577 | return ["[", this.stime, "|", this.ttl, "/", this.dur, "]", "(", this.mode, ")", this.text].join(""); 578 | }; 579 | CoreComment.LINEAR = function (t, b, c, d) { 580 | return t * c / d + b; 581 | }; 582 | return CoreComment; 583 | }()); 584 | var ScrollComment = (function (_super) { 585 | __extends(ScrollComment, _super); 586 | function ScrollComment(parent, data) { 587 | _super.call(this, parent, data); 588 | this.dur *= this.parent.options.scroll.scale; 589 | this.ttl *= this.parent.options.scroll.scale; 590 | } 591 | Object.defineProperty(ScrollComment.prototype, "alpha", { 592 | set: function (a) { 593 | this._alpha = a; 594 | this.dom.style.opacity = Math.min(Math.min(this._alpha, this.parent.options.global.opacity), this.parent.options.scroll.opacity) + ""; 595 | }, 596 | enumerable: true, 597 | configurable: true 598 | }); 599 | ScrollComment.prototype.init = function (recycle) { 600 | if (recycle === void 0) { recycle = null; } 601 | _super.prototype.init.call(this, recycle); 602 | this.x = this.parent.width; 603 | if (this.parent.options.scroll.opacity < 1) { 604 | this.alpha = this._alpha; 605 | } 606 | this.absolute = true; 607 | }; 608 | ScrollComment.prototype.update = function () { 609 | this.x = (this.ttl / this.dur) * (this.parent.width + this.width) - this.width; 610 | }; 611 | return ScrollComment; 612 | }(CoreComment)); 613 | var CSSCompatLayer = (function () { 614 | function CSSCompatLayer() { 615 | } 616 | CSSCompatLayer.transform = function (dom, trans) { 617 | dom.style.transform = trans; 618 | dom.style["webkitTransform"] = trans; 619 | dom.style["msTransform"] = trans; 620 | dom.style["oTransform"] = trans; 621 | }; 622 | return CSSCompatLayer; 623 | }()); 624 | var CSSScrollComment = (function (_super) { 625 | __extends(CSSScrollComment, _super); 626 | function CSSScrollComment() { 627 | _super.apply(this, arguments); 628 | this._dirtyCSS = true; 629 | } 630 | Object.defineProperty(CSSScrollComment.prototype, "x", { 631 | get: function () { 632 | return (this.ttl / this.dur) * (this.parent.width + this.width) - this.width; 633 | }, 634 | set: function (x) { 635 | if (typeof this._x === "number") { 636 | var dx = x - this._x; 637 | this._x = x; 638 | CSSCompatLayer.transform(this.dom, "translateX(" + dx + "px)"); 639 | } 640 | else { 641 | this._x = x; 642 | if (!this.absolute) { 643 | this._x *= this.parent.width; 644 | } 645 | if (this.align % 2 === 0) { 646 | this.dom.style.left = this._x + "px"; 647 | } 648 | else { 649 | this.dom.style.right = this._x + "px"; 650 | } 651 | } 652 | }, 653 | enumerable: true, 654 | configurable: true 655 | }); 656 | CSSScrollComment.prototype.update = function () { 657 | if (this._dirtyCSS) { 658 | this.dom.style.transition = "transform " + this.ttl + "ms linear"; 659 | this.x = -this.width; 660 | this._dirtyCSS = false; 661 | } 662 | }; 663 | CSSScrollComment.prototype.invalidate = function () { 664 | _super.prototype.invalidate.call(this); 665 | this._dirtyCSS = true; 666 | }; 667 | CSSScrollComment.prototype.stop = function () { 668 | this.dom.style.transition = ""; 669 | this.x = this._x; 670 | this._x = null; 671 | this.x = (this.ttl / this.dur) * (this.parent.width + this.width) - this.width; 672 | this._dirtyCSS = true; 673 | }; 674 | return CSSScrollComment; 675 | }(ScrollComment)); 676 | 677 | /** 678 | * Comment Filters Module Simplified (only supports modifiers & types) 679 | * @license MIT 680 | * @author Jim Chen 681 | */ 682 | function CommentFilter(){ 683 | this.modifiers = []; 684 | this.runtime = null; 685 | this.allowTypes = { 686 | "1":true, 687 | "4":true, 688 | "5":true, 689 | "6":true, 690 | "7":true, 691 | "8":true, 692 | "17":true 693 | }; 694 | this.doModify = function(cmt){ 695 | for(var k=0;k 0) 803 | return; 804 | var lastTPos = new Date().getTime(); 805 | var cmMgr = this; 806 | __timer = window.setInterval(function(){ 807 | var elapsed = new Date().getTime() - lastTPos; 808 | lastTPos = new Date().getTime(); 809 | cmMgr.onTimerEvent(elapsed,cmMgr); 810 | cmMgr.sendQueueLoader(); 811 | },1e3/60); 812 | this.paused = false; 813 | this.pausedTime = Date.now() - pauseTime; 814 | }; 815 | this.stopTimer = function(){ 816 | window.clearInterval(__timer); 817 | __timer = 0; 818 | this.paused = true; 819 | pauseTime = Date.now(); 820 | }; 821 | var prevOpacity = this.options.global.opacity, 822 | ticking=false, 823 | canvasFPS=0, 824 | onScreenCommentCount=0, 825 | autoOpacity = function(){ 826 | if(self.options.global.autoOpacity){ 827 | if(self.options.global.useCSS){ 828 | self.stage.style.opacity = autoOpacityFromComment(onScreenCommentCount); 829 | }else{ 830 | self.options.global.autoOpacityVal = self.options.global.opacity * autoOpacityFromComment(onScreenCommentCount); 831 | } 832 | } 833 | }; 834 | setInterval(function(){ 835 | self.canvasFPS = canvasFPS; 836 | canvasFPS = 0; 837 | },1e3); 838 | this.addEventListener('enterComment',function(){ 839 | onScreenCommentCount++; 840 | autoOpacity(); 841 | }); 842 | this.addEventListener('exitComment',function(){ 843 | onScreenCommentCount--; 844 | autoOpacity(); 845 | }); 846 | this.canvasDrawerWrapper = function(now){ 847 | if(ticking)return; 848 | if(!now)now=performance.now(); 849 | ticking=true; 850 | canvasFPS++; 851 | self.canvasDrawer(now|0); 852 | ticking=false; 853 | }; 854 | this.ttlRecalcAll=function(){ 855 | this.runline.forEach(ttlRecalc); 856 | }; 857 | var sendQueue=[]; 858 | this.send = function(data){ 859 | sendQueue.push(data); 860 | } 861 | this.sendQueueLoader = function(){ 862 | var start = performance.now(),passed; 863 | sendQueue.length && self.sendAsync(sendQueue.shift()); 864 | /*while(sendQueue.length > 0){ 865 | self.sendAsync(sendQueue.shift()); 866 | passed = performance.now()-start; 867 | if(passed > 5) 868 | return; 869 | }*/ 870 | } 871 | this.addEventListener('clear',function(){ 872 | sendQueue=[]; 873 | }); 874 | 875 | requestAnimationFrame(this.canvasDrawerWrapper); 876 | (function(){ 877 | var prevRatio = window.devicePixelRatio; 878 | window.addEventListener('resize',function(){ 879 | var ratio = window.devicePixelRatio; 880 | if(prevRatio != ratio){ 881 | self.runline.forEach(function(i){ 882 | if(i.textData) 883 | commentCanvasDrawer(i, self.options.global.outline, self.options.global.shadow) 884 | }) 885 | prevRatio = ratio; 886 | } 887 | self.ttlRecalcAll(); 888 | }) 889 | })() 890 | } 891 | 892 | /** Public **/ 893 | CommentManager.prototype.stop = function(){ 894 | this.stopTimer(); 895 | for(var i = 0; i < this.runline.length; i++){ 896 | if(typeof this.runline[i].stop !== "undefined"){ 897 | this.runline[i].stop(); 898 | } 899 | } 900 | }; 901 | 902 | CommentManager.prototype.start = function(){ 903 | this.startTimer(); 904 | }; 905 | 906 | CommentManager.prototype.seek = function(time){ 907 | this.position = BinArray.bsearch(this.timeline, time, function(a,b){ 908 | if(a < b.stime) return -1 909 | else if(a > b.stime) return 1; 910 | else return 0; 911 | }); 912 | }; 913 | 914 | CommentManager.prototype.validate = function(cmt){ 915 | if(cmt == null) 916 | return false; 917 | return this.filter.doValidate(cmt); 918 | }; 919 | 920 | CommentManager.prototype.load = function(a){ 921 | this.timeline = a; 922 | this.timeline.sort(function(a,b){ 923 | if(a.stime > b.stime) return 2; 924 | else if(a.stime < b.stime) return -2; 925 | else{ 926 | if(a.date > b.date) return 1; 927 | else if(a.date < b.date) return -1; 928 | else if(a.dbid != null && b.dbid != null){ 929 | if(a.dbid > b.dbid) return 1; 930 | else if(a.dbid < b.dbid) return -1; 931 | return 0; 932 | }else 933 | return 0; 934 | } 935 | }); 936 | this.dispatchEvent("load"); 937 | }; 938 | 939 | CommentManager.prototype.insert = function(c){ 940 | var index = BinArray.binsert(this.timeline, c, function(a,b){ 941 | if(a.stime > b.stime) return 2; 942 | else if(a.stime < b.stime) return -2; 943 | else{ 944 | if(a.date > b.date) return 1; 945 | else if(a.date < b.date) return -1; 946 | else if(a.dbid != null && b.dbid != null){ 947 | if(a.dbid > b.dbid) return 1; 948 | else if(a.dbid < b.dbid) return -1; 949 | return 0; 950 | }else 951 | return 0; 952 | } 953 | }); 954 | if(index <= this.position){ 955 | this.position++; 956 | } 957 | this.dispatchEvent("insert"); 958 | }; 959 | 960 | CommentManager.prototype.clear = function(){ 961 | while(this.runline.length > 0){ 962 | this.runline[0].finish(); 963 | } 964 | this.dispatchEvent("clear"); 965 | this.canvas.getContext('2d').clearRect(0,0,this.canvas.width,this.canvas.height); 966 | }; 967 | 968 | CommentManager.prototype.setBounds = function(){ 969 | this.width = this.stage.offsetWidth; 970 | this.height= this.stage.offsetHeight; 971 | this.dispatchEvent("resize"); 972 | for(var comAlloc in this.csa){ 973 | this.csa[comAlloc].setBounds(this.width,this.height); 974 | } 975 | // Update 3d perspective 976 | this.stage.style.perspective = this.width * Math.tan(40 * Math.PI/180) / 2 + "px"; 977 | this.stage.style.webkitPerspective = this.width * Math.tan(40 * Math.PI/180) / 2 + "px"; 978 | this.canvasResize(); 979 | }; 980 | CommentManager.prototype.init = function(){ 981 | this.setBounds(); 982 | if(this.filter == null) { 983 | this.filter = new CommentFilter(); //Only create a filter if none exist 984 | } 985 | }; 986 | CommentManager.prototype.time = function(time){ 987 | time = time - 1; 988 | if(this.position >= this.timeline.length || Math.abs(this._lastPosition - time) >= 2000){ 989 | this.seek(time); 990 | this._lastPosition = time; 991 | if(this.timeline.length <= this.position) { 992 | return; 993 | } 994 | }else{ 995 | this._lastPosition = time; 996 | } 997 | for(;this.position < this.timeline.length;this.position++){ 998 | if(this.timeline[this.position]['stime']<=time){ 999 | if(this.options.limit > 0 && this.runline.length > this.limiter) { 1000 | continue; // Skip comments but still move the position pointer 1001 | } else if(this.validate(this.timeline[this.position])){ 1002 | this.send(this.timeline[this.position]); 1003 | } 1004 | }else{ 1005 | break; 1006 | } 1007 | } 1008 | }; 1009 | CommentManager.prototype.canvasResize = function(){ 1010 | try{ 1011 | var w=this.width,h=this.height,devicePixelRatio=window.devicePixelRatio; 1012 | this.canvas.width = this.canvas.offsetWidth * devicePixelRatio; 1013 | this.canvas.height = this.canvas.offsetHeight * devicePixelRatio; 1014 | this.ttlRecalcAll(); 1015 | drawForResize = true; 1016 | 1017 | }catch(e){ 1018 | console.error('shit happened! forcing CSS! ',e.message); 1019 | this.useCSS(true); 1020 | return; 1021 | } 1022 | }; 1023 | var drawForResize = false; 1024 | CommentManager.prototype.canvasDrawer = function(){ 1025 | if(this.options.global.useCSS){ 1026 | return; 1027 | } 1028 | if(this.paused && !drawForResize){ 1029 | requestAnimationFrame(this.canvasDrawerWrapper); 1030 | return; 1031 | } 1032 | var now=performance.now()|0, cmt, i, devicePixelRatio = window.devicePixelRatio, pausedTime = this.pausedTime, 1033 | ctx = this.canvas.getContext('2d'), 1034 | canvasWidth = this.width, canvasHeight = this.height, 1035 | x, y; 1036 | ctx.clearRect(0, 0, canvasWidth * devicePixelRatio, canvasHeight * devicePixelRatio); 1037 | ctx.globalAlpha=this.options.global.autoOpacity ? this.options.global.autoOpacityVal : this.options.global.opacity; 1038 | ctx.imageSmoothingEnabled = false; 1039 | 1040 | if(pausedTime!=0){ 1041 | this.runline.forEach(function(cmt){ 1042 | if(!cmt.textData)return; 1043 | switch(cmt.mode){ 1044 | case 1: 1045 | cmt.prev += pausedTime; 1046 | break; 1047 | case 4: 1048 | case 5: 1049 | cmt.removeTime += pausedTime; 1050 | break; 1051 | } 1052 | }) 1053 | this.pausedTime = 0; 1054 | } 1055 | 1056 | var devicePixelRatio = window.devicePixelRatio; 1057 | /* 1058 | maxBottomLine=[0]; 1059 | maxBottomMaxWidth=[0], 1060 | maxBottomHeight=[0], 1061 | maxTopMaxWidth=[0], 1062 | maxTopHeight=[0]; 1063 | this.runline.forEach(function(cmt){ 1064 | if(cmt.mode==1){ 1065 | maxBottomLine.push(cmt._y+cmt._height); 1066 | } else if(cmt.mode == 4){ 1067 | maxBottomMaxWidth.push(cmt._width); 1068 | maxBottomHeight.push(cmt._y+cmt._height); 1069 | } else if(cmt.mode == 5) { 1070 | maxTopMaxWidth.push(cmt._width); 1071 | maxTopHeight.push(cmt._y+cmt._height); 1072 | } 1073 | }); 1074 | maxBottomLine=Math.max.apply(Math,maxBottomLine); 1075 | maxBottomMaxWidth=Math.max.apply(Math,maxBottomMaxWidth); 1076 | maxBottomHeight=Math.max.apply(Math,maxBottomHeight); 1077 | maxTopMaxWidth=Math.max.apply(Math,maxTopMaxWidth); 1078 | maxTopHeight=Math.max.apply(Math,maxTopHeight);*/ 1079 | 1080 | //canvasDraw(this); 1081 | /** 1082 | * 180303 1083 | * canvas重构 1084 | * 恢复全屏canvas 1085 | * 记录顶部高度进行部分擦除 1086 | * 0,0 到 width,滚动高 1087 | * 顶宽左,滚动高 到 顶宽右,顶高 (范围内不擦除) 1088 | * 底宽左,高-底高 到 底宽右,高 (范围按滚动高改动) 1089 | */ 1090 | /* 1091 | if(cachedMaxBottomLine > 0){ 1092 | ctx.clearRect(0, 0, round(canvasWidth * devicePixelRatio), round(cachedMaxBottomLine * devicePixelRatio)); 1093 | } 1094 | if(cachedFixedTopHeight>cachedMaxBottomLine) { 1095 | ctx.clearRect( 1096 | round((canvasWidth-cachedFixedTopMaxWidth)/2 * devicePixelRatio), 1097 | round(cachedMaxBottomLine * devicePixelRatio), 1098 | round((canvasWidth+cachedFixedTopMaxWidth)/2 * devicePixelRatio), 1099 | round(cachedFixedTopHeight * devicePixelRatio) 1100 | ); 1101 | } 1102 | ctx.clearRect( 1103 | round((canvasWidth-cachedFixedBottomMaxWidth)/2 * devicePixelRatio), 1104 | round((Math.max(canvasHeight-cachedFixedBottomHeight, cachedMaxBottomLine)) * devicePixelRatio), 1105 | round((canvasWidth+cachedFixedBottomMaxWidth)/2 * devicePixelRatio), 1106 | round(canvasHeight * devicePixelRatio) 1107 | ); 1108 | cachedMaxBottomLine=maxBottomLine; 1109 | cachedFixedBottomMaxWidth=maxBottomMaxWidth; 1110 | cachedFixedBottomHeight=maxBottomHeight; 1111 | cachedFixedTopMaxWidth=maxTopMaxWidth; 1112 | cachedFixedTopHeight=maxTopHeight; 1113 | */ 1114 | 1115 | //ctx.globalAlpha = 1; 1116 | //ctx.drawImage(window.abpinst.video, 0, 0); 1117 | 1118 | var cmMgr=this; 1119 | 1120 | ctx.globalAlpha=cmMgr.options.global.autoOpacity ? cmMgr.options.global.autoOpacityVal : cmMgr.options.global.opacity; 1121 | cmMgr.runline.forEach(function(cmt){ 1122 | if(!cmt.textData)return; 1123 | switch(cmt.mode){ 1124 | case 1: 1125 | //scroll 1126 | if (!drawForResize) { 1127 | cmt.rx += cmt.speed * ( now - cmt.prev ) / 1e3; 1128 | cmt.prev = now; 1129 | cmt.x = canvasWidth - cmt.rx; 1130 | } 1131 | x = (canvasWidth - cmt.rx); 1132 | y = cmt.y; 1133 | break; 1134 | case 4: 1135 | //bottom 1136 | cmt.x = (canvasWidth - cmt.width) / 2; 1137 | x = cmt.x; 1138 | y = (canvasHeight - cmt.y - cmt.height); 1139 | break; 1140 | case 5: 1141 | //top 1142 | cmt.x = (canvasWidth - cmt.width) / 2; 1143 | x = cmt.x; 1144 | y = (cmt.y); 1145 | break; 1146 | default: 1147 | return; 1148 | } 1149 | ctx.drawImage(cmt.textData, round(x * devicePixelRatio), round(y * devicePixelRatio)); 1150 | }); 1151 | //this.canvas.style.opacity = this.options.global.opacity; 1152 | //this.canvas.getContext('2d').putImageData(ctx.getImageData(0, 0, this.canvas.width, this.canvas.height), 0, 0) 1153 | drawForResize = false; 1154 | requestAnimationFrame(this.canvasDrawerWrapper); 1155 | }; 1156 | var prevMoving=false,ceil=Math.ceil,round=Math.round,colorGetter = function(color){ 1157 | var color = color.toString(16); 1158 | while(color.length<6) 1159 | color = '0'+color; 1160 | return color; 1161 | /* 1162 | var r = (color >>> 16), 1163 | g = (color >>> 8) & 0xff, 1164 | b = color & 0xff; 1165 | return [r,g,b];*/ 1166 | },ttlRecalc=function(cmt){ 1167 | if(cmt.speed){ 1168 | var runned = cmt.dur - cmt.ttl; 1169 | cmt.dur = ( cmt.parent.width + cmt.width ) / cmt.speed * 1e3; 1170 | cmt.ttl = cmt.dur - runned; 1171 | } 1172 | },commentCanvasDrawer = function(cmt, outline, shadow){ 1173 | var commentCanvas = document.createElement('canvas'), commentCanvasCtx = commentCanvas.getContext('2d'), devicePixelRatio = window.devicePixelRatio; 1174 | commentCanvas.width = 1; 1175 | commentCanvas.height = 1; 1176 | commentCanvasCtx.font = 'bold '+ (cmt.size * devicePixelRatio) + 'px ' + font; 1177 | commentCanvasCtx.imageSmoothingEnabled = false; 1178 | cmt.width = ceil(commentCanvasCtx.measureText(cmt.text).width / devicePixelRatio)+2; 1179 | cmt.height = ceil(cmt.size+3)+2; 1180 | cmt.oriWidth = ceil(cmt.width * devicePixelRatio); 1181 | cmt.oriHeight = ceil(cmt.height * devicePixelRatio); 1182 | 1183 | commentCanvas.width = cmt.oriWidth; 1184 | commentCanvas.height = cmt.oriHeight; 1185 | commentCanvasCtx.font = 'bold '+ (cmt.size * devicePixelRatio) + 'px ' + font; 1186 | commentCanvasCtx.lineWidth = .7 * devicePixelRatio; 1187 | commentCanvasCtx.strokeStyle = (cmt._color == 0) ? '#FFFFFF' : '#000000'; 1188 | commentCanvasCtx.textBaseline = 'bottom'; 1189 | commentCanvasCtx.textAlign = 'left'; 1190 | 1191 | if(shadow) { 1192 | commentCanvasCtx.lineWidth = .25 * devicePixelRatio; 1193 | commentCanvasCtx.shadowBlur = 2 * devicePixelRatio; 1194 | commentCanvasCtx.shadowColor = (cmt._color == 0) ? '#FFFFFF' : '#000000'; 1195 | } 1196 | commentCanvasCtx.fillStyle = '#' + colorGetter(cmt.color); 1197 | commentCanvasCtx.fillText(cmt.text, 1, commentCanvas.height-1); 1198 | if (outline) 1199 | commentCanvasCtx.strokeText(cmt.text, 1, commentCanvas.height-1); 1200 | 1201 | if(cmt.border){ 1202 | commentCanvasCtx.lineWidth = round(2 * devicePixelRatio); 1203 | commentCanvasCtx.strokeStyle = '#00ffff'; 1204 | commentCanvasCtx.shadowBlur = 0; 1205 | commentCanvasCtx.strokeRect(0,0,commentCanvas.width,commentCanvas.height); 1206 | } 1207 | cmt.textData = commentCanvas; 1208 | }; 1209 | CommentManager.prototype.getCommentFromPoint = function(x, y){ 1210 | var dmList=[],dx,dy,height=this.height; 1211 | this.runline.forEach(function(i){ 1212 | dx=x-i.x; 1213 | if(i.mode==4){ 1214 | dy=y-(height-i.y-i.height); 1215 | }else 1216 | dy=y-i.y; 1217 | if(dx>=0&&dx<=i.width && 1218 | dy>=0&&dy<=i.height) 1219 | dmList.push(i); 1220 | }); 1221 | return dmList; 1222 | }; 1223 | CommentManager.prototype.useCSS = function(state){ 1224 | this.options.global.useCSS = state; 1225 | this.clear(); 1226 | if(!state){ 1227 | this.stage.style.opacity=''; 1228 | requestAnimationFrame(this.canvasDrawerWrapper); 1229 | } 1230 | }; 1231 | CommentManager.prototype.autoOpacity = function(state){ 1232 | this.options.global.autoOpacity = state; 1233 | }; 1234 | CommentManager.prototype.sendAsync = function(data){ 1235 | if(data.mode === 8){ 1236 | if(this.scripting){ 1237 | this.scripting.eval(data.code); 1238 | } 1239 | return; 1240 | } 1241 | if(this.options.global.density > 0 && data.mode == 1 && data.border !== true && this.csa.scroll.length>=this.options.global.density) return false; 1242 | if(this.filter != null){ 1243 | data = this.filter.doModify(data); 1244 | if(data == null || data === false) return; 1245 | } 1246 | 1247 | //canvas break 1248 | if(!this.options.global.useCSS && [1,4,5].indexOf(data.mode) != -1 ){ 1249 | var now = performance.now(); 1250 | var cmt = new CoreComment(this, data); 1251 | cmt.dom = {style:{}}; 1252 | commentCanvasDrawer(cmt, this.options.global.outline, this.options.global.shadow); 1253 | if( data.mode == 1 || data.mode == 6){ 1254 | cmt.rx = 0; 1255 | cmt.x = this.width; 1256 | cmt.prev = now; 1257 | cmt.speed = ( this.width + cmt.width ) / cmt.dur * 1e3; 1258 | }else if ( data.mode == 4 || data.mode == 5 ){ 1259 | cmt.removeTime = now + cmt.dur; 1260 | } 1261 | switch(cmt.mode){ 1262 | default: 1263 | case 1:{this.csa.scroll.add(cmt);}break; 1264 | case 4:{this.csa.bottom.add(cmt);}break; 1265 | case 5:{this.csa.top.add(cmt);}break; 1266 | } 1267 | }else{ 1268 | 1269 | if(data.mode === 1 || data.mode === 2 || data.mode === 6){ 1270 | var cmt = new CSSScrollComment(this, data); 1271 | }else{ 1272 | var cmt = new CoreComment(this, data); 1273 | } 1274 | switch(cmt.mode){ 1275 | case 1:cmt.align = 0;break; 1276 | case 2:cmt.align = 2;break; 1277 | case 4:cmt.align = 2;break; 1278 | case 5:cmt.align = 0;break; 1279 | case 6:cmt.align = 1;break; 1280 | } 1281 | cmt.init(); 1282 | this.stage.appendChild(cmt.dom); 1283 | cmt.dom.transitionStartTime=(new Date).getTime(); 1284 | switch(cmt.mode){ 1285 | default: 1286 | case 1:{this.csa.scroll.add(cmt);}break; 1287 | case 2:{this.csa.scrollbtm.add(cmt);}break; 1288 | case 4:{this.csa.bottom.add(cmt);}break; 1289 | case 5:{this.csa.top.add(cmt);}break; 1290 | case 6:{this.csa.reverse.add(cmt);}break; 1291 | case 17: 1292 | case 7:{ 1293 | if(data.rY !== 0 || data.rZ !== 0){ 1294 | /** TODO: revise when browser manufacturers make up their mind on Transform APIs **/ 1295 | cmt.dom.style.transform = getRotMatrix(data.rY, data.rZ); 1296 | cmt.dom.style.webkitTransform = getRotMatrix(data.rY, data.rZ); 1297 | cmt.dom.style.OTransform = getRotMatrix(data.rY, data.rZ); 1298 | cmt.dom.style.MozTransform = getRotMatrix(data.rY, data.rZ); 1299 | cmt.dom.style.MSTransform = getRotMatrix(data.rY, data.rZ); 1300 | } 1301 | }break; 1302 | } 1303 | cmt.y = cmt.y; 1304 | } 1305 | cmt.originalData=data; 1306 | this.dispatchEvent("enterComment", cmt); 1307 | this.runline.push(cmt); 1308 | }; 1309 | CommentManager.prototype.finish = function(cmt){ 1310 | this.dispatchEvent("exitComment", cmt); 1311 | try{ 1312 | this.stage.removeChild(cmt.dom); 1313 | }catch(e){} 1314 | var index = this.runline.indexOf(cmt); 1315 | if(index >= 0){ 1316 | this.runline.splice(index, 1); 1317 | } 1318 | switch(cmt.mode){ 1319 | default: 1320 | case 1:{this.csa.scroll.remove(cmt);}break; 1321 | case 2:{this.csa.scrollbtm.remove(cmt);}break; 1322 | case 4:{this.csa.bottom.remove(cmt);}break; 1323 | case 5:{this.csa.top.remove(cmt);}break; 1324 | case 6:{this.csa.reverse.remove(cmt);}break; 1325 | case 7:break; 1326 | } 1327 | if(cmt.textData) 1328 | cmt.textData = null; 1329 | }; 1330 | CommentManager.prototype.resumeComment=function (){ 1331 | Array.prototype.slice.call(this.stage.children).forEach(function(a){ 1332 | a.classList.contains("cmt") && 1333 | a.classList.contains("paused") && 1334 | ( 1335 | a.style.transitionDuration=a.finalDuration+"ms", 1336 | a.style.transform=a.finalTransform, 1337 | a.transitionStartTime=(new Date).getTime(), 1338 | a.classList.remove("paused") 1339 | ) 1340 | }) 1341 | }; 1342 | CommentManager.prototype.pauseComment=function (){ 1343 | Array.prototype.slice.call(this.stage.children).forEach(function(a){ 1344 | a.classList.contains("cmt")&& 1345 | !a.classList.contains("paused")&& 1346 | ( 1347 | a.finalTransform=a.style.transform, 1348 | a.style.transform=window.getComputedStyle(a).getPropertyValue("transform"), 1349 | a.finalDuration=parseFloat(a.style.transitionDuration)-(new Date).getTime()+a.transitionStartTime, 1350 | a.style.transitionDuration="10ms", 1351 | a.classList.add("paused") 1352 | ) 1353 | }) 1354 | }; 1355 | CommentManager.prototype.addEventListener = function(event, listener){ 1356 | if(typeof this._listeners[event] !== "undefined"){ 1357 | this._listeners[event].push(listener); 1358 | }else{ 1359 | this._listeners[event] = [listener]; 1360 | } 1361 | }; 1362 | CommentManager.prototype.dispatchEvent = function(event, data){ 1363 | if(typeof this._listeners[event] !== "undefined"){ 1364 | for(var i = 0; i < this._listeners[event].length; i++){ 1365 | try{ 1366 | this._listeners[event][i](data); 1367 | }catch(e){ 1368 | console.err(e.stack); 1369 | } 1370 | } 1371 | } 1372 | }; 1373 | /** Static Functions **/ 1374 | CommentManager.prototype.onTimerEvent = function(timePassed,cmObj){ 1375 | for(var i= 0;i < cmObj.runline.length; i++){ 1376 | var cmt = cmObj.runline[i]; 1377 | if(cmt.hold){ 1378 | continue; 1379 | } 1380 | cmt.time(timePassed); 1381 | } 1382 | }; 1383 | return CommentManager; 1384 | })(); 1385 | 1386 | /** 1387 | * AcFun Format Parser 1388 | * Takes in JSON and parses it based on current documentation for AcFun comments 1389 | * @license MIT License 1390 | **/ 1391 | var AcfunFormat = (function () { 1392 | var AcfunFormat = {}; 1393 | 1394 | AcfunFormat.JSONParser = function (params) { 1395 | this._logBadComments = true; 1396 | this._logNotImplemented = false; 1397 | if (typeof params === 'object') { 1398 | this._logBadComments = params.logBadComments === false ? false : true; 1399 | this._logNotImplemented = params.logNotImplemented === true ? true : false; 1400 | } 1401 | }; 1402 | 1403 | AcfunFormat.JSONParser.prototype.parseOne = function (comment) { 1404 | // Read a comment and generate a correct comment object 1405 | var data = {}; 1406 | if (typeof comment !== 'object' || comment == null || !comment.hasOwnProperty('c')) { 1407 | // This cannot be parsed. The comment contains no config data 1408 | return null; 1409 | } 1410 | var config = comment['c'].split(','); 1411 | if (config.length >= 6) { 1412 | data.stime = parseFloat(config[0]) * 1000; 1413 | data.color = parseInt(config[1]) 1414 | data.mode = parseInt(config[2]); 1415 | data.size = parseInt(config[3]); 1416 | data.hash = config[4]; 1417 | data.date = parseInt(config[5]); 1418 | data.dbid = config[6]; 1419 | data.pool = 0; 1420 | data.position = "absolute"; 1421 | if (data.mode !== 7) { 1422 | // Do some text normalization on low complexity comments 1423 | data.text = comment.m.replace(/(\/n|\\n|\n|\r\n|\\r)/g,"\n"); 1424 | data.text = data.text.replace(/\r/g,"\n"); 1425 | data.text = data.text.replace(/\s/g,"\u00a0"); 1426 | } else { 1427 | try { 1428 | var x = JSON.parse(comment.m); 1429 | } catch (e) { 1430 | if (this._logBadComments) { 1431 | console.warn('Error parsing internal data for comment'); 1432 | console.log('[Dbg] ' + data.text); 1433 | } 1434 | return null; // Can't actually parse this! 1435 | } 1436 | data.position = "relative"; 1437 | data.text = x.n; /*.replace(/\r/g,"\n");*/ 1438 | data.text = data.text.replace(/\ /g,"\u00a0"); 1439 | if (typeof x.a === 'number') { 1440 | data.opacity = x.a; 1441 | } else { 1442 | data.opacity = 1; 1443 | } 1444 | if (typeof x.p === 'object') { 1445 | // Relative position 1446 | data.x = x.p.x / 1000; 1447 | data.y = x.p.y / 1000; 1448 | } else { 1449 | data.x = 0; 1450 | data.y = 0; 1451 | } 1452 | if (typeof x.c === 'number') { 1453 | switch (x.c) { 1454 | case 0: data.align = 0; break; 1455 | case 2: data.align = 1; break; 1456 | case 6: data.align = 2; break; 1457 | case 8: data.align = 3; break; 1458 | default: 1459 | if (this._logNotImplemented) { 1460 | console.log('Cannot handle aligning to center! AlignMode=' + x.c); 1461 | } 1462 | } 1463 | } 1464 | // Use default axis 1465 | data.axis = 0; 1466 | data.shadow = x.b; 1467 | data.dur = 4000; 1468 | if (typeof x.l === 'number') { 1469 | data.dur = x.l * 1000; 1470 | } 1471 | if (x.z != null && x.z.length > 0) { 1472 | data.movable = true; 1473 | data.motion = []; 1474 | var moveDuration = 0; 1475 | var last = { 1476 | x: data.x, 1477 | y: data.y, 1478 | alpha: data.opacity, 1479 | color: data.color 1480 | }; 1481 | for (var m = 0; m < x.z.length; m++) { 1482 | var dur = x.z[m].l != null ? (x.z[m].l * 1000) : 500; 1483 | moveDuration += dur; 1484 | var motion = {}; 1485 | if (x.z[m].hasOwnProperty('rx') && typeof x.z[m].rx === 'number') { 1486 | // TODO: Support this 1487 | if (this._logNotImplemented) { 1488 | console.log('Encountered animated x-axis rotation. Ignoring.'); 1489 | } 1490 | } 1491 | if (x.z[m].hasOwnProperty('e') && typeof x.z[m].e === 'number') { 1492 | // TODO: Support this 1493 | if (this._logNotImplemented) { 1494 | console.log('Encountered animated y-axis rotation. Ignoring.'); 1495 | } 1496 | } 1497 | if (x.z[m].hasOwnProperty('d') && typeof x.z[m].d === 'number') { 1498 | // TODO: Support this 1499 | if (this._logNotImplemented) { 1500 | console.log('Encountered animated z-axis rotation. Ignoring.'); 1501 | } 1502 | } 1503 | if (x.z[m].hasOwnProperty('x') && typeof x.z[m].x === 'number') { 1504 | motion.x = { 1505 | from: last.x, 1506 | to: x.z[m].x / 1000, 1507 | dur: dur, 1508 | delay: 0 1509 | }; 1510 | } 1511 | if (x.z[m].hasOwnProperty('y') && typeof x.z[m].y === 'number') { 1512 | motion.y = { 1513 | from: last.y, 1514 | to: x.z[m].y / 1000, 1515 | dur: dur, 1516 | delay: 0 1517 | }; 1518 | } 1519 | last.x = motion.hasOwnProperty('x') ? motion.x.to : last.x; 1520 | last.y = motion.hasOwnProperty('y') ? motion.y.to : last.y; 1521 | if (x.z[m].hasOwnProperty('t') && 1522 | typeof x.z[m].t === 'number' && 1523 | x.z[m].t !== last.alpha) { 1524 | motion.alpha = { 1525 | from: last.alpha, 1526 | to: x.z[m].t, 1527 | dur: dur, 1528 | delay: 0 1529 | }; 1530 | last.alpha = motion.alpha.to; 1531 | } 1532 | if (x.z[m].hasOwnProperty('c') && 1533 | typeof x.z[m].c === 'number' && 1534 | x.z[m].c !== last.color) { 1535 | motion.color = { 1536 | from: last.color, 1537 | to:x.z[m].c, 1538 | dur: dur, 1539 | delay: 0 1540 | }; 1541 | last.color = motion.color.to; 1542 | } 1543 | data.motion.push(motion); 1544 | } 1545 | data.dur = moveDuration + (data.moveDelay ? data.moveDelay : 0); 1546 | } 1547 | if (x.hasOwnProperty('w')) { 1548 | if (x.w.hasOwnProperty('f')) { 1549 | data.font = x.w.f; 1550 | } 1551 | if (x.w.hasOwnProperty('l') && Array.isArray(x.w.l)) { 1552 | if (x.w.l.length > 0) { 1553 | // Filters 1554 | if (this._logNotImplemented) { 1555 | console.log('[Dbg] Filters not supported! ' + 1556 | JSON.stringify(x.w.l)); 1557 | } 1558 | } 1559 | } 1560 | } 1561 | if (x.r != null && x.k != null) { 1562 | data.rX = x.r; 1563 | data.rY = x.k; 1564 | } 1565 | 1566 | } 1567 | return data; 1568 | } else { 1569 | // Not enough arguments. 1570 | if (this._logBadComments) { 1571 | console.warn('Dropping this comment due to insufficient parameters. Got: ' + config.length); 1572 | console.log('[Dbg] ' + comment['c']); 1573 | } 1574 | return null; 1575 | } 1576 | }; 1577 | 1578 | AcfunFormat.JSONParser.prototype.parseMany = function (comments) { 1579 | if (!Array.isArray(comments)) { 1580 | return null; 1581 | } 1582 | var list = []; 1583 | for (var i = 0; i < comments.length; i++) { 1584 | var comment = this.parseOne(comments[i]); 1585 | if (comment !== null) { 1586 | list.push(comment); 1587 | } 1588 | } 1589 | return list; 1590 | }; 1591 | 1592 | AcfunFormat.TextParser = function (param) { 1593 | this._jsonParser = new AcfunFormat.JSONParser(param); 1594 | } 1595 | 1596 | AcfunFormat.TextParser.prototype.parseOne = function (comment) { 1597 | try { 1598 | return this._jsonParser.parseOne(JSON.parse(comment)); 1599 | } catch (e) { 1600 | console.warn(e); 1601 | return null; 1602 | } 1603 | } 1604 | 1605 | AcfunFormat.TextParser.prototype.parseMany = function (comment) { 1606 | try { 1607 | return this._jsonParser.parseMany(JSON.parse(comment)); 1608 | } catch (e) { 1609 | console.warn(e); 1610 | return null; 1611 | } 1612 | } 1613 | 1614 | return AcfunFormat; 1615 | })(); 1616 | --------------------------------------------------------------------------------