1.readme.md
@@ -1 +1,174 @@ | |||
1 | - | # 说明 | |
1 | + | ## 🎵 音乐胶囊模块使用说明 | |
2 | + | ||
3 | + | 本仓库提供了一个可集成到 Hexo 主题 **liushen** 的音乐胶囊播放器模块。模块包含四个主要部分: | |
4 | + | ||
5 | + | * **主题配置文件** | |
6 | + | * **布局模板文件** | |
7 | + | * **样式文件** | |
8 | + | * **前端脚本** | |
9 | + | ||
10 | + | 本文档将详细介绍它们的放置位置、引用方式和变量配置。 | |
11 | + | ||
12 | + | --- | |
13 | + | ||
14 | + | ### 1️⃣ 配置文件(根目录) | |
15 | + | ||
16 | + | **文件:** `_config.liushen.yml` | |
17 | + | **位置:** 项目根目录(`blog/_config.liushen.yml`),**不是主题根目录**。 | |
18 | + | ||
19 | + | 该文件用于存放音乐模块的相关配置(如是否启用、播放列表、API 接口等)。 | |
20 | + | 示例(按需调整): | |
21 | + | ||
22 | + | ```yaml | |
23 | + | # 页脚音乐胶囊 | |
24 | + | capsule: | |
25 | + | enable: true | |
26 | + | # 歌单 ID / 单曲 ID | |
27 | + | id: 13597135963 | |
28 | + | # 服务商:netease / qq / xiami / kugou / baidu | |
29 | + | server: netease | |
30 | + | # 类型:playlist / song | |
31 | + | type: playlist | |
32 | + | meting_api: https://met.example.com/api?server=:server&type=:type&id=:id&r=:r | |
33 | + | volume: 0.8 | |
34 | + | ``` | |
35 | + | ||
36 | + | --- | |
37 | + | ||
38 | + | ### 2️⃣ 布局模板文件 | |
39 | + | ||
40 | + | **文件:** `music.pug` | |
41 | + | **位置:** `blog/themes/liushen/layout/includes/third-party/music.pug` | |
42 | + | ||
43 | + | 该文件用于渲染音乐胶囊播放器 UI,需要在 `layout.pug` 中手动引入。 | |
44 | + | ||
45 | + | 在 `blog/themes/liushen/layout/includes/layout.pug` **底部** 添加以下代码(保留现有内容,仅在末尾追加): | |
46 | + | ||
47 | + | ```pug | |
48 | + | if theme.capsule && theme.capsule.enable | |
49 | + | include ./third-party/music.pug | |
50 | + | ``` | |
51 | + | ||
52 | + | > 📌 该判断会根据 `_config.liushen.yml` 中的 `capsule.enable` 来决定是否加载播放器。 | |
53 | + | ||
54 | + | --- | |
55 | + | ||
56 | + | ### 3️⃣ 样式文件 | |
57 | + | ||
58 | + | **文件:** `music-capsule.styl` | |
59 | + | **位置:** `blog/themes/liushen/source/css/__layout/music-capsule.styl` | |
60 | + | ||
61 | + | 该位置的`styl`样式表会被自动整合到`main.css` | |
62 | + | ||
63 | + | #### 💡 样式变量对照表 | |
64 | + | ||
65 | + | 音乐胶囊使用了一些 CSS 变量,这些变量在亮色与暗色模式下分别定义。 | |
66 | + | ||
67 | + | ##### 🌞 亮色模式(默认) | |
68 | + | ||
69 | + | ```css | |
70 | + | /* nav */ | |
71 | + | --liushen-nav-bg: rgba(255, 255, 255, 0.8); | |
72 | + | --liushen-nav-shadow: rgba(133, 133, 133, 0.6) 0px 5px 6px -5px; | |
73 | + | ||
74 | + | /* ai_summary */ | |
75 | + | --liushen-title-font-color: #0883b7; | |
76 | + | --liushen-maskbg: rgba(255, 255, 255, 0.85); | |
77 | + | --liushen-ai-bg: conic-gradient(from 1.5708rad at 50% 50%, #d6b300 0%, #42A2FF 54%, #d6b300 100%); | |
78 | + | ||
79 | + | /* card */ | |
80 | + | --liushen-card-bg: #fff; | |
81 | + | --liushen-card-secondbg: #f1f3f8; | |
82 | + | --liushen-card-border: 1px solid #e3e8f7; | |
83 | + | ||
84 | + | /* button */ | |
85 | + | --liushen-button-bg: #f1f3f8; | |
86 | + | --liushen-button-hover-bg: $theme-color; | |
87 | + | ||
88 | + | /* text */ | |
89 | + | --liushen-text: #4c4948; | |
90 | + | --liushen-secondtext: #3c3c43cc; | |
91 | + | ||
92 | + | /* snackbar */ | |
93 | + | --snackbar-bg: rgba(255, 255, 255, 0.809); | |
94 | + | --snackbar-text: #4c4948; | |
95 | + | --snackbar-border: 1px solid rgba(126, 126, 126, 0.527); | |
96 | + | ||
97 | + | /* menu child */ | |
98 | + | --menu-child-bg: rgba(255,255,255,0.8); | |
99 | + | ||
100 | + | /* fancybox */ | |
101 | + | --liushen-fancybox-bg: rgba(255,255,255,0.5); | |
102 | + | --liushen-fancybox-button-color: #000000; | |
103 | + | ``` | |
104 | + | ||
105 | + | ##### 🌙 暗色模式 | |
106 | + | ||
107 | + | ```css | |
108 | + | [data-theme='dark'] { | |
109 | + | /* nav */ | |
110 | + | --liushen-nav-bg: rgba(18,18,18,.8); | |
111 | + | --liushen-nav-shadow: rgba(133, 133, 133, 0) 0px 5px 6px -5px; | |
112 | + | ||
113 | + | /* ai_summary */ | |
114 | + | --liushen-maskbg: rgba(0, 0, 0, 0.85); | |
115 | + | --liushen-ai-bg: conic-gradient(from 1.5708rad at 50% 50%,rgba(214, 178, 0, 0.46) 0%,rgba(66, 161, 255, 0.53) 54%,rgba(214, 178, 0, 0.49) 100%); | |
116 | + | ||
117 | + | /* card */ | |
118 | + | --liushen-card-bg: #2d2d2d; | |
119 | + | --liushen-card-secondbg: #3e3f41; | |
120 | + | --liushen-card-border: 1px solid #42444a; | |
121 | + | ||
122 | + | /* button */ | |
123 | + | --liushen-button-bg: #30343f; | |
124 | + | --liushen-button-hover-bg: $theme-color; | |
125 | + | ||
126 | + | /* text */ | |
127 | + | --liushen-text: #ffffffb3; | |
128 | + | --liushen-secondtext: #a1a2b8; | |
129 | + | ||
130 | + | /* snackbar */ | |
131 | + | --snackbar-bg: rgba(48, 48, 48, 0.809); | |
132 | + | --snackbar-text: #dfdfdf; | |
133 | + | --snackbar-border: 1px solid #cfd4dc40; | |
134 | + | ||
135 | + | /* menu child */ | |
136 | + | --menu-child-bg: rgba(18,18,18,0.8); | |
137 | + | ||
138 | + | /* fancybox */ | |
139 | + | --liushen-fancybox-bg: rgba(0,0,0,0.5); | |
140 | + | --liushen-fancybox-button-color: #ffffff; | |
141 | + | } | |
142 | + | ``` | |
143 | + | ||
144 | + | > 你可以将这些变量整合到主题的全局变量文件中,或根据配色需求自行调整。 | |
145 | + | ||
146 | + | --- | |
147 | + | ||
148 | + | ### 4️⃣ 前端脚本 | |
149 | + | ||
150 | + | **文件:** `music.js` | |
151 | + | **位置:** 可放在主题的任意 JS 文件中(例如 `blog/themes/liushen/source/js/music.js`)或合并到 `main.js` 中。 | |
152 | + | ||
153 | + | ### 引入方式一(单独文件) | |
154 | + | ||
155 | + | 在主题 `layout.pug` 的底部或 `additional-js.pug` 中添加: | |
156 | + | ||
157 | + | ```pug | |
158 | + | script(src='/js/music.js') | |
159 | + | ``` | |
160 | + | ||
161 | + | #### 引入方式二(合并代码) | |
162 | + | ||
163 | + | 将 `music.js` 中的代码直接复制到 `main.js` 或其他已加载的脚本文件中。 | |
164 | + | ||
165 | + | --- | |
166 | + | ||
167 | + | ### 🔗 集成流程总结 | |
168 | + | ||
169 | + | 1. 将 `_config.liushen.yml` 添加到 **项目根目录** 并配置 `capsule.enable: true`。 | |
170 | + | 2. 将 `music.pug` 放入 `blog/themes/liushen/layout/includes/third-party/`。 | |
171 | + | 3. 编辑 `layout.pug`,在底部添加 `include ./third-party/music.pug`(带条件判断)。 | |
172 | + | 4. 将 `music-capsule.styl` 放入 `blog/themes/liushen/source/css/__layout/`。 | |
173 | + | 5. 将 `music.js` 放入 JS 目录并在页面加载时引入,或者可以添加到任意js文件中。 | |
174 | + | 6. 根据需要修改 CSS 变量配色。 |
1.readme.md(文件已创建)
@@ -0,0 +1 @@ | |||
1 | + | # 说明 |
music-capsule.styl(文件已创建)
@@ -0,0 +1,230 @@ | |||
1 | + | @keyframes changeright | |
2 | + | 0%, 50%, 100% | |
3 | + | transform: rotate(0deg) scale(1.1) | |
4 | + | box-shadow: 0 0 2px #ffffff00 | |
5 | + | 25%, 75% | |
6 | + | transform: rotate(90deg) scale(1.1) | |
7 | + | box-shadow: 0 0 14px #ffffff | |
8 | + | ||
9 | + | @keyframes playingShadow | |
10 | + | 0%, 100% | |
11 | + | box-shadow: 0 0px 12px -3px #00000000 | |
12 | + | 50% | |
13 | + | box-shadow: 0 0px 12px 0px var(--default-bg-color) | |
14 | + | ||
15 | + | @keyframes lightBar | |
16 | + | 0%, 100% | |
17 | + | opacity: 0.1 | |
18 | + | 60% | |
19 | + | opacity: 0.3 | |
20 | + | ||
21 | + | .aplayer.aplayer-narrow | |
22 | + | .aplayer-body, | |
23 | + | .aplayer-pic | |
24 | + | height: 66px | |
25 | + | width: 66px | |
26 | + | ||
27 | + | #nav-music | |
28 | + | display: flex | |
29 | + | align-items: center | |
30 | + | position: fixed | |
31 | + | z-index: 10000 | |
32 | + | bottom: 10px | |
33 | + | left: 10px | |
34 | + | cursor: pointer | |
35 | + | transition: all 0.5s, left 0s | |
36 | + | transform-origin: left bottom | |
37 | + | box-shadow: var(--liushen-nav-shadow) | |
38 | + | border-radius: 40px | |
39 | + | overflow: hidden | |
40 | + | ||
41 | + | &:active | |
42 | + | transform: scale(0.97) | |
43 | + | ||
44 | + | &.playing | |
45 | + | border: var(--liushen-card-border) | |
46 | + | box-shadow: 0 0px 12px -3px #00000000 | |
47 | + | animation: playingShadow 5s linear infinite | |
48 | + | ||
49 | + | .aplayer.aplayer-withlrc | |
50 | + | .aplayer-pic | |
51 | + | box-shadow: 0 0 14px #ffffffa6 | |
52 | + | transform: rotate(0deg) scale(1.1) | |
53 | + | border-color: white | |
54 | + | animation-play-state: running | |
55 | + | ||
56 | + | .aplayer-info | |
57 | + | color: white | |
58 | + | ||
59 | + | #nav-music-hoverTips | |
60 | + | width: 0 | |
61 | + | ||
62 | + | .aplayer | |
63 | + | background: var(--default-bg-color) | |
64 | + | border: var(--liushen-card-border) | |
65 | + | backdrop-filter: saturate(180%) blur(20px) | |
66 | + | transform: translateZ(0) | |
67 | + | ||
68 | + | .aplayer .aplayer-info .aplayer-controller .aplayer-bar-wrap .aplayer-bar .aplayer-played | |
69 | + | animation-play-state: running | |
70 | + | ||
71 | + | &:hover:not(.playing) #nav-music-hoverTips | |
72 | + | opacity: 1 | |
73 | + | ||
74 | + | .aplayer.aplayer-withlrc | |
75 | + | .aplayer-pic | |
76 | + | height: 25px | |
77 | + | width: 25px | |
78 | + | border-radius: 40px | |
79 | + | z-index: 1 | |
80 | + | transition: 0.3s | |
81 | + | transform: rotate(0deg) scale(1) | |
82 | + | border: var(--liushen-card-border) | |
83 | + | animation: changeright 24s linear infinite | |
84 | + | animation-play-state: paused | |
85 | + | ||
86 | + | .aplayer-info | |
87 | + | height: 100% | |
88 | + | color: var(--liushen-text) | |
89 | + | margin: 0 | |
90 | + | padding: 0 | |
91 | + | display: flex | |
92 | + | align-items: center | |
93 | + | ||
94 | + | #nav-music-hoverTips | |
95 | + | color: white | |
96 | + | background: var(--default-bg-color) | |
97 | + | width: 100% | |
98 | + | height: 100% | |
99 | + | position: absolute | |
100 | + | top: 0 | |
101 | + | left: 0 | |
102 | + | align-items: center | |
103 | + | justify-content: center | |
104 | + | display: flex | |
105 | + | border-radius: 40px | |
106 | + | opacity: 0 | |
107 | + | font-size: 12px | |
108 | + | z-index: 2 | |
109 | + | transition: 0.3s | |
110 | + | ||
111 | + | .aplayer | |
112 | + | background: var(--liushen-card-bg) | |
113 | + | border-radius: 60px | |
114 | + | height: 41px | |
115 | + | display: flex | |
116 | + | margin: 0 | |
117 | + | transition: 0.3s | |
118 | + | border: var(--liushen-card-border) | |
119 | + | box-shadow: none | |
120 | + | ||
121 | + | .aplayer-notice, | |
122 | + | .aplayer-miniswitcher, | |
123 | + | .aplayer-list | |
124 | + | display: none | |
125 | + | ||
126 | + | .aplayer-body | |
127 | + | position: relative | |
128 | + | display: flex | |
129 | + | align-items: center | |
130 | + | min-width: 180px | |
131 | + | ||
132 | + | .aplayer-info | |
133 | + | .aplayer-music | |
134 | + | margin: 0 | |
135 | + | display: flex | |
136 | + | align-items: center | |
137 | + | padding: 0 12px 0 8px | |
138 | + | cursor: pointer | |
139 | + | z-index: 1 | |
140 | + | height: 100% | |
141 | + | ||
142 | + | .aplayer-title | |
143 | + | cursor: pointer | |
144 | + | line-height: 1 | |
145 | + | display: inline-block | |
146 | + | white-space: nowrap | |
147 | + | max-width: 120px | |
148 | + | overflow: hidden | |
149 | + | text-overflow: ellipsis | |
150 | + | transition: 0.3s | |
151 | + | user-select: none | |
152 | + | ||
153 | + | .aplayer-controller | |
154 | + | position: absolute | |
155 | + | width: 100% | |
156 | + | height: 100% | |
157 | + | top: 0 | |
158 | + | left: 0 | |
159 | + | ||
160 | + | .aplayer-bar-wrap | |
161 | + | margin: 0 | |
162 | + | padding: 0 | |
163 | + | ||
164 | + | .aplayer-bar | |
165 | + | height: 100% | |
166 | + | background: 0 0 | |
167 | + | ||
168 | + | .aplayer-loaded | |
169 | + | display: none | |
170 | + | ||
171 | + | .aplayer-played | |
172 | + | height: 100% | |
173 | + | opacity: 0.1 | |
174 | + | background-color: white !important | |
175 | + | animation: lightBar 5s ease infinite | |
176 | + | animation-play-state: paused | |
177 | + | ||
178 | + | .aplayer-pic | |
179 | + | pointer-events: none | |
180 | + | ||
181 | + | .aplayer-button | |
182 | + | bottom: 50% | |
183 | + | right: 50% | |
184 | + | transform: translate(50%, 50%) | |
185 | + | margin: 0 | |
186 | + | transition: 0.3s | |
187 | + | pointer-events all | |
188 | + | ||
189 | + | &:has(.aplayer-button.aplayer-play) | |
190 | + | animation-play-state: paused | |
191 | + | transform: rotate(0deg) scale(1) !important | |
192 | + | ||
193 | + | margin-left: 8px | |
194 | + | ||
195 | + | .aplayer-info .aplayer-controller .aplayer-time, | |
196 | + | .aplayer-info .aplayer-music .aplayer-author | |
197 | + | display: none | |
198 | + | ||
199 | + | &.aplayer-withlist .aplayer-info | |
200 | + | border: none | |
201 | + | ||
202 | + | .aplayer-lrc | |
203 | + | width: 0 | |
204 | + | opacity: 0 | |
205 | + | transition: 0.3s | |
206 | + | margin-bottom: -26px | |
207 | + | ||
208 | + | p.aplayer-lrc-current | |
209 | + | color: white | |
210 | + | border: none | |
211 | + | min-height: 20px | |
212 | + | filter: none | |
213 | + | ||
214 | + | &:after, | |
215 | + | &:before | |
216 | + | display: none | |
217 | + | ||
218 | + | p | |
219 | + | color: #ffffffb3 | |
220 | + | filter: blur(.8px) | |
221 | + | ||
222 | + | @media screen and (min-width: 600px) | |
223 | + | #nav-music.stretch .aplayer.aplayer-withlrc .aplayer-lrc | |
224 | + | width: 200px | |
225 | + | margin-left: 8px | |
226 | + | opacity: 1 | |
227 | + | ||
228 | + | .aplayer-thumb | |
229 | + | width: 0 !important | |
230 | + | height: 0 !important |
music.js(文件已创建)
@@ -0,0 +1,39 @@ | |||
1 | + | const liuMusic = { | |
2 | + | musicPlaying: false, | |
3 | + | isMusicBind: false, | |
4 | + | ||
5 | + | musicToggle(isMeting = true) { | |
6 | + | if (!this.isMusicBind) { | |
7 | + | this.musicBind(); | |
8 | + | } | |
9 | + | ||
10 | + | const $music = document.querySelector("#nav-music"); | |
11 | + | const $meting = document.querySelector("meting-js"); | |
12 | + | const $console = document.getElementById("consoleMusic"); | |
13 | + | ||
14 | + | this.musicPlaying = !this.musicPlaying; | |
15 | + | $music?.classList.toggle("playing", this.musicPlaying); | |
16 | + | $music?.classList.toggle("stretch", this.musicPlaying); | |
17 | + | $console?.classList.toggle("on", this.musicPlaying); | |
18 | + | ||
19 | + | if (isMeting) { | |
20 | + | this.musicPlaying ? $meting?.aplayer?.play() : $meting?.aplayer?.pause(); | |
21 | + | } | |
22 | + | }, | |
23 | + | ||
24 | + | musicBind() { | |
25 | + | const $music = document.querySelector("#nav-music"); | |
26 | + | const $name = document.querySelector("#nav-music .aplayer-music"); | |
27 | + | const $button = document.querySelector("#nav-music .aplayer-button"); | |
28 | + | ||
29 | + | $name?.addEventListener("click", () => { | |
30 | + | $music?.classList.toggle("stretch"); | |
31 | + | }); | |
32 | + | ||
33 | + | $button?.addEventListener("click", () => { | |
34 | + | this.musicToggle(false); | |
35 | + | }); | |
36 | + | ||
37 | + | this.isMusicBind = true; | |
38 | + | } | |
39 | + | }; |
music.pug(文件已创建)
@@ -0,0 +1,3 @@ | |||
1 | + | div.needEndHide#nav-music | |
2 | + | #nav-music-hoverTips(onclick='liuMusic.musicToggle()')= __('music.hit') | |
3 | + | meting-js(id=theme.capsule.id server=theme.capsule.server type=theme.capsule.type mutex="true" preload="none" data-lrctype="0" order="random" volume=theme.capsule.volume api=theme.capsule.meting_api) |
_comfig.liushen.yml(文件已创建)
@@ -0,0 +1,11 @@ | |||
1 | + | # 页脚音乐胶囊 | |
2 | + | capsule: | |
3 | + | enable: true | |
4 | + | # 歌单 ID / 单曲 ID | |
5 | + | id: 13597135963 | |
6 | + | # 服务商:netease / qq / xiami / kugou / baidu | |
7 | + | server: netease | |
8 | + | # 类型:playlist / song | |
9 | + | type: playlist | |
10 | + | meting_api: https://met.example.com/api?server=:server&type=:type&id=:id&r=:r | |
11 | + | volume: 0.8 |