├── .nvmrc
├── public
├── favicon.ico
├── images
│ └── og-media.png
├── robots.txt
└── sitemap.xml
├── src
├── assets
│ ├── logo.png
│ ├── images
│ │ └── j9rSZOk.png
│ └── style.css
├── constants.js
├── components
│ ├── Analysis.vue
│ ├── GetComments.vue
│ ├── CommentItem.vue
│ └── MainArea.vue
├── main.js
├── App.vue
└── store.js
├── vercel.json
├── .eslintrc.json
├── .gitignore
├── package.json
├── README.md
├── vite.config.js
└── index.html
/.nvmrc:
--------------------------------------------------------------------------------
1 | 18
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/circle-hotaru/bilibili-comment2png/HEAD/public/favicon.ico
--------------------------------------------------------------------------------
/src/assets/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/circle-hotaru/bilibili-comment2png/HEAD/src/assets/logo.png
--------------------------------------------------------------------------------
/public/images/og-media.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/circle-hotaru/bilibili-comment2png/HEAD/public/images/og-media.png
--------------------------------------------------------------------------------
/src/assets/images/j9rSZOk.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/circle-hotaru/bilibili-comment2png/HEAD/src/assets/images/j9rSZOk.png
--------------------------------------------------------------------------------
/public/robots.txt:
--------------------------------------------------------------------------------
1 | # *
2 | User-agent: *
3 | Allow: /
4 |
5 | # Sitemaps
6 | Sitemap: https://bilibili.circlehotarux.me/sitemap.xml
7 |
--------------------------------------------------------------------------------
/vercel.json:
--------------------------------------------------------------------------------
1 | {
2 | "rewrites": [
3 | {
4 | "source": "/bili.api/:path*",
5 | "destination": "https://api.bilibili.com/:path*"
6 | }
7 | ]
8 | }
9 |
--------------------------------------------------------------------------------
/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "parser": "@babel/eslint-parser",
3 | "root": true,
4 | "env": {
5 | "node": true,
6 | "browser": true
7 | },
8 | "extends": ["eslint:recommended", "plugin:vue/essential"]
9 | }
10 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | /dist
4 |
5 |
6 | # local env files
7 | .env.local
8 | .env.*.local
9 |
10 | # Log files
11 | npm-debug.log*
12 | yarn-debug.log*
13 | yarn-error.log*
14 | pnpm-debug.log*
15 |
16 | # Editor directories and files
17 | .idea
18 | .vscode
19 | *.suo
20 | *.ntvs*
21 | *.njsproj
22 | *.sln
23 | *.sw?
24 |
--------------------------------------------------------------------------------
/src/constants.js:
--------------------------------------------------------------------------------
1 | export const SYSTEM_MESSAGE =
2 | 'You are a professional social media analyst. I will send you the comments from a video, please provide a brief summary and analysis of these comments, including the sentiment tendencies of the comments, as well as extract valuable suggestions from the comments. Please communicate with me in Chinese.'
3 |
--------------------------------------------------------------------------------
/src/components/Analysis.vue:
--------------------------------------------------------------------------------
1 |
2 |
6 | {{ sharedState.analysis }}
7 |
8 |
9 |
10 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/src/main.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import App from './App.vue'
3 | import { BootstrapVue, IconsPlugin } from 'bootstrap-vue'
4 | import 'normalize.css/normalize.css'
5 | import 'bootstrap/dist/css/bootstrap.css'
6 | import 'bootstrap-vue/dist/bootstrap-vue.css'
7 | import './assets/style.css'
8 |
9 | Vue.use(BootstrapVue)
10 | Vue.use(IconsPlugin)
11 |
12 | Vue.config.productionTip = false
13 |
14 | new Vue({
15 | render: h => h(App),
16 | }).$mount('#app')
17 |
--------------------------------------------------------------------------------
/src/assets/style.css:
--------------------------------------------------------------------------------
1 | :root {
2 | --comment-general-background: #f9f9f9;
3 | --comment-text-primary: #222;
4 | --comment-text-secondary: #aaa;
5 | --comment-dark-background: #181818;
6 | --comment-dark-text-primary: #fff;
7 | }
8 |
9 | body {
10 | font-family: -apple-system, system-ui, BlinkMacSystemFont, sans-serif;
11 | font-size: 0.9rem;
12 | font-weight: 400;
13 | line-height: 1.6;
14 | color: #212529;
15 | text-align: left;
16 | background-color: #f2f2f2;
17 | }
18 |
--------------------------------------------------------------------------------
/public/sitemap.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | https://bilibili.circlehotarux.me2022-08-231
4 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "bilibili-comment2png",
3 | "version": "0.1.3",
4 | "private": true,
5 | "engines": {
6 | "node": ">=18"
7 | },
8 | "scripts": {
9 | "dev": "vite",
10 | "build": "vite build",
11 | "serve": "vite preview"
12 | },
13 | "dependencies": {
14 | "axios": "^0.28.0",
15 | "bootstrap": "4.5.3",
16 | "bootstrap-vue": "2.18.1",
17 | "file-saver": "2.0.2",
18 | "html2canvas": "1.0.0-rc.7",
19 | "jszip": "3.5.0",
20 | "normalize.css": "8.0.1",
21 | "vue": "^2.6.11"
22 | },
23 | "devDependencies": {
24 | "eslint": "^8.22.0",
25 | "eslint-plugin-vue": "^8.7.1",
26 | "vite": "^2.7.2",
27 | "vite-plugin-env-compatible": "^1.1.1",
28 | "vite-plugin-html": "3.2.0",
29 | "vite-plugin-vue2": "^1.9.0"
30 | },
31 | "browserslist": [
32 | "> 1%",
33 | "last 2 versions",
34 | "not dead"
35 | ]
36 | }
37 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Bilibili 评论转图片神器
2 |
3 | 供 Bilibili UP 主与观众互动,将 Bilibili 视频评论区的评论转换成 PNG,应用场景如:呈现观众评论、评论互动、频道 Q&A,将会陆续完善其他功能,敬请期待!
4 |
5 | 目前功能特色:
6 |
7 | - AI 总结评论
8 | - 无评论获取数量上限
9 | - 自由修改评论外观
10 | - ZIP 压缩包打包下载
11 | - 评论内容为文件名
12 |
13 | ## Demo
14 |
15 | https://bilibili.incircle.dev
16 |
17 | ## Technology Stack
18 |
19 | - Vue
20 | - Bootstrap
21 | - html2canvas
22 | - JSZip
23 |
24 | ## Installation & Usage
25 |
26 | 1. Clone or Download the repository (Depending on whether you are using HTTPS or SSH)
27 |
28 | ```
29 | git clone https://github.com/circle-hotaru/bilibili-comment2png.git
30 | cd bilibili-comment2png
31 | ```
32 |
33 | 2. Install dependencies
34 |
35 | ```
36 | npm i
37 | ```
38 |
39 | 3. Start the application
40 |
41 | ```
42 | npm run serve
43 | ```
44 |
45 | After the application starts visit http://localhost:8080 to view it in the browser.
46 |
47 | ## 🙏 感谢
48 |
49 | https://github.com/SocialSisterYi/bilibili-API-collect
50 |
--------------------------------------------------------------------------------
/vite.config.js:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'vite'
2 | import path from 'path'
3 | import { createVuePlugin } from 'vite-plugin-vue2'
4 | import envCompatible from 'vite-plugin-env-compatible'
5 | import { createHtmlPlugin } from 'vite-plugin-html'
6 |
7 | // https://vitejs.dev/config/
8 | export default defineConfig({
9 | resolve: {
10 | alias: [
11 | {
12 | find: /^~/,
13 | replacement: '',
14 | },
15 | {
16 | find: '@',
17 | replacement: path.resolve(__dirname, './src'), //eslint-disable-line
18 | },
19 | ],
20 | extensions: ['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json', '.vue'],
21 | },
22 | plugins: [
23 | createVuePlugin({ jsx: true }),
24 | envCompatible(),
25 | createHtmlPlugin({
26 | inject: {
27 | data: {
28 | title: 'bilibili-comment2png',
29 | },
30 | },
31 | }),
32 | ],
33 | base: './',
34 | build: {},
35 | server: {
36 | proxy: {
37 | '/bili.api': {
38 | target: 'https://api.bilibili.com',
39 | changeOrigin: true,
40 | rewrite: (path) => path.replace(/^\/bili.api/, ''),
41 | },
42 | },
43 | },
44 | })
45 |
--------------------------------------------------------------------------------
/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
Bilibili 评论转图片神器
6 |
7 |

