├── .gitattributes ├── .gitignore ├── README.md ├── babel.config.js ├── cnpm ├── getMatadata.js ├── images with instructions in English ├── JRP6PZO4_RDBNH)E3(_LU32.png ├── QQ截图20240201123056.png ├── QQ截图20240201123651.png ├── QQ截图20240201123854.png ├── QQ截图20240201124035.png ├── QQ截图20240201124205.png ├── QQ截图20240201124741.png ├── QQ截图20240201125348.png ├── QQ截图20240201125659.png └── settings.txt ├── images ├── 截图20240104224403.png ├── 截图20240104224443.png ├── 截图20240104224513.png └── 截图20240104224537.png ├── index.html ├── jsconfig.json ├── main.js ├── npminstall-debug.log ├── package-lock.json ├── package.json ├── preload.js ├── public ├── favicon.ico └── index.html ├── src ├── App.vue ├── App2.vue ├── assets │ ├── EQ.png │ ├── add.png │ ├── addPlaylist.png │ ├── album.png │ ├── artist.png │ ├── choice.png │ ├── close.png │ ├── closeWindow.png │ ├── color.png │ ├── dLyric.png │ ├── defaultBack.png │ ├── delete.png │ ├── delete2.png │ ├── delete3.png │ ├── downVolume.png │ ├── file.png │ ├── folder.png │ ├── folder2.png │ ├── fullS.png │ ├── home.png │ ├── img.png │ ├── info.png │ ├── info2.png │ ├── library.png │ ├── logoImg.png │ ├── lrc.png │ ├── lrc2.png │ ├── match.png │ ├── maximize.png │ ├── mini.png │ ├── minimize.png │ ├── more.png │ ├── next.png │ ├── nextSongs.png │ ├── noVolume.png │ ├── onesong.png │ ├── order.png │ ├── pause.png │ ├── play.png │ ├── play2.png │ ├── playlist.png │ ├── playlist3.png │ ├── playlist4.png │ ├── prev.png │ ├── queue.png │ ├── random.png │ ├── rotate.png │ ├── search.png │ ├── set.png │ ├── spectrum.png │ ├── target.png │ ├── volume.png │ └── znone.png ├── components │ ├── Footer.vue │ ├── Header.vue │ ├── HowlerPlayer.vue │ └── WebAudioApi.js ├── main.js ├── mixin.js ├── pages │ ├── AlbumDetail.vue │ ├── Albums.vue │ ├── ArtistDetail.vue │ ├── Artists.vue │ ├── Folders.vue │ ├── Home.vue │ ├── Library.vue │ ├── Playlists.vue │ ├── Search.vue │ ├── Settings.vue │ ├── SongsInFolder.vue │ └── SongsInPlaylist.vue ├── plugins.js ├── router │ └── index.js └── vuex │ └── store.js ├── vue.config.js └── yarn.lock /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | 5 | 6 | # local env files 7 | .env.local 8 | .env.*.local 9 | 10 | # Log files 11 | npm-debug.log* 12 | yarn-debug.log* 13 | yarn-error.log* 14 | pnpm-debug.log* 15 | 16 | # Editor directories and files 17 | .idea 18 | .vscode 19 | *.suo 20 | *.ntvs* 21 | *.njsproj 22 | *.sln 23 | *.sw? 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Sonorbit - 基于 Electron 和 Vue2 的本地音乐播放器。 2 | 3 | ## 特点 4 | 5 | - 集现代与复古为一体的 UI ,简约美观 6 | - 匹配下载网易云歌词和封面(可精确匹配某一首歌) 7 | - 识别内嵌歌词和本地 lrc 文件,自定义歌词文件夹 8 | - 丰富且可自定义的快捷键 9 | - 流畅的操作动效 10 | - 桌面歌词 11 | - 均衡器 12 | - 标签属性编辑 13 | - 可视化频谱(较耗性能) 14 | 15 | ## 运行 16 | 17 | - npm install 18 | - npm run serve 19 | - npm start 20 | 21 | ## 打包 22 | 23 | - 打包过程较为复杂,请私下咨询我 24 | 25 | 26 | 27 | ## 图片展示 28 | 29 | ![shortcut1](images/截图20240104224403.png) 30 | 31 | ![shortcut2](images/截图20240104224443.png) 32 | 33 | ![shortcut3](images/截图20240104224513.png) 34 | 35 | ![shortcut4](images/截图20240104224537.png) 36 | 37 | 38 | 39 | ## 视频展示 40 | 41 | b站地址:https://www.bilibili.com/video/BV1or4y1X7hc/ 42 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | '@vue/cli-plugin-babel/preset' 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /cnpm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Violexjj/Loop-Sound-Player/a353aab42f5586acb7ce115da2d974b7f48edfb8/cnpm -------------------------------------------------------------------------------- /getMatadata.js: -------------------------------------------------------------------------------- 1 | const mm = require('music-metadata'); 2 | const path = require('path'); 3 | 4 | const audioFilePath = path.join(__dirname, process.argv[2]); 5 | 6 | mm.parseFile(audioFilePath) 7 | .then(metadata => { 8 | process.send({ metadata }); 9 | }) 10 | .catch(error => { 11 | process.send({ error: error.message }); 12 | }); 13 | -------------------------------------------------------------------------------- /images with instructions in English/JRP6PZO4_RDBNH)E3(_LU32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Violexjj/Loop-Sound-Player/a353aab42f5586acb7ce115da2d974b7f48edfb8/images with instructions in English/JRP6PZO4_RDBNH)E3(_LU32.png -------------------------------------------------------------------------------- /images with instructions in English/QQ截图20240201123056.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Violexjj/Loop-Sound-Player/a353aab42f5586acb7ce115da2d974b7f48edfb8/images with instructions in English/QQ截图20240201123056.png -------------------------------------------------------------------------------- /images with instructions in English/QQ截图20240201123651.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Violexjj/Loop-Sound-Player/a353aab42f5586acb7ce115da2d974b7f48edfb8/images with instructions in English/QQ截图20240201123651.png -------------------------------------------------------------------------------- /images with instructions in English/QQ截图20240201123854.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Violexjj/Loop-Sound-Player/a353aab42f5586acb7ce115da2d974b7f48edfb8/images with instructions in English/QQ截图20240201123854.png -------------------------------------------------------------------------------- /images with instructions in English/QQ截图20240201124035.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Violexjj/Loop-Sound-Player/a353aab42f5586acb7ce115da2d974b7f48edfb8/images with instructions in English/QQ截图20240201124035.png -------------------------------------------------------------------------------- /images with instructions in English/QQ截图20240201124205.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Violexjj/Loop-Sound-Player/a353aab42f5586acb7ce115da2d974b7f48edfb8/images with instructions in English/QQ截图20240201124205.png -------------------------------------------------------------------------------- /images with instructions in English/QQ截图20240201124741.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Violexjj/Loop-Sound-Player/a353aab42f5586acb7ce115da2d974b7f48edfb8/images with instructions in English/QQ截图20240201124741.png -------------------------------------------------------------------------------- /images with instructions in English/QQ截图20240201125348.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Violexjj/Loop-Sound-Player/a353aab42f5586acb7ce115da2d974b7f48edfb8/images with instructions in English/QQ截图20240201125348.png -------------------------------------------------------------------------------- /images with instructions in English/QQ截图20240201125659.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Violexjj/Loop-Sound-Player/a353aab42f5586acb7ce115da2d974b7f48edfb8/images with instructions in English/QQ截图20240201125659.png -------------------------------------------------------------------------------- /images with instructions in English/settings.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Violexjj/Loop-Sound-Player/a353aab42f5586acb7ce115da2d974b7f48edfb8/images with instructions in English/settings.txt -------------------------------------------------------------------------------- /images/截图20240104224403.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Violexjj/Loop-Sound-Player/a353aab42f5586acb7ce115da2d974b7f48edfb8/images/截图20240104224403.png -------------------------------------------------------------------------------- /images/截图20240104224443.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Violexjj/Loop-Sound-Player/a353aab42f5586acb7ce115da2d974b7f48edfb8/images/截图20240104224443.png -------------------------------------------------------------------------------- /images/截图20240104224513.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Violexjj/Loop-Sound-Player/a353aab42f5586acb7ce115da2d974b7f48edfb8/images/截图20240104224513.png -------------------------------------------------------------------------------- /images/截图20240104224537.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Violexjj/Loop-Sound-Player/a353aab42f5586acb7ce115da2d974b7f48edfb8/images/截图20240104224537.png -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | electron创建圆角窗口附带阴影效果 6 | 20 | 21 | 22 |
圆角窗口+阴影特效
23 | 24 | 25 | -------------------------------------------------------------------------------- /jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "module": "esnext", 5 | "baseUrl": "./", 6 | "moduleResolution": "node", 7 | "paths": { 8 | "@/*": [ 9 | "src/*" 10 | ] 11 | }, 12 | "lib": [ 13 | "esnext", 14 | "dom", 15 | "dom.iterable", 16 | "scripthost" 17 | ] 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /npminstall-debug.log: -------------------------------------------------------------------------------- 1 | { 2 | root: 'D:\\Projects\\backups\\vue_pro', 3 | registry: 'https://registry.npm.taobao.org', 4 | pkgs: [], 5 | production: false, 6 | cacheStrict: false, 7 | cacheDir: 'C:\\Users\\30595\\.npminstall_tarball', 8 | env: { 9 | npm_config_registry: 'https://registry.npm.taobao.org', 10 | npm_config_argv: '{"remain":[],"cooked":["--fix-bug-versions","--china","--userconfig=C:\\\\Users\\\\30595\\\\.cnpmrc","--disturl=https://cdn.npmmirror.com/binaries/node","--registry=https://registry.npm.taobao.org"],"original":["--fix-bug-versions","--china","--userconfig=C:\\\\Users\\\\30595\\\\.cnpmrc","--disturl=https://cdn.npmmirror.com/binaries/node","--registry=https://registry.npm.taobao.org"]}', 11 | npm_config_user_agent: 'npminstall/7.9.0 npm/? node/v18.17.1 win32 x64', 12 | npm_config_cache: 'C:\\Users\\30595\\.npminstall_tarball', 13 | NODE: 'C:\\Program Files\\nodejs\\node.exe', 14 | npm_node_execpath: 'C:\\Program Files\\nodejs\\node.exe', 15 | npm_execpath: 'C:\\Users\\30595\\AppData\\Roaming\\npm\\node_modules\\cnpm\\node_modules\\npminstall\\bin\\install.js', 16 | npm_config_userconfig: 'C:\\Users\\30595\\.cnpmrc', 17 | npm_config_disturl: 'https://cdn.npmmirror.com/binaries/node', 18 | npm_config_r: 'https://registry.npm.taobao.org', 19 | COREPACK_NPM_REGISTRY: 'https://registry.npmmirror.com', 20 | EDGEDRIVER_CDNURL: 'https://npmmirror.com/mirrors/edgedriver', 21 | NODEJS_ORG_MIRROR: 'https://cdn.npmmirror.com/binaries/node', 22 | NVM_NODEJS_ORG_MIRROR: 'https://cdn.npmmirror.com/binaries/node', 23 | PHANTOMJS_CDNURL: 'https://cdn.npmmirror.com/binaries/phantomjs', 24 | CHROMEDRIVER_CDNURL: 'https://cdn.npmmirror.com/binaries/chromedriver', 25 | OPERADRIVER_CDNURL: 'https://cdn.npmmirror.com/binaries/operadriver', 26 | CYPRESS_DOWNLOAD_PATH_TEMPLATE: 'https://cdn.npmmirror.com/binaries/cypress/${version}/${platform}-${arch}/cypress.zip', 27 | ELECTRON_MIRROR: 'https://cdn.npmmirror.com/binaries/electron/', 28 | ELECTRON_BUILDER_BINARIES_MIRROR: 'https://cdn.npmmirror.com/binaries/electron-builder-binaries/', 29 | SASS_BINARY_SITE: 'https://cdn.npmmirror.com/binaries/node-sass', 30 | SWC_BINARY_SITE: 'https://cdn.npmmirror.com/binaries/node-swc', 31 | NWJS_URLBASE: 'https://cdn.npmmirror.com/binaries/nwjs/v', 32 | PUPPETEER_DOWNLOAD_HOST: 'https://cdn.npmmirror.com/binaries/chrome-for-testing', 33 | PUPPETEER_DOWNLOAD_BASE_URL: 'https://cdn.npmmirror.com/binaries/chrome-for-testing', 34 | PLAYWRIGHT_DOWNLOAD_HOST: 'https://cdn.npmmirror.com/binaries/playwright', 35 | SENTRYCLI_CDNURL: 'https://cdn.npmmirror.com/binaries/sentry-cli', 36 | SAUCECTL_INSTALL_BINARY_MIRROR: 'https://cdn.npmmirror.com/binaries/saucectl', 37 | RE2_DOWNLOAD_MIRROR: 'https://cdn.npmmirror.com/binaries/node-re2', 38 | RE2_DOWNLOAD_SKIP_PATH: 'true', 39 | PRISMA_ENGINES_MIRROR: 'https://cdn.npmmirror.com/binaries/prisma', 40 | npm_config_better_sqlite3_binary_host: 'https://cdn.npmmirror.com/binaries/better-sqlite3', 41 | npm_config_keytar_binary_host: 'https://cdn.npmmirror.com/binaries/keytar', 42 | npm_config_sharp_binary_host: 'https://cdn.npmmirror.com/binaries/sharp', 43 | npm_config_sharp_libvips_binary_host: 'https://cdn.npmmirror.com/binaries/sharp-libvips', 44 | npm_config_robotjs_binary_host: 'https://cdn.npmmirror.com/binaries/robotjs', 45 | npm_rootpath: 'D:\\Projects\\backups\\vue_pro', 46 | INIT_CWD: 'D:\\Projects\\backups\\vue_pro' 47 | }, 48 | binaryMirrors: { 49 | ENVS: { 50 | COREPACK_NPM_REGISTRY: 'https://registry.npmmirror.com', 51 | EDGEDRIVER_CDNURL: 'https://npmmirror.com/mirrors/edgedriver', 52 | NODEJS_ORG_MIRROR: 'https://cdn.npmmirror.com/binaries/node', 53 | NVM_NODEJS_ORG_MIRROR: 'https://cdn.npmmirror.com/binaries/node', 54 | PHANTOMJS_CDNURL: 'https://cdn.npmmirror.com/binaries/phantomjs', 55 | CHROMEDRIVER_CDNURL: 'https://cdn.npmmirror.com/binaries/chromedriver', 56 | OPERADRIVER_CDNURL: 'https://cdn.npmmirror.com/binaries/operadriver', 57 | CYPRESS_DOWNLOAD_PATH_TEMPLATE: 'https://cdn.npmmirror.com/binaries/cypress/${version}/${platform}-${arch}/cypress.zip', 58 | ELECTRON_MIRROR: 'https://cdn.npmmirror.com/binaries/electron/', 59 | ELECTRON_BUILDER_BINARIES_MIRROR: 'https://cdn.npmmirror.com/binaries/electron-builder-binaries/', 60 | SASS_BINARY_SITE: 'https://cdn.npmmirror.com/binaries/node-sass', 61 | SWC_BINARY_SITE: 'https://cdn.npmmirror.com/binaries/node-swc', 62 | NWJS_URLBASE: 'https://cdn.npmmirror.com/binaries/nwjs/v', 63 | PUPPETEER_DOWNLOAD_HOST: 'https://cdn.npmmirror.com/binaries/chrome-for-testing', 64 | PUPPETEER_DOWNLOAD_BASE_URL: 'https://cdn.npmmirror.com/binaries/chrome-for-testing', 65 | PLAYWRIGHT_DOWNLOAD_HOST: 'https://cdn.npmmirror.com/binaries/playwright', 66 | SENTRYCLI_CDNURL: 'https://cdn.npmmirror.com/binaries/sentry-cli', 67 | SAUCECTL_INSTALL_BINARY_MIRROR: 'https://cdn.npmmirror.com/binaries/saucectl', 68 | RE2_DOWNLOAD_MIRROR: 'https://cdn.npmmirror.com/binaries/node-re2', 69 | RE2_DOWNLOAD_SKIP_PATH: 'true', 70 | PRISMA_ENGINES_MIRROR: 'https://cdn.npmmirror.com/binaries/prisma', 71 | npm_config_better_sqlite3_binary_host: 'https://cdn.npmmirror.com/binaries/better-sqlite3', 72 | npm_config_keytar_binary_host: 'https://cdn.npmmirror.com/binaries/keytar', 73 | npm_config_sharp_binary_host: 'https://cdn.npmmirror.com/binaries/sharp', 74 | npm_config_sharp_libvips_binary_host: 'https://cdn.npmmirror.com/binaries/sharp-libvips', 75 | npm_config_robotjs_binary_host: 'https://cdn.npmmirror.com/binaries/robotjs' 76 | }, 77 | '@ali/s2': { host: 'https://cdn.npmmirror.com/binaries/looksgood-s2' }, 78 | sharp: { replaceHostFiles: [Array], replaceHostMap: [Object] }, 79 | '@tensorflow/tfjs-node': { 80 | replaceHostFiles: [Array], 81 | replaceHostRegExpMap: [Object], 82 | replaceHostMap: [Object] 83 | }, 84 | cypress: { 85 | host: 'https://cdn.npmmirror.com/binaries/cypress', 86 | newPlatforms: [Object] 87 | }, 88 | 'utf-8-validate': { 89 | host: 'https://cdn.npmmirror.com/binaries/utf-8-validate/v{version}' 90 | }, 91 | xprofiler: { 92 | remote_path: './xprofiler/v{version}/', 93 | host: 'https://cdn.npmmirror.com/binaries' 94 | }, 95 | leveldown: { host: 'https://cdn.npmmirror.com/binaries/leveldown/v{version}' }, 96 | couchbase: { host: 'https://cdn.npmmirror.com/binaries/couchbase/v{version}' }, 97 | gl: { host: 'https://cdn.npmmirror.com/binaries/gl/v{version}' }, 98 | sqlite3: { 99 | host: 'https://cdn.npmmirror.com/binaries/sqlite3', 100 | remote_path: 'v{version}' 101 | }, 102 | '@journeyapps/sqlcipher': { host: 'https://cdn.npmmirror.com/binaries' }, 103 | grpc: { 104 | host: 'https://cdn.npmmirror.com/binaries', 105 | remote_path: '{name}/v{version}' 106 | }, 107 | 'grpc-tools': { host: 'https://cdn.npmmirror.com/binaries' }, 108 | wrtc: { 109 | host: 'https://cdn.npmmirror.com/binaries', 110 | remote_path: '{name}/v{version}' 111 | }, 112 | fsevents: { host: 'https://cdn.npmmirror.com/binaries/fsevents' }, 113 | nodejieba: { host: 'https://cdn.npmmirror.com/binaries/nodejieba' }, 114 | canvas: { host: 'https://cdn.npmmirror.com/binaries/canvas' }, 115 | 'skia-canvas': { host: 'https://cdn.npmmirror.com/binaries/skia-canvas' }, 116 | 'flow-bin': { 117 | replaceHost: 'https://github.com/facebook/flow/releases/download/v', 118 | host: 'https://cdn.npmmirror.com/binaries/flow/v' 119 | }, 120 | 'jpegtran-bin': { 121 | replaceHost: [Array], 122 | host: 'https://cdn.npmmirror.com/binaries/jpegtran-bin' 123 | }, 124 | 'cwebp-bin': { 125 | replaceHost: [Array], 126 | host: 'https://cdn.npmmirror.com/binaries/cwebp-bin' 127 | }, 128 | 'zopflipng-bin': { 129 | replaceHost: [Array], 130 | host: 'https://cdn.npmmirror.com/binaries/zopflipng-bin' 131 | }, 132 | 'optipng-bin': { 133 | replaceHost: [Array], 134 | host: 'https://cdn.npmmirror.com/binaries/optipng-bin' 135 | }, 136 | mozjpeg: { 137 | replaceHost: [Array], 138 | host: 'https://cdn.npmmirror.com/binaries/mozjpeg-bin' 139 | }, 140 | gifsicle: { 141 | replaceHost: [Array], 142 | host: 'https://cdn.npmmirror.com/binaries/gifsicle-bin' 143 | }, 144 | 'pngquant-bin': { 145 | replaceHost: [Array], 146 | host: 'https://cdn.npmmirror.com/binaries/pngquant-bin', 147 | replaceHostMap: [Object] 148 | }, 149 | 'pngcrush-bin': { 150 | replaceHost: [Array], 151 | host: 'https://cdn.npmmirror.com/binaries/pngcrush-bin' 152 | }, 153 | 'jpeg-recompress-bin': { 154 | replaceHost: [Array], 155 | host: 'https://cdn.npmmirror.com/binaries/jpeg-recompress-bin' 156 | }, 157 | 'advpng-bin': { 158 | replaceHost: [Array], 159 | host: 'https://cdn.npmmirror.com/binaries/advpng-bin' 160 | }, 161 | 'pngout-bin': { 162 | replaceHost: [Array], 163 | host: 'https://cdn.npmmirror.com/binaries/pngout-bin' 164 | }, 165 | 'jpegoptim-bin': { 166 | replaceHost: [Array], 167 | host: 'https://cdn.npmmirror.com/binaries/jpegoptim-bin' 168 | }, 169 | argon2: { host: 'https://cdn.npmmirror.com/binaries/argon2' }, 170 | 'ali-zeromq': { host: 'https://cdn.npmmirror.com/binaries/ali-zeromq' }, 171 | 'ali-usb_ctl': { host: 'https://cdn.npmmirror.com/binaries/ali-usb_ctl' }, 172 | 'gdal-async': { host: 'https://cdn.npmmirror.com/binaries/node-gdal-async' }, 173 | 'libpg-query': { host: 'https://cdn.npmmirror.com/binaries' } 174 | }, 175 | forbiddenLicenses: null, 176 | flatten: false, 177 | proxy: undefined, 178 | prune: false, 179 | disableFallbackStore: false, 180 | workspacesMap: Map(0) {}, 181 | enableWorkspace: false, 182 | workspaceRoot: 'D:\\Projects\\backups\\vue_pro', 183 | isWorkspaceRoot: true, 184 | isWorkspacePackage: false, 185 | offline: false, 186 | strictSSL: true, 187 | ignoreScripts: false, 188 | foregroundScripts: false, 189 | ignoreOptionalDependencies: false, 190 | detail: false, 191 | forceLinkLatest: false, 192 | trace: false, 193 | engineStrict: false, 194 | registryOnly: false, 195 | client: false, 196 | autoFixVersion: [Function: autoFixVersion] 197 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue_pro", 3 | "version": "1.0.8", 4 | "private": true, 5 | "main": "main.js", 6 | "description": "An exquisite local music player", 7 | "author": "Violex", 8 | "productName": "Sonorbit", 9 | "scripts": { 10 | "serve": "vue-cli-service serve", 11 | "build": "vue-cli-service build", 12 | "lint": "vue-cli-service lint", 13 | "start": "electron .", 14 | "pack": "electron-builder --dir", 15 | "dist": "electron-builder" 16 | }, 17 | "build": { 18 | "nsis": { 19 | "oneClick": false, 20 | "allowToChangeInstallationDirectory": true 21 | }, 22 | "electronDownload": { 23 | "mirror": "https://npm.taobao.org/mirrors/electron/" 24 | }, 25 | "appId": "Sonorbit", 26 | "win": { 27 | "icon": "/dist/img/logo.ico" 28 | }, 29 | "files": [ 30 | "dist/**/*", 31 | "main.js", 32 | "preload.js", 33 | "node_modules/**" 34 | ], 35 | "directories": { 36 | "output": "release" 37 | }, 38 | "asar": false 39 | }, 40 | "dependencies": { 41 | "axios": "^0.27.2", 42 | "bean": "latest", 43 | "core-js": "^3.8.3", 44 | "drag": "^0.0.4", 45 | "electron-drag": "^2.0.0", 46 | "electron-localshortcut": "^3.2.1", 47 | "electron-store": "^8.1.0", 48 | "electron-win-state": "^1.1.22", 49 | "electron-window-state": "^5.0.3", 50 | "fs": "^0.0.1-security", 51 | "howler": "^2.2.3", 52 | "microtip": "^0.2.2", 53 | "mime-types": "^2.1.35", 54 | "music-metadata": "^8.1.4", 55 | "NeteaseCloudMusicApi": "^4.8.7", 56 | "node-taglib-sharp": "^5.2.3", 57 | "os": "^0.1.2", 58 | "path": "^0.12.7", 59 | "path-browserify": "^1.0.1", 60 | "qs": "^6.11.2", 61 | "scroll-into-view": "^1.16.2", 62 | "sharp": "^0.32.6", 63 | "vue": "^2.6.14", 64 | "vue-color": "^2.8.1", 65 | "vue-lazyload": "^3.0.0", 66 | "vue-router": "^3.6.5", 67 | "vue-slider-component": "^3.2.24", 68 | "vuex": "^3.6.2" 69 | }, 70 | "devDependencies": { 71 | "@babel/core": "^7.12.16", 72 | "@babel/eslint-parser": "^7.12.16", 73 | "@vue/cli-plugin-babel": "~5.0.0", 74 | "@vue/cli-plugin-eslint": "~5.0.0", 75 | "@vue/cli-service": "~5.0.0", 76 | "electron": "^19.0.8", 77 | "electron-builder": "^24.6.3", 78 | "eslint": "^7.32.0", 79 | "eslint-plugin-vue": "^8.0.3", 80 | "vue-template-compiler": "^2.6.14" 81 | }, 82 | "eslintConfig": { 83 | "root": true, 84 | "env": { 85 | "node": true 86 | }, 87 | "extends": [ 88 | "plugin:vue/essential", 89 | "eslint:recommended" 90 | ], 91 | "parserOptions": { 92 | "parser": "@babel/eslint-parser" 93 | }, 94 | "rules": {} 95 | }, 96 | "browserslist": [ 97 | "> 1%", 98 | "last 2 versions", 99 | "not dead" 100 | ] 101 | } 102 | -------------------------------------------------------------------------------- /preload.js: -------------------------------------------------------------------------------- 1 | 2 | const {contextBridge, ipcRenderer} = require('electron') 3 | 4 | 5 | window.addEventListener('DOMContentLoaded', () => { 6 | const lock = document.getElementById('lockButton') 7 | const unlock = document.getElementById('unlockButton') 8 | 9 | if (lock) { 10 | lock.addEventListener('mouseenter', () => { 11 | setTimeout(()=>{ 12 | ipcRenderer.send('set-ignore-mouse-events') 13 | },1000) 14 | }) 15 | } 16 | 17 | if (unlock) { 18 | unlock.addEventListener('mouseenter', () => { 19 | setTimeout(()=>{ 20 | ipcRenderer.send('set-ignore-mouse-events') 21 | },1000) 22 | }) 23 | } 24 | }) 25 | 26 | contextBridge.exposeInMainWorld('myAPI', { 27 | 28 | onPlayLast: (callback) => ipcRenderer.on('playLast', callback), 29 | onPlayLastG: (callback) => ipcRenderer.on('playLastG', callback), 30 | onToggle: (callback) => ipcRenderer.on('toggle', callback), 31 | onToggleG: (callback) => ipcRenderer.on('toggleG', callback), 32 | onPlayNext: (callback) => ipcRenderer.on('playNext', callback), 33 | onPlayNextG: (callback) => ipcRenderer.on('playNextG', callback), 34 | onDownVolume: (callback) => ipcRenderer.on('downVolume', callback), 35 | onDownVolumeG: (callback) => ipcRenderer.on('downVolumeG', callback), 36 | onUpVolume: (callback) => ipcRenderer.on('upVolume', callback), 37 | onUpVolumeG: (callback) => ipcRenderer.on('upVolumeG', callback), 38 | onChangeMute: (callback) => ipcRenderer.on('changeMute', callback), 39 | onChangeMuteG: (callback) => ipcRenderer.on('changeMuteG', callback), 40 | onChangeModeG: (callback) => ipcRenderer.on('changeModeG', callback), 41 | onChangeShowDLyric: (callback) => ipcRenderer.on('changeShowDLyric', callback), 42 | onChangeShowDLyricG: (callback) => ipcRenderer.on('changeShowDLyricG', callback), 43 | 44 | onSaveBeforeQuit: (callback,arg) => ipcRenderer.on('saveBeforeQuit', callback, arg), 45 | onForwardBack: (callback,arg) => ipcRenderer.on('forwardBack', callback, arg), 46 | onCloseFromBottom: (callback) => ipcRenderer.on('closeFromBottom', callback), 47 | onLoop: (callback) => ipcRenderer.on('loop', callback), 48 | onRandom: (callback) => ipcRenderer.on('random', callback), 49 | onOne: (callback) => ipcRenderer.on('one', callback), 50 | onFinishScan: (callback, arg, arg2) => ipcRenderer.on('finishScan', callback,arg,arg2), 51 | onFinishScanErrorMix: (callback) => ipcRenderer.on('finishScanErrorMix', callback), 52 | onErrorFile: (callback) => ipcRenderer.on('errorFile', callback), 53 | onCancelScan: (callback) => ipcRenderer.on('cancelScan', callback), 54 | onOpenSettings: (callback) => ipcRenderer.on('openSettings', callback), 55 | onShowInfo: (callback) => ipcRenderer.on('showInfo', callback), 56 | onShowPlaylists: (callback) => ipcRenderer.on('showPlaylists', callback), 57 | onShowLyric: (callback) => ipcRenderer.on('showLyric', callback), 58 | onReturnHome: (callback) => ipcRenderer.on('returnHome', callback), 59 | onShowQueue: (callback) => ipcRenderer.on('showQueue', callback), 60 | onSearch: (callback) => ipcRenderer.on('search', callback), 61 | onFocusMode: (callback) => ipcRenderer.on('focusMode', callback), 62 | 63 | onLyricFromWin: (callback,arg1, arg2) => ipcRenderer.on('lyricFromWin', callback, arg1, arg2), 64 | onLockButton: (callback,arg) => ipcRenderer.on('lockButton', callback, arg), 65 | onCloseDeskTopLyric: (callback) => ipcRenderer.on('closeDeskTopLyric', callback), 66 | onSendIsPlaying: (callback,arg) => ipcRenderer.on('sendIsPlaying', callback, arg), 67 | onChangeBold: (callback,arg) => ipcRenderer.on('changeBold', callback, arg), 68 | onChangeFont: (callback,arg) => ipcRenderer.on('changeFont', callback, arg), 69 | onChangeColor: (callback,arg1,arg2) => ipcRenderer.on('changeColor', callback, arg1, arg2), 70 | 71 | 72 | rename:({oldName,newName})=>{ 73 | ipcRenderer.invoke('rename',{oldName,newName}) 74 | }, 75 | 76 | sendProgress:(progress)=>{ 77 | ipcRenderer.invoke('sendProgress',progress) 78 | }, 79 | 80 | sendToggle:(progress, isPlaying)=>{ 81 | ipcRenderer.invoke('sendToggle', progress, isPlaying) 82 | }, 83 | 84 | openFile:(filePath,directory)=>{ 85 | ipcRenderer.invoke('openFile',filePath,directory) 86 | }, 87 | openFolder:(folderPath)=>{ 88 | ipcRenderer.invoke('openFolder', folderPath) 89 | }, 90 | readFile: async (filePath,lyricDirectory,songId) => { 91 | try { 92 | const response = await ipcRenderer.invoke('read-file', filePath,lyricDirectory,songId); 93 | return response; 94 | } catch (error) { 95 | console.error('Error reading file:', error); 96 | return "[00:00.00]加载歌曲文件错误" 97 | } 98 | }, 99 | searchSong: async (keyword) => { 100 | try { 101 | const response = await ipcRenderer.invoke('searchSong', keyword); 102 | return response; 103 | } catch (error) { 104 | return "未知错误" 105 | } 106 | }, 107 | searchLyric: async (songId) => { 108 | try { 109 | const response = await ipcRenderer.invoke('searchLyric',songId); 110 | return response; 111 | } catch (error) { 112 | return "未知错误" 113 | } 114 | }, 115 | readFileForMoreInfo: async (filePath,songId,lyricDirectory) => { 116 | try { 117 | const response = await ipcRenderer.invoke('readFileForMoreInfo', filePath,songId,lyricDirectory); 118 | return response; 119 | } catch (error) { 120 | console.error('Error reading file:', error); 121 | throw error; 122 | } 123 | }, 124 | getLyrics: async (filePath,lyricDirectory) => { 125 | try { 126 | const response = await ipcRenderer.invoke('getLyrics', filePath,lyricDirectory); 127 | return response; 128 | } catch (error) { 129 | console.error('Error reading file:', error); 130 | throw error; 131 | } 132 | }, 133 | editMetadata:(data, lyricDirectory)=>{ 134 | ipcRenderer.invoke('editMetadata',data, lyricDirectory) 135 | }, 136 | changeInfo:(filePath)=>{ 137 | ipcRenderer.invoke('changeInfo',filePath) 138 | }, 139 | closeWelcome:()=>{ 140 | ipcRenderer.invoke('closeWelcome') 141 | }, 142 | minimize:()=>{ 143 | ipcRenderer.invoke('minimize-window') 144 | }, 145 | maximize:(flag)=>{ 146 | ipcRenderer.invoke('maximize-window',flag) 147 | }, 148 | closeWindow:(savingState)=>{ 149 | ipcRenderer.invoke('close-window',savingState) 150 | }, 151 | writeOnlineLrc:(onlineLrc, songPath,lyricDirectory)=>{ 152 | ipcRenderer.invoke('writeOnlineLrc',onlineLrc, songPath,lyricDirectory) 153 | }, 154 | hideWindow:()=>{ 155 | ipcRenderer.invoke('hide-window') 156 | }, 157 | saveNow:(savingState)=>{ 158 | ipcRenderer.invoke('save-now',savingState) 159 | }, 160 | getAllSongs: async () => { 161 | try { 162 | const response = await ipcRenderer.invoke('getAllSongs'); 163 | return response; 164 | } catch (error) { 165 | console.error('Error reading file:', error); 166 | throw error; 167 | } 168 | }, 169 | changeLyricDirectory: async () => { 170 | try { 171 | const response = await ipcRenderer.invoke('changeLyricDirectory'); 172 | return response; 173 | } catch (error) { 174 | console.error('Error reading file:', error); 175 | throw error; 176 | } 177 | }, 178 | getSavingState: async () => { 179 | try { 180 | const response = await ipcRenderer.invoke('getSavingState'); 181 | return response; 182 | } catch (error) { 183 | console.error('Error reading file:', error); 184 | throw error; 185 | } 186 | }, 187 | getAllPlaylists: async () => { 188 | try { 189 | const response = await ipcRenderer.invoke('getAllPlaylists'); 190 | return response; 191 | } catch (error) { 192 | console.error('Error reading file:', error); 193 | throw error; 194 | } 195 | }, 196 | getSongCover: async (filePath,type) => { 197 | try { 198 | const response = await ipcRenderer.invoke('getSongCover',filePath,type); 199 | return response; 200 | } catch (error) { 201 | console.error('Error reading file:', error); 202 | throw error; 203 | } 204 | }, 205 | getSongCoverFromNet: async (filePath,netId, keywords) => { 206 | try { 207 | const response = await ipcRenderer.invoke('getSongCoverFromNet',filePath,netId, keywords); 208 | return response; 209 | } catch (error) { 210 | console.error('Error reading file:', error); 211 | throw error; 212 | } 213 | }, 214 | getPlaylistCover: async (playlistName) => { 215 | try { 216 | const response = await ipcRenderer.invoke('getPlaylistCover',playlistName); 217 | return response; 218 | } catch (error) { 219 | console.error('Error reading file:', error); 220 | throw error; 221 | } 222 | }, 223 | getBackCover: async (backCoverPath) => { 224 | try { 225 | const response = await ipcRenderer.invoke('getBackCover',backCoverPath); 226 | return response; 227 | } catch (error) { 228 | console.error('Error reading cover:', error); 229 | throw error; 230 | } 231 | }, 232 | 233 | setPlaylistCover: async (playlistName) => { 234 | try { 235 | const response = await ipcRenderer.invoke('setPlaylistCover',playlistName); 236 | return response; 237 | } catch (error) { 238 | console.error('Error reading file:', error); 239 | throw error; 240 | } 241 | }, 242 | 243 | refreshLibrary: async () => { 244 | try { 245 | const response = await ipcRenderer.invoke('refreshLibrary'); 246 | return response; 247 | } catch (error) { 248 | console.error('Error refresh library:', error); 249 | throw error; 250 | } 251 | }, 252 | 253 | chooseCover: async (flag) => { 254 | try { 255 | const response = await ipcRenderer.invoke('chooseCover',flag); 256 | return response; 257 | } catch (error) { 258 | console.error('Error reading file:', error); 259 | throw error; 260 | } 261 | }, 262 | 263 | addNewPlaylistOrDelete:(newPlaylist, addOrDelete) =>{ 264 | ipcRenderer.invoke('add-new-playlist-or-delete',newPlaylist,addOrDelete) 265 | }, 266 | 267 | setId:(netId, songId) =>{ 268 | ipcRenderer.invoke('setId',netId, songId) 269 | }, 270 | 271 | sendColor:(color, type) =>{ 272 | ipcRenderer.invoke('sendColor',color, type) 273 | }, 274 | 275 | sendBold:(bold) =>{ 276 | ipcRenderer.invoke('sendBold',bold) 277 | }, 278 | 279 | sendFont:(font) =>{ 280 | ipcRenderer.invoke('sendFont',font) 281 | }, 282 | 283 | deskTopLyricButtons:(buttonNo) =>{ 284 | ipcRenderer.invoke('deskTopLyricButtons',buttonNo) 285 | }, 286 | 287 | sendLyric:(text1, text2) =>{ 288 | ipcRenderer.invoke('sendLyric', text1, text2) 289 | }, 290 | 291 | 292 | openDeckTopLyric:(flag, isPlaying) =>{ 293 | ipcRenderer.invoke('openDeckTopLyric',flag, isPlaying) 294 | }, 295 | 296 | changeShortcuts:(type, whichKey, oldVal, newVal) =>{ 297 | ipcRenderer.invoke('changeShortcuts',type, whichKey, oldVal, newVal) 298 | }, 299 | 300 | initializeShortcuts:(shortcuts) =>{ 301 | ipcRenderer.invoke('initializeShortcuts',shortcuts) 302 | }, 303 | 304 | delOnlineLrc:(songPath, lrcDirectory)=>{ 305 | ipcRenderer.invoke('delOnlineLrc',songPath, lrcDirectory) 306 | }, 307 | 308 | addToOrDeleteFromPlaylist:(playlistName, toModifySongsId,addOrDelete) =>{ 309 | ipcRenderer.invoke('addTo-or-deleteFrom-playlist',playlistName,toModifySongsId,addOrDelete) 310 | }, 311 | 312 | deleteFromLibrary:(toDeleteSongsId)=>{ 313 | ipcRenderer.invoke('delete-from-library',toDeleteSongsId) 314 | }, 315 | 316 | deleteLocalFile:(toDeleteLocalFile)=>{ 317 | ipcRenderer.invoke('deleteLocalFile',toDeleteLocalFile) 318 | }, 319 | sortSongs:(orderType,newArray,playlistName) =>{ 320 | ipcRenderer.invoke('sort-songs',orderType,newArray,playlistName) 321 | }, 322 | addFolders:()=>{ 323 | ipcRenderer.invoke('add-folders') 324 | }, 325 | 326 | addFiles:()=>{ 327 | ipcRenderer.invoke('add-files') 328 | }, 329 | dragFile:(filePaths)=>{ 330 | ipcRenderer.invoke('dragFile', filePaths) 331 | }, 332 | miniMode:(miniMode)=>{ 333 | ipcRenderer.invoke('miniMode',miniMode) 334 | }, 335 | 336 | enableDrag:()=>{ 337 | ipcRenderer.invoke('enableDrag') 338 | } 339 | }); 340 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Violexjj/Loop-Sound-Player/a353aab42f5586acb7ce115da2d974b7f48edfb8/public/favicon.ico -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Sonorbit 10 | 11 | 12 | 15 |
16 | 17 | 18 | 26 | 27 | -------------------------------------------------------------------------------- /src/assets/EQ.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Violexjj/Loop-Sound-Player/a353aab42f5586acb7ce115da2d974b7f48edfb8/src/assets/EQ.png -------------------------------------------------------------------------------- /src/assets/add.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Violexjj/Loop-Sound-Player/a353aab42f5586acb7ce115da2d974b7f48edfb8/src/assets/add.png -------------------------------------------------------------------------------- /src/assets/addPlaylist.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Violexjj/Loop-Sound-Player/a353aab42f5586acb7ce115da2d974b7f48edfb8/src/assets/addPlaylist.png -------------------------------------------------------------------------------- /src/assets/album.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Violexjj/Loop-Sound-Player/a353aab42f5586acb7ce115da2d974b7f48edfb8/src/assets/album.png -------------------------------------------------------------------------------- /src/assets/artist.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Violexjj/Loop-Sound-Player/a353aab42f5586acb7ce115da2d974b7f48edfb8/src/assets/artist.png -------------------------------------------------------------------------------- /src/assets/choice.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Violexjj/Loop-Sound-Player/a353aab42f5586acb7ce115da2d974b7f48edfb8/src/assets/choice.png -------------------------------------------------------------------------------- /src/assets/close.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Violexjj/Loop-Sound-Player/a353aab42f5586acb7ce115da2d974b7f48edfb8/src/assets/close.png -------------------------------------------------------------------------------- /src/assets/closeWindow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Violexjj/Loop-Sound-Player/a353aab42f5586acb7ce115da2d974b7f48edfb8/src/assets/closeWindow.png -------------------------------------------------------------------------------- /src/assets/color.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Violexjj/Loop-Sound-Player/a353aab42f5586acb7ce115da2d974b7f48edfb8/src/assets/color.png -------------------------------------------------------------------------------- /src/assets/dLyric.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Violexjj/Loop-Sound-Player/a353aab42f5586acb7ce115da2d974b7f48edfb8/src/assets/dLyric.png -------------------------------------------------------------------------------- /src/assets/defaultBack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Violexjj/Loop-Sound-Player/a353aab42f5586acb7ce115da2d974b7f48edfb8/src/assets/defaultBack.png -------------------------------------------------------------------------------- /src/assets/delete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Violexjj/Loop-Sound-Player/a353aab42f5586acb7ce115da2d974b7f48edfb8/src/assets/delete.png -------------------------------------------------------------------------------- /src/assets/delete2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Violexjj/Loop-Sound-Player/a353aab42f5586acb7ce115da2d974b7f48edfb8/src/assets/delete2.png -------------------------------------------------------------------------------- /src/assets/delete3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Violexjj/Loop-Sound-Player/a353aab42f5586acb7ce115da2d974b7f48edfb8/src/assets/delete3.png -------------------------------------------------------------------------------- /src/assets/downVolume.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Violexjj/Loop-Sound-Player/a353aab42f5586acb7ce115da2d974b7f48edfb8/src/assets/downVolume.png -------------------------------------------------------------------------------- /src/assets/file.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Violexjj/Loop-Sound-Player/a353aab42f5586acb7ce115da2d974b7f48edfb8/src/assets/file.png -------------------------------------------------------------------------------- /src/assets/folder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Violexjj/Loop-Sound-Player/a353aab42f5586acb7ce115da2d974b7f48edfb8/src/assets/folder.png -------------------------------------------------------------------------------- /src/assets/folder2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Violexjj/Loop-Sound-Player/a353aab42f5586acb7ce115da2d974b7f48edfb8/src/assets/folder2.png -------------------------------------------------------------------------------- /src/assets/fullS.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Violexjj/Loop-Sound-Player/a353aab42f5586acb7ce115da2d974b7f48edfb8/src/assets/fullS.png -------------------------------------------------------------------------------- /src/assets/home.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Violexjj/Loop-Sound-Player/a353aab42f5586acb7ce115da2d974b7f48edfb8/src/assets/home.png -------------------------------------------------------------------------------- /src/assets/img.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Violexjj/Loop-Sound-Player/a353aab42f5586acb7ce115da2d974b7f48edfb8/src/assets/img.png -------------------------------------------------------------------------------- /src/assets/info.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Violexjj/Loop-Sound-Player/a353aab42f5586acb7ce115da2d974b7f48edfb8/src/assets/info.png -------------------------------------------------------------------------------- /src/assets/info2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Violexjj/Loop-Sound-Player/a353aab42f5586acb7ce115da2d974b7f48edfb8/src/assets/info2.png -------------------------------------------------------------------------------- /src/assets/library.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Violexjj/Loop-Sound-Player/a353aab42f5586acb7ce115da2d974b7f48edfb8/src/assets/library.png -------------------------------------------------------------------------------- /src/assets/logoImg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Violexjj/Loop-Sound-Player/a353aab42f5586acb7ce115da2d974b7f48edfb8/src/assets/logoImg.png -------------------------------------------------------------------------------- /src/assets/lrc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Violexjj/Loop-Sound-Player/a353aab42f5586acb7ce115da2d974b7f48edfb8/src/assets/lrc.png -------------------------------------------------------------------------------- /src/assets/lrc2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Violexjj/Loop-Sound-Player/a353aab42f5586acb7ce115da2d974b7f48edfb8/src/assets/lrc2.png -------------------------------------------------------------------------------- /src/assets/match.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Violexjj/Loop-Sound-Player/a353aab42f5586acb7ce115da2d974b7f48edfb8/src/assets/match.png -------------------------------------------------------------------------------- /src/assets/maximize.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Violexjj/Loop-Sound-Player/a353aab42f5586acb7ce115da2d974b7f48edfb8/src/assets/maximize.png -------------------------------------------------------------------------------- /src/assets/mini.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Violexjj/Loop-Sound-Player/a353aab42f5586acb7ce115da2d974b7f48edfb8/src/assets/mini.png -------------------------------------------------------------------------------- /src/assets/minimize.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Violexjj/Loop-Sound-Player/a353aab42f5586acb7ce115da2d974b7f48edfb8/src/assets/minimize.png -------------------------------------------------------------------------------- /src/assets/more.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Violexjj/Loop-Sound-Player/a353aab42f5586acb7ce115da2d974b7f48edfb8/src/assets/more.png -------------------------------------------------------------------------------- /src/assets/next.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Violexjj/Loop-Sound-Player/a353aab42f5586acb7ce115da2d974b7f48edfb8/src/assets/next.png -------------------------------------------------------------------------------- /src/assets/nextSongs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Violexjj/Loop-Sound-Player/a353aab42f5586acb7ce115da2d974b7f48edfb8/src/assets/nextSongs.png -------------------------------------------------------------------------------- /src/assets/noVolume.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Violexjj/Loop-Sound-Player/a353aab42f5586acb7ce115da2d974b7f48edfb8/src/assets/noVolume.png -------------------------------------------------------------------------------- /src/assets/onesong.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Violexjj/Loop-Sound-Player/a353aab42f5586acb7ce115da2d974b7f48edfb8/src/assets/onesong.png -------------------------------------------------------------------------------- /src/assets/order.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Violexjj/Loop-Sound-Player/a353aab42f5586acb7ce115da2d974b7f48edfb8/src/assets/order.png -------------------------------------------------------------------------------- /src/assets/pause.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Violexjj/Loop-Sound-Player/a353aab42f5586acb7ce115da2d974b7f48edfb8/src/assets/pause.png -------------------------------------------------------------------------------- /src/assets/play.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Violexjj/Loop-Sound-Player/a353aab42f5586acb7ce115da2d974b7f48edfb8/src/assets/play.png -------------------------------------------------------------------------------- /src/assets/play2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Violexjj/Loop-Sound-Player/a353aab42f5586acb7ce115da2d974b7f48edfb8/src/assets/play2.png -------------------------------------------------------------------------------- /src/assets/playlist.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Violexjj/Loop-Sound-Player/a353aab42f5586acb7ce115da2d974b7f48edfb8/src/assets/playlist.png -------------------------------------------------------------------------------- /src/assets/playlist3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Violexjj/Loop-Sound-Player/a353aab42f5586acb7ce115da2d974b7f48edfb8/src/assets/playlist3.png -------------------------------------------------------------------------------- /src/assets/playlist4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Violexjj/Loop-Sound-Player/a353aab42f5586acb7ce115da2d974b7f48edfb8/src/assets/playlist4.png -------------------------------------------------------------------------------- /src/assets/prev.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Violexjj/Loop-Sound-Player/a353aab42f5586acb7ce115da2d974b7f48edfb8/src/assets/prev.png -------------------------------------------------------------------------------- /src/assets/queue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Violexjj/Loop-Sound-Player/a353aab42f5586acb7ce115da2d974b7f48edfb8/src/assets/queue.png -------------------------------------------------------------------------------- /src/assets/random.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Violexjj/Loop-Sound-Player/a353aab42f5586acb7ce115da2d974b7f48edfb8/src/assets/random.png -------------------------------------------------------------------------------- /src/assets/rotate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Violexjj/Loop-Sound-Player/a353aab42f5586acb7ce115da2d974b7f48edfb8/src/assets/rotate.png -------------------------------------------------------------------------------- /src/assets/search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Violexjj/Loop-Sound-Player/a353aab42f5586acb7ce115da2d974b7f48edfb8/src/assets/search.png -------------------------------------------------------------------------------- /src/assets/set.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Violexjj/Loop-Sound-Player/a353aab42f5586acb7ce115da2d974b7f48edfb8/src/assets/set.png -------------------------------------------------------------------------------- /src/assets/spectrum.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Violexjj/Loop-Sound-Player/a353aab42f5586acb7ce115da2d974b7f48edfb8/src/assets/spectrum.png -------------------------------------------------------------------------------- /src/assets/target.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Violexjj/Loop-Sound-Player/a353aab42f5586acb7ce115da2d974b7f48edfb8/src/assets/target.png -------------------------------------------------------------------------------- /src/assets/volume.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Violexjj/Loop-Sound-Player/a353aab42f5586acb7ce115da2d974b7f48edfb8/src/assets/volume.png -------------------------------------------------------------------------------- /src/assets/znone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Violexjj/Loop-Sound-Player/a353aab42f5586acb7ce115da2d974b7f48edfb8/src/assets/znone.png -------------------------------------------------------------------------------- /src/components/Header.vue: -------------------------------------------------------------------------------- 1 | 32 | 33 | 141 | 142 | 261 | 262 | 263 | -------------------------------------------------------------------------------- /src/components/WebAudioApi.js: -------------------------------------------------------------------------------- 1 | const EQ = [ 2 | { 3 | frequency: 31, 4 | type: 'lowshelf' 5 | }, 6 | { 7 | frequency: 62, 8 | type: 'peaking' 9 | }, 10 | { 11 | frequency: 125, 12 | type: 'peaking' 13 | }, 14 | { 15 | frequency: 250, 16 | type: 'peaking' 17 | }, 18 | { 19 | frequency: 500, 20 | type: 'peaking' 21 | }, 22 | { 23 | frequency: 1000, 24 | type: 'peaking' 25 | }, 26 | { 27 | frequency: 2000, 28 | type: 'peaking' 29 | }, 30 | { 31 | frequency: 4000, 32 | type: 'peaking' 33 | }, 34 | { 35 | frequency: 8000, 36 | type: 'peaking' 37 | }, 38 | { 39 | frequency: 16000, 40 | type: 'highshelf' 41 | } 42 | ] 43 | 44 | export class WebAudioApi { 45 | constructor(audioCtx, audioNode) { 46 | this.audioCtx = audioCtx 47 | this.audioNode = audioNode 48 | this.audioSource = null 49 | } 50 | 51 | static create(audioCtx, audioNode) { 52 | return new WebAudioApi(audioCtx, audioNode).setup() 53 | } 54 | 55 | setup() { 56 | const audioCtx = this.audioCtx 57 | const audioNode = this.audioNode 58 | this.splitterNode = audioCtx.createChannelSplitter(2) 59 | this.mergerNode = audioCtx.createChannelMerger(2) 60 | 61 | this.leftChannelAnalyser = audioCtx.createAnalyser() 62 | this.rightChannelAnalyser = audioCtx.createAnalyser() 63 | this.analyser = audioCtx.createAnalyser() 64 | 65 | this.leftChannelAnalyser.fftSize = 512 66 | this.rightChannelAnalyser.fftSize = 512 67 | this.analyser.fftSize = 512 68 | 69 | this.distortion = audioCtx.createWaveShaper() 70 | this.stereoPanNode = audioCtx.createStereoPanner() 71 | this.gainNode = audioCtx.createGain() 72 | this.biquadFilters = this.createBiquadFilters() 73 | if (!this.audioSource) this.audioSource = audioCtx.createMediaElementSource(audioNode) 74 | this.audioSource.connect(this.splitterNode) 75 | this.splitterNode.connect(this.leftChannelAnalyser, 0) 76 | this.splitterNode.connect(this.rightChannelAnalyser, 1) 77 | this.leftChannelAnalyser.connect(this.mergerNode, 0, 0) 78 | this.rightChannelAnalyser.connect(this.mergerNode, 0, 1) 79 | this.mergerNode.connect(this.analyser) 80 | this.analyser.connect(this.distortion) 81 | this.connectBiquadFilters(this.biquadFilters, this.distortion, this.stereoPanNode) 82 | this.stereoPanNode.connect(this.gainNode) 83 | this.gainNode.connect(audioCtx.destination) 84 | //this.audioSource.connect(audioCtx.destination) 85 | return this 86 | } 87 | 88 | createBiquadFilters() { 89 | const audioCtx = this.audioCtx 90 | if (!audioCtx) return [] 91 | let filters = EQ.map(band => { 92 | let filter = audioCtx.createBiquadFilter() 93 | filter.type = band.type 94 | filter.gain.value = 0 // -40 ~ 40 95 | filter.Q.value = 1 96 | filter.frequency.value = band.frequency 97 | return filter 98 | }) 99 | return filters 100 | } 101 | 102 | // Node Chain: currentNode -> filters -> nextNode 103 | connectBiquadFilters(filters, currentNode, nextNode) { 104 | if (!filters || filters.length < 0) return 105 | filters.reduce((prev, curr) => { 106 | prev.connect(curr) 107 | return curr 108 | }, currentNode).connect(nextNode) 109 | } 110 | 111 | updateEQ(values) { 112 | const eqFilters = this.biquadFilters 113 | if (!eqFilters || eqFilters.length < 1) return 114 | eqFilters.forEach((filter, index) => { 115 | filter.gain.value = values[index] 116 | }) 117 | } 118 | 119 | //混响 audioNodes -> reverb -> destination 120 | connectReverb() { 121 | this.gainNode.disconnect() 122 | this.gainNode.connect(this.convolver) 123 | this.convolver.connect(this.audioCtx.destination) 124 | } 125 | 126 | disconnectReverb() { 127 | this.gainNode.disconnect() 128 | this.gainNode.connect(this.audioCtx.destination) 129 | } 130 | 131 | //source格式: xxx.wav 132 | async updateIR(source) { 133 | console.log(source) 134 | if (!source) { 135 | this.disconnectReverb() 136 | return 137 | } 138 | const audioCtx = this.audioCtx 139 | if (!this.convolver) { 140 | this.convolver = audioCtx.createConvolver() 141 | } 142 | this.connectReverb() 143 | 144 | //TODO 145 | //从文件加载脉冲反应(Impulse Response) 146 | let response = await fetch(`impulse/${source}`) 147 | let buffer = await response.arrayBuffer() 148 | this.convolver.buffer = await audioCtx.decodeAudioData(buffer) 149 | 150 | return this.convolver 151 | } 152 | 153 | updateStereoPan(value) { 154 | value = value || 0.0 155 | value = Math.max(-1.0, value) 156 | value = Math.min(1.0, value) 157 | 158 | this.stereoPanNode.pan.setValueAtTime(value, this.audioCtx.currentTime) 159 | } 160 | 161 | updateVolumeGain(value) { 162 | value = Number(value) 163 | value = Math.max(0, value) 164 | value = Math.min(3.0, value) 165 | 166 | this.gainNode.gain.setValueAtTime(value, this.audioCtx.currentTime) 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | //安装vue,等同于导入vue.js文件 2 | import Vue from 'vue' 3 | //导入App组件(根组件) 4 | import App from './App.vue' 5 | //取消生产提示 6 | Vue.config.productionTip = false 7 | 8 | //导入混入 9 | //全局混入 10 | //Vue.mixin(mix1) 11 | 12 | //导入插件 13 | import {p1} from "./plugins"; 14 | //使用插件(一般放在Vue实例之前) 15 | Vue.use(p1, 1, 2, 4) 16 | 17 | //引入vuex插件中的核心对象:store 18 | import store from "./vuex/store"; 19 | 20 | //导入vue-router插件 21 | import VueRouter from 'vue-router' 22 | //使用vue-router插件 23 | Vue.use(VueRouter) 24 | //导入路由器对象,下面的new vue要加配置项:router 25 | import router from './router/index' 26 | 27 | new Vue({ 28 | el: "#app", 29 | store : store, //用this.$store来拿到共享对象 30 | async beforeCreate() { 31 | //全局事件总线, 所有组件共享这个this, vue实例,通过$bus来在组件之间传输数据 32 | Vue.prototype.$bus = this 33 | window.myAPI.getSavingState().then(savingState => { 34 | if (savingState) { 35 | this.$store.commit('SET_VOLUME', savingState.volume) 36 | this.$store.commit('SET_CURRENT_INDEX', savingState.currentIndex) 37 | this.$store.commit('SET_NOW_MODE', savingState.nowMode) 38 | this.$store.commit('SET_IS_MUTE', savingState.isMute) 39 | this.$store.commit('SET_QUEUE', savingState.queue) 40 | this.$store.commit('SET_SHOW_LYRICS', savingState.showLyrics) 41 | this.$store.commit('SET_TO_HOME_AFTER_CHANGE_QUEUE', savingState.toHomeAfterChangeQueue) 42 | this.$store.commit('SET_AUTO_HIDE_LRC', savingState.autoHideLrc) 43 | this.$store.commit('SET_SHOW_QUEUE', savingState.showQueue) 44 | this.$store.commit('SET_LYRIC_ALIGNMENT_MODE', savingState.lyricAlignmentMode) 45 | this.$store.commit('SET_HIGHLIGHT', savingState.highlight) 46 | this.$store.commit('SET_SHOW_FORMAT', savingState.showFormat) 47 | this.$store.commit('SET_INFO_MODAL', savingState.infoModal) 48 | this.$store.commit('SET_LYRICS_MODAL', savingState.lyricsModal) 49 | this.$store.commit('SET_QUEUE_MODAL', savingState.queueModal) 50 | 51 | this.$store.commit('SET_EXIT', savingState.exit) 52 | this.$store.commit('SET_GLOBAL_SHORTCUT', savingState.globalShortcut) 53 | this.$store.commit('SET_SAVED_CURRENT_PLAYTIME', savingState.savedCurrentPlaytime) 54 | this.$store.commit('SET_LYRIC_FONT', savingState.lyricFont) 55 | this.$store.commit('SET_LYRIC_FONT2', savingState.lyricFont2) 56 | this.$store.commit('SET_ONLINE_LRC', savingState.onlineLrc) 57 | this.$store.commit('SET_LYRIC_DIRECTORY', savingState.lyricDirectory) 58 | this.$store.commit('SET_BIGGER_LYRIC', savingState.biggerLyric) 59 | this.$store.commit('SET_SHOW_TLYRIC', savingState.showTlyric) 60 | this.$store.commit('SET_CHECK', savingState.check) 61 | this.$store.commit('SET_BLUR', savingState.blur) 62 | this.$store.commit('SET_BRIGHT', savingState.bright) 63 | this.$store.commit('SET_SHOW_ALBUMS', savingState.showAlbums) 64 | this.$store.commit('SET_SHOW_ARTISTS', savingState.showArtists) 65 | this.$store.commit('SET_SHOW_FOLDERS', savingState.showFolders) 66 | this.$store.commit('SET_OTHER_BLUR', savingState.otherBlur) 67 | this.$store.commit('SET_SHORTCUTS', savingState.shortcuts) 68 | this.$store.commit('SET_DLYRIC_COLOR', savingState.dLyricColor) 69 | this.$store.commit('SET_USE_PURE_COLOR', savingState.usePureColor) 70 | this.$store.commit('SET_DLYRIC_COLOR_PURE', savingState.dLyricColorPure) 71 | this.$store.commit('SET_UseEQ', savingState.useEQ) 72 | this.$store.commit('SET_EQPARAM', savingState.EQParam) 73 | this.$store.commit('SET_BOLD_LRC', savingState.boldLrc) 74 | this.$store.commit('SET_SHOW_SPECTRUM', savingState.showSpectrum) 75 | this.$store.commit('SET_PFONT', savingState.pFont) 76 | this.$store.commit('SET_DFONT', savingState.dFont) 77 | this.$store.commit('SET_MATCH_BLANK', savingState.matchBlank) 78 | this.$store.commit('SET_SPECTRUM_SPEED', savingState.spectrumSpeed) 79 | this.$store.commit('SET_SHOW_SONG_INFO', savingState.showSongInfo) 80 | this.$store.commit('SET_USE_BACK_COVER', savingState.useBackCover) 81 | this.$store.commit('SET_BACK_COVER_PATH', savingState.backCoverPath) 82 | this.$store.commit('SET_ROTATE_COVER', savingState.rotateCover) 83 | this.$store.commit('SET_VOLUME_CHANGE', savingState.volumeChange) 84 | this.$store.commit('SET_DOWNLOAD_ONLINE_IMG', savingState.downloadOnlineImg) 85 | console.log("读取设置:成功") 86 | if (this.$store.state.queue[0] !== undefined) { 87 | if (this.$store.state.queue[0].id === "") { 88 | window.myAPI.closeWelcome() 89 | } 90 | } else { 91 | window.myAPI.closeWelcome() 92 | } 93 | } else { 94 | console.log("读取设置:失败") 95 | } 96 | }); 97 | 98 | window.myAPI.getAllSongs().then(songs => { 99 | this.$store.commit('SET_SONGS', songs); 100 | }); 101 | window.myAPI.getAllPlaylists().then(playlists => { 102 | this.$store.commit('SET_PLAYLISTS', playlists); 103 | }); 104 | }, 105 | router : router, 106 | render: h => h(App), 107 | /*原本是这样的↓ 108 | * render :(createElement)=>{ 109 | * return createElement(App) 110 | * } 111 | * */ 112 | }); 113 | 114 | -------------------------------------------------------------------------------- /src/mixin.js: -------------------------------------------------------------------------------- 1 | import {mapGetters} from "vuex"; 2 | 3 | export const mix1 = { 4 | //从alen walker - faded获取真正的专辑名:faded 5 | methods : { 6 | getAlbumName(album) { 7 | const parts = album.split("-"); 8 | return parts.length > 1 ? parts[1].trim() : album.trim(); 9 | } 10 | } 11 | } 12 | export const mix2 = { 13 | //根据artist,点击后跳转到歌手详情界面,artist有name和数组songs 14 | methods: { 15 | async displayArtistDetail(artist) { 16 | await this.changeArtistCover(artist.songs,artist) 17 | } 18 | } 19 | } 20 | export const mix4 = { 21 | //根据album,点击后跳转到专辑详情界面,album有name和数组songs 22 | methods: { 23 | async displayAlbumDetail(album) { 24 | await this.changeAlbumCover(album.songs,album) 25 | } 26 | } 27 | } 28 | export const mix3 = { 29 | //获取正在播放的歌曲信息 30 | computed : { 31 | ...mapGetters(['nowSong']) 32 | } 33 | } 34 | 35 | export const mix6 = { 36 | //修改专辑封面 37 | methods : { 38 | async changeAlbumCover(albumSongs,album){ 39 | const path = albumSongs[0].path 40 | const coverData = await window.myAPI.getSongCover(path,1); 41 | // 更新封面 42 | if (albumSongs.length > 1) { 43 | album.songs.sort((a, b) => { 44 | if ((!a.trackNumber || a.trackNumber === 0) && (!b.trackNumber || b.trackNumber === 0)) { 45 | return 0; 46 | } 47 | if (!a.trackNumber || a.trackNumber === 0) { 48 | return 1; 49 | } 50 | if (!b.trackNumber || b.trackNumber === 0) { 51 | return -1; 52 | } 53 | return a.trackNumber - b.trackNumber; 54 | }); 55 | } 56 | this.$store.state.nowAlbumCover = coverData; 57 | await this.$router.push({ 58 | name: 'AlbumDetail', 59 | params: { 60 | album: album, 61 | }, 62 | }); 63 | }, 64 | } 65 | } 66 | export const mix7 = { 67 | // 修改艺术家封面 68 | methods : { 69 | async changeArtistCover(artistSongs,artist){ 70 | const randomIndex = (Math.floor(Math.random() * artistSongs.length)); 71 | const path = artistSongs[randomIndex].path 72 | const coverData = await window.myAPI.getSongCover(path,1); 73 | // 更新封面 74 | this.$store.state.nowArtistCover = coverData; 75 | this.$router.push({ 76 | name: 'ArtistDetail', 77 | params: { 78 | artist: artist, 79 | }, 80 | }); 81 | }, 82 | } 83 | } 84 | 85 | export const mix5 = { 86 | //改变播放模式并播放 87 | methods: { 88 | setNextSongToPlay(song, index){ 89 | if (this.$store.state.playNextSongs) { 90 | this.$store.state.notChangeNextSong = true 91 | this.$store.state.nextSongs.splice(this.$store.state.nextSongsIndex + 1, 0, song[index]); 92 | }else{ 93 | this.$store.state.nextSongs.unshift(song[index]) 94 | } 95 | }, 96 | changeQueueAndPlay(songs, index) { 97 | if (this.$store.state.selectMode) { 98 | return 99 | } 100 | this.$store.state.playNextSongs = false 101 | this.$store.state.nextSongsIndex = -1 102 | this.$store.state.nextSongs = [] 103 | this.$store.commit('CHANGE_QUEUE_AND_PLAY', { songs, index }); 104 | this.$store.state.showContextMenu =false 105 | if (this.$store.state.toHomeAfterChangeQueue) { 106 | setTimeout(()=>{ 107 | this.$router.push({ name: 'Home' }); 108 | },5) 109 | 110 | } 111 | } 112 | } 113 | } 114 | export const clearShuffledIndex = { 115 | //改变播放模式并播放 116 | methods: { 117 | clearShuffledIndex() { 118 | if (this.$store.state.selectMode) { 119 | return 120 | } 121 | this.$store.commit('CLEAR_SHUFFLED_INDEX'); 122 | } 123 | } 124 | } 125 | //对文本长度的处理 126 | export const textTruncateMixin = { 127 | methods: { 128 | truncateText(text, maxWidth) { 129 | const ellipsisWidth = 30; // 宽度用于省略号的预估值 130 | const availableWidth = maxWidth - ellipsisWidth; 131 | 132 | if (text.length * 8 > availableWidth) { 133 | const truncatedText = text.substring(0, Math.floor(availableWidth / 8)) + '...'; 134 | return truncatedText; 135 | } 136 | 137 | return text; 138 | } 139 | } 140 | } 141 | 142 | -------------------------------------------------------------------------------- /src/pages/AlbumDetail.vue: -------------------------------------------------------------------------------- 1 | 23 | 24 | 40 | 41 | 114 | -------------------------------------------------------------------------------- /src/pages/Albums.vue: -------------------------------------------------------------------------------- 1 | 23 | 24 | 109 | 110 | 196 | -------------------------------------------------------------------------------- /src/pages/ArtistDetail.vue: -------------------------------------------------------------------------------- 1 | 24 | 96 | 106 | 107 | 108 | -------------------------------------------------------------------------------- /src/pages/Artists.vue: -------------------------------------------------------------------------------- 1 | 24 | 25 | 121 | 122 | 217 | 218 | -------------------------------------------------------------------------------- /src/pages/Folders.vue: -------------------------------------------------------------------------------- 1 | 62 | 63 | 149 | 150 | 393 | 394 | -------------------------------------------------------------------------------- /src/pages/Home.vue: -------------------------------------------------------------------------------- 1 | 119 | 120 | 121 | 500 | 753 | -------------------------------------------------------------------------------- /src/pages/Playlists.vue: -------------------------------------------------------------------------------- 1 | 105 | 106 | 248 | 249 | 511 | 512 | -------------------------------------------------------------------------------- /src/pages/Search.vue: -------------------------------------------------------------------------------- 1 | 118 | 119 | 120 | 121 | 336 | 491 | -------------------------------------------------------------------------------- /src/plugins.js: -------------------------------------------------------------------------------- 1 | export const p1 = { 2 | 3 | } 4 | -------------------------------------------------------------------------------- /src/router/index.js: -------------------------------------------------------------------------------- 1 | 2 | // 导入vue-router插件 3 | import VueRouter from "vue-router" 4 | 5 | // 导入组件 6 | import Home from '../pages/Home' 7 | import Search from '../pages/Search' 8 | import Playlists from '../pages/Playlists' 9 | import Library from '../pages/Library' 10 | import Albums from '../pages/Albums' 11 | import AlbumDetail from '../pages/AlbumDetail' 12 | import Artists from '../pages/Artists' 13 | import ArtistDetail from '../pages/ArtistDetail' 14 | import Settings from '../pages/Settings' 15 | import SongsInPlaylist from "@/pages/SongsInPlaylist"; 16 | import SongsInFolder from "@/pages/SongsInFolder"; 17 | import Folders from "@/pages/Folders"; 18 | 19 | 20 | // 创建路由器对象(在路由器对象中配置路由。) 21 | const router = new VueRouter({ 22 | // 在这里配置所有的路由规则。 23 | routes : [ 24 | { 25 | name : 'SongsInFolder', 26 | path : '/SongsInFolder', 27 | component : SongsInFolder, 28 | props : true 29 | }, 30 | { 31 | name : 'Folders', 32 | path : '/Folders', 33 | component : Folders, 34 | props : true 35 | }, 36 | { 37 | name : 'Search', 38 | path : '/Search', 39 | component : Search, 40 | props : true 41 | }, 42 | { 43 | name : 'Home', 44 | path : '/', 45 | component : Home, 46 | props : true, 47 | }, 48 | { 49 | name : 'Playlists', 50 | path : '/Playlists', 51 | component : Playlists, 52 | props : true 53 | }, 54 | { 55 | name : "SongsInPlaylist", 56 | path : '/SongsInPlaylist', 57 | component : SongsInPlaylist, 58 | props:true 59 | }, 60 | { 61 | name : 'Library', 62 | path : '/Library', 63 | component : Library, 64 | props : true 65 | }, 66 | { 67 | name : 'Albums', 68 | path : '/Albums', 69 | component : Albums, 70 | props : true 71 | }, 72 | { 73 | name : 'AlbumDetail', 74 | path: '/AlbumDetail/', 75 | component: AlbumDetail, 76 | props: true 77 | }, 78 | { 79 | name : 'Artists', 80 | path : '/Artists', 81 | component : Artists, 82 | props : true 83 | }, 84 | { 85 | name : 'ArtistDetail', 86 | path: '/ArtistDetail/:artist', 87 | component: ArtistDetail, 88 | props: true 89 | }, 90 | { 91 | name : 'Settings', 92 | path : '/Settings', 93 | component : Settings, 94 | props : true 95 | } 96 | ] 97 | }) 98 | 99 | // 暴露路由器对象(导出路由器对象) 100 | export default router 101 | -------------------------------------------------------------------------------- /src/vuex/store.js: -------------------------------------------------------------------------------- 1 | // 引入Vue,因为下面使用Vuex插件的时候需要Vue 2 | import Vue from 'vue' 3 | //引入歌曲json文件 4 | 5 | // const songsModule = await import('@allSourcesOfSongs/songsNoSameId.json'); 6 | // const songs = songsModule.default; // 注意这里使用 .default 获取导出的数组 7 | // console.log('@allSourcesOfSongs/songsNoSameId.json'); 8 | // console.log(songs); 9 | 10 | // 引入vuex插件 11 | import Vuex from 'vuex' 12 | // 使用插件 13 | Vue.use(Vuex) 14 | //引入播放列表 15 | //import loveSong from '../../public/playlists/loveSong.json' 16 | 17 | const actions = { 18 | // setPlaylist({ commit }, playlist) { 19 | // commit('SET_PLAYLIST', playlist); 20 | // }, 21 | // playSong({ commit, state }, index) { 22 | // const newIndex = state.shuffledIndexList[index]; // 使用乱序索引 23 | // if (newIndex >= 0 && newIndex < state.queue.length) { 24 | // commit('SET_CURRENT_INDEX', newIndex); 25 | // commit('SET_PLAYING_STATE', true); 26 | // } 27 | // }, 28 | prevSong({ commit, state }) { 29 | if (state.modeType[state.nowMode] === "无序") { 30 | if (state.shuffledIndex.length === 0) { 31 | // 如果无序队列索引为空,重新生成 32 | 33 | commit('SHUFFLE_INDEX_LIST'); 34 | } 35 | const currentShuffledIndex = state.shuffledIndex[state.currentIndex]; 36 | let prevShuffledIndex = currentShuffledIndex - 1; 37 | if (prevShuffledIndex < 0) { 38 | prevShuffledIndex = state.shuffledIndex.length - 1; // 重新从末尾开始 39 | } 40 | const prevQueueIndex = state.shuffledIndex.indexOf(prevShuffledIndex); 41 | commit('SET_CURRENT_INDEX', prevQueueIndex); 42 | commit('SET_PLAYING_STATE', true); 43 | }else{ 44 | const prevIndex = (state.currentIndex - 1 + state.queue.length) % state.queue.length; 45 | commit('SET_CURRENT_INDEX', prevIndex); 46 | commit('SET_PLAYING_STATE', true); 47 | } 48 | }, 49 | 50 | nextSong({ commit, state }) { 51 | if (state.modeType[state.nowMode] === "循环" || state.modeType[state.nowMode] === "单曲") { 52 | const nextIndex = (state.currentIndex + 1) % state.queue.length; 53 | commit('SET_CURRENT_INDEX', nextIndex); 54 | commit('SET_PLAYING_STATE', true); 55 | 56 | } 57 | else if(state.modeType[state.nowMode] === "无序"){ 58 | if (state.shuffledIndex.length === 0) { 59 | // 如果无序队列索引为空,重新生成 60 | commit('SHUFFLE_INDEX_LIST'); 61 | } 62 | const currentShuffledIndex = state.shuffledIndex[state.currentIndex]; 63 | // 计算下一首歌的无序索引 64 | let nextShuffledIndex = currentShuffledIndex + 1; 65 | if (nextShuffledIndex >= state.shuffledIndex.length) { 66 | nextShuffledIndex = 0; // 重新从头开始 67 | } 68 | // 根据无序索引获取在队列中的索引 69 | const nextQueueIndex = state.shuffledIndex.indexOf(nextShuffledIndex); 70 | commit('SET_CURRENT_INDEX', nextQueueIndex); 71 | commit('SET_PLAYING_STATE', true); 72 | } 73 | 74 | }, 75 | togglePlay({ commit, state }) { 76 | commit('SET_PLAYING_STATE', !state.isPlaying); 77 | } 78 | } 79 | 80 | const mutations = { 81 | SET_SONGS(state, songs){ 82 | state.songs.songs = songs 83 | }, 84 | SET_PLAYLISTS(state, playlists){ 85 | state.playlists = playlists 86 | }, 87 | SET_VOLUME(state, volume) { 88 | if (volume !== undefined) { 89 | state.volume = volume; 90 | } 91 | 92 | }, 93 | SET_FILTER_TYPE(state, value){ 94 | state.filterType = value; 95 | }, 96 | SET_SELECTED_PLAYLIST_NAME(state,playlistName){ 97 | state.selectedPlaylistName = playlistName 98 | }, 99 | SEARCHSONGS(state, value){ 100 | const keyword = value.toLowerCase(); 101 | 102 | state.searchResults = { 103 | searchedArtists: [], 104 | searchedAlbums: [], 105 | searchedSongs: [] 106 | }; 107 | 108 | state.songs.songs.forEach(song => { 109 | 110 | if (song.artist.toLowerCase().includes(keyword)) { 111 | // 拆分多个艺术家 112 | const artists = song.artist.split('/').map(artist => artist.trim()); 113 | 114 | // 处理组合艺术家 115 | const existingCombinationArtist = state.searchResults.searchedArtists.find(artist => artist.name === song.artist); 116 | if (!existingCombinationArtist) { 117 | state.searchResults.searchedArtists.push({ 118 | name: song.artist, 119 | songs: [song] 120 | }); 121 | } else { 122 | existingCombinationArtist.songs.push(song); 123 | } 124 | 125 | // 处理单个艺术家 126 | artists.forEach(artist => { 127 | if (artist.toLowerCase().includes(keyword)) { 128 | const existingArtist = state.searchResults.searchedArtists.find(a => a.name === artist); 129 | 130 | if (!existingArtist) { 131 | state.searchResults.searchedArtists.push({ 132 | name: artist, 133 | songs: [song] 134 | }); 135 | } else { 136 | // 检查这首歌是否已经存在于该艺术家的歌曲列表中,避免重复添加 137 | if (!existingArtist.songs.find(s => s === song)) { 138 | existingArtist.songs.push(song); 139 | } 140 | } 141 | } 142 | }); 143 | } 144 | 145 | if (song.title.toLowerCase().includes(keyword)) { 146 | state.searchResults.searchedSongs.push(song); 147 | } 148 | 149 | 150 | if (song.album.toLowerCase().includes(keyword)) { 151 | const existingAlbum = state.searchResults.searchedAlbums.find(album => album.name === song.album); 152 | 153 | if (!existingAlbum) { 154 | state.searchResults.searchedAlbums.push({ 155 | name: song.album, 156 | songs: [song] 157 | }); 158 | } else { 159 | existingAlbum.songs.push(song); 160 | } 161 | } 162 | }); 163 | }, 164 | CHANGE_QUEUE_AND_PLAY(state, {songs, index}){ 165 | state.queue = songs; 166 | state.currentIndex = index; 167 | state.isPlaying = true; 168 | }, 169 | CLEAR_SHUFFLED_INDEX(){ 170 | state.shuffledIndex.splice(0, state.shuffledIndex.length); 171 | }, 172 | 173 | SET_CURRENT_INDEX(state, index) { 174 | if (index !== undefined) { 175 | state.currentIndex = index; 176 | } 177 | 178 | }, 179 | 180 | SET_NOW_MODE(state, nowMode) { 181 | if (nowMode !== undefined) { 182 | state.nowMode = nowMode; 183 | } 184 | 185 | }, 186 | SET_IS_MUTE(state, isMute) { 187 | if (isMute !== undefined) { 188 | state.isMute = isMute; 189 | } 190 | 191 | }, 192 | SET_QUEUE(state, queue) { 193 | if (queue !== undefined) { 194 | state.queue = queue; 195 | } 196 | 197 | }, 198 | SET_SHOW_LYRICS(state, showLyrics) { 199 | if (showLyrics !== undefined) { 200 | state.showLyrics = showLyrics; 201 | } 202 | 203 | }, 204 | SET_SHOW_QUEUE(state, showQueue){ 205 | if (showQueue !== undefined) { 206 | state.showQueue = showQueue; 207 | } 208 | 209 | }, 210 | SET_SHOW_FORMAT(state, showFormat){ 211 | if (showFormat !== undefined) { 212 | state.showFormat = showFormat 213 | } 214 | 215 | }, 216 | SET_LYRIC_ALIGNMENT_MODE(state, lyricAlignmentMode){ 217 | if (lyricAlignmentMode !== undefined) { 218 | state.lyricAlignmentMode = lyricAlignmentMode; 219 | } 220 | 221 | }, 222 | SET_TO_HOME_AFTER_CHANGE_QUEUE(state, toHomeAfterChangeQueue) { 223 | if (toHomeAfterChangeQueue !== undefined) { 224 | state.toHomeAfterChangeQueue = toHomeAfterChangeQueue; 225 | } 226 | 227 | }, 228 | SET_AUTO_HIDE_LRC(state, autoHideLrc) { 229 | if (autoHideLrc !== undefined) { 230 | state.autoHideLrc = autoHideLrc; 231 | } 232 | 233 | }, 234 | SET_NOW_SONG_COVER(state, nowSongCover) { 235 | state.nowSongCover = nowSongCover; 236 | }, 237 | 238 | SET_PLAYING_STATE(state, isPlaying) { 239 | state.isPlaying = isPlaying; 240 | // console.log(state.isPlaying?"播放":"暂停") 241 | }, 242 | CHANGE_LYRIC_ALIGNMENT_MODE(state, no){ 243 | state.lyricAlignmentMode = no 244 | }, 245 | CHANGE_MODE_AND_INDEX(state){ 246 | //改变当前mode 247 | state.nowMode < (state.modeType.length-1) ? state.nowMode++ : state.nowMode = 0 248 | //更新乱序队列索引 249 | if (state.modeType[state.nowMode] === "无序") { 250 | let unShuffledIndex = [] 251 | for (let i = 0; i < state.queue.length; i++) { 252 | unShuffledIndex.push(i) 253 | } 254 | //Fisher-Yates洗牌算法,用来打乱unShuffledIndex 255 | for (let i = unShuffledIndex.length - 1; i > 0; i--) { 256 | const j = Math.floor(Math.random() * (i + 1)); 257 | [unShuffledIndex[i], unShuffledIndex[j]] = [unShuffledIndex[j], unShuffledIndex[i]]; 258 | } 259 | state.shuffledIndex = unShuffledIndex 260 | } 261 | }, 262 | //初始化无序播放 263 | SHUFFLE_INDEX_LIST(state) { 264 | const totalSongs = state.queue.length; 265 | state.shuffledIndex = Array.from({ length: totalSongs }, (_, index) => index); 266 | for (let i = totalSongs - 1; i > 0; i--) { 267 | const j = Math.floor(Math.random() * (i + 1)); 268 | [state.shuffledIndex[i], state.shuffledIndex[j]] = [state.shuffledIndex[j], state.shuffledIndex[i]]; 269 | } 270 | }, 271 | SET_SELECT_MODE(state,value){ 272 | state.selectMode = value 273 | }, 274 | SET_HIGHLIGHT(state,value){ 275 | if (value !== undefined) { 276 | state.highlight = value 277 | } 278 | 279 | }, 280 | SET_INFO_MODAL(state,value){ 281 | if (value !== undefined) { 282 | state.infoModal = value 283 | } 284 | 285 | }, 286 | SET_LYRICS_MODAL(state,value){ 287 | if (value !== undefined) { 288 | state.lyricsModal = value 289 | } 290 | 291 | }, 292 | SET_QUEUE_MODAL(state,value){ 293 | if (value !== undefined) { 294 | state.queueModal = value 295 | } 296 | 297 | }, 298 | SET_GLOBAL_SHORTCUT(state,value){ 299 | if (value !== undefined) { 300 | state.globalShortcut = value 301 | } 302 | 303 | }, 304 | SET_SAVED_CURRENT_PLAYTIME(state, value){ 305 | if (value !== undefined) { 306 | state.savedCurrentPlaytime = value 307 | } 308 | 309 | }, 310 | SET_EXIT(state,value){ 311 | if (value !== undefined) { 312 | state.exit = value 313 | } 314 | 315 | }, 316 | DELETE_FROM_PLAYLIST(state,indexArray){ 317 | const playlistName = state.selectedPlaylistName; // 获取选中的播放列表名称 318 | const playlistIndex = state.playlists.findIndex(playlist => playlist.name === playlistName); // 找到播放列表的索引 319 | 320 | if (playlistIndex !== -1) { 321 | const playlist = state.playlists[playlistIndex]; 322 | 323 | // 从后往前删除,以免删除后的索引影响后续元素的删除 324 | indexArray.sort((a, b) => b - a); 325 | indexArray.forEach(index => { 326 | if (index >= 0 && index < playlist.songsId.length) { 327 | playlist.songsId.splice(index, 1); // 删除歌曲 ID 328 | } 329 | }); 330 | } 331 | }, 332 | DELETE_FROM_LIBRARY(state,indexArray){ 333 | indexArray.sort((a, b) => b - a); 334 | indexArray.forEach(index => { 335 | if (index >= 0 && index < state.songs.songs.length) { 336 | state.songs.songs.splice(index, 1); // Delete song object from songs array 337 | } 338 | }); 339 | }, 340 | DELETE_FROM_PLAYLIST2(state,toDeleteSongsId){ 341 | for (let i = 0; i < state.playlists.length; i++) { 342 | const playlist = state.playlists[i]; 343 | playlist.songsId = playlist.songsId.filter(id => !toDeleteSongsId.includes(id)); 344 | } 345 | }, 346 | ADD_TO_PLAYLIST(state, payload) { 347 | const { playlistName, songIds } = payload; 348 | // 找到指定的播放列表 349 | const playlist = state.playlists.find((pl) => pl.name === playlistName); 350 | // 将歌曲 ID 添加到播放列表中 351 | for (const songId of songIds) { 352 | if (!playlist.songsId.includes(songId)) { 353 | playlist.songsId.unshift(songId); 354 | }else{ 355 | state.showIsExist = true 356 | setTimeout(()=>{ 357 | state.showIsExist = false 358 | },2000) 359 | } 360 | } 361 | }, 362 | DELETE_PLAYLIST(state, playlistName) { 363 | const playlistIndex = state.playlists.findIndex(playlist => playlist.name === playlistName); 364 | if (playlistIndex !== -1) { 365 | state.playlists.splice(playlistIndex, 1); 366 | } 367 | }, 368 | SET_CURRENT_PROGRESS(state, progress) { 369 | state.currentProgress = progress; 370 | }, 371 | SET_LYRIC_FONT(state, value) { 372 | if (value !== undefined) { 373 | state.lyricFont = value; 374 | } 375 | 376 | }, 377 | SET_LYRIC_FONT2(state, value) { 378 | if (value !== undefined) { 379 | state.lyricFont2 = value; 380 | } 381 | 382 | }, 383 | SET_ONLINE_LRC(state, value) { 384 | if (value !== undefined) { 385 | state.onlineLrc = value; 386 | } 387 | 388 | }, 389 | SET_LYRIC_DIRECTORY(state, value) { 390 | if (value !== undefined) { 391 | state.lyricDirectory = value; 392 | } 393 | }, 394 | SET_BIGGER_LYRIC(state, value) { 395 | if (value>=0&&value<=15) { 396 | state.biggerLyric = value; 397 | } 398 | }, 399 | SET_SHOW_TLYRIC(state, value) { 400 | if (value !== undefined) { 401 | state.showTlyric = value; 402 | } 403 | 404 | }, 405 | SET_BRIGHT(state, value) { 406 | if (value !== undefined) { 407 | state.bright = value; 408 | } 409 | 410 | }, 411 | SET_BLUR(state, value) { 412 | if (value !== undefined) { 413 | state.blur = value; 414 | } 415 | 416 | }, 417 | SET_SHOW_ALBUMS(state, value) { 418 | if (value !== undefined) { 419 | state.showAlbums = value; 420 | } 421 | 422 | }, 423 | SET_SHOW_ARTISTS(state, value) { 424 | if (value !== undefined) { 425 | state.showArtists = value; 426 | } 427 | 428 | }, 429 | SET_SHOW_FOLDERS(state, value) { 430 | if (value !== undefined) { 431 | state.showFolders = value; 432 | } 433 | }, 434 | SET_OTHER_BLUR(state, value){ 435 | if (value !== undefined) { 436 | state.otherBlur = value; 437 | } 438 | }, 439 | SET_SHORTCUTS(state, value){ 440 | if (value !== undefined) { 441 | state.shortcuts = value; 442 | } 443 | window.myAPI.initializeShortcuts(state.shortcuts) 444 | }, 445 | 446 | SET_DLYRIC_COLOR(state, value){ 447 | if (value !== undefined) { 448 | state.dLyricColor = value; 449 | } 450 | }, 451 | 452 | SET_DLYRIC_COLOR_PURE(state, value){ 453 | if (value !== undefined) { 454 | state.dLyricColorPure = value; 455 | } 456 | }, 457 | 458 | SET_UseEQ(state, value){ 459 | if (value !== undefined) { 460 | state.useEQ = value; 461 | } 462 | }, 463 | 464 | SET_EQPARAM(state, value){ 465 | if (value !== undefined) { 466 | state.EQParam = value; 467 | } 468 | }, 469 | 470 | SET_USE_PURE_COLOR(state, value){ 471 | if (value !== undefined) { 472 | state.usePureColor = value; 473 | } 474 | }, 475 | 476 | SET_BOLD_LRC(state, value){ 477 | if (value !== undefined) { 478 | state.boldLrc = value; 479 | } 480 | }, 481 | 482 | SET_SHOW_SPECTRUM(state, value){ 483 | if (value !== undefined) { 484 | state.showSpectrum = value; 485 | } 486 | }, 487 | 488 | SET_PFONT(state, value){ 489 | if (value !== undefined) { 490 | state.pFont = value; 491 | } 492 | }, 493 | 494 | SET_DFONT(state, value){ 495 | if (value !== undefined) { 496 | state.dFont = value; 497 | } 498 | }, 499 | 500 | SET_SPECTRUM_SPEED(state, value){ 501 | if (value !== undefined) { 502 | state.spectrumSpeed = value; 503 | } 504 | }, 505 | 506 | SET_SHOW_SONG_INFO(state, value){ 507 | if (value !== undefined) { 508 | state.showSongInfo = value; 509 | } 510 | }, 511 | SET_USE_BACK_COVER(state, value){ 512 | if (value !== undefined) { 513 | state.useBackCover = value; 514 | } 515 | }, 516 | SET_BACK_COVER_PATH(state, value){ 517 | if (value !== undefined) { 518 | state.backCoverPath = value; 519 | } 520 | }, 521 | SET_ROTATE_COVER(state, value){ 522 | if (value !== undefined) { 523 | state.rotateCover = value; 524 | } 525 | }, 526 | SET_VOLUME_CHANGE(state, value){ 527 | if (value !== undefined) { 528 | state.volumeChange = value; 529 | } 530 | }, 531 | SET_DOWNLOAD_ONLINE_IMG(state, value){ 532 | if (value !== undefined) { 533 | state.downloadOnlineImg = value; 534 | } 535 | }, 536 | SET_MATCH_BLANK(state, value){ 537 | if (value !== undefined) { 538 | state.matchBlank = value; 539 | } 540 | }, 541 | 542 | SET_CHECK(state, value) { 543 | if (value !== undefined) { 544 | state.check = value; 545 | } 546 | 547 | }, 548 | RENAME_PLAYLIST(state, { oldName, newName }){ 549 | const playlistIndex = state.playlists.findIndex(playlist => playlist.name === oldName); 550 | if (playlistIndex !== -1) { 551 | Vue.set(state.playlists, playlistIndex, { ...state.playlists[playlistIndex], name: newName }); 552 | } else { 553 | console.log("未找到匹配的播放列表"); 554 | } 555 | }, 556 | } 557 | 558 | const state = { 559 | check: null, 560 | nowVersion: "1.0.8", 561 | latestVersion: null, 562 | latestVersionInfo: "", 563 | errorMessage:"请开启自动检查更新", 564 | songs : {songs :[]}, 565 | miniMode: false, 566 | playlists : [], //用户拥有的列表 567 | playlistsCovers: [], 568 | backCoverPath: "C:\\Users\\30595\\Desktop\\原壁纸.jpg", 569 | backCover: null, 570 | useBackCover: false, 571 | defaultCover: null, 572 | selectedPlaylistName :'', 573 | //过滤方式 574 | filterType : '', 575 | searchResults : { 576 | searchedArtists : [], 577 | searchedAlbums : [], 578 | searchedSongs : [] 579 | }, 580 | queue: [ 581 | ], //当前播放队列 582 | shuffledIndex : [], //无序队列索引 583 | currentIndex: 0, // 当前播放索引 584 | isPlaying: false, // 播放状态 585 | modeType : ['循环','无序','单曲'], //播放模式类型 586 | nowMode : 0, //当前播放模式 587 | volume: 18, 588 | isMute : false, 589 | selectMode: false, 590 | showSongInfo: true, 591 | currentProgress: 0, 592 | showIsExist : false, 593 | moreInfoOfNowSong : null, 594 | lyricOfNowSong : "加载歌词中", 595 | homeLyric:[], 596 | currentPlayTime : 0, 597 | currentLyricIndex: 0, 598 | nowSongTime:0, 599 | showLyrics : true, 600 | lyricFont : 20, 601 | lyricFont2 : 15, 602 | biggerLyric : 10, 603 | volumeChange : 3, 604 | showQueue : true, 605 | nowSongCover : null, 606 | nowArtistCover : null, 607 | nowAlbumCover : null, 608 | toHomeAfterChangeQueue : true, 609 | autoHideLrc : true, 610 | lyricAlignmentType : ["left","center","right"], 611 | lyricAlignmentMode : 0, 612 | highlight : false, 613 | showInfo : true, 614 | showFormat : true, 615 | blockSpace : false, 616 | queueModal : true, 617 | infoModal : false, 618 | lyricsModal : false, 619 | exit : false, 620 | globalShortcut : false, 621 | deleteLocalFile : false, 622 | savedCurrentPlaytime : 0, 623 | onlineLrc:false, 624 | downloadOnlineImg:true, 625 | lyricDirectory:"未设置", 626 | nowSongNetId: -1, 627 | indexInLibrary: -1, 628 | showContextMenu:false, 629 | songDialogInfo:null, 630 | nowSongDialogInfo:null, 631 | playNextSongs: false, 632 | nextSongs:[], 633 | nextSongsIndex:-1, 634 | notChangeNextSong: false, 635 | showTlyric: true, 636 | bright: 100, 637 | blur: 40, 638 | otherBlur:false, 639 | folders:[], 640 | selectedFolderPath:'', 641 | showAlbums: true, 642 | showArtists: true, 643 | showFolders: true, 644 | focusMode: false, 645 | focusMode2: true, 646 | deckTopLyric: false, 647 | dLyricColor: ["#FFA6B7","#1E2AD2"], 648 | dLyricColorPure: "#03A9F4", 649 | usePureColor: false, 650 | EQParam: [0,0,0,0,0,0,0,0,0,0], 651 | useEQ: false, 652 | boldLrc: true, 653 | dataArray:[], 654 | matchBlank: true, 655 | showSpectrum: false, 656 | rotateCover: true, 657 | spectrumSpeed: 0.5, 658 | pFont: "微软雅黑", 659 | dFont: "微软雅黑", 660 | shortcuts: { 661 | "local": { 662 | "lExit": "Escape", 663 | "lToggle": "Space", 664 | "lLast": "Ctrl+Left", 665 | "lNext": "Ctrl+Right", 666 | "lBack3": "Left", 667 | "lForward3": "Right", 668 | "lUpVolume": "Up", 669 | "lDownVolume": "Down", 670 | "lFullScreen": "F11", 671 | "lMiniSize": "Ctrl+M", 672 | "lToHome": "Ctrl+Z", 673 | "lSettings": "Ctrl+S", 674 | "lLoopMode": "Ctrl+O", 675 | "lMute": "Ctrl+N", 676 | "lSearch": "Ctrl+F", 677 | "lQueue": "Ctrl+Q", 678 | "lLyric": "Ctrl+L", 679 | "lInfo": "Ctrl+I", 680 | "lPlaylists": "Ctrl+P", 681 | "lDesktopLyric": "Ctrl+D", 682 | "lFocusMode": "Ctrl+Enter" 683 | }, 684 | "global": { 685 | "gOpen": "Alt+F10", 686 | "gToggle": "Alt+F9", 687 | "gLast": "Alt+F11", 688 | "gNext": "Alt+F12", 689 | "gUpVolume": "Alt+F7", 690 | "gDownVolume": "Alt+F6", 691 | "gLoopMode": "Alt+F5", 692 | "gMute": "Alt+F8", 693 | "gDesktopLyric": "Alt+F1", 694 | "gExit": "Alt+E" 695 | } 696 | } 697 | } 698 | 699 | const getters = { 700 | filteredSongs: state => { 701 | if (state.filterType === 'byAlbums') { 702 | const albumsMap = new Map(); 703 | // Group songs by album name 704 | state.songs.songs.forEach((song) => { 705 | if (!albumsMap.has(song.album)) { 706 | albumsMap.set(song.album, []); 707 | } 708 | albumsMap.get(song.album).push(song); 709 | }); 710 | // Create albums array 711 | const albums = []; 712 | albumsMap.forEach((songs, album) => { 713 | albums.push({ 714 | name: album, 715 | songs 716 | }); 717 | }); 718 | 719 | return albums; 720 | 721 | } 722 | else if (state.filterType === 'byArtists') { 723 | const artistsMap = new Map(); 724 | // Group songs by artist name 725 | state.songs.songs.forEach((song) => { 726 | 727 | const artists = song.artist.split('/'); 728 | artists.forEach((artist) => { 729 | artist = artist.trim() 730 | if (!artistsMap.has(artist)) { 731 | artistsMap.set(artist, []); 732 | } 733 | artistsMap.get(artist).push(song); 734 | }); 735 | }); 736 | // Create artists array 737 | const artists = []; 738 | artistsMap.forEach((songs, artist) => { 739 | artists.push({ 740 | name: artist, 741 | songs 742 | }); 743 | }); 744 | 745 | return artists; 746 | } 747 | else if(state.filterType === 'byPlaylist'){ 748 | if (state.selectedPlaylistName != null) { 749 | const selectedPlaylist = state.playlists.find(playlist => playlist.name === state.selectedPlaylistName); 750 | if (selectedPlaylist) { 751 | const songsInSelectedPlaylist = selectedPlaylist.songsId.map(songId => { 752 | const song = state.songs.songs.find(song => song.id === songId); 753 | return song ? song : null; // Return song if found, otherwise null 754 | }); 755 | return songsInSelectedPlaylist.filter(song => song !== null); 756 | } 757 | } 758 | } 759 | else if(state.filterType === 'byFolder'){ 760 | const existingIndex = state.folders.findIndex(folder => folder.path === state.selectedFolderPath); 761 | if (existingIndex !== -1) { 762 | return state.folders[existingIndex].songs 763 | } 764 | } 765 | else { 766 | return state.songs.songs; 767 | } 768 | }, 769 | nowSong(state) { 770 | if (state.playNextSongs) { 771 | return state.nextSongs[state.nextSongsIndex] 772 | }else{ 773 | if (state.currentIndex >= 0 && state.currentIndex < state.queue.length) { 774 | return state.queue[state.currentIndex]; 775 | } 776 | return null; 777 | } 778 | } 779 | } 780 | // 简写形式 781 | export default new Vuex.Store({actions,mutations,state,getters}) 782 | -------------------------------------------------------------------------------- /vue.config.js: -------------------------------------------------------------------------------- 1 | const { defineConfig } = require('@vue/cli-service') 2 | module.exports = defineConfig({ 3 | transpileDependencies: true, 4 | lintOnSave: false, 5 | publicPath : './', 6 | pluginOptions:{ 7 | electronBuilder:{ 8 | nodeIntegration:true 9 | } 10 | } 11 | }) 12 | --------------------------------------------------------------------------------