blivechat/frontend/src/views/Room.vue

397 lines
12 KiB
Vue
Raw Normal View History

2019-06-17 12:29:25 +08:00
<template>
<chat-renderer ref="renderer" :maxNumber="config.maxNumber" :showGiftName="config.showGiftName"></chat-renderer>
2019-06-17 12:29:25 +08:00
</template>
<script>
2022-02-26 14:53:22 +08:00
import * as i18n from '@/i18n'
2022-01-04 21:41:12 +08:00
import { mergeConfig, toBool, toInt } from '@/utils'
2022-02-27 14:45:19 +08:00
import * as trie from '@/utils/trie'
2020-11-28 21:53:49 +08:00
import * as pronunciation from '@/utils/pronunciation'
import * as chatConfig from '@/api/chatConfig'
import * as chat from '@/api/chat'
2021-04-05 18:48:49 +08:00
import ChatClientTest from '@/api/chat/ChatClientTest'
2023-09-09 23:16:13 +08:00
import ChatClientDirectWeb from '@/api/chat/ChatClientDirectWeb'
import ChatClientDirectOpenLive from '@/api/chat/ChatClientDirectOpenLive'
import ChatClientRelay from '@/api/chat/ChatClientRelay'
2019-06-17 12:29:25 +08:00
import ChatRenderer from '@/components/ChatRenderer'
2019-06-22 16:15:40 +08:00
import * as constants from '@/components/ChatRenderer/constants'
2019-06-17 12:29:25 +08:00
export default {
name: 'Room',
components: {
ChatRenderer
},
2021-04-05 18:48:49 +08:00
props: {
2023-09-09 17:13:53 +08:00
roomKeyType: {
type: Number,
2023-09-09 17:13:53 +08:00
default: 1
},
roomKeyValue: {
type: [Number, String],
default: null
},
strConfig: {
type: Object,
default: () => ({})
}
2021-04-05 18:48:49 +08:00
},
2019-06-17 12:29:25 +08:00
data() {
return {
2022-02-26 23:27:10 +08:00
config: chatConfig.deepCloneDefaultConfig(),
2020-11-28 21:53:49 +08:00
chatClient: null,
2023-08-27 00:23:52 +08:00
pronunciationConverter: null,
textEmoticons: [], // 官方的文本表情
}
},
computed: {
2022-02-27 14:45:19 +08:00
blockKeywordsTrie() {
let blockKeywords = this.config.blockKeywords.split('\n')
let res = new trie.Trie()
for (let keyword of blockKeywords) {
if (keyword !== '') {
res.set(keyword, true)
}
}
return res
},
blockUsersTrie() {
let blockUsers = this.config.blockUsers.split('\n')
let res = new trie.Trie()
for (let user of blockUsers) {
if (user !== '') {
res.set(user, true)
}
}
return res
},
2022-02-27 14:45:19 +08:00
emoticonsTrie() {
let res = new trie.Trie()
for (let emoticons of [this.config.emoticons, this.textEmoticons]) {
for (let emoticon of emoticons) {
if (emoticon.keyword !== '' && emoticon.url !== '') {
res.set(emoticon.keyword, emoticon)
}
2022-02-27 14:45:19 +08:00
}
}
return res
2019-06-17 12:29:25 +08:00
}
},
2020-11-28 21:53:49 +08:00
mounted() {
2020-09-12 17:37:52 +08:00
this.initConfig()
this.initChatClient()
this.initTextEmoticons()
2020-11-28 21:53:49 +08:00
if (this.config.giftUsernamePronunciation !== '') {
this.pronunciationConverter = new pronunciation.PronunciationConverter()
this.pronunciationConverter.loadDict(this.config.giftUsernamePronunciation)
}
2020-02-29 19:20:29 +08:00
// 提示用户已加载
this.$message({
message: 'Loaded',
duration: 500
2020-02-29 19:20:29 +08:00
})
2019-06-17 12:29:25 +08:00
},
beforeDestroy() {
2020-09-12 17:37:52 +08:00
if (this.chatClient) {
this.chatClient.stop()
}
2019-06-17 12:29:25 +08:00
},
methods: {
2020-09-12 17:37:52 +08:00
initConfig() {
2022-02-26 14:53:22 +08:00
let locale = this.strConfig.lang
if (locale) {
i18n.setLocale(locale)
}
2020-02-01 21:27:50 +08:00
let cfg = {}
// 留空的使用默认值
for (let i in this.strConfig) {
if (this.strConfig[i] !== '') {
cfg[i] = this.strConfig[i]
2020-02-01 21:27:50 +08:00
}
2019-10-06 16:20:48 +08:00
}
2022-02-26 23:27:10 +08:00
cfg = mergeConfig(cfg, chatConfig.deepCloneDefaultConfig())
2020-02-01 21:27:50 +08:00
cfg.minGiftPrice = toInt(cfg.minGiftPrice, chatConfig.DEFAULT_CONFIG.minGiftPrice)
2020-02-01 21:27:50 +08:00
cfg.showDanmaku = toBool(cfg.showDanmaku)
cfg.showGift = toBool(cfg.showGift)
cfg.showGiftName = toBool(cfg.showGiftName)
cfg.mergeSimilarDanmaku = toBool(cfg.mergeSimilarDanmaku)
cfg.mergeGift = toBool(cfg.mergeGift)
cfg.maxNumber = toInt(cfg.maxNumber, chatConfig.DEFAULT_CONFIG.maxNumber)
2022-02-26 23:27:10 +08:00
2020-02-01 21:27:50 +08:00
cfg.blockGiftDanmaku = toBool(cfg.blockGiftDanmaku)
cfg.blockLevel = toInt(cfg.blockLevel, chatConfig.DEFAULT_CONFIG.blockLevel)
2020-02-01 21:27:50 +08:00
cfg.blockNewbie = toBool(cfg.blockNewbie)
cfg.blockNotMobileVerified = toBool(cfg.blockNotMobileVerified)
cfg.blockMedalLevel = toInt(cfg.blockMedalLevel, chatConfig.DEFAULT_CONFIG.blockMedalLevel)
2022-02-26 23:27:10 +08:00
cfg.relayMessagesByServer = toBool(cfg.relayMessagesByServer)
2020-02-06 17:39:56 +08:00
cfg.autoTranslate = toBool(cfg.autoTranslate)
2022-02-26 23:27:10 +08:00
cfg.emoticons = this.toObjIfJson(cfg.emoticons)
2020-02-01 21:27:50 +08:00
2022-02-26 23:27:10 +08:00
chatConfig.sanitizeConfig(cfg)
2020-02-01 21:27:50 +08:00
this.config = cfg
2019-10-06 16:20:48 +08:00
},
2022-02-26 23:27:10 +08:00
toObjIfJson(str) {
if (typeof str !== 'string') {
return str
}
try {
return JSON.parse(str)
} catch {
return {}
}
},
2020-09-12 17:37:52 +08:00
initChatClient() {
2023-09-09 17:13:53 +08:00
if (this.roomKeyValue === null) {
2021-04-05 18:48:49 +08:00
this.chatClient = new ChatClientTest()
2023-09-09 17:13:53 +08:00
} else if (this.config.relayMessagesByServer) {
let roomKey = {
type: this.roomKeyType,
value: this.roomKeyValue
}
this.chatClient = new ChatClientRelay(roomKey, this.config.autoTranslate)
} else {
2023-09-09 17:13:53 +08:00
if (this.roomKeyType === 1) {
2023-09-09 23:16:13 +08:00
this.chatClient = new ChatClientDirectWeb(this.roomKeyValue)
2021-04-05 18:48:49 +08:00
} else {
2023-09-09 23:16:13 +08:00
this.chatClient = new ChatClientDirectOpenLive(this.roomKeyValue)
2021-04-05 18:48:49 +08:00
}
}
2020-09-12 17:37:52 +08:00
this.chatClient.onAddText = this.onAddText
this.chatClient.onAddGift = this.onAddGift
this.chatClient.onAddMember = this.onAddMember
this.chatClient.onAddSuperChat = this.onAddSuperChat
this.chatClient.onDelSuperChat = this.onDelSuperChat
this.chatClient.onUpdateTranslation = this.onUpdateTranslation
this.chatClient.onFatalError = this.onFatalError
2020-09-12 17:37:52 +08:00
this.chatClient.start()
2019-10-06 16:20:48 +08:00
},
async initTextEmoticons() {
this.textEmoticons = await chat.getTextEmoticons()
},
2020-09-12 17:37:52 +08:00
start() {
this.chatClient.start()
},
stop() {
this.chatClient.stop()
},
2020-09-12 17:37:52 +08:00
onAddText(data) {
if (!this.config.showDanmaku || !this.filterTextMessage(data) || this.mergeSimilarText(data.content)) {
return
}
let message = {
id: data.id,
type: constants.MESSAGE_TYPE_TEXT,
avatarUrl: data.avatarUrl,
time: new Date(data.timestamp * 1000),
authorName: data.authorName,
authorType: data.authorType,
content: data.content,
2022-02-27 14:45:19 +08:00
richContent: this.getRichContent(data),
2020-09-12 17:37:52 +08:00
privilegeType: data.privilegeType,
repeated: 1,
translation: data.translation
}
this.$refs.renderer.addMessage(message)
2019-06-17 12:29:25 +08:00
},
2020-09-12 17:37:52 +08:00
onAddGift(data) {
if (!this.config.showGift) {
return
2019-10-06 16:20:48 +08:00
}
2020-09-12 17:37:52 +08:00
let price = data.totalCoin / 1000
if (this.mergeSimilarGift(data.authorName, price, data.giftName, data.num)) {
2019-10-06 16:20:48 +08:00
return
}
2020-09-12 17:37:52 +08:00
if (price < this.config.minGiftPrice) { // 丢人
return
}
let message = {
id: data.id,
type: constants.MESSAGE_TYPE_GIFT,
avatarUrl: data.avatarUrl,
time: new Date(data.timestamp * 1000),
authorName: data.authorName,
2020-11-28 21:53:49 +08:00
authorNamePronunciation: this.getPronunciation(data.authorName),
2020-09-12 17:37:52 +08:00
price: price,
giftName: data.giftName,
num: data.num
}
this.$refs.renderer.addMessage(message)
2019-10-06 16:20:48 +08:00
},
2020-09-12 17:37:52 +08:00
onAddMember(data) {
if (!this.config.showGift || !this.filterNewMemberMessage(data)) {
return
2019-06-17 12:29:25 +08:00
}
2020-09-12 17:37:52 +08:00
let message = {
id: data.id,
type: constants.MESSAGE_TYPE_MEMBER,
avatarUrl: data.avatarUrl,
time: new Date(data.timestamp * 1000),
authorName: data.authorName,
2020-11-28 21:53:49 +08:00
authorNamePronunciation: this.getPronunciation(data.authorName),
2020-09-12 17:37:52 +08:00
privilegeType: data.privilegeType,
2022-02-26 14:53:22 +08:00
title: this.$t('chat.membershipTitle')
2020-09-12 17:37:52 +08:00
}
this.$refs.renderer.addMessage(message)
},
onAddSuperChat(data) {
if (!this.config.showGift || !this.filterSuperChatMessage(data)) {
return
}
if (data.price < this.config.minGiftPrice) { // 丢人
return
}
let message = {
id: data.id,
type: constants.MESSAGE_TYPE_SUPER_CHAT,
avatarUrl: data.avatarUrl,
authorName: data.authorName,
2020-11-28 21:53:49 +08:00
authorNamePronunciation: this.getPronunciation(data.authorName),
2020-09-12 17:37:52 +08:00
price: data.price,
time: new Date(data.timestamp * 1000),
2020-11-28 21:53:49 +08:00
content: data.content.trim(),
translation: data.translation
2019-06-17 12:29:25 +08:00
}
2020-09-12 17:37:52 +08:00
this.$refs.renderer.addMessage(message)
},
onDelSuperChat(data) {
2022-02-26 23:27:10 +08:00
this.$refs.renderer.delMessages(data.ids)
2019-06-17 12:29:25 +08:00
},
2020-09-12 17:37:52 +08:00
onUpdateTranslation(data) {
if (!this.config.autoTranslate) {
return
}
2022-01-04 21:41:12 +08:00
this.$refs.renderer.updateMessage(data.id, { translation: data.translation })
2020-09-12 17:37:52 +08:00
},
onFatalError(error) {
this.$message.error({
message: error.toString(),
duration: 10 * 1000
})
this.chatClient.stop()
if (error.type === chat.FATAL_ERROR_TYPE_AUTH_CODE_ERROR) {
// Read The Fucking Manual
this.$router.push({ name: 'help' })
}
},
2020-09-12 17:37:52 +08:00
2019-06-17 12:29:25 +08:00
filterTextMessage(data) {
if (this.config.blockGiftDanmaku && data.isGiftDanmaku) {
return false
} else if (this.config.blockLevel > 0 && data.authorLevel < this.config.blockLevel) {
return false
} else if (this.config.blockNewbie && data.isNewbie) {
return false
} else if (this.config.blockNotMobileVerified && !data.isMobileVerified) {
return false
2019-06-21 17:38:22 +08:00
} else if (this.config.blockMedalLevel > 0 && data.medalLevel < this.config.blockMedalLevel) {
return false
2019-06-17 12:29:25 +08:00
}
2022-02-26 23:27:10 +08:00
return this.filterByContent(data.content) && this.filterByAuthorName(data.authorName)
2019-06-17 12:29:25 +08:00
},
2019-09-23 22:22:27 +08:00
filterSuperChatMessage(data) {
2022-02-26 23:27:10 +08:00
return this.filterByContent(data.content) && this.filterByAuthorName(data.authorName)
},
filterNewMemberMessage(data) {
return this.filterByAuthorName(data.authorName)
},
filterByContent(content) {
2022-02-27 14:45:19 +08:00
let blockKeywordsTrie = this.blockKeywordsTrie
for (let i = 0; i < content.length; i++) {
let remainContent = content.substring(i)
2023-07-29 11:52:09 +08:00
if (blockKeywordsTrie.lazyMatch(remainContent) !== null) {
2019-09-23 22:22:27 +08:00
return false
}
}
2022-02-26 23:27:10 +08:00
return true
2020-02-01 21:27:50 +08:00
},
2022-02-26 23:27:10 +08:00
filterByAuthorName(authorName) {
2022-02-27 14:45:19 +08:00
return !this.blockUsersTrie.has(authorName)
2019-09-23 22:22:27 +08:00
},
mergeSimilarText(content) {
2019-06-17 12:29:25 +08:00
if (!this.config.mergeSimilarDanmaku) {
return false
}
return this.$refs.renderer.mergeSimilarText(content)
2019-11-29 23:48:43 +08:00
},
mergeSimilarGift(authorName, price, giftName, num) {
if (!this.config.mergeGift) {
2019-11-29 23:48:43 +08:00
return false
}
return this.$refs.renderer.mergeSimilarGift(authorName, price, giftName, num)
2020-11-28 21:53:49 +08:00
},
getPronunciation(text) {
if (this.pronunciationConverter === null) {
return ''
}
return this.pronunciationConverter.getPronunciation(text)
2022-02-27 14:45:19 +08:00
},
getRichContent(data) {
let richContent = []
// B站官方表情
if (data.emoticon !== null) {
richContent.push({
type: constants.CONTENT_TYPE_IMAGE,
text: data.content,
url: data.emoticon
})
return richContent
}
2023-08-27 00:23:52 +08:00
// 没有文本表情,只能是纯文本
if (this.config.emoticons.length === 0 && this.textEmoticons.length === 0) {
2022-02-27 14:45:19 +08:00
richContent.push({
type: constants.CONTENT_TYPE_TEXT,
text: data.content
})
return richContent
}
2023-08-27 00:23:52 +08:00
// 可能含有文本表情,需要解析
2022-02-27 14:45:19 +08:00
let emoticonsTrie = this.emoticonsTrie
let startPos = 0
let pos = 0
while (pos < data.content.length) {
let remainContent = data.content.substring(pos)
2023-07-29 11:52:09 +08:00
let matchEmoticon = emoticonsTrie.lazyMatch(remainContent)
2022-02-27 14:45:19 +08:00
if (matchEmoticon === null) {
pos++
continue
}
// 加入之前的文本
if (pos !== startPos) {
richContent.push({
type: constants.CONTENT_TYPE_TEXT,
text: data.content.slice(startPos, pos)
})
}
// 加入表情
richContent.push({
type: constants.CONTENT_TYPE_IMAGE,
text: matchEmoticon.keyword,
url: matchEmoticon.url
})
pos += matchEmoticon.keyword.length
startPos = pos
}
// 加入尾部的文本
if (pos !== startPos) {
richContent.push({
type: constants.CONTENT_TYPE_TEXT,
text: data.content.slice(startPos, pos)
})
}
return richContent
2019-06-17 12:29:25 +08:00
}
}
}
</script>