mirror of
https://hubproxy.babadafafafafa.cn/https://github.com/lyswhut/lx-music-desktop.git
synced 2026-09-20 08:04:00 +08:00
Compare commits
15 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ad95d5091c | ||
|
|
a04cf3b307 | ||
|
|
f9f0e61c5b | ||
|
|
d2f5485996 | ||
|
|
e20b2844fb | ||
|
|
e9bc6a572b | ||
|
|
bb8d07274f | ||
|
|
950029884c | ||
|
|
7c78e557ed | ||
|
|
78eb5c48d7 | ||
|
|
96fd33065a | ||
|
|
abcbf5fa00 | ||
|
|
378174c277 | ||
|
|
39466f157c | ||
|
|
d1fa51c2bb |
2
.github/workflows/beta-pack.yml
vendored
2
.github/workflows/beta-pack.yml
vendored
@@ -132,7 +132,7 @@ jobs:
|
||||
|
||||
- name: Prepare win7 electron env
|
||||
run: |
|
||||
npm install electron@22
|
||||
npm install electron@22 better-sqlite3@12
|
||||
pip.exe install setuptools
|
||||
|
||||
- name: Build Package win7 Setup x64
|
||||
|
||||
2
.github/workflows/release.yml
vendored
2
.github/workflows/release.yml
vendored
@@ -112,7 +112,7 @@ jobs:
|
||||
|
||||
- name: Prepare win7 electron env
|
||||
run: |
|
||||
npm install electron@22
|
||||
npm install electron@22 better-sqlite3@12
|
||||
pip.exe install setuptools
|
||||
|
||||
- name: Release win7 package
|
||||
|
||||
41
CHANGELOG.md
41
CHANGELOG.md
@@ -6,6 +6,47 @@ Project versioning adheres to [Semantic Versioning](http://semver.org/).
|
||||
Commit convention is based on [Conventional Commits](http://conventionalcommits.org).
|
||||
Change log format is based on [Keep a Changelog](http://keepachangelog.com/).
|
||||
|
||||
## [2.12.6](https://github.com/lyswhut/lx-music-desktop/compare/v2.12.5...v2.12.6) - 2026-09-19
|
||||
|
||||
目前新项目 Any Listen 的桌面版、Web 版已实现 LX Music 的大部分功能,并额外支持 WebDAV 歌曲播放、WebDAV 数据同步、独立播放列表等功能。
|
||||
以后的开发精力将主要集中在新项目上,之前大家在 LX Music 提的功能我们也会考虑在新项目中添加。
|
||||
对于日常使用 LX Music 的人可以试试迁移到 Any Listen,若遇到任何问题可以发 issue 反馈。
|
||||
Any Listen 的项目地址为 https://github.com/any-listen/any-listen
|
||||
|
||||
### 优化
|
||||
|
||||
- 优化 tx 推荐歌单列表
|
||||
- 优化禁用透明窗口的窗口边框显示效果
|
||||
|
||||
### 修复
|
||||
|
||||
- 修复打开某些 kg 歌单时歌曲丢失的问题
|
||||
- 修复 Windows 7 无法启动的问题
|
||||
- 修复禁用透明窗口时按 F11 无法全屏的问题
|
||||
|
||||
## [2.12.5](https://github.com/lyswhut/lx-music-desktop/compare/v2.12.4...v2.12.5) - 2026-09-14
|
||||
|
||||
目前新项目 Any Listen 的桌面版、Web 版已实现 LX Music 的大部分功能,并额外支持 WebDAV 歌曲播放、WebDAV 数据同步、独立播放列表等功能。
|
||||
以后的开发精力将主要集中在新项目上,之前大家在 LX Music 提的功能我们也会考虑在新项目中添加。
|
||||
对于日常使用 LX Music 的人可以试试迁移到 Any Listen,若遇到任何问题可以发 issue 反馈。
|
||||
Any Listen 的项目地址为 https://github.com/any-listen/any-listen
|
||||
|
||||
### 修复
|
||||
|
||||
- 修复自定义主题编辑器的颜色选择器默认值显示异常的问题(#2957)
|
||||
- 修复下载的 MP3 文件内嵌歌曲数据失败的问题(#2959)
|
||||
|
||||
## [2.12.4](https://github.com/lyswhut/lx-music-desktop/compare/v2.12.3...v2.12.4) - 2026-09-12
|
||||
|
||||
目前新项目 Any Listen 的桌面版、Web 版已实现 LX Music 的大部分功能,并额外支持 WebDAV 歌曲播放、WebDAV 数据同步、独立播放列表等功能。
|
||||
以后的开发精力将主要集中在新项目上,之前大家在 LX Music 提的功能我们也会考虑在新项目中添加。
|
||||
对于日常使用 LX Music 的人可以试试迁移到 Any Listen,若遇到任何问题可以发 issue 反馈。
|
||||
Any Listen 的项目地址为 https://github.com/any-listen/any-listen
|
||||
|
||||
### 修复
|
||||
|
||||
- 修复自定义主题背景图片无法显示的问题
|
||||
|
||||
## [2.12.3](https://github.com/lyswhut/lx-music-desktop/compare/v2.12.2...v2.12.3) - 2026-09-12
|
||||
|
||||
目前新项目 Any Listen 的桌面版、Web 版已实现 LX Music 的大部分功能,并额外支持 WebDAV 歌曲播放、WebDAV 数据同步、独立播放列表等功能。
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -37,6 +37,7 @@ module.exports = merge(baseConfig, {
|
||||
new webpack.DefinePlugin({
|
||||
'process.env': {
|
||||
NODE_ENV: '"production"',
|
||||
BUILD_WIN7: `'${process.env.BUILD_WIN7}'`,
|
||||
},
|
||||
}),
|
||||
],
|
||||
|
||||
73
package-lock.json
generated
73
package-lock.json
generated
@@ -1,16 +1,16 @@
|
||||
{
|
||||
"name": "lx-music-desktop",
|
||||
"version": "2.12.3",
|
||||
"version": "2.12.6",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "lx-music-desktop",
|
||||
"version": "2.12.3",
|
||||
"version": "2.12.6",
|
||||
"hasInstallScript": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@simonwep/pickr": "^1.10.2",
|
||||
"@simonwep/pickr": "1.9.1",
|
||||
"better-sqlite3": "^13.0.3",
|
||||
"bufferutil": "^4.1.0",
|
||||
"comlink": "~4.3.1",
|
||||
@@ -50,7 +50,7 @@
|
||||
"css-loader": "^7.1.5",
|
||||
"css-minimizer-webpack-plugin": "^8.0.0",
|
||||
"del": "^6.1.1",
|
||||
"electron": "42.11.3",
|
||||
"electron": "42.11.6",
|
||||
"electron-builder": "^26.15.7",
|
||||
"electron-debug": "^3.2.0",
|
||||
"electron-devtools-installer": "github:lyswhut/electron-devtools-installer#64596d615c1fc891eefd8aef1dfcb2c87aaadf03",
|
||||
@@ -86,7 +86,7 @@
|
||||
"typescript": "5.9.3",
|
||||
"vue-eslint-parser": "^9.4.3",
|
||||
"vue-loader": "^17.4.2",
|
||||
"webpack": "5.107.2",
|
||||
"webpack": "5.106.2",
|
||||
"webpack-cli": "^7.2.3",
|
||||
"webpack-dev-server": "5.2.6",
|
||||
"webpack-hot-middleware": "github:lyswhut/webpack-hot-middleware#329c4375134b89d39da23a56a94db651247c74a1",
|
||||
@@ -1594,10 +1594,25 @@
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/@simonwep/pickr": {
|
||||
"version": "1.10.2",
|
||||
"resolved": "https://registry.npmjs.org/@simonwep/pickr/-/pickr-1.10.2.tgz",
|
||||
"integrity": "sha512-R7t4ETDcZrM7unKWaHy3aMDUV4WL1TRVEWfKjy/orO4tRlWEPGDcUYZ75f5b0Qrmr2m7YeL0DOcEH6/zY+n5vQ==",
|
||||
"license": "MIT"
|
||||
"version": "1.9.1",
|
||||
"resolved": "https://registry.npmjs.org/@simonwep/pickr/-/pickr-1.9.1.tgz",
|
||||
"integrity": "sha512-fR3qmfAcPf/HSFS7GEnTmZLM3+xERv1+jyMBbzT63ilRRM8veYjI7ELvkHHKk0/du3lHp7uh/FqatjM3646X1g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"core-js": "3.37.0",
|
||||
"nanopop": "2.4.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@simonwep/pickr/node_modules/core-js": {
|
||||
"version": "3.37.0",
|
||||
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.37.0.tgz",
|
||||
"integrity": "sha512-fu5vHevQ8ZG4og+LXug8ulUtVxjOcEYvifJr7L5Bfq9GOztVqsKd9/59hUk2ZSbCrS3BqUr3EpaYGIYzq7g3Ug==",
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/core-js"
|
||||
}
|
||||
},
|
||||
"node_modules/@sinclair/typebox": {
|
||||
"version": "0.34.52",
|
||||
@@ -1748,6 +1763,17 @@
|
||||
"@types/json-schema": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/eslint-scope": {
|
||||
"version": "3.7.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz",
|
||||
"integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/eslint": "*",
|
||||
"@types/estree": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/estree": {
|
||||
"version": "1.0.9",
|
||||
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz",
|
||||
@@ -5370,9 +5396,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/electron": {
|
||||
"version": "42.11.3",
|
||||
"resolved": "https://registry.npmjs.org/electron/-/electron-42.11.3.tgz",
|
||||
"integrity": "sha512-r/rC6BikQ2vEGQLhnHmFwFpvVPlWTc/rnHcYfJe4HDa5MEl00yhx72ffKw7zMf1WvAM2r2hcGJ3ZftuJRo0QaQ==",
|
||||
"version": "42.11.6",
|
||||
"resolved": "https://registry.npmjs.org/electron/-/electron-42.11.6.tgz",
|
||||
"integrity": "sha512-IgDsjQp+CYLnArfQbzzS2VmkRgHmSU1G9nGVOtSnFpkUYR8rkeAUSDO77qtqAPX1jgAGly1kgisUmwB9CbUHXw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -9789,6 +9815,12 @@
|
||||
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/nanopop": {
|
||||
"version": "2.4.2",
|
||||
"resolved": "https://registry.npmjs.org/nanopop/-/nanopop-2.4.2.tgz",
|
||||
"integrity": "sha512-NzOgmMQ+elxxHeIha+OG/Pv3Oc3p4RU2aBhwWwAqDpXrdTbtRylbRLQztLy8dMMwfl6pclznBdfUhccEn9ZIzw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/natural-compare": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
|
||||
@@ -15405,12 +15437,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/webpack": {
|
||||
"version": "5.107.2",
|
||||
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.107.2.tgz",
|
||||
"integrity": "sha512-v7RhXaJbpMlV0D7hC7lb2EbnxkoeUqf9qhKr6lozx3Q48pmFrqqNRmZFUEGmi7pSwm6fCQ2H1IjvCkHqdpVdjQ==",
|
||||
"version": "5.106.2",
|
||||
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.106.2.tgz",
|
||||
"integrity": "sha512-wGN3qcrBQIFmQ/c0AiOAQBvrZ5lmY8vbbMv4Mxfgzqd/B6+9pXtLo73WuS1dSGXM5QYY3hZnIbvx+K1xxe6FyA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/eslint-scope": "^3.7.7",
|
||||
"@types/estree": "^1.0.8",
|
||||
"@types/json-schema": "^7.0.15",
|
||||
"@webassemblyjs/ast": "^1.14.1",
|
||||
@@ -15420,20 +15453,20 @@
|
||||
"acorn-import-phases": "^1.0.3",
|
||||
"browserslist": "^4.28.1",
|
||||
"chrome-trace-event": "^1.0.2",
|
||||
"enhanced-resolve": "^5.22.0",
|
||||
"es-module-lexer": "^2.1.0",
|
||||
"enhanced-resolve": "^5.20.0",
|
||||
"es-module-lexer": "^2.0.0",
|
||||
"eslint-scope": "5.1.1",
|
||||
"events": "^3.2.0",
|
||||
"glob-to-regexp": "^0.4.1",
|
||||
"graceful-fs": "^4.2.11",
|
||||
"loader-runner": "^4.3.2",
|
||||
"loader-runner": "^4.3.1",
|
||||
"mime-db": "^1.54.0",
|
||||
"neo-async": "^2.6.2",
|
||||
"schema-utils": "^4.3.3",
|
||||
"tapable": "^2.3.0",
|
||||
"terser-webpack-plugin": "^5.5.0",
|
||||
"terser-webpack-plugin": "^5.3.17",
|
||||
"watchpack": "^2.5.1",
|
||||
"webpack-sources": "^3.5.0"
|
||||
"webpack-sources": "^3.3.4"
|
||||
},
|
||||
"bin": {
|
||||
"webpack": "bin/webpack.js"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "lx-music-desktop",
|
||||
"version": "2.12.3",
|
||||
"version": "2.12.6",
|
||||
"description": "一个免费的音乐查找助手",
|
||||
"main": "./dist/main.js",
|
||||
"scripts": {
|
||||
@@ -123,7 +123,7 @@
|
||||
"css-loader": "^7.1.5",
|
||||
"css-minimizer-webpack-plugin": "^8.0.0",
|
||||
"del": "^6.1.1",
|
||||
"electron": "42.11.3",
|
||||
"electron": "42.11.6",
|
||||
"electron-builder": "^26.15.7",
|
||||
"electron-debug": "^3.2.0",
|
||||
"electron-devtools-installer": "github:lyswhut/electron-devtools-installer#64596d615c1fc891eefd8aef1dfcb2c87aaadf03",
|
||||
@@ -159,14 +159,14 @@
|
||||
"typescript": "5.9.3",
|
||||
"vue-eslint-parser": "^9.4.3",
|
||||
"vue-loader": "^17.4.2",
|
||||
"webpack": "5.107.2",
|
||||
"webpack": "5.106.2",
|
||||
"webpack-cli": "^7.2.3",
|
||||
"webpack-dev-server": "5.2.6",
|
||||
"webpack-hot-middleware": "github:lyswhut/webpack-hot-middleware#329c4375134b89d39da23a56a94db651247c74a1",
|
||||
"webpack-merge": "^6.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@simonwep/pickr": "^1.10.2",
|
||||
"@simonwep/pickr": "1.9.1",
|
||||
"better-sqlite3": "^13.0.3",
|
||||
"bufferutil": "^4.1.0",
|
||||
"comlink": "~4.3.1",
|
||||
|
||||
@@ -5,17 +5,11 @@ Any Listen 的项目地址为 https://github.com/any-listen/any-listen
|
||||
|
||||
### 优化
|
||||
|
||||
- 优化kw歌单列表数据显示
|
||||
- 同步服务在连接时允许URL重定向
|
||||
- Linux 点击托盘时将显示主界面(#2840)
|
||||
- 优化自动换源歌曲匹配机制
|
||||
- 优化 tx 推荐歌单列表
|
||||
- 优化禁用透明窗口的窗口边框显示效果
|
||||
|
||||
### 修复
|
||||
|
||||
- 修复 kg 搜索结果显示问题 (#2782)
|
||||
- 修复某些情况下开放 API 获取到的音量为 0 的问题 (#2790)
|
||||
- 修复 mg 图片、歌词获取
|
||||
- 修复某些 tx 歌单打开失败的问题 (#1060, @ght-000)
|
||||
- 修复在某些情况下添加、移动歌曲时可能导致保存的歌曲顺序不对的问题(#2842)
|
||||
- 修复歌词标签解析格式没有严格按照标准的问题(#2855)
|
||||
- 修复 tx 歌曲搜索失败的问题(#2848, @ikun0014)
|
||||
- 修复打开某些 kg 歌单时歌曲丢失的问题
|
||||
- 修复 Windows 7 无法启动的问题
|
||||
- 修复禁用透明窗口时按 F11 无法全屏的问题
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1,4 +1,5 @@
|
||||
import log from 'electron-log/node'
|
||||
import os from 'node:os'
|
||||
|
||||
|
||||
export const isLinux = process.platform == 'linux'
|
||||
@@ -13,7 +14,12 @@ export const getPlatform = (platform: NodeJS.Platform = process.platform) => {
|
||||
default: return 'linux'
|
||||
}
|
||||
}
|
||||
|
||||
export const getOSVersion = (): string => {
|
||||
const release = os.release()
|
||||
const versionMatch = /^(\d+)/.exec(release)
|
||||
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
|
||||
return versionMatch?.[1] || release
|
||||
}
|
||||
|
||||
// https://stackoverflow.com/a/53387532
|
||||
export function compareVer(currentVer: string, targetVer: string): -1 | 0 | 1 {
|
||||
|
||||
@@ -16,6 +16,7 @@ import registerModules from '@main/modules'
|
||||
// 初始化应用
|
||||
const init = () => {
|
||||
console.log('init')
|
||||
if (process.env.BUILD_WIN7 == 'true') import('./utils/winLegacy')
|
||||
void initAppSetting().then(() => {
|
||||
registerModules()
|
||||
global.lx.event_app.app_inited()
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { BrowserWindow, dialog, session } from 'electron'
|
||||
import path from 'node:path'
|
||||
import { createTaskBarButtons, getWindowSizeInfo } from './utils'
|
||||
import { getPlatform, isLinux, isWin } from '@common/utils'
|
||||
import { getOSVersion, getPlatform, isLinux, isMac, isWin } from '@common/utils'
|
||||
import { getProxy, openDevTools as handleOpenDevTools } from '@main/utils'
|
||||
import { mainSend } from '@common/mainIpc'
|
||||
import { sendFocus, sendTaskbarButtonClick } from './rendererEvent'
|
||||
@@ -40,6 +40,19 @@ const winEvent = () => {
|
||||
browserWindow.on('blur', () => {
|
||||
global.lx.event_app.main_window_blur()
|
||||
})
|
||||
browserWindow.on('enter-full-screen', () => {
|
||||
global.lx.event_app.main_window_fullscreen(true)
|
||||
})
|
||||
browserWindow.on('leave-full-screen', () => {
|
||||
global.lx.event_app.main_window_fullscreen(false)
|
||||
|
||||
// macOS needs here to set resizable to false after exiting full screen
|
||||
if (isMac) {
|
||||
if (browserWindow?.resizable) {
|
||||
browserWindow.setResizable(false)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
browserWindow.once('ready-to-show', () => {
|
||||
if (!global.envParams.cmdParams.hidden) {
|
||||
@@ -107,7 +120,7 @@ export const createWindow = () => {
|
||||
browserWindow = new BrowserWindow(options)
|
||||
|
||||
const winURL = process.env.NODE_ENV !== 'production' ? 'http://localhost:9080' : `file://${path.join(encodePath(__dirname), 'index.html')}`
|
||||
void browserWindow.loadURL(winURL + `?os=${getPlatform()}&dt=${global.envParams.cmdParams.dt}&dark=${shouldUseDarkColors}&theme=${encodeURIComponent(JSON.stringify(theme))}`)
|
||||
void browserWindow.loadURL(winURL + `?os=${getPlatform()}&osver=${encodeURIComponent(getOSVersion())}&dt=${global.envParams.cmdParams.dt}&dark=${shouldUseDarkColors}&theme=${encodeURIComponent(JSON.stringify(theme))}`)
|
||||
|
||||
winEvent()
|
||||
|
||||
@@ -228,13 +241,17 @@ export const toggleDevTools = () => {
|
||||
|
||||
export const setFullScreen = (isFullscreen: boolean): boolean => {
|
||||
if (!browserWindow) return false
|
||||
if (isLinux) { // linux 需要先设置为可调整窗口大小才能全屏
|
||||
// https://github.com/any-listen/any-listen/issues/190
|
||||
// in electron ^41.2.0, windows -dt mode need to set resizable to true before setting full screen
|
||||
if (!!global.envParams.cmdParams.dt || isLinux) {
|
||||
// linux 需要先设置为可调整窗口大小才能全屏
|
||||
if (isFullscreen) {
|
||||
browserWindow.setResizable(isFullscreen)
|
||||
browserWindow.setFullScreen(isFullscreen)
|
||||
} else {
|
||||
browserWindow.setFullScreen(isFullscreen)
|
||||
browserWindow.setResizable(isFullscreen)
|
||||
// windows/linux need to set resizable to true after exiting full screen
|
||||
if (!isMac) browserWindow.setResizable(isFullscreen)
|
||||
}
|
||||
} else {
|
||||
browserWindow.setFullScreen(isFullscreen)
|
||||
|
||||
@@ -263,7 +263,7 @@ export const getTheme = () => {
|
||||
theme.config.extInfo['--background-image'] =
|
||||
isUrl(theme.config.extInfo['--background-image'])
|
||||
? `url(${theme.config.extInfo['--background-image']})`
|
||||
: `url(file:///${encodePath(joinPath(global.lxDataPath, 'theme_images', theme.config.extInfo['--background-image']))})`
|
||||
: `url(${encodePath(joinPath(global.lxDataPath, 'theme_images', theme.config.extInfo['--background-image']))})`
|
||||
}
|
||||
} else {
|
||||
themeId = global.lx.appSetting['theme.id'] == 'auto' && shouldUseDarkColors ? 'black' : 'green'
|
||||
|
||||
44
src/main/utils/winLegacy.ts
Normal file
44
src/main/utils/winLegacy.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
import os from 'node:os'
|
||||
|
||||
import { dialog } from 'electron'
|
||||
import { STORE_NAMES } from '@common/constants'
|
||||
import getStore from '@main/utils/store'
|
||||
import { openUrl } from '@common/utils/electron'
|
||||
|
||||
|
||||
const showWinLegacyMessage = () => {
|
||||
if (process.platform !== 'win32') return
|
||||
const storeKey = 'winLegacyMessageShown'
|
||||
const dataStore = getStore(STORE_NAMES.DATA)
|
||||
const count = dataStore.get<number>(storeKey) || 0
|
||||
if (count > 2) return
|
||||
const osVersion = os.release()
|
||||
const majorVersion = parseInt(osVersion.split('.')[0], 10)
|
||||
const isOldWindows = majorVersion < 10
|
||||
|
||||
if (isOldWindows) {
|
||||
const result = dialog.showMessageBoxSync({
|
||||
type: 'warning',
|
||||
title: 'Windows 旧版提示',
|
||||
message: '您正在使用专为旧版 Windows 准备的 LX Music,它仅用于实在无法升级到新版系统的用户。\n该版本缺乏安全更新,可能存在安全风险,并且功能未经测试,可能存在兼容性问题。\n\n如果您的设备支持 Windows 10 或更高版本,强烈建议升级系统,切换到标准版本的 LX Music,以获得更好的安全性和性能。',
|
||||
buttons: ['知道了'],
|
||||
})
|
||||
if (result === 0) {
|
||||
dataStore.set(storeKey, count + 1)
|
||||
}
|
||||
} else {
|
||||
const result = dialog.showMessageBoxSync({
|
||||
type: 'warning',
|
||||
title: '您正在使用旧版',
|
||||
message: '您正在使用专为旧版 Windows 准备的 LX Music,它仅用于实在无法升级到新版系统的用户,但您的系统似乎在标准版的支持范围内,为了获得最佳体验,请切换到 LX Music 的标准版本。\n\n注意:当前版本缺乏安全更新,可能存在安全风险,并且功能未经测试,可能存在兼容性问题。',
|
||||
buttons: ['跳转新版发布页', '知道了'],
|
||||
})
|
||||
if (result === 0) {
|
||||
void openUrl('https://github.com/lyswhut/lx-music-desktop/releases')
|
||||
} else if (result === 1) {
|
||||
dataStore.set('winLegacyMessageShown', count + 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
showWinLegacyMessage()
|
||||
@@ -99,8 +99,11 @@ body {
|
||||
.disableTransparent {
|
||||
background-color: var(--color-content-background);
|
||||
|
||||
#body {
|
||||
border: 1Px solid var(--color-primary-light-500);
|
||||
&.linux #body {
|
||||
border: 1px solid var(--color-primary-light-500);
|
||||
}
|
||||
&.windows:not(.windows-11, .fullscreen) #body {
|
||||
border-top: 1px solid #aaa;
|
||||
}
|
||||
|
||||
#right {
|
||||
|
||||
@@ -15,31 +15,35 @@
|
||||
<div id="root" style="display: none;">
|
||||
</div>
|
||||
<script>
|
||||
const formatLang = (lang = 'en') => {
|
||||
if (lang === 'zh-cn') return 'zh-Hans'
|
||||
if (lang === 'zh-tw') return 'zh-Hant'
|
||||
return lang.split('-')[0]
|
||||
}
|
||||
window.setLang = (lang = navigator.language.toLocaleLowerCase()) => {
|
||||
document.documentElement.setAttribute('lang', formatLang(lang))
|
||||
}
|
||||
window.setLang()
|
||||
document.documentElement.classList.add(/os=(\w+)/.exec(window.location.search)[1])
|
||||
window.shouldUseDarkColors = /dark=true/.test(window.location.search)
|
||||
window.dt = /dt=true/.test(window.location.search)
|
||||
document.documentElement.classList.add(window.dt ? 'disableTransparent' : 'transparent')
|
||||
(() => {
|
||||
const formatLang = (lang = 'en') => {
|
||||
if (lang === 'zh-cn') return 'zh-Hans'
|
||||
if (lang === 'zh-tw') return 'zh-Hant'
|
||||
return lang.split('-')[0]
|
||||
}
|
||||
window.setLang = (lang = navigator.language.toLocaleLowerCase()) => {
|
||||
document.documentElement.setAttribute('lang', formatLang(lang))
|
||||
}
|
||||
window.setLang()
|
||||
const os = /os=(\w+)/.exec(window.location.search)?.[1]
|
||||
const osver = decodeURIComponent(/osver=([^&]+)/.exec(window.location.search)?.[1] || '')
|
||||
document.documentElement.classList.add(os, `${os}-${osver}`)
|
||||
window.shouldUseDarkColors = /dark=true/.test(window.location.search)
|
||||
window.dt = /dt=true/.test(window.location.search)
|
||||
document.documentElement.classList.add(window.dt ? 'disableTransparent' : 'transparent')
|
||||
|
||||
window.dom_style = document.createElement('style')
|
||||
window.dom_style = document.createElement('style')
|
||||
|
||||
window.setTheme = colors => {
|
||||
window.dom_style.innerText = `:root {${(Object.entries(colors)).map(([key, value]) => `${key}:${value};`).join('')}}`
|
||||
}
|
||||
const applyThemeColor = (theme) => {
|
||||
theme = JSON.parse(decodeURIComponent(theme))
|
||||
window.setTheme(theme.colors)
|
||||
document.body.appendChild(window.dom_style)
|
||||
}
|
||||
if (/theme=(.+)(#|$)/.test(window.location.search)) applyThemeColor(RegExp.$1)
|
||||
window.setTheme = colors => {
|
||||
window.dom_style.innerText = `:root {${(Object.entries(colors)).map(([key, value]) => `${key}:${value};`).join('')}}`
|
||||
}
|
||||
const applyThemeColor = (theme) => {
|
||||
theme = JSON.parse(decodeURIComponent(theme))
|
||||
window.setTheme(theme.colors)
|
||||
document.body.appendChild(window.dom_style)
|
||||
}
|
||||
if (/theme=(.+)(#|$)/.test(window.location.search)) applyThemeColor(RegExp.$1)
|
||||
})()
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -18,7 +18,7 @@ export const assertApiSupport = (source: LX.Source): boolean => {
|
||||
export const buildBgUrl = (originUrl: string, dataPath: string): string => {
|
||||
return isUrl(originUrl)
|
||||
? `url(${originUrl})`
|
||||
: `url(file:///${encodePath(joinPath(dataPath, originUrl).replaceAll('\\', '/'))})`
|
||||
: `url(${encodePath(joinPath(dataPath, originUrl).replaceAll('\\', '/'))})`
|
||||
}
|
||||
|
||||
export const getThemes = (callback: (themeInfo: LX.ThemeInfo) => void) => {
|
||||
|
||||
@@ -384,8 +384,10 @@ export default {
|
||||
},
|
||||
})
|
||||
if (!songInfo.list) {
|
||||
if (songInfo.global_collection_id) return this.getUserListDetail2(songInfo.global_collection_id)
|
||||
else return this.getUserListDetail4(songInfo, chain, page).catch(() => this.getUserListDetail5(chain))
|
||||
if (songInfo.global_collection_id) {
|
||||
return this.getListDetailByGcidChain(songInfo.global_collection_id, chain)
|
||||
.catch(() => this.getUserListDetail2(songInfo.global_collection_id))
|
||||
} else return this.getUserListDetail4(songInfo, chain, page).catch(() => this.getUserListDetail5(chain))
|
||||
}
|
||||
let list = await this.getMusicInfos(songInfo.list)
|
||||
// console.log(info, songInfo)
|
||||
@@ -490,6 +492,53 @@ export default {
|
||||
}
|
||||
return Promise.all(tasks).then(([...datas]) => datas.flat())
|
||||
},
|
||||
async getListDetailByGcidChain(id, chain) {
|
||||
const params = 'srcappid=2919&clientver=20000&clienttime=1789566751657&mid=1789566751657&uuid=1789566751657&dfid=-&listid=15&type=0&pagesize=50&global_collection_id=' + id + '&page=1&share_type=collect&appid=1058&chain=' + chain
|
||||
const data = await this.createHttp(`https://m3ws.kugou.com/v2/zlist/list?${params}&signature=${signatureParams(params, 'web')}`, {
|
||||
headers: {
|
||||
mid: '1586163263991',
|
||||
Referer: 'https://m3ws.kugou.com/share/index.php',
|
||||
'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1',
|
||||
dfid: '-',
|
||||
clienttime: '1586163263991',
|
||||
},
|
||||
})
|
||||
const info = data.info[0]
|
||||
if (!info) throw new Error('get list error')
|
||||
let tasks = [Promise.resolve(data.list.info)]
|
||||
let page = 1
|
||||
let totalPage = Math.ceil(info.count / 50)
|
||||
while (page < totalPage) {
|
||||
const limit = 50
|
||||
page += 1
|
||||
const params = 'srcappid=2919&clientver=20000&clienttime=1789566751657&mid=1789566751657&uuid=1789566751657&dfid=-&listid=15&type=0&pagesize=' + limit + '&global_collection_id=' + id + '&page=' + page + '&share_type=collect&appid=1058&chain=' + chain
|
||||
tasks.push(this.createHttp(`https://m3ws.kugou.com/v2/zlist/list?${params}&signature=${signatureParams(params, 'web')}`, {
|
||||
headers: {
|
||||
mid: '1586163263991',
|
||||
Referer: 'https://m3ws.kugou.com/share/index.php',
|
||||
'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1',
|
||||
dfid: '-',
|
||||
clienttime: '1586163263991',
|
||||
},
|
||||
}).then(data => data.list.info))
|
||||
}
|
||||
const hashs = await Promise.all(tasks).then(([...datas]) => datas.flat())
|
||||
let list = await this.getMusicInfos(hashs)
|
||||
return {
|
||||
list,
|
||||
page: 1,
|
||||
limit: this.listDetailLimit,
|
||||
total: info.count,
|
||||
source: 'kg',
|
||||
info: {
|
||||
name: info.name,
|
||||
img: info.pic && info.pic.replace('{size}', 240),
|
||||
desc: info.intro,
|
||||
author: info.list_create_username,
|
||||
// play_count: formatPlayCount(info.playcount),
|
||||
},
|
||||
}
|
||||
},
|
||||
async getUserListDetail2(global_collection_id) {
|
||||
let id = global_collection_id
|
||||
if (id.length > 1000) throw new Error('get list error')
|
||||
@@ -613,7 +662,10 @@ export default {
|
||||
async getUserListDetail(link, page, retryNum = 0) {
|
||||
if (retryNum > 3) return Promise.reject(new Error('link try max num'))
|
||||
if (link.includes('#')) link = link.replace(/#.*$/, '')
|
||||
if (link.includes('global_collection_id')) return this.getUserListDetail2(link.replace(/^.*?global_collection_id=(\w+)(?:&.*$|#.*$|$)/, '$1'))
|
||||
if (link.includes('global_collection_id') && link.includes('chain')) {
|
||||
return this.getListDetailByGcidChain(link.replace(/^.*?global_collection_id=(\w+)(?:&.*$|#.*$|$)/, '$1'), link.replace(/^.*?chain=(\w+)(?:&.*$|#.*$|$)/, '$1'))
|
||||
}
|
||||
if (link.includes('chain=')) return this.getUserListDetail3(link.replace(/^.*?chain=(\w+)(?:&.*$|#.*$|$)/, '$1'), page)
|
||||
if (link.includes('gcid_')) {
|
||||
let gcid = link.match(/gcid_\w+/)?.[0]
|
||||
if (gcid) {
|
||||
@@ -621,7 +673,6 @@ export default {
|
||||
if (global_collection_id) return this.getUserListDetail2(global_collection_id)
|
||||
}
|
||||
}
|
||||
if (link.includes('chain=')) return this.getUserListDetail3(link.replace(/^.*?chain=(\w+)(?:&.*$|#.*$|$)/, '$1'), page)
|
||||
if (link.includes('.html')) {
|
||||
if (link.includes('zlist.html')) {
|
||||
link = link.replace(/^(.*)zlist\.html/, 'https://m3ws.kugou.com/zlist/list')
|
||||
@@ -632,6 +683,7 @@ export default {
|
||||
}
|
||||
} else if (!link.includes('song.html')) return this.getUserListDetail3(link.replace(/.+\/(\w+).html(?:\?.*|&.*$|#.*$|$)/, '$1'), page)
|
||||
}
|
||||
if (link.includes('global_collection_id')) return this.getUserListDetail2(link.replace(/^.*?global_collection_id=(\w+)(?:&.*$|#.*$|$)/, '$1'))
|
||||
|
||||
const requestObj_listDetailLink = httpFetch(link, {
|
||||
headers: {
|
||||
@@ -643,16 +695,18 @@ export default {
|
||||
// console.log(body, location)
|
||||
if (statusCode > 400) return this.getUserListDetail(link, page, ++retryNum)
|
||||
if (location) {
|
||||
if (location.includes('global_collection_id') && location.includes('chain')) {
|
||||
return this.getListDetailByGcidChain(location.replace(/^.*?global_collection_id=(\w+)(?:&.*$|#.*$|$)/, '$1'), location.replace(/^.*?chain=(\w+)(?:&.*$|#.*$|$)/, '$1'))
|
||||
}
|
||||
// console.log(location)
|
||||
if (location.includes('global_collection_id')) return this.getUserListDetail2(location.replace(/^.*?global_collection_id=(\w+)(?:&.*$|#.*$|$)/, '$1'))
|
||||
if (location.includes('chain=')) return this.getUserListDetail3(location.replace(/^.*?chain=(\w+)(?:&.*$|#.*$|$)/, '$1'), page)
|
||||
if (location.includes('gcid_')) {
|
||||
let gcid = link.match(/gcid_\w+/)?.[0]
|
||||
let gcid = location.match(/gcid_\w+/)?.[0]
|
||||
if (gcid) {
|
||||
const global_collection_id = await this.decodeGcid(gcid)
|
||||
if (global_collection_id) return this.getUserListDetail2(global_collection_id)
|
||||
}
|
||||
}
|
||||
if (location.includes('chain=')) return this.getUserListDetail3(location.replace(/^.*?chain=(\w+)(?:&.*$|#.*$|$)/, '$1'), page)
|
||||
if (location.includes('.html')) {
|
||||
if (location.includes('zlist.html')) {
|
||||
let link = location.replace(/^(.*)zlist\.html/, 'https://m3ws.kugou.com/zlist/list')
|
||||
@@ -664,6 +718,7 @@ export default {
|
||||
return this.getUserListDetail(link, page, ++retryNum)
|
||||
} else return this.getUserListDetail3(location.replace(/.+\/(\w+).html(?:\?.*|&.*$|#.*$|$)/, '$1'), page)
|
||||
}
|
||||
if (location.includes('global_collection_id')) return this.getUserListDetail2(location.replace(/^.*?global_collection_id=(\w+)(?:&.*$|#.*$|$)/, '$1'))
|
||||
// console.log('location', location)
|
||||
return this.getUserListDetail(location, page, ++retryNum)
|
||||
}
|
||||
|
||||
@@ -10,9 +10,13 @@ export default {
|
||||
limit_song: 100000,
|
||||
successCode: 0,
|
||||
sortList: [
|
||||
{
|
||||
name: '推荐',
|
||||
id: -1,
|
||||
},
|
||||
{
|
||||
name: '最热',
|
||||
id: 5,
|
||||
id: 3,
|
||||
},
|
||||
{
|
||||
name: '最新',
|
||||
@@ -30,10 +34,9 @@ export default {
|
||||
},
|
||||
tagsUrl: 'https://u.y.qq.com/cgi-bin/musicu.fcg?loginUin=0&hostUin=0&format=json&inCharset=utf-8&outCharset=utf-8¬ice=0&platform=wk_v15.json&needNewCode=0&data=%7B%22tags%22%3A%7B%22method%22%3A%22get_all_categories%22%2C%22param%22%3A%7B%22qq%22%3A%22%22%7D%2C%22module%22%3A%22playlist.PlaylistAllCategoriesServer%22%7D%7D',
|
||||
hotTagUrl: 'https://c.y.qq.com/node/pc/wk_v15/category_playlist.html',
|
||||
getListUrl(sortId, id, page) {
|
||||
if (id) {
|
||||
id = parseInt(id)
|
||||
return `https://u.y.qq.com/cgi-bin/musicu.fcg?loginUin=0&hostUin=0&format=json&inCharset=utf-8&outCharset=utf-8¬ice=0&platform=wk_v15.json&needNewCode=0&data=${encodeURIComponent(JSON.stringify({
|
||||
getListUrl(id, page) {
|
||||
id = parseInt(id)
|
||||
return `https://u.y.qq.com/cgi-bin/musicu.fcg?loginUin=0&hostUin=0&format=json&inCharset=utf-8&outCharset=utf-8¬ice=0&platform=wk_v15.json&needNewCode=0&data=${encodeURIComponent(JSON.stringify({
|
||||
comm: { cv: 1602, ct: 20 },
|
||||
playlist: {
|
||||
method: 'get_category_content',
|
||||
@@ -48,15 +51,14 @@ export default {
|
||||
module: 'playlist.PlayListCategoryServer',
|
||||
},
|
||||
}))}`
|
||||
}
|
||||
return `https://u.y.qq.com/cgi-bin/musicu.fcg?loginUin=0&hostUin=0&format=json&inCharset=utf-8&outCharset=utf-8¬ice=0&platform=wk_v15.json&needNewCode=0&data=${encodeURIComponent(JSON.stringify({
|
||||
comm: { cv: 1602, ct: 20 },
|
||||
playlist: {
|
||||
method: 'get_playlist_by_tag',
|
||||
param: { id: 10000000, sin: this.limit_list * (page - 1), size: this.limit_list, order: sortId, cur_page: page },
|
||||
module: 'playlist.PlayListPlazaServer',
|
||||
},
|
||||
}))}`
|
||||
// return `https://u.y.qq.com/cgi-bin/musicu.fcg?loginUin=0&hostUin=0&format=json&inCharset=utf-8&outCharset=utf-8&data=${encodeURIComponent(JSON.stringify({
|
||||
// comm: { cv: 1602, ct: 20 },
|
||||
// playlist: {
|
||||
// method: 'get_playlist_by_tag',
|
||||
// param: { id: 10000000, sin: this.limit_list * (page - 1), size: this.limit_list, order: sortId, cur_page: page },
|
||||
// module: 'playlist.PlayListPlazaServer',
|
||||
// },
|
||||
// }))}`
|
||||
},
|
||||
getListDetailUrl(id) {
|
||||
return `https://c.y.qq.com/qzone/fcg-bin/fcg_ucc_getcdinfo_byids_cp.fcg?type=1&json=1&utf8=1&onlysong=0&new_format=1&disstid=${id}&loginUin=0&hostUin=0&format=json&inCharset=utf8&outCharset=utf-8¬ice=0&platform=yqq.json&needNewCode=0`
|
||||
@@ -112,41 +114,85 @@ export default {
|
||||
}))
|
||||
},
|
||||
|
||||
async getRecommendList(page) {
|
||||
const { body } = await httpFetch(
|
||||
`https://u.y.qq.com/cgi-bin/musicu.fcg?loginUin=0&hostUin=0&format=json&inCharset=utf-8&outCharset=utf-8¬ice=0&platform=wk_v15.json&needNewCode=0&data=${encodeURIComponent(
|
||||
JSON.stringify({
|
||||
comm: { cv: 1602, ct: 20 },
|
||||
playlist: {
|
||||
module: 'music.playlist.PlaylistSquare',
|
||||
method: 'GetRecommendWhole',
|
||||
param: {
|
||||
IsReqFeed: true,
|
||||
FeedReq: {
|
||||
From: (page - 1) * this.limit_list,
|
||||
Size: this.limit_list,
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
)}`,
|
||||
).promise
|
||||
if (body.code !== this.successCode) throw new Error('tx getRecommendList failed')
|
||||
return {
|
||||
list:
|
||||
body.playlist.data.FeedRsp.List?.map(({ Playlist }) => ({
|
||||
play_count: formatPlayCount(Playlist.basic.play_cnt),
|
||||
id: String(Playlist.basic.tid),
|
||||
author: decodeName(Playlist.basic.creator.nick),
|
||||
name: decodeName(Playlist.basic.title),
|
||||
time: Playlist.basic.modify_time ? dateFormat(Playlist.basic.modify_time * 1000, 'Y-M-D') : '',
|
||||
img: Playlist.basic.cover.medium_url || Playlist.basic.cover.default_url,
|
||||
total: Playlist.basic.song_cnt,
|
||||
desc: decodeName(Playlist.basic.desc).replace(/<br>/g, '\n'),
|
||||
source: 'tx',
|
||||
})) || [],
|
||||
total: body.playlist.data.FeedRsp.FromLimit,
|
||||
limit: this.limit_list,
|
||||
page,
|
||||
source: 'tx',
|
||||
}
|
||||
},
|
||||
|
||||
// 获取列表数据
|
||||
getList(sortId, tagId, page, tryNum = 0) {
|
||||
if (this._requestObj_list) this._requestObj_list.cancelHttp()
|
||||
if (tryNum > 2) return Promise.reject(new Error('try max num'))
|
||||
if (!tagId) {
|
||||
if (!tagId && sortId == -1) return this.getRecommendList(page)
|
||||
tagId = sortId
|
||||
}
|
||||
this._requestObj_list = httpFetch(
|
||||
this.getListUrl(sortId, tagId, page),
|
||||
this.getListUrl(tagId, page),
|
||||
)
|
||||
// console.log(this.getListUrl(sortId, tagId, page))
|
||||
return this._requestObj_list.promise.then(({ body }) => {
|
||||
if (body.code !== this.successCode) return this.getList(sortId, tagId, page, ++tryNum)
|
||||
return tagId ? this.filterList2(body.playlist.data, page) : this.filterList(body.playlist.data, page)
|
||||
return this.filterList(body.playlist.data, page)
|
||||
})
|
||||
},
|
||||
|
||||
filterList(data, page) {
|
||||
return {
|
||||
list: data.v_playlist.map(item => ({
|
||||
play_count: formatPlayCount(item.access_num),
|
||||
id: String(item.tid),
|
||||
author: item.creator_info.nick,
|
||||
name: item.title,
|
||||
time: item.modify_time ? dateFormat(item.modify_time * 1000, 'Y-M-D') : '',
|
||||
img: item.cover_url_medium,
|
||||
// grade: item.favorcnt / 10,
|
||||
total: item.song_ids?.length,
|
||||
desc: decodeName(item.desc).replace(/<br>/g, '\n'),
|
||||
source: 'tx',
|
||||
})),
|
||||
total: data.total,
|
||||
page,
|
||||
limit: this.limit_list,
|
||||
source: 'tx',
|
||||
}
|
||||
},
|
||||
filterList2({ content }, page) {
|
||||
// filterList(data, page) {
|
||||
// return {
|
||||
// list: data.v_playlist.map(item => ({
|
||||
// play_count: formatPlayCount(item.access_num),
|
||||
// id: String(item.tid),
|
||||
// author: item.creator_info.nick,
|
||||
// name: item.title,
|
||||
// time: item.modify_time ? dateFormat(item.modify_time * 1000, 'Y-M-D') : '',
|
||||
// img: item.cover_url_medium,
|
||||
// // grade: item.favorcnt / 10,
|
||||
// total: item.song_ids?.length,
|
||||
// desc: decodeName(item.desc).replace(/<br>/g, '\n'),
|
||||
// source: 'tx',
|
||||
// })),
|
||||
// total: data.total,
|
||||
// page,
|
||||
// limit: this.limit_list,
|
||||
// source: 'tx',
|
||||
// }
|
||||
// },
|
||||
filterList({ content }, page) {
|
||||
// console.log(content.v_item)
|
||||
return {
|
||||
list: content.v_item.map(({ basic }) => ({
|
||||
|
||||
Reference in New Issue
Block a user