From dfda000823445d6179e8d8771eab472ff626295f Mon Sep 17 00:00:00 2001 From: intergrav Date: Mon, 13 Jul 2026 13:14:13 -0400 Subject: [PATCH] refactor: various improvements MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - cleaned up dup loading code - improve icon and locale loadinmg - dialog/settings simplifications - update dependencies - some other things sorry i should have split this into multiple commits im sleepy 🐈 --- biome.json | 2 +- flake.nix | 2 +- index.html | 2 +- knip.json | 1 - package-lock.json | 499 +++++++++++++++++--- package.json | 19 +- src/app.css | 1 - src/lib/Library.svelte | 23 +- src/lib/NowPlaying.svelte | 3 +- src/lib/app.svelte.ts | 2 + src/lib/auth.svelte.ts | 56 +-- src/lib/client.svelte.ts | 12 +- src/lib/dialogs/AuthModal.svelte | 2 +- src/lib/dialogs/SettingsModal.svelte | 41 +- src/lib/dialogs/ShareModal.svelte | 34 +- src/lib/dialogs/UnsyncedChangesModal.svelte | 9 +- src/lib/icons/Icon.svelte | 6 +- src/lib/icons/index.ts | 19 +- src/lib/icons/packs.svelte.ts | 11 +- src/lib/languages/locales.svelte.ts | 11 +- src/lib/library.svelte.ts | 19 +- src/lib/theme.svelte.ts | 13 +- src/main.ts | 5 +- tsconfig.node.json | 2 +- vite.config.ts | 3 - 25 files changed, 569 insertions(+), 228 deletions(-) diff --git a/biome.json b/biome.json index 7ec4861..6127ee9 100644 --- a/biome.json +++ b/biome.json @@ -1,5 +1,5 @@ { - "$schema": "https://biomejs.dev/schemas/2.5.2/schema.json", + "$schema": "https://biomejs.dev/schemas/2.5.3/schema.json", "vcs": { "enabled": true, "clientKind": "git", diff --git a/flake.nix b/flake.nix index 2013855..a491696 100644 --- a/flake.nix +++ b/flake.nix @@ -19,7 +19,7 @@ version = "2.36.8"; src = ./.; - npmDepsHash = "sha256-YkdBHUx6p61mMBSJCXNA3lbQ8Rd92F7CNJ7J+315Pug="; + npmDepsHash = "sha256-Loy++nRVvQBSmNyKJ4XPTVZdLwQdnKTb0uf4E3jQpiY="; npmBuildScript = "build"; installPhase = '' diff --git a/index.html b/index.html index 8b1de42..3344c66 100644 --- a/index.html +++ b/index.html @@ -10,7 +10,7 @@ - + =16.20.0" + } + }, + "node_modules/@typescript/typescript-darwin-arm64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-darwin-arm64/-/typescript-darwin-arm64-7.0.2.tgz", + "integrity": "sha512-gowzar9MwS/aRWp6f3a4KUqzRjAZjOsmGNCM6LcTgXum+dBfgsBVMN+AgvOCCbguXyick6LJhpBszxMebJ8syA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-darwin-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-darwin-x64/-/typescript-darwin-x64-7.0.2.tgz", + "integrity": "sha512-SZ9xZInqApNlNGc9s0W1VSsktYSOe9cFqNOIqmN1Gs8SmkjKZYFt017G4VwPxASInODuAdbTW7sXiFUf893RgA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-freebsd-arm64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-freebsd-arm64/-/typescript-freebsd-arm64-7.0.2.tgz", + "integrity": "sha512-W5NH4y/J0plIIS5b2xvTEkU7JFxyqdMAOgf+Ilhl0vHQXKO5dZoxd+C/jEtq56c4F3wk71RB4BMRQ2XdI+bwYQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-freebsd-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-freebsd-x64/-/typescript-freebsd-x64-7.0.2.tgz", + "integrity": "sha512-UMGDx5sTpzNw3WiPebH7l90IWfJggEd+egHt/q6p7/Cm3zqoV7VxkGXt+3DxPIw8CcmvAB0j3sVVfbhX+M4Tpw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-arm": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-arm/-/typescript-linux-arm-7.0.2.tgz", + "integrity": "sha512-gffT3xPz9sR7j/YJExkyPntrI0P2EP9XbOyWzth2/Gs0RstK+90RBcO0ncXoXy/beYll1SXw846Nf2zdnEz0QQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-arm64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-arm64/-/typescript-linux-arm64-7.0.2.tgz", + "integrity": "sha512-Qh4eU4/y3yDjnfjjyPYihMj5/ODIlmt+Bzu17OI+fiSRDW57QmU5SiN63exPRNJPKUzcc1INa1NXdrJ+MqHjUQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-loong64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-loong64/-/typescript-linux-loong64-7.0.2.tgz", + "integrity": "sha512-uEHck9i8hoAzXPiYRib1O7miOnz23SxIeVl6F4LXox+qov1K35jHcEW6VHKvZI+pyvl7fZEP4MCU5LYvIq1GuQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-mips64el": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-mips64el/-/typescript-linux-mips64el-7.0.2.tgz", + "integrity": "sha512-R4KvAMnE43W5Qeqb0Ly56O3mWMWIAgsMyz36DCaycd5nbg/9kzm0liw3JocfRqyJY0KPmzFjbswozXyW0DnIYA==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-ppc64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-ppc64/-/typescript-linux-ppc64-7.0.2.tgz", + "integrity": "sha512-DORx5b3sd/4S7eayxm4FQv+A7CrkUIGRaHiwI8oiHTAI1fAPWhF4J0vAlkC8biAlHSVVwxMQ3tjZ2/DVbnQiiA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-riscv64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-riscv64/-/typescript-linux-riscv64-7.0.2.tgz", + "integrity": "sha512-wf0jqEDOjrPRnKwYRyyJDRo11KMbvMFrU+q4zqKyChODBzvlkbhNQfKvLxQCcwTpdDaXSHZTVuh0JoCrKCUMHQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-s390x": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-s390x/-/typescript-linux-s390x-7.0.2.tgz", + "integrity": "sha512-IkwJc3L7yhytWd/ewjyxNDfOmswCm9GWMJT/ue/dU4aZNbwZeYAetq42VyLmsmSjvoX7z74X6ZaYCtzAr0EuGw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-x64/-/typescript-linux-x64-7.0.2.tgz", + "integrity": "sha512-EYdf2cNg7rgCWJnxCdJ+F3V39O8ihb37eHAu1LK8oAFizgTQbPOK7zHHXbPt8rX24COqODXeI3sIf0fCXG7H/A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-netbsd-arm64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-netbsd-arm64/-/typescript-netbsd-arm64-7.0.2.tgz", + "integrity": "sha512-+polYF4MF04aPpO5FTkHran9yUQDSXqy5GiSDKpsll5jy3l3+g9QLhpf39T+ePtefhXLOGrLl0QIjkQP6VnelA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-netbsd-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-netbsd-x64/-/typescript-netbsd-x64-7.0.2.tgz", + "integrity": "sha512-8YIT0EHM/3dq10ZOVF/A7pc/YSMtbcecct4rWtexrnSCHOPcpC2KTLXfTCR6vDpnSiY12heNb1GiN/wu+T/FyA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-openbsd-arm64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-openbsd-arm64/-/typescript-openbsd-arm64-7.0.2.tgz", + "integrity": "sha512-APT8+ClYnuYm1u9+kgGXoMj2VzWzcymwh2gNSQVySHfkRDGOTVkoWLjCmOQSaO+PoqQ57B0flRp9SA+7GnnkzQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-openbsd-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-openbsd-x64/-/typescript-openbsd-x64-7.0.2.tgz", + "integrity": "sha512-yX7s+Q0Dln0Dt9tEzZsAjXXR/+ytBM7AlglaqyeMPxQszJ1JhlJdZ6jLA+IzldHtflX81em7lDao1xXu+aRRkg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-sunos-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-sunos-x64/-/typescript-sunos-x64-7.0.2.tgz", + "integrity": "sha512-dLJDGaLZ1D4HPQn62u1n8mBDkJREwMsAkCdkwd4Ieqw+x3TUyTsqY0YiBCtE6H6OzzgGk3iuZ3vFWRS+E8/d1g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-win32-arm64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-win32-arm64/-/typescript-win32-arm64-7.0.2.tgz", + "integrity": "sha512-Gyl1Vy6OsWesLzmq+EP0Fb7b4Nid5232AvcA2SFcdYreldpNtYFFofPjnt62y9hQy7VTaZp65ICJjuAQRaVcIQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-win32-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-win32-x64/-/typescript-win32-x64-7.0.2.tgz", + "integrity": "sha512-0BQ3HkAHHlKLSp1qRvf3SUhGpGsDuhB/jgFw75guyqbxJqEaS0Cw/VFO8i2nHglJUzQCRtMMR/IBAKE3ETMC4g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=16.20.0" + } + }, "node_modules/@vite-pwa/assets-generator": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/@vite-pwa/assets-generator/-/assets-generator-1.0.2.tgz", @@ -6010,9 +6350,9 @@ } }, "node_modules/knip": { - "version": "6.24.0", - "resolved": "https://registry.npmjs.org/knip/-/knip-6.24.0.tgz", - "integrity": "sha512-PokLlgeEjLh1rAsB7ts+52wZ37HBr1nDhE6NNONwEaXdeZGCJOkP7ZlIAI2Gtu8xohquzTWy75bc/1diI9shQw==", + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/knip/-/knip-6.26.0.tgz", + "integrity": "sha512-e9eELEEpBpGTd4H4HB7818/DYj9dMzMyUqAddfYwUN/EbSkgIjOuWEF96W/xHsmV0SDrsdXjIM+oZ2xpPzPsBA==", "dev": true, "funding": [ { @@ -6363,9 +6703,9 @@ } }, "node_modules/lucide-static": { - "version": "1.23.0", - "resolved": "https://registry.npmjs.org/lucide-static/-/lucide-static-1.23.0.tgz", - "integrity": "sha512-V4tqLEHfvsptGaAZMD8sFJKeGsz2nTAU0+ctxTX3afao/5bs+mhrvvGDmvQmyI7YhQwpIFodZmnkPTMYyGzH4Q==", + "version": "1.24.0", + "resolved": "https://registry.npmjs.org/lucide-static/-/lucide-static-1.24.0.tgz", + "integrity": "sha512-NDSgPb/RWllI9QooPbGXfQCXQi/45oquDmtljeN3qVxqfEUf91uM2C4zijy8bs+pEWxKckA0/WZLZT43YD4Xnw==", "dev": true, "license": "ISC" }, @@ -7587,9 +7927,9 @@ } }, "node_modules/svelte-check": { - "version": "4.7.1", - "resolved": "https://registry.npmjs.org/svelte-check/-/svelte-check-4.7.1.tgz", - "integrity": "sha512-FGUOmAqxXdN/H9Zm8slrqO7SLtFisXRB7rfOsHNJ3MLTD2po/+Stg8XyErkpumPHbuUiYTcqrEIzxpVWKTLqtg==", + "version": "4.7.2", + "resolved": "https://registry.npmjs.org/svelte-check/-/svelte-check-4.7.2.tgz", + "integrity": "sha512-GoS4XJdGswlq0rIT1vtFLzJY1bvHtY37McY9H9Gkm1Ggw/ICdZYn8J/Z8Yi0BEL0i3R4+jtaWVePjyppMlij/A==", "dev": true, "license": "MIT", "dependencies": { @@ -7793,17 +8133,38 @@ } }, "node_modules/typescript": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz", - "integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-7.0.2.tgz", + "integrity": "sha512-8FYau96o3NKOhbjKi/qNvG/W5jhzxkbdm5sj9AbZ/5T5sWqn3hJgLfGx27sRKZWTvyzCP8dLRBTf5tBTSRVUNA==", "dev": true, "license": "Apache-2.0", "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" + "tsc": "bin/tsc" }, "engines": { - "node": ">=14.17" + "node": ">=16.20.0" + }, + "optionalDependencies": { + "@typescript/typescript-aix-ppc64": "7.0.2", + "@typescript/typescript-darwin-arm64": "7.0.2", + "@typescript/typescript-darwin-x64": "7.0.2", + "@typescript/typescript-freebsd-arm64": "7.0.2", + "@typescript/typescript-freebsd-x64": "7.0.2", + "@typescript/typescript-linux-arm": "7.0.2", + "@typescript/typescript-linux-arm64": "7.0.2", + "@typescript/typescript-linux-loong64": "7.0.2", + "@typescript/typescript-linux-mips64el": "7.0.2", + "@typescript/typescript-linux-ppc64": "7.0.2", + "@typescript/typescript-linux-riscv64": "7.0.2", + "@typescript/typescript-linux-s390x": "7.0.2", + "@typescript/typescript-linux-x64": "7.0.2", + "@typescript/typescript-netbsd-arm64": "7.0.2", + "@typescript/typescript-netbsd-x64": "7.0.2", + "@typescript/typescript-openbsd-arm64": "7.0.2", + "@typescript/typescript-openbsd-x64": "7.0.2", + "@typescript/typescript-sunos-x64": "7.0.2", + "@typescript/typescript-win32-arm64": "7.0.2", + "@typescript/typescript-win32-x64": "7.0.2" } }, "node_modules/unbash": { @@ -7983,16 +8344,16 @@ } }, "node_modules/vite": { - "version": "8.1.3", - "resolved": "https://registry.npmjs.org/vite/-/vite-8.1.3.tgz", - "integrity": "sha512-Ds+gBRbj0lwRO2Y5hwnUBdxSwlAve9LeRyU4sNnAr0ewW0gWF0n5bgXgUzbgZ49MV9BVUAQUFYVcDUcilUExMA==", + "version": "8.1.4", + "resolved": "https://registry.npmjs.org/vite/-/vite-8.1.4.tgz", + "integrity": "sha512-bTT9PsdWO+MQMNG9ZXIP/qM9wGh37DFxTV/sPq9cFpHr3w4jkgef032PkAL9jAqhk3Nz8NQw3O8n6/xFkqO4QQ==", "dev": true, "license": "MIT", "dependencies": { "lightningcss": "^1.32.0", - "picomatch": "^4.0.4", + "picomatch": "^4.0.5", "postcss": "^8.5.16", - "rolldown": "~1.1.3", + "rolldown": "~1.1.4", "tinyglobby": "^0.2.17" }, "bin": { diff --git a/package.json b/package.json index 0ddf91e..74dc1b9 100644 --- a/package.json +++ b/package.json @@ -3,8 +3,9 @@ "version": "2.36.8", "type": "module", "scripts": { + "generate:pwa-assets": "pwa-assets-generator", "dev": "vite", - "build": "vite build --mode production", + "build": "vite build", "preview": "vite preview", "check:svelte": "svelte-check --tsconfig ./tsconfig.app.json", "check:tsc": "tsc --noEmit", @@ -14,24 +15,24 @@ "fix": "biome check --write" }, "devDependencies": { - "@biomejs/biome": "2.5.2", + "@biomejs/biome": "2.5.3", "@intergrav/famfamfam-silk-svg": "^1.0.0", - "@sveltejs/vite-plugin-svelte": "^7.1.2", + "@sveltejs/vite-plugin-svelte": "^7.2.0", "@tsconfig/svelte": "^5.0.8", "@types/colorthief": "^2.6.1", - "@types/node": "^26.1.0", + "@types/node": "^26.1.1", "@types/spark-md5": "^3.0.5", "@vite-pwa/assets-generator": "^1.0.2", "colorthief": "^3.4.0", "heroicons": "^2.2.0", - "knip": "^6.24.0", - "lucide-static": "^1.23.0", + "knip": "^6.26.0", + "lucide-static": "^1.24.0", "modern-normalize": "^3.0.1", "spark-md5": "^3.0.2", "svelte": "^5.56.4", - "svelte-check": "^4.7.1", - "typescript": "~6.0.3", - "vite": "^8.1.3", + "svelte-check": "^4.7.2", + "typescript": "~7.0.2", + "vite": "^8.1.4", "vite-plugin-pwa": "^1.3.0", "workbox-window": "^7.4.1" } diff --git a/src/app.css b/src/app.css index 0f844c5..8118752 100644 --- a/src/app.css +++ b/src/app.css @@ -16,7 +16,6 @@ --radius-sm: 2px; --radius-md: 4px; - --radius-lg: 8px; } html { diff --git a/src/lib/Library.svelte b/src/lib/Library.svelte index 988fb7c..36c7c05 100644 --- a/src/lib/Library.svelte +++ b/src/lib/Library.svelte @@ -14,6 +14,17 @@ import TreeItem from "./TreeItem.svelte"; let query = $state(""), results = $state | null>(null); +const simpleAlbumTypes: AlbumListType[] = [ + "random", + "newest", + "highest", + "frequent", + "recent", + "alphabeticalByName", + "alphabeticalByArtist", + "starred", +]; + let expanded = $state({ artists: true, playlists: true, @@ -39,17 +50,7 @@ function parseAlbumsPrefix(raw: string): { if (!match) return null; const typePart = match[1]; const arg = match[2]?.trim(); - const validSimple: AlbumListType[] = [ - "random", - "newest", - "highest", - "frequent", - "recent", - "alphabeticalByName", - "alphabeticalByArtist", - "starred", - ]; - const normalizedType = validSimple.find( + const normalizedType = simpleAlbumTypes.find( (t) => t.toLowerCase() === typePart.toLowerCase(), ); if (normalizedType) return { type: normalizedType }; diff --git a/src/lib/NowPlaying.svelte b/src/lib/NowPlaying.svelte index 57c9435..a6d287d 100644 --- a/src/lib/NowPlaying.svelte +++ b/src/lib/NowPlaying.svelte @@ -39,8 +39,7 @@ let currentLine = $derived(lyrics.sync[currentLineIndex]?.text || ""); async function loadLyrics() { const track = player.track; - if (!track) return; - if (isRadio(track)) { + if (!track || isRadio(track)) { lyrics.full = ""; lyrics.sync = []; return; diff --git a/src/lib/app.svelte.ts b/src/lib/app.svelte.ts index e3b0e63..43d6d05 100644 --- a/src/lib/app.svelte.ts +++ b/src/lib/app.svelte.ts @@ -7,6 +7,7 @@ export * from "./settings.svelte.js"; export * from "./ui.svelte.js"; import { restoreSession } from "./auth.svelte.js"; +import { ensureIconPack } from "./icons/packs.svelte.js"; import { rtlLangs } from "./languages/index.js"; import { ensureLocale } from "./languages/locales.svelte.js"; import { offlineManager } from "./offline/offlineManager.svelte.js"; @@ -116,6 +117,7 @@ $effect.root(() => { $effect(() => { if (!ui.busy) { void ensureLocale(settings.lang); + void ensureIconPack(settings.iconPack); document.documentElement.lang = settings.lang; document.documentElement.dir = rtlLangs.has(settings.lang) ? "rtl" diff --git a/src/lib/auth.svelte.ts b/src/lib/auth.svelte.ts index de44d82..92ad362 100644 --- a/src/lib/auth.svelte.ts +++ b/src/lib/auth.svelte.ts @@ -14,6 +14,25 @@ import { syncQueue } from "./queue.svelte.js"; const isAdminRole = (role: unknown) => role === true || role === "true"; +const loadSessionData = async (username: string) => { + let admin = false; + const tasks: Promise[] = [loadLib(), syncQueue()]; + if (username) { + tasks.push( + api + .getUser(username) + .then((user) => { + admin = isAdminRole(user.adminRole); + }) + .catch((err) => { + console.error("failed to fetch user info:", err); + }), + ); + } + await Promise.all(tasks); + return admin; +}; + export const auth = $state({ loggedIn: false, busy: false, @@ -78,23 +97,7 @@ export const login = async ( } } - let admin = false; - const tasks: Promise[] = [loadLib(), syncQueue()]; - - if (username) { - tasks.push( - api - .getUser(username) - .then((user) => { - admin = isAdminRole(user.adminRole); - }) - .catch((err) => { - console.error("failed to fetch user info:", err); - }), - ); - } - - await Promise.all(tasks); + const admin = await loadSessionData(username); persistCredentials(); offlineManager.setConnected(); @@ -128,27 +131,10 @@ export const logout = async () => { export const isOwner = (owner?: string | null) => !owner || !auth.user || owner.toLowerCase() === auth.user.toLowerCase(); -const refreshSession = async () => { - const tasks: Promise[] = [loadLib(), syncQueue()]; - if (auth.user) { - tasks.push( - api - .getUser(auth.user) - .then((user) => { - auth.admin = isAdminRole(user.adminRole); - }) - .catch((err) => { - console.error("failed to fetch user info:", err); - }), - ); - } - await Promise.all(tasks); -}; - export const reconnectSession = async () => { try { await detectExtensions(); - await refreshSession(); + auth.admin = await loadSessionData(auth.user); } catch (err) { console.error("failed to reconnect session:", err); } diff --git a/src/lib/client.svelte.ts b/src/lib/client.svelte.ts index 1ee7080..eac7b9c 100644 --- a/src/lib/client.svelte.ts +++ b/src/lib/client.svelte.ts @@ -759,10 +759,14 @@ let sparkMd5Promise: Promise | null = null; export const createToken = async (password: string) => { const salt = Math.random().toString(36).substring(2, 8); - if (!sparkMd5Promise) - sparkMd5Promise = import("spark-md5").then( - (mod) => ("default" in mod ? mod.default : mod) as SparkMd5Lib, - ); + if (!sparkMd5Promise) { + sparkMd5Promise = import("spark-md5") + .then((mod) => ("default" in mod ? mod.default : mod) as SparkMd5Lib) + .catch((err: unknown) => { + sparkMd5Promise = null; + throw err; + }); + } const SparkMD5 = await sparkMd5Promise; return { token: SparkMD5.hash(password + salt), salt }; }; diff --git a/src/lib/dialogs/AuthModal.svelte b/src/lib/dialogs/AuthModal.svelte index 1bb6c07..9f5be8c 100644 --- a/src/lib/dialogs/AuthModal.svelte +++ b/src/lib/dialogs/AuthModal.svelte @@ -63,7 +63,7 @@ $effect(() => { console.warn("failed to fetch extensions anonymously:", err); } } - } catch (err) { + } catch { if (server !== requestServer) return; pingStatus = "fail"; } diff --git a/src/lib/dialogs/SettingsModal.svelte b/src/lib/dialogs/SettingsModal.svelte index 89e5f5e..0d46552 100644 --- a/src/lib/dialogs/SettingsModal.svelte +++ b/src/lib/dialogs/SettingsModal.svelte @@ -1,6 +1,6 @@ {#if iconPack === "silk16" && iconPacks[iconPack]?.[name]} diff --git a/src/lib/icons/index.ts b/src/lib/icons/index.ts index 0f5bb1a..98923f7 100644 --- a/src/lib/icons/index.ts +++ b/src/lib/icons/index.ts @@ -25,14 +25,17 @@ const iconNames = [ export type IconName = (typeof iconNames)[number]; -export const iconPackNames = [ - "heroicons16solid", - "heroicons20solid", - "heroicons24solid", - "heroicons24outline", - "lucide24", - "silk16", +export const iconPacks = [ + { id: "heroicons16solid", label: "heroicons (16 solid)", size: 16 }, + { id: "heroicons20solid", label: "heroicons (20 solid)", size: 20 }, + { id: "heroicons24solid", label: "heroicons (24 solid)", size: 24 }, + { id: "heroicons24outline", label: "heroicons (24 outline)", size: 24 }, + { id: "lucide24", label: "lucide (24)", size: 24 }, + { id: "silk16", label: "silk (16)", size: 16 }, ] as const; -export type IconPackName = (typeof iconPackNames)[number]; +export type IconPackName = (typeof iconPacks)[number]["id"]; +export const iconPackNames: readonly IconPackName[] = iconPacks.map( + (pack) => pack.id, +); export type IconPack = Record; diff --git a/src/lib/icons/packs.svelte.ts b/src/lib/icons/packs.svelte.ts index 0bd33d7..2884e57 100644 --- a/src/lib/icons/packs.svelte.ts +++ b/src/lib/icons/packs.svelte.ts @@ -20,7 +20,12 @@ export async function ensureIconPack(name: IconPackName): Promise { const load = iconPackLoaders[`./packs/${name}.ts`]; if (!load) return heroicons16solid; - const { default: iconPack } = await load(); - iconPacks[name] = iconPack; - return iconPack; + try { + const { default: iconPack } = await load(); + iconPacks[name] = iconPack; + return iconPack; + } catch (err) { + console.error("failed to load icon pack:", name, err); + return heroicons16solid; + } } diff --git a/src/lib/languages/locales.svelte.ts b/src/lib/languages/locales.svelte.ts index 7a048e3..afb409c 100644 --- a/src/lib/languages/locales.svelte.ts +++ b/src/lib/languages/locales.svelte.ts @@ -20,9 +20,14 @@ export async function ensureLocale(lang: LangCode): Promise { const load = localeLoaders[`./locales/${lang}.ts`]; if (!load) return en; - const { default: locale } = await load(); - loadedLocales[lang] = locale; - return locale; + try { + const { default: locale } = await load(); + loadedLocales[lang] = locale; + return locale; + } catch (err) { + console.error("failed to load locale:", lang, err); + return en; + } } export type { BaseDict, LangCode }; diff --git a/src/lib/library.svelte.ts b/src/lib/library.svelte.ts index ebe19fc..f4ec4a3 100644 --- a/src/lib/library.svelte.ts +++ b/src/lib/library.svelte.ts @@ -32,6 +32,14 @@ export const loadPlaylists = async () => { export const loadShares = async () => { lib.busy = true; + try { + await refreshShares(); + } finally { + lib.busy = false; + } +}; + +const refreshShares = async () => { try { lib.shares = await api.getShares(); lib.isSharingSupported = true; @@ -39,8 +47,6 @@ export const loadShares = async () => { console.warn("sharing not supported by server:", err); lib.shares = []; lib.isSharingSupported = false; - } finally { - lib.busy = false; } }; @@ -71,14 +77,7 @@ export const loadLib = async () => { lib.playlists = playlists; if (!offlineManager.isOfflineMode) { - try { - lib.shares = await api.getShares(); - lib.isSharingSupported = true; - } catch (err) { - console.warn("sharing not supported by server:", err); - lib.shares = []; - lib.isSharingSupported = false; - } + await refreshShares(); await loadRadioStations(); } else { diff --git a/src/lib/theme.svelte.ts b/src/lib/theme.svelte.ts index 6029b01..6135002 100644 --- a/src/lib/theme.svelte.ts +++ b/src/lib/theme.svelte.ts @@ -11,8 +11,6 @@ interface DominantColor { const cache = new Map(); -const dynamicColor = $state({ value: "" }); - let colorThiefPromise: Promise | null = null; const darkMQ = window.matchMedia("(prefers-color-scheme: dark)"); let themeMeta: HTMLMetaElement | null = null; @@ -46,8 +44,6 @@ const applyTheme = (bg: string, text: string, dark: boolean) => { style.setProperty("--text", text); style.colorScheme = dark ? "dark" : "light"; updateMeta(bg); - - dynamicColor.value = bg; }; const clearTheme = () => { @@ -56,8 +52,6 @@ const clearTheme = () => { style.removeProperty("--text"); style.colorScheme = ""; updateMeta(); - - dynamicColor.value = ""; }; export const initTheme = () => { @@ -85,7 +79,12 @@ export const initTheme = () => { img.onerror = null; if (!settings.dynamicColors || player.track?.id !== track.id) return; try { - if (!colorThiefPromise) colorThiefPromise = import("colorthief"); + if (!colorThiefPromise) { + colorThiefPromise = import("colorthief").catch((err: unknown) => { + colorThiefPromise = null; + throw err; + }); + } const { getColor } = await colorThiefPromise; const dominant = (await getColor(img, { ignoreWhite: false, diff --git a/src/main.ts b/src/main.ts index 4b48aee..6ae4b59 100644 --- a/src/main.ts +++ b/src/main.ts @@ -3,6 +3,9 @@ import "./app.css"; import { mount } from "svelte"; import App from "./App.svelte"; +const target = document.getElementById("app"); +if (!target) throw new Error("Missing #app mount point"); + export default mount(App, { - target: document.getElementById("app") ?? document.body, + target, }); diff --git a/tsconfig.node.json b/tsconfig.node.json index 6a12664..d4c5b2b 100644 --- a/tsconfig.node.json +++ b/tsconfig.node.json @@ -20,5 +20,5 @@ "erasableSyntaxOnly": true, "noFallthroughCasesInSwitch": true }, - "include": ["vite.config.ts"] + "include": ["vite.config.ts", "pwa-assets.config.ts"] } diff --git a/vite.config.ts b/vite.config.ts index 6650802..ea7b825 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -15,10 +15,7 @@ export default defineConfig({ description: "a simple but full-featured web player for OpenSubsonic compatible music servers", display: "standalone", - background_color: undefined, theme_color: "#000000", - lang: undefined, - scope: undefined, icons: [ { src: "pwa-64x64.png", -- 2.51.2