feat: 通过 NeteaseMiniPlayer 支持播放来自网易云音乐的音乐

This commit is contained in:
2025-12-07 16:36:55 +08:00
parent 66d7c9cb3c
commit 2cdd81e74b
9 changed files with 1775 additions and 2 deletions

View File

@@ -15,6 +15,14 @@
- 构建Vite
- 部署Vercel静态构建 + Serverless Functions
## 致谢
排名不分先后
- [`Netease Mini Player`](https://github.com/numakkiyu/NeteaseMiniPlayer): 迷你网易云播放器组件,为本项目的音乐播放功能提供支持。
感谢以上开源项目原作者与维护者的贡献。
## 配置指南
### 站点配置文件 (`src/config/siteConfig.ts`)
@@ -61,6 +69,28 @@ const siteConfig: SiteConfig = {
startDate:"xxxx-xx-xx", // 网站创建日期
},
music: {
// 是否启用音乐播放器
enable: true,
// floating - 浮动模式播放器(推荐)- 用于播放网易云歌单
// embed - 嵌入模式播放器 - 用于播放网易云单曲
mode: "floating", // "floating" 或 "embed"
// 歌单ID从网易云音乐链接获取如 https://music.163.com/#/playlist?id=14273792576
playlistId: undefined, // 例如: "14273792576"
// 歌曲ID仅在嵌入模式下使用
songId: undefined, // 例如: "554242291"
// 播放器位置(浮动模式): "bottom-left" | "bottom-right" | "top-left" | "top-right"
position: "bottom-left",
// 是否显示歌词
lyric: true,
// 主题: "light" | "dark" | "auto"
theme: "dark",
// 是否自动播放
autoplay: false,
// 是否默认以黑胶唱片状态启动(仅浮动模式)
defaultMinimized: true,
},
umami: {
enable: true, // 是否启用 Umami 分析
url: "https://cloud.umami.is/script.js", // Umami 分析脚本 URL一般无需修改

View File

@@ -6,11 +6,15 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Cloud Home</title>
<link rel="icon" href="/favicon.ico" />
<!-- NeteaseMiniPlayer v2 CSS -->
<link rel="stylesheet" href="https://api.hypcvgm.top/NeteaseMiniPlayer/netease-mini-player-v2.css">
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
<!-- NeteaseMiniPlayer v2 JS -->
<script src="/js/netease-mini-player-v2.js"></script>
</body>
</html>

View File

@@ -10,6 +10,7 @@
"dependencies": {
"@jaseeey/vue-umami-plugin": "^1.4.0",
"@vercel/node": "^5.5.15",
"cros": "^1.1.0",
"express": "^5.2.1",
"he": "^1.2.0",
"nodemailer": "^7.0.11",

File diff suppressed because it is too large Load Diff

View File

@@ -21,6 +21,8 @@
<Transition name="fade-down">
<FooterSection v-if="!hideComponents" :contact="contact" key="footer" />
</Transition>
<!-- 音乐播放器 -->
<MusicPlayer />
</div>
</template>
@@ -28,6 +30,7 @@
import { onMounted, computed, ref } from "vue";
import PageSwitcher from "./components/PageSwitcher.vue";
import FooterSection from "./components/FooterSection.vue";
import MusicPlayer from "./components/MusicPlayer.vue";
import siteConfig from "./config/siteConfig";
const contact = siteConfig.footer;
@@ -53,7 +56,7 @@ const getBackgroundImage = () => {
if (!image) return undefined;
return image.startsWith("http") ? image : `/public/${image}`;
return image.startsWith("http") ? image : `/${image}`;
};
const backgroundStyle = computed(() => {

View File

@@ -0,0 +1,30 @@
<template>
<div
v-if="music.enable && (music.playlistId || music.songId)"
class="netease-mini-player"
:data-playlist-id="music.mode === 'floating' ? music.playlistId : undefined"
:data-song-id="music.mode === 'embed' ? music.songId : undefined"
:data-embed="music.mode === 'embed'"
:data-position="music.position"
:data-lyric="music.lyric"
:data-theme="music.theme"
:data-autoplay="music.autoplay"
:data-default-minimized="music.defaultMinimized"
></div>
</template>
<script setup lang="ts">
import siteConfig from "../config/siteConfig";
const music = siteConfig.music;
</script>
<!-- <style scoped>
/* 音乐播放器样式由 NeteaseMiniPlayer 提供 */
/* 使用 display: contents 使外层容器不占用空间 */
/* 确保播放器浮动定位,不影响页面布局 */
:deep(.netease-mini-player) {
position: fixed !important;
z-index: 999 !important;
}
</style> -->

View File

@@ -47,6 +47,26 @@ const siteConfig = {
},
},
music: {
enable: true,
// 浮动模式播放器(推荐)- 用于播放网易云歌单
mode: "floating", // "floating" 或 "embed"
// 歌单ID从网易云音乐链接获取如 https://music.163.com/#/playlist?id=14273792576
playlistId: "14366453940", // 例如: "14273792576"
// 歌曲ID仅在嵌入模式下使用
songId: undefined, // 例如: "554242291"
// 播放器位置(浮动模式): "bottom-left" | "bottom-right" | "top-left" | "top-right"
position: "bottom-left",
// 是否显示歌词
lyric: true,
// 主题: "light" | "dark" | "auto"
theme: "dark",
// 是否自动播放
autoplay: false,
// 是否默认以黑胶唱片状态启动(仅浮动模式)
defaultMinimized: true,
},
umami: {
enable: true,
url: "https://cloud.umami.is/script.js",

View File

@@ -12,4 +12,5 @@ if (process.env.NODE_ENV !== "development") {
app.use(VueUmamiPlugin({ websiteID: siteConfig.umami.websiteId, scriptSrc: siteConfig.umami.url, router }));
}
}
app.use(router).mount("#app");

View File

@@ -1,3 +1,7 @@
html {
height: 100%;
}
:root {
color-scheme: light dark;
font-family: "Inter", system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
@@ -7,7 +11,7 @@
body {
margin: 0;
min-height: 100vh;
min-height: 100%;
background: radial-gradient(circle at 20% 20%, #1b2b4b, #0f1629);
}
@@ -90,3 +94,98 @@ p {
text-align: center;
margin-top: 8px;
}
/* Ensure the Netease mini player doesn't occupy page layout space
and stays fixed above content. Use !important to override
styles injected by third-party scripts. */
.netease-mini-player {
position: fixed !important;
bottom: 20px !important;
left: 20px !important;
right: auto !important;
/* do not force width here — let the player's own minimized/expanded
styles control sizing. Only constrain max width as a safety net. */
max-width: calc(100% - 40px) !important;
z-index: 9999 !important;
margin: 0 !important;
transform: none !important;
}
/* If the player injects a full-width bar, make sure it won't
push page content by forcing it out of the normal flow. */
.netease-mini-player > * {
box-sizing: border-box;
}
/* Defensive: hide any accidental full-width injected container from the player
that might occupy vertical space. This targets common helper classes used
by the player script. */
.netease-mini-player-embed,
.nmpv2-player,
.nmpv2-root {
position: fixed !important;
bottom: 20px !important;
left: 20px !important;
right: auto !important;
z-index: 9999 !important;
}
/* Fix: prevent playlist dropdown from increasing document height
by forcing the playlist container to be fixed and clipped to viewport. */
.netease-mini-player[data-position="bottom-left"] .playlist-container,
.netease-mini-player[data-position="bottom-right"] .playlist-container {
position: fixed !important;
bottom: calc(20px + 80px) !important;
left: 20px !important;
right: auto !important;
width: 290px !important;
max-height: 50vh !important;
overflow: auto !important;
z-index: 10001 !important;
}
.netease-mini-player[data-position="top-left"] .playlist-container,
.netease-mini-player[data-position="top-right"] .playlist-container {
position: fixed !important;
top: calc(20px + 80px) !important;
left: 20px !important;
right: auto !important;
width: 290px !important;
max-height: 50vh !important;
overflow: auto !important;
z-index: 10001 !important;
}
/* If player is docked to the right, align playlist to right edge */
.netease-mini-player[data-position="bottom-right"] .playlist-container,
.netease-mini-player[data-position="top-right"] .playlist-container {
left: auto !important;
right: 20px !important;
}
/* Ensure minimized player displays as a circle and its album cover fits */
.netease-mini-player.minimized {
width: 80px !important;
height: 80px !important;
border-radius: 50% !important;
padding: 0 !important;
overflow: hidden !important;
box-shadow: none !important;
}
.netease-mini-player.minimized .album-cover-container {
width: 100% !important;
height: 100% !important;
position: absolute !important;
top: 0 !important;
left: 0 !important;
border-radius: 50% !important;
overflow: hidden !important;
}
.netease-mini-player.minimized .album-cover {
width: 100% !important;
height: 100% !important;
object-fit: cover !important;
border-radius: 50% !important;
}