Skip to content

Commit afc7f69

Browse files
Dev cy (#782)
* ✨ feat: 史诗级加强No-cover * ✨ feat: 自定义歌单界面 * ✨ feat: 优化设置排布 * ✨ feat: 支持关闭开发者模式 * ✨ feat: 歌词设置整理 支持替换括号内容 * ✨ feat: 歌词括号 * 🐞 fix: 代码审查 * ✨ feat: 史诗级加强No-cover x2 * 🐞 fix: 对齐数据 * 🐞 fix: 修复在某些情况下(如歌手信息为纯字符串而非数组时)可能导致元数据写入失败的问题 * 🐞 fix: 代码审查 * ✨ feat: 支持删除歌手信息的括号 * ✨ feat: 加载骨架修改 * Revert "✨ feat: 加载骨架修改" This reverts commit 20b4790. * ✨ feat: 遮罩动画 * ✨ feat: 一键开启关闭 * 🐞 fix: 确认类型 * 🐞 fix: 代码审查 * ✨ feat: 本地读取响度 #411
1 parent a00c0b4 commit afc7f69

56 files changed

Lines changed: 2063 additions & 1047 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

components.d.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ declare module 'vue' {
2929
copy: typeof import('./src/components/Global/Provider copy.vue')['default']
3030
CopyLyrics: typeof import('./src/components/Modal/CopyLyrics.vue')['default']
3131
CoverList: typeof import('./src/components/List/CoverList.vue')['default']
32+
CoverManager: typeof import('./src/components/Modal/Setting/CoverManager.vue')['default']
3233
CoverMenu: typeof import('./src/components/Menu/CoverMenu.vue')['default']
3334
CreatePlaylist: typeof import('./src/components/Modal/CreatePlaylist.vue')['default']
3435
CustomCode: typeof import('./src/components/Modal/Setting/CustomCode.vue')['default']
@@ -161,6 +162,7 @@ declare module 'vue' {
161162
PlayerSlider: typeof import('./src/components/Player/PlayerComponents/PlayerSlider.vue')['default']
162163
PlayerSpectrum: typeof import('./src/components/Player/PlayerComponents/PlayerSpectrum.vue')['default']
163164
PlaylistAdd: typeof import('./src/components/Modal/PlaylistAdd.vue')['default']
165+
PlaylistPageManager: typeof import('./src/components/Modal/Setting/PlaylistPageManager.vue')['default']
164166
PlaySetting: typeof import('./src/components/Setting/old/PlaySetting.vue')['default']
165167
Provider: typeof import('./src/components/Global/Provider.vue')['default']
166168
ProxyConfig: typeof import('./src/components/Setting/components/ProxyConfig.vue')['default']

electron/main/ipc/ipc-file.ts

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,12 @@ const initFileIpc = (): void => {
156156
size: (size / (1024 * 1024)).toFixed(2),
157157
path: fullPath,
158158
quality: format.bitrate ?? 0,
159+
replayGain: {
160+
trackGain: common.replaygain_track_gain?.ratio,
161+
trackPeak: common.replaygain_track_peak?.ratio,
162+
albumGain: common.replaygain_album_gain?.ratio,
163+
albumPeak: common.replaygain_album_peak?.ratio,
164+
},
159165
};
160166
} catch (err) {
161167
ipcLog.warn(`⚠️ Failed to parse file: ${fullPath}`, err);
@@ -193,6 +199,12 @@ const initFileIpc = (): void => {
193199
format,
194200
// md5
195201
md5: await getFileMD5(filePath),
202+
replayGain: {
203+
trackGain: common.replaygain_track_gain?.ratio,
204+
trackPeak: common.replaygain_track_peak?.ratio,
205+
albumGain: common.replaygain_album_gain?.ratio,
206+
albumPeak: common.replaygain_album_peak?.ratio,
207+
},
196208
};
197209
} catch (error) {
198210
ipcLog.error("❌ Error fetching music metadata:", error);
@@ -636,9 +648,26 @@ const initFileIpc = (): void => {
636648
Id3v2Settings.defaultVersion = 3;
637649

638650
songFile.tag.title = songData?.name || "未知曲目";
639-
songFile.tag.album = songData?.album?.name || "未知专辑";
640-
songFile.tag.performers = songData?.artists?.map((ar: any) => ar.name) || ["未知艺术家"];
641-
songFile.tag.albumArtists = songData?.artists?.map((ar: any) => ar.name) || ["未知艺术家"];
651+
songFile.tag.album =
652+
(typeof songData?.album === "string" ? songData.album : songData?.album?.name) || "未知专辑";
653+
// 处理歌手信息(兼容字符串和数组格式)
654+
const getArtistNames = (artists: any): string[] => {
655+
if (Array.isArray(artists)) {
656+
return artists
657+
.map((ar: any) => (typeof ar === "string" ? ar : ar?.name || ""))
658+
.filter((name) => name && name.trim().length > 0);
659+
}
660+
if (typeof artists === "string" && artists.trim().length > 0) {
661+
return [artists];
662+
}
663+
return [];
664+
};
665+
666+
const artistNames = getArtistNames(songData?.artists);
667+
const finalArtists = artistNames.length > 0 ? artistNames : ["未知艺术家"];
668+
669+
songFile.tag.performers = finalArtists;
670+
songFile.tag.albumArtists = finalArtists;
642671
if (lyric && downloadLyric) songFile.tag.lyrics = lyric;
643672
if (songCover && downloadCover) songFile.tag.pictures = [songCover];
644673
// 保存元信息

src/components/Card/SongCard.vue

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,12 +40,12 @@
4040
class="name-text"
4141
>
4242
{{
43-
settingStore.hideLyricBrackets
43+
settingStore.hideBracketedContent
4444
? removeBrackets(song?.name)
4545
: song?.name || "未知曲目"
4646
}}
4747
<n-text
48-
v-if="song.alia?.length && !settingStore.hideLyricBrackets"
48+
v-if="song.alia?.length && !settingStore.hideBracketedContent"
4949
class="alia"
5050
depth="3"
5151
>
@@ -120,14 +120,22 @@
120120
class="ar"
121121
@click="openJumpArtist(song.artists, ar.id)"
122122
>
123-
{{ ar.name }}
123+
{{
124+
settingStore.hideBracketedContent ? removeBrackets(ar.name) : ar.name
125+
}}
124126
</n-text>
125127
</div>
126128
<div v-else-if="song.type === 'radio'" class="artists">
127129
<n-text class="ar"> 电台节目 </n-text>
128130
</div>
129131
<div v-else class="artists" @click="openJumpArtist(song.artists)">
130-
<n-text class="ar"> {{ song.artists || "未知艺术家" }} </n-text>
132+
<n-text class="ar">
133+
{{
134+
settingStore.hideBracketedContent
135+
? removeBrackets(song.artists)
136+
: song.artists || "未知艺术家"
137+
}}
138+
</n-text>
131139
</div>
132140
</n-flex>
133141
</n-flex>
@@ -236,7 +244,7 @@ const qualityColor = computed(() => {
236244
const albumName = computed(() => {
237245
const album = song.value.album;
238246
const name = isObject(album) ? album.name : album;
239-
return (settingStore.hideLyricBrackets ? removeBrackets(name) : name) || "未知专辑";
247+
return (settingStore.hideBracketedContent ? removeBrackets(name) : name) || "未知专辑";
240248
});
241249
242250
// 加载本地歌曲封面

src/components/Card/SongDataCard.vue

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,20 @@
1919
<div v-if="Array.isArray(data.artists)" class="artists text-hidden">
2020
<SvgIcon name="Artist" :depth="3" />
2121
<n-text v-for="ar in data.artists" :key="ar.id" class="ar">
22-
{{ ar.name }}
22+
{{
23+
settingStore.hideBracketedContent ? removeBrackets(ar.name) : ar.name
24+
}}
2325
</n-text>
2426
</div>
2527
<div v-else class="artists text-hidden">
2628
<SvgIcon name="Artist" :depth="3" />
27-
<n-text class="ar"> {{ data.artists || "未知艺术家" }} </n-text>
29+
<n-text class="ar">
30+
{{
31+
settingStore.hideBracketedContent
32+
? removeBrackets(data.artists)
33+
: data.artists || "未知艺术家"
34+
}}
35+
</n-text>
2836
</div>
2937
<div class="album text-hidden">
3038
<SvgIcon name="Album" :depth="3" />
@@ -47,6 +55,10 @@
4755
import type { SongType } from "@/types/main";
4856
import { coverLoaded } from "@/utils/helper";
4957
import { isObject } from "lodash-es";
58+
import { removeBrackets } from "@/utils/format";
59+
import { useSettingStore } from "@/stores";
60+
61+
const settingStore = useSettingStore();
5062
5163
defineProps<{
5264
data: SongType | null;

src/components/Card/SongListCard.vue

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
</n-flex>
88
<div class="content">
99
<!-- 封面 -->
10-
<div class="cover">
10+
<div v-if="!hiddenCover" class="cover">
1111
<n-image v-if="cover" :src="cover" preview-disabled lazy @load="coverLoaded">
1212
<template #placeholder>
1313
<div class="cover-loading">
@@ -65,6 +65,7 @@ const props = defineProps<{
6565
loading?: boolean;
6666
height?: number;
6767
cover?: string;
68+
hiddenCover?: boolean;
6869
}>();
6970
7071
// 列表前三首

src/components/List/ArtistList.vue

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
<div
66
v-for="(item, index) in data"
77
:key="index"
8-
class="artist-item"
8+
:class="['artist-item', { 'no-cover': hiddenCover }]"
99
@click="
1010
router.push({
1111
name: 'artist',
@@ -14,7 +14,7 @@
1414
"
1515
>
1616
<!-- 封面 -->
17-
<div class="cover">
17+
<div v-if="!hiddenCover" class="cover">
1818
<s-image
1919
:src="item.coverSize?.m || item.cover"
2020
default-src="/images/artist.jpg?asset"
@@ -31,7 +31,9 @@
3131
</div>
3232
<!-- 信息 -->
3333
<div class="cover-data">
34-
<n-text class="name text-hidden">{{ item.name }}</n-text>
34+
<n-text class="name text-hidden">{{
35+
settingStore.hideBracketedContent ? removeBrackets(item.name) : item.name
36+
}}</n-text>
3537
<!-- 数量 -->
3638
<div v-if="item.musicSize" class="num">
3739
<SvgIcon name="Music" :depth="3" />
@@ -49,8 +51,8 @@
4951
</div>
5052
<div v-else-if="loading" class="artist-list">
5153
<div class="artist-grid">
52-
<div v-for="item in 50" :key="item" class="artist-item">
53-
<div class="cover">
54+
<div v-for="item in 50" :key="item" :class="['artist-item', { 'no-cover': hiddenCover }]">
55+
<div v-if="!hiddenCover" class="cover">
5456
<n-skeleton class="cover-img" />
5557
</div>
5658
<div class="cover-data">
@@ -66,13 +68,16 @@
6668

6769
<script setup lang="ts">
6870
import type { ArtistType } from "@/types/main";
71+
import { removeBrackets } from "@/utils/format";
72+
import { useSettingStore } from "@/stores";
6973
7074
defineProps<{
7175
data: ArtistType[];
7276
type?: "playlist" | "album" | "video";
7377
loadMore?: boolean;
7478
loading?: boolean;
7579
loadingText?: string;
80+
hiddenCover?: boolean;
7681
}>();
7782
7883
const emit = defineEmits<{
@@ -81,6 +86,7 @@ const emit = defineEmits<{
8186
}>();
8287
8388
const router = useRouter();
89+
const settingStore = useSettingStore();
8490
</script>
8591

8692
<style lang="scss" scoped>
@@ -191,6 +197,21 @@ const router = useRouter();
191197
&:active {
192198
transform: scale(0.98);
193199
}
200+
&.no-cover {
201+
background-color: var(--surface-container-hex);
202+
border: 2px solid rgba(var(--primary), 0.12);
203+
padding: 12px 0;
204+
&:hover {
205+
border-color: rgba(var(--primary), 0.58);
206+
}
207+
.cover-data {
208+
height: 100%;
209+
justify-content: center;
210+
.name {
211+
font-weight: bold;
212+
}
213+
}
214+
}
194215
}
195216
.load-more {
196217
margin: 20px 0;

src/components/List/CommentList.vue

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,13 @@
22
<Transition name="fade" mode="out-in">
33
<n-flex v-if="data.length > 0" :size="20" :class="['comment-list', { transparent }]" vertical>
44
<n-flex
5-
v-for="(item, index) in data"
6-
:key="index"
7-
:size="20"
8-
class="comments"
9-
@dblclick="handleDoubleClick(item)"
10-
>
11-
<div v-if="!transparent" class="user">
5+
v-for="(item, index) in data"
6+
:key="index"
7+
:size="0"
8+
class="comments"
9+
@dblclick="handleDoubleClick(item)"
10+
>
11+
<div v-if="!transparent && !hiddenCover" class="user">
1212
<div class="avatar">
1313
<n-image
1414
:src="
@@ -116,6 +116,7 @@ const props = defineProps<{
116116
transparent?: boolean;
117117
// 资源 ID
118118
resId: number;
119+
hiddenCover?: boolean;
119120
}>();
120121
121122
const emit = defineEmits<{
@@ -228,6 +229,7 @@ const handleDoubleClick = debounce(async (item: CommentType) => {
228229
align-items: center;
229230
min-width: 60px;
230231
width: 60px;
232+
margin-right: 12px;
231233
.avatar {
232234
position: relative;
233235
display: flex;

0 commit comments

Comments
 (0)