feat: 完善弹幕AI
This commit is contained in:
parent
d723fc6cda
commit
bfcc4a5ce3
@ -128,7 +128,7 @@ export default function Controls(): JSX.Element {
|
||||
className="btn join-item"
|
||||
onClick={() => {
|
||||
query({
|
||||
name: "红豆",
|
||||
name: "音乐弹幕",
|
||||
})
|
||||
.then((result) => {
|
||||
// eslint-disable-next-line no-console -- temp
|
||||
@ -157,7 +157,7 @@ export default function Controls(): JSX.Element {
|
||||
>
|
||||
<div className="text-center">当前延迟 {offset / 1000} 秒</div>
|
||||
</div>
|
||||
<div className="w-full max-h-40 overflow-auto">
|
||||
<div className="w-full h-[20vh] overflow-auto">
|
||||
<ul className="timeline timeline-vertical">
|
||||
{history.map((item, i) => (
|
||||
<li key={i}>
|
||||
|
@ -3,10 +3,11 @@ import { useState, useEffect, useCallback, useRef } from "react";
|
||||
import useWebSocket, { ReadyState } from "react-use-websocket";
|
||||
import MessageDispatcher from "./message";
|
||||
import { Token } from "@/lib/types";
|
||||
import dayjs from "dayjs";
|
||||
|
||||
const MOMO_IM_URL = "wss://live-ws.immomo.com/ws/im";
|
||||
|
||||
export const Danmu: React.FC<{ token: Token }> = ({ token }) => {
|
||||
export default function Danmu({ token }: { token: Token }) {
|
||||
const [messageHistory, setMessageHistory] = useState<MessageEvent<any>[]>([]);
|
||||
const ref = useRef<HTMLDivElement>(null);
|
||||
|
||||
@ -52,15 +53,28 @@ export const Danmu: React.FC<{ token: Token }> = ({ token }) => {
|
||||
useEffect(() => {
|
||||
if (lastMessage !== null) {
|
||||
if (lastMessage.data) {
|
||||
const current = dayjs().format("HH:mm:ss");
|
||||
const message = JSON.parse(lastMessage.data);
|
||||
if (message.type === "pong") {
|
||||
return;
|
||||
}
|
||||
console.log(message);
|
||||
setMessageHistory((prev) => prev.concat(message));
|
||||
if (ref.current) {
|
||||
if (message.type === "group") {
|
||||
message.groups.forEach((group: any) => {
|
||||
group.current = current;
|
||||
setMessageHistory((prev) => prev.concat(group));
|
||||
setTimeout(() => {
|
||||
if (ref.current) {
|
||||
ref.current.scrollTop = ref.current.scrollHeight;
|
||||
}
|
||||
}, 0);
|
||||
});
|
||||
} else {
|
||||
message.current = current;
|
||||
setMessageHistory((prev) => prev.concat(message));
|
||||
setTimeout(() => {
|
||||
ref.current.scrollTop = ref.current.scrollHeight;
|
||||
if (ref.current) {
|
||||
ref.current.scrollTop = ref.current.scrollHeight;
|
||||
}
|
||||
}, 0);
|
||||
}
|
||||
}
|
||||
@ -68,10 +82,10 @@ export const Danmu: React.FC<{ token: Token }> = ({ token }) => {
|
||||
}, [lastMessage]);
|
||||
|
||||
return (
|
||||
<div className="h-[50vh] overflow-auto" ref={ref}>
|
||||
<div className="h-[60vh] overflow-auto" ref={ref}>
|
||||
{messageHistory.map((message, idx) => (
|
||||
<MessageDispatcher key={idx} message={message} />
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
@ -1,21 +1,50 @@
|
||||
export default function MessageDispatcher({ message }: { message: any }) {
|
||||
const messageType = message?.groups?.[0]?.units?.[0]?.type;
|
||||
let nick = "wait";
|
||||
let content = "wait";
|
||||
import dayjs from 'dayjs';
|
||||
|
||||
if (message?.type === 'sauth_ret') {
|
||||
return <div>{message?.data?.em}</div>
|
||||
export default function MessageDispatcher({ message }: { message: any }) {
|
||||
const messageType = message?.units?.[0]?.type;
|
||||
let nick = "";
|
||||
let content = "[暂不支持该类型消息]";
|
||||
let fortuneLv = 0;
|
||||
let text = '';
|
||||
let productId = '';
|
||||
let amount = 0;
|
||||
|
||||
if (message?.type === "sauth_ret") {
|
||||
if (message?.data?.em !== "ok") {
|
||||
return <div>{message?.data?.em}</div>;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
if (messageType === "Message") {
|
||||
nick = message?.groups?.[0]?.nick;
|
||||
content = message?.groups?.[0]?.units?.[0]?.["Msg.Message.data"]?.text;
|
||||
switch (messageType) {
|
||||
case "Message":
|
||||
nick = message?.nick;
|
||||
content = message?.units?.[0]?.["Msg.Message.data"]?.text;
|
||||
break;
|
||||
case "EnterRoom":
|
||||
text = message?.units?.[0]?.["Set.EnterRoom.data"]?.text;
|
||||
fortuneLv = message?.units?.[0]?.["Set.EnterRoom.data"]?.fortune_lv;
|
||||
content = `有新人:${text} lv: ${fortuneLv}`;
|
||||
break;
|
||||
case "Version":
|
||||
// TODO 解析
|
||||
return null
|
||||
case "GiftV3":
|
||||
nick = message?.nick;
|
||||
text = message?.['units']?.[0]?.['GiftV3.giftV3']?.['text']
|
||||
productId = message?.['units']?.[0]?.['GiftV3.giftV3']?.['productId']
|
||||
amount = message?.['units']?.[0]?.['GiftV3.giftV3']?.['weight']
|
||||
content = `${nick} 送出礼物,内容为: ${text},产品ID为: ${productId}, 价值:${amount}`
|
||||
nick = ''
|
||||
break;
|
||||
default:
|
||||
console.log("debug....", messageType, message);
|
||||
break;
|
||||
}
|
||||
return (
|
||||
<div className="chat chat-start">
|
||||
<div className="chat-bubble">
|
||||
{nick}: {content}
|
||||
<div className="p-1 text-xs">
|
||||
[{message.current}]{nick}{nick ? ': ' : ''}{content}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -1,16 +1,56 @@
|
||||
import { getToken } from "@/lib/actions/token";
|
||||
import Controls from "./controls";
|
||||
import { Danmu } from "./danmu";
|
||||
import Danmu from "./danmu";
|
||||
import { listLives } from "@/lib/actions/live";
|
||||
import { listSongs } from "../songs/actions";
|
||||
|
||||
export default async function Page() {
|
||||
const token = await getToken();
|
||||
const lives = await listLives();
|
||||
const songs = await listSongs();
|
||||
return (
|
||||
<div className="flex flex-col md:flex-row">
|
||||
<section className="basis-1/3 card">
|
||||
<div className="card-body max-h-[50vh] overflow-auto">直播间列表</div>
|
||||
<div className="h-[50vh] md:h-[80vh] overflow-auto card bg-base-100 card-bordered m-8">
|
||||
<div className="card-body">
|
||||
<div className="card-title">直播间列表</div>
|
||||
<ul>
|
||||
{lives.map((live, i) => (
|
||||
<li key={i}>
|
||||
<label>
|
||||
{live.name} - {live.room_id}
|
||||
<input
|
||||
className="raido radio-primary"
|
||||
type="radio"
|
||||
name="live"
|
||||
/>
|
||||
</label>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<section className="basis-1/3 card">
|
||||
<div className="card-body max-h-[50vh] overflow-auto">歌曲清单</div>
|
||||
<div className="h-[50vh] md:h-[80vh] overflow-auto card bg-base-100 card-bordered m-8">
|
||||
<div className="card-body">
|
||||
<div className="card-title">收藏的歌曲</div>
|
||||
<ul>
|
||||
{songs.map((song, i) => (
|
||||
<li key={i}>
|
||||
<label>
|
||||
{song.name} - {song.artist}
|
||||
<input
|
||||
className="raido radio-primary"
|
||||
type="radio"
|
||||
name="song"
|
||||
/>
|
||||
</label>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<section className="basis-1/3 card">
|
||||
<div className="card-body">
|
||||
|
26
lib/actions/live.ts
Normal file
26
lib/actions/live.ts
Normal file
@ -0,0 +1,26 @@
|
||||
"use server";
|
||||
|
||||
import { cookies } from "next/headers";
|
||||
|
||||
export async function listLives(): Promise<any[]> {
|
||||
const token = cookies().get("token");
|
||||
const params = new URLSearchParams();
|
||||
params.append("pageSize", "99999");
|
||||
const lives = await fetch(
|
||||
"https://tachy.daoyoucloud.com/api/lives:list?" + params.toString(),
|
||||
{
|
||||
method: "GET",
|
||||
headers: {
|
||||
"X-App": "danmu-sim",
|
||||
"X-Authenticator": "basic",
|
||||
authorization: "Bearer " + token?.value,
|
||||
"content-type": "application/json",
|
||||
},
|
||||
next: {
|
||||
tags: ["lives"],
|
||||
},
|
||||
}
|
||||
);
|
||||
const result = await lives.json();
|
||||
return result?.data ?? [];
|
||||
}
|
@ -10,6 +10,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"axios": "^1.6.8",
|
||||
"dayjs": "^1.11.10",
|
||||
"fuse.js": "^7.0.0",
|
||||
"next": "14.1.4",
|
||||
"react": "^18.2.0",
|
||||
|
@ -8,6 +8,9 @@ dependencies:
|
||||
axios:
|
||||
specifier: ^1.6.8
|
||||
version: 1.6.8
|
||||
dayjs:
|
||||
specifier: ^1.11.10
|
||||
version: 1.11.10
|
||||
fuse.js:
|
||||
specifier: ^7.0.0
|
||||
version: 7.0.0
|
||||
@ -826,6 +829,10 @@ packages:
|
||||
is-data-view: 1.0.1
|
||||
dev: true
|
||||
|
||||
/dayjs@1.11.10:
|
||||
resolution: {integrity: sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ==}
|
||||
dev: false
|
||||
|
||||
/debug@3.2.7:
|
||||
resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==}
|
||||
peerDependencies:
|
||||
|
Loading…
Reference in New Issue
Block a user