mirror of
https://github.com/xfgryujk/blivechat.git
synced 2026-08-22 11:23:28 +08:00
添加标注打赏用户名读音
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
import {inflate} from 'pako'
|
import * as pako from 'pako'
|
||||||
|
|
||||||
import {getUuid4Hex} from '@/utils'
|
import {getUuid4Hex} from '@/utils'
|
||||||
import * as avatar from './avatar'
|
import * as avatar from './avatar'
|
||||||
@@ -172,7 +172,7 @@ export default class ChatClientDirect {
|
|||||||
case OP_SEND_MSG_REPLY: {
|
case OP_SEND_MSG_REPLY: {
|
||||||
let body = new Uint8Array(data.buffer, offset + HEADER_SIZE, packLen - HEADER_SIZE)
|
let body = new Uint8Array(data.buffer, offset + HEADER_SIZE, packLen - HEADER_SIZE)
|
||||||
if (ver == WS_BODY_PROTOCOL_VERSION_DEFLATE) {
|
if (ver == WS_BODY_PROTOCOL_VERSION_DEFLATE) {
|
||||||
body = inflate(body)
|
body = pako.inflate(body)
|
||||||
this.handlerMessage(body)
|
this.handlerMessage(body)
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -18,7 +18,8 @@ export const DEFAULT_CONFIG = {
|
|||||||
blockMedalLevel: 0,
|
blockMedalLevel: 0,
|
||||||
|
|
||||||
relayMessagesByServer: false,
|
relayMessagesByServer: false,
|
||||||
autoTranslate: false
|
autoTranslate: false,
|
||||||
|
giftUsernamePronunciation: ''
|
||||||
}
|
}
|
||||||
|
|
||||||
export function setLocalConfig (config) {
|
export function setLocalConfig (config) {
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import {DEFAULT_AVATAR_URL} from '@/api/chat/avatar'
|
import * as avatar from '@/api/chat/avatar'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'ImgShadow',
|
name: 'ImgShadow',
|
||||||
@@ -26,8 +26,8 @@ export default {
|
|||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
onLoadError() {
|
onLoadError() {
|
||||||
if (this.showImgUrl !== DEFAULT_AVATAR_URL) {
|
if (this.showImgUrl !== avatar.DEFAULT_AVATAR_URL) {
|
||||||
this.showImgUrl = DEFAULT_AVATAR_URL
|
this.showImgUrl = avatar.DEFAULT_AVATAR_URL
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,12 +24,12 @@
|
|||||||
<template v-if="pinnedMessage">
|
<template v-if="pinnedMessage">
|
||||||
<membership-item :key="pinnedMessage.id" v-if="pinnedMessage.type === MESSAGE_TYPE_MEMBER"
|
<membership-item :key="pinnedMessage.id" v-if="pinnedMessage.type === MESSAGE_TYPE_MEMBER"
|
||||||
class="style-scope yt-live-chat-ticker-renderer"
|
class="style-scope yt-live-chat-ticker-renderer"
|
||||||
:avatarUrl="pinnedMessage.avatarUrl" :authorName="pinnedMessage.authorName" :privilegeType="pinnedMessage.privilegeType"
|
:avatarUrl="pinnedMessage.avatarUrl" :authorName="getShowAuthorName(pinnedMessage)" :privilegeType="pinnedMessage.privilegeType"
|
||||||
:title="pinnedMessage.title" :time="pinnedMessage.time"
|
:title="pinnedMessage.title" :time="pinnedMessage.time"
|
||||||
></membership-item>
|
></membership-item>
|
||||||
<paid-message :key="pinnedMessage.id" v-else
|
<paid-message :key="pinnedMessage.id" v-else
|
||||||
class="style-scope yt-live-chat-ticker-renderer"
|
class="style-scope yt-live-chat-ticker-renderer"
|
||||||
:price="pinnedMessage.price" :avatarUrl="pinnedMessage.avatarUrl" :authorName="pinnedMessage.authorName"
|
:price="pinnedMessage.price" :avatarUrl="pinnedMessage.avatarUrl" :authorName="getShowAuthorName(pinnedMessage)"
|
||||||
:time="pinnedMessage.time" :content="pinnedMessageShowContent"
|
:time="pinnedMessage.time" :content="pinnedMessageShowContent"
|
||||||
></paid-message>
|
></paid-message>
|
||||||
</template>
|
</template>
|
||||||
@@ -98,6 +98,7 @@ export default {
|
|||||||
window.clearInterval(this.updateTimerId)
|
window.clearInterval(this.updateTimerId)
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
getShowAuthorName: constants.getShowAuthorName,
|
||||||
needToShow(message) {
|
needToShow(message) {
|
||||||
let pinTime = this.getPinTime(message)
|
let pinTime = this.getPinTime(message)
|
||||||
return (new Date() - message.addTime) / (60 * 1000) < pinTime
|
return (new Date() - message.addTime) / (60 * 1000) < pinTime
|
||||||
|
|||||||
@@ -122,16 +122,23 @@ export function getPriceConfig (price) {
|
|||||||
return PRICE_CONFIGS[PRICE_CONFIGS.length - 1]
|
return PRICE_CONFIGS[PRICE_CONFIGS.length - 1]
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getShowContent(message) {
|
export function getShowContent (message) {
|
||||||
if (message.translation) {
|
if (message.translation) {
|
||||||
return `${message.content}(${message.translation})`
|
return `${message.content}(${message.translation})`
|
||||||
}
|
}
|
||||||
return message.content
|
return message.content
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getGiftShowContent(message, showGiftName) {
|
export function getGiftShowContent (message, showGiftName) {
|
||||||
if (!showGiftName) {
|
if (!showGiftName) {
|
||||||
return ''
|
return ''
|
||||||
}
|
}
|
||||||
return `Sent ${message.giftName}x${message.num}`
|
return `Sent ${message.giftName}x${message.num}`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getShowAuthorName (message) {
|
||||||
|
if (message.authorNamePronunciation) {
|
||||||
|
return `${message.authorName}(${message.authorNamePronunciation})`
|
||||||
|
}
|
||||||
|
return message.authorName
|
||||||
|
}
|
||||||
|
|||||||
@@ -18,17 +18,17 @@
|
|||||||
></text-message>
|
></text-message>
|
||||||
<paid-message :key="message.id" v-else-if="message.type === MESSAGE_TYPE_GIFT"
|
<paid-message :key="message.id" v-else-if="message.type === MESSAGE_TYPE_GIFT"
|
||||||
class="style-scope yt-live-chat-item-list-renderer"
|
class="style-scope yt-live-chat-item-list-renderer"
|
||||||
:price="message.price" :avatarUrl="message.avatarUrl" :authorName="message.authorName"
|
:price="message.price" :avatarUrl="message.avatarUrl" :authorName="getShowAuthorName(message)"
|
||||||
:time="message.time" :content="getGiftShowContent(message)"
|
:time="message.time" :content="getGiftShowContent(message)"
|
||||||
></paid-message>
|
></paid-message>
|
||||||
<membership-item :key="message.id" v-else-if="message.type === MESSAGE_TYPE_MEMBER"
|
<membership-item :key="message.id" v-else-if="message.type === MESSAGE_TYPE_MEMBER"
|
||||||
class="style-scope yt-live-chat-item-list-renderer"
|
class="style-scope yt-live-chat-item-list-renderer"
|
||||||
:avatarUrl="message.avatarUrl" :authorName="message.authorName" :privilegeType="message.privilegeType"
|
:avatarUrl="message.avatarUrl" :authorName="getShowAuthorName(message)" :privilegeType="message.privilegeType"
|
||||||
:title="message.title" :time="message.time"
|
:title="message.title" :time="message.time"
|
||||||
></membership-item>
|
></membership-item>
|
||||||
<paid-message :key="message.id" v-else-if="message.type === MESSAGE_TYPE_SUPER_CHAT"
|
<paid-message :key="message.id" v-else-if="message.type === MESSAGE_TYPE_SUPER_CHAT"
|
||||||
class="style-scope yt-live-chat-item-list-renderer"
|
class="style-scope yt-live-chat-item-list-renderer"
|
||||||
:price="message.price" :avatarUrl="message.avatarUrl" :authorName="message.authorName"
|
:price="message.price" :avatarUrl="message.avatarUrl" :authorName="getShowAuthorName(message)"
|
||||||
:time="message.time" :content="getShowContent(message)"
|
:time="message.time" :content="getShowContent(message)"
|
||||||
></paid-message>
|
></paid-message>
|
||||||
</template>
|
</template>
|
||||||
@@ -132,6 +132,7 @@ export default {
|
|||||||
return constants.getGiftShowContent(message, this.showGiftName)
|
return constants.getGiftShowContent(message, this.showGiftName)
|
||||||
},
|
},
|
||||||
getShowContent: constants.getShowContent,
|
getShowContent: constants.getShowContent,
|
||||||
|
getShowAuthorName: constants.getShowAuthorName,
|
||||||
|
|
||||||
addMessage(message) {
|
addMessage(message) {
|
||||||
this.addMessages([message])
|
this.addMessages([message])
|
||||||
|
|||||||
@@ -33,6 +33,10 @@ export default {
|
|||||||
advanced: 'Advanced',
|
advanced: 'Advanced',
|
||||||
relayMessagesByServer: 'Relay messages by server',
|
relayMessagesByServer: 'Relay messages by server',
|
||||||
autoTranslate: 'Auto translate messages to Japanese (requires relay messages by server)',
|
autoTranslate: 'Auto translate messages to Japanese (requires relay messages by server)',
|
||||||
|
giftUsernamePronunciation: 'Pronunciation of gift username',
|
||||||
|
dontShow: 'None',
|
||||||
|
pinyin: 'Pinyin',
|
||||||
|
kana: 'Kana',
|
||||||
|
|
||||||
roomUrl: 'Room URL',
|
roomUrl: 'Room URL',
|
||||||
copy: 'Copy',
|
copy: 'Copy',
|
||||||
|
|||||||
@@ -33,6 +33,10 @@ export default {
|
|||||||
advanced: 'アドバンスド',
|
advanced: 'アドバンスド',
|
||||||
relayMessagesByServer: 'サーバを介してメッセージを転送する',
|
relayMessagesByServer: 'サーバを介してメッセージを転送する',
|
||||||
autoTranslate: 'コメントを日本語に翻訳する(サーバを介してメッセージを転送する必要)',
|
autoTranslate: 'コメントを日本語に翻訳する(サーバを介してメッセージを転送する必要)',
|
||||||
|
giftUsernamePronunciation: 'スーパーチャットのユーザー名の発音',
|
||||||
|
dontShow: '非表示',
|
||||||
|
pinyin: 'ピンイン',
|
||||||
|
kana: '仮名',
|
||||||
|
|
||||||
roomUrl: 'ルームのURL',
|
roomUrl: 'ルームのURL',
|
||||||
copy: 'コピー',
|
copy: 'コピー',
|
||||||
|
|||||||
@@ -33,6 +33,10 @@ export default {
|
|||||||
advanced: '高级',
|
advanced: '高级',
|
||||||
relayMessagesByServer: '通过服务器转发消息',
|
relayMessagesByServer: '通过服务器转发消息',
|
||||||
autoTranslate: '自动翻译弹幕到日语(需要通过服务器转发消息)',
|
autoTranslate: '自动翻译弹幕到日语(需要通过服务器转发消息)',
|
||||||
|
giftUsernamePronunciation: '标注打赏用户名读音',
|
||||||
|
dontShow: '不显示',
|
||||||
|
pinyin: '拼音',
|
||||||
|
kana: '日文假名',
|
||||||
|
|
||||||
roomUrl: '房间URL',
|
roomUrl: '房间URL',
|
||||||
copy: '复制',
|
copy: '复制',
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ export default {
|
|||||||
hideSidebar: true
|
hideSidebar: true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
created() {
|
mounted() {
|
||||||
window.addEventListener('resize', this.onResize)
|
window.addEventListener('resize', this.onResize)
|
||||||
this.onResize()
|
this.onResize()
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -3,7 +3,8 @@ import VueRouter from 'vue-router'
|
|||||||
import VueI18n from 'vue-i18n'
|
import VueI18n from 'vue-i18n'
|
||||||
import {
|
import {
|
||||||
Aside, Autocomplete, Badge, Button, Col, ColorPicker, Container, Divider, Form, FormItem, Image,
|
Aside, Autocomplete, Badge, Button, Col, ColorPicker, Container, Divider, Form, FormItem, Image,
|
||||||
Input, Main, Menu, MenuItem, Message, Row, Scrollbar, Slider, Submenu, Switch, TabPane, Tabs, Tooltip
|
Input, Main, Menu, MenuItem, Message, Radio, RadioGroup, Row, Scrollbar, Slider, Submenu, Switch,
|
||||||
|
TabPane, Tabs, Tooltip
|
||||||
} from 'element-ui'
|
} from 'element-ui'
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
|
|
||||||
@@ -42,6 +43,8 @@ Vue.use(Input)
|
|||||||
Vue.use(Main)
|
Vue.use(Main)
|
||||||
Vue.use(Menu)
|
Vue.use(Menu)
|
||||||
Vue.use(MenuItem)
|
Vue.use(MenuItem)
|
||||||
|
Vue.use(Radio)
|
||||||
|
Vue.use(RadioGroup)
|
||||||
Vue.use(Row)
|
Vue.use(Row)
|
||||||
Vue.use(Scrollbar)
|
Vue.use(Scrollbar)
|
||||||
Vue.use(Slider)
|
Vue.use(Slider)
|
||||||
|
|||||||
20902
frontend/src/utils/pronunciation/dictKana.js
Normal file
20902
frontend/src/utils/pronunciation/dictKana.js
Normal file
File diff suppressed because it is too large
Load Diff
20902
frontend/src/utils/pronunciation/dictPinyin.js
Normal file
20902
frontend/src/utils/pronunciation/dictPinyin.js
Normal file
File diff suppressed because it is too large
Load Diff
54
frontend/src/utils/pronunciation/index.js
Normal file
54
frontend/src/utils/pronunciation/index.js
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
export const DICT_PINYIN = 'pinyin'
|
||||||
|
export const DICT_KANA = 'kana'
|
||||||
|
|
||||||
|
export class PronunciationConverter {
|
||||||
|
constructor () {
|
||||||
|
this.pronunciationMap = new Map()
|
||||||
|
}
|
||||||
|
|
||||||
|
async loadDict (dictName) {
|
||||||
|
let promise
|
||||||
|
switch (dictName) {
|
||||||
|
case DICT_PINYIN:
|
||||||
|
promise = import('./dictPinyin')
|
||||||
|
break
|
||||||
|
case DICT_KANA:
|
||||||
|
promise = import('./dictKana')
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let dictTxt = (await promise).default
|
||||||
|
let pronunciationMap = new Map()
|
||||||
|
for (let item of dictTxt.split('\n')) {
|
||||||
|
if (item.length === 0) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
pronunciationMap.set(item.substring(0, 1), item.substring(1))
|
||||||
|
}
|
||||||
|
this.pronunciationMap = pronunciationMap
|
||||||
|
}
|
||||||
|
|
||||||
|
getPronunciation (text) {
|
||||||
|
let res = []
|
||||||
|
let lastHasPronunciation = null
|
||||||
|
for (let char of text) {
|
||||||
|
let pronunciation = this.pronunciationMap.get(char)
|
||||||
|
if (pronunciation === undefined) {
|
||||||
|
if (lastHasPronunciation !== null && lastHasPronunciation) {
|
||||||
|
res.push(' ')
|
||||||
|
}
|
||||||
|
lastHasPronunciation = false
|
||||||
|
res.push(char)
|
||||||
|
} else {
|
||||||
|
if (lastHasPronunciation !== null) {
|
||||||
|
res.push(' ')
|
||||||
|
}
|
||||||
|
lastHasPronunciation = true
|
||||||
|
res.push(pronunciation)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res.join('')
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -64,6 +64,13 @@
|
|||||||
<el-form-item :label="$t('home.autoTranslate')">
|
<el-form-item :label="$t('home.autoTranslate')">
|
||||||
<el-switch v-model="form.autoTranslate" :disabled="!serverConfig.enableTranslate || !form.relayMessagesByServer"></el-switch>
|
<el-switch v-model="form.autoTranslate" :disabled="!serverConfig.enableTranslate || !form.relayMessagesByServer"></el-switch>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t('home.giftUsernamePronunciation')">
|
||||||
|
<el-radio-group v-model="form.giftUsernamePronunciation">
|
||||||
|
<el-radio label="">{{$t('home.dontShow')}}</el-radio>
|
||||||
|
<el-radio label="pinyin">{{$t('home.pinyin')}}</el-radio>
|
||||||
|
<el-radio label="kana">{{$t('home.kana')}}</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
</el-tabs>
|
</el-tabs>
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import {mergeConfig, toBool, toInt} from '@/utils'
|
import {mergeConfig, toBool, toInt} from '@/utils'
|
||||||
|
import * as pronunciation from '@/utils/pronunciation'
|
||||||
import * as chatConfig from '@/api/chatConfig'
|
import * as chatConfig from '@/api/chatConfig'
|
||||||
import ChatClientDirect from '@/api/chat/ChatClientDirect'
|
import ChatClientDirect from '@/api/chat/ChatClientDirect'
|
||||||
import ChatClientRelay from '@/api/chat/ChatClientRelay'
|
import ChatClientRelay from '@/api/chat/ChatClientRelay'
|
||||||
@@ -18,7 +19,8 @@ export default {
|
|||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
config: {...chatConfig.DEFAULT_CONFIG},
|
config: {...chatConfig.DEFAULT_CONFIG},
|
||||||
chatClient: null
|
chatClient: null,
|
||||||
|
pronunciationConverter: null
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
@@ -29,9 +31,14 @@ export default {
|
|||||||
return this.config.blockUsers.split('\n').filter(val => val)
|
return this.config.blockUsers.split('\n').filter(val => val)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
created() {
|
mounted() {
|
||||||
this.initConfig()
|
this.initConfig()
|
||||||
this.initChatClient()
|
this.initChatClient()
|
||||||
|
if (this.config.giftUsernamePronunciation !== '') {
|
||||||
|
this.pronunciationConverter = new pronunciation.PronunciationConverter()
|
||||||
|
this.pronunciationConverter.loadDict(this.config.giftUsernamePronunciation)
|
||||||
|
}
|
||||||
|
|
||||||
// 提示用户已加载
|
// 提示用户已加载
|
||||||
this.$message({
|
this.$message({
|
||||||
message: 'Loaded',
|
message: 'Loaded',
|
||||||
@@ -122,6 +129,7 @@ export default {
|
|||||||
avatarUrl: data.avatarUrl,
|
avatarUrl: data.avatarUrl,
|
||||||
time: new Date(data.timestamp * 1000),
|
time: new Date(data.timestamp * 1000),
|
||||||
authorName: data.authorName,
|
authorName: data.authorName,
|
||||||
|
authorNamePronunciation: this.getPronunciation(data.authorName),
|
||||||
price: price,
|
price: price,
|
||||||
giftName: data.giftName,
|
giftName: data.giftName,
|
||||||
num: data.num
|
num: data.num
|
||||||
@@ -138,6 +146,7 @@ export default {
|
|||||||
avatarUrl: data.avatarUrl,
|
avatarUrl: data.avatarUrl,
|
||||||
time: new Date(data.timestamp * 1000),
|
time: new Date(data.timestamp * 1000),
|
||||||
authorName: data.authorName,
|
authorName: data.authorName,
|
||||||
|
authorNamePronunciation: this.getPronunciation(data.authorName),
|
||||||
privilegeType: data.privilegeType,
|
privilegeType: data.privilegeType,
|
||||||
title: 'New member'
|
title: 'New member'
|
||||||
}
|
}
|
||||||
@@ -155,9 +164,11 @@ export default {
|
|||||||
type: constants.MESSAGE_TYPE_SUPER_CHAT,
|
type: constants.MESSAGE_TYPE_SUPER_CHAT,
|
||||||
avatarUrl: data.avatarUrl,
|
avatarUrl: data.avatarUrl,
|
||||||
authorName: data.authorName,
|
authorName: data.authorName,
|
||||||
|
authorNamePronunciation: this.getPronunciation(data.authorName),
|
||||||
price: data.price,
|
price: data.price,
|
||||||
time: new Date(data.timestamp * 1000),
|
time: new Date(data.timestamp * 1000),
|
||||||
content: data.content.trim()
|
content: data.content.trim(),
|
||||||
|
translation: data.translation
|
||||||
}
|
}
|
||||||
this.$refs.renderer.addMessage(message)
|
this.$refs.renderer.addMessage(message)
|
||||||
},
|
},
|
||||||
@@ -214,6 +225,12 @@ export default {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return this.$refs.renderer.mergeSimilarGift(authorName, price, giftName, num)
|
return this.$refs.renderer.mergeSimilarGift(authorName, price, giftName, num)
|
||||||
|
},
|
||||||
|
getPronunciation(text) {
|
||||||
|
if (this.pronunciationConverter === null) {
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
return this.pronunciationConverter.getPronunciation(text)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,3 +24,5 @@ async def _do_check_update():
|
|||||||
print('---------------------------------------------')
|
print('---------------------------------------------')
|
||||||
except aiohttp.ClientConnectionError:
|
except aiohttp.ClientConnectionError:
|
||||||
print('Failed to check update: connection failed')
|
print('Failed to check update: connection failed')
|
||||||
|
except asyncio.TimeoutError:
|
||||||
|
print('Failed to check update: timeout')
|
||||||
|
|||||||
Reference in New Issue
Block a user