├── 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 | ![](src/icon.png) 5 | 6 | 一个装B播放器,送给缺B乐的各位(被打 7 | 8 | ## 安装 9 | 当前版本:[![VERSION_TAG_NUMBER](https://img.shields.io/github/tag/esterTion/AcFun-HTML5-Player.svg)](update_note.md) 10 | - [Firefox](https://estertion.github.io/AcFun-HTML5-Player/signed.xpi) (firefox 57.0+) 11 | - [Chrome ![Chrome商店](https://img.shields.io/chrome-web-store/users/onjihgccojkcmlmlbjmgkcnehdbpbhcf.svg)](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 | ![](https://estertion.win/wp-content/uploads/2018/10/f2018174470233ba6ca7f89a0b3fd60957e2f96a.png) 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 += '
' + list.text[i] + '
'; 137 | } 138 | $$('#shield_text').innerHTML = str; 139 | del = $('#shield_text .shield_item .delete'); 140 | for (i = 0, len = del.length; i < len; i++) { 141 | del[i].onclick = obj.del; 142 | } 143 | break; 144 | case 1: 145 | //用户 146 | var str = '', i = 0, del; 147 | for (;i < list.user.length; i++) { 148 | str += '
' + list.user[i] + '
'; 149 | } 150 | if (i == 0) { 151 | str = '
' + ABP.Strings.blockUserEmpty + '
'; 152 | } 153 | $$('#shield_user').innerHTML = str; 154 | del = $('#shield_user .shield_item .delete'); 155 | for (i = 0, len = del.length; i < len; i++) { 156 | del[i].onclick = obj.delUser; 157 | } 158 | break; 159 | case 2: 160 | //颜色 161 | var str = '', i = 0, color, del; 162 | for (;i < list.color.length; i++) { 163 | color = list.color[i].toString(16); 164 | while (color.length < 6) { 165 | color = '0' + color; 166 | } 167 | str += '
' + list.color[i] + '
'; 168 | } 169 | if (i == 0) { 170 | str = '
' + ABP.Strings.blockColorEmpty + '
'; 171 | } 172 | $$('#shield_color').innerHTML = str; 173 | del = $('#shield_color .shield_color .delete'); 174 | for (i = 0, len = del.length; i < len; i++) { 175 | del[i].onclick = obj.delColor; 176 | } 177 | break; 178 | case 3: 179 | //设置 180 | $$('#useReg').className = 'shield_toggle' + (useReg ? ' on' : ''); 181 | $$('#blockTop').className = 'shield_toggle' + ((list.mode.indexOf(5) != -1) ? ' on' : ''); 182 | $$('#blockBottom').className = 'shield_toggle' + ((list.mode.indexOf(4) != -1) ? ' on' : ''); 183 | $$('#blockVisitor').className = 'shield_toggle' + (list.visitor ? ' on' : ''); 184 | var perc = (limit - 2) / 49, limitstr = limit + ' ' + ABP.Strings.repeatPcs; 185 | if (limit == 0) 186 | perc = 1, limitstr = ABP.Strings.repeatUnlimited; 187 | $$('#repeat .fill').style.width = perc * 100 + '%'; 188 | $$('#repeat .button').style.left = perc * 100 + '%'; 189 | $$('#repeat .slide_info').innerHTML = limitstr; 190 | break; 191 | default: 192 | return; 193 | }tab++;} 194 | }, 195 | save: function () { 196 | list.useReg = useReg; 197 | list.limit = limit; 198 | localStorage.shieldList = JSON.stringify(list); 199 | obj.shield(); 200 | }, 201 | show: function () { 202 | if (hidden) { 203 | $('.shield')[0].setAttribute('class', 'shield'); 204 | } else { 205 | $('.shield')[0].setAttribute('class', 'shield hidden'); 206 | } 207 | hidden = !hidden; 208 | }, 209 | add: function () { 210 | obj.addText($$('.shield_item .new').value) && ($$('.shield_item .new').value = ''); 211 | }, 212 | addText: function (text) { 213 | if (text == '' || list.text.indexOf(text) != -1) 214 | return false; 215 | try { 216 | if (useReg) { 217 | new RegExp(text); 218 | } 219 | } catch (e) { 220 | playerInstance.createPopup('格式错误,' + e.message, 3e3); 221 | return false; 222 | } 223 | list.text.push(text); 224 | obj.save(); 225 | obj.render(0); 226 | return true; 227 | }, 228 | addUser: function (user) { 229 | if (list.user.indexOf(user) != -1) 230 | return false; 231 | list.user.push(user); 232 | obj.save(); 233 | obj.render(1); 234 | }, 235 | addColor: function (color) { 236 | color = parseInt(color, 16); 237 | if (isNaN(color) || list.color.indexOf(color) != -1) 238 | return false; 239 | list.color.push(color); 240 | obj.save(); 241 | obj.render(2); 242 | }, 243 | mode: function (mode) { 244 | var index, block = ((index = list.mode.indexOf(mode)) == -1); 245 | if (block) { 246 | list.mode.push(mode); 247 | } else { 248 | list.mode.splice(index, 1); 249 | } 250 | obj.save(); 251 | obj.render(3); 252 | }, 253 | visitor: function () { 254 | list.visitor = !list.visitor; 255 | obj.save(); 256 | obj.render(3); 257 | }, 258 | del: function (e) { 259 | var newlist, delstr = e.target.parentNode.firstChild.innerHTML, index = list.text.indexOf(delstr); 260 | if (index == -1) 261 | return false; 262 | newlist = list.text.splice(0, index); 263 | list.text = newlist.concat(list.text.splice(1)); 264 | obj.save(); 265 | obj.render(0); 266 | }, 267 | delUser: function (e) { 268 | var newlist, delUser = e.target.parentNode.firstChild.innerHTML.split(' ')[0], index = list.user.indexOf(delUser); 269 | if (index == -1) 270 | return false; 271 | newlist = list.user.splice(0, index); 272 | list.user = newlist.concat(list.user.splice(1)); 273 | obj.save(); 274 | obj.render(1); 275 | }, 276 | delColor: function (e) { 277 | var newlist, delColor = e.target.parentNode.firstChild.innerHTML, index = list.color.indexOf(delColor * 1); 278 | if (index == -1) 279 | return false; 280 | newlist = list.color.splice(0, index); 281 | list.color = newlist.concat(list.color.splice(1)); 282 | obj.save(); 283 | obj.render(2); 284 | }, 285 | filter: function (cm) { 286 | /*for(var i=0,len=list.text.length;i 0) { 313 | for (;i < len; i++) { 314 | try { 315 | clean.push(cm[i].text.replace(danmakuMatcher, '')) 316 | } catch (e) { 317 | clean.push('') 318 | } 319 | } 320 | for (i = 0; i < len; i++) { 321 | if (cm[i].mode > 6) continue; 322 | var wordSet = mergedTimeline[clean[i]]; 323 | if (!wordSet) { 324 | mergedTimeline[clean[i]] = [[cm[i].stime, cm[i].stime, 1, i]]; 325 | } else { 326 | var lastRange = wordSet[wordSet.length - 1], delta = cm[i].stime - lastRange[1]; 327 | if (delta >= 10000) { 328 | wordSet.push([cm[i].stime, cm[i].stime, 1, i]); 329 | } else { 330 | lastRange[1] = cm[i].stime; 331 | lastRange[2]++; 332 | } 333 | } 334 | } 335 | } 336 | for (j = 0; j < list.text.length; j++) { 337 | textList.push(useReg ? new RegExp(list.text[j]) : list.text[j]); 338 | } 339 | var shouldBlockRepeat = function (ranges, cmt) { 340 | for (var i = 0; i < ranges.length; i++) { 341 | if (cmt.stime > ranges[i][1]) continue; 342 | return ranges[i][2] >= limit ? ranges[i] : false; 343 | } 344 | return false; 345 | } 346 | for (i = 0; i < len; i++) { 347 | cmt = cm[i]; 348 | cmt.isBlocked = false; 349 | cmt.isRepeat = false; 350 | var repeatRange; 351 | if (cmt.mode <= 6 && mergedTimeline[clean[i]] && (repeatRange = shouldBlockRepeat(mergedTimeline[clean[i]], cmt))) { 352 | cmt.isBlocked = !0; 353 | cmt.isRepeat = true; 354 | cmt.isFirstRepeat = false; 355 | if (repeatRange[3] === i) { 356 | cmt.isFirstRepeat = true; 357 | cmt.repeatCount = repeatRange[2]; 358 | }; 359 | cmt.blockReason = '重复弹幕'; 360 | } else if (list.color.indexOf(cmt.color) != -1) { 361 | cmt.isBlocked = !0; 362 | cmt.blockReason = '颜色'; 363 | } else if (list.user.indexOf(cmt.hash) != -1) { 364 | cmt.isBlocked = !0; 365 | cmt.blockReason = '用户'; 366 | } else if (list.mode.indexOf(cmt.mode) != -1) { 367 | cmt.isBlocked = !0; 368 | cmt.blockReason = '位置'; 369 | } else if ((list.visitor && isVisitor(cmt.hash))) { 370 | cmt.isBlocked = !0; 371 | cmt.blockReason = '游客'; 372 | } else { 373 | for (j = 0; j < textList.length; j++) { 374 | try { 375 | if (cmt.text.match(textList[j]) != null) { 376 | cmt.isBlocked = !0; 377 | cmt.blockReason = textList[j]; 378 | break; 379 | } 380 | } catch (e) { } 381 | } 382 | } 383 | } 384 | 385 | for (i = onScreen.length - 1; i >= 0; i--) { 386 | if (onScreen[i].originalData.isBlocked) { 387 | onScreen[i].finish(); 388 | } 389 | } 390 | playerInstance.renderCommentList(); 391 | 392 | 393 | /* 394 | int sta=0,end=sta; 395 | while(end!=danmaku.size()){ 396 | while(danmaku[sta]->time+10000time){ 397 | if(--count[clean[sta]]==0){ 398 | count.remove(clean[sta]); 399 | } 400 | ++sta; 401 | } 402 | if(++count[clean[end]]>l&&danmaku[end]->mode<=6){ 403 | set.insert(clean[end]); 404 | } 405 | ++end; 406 | }*/ 407 | } 408 | }; 409 | return obj; 410 | })(); 411 | window.shield = shield; 412 | -------------------------------------------------------------------------------- /src/_locales/en/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "statsPlayer": { 3 | "message": "Player dimension:" 4 | }, 5 | "statsVideo": { 6 | "message": "Video resolution:" 7 | }, 8 | "statsBuffer": { 9 | "message": "Available buffer:" 10 | }, 11 | "statsBufferClip": { 12 | "message": "Buffer clips:" 13 | }, 14 | "statsPresent": { 15 | "message": "Expected fps:" 16 | }, 17 | "statsDrop": { 18 | "message": "Drop rate:" 19 | }, 20 | "statsMimetype": { 21 | "message": "MIME type:" 22 | }, 23 | "statsVideoBitrate": { 24 | "message": "Video bitrate:" 25 | }, 26 | "statsAudioBitrate": { 27 | "message": "Audio bitrate:" 28 | }, 29 | "statsCurrentBitrate": { 30 | "message": "Current bitrate:" 31 | }, 32 | "statsRealtimeBitrate": { 33 | "message": "Realtime bitrate:" 34 | }, 35 | "overallBitrate": { 36 | "message": "Overall bitrate:" 37 | }, 38 | "reload": { 39 | "message": "Reload" 40 | }, 41 | "statsDownloadSpeed": { 42 | "message": "Download speed:" 43 | }, 44 | "sendSmall": { 45 | "message": "Small" 46 | }, 47 | "sendMid": { 48 | "message": "Middle" 49 | }, 50 | "sendSize": { 51 | "message": "Comment size" 52 | }, 53 | "sendMode": { 54 | "message": "Comment mode" 55 | }, 56 | "sendTop": { 57 | "message": "Top" 58 | }, 59 | "sendScroll": { 60 | "message": "Scroll" 61 | }, 62 | "sendBottom": { 63 | "message": "Bottom" 64 | }, 65 | "send": { 66 | "message": "Send" 67 | }, 68 | "sendStyle": { 69 | "message": "Comment style" 70 | }, 71 | "sendColor": { 72 | "message": "Comment color" 73 | }, 74 | "commentSpeed": { 75 | "message": "Comment speed" 76 | }, 77 | "commentScale": { 78 | "message": "Comment scale" 79 | }, 80 | "commentDensity": { 81 | "message": "Comment density" 82 | }, 83 | "commentOpacity": { 84 | "message": "Comment opacity" 85 | }, 86 | "commentBlock": { 87 | "message": "Filtering list" 88 | }, 89 | "playSpeed": { 90 | "message": "Playback speed" 91 | }, 92 | "playSpeedReset": { 93 | "message": "Reset" 94 | }, 95 | "displayScaleD": { 96 | "message": "Default" 97 | }, 98 | "displayScaleF": { 99 | "message": "Fill" 100 | }, 101 | "shieldTypeText": { 102 | "message": "Text" 103 | }, 104 | "shieldTypeUser": { 105 | "message": "User" 106 | }, 107 | "shieldTypeColor": { 108 | "message": "Color" 109 | }, 110 | "shieldTypeSetting": { 111 | "message": "Settings" 112 | }, 113 | "shieldAdd": { 114 | "message": "Add new……" 115 | }, 116 | "shieldUseRegex": { 117 | "message": "Use regular expression" 118 | }, 119 | "shieldBlockTop": { 120 | "message": "Filter top comment" 121 | }, 122 | "shieldBlockBottom": { 123 | "message": "Filter bottom comment" 124 | }, 125 | "shieldBlockVisitor": { 126 | "message": "Filter non-members\" comment" 127 | }, 128 | "shieldRepeat": { 129 | "message": "Filter repeated comment" 130 | }, 131 | "viewers": { 132 | "message": " Viewers" 133 | }, 134 | "comments": { 135 | "message": " Comments" 136 | }, 137 | "commentTime": { 138 | "message": "Time" 139 | }, 140 | "commentContent": { 141 | "message": "Content" 142 | }, 143 | "commentDate": { 144 | "message": "Send date" 145 | }, 146 | "blockMatch":{ 147 | "message": "Hit rule:" 148 | }, 149 | "showStats": { 150 | "message": "Show playback statstics" 151 | }, 152 | "loadingMeta": { 153 | "message": "Loading video metadata" 154 | }, 155 | "switching": { 156 | "message": "Switching" 157 | }, 158 | "fetchURL": { 159 | "message": "Fetching video source" 160 | }, 161 | "buffering": { 162 | "message": "Loading" 163 | }, 164 | "play": { 165 | "message": "Play" 166 | }, 167 | "pause": { 168 | "message": "Pause" 169 | }, 170 | "mute": { 171 | "message": "Mute" 172 | }, 173 | "unmute": { 174 | "message": "Unmute" 175 | }, 176 | "muteNotSupported": { 177 | "message": "Mute not supported" 178 | }, 179 | "fullScreen": { 180 | "message": "Enter fullscreen" 181 | }, 182 | "exitFullScreen": { 183 | "message": "Exit fullscreen" 184 | }, 185 | "webFull": { 186 | "message": "Enter webpage fullscreen" 187 | }, 188 | "exitWebFull": { 189 | "message": "Exit webpage fullscreen" 190 | }, 191 | "cmtListShow": { 192 | "message": "Show comment list" 193 | }, 194 | "cmtListHide": { 195 | "message": "Hide comment list" 196 | }, 197 | "sendTooltip": { 198 | "message": "Shoot!" 199 | }, 200 | "showComment": { 201 | "message": "Show comments" 202 | }, 203 | "hideComment": { 204 | "message": "Hide comments" 205 | }, 206 | "loopOn": { 207 | "message": "Loop on" 208 | }, 209 | "loopOff": { 210 | "message": "Loop off" 211 | }, 212 | "usingCanvas": { 213 | "message": "Using canvas" 214 | }, 215 | "usingCSS": { 216 | "message": "Using CSS" 217 | }, 218 | "useCSS": { 219 | "message": "Draw with CSS" 220 | }, 221 | "autoOpacityOn": { 222 | "message": "Turn off auto opacity" 223 | }, 224 | "autoOpacityOff": { 225 | "message": "Turn on auto opacity" 226 | }, 227 | "copyComment": { 228 | "message": "Copy contents" 229 | }, 230 | "findComment": { 231 | "message": "Find comment" 232 | }, 233 | "blockContent": { 234 | "message": "Filter content " 235 | }, 236 | "blockUser": { 237 | "message": "Filter sender " 238 | }, 239 | "blockColor": { 240 | "message": "Filter color" 241 | }, 242 | "blockColorWhite": { 243 | "message": "Can\"t filter" 244 | }, 245 | "copyFail": { 246 | "message": "Copying failed: not supported by browser" 247 | }, 248 | "blockUserEmpty": { 249 | "message": "Nobody filtered yet" 250 | }, 251 | "blockColorEmpty": { 252 | "message": "No color filtered yet" 253 | }, 254 | "repeatPcs": { 255 | "message": " " 256 | }, 257 | "repeatUnlimited": { 258 | "message": "No limits" 259 | }, 260 | "dragControlLowInc": { 261 | "message": "Slow forward" 262 | }, 263 | "dragControlLowDec": { 264 | "message": "Slow rewind" 265 | }, 266 | "dragControlMedInc": { 267 | "message": "Medium forward" 268 | }, 269 | "dragControlMedDec": { 270 | "message": "Medium rewind" 271 | }, 272 | "dragControlHighInc": { 273 | "message": "Fast forward" 274 | }, 275 | "dragControlHighDec": { 276 | "message": "Fast rewind" 277 | }, 278 | "dragControlCancel": { 279 | "message": "Cancelling" 280 | }, 281 | "extName": { 282 | "message": "AcFun HTML5 Player" 283 | }, 284 | "extDesc": { 285 | "message": "Open source:https://github.com/esterTion/AcFun-HTML5-Player" 286 | }, 287 | "iconPending": { 288 | "message": " video(s) pending playback" 289 | }, 290 | "iconPlaying": { 291 | "message": " video(s) playing" 292 | }, 293 | "iconIdle": { 294 | "message": "No replacable player found" 295 | }, 296 | "close": { 297 | "message": "Close" 298 | }, 299 | "flvhd": { 300 | "message": "Fast" 301 | }, 302 | "mp4hd": { 303 | "message": "SD" 304 | }, 305 | "mp4hd2": { 306 | "message": "HD" 307 | }, 308 | "mp4hd3": { 309 | "message": "FHD" 310 | }, 311 | "emptyPW": { 312 | "message": "Empty password. " 313 | }, 314 | "currentLang": { 315 | "message": "Current audio language:" 316 | }, 317 | "needPW": { 318 | "message": "Video requires password access, please enter password:" 319 | }, 320 | "enterPW": { 321 | "message": "Enter access password" 322 | }, 323 | "rememberPW": { 324 | "message": "Remember password" 325 | }, 326 | "submit": { 327 | "message": "Submit" 328 | }, 329 | "wrongPW": { 330 | "message": "Video access password incorrect, please reenter password:" 331 | }, 332 | "fetchSourceErr": { 333 | "message": "Failed fetching video source, error details:" 334 | }, 335 | "audioLang": { 336 | "message": "Audio language" 337 | }, 338 | "toYouku": { 339 | "message": "Play on youku.com" 340 | }, 341 | "fetchCommentErr": { 342 | "message": "Failed fetching comment" 343 | }, 344 | "loadErr": { 345 | "message": "Load video failed, cannot play this video" 346 | }, 347 | "playErr": { 348 | "message": "Playback error" 349 | }, 350 | "playErrPop": { 351 | "message": " failed to play, downgrading to " 352 | }, 353 | "switchErr": { 354 | "message": "Switching failed, this language / definition cannot be played" 355 | }, 356 | "partialAvailable": { 357 | "message": "You have limited access on viewing this video, please check your payment status" 358 | }, 359 | "restoreFlash": { 360 | "message": "Restore flash player" 361 | }, 362 | "fetchInfoErr": { 363 | "message": "Failed fetching video info, error details:" 364 | }, 365 | "uploader": { 366 | "message": "Uploader:" 367 | }, 368 | "outputUrl": { 369 | "message": "Output all parts" 370 | }, 371 | "noVisitorComment": { 372 | "message": "Visitor can't post comments" 373 | }, 374 | "postCommentFail": { 375 | "message": "Post comment failed" 376 | }, 377 | "replaceEmbed": { 378 | "message": "Replace embed players" 379 | }, 380 | "autoSwitch": { 381 | "message": "Auto jump to next episode" 382 | }, 383 | "mayBlocked": { 384 | "message": "You may have enabled an ad blocker, and it had blocked some important content. Please try again after disable the blocker. \nAfter player normally loaded, you can enable blocker again. \n\nIf you had seen this note in the past, please check your network status. " 385 | }, 386 | "officialHtml5": { 387 | "message": "Use official html5 player" 388 | }, 389 | "settings": { 390 | "message": "Settings" 391 | }, 392 | "settComment": { 393 | "message": "Comment preferences" 394 | }, 395 | "recordPlaySpeed": { 396 | "message": "Set current speed as default" 397 | }, 398 | "settPlayer": { 399 | "message": "Player preferences" 400 | }, 401 | "autoPlay": { 402 | "message": "Start playback automatically" 403 | }, 404 | "defaultFull": { 405 | "message": "Enter fullscreen mode automatically" 406 | }, 407 | "settExtension": { 408 | "message": "Extension preferences" 409 | }, 410 | "statsSourceHost": { 411 | "message": "Source host:" 412 | }, 413 | "statsRedirection": { 414 | "message": "Redirection:" 415 | }, 416 | "statsRedirectionNone": { 417 | "message": "None" 418 | }, 419 | "extUpdated": { 420 | "message": "Yet Another Player for Youku has been updated!" 421 | }, 422 | "extUpdated_ver": { 423 | "message": "We are currently at version " 424 | }, 425 | "extUpdated_detail": { 426 | "message": "Here are some update notes:\n1、Project has been renamed to 【Yet Another Player for Youku】\n2、Attempt to play the lower quality video when playback error occurs." 427 | }, 428 | "playerTheme": { 429 | "message": "Player theme" 430 | }, 431 | "cmStyle":{ 432 | "message": "Comment style: " 433 | }, 434 | "cmStyle_st":{ 435 | "message": "Stroke" 436 | }, 437 | "cmStyle_sh":{ 438 | "message": "Shadow" 439 | }, 440 | "cmStyle_stsh":{ 441 | "message": "Stroke & Shadow" 442 | }, 443 | "next": { 444 | "message": "Next video: " 445 | }, 446 | "storylinePoints": { 447 | "message": "Timeline Highlights" 448 | }, 449 | "skipHead": { 450 | "message": "Skip the opening and ending part" 451 | }, 452 | "volumeChange": { 453 | "message": "Volume changed to " 454 | }, 455 | "rateChange": { 456 | "message": "Speed changed to " 457 | }, 458 | "copySegUrl": { 459 | "message": "Copy URL" 460 | }, 461 | "copied": { 462 | "message": "Copied! " 463 | }, 464 | "Auto": { 465 | "message": "Auto" 466 | }, 467 | "switchingTo": { 468 | "message": "Switching to " 469 | }, 470 | "switched": { 471 | "message": "Switched" 472 | }, 473 | "currentQuality": { 474 | "message": "Current quality:" 475 | }, 476 | "currentFragment": { 477 | "message": "Current fragment:" 478 | }, 479 | "playerCoreSetting": { 480 | "message": "Player core:" 481 | }, 482 | "playerCoreSettingTip": { 483 | "message": "Need to refresh page after change" 484 | }, 485 | "screenshot": { 486 | "message": "Screenshot" 487 | }, 488 | "screenshotWithoutComment": { 489 | "message": "Without comments" 490 | }, 491 | "screenshotWithComment": { 492 | "message": "With comments" 493 | }, 494 | "screenshotCSSNoSupport": { 495 | "message": "CSS rendering is not supported" 496 | }, 497 | "screenshotError": { 498 | "message": "Cannot take screenshot due to video source limitation" 499 | }, 500 | "chromeAutoPlay": { 501 | "message": "Sound playback denied, click webpage to resume" 502 | }, 503 | "commentLoadPagesSetting": { 504 | "message": "Load comments up to " 505 | } 506 | } 507 | -------------------------------------------------------------------------------- /src/hlsjsMediaInfo.min.js: -------------------------------------------------------------------------------- 1 | !function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var t;t="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,t.HlsjsMediaInfoModule=e()}}(function(){var e;return function e(t,r,a){function n(i,f){if(!r[i]){if(!t[i]){var s="function"==typeof require&&require;if(!f&&s)return s(i,!0);if(o)return o(i,!0);var l=new Error("Cannot find module '"+i+"'");throw l.code="MODULE_NOT_FOUND",l}var u=r[i]={exports:{}};t[i][0].call(u.exports,function(e){var r=t[i][1][e];return n(r||e)},u,u.exports,e,t,r,a)}return r[i].exports}for(var o="function"==typeof require&&require,i=0;i0){var f=a+Math.floor(i/2),s=t[f],l=r[f],u={key:s,data:l,parent:e};return u.left=n(u,t,r,a,f),u.right=n(u,t,r,f+1,o),u}return null}function o(e){if(null===e)return 0;var t=o(e.left),r=o(e.right);return e.balanceFactor=t-r,Math.max(t,r)+1}function i(e,t,r,a,n){if(!(r>=a)){for(var o=e[r+a>>1],f=r-1,s=a+1;;){do{f++}while(n(e[f],o)<0);do{s--}while(n(e[s],o)>0);if(f>=s)break;var l=e[f];e[f]=e[s],e[s]=l,l=t[f],t[f]=t[s],t[s]=l}i(e,t,r,s,n),i(e,t,s+1,a,n)}}function f(e,t){return e>t?1:e0&&(t.balanceFactor+=e.balanceFactor),t}function l(e){var t=e.left;return e.left=t.right,e.left&&(e.left.parent=e),t.parent=e.parent,t.parent&&(t.parent.left===e?t.parent.left=t:t.parent.right=t),e.parent=t,t.right=e,e.balanceFactor-=1,t.balanceFactor>0&&(e.balanceFactor-=t.balanceFactor),t.balanceFactor-=1,e.balanceFactor<0&&(t.balanceFactor+=e.balanceFactor),t}var u=function(e,t){void 0===t&&(t=!1),this._comparator=e||f,this._root=null,this._size=0,this._noDuplicates=!!t},c={size:{configurable:!0}};return u.prototype.destroy=function(){return this.clear()},u.prototype.clear=function(){return this._root=null,this._size=0,this},c.size.get=function(){return this._size},u.prototype.contains=function(e){if(this._root)for(var t=this._root,r=this._comparator;t;){var a=r(e,t.key);if(0===a)return!0;t=a<0?t.left:t.right}return!1},u.prototype.next=function(e){var t=e;if(t)if(t.right)for(t=t.right;t.left;)t=t.left;else for(t=e.parent;t&&t.right===e;)e=t,t=t.parent;return t},u.prototype.prev=function(e){var t=e;if(t)if(t.left)for(t=t.left;t.right;)t=t.right;else for(t=e.parent;t&&t.left===e;)e=t,t=t.parent;return t},u.prototype.forEach=function(e){for(var t=this._root,r=[],a=!1,n=0;!a;)t?(r.push(t),t=t.left):r.length>0?(t=r.pop(),e(t,n++),t=t.right):a=!0;return this},u.prototype.range=function(e,t,r,a){for(var n=this,o=[],i=this._comparator,f=this._root;0!==o.length||f;)if(f)o.push(f),f=f.left;else{if(f=o.pop(),i(f.key,t)>0)break;if(i(f.key,e)>=0&&r.call(a,f))return n;f=f.right}return this},u.prototype.keys=function(){for(var e=this._root,t=[],r=[],a=!1;!a;)e?(t.push(e),e=e.left):t.length>0?(e=t.pop(),r.push(e.key),e=e.right):a=!0;return r},u.prototype.values=function(){for(var e=this._root,t=[],r=[],a=!1;!a;)e?(t.push(e),e=e.left):t.length>0?(e=t.pop(),r.push(e.data),e=e.right):a=!0;return r},u.prototype.at=function(e){for(var t=this._root,r=[],a=!1,n=0;!a;)if(t)r.push(t),t=t.left;else if(r.length>0){if(t=r.pop(),n===e)return t;n++,t=t.right}else a=!0;return null},u.prototype.minNode=function(){var e=this._root;if(!e)return null;for(;e.left;)e=e.left;return e},u.prototype.maxNode=function(){var e=this._root;if(!e)return null;for(;e.right;)e=e.right;return e},u.prototype.min=function(){var e=this._root;if(!e)return null;for(;e.left;)e=e.left;return e.key},u.prototype.max=function(){var e=this._root;if(!e)return null;for(;e.right;)e=e.right;return e.key},u.prototype.isEmpty=function(){return!this._root},u.prototype.pop=function(){var e=this._root,t=null;if(e){for(;e.left;)e=e.left;t={key:e.key,data:e.data},this.remove(e.key)}return t},u.prototype.find=function(e){for(var t,r=this._root,a=r,n=this._comparator;a;){if(0===(t=n(e,a.key)))return a;a=t<0?a.left:a.right}return null},u.prototype.insert=function(e,t){var r=this;if(!this._root)return this._root={parent:null,left:null,right:null,balanceFactor:0,key:e,data:t},this._size++,this._root;var a=this._comparator,n=this._root,o=null,i=0;if(this._noDuplicates)for(;n;){if(i=a(e,n.key),o=n,0===i)return null;n=i<0?n.left:n.right}else for(;n;)i=a(e,n.key),o=n,n=i<=0?n.left:n.right;var f,u={left:null,right:null,balanceFactor:0,parent:o,key:e,data:t};for(i<=0?o.left=u:o.right=u;o&&(i=a(o.key,e),i<0?o.balanceFactor-=1:o.balanceFactor+=1,0!==o.balanceFactor);){if(o.balanceFactor<-1){1===o.right.balanceFactor&&l(o.right),f=s(o),o===r._root&&(r._root=f);break}if(o.balanceFactor>1){-1===o.left.balanceFactor&&s(o.left),f=l(o),o===r._root&&(r._root=f);break}o=o.parent}return this._size++,u},u.prototype.remove=function(e){var t=this;if(!this._root)return null;for(var r=this._root,a=this._comparator,n=0;r&&0!==(n=a(e,r.key));)r=n<0?r.left:r.right;if(!r)return null;var o,i,f=r.key;if(r.left){for(o=r.left;o.left||o.right;){for(;o.right;)o=o.right;r.key=o.key,r.data=o.data,o.left&&(r=o,o=o.left)}r.key=o.key,r.data=o.data,r=o}if(r.right){for(i=r.right;i.left||i.right;){for(;i.left;)i=i.left;r.key=i.key,r.data=i.data,i.right&&(r=i,i=i.right)}r.key=i.key,r.data=i.data,r=i}for(var u,c=r.parent,d=r;c&&(c.left===d?c.balanceFactor-=1:c.balanceFactor+=1,c.balanceFactor<-1?(1===c.right.balanceFactor&&l(c.right),u=s(c),c===t._root&&(t._root=u),c=u):c.balanceFactor>1&&(-1===c.left.balanceFactor&&s(c.left),u=l(c),c===t._root&&(t._root=u),c=u),-1!==c.balanceFactor&&1!==c.balanceFactor);)d=c,c=c.parent;return r.parent&&(r.parent.left===r?r.parent.left=null:r.parent.right=null),r===this._root&&(this._root=null),this._size--,f},u.prototype.load=function(e,t,r){if(void 0===e&&(e=[]),void 0===t&&(t=[]),0!==this._size)throw new Error("bulk-load: tree is not empty");var a=e.length;return r&&i(e,t,0,a-1,this._comparator),this._root=n(null,e,t,0,a),o(this._root),this._size=a,this},u.prototype.isBalanced=function(){return r(this._root)},u.prototype.toString=function(t){return e(this._root,t)},Object.defineProperties(u.prototype,c),u.default=u,u})},{}],2:[function(e,t,r){"use strict";function a(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}Object.defineProperty(r,"__esModule",{value:!0});var n=function(){function e(e,t){for(var r=0;r32)throw new Error("ExpGolomb: readBits() bits exceeded max 32bits!");if(e<=this._current_word_bits_left){var t=this._current_word>>>32-e;return this._current_word<<=e,this._current_word_bits_left-=e,t}var r=this._current_word_bits_left?this._current_word:0;r>>>=32-this._current_word_bits_left;var a=e-this._current_word_bits_left;this._fillCurrentWord();var n=Math.min(a,this._current_word_bits_left),o=this._current_word>>>32-n;return this._current_word<<=n,this._current_word_bits_left-=n,r=r<>>e))return this._current_word<<=e,this._current_word_bits_left-=e,e;return this._fillCurrentWord(),e+this._skipLeadingZero()}},{key:"readUEG",value:function(){var e=this._skipLeadingZero();return this.readBits(e+1)-1}},{key:"readSEG",value:function(){var e=this.readUEG();return 1&e?e+1>>>1:-1*(e>>>1)}}]),e}();r.default=o},{}],3:[function(e,t,r){"use strict";function a(e){return e&&e.__esModule?e:{default:e}}function n(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}Object.defineProperty(r,"__esModule",{value:!0});var o=function(){function e(e,t){for(var r=0;r>>3,m=(7&_[0])<<1|_[1]>>>7,g=(120&_[1])>>>3;e[d[a]]={data:_,originalAudioObjectType:y,samplingIndex:m,channelConfig:g}}}Object.defineProperty(r,"__esModule",{value:!0});var l=function(){function e(e,t){for(var r=0;r=t+r;return 0==r?{size:8,headSize:n,name:"",fullyLoaded:!0}:{size:r,headSize:n,name:a,fullyLoaded:s}}},{key:"parseMoov",value:function(t,r,a,l){for(var u=0;u>1,trackInPreview:(4&p[3])>>2,trackInPoster:(8&p[3])>>3},m=o(p,12),g=o(p,20),w=n(p,34),k=parseFloat(n(p,72)+"."+n(p,74)),S=parseFloat(n(p,76)+"."+n(p,78));t[d.name]={flags:y,trackID:m,duration:g,group:w,trackWidth:k,trackHeight:S};break;case"mdhd":p=new Uint8Array(r.buffer,r.byteOffset+a+u+8,d.size-8);var z=p[0],E=1==z?24:16,U=(1==z?i:o)(p,E);E+=1==z?8:4;var F=n(p,E);t[d.name]={version:z,duration:U,language:F};break;case"stsd":t[d.name]=t[d.name]||[],t[d.name].push({}),e.parseMoov(t[d.name][t[d.name].length-1],r,a+u+16,d.size-16);break;case"avc1":p=new Uint8Array(r.buffer,r.byteOffset+a+u+8,d.size-8);var B=o(p,4),x=n(p,8),A=n(p,10),O=o(p,12),M=o(p,16),C=o(p,20),G=n(p,24),I=n(p,26),D=parseFloat(n(p,28)+"."+n(p,30)),P=parseFloat(n(p,32)+"."+n(p,34)),j=o(p,36),L=n(p,40),T=f(p,42,32),H=n(p,74),R=n(p,76);t[d.name]={dataReferenceIndex:B,version:x,revisionLevel:A,vendor:O,temporalQuality:M,spatialQuality:C,width:G,height:I,horizontalResolution:D,verticalResolution:P,dataSize:j,frameCount:L,compressorName:T,depth:H,colorTableID:R,extensions:{}},e.parseMoov(t[d.name].extensions,r,a+u+86,d.size-86);break;case"avcC":p=new Uint8Array(r.buffer,r.byteOffset+a+u+8,d.size-8);for(var N=p[0],W=p[1],V=p[2],q=p[3],Z=3&p[4],Q=31&p[5],J=new Array(Q),K=void 0,X=6,Y=0;Y=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 | --------------------------------------------------------------------------------