mirror of
https://github.com/xfgryujk/blivechat.git
synced 2025-01-13 22:00:15 +08:00
整理前端代码风格
This commit is contained in:
parent
03a2801099
commit
36345c37ab
79
frontend/.eslintrc.js
Normal file
79
frontend/.eslintrc.js
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
module.exports = {
|
||||||
|
"root": true,
|
||||||
|
"env": {
|
||||||
|
"browser": true,
|
||||||
|
"node": true
|
||||||
|
},
|
||||||
|
"parserOptions": {
|
||||||
|
"parser": "babel-eslint"
|
||||||
|
},
|
||||||
|
"extends": [
|
||||||
|
"plugin:vue/essential",
|
||||||
|
"eslint:recommended"
|
||||||
|
],
|
||||||
|
"rules": {
|
||||||
|
"array-bracket-spacing": ["error", "never"], // 数组括号内不加空格
|
||||||
|
"arrow-parens": ["error", "as-needed"], // 箭头函数单个参数不加括号
|
||||||
|
"arrow-spacing": "error", // 箭头前后加空格
|
||||||
|
"block-spacing": "error", // 块大括号内加空格
|
||||||
|
"brace-style": "error", // 大括号不独占一行
|
||||||
|
"comma-spacing": "error", // 逗号前面不加空格,后面加空格
|
||||||
|
"comma-style": "error", // 逗号在语句后面而不是下一条的前面
|
||||||
|
"computed-property-spacing": "error", // 计算属性名前后不加空格
|
||||||
|
"curly": "error", // 禁止省略大括号
|
||||||
|
"dot-notation": "error", // 使用点访问成员
|
||||||
|
"eol-last": "error", // 文件末尾加换行符
|
||||||
|
"func-call-spacing": "error", // 调用函数名和括号间不加空格
|
||||||
|
"func-style": ["error", "declaration", { "allowArrowFunctions": true }], // 使用函数定义语法,而不是把函数表达式赋值到变量
|
||||||
|
"indent": ["error", 2], // 缩进2空格
|
||||||
|
"key-spacing": ["error", { "mode": "minimum" }],
|
||||||
|
"keyword-spacing": "error", // 关键词前后加空格
|
||||||
|
"lines-between-class-members": "error", // 类成员定义间加空格
|
||||||
|
"max-lines-per-function": ["error", 150], // 每个函数最多行数
|
||||||
|
"max-nested-callbacks": ["error", 3], // 每个函数最多嵌套回调数
|
||||||
|
"new-parens": "error", // new调用构造函数加空格
|
||||||
|
"no-array-constructor": "error", // 使用数组字面量,而不是数组构造函数
|
||||||
|
"no-floating-decimal": "error", // 禁止省略浮点数首尾的0
|
||||||
|
"no-implicit-coercion": "error", // 禁止隐式转换
|
||||||
|
"no-empty": ["error", { "allowEmptyCatch": true }], // 禁止空的块,除了catch
|
||||||
|
"no-extra-parens": ["error", "all", { "nestedBinaryExpressions": false }], // 禁止多余的括号
|
||||||
|
"no-labels": "error", // 禁止使用标签
|
||||||
|
"no-lone-blocks": "error", // 禁止没用的块
|
||||||
|
"no-mixed-operators": "error", // 禁止混用不同优先级的操作符而不加括号
|
||||||
|
"no-multi-spaces": ["error", { "ignoreEOLComments": true }], // 禁止多个空格,除了行尾注释前
|
||||||
|
"no-multiple-empty-lines": "error", // 最多2个连续空行
|
||||||
|
"no-nested-ternary": "error", // 禁止嵌套三元表达式
|
||||||
|
"no-sequences": "error", // 禁止使用逗号操作符
|
||||||
|
"no-tabs": "error", // 禁止使用tab
|
||||||
|
"no-trailing-spaces": ["error", { "skipBlankLines": true }], // 禁止行尾的空格,除了空行
|
||||||
|
"no-unused-expressions": "error", // 禁止没用的表达式
|
||||||
|
"no-useless-concat": "error", // 禁止没用的字符串连接
|
||||||
|
"no-useless-rename": "error", // 禁止没用的模块导入重命名、解构赋值重命名
|
||||||
|
"no-useless-return": "error", // 禁止没用的return
|
||||||
|
"no-var": "error", // 禁止使用var声明变量
|
||||||
|
"no-void": "error", // 禁止使用void
|
||||||
|
"no-whitespace-before-property": "error", // 禁止访问属性的点前后加空格
|
||||||
|
"object-curly-spacing": ["error", "always"], // 对象字面量括号内加空格
|
||||||
|
"operator-assignment": "error", // 尽量使用+=
|
||||||
|
"operator-linebreak": ["error", "before"], // 操作符放行首
|
||||||
|
"prefer-object-spread": "error", // 使用{...obj},而不是Object.assign
|
||||||
|
"prefer-rest-params": "error", // 使用...args,而不是arguments
|
||||||
|
"prefer-spread": "error", // 使用func(...args),而不是apply
|
||||||
|
"prefer-template": "error", // 使用模板字符串,而不是字符串连接
|
||||||
|
"rest-spread-spacing": ["error", "never"], // 解包操作符不加空格
|
||||||
|
"semi": ["error", "never"], // 禁止使用多余的分号
|
||||||
|
"semi-spacing": "error", // 分号前面不加空格,后面加空格
|
||||||
|
"semi-style": "error", // 分号在语句后面而不是下一条的前面
|
||||||
|
"space-before-blocks": "error", // 块大括号前加空格
|
||||||
|
"space-before-function-paren": ["error", "never"], // 函数定义名称和括号间不加空格
|
||||||
|
"space-in-parens": "error", // 括号内不加空格
|
||||||
|
"space-infix-ops": "error", // 二元操作符前后加空格
|
||||||
|
"space-unary-ops": "error", // 关键词一元操作符后加空格,符号一元操作符不加
|
||||||
|
"spaced-comment": ["error", "always", { "block": { "balanced": true } }], // 注释前面加空格
|
||||||
|
"template-curly-spacing": "error", // 模板字符串中变量大括号内不加空格
|
||||||
|
|
||||||
|
"no-shadow": "warn", // 变量名和外部作用域重复
|
||||||
|
|
||||||
|
"no-console": "off", // 线上尽量不要用console输出,看不到的
|
||||||
|
}
|
||||||
|
}
|
14
frontend/jsconfig.json
Normal file
14
frontend/jsconfig.json
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "es2015",
|
||||||
|
"module": "esnext",
|
||||||
|
"baseUrl": "./",
|
||||||
|
"paths": {
|
||||||
|
"@/*": ["src/*"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"include": [
|
||||||
|
"./src/**/*.js",
|
||||||
|
"./src/**/*.vue"
|
||||||
|
]
|
||||||
|
}
|
@ -1,7 +1,7 @@
|
|||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
|
|
||||||
import {BrotliDecode} from './brotli_decode'
|
import { BrotliDecode } from './brotli_decode'
|
||||||
import {getUuid4Hex} from '@/utils'
|
import { getUuid4Hex } from '@/utils'
|
||||||
import * as avatar from '../avatar'
|
import * as avatar from '../avatar'
|
||||||
|
|
||||||
const HEADER_SIZE = 16
|
const HEADER_SIZE = 16
|
||||||
@ -37,18 +37,18 @@ const AUTH_REPLY_CODE_OK = 0
|
|||||||
// const AUTH_REPLY_CODE_TOKEN_ERROR = -101
|
// const AUTH_REPLY_CODE_TOKEN_ERROR = -101
|
||||||
|
|
||||||
const HEARTBEAT_INTERVAL = 10 * 1000
|
const HEARTBEAT_INTERVAL = 10 * 1000
|
||||||
const RECEIVE_TIMEOUT = HEARTBEAT_INTERVAL + 5 * 1000
|
const RECEIVE_TIMEOUT = HEARTBEAT_INTERVAL + (5 * 1000)
|
||||||
|
|
||||||
let textEncoder = new TextEncoder()
|
let textEncoder = new TextEncoder()
|
||||||
let textDecoder = new TextDecoder()
|
let textDecoder = new TextDecoder()
|
||||||
|
|
||||||
export default class ChatClientDirect {
|
export default class ChatClientDirect {
|
||||||
constructor (roomId) {
|
constructor(roomId) {
|
||||||
// 调用initRoom后初始化,如果失败,使用这里的默认值
|
// 调用initRoom后初始化,如果失败,使用这里的默认值
|
||||||
this.roomId = roomId
|
this.roomId = roomId
|
||||||
this.roomOwnerUid = 0
|
this.roomOwnerUid = 0
|
||||||
this.hostServerList = [
|
this.hostServerList = [
|
||||||
{host: "broadcastlv.chat.bilibili.com", port: 2243, wss_port: 443, ws_port: 2244}
|
{ host: "broadcastlv.chat.bilibili.com", port: 2243, wss_port: 443, ws_port: 2244 }
|
||||||
]
|
]
|
||||||
|
|
||||||
this.onAddText = null
|
this.onAddText = null
|
||||||
@ -65,24 +65,24 @@ export default class ChatClientDirect {
|
|||||||
this.receiveTimeoutTimerId = null
|
this.receiveTimeoutTimerId = null
|
||||||
}
|
}
|
||||||
|
|
||||||
async start () {
|
async start() {
|
||||||
await this.initRoom()
|
await this.initRoom()
|
||||||
this.wsConnect()
|
this.wsConnect()
|
||||||
}
|
}
|
||||||
|
|
||||||
stop () {
|
stop() {
|
||||||
this.isDestroying = true
|
this.isDestroying = true
|
||||||
if (this.websocket) {
|
if (this.websocket) {
|
||||||
this.websocket.close()
|
this.websocket.close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async initRoom () {
|
async initRoom() {
|
||||||
let res
|
let res
|
||||||
try {
|
try {
|
||||||
res = (await axios.get('/api/room_info', {params: {
|
res = (await axios.get('/api/room_info', { params: {
|
||||||
roomId: this.roomId
|
roomId: this.roomId
|
||||||
}})).data
|
} })).data
|
||||||
} catch {
|
} catch {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -93,7 +93,7 @@ export default class ChatClientDirect {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
makePacket (data, operation) {
|
makePacket(data, operation) {
|
||||||
let body = textEncoder.encode(JSON.stringify(data))
|
let body = textEncoder.encode(JSON.stringify(data))
|
||||||
let header = new ArrayBuffer(HEADER_SIZE)
|
let header = new ArrayBuffer(HEADER_SIZE)
|
||||||
let headerView = new DataView(header)
|
let headerView = new DataView(header)
|
||||||
@ -105,7 +105,7 @@ export default class ChatClientDirect {
|
|||||||
return new Blob([header, body])
|
return new Blob([header, body])
|
||||||
}
|
}
|
||||||
|
|
||||||
sendAuth () {
|
sendAuth() {
|
||||||
let authParams = {
|
let authParams = {
|
||||||
uid: 0,
|
uid: 0,
|
||||||
roomid: this.roomId,
|
roomid: this.roomId,
|
||||||
@ -116,7 +116,7 @@ export default class ChatClientDirect {
|
|||||||
this.websocket.send(this.makePacket(authParams, OP_AUTH))
|
this.websocket.send(this.makePacket(authParams, OP_AUTH))
|
||||||
}
|
}
|
||||||
|
|
||||||
wsConnect () {
|
wsConnect() {
|
||||||
if (this.isDestroying) {
|
if (this.isDestroying) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -129,13 +129,13 @@ export default class ChatClientDirect {
|
|||||||
this.websocket.onmessage = this.onWsMessage.bind(this)
|
this.websocket.onmessage = this.onWsMessage.bind(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
onWsOpen () {
|
onWsOpen() {
|
||||||
this.sendAuth()
|
this.sendAuth()
|
||||||
this.heartbeatTimerId = window.setInterval(this.sendHeartbeat.bind(this), HEARTBEAT_INTERVAL)
|
this.heartbeatTimerId = window.setInterval(this.sendHeartbeat.bind(this), HEARTBEAT_INTERVAL)
|
||||||
this.refreshReceiveTimeoutTimer()
|
this.refreshReceiveTimeoutTimer()
|
||||||
}
|
}
|
||||||
|
|
||||||
sendHeartbeat () {
|
sendHeartbeat() {
|
||||||
this.websocket.send(this.makePacket({}, OP_HEARTBEAT))
|
this.websocket.send(this.makePacket({}, OP_HEARTBEAT))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -147,7 +147,7 @@ export default class ChatClientDirect {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onReceiveTimeout() {
|
onReceiveTimeout() {
|
||||||
window.console.warn('接收消息超时')
|
console.warn('接收消息超时')
|
||||||
this.discardWebsocket()
|
this.discardWebsocket()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -163,7 +163,7 @@ export default class ChatClientDirect {
|
|||||||
this.onWsClose()
|
this.onWsClose()
|
||||||
}
|
}
|
||||||
|
|
||||||
onWsClose () {
|
onWsClose() {
|
||||||
this.websocket = null
|
this.websocket = null
|
||||||
if (this.heartbeatTimerId) {
|
if (this.heartbeatTimerId) {
|
||||||
window.clearInterval(this.heartbeatTimerId)
|
window.clearInterval(this.heartbeatTimerId)
|
||||||
@ -178,14 +178,14 @@ export default class ChatClientDirect {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
this.retryCount++
|
this.retryCount++
|
||||||
window.console.warn('掉线重连中', this.retryCount)
|
console.warn('掉线重连中', this.retryCount)
|
||||||
window.setTimeout(this.wsConnect.bind(this), 1000)
|
window.setTimeout(this.wsConnect.bind(this), 1000)
|
||||||
}
|
}
|
||||||
|
|
||||||
onWsMessage (event) {
|
onWsMessage(event) {
|
||||||
this.refreshReceiveTimeoutTimer()
|
this.refreshReceiveTimeoutTimer()
|
||||||
if (!(event.data instanceof ArrayBuffer)) {
|
if (!(event.data instanceof ArrayBuffer)) {
|
||||||
window.console.warn('未知的websocket消息类型,data=', event.data)
|
console.warn('未知的websocket消息类型,data=', event.data)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -196,7 +196,7 @@ export default class ChatClientDirect {
|
|||||||
this.retryCount = 0
|
this.retryCount = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
parseWsMessage (data) {
|
parseWsMessage(data) {
|
||||||
let offset = 0
|
let offset = 0
|
||||||
let dataView = new DataView(data.buffer)
|
let dataView = new DataView(data.buffer)
|
||||||
let packLen = dataView.getUint32(0)
|
let packLen = dataView.getUint32(0)
|
||||||
@ -231,13 +231,13 @@ export default class ChatClientDirect {
|
|||||||
default: {
|
default: {
|
||||||
// 未知消息
|
// 未知消息
|
||||||
let body = new Uint8Array(data.buffer, offset + rawHeaderSize, packLen - rawHeaderSize)
|
let body = new Uint8Array(data.buffer, offset + rawHeaderSize, packLen - rawHeaderSize)
|
||||||
window.console.warn('未知包类型,operation=', operation, dataView, body)
|
console.warn('未知包类型,operation=', operation, dataView, body)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
parseBusinessMessage (dataView, body) {
|
parseBusinessMessage(dataView, body) {
|
||||||
let ver = dataView.getUint16(6)
|
let ver = dataView.getUint16(6)
|
||||||
let operation = dataView.getUint32(8)
|
let operation = dataView.getUint32(8)
|
||||||
|
|
||||||
@ -255,7 +255,7 @@ export default class ChatClientDirect {
|
|||||||
body = JSON.parse(textDecoder.decode(body))
|
body = JSON.parse(textDecoder.decode(body))
|
||||||
this.handlerCommand(body)
|
this.handlerCommand(body)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
window.console.error('body=', body)
|
console.error('body=', body)
|
||||||
throw e
|
throw e
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -266,7 +266,7 @@ export default class ChatClientDirect {
|
|||||||
// 认证响应
|
// 认证响应
|
||||||
body = JSON.parse(textDecoder.decode(body))
|
body = JSON.parse(textDecoder.decode(body))
|
||||||
if (body.code !== AUTH_REPLY_CODE_OK) {
|
if (body.code !== AUTH_REPLY_CODE_OK) {
|
||||||
window.console.error('认证响应错误,body=', body)
|
console.error('认证响应错误,body=', body)
|
||||||
// 这里应该重新获取token再重连的,但前端没有用到token,所以不重新init了
|
// 这里应该重新获取token再重连的,但前端没有用到token,所以不重新init了
|
||||||
this.discardWebsocket()
|
this.discardWebsocket()
|
||||||
throw new Error('认证响应错误')
|
throw new Error('认证响应错误')
|
||||||
@ -276,13 +276,13 @@ export default class ChatClientDirect {
|
|||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
// 未知消息
|
// 未知消息
|
||||||
window.console.warn('未知包类型,operation=', operation, dataView, body)
|
console.warn('未知包类型,operation=', operation, dataView, body)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
handlerCommand (command) {
|
handlerCommand(command) {
|
||||||
let cmd = command.cmd || ''
|
let cmd = command.cmd || ''
|
||||||
let pos = cmd.indexOf(':')
|
let pos = cmd.indexOf(':')
|
||||||
if (pos != -1) {
|
if (pos != -1) {
|
||||||
@ -294,7 +294,7 @@ export default class ChatClientDirect {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async danmuMsgCallback (command) {
|
async danmuMsgCallback(command) {
|
||||||
if (!this.onAddText) {
|
if (!this.onAddText) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -329,10 +329,10 @@ export default class ChatClientDirect {
|
|||||||
authorType: authorType,
|
authorType: authorType,
|
||||||
content: info[1],
|
content: info[1],
|
||||||
privilegeType: privilegeType,
|
privilegeType: privilegeType,
|
||||||
isGiftDanmaku: !!info[0][9],
|
isGiftDanmaku: Boolean(info[0][9]),
|
||||||
authorLevel: info[4][0],
|
authorLevel: info[4][0],
|
||||||
isNewbie: info[2][5] < 10000,
|
isNewbie: info[2][5] < 10000,
|
||||||
isMobileVerified: !!info[2][6],
|
isMobileVerified: Boolean(info[2][6]),
|
||||||
medalLevel: roomId === this.roomId ? medalLevel : 0,
|
medalLevel: roomId === this.roomId ? medalLevel : 0,
|
||||||
id: getUuid4Hex(),
|
id: getUuid4Hex(),
|
||||||
translation: '',
|
translation: '',
|
||||||
@ -341,7 +341,7 @@ export default class ChatClientDirect {
|
|||||||
this.onAddText(data)
|
this.onAddText(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
sendGiftCallback (command) {
|
sendGiftCallback(command) {
|
||||||
if (!this.onAddGift) {
|
if (!this.onAddGift) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -362,7 +362,7 @@ export default class ChatClientDirect {
|
|||||||
this.onAddGift(data)
|
this.onAddGift(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
async guardBuyCallback (command) {
|
async guardBuyCallback(command) {
|
||||||
if (!this.onAddMember) {
|
if (!this.onAddMember) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -378,7 +378,7 @@ export default class ChatClientDirect {
|
|||||||
this.onAddMember(data)
|
this.onAddMember(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
superChatMessageCallback (command) {
|
superChatMessageCallback(command) {
|
||||||
if (!this.onAddSuperChat) {
|
if (!this.onAddSuperChat) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -396,7 +396,7 @@ export default class ChatClientDirect {
|
|||||||
this.onAddSuperChat(data)
|
this.onAddSuperChat(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
superChatMessageDeleteCallback (command) {
|
superChatMessageDeleteCallback(command) {
|
||||||
if (!this.onDelSuperChat) {
|
if (!this.onDelSuperChat) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -405,7 +405,7 @@ export default class ChatClientDirect {
|
|||||||
for (let id of command.data.ids) {
|
for (let id of command.data.ids) {
|
||||||
ids.push(id.toString())
|
ids.push(id.toString())
|
||||||
}
|
}
|
||||||
this.onDelSuperChat({ids})
|
this.onDelSuperChat({ ids })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,10 +11,10 @@ const COMMAND_UPDATE_TRANSLATION = 7
|
|||||||
const CONTENT_TYPE_EMOTICON = 1
|
const CONTENT_TYPE_EMOTICON = 1
|
||||||
|
|
||||||
const HEARTBEAT_INTERVAL = 10 * 1000
|
const HEARTBEAT_INTERVAL = 10 * 1000
|
||||||
const RECEIVE_TIMEOUT = HEARTBEAT_INTERVAL + 5 * 1000
|
const RECEIVE_TIMEOUT = HEARTBEAT_INTERVAL + (5 * 1000)
|
||||||
|
|
||||||
export default class ChatClientRelay {
|
export default class ChatClientRelay {
|
||||||
constructor (roomId, autoTranslate) {
|
constructor(roomId, autoTranslate) {
|
||||||
this.roomId = roomId
|
this.roomId = roomId
|
||||||
this.autoTranslate = autoTranslate
|
this.autoTranslate = autoTranslate
|
||||||
|
|
||||||
@ -32,18 +32,18 @@ export default class ChatClientRelay {
|
|||||||
this.receiveTimeoutTimerId = null
|
this.receiveTimeoutTimerId = null
|
||||||
}
|
}
|
||||||
|
|
||||||
start () {
|
start() {
|
||||||
this.wsConnect()
|
this.wsConnect()
|
||||||
}
|
}
|
||||||
|
|
||||||
stop () {
|
stop() {
|
||||||
this.isDestroying = true
|
this.isDestroying = true
|
||||||
if (this.websocket) {
|
if (this.websocket) {
|
||||||
this.websocket.close()
|
this.websocket.close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
wsConnect () {
|
wsConnect() {
|
||||||
if (this.isDestroying) {
|
if (this.isDestroying) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -57,7 +57,7 @@ export default class ChatClientRelay {
|
|||||||
this.websocket.onmessage = this.onWsMessage.bind(this)
|
this.websocket.onmessage = this.onWsMessage.bind(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
onWsOpen () {
|
onWsOpen() {
|
||||||
this.retryCount = 0
|
this.retryCount = 0
|
||||||
this.websocket.send(JSON.stringify({
|
this.websocket.send(JSON.stringify({
|
||||||
cmd: COMMAND_JOIN_ROOM,
|
cmd: COMMAND_JOIN_ROOM,
|
||||||
@ -72,7 +72,7 @@ export default class ChatClientRelay {
|
|||||||
this.refreshReceiveTimeoutTimer()
|
this.refreshReceiveTimeoutTimer()
|
||||||
}
|
}
|
||||||
|
|
||||||
sendHeartbeat () {
|
sendHeartbeat() {
|
||||||
this.websocket.send(JSON.stringify({
|
this.websocket.send(JSON.stringify({
|
||||||
cmd: COMMAND_HEARTBEAT
|
cmd: COMMAND_HEARTBEAT
|
||||||
}))
|
}))
|
||||||
@ -86,7 +86,7 @@ export default class ChatClientRelay {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onReceiveTimeout() {
|
onReceiveTimeout() {
|
||||||
window.console.warn('接收消息超时')
|
console.warn('接收消息超时')
|
||||||
this.receiveTimeoutTimerId = null
|
this.receiveTimeoutTimerId = null
|
||||||
|
|
||||||
// 直接丢弃阻塞的websocket,不等onclose回调了
|
// 直接丢弃阻塞的websocket,不等onclose回调了
|
||||||
@ -95,7 +95,7 @@ export default class ChatClientRelay {
|
|||||||
this.onWsClose()
|
this.onWsClose()
|
||||||
}
|
}
|
||||||
|
|
||||||
onWsClose () {
|
onWsClose() {
|
||||||
this.websocket = null
|
this.websocket = null
|
||||||
if (this.heartbeatTimerId) {
|
if (this.heartbeatTimerId) {
|
||||||
window.clearInterval(this.heartbeatTimerId)
|
window.clearInterval(this.heartbeatTimerId)
|
||||||
@ -109,14 +109,14 @@ export default class ChatClientRelay {
|
|||||||
if (this.isDestroying) {
|
if (this.isDestroying) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
window.console.warn(`掉线重连中${++this.retryCount}`)
|
console.warn(`掉线重连中${++this.retryCount}`)
|
||||||
window.setTimeout(this.wsConnect.bind(this), 1000)
|
window.setTimeout(this.wsConnect.bind(this), 1000)
|
||||||
}
|
}
|
||||||
|
|
||||||
onWsMessage (event) {
|
onWsMessage(event) {
|
||||||
this.refreshReceiveTimeoutTimer()
|
this.refreshReceiveTimeoutTimer()
|
||||||
|
|
||||||
let {cmd, data} = JSON.parse(event.data)
|
let { cmd, data } = JSON.parse(event.data)
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
case COMMAND_HEARTBEAT: {
|
case COMMAND_HEARTBEAT: {
|
||||||
break
|
break
|
||||||
@ -140,10 +140,10 @@ export default class ChatClientRelay {
|
|||||||
authorType: data[3],
|
authorType: data[3],
|
||||||
content: data[4],
|
content: data[4],
|
||||||
privilegeType: data[5],
|
privilegeType: data[5],
|
||||||
isGiftDanmaku: !!data[6],
|
isGiftDanmaku: Boolean(data[6]),
|
||||||
authorLevel: data[7],
|
authorLevel: data[7],
|
||||||
isNewbie: !!data[8],
|
isNewbie: Boolean(data[8]),
|
||||||
isMobileVerified: !!data[9],
|
isMobileVerified: Boolean(data[9]),
|
||||||
medalLevel: data[10],
|
medalLevel: data[10],
|
||||||
id: data[11],
|
id: data[11],
|
||||||
translation: data[12],
|
translation: data[12],
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import {getUuid4Hex} from '@/utils'
|
import { getUuid4Hex } from '@/utils'
|
||||||
import * as constants from '@/components/ChatRenderer/constants'
|
import * as constants from '@/components/ChatRenderer/constants'
|
||||||
import * as avatar from './avatar'
|
import * as avatar from './avatar'
|
||||||
|
|
||||||
@ -19,7 +19,7 @@ const CONTENTS = [
|
|||||||
'有一说一,这件事大家懂的都懂,不懂的,说了你也不明白,不如不说', '让我看看', '我柜子动了,我不玩了'
|
'有一说一,这件事大家懂的都懂,不懂的,说了你也不明白,不如不说', '让我看看', '我柜子动了,我不玩了'
|
||||||
]
|
]
|
||||||
|
|
||||||
// TODO 改成对象?
|
// TODO 改成对象?
|
||||||
const EMOTICONS = [
|
const EMOTICONS = [
|
||||||
'/static/img/emoticons/233.png',
|
'/static/img/emoticons/233.png',
|
||||||
'/static/img/emoticons/miaoa.png',
|
'/static/img/emoticons/miaoa.png',
|
||||||
@ -27,13 +27,13 @@ const EMOTICONS = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
const AUTHOR_TYPES = [
|
const AUTHOR_TYPES = [
|
||||||
{weight: 10, value: constants.AUTHRO_TYPE_NORMAL},
|
{ weight: 10, value: constants.AUTHRO_TYPE_NORMAL },
|
||||||
{weight: 5, value: constants.AUTHRO_TYPE_MEMBER},
|
{ weight: 5, value: constants.AUTHRO_TYPE_MEMBER },
|
||||||
{weight: 2, value: constants.AUTHRO_TYPE_ADMIN},
|
{ weight: 2, value: constants.AUTHRO_TYPE_ADMIN },
|
||||||
{weight: 1, value: constants.AUTHRO_TYPE_OWNER}
|
{ weight: 1, value: constants.AUTHRO_TYPE_OWNER }
|
||||||
]
|
]
|
||||||
|
|
||||||
function randGuardInfo () {
|
function randGuardInfo() {
|
||||||
let authorType = randomChoose(AUTHOR_TYPES)
|
let authorType = randomChoose(AUTHOR_TYPES)
|
||||||
let privilegeType
|
let privilegeType
|
||||||
if (authorType === constants.AUTHRO_TYPE_MEMBER || authorType === constants.AUTHRO_TYPE_ADMIN) {
|
if (authorType === constants.AUTHRO_TYPE_MEMBER || authorType === constants.AUTHRO_TYPE_ADMIN) {
|
||||||
@ -41,16 +41,16 @@ function randGuardInfo () {
|
|||||||
} else {
|
} else {
|
||||||
privilegeType = 0
|
privilegeType = 0
|
||||||
}
|
}
|
||||||
return {authorType, privilegeType}
|
return { authorType, privilegeType }
|
||||||
}
|
}
|
||||||
|
|
||||||
const GIFT_INFO_LIST = [
|
const GIFT_INFO_LIST = [
|
||||||
{giftName: 'B坷垃', totalCoin: 9900},
|
{ giftName: 'B坷垃', totalCoin: 9900 },
|
||||||
{giftName: '礼花', totalCoin: 28000},
|
{ giftName: '礼花', totalCoin: 28000 },
|
||||||
{giftName: '花式夸夸', totalCoin: 39000},
|
{ giftName: '花式夸夸', totalCoin: 39000 },
|
||||||
{giftName: '天空之翼', totalCoin: 100000},
|
{ giftName: '天空之翼', totalCoin: 100000 },
|
||||||
{giftName: '摩天大楼', totalCoin: 450000},
|
{ giftName: '摩天大楼', totalCoin: 450000 },
|
||||||
{giftName: '小电视飞船', totalCoin: 1245000}
|
{ giftName: '小电视飞船', totalCoin: 1245000 }
|
||||||
]
|
]
|
||||||
|
|
||||||
const SC_PRICES = [
|
const SC_PRICES = [
|
||||||
@ -159,7 +159,7 @@ const MESSAGE_GENERATORS = [
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
function randomChoose (nodes) {
|
function randomChoose(nodes) {
|
||||||
if (nodes.length === 0) {
|
if (nodes.length === 0) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
@ -187,12 +187,12 @@ function randomChoose (nodes) {
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
function randInt (min, max) {
|
function randInt(min, max) {
|
||||||
return Math.floor(min + (max - min + 1) * Math.random())
|
return Math.floor(min + ((max - min + 1) * Math.random()))
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class ChatClientTest {
|
export default class ChatClientTest {
|
||||||
constructor () {
|
constructor() {
|
||||||
this.minSleepTime = 800
|
this.minSleepTime = 800
|
||||||
this.maxSleepTime = 1200
|
this.maxSleepTime = 1200
|
||||||
|
|
||||||
@ -206,25 +206,25 @@ export default class ChatClientTest {
|
|||||||
this.timerId = null
|
this.timerId = null
|
||||||
}
|
}
|
||||||
|
|
||||||
start () {
|
start() {
|
||||||
this.refreshTimer()
|
this.refreshTimer()
|
||||||
}
|
}
|
||||||
|
|
||||||
stop () {
|
stop() {
|
||||||
if (this.timerId) {
|
if (this.timerId) {
|
||||||
window.clearTimeout(this.timerId)
|
window.clearTimeout(this.timerId)
|
||||||
this.timerId = null
|
this.timerId = null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
refreshTimer () {
|
refreshTimer() {
|
||||||
this.timerId = window.setTimeout(this.onTimeout.bind(this), randInt(this.minSleepTime, this.maxSleepTime))
|
this.timerId = window.setTimeout(this.onTimeout.bind(this), randInt(this.minSleepTime, this.maxSleepTime))
|
||||||
}
|
}
|
||||||
|
|
||||||
onTimeout () {
|
onTimeout() {
|
||||||
this.refreshTimer()
|
this.refreshTimer()
|
||||||
|
|
||||||
let {type, message} = randomChoose(MESSAGE_GENERATORS)()
|
let { type, message } = randomChoose(MESSAGE_GENERATORS)()
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case constants.MESSAGE_TYPE_TEXT:
|
case constants.MESSAGE_TYPE_TEXT:
|
||||||
this.onAddText(message)
|
this.onAddText(message)
|
||||||
|
@ -2,7 +2,7 @@ import axios from 'axios'
|
|||||||
|
|
||||||
export const DEFAULT_AVATAR_URL = '//static.hdslb.com/images/member/noface.gif'
|
export const DEFAULT_AVATAR_URL = '//static.hdslb.com/images/member/noface.gif'
|
||||||
|
|
||||||
export function processAvatarUrl (avatarUrl) {
|
export function processAvatarUrl(avatarUrl) {
|
||||||
// 去掉协议,兼容HTTP、HTTPS
|
// 去掉协议,兼容HTTP、HTTPS
|
||||||
let m = avatarUrl.match(/(?:https?:)?(.*)/)
|
let m = avatarUrl.match(/(?:https?:)?(.*)/)
|
||||||
if (m) {
|
if (m) {
|
||||||
@ -15,12 +15,12 @@ export function processAvatarUrl (avatarUrl) {
|
|||||||
return avatarUrl
|
return avatarUrl
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getAvatarUrl (uid) {
|
export async function getAvatarUrl(uid) {
|
||||||
let res
|
let res
|
||||||
try {
|
try {
|
||||||
res = (await axios.get('/api/avatar_url', {params: {
|
res = (await axios.get('/api/avatar_url', { params: {
|
||||||
uid: uid
|
uid: uid
|
||||||
}})).data
|
} })).data
|
||||||
} catch {
|
} catch {
|
||||||
return DEFAULT_AVATAR_URL
|
return DEFAULT_AVATAR_URL
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import {mergeConfig} from '@/utils'
|
import { mergeConfig } from '@/utils'
|
||||||
|
|
||||||
export const DEFAULT_CONFIG = {
|
export const DEFAULT_CONFIG = {
|
||||||
minGiftPrice: 7, // $1
|
minGiftPrice: 7, // $1
|
||||||
@ -22,15 +22,15 @@ export const DEFAULT_CONFIG = {
|
|||||||
giftUsernamePronunciation: ''
|
giftUsernamePronunciation: ''
|
||||||
}
|
}
|
||||||
|
|
||||||
export function setLocalConfig (config) {
|
export function setLocalConfig(config) {
|
||||||
config = mergeConfig(config, DEFAULT_CONFIG)
|
config = mergeConfig(config, DEFAULT_CONFIG)
|
||||||
window.localStorage.config = JSON.stringify(config)
|
window.localStorage.config = JSON.stringify(config)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getLocalConfig () {
|
export function getLocalConfig() {
|
||||||
try {
|
try {
|
||||||
return mergeConfig(JSON.parse(window.localStorage.config), DEFAULT_CONFIG)
|
return mergeConfig(JSON.parse(window.localStorage.config), DEFAULT_CONFIG)
|
||||||
} catch {
|
} catch {
|
||||||
return {...DEFAULT_CONFIG}
|
return { ...DEFAULT_CONFIG }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,9 +9,9 @@
|
|||||||
<div id="header-content-primary-column" class="style-scope yt-live-chat-membership-item-renderer">
|
<div id="header-content-primary-column" class="style-scope yt-live-chat-membership-item-renderer">
|
||||||
<div id="header-content-inner-column" class="style-scope yt-live-chat-membership-item-renderer">
|
<div id="header-content-inner-column" class="style-scope yt-live-chat-membership-item-renderer">
|
||||||
<yt-live-chat-author-chip class="style-scope yt-live-chat-membership-item-renderer">
|
<yt-live-chat-author-chip class="style-scope yt-live-chat-membership-item-renderer">
|
||||||
<span id="author-name" dir="auto" class="member style-scope yt-live-chat-author-chip">{{
|
<span id="author-name" dir="auto" class="member style-scope yt-live-chat-author-chip">
|
||||||
authorName
|
<template>{{ authorName }}</template>
|
||||||
}}<!-- 这里是已验证勋章 -->
|
<!-- 这里是已验证勋章 -->
|
||||||
<span id="chip-badges" class="style-scope yt-live-chat-author-chip"></span>
|
<span id="chip-badges" class="style-scope yt-live-chat-author-chip"></span>
|
||||||
</span>
|
</span>
|
||||||
<span id="chat-badges" class="style-scope yt-live-chat-author-chip">
|
<span id="chat-badges" class="style-scope yt-live-chat-author-chip">
|
||||||
@ -21,9 +21,9 @@
|
|||||||
</span>
|
</span>
|
||||||
</yt-live-chat-author-chip>
|
</yt-live-chat-author-chip>
|
||||||
</div>
|
</div>
|
||||||
<div id="header-subtext" class="style-scope yt-live-chat-membership-item-renderer">{{title}}</div>
|
<div id="header-subtext" class="style-scope yt-live-chat-membership-item-renderer">{{ title }}</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="timestamp" class="style-scope yt-live-chat-membership-item-renderer">{{timeText}}</div>
|
<div id="timestamp" class="style-scope yt-live-chat-membership-item-renderer">{{ timeText }}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -16,16 +16,14 @@
|
|||||||
></img-shadow>
|
></img-shadow>
|
||||||
<div id="header-content" class="style-scope yt-live-chat-paid-message-renderer">
|
<div id="header-content" class="style-scope yt-live-chat-paid-message-renderer">
|
||||||
<div id="header-content-primary-column" class="style-scope yt-live-chat-paid-message-renderer">
|
<div id="header-content-primary-column" class="style-scope yt-live-chat-paid-message-renderer">
|
||||||
<div id="author-name" class="style-scope yt-live-chat-paid-message-renderer">{{authorName}}</div>
|
<div id="author-name" class="style-scope yt-live-chat-paid-message-renderer">{{ authorName }}</div>
|
||||||
<div id="purchase-amount" class="style-scope yt-live-chat-paid-message-renderer">{{priceText}}</div>
|
<div id="purchase-amount" class="style-scope yt-live-chat-paid-message-renderer">{{ priceText }}</div>
|
||||||
</div>
|
</div>
|
||||||
<span id="timestamp" class="style-scope yt-live-chat-paid-message-renderer">{{timeText}}</span>
|
<span id="timestamp" class="style-scope yt-live-chat-paid-message-renderer">{{ timeText }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="content" class="style-scope yt-live-chat-paid-message-renderer">
|
<div id="content" class="style-scope yt-live-chat-paid-message-renderer">
|
||||||
<div id="message" dir="auto" class="style-scope yt-live-chat-paid-message-renderer">{{
|
<div id="message" dir="auto" class="style-scope yt-live-chat-paid-message-renderer">{{ content }}</div>
|
||||||
content
|
|
||||||
}}</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</yt-live-chat-paid-message-renderer>
|
</yt-live-chat-paid-message-renderer>
|
||||||
@ -53,7 +51,7 @@ export default {
|
|||||||
return constants.getPriceConfig(this.price).colors
|
return constants.getPriceConfig(this.price).colors
|
||||||
},
|
},
|
||||||
priceText() {
|
priceText() {
|
||||||
return 'CN¥' + utils.formatCurrency(this.price)
|
return `CN¥${utils.formatCurrency(this.price)}`
|
||||||
},
|
},
|
||||||
timeText() {
|
timeText() {
|
||||||
return utils.getTimeTextHourMin(this.time)
|
return utils.getTimeTextHourMin(this.time)
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
:imgUrl="avatarUrl"
|
:imgUrl="avatarUrl"
|
||||||
></img-shadow>
|
></img-shadow>
|
||||||
<div id="content" class="style-scope yt-live-chat-text-message-renderer">
|
<div id="content" class="style-scope yt-live-chat-text-message-renderer">
|
||||||
<span id="timestamp" class="style-scope yt-live-chat-text-message-renderer">{{timeText}}</span>
|
<span id="timestamp" class="style-scope yt-live-chat-text-message-renderer">{{ timeText }}</span>
|
||||||
<yt-live-chat-author-chip class="style-scope yt-live-chat-text-message-renderer">
|
<yt-live-chat-author-chip class="style-scope yt-live-chat-text-message-renderer">
|
||||||
<span id="author-name" dir="auto" class="style-scope yt-live-chat-author-chip" :type="authorTypeText">
|
<span id="author-name" dir="auto" class="style-scope yt-live-chat-author-chip" :type="authorTypeText">
|
||||||
<template>{{ authorName }}</template>
|
<template>{{ authorName }}</template>
|
||||||
@ -23,7 +23,7 @@
|
|||||||
:src="emoticon" :alt="content" shared-tooltip-text="" id="emoji"
|
:src="emoticon" :alt="content" shared-tooltip-text="" id="emoji"
|
||||||
>
|
>
|
||||||
<el-badge :value="repeated" :max="99" v-show="repeated > 1" class="style-scope yt-live-chat-text-message-renderer"
|
<el-badge :value="repeated" :max="99" v-show="repeated > 1" class="style-scope yt-live-chat-text-message-renderer"
|
||||||
:style="{'--repeated-mark-color': repeatedMarkColor}"
|
:style="{ '--repeated-mark-color': repeatedMarkColor }"
|
||||||
></el-badge>
|
></el-badge>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
@ -73,7 +73,7 @@ export default {
|
|||||||
color = [0, 0, 0]
|
color = [0, 0, 0]
|
||||||
let t = (this.repeated - 2) / (10 - 2)
|
let t = (this.repeated - 2) / (10 - 2)
|
||||||
for (let i = 0; i < 3; i++) {
|
for (let i = 0; i < 3; i++) {
|
||||||
color[i] = REPEATED_MARK_COLOR_START[i] + (REPEATED_MARK_COLOR_END[i] - REPEATED_MARK_COLOR_START[i]) * t
|
color[i] = REPEATED_MARK_COLOR_START[i] + ((REPEATED_MARK_COLOR_END[i] - REPEATED_MARK_COLOR_START[i]) * t)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return `hsl(${color[0]}, ${color[1]}%, ${color[2]}%)`
|
return `hsl(${color[0]}, ${color[1]}%, ${color[2]}%)`
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
<img-shadow id="author-photo" height="24" width="24" class="style-scope yt-live-chat-ticker-paid-message-item-renderer"
|
<img-shadow id="author-photo" height="24" width="24" class="style-scope yt-live-chat-ticker-paid-message-item-renderer"
|
||||||
:imgUrl="message.raw.avatarUrl"
|
:imgUrl="message.raw.avatarUrl"
|
||||||
></img-shadow>
|
></img-shadow>
|
||||||
<span id="text" dir="ltr" class="style-scope yt-live-chat-ticker-paid-message-item-renderer">{{message.text}}</span>
|
<span id="text" dir="ltr" class="style-scope yt-live-chat-ticker-paid-message-item-renderer">{{ message.text }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</yt-live-chat-ticker-paid-message-item-renderer>
|
</yt-live-chat-ticker-paid-message-item-renderer>
|
||||||
@ -40,7 +40,7 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import * as chatConfig from '@/api/chatConfig'
|
import * as chatConfig from '@/api/chatConfig'
|
||||||
import {formatCurrency} from '@/utils'
|
import { formatCurrency } from '@/utils'
|
||||||
import ImgShadow from './ImgShadow.vue'
|
import ImgShadow from './ImgShadow.vue'
|
||||||
import MembershipItem from './MembershipItem.vue'
|
import MembershipItem from './MembershipItem.vue'
|
||||||
import PaidMessage from './PaidMessage.vue'
|
import PaidMessage from './PaidMessage.vue'
|
||||||
@ -142,7 +142,7 @@ export default {
|
|||||||
color2 = config.colors.headerBg
|
color2 = config.colors.headerBg
|
||||||
}
|
}
|
||||||
let pinTime = this.getPinTime(message)
|
let pinTime = this.getPinTime(message)
|
||||||
let progress = (1 - (this.curTime - message.addTime) / (60 * 1000) / pinTime) * 100
|
let progress = (1 - ((this.curTime - message.addTime) / (60 * 1000) / pinTime)) * 100
|
||||||
if (progress < 0) {
|
if (progress < 0) {
|
||||||
progress = 0
|
progress = 0
|
||||||
} else if (progress > 100) {
|
} else if (progress > 100) {
|
||||||
@ -160,7 +160,7 @@ export default {
|
|||||||
if (message.type === constants.MESSAGE_TYPE_MEMBER) {
|
if (message.type === constants.MESSAGE_TYPE_MEMBER) {
|
||||||
return 'Member'
|
return 'Member'
|
||||||
}
|
}
|
||||||
return 'CN¥' + formatCurrency(message.price)
|
return `CN¥${formatCurrency(message.price)}`
|
||||||
},
|
},
|
||||||
getPinTime(message) {
|
getPinTime(message) {
|
||||||
if (message.type === constants.MESSAGE_TYPE_MEMBER) {
|
if (message.type === constants.MESSAGE_TYPE_MEMBER) {
|
||||||
|
@ -100,7 +100,7 @@ export const PRICE_CONFIGS = [
|
|||||||
pinTime: 0
|
pinTime: 0
|
||||||
},
|
},
|
||||||
{ // $1蓝
|
{ // $1蓝
|
||||||
price: 1 * EXCHANGE_RATE,
|
price: EXCHANGE_RATE,
|
||||||
colors: {
|
colors: {
|
||||||
contentBg: 'rgba(30,136,229,1)',
|
contentBg: 'rgba(30,136,229,1)',
|
||||||
headerBg: 'rgba(21,101,192,1)',
|
headerBg: 'rgba(21,101,192,1)',
|
||||||
@ -113,7 +113,7 @@ export const PRICE_CONFIGS = [
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
export function getPriceConfig (price) {
|
export function getPriceConfig(price) {
|
||||||
for (const config of PRICE_CONFIGS) {
|
for (const config of PRICE_CONFIGS) {
|
||||||
if (price >= config.price) {
|
if (price >= config.price) {
|
||||||
return config
|
return config
|
||||||
@ -122,21 +122,21 @@ 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) {
|
export function getShowAuthorName(message) {
|
||||||
if (message.authorNamePronunciation && message.authorNamePronunciation !== message.authorName) {
|
if (message.authorNamePronunciation && message.authorNamePronunciation !== message.authorName) {
|
||||||
return `${message.authorName}(${message.authorNamePronunciation})`
|
return `${message.authorName}(${message.authorNamePronunciation})`
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
<div ref="scroller" id="item-scroller" class="style-scope yt-live-chat-item-list-renderer animated" @scroll="onScroll">
|
<div ref="scroller" id="item-scroller" class="style-scope yt-live-chat-item-list-renderer animated" @scroll="onScroll">
|
||||||
<div ref="itemOffset" id="item-offset" class="style-scope yt-live-chat-item-list-renderer" style="height: 0px;">
|
<div ref="itemOffset" id="item-offset" class="style-scope yt-live-chat-item-list-renderer" style="height: 0px;">
|
||||||
<div ref="items" id="items" class="style-scope yt-live-chat-item-list-renderer" style="overflow: hidden"
|
<div ref="items" id="items" class="style-scope yt-live-chat-item-list-renderer" style="overflow: hidden"
|
||||||
:style="{transform: `translateY(${Math.floor(scrollPixelsRemaining)}px)`}"
|
:style="{ transform: `translateY(${Math.floor(scrollPixelsRemaining)}px)` }"
|
||||||
>
|
>
|
||||||
<template v-for="message in messages">
|
<template v-for="message in messages">
|
||||||
<text-message :key="message.id" v-if="message.type === MESSAGE_TYPE_TEXT"
|
<text-message :key="message.id" v-if="message.type === MESSAGE_TYPE_TEXT"
|
||||||
@ -114,7 +114,7 @@ export default {
|
|||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
canScrollToBottom() {
|
canScrollToBottom() {
|
||||||
return this.atBottom/* || this.allowScroll*/
|
return this.atBottom/* || this.allowScroll */
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
@ -288,7 +288,7 @@ export default {
|
|||||||
this.emitSmoothedMessageTimerId = window.setTimeout(this.emitSmoothedMessages)
|
this.emitSmoothedMessageTimerId = window.setTimeout(this.emitSmoothedMessages)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
messageNeedSmooth({type}) {
|
messageNeedSmooth({ type }) {
|
||||||
return NEED_SMOOTH_MESSAGE_TYPES.indexOf(type) !== -1
|
return NEED_SMOOTH_MESSAGE_TYPES.indexOf(type) !== -1
|
||||||
},
|
},
|
||||||
emitSmoothedMessages() {
|
emitSmoothedMessages() {
|
||||||
@ -355,18 +355,18 @@ export default {
|
|||||||
|
|
||||||
for (let message of messageGroup) {
|
for (let message of messageGroup) {
|
||||||
switch (message.type) {
|
switch (message.type) {
|
||||||
case constants.MESSAGE_TYPE_TEXT:
|
case constants.MESSAGE_TYPE_TEXT:
|
||||||
case constants.MESSAGE_TYPE_GIFT:
|
case constants.MESSAGE_TYPE_GIFT:
|
||||||
case constants.MESSAGE_TYPE_MEMBER:
|
case constants.MESSAGE_TYPE_MEMBER:
|
||||||
case constants.MESSAGE_TYPE_SUPER_CHAT:
|
case constants.MESSAGE_TYPE_SUPER_CHAT:
|
||||||
this.handleAddMessage(message)
|
this.handleAddMessage(message)
|
||||||
break
|
break
|
||||||
case constants.MESSAGE_TYPE_DEL:
|
case constants.MESSAGE_TYPE_DEL:
|
||||||
this.handleDelMessage(message)
|
this.handleDelMessage(message)
|
||||||
break
|
break
|
||||||
case constants.MESSAGE_TYPE_UPDATE:
|
case constants.MESSAGE_TYPE_UPDATE:
|
||||||
this.handleUpdateMessage(message)
|
this.handleUpdateMessage(message)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -389,7 +389,7 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
handleDelMessage({id}) {
|
handleDelMessage({ id }) {
|
||||||
for (let arr of [this.messages, this.paidMessages, this.messagesBuffer]) {
|
for (let arr of [this.messages, this.paidMessages, this.messagesBuffer]) {
|
||||||
for (let i = 0; i < arr.length; i++) {
|
for (let i = 0; i < arr.length; i++) {
|
||||||
if (arr[i].id === id) {
|
if (arr[i].id === id) {
|
||||||
@ -400,7 +400,7 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
handleUpdateMessage({id, newValuesObj}) {
|
handleUpdateMessage({ id, newValuesObj }) {
|
||||||
// 遍历滚动的消息
|
// 遍历滚动的消息
|
||||||
this.forEachRecentMessage(999999999, message => {
|
this.forEachRecentMessage(999999999, message => {
|
||||||
if (message.id !== id) {
|
if (message.id !== id) {
|
||||||
@ -468,7 +468,7 @@ export default {
|
|||||||
this.lastSmoothChatMessageAddMs = performance.now()
|
this.lastSmoothChatMessageAddMs = performance.now()
|
||||||
}
|
}
|
||||||
let interval = performance.now() - this.lastSmoothChatMessageAddMs
|
let interval = performance.now() - this.lastSmoothChatMessageAddMs
|
||||||
this.chatRateMs = 0.9 * this.chatRateMs + 0.1 * interval
|
this.chatRateMs = (0.9 * this.chatRateMs) + (0.1 * interval)
|
||||||
if (this.isSmoothed) {
|
if (this.isSmoothed) {
|
||||||
if (this.chatRateMs < 400) {
|
if (this.chatRateMs < 400) {
|
||||||
this.isSmoothed = false
|
this.isSmoothed = false
|
||||||
|
@ -8,35 +8,35 @@
|
|||||||
:default-active="$route.path"
|
:default-active="$route.path"
|
||||||
>
|
>
|
||||||
<el-menu-item index="/">
|
<el-menu-item index="/">
|
||||||
<i class="el-icon-s-home"></i>{{$t('sidebar.home')}}
|
<i class="el-icon-s-home"></i>{{ $t('sidebar.home') }}
|
||||||
</el-menu-item>
|
</el-menu-item>
|
||||||
<el-menu-item :index="$router.resolve({name: 'stylegen'}).href">
|
<el-menu-item :index="$router.resolve({ name: 'stylegen' }).href">
|
||||||
<i class="el-icon-brush"></i>{{$t('sidebar.stylegen')}}
|
<i class="el-icon-brush"></i>{{ $t('sidebar.stylegen') }}
|
||||||
</el-menu-item>
|
</el-menu-item>
|
||||||
<el-menu-item :index="$router.resolve({name: 'help'}).href">
|
<el-menu-item :index="$router.resolve({ name: 'help' }).href">
|
||||||
<i class="el-icon-question"></i>{{$t('sidebar.help')}}
|
<i class="el-icon-question"></i>{{ $t('sidebar.help') }}
|
||||||
</el-menu-item>
|
</el-menu-item>
|
||||||
<a href="https://github.com/xfgryujk/blivechat" target="_blank">
|
<a href="https://github.com/xfgryujk/blivechat" target="_blank">
|
||||||
<el-menu-item>
|
<el-menu-item>
|
||||||
<i class="el-icon-share"></i>{{$t('sidebar.projectAddress')}}
|
<i class="el-icon-share"></i>{{ $t('sidebar.projectAddress') }}
|
||||||
</el-menu-item>
|
</el-menu-item>
|
||||||
</a>
|
</a>
|
||||||
<a href="http://link.bilibili.com/ctool/vtuber" target="_blank">
|
<a href="http://link.bilibili.com/ctool/vtuber" target="_blank">
|
||||||
<el-menu-item>
|
<el-menu-item>
|
||||||
<i class="el-icon-link"></i>{{$t('sidebar.giftRecordOfficial')}}
|
<i class="el-icon-link"></i>{{ $t('sidebar.giftRecordOfficial') }}
|
||||||
</el-menu-item>
|
</el-menu-item>
|
||||||
</a>
|
</a>
|
||||||
<el-submenu index="null">
|
<el-submenu index="null">
|
||||||
<template slot="title">
|
<template slot="title">
|
||||||
<i class="el-icon-chat-line-square"></i>Language
|
<i class="el-icon-chat-line-square"></i>Language
|
||||||
</template>
|
</template>
|
||||||
<el-menu-item v-for="{locale, name} in [
|
<el-menu-item v-for="{ locale, name } in [
|
||||||
{locale: 'zh', name: '中文'},
|
{ locale: 'zh', name: '中文' },
|
||||||
{locale: 'ja', name: '日本語'},
|
{ locale: 'ja', name: '日本語' },
|
||||||
{locale: 'en', name: 'English'}
|
{ locale: 'en', name: 'English' }
|
||||||
]" :key="locale"
|
]"
|
||||||
@click="onSelectLanguage(locale)"
|
:key="locale" @click="onSelectLanguage(locale)"
|
||||||
>{{name}}</el-menu-item>
|
>{{ name }}</el-menu-item>
|
||||||
</el-submenu>
|
</el-submenu>
|
||||||
</el-menu>
|
</el-menu>
|
||||||
</el-scrollbar>
|
</el-scrollbar>
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<el-container class="app-wrapper" :class="{mobile: isMobile}">
|
<el-container class="app-wrapper" :class="{ mobile: isMobile }">
|
||||||
<div v-show="isMobile && !hideSidebar" class="drawer-bg" @click="hideSidebar = true"></div>
|
<div v-show="isMobile && !hideSidebar" class="drawer-bg" @click="hideSidebar = true"></div>
|
||||||
<el-aside width="230px" class="sidebar-container" :class="{'hide-sidebar': hideSidebar}">
|
<el-aside width="230px" class="sidebar-container" :class="{ 'hide-sidebar': hideSidebar }">
|
||||||
<div class="logo-container">
|
<div class="logo-container">
|
||||||
<router-link to="/">
|
<router-link to="/">
|
||||||
<img src="@/assets/img/logo.png" class="sidebar-logo">
|
<img src="@/assets/img/logo.png" class="sidebar-logo">
|
||||||
|
@ -71,12 +71,12 @@ const router = new VueRouter({
|
|||||||
path: '/',
|
path: '/',
|
||||||
component: Layout,
|
component: Layout,
|
||||||
children: [
|
children: [
|
||||||
{path: '', component: Home},
|
{ path: '', component: Home },
|
||||||
{path: 'stylegen', name: 'stylegen', component: StyleGenerator},
|
{ path: 'stylegen', name: 'stylegen', component: StyleGenerator },
|
||||||
{path: 'help', name: 'help', component: Help}
|
{ path: 'help', name: 'help', component: Help }
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{path: '/room/test', name: 'test_room', component: Room, props: route => ({strConfig: route.query})},
|
{ path: '/room/test', name: 'test_room', component: Room, props: route => ({ strConfig: route.query }) },
|
||||||
{
|
{
|
||||||
path: '/room/:roomId',
|
path: '/room/:roomId',
|
||||||
name: 'room',
|
name: 'room',
|
||||||
@ -86,10 +86,10 @@ const router = new VueRouter({
|
|||||||
if (isNaN(roomId)) {
|
if (isNaN(roomId)) {
|
||||||
roomId = null
|
roomId = null
|
||||||
}
|
}
|
||||||
return {roomId, strConfig: route.query}
|
return { roomId, strConfig: route.query }
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{path: '*', component: NotFound}
|
{ path: '*', component: NotFound }
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
export function mergeConfig (config, defaultConfig) {
|
export function mergeConfig(config, defaultConfig) {
|
||||||
let res = {}
|
let res = {}
|
||||||
for (let i in defaultConfig) {
|
for (let i in defaultConfig) {
|
||||||
res[i] = i in config ? config[i] : defaultConfig[i]
|
res[i] = i in config ? config[i] : defaultConfig[i]
|
||||||
@ -6,14 +6,14 @@ export function mergeConfig (config, defaultConfig) {
|
|||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
export function toBool (val) {
|
export function toBool(val) {
|
||||||
if (typeof val === 'string') {
|
if (typeof val === 'string') {
|
||||||
return ['false', 'no', 'off', '0', ''].indexOf(val.toLowerCase()) === -1
|
return ['false', 'no', 'off', '0', ''].indexOf(val.toLowerCase()) === -1
|
||||||
}
|
}
|
||||||
return !!val
|
return Boolean(val)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function toInt (val, _default) {
|
export function toInt(val, _default) {
|
||||||
let res = parseInt(val)
|
let res = parseInt(val)
|
||||||
if (isNaN(res)) {
|
if (isNaN(res)) {
|
||||||
res = _default
|
res = _default
|
||||||
@ -21,19 +21,19 @@ export function toInt (val, _default) {
|
|||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
export function formatCurrency (price) {
|
export function formatCurrency(price) {
|
||||||
return new Intl.NumberFormat('zh-CN', {
|
return new Intl.NumberFormat('zh-CN', {
|
||||||
minimumFractionDigits: price < 100 ? 2 : 0
|
minimumFractionDigits: price < 100 ? 2 : 0
|
||||||
}).format(price)
|
}).format(price)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getTimeTextHourMin (date) {
|
export function getTimeTextHourMin(date) {
|
||||||
let hour = date.getHours()
|
let hour = date.getHours()
|
||||||
let min = ('00' + date.getMinutes()).slice(-2)
|
let min = `00${date.getMinutes()}`.slice(-2)
|
||||||
return `${hour}:${min}`
|
return `${hour}:${min}`
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getUuid4Hex () {
|
export function getUuid4Hex() {
|
||||||
let chars = []
|
let chars = []
|
||||||
for (let i = 0; i < 32; i++) {
|
for (let i = 0; i < 32; i++) {
|
||||||
let char = Math.floor(Math.random() * 16).toString(16)
|
let char = Math.floor(Math.random() * 16).toString(16)
|
||||||
|
@ -2,21 +2,21 @@ export const DICT_PINYIN = 'pinyin'
|
|||||||
export const DICT_KANA = 'kana'
|
export const DICT_KANA = 'kana'
|
||||||
|
|
||||||
export class PronunciationConverter {
|
export class PronunciationConverter {
|
||||||
constructor () {
|
constructor() {
|
||||||
this.pronunciationMap = new Map()
|
this.pronunciationMap = new Map()
|
||||||
}
|
}
|
||||||
|
|
||||||
async loadDict (dictName) {
|
async loadDict(dictName) {
|
||||||
let promise
|
let promise
|
||||||
switch (dictName) {
|
switch (dictName) {
|
||||||
case DICT_PINYIN:
|
case DICT_PINYIN:
|
||||||
promise = import('./dictPinyin')
|
promise = import('./dictPinyin')
|
||||||
break
|
break
|
||||||
case DICT_KANA:
|
case DICT_KANA:
|
||||||
promise = import('./dictKana')
|
promise = import('./dictKana')
|
||||||
break
|
break
|
||||||
default:
|
default:
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
let dictTxt = (await promise).default
|
let dictTxt = (await promise).default
|
||||||
@ -30,7 +30,7 @@ export class PronunciationConverter {
|
|||||||
this.pronunciationMap = pronunciationMap
|
this.pronunciationMap = pronunciationMap
|
||||||
}
|
}
|
||||||
|
|
||||||
getPronunciation (text) {
|
getPronunciation(text) {
|
||||||
let res = []
|
let res = []
|
||||||
let lastHasPronunciation = null
|
let lastHasPronunciation = null
|
||||||
for (let char of text) {
|
for (let char of text) {
|
||||||
|
@ -1,15 +1,15 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<h1>{{$t('help.help')}}</h1>
|
<h1>{{ $t('help.help') }}</h1>
|
||||||
<p>{{$t('help.p1')}}</p>
|
<p>{{ $t('help.p1') }}</p>
|
||||||
<p class="img-container"><el-image fit="scale-down" src="/static/img/tutorial/tutorial-1.png"></el-image></p>
|
<p class="img-container"><el-image fit="scale-down" src="/static/img/tutorial/tutorial-1.png"></el-image></p>
|
||||||
<p>{{$t('help.p2')}}</p>
|
<p>{{ $t('help.p2') }}</p>
|
||||||
<p class="img-container large-img"><el-image fit="scale-down" src="/static/img/tutorial/tutorial-2.png"></el-image></p>
|
<p class="img-container large-img"><el-image fit="scale-down" src="/static/img/tutorial/tutorial-2.png"></el-image></p>
|
||||||
<p>{{$t('help.p3')}}</p>
|
<p>{{ $t('help.p3') }}</p>
|
||||||
<p class="img-container large-img"><el-image fit="scale-down" src="/static/img/tutorial/tutorial-3.png"></el-image></p>
|
<p class="img-container large-img"><el-image fit="scale-down" src="/static/img/tutorial/tutorial-3.png"></el-image></p>
|
||||||
<p>{{$t('help.p4')}}</p>
|
<p>{{ $t('help.p4') }}</p>
|
||||||
<p class="img-container"><el-image fit="scale-down" src="/static/img/tutorial/tutorial-4.png"></el-image></p>
|
<p class="img-container"><el-image fit="scale-down" src="/static/img/tutorial/tutorial-4.png"></el-image></p>
|
||||||
<p>{{$t('help.p5')}}</p>
|
<p>{{ $t('help.p5') }}</p>
|
||||||
<p class="img-container large-img"><el-image fit="scale-down" src="/static/img/tutorial/tutorial-5.png"></el-image></p>
|
<p class="img-container large-img"><el-image fit="scale-down" src="/static/img/tutorial/tutorial-5.png"></el-image></p>
|
||||||
<p><br><br><br><br><br><br><br><br>--------------------------------------------------------------------------------------------------------</p>
|
<p><br><br><br><br><br><br><br><br>--------------------------------------------------------------------------------------------------------</p>
|
||||||
<p>喜欢的话可以推荐给别人,专栏求支持_(:з」∠)_ <a href="https://www.bilibili.com/read/cv4594365" target="_blank">https://www.bilibili.com/read/cv4594365</a></p>
|
<p>喜欢的话可以推荐给别人,专栏求支持_(:з」∠)_ <a href="https://www.bilibili.com/read/cv4594365" target="_blank">https://www.bilibili.com/read/cv4594365</a></p>
|
||||||
|
@ -142,7 +142,7 @@ import _ from 'lodash'
|
|||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
import download from 'downloadjs'
|
import download from 'downloadjs'
|
||||||
|
|
||||||
import {mergeConfig} from '@/utils'
|
import { mergeConfig } from '@/utils'
|
||||||
import * as chatConfig from '@/api/chatConfig'
|
import * as chatConfig from '@/api/chatConfig'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
@ -189,7 +189,7 @@ export default {
|
|||||||
try {
|
try {
|
||||||
this.serverConfig = (await axios.get('/api/server_info')).data.config
|
this.serverConfig = (await axios.get('/api/server_info')).data.config
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.$message.error('Failed to fetch server information: ' + e)
|
this.$message.error(`Failed to fetch server information: ${e}`)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
enterRoom() {
|
enterRoom() {
|
||||||
@ -202,13 +202,13 @@ export default {
|
|||||||
if (isTestRoom && this.form.roomId === '') {
|
if (isTestRoom && this.form.roomId === '') {
|
||||||
return ''
|
return ''
|
||||||
}
|
}
|
||||||
let query = {...this.form}
|
let query = { ...this.form }
|
||||||
delete query.roomId
|
delete query.roomId
|
||||||
let resolved
|
let resolved
|
||||||
if (isTestRoom) {
|
if (isTestRoom) {
|
||||||
resolved = this.$router.resolve({name: 'test_room', query})
|
resolved = this.$router.resolve({ name: 'test_room', query })
|
||||||
} else {
|
} else {
|
||||||
resolved = this.$router.resolve({name: 'room', params: {roomId: this.form.roomId}, query})
|
resolved = this.$router.resolve({ name: 'room', params: { roomId: this.form.roomId }, query })
|
||||||
}
|
}
|
||||||
return `${window.location.protocol}//${window.location.host}${resolved.href}`
|
return `${window.location.protocol}//${window.location.host}${resolved.href}`
|
||||||
},
|
},
|
||||||
@ -235,7 +235,7 @@ export default {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
cfg = mergeConfig(cfg, chatConfig.DEFAULT_CONFIG)
|
cfg = mergeConfig(cfg, chatConfig.DEFAULT_CONFIG)
|
||||||
this.form = {roomId: this.form.roomId, ...cfg}
|
this.form = { roomId: this.form.roomId, ...cfg }
|
||||||
}
|
}
|
||||||
reader.readAsText(input.files[0])
|
reader.readAsText(input.files[0])
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import {mergeConfig, toBool, toInt} from '@/utils'
|
import { mergeConfig, toBool, toInt } from '@/utils'
|
||||||
import * as pronunciation from '@/utils/pronunciation'
|
import * as pronunciation from '@/utils/pronunciation'
|
||||||
import * as chatConfig from '@/api/chatConfig'
|
import * as chatConfig from '@/api/chatConfig'
|
||||||
import ChatClientTest from '@/api/chat/ChatClientTest'
|
import ChatClientTest from '@/api/chat/ChatClientTest'
|
||||||
@ -29,7 +29,7 @@ export default {
|
|||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
config: {...chatConfig.DEFAULT_CONFIG},
|
config: { ...chatConfig.DEFAULT_CONFIG },
|
||||||
chatClient: null,
|
chatClient: null,
|
||||||
pronunciationConverter: null
|
pronunciationConverter: null
|
||||||
}
|
}
|
||||||
@ -203,7 +203,7 @@ export default {
|
|||||||
if (!this.config.autoTranslate) {
|
if (!this.config.autoTranslate) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
this.$refs.renderer.updateMessage(data.id, {translation: data.translation})
|
this.$refs.renderer.updateMessage(data.id, { translation: data.translation })
|
||||||
},
|
},
|
||||||
|
|
||||||
filterTextMessage(data) {
|
filterTextMessage(data) {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<el-form label-width="150px" size="mini">
|
<el-form label-width="150px" size="mini">
|
||||||
<h3>{{$t('stylegen.outlines')}}</h3>
|
<h3>{{ $t('stylegen.outlines') }}</h3>
|
||||||
<el-card shadow="never">
|
<el-card shadow="never">
|
||||||
<el-row :gutter="20">
|
<el-row :gutter="20">
|
||||||
<el-col :xs="24" :sm="12">
|
<el-col :xs="24" :sm="12">
|
||||||
@ -20,7 +20,7 @@
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-card>
|
</el-card>
|
||||||
|
|
||||||
<h3>{{$t('stylegen.avatars')}}</h3>
|
<h3>{{ $t('stylegen.avatars') }}</h3>
|
||||||
<el-card shadow="never">
|
<el-card shadow="never">
|
||||||
<el-row :gutter="20">
|
<el-row :gutter="20">
|
||||||
<el-col :xs="24" :sm="12">
|
<el-col :xs="24" :sm="12">
|
||||||
@ -36,7 +36,7 @@
|
|||||||
</el-row>
|
</el-row>
|
||||||
</el-card>
|
</el-card>
|
||||||
|
|
||||||
<h3>{{$t('stylegen.userNames')}}</h3>
|
<h3>{{ $t('stylegen.userNames') }}</h3>
|
||||||
<el-card shadow="never">
|
<el-card shadow="never">
|
||||||
<el-row :gutter="20">
|
<el-row :gutter="20">
|
||||||
<el-col :xs="24" :sm="12">
|
<el-col :xs="24" :sm="12">
|
||||||
@ -100,7 +100,7 @@
|
|||||||
</el-row>
|
</el-row>
|
||||||
</el-card>
|
</el-card>
|
||||||
|
|
||||||
<h3>{{$t('stylegen.messages')}}</h3>
|
<h3>{{ $t('stylegen.messages') }}</h3>
|
||||||
<el-card shadow="never">
|
<el-card shadow="never">
|
||||||
<el-row :gutter="20">
|
<el-row :gutter="20">
|
||||||
<el-col :xs="24" :sm="12">
|
<el-col :xs="24" :sm="12">
|
||||||
@ -138,7 +138,7 @@
|
|||||||
</el-row>
|
</el-row>
|
||||||
</el-card>
|
</el-card>
|
||||||
|
|
||||||
<h3>{{$t('stylegen.time')}}</h3>
|
<h3>{{ $t('stylegen.time') }}</h3>
|
||||||
<el-card shadow="never">
|
<el-card shadow="never">
|
||||||
<el-form-item :label="$t('stylegen.showTime')">
|
<el-form-item :label="$t('stylegen.showTime')">
|
||||||
<el-switch v-model="form.showTime"></el-switch>
|
<el-switch v-model="form.showTime"></el-switch>
|
||||||
@ -169,7 +169,7 @@
|
|||||||
</el-row>
|
</el-row>
|
||||||
</el-card>
|
</el-card>
|
||||||
|
|
||||||
<h3>{{$t('stylegen.backgrounds')}}</h3>
|
<h3>{{ $t('stylegen.backgrounds') }}</h3>
|
||||||
<el-card shadow="never">
|
<el-card shadow="never">
|
||||||
<el-row :gutter="20">
|
<el-row :gutter="20">
|
||||||
<el-col :xs="24" :sm="12">
|
<el-col :xs="24" :sm="12">
|
||||||
@ -209,7 +209,7 @@
|
|||||||
</el-row>
|
</el-row>
|
||||||
</el-card>
|
</el-card>
|
||||||
|
|
||||||
<h3>{{$t('stylegen.scAndNewMember')}}</h3>
|
<h3>{{ $t('stylegen.scAndNewMember') }}</h3>
|
||||||
<el-card shadow="never">
|
<el-card shadow="never">
|
||||||
<el-row :gutter="20">
|
<el-row :gutter="20">
|
||||||
<el-col :xs="24" :sm="12">
|
<el-col :xs="24" :sm="12">
|
||||||
@ -306,7 +306,7 @@
|
|||||||
</el-row>
|
</el-row>
|
||||||
</el-card>
|
</el-card>
|
||||||
|
|
||||||
<h3>{{$t('stylegen.animation')}}</h3>
|
<h3>{{ $t('stylegen.animation') }}</h3>
|
||||||
<el-card shadow="never">
|
<el-card shadow="never">
|
||||||
<el-row :gutter="20">
|
<el-row :gutter="20">
|
||||||
<el-col :xs="24" :sm="12">
|
<el-col :xs="24" :sm="12">
|
||||||
@ -357,7 +357,7 @@ import _ from 'lodash'
|
|||||||
|
|
||||||
import FontSelect from './FontSelect'
|
import FontSelect from './FontSelect'
|
||||||
import * as common from './common'
|
import * as common from './common'
|
||||||
import {mergeConfig} from '@/utils'
|
import { mergeConfig } from '@/utils'
|
||||||
|
|
||||||
export const DEFAULT_CONFIG = {
|
export const DEFAULT_CONFIG = {
|
||||||
showOutlines: true,
|
showOutlines: true,
|
||||||
@ -484,7 +484,7 @@ yt-live-chat-renderer * {
|
|||||||
line-height: ${this.form.messageLineHeight || this.form.messageFontSize}px !important;
|
line-height: ${this.form.messageLineHeight || this.form.messageFontSize}px !important;
|
||||||
}`
|
}`
|
||||||
},
|
},
|
||||||
showOutlinesStyle () {
|
showOutlinesStyle() {
|
||||||
if (!this.form.showOutlines || !this.form.outlineSize) {
|
if (!this.form.showOutlines || !this.form.outlineSize) {
|
||||||
return ''
|
return ''
|
||||||
}
|
}
|
||||||
@ -668,11 +668,11 @@ yt-live-chat-ticker-sponsor-item-renderer * {
|
|||||||
try {
|
try {
|
||||||
return mergeConfig(JSON.parse(window.localStorage.stylegenConfig), DEFAULT_CONFIG)
|
return mergeConfig(JSON.parse(window.localStorage.stylegenConfig), DEFAULT_CONFIG)
|
||||||
} catch {
|
} catch {
|
||||||
return {...DEFAULT_CONFIG}
|
return { ...DEFAULT_CONFIG }
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
resetConfig() {
|
resetConfig() {
|
||||||
this.form = {...DEFAULT_CONFIG}
|
this.form = { ...DEFAULT_CONFIG }
|
||||||
},
|
},
|
||||||
|
|
||||||
getBgStyleForAuthorType(authorType, color) {
|
getBgStyleForAuthorType(authorType, color) {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<el-form label-width="150px" size="mini">
|
<el-form label-width="150px" size="mini">
|
||||||
<h3>{{$t('stylegen.avatars')}}</h3>
|
<h3>{{ $t('stylegen.avatars') }}</h3>
|
||||||
<el-card shadow="never">
|
<el-card shadow="never">
|
||||||
<el-row :gutter="20">
|
<el-row :gutter="20">
|
||||||
<el-col :xs="24" :sm="12">
|
<el-col :xs="24" :sm="12">
|
||||||
@ -17,7 +17,7 @@
|
|||||||
</el-row>
|
</el-row>
|
||||||
</el-card>
|
</el-card>
|
||||||
|
|
||||||
<h3>{{$t('stylegen.userNames')}}</h3>
|
<h3>{{ $t('stylegen.userNames') }}</h3>
|
||||||
<el-card shadow="never">
|
<el-card shadow="never">
|
||||||
<el-row :gutter="20">
|
<el-row :gutter="20">
|
||||||
<el-col :xs="24" :sm="12">
|
<el-col :xs="24" :sm="12">
|
||||||
@ -76,7 +76,7 @@
|
|||||||
</el-row>
|
</el-row>
|
||||||
</el-card>
|
</el-card>
|
||||||
|
|
||||||
<h3>{{$t('stylegen.messages')}}</h3>
|
<h3>{{ $t('stylegen.messages') }}</h3>
|
||||||
<el-card shadow="never">
|
<el-card shadow="never">
|
||||||
<el-row :gutter="20">
|
<el-row :gutter="20">
|
||||||
<el-col :xs="24" :sm="12">
|
<el-col :xs="24" :sm="12">
|
||||||
@ -111,7 +111,7 @@
|
|||||||
</el-row>
|
</el-row>
|
||||||
</el-card>
|
</el-card>
|
||||||
|
|
||||||
<h3>{{$t('stylegen.time')}}</h3>
|
<h3>{{ $t('stylegen.time') }}</h3>
|
||||||
<el-card shadow="never">
|
<el-card shadow="never">
|
||||||
<el-form-item :label="$t('stylegen.showTime')">
|
<el-form-item :label="$t('stylegen.showTime')">
|
||||||
<el-switch v-model="form.showTime"></el-switch>
|
<el-switch v-model="form.showTime"></el-switch>
|
||||||
@ -142,7 +142,7 @@
|
|||||||
</el-row>
|
</el-row>
|
||||||
</el-card>
|
</el-card>
|
||||||
|
|
||||||
<h3>{{$t('stylegen.backgrounds')}}</h3>
|
<h3>{{ $t('stylegen.backgrounds') }}</h3>
|
||||||
<el-card shadow="never">
|
<el-card shadow="never">
|
||||||
<el-row :gutter="20">
|
<el-row :gutter="20">
|
||||||
<el-col :xs="24" :sm="12">
|
<el-col :xs="24" :sm="12">
|
||||||
@ -177,7 +177,7 @@
|
|||||||
</el-row>
|
</el-row>
|
||||||
</el-card>
|
</el-card>
|
||||||
|
|
||||||
<h3>{{$t('stylegen.scAndNewMember')}}</h3>
|
<h3>{{ $t('stylegen.scAndNewMember') }}</h3>
|
||||||
<el-card shadow="never">
|
<el-card shadow="never">
|
||||||
<el-row :gutter="20">
|
<el-row :gutter="20">
|
||||||
<el-col :xs="24" :sm="12">
|
<el-col :xs="24" :sm="12">
|
||||||
@ -256,7 +256,7 @@
|
|||||||
</el-row>
|
</el-row>
|
||||||
</el-card>
|
</el-card>
|
||||||
|
|
||||||
<h3>{{$t('stylegen.animation')}}</h3>
|
<h3>{{ $t('stylegen.animation') }}</h3>
|
||||||
<el-card shadow="never">
|
<el-card shadow="never">
|
||||||
<el-row :gutter="20">
|
<el-row :gutter="20">
|
||||||
<el-col :xs="24" :sm="12">
|
<el-col :xs="24" :sm="12">
|
||||||
@ -307,7 +307,7 @@ import _ from 'lodash'
|
|||||||
|
|
||||||
import FontSelect from './FontSelect'
|
import FontSelect from './FontSelect'
|
||||||
import * as common from './common'
|
import * as common from './common'
|
||||||
import {mergeConfig} from '@/utils'
|
import { mergeConfig } from '@/utils'
|
||||||
|
|
||||||
export const DEFAULT_CONFIG = {
|
export const DEFAULT_CONFIG = {
|
||||||
showAvatars: true,
|
showAvatars: true,
|
||||||
@ -477,8 +477,8 @@ yt-live-chat-text-message-renderer #message::before {
|
|||||||
content: "";
|
content: "";
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: ${this.form.showUserNames ? ((this.form.userNameLineHeight || this.form.userNameFontSize) + 10) : 20}px;
|
top: ${this.form.showUserNames ? (this.form.userNameLineHeight || this.form.userNameFontSize) + 10 : 20}px;
|
||||||
left: ${this.form.showAvatars ? (this.form.avatarSize + this.form.avatarSize / 4 - 8) : -8}px;
|
left: ${this.form.showAvatars ? this.form.avatarSize + (this.form.avatarSize / 4) - 8 : -8}px;
|
||||||
border: 8px solid transparent;
|
border: 8px solid transparent;
|
||||||
border-right: 18px solid;
|
border-right: 18px solid;
|
||||||
transform: rotate(35deg);
|
transform: rotate(35deg);
|
||||||
@ -586,11 +586,11 @@ yt-live-chat-ticker-sponsor-item-renderer * {
|
|||||||
try {
|
try {
|
||||||
return mergeConfig(JSON.parse(window.localStorage.stylegenLineLikeConfig), DEFAULT_CONFIG)
|
return mergeConfig(JSON.parse(window.localStorage.stylegenLineLikeConfig), DEFAULT_CONFIG)
|
||||||
} catch {
|
} catch {
|
||||||
return {...DEFAULT_CONFIG}
|
return { ...DEFAULT_CONFIG }
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
resetConfig() {
|
resetConfig() {
|
||||||
this.form = {...DEFAULT_CONFIG}
|
this.form = { ...DEFAULT_CONFIG }
|
||||||
},
|
},
|
||||||
|
|
||||||
getBgStyleForAuthorType(authorType, color) {
|
getBgStyleForAuthorType(authorType, color) {
|
||||||
|
@ -53,7 +53,7 @@ yt-live-chat-membership-item-renderer a {
|
|||||||
text-decoration: none !important;
|
text-decoration: none !important;
|
||||||
}`
|
}`
|
||||||
|
|
||||||
export function getImportStyle (allFonts) {
|
export function getImportStyle(allFonts) {
|
||||||
let fontsNeedToImport = new Set()
|
let fontsNeedToImport = new Set()
|
||||||
for (let font of allFonts) {
|
for (let font of allFonts) {
|
||||||
if (fonts.NETWORK_FONTS.indexOf(font) !== -1) {
|
if (fonts.NETWORK_FONTS.indexOf(font) !== -1) {
|
||||||
@ -67,7 +67,7 @@ export function getImportStyle (allFonts) {
|
|||||||
return res.join('\n')
|
return res.join('\n')
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getAvatarStyle (config) {
|
export function getAvatarStyle(config) {
|
||||||
return `/* Avatars */
|
return `/* Avatars */
|
||||||
yt-live-chat-text-message-renderer #author-photo,
|
yt-live-chat-text-message-renderer #author-photo,
|
||||||
yt-live-chat-text-message-renderer #author-photo img,
|
yt-live-chat-text-message-renderer #author-photo img,
|
||||||
@ -83,7 +83,7 @@ yt-live-chat-membership-item-renderer #author-photo img {
|
|||||||
}`
|
}`
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getTimeStyle (config) {
|
export function getTimeStyle(config) {
|
||||||
return `/* Timestamps */
|
return `/* Timestamps */
|
||||||
yt-live-chat-text-message-renderer #timestamp {
|
yt-live-chat-text-message-renderer #timestamp {
|
||||||
display: ${config.showTime ? 'inline' : 'none'} !important;
|
display: ${config.showTime ? 'inline' : 'none'} !important;
|
||||||
@ -94,7 +94,7 @@ yt-live-chat-text-message-renderer #timestamp {
|
|||||||
}`
|
}`
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getAnimationStyle (config) {
|
export function getAnimationStyle(config) {
|
||||||
if (!config.animateIn && !config.animateOut) {
|
if (!config.animateIn && !config.animateOut) {
|
||||||
return ''
|
return ''
|
||||||
}
|
}
|
||||||
@ -113,13 +113,13 @@ export function getAnimationStyle (config) {
|
|||||||
: ` transform: translateX(${config.reverseSlide ? 16 : -16}px);`
|
: ` transform: translateX(${config.reverseSlide ? 16 : -16}px);`
|
||||||
} }`)
|
} }`)
|
||||||
curTime += config.fadeInTime
|
curTime += config.fadeInTime
|
||||||
keyframes.push(` ${(curTime / totalTime) * 100}% { opacity: 1; transform: none; }`)
|
keyframes.push(` ${curTime / totalTime * 100}% { opacity: 1; transform: none; }`)
|
||||||
}
|
}
|
||||||
if (config.animateOut) {
|
if (config.animateOut) {
|
||||||
curTime += config.animateOutWaitTime * 1000
|
curTime += config.animateOutWaitTime * 1000
|
||||||
keyframes.push(` ${(curTime / totalTime) * 100}% { opacity: 1; transform: none; }`)
|
keyframes.push(` ${curTime / totalTime * 100}% { opacity: 1; transform: none; }`)
|
||||||
curTime += config.fadeOutTime
|
curTime += config.fadeOutTime
|
||||||
keyframes.push(` ${(curTime / totalTime) * 100}% { opacity: 0;${!config.slide ? ''
|
keyframes.push(` ${curTime / totalTime * 100}% { opacity: 0;${!config.slide ? ''
|
||||||
: ` transform: translateX(${config.reverseSlide ? -16 : 16}px);`
|
: ` transform: translateX(${config.reverseSlide ? -16 : 16}px);`
|
||||||
} }`)
|
} }`)
|
||||||
}
|
}
|
||||||
@ -136,7 +136,7 @@ yt-live-chat-paid-message-renderer {
|
|||||||
}`
|
}`
|
||||||
}
|
}
|
||||||
|
|
||||||
export function cssEscapeStr (str) {
|
export function cssEscapeStr(str) {
|
||||||
let res = []
|
let res = []
|
||||||
for (let char of str) {
|
for (let char of str) {
|
||||||
res.push(cssEscapeChar(char))
|
res.push(cssEscapeChar(char))
|
||||||
@ -144,7 +144,7 @@ export function cssEscapeStr (str) {
|
|||||||
return res.join('')
|
return res.join('')
|
||||||
}
|
}
|
||||||
|
|
||||||
function cssEscapeChar (char) {
|
function cssEscapeChar(char) {
|
||||||
if (!needEscapeChar(char)) {
|
if (!needEscapeChar(char)) {
|
||||||
return char
|
return char
|
||||||
}
|
}
|
||||||
@ -153,7 +153,7 @@ function cssEscapeChar (char) {
|
|||||||
return `\\${hexCode} `
|
return `\\${hexCode} `
|
||||||
}
|
}
|
||||||
|
|
||||||
function needEscapeChar (char) {
|
function needEscapeChar(char) {
|
||||||
let code = char.codePointAt(0)
|
let code = char.codePointAt(0)
|
||||||
if (0x20 <= code && code <= 0x7E) {
|
if (0x20 <= code && code <= 0x7E) {
|
||||||
return char === '"' || char === '\\'
|
return char === '"' || char === '\\'
|
||||||
|
@ -11,21 +11,21 @@
|
|||||||
</el-tabs>
|
</el-tabs>
|
||||||
|
|
||||||
<el-form label-width="150px" size="mini">
|
<el-form label-width="150px" size="mini">
|
||||||
<h3>{{$t('stylegen.result')}}</h3>
|
<h3>{{ $t('stylegen.result') }}</h3>
|
||||||
<el-card shadow="never">
|
<el-card shadow="never">
|
||||||
<el-form-item label="CSS">
|
<el-form-item label="CSS">
|
||||||
<el-input v-model="inputResult" ref="result" type="textarea" :rows="20"></el-input>
|
<el-input v-model="inputResult" ref="result" type="textarea" :rows="20"></el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
<el-button type="primary" @click="copyResult">{{$t('stylegen.copy')}}</el-button>
|
<el-button type="primary" @click="copyResult">{{ $t('stylegen.copy') }}</el-button>
|
||||||
<el-button @click="resetConfig">{{$t('stylegen.resetConfig')}}</el-button>
|
<el-button @click="resetConfig">{{ $t('stylegen.resetConfig') }}</el-button>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-card>
|
</el-card>
|
||||||
</el-form>
|
</el-form>
|
||||||
</el-col>
|
</el-col>
|
||||||
|
|
||||||
<el-col :sm="24" :md="8">
|
<el-col :sm="24" :md="8">
|
||||||
<div :style="{position: 'relative', top: `${exampleTop}px`}">
|
<div :style="{ position: 'relative', top: `${exampleTop}px` }">
|
||||||
<el-form inline style="line-height: 40px">
|
<el-form inline style="line-height: 40px">
|
||||||
<el-form-item :label="$t('stylegen.playAnimation')" style="margin: 0">
|
<el-form-item :label="$t('stylegen.playAnimation')" style="margin: 0">
|
||||||
<el-switch v-model="playAnimation" @change="onPlayAnimationChange"></el-switch>
|
<el-switch v-model="playAnimation" @change="onPlayAnimationChange"></el-switch>
|
||||||
@ -34,7 +34,7 @@
|
|||||||
<el-switch v-model="exampleBgLight" :active-text="$t('stylegen.light')" :inactive-text="$t('stylegen.dark')"></el-switch>
|
<el-switch v-model="exampleBgLight" :active-text="$t('stylegen.light')" :inactive-text="$t('stylegen.dark')"></el-switch>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
<div id="example-container" :class="{light: exampleBgLight}">
|
<div id="example-container" :class="{ light: exampleBgLight }">
|
||||||
<div id="fakebody">
|
<div id="fakebody">
|
||||||
<room ref="room"></room>
|
<room ref="room"></room>
|
||||||
</div>
|
</div>
|
||||||
|
Loading…
Reference in New Issue
Block a user