forked from miao-moe/QZMusic_PC
fork(fix): Clone AMLL 并修复 BUG
- 将AMLL Clone到本以地进行修复和优化(emm虽然这很不优雅但是暂时无时间做子模块和Fork) - 修复在当前播放歌词行不可见的视口Seek会出现滚动偏移的问题
This commit is contained in:
24
amll-local/packages/playground/react/index.html
Normal file
24
amll-local/packages/playground/react/index.html
Normal file
@@ -0,0 +1,24 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>AMLL React Wrapper Test</title>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<script src="src/test.tsx" type="module" defer></script>
|
||||
<style>
|
||||
:root {
|
||||
font-family:
|
||||
-apple-system, BlinkMacSystemFont, "SF Pro Display", "PingFang SC", system-ui, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif;
|
||||
}
|
||||
|
||||
body {
|
||||
background: #222;
|
||||
margin: 0;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body style="height: 100vh; overflow: hidden;">
|
||||
<div id="root" style="height: 100vh; overflow: hidden;"></div>
|
||||
</body>
|
||||
</html>
|
||||
31
amll-local/packages/playground/react/package.json
Normal file
31
amll-local/packages/playground/react/package.json
Normal file
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"name": "@applemusic-like-lyrics/playground-react",
|
||||
"private": true,
|
||||
"version": "0.0.0",
|
||||
"type": "module",
|
||||
"nx": {
|
||||
"tags": [
|
||||
"playground"
|
||||
]
|
||||
},
|
||||
"scripts": {
|
||||
"dev": "vite dev"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@applemusic-like-lyrics/core": "workspace:^",
|
||||
"@applemusic-like-lyrics/lyric": "workspace:^",
|
||||
"@applemusic-like-lyrics/react": "workspace:^",
|
||||
"@types/react": "catalog:",
|
||||
"@types/react-dom": "catalog:",
|
||||
"@vitejs/plugin-react": "catalog:",
|
||||
"react": "catalog:",
|
||||
"react-dom": "catalog:",
|
||||
"vite": "catalog:",
|
||||
"@pixi/app": "^7.4.3",
|
||||
"@pixi/core": "^7.4.3",
|
||||
"@pixi/display": "^7.4.3",
|
||||
"@pixi/filter-blur": "^7.4.3",
|
||||
"@pixi/filter-color-matrix": "^7.4.3",
|
||||
"@pixi/sprite": "^7.4.3"
|
||||
}
|
||||
}
|
||||
165
amll-local/packages/playground/react/src/test-app.tsx
Normal file
165
amll-local/packages/playground/react/src/test-app.tsx
Normal file
@@ -0,0 +1,165 @@
|
||||
import type { LyricLine } from "@applemusic-like-lyrics/core";
|
||||
import {
|
||||
parseTTML,
|
||||
type LyricLine as RawLyricLine,
|
||||
} from "@applemusic-like-lyrics/lyric";
|
||||
import {
|
||||
BackgroundRender,
|
||||
LyricPlayer,
|
||||
type LyricPlayerRef,
|
||||
} from "@applemusic-like-lyrics/react";
|
||||
import type { FC } from "react";
|
||||
import { useCallback, useEffect, useRef, useState } from "react";
|
||||
|
||||
const mapTTMLLyric = (line: RawLyricLine): LyricLine => ({
|
||||
...line,
|
||||
words: line.words.map((word) => ({ obscene: false, ...word })),
|
||||
});
|
||||
|
||||
export const App: FC = () => {
|
||||
const audioRef = useRef<HTMLAudioElement>(null);
|
||||
const [audioUrl, setAudioUrl] = useState("");
|
||||
const [albumUrl, setAlbumUrl] = useState("");
|
||||
const [albumIsVideo, setAlbumIsVideo] = useState(false);
|
||||
const lyricPlayerRef = useRef<LyricPlayerRef>(null);
|
||||
const [lyricLines, setLyricLines] = useState<LyricLine[]>([]);
|
||||
const onClickOpenAudio = useCallback(() => {
|
||||
const input = document.createElement("input");
|
||||
input.type = "file";
|
||||
input.accept = "audio/*";
|
||||
input.onchange = () => {
|
||||
const file = input.files?.[0];
|
||||
if (file) {
|
||||
setAudioUrl((old) => {
|
||||
if (old.trim().length > 0) {
|
||||
URL.revokeObjectURL(old);
|
||||
}
|
||||
return URL.createObjectURL(file);
|
||||
});
|
||||
}
|
||||
};
|
||||
input.click();
|
||||
}, []);
|
||||
const onClickOpenAlbumImage = useCallback(() => {
|
||||
const input = document.createElement("input");
|
||||
input.type = "file";
|
||||
input.accept = "image/*,video/*";
|
||||
input.onchange = () => {
|
||||
const file = input.files?.[0];
|
||||
if (file) {
|
||||
setAlbumIsVideo(file.type.startsWith("video/"));
|
||||
setAlbumUrl((old) => {
|
||||
if (old.trim().length > 0) {
|
||||
URL.revokeObjectURL(old);
|
||||
}
|
||||
return URL.createObjectURL(file);
|
||||
});
|
||||
}
|
||||
};
|
||||
input.click();
|
||||
}, []);
|
||||
const onClickOpenTTMLLyric = useCallback(() => {
|
||||
const input = document.createElement("input");
|
||||
input.type = "file";
|
||||
input.accept = ".ttml,text/*";
|
||||
input.onchange = async () => {
|
||||
const file = input.files?.[0];
|
||||
if (file) {
|
||||
const text = await file.text();
|
||||
setLyricLines(parseTTML(text).lines.map(mapTTMLLyric));
|
||||
}
|
||||
};
|
||||
input.click();
|
||||
}, []);
|
||||
useEffect(() => {
|
||||
if (audioRef.current) {
|
||||
let lastTime = -1;
|
||||
const onFrame = (time: number) => {
|
||||
if (audioRef.current && !audioRef.current.paused) {
|
||||
if (lastTime === -1) {
|
||||
lastTime = time;
|
||||
}
|
||||
lyricPlayerRef.current?.lyricPlayer?.update(time - lastTime);
|
||||
lastTime = time;
|
||||
lyricPlayerRef.current?.lyricPlayer?.setCurrentTime(
|
||||
(audioRef.current.currentTime * 1000) | 0,
|
||||
);
|
||||
requestAnimationFrame(onFrame);
|
||||
}
|
||||
};
|
||||
const onPlay = () => onFrame(0);
|
||||
audioRef.current.addEventListener("play", onPlay);
|
||||
return () => {
|
||||
audioRef.current?.removeEventListener("play", onPlay);
|
||||
};
|
||||
}
|
||||
return;
|
||||
}, []);
|
||||
useEffect(() => {
|
||||
if (lyricPlayerRef.current) {
|
||||
// biome-ignore lint/suspicious/noExplicitAny: 调试用途,暴露到 Window
|
||||
(window as any).lyricPlayer = lyricPlayerRef.current;
|
||||
}
|
||||
}, []);
|
||||
return (
|
||||
<>
|
||||
<BackgroundRender
|
||||
style={{
|
||||
position: "absolute",
|
||||
top: "0",
|
||||
left: "0",
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
}}
|
||||
album={albumUrl}
|
||||
albumIsVideo={albumIsVideo}
|
||||
/>
|
||||
<LyricPlayer
|
||||
style={{
|
||||
position: "absolute",
|
||||
top: "0",
|
||||
left: "0",
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
maxWidth: "100%",
|
||||
maxHeight: "100%",
|
||||
contain: "paint layout",
|
||||
overflow: "hidden",
|
||||
mixBlendMode: "plus-lighter",
|
||||
}}
|
||||
ref={lyricPlayerRef}
|
||||
alignAnchor="center"
|
||||
lyricLines={lyricLines}
|
||||
/>
|
||||
<div
|
||||
style={{
|
||||
position: "absolute",
|
||||
right: "0",
|
||||
bottom: "0",
|
||||
backgroundColor: "#0004",
|
||||
margin: "1rem",
|
||||
padding: "1rem",
|
||||
borderRadius: "0.5rem",
|
||||
color: "white",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
gap: "0.5rem",
|
||||
}}
|
||||
>
|
||||
<div>AMLL React 绑定调试页面</div>
|
||||
<div>为了减少依赖,没有过多的调试设置。</div>
|
||||
<div>更加详尽的调试可以直接使用 Core 模块调试。</div>
|
||||
<button type="button" onClick={onClickOpenAudio}>
|
||||
加载音乐
|
||||
</button>
|
||||
<button type="button" onClick={onClickOpenAlbumImage}>
|
||||
加载专辑背景资源(图片/视频)
|
||||
</button>
|
||||
<button type="button" onClick={onClickOpenTTMLLyric}>
|
||||
加载歌词
|
||||
</button>
|
||||
<audio controls ref={audioRef} src={audioUrl} preload="auto" />
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
9
amll-local/packages/playground/react/src/test.tsx
Normal file
9
amll-local/packages/playground/react/src/test.tsx
Normal file
@@ -0,0 +1,9 @@
|
||||
import { StrictMode } from "react";
|
||||
import { createRoot } from "react-dom/client";
|
||||
import { App } from "./test-app";
|
||||
|
||||
createRoot(document.getElementById("root") as HTMLElement).render(
|
||||
<StrictMode>
|
||||
<App />
|
||||
</StrictMode>,
|
||||
);
|
||||
4
amll-local/packages/playground/react/tsconfig.json
Normal file
4
amll-local/packages/playground/react/tsconfig.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"extends": "../../../tsconfig.base.json",
|
||||
"include": ["src"]
|
||||
}
|
||||
24
amll-local/packages/playground/react/vite.config.ts
Normal file
24
amll-local/packages/playground/react/vite.config.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import path from "node:path";
|
||||
import react from "@vitejs/plugin-react";
|
||||
import { defineConfig } from "vite";
|
||||
|
||||
export default defineConfig({
|
||||
resolve: {
|
||||
alias: {
|
||||
"@applemusic-like-lyrics/core/style.css": path.resolve(
|
||||
__dirname,
|
||||
"../../core/src/styles/index.css",
|
||||
),
|
||||
"@applemusic-like-lyrics/react": path.resolve(
|
||||
__dirname,
|
||||
"../../react/src",
|
||||
),
|
||||
"@applemusic-like-lyrics/core": path.resolve(__dirname, "../../core/src"),
|
||||
"@applemusic-like-lyrics/lyric": path.resolve(
|
||||
__dirname,
|
||||
"../../lyric/src",
|
||||
),
|
||||
},
|
||||
},
|
||||
plugins: [react()],
|
||||
});
|
||||
Reference in New Issue
Block a user