| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137 |
- const MAX_LINES = 80
- /** 左下角弹幕展示的类型(不含 follow:关注成功不在此展示) */
- const CHAT_TYPES = new Set(['msg', 'seek', 'like', 'review'])
- const NAME_COLORS = [
- '#ff9f43', '#ffffff', '#ff9f43', '#ffd93d', '#6bcb77',
- '#8fbc8f', '#6bcb77', '#c084fc', '#ff6b8a', '#ff6b8a', '#c084fc'
- ]
- export function resolveRoomGroupId(session, roomKey = '') {
- if (!session || typeof session !== 'object') return String(roomKey || '')
- // 发送/订阅群组与老工程一致:优先 liveid,其次 group
- const group = session.liveid || session.group || session.live_id
- if (group != null && group !== '') return String(group)
- return String(roomKey || '')
- }
- /**
- * 收集当前房间可用于匹配 WS group 的候选(参考 live-room.nvue)。
- * 后端可能把 group 发成 liveid(hash) / 路由 id / 数字 id。
- */
- export function collectRoomGroupCandidates(room, roomKey = '') {
- return [
- roomKey,
- room?.liveid,
- room?.group,
- room?.id,
- room?.live_id,
- room?.liveId
- ]
- .filter((v) => v !== undefined && v !== null && v !== '')
- .map(String)
- }
- /**
- * 判断 WS 消息是否属于当前直播间(参考 live-room.nvue 的 groupCandidates)。
- * @param {string} [roomKey] 路由 id(liveId),后端有时把 group 发成 id 而非 liveid
- */
- export function groupMatchesRoom(msg, room, roomKey = '') {
- const msgGroup =
- msg?.group != null && msg.group !== ''
- ? String(msg.group)
- : (msg?.liveid != null && msg.liveid !== '' ? String(msg.liveid) : '')
- if (!msgGroup) return true
- const keys = collectRoomGroupCandidates(room, roomKey)
- return !keys.length || keys.includes(msgGroup)
- }
- function readInnerMessage(msg) {
- if (!msg) return null
- if (msg.message && typeof msg.message === 'object') return msg.message
- if (typeof msg.message === 'string') return { type: 'msg', text: msg.message }
- return null
- }
- export function isChatDisplayType(innerType) {
- return CHAT_TYPES.has(innerType)
- }
- export function extractEnterNotice(msg) {
- const inner = readInnerMessage(msg)
- if (!inner || inner.type !== 'coming') return null
- const form = msg.form || {}
- return {
- nickname: form.nickname || form.name || msg.username || '观众'
- }
- }
- export function extractChatLine(msg) {
- if (!msg) return null
- const inner = readInnerMessage(msg)
- if (inner) {
- if (inner.type === 'coming') return null
- if (isChatDisplayType(inner.type)) {
- const text = inner.text || inner.msg || inner.message || inner.content
- if (!text) return null
- const form = msg.form || {}
- return buildLine({
- userId: form.id,
- user: form.nickname || form.name || msg.username || msg.nickname || '观众',
- avatar: form.avatar || msg.avatar || '',
- text: String(text)
- })
- }
- }
- if (msg.type === 'msg' || msg.type === 'message') {
- const text = msg.message || msg.content || msg.text
- if (!text || typeof text === 'object') return null
- return buildLine({
- userId: msg.form?.id ?? msg.user_id,
- user: msg.form?.nickname || msg.username || msg.nickname || '观众',
- avatar: msg.form?.avatar || msg.avatar || '',
- text: String(text)
- })
- }
- return null
- }
- function buildLine({ userId, user, avatar, text }) {
- return {
- id: `${Date.now()}_${Math.random()}`,
- userId: userId != null ? String(userId) : '',
- user: user || '观众',
- avatar: avatar || '',
- text: text || ''
- }
- }
- export function chatLineFingerprint(line) {
- if (!line) return ''
- return `${line.userId}|${(line.text || '').slice(0, 200)}`
- }
- export function appendChatLine(list, line) {
- if (!line) return list
- const next = list.concat(line)
- return next.length > MAX_LINES ? next.slice(-MAX_LINES) : next
- }
- export function nicknameColor(userId) {
- const id = Number.parseInt(String(userId || '0'), 10)
- const idx = Number.isFinite(id) ? Math.abs(id) % NAME_COLORS.length : 0
- return NAME_COLORS[idx]
- }
- /**
- * 后端在主播下播时会推送 `{ message: { type: 'end' } }` 或 `{ type: 'end' }`。
- */
- export function isBroadcastEndedSignal(msg) {
- if (!msg) return false
- if (msg.type === 'end') return true
- if (msg.message && typeof msg.message === 'object' && msg.message.type === 'end') return true
- return false
- }
|