From 7bcedf8aad6dd23c8415de18100b683343e8a5d0 Mon Sep 17 00:00:00 2001
From: Shomi <96868062+Shomi-FJS@users.noreply.github.com>
Date: Mon, 22 Jun 2026 17:16:56 +0800
Subject: [PATCH] =?UTF-8?q?feat(lyric/setting):=20=E6=96=B0=E5=A2=9E?=
=?UTF-8?q?=E5=85=A8=E5=B1=80=E6=AD=8C=E8=AF=8D=E6=97=B6=E9=97=B4=E8=BD=B4?=
=?UTF-8?q?=E5=81=8F=E7=A7=BB=E5=8A=9F=E8=83=BD?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 新增全局歌词偏移相关的状态配置到设置存储
- 在设置页面添加全局歌词偏移的完整配置选项
- 在播放器快捷菜单中集成全局歌词偏移的快速调节控件
- 为桌面端与移动端播放器封面添加双击应用全局偏移的交互
- 优化移动端歌词页封面的手势交互避免冲突
---
src/components/Player/FullPlayerMobile.vue | 90 +++++++++++++-
src/components/Player/PlayerLyric/index.vue | 9 +-
.../Player/PlayerMeta/PlayerCover.vue | 61 ++++++++++
.../Player/PlayerQuickActionsMenu.vue | 111 ++++++++++++++++++
src/components/Setting/config/lyric.ts | 60 ++++++++++
src/stores/setting.ts | 15 +++
src/stores/status.ts | 19 ++-
7 files changed, 356 insertions(+), 9 deletions(-)
diff --git a/src/components/Player/FullPlayerMobile.vue b/src/components/Player/FullPlayerMobile.vue
index 7303bfe56..727291ca9 100644
--- a/src/components/Player/FullPlayerMobile.vue
+++ b/src/components/Player/FullPlayerMobile.vue
@@ -167,7 +167,18 @@ let savedPageType: MobilePageType = "info";
@@ -326,6 +424,19 @@ const adjustLandscapeCoverOffset = (delta: number) => {
);
};
+const adjustGlobalLyricOffset = (delta: number) => {
+ settingStore.globalLyricOffsetValue = clampValue(
+ settingStore.globalLyricOffsetValue + delta,
+ -10000,
+ 10000,
+ );
+};
+
+const applyGlobalLyricOffsetPreset = (value: number) => {
+ const signMultiplier = settingStore.globalLyricOffsetPresetSign === "-" ? -1 : 1;
+ settingStore.globalLyricOffsetValue = value * signMultiplier;
+};
+
const adjustLandscapeLyricPadding = (delta: number) => {
settingStore.landscapeLyricPaddingX = clampValue(
settingStore.landscapeLyricPaddingX + delta,
diff --git a/src/components/Setting/config/lyric.ts b/src/components/Setting/config/lyric.ts
index fb5912c28..f1d85c9de 100644
--- a/src/components/Setting/config/lyric.ts
+++ b/src/components/Setting/config/lyric.ts
@@ -462,6 +462,66 @@ export const useLyricSettings = (): SettingConfig => {
set: (v) => (settingStore.lyricsBlendMode = v),
}),
},
+ {
+ key: "globalLyricOffsetEnabled",
+ label: "全局歌词偏移",
+ type: "switch",
+ description: "是否启用全局歌词时间轴偏移",
+ value: computed({
+ get: () => settingStore.globalLyricOffsetEnabled,
+ set: (v) => (settingStore.globalLyricOffsetEnabled = v),
+ }),
+ children: [
+ {
+ key: "globalLyricOffsetValue",
+ label: "偏移数值",
+ type: "input-number",
+ description: "全局歌词偏移数值 (+ -),单位毫秒",
+ min: -10000,
+ max: 10000,
+ step: 10,
+ suffix: "ms",
+ value: computed({
+ get: () => settingStore.globalLyricOffsetValue,
+ set: (v) => (settingStore.globalLyricOffsetValue = v || 0),
+ }),
+ },
+ {
+ key: "globalLyricOffsetPresetSign",
+ label: "快捷预设单位",
+ type: "select",
+ description: "快捷开关中的预设数值符号 (+ 或 -)",
+ options: [
+ { label: "+", value: "+" },
+ { label: "-", value: "-" },
+ ],
+ value: computed({
+ get: () => settingStore.globalLyricOffsetPresetSign,
+ set: (v) => (settingStore.globalLyricOffsetPresetSign = v),
+ }),
+ },
+ {
+ key: "globalLyricOffsetAlwaysApply",
+ label: "始终启用偏移",
+ type: "switch",
+ description: "开启后,任何歌曲播放时都将默认应用该偏移数值",
+ value: computed({
+ get: () => settingStore.globalLyricOffsetAlwaysApply,
+ set: (v) => (settingStore.globalLyricOffsetAlwaysApply = v),
+ }),
+ },
+ {
+ key: "globalLyricOffsetDoubleClickApply",
+ label: "双击歌词页封面应用偏移",
+ type: "switch",
+ description: "开启后,双击歌词页封面可应用当前全局偏移",
+ value: computed({
+ get: () => settingStore.globalLyricOffsetDoubleClickApply,
+ set: (v) => (settingStore.globalLyricOffsetDoubleClickApply = v),
+ }),
+ },
+ ],
+ },
{
key: "lyricOffsetStep",
label: "歌词时延调节步长",
diff --git a/src/stores/setting.ts b/src/stores/setting.ts
index 0adb3d7d3..df9e623e2 100644
--- a/src/stores/setting.ts
+++ b/src/stores/setting.ts
@@ -425,6 +425,16 @@ export interface SettingState {
time: boolean;
description: boolean;
};
+ /** 全局歌词时间轴偏移开关 */
+ globalLyricOffsetEnabled: boolean;
+ /** 全局歌词时间轴偏移数值 (ms) */
+ globalLyricOffsetValue: number;
+ /** 全局歌词时间轴快捷预设单位符号 */
+ globalLyricOffsetPresetSign: "+" | "-";
+ /** 双击歌词页封面应用全局偏移 */
+ globalLyricOffsetDoubleClickApply: boolean;
+ /** 始终启用全局偏移 */
+ globalLyricOffsetAlwaysApply: boolean;
/** 全屏播放器界面元素显示配置 */
fullscreenPlayerElements: {
like: boolean;
@@ -758,6 +768,11 @@ export const useSettingStore = defineStore("setting", {
time: true,
description: true,
},
+ globalLyricOffsetEnabled: false,
+ globalLyricOffsetValue: 0,
+ globalLyricOffsetPresetSign: "+",
+ globalLyricOffsetDoubleClickApply: false,
+ globalLyricOffsetAlwaysApply: false,
fullscreenPlayerElements: {
like: true,
addToPlaylist: true,
diff --git a/src/stores/status.ts b/src/stores/status.ts
index 815d640ff..420596905 100644
--- a/src/stores/status.ts
+++ b/src/stores/status.ts
@@ -11,6 +11,7 @@ import type {
import type { RepeatModeType, ShuffleModeType } from "@/types/shared/play-mode";
import { isDevBuild } from "@/utils/env";
import { defineStore } from "pinia";
+import { useSettingStore } from "./setting";
interface StatusState {
/** 菜单折叠状态 */
@@ -335,7 +336,14 @@ export const useStatusStore = defineStore("status", {
getSongOffset(songId?: number): number {
if (!songId) return 0;
const offsetTime = this.currentTimeOffsetMap?.[songId] ?? 0;
- return Math.floor(offsetTime * 1000);
+ const baseOffset = Math.floor(offsetTime * 1000);
+
+ // 注意:这里需要动态导入 settingStore 避免循环依赖
+ const settingStore = useSettingStore();
+ if (settingStore.globalLyricOffsetEnabled && settingStore.globalLyricOffsetAlwaysApply) {
+ return baseOffset + settingStore.globalLyricOffsetValue;
+ }
+ return baseOffset;
},
/**
* 设置指定歌曲的偏移
@@ -362,12 +370,13 @@ export const useStatusStore = defineStore("status", {
*/
incSongOffset(songId?: number, delta: number = 500) {
if (!songId) return;
- const current = this.getSongOffset(songId);
- const next = current + delta;
- if (next === 0) {
+ const offsetTime = this.currentTimeOffsetMap?.[songId] ?? 0;
+ const currentLocal = Math.floor(offsetTime * 1000);
+ const nextLocal = currentLocal + delta;
+ if (nextLocal === 0) {
delete this.currentTimeOffsetMap[songId];
} else {
- this.setSongOffset(songId, next);
+ this.setSongOffset(songId, nextLocal);
}
},
/** 重置指定歌曲的偏移为 0 */