From 300462d2300adcb2704e2a7e3f0111eaf167a8be Mon Sep 17 00:00:00 2001 From: Maybe <1913093102@qq.com> Date: Sat, 28 Feb 2026 17:10:52 +0800 Subject: [PATCH 01/16] =?UTF-8?q?=E5=B0=81=E9=9D=A2=E6=98=BE=E7=A4=BA?= =?UTF-8?q?=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package-lock.json | 68 +++++--- src/common/defaultSetting.ts | 2 + src/common/types/app_setting.d.ts | 10 ++ src/lang/en-us.json | 6 + src/lang/zh-cn.json | 6 + src/lang/zh-tw.json | 6 + src/renderer/views/List/MusicList/index.vue | 66 +++++++- src/renderer/views/List/MusicList/useCover.js | 152 ++++++++++++++++++ .../views/Setting/components/SettingBasic.vue | 18 +++ 9 files changed, 304 insertions(+), 30 deletions(-) create mode 100644 src/renderer/views/List/MusicList/useCover.js diff --git a/package-lock.json b/package-lock.json index 2d9324c969..fa07ebac1b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -138,7 +138,6 @@ "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/code-frame": "^7.29.0", "@babel/generator": "^7.29.0", @@ -2118,6 +2117,7 @@ "dev": true, "license": "BSD-2-Clause", "optional": true, + "peer": true, "dependencies": { "cross-dirname": "^0.1.0", "debug": "^4.3.4", @@ -2139,6 +2139,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", @@ -2155,6 +2156,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "dependencies": { "universalify": "^2.0.0" }, @@ -2169,6 +2171,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "engines": { "node": ">= 10.0.0" } @@ -3211,7 +3214,8 @@ "resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz", "integrity": "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==", "dev": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/@simonwep/pickr": { "version": "1.9.1", @@ -3517,7 +3521,8 @@ "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", "dev": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/@types/keyv": { "version": "3.1.4", @@ -3611,7 +3616,8 @@ "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.7.1.tgz", "integrity": "sha512-FmgJfu+MOcQ370SD0ev7EI8TlCAfKYU+B4m5T3yXc1CiRN94g/SZPtsCkk506aUDtlMnFZvasDwHHUcZUEaYuA==", "dev": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/@types/send": { "version": "1.2.1", @@ -3765,7 +3771,6 @@ "integrity": "sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ==", "dev": true, "license": "BSD-2-Clause", - "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "6.21.0", "@typescript-eslint/types": "6.21.0", @@ -3813,6 +3818,7 @@ "integrity": "sha512-rZQI7wHfao8qMX3Rd3xqeYSMCL3SoiSQLBATSiVKARdFGCYSRvmViieZjqc58jKgs8Y8i9YvVVhRbHSTA4VBag==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@typescript-eslint/typescript-estree": "6.21.0", "@typescript-eslint/utils": "6.21.0", @@ -3884,6 +3890,7 @@ "integrity": "sha512-NfWVaC8HP9T8cbKQxHcsJBY5YE1O33+jpMwN45qzWWaPDZgLIbo12toGMWnmhvCpd3sIxkpDw3Wv1B3dYrbDQQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@types/json-schema": "^7.0.12", @@ -4360,7 +4367,6 @@ "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, "license": "MIT", - "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -4421,7 +4427,6 @@ "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -4761,6 +4766,7 @@ "integrity": "sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.4", @@ -4794,6 +4800,7 @@ "integrity": "sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.4", @@ -4816,6 +4823,7 @@ "integrity": "sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "call-bind": "^1.0.8", "define-properties": "^1.2.1", @@ -4835,6 +4843,7 @@ "integrity": "sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "call-bind": "^1.0.8", "define-properties": "^1.2.1", @@ -5384,7 +5393,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "baseline-browser-mapping": "^2.9.0", "caniuse-lite": "^1.0.30001759", @@ -5446,7 +5454,6 @@ "integrity": "sha512-ZMANVnAixE6AWWnPzlW2KpUrxhm9woycYvPOo67jWHyFowASTEd9s+QN1EIMsSDtwhIxN4sWE1jotpuDUIgyIw==", "hasInstallScript": true, "license": "MIT", - "peer": true, "dependencies": { "node-gyp-build": "^4.3.0" }, @@ -5537,6 +5544,7 @@ "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=6" }, @@ -5550,6 +5558,7 @@ "integrity": "sha512-SW9lzGTLvWTP1AY8xeAMZimqDrIaSdLQUcVr9DMef51niJ022Ri87SwRRKYm4A6iHfkPaiVUu/Duw2Wc4J7kKg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "semver": "^7.0.0" } @@ -6511,7 +6520,8 @@ "integrity": "sha512-+R08/oI0nl3vfPcqftZRpytksBXDzOUveBq/NBVx0sUp1axwzPQrKinNx5yd5sxPu8j1wIy8AfnVQ+5eFdha6Q==", "dev": true, "license": "MIT", - "optional": true + "optional": true, + "peer": true }, "node_modules/cross-env": { "version": "10.1.0", @@ -7838,6 +7848,7 @@ "dev": true, "hasInstallScript": true, "license": "MIT", + "peer": true, "dependencies": { "@electron/asar": "^3.2.1", "debug": "^4.1.1", @@ -7858,6 +7869,7 @@ "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "graceful-fs": "^4.1.2", "jsonfile": "^4.0.0", @@ -8149,6 +8161,7 @@ "integrity": "sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "hasown": "^2.0.2" }, @@ -8219,7 +8232,6 @@ "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", @@ -8276,6 +8288,7 @@ "integrity": "sha512-3z3vFexKIEnjHE3zCMRo6fn/e44U7T1khUjg+Hp0ZQMCigh28rALD0nPFBcGZuiLC5rLZa2ubQHDRln09JfU2Q==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "semver": "^7.5.4" }, @@ -8361,6 +8374,7 @@ "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "debug": "^3.2.7", "is-core-module": "^2.13.0", @@ -8373,6 +8387,7 @@ "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "ms": "^2.1.1" } @@ -8383,6 +8398,7 @@ "integrity": "sha512-L8jSWTze7K2mTg0vos/RuLRS5soomksDPoJLXIslC7c8Wmut3bx7CPpJijDcBZtxQ5lrbUdM+s0OlNbz0DCDNw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "debug": "^3.2.7" }, @@ -8401,6 +8417,7 @@ "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "ms": "^2.1.1" } @@ -8415,6 +8432,7 @@ "https://opencollective.com/eslint" ], "license": "MIT", + "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.1.2", "@eslint-community/regexpp": "^4.11.0", @@ -8446,6 +8464,7 @@ "integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@rtsao/scc": "^1.1.0", "array-includes": "^3.1.9", @@ -8480,6 +8499,7 @@ "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "ms": "^2.1.1" } @@ -8490,6 +8510,7 @@ "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", "dev": true, "license": "Apache-2.0", + "peer": true, "dependencies": { "esutils": "^2.0.2" }, @@ -8550,7 +8571,6 @@ "integrity": "sha512-174lJKuNsuDIlLpjeXc5E2Tss8P44uIimAfGD0b90k0NoirJqpG7stLuU9Vp/9ioTOrQdWVREc4mRd1BD+CvGw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "globals": "^13.24.0", @@ -9661,6 +9681,7 @@ "integrity": "sha512-shZT/QMiSHc/YBLxxOkMtgSid5HFoauqCE3/exfsEcwg1WkeqjG+V40yBbBrsD+jW2HDXcs28xOfcbm2jI8Ddw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "resolve-pkg-maps": "^1.0.0" }, @@ -10654,6 +10675,7 @@ "integrity": "sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "builtin-modules": "^3.3.0" }, @@ -12789,6 +12811,7 @@ "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", @@ -12808,6 +12831,7 @@ "integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", @@ -12823,6 +12847,7 @@ "integrity": "sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", @@ -13415,7 +13440,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", @@ -14131,7 +14155,6 @@ "integrity": "sha512-spBB5sgC4cv2YcW03f/IAUN1pgDJWNWD8FzkyY4mArLUMJW+KlQhlmUdKAHQuPfb00Jl5xIfImeOsf6YL8QK7Q==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "posthtml-parser": "^0.2.0", "posthtml-render": "^1.0.5" @@ -14435,6 +14458,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "dependencies": { "commander": "^9.4.0" }, @@ -14452,6 +14476,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "engines": { "node": "^12.20.0 || >=14" } @@ -14746,7 +14771,6 @@ "integrity": "sha512-uBi6kmc9f3SZ3PXxqcHiUZLmIXgfgWooKWXcwSGwQd2Zi5Rb0bT14+8CJjJgI8AB+nndLaNgHGrcc6bPIB665g==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "pug-code-gen": "^3.0.3", "pug-filters": "^4.0.0", @@ -15503,6 +15527,7 @@ "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", "dev": true, "license": "MIT", + "peer": true, "funding": { "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" } @@ -15802,7 +15827,6 @@ "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", @@ -16690,6 +16714,7 @@ "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=4" } @@ -17193,6 +17218,7 @@ "integrity": "sha512-yYrrsWnrXMcdsnu/7YMYAofM1ktpL5By7vZhf15CrXijWWrEYZks5AXBudalfSWJLlnen/QUJUB5aoB0kqZUGA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "mkdirp": "^0.5.1", "rimraf": "~2.6.2" @@ -17257,6 +17283,7 @@ "deprecated": "Rimraf versions prior to v4 are no longer supported", "dev": true, "license": "ISC", + "peer": true, "dependencies": { "glob": "^7.1.3" }, @@ -17594,6 +17621,7 @@ "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@types/json5": "^0.0.29", "json5": "^1.0.2", @@ -17606,8 +17634,7 @@ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "dev": true, - "license": "0BSD", - "peer": true + "license": "0BSD" }, "node_modules/tsyringe": { "version": "4.10.0", @@ -17807,7 +17834,6 @@ "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "devOptional": true, "license": "Apache-2.0", - "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -18052,7 +18078,6 @@ "integrity": "sha512-q3l3P9UtEEiAHcsgsqTgf9PPjctrDWoIXW3NpOHFdRDbLvu4DLIcxHangJ4RLrWkBcKjmcs/6NkerI8T/rE4LA==", "hasInstallScript": true, "license": "MIT", - "peer": true, "dependencies": { "node-gyp-build": "^4.3.0" }, @@ -18148,7 +18173,6 @@ "resolved": "https://registry.npmjs.org/vue/-/vue-3.3.13.tgz", "integrity": "sha512-LDnUpQvDgsfc0u/YgtAgTMXJlJQqjkxW1PVcOnJA5cshPleULDjHi7U45pl2VJYazSSvLH8UKcid/kzH8I0a0Q==", "license": "MIT", - "peer": true, "dependencies": { "@vue/compiler-dom": "3.3.13", "@vue/compiler-sfc": "3.3.13", @@ -18171,7 +18195,6 @@ "integrity": "sha512-2rYRLWlIpaiN8xbPiDyXZXRgLGOtWxERV7ND5fFAv5qo1D2N9Fu9MNajBNc6o13lZ+24DAWCkQCvj4klgmcITg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "debug": "^4.3.4", "eslint-scope": "^7.1.1", @@ -18322,7 +18345,6 @@ "integrity": "sha512-dRXm0a2qcHPUBEzVk8uph0xWSjV/xZxenQQbLwnwP7caQCYpqG1qddwlyEkIDkYn0K8tvmcrZ+bOrzoQ3HxCDw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@types/eslint-scope": "^3.7.7", "@types/estree": "^1.0.8", diff --git a/src/common/defaultSetting.ts b/src/common/defaultSetting.ts index e4ce730f6a..32f4c4f6a5 100644 --- a/src/common/defaultSetting.ts +++ b/src/common/defaultSetting.ts @@ -104,6 +104,8 @@ const defaultSetting: LX.AppSetting = { 'desktopLyric.style.isFontWeightExtended': true, 'list.isClickPlayList': false, + 'list.isShowCover': false, + 'list.coverSize': 44, 'list.isShowSource': true, 'list.isSaveScrollLocation': true, 'list.addMusicLocationType': 'top', diff --git a/src/common/types/app_setting.d.ts b/src/common/types/app_setting.d.ts index 14ca61afc6..f39e4dcbad 100644 --- a/src/common/types/app_setting.d.ts +++ b/src/common/types/app_setting.d.ts @@ -495,6 +495,16 @@ declare global { */ 'list.actionButtonsVisible': boolean + /** + * 是否在列表中显示歌曲封面 + */ + 'list.isShowCover': boolean + + /** + * 列表中歌曲封面大小 + */ + 'list.coverSize': number + /** * 是否启用下载功能 */ diff --git a/src/lang/en-us.json b/src/lang/en-us.json index f04971a59c..a24e8c092e 100644 --- a/src/lang/en-us.json +++ b/src/lang/en-us.json @@ -332,6 +332,12 @@ "setting__basic_playbar_progress_style_full": "Full-width", "setting__basic_playbar_progress_style_middle": "Medium", "setting__basic_playbar_progress_style_mini": "Mini", + "setting__basic_list_cover": "List Cover", + "setting__basic_list_show_cover": "Show song cover in list", + "setting__basic_list_cover_size_32px": "32px", + "setting__basic_list_cover_size_44px": "44px", + "setting__basic_list_cover_size_56px": "56px", + "setting__basic_list_cover_size_72px": "72px", "setting__basic_show_animation": "Show animation", "setting__basic_source": "Music API", "setting__basic_source_status_failed": "Failed to initialize", diff --git a/src/lang/zh-cn.json b/src/lang/zh-cn.json index c5a5242380..895da72f15 100644 --- a/src/lang/zh-cn.json +++ b/src/lang/zh-cn.json @@ -332,6 +332,12 @@ "setting__basic_playbar_progress_style_full": "全宽", "setting__basic_playbar_progress_style_middle": "中等", "setting__basic_playbar_progress_style_mini": "迷你", + "setting__basic_list_cover": "列表封面", + "setting__basic_list_show_cover": "在列表中显示歌曲封面", + "setting__basic_list_cover_size_32px": "32px", + "setting__basic_list_cover_size_44px": "44px", + "setting__basic_list_cover_size_56px": "56px", + "setting__basic_list_cover_size_72px": "72px", "setting__basic_show_animation": "显示动画效果", "setting__basic_source": "自定义源", "setting__basic_source_status_failed": "初始化失败", diff --git a/src/lang/zh-tw.json b/src/lang/zh-tw.json index 491563fa56..9de078d54a 100644 --- a/src/lang/zh-tw.json +++ b/src/lang/zh-tw.json @@ -332,6 +332,12 @@ "setting__basic_playbar_progress_style_full": "全寬", "setting__basic_playbar_progress_style_middle": "中等", "setting__basic_playbar_progress_style_mini": "迷你", + "setting__basic_list_cover": "列表封面", + "setting__basic_list_show_cover": "在列表中顯示歌曲封面", + "setting__basic_list_cover_size_32px": "32px", + "setting__basic_list_cover_size_44px": "44px", + "setting__basic_list_cover_size_56px": "56px", + "setting__basic_list_cover_size_72px": "72px", "setting__basic_show_animation": "顯示動畫效果", "setting__basic_source": "自訂來源 API", "setting__basic_source_status_failed": "初始化失敗", diff --git a/src/renderer/views/List/MusicList/index.vue b/src/renderer/views/List/MusicList/index.vue index 9681972deb..a05e3e0a48 100644 --- a/src/renderer/views/List/MusicList/index.vue +++ b/src/renderer/views/List/MusicList/index.vue @@ -5,6 +5,7 @@ # + {{ $t('music_name') }} {{ $t('music_singer') }} {{ $t('music_album') }} @@ -13,6 +14,7 @@ # + {{ $t('music_name') }} {{ $t('music_singer') }} {{ $t('music_album') }} @@ -25,7 +27,7 @@
{{ index + 1 }}
+
+
+ +
+
{{ item.name }} {{ item.source }} @@ -56,7 +63,7 @@
{{ index + 1 }}
+
+
+ +
+
{{ item.name }} {{ item.source }} @@ -120,7 +132,9 @@ import useMusicActions from './useMusicActions' import useSearch from './useSearch' import useListScroll from './useListScroll' import useMusicToggle from './useMusicToggle' +import useCover from './useCover' import { appSetting } from '@renderer/store/setting' + export default { name: 'MusicList', components: { @@ -138,17 +152,31 @@ export default { setup(props, { emit }) { const actionButtonsVisible = appSetting['list.actionButtonsVisible'] + // 封面相关逻辑 + const { + isShowCover, + coverSize, + getCoverUrl, + handleCoverError, + handleScroll: handleCoverScroll, + loadCoversOnListLoaded, + setListRef, + setList, + } = useCover() + let scrollIndex = null let isAnimation = false const handleRestoreScroll = (_scrollIndex, _isAnimation) => { scrollIndex = _scrollIndex isAnimation = _isAnimation - if (isAnimation) void restoreScroll(scrollIndex, isAnimation) - // console.log('handleRestoreScroll', scrollIndex, isAnimation) + if (isAnimation) { + void restoreScroll(scrollIndex, isAnimation) + } } - const onLoadedList = () => { - // console.log('restoreScroll', scrollIndex, isAnimation) + const onLoadedList = (currentList, currentListItemHeight) => { void restoreScroll(scrollIndex, isAnimation) + // 列表加载完成后懒加载封面 + loadCoversOnListLoaded(dom_listContent.value, currentListItemHeight, props.listId) } const { @@ -161,7 +189,11 @@ export default { setSelectedIndex, isShowSource, excludeListIds, - } = useListInfo({ props, onLoadedList }) + } = useListInfo({ props, onLoadedList: (l, h) => { onLoadedList(l, h) } }) + + // 设置封面逻辑所需的引用 + setListRef(listRef) + setList(list) const { selectedList, @@ -351,6 +383,12 @@ export default { actionButtonsVisible, + isShowCover, + coverSize, + getCoverUrl, + handleCoverError, + handleCoverScroll, + isShowMusicToggleModal, selectedToggleMusicInfo, toggleSource, @@ -393,6 +431,20 @@ export default { justify-content: center; position: relative; } +.cover { + flex: 0 0 auto; + margin-right: 8px; + border-radius: 4px; + overflow: hidden; + background-color: var(--color-500); + flex-shrink: 0; + + .coverImg { + width: 100%; + height: 100%; + object-fit: cover; + } +} .playIcon { position: absolute; left: 0; diff --git a/src/renderer/views/List/MusicList/useCover.js b/src/renderer/views/List/MusicList/useCover.js new file mode 100644 index 0000000000..92ea7318d2 --- /dev/null +++ b/src/renderer/views/List/MusicList/useCover.js @@ -0,0 +1,152 @@ +import { reactive, onBeforeUnmount } from '@common/utils/vueTools' +import { appSetting } from '@renderer/store/setting' +import { getPicUrl as getOnlinePicUrl } from '@renderer/core/music/online' +import { getPicUrl as getLocalPicUrl } from '@renderer/core/music/local' + +export default () => { + const isShowCover = appSetting['list.isShowCover'] + const coverSize = appSetting['list.coverSize'] + + // 封面缓存映射(使用 reactive 以便跟踪变化) + const coverUrls = reactive(new Map()) + const fetchingPics = reactive(new Set()) + + let scrollTimer = null + let listRefValue = null + let listValue = null + + const setListRef = (ref) => { listRefValue = ref } + const setList = (list) => { listValue = list } + + /** + * 获取封面 URL + * @param {Object} item - 音乐项 + * @returns {string} 封面 URL 或空字符串 + */ + const getCoverUrl = (item) => { + if (!isShowCover) return '' + // 优先使用已缓存的封面 + if (item.meta.picUrl) { + coverUrls.set(item.id, item.meta.picUrl) + return item.meta.picUrl + } + // 如果已经有缓存的 URL + if (coverUrls.has(item.id)) { + return coverUrls.get(item.id) + } + // 返回空字符串,等待懒加载 + return '' + } + + /** + * 处理封面加载错误 + * @param {Event} event - 错误事件 + */ + const handleCoverError = (event) => { + event.target.style.display = 'none' + } + + /** + * 获取单个歌曲的封面 + * @param {Object} musicInfo - 音乐信息 + * @param {string} listId - 列表 ID + */ + const fetchCover = async(musicInfo, listId) => { + const musicId = musicInfo.id + if (fetchingPics.has(musicId)) return + if (coverUrls.has(musicId)) return + + fetchingPics.add(musicId) + try { + let picUrl + if (musicInfo.source === 'local') { + picUrl = await getLocalPicUrl({ musicInfo, listId, isRefresh: false }) + } else { + picUrl = await getOnlinePicUrl({ musicInfo, listId, isRefresh: false }) + } + if (picUrl) { + coverUrls.set(musicId, picUrl) + // 更新列表中的封面 + if (listValue) { + const musicItem = listValue.find(m => m.id === musicId) + if (musicItem) { + musicItem.meta.picUrl = picUrl + } + } + } + } catch (err) { + console.log('Failed to fetch cover:', err) + } finally { + fetchingPics.delete(musicId) + } + } + + /** + * 懒加载当前可见区域的封面 + * @param {HTMLElement} domContent - 滚动容器元素 + * @param {number} listItemHeight - 列表项高度 + * @param {string} listId - 列表 ID + */ + const loadVisibleCovers = (domContent, listItemHeight, listId) => { + if (!isShowCover || !listRefValue || !listValue) return + + const scrollTop = domContent?.scrollTop ?? 0 + const viewHeight = domContent?.clientHeight ?? 0 + const startIndex = Math.floor(scrollTop / listItemHeight) + const endIndex = Math.min(listValue.length, Math.ceil((scrollTop + viewHeight) / listItemHeight) + 5) + + // 加载可见区域的封面 + for (let i = startIndex; i < endIndex; i++) { + const item = listValue[i] + if (item && !coverUrls.has(item.id) && !fetchingPics.has(item.id)) { + if (!item.meta.picUrl) { + fetchCover(item, listId).catch(() => {}) + } + } + } + } + + /** + * 处理滚动事件(防抖) + * @param {Event} event - 滚动事件 + * @param {HTMLElement} domContent - 滚动容器元素 + * @param {number} listItemHeight - 列表项高度 + * @param {string} listId - 列表 ID + */ + const handleScroll = (event, domContent, listItemHeight, listId) => { + // 防抖处理 + if (scrollTimer) clearTimeout(scrollTimer) + scrollTimer = setTimeout(() => { + loadVisibleCovers(domContent, listItemHeight, listId) + }, 100) + } + + /** + * 列表加载完成后加载封面 + * @param {HTMLElement} domContent - 滚动容器元素 + * @param {number} listItemHeight - 列表项高度 + * @param {string} listId - 列表 ID + */ + const loadCoversOnListLoaded = (domContent, listItemHeight, listId) => { + if (isShowCover) { + setTimeout(() => { + loadVisibleCovers(domContent, listItemHeight, listId) + }, 100) + } + } + + onBeforeUnmount(() => { + if (scrollTimer) clearTimeout(scrollTimer) + }) + + return { + isShowCover, + coverSize, + getCoverUrl, + handleCoverError, + handleScroll, + loadCoversOnListLoaded, + setListRef, + setList, + } +} diff --git a/src/renderer/views/Setting/components/SettingBasic.vue b/src/renderer/views/Setting/components/SettingBasic.vue index 3a0552a289..371d4f00b0 100644 --- a/src/renderer/views/Setting/components/SettingBasic.vue +++ b/src/renderer/views/Setting/components/SettingBasic.vue @@ -105,6 +105,14 @@ dd id="setting_basic_playbar_progress_style_full" name="setting_basic_playbar_progress_style" need :model-value="appSetting['common.playBarProgressStyle']" value="full" :label="$t('setting__basic_playbar_progress_style_full')" @update:model-value="updateSetting({'common.playBarProgressStyle': $event})") +dd + h3#basic_list_cover {{ $t('setting__basic_list_cover') }} + div + .gap-top + base-checkbox(id="setting_list_show_cover" :model-value="appSetting['list.isShowCover']" :label="$t('setting__basic_list_show_cover')" @update:model-value="updateSetting({'list.isShowCover': $event})") + .gap-top(v-if="appSetting['list.isShowCover']") + base-selection.gap-left(:list="coverSizeList" :model-value="appSetting['list.coverSize']" item-key="id" item-name="label" @update:model-value="updateSetting({'list.coverSize': $event})") + ThemeSelectorModal(v-model="isShowThemeSelectorModal") ThemeEditModal(v-model="isShowThemeEditModal" :theme-id="editThemeId" @submit="handleRefreshTheme") play-timeout-modal(v-model="isShowPlayTimeoutModal") @@ -324,6 +332,15 @@ export default { ] }) + const coverSizeList = computed(() => { + return [ + { id: 32, label: t('setting__basic_list_cover_size_32px') }, + { id: 44, label: t('setting__basic_list_cover_size_44px') }, + { id: 56, label: t('setting__basic_list_cover_size_56px') }, + { id: 72, label: t('setting__basic_list_cover_size_72px') }, + ] + }) + return { appSetting, @@ -356,6 +373,7 @@ export default { editThemeId, handleEditTheme, fontSizeList, + coverSizeList, } }, } From 1bc217ff316dc415f7f372fa9eca4528fcd99832 Mon Sep 17 00:00:00 2001 From: Maybe <1913093102@qq.com> Date: Sat, 28 Feb 2026 17:27:39 +0800 Subject: [PATCH 02/16] =?UTF-8?q?=E6=8E=92=E8=A1=8C=E6=A6=9C=E5=92=8C?= =?UTF-8?q?=E6=AD=8C=E5=8D=95=E5=86=85=E6=98=BE=E7=A4=BA=E5=B0=81=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/material/OnlineList/index.vue | 108 +++++++++++++++++- src/renderer/views/List/MusicList/index.vue | 13 +-- 2 files changed, 111 insertions(+), 10 deletions(-) diff --git a/src/renderer/components/material/OnlineList/index.vue b/src/renderer/components/material/OnlineList/index.vue index fcdf52728d..9ae18762f3 100644 --- a/src/renderer/components/material/OnlineList/index.vue +++ b/src/renderer/components/material/OnlineList/index.vue @@ -7,6 +7,7 @@ # + {{ $t('music_name') }} {{ $t('music_singer') }} {{ $t('music_album') }} @@ -15,6 +16,7 @@ # + {{ $t('music_name') }} {{ $t('music_singer') }} {{ $t('music_album') }} @@ -32,7 +34,12 @@ @click="handleListItemClick($event, index)" @contextmenu="handleListItemRightClick($event, index)" >
{{ index + 1 }}
-
+
+
+ +
+
+
{{ item.name }} {{ $t('tag__lossless_24bit') }} {{ $t('tag__lossless') }} @@ -60,7 +67,12 @@ @click="handleListItemClick($event, index)" @contextmenu="handleListItemRightClick($event, index)" >
{{ index + 1 }}
-
+
+
+ +
+
+
{{ item.name }} {{ $t('tag__lossless_24bit') }} {{ $t('tag__lossless') }} @@ -101,7 +113,7 @@