🐞 fix: 修复桌面歌词字体调节

This commit is contained in:
imsyy
2025-11-06 15:04:40 +08:00
parent a556a2e102
commit 1c9109af73
8 changed files with 206 additions and 77 deletions

View File

@@ -64,6 +64,11 @@ const initLyricIpc = (): void => {
// 更新歌词窗口配置 // 更新歌词窗口配置
ipcMain.on("update-desktop-lyric-option", (_, option, callback: boolean = false) => { ipcMain.on("update-desktop-lyric-option", (_, option, callback: boolean = false) => {
if (!option || !isWinAlive(lyricWin)) return; if (!option || !isWinAlive(lyricWin)) return;
// 增量更新
const prevOption = store.get("lyric.config");
if (prevOption) {
option = { ...prevOption, ...option };
}
store.set("lyric.config", option); store.set("lyric.config", option);
// 触发窗口更新 // 触发窗口更新
if (callback && isWinAlive(lyricWin)) { if (callback && isWinAlive(lyricWin)) {
@@ -124,9 +129,11 @@ const initLyricIpc = (): void => {
// 更新高度 // 更新高度
ipcMain.on("update-window-height", (_, height) => { ipcMain.on("update-window-height", (_, height) => {
if (!isWinAlive(lyricWin)) return; if (!isWinAlive(lyricWin)) return;
const store = useStore();
const { width } = lyricWin.getBounds(); const { width } = lyricWin.getBounds();
// 更新窗口高度 // 更新窗口高度
lyricWin.setBounds({ width, height }); lyricWin.setBounds({ width, height });
store.set("lyric", { ...store.get("lyric"), height });
}); });
// 请求歌词数据及配置 // 请求歌词数据及配置
@@ -139,8 +146,6 @@ const initLyricIpc = (): void => {
// 获取配置 // 获取配置
ipcMain.handle("request-desktop-lyric-option", () => { ipcMain.handle("request-desktop-lyric-option", () => {
const config = store.get("lyric.config"); const config = store.get("lyric.config");
console.log(config);
if (isWinAlive(lyricWin)) { if (isWinAlive(lyricWin)) {
lyricWin.webContents.send("update-desktop-lyric-option", config); lyricWin.webContents.send("update-desktop-lyric-option", config);
} }

View File

@@ -1,5 +1,7 @@
import { screen } from "electron";
import { storeLog } from "../logger"; import { storeLog } from "../logger";
import type { LyricConfig } from "../../../src/types/desktop-lyric"; import type { LyricConfig } from "../../../src/types/desktop-lyric";
import defaultLyricConfig from "../../../src/assets/data/lyricConfig";
import Store from "electron-store"; import Store from "electron-store";
storeLog.info("🌱 Store init"); storeLog.info("🌱 Store init");
@@ -13,9 +15,6 @@ export interface StoreType {
maximized?: boolean; maximized?: boolean;
}; };
lyric: { lyric: {
fontSize: number;
mainColor: string;
shadowColor: string;
// 窗口位置 // 窗口位置
x?: number; x?: number;
y?: number; y?: number;
@@ -32,6 +31,8 @@ export interface StoreType {
* @returns Store<StoreType> * @returns Store<StoreType>
*/ */
export const useStore = () => { export const useStore = () => {
// 获取主屏幕
const screenData = screen.getPrimaryDisplay();
return new Store<StoreType>({ return new Store<StoreType>({
defaults: { defaults: {
window: { window: {
@@ -39,25 +40,11 @@ export const useStore = () => {
height: 800, height: 800,
}, },
lyric: { lyric: {
fontSize: 30, x: screenData.workAreaSize.width / 2 - 400,
mainColor: "#fff", y: screenData.workAreaSize.height - 90,
shadowColor: "rgba(0, 0, 0, 0.5)",
x: 0,
y: 0,
width: 800, width: 800,
height: 180, height: 152,
config: { config: defaultLyricConfig,
isLock: false,
playedColor: "#fe7971",
unplayedColor: "#ccc",
stroke: "#000",
strokeWidth: 2,
fontFamily: "system-ui",
fontSize: 24,
isDoubleLine: true,
position: "both",
limitBounds: false,
},
}, },
proxy: "", proxy: "",
}, },

View File

@@ -43,28 +43,28 @@ class LyricWindow {
width: width || 800, width: width || 800,
height: height || 180, height: height || 180,
minWidth: 440, minWidth: 440,
minHeight: 120, minHeight: 140,
center: !(x && y), // 没有指定位置时居中显示 maxWidth: 1600,
// maxWidth: 1600, maxHeight: 360,
// maxHeight: 300, // 没有指定位置时居中显示
center: !(x && y),
// 窗口位置 // 窗口位置
x, x,
y, y,
// transparent: true, transparent: true,
// backgroundColor: "rgba(0, 0, 0, 0)", backgroundColor: "rgba(0, 0, 0, 0)",
alwaysOnTop: true, alwaysOnTop: true,
resizable: true, resizable: true,
movable: true, movable: true,
show: false, show: false,
// 不在任务栏显示 // 不在任务栏显示
// skipTaskbar: true, // skipTaskbar: true,
// // 窗口不能最小化 // 窗口不能最小化
// minimizable: false, minimizable: false,
// // 窗口不能最大化 // 窗口不能最大化
// maximizable: false, maximizable: false,
// // 窗口不能进入全屏状态 // 窗口不能进入全屏状态
// fullscreenable: false, fullscreenable: false,
frame: true,
}); });
if (!this.win) return null; if (!this.win) return null;
// 加载地址 // 加载地址

View File

@@ -0,0 +1,16 @@
import type { LyricConfig } from "../../types/desktop-lyric";
const config: LyricConfig = {
isLock: false,
playedColor: "#fe7971",
unplayedColor: "#ccc",
shadowColor: "rgba(0, 0, 0, 0.5)",
fontFamily: "system-ui",
fontSize: 24,
fontIsBold: false,
isDoubleLine: true,
position: "both",
limitBounds: false,
};
export default config;

View File

@@ -387,16 +387,58 @@
</n-card> </n-card>
<n-card class="set-item"> <n-card class="set-item">
<div class="label"> <div class="label">
<n-text class="name">桌面歌词文字大小</n-text> <n-text class="name">歌词字体</n-text>
<n-text class="tip" :depth="3"> 更改桌面歌词字体 </n-text>
</div>
<n-flex>
<Transition name="fade" mode="out-in">
<n-button
v-if="desktopLyricConfig.fontFamily !== 'system-ui'"
type="primary"
strong
secondary
@click="
() => {
desktopLyricConfig.fontFamily = 'system-ui';
saveDesktopLyricConfig();
}
"
>
恢复默认
</n-button>
</Transition>
<n-select
v-model:value="desktopLyricConfig.fontFamily"
:options="allFontsData"
class="set"
@update:value="saveDesktopLyricConfig"
/>
</n-flex>
</n-card>
<n-card class="set-item">
<div class="label">
<n-text class="name">文字加粗</n-text>
<n-text class="tip" :depth="3">是否加粗桌面歌词文字</n-text>
</div>
<n-switch
v-model:value="desktopLyricConfig.fontIsBold"
:round="false"
class="set"
@update:value="saveDesktopLyricConfig"
/>
</n-card>
<n-card class="set-item">
<div class="label">
<n-text class="name">文字大小</n-text>
<n-text class="tip" :depth="3">翻译或其他文字将会跟随变化</n-text> <n-text class="tip" :depth="3">翻译或其他文字将会跟随变化</n-text>
</div> </div>
<n-select <n-select
v-model:value="desktopLyricConfig.fontSize" v-model:value="desktopLyricConfig.fontSize"
:options=" :options="
Array.from({ length: 41 }, (_, i) => { Array.from({ length: 96 - 20 + 1 }, (_, i) => {
return { return {
label: `${10 + i} px`, label: `${20 + i} px`,
value: 10 + i, value: 20 + i,
}; };
}) })
" "
@@ -458,29 +500,22 @@ import { useSettingStore, useStatusStore } from "@/stores";
import { cloneDeep, isEqual } from "lodash-es"; import { cloneDeep, isEqual } from "lodash-es";
import { isElectron } from "@/utils/env"; import { isElectron } from "@/utils/env";
import { openLyricExclude } from "@/utils/modal"; import { openLyricExclude } from "@/utils/modal";
import player from "@/utils/player";
import { LyricConfig } from "@/types/desktop-lyric"; import { LyricConfig } from "@/types/desktop-lyric";
import defaultDesktopLyricConfig from "@/assets/data/lyricConfig";
import player from "@/utils/player";
import { SelectOption } from "naive-ui";
const statusStore = useStatusStore(); const statusStore = useStatusStore();
const settingStore = useSettingStore(); const settingStore = useSettingStore();
// 全部字体
const allFontsData = ref<SelectOption[]>([]);
// 桌面歌词配置 // 桌面歌词配置
const defaultDesktopLyricConfig = {
isLock: false,
playedColor: "#fe7971",
unplayedColor: "#ccc",
shadowColor: "rgba(0, 0, 0, 0.5)",
fontFamily: "system-ui",
fontSize: 24,
isDoubleLine: true,
position: "both",
limitBounds: false,
} as LyricConfig;
const desktopLyricConfig = reactive<LyricConfig>({ ...defaultDesktopLyricConfig }); const desktopLyricConfig = reactive<LyricConfig>({ ...defaultDesktopLyricConfig });
// 获取桌面歌词配置 // 获取桌面歌词配置
const getDesktopLyricConfig = async () => { const getDesktopLyricConfig = async () => {
if (!isElectron) return;
const config = await window.electron.ipcRenderer.invoke("request-desktop-lyric-option"); const config = await window.electron.ipcRenderer.invoke("request-desktop-lyric-option");
if (config) Object.assign(desktopLyricConfig, config); if (config) Object.assign(desktopLyricConfig, config);
// 监听更新 // 监听更新
@@ -527,8 +562,35 @@ const restoreDesktopLyricConfig = () => {
} }
}; };
// 获取全部系统字体
const getAllSystemFonts = async () => {
const allFonts = await window.electron.ipcRenderer.invoke("get-all-fonts");
allFonts.map((v: string) => {
// 去除前后的引号
v = v.replace(/^['"]+|['"]+$/g, "");
allFontsData.value.push({
label: v,
value: v,
style: {
fontFamily: v,
},
});
});
// 添加默认选项
allFontsData.value.unshift({
label: "系统默认",
value: "system-ui",
style: {
fontFamily: "system-ui",
},
});
};
onMounted(() => { onMounted(() => {
getDesktopLyricConfig(); if (isElectron) {
getDesktopLyricConfig();
getAllSystemFonts();
}
}); });
</script> </script>

View File

@@ -29,6 +29,8 @@ export interface LyricConfig {
fontFamily: string; fontFamily: string;
/** 字体大小 */ /** 字体大小 */
fontSize: number; fontSize: number;
/** 字体是否加粗 */
fontIsBold: boolean;
/** 是否双行 */ /** 是否双行 */
isDoubleLine: boolean; isDoubleLine: boolean;
/** 文本排版位置 */ /** 文本排版位置 */

View File

@@ -14,12 +14,6 @@
<div class="menu-btn" title="返回应用" @click.stop="sendToMain('win-show')"> <div class="menu-btn" title="返回应用" @click.stop="sendToMain('win-show')">
<SvgIcon name="Music" /> <SvgIcon name="Music" />
</div> </div>
<div class="menu-btn" title="增加字体大小">
<SvgIcon :offset="-1" name="TextSizeAdd" />
</div>
<div class="menu-btn" title="减少字体大小">
<SvgIcon :offset="-1" name="TextSizeReduce" />
</div>
<span class="song-name">{{ lyricData.playName }}</span> <span class="song-name">{{ lyricData.playName }}</span>
</n-flex> </n-flex>
<n-flex :wrap="false" align="center" justify="center" size="small" @pointerdown.stop> <n-flex :wrap="false" align="center" justify="center" size="small" @pointerdown.stop>
@@ -38,6 +32,9 @@
</div> </div>
</n-flex> </n-flex>
<n-flex :wrap="false" align="center" justify="flex-end" size="small" @pointerdown.stop> <n-flex :wrap="false" align="center" justify="flex-end" size="small" @pointerdown.stop>
<div class="menu-btn" title="设置">
<SvgIcon name="Settings" />
</div>
<div class="menu-btn" title="锁定"> <div class="menu-btn" title="锁定">
<SvgIcon name="Lock" /> <SvgIcon name="Lock" />
</div> </div>
@@ -53,9 +50,12 @@
:style="{ :style="{
fontSize: lyricConfig.fontSize + 'px', fontSize: lyricConfig.fontSize + 'px',
fontFamily: lyricConfig.fontFamily, fontFamily: lyricConfig.fontFamily,
fontWeight: lyricConfig.fontIsBold ? 'bold' : 'normal',
textShadow: `0 0 4px ${lyricConfig.shadowColor}`, textShadow: `0 0 4px ${lyricConfig.shadowColor}`,
}" }"
:class="['lyric-container', lyricConfig.position]" :class="['lyric-container', lyricConfig.position]"
:size="0"
justify="space-around"
vertical vertical
> >
<span <span
@@ -69,9 +69,7 @@
{{ line.text }} {{ line.text }}
</span> </span>
<!-- 占位 --> <!-- 占位 -->
<span v-if="lyricConfig.isDoubleLine && renderLyricLines.length === 1" class="lyric-line"> <span v-if="renderLyricLines.length === 1" class="lyric-line"> &nbsp; </span>
&nbsp;
</span>
</n-flex> </n-flex>
</div> </div>
</n-config-provider> </n-config-provider>
@@ -80,6 +78,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { Position } from "@vueuse/core"; import { Position } from "@vueuse/core";
import { LyricConfig, LyricData, RenderLine } from "@/types/desktop-lyric"; import { LyricConfig, LyricData, RenderLine } from "@/types/desktop-lyric";
import defaultDesktopLyricConfig from "@/assets/data/lyricConfig";
// 桌面歌词数据 // 桌面歌词数据
const lyricData = reactive<LyricData>({ const lyricData = reactive<LyricData>({
@@ -93,15 +92,7 @@ const lyricData = reactive<LyricData>({
// 桌面歌词配置 // 桌面歌词配置
const lyricConfig = reactive<LyricConfig>({ const lyricConfig = reactive<LyricConfig>({
isLock: false, ...defaultDesktopLyricConfig,
playedColor: "#fe7971",
unplayedColor: "#ccc",
shadowColor: "rgba(0, 0, 0, 0.5)",
fontFamily: "system-ui",
fontSize: 24,
isDoubleLine: true,
position: "both",
limitBounds: false,
}); });
// 桌面歌词元素 // 桌面歌词元素
@@ -223,6 +214,68 @@ useDraggable(desktopLyricRef, {
}, },
}); });
// 监听窗口大小变化
const { height: winHeight } = useWindowSize();
/**
* 根据窗口高度计算字体大小
* 线性映射并取整,范围 20-96
*/
const computedFontSize = computed(() => {
const h = Number(winHeight?.value ?? 0);
const minH = 140;
const maxH = 360;
const minF = 20;
const maxF = 96;
if (!Number.isFinite(h) || h <= minH) return minF;
if (h >= maxH) return maxF;
const ratio = (h - minH) / (maxH - minH);
return Math.round(minF + ratio * (maxF - minF));
});
// 监听字体大小变化,同步更新窗口高度
watch(
computedFontSize,
(size) => {
if (!Number.isFinite(size)) return;
if (size === lyricConfig.fontSize) return;
const next = { fontSize: size };
window.electron.ipcRenderer.send("update-desktop-lyric-option", next, true);
},
{ immediate: true },
);
/**
* 根据字体大小计算窗口高度20-96 <-> 140-360
* @param size 字体大小
* @returns 窗口高度
*/
const fontSizeToHeight = (size: number) => {
const minH = 140;
const maxH = 360;
const minF = 20;
const maxF = 96;
const s = Math.min(Math.max(Math.round(size), minF), maxF);
const ratio = (s - minF) / (maxF - minF);
return Math.round(minH + ratio * (maxH - minH));
};
// 防抖推送窗口高度更新,避免频繁抖动
const pushWindowHeight = useDebounceFn((nextHeight: number) => {
if (!Number.isFinite(nextHeight)) return;
window.electron.ipcRenderer.send("update-window-height", nextHeight);
}, 100);
// 监听配置中的字体大小变化,同步更新窗口高度
watch(
() => lyricConfig.fontSize,
(size) => {
const height = fontSizeToHeight(size);
if (height) pushWindowHeight(height);
},
{ immediate: true },
);
// 发送至主进程 // 发送至主进程
const sendToMain = (eventName: string, ...args: any[]) => { const sendToMain = (eventName: string, ...args: any[]) => {
window.electron.ipcRenderer.send(eventName, ...args); window.electron.ipcRenderer.send(eventName, ...args);
@@ -253,6 +306,9 @@ onMounted(() => {
height: 100%; height: 100%;
} }
.desktop-lyric { .desktop-lyric {
display: flex;
flex-direction: column;
height: 100%;
color: #fff; color: #fff;
background-color: transparent; background-color: transparent;
padding: 12px; padding: 12px;
@@ -306,10 +362,11 @@ onMounted(() => {
} }
} }
.lyric-container { .lyric-container {
height: 100%;
padding: 0 8px; padding: 0 8px;
.lyric-line { .lyric-line {
// 单行
width: 100%; width: 100%;
line-height: normal;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
white-space: nowrap; white-space: nowrap;
@@ -336,7 +393,7 @@ onMounted(() => {
} }
&:hover { &:hover {
&:not(.locked) { &:not(.locked) {
background-color: rgba(0, 0, 0, 0.3); background-color: rgba(0, 0, 0, 0.6);
.header { .header {
opacity: 1; opacity: 1;
} }
@@ -352,9 +409,9 @@ onMounted(() => {
} }
</style> </style>
<!-- <style> <style>
body { body {
background-color: transparent !important; background-color: transparent !important;
/* background-image: url("https://picsum.photos/1920/1080"); */ /* background-image: url("https://picsum.photos/1920/1080"); */
} }
</style> --> </style>

View File

@@ -10,7 +10,7 @@
"electron/main/index.d.ts", "electron/main/index.d.ts",
"electron/preload/index.d.ts", "electron/preload/index.d.ts",
"electron/preload/index.ts", "electron/preload/index.ts",
"dist/lastfm.ts" "src/assets/data/*"
], ],
"compilerOptions": { "compilerOptions": {
"composite": true, "composite": true,