From bfcc4a5ce36968ce3a25b59fe2c2d6c30c440cb8 Mon Sep 17 00:00:00 2001 From: sealday Date: Sun, 7 Apr 2024 03:23:34 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=AE=8C=E5=96=84=E5=BC=B9=E5=B9=95AI?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/danmu/controls.tsx | 4 +-- app/danmu/danmu.tsx | 28 +++++++++++++++------ app/danmu/message.tsx | 55 ++++++++++++++++++++++++++++++++---------- app/danmu/page.tsx | 46 ++++++++++++++++++++++++++++++++--- lib/actions/live.ts | 26 ++++++++++++++++++++ package.json | 1 + pnpm-lock.yaml | 7 ++++++ 7 files changed, 142 insertions(+), 25 deletions(-) create mode 100644 lib/actions/live.ts diff --git a/app/danmu/controls.tsx b/app/danmu/controls.tsx index 08fd1a7..ed2d365 100644 --- a/app/danmu/controls.tsx +++ b/app/danmu/controls.tsx @@ -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 { >
当前延迟 {offset / 1000} 秒
-
+
    {history.map((item, i) => (
  • diff --git a/app/danmu/danmu.tsx b/app/danmu/danmu.tsx index 8eed021..c9905fd 100644 --- a/app/danmu/danmu.tsx +++ b/app/danmu/danmu.tsx @@ -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[]>([]); const ref = useRef(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 ( -
    +
    {messageHistory.map((message, idx) => ( ))}
    ); -}; +} diff --git a/app/danmu/message.tsx b/app/danmu/message.tsx index 6675970..ff736ed 100644 --- a/app/danmu/message.tsx +++ b/app/danmu/message.tsx @@ -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
    {message?.data?.em}
    +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
    {message?.data?.em}
    ; + } 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 ( -
    -
    - {nick}: {content} +
    + [{message.current}]{nick}{nick ? ': ' : ''}{content}
    -
    ); } diff --git a/app/danmu/page.tsx b/app/danmu/page.tsx index 04bf24c..4a1e42b 100644 --- a/app/danmu/page.tsx +++ b/app/danmu/page.tsx @@ -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 (
    -
    直播间列表
    +
    +
    +
    直播间列表
    +
      + {lives.map((live, i) => ( +
    • + +
    • + ))} +
    +
    +
    -
    歌曲清单
    +
    +
    +
    收藏的歌曲
    +
      + {songs.map((song, i) => ( +
    • + +
    • + ))} +
    +
    +
    diff --git a/lib/actions/live.ts b/lib/actions/live.ts new file mode 100644 index 0000000..706b61a --- /dev/null +++ b/lib/actions/live.ts @@ -0,0 +1,26 @@ +"use server"; + +import { cookies } from "next/headers"; + +export async function listLives(): Promise { + 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 ?? []; +} diff --git a/package.json b/package.json index aed6bc1..171d33a 100644 --- a/package.json +++ b/package.json @@ -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", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 42233df..8efe61c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -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: