progessing on client

This commit is contained in:
2024-12-19 10:18:05 +08:00
parent 31930b362b
commit 7d35fe286d
25 changed files with 1634 additions and 504 deletions

View File

@@ -5,7 +5,7 @@ import { useDanmakuClient } from '@/store/useDanmakuClient';
// @ts-ignore
import * as constants from './blivechat/constants';
// @ts-ignore
import * as chatModels from './blivechat/models';
import * as chatModels from '../../data/chat/models';
// @ts-ignore
import * as pronunciation from './blivechat/utils/pronunciation'
// @ts-ignore

View File

@@ -12,7 +12,7 @@ import { useElementSize } from '@vueuse/core'
import { computed, onMounted, onUnmounted, ref } from 'vue'
import { useRoute } from 'vue-router'
import { Vue3Marquee } from 'vue3-marquee'
import { NCard, NDivider, NEmpty, NSpace, NText, useMessage } from 'naive-ui'
import { NCard, NDivider, NEmpty, NMessageProvider, NSpace, NText, useMessage } from 'naive-ui'
import { List } from 'linqts'
const props = defineProps<{
@@ -25,6 +25,7 @@ const currentId = computed(() => {
return props.id ?? route.query.id
})
const cardRef = ref()
const listContainerRef = ref()
const { height, width } = useElementSize(listContainerRef)
const itemHeight = 40
@@ -140,7 +141,8 @@ onUnmounted(() => {
</script>
<template>
<div class="live-request-background" v-bind="$attrs">
<NMessageProvider :to="cardRef" />
<div ref="cardRef" class="live-request-background" v-bind="$attrs">
<p class="live-request-header">{{ settings.obsTitle ?? '点播' }}</p>
<NDivider class="live-request-divider">
<p class="live-request-header-count">已有 {{ activeSongs.length ?? 0 }} </p>

View File

@@ -1,12 +1,76 @@
<script setup lang="ts">
import { useWebFetcher } from '@/store/useWebFetcher'
import { onMounted, onUnmounted, ref } from 'vue'
import { RPC } from '@mixer/postmessage-rpc'
import DirectClient, { DirectClientAuthInfo } from '@/data/DanmakuClients/DirectClient';
import OpenLiveClient from '@/data/DanmakuClients/OpenLiveClient';
const webFetcher = useWebFetcher()
let rpc: RPC | undefined
type QueryData = {
url: string;
headers?: { [key: string]: string };
body?: any;
}
function onGetDanmaku(data: any) {
rpc?.call('on-get-danmaku', data, false)
}
let timer: any
onMounted(async () => {
await webFetcher.Start()
if (window.parent) { //当是客户端组件时不自动启动, 需要客户端来启动以获取启动响应
console.log('[web-fetcher-iframe] 当前为客户端组件')
rpc = new RPC({
target: window.parent,
serviceId: 'web-fetcher',
origin: '*'
})
rpc.expose('status', () => {
return {
status: webFetcher.isStarted ? 'running' : 'stopped',
type: webFetcher.client?.type,
roomId: webFetcher.client instanceof OpenLiveClient ?
webFetcher.client.roomAuthInfo?.anchor_info.room_id :
webFetcher.client instanceof DirectClient ?
webFetcher.client.authInfo.roomId : -1,
startedAt: webFetcher.startedAt,
}
})
rpc.expose('start', async (data: { type: 'openlive' | 'direct', directAuthInfo?: DirectClientAuthInfo, force: boolean }) => {
console.log('[web-fetcher-iframe] 接收到 ' + (data.force ? '强制' : '') + '启动请求')
if (data.force && webFetcher.isStarted) {
webFetcher.Stop()
}
return await webFetcher.Start(data.type, data.directAuthInfo, true).then((result) => {
webFetcher.client?.on('all', (data) => onGetDanmaku(data))
})
})
rpc.expose('stop', () => {
console.log('[web-fetcher-iframe] 接收到停止请求')
webFetcher.Stop()
})
rpc.expose('call-hub', (data: {
name: string;
args: any[];
}) => {
return webFetcher.signalRClient?.invoke(data.name, ...data.args)
})
setTimeout(() => {
rpc?.call('ready', {}, false)
}, 1000);
console.log('[web-fetcher-iframe] RPC 初始化完成')
}
else {
await webFetcher.Start()
}
setTimeout(() => {
// @ts-expect-error obs的东西
if (!webFetcher.isStarted && window.obsstudio) {
@@ -23,16 +87,18 @@ onMounted(async () => {
})
onUnmounted(() => {
clearInterval(timer)
if (window.parent) {
webFetcher.client?.off('all', onGetDanmaku)
rpc?.destroy()
}
})
</script>
<template>
<div
class="web-fetcher-status"
:style="{
backgroundColor: webFetcher.isStarted ? '#6dc56d' : '#e34a4a',
}"
></div>
<div class="web-fetcher-status" :style="{
backgroundColor: webFetcher.isStarted ? '#6dc56d' : '#e34a4a',
}"></div>
</template>
<style scoped>
@@ -45,6 +111,7 @@ onUnmounted(() => {
animation: animated-border 3s infinite;
transition: background-color 0.5s;
}
@keyframes animated-border {
0% {
box-shadow: 0 0 0px #589580;

View File

@@ -6,7 +6,7 @@
</template>
<script>
import * as models from './models'
import * as models from '../../../data/chat/models'
export default {
name: 'ImgShadow',

View File

@@ -1,126 +0,0 @@
import { getUuid4Hex } from './utils'
import * as constants from './constants'
export const DEFAULT_AVATAR_URL = 'https://i0.hdslb.com/bfs/face/member/noface.jpg@64w_64h'
export class AddTextMsg {
constructor({
avatarUrl = DEFAULT_AVATAR_URL,
timestamp = new Date().getTime() / 1000,
authorName = '',
authorType = constants.AUTHOR_TYPE_NORMAL,
content = '',
privilegeType = 0,
isGiftDanmaku = false,
authorLevel = 1,
isNewbie = false,
isMobileVerified = true,
medalLevel = 0,
id = getUuid4Hex(),
translation = '',
emoticon = null
} = {}) {
this.avatarUrl = avatarUrl
this.timestamp = timestamp
this.authorName = authorName
this.authorType = authorType
this.content = content
this.privilegeType = privilegeType
this.isGiftDanmaku = isGiftDanmaku
this.authorLevel = authorLevel
this.isNewbie = isNewbie
this.isMobileVerified = isMobileVerified
this.medalLevel = medalLevel
this.id = id
this.translation = translation
this.emoticon = emoticon
}
}
export class AddGiftMsg {
constructor({
id = getUuid4Hex(),
avatarUrl = DEFAULT_AVATAR_URL,
timestamp = new Date().getTime() / 1000,
authorName = '',
totalCoin = 0,
totalFreeCoin = 0,
giftName = '',
num = 1
} = {}) {
this.id = id
this.avatarUrl = avatarUrl
this.timestamp = timestamp
this.authorName = authorName
this.totalCoin = totalCoin
this.totalFreeCoin = totalFreeCoin
this.giftName = giftName
this.num = num
}
}
export class AddMemberMsg {
constructor({
id = getUuid4Hex(),
avatarUrl = DEFAULT_AVATAR_URL,
timestamp = new Date().getTime() / 1000,
authorName = '',
privilegeType = 1
} = {}) {
this.id = id
this.avatarUrl = avatarUrl
this.timestamp = timestamp
this.authorName = authorName
this.privilegeType = privilegeType
}
}
export class AddSuperChatMsg {
constructor({
id = getUuid4Hex(),
avatarUrl = DEFAULT_AVATAR_URL,
timestamp = new Date().getTime() / 1000,
authorName = '',
price = 0,
content = '',
translation = ''
} = {}) {
this.id = id
this.avatarUrl = avatarUrl
this.timestamp = timestamp
this.authorName = authorName
this.price = price
this.content = content
this.translation = translation
}
}
export class DelSuperChatMsg {
constructor({ ids = [] } = {}) {
this.ids = ids
}
}
export class UpdateTranslationMsg {
constructor({ id = getUuid4Hex(), translation = '' } = {}) {
this.id = id
this.translation = translation
}
}
export const FATAL_ERROR_TYPE_AUTH_CODE_ERROR = 1
export const FATAL_ERROR_TYPE_TOO_MANY_RETRIES = 2
export const FATAL_ERROR_TYPE_TOO_MANY_CONNECTIONS = 3
export class ChatClientFatalError extends Error {
constructor(type, message) {
super(message)
this.type = type
}
}
export class DebugMsg {
constructor({ content = '' } = {}) {
this.content = content
}
}