12 |
13 |
14 |
15 |
16 | 此工具由
17 | circlehotarux
20 | 开发可以将 Bilibili
21 | 视频评论区里的评论转换成图片。应用场景如:呈现观众评论、评论互动、频道Q&A,将会陆续完善其他功能,敬请期待。
22 |
23 |
目前功能特色:
24 |
25 | - AI总结评论
26 | - 无评论获取数量上限
27 | - 自由修改评论外观
28 | - ZIP压缩包打包下载
29 | - 评论内容为文件名
30 |
31 |
32 |
33 |
34 |
39 |
40 |
41 |
42 |
56 |
57 |
66 |
--------------------------------------------------------------------------------
/src/components/GetComments.vue:
--------------------------------------------------------------------------------
1 |
2 |
45 |
46 |
47 |
67 |
68 |
69 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
12 |
16 |
17 |
18 |
19 |
23 |
24 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
38 |
42 |
43 | Bilibili 评论转图片神器
44 |
45 |
46 |
47 |
53 |
54 |
55 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/src/store.js:
--------------------------------------------------------------------------------
1 | import axios from 'axios'
2 | import { SYSTEM_MESSAGE } from './constants'
3 |
4 | export const store = {
5 | state: {
6 | AVId: '',
7 | BVId: '',
8 | title: '',
9 | fetching: false,
10 | pending: false,
11 | comments: [],
12 | // 排序模式 0按时间,2按热度
13 | mode: 2,
14 | // 调整评论样式圆角
15 | borderRadius: 10,
16 | displayTime: true,
17 | darkTheme: false,
18 | // 评论数
19 | count: 0,
20 | // 当前页
21 | currentPage: 1,
22 | // 页面尺寸
23 | perPage: 20,
24 | // 下载评论开关
25 | download: false,
26 | fetchingAnalysis: false,
27 | analysis: undefined,
28 | },
29 | getId() {
30 | this.state.fetching = true
31 |
32 | const rawBVID = this.state.BVId
33 | const regex = /BV[0-9A-Z]+/i
34 | const matches = rawBVID.match(regex)
35 | const realBVID = matches ? matches[0].replace(/^BV/, '') : rawBVID
36 |
37 | const url = `/bili.api/x/web-interface/view?bvid=${realBVID}`
38 | axios
39 | .get(url)
40 | .then((response) => {
41 | const { data } = response
42 | this.state.AVId = data.data.aid
43 | this.state.title = data.data.title
44 | this.getComments()
45 | })
46 | .catch((error) => console.error(error))
47 | },
48 | getComments() {
49 | const url = `/bili.api/x/v2/reply?type=1&oid=${this.state.AVId}&sort=${this.state.mode}&pn=${this.state.currentPage}&ps=${this.state.perPage}&nohot=1`
50 | axios
51 | .get(url)
52 | .then((response) => {
53 | const { data } = response
54 | if (data.code === 0) {
55 | this.state.comments = data.data.replies
56 | this.state.count = data.data.page.count
57 | this.state.fetching = false
58 | } else {
59 | this.state.fetching = false
60 | console.log(data.message)
61 | }
62 | })
63 | .catch((error) => {
64 | this.state.fetching = false
65 | console.error(error)
66 | })
67 | },
68 | downloadComments() {
69 | this.state.download = true
70 | },
71 | getAnalysis() {
72 | this.state.fetchingAnalysis = true
73 | const comments = this.state.comments
74 | .map((comment) => comment.content.message)
75 | .join(';')
76 | const apiURL = `${process.env.VUE_APP_OPENAI_API_URL}/v1/chat/completions`
77 | const messages = [
78 | {
79 | role: 'system',
80 | content: SYSTEM_MESSAGE,
81 | },
82 | {
83 | role: 'user',
84 | content: comments,
85 | },
86 | ]
87 | axios
88 | .post(
89 | apiURL,
90 | {
91 | model: 'gpt-4o-2024-05-13',
92 | messages: messages,
93 | },
94 | {
95 | headers: {
96 | 'Content-Type': 'application/json',
97 | Authorization: `Bearer ${process.env.VUE_APP_OPENAI_API_KEY}`,
98 | },
99 | }
100 | )
101 | .then(({ data }) => {
102 | this.state.fetchingAnalysis = false
103 | this.state.analysis = data.choices[0].message.content
104 | })
105 | .catch((error) => {
106 | this.state.fetchingAnalysis = false
107 | console.error(error)
108 | })
109 | },
110 | }
111 |
--------------------------------------------------------------------------------
/src/components/CommentItem.vue:
--------------------------------------------------------------------------------
1 |
2 |
25 |
26 |
27 |
124 |
125 |
178 |
--------------------------------------------------------------------------------
/src/components/MainArea.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
9 |
17 |
18 |
19 | 显示时间
22 |
23 |
24 | 深色主题
27 |
28 |
29 |
38 |
39 |
40 |
49 |
50 |
51 |
66 |
67 |
68 |
78 |
79 |
80 |
86 |
87 |
88 |
89 |
90 |
177 |
178 |
179 |
--------------------------------------------------------------------------------