mirror of
https://github.com/xfgryujk/blivechat.git
synced 2025-03-12 18:50:45 +08:00
添加弹幕速度限制等设置
This commit is contained in:
parent
ef4c0daede
commit
ec27b1bbcc
2
blivedm
2
blivedm
@ -1 +1 @@
|
|||||||
Subproject commit 2f705b86ce02e4c8c93ca6d066964747160fd617
|
Subproject commit 0d63944da4558981cd55c1fdbfb11b97837780ff
|
@ -6,6 +6,9 @@ import stylegen from '@/views/StyleGenerator/stylegen'
|
|||||||
export const DEFAULT_CONFIG = {
|
export const DEFAULT_CONFIG = {
|
||||||
minGiftPrice: 6.911, // $1
|
minGiftPrice: 6.911, // $1
|
||||||
mergeSimilarDanmaku: true,
|
mergeSimilarDanmaku: true,
|
||||||
|
showDanmaku: true,
|
||||||
|
showGift: true,
|
||||||
|
maxSpeed: 4,
|
||||||
|
|
||||||
blockGiftDanmaku: true,
|
blockGiftDanmaku: true,
|
||||||
blockLevel: 0,
|
blockLevel: 0,
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
</yt-live-chat-ticker-paid-message-item-renderer>
|
</yt-live-chat-ticker-paid-message-item-renderer>
|
||||||
</yt-live-chat-ticker-renderer> -->
|
</yt-live-chat-ticker-renderer> -->
|
||||||
<yt-live-chat-item-list-renderer class="style-scope yt-live-chat-renderer" allow-scroll>
|
<yt-live-chat-item-list-renderer class="style-scope yt-live-chat-renderer" allow-scroll>
|
||||||
<div id="item-scroller" ref="scroller" class="style-scope yt-live-chat-item-list-renderer animated">
|
<div id="item-scroller" ref="scroller" class="style-scope yt-live-chat-item-list-renderer animated" @scroll="onScroll">
|
||||||
<div id="item-offset" class="style-scope yt-live-chat-item-list-renderer" style="height: 1800px;">
|
<div id="item-offset" class="style-scope yt-live-chat-item-list-renderer" style="height: 1800px;">
|
||||||
<div id="items" class="style-scope yt-live-chat-item-list-renderer" style="overflow: hidden; transform: translateY(0px);">
|
<div id="items" class="style-scope yt-live-chat-item-list-renderer" style="overflow: hidden; transform: translateY(0px);">
|
||||||
<template v-for="message in messages">
|
<template v-for="message in messages">
|
||||||
@ -47,6 +47,7 @@
|
|||||||
import TextMessage from './TextMessage.vue'
|
import TextMessage from './TextMessage.vue'
|
||||||
import LegacyPaidMessage from './LegacyPaidMessage.vue'
|
import LegacyPaidMessage from './LegacyPaidMessage.vue'
|
||||||
import PaidMessage from './PaidMessage.vue'
|
import PaidMessage from './PaidMessage.vue'
|
||||||
|
import { METHODS } from 'http';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'ChatRenderer',
|
name: 'ChatRenderer',
|
||||||
@ -63,23 +64,35 @@ export default {
|
|||||||
let styleElement = document.createElement('style')
|
let styleElement = document.createElement('style')
|
||||||
document.head.appendChild(styleElement)
|
document.head.appendChild(styleElement)
|
||||||
return {
|
return {
|
||||||
styleElement
|
styleElement,
|
||||||
|
canAutoScroll: true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.styleElement.innerText = this.css
|
this.styleElement.innerText = this.css
|
||||||
this.$refs.scroller.scrollTo(0, this.$refs.scroller.scrollHeight)
|
this.scrollToBottom()
|
||||||
},
|
},
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
document.head.removeChild(this.styleElement)
|
document.head.removeChild(this.styleElement)
|
||||||
},
|
},
|
||||||
updated() {
|
updated() {
|
||||||
this.$refs.scroller.scrollTo(0, this.$refs.scroller.scrollHeight)
|
if (this.canAutoScroll) {
|
||||||
|
this.scrollToBottom()
|
||||||
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
css(val) {
|
css(val) {
|
||||||
this.styleElement.innerText = val
|
this.styleElement.innerText = val
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
scrollToBottom() {
|
||||||
|
this.$refs.scroller.scrollTop = this.$refs.scroller.scrollHeight
|
||||||
|
},
|
||||||
|
onScroll() {
|
||||||
|
this.canAutoScroll = Math.abs(this.$refs.scroller.scrollHeight - this.$refs.scroller.scrollTop
|
||||||
|
- this.$refs.scroller.clientHeight) < 2
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@ -10,37 +10,46 @@
|
|||||||
<el-form-item label="房间ID" required prop="roomId">
|
<el-form-item label="房间ID" required prop="roomId">
|
||||||
<el-input v-model.number="form.roomId" type="number" min="1"></el-input>
|
<el-input v-model.number="form.roomId" type="number" min="1"></el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="最低显示礼物价格(元)" prop="minGiftPrice">
|
<el-form-item label="显示弹幕">
|
||||||
|
<el-switch v-model="form.showDanmaku"></el-switch>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="显示礼物和新舰长">
|
||||||
|
<el-switch v-model="form.showGift"></el-switch>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="合并相似弹幕">
|
||||||
|
<el-switch v-model="form.mergeSimilarDanmaku"></el-switch>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="最低显示礼物价格(元)">
|
||||||
<el-input v-model.number="form.minGiftPrice" type="number" min="0"></el-input>
|
<el-input v-model.number="form.minGiftPrice" type="number" min="0"></el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="合并相似弹幕" prop="mergeSimilarDanmaku">
|
<el-form-item label="弹幕最大速度(条/秒,0为无限制)">
|
||||||
<el-switch v-model="form.mergeSimilarDanmaku"></el-switch>
|
<el-input v-model.number="form.maxSpeed" type="number" min="0"></el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
|
|
||||||
<el-tab-pane label="屏蔽">
|
<el-tab-pane label="屏蔽">
|
||||||
<el-form-item label="礼物弹幕" prop="blockGiftDanmaku">
|
<el-form-item label="礼物弹幕">
|
||||||
<el-switch v-model="form.blockGiftDanmaku"></el-switch>
|
<el-switch v-model="form.blockGiftDanmaku"></el-switch>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="用户等级低于" prop="blockLevel">
|
<el-form-item label="用户等级低于">
|
||||||
<el-slider v-model="form.blockLevel" show-input :min="0" :max="60"></el-slider>
|
<el-slider v-model="form.blockLevel" show-input :min="0" :max="60"></el-slider>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="非正式会员" prop="blockNewbie">
|
<el-form-item label="非正式会员">
|
||||||
<el-switch v-model="form.blockNewbie"></el-switch>
|
<el-switch v-model="form.blockNewbie"></el-switch>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="未绑定手机用户" prop="blockNotMobileVerified">
|
<el-form-item label="未绑定手机用户">
|
||||||
<el-switch v-model="form.blockNotMobileVerified"></el-switch>
|
<el-switch v-model="form.blockNotMobileVerified"></el-switch>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="屏蔽关键词" prop="blockKeywords">
|
<el-form-item label="屏蔽关键词">
|
||||||
<el-input v-model="form.blockKeywords" type="textarea" :rows="5" placeholder="一行一个"></el-input>
|
<el-input v-model="form.blockKeywords" type="textarea" :rows="5" placeholder="一行一个"></el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="屏蔽用户" prop="blockUsers">
|
<el-form-item label="屏蔽用户">
|
||||||
<el-input v-model="form.blockUsers" type="textarea" :rows="5" placeholder="一行一个"></el-input>
|
<el-input v-model="form.blockUsers" type="textarea" :rows="5" placeholder="一行一个"></el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
|
|
||||||
<el-tab-pane label="样式">
|
<el-tab-pane label="样式">
|
||||||
<el-form-item label="CSS" prop="css">
|
<el-form-item label="CSS">
|
||||||
<el-input v-model="form.css" type="textarea" :rows="20"></el-input>
|
<el-input v-model="form.css" type="textarea" :rows="20"></el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
|
@ -20,11 +20,14 @@ export default {
|
|||||||
let cfg = {...config.DEFAULT_CONFIG}
|
let cfg = {...config.DEFAULT_CONFIG}
|
||||||
cfg.blockKeywords = cfg.blockKeywords.split('\n').filter(val => val)
|
cfg.blockKeywords = cfg.blockKeywords.split('\n').filter(val => val)
|
||||||
cfg.blockUsers = cfg.blockUsers.split('\n').filter(val => val)
|
cfg.blockUsers = cfg.blockUsers.split('\n').filter(val => val)
|
||||||
|
cfg.maxSpeed = 0
|
||||||
return {
|
return {
|
||||||
config: cfg,
|
config: cfg,
|
||||||
websocket: null,
|
websocket: null,
|
||||||
messages: [],
|
messagesBufferTimerId: null,
|
||||||
nextId: 0
|
nextId: 0,
|
||||||
|
messagesBuffer: [], // 暂时不显示的消息,可能会丢弃
|
||||||
|
messages: [] // 正在显示的消息
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async created() {
|
async created() {
|
||||||
@ -46,8 +49,22 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
|
if (this.messagesBufferTimerId) {
|
||||||
|
window.clearInterval(this.messagesBufferTimerId)
|
||||||
|
}
|
||||||
this.websocket.close()
|
this.websocket.close()
|
||||||
},
|
},
|
||||||
|
watch: {
|
||||||
|
config(val) {
|
||||||
|
if (this.messagesBufferTimerId) {
|
||||||
|
window.clearInterval(this.messagesBufferTimerId)
|
||||||
|
this.messagesBufferTimerId = null
|
||||||
|
}
|
||||||
|
if (val.maxSpeed > 0) {
|
||||||
|
this.messagesBufferTimerId = window.setInterval(this.handleMessagesBuffer.bind(this), 1000 / val.maxSpeed)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
onWsOpen() {
|
onWsOpen() {
|
||||||
this.websocket.send(JSON.stringify({
|
this.websocket.send(JSON.stringify({
|
||||||
@ -63,11 +80,10 @@ export default {
|
|||||||
let time = data.timestamp ? new Date(data.timestamp * 1000) : new Date()
|
let time = data.timestamp ? new Date(data.timestamp * 1000) : new Date()
|
||||||
switch(cmd) {
|
switch(cmd) {
|
||||||
case COMMAND_ADD_TEXT:
|
case COMMAND_ADD_TEXT:
|
||||||
if (!this.filterTextMessage(data) || this.mergeSimilar(data.content)) {
|
if (!this.config.showDanmaku || !this.filterTextMessage(data) || this.mergeSimilar(data.content)) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
message = {
|
message = {
|
||||||
id: this.nextId++,
|
|
||||||
type: 0, // TextMessage
|
type: 0, // TextMessage
|
||||||
avatarUrl: data.avatarUrl,
|
avatarUrl: data.avatarUrl,
|
||||||
time: `${time.getMinutes()}:${time.getSeconds()}`,
|
time: `${time.getMinutes()}:${time.getSeconds()}`,
|
||||||
@ -79,11 +95,13 @@ export default {
|
|||||||
}
|
}
|
||||||
break
|
break
|
||||||
case COMMAND_ADD_GIFT: {
|
case COMMAND_ADD_GIFT: {
|
||||||
|
if (!this.config.showGift) {
|
||||||
|
break
|
||||||
|
}
|
||||||
let price = data.totalCoin / 1000
|
let price = data.totalCoin / 1000
|
||||||
if (price < this.config.minGiftPrice) // 丢人
|
if (price < this.config.minGiftPrice) // 丢人
|
||||||
break
|
break
|
||||||
message = {
|
message = {
|
||||||
id: this.nextId++,
|
|
||||||
type: 2, // PaidMessage
|
type: 2, // PaidMessage
|
||||||
avatarUrl: data.avatarUrl,
|
avatarUrl: data.avatarUrl,
|
||||||
authorName: data.authorName,
|
authorName: data.authorName,
|
||||||
@ -94,8 +112,10 @@ export default {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
case COMMAND_ADD_MEMBER:
|
case COMMAND_ADD_MEMBER:
|
||||||
|
if (!this.config.showGift) {
|
||||||
|
break
|
||||||
|
}
|
||||||
message = {
|
message = {
|
||||||
id: this.nextId++,
|
|
||||||
type: 1, // LegacyPaidMessage
|
type: 1, // LegacyPaidMessage
|
||||||
avatarUrl: data.avatarUrl,
|
avatarUrl: data.avatarUrl,
|
||||||
time: `${time.getMinutes()}:${time.getSeconds()}`,
|
time: `${time.getMinutes()}:${time.getSeconds()}`,
|
||||||
@ -106,10 +126,7 @@ export default {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
if (message) {
|
if (message) {
|
||||||
this.messages.push(message)
|
this.addMessageBuffer(message)
|
||||||
if (this.messages.length > 50) {
|
|
||||||
this.messages.splice(0, this.messages.length - 50)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
filterTextMessage(data) {
|
filterTextMessage(data) {
|
||||||
@ -149,6 +166,33 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
|
},
|
||||||
|
addMessageBuffer(message) {
|
||||||
|
if (this.config.maxSpeed > 0 && message.type === 0) {
|
||||||
|
message.addTime = new Date()
|
||||||
|
this.messagesBuffer.push(message)
|
||||||
|
} else {
|
||||||
|
// 无速度限制或者是礼物
|
||||||
|
this.addMessageShow(message)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
addMessageShow(message) {
|
||||||
|
message.id = this.nextId++
|
||||||
|
this.messages.push(message)
|
||||||
|
if (this.messages.length > 50) {
|
||||||
|
this.messages.splice(0, this.messages.length - 50)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
handleMessagesBuffer() {
|
||||||
|
// 3秒内未发出则丢弃
|
||||||
|
let curTime = new Date()
|
||||||
|
while (this.messagesBuffer.length > 0 && curTime - this.messagesBuffer[0].addTime > 3 * 1000) {
|
||||||
|
this.messagesBuffer.shift()
|
||||||
|
}
|
||||||
|
if (this.messagesBuffer.length <= 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.addMessageShow(this.messagesBuffer.shift())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,9 +8,9 @@ from typing import *
|
|||||||
configs: Dict[str, dict] = {}
|
configs: Dict[str, dict] = {}
|
||||||
|
|
||||||
ALLOWED_FIELDS = (
|
ALLOWED_FIELDS = (
|
||||||
'minGiftPrice', 'mergeSimilarDanmaku', 'blockGiftDanmaku', 'blockLevel',
|
'showDanmaku', 'showGift', 'mergeSimilarDanmaku', 'minGiftPrice', 'maxSpeed',
|
||||||
'blockNewbie', 'blockNotMobileVerified', 'blockKeywords', 'blockUsers',
|
'blockGiftDanmaku', 'blockLevel', 'blockNewbie', 'blockNotMobileVerified',
|
||||||
'css'
|
'blockKeywords', 'blockUsers', 'css'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user