添加super chat消息

This commit is contained in:
John Smith 2019-05-22 19:38:36 +08:00
parent 83882c53a0
commit efcecf2715
4 changed files with 215 additions and 23 deletions

91
chat.py
View File

@ -4,6 +4,7 @@ import asyncio
import enum import enum
import json import json
import logging import logging
import time
from typing import * from typing import *
import aiohttp import aiohttp
@ -65,19 +66,38 @@ class Room(blivedm.BLiveClient):
client.write_message(body) client.write_message(body)
async def __my_on_get_danmaku(self, command): async def __my_on_get_danmaku(self, command):
data = { self.send_message(Command.ADD_TEXT, {
'avatarUrl': await get_avatar_url(command['info'][2][0]), 'avatarUrl': await get_avatar_url(command['info'][2][0]),
'timestamp': command['info'][0][4], 'timestamp': command['info'][0][4],
'content': command['info'][1], 'authorName': command['info'][2][1],
'authorName': command['info'][2][1] 'content': command['info'][1]
} })
self.send_message(Command.ADD_TEXT, data)
_COMMAND_HANDLERS['DANMU_MSG'] = __my_on_get_danmaku _COMMAND_HANDLERS['DANMU_MSG'] = __my_on_get_danmaku
# 新舰长 {'cmd': 'GUARD_BUY', 'data': {'uid': 1822222, 'username': 'MRSKING', 'guard_level': 3, async def __my_on_gift(self, command):
# 'num': 1, 'price': 198000, 'gift_id': 10003, 'gift_name': '舰长', 'start_time': 1558506165, if command['data']['coin_type'] != 'gold': # 丢人
# 'end_time': 1558506165}} 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: class RoomManager:
@ -94,6 +114,9 @@ class RoomManager:
room.start() room.start()
room.clients.append(client) room.clients.append(client)
# 测试用
# self.__send_test_message(room)
def del_client(self, room_id, client: 'ChatHandler'): def del_client(self, room_id, client: 'ChatHandler'):
if room_id not in self._rooms: if room_id not in self._rooms:
return return
@ -104,6 +127,54 @@ class RoomManager:
room.stop() room.stop()
del self._rooms[room_id] 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() room_manager = RoomManager()
@ -134,5 +205,5 @@ class ChatHandler(tornado.websocket.WebSocketHandler):
room_manager.del_client(self.room_id, self) room_manager.del_client(self.room_id, self)
# 测试用 # 测试用
def check_origin(self, origin): # def check_origin(self, origin):
return True # return True

View 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>

View 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>

View File

@ -16,9 +16,16 @@
</yt-live-chat-ticker-renderer> --> </yt-live-chat-ticker-renderer> -->
<yt-live-chat-item-list-renderer> <yt-live-chat-item-list-renderer>
<template v-for="message in messages"> <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" :avatarUrl="message.avatarUrl" :time="message.time" :authorName="message.authorName" :content="message.content"
></text-message> ></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> </template>
</yt-live-chat-item-list-renderer> </yt-live-chat-item-list-renderer>
</yt-live-chat-renderer> </yt-live-chat-renderer>
@ -26,11 +33,15 @@
<script> <script>
import TextMessage from './TextMessage.vue' import TextMessage from './TextMessage.vue'
import LegacyPaidMessage from './LegacyPaidMessage.vue'
import PaidMessage from './PaidMessage.vue'
export default { export default {
name: 'Room', name: 'Room',
components: { components: {
TextMessage TextMessage,
LegacyPaidMessage,
PaidMessage
}, },
data() { data() {
return { return {
@ -40,9 +51,9 @@ export default {
} }
}, },
created() { 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({ this.websocket.onopen = () => this.websocket.send(JSON.stringify({
cmd: 0, // JOIN_ROOM cmd: 0, // JOIN_ROOM
data: { data: {
@ -51,23 +62,57 @@ export default {
})) }))
this.websocket.onmessage = (event) => { this.websocket.onmessage = (event) => {
let body = JSON.parse(event.data) let body = JSON.parse(event.data)
let time = new Date(body.data.timestamp * 1000) let message = null
let message = { let time, price, level
id: this.nextId++,
time: `${time.getHours()}:${time.getMinutes()}`,
...body.data
}
switch(body.cmd) { switch(body.cmd) {
case 1: // ADD_TEXT case 1: // ADD_TEXT
this.messages.push(message) time = new Date(body.data.timestamp * 1000)
if (this.messages.length > 50) message = {
this.messages.shift() id: this.nextId++,
type: 0, // TextMessage
avatarUrl: body.data.avatarUrl,
time: `${time.getHours()}:${time.getMinutes()}`,
authorName: body.data.authorName,
content: body.data.content
}
break; break;
case 2: // ADD_GIFT 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; break;
case 3: // ADD_VIP case 3: // ADD_VIP
message = {
id: this.nextId++,
type: 1, // LegacyPaidMessage
avatarUrl: body.data.avatarUrl,
title: `NEW MEMBER!`,
content: `Welcome ${body.data.authorName}`
}
break; break;
} }
if (message) {
this.messages.push(message)
if (this.messages.length > 50)
this.messages.shift()
}
} }
}, },
beforeDestroy() { beforeDestroy() {