mirror of
https://github.com/xfgryujk/blivechat.git
synced 2025-01-31 06:40:09 +08:00
添加super chat消息
This commit is contained in:
parent
83882c53a0
commit
efcecf2715
91
chat.py
91
chat.py
@ -4,6 +4,7 @@ import asyncio
|
||||
import enum
|
||||
import json
|
||||
import logging
|
||||
import time
|
||||
from typing import *
|
||||
|
||||
import aiohttp
|
||||
@ -65,19 +66,38 @@ class Room(blivedm.BLiveClient):
|
||||
client.write_message(body)
|
||||
|
||||
async def __my_on_get_danmaku(self, command):
|
||||
data = {
|
||||
self.send_message(Command.ADD_TEXT, {
|
||||
'avatarUrl': await get_avatar_url(command['info'][2][0]),
|
||||
'timestamp': command['info'][0][4],
|
||||
'content': command['info'][1],
|
||||
'authorName': command['info'][2][1]
|
||||
}
|
||||
self.send_message(Command.ADD_TEXT, data)
|
||||
'authorName': command['info'][2][1],
|
||||
'content': command['info'][1]
|
||||
})
|
||||
|
||||
_COMMAND_HANDLERS['DANMU_MSG'] = __my_on_get_danmaku
|
||||
|
||||
# 新舰长 {'cmd': 'GUARD_BUY', 'data': {'uid': 1822222, 'username': 'MRSKING', 'guard_level': 3,
|
||||
# 'num': 1, 'price': 198000, 'gift_id': 10003, 'gift_name': '舰长', 'start_time': 1558506165,
|
||||
# 'end_time': 1558506165}}
|
||||
async def __my_on_gift(self, command):
|
||||
if command['data']['coin_type'] != 'gold': # 丢人
|
||||
return
|
||||
self.send_message(Command.ADD_GIFT, {
|
||||
'avatarUrl': await get_avatar_url(command['data']['uid']),
|
||||
'authorName': command['data']['uname'],
|
||||
'giftName': command['data']['giftName'],
|
||||
'giftNum': command['data']['num'],
|
||||
'totalCoin': command['data']['total_coin']
|
||||
})
|
||||
|
||||
_COMMAND_HANDLERS['SEND_GIFT'] = __my_on_gift
|
||||
|
||||
async def __on_new_member(self, command):
|
||||
# 新舰长 {'cmd': 'GUARD_BUY', 'data': {'uid': 1822222, 'username': 'MRSKING', 'guard_level': 3,
|
||||
# 'num': 1, 'price': 198000, 'gift_id': 10003, 'gift_name': '舰长', 'start_time': 1558506165,
|
||||
# 'end_time': 1558506165}}
|
||||
self.send_message(Command.ADD_VIP, {
|
||||
'avatarUrl': await get_avatar_url(command['data']['uid']),
|
||||
'authorName': command['data']['username'],
|
||||
})
|
||||
|
||||
_COMMAND_HANDLERS['GUARD_BUY'] = __on_new_member
|
||||
|
||||
|
||||
class RoomManager:
|
||||
@ -94,6 +114,9 @@ class RoomManager:
|
||||
room.start()
|
||||
room.clients.append(client)
|
||||
|
||||
# 测试用
|
||||
# self.__send_test_message(room)
|
||||
|
||||
def del_client(self, room_id, client: 'ChatHandler'):
|
||||
if room_id not in self._rooms:
|
||||
return
|
||||
@ -104,6 +127,54 @@ class RoomManager:
|
||||
room.stop()
|
||||
del self._rooms[room_id]
|
||||
|
||||
# 测试用
|
||||
@staticmethod
|
||||
def __send_test_message(room):
|
||||
room.send_message(Command.ADD_TEXT, {
|
||||
'avatarUrl': 'https://i0.hdslb.com/bfs/face/29b6be8aa611e70a3d3ac219cdaf5e72b604f2de.jpg@24w_24h.webp',
|
||||
'timestamp': time.time(),
|
||||
'authorName': 'xfgryujk',
|
||||
'content': '我能吞下玻璃而不伤身体'
|
||||
})
|
||||
room.send_message(Command.ADD_TEXT, {
|
||||
'avatarUrl': 'https://i0.hdslb.com/bfs/face/29b6be8aa611e70a3d3ac219cdaf5e72b604f2de.jpg@24w_24h.webp',
|
||||
'timestamp': time.time(),
|
||||
'authorName': 'xfgryujk',
|
||||
'content': "I can eat glass, it doesn't hurt me."
|
||||
})
|
||||
room.send_message(Command.ADD_VIP, {
|
||||
'avatarUrl': 'https://i0.hdslb.com/bfs/face/29b6be8aa611e70a3d3ac219cdaf5e72b604f2de.jpg@24w_24h.webp',
|
||||
'authorName': 'xfgryujk',
|
||||
})
|
||||
room.send_message(Command.ADD_GIFT, {
|
||||
'avatarUrl': 'https://i0.hdslb.com/bfs/face/29b6be8aa611e70a3d3ac219cdaf5e72b604f2de.jpg@24w_24h.webp',
|
||||
'authorName': 'xfgryujk',
|
||||
'giftName': '礼花',
|
||||
'giftNum': 1,
|
||||
'totalCoin': 28000
|
||||
})
|
||||
room.send_message(Command.ADD_GIFT, {
|
||||
'avatarUrl': 'https://i0.hdslb.com/bfs/face/29b6be8aa611e70a3d3ac219cdaf5e72b604f2de.jpg@24w_24h.webp',
|
||||
'authorName': 'xfgryujk',
|
||||
'giftName': '节奏风暴',
|
||||
'giftNum': 1,
|
||||
'totalCoin': 100000
|
||||
})
|
||||
room.send_message(Command.ADD_GIFT, {
|
||||
'avatarUrl': 'https://i0.hdslb.com/bfs/face/29b6be8aa611e70a3d3ac219cdaf5e72b604f2de.jpg@24w_24h.webp',
|
||||
'authorName': 'xfgryujk',
|
||||
'giftName': '摩天大楼',
|
||||
'giftNum': 1,
|
||||
'totalCoin': 450000
|
||||
})
|
||||
room.send_message(Command.ADD_GIFT, {
|
||||
'avatarUrl': 'https://i0.hdslb.com/bfs/face/29b6be8aa611e70a3d3ac219cdaf5e72b604f2de.jpg@24w_24h.webp',
|
||||
'authorName': 'xfgryujk',
|
||||
'giftName': '小电视飞船',
|
||||
'giftNum': 1,
|
||||
'totalCoin': 1245000
|
||||
})
|
||||
|
||||
|
||||
room_manager = RoomManager()
|
||||
|
||||
@ -134,5 +205,5 @@ class ChatHandler(tornado.websocket.WebSocketHandler):
|
||||
room_manager.del_client(self.room_id, self)
|
||||
|
||||
# 测试用
|
||||
def check_origin(self, origin):
|
||||
return True
|
||||
# def check_origin(self, origin):
|
||||
# return True
|
||||
|
20
frontend/src/components/LegacyPaidMessage.vue
Normal file
20
frontend/src/components/LegacyPaidMessage.vue
Normal file
@ -0,0 +1,20 @@
|
||||
<template>
|
||||
<yt-live-chat-legacy-paid-message-renderer>
|
||||
<div id="author-photo" :style="`background-image: url(${avatarUrl})`"></div>
|
||||
<div id="content">
|
||||
<div id="event-text">{{title}}</div>
|
||||
<div id="detail-text">{{content}}</div>
|
||||
</div>
|
||||
</yt-live-chat-legacy-paid-message-renderer>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'LegacyPaidMessage',
|
||||
props: {
|
||||
avatarUrl: String,
|
||||
title: String,
|
||||
content: String
|
||||
}
|
||||
}
|
||||
</script>
|
56
frontend/src/components/PaidMessage.vue
Normal file
56
frontend/src/components/PaidMessage.vue
Normal file
@ -0,0 +1,56 @@
|
||||
<template>
|
||||
<yt-live-chat-paid-message-renderer>
|
||||
<div id="header" :style="'background-color: ' + headerColor">
|
||||
<div id="author-photo" :style="`background-image: url(${avatarUrl})`"></div>
|
||||
<div id="header-content">
|
||||
<div id="author-name">{{authorName}}</div>
|
||||
<div id="purchase-amount">{{title}}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="content" :style="'background-color: ' + contentColor">
|
||||
<div id="message" dir="auto">{{content}}</div>
|
||||
</div>
|
||||
</yt-live-chat-paid-message-renderer>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
let LEVEL_TO_HEADER_COLOR = [
|
||||
'rgba(0,184,212,1)', // $2浅蓝
|
||||
'rgba(255,176,0,1)', // $10黄
|
||||
'rgba(245,91,0,1)', // $20橙
|
||||
'rgba(208,0,0,1)' // $100红
|
||||
]
|
||||
let LEVEL_TO_CONTENT_COLOR = [
|
||||
'rgba(0,229,255,1)', // $2浅蓝
|
||||
'rgba(236,182,29,1)', // $10黄
|
||||
'rgba(255,127,0,1)', // $20橙
|
||||
'rgba(230,33,23,1)' // $100红
|
||||
]
|
||||
|
||||
export default {
|
||||
name: 'PaidMessage',
|
||||
props: {
|
||||
level: Number, // 高亮等级,决定颜色
|
||||
avatarUrl: String,
|
||||
authorName: String,
|
||||
title: String,
|
||||
content: String
|
||||
},
|
||||
computed: {
|
||||
headerColor() {
|
||||
if (this.level < 0)
|
||||
return LEVEL_TO_HEADER_COLOR[0]
|
||||
if (this.level >= LEVEL_TO_HEADER_COLOR.length)
|
||||
return LEVEL_TO_HEADER_COLOR[LEVEL_TO_HEADER_COLOR.length - 1]
|
||||
return LEVEL_TO_HEADER_COLOR[this.level]
|
||||
},
|
||||
contentColor() {
|
||||
if (this.level < 0)
|
||||
return LEVEL_TO_CONTENT_COLOR[0]
|
||||
if (this.level >= LEVEL_TO_CONTENT_COLOR.length)
|
||||
return LEVEL_TO_CONTENT_COLOR[LEVEL_TO_CONTENT_COLOR.length - 1]
|
||||
return LEVEL_TO_CONTENT_COLOR[this.level]
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
@ -16,9 +16,16 @@
|
||||
</yt-live-chat-ticker-renderer> -->
|
||||
<yt-live-chat-item-list-renderer>
|
||||
<template v-for="message in messages">
|
||||
<text-message :key="message.id"
|
||||
<text-message :key="message.id" v-if="message.type == 0"
|
||||
:avatarUrl="message.avatarUrl" :time="message.time" :authorName="message.authorName" :content="message.content"
|
||||
></text-message>
|
||||
<legacy-paid-message :key="message.id" v-else-if="message.type == 1"
|
||||
:avatarUrl="message.avatarUrl" :title="message.title" :content="message.content"
|
||||
></legacy-paid-message>
|
||||
<paid-message :key="message.id" v-else
|
||||
:level="message.level" :avatarUrl="message.avatarUrl" :authorName="message.authorName"
|
||||
:title="message.title" :content="message.content"
|
||||
></paid-message>
|
||||
</template>
|
||||
</yt-live-chat-item-list-renderer>
|
||||
</yt-live-chat-renderer>
|
||||
@ -26,11 +33,15 @@
|
||||
|
||||
<script>
|
||||
import TextMessage from './TextMessage.vue'
|
||||
import LegacyPaidMessage from './LegacyPaidMessage.vue'
|
||||
import PaidMessage from './PaidMessage.vue'
|
||||
|
||||
export default {
|
||||
name: 'Room',
|
||||
components: {
|
||||
TextMessage
|
||||
TextMessage,
|
||||
LegacyPaidMessage,
|
||||
PaidMessage
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
@ -40,9 +51,9 @@ export default {
|
||||
}
|
||||
},
|
||||
created() {
|
||||
// this.websocket = new WebSocket(`ws://${window.location.host}/chat`)
|
||||
this.websocket = new WebSocket(`ws://${window.location.host}/chat`)
|
||||
// 测试用
|
||||
this.websocket = new WebSocket('ws://localhost/chat')
|
||||
// this.websocket = new WebSocket('ws://localhost/chat')
|
||||
this.websocket.onopen = () => this.websocket.send(JSON.stringify({
|
||||
cmd: 0, // JOIN_ROOM
|
||||
data: {
|
||||
@ -51,23 +62,57 @@ export default {
|
||||
}))
|
||||
this.websocket.onmessage = (event) => {
|
||||
let body = JSON.parse(event.data)
|
||||
let time = new Date(body.data.timestamp * 1000)
|
||||
let message = {
|
||||
id: this.nextId++,
|
||||
time: `${time.getHours()}:${time.getMinutes()}`,
|
||||
...body.data
|
||||
}
|
||||
let message = null
|
||||
let time, price, level
|
||||
switch(body.cmd) {
|
||||
case 1: // ADD_TEXT
|
||||
this.messages.push(message)
|
||||
if (this.messages.length > 50)
|
||||
this.messages.shift()
|
||||
time = new Date(body.data.timestamp * 1000)
|
||||
message = {
|
||||
id: this.nextId++,
|
||||
type: 0, // TextMessage
|
||||
avatarUrl: body.data.avatarUrl,
|
||||
time: `${time.getHours()}:${time.getMinutes()}`,
|
||||
authorName: body.data.authorName,
|
||||
content: body.data.content
|
||||
}
|
||||
break;
|
||||
case 2: // ADD_GIFT
|
||||
price = body.data.totalCoin / 1000
|
||||
if (price < 9.9) // 丢人
|
||||
break
|
||||
else if (price < 100) // B坷垃~打call
|
||||
level = 0
|
||||
else if (price < 300) // 节奏风暴、天空之翼
|
||||
level = 1
|
||||
else if (price < 500) // 摩天大楼
|
||||
level = 2
|
||||
else // 小电视飞船
|
||||
level = 3
|
||||
message = {
|
||||
id: this.nextId++,
|
||||
type: 2, // PaidMessage
|
||||
level: level,
|
||||
avatarUrl: body.data.avatarUrl,
|
||||
authorName: body.data.authorName,
|
||||
title: `CNY${price}`,
|
||||
content: `Sent ${body.data.giftName}x${body.data.giftNum}`
|
||||
}
|
||||
break;
|
||||
case 3: // ADD_VIP
|
||||
message = {
|
||||
id: this.nextId++,
|
||||
type: 1, // LegacyPaidMessage
|
||||
avatarUrl: body.data.avatarUrl,
|
||||
title: `NEW MEMBER!`,
|
||||
content: `Welcome ${body.data.authorName}`
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (message) {
|
||||
this.messages.push(message)
|
||||
if (this.messages.length > 50)
|
||||
this.messages.shift()
|
||||
}
|
||||
}
|
||||
},
|
||||
beforeDestroy() {
|
||||
|
Loading…
Reference in New Issue
Block a user