├── .gitattributes ├── .github ├── FUNDING.yml └── workflows │ └── pages-deploy.yml ├── .gitignore ├── .prettierrc ├── LICENSE ├── README.md ├── babel.config.js ├── jsconfig.json ├── package.json ├── public ├── index.html └── live.html ├── src ├── components │ ├── DanmakuItem.vue │ ├── DanmakuList.vue │ ├── InputGroup.vue │ └── Live.vue ├── pages │ ├── index │ │ ├── App.vue │ │ └── main.js │ └── live │ │ ├── App.vue │ │ └── main.js └── utils │ ├── biliOpen.js │ ├── bufferPolyfill.js │ ├── face.js │ ├── loadImg.js │ ├── props.js │ ├── protobuf.js │ ├── qrLogin.js │ ├── request.js │ └── storage.js ├── vercel.json ├── vue.config.js └── yarn.lock /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | ko_fi: jindaikirin 2 | custom: ['https://afdian.net/@jindaikirin'] 3 | -------------------------------------------------------------------------------- /.github/workflows/pages-deploy.yml: -------------------------------------------------------------------------------- 1 | name: Deploy to Pages 2 | 3 | on: 4 | workflow_dispatch: 5 | 6 | jobs: 7 | build-and-deploy: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - name: Checkout 11 | uses: actions/checkout@v2 12 | with: 13 | ref: master 14 | persist-credentials: false 15 | - name: Install dependencies 16 | run: yarn install --frozen-lockfile 17 | - name: Build 18 | run: yarn run build 19 | - name: Deploy 20 | uses: JamesIves/github-pages-deploy-action@3.7.1 21 | with: 22 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 23 | BRANCH: dist 24 | FOLDER: dist 25 | CLEAN: true 26 | SINGLE_COMMIT: true 27 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | 9 | # Diagnostic reports (https://nodejs.org/api/report.html) 10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 11 | 12 | # Runtime data 13 | pids 14 | *.pid 15 | *.seed 16 | *.pid.lock 17 | 18 | # Directory for instrumented libs generated by jscoverage/JSCover 19 | lib-cov 20 | 21 | # Coverage directory used by tools like istanbul 22 | coverage 23 | *.lcov 24 | 25 | # nyc test coverage 26 | .nyc_output 27 | 28 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 29 | .grunt 30 | 31 | # Bower dependency directory (https://bower.io/) 32 | bower_components 33 | 34 | # node-waf configuration 35 | .lock-wscript 36 | 37 | # Compiled binary addons (https://nodejs.org/api/addons.html) 38 | build/Release 39 | 40 | # Dependency directories 41 | node_modules/ 42 | jspm_packages/ 43 | 44 | # TypeScript v1 declaration files 45 | typings/ 46 | 47 | # TypeScript cache 48 | *.tsbuildinfo 49 | 50 | # Optional npm cache directory 51 | .npm 52 | 53 | # Optional eslint cache 54 | .eslintcache 55 | 56 | # Microbundle cache 57 | .rpt2_cache/ 58 | .rts2_cache_cjs/ 59 | .rts2_cache_es/ 60 | .rts2_cache_umd/ 61 | 62 | # Optional REPL history 63 | .node_repl_history 64 | 65 | # Output of 'npm pack' 66 | *.tgz 67 | 68 | # Yarn Integrity file 69 | .yarn-integrity 70 | 71 | # dotenv environment variables file 72 | .env 73 | .env.test 74 | 75 | # parcel-bundler cache (https://parceljs.org/) 76 | .cache 77 | 78 | # Next.js build output 79 | .next 80 | 81 | # Nuxt.js build / generate output 82 | .nuxt 83 | dist 84 | 85 | # Gatsby files 86 | .cache/ 87 | # Comment in the public line in if your project uses Gatsby and *not* Next.js 88 | # https://nextjs.org/blog/next-9-1#public-directory-support 89 | # public 90 | 91 | # vuepress build output 92 | .vuepress/dist 93 | 94 | # Serverless directories 95 | .serverless/ 96 | 97 | # FuseBox cache 98 | .fusebox/ 99 | 100 | # DynamoDB Local files 101 | .dynamodb/ 102 | 103 | # TernJS port file 104 | .tern-port 105 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 120, 3 | "singleQuote": true, 4 | "trailingComma": "es5", 5 | "arrowParens": "avoid", 6 | "htmlWhitespaceSensitivity": "css", 7 | "useTabs": false, 8 | "tabWidth": 2, 9 | "semi": true 10 | } 11 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 神代綺凜 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Bilibili Live Chat 2 | 3 | ![Preview](https://i.loli.net/2020/06/20/vXuZKCq396co2HO.gif) 4 | 5 | 这是一个无后端的,仿 YouTube Live Chat 的,箱都不用开就能食用的 Bilibili 直播弹幕姬 6 | 7 | 主要用于 OBS,为的是在低功能需求的情况下,不依靠任何第三方本地软件实现弹幕和礼物的展示 8 | 9 | 老版本在 `v1` 分支,新版本是使用 Vue 3 重构的版本,并增加了一些新特性,成品直接部署在 Github Pages 10 | 11 | ## 食用步骤 12 | 13 | 1. 打开 [blc.lolicon.app](https://blc.lolicon.app/) 14 | 2. 输入房间号,填写设置项,点击“Go!”,然后复制新页面的地址 15 | 3. 在 OBS 中添加“浏览器”来源,将地址粘贴到“URL”处,根据自己需要调整宽高和缩放 16 | 4. Enjoy~ 17 | 18 | ## 其他说明 19 | 20 | ### 连接模式 21 | 22 | B站在2023年7月左右开始对游客模式下的直播弹幕进行用户名打码、限流等操作,如果需要正常使用有两种方法 23 | 24 | 1. 在“普通模式”下额外提供 [live.bilibili.com](https://live.bilibili.com/) 的 cookie,**可以连接任意直播间** 25 | 2. 【推荐】使用“开放平台”模式,需要注册 Bilibili 开放平台个人开发者并提供一些参数,**只能连接自己的直播间** 26 | 27 | #### 普通模式 28 | 29 | 该模式若未提供 cookie 则为游客身份连接,会出现收到的弹幕用户名被打码且随机限流(部分弹幕收不到)的情况 30 | 31 | 若提供 [live.bilibili.com](https://live.bilibili.com/) 的 cookie,则会使用该 cookie 调用B站 API 获取直播弹幕连接 token 32 | 33 | 支持手机 APP 扫码登录(仅限本项目官方站点)([隐私声明](#隐私声明)) 34 | 35 | > [!NOTE] 36 | > 由于需要发送 cookie,因此无论是否开启跨域模式,调用该 API 都需要依赖反代服务(详见[跨域模式](#跨域模式)) 37 | 38 | #### 开放平台 39 | 40 | 该模式只能连接自己的直播间,但为 Bilibili 官方开放的连接方式,因此更推荐使用 41 | 42 | 1. 前往开放平台注册个人开发者([注册地址](https://open-live.bilibili.com/open-register-form/personal)),提交注册后需要等待审核通过 43 | 2. 前往[创作者服务中心](https://open-live.bilibili.com/open-manage)-我的项目,随意创建一个项目,点进项目拿到**项目ID** 44 | 3. 前往[创作者服务中心](https://open-live.bilibili.com/open-manage)-个人资料,拿到 **access_key_id** 和 **access_key_secret** 45 | 4. 获取**身份码**,两种方法任选其一 46 | - [我的直播间](https://link.bilibili.com/p/center/index/#/my-room/start-live)-开始直播-身份码 47 | - [互动应用中心](https://play-live.bilibili.com/)-右下角菜单-身份码 48 | 49 | ### 跨域模式 50 | 51 | B站 API 无法被跨域调用,若不开启跨域模式,则会使用反代服务([隐私声明](#隐私声明)) 52 | 53 | 若在 OBS 使用,则推荐开启跨域模式,方法如下: 54 | 55 | 任何基于 Chromium 的浏览器(例如 OBS Browser 和 Chrome)都可以通过添加 `--disable-web-security` 启动参数来禁用网页安全机制,此时可以开启“跨域模式”选项,几乎所有B站 API 将被直接跨域调用(需要 cookie 的除外),这样就不需要依赖反代服务 56 | 57 | 示例: 58 | 59 | - OBS:直接在启动的快捷方式后追加该参数,然后通过快捷方式启动即可 60 | ![obs](https://i.loli.net/2020/06/20/QkXOfoTalnpAvt3.png) 61 | - Chrome:和 OBS 同理,不过必须额外添加一个 `--user-data-dir` 参数来指定用户目录,随意新建一个空文件夹来指定即可 62 | 该操作看上去十分麻烦,实则是 Chrome 的一个安全措施,因为**禁用网页安全机制是危险行为,日常使用时千万别这么做** 63 | ![chrome](https://s2.loli.net/2023/09/24/KL8UkX93p2ZdYSe.png) 64 | 65 | 其他内核的浏览器可以自行搜索相应参数来禁用网页安全机制 66 | 67 | ### 显示头像 68 | 69 | > 已支持从弹幕信息中获取头像,不再需要调用 API 70 | > 不过普通模式下可能没有头像,不知道为什么B站又不提供 `dm_v2` 了 71 | 72 | 头像加载机制: 73 | 74 | - 获取到头像后,图片会被预加载,加载完毕或超时(5 秒)后弹幕才会被插入弹幕列表 75 | - 非 GIF 头像会优先加载小头像(48x48)以节省流量,若首包到达时间超过 2 秒(B站 COS 图片压缩处理卡了,偶尔可能发生),则会回退为加载完整大小的头像图片 76 | 77 | ## 隐私声明 78 | 79 | 本项目官方站点 [blc.lolicon.app](https://blc.lolicon.app/) 会额外使用到以下两个本人开源并部署在公共平台上的服务: 80 | 81 | 1. B站API反向代理服务 [Tsuk1ko/blc-proxy](https://github.com/Tsuk1ko/blc-proxy) 部署于 HuggingFace 82 | 2. B站扫码登录服务 [Tsuk1ko/bilibili-qr-login](https://github.com/Tsuk1ko/bilibili-qr-login) 部署于 HuggingFace 83 | 84 | 本站及上述服务不会收集任何信息,若不信任请勿在【关闭跨域模式】或【在普通连接模式下提供 cookie】的情况下使用本项目及【扫码登录】功能 85 | 86 | ## Project setup 87 | 88 | ```bash 89 | yarn install 90 | ``` 91 | 92 | ### Compiles and hot-reloads for development 93 | 94 | ```bash 95 | yarn serve 96 | ``` 97 | 98 | ### Compiles and minifies for production 99 | 100 | ```bash 101 | yarn build 102 | ``` 103 | 104 | ### Lints and fixes files 105 | 106 | ```bash 107 | yarn lint 108 | ``` 109 | 110 | ### Customize configuration 111 | 112 | See [Configuration Reference](https://cli.vuejs.org/config/). 113 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: ['lodash', '@babel/plugin-proposal-nullish-coalescing-operator', '@babel/plugin-proposal-optional-chaining'], 3 | presets: ['@vue/cli-plugin-babel/preset'], 4 | }; 5 | -------------------------------------------------------------------------------- /jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": ["./src/**/*"], 3 | "compilerOptions": { 4 | "target": "ESNext", 5 | "baseUrl": ".", 6 | "moduleResolution": "node", 7 | "resolveJsonModule": true, 8 | "paths": { 9 | "@/*": ["src/*"] 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bilibili-live-chat", 3 | "version": "2.8.1", 4 | "private": true, 5 | "scripts": { 6 | "serve": "vue-cli-service serve", 7 | "build": "vue-cli-service build", 8 | "lint": "vue-cli-service lint", 9 | "postversion": "tpv" 10 | }, 11 | "dependencies": { 12 | "@babel/plugin-proposal-nullish-coalescing-operator": "^7.18.6", 13 | "@babel/plugin-proposal-optional-chaining": "^7.21.0", 14 | "bilibili-live-ws": "^6.3.1", 15 | "buffer": "^6.0.3", 16 | "core-js": "^3.32.2", 17 | "lodash": "^4.17.21", 18 | "lru-cache": "^10.0.1", 19 | "md5": "^2.3.0", 20 | "pako": "^2.1.0", 21 | "protobufjs": "^7.2.5", 22 | "query-string": "^7.1.3", 23 | "uuid": "^9.0.1", 24 | "vue": "^3.3.4" 25 | }, 26 | "devDependencies": { 27 | "@tsuk1ko/postversion": "^1.0.2", 28 | "@vue/cli-plugin-babel": "^5.0.8", 29 | "@vue/cli-plugin-eslint": "^5.0.8", 30 | "@vue/cli-service": "^5.0.8", 31 | "@vue/compiler-sfc": "^3.3.4", 32 | "babel-eslint": "^10.1.0", 33 | "babel-plugin-lodash": "^3.3.4", 34 | "eslint": "^7.32.0", 35 | "eslint-plugin-vue": "^9.17.0", 36 | "lint-staged": "^13.3.0", 37 | "prettier": "^3.0.3", 38 | "sass": "^1.68.0", 39 | "sass-loader": "^13.3.2" 40 | }, 41 | "eslintConfig": { 42 | "root": true, 43 | "env": { 44 | "node": true 45 | }, 46 | "extends": [ 47 | "plugin:vue/vue3-essential", 48 | "eslint:recommended" 49 | ], 50 | "parserOptions": { 51 | "parser": "babel-eslint" 52 | }, 53 | "rules": { 54 | "no-empty": "off", 55 | "no-unused-vars": "warn", 56 | "vue/multi-word-component-names": "off" 57 | } 58 | }, 59 | "browserslist": [ 60 | "> 1%", 61 | "last 2 versions", 62 | "not dead" 63 | ], 64 | "gitHooks": { 65 | "pre-commit": "lint-staged" 66 | }, 67 | "lint-staged": { 68 | "*.{js,vue}": [ 69 | "vue-cli-service lint", 70 | "prettier --write", 71 | "git add" 72 | ] 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 10 | 11 | 12 | 13 | Bilibili Live Chat 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 28 | 29 | 30 | 31 |
32 | 33 | 34 | -------------------------------------------------------------------------------- /public/live.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 10 | 11 | 12 | 13 | Bilibili Live Chat 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 27 | 28 | 29 | 30 | 31 |
32 | 33 | 34 | -------------------------------------------------------------------------------- /src/components/DanmakuItem.vue: -------------------------------------------------------------------------------- 1 | 28 | 29 | 67 | 68 | 174 | -------------------------------------------------------------------------------- /src/components/DanmakuList.vue: -------------------------------------------------------------------------------- 1 | 35 | 36 | 145 | 146 | 173 | -------------------------------------------------------------------------------- /src/components/InputGroup.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 18 | -------------------------------------------------------------------------------- /src/components/Live.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 239 | 240 | 251 | -------------------------------------------------------------------------------- /src/pages/index/App.vue: -------------------------------------------------------------------------------- 1 |