Skip to content

Commit

Permalink
Merge branch 'dev'
Browse files Browse the repository at this point in the history
  • Loading branch information
xfgryujk committed Sep 5, 2020
2 parents 583deb4 + 47d7528 commit cb150ef
Show file tree
Hide file tree
Showing 29 changed files with 1,086 additions and 476 deletions.
7 changes: 6 additions & 1 deletion .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,15 @@ build/
**/node_modules/

# IDEs and editors
/.idea
.idea/

# misc
**/.git*
*.spec
screenshots/
README.md

# runtime data
data/*
!data/config.ini
log/*
16 changes: 9 additions & 7 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -14,20 +14,22 @@ RUN wget https://nodejs.org/dist/v10.16.0/node-v10.16.0-linux-x64.tar.xz \
&& ln -s /node-v10.16.0-linux-x64/bin/npm /usr/local/bin/npm

# 后端依赖
COPY requirements.txt /blivechat/
RUN pip3 install --no-cache-dir -i https://pypi.tuna.tsinghua.edu.cn/simple -r /blivechat/requirements.txt
WORKDIR /blivechat
COPY requirements.txt ./
RUN pip3 install --no-cache-dir -i https://pypi.tuna.tsinghua.edu.cn/simple -r requirements.txt

# 前端依赖
WORKDIR /blivechat/frontend
COPY frontend/package*.json ./
WORKDIR ./frontend
COPY frontend/package.json frontend/package-lock.json ./
RUN npm i --registry=https://registry.npm.taobao.org

# 编译
COPY . /blivechat
# 编译前端
COPY . ../
RUN npm run build

# 运行
WORKDIR /blivechat
WORKDIR ..
VOLUME /blivechat/data /blivechat/log /blivechat/frontend/dist
EXPOSE 12450
ENTRYPOINT ["python3", "main.py"]
CMD ["--host", "0.0.0.0", "--port", "12450"]
88 changes: 80 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
* 支持自动翻译弹幕、醒目留言到日语

## 使用方法
### 本地使用
### 一、本地使用
1. 下载[发布版](https://github.com/xfgryujk/blivechat/releases)(仅提供x64 Windows版)
2. 双击`blivechat.exe`运行服务器,或者用命令行可以指定host和端口号:
```bat
Expand All @@ -28,18 +28,25 @@

**注意事项:**

* 应该先启动blivechat后启动OBS,否则网页会加载失败,这时应该刷新OBS的浏览器源,显示Loaded则加载成功
* 本地使用时不要关闭blivechat.exe那个黑框,否则不能继续获取弹幕
* 样式生成器没有列出所有本地字体,但是可以手动输入本地字体

### 公共服务器
请优先在本地使用,使用公共服务器会有更大的弹幕延迟,而且服务器故障时可能出现直播事故
### 二、公共服务器
请优先在本地使用,使用公共服务器会有更大的弹幕延迟,而且服务器故障时可能发生直播事故

* [第三方公共服务器](http://chat.bilisc.com/)
* [仅样式生成器](https://style.vtbs.moe/)

### 源代码版
1. 编译前端(需要安装Node.js和npm):
### 三、源代码版(自建服务器或在Windows以外平台)
0. 由于使用了git子模块,clone时需要加上`--recursive`参数:
```sh
git clone --recursive https://github.com/xfgryujk/blivechat.git
```
如果已经clone,拉子模块的方法:
```sh
git submodule update --init --recursive
```
1. 编译前端(需要安装Node.js):
```sh
cd frontend
npm i
Expand All @@ -56,8 +63,73 @@
```
3. 用浏览器打开[http://localhost:12450](http://localhost:12450),以下略

### Docker
### 四、Docker(自建服务器)
1. ```sh
docker run -d -p 12450:12450 xfgryujk/blivechat:latest
docker run --name blivechat -d -p 12450:12450 \
--mount source=blc-data,target=/blivechat/data \
--mount source=blc-log,target=/blivechat/log \
--mount source=blc-frontend,target=/blivechat/frontend/dist \
xfgryujk/blivechat:latest
```
2. 用浏览器打开[http://localhost:12450](http://localhost:12450),以下略

### nginx配置(可选)
自建服务器时使用,`sudo vim /etc/nginx/sites-enabled/blivechat.conf`

```conf
upstream blivechat {
keepalive 8;
# blivechat地址
server 127.0.0.1:12450;
}
# 强制HTTPS
server {
listen 80;
listen [::]:80;
server_name YOUR.DOMAIN.NAME;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name YOUR.DOMAIN.NAME;
# SSL
ssl_certificate /PATH/TO/CERT.crt;
ssl_certificate_key /PATH/TO/CERT_KEY.key;
# 代理header
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header Connection "";
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# 静态文件
location / {
root /PATH/TO/BLIVECHAT/frontend/dist;
# 如果文件不存在,交给前端路由
try_files $uri $uri/ /index.html;
}
# 动态API
location /api {
proxy_pass http://blivechat;
}
# websocket
location = /api/chat {
proxy_pass http://blivechat;
# 代理websocket必须设置
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
# 由于这个块有proxy_set_header,这些不会自动继承
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
```
140 changes: 87 additions & 53 deletions api/chat.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ def __parse_gift(self, command):
def __parse_buy_guard(self, command):
data = command['data']
return self._on_buy_guard(blivedm.GuardBuyMessage(
data['uid'], data['username'], None, None, None,
data['uid'], data['username'], data['guard_level'], None, None,
None, None, data['start_time'], None
))

Expand Down Expand Up @@ -149,34 +149,21 @@ async def __on_receive_danmaku(self, danmaku: blivedm.DanmakuMessage):

id_ = uuid.uuid4().hex
# 为了节省带宽用list而不是dict
self.send_message(Command.ADD_TEXT, [
# 0: avatarUrl
self.send_message(Command.ADD_TEXT, make_text_message(
await models.avatar.get_avatar_url(danmaku.uid),
# 1: timestamp
int(danmaku.timestamp / 1000),
# 2: authorName
danmaku.uname,
# 3: authorType
author_type,
# 4: content
danmaku.msg,
# 5: privilegeType
danmaku.privilege_type,
# 6: isGiftDanmaku
1 if danmaku.msg_type else 0,
# 7: authorLevel
danmaku.msg_type,
danmaku.user_level,
# 8: isNewbie
1 if danmaku.urank < 10000 else 0,
# 9: isMobileVerified
1 if danmaku.mobile_verify else 0,
# 10: medalLevel
danmaku.urank < 10000,
danmaku.mobile_verify,
0 if danmaku.room_id != self.room_id else danmaku.medal_level,
# 11: id
id_,
# 12: translation
translation
])
))

if need_translate:
await self._translate_and_response(danmaku.msg, id_)
Expand Down Expand Up @@ -206,7 +193,8 @@ async def __on_buy_guard(self, message: blivedm.GuardBuyMessage):
'id': id_,
'avatarUrl': await models.avatar.get_avatar_url(message.uid),
'timestamp': message.start_time,
'authorName': message.username
'authorName': message.username,
'privilegeType': message.guard_level
})

async def _on_super_chat(self, message: blivedm.SuperChatMessage):
Expand Down Expand Up @@ -244,8 +232,10 @@ async def _on_super_chat_delete(self, message: blivedm.SuperChatDeleteMessage):
})

def _need_translate(self, text):
cfg = config.get_config()
return (
config.get_config().enable_translate
cfg.enable_translate
and (not cfg.allow_translate_rooms or self.room_id in cfg.allow_translate_rooms)
and self.auto_translate_count > 0
and models.translate.need_translate(text)
)
Expand All @@ -266,6 +256,39 @@ async def _translate_and_response(self, text, msg_id):
)


def make_text_message(avatar_url, timestamp, author_name, author_type, content, privilege_type,
is_gift_danmaku, author_level, is_newbie, is_mobile_verified, medal_level,
id_, translation):
return [
# 0: avatarUrl
avatar_url,
# 1: timestamp
timestamp,
# 2: authorName
author_name,
# 3: authorType
author_type,
# 4: content
content,
# 5: privilegeType
privilege_type,
# 6: isGiftDanmaku
1 if is_gift_danmaku else 0,
# 7: authorLevel
author_level,
# 8: isNewbie
1 if is_newbie else 0,
# 9: isMobileVerified
1 if is_mobile_verified else 0,
# 10: medalLevel
medal_level,
# 11: id
id_,
# 12: translation
translation
]


class RoomManager:
def __init__(self):
self._rooms: Dict[int, Room] = {}
Expand All @@ -284,8 +307,7 @@ async def add_client(self, room_id, client: 'ChatHandler'):
if client.auto_translate:
room.auto_translate_count += 1

if client.application.settings['debug']:
await client.send_test_message()
await client.on_join_room()

def del_client(self, room_id, client: 'ChatHandler'):
room = self._rooms.get(room_id, None)
Expand Down Expand Up @@ -390,44 +412,67 @@ def check_origin(self, origin):
return True
return super().check_origin(origin)

@property
def has_joined_room(self):
return self.room_id is not None

def send_message(self, cmd, data):
body = json.dumps({'cmd': cmd, 'data': data})
try:
self.write_message(body)
except tornado.websocket.WebSocketClosedError:
self.on_close()

async def on_join_room(self):
if self.application.settings['debug']:
await self.send_test_message()

# 不允许自动翻译的提示
if self.auto_translate:
cfg = config.get_config()
if cfg.allow_translate_rooms and self.room_id not in cfg.allow_translate_rooms:
self.send_message(Command.ADD_TEXT, make_text_message(
models.avatar.DEFAULT_AVATAR_URL,
int(time.time()),
'blivechat',
2,
'Translation is not allowed in this room. Please download to use translation',
0,
False,
60,
False,
True,
0,
uuid.uuid4().hex,
''
))

# 测试用
async def send_test_message(self):
base_data = {
'avatarUrl': await models.avatar.get_avatar_url(300474),
'timestamp': int(time.time()),
'authorName': 'xfgryujk',
}
text_data = [
# 0: avatarUrl
text_data = make_text_message(
base_data['avatarUrl'],
# 1: timestamp
base_data['timestamp'],
# 2: authorName
base_data['authorName'],
# 3: authorType
0,
# 4: content
'我能吞下玻璃而不伤身体',
# 5: privilegeType
0,
# 6: isGiftDanmaku
0,
# 7: authorLevel
False,
20,
# 8: isNewbie
0,
# 9: isMobileVerified
1,
# 10: medalLevel
False,
True,
0,
# 11: id
uuid.uuid4().hex,
# 12: translation
''
]
)
member_data = {
**base_data,
'id': uuid.uuid4().hex
'id': uuid.uuid4().hex,
'privilegeType': 3
}
gift_data = {
**base_data,
Expand Down Expand Up @@ -461,14 +506,3 @@ async def send_test_message(self):
gift_data['totalCoin'] = 1245000
gift_data['giftName'] = '小电视飞船'
self.send_message(Command.ADD_GIFT, gift_data)

@property
def has_joined_room(self):
return self.room_id is not None

def send_message(self, cmd, data):
body = json.dumps({'cmd': cmd, 'data': data})
try:
self.write_message(body)
except tornado.websocket.WebSocketClosedError:
self.on_close()
Loading

0 comments on commit cb150ef

Please sign in to comment.