diff --git a/package-lock.json b/package-lock.json index a3239e2..5ddd914 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,11 @@ "version": "0.0.0", "dependencies": { "@tanstack/vue-virtual": "^3.1.2", - "@tauri-apps/api": "^1.6.0", + "@tauri-apps/api": "^2.1.1", + "@tauri-apps/plugin-dialog": "^2.2.0", + "@tauri-apps/plugin-global-shortcut": "^2.2.0", + "@tauri-apps/plugin-os": "^2.2.0", + "@tauri-apps/plugin-shell": "^2.2.0", "codemirror": "^6.0.1", "floating-vue": "^5.2.2", "lodash": "^4.17.21", @@ -24,7 +28,7 @@ "vue-toastification": "^2.0.0-rc.5" }, "devDependencies": { - "@tauri-apps/cli": "^1.6.2", + "@tauri-apps/cli": "^2.1.0", "@vitejs/plugin-vue": "^3.0.1", "autoprefixer": "^10.4.12", "postcss": "^8.4.18", @@ -377,24 +381,21 @@ } }, "node_modules/@tauri-apps/api": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@tauri-apps/api/-/api-1.6.0.tgz", - "integrity": "sha512-rqI++FWClU5I2UBp4HXFvl+sBWkdigBkxnpJDQUWttNyG7IZP4FwQGhTNL5EOw0vI8i6eSAJ5frLqO7n7jbJdg==", - "engines": { - "node": ">= 14.6.0", - "npm": ">= 6.6.0", - "yarn": ">= 1.19.1" - }, + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@tauri-apps/api/-/api-2.1.1.tgz", + "integrity": "sha512-fzUfFFKo4lknXGJq8qrCidkUcKcH2UHhfaaCNt4GzgzGaW2iS26uFOg4tS3H4P8D6ZEeUxtiD5z0nwFF0UN30A==", + "license": "Apache-2.0 OR MIT", "funding": { "type": "opencollective", "url": "https://opencollective.com/tauri" } }, "node_modules/@tauri-apps/cli": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli/-/cli-1.6.2.tgz", - "integrity": "sha512-zpfZdxhm20s7d/Uejpg/T3a9sqLVe3Ih2ztINfy8v6iLw9Ohowkb9g+agZffYKlEWfOSpmCy69NFyBLj7OZL0A==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli/-/cli-2.1.0.tgz", + "integrity": "sha512-K2VhcKqBhAeS5pNOVdnR/xQRU6jwpgmkSL2ejHXcl0m+kaTggT0WRDQnFtPq6NljA7aE03cvwsbCAoFG7vtkJw==", "dev": true, + "license": "Apache-2.0 OR MIT", "bin": { "tauri": "tauri.js" }, @@ -406,26 +407,27 @@ "url": "https://opencollective.com/tauri" }, "optionalDependencies": { - "@tauri-apps/cli-darwin-arm64": "1.6.2", - "@tauri-apps/cli-darwin-x64": "1.6.2", - "@tauri-apps/cli-linux-arm-gnueabihf": "1.6.2", - "@tauri-apps/cli-linux-arm64-gnu": "1.6.2", - "@tauri-apps/cli-linux-arm64-musl": "1.6.2", - "@tauri-apps/cli-linux-x64-gnu": "1.6.2", - "@tauri-apps/cli-linux-x64-musl": "1.6.2", - "@tauri-apps/cli-win32-arm64-msvc": "1.6.2", - "@tauri-apps/cli-win32-ia32-msvc": "1.6.2", - "@tauri-apps/cli-win32-x64-msvc": "1.6.2" + "@tauri-apps/cli-darwin-arm64": "2.1.0", + "@tauri-apps/cli-darwin-x64": "2.1.0", + "@tauri-apps/cli-linux-arm-gnueabihf": "2.1.0", + "@tauri-apps/cli-linux-arm64-gnu": "2.1.0", + "@tauri-apps/cli-linux-arm64-musl": "2.1.0", + "@tauri-apps/cli-linux-x64-gnu": "2.1.0", + "@tauri-apps/cli-linux-x64-musl": "2.1.0", + "@tauri-apps/cli-win32-arm64-msvc": "2.1.0", + "@tauri-apps/cli-win32-ia32-msvc": "2.1.0", + "@tauri-apps/cli-win32-x64-msvc": "2.1.0" } }, "node_modules/@tauri-apps/cli-darwin-arm64": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-arm64/-/cli-darwin-arm64-1.6.2.tgz", - "integrity": "sha512-6mdRyf9DaLqlZvj8kZB09U3rwY+dOHSGzTZ7+GDg665GJb17f4cb30e8dExj6/aghcsOie9EGpgiURcDUvLNSQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-arm64/-/cli-darwin-arm64-2.1.0.tgz", + "integrity": "sha512-ESc6J6CE8hl1yKH2vJ+ALF+thq4Be+DM1mvmTyUCQObvezNCNhzfS6abIUd3ou4x5RGH51ouiANeT3wekU6dCw==", "cpu": [ "arm64" ], "dev": true, + "license": "Apache-2.0 OR MIT", "optional": true, "os": [ "darwin" @@ -435,13 +437,14 @@ } }, "node_modules/@tauri-apps/cli-darwin-x64": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-x64/-/cli-darwin-x64-1.6.2.tgz", - "integrity": "sha512-PLxZY5dn38H3R9VRmBN/l0ZDB5JFanCwlK4rmpzDQPPg3tQmbu5vjSCP6TVj5U6aLKsj79kFyULblPr5Dn9+vw==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-x64/-/cli-darwin-x64-2.1.0.tgz", + "integrity": "sha512-TasHS442DFs8cSH2eUQzuDBXUST4ECjCd0yyP+zZzvAruiB0Bg+c8A+I/EnqCvBQ2G2yvWLYG8q/LI7c87A5UA==", "cpu": [ "x64" ], "dev": true, + "license": "Apache-2.0 OR MIT", "optional": true, "os": [ "darwin" @@ -451,13 +454,14 @@ } }, "node_modules/@tauri-apps/cli-linux-arm-gnueabihf": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm-gnueabihf/-/cli-linux-arm-gnueabihf-1.6.2.tgz", - "integrity": "sha512-xnpj4BLeeGOh5I/ewCQlYJZwHH0CBNBN+4q8BNWNQ9MKkjN9ST366RmHRzl2ANNgWwijOPxyce7GiUmvuH8Atw==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm-gnueabihf/-/cli-linux-arm-gnueabihf-2.1.0.tgz", + "integrity": "sha512-aP7ZBGNL4ny07Cbb6kKpUOSrmhcIK2KhjviTzYlh+pPhAptxnC78xQGD3zKQkTi2WliJLPmBYbOHWWQa57lQ9w==", "cpu": [ "arm" ], "dev": true, + "license": "Apache-2.0 OR MIT", "optional": true, "os": [ "linux" @@ -467,13 +471,14 @@ } }, "node_modules/@tauri-apps/cli-linux-arm64-gnu": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-gnu/-/cli-linux-arm64-gnu-1.6.2.tgz", - "integrity": "sha512-uaiRE0vE2P+tdsCngfKt+7yKr3VZXIq/t3w01DzSdnBgHSp0zmRsRR4AhZt7ibvoEgA8GzBP+eSHJdFNZsTU9w==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-gnu/-/cli-linux-arm64-gnu-2.1.0.tgz", + "integrity": "sha512-ZTdgD5gLeMCzndMT2f358EkoYkZ5T+Qy6zPzU+l5vv5M7dHVN9ZmblNAYYXmoOuw7y+BY4X/rZvHV9pcGrcanQ==", "cpu": [ "arm64" ], "dev": true, + "license": "Apache-2.0 OR MIT", "optional": true, "os": [ "linux" @@ -483,13 +488,14 @@ } }, "node_modules/@tauri-apps/cli-linux-arm64-musl": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-musl/-/cli-linux-arm64-musl-1.6.2.tgz", - "integrity": "sha512-o9JunVrMrhqTBLrdvEbS64W0bo1dPm0lxX51Mx+6x9SmbDjlEWGgaAHC3iKLK9khd5Yu1uO1e+8TJltAcScvmw==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.1.0.tgz", + "integrity": "sha512-NzwqjUCilhnhJzusz3d/0i0F1GFrwCQbkwR6yAHUxItESbsGYkZRJk0yMEWkg3PzFnyK4cWTlQJMEU52TjhEzA==", "cpu": [ "arm64" ], "dev": true, + "license": "Apache-2.0 OR MIT", "optional": true, "os": [ "linux" @@ -499,13 +505,14 @@ } }, "node_modules/@tauri-apps/cli-linux-x64-gnu": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-gnu/-/cli-linux-x64-gnu-1.6.2.tgz", - "integrity": "sha512-jL9f+o61DdQmNYKIt2Q3BA8YJ+hyC5+GdNxqDf7j5SoQ85j//YfUWbmp9ZgsPHVBxgSGZVvgGMNvf64Ykp0buQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-gnu/-/cli-linux-x64-gnu-2.1.0.tgz", + "integrity": "sha512-TyiIpMEtZxNOQmuFyfJwaaYbg3movSthpBJLIdPlKxSAB2BW0VWLY3/ZfIxm/G2YGHyREkjJvimzYE0i37PnMA==", "cpu": [ "x64" ], "dev": true, + "license": "Apache-2.0 OR MIT", "optional": true, "os": [ "linux" @@ -515,13 +522,14 @@ } }, "node_modules/@tauri-apps/cli-linux-x64-musl": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-musl/-/cli-linux-x64-musl-1.6.2.tgz", - "integrity": "sha512-xsa4Pu9YMHKAX0J8pIoXfN/uhvAAAoECZDixDhWw8zi57VZ4QX28ycqolS+NscdD9NAGSgHk45MpBZWdvRtvjQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-musl/-/cli-linux-x64-musl-2.1.0.tgz", + "integrity": "sha512-/dQd0TlaxBdJACrR72DhynWftzHDaX32eBtS5WBrNJ+nnNb+znM3gON6nJ9tSE9jgDa6n1v2BkI/oIDtypfUXw==", "cpu": [ "x64" ], "dev": true, + "license": "Apache-2.0 OR MIT", "optional": true, "os": [ "linux" @@ -531,13 +539,14 @@ } }, "node_modules/@tauri-apps/cli-win32-arm64-msvc": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-arm64-msvc/-/cli-win32-arm64-msvc-1.6.2.tgz", - "integrity": "sha512-eJtUOx2UFhJpCCkm5M5+4Co9JbjvgIHTdyS/hTSZfOEdT58CNEGVJXMA39FsSZXYoxYPE+9K7Km6haMozSmlxw==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-arm64-msvc/-/cli-win32-arm64-msvc-2.1.0.tgz", + "integrity": "sha512-NdQJO7SmdYqOcE+JPU7bwg7+odfZMWO6g8xF9SXYCMdUzvM2Gv/AQfikNXz5yS7ralRhNFuW32i5dcHlxh4pDg==", "cpu": [ "arm64" ], "dev": true, + "license": "Apache-2.0 OR MIT", "optional": true, "os": [ "win32" @@ -547,13 +556,14 @@ } }, "node_modules/@tauri-apps/cli-win32-ia32-msvc": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-ia32-msvc/-/cli-win32-ia32-msvc-1.6.2.tgz", - "integrity": "sha512-9Jwx3PrhNw3VKOgPISRRXPkvoEAZP+7rFRHXIo49dvlHy2E/o9qpWi1IntE33HWeazP6KhvsCjvXB2Ai4eGooA==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-ia32-msvc/-/cli-win32-ia32-msvc-2.1.0.tgz", + "integrity": "sha512-f5h8gKT/cB8s1ticFRUpNmHqkmaLutT62oFDB7N//2YTXnxst7EpMIn1w+QimxTvTk2gcx6EcW6bEk/y2hZGzg==", "cpu": [ "ia32" ], "dev": true, + "license": "Apache-2.0 OR MIT", "optional": true, "os": [ "win32" @@ -563,13 +573,14 @@ } }, "node_modules/@tauri-apps/cli-win32-x64-msvc": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-x64-msvc/-/cli-win32-x64-msvc-1.6.2.tgz", - "integrity": "sha512-5Z+ZjRFJE8MXghJe1UXvGephY5ZcgVhiTI9yuMi9xgX3CEaAXASatyXllzsvGJ9EDaWMEpa0PHjAzi7LBAWROw==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-x64-msvc/-/cli-win32-x64-msvc-2.1.0.tgz", + "integrity": "sha512-P/+LrdSSb5Xbho1LRP4haBjFHdyPdjWvGgeopL96OVtrFpYnfC+RctB45z2V2XxqFk3HweDDxk266btjttfjGw==", "cpu": [ "x64" ], "dev": true, + "license": "Apache-2.0 OR MIT", "optional": true, "os": [ "win32" @@ -578,6 +589,42 @@ "node": ">= 10" } }, + "node_modules/@tauri-apps/plugin-dialog": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@tauri-apps/plugin-dialog/-/plugin-dialog-2.2.0.tgz", + "integrity": "sha512-6bLkYK68zyK31418AK5fNccCdVuRnNpbxquCl8IqgFByOgWFivbiIlvb79wpSXi0O+8k8RCSsIpOquebusRVSg==", + "license": "MIT OR Apache-2.0", + "dependencies": { + "@tauri-apps/api": "^2.0.0" + } + }, + "node_modules/@tauri-apps/plugin-global-shortcut": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@tauri-apps/plugin-global-shortcut/-/plugin-global-shortcut-2.2.0.tgz", + "integrity": "sha512-clI9Bg/BcxWXNDK+ij601o1qC2WxMEy8ovhGgEW5Ai17oPy0KK8uwzmc59KiVnOYKpBWHCUPqBxG+KBNUFXgzw==", + "license": "MIT OR Apache-2.0", + "dependencies": { + "@tauri-apps/api": "^2.0.0" + } + }, + "node_modules/@tauri-apps/plugin-os": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@tauri-apps/plugin-os/-/plugin-os-2.2.0.tgz", + "integrity": "sha512-HszbCdbisMlu5QhCNAN8YIWyz2v33abAWha6+uvV2CKX8P5VSct/y+kEe22JeyqrxCnWlQ3DRx7s49Byg7/0EA==", + "license": "MIT OR Apache-2.0", + "dependencies": { + "@tauri-apps/api": "^2.0.0" + } + }, + "node_modules/@tauri-apps/plugin-shell": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@tauri-apps/plugin-shell/-/plugin-shell-2.2.0.tgz", + "integrity": "sha512-iC3Ic1hLmasoboG7BO+7p+AriSoqAwKrIk+Hpk+S/bjTQdXqbl2GbdclghI4gM32X0bls7xHzIFqhRdrlvJeaA==", + "license": "MIT OR Apache-2.0", + "dependencies": { + "@tauri-apps/api": "^2.0.0" + } + }, "node_modules/@types/web-bluetooth": { "version": "0.0.20", "resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.20.tgz", @@ -3174,98 +3221,130 @@ } }, "@tauri-apps/api": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@tauri-apps/api/-/api-1.6.0.tgz", - "integrity": "sha512-rqI++FWClU5I2UBp4HXFvl+sBWkdigBkxnpJDQUWttNyG7IZP4FwQGhTNL5EOw0vI8i6eSAJ5frLqO7n7jbJdg==" + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@tauri-apps/api/-/api-2.1.1.tgz", + "integrity": "sha512-fzUfFFKo4lknXGJq8qrCidkUcKcH2UHhfaaCNt4GzgzGaW2iS26uFOg4tS3H4P8D6ZEeUxtiD5z0nwFF0UN30A==" }, "@tauri-apps/cli": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli/-/cli-1.6.2.tgz", - "integrity": "sha512-zpfZdxhm20s7d/Uejpg/T3a9sqLVe3Ih2ztINfy8v6iLw9Ohowkb9g+agZffYKlEWfOSpmCy69NFyBLj7OZL0A==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli/-/cli-2.1.0.tgz", + "integrity": "sha512-K2VhcKqBhAeS5pNOVdnR/xQRU6jwpgmkSL2ejHXcl0m+kaTggT0WRDQnFtPq6NljA7aE03cvwsbCAoFG7vtkJw==", "dev": true, "requires": { - "@tauri-apps/cli-darwin-arm64": "1.6.2", - "@tauri-apps/cli-darwin-x64": "1.6.2", - "@tauri-apps/cli-linux-arm-gnueabihf": "1.6.2", - "@tauri-apps/cli-linux-arm64-gnu": "1.6.2", - "@tauri-apps/cli-linux-arm64-musl": "1.6.2", - "@tauri-apps/cli-linux-x64-gnu": "1.6.2", - "@tauri-apps/cli-linux-x64-musl": "1.6.2", - "@tauri-apps/cli-win32-arm64-msvc": "1.6.2", - "@tauri-apps/cli-win32-ia32-msvc": "1.6.2", - "@tauri-apps/cli-win32-x64-msvc": "1.6.2" + "@tauri-apps/cli-darwin-arm64": "2.1.0", + "@tauri-apps/cli-darwin-x64": "2.1.0", + "@tauri-apps/cli-linux-arm-gnueabihf": "2.1.0", + "@tauri-apps/cli-linux-arm64-gnu": "2.1.0", + "@tauri-apps/cli-linux-arm64-musl": "2.1.0", + "@tauri-apps/cli-linux-x64-gnu": "2.1.0", + "@tauri-apps/cli-linux-x64-musl": "2.1.0", + "@tauri-apps/cli-win32-arm64-msvc": "2.1.0", + "@tauri-apps/cli-win32-ia32-msvc": "2.1.0", + "@tauri-apps/cli-win32-x64-msvc": "2.1.0" } }, "@tauri-apps/cli-darwin-arm64": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-arm64/-/cli-darwin-arm64-1.6.2.tgz", - "integrity": "sha512-6mdRyf9DaLqlZvj8kZB09U3rwY+dOHSGzTZ7+GDg665GJb17f4cb30e8dExj6/aghcsOie9EGpgiURcDUvLNSQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-arm64/-/cli-darwin-arm64-2.1.0.tgz", + "integrity": "sha512-ESc6J6CE8hl1yKH2vJ+ALF+thq4Be+DM1mvmTyUCQObvezNCNhzfS6abIUd3ou4x5RGH51ouiANeT3wekU6dCw==", "dev": true, "optional": true }, "@tauri-apps/cli-darwin-x64": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-x64/-/cli-darwin-x64-1.6.2.tgz", - "integrity": "sha512-PLxZY5dn38H3R9VRmBN/l0ZDB5JFanCwlK4rmpzDQPPg3tQmbu5vjSCP6TVj5U6aLKsj79kFyULblPr5Dn9+vw==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-x64/-/cli-darwin-x64-2.1.0.tgz", + "integrity": "sha512-TasHS442DFs8cSH2eUQzuDBXUST4ECjCd0yyP+zZzvAruiB0Bg+c8A+I/EnqCvBQ2G2yvWLYG8q/LI7c87A5UA==", "dev": true, "optional": true }, "@tauri-apps/cli-linux-arm-gnueabihf": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm-gnueabihf/-/cli-linux-arm-gnueabihf-1.6.2.tgz", - "integrity": "sha512-xnpj4BLeeGOh5I/ewCQlYJZwHH0CBNBN+4q8BNWNQ9MKkjN9ST366RmHRzl2ANNgWwijOPxyce7GiUmvuH8Atw==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm-gnueabihf/-/cli-linux-arm-gnueabihf-2.1.0.tgz", + "integrity": "sha512-aP7ZBGNL4ny07Cbb6kKpUOSrmhcIK2KhjviTzYlh+pPhAptxnC78xQGD3zKQkTi2WliJLPmBYbOHWWQa57lQ9w==", "dev": true, "optional": true }, "@tauri-apps/cli-linux-arm64-gnu": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-gnu/-/cli-linux-arm64-gnu-1.6.2.tgz", - "integrity": "sha512-uaiRE0vE2P+tdsCngfKt+7yKr3VZXIq/t3w01DzSdnBgHSp0zmRsRR4AhZt7ibvoEgA8GzBP+eSHJdFNZsTU9w==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-gnu/-/cli-linux-arm64-gnu-2.1.0.tgz", + "integrity": "sha512-ZTdgD5gLeMCzndMT2f358EkoYkZ5T+Qy6zPzU+l5vv5M7dHVN9ZmblNAYYXmoOuw7y+BY4X/rZvHV9pcGrcanQ==", "dev": true, "optional": true }, "@tauri-apps/cli-linux-arm64-musl": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-musl/-/cli-linux-arm64-musl-1.6.2.tgz", - "integrity": "sha512-o9JunVrMrhqTBLrdvEbS64W0bo1dPm0lxX51Mx+6x9SmbDjlEWGgaAHC3iKLK9khd5Yu1uO1e+8TJltAcScvmw==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.1.0.tgz", + "integrity": "sha512-NzwqjUCilhnhJzusz3d/0i0F1GFrwCQbkwR6yAHUxItESbsGYkZRJk0yMEWkg3PzFnyK4cWTlQJMEU52TjhEzA==", "dev": true, "optional": true }, "@tauri-apps/cli-linux-x64-gnu": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-gnu/-/cli-linux-x64-gnu-1.6.2.tgz", - "integrity": "sha512-jL9f+o61DdQmNYKIt2Q3BA8YJ+hyC5+GdNxqDf7j5SoQ85j//YfUWbmp9ZgsPHVBxgSGZVvgGMNvf64Ykp0buQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-gnu/-/cli-linux-x64-gnu-2.1.0.tgz", + "integrity": "sha512-TyiIpMEtZxNOQmuFyfJwaaYbg3movSthpBJLIdPlKxSAB2BW0VWLY3/ZfIxm/G2YGHyREkjJvimzYE0i37PnMA==", "dev": true, "optional": true }, "@tauri-apps/cli-linux-x64-musl": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-musl/-/cli-linux-x64-musl-1.6.2.tgz", - "integrity": "sha512-xsa4Pu9YMHKAX0J8pIoXfN/uhvAAAoECZDixDhWw8zi57VZ4QX28ycqolS+NscdD9NAGSgHk45MpBZWdvRtvjQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-musl/-/cli-linux-x64-musl-2.1.0.tgz", + "integrity": "sha512-/dQd0TlaxBdJACrR72DhynWftzHDaX32eBtS5WBrNJ+nnNb+znM3gON6nJ9tSE9jgDa6n1v2BkI/oIDtypfUXw==", "dev": true, "optional": true }, "@tauri-apps/cli-win32-arm64-msvc": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-arm64-msvc/-/cli-win32-arm64-msvc-1.6.2.tgz", - "integrity": "sha512-eJtUOx2UFhJpCCkm5M5+4Co9JbjvgIHTdyS/hTSZfOEdT58CNEGVJXMA39FsSZXYoxYPE+9K7Km6haMozSmlxw==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-arm64-msvc/-/cli-win32-arm64-msvc-2.1.0.tgz", + "integrity": "sha512-NdQJO7SmdYqOcE+JPU7bwg7+odfZMWO6g8xF9SXYCMdUzvM2Gv/AQfikNXz5yS7ralRhNFuW32i5dcHlxh4pDg==", "dev": true, "optional": true }, "@tauri-apps/cli-win32-ia32-msvc": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-ia32-msvc/-/cli-win32-ia32-msvc-1.6.2.tgz", - "integrity": "sha512-9Jwx3PrhNw3VKOgPISRRXPkvoEAZP+7rFRHXIo49dvlHy2E/o9qpWi1IntE33HWeazP6KhvsCjvXB2Ai4eGooA==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-ia32-msvc/-/cli-win32-ia32-msvc-2.1.0.tgz", + "integrity": "sha512-f5h8gKT/cB8s1ticFRUpNmHqkmaLutT62oFDB7N//2YTXnxst7EpMIn1w+QimxTvTk2gcx6EcW6bEk/y2hZGzg==", "dev": true, "optional": true }, "@tauri-apps/cli-win32-x64-msvc": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-x64-msvc/-/cli-win32-x64-msvc-1.6.2.tgz", - "integrity": "sha512-5Z+ZjRFJE8MXghJe1UXvGephY5ZcgVhiTI9yuMi9xgX3CEaAXASatyXllzsvGJ9EDaWMEpa0PHjAzi7LBAWROw==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-x64-msvc/-/cli-win32-x64-msvc-2.1.0.tgz", + "integrity": "sha512-P/+LrdSSb5Xbho1LRP4haBjFHdyPdjWvGgeopL96OVtrFpYnfC+RctB45z2V2XxqFk3HweDDxk266btjttfjGw==", "dev": true, "optional": true }, + "@tauri-apps/plugin-dialog": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@tauri-apps/plugin-dialog/-/plugin-dialog-2.2.0.tgz", + "integrity": "sha512-6bLkYK68zyK31418AK5fNccCdVuRnNpbxquCl8IqgFByOgWFivbiIlvb79wpSXi0O+8k8RCSsIpOquebusRVSg==", + "requires": { + "@tauri-apps/api": "^2.0.0" + } + }, + "@tauri-apps/plugin-global-shortcut": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@tauri-apps/plugin-global-shortcut/-/plugin-global-shortcut-2.2.0.tgz", + "integrity": "sha512-clI9Bg/BcxWXNDK+ij601o1qC2WxMEy8ovhGgEW5Ai17oPy0KK8uwzmc59KiVnOYKpBWHCUPqBxG+KBNUFXgzw==", + "requires": { + "@tauri-apps/api": "^2.0.0" + } + }, + "@tauri-apps/plugin-os": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@tauri-apps/plugin-os/-/plugin-os-2.2.0.tgz", + "integrity": "sha512-HszbCdbisMlu5QhCNAN8YIWyz2v33abAWha6+uvV2CKX8P5VSct/y+kEe22JeyqrxCnWlQ3DRx7s49Byg7/0EA==", + "requires": { + "@tauri-apps/api": "^2.0.0" + } + }, + "@tauri-apps/plugin-shell": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@tauri-apps/plugin-shell/-/plugin-shell-2.2.0.tgz", + "integrity": "sha512-iC3Ic1hLmasoboG7BO+7p+AriSoqAwKrIk+Hpk+S/bjTQdXqbl2GbdclghI4gM32X0bls7xHzIFqhRdrlvJeaA==", + "requires": { + "@tauri-apps/api": "^2.0.0" + } + }, "@types/web-bluetooth": { "version": "0.0.20", "resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.20.tgz", diff --git a/package.json b/package.json index 5525778..0c0417f 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,11 @@ }, "dependencies": { "@tanstack/vue-virtual": "^3.1.2", - "@tauri-apps/api": "^1.6.0", + "@tauri-apps/api": "^2.1.1", + "@tauri-apps/plugin-dialog": "^2.2.0", + "@tauri-apps/plugin-global-shortcut": "^2.2.0", + "@tauri-apps/plugin-os": "^2.2.0", + "@tauri-apps/plugin-shell": "^2.2.0", "codemirror": "^6.0.1", "floating-vue": "^5.2.2", "lodash": "^4.17.21", @@ -25,7 +29,7 @@ "vue-toastification": "^2.0.0-rc.5" }, "devDependencies": { - "@tauri-apps/cli": "^1.6.2", + "@tauri-apps/cli": "^2.1.0", "@vitejs/plugin-vue": "^3.0.1", "autoprefixer": "^10.4.12", "postcss": "^8.4.18", diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 094bfb7..210b0c1 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -108,28 +108,167 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" +[[package]] +name = "ashpd" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d43c03d9e36dd40cab48435be0b09646da362c278223ca535493877b2c1dee9" +dependencies = [ + "enumflags2", + "futures-channel", + "futures-util", + "rand 0.8.5", + "raw-window-handle", + "serde", + "serde_repr", + "tokio", + "url", + "wayland-backend", + "wayland-client", + "wayland-protocols", + "zbus", +] + +[[package]] +name = "async-broadcast" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "435a87a52755b8f27fcf321ac4f04b2802e337c8c4872923137471ec39c37532" +dependencies = [ + "event-listener", + "event-listener-strategy", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-channel" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89b47800b0be77592da0afd425cc03468052844aff33b84e33cc696f64e77b6a" +dependencies = [ + "concurrent-queue", + "event-listener-strategy", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-io" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a2b323ccce0a1d90b449fd71f2a06ca7faa7c54c2751f06c9bd851fc061059" +dependencies = [ + "async-lock", + "cfg-if", + "concurrent-queue", + "futures-io", + "futures-lite", + "parking", + "polling", + "rustix", + "slab", + "tracing", + "windows-sys 0.59.0", +] + +[[package]] +name = "async-lock" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18" +dependencies = [ + "event-listener", + "event-listener-strategy", + "pin-project-lite", +] + +[[package]] +name = "async-process" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63255f1dc2381611000436537bbedfe83183faa303a5a0edaf191edef06526bb" +dependencies = [ + "async-channel", + "async-io", + "async-lock", + "async-signal", + "async-task", + "blocking", + "cfg-if", + "event-listener", + "futures-lite", + "rustix", + "tracing", +] + +[[package]] +name = "async-recursion" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.91", +] + +[[package]] +name = "async-signal" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "637e00349800c0bdf8bfc21ebbc0b6524abea702b0da4168ac00d070d0c0b9f3" +dependencies = [ + "async-io", + "async-lock", + "atomic-waker", + "cfg-if", + "futures-core", + "futures-io", + "rustix", + "signal-hook-registry", + "slab", + "windows-sys 0.59.0", +] + +[[package]] +name = "async-task" +version = "4.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" + +[[package]] +name = "async-trait" +version = "0.1.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.91", +] + [[package]] name = "atk" -version = "0.15.1" +version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c3d816ce6f0e2909a96830d6911c2aff044370b1ef92d7f267b43bae5addedd" +checksum = "241b621213072e993be4f6f3a9e4b45f65b7e6faad43001be957184b7bb1824b" dependencies = [ "atk-sys", - "bitflags 1.3.2", "glib", "libc", ] [[package]] name = "atk-sys" -version = "0.15.1" +version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58aeb089fb698e06db8089971c7ee317ab9644bade33383f63631437b03aafb6" +checksum = "c5e48b684b0ca77d2bbadeef17424c2ea3c897d44d566a1617e7e8f30614d086" dependencies = [ "glib-sys", "gobject-sys", "libc", - "system-deps 6.2.2", + "system-deps", ] [[package]] @@ -159,12 +298,6 @@ dependencies = [ "windows-targets 0.52.6", ] -[[package]] -name = "base64" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" - [[package]] name = "base64" version = "0.21.7" @@ -192,7 +325,7 @@ dependencies = [ "regex", "rustc-hash", "shlex", - "syn 2.0.77", + "syn 2.0.91", ] [[package]] @@ -206,6 +339,9 @@ name = "bitflags" version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +dependencies = [ + "serde", +] [[package]] name = "block" @@ -222,11 +358,33 @@ dependencies = [ "generic-array", ] +[[package]] +name = "block2" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c132eebf10f5cad5289222520a4a058514204aed6d791f1cf4fe8088b82d15f" +dependencies = [ + "objc2", +] + +[[package]] +name = "blocking" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "703f41c54fc768e63e091340b424302bb1c29ef4aa0c7f10fe849dfb114d29ea" +dependencies = [ + "async-channel", + "async-task", + "futures-io", + "futures-lite", + "piper", +] + [[package]] name = "brotli" -version = "6.0.0" +version = "7.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74f7971dbd9326d58187408ab83117d8ac1bb9c17b085fdacd1cf2f598719b6b" +checksum = "cc97b8f16f944bba54f0433f07e30be199b6dc2bd25937444bbad560bcea29bd" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", @@ -276,39 +434,75 @@ name = "bytes" version = "1.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "428d9aa8fbc0670b7b8d6030a7fadd0f86151cae55e4dbbece15f3780a3dfaf3" +dependencies = [ + "serde", +] [[package]] name = "cairo-rs" -version = "0.15.12" +version = "0.18.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c76ee391b03d35510d9fa917357c7f1855bd9a6659c95a1b392e33f49b3369bc" +checksum = "8ca26ef0159422fb77631dc9d17b102f253b876fe1586b03b803e63a309b4ee2" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.6.0", "cairo-sys-rs", "glib", "libc", - "thiserror", + "once_cell", + "thiserror 1.0.63", ] [[package]] name = "cairo-sys-rs" -version = "0.15.1" +version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c55d429bef56ac9172d25fecb85dc8068307d17acd74b377866b7a1ef25d3c8" +checksum = "685c9fa8e590b8b3d678873528d83411db17242a73fccaed827770ea0fedda51" dependencies = [ "glib-sys", "libc", - "system-deps 6.2.2", + "system-deps", +] + +[[package]] +name = "camino" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b96ec4966b5813e2c0507c1f86115c8c5abaadc3980879c3424042a02fd1ad3" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo-platform" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e35af189006b9c0f00a064685c727031e3ed2d8020f7ba284d78cc2671bd36ea" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo_metadata" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d886547e41f740c616ae73108f6eb70afe6d940c7bc697cb30f13daec073037" +dependencies = [ + "camino", + "cargo-platform", + "semver", + "serde", + "serde_json", + "thiserror 1.0.63", ] [[package]] name = "cargo_toml" -version = "0.15.3" +version = "0.17.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "599aa35200ffff8f04c1925aa1acc92fa2e08874379ef42e210a80e527e60838" +checksum = "8a969e13a7589e9e3e4207e153bae624ade2b5622fb4684a4923b23ec3d57719" dependencies = [ "serde", - "toml 0.7.8", + "toml 0.8.2", ] [[package]] @@ -348,15 +542,6 @@ dependencies = [ "uuid", ] -[[package]] -name = "cfg-expr" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3431df59f28accaf4cb4eed4a9acc66bea3f3c3753aa6cdc2f024174ef232af7" -dependencies = [ - "smallvec", -] - [[package]] name = "cfg-expr" version = "0.15.8" @@ -373,6 +558,12 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + [[package]] name = "chrono" version = "0.4.38" @@ -394,34 +585,34 @@ checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" dependencies = [ "glob", "libc", - "libloading", + "libloading 0.8.5", ] [[package]] name = "cocoa" -version = "0.24.1" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f425db7937052c684daec3bd6375c8abe2d146dca4b8b143d6db777c39138f3a" +checksum = "f79398230a6e2c08f5c9760610eb6924b52aa9e7950a619602baba59dcbbdbb2" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.6.0", "block", "cocoa-foundation", - "core-foundation", + "core-foundation 0.10.0", "core-graphics", - "foreign-types", + "foreign-types 0.5.0", "libc", "objc", ] [[package]] name = "cocoa-foundation" -version = "0.1.2" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c6234cbb2e4c785b456c0644748b1ac416dd045799740356f8363dfe00c93f7" +checksum = "e14045fb83be07b5acf1c0884b2180461635b433455fa35d1cd6f17f1450679d" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.6.0", "block", - "core-foundation", + "core-foundation 0.10.0", "core-graphics-types", "libc", "objc", @@ -433,12 +624,6 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba28d63cd46c3b6dc8d75b63f563b724dc9c5e09c59cf5b62f315a7ddfcc135a" -[[package]] -name = "color_quant" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" - [[package]] name = "combine" version = "4.6.7" @@ -449,12 +634,31 @@ dependencies = [ "memchr", ] +[[package]] +name = "concurrent-queue" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "convert_case" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" +[[package]] +name = "cookie" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ddef33a339a91ea89fb53151bd0a4689cfce27055c291dfa69945475d22c747" +dependencies = [ + "time", + "version_check", +] + [[package]] name = "core-foundation" version = "0.9.4" @@ -465,6 +669,16 @@ dependencies = [ "libc", ] +[[package]] +name = "core-foundation" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b55271e5c8c478ad3f38ad24ef34923091e0548492a266d19b3c0b4d82574c63" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "core-foundation-sys" version = "0.8.7" @@ -473,25 +687,25 @@ checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "core-graphics" -version = "0.22.3" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2581bbab3b8ffc6fcbd550bf46c355135d16e9ff2a6ea032ad6b9bf1d7efe4fb" +checksum = "fa95a34622365fa5bbf40b20b75dba8dfa8c94c734aea8ac9a5ca38af14316f1" dependencies = [ - "bitflags 1.3.2", - "core-foundation", + "bitflags 2.6.0", + "core-foundation 0.10.0", "core-graphics-types", - "foreign-types", + "foreign-types 0.5.0", "libc", ] [[package]] name = "core-graphics-types" -version = "0.1.3" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45390e6114f68f718cc7a830514a96f903cccd70d02a8f6d9f643ac4ba45afaf" +checksum = "3d44a101f213f6c4cdc1853d4b78aef6db6bdfa3468798cc1d9912f4735013eb" dependencies = [ - "bitflags 1.3.2", - "core-foundation", + "bitflags 2.6.0", + "core-foundation 0.10.0", "libc", ] @@ -525,7 +739,7 @@ dependencies = [ "core-foundation-sys", "coreaudio-rs", "dasp_sample", - "jni 0.21.1", + "jni", "js-sys", "libc", "mach2", @@ -624,7 +838,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331" dependencies = [ "quote", - "syn 2.0.77", + "syn 2.0.91", ] [[package]] @@ -634,7 +848,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "edb49164822f3ee45b17acd4a208cfc1251410cf0cad9a833234c9890774dd9f" dependencies = [ "quote", - "syn 2.0.77", + "syn 2.0.91", ] [[package]] @@ -658,7 +872,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.77", + "syn 2.0.91", ] [[package]] @@ -669,7 +883,7 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core", "quote", - "syn 2.0.77", + "syn 2.0.91", ] [[package]] @@ -694,6 +908,17 @@ dependencies = [ "serde", ] +[[package]] +name = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "derive_more" version = "0.99.18" @@ -704,7 +929,7 @@ dependencies = [ "proc-macro2", "quote", "rustc_version", - "syn 2.0.77", + "syn 2.0.91", ] [[package]] @@ -718,24 +943,24 @@ dependencies = [ ] [[package]] -name = "dirs-next" -version = "2.0.0" +name = "dirs" +version = "5.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" +checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" dependencies = [ - "cfg-if", - "dirs-sys-next", + "dirs-sys", ] [[package]] -name = "dirs-sys-next" -version = "0.1.2" +name = "dirs-sys" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" +checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" dependencies = [ "libc", + "option-ext", "redox_users", - "winapi", + "windows-sys 0.48.0", ] [[package]] @@ -744,6 +969,53 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" +[[package]] +name = "dlib" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412" +dependencies = [ + "libloading 0.8.5", +] + +[[package]] +name = "dlopen2" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1297103d2bbaea85724fcee6294c2d50b1081f9ad47d0f6f6f61eda65315a6" +dependencies = [ + "dlopen2_derive", + "libc", + "once_cell", + "winapi", +] + +[[package]] +name = "dlopen2_derive" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2b99bf03862d7f545ebc28ddd33a665b50865f4dfd84031a393823879bd4c54" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.91", +] + +[[package]] +name = "downcast-rs" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" + +[[package]] +name = "dpi" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f25c0e292a7ca6d6498557ff1df68f32c99850012b6ea401cf8daf771f22ff53" +dependencies = [ + "serde", +] + [[package]] name = "dtoa" version = "1.0.9" @@ -765,6 +1037,12 @@ version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" +[[package]] +name = "dyn-clone" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125" + [[package]] name = "educe" version = "0.6.0" @@ -774,7 +1052,7 @@ dependencies = [ "enum-ordinalize", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.91", ] [[package]] @@ -792,7 +1070,7 @@ dependencies = [ "cc", "memchr", "rustc_version", - "toml 0.8.19", + "toml 0.8.2", "vswhom", "winreg", ] @@ -812,6 +1090,12 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "endi" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3d8a32ae18130a3c84dd492d4215c3d913c3b07c6b63c2eb3eb7ff1101ab7bf" + [[package]] name = "enum-ordinalize" version = "4.3.0" @@ -829,7 +1113,28 @@ checksum = "0d28318a75d4aead5c4db25382e8ef717932d0346600cacae6357eb5941bc5ff" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.91", +] + +[[package]] +name = "enumflags2" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d232db7f5956f3f14313dc2f87985c58bd2c695ce124c8cdd984e08e15ac133d" +dependencies = [ + "enumflags2_derive", + "serde", +] + +[[package]] +name = "enumflags2_derive" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de0d48a183585823424a4ce1aa132d174a6a81bd540895822eb4c8373a8e49e8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.91", ] [[package]] @@ -838,6 +1143,16 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" +[[package]] +name = "erased-serde" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24e2389d65ab4fab27dc2a5de7b191e1f6617d1f1c8855c0dc569c94a4cbb18d" +dependencies = [ + "serde", + "typeid", +] + [[package]] name = "errno" version = "0.3.9" @@ -848,6 +1163,27 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "event-listener" +version = "5.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6032be9bd27023a771701cc49f9f053c751055f71efb2e0ae5c15809093675ba" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener-strategy" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c3e4e0dd3673c1139bf041f3008816d9cf2946bbfac2945c09e523b8d7b05b2" +dependencies = [ + "event-listener", + "pin-project-lite", +] + [[package]] name = "extended" version = "0.1.0" @@ -891,18 +1227,6 @@ dependencies = [ "rustc_version", ] -[[package]] -name = "filetime" -version = "0.2.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35c0522e981e68cbfa8c3f978441a5f34b30b96e146b33cd3359176b50fe8586" -dependencies = [ - "cfg-if", - "libc", - "libredox", - "windows-sys 0.59.0", -] - [[package]] name = "flate2" version = "1.0.33" @@ -913,15 +1237,6 @@ dependencies = [ "miniz_oxide 0.8.0", ] -[[package]] -name = "fluent-uri" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17c704e9dbe1ddd863da1e6ff3567795087b1eb201ce80d8fa81162e1516500d" -dependencies = [ - "bitflags 1.3.2", -] - [[package]] name = "fnv" version = "1.0.7" @@ -934,7 +1249,28 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" dependencies = [ - "foreign-types-shared", + "foreign-types-shared 0.1.1", +] + +[[package]] +name = "foreign-types" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965" +dependencies = [ + "foreign-types-macros", + "foreign-types-shared 0.3.1", +] + +[[package]] +name = "foreign-types-macros" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.91", ] [[package]] @@ -943,6 +1279,12 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" +[[package]] +name = "foreign-types-shared" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b" + [[package]] name = "form_urlencoded" version = "1.2.1" @@ -994,6 +1336,19 @@ version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" +[[package]] +name = "futures-lite" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cef40d21ae2c515b51041df9ed313ed21e572df340ea58a922a0aefe7e8891a1" +dependencies = [ + "fastrand", + "futures-core", + "futures-io", + "parking", + "pin-project-lite", +] + [[package]] name = "futures-macro" version = "0.3.30" @@ -1002,7 +1357,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.91", ] [[package]] @@ -1024,8 +1379,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" dependencies = [ "futures-core", + "futures-io", "futures-macro", + "futures-sink", "futures-task", + "memchr", "pin-project-lite", "pin-utils", "slab", @@ -1042,11 +1400,10 @@ dependencies = [ [[package]] name = "gdk" -version = "0.15.4" +version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6e05c1f572ab0e1f15be94217f0dc29088c248b14f792a5ff0af0d84bcda9e8" +checksum = "d9f245958c627ac99d8e529166f9823fb3b838d1d41fd2b297af3075093c2691" dependencies = [ - "bitflags 1.3.2", "cairo-rs", "gdk-pixbuf", "gdk-sys", @@ -1058,35 +1415,35 @@ dependencies = [ [[package]] name = "gdk-pixbuf" -version = "0.15.11" +version = "0.18.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad38dd9cc8b099cceecdf41375bb6d481b1b5a7cd5cd603e10a69a9383f8619a" +checksum = "50e1f5f1b0bfb830d6ccc8066d18db35c487b1b2b1e8589b5dfe9f07e8defaec" dependencies = [ - "bitflags 1.3.2", "gdk-pixbuf-sys", "gio", "glib", "libc", + "once_cell", ] [[package]] name = "gdk-pixbuf-sys" -version = "0.15.10" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "140b2f5378256527150350a8346dbdb08fadc13453a7a2d73aecd5fab3c402a7" +checksum = "3f9839ea644ed9c97a34d129ad56d38a25e6756f99f3a88e15cd39c20629caf7" dependencies = [ "gio-sys", "glib-sys", "gobject-sys", "libc", - "system-deps 6.2.2", + "system-deps", ] [[package]] name = "gdk-sys" -version = "0.15.1" +version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32e7a08c1e8f06f4177fb7e51a777b8c1689f743a7bc11ea91d44d2226073a88" +checksum = "5c2d13f38594ac1e66619e188c6d5a1adb98d11b2fcf7894fc416ad76aa2f3f7" dependencies = [ "cairo-sys-rs", "gdk-pixbuf-sys", @@ -1096,47 +1453,48 @@ dependencies = [ "libc", "pango-sys", "pkg-config", - "system-deps 6.2.2", + "system-deps", ] [[package]] name = "gdkwayland-sys" -version = "0.15.3" +version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cca49a59ad8cfdf36ef7330fe7bdfbe1d34323220cc16a0de2679ee773aee2c2" +checksum = "140071d506d223f7572b9f09b5e155afbd77428cd5cc7af8f2694c41d98dfe69" dependencies = [ "gdk-sys", "glib-sys", "gobject-sys", "libc", "pkg-config", - "system-deps 6.2.2", + "system-deps", ] [[package]] -name = "gdkx11-sys" -version = "0.15.1" +name = "gdkx11" +version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4b7f8c7a84b407aa9b143877e267e848ff34106578b64d1e0a24bf550716178" +checksum = "3caa00e14351bebbc8183b3c36690327eb77c49abc2268dd4bd36b856db3fbfe" dependencies = [ - "gdk-sys", - "glib-sys", + "gdk", + "gdkx11-sys", + "gio", + "glib", "libc", - "system-deps 6.2.2", "x11", ] [[package]] -name = "generator" -version = "0.7.5" +name = "gdkx11-sys" +version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cc16584ff22b460a382b7feec54b23d2908d858152e5739a120b949293bd74e" +checksum = "6e2e7445fe01ac26f11601db260dd8608fe172514eb63b3b5e261ea6b0f4428d" dependencies = [ - "cc", + "gdk-sys", + "glib-sys", "libc", - "log", - "rustversion", - "windows 0.48.0", + "system-deps", + "x11", ] [[package]] @@ -1149,6 +1507,16 @@ dependencies = [ "version_check", ] +[[package]] +name = "gethostname" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc3655aa6818d65bc620d6911f05aa7b6aeb596291e1e9f79e52df85583d1e30" +dependencies = [ + "rustix", + "windows-targets 0.52.6", +] + [[package]] name = "getrandom" version = "0.1.16" @@ -1179,31 +1547,33 @@ checksum = "32085ea23f3234fc7846555e85283ba4de91e21016dc0455a16286d87a292d64" [[package]] name = "gio" -version = "0.15.12" +version = "0.18.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68fdbc90312d462781a395f7a16d96a2b379bb6ef8cd6310a2df272771c4283b" +checksum = "d4fc8f532f87b79cbc51a79748f16a6828fb784be93145a322fa14d06d354c73" dependencies = [ - "bitflags 1.3.2", "futures-channel", "futures-core", "futures-io", + "futures-util", "gio-sys", "glib", "libc", "once_cell", - "thiserror", + "pin-project-lite", + "smallvec", + "thiserror 1.0.63", ] [[package]] name = "gio-sys" -version = "0.15.10" +version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32157a475271e2c4a023382e9cab31c4584ee30a97da41d3c4e9fdd605abcf8d" +checksum = "37566df850baf5e4cb0dfb78af2e4b9898d817ed9263d1090a2df958c64737d2" dependencies = [ "glib-sys", "gobject-sys", "libc", - "system-deps 6.2.2", + "system-deps", "winapi", ] @@ -1218,47 +1588,49 @@ dependencies = [ [[package]] name = "glib" -version = "0.15.12" +version = "0.18.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edb0306fbad0ab5428b0ca674a23893db909a98582969c9b537be4ced78c505d" +checksum = "233daaf6e83ae6a12a52055f568f9d7cf4671dabb78ff9560ab6da230ce00ee5" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.6.0", "futures-channel", "futures-core", "futures-executor", "futures-task", + "futures-util", + "gio-sys", "glib-macros", "glib-sys", "gobject-sys", "libc", + "memchr", "once_cell", "smallvec", - "thiserror", + "thiserror 1.0.63", ] [[package]] name = "glib-macros" -version = "0.15.13" +version = "0.18.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10c6ae9f6fa26f4fb2ac16b528d138d971ead56141de489f8111e259b9df3c4a" +checksum = "0bb0228f477c0900c880fd78c8759b95c7636dbd7842707f49e132378aa2acdc" dependencies = [ - "anyhow", "heck 0.4.1", - "proc-macro-crate 1.3.1", + "proc-macro-crate 2.0.2", "proc-macro-error", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.91", ] [[package]] name = "glib-sys" -version = "0.15.10" +version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef4b192f8e65e9cf76cbf4ea71fa8e3be4a0e18ffe3d68b8da6836974cc5bad4" +checksum = "063ce2eb6a8d0ea93d2bf8ba1957e78dbab6be1c2220dd3daca57d5a9d869898" dependencies = [ "libc", - "system-deps 6.2.2", + "system-deps", ] [[package]] @@ -1267,6 +1639,23 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" +[[package]] +name = "global-hotkey" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b00d88f1be7bf4cd2e61623ce08e84be2dfa4eab458e5d632d3dab95f16c1f64" +dependencies = [ + "crossbeam-channel", + "keyboard-types", + "objc2", + "objc2-app-kit", + "once_cell", + "serde", + "thiserror 1.0.63", + "windows-sys 0.59.0", + "x11-dl", +] + [[package]] name = "globset" version = "0.4.15" @@ -1276,8 +1665,8 @@ dependencies = [ "aho-corasick", "bstr", "log", - "regex-automata 0.4.7", - "regex-syntax 0.8.4", + "regex-automata", + "regex-syntax", ] [[package]] @@ -1293,23 +1682,22 @@ dependencies = [ [[package]] name = "gobject-sys" -version = "0.15.10" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d57ce44246becd17153bd035ab4d32cfee096a657fc01f2231c9278378d1e0a" +checksum = "0850127b514d1c4a4654ead6dedadb18198999985908e6ffe4436f53c785ce44" dependencies = [ "glib-sys", "libc", - "system-deps 6.2.2", + "system-deps", ] [[package]] name = "gtk" -version = "0.15.5" +version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92e3004a2d5d6d8b5057d2b57b3712c9529b62e82c77f25c1fecde1fd5c23bd0" +checksum = "fd56fb197bfc42bd5d2751f4f017d44ff59fbb58140c6b49f9b3b2bdab08506a" dependencies = [ "atk", - "bitflags 1.3.2", "cairo-rs", "field-offset", "futures-channel", @@ -1320,16 +1708,15 @@ dependencies = [ "gtk-sys", "gtk3-macros", "libc", - "once_cell", "pango", "pkg-config", ] [[package]] name = "gtk-sys" -version = "0.15.3" +version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5bc2f0587cba247f60246a0ca11fe25fb733eabc3de12d1965fc07efab87c84" +checksum = "8f29a1c21c59553eb7dd40e918be54dccd60c52b049b75119d5d96ce6b624414" dependencies = [ "atk-sys", "cairo-sys-rs", @@ -1340,21 +1727,20 @@ dependencies = [ "gobject-sys", "libc", "pango-sys", - "system-deps 6.2.2", + "system-deps", ] [[package]] name = "gtk3-macros" -version = "0.15.6" +version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "684c0456c086e8e7e9af73ec5b84e35938df394712054550e81558d21c44ab0d" +checksum = "52ff3c5b21f14f0736fed6dcfc0bfb4225ebf5725f3c0209edeec181e4d73e9d" dependencies = [ - "anyhow", "proc-macro-crate 1.3.1", "proc-macro-error", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.91", ] [[package]] @@ -1368,7 +1754,7 @@ dependencies = [ "fnv", "futures-core", "futures-sink", - "http 1.1.0", + "http", "indexmap 2.5.0", "slab", "tokio", @@ -1400,15 +1786,6 @@ dependencies = [ "hashbrown 0.14.5", ] -[[package]] -name = "heck" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" -dependencies = [ - "unicode-segmentation", -] - [[package]] name = "heck" version = "0.4.1" @@ -1427,6 +1804,12 @@ version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" +[[package]] +name = "hermit-abi" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" + [[package]] name = "hex" version = "0.4.3" @@ -1447,17 +1830,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "http" -version = "0.2.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" -dependencies = [ - "bytes", - "fnv", - "itoa 1.0.11", -] - [[package]] name = "http" version = "1.1.0" @@ -1476,7 +1848,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ "bytes", - "http 1.1.0", + "http", ] [[package]] @@ -1487,7 +1859,7 @@ checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" dependencies = [ "bytes", "futures-util", - "http 1.1.0", + "http", "http-body", "pin-project-lite", ] @@ -1514,7 +1886,7 @@ dependencies = [ "futures-channel", "futures-util", "h2", - "http 1.1.0", + "http", "http-body", "httparse", "itoa 1.0.11", @@ -1531,7 +1903,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08afdbb5c31130e3034af566421053ab03787c640246a446327f550d11bcb333" dependencies = [ "futures-util", - "http 1.1.0", + "http", "hyper", "hyper-util", "rustls", @@ -1566,7 +1938,7 @@ dependencies = [ "bytes", "futures-channel", "futures-util", - "http 1.1.0", + "http", "http-body", "hyper", "pin-project-lite", @@ -1636,24 +2008,12 @@ dependencies = [ "globset", "log", "memchr", - "regex-automata 0.4.7", + "regex-automata", "same-file", "walkdir", "winapi-util", ] -[[package]] -name = "image" -version = "0.24.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5690139d2f55868e080017335e4b94cb7414274c74f1669c84fb5feba2c9f69d" -dependencies = [ - "bytemuck", - "byteorder", - "color_quant", - "num-traits", -] - [[package]] name = "indexmap" version = "1.9.3" @@ -1684,9 +2044,9 @@ checksum = "b248f5224d1d606005e02c97f5aa4e88eeb230488bcc03bc9ca4d7991399f2b5" [[package]] name = "infer" -version = "0.13.0" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f551f8c3a39f68f986517db0d1759de85881894fdc7db798bd2a9df9cb04b7fc" +checksum = "bc150e5ce2330295b8616ce0e3f53250e53af31759a9dbedad1621ba29151847" dependencies = [ "cfb", ] @@ -1706,6 +2066,25 @@ version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "187674a687eed5fe42285b40c6291f9a01517d415fad1c3cbc6a9f778af7fcd4" +[[package]] +name = "is-docker" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "928bae27f42bc99b60d9ac7334e3a21d10ad8f1835a4e12ec3ec0464765ed1b3" +dependencies = [ + "once_cell", +] + +[[package]] +name = "is-wsl" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "173609498df190136aa7dea1a91db051746d339e18476eed5ca40521f02d7aa5" +dependencies = [ + "is-docker", + "once_cell", +] + [[package]] name = "itertools" version = "0.13.0" @@ -1729,9 +2108,9 @@ checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] name = "javascriptcore-rs" -version = "0.16.0" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf053e7843f2812ff03ef5afe34bb9c06ffee120385caad4f6b9967fcd37d41c" +checksum = "ca5671e9ffce8ffba57afc24070e906da7fc4b1ba66f2cabebf61bf2ea257fcc" dependencies = [ "bitflags 1.3.2", "glib", @@ -1740,28 +2119,14 @@ dependencies = [ [[package]] name = "javascriptcore-rs-sys" -version = "0.4.0" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "905fbb87419c5cde6e3269537e4ea7d46431f3008c5d057e915ef3f115e7793c" +checksum = "af1be78d14ffa4b75b66df31840478fef72b51f8c2465d4ca7c194da9f7a5124" dependencies = [ "glib-sys", "gobject-sys", "libc", - "system-deps 5.0.0", -] - -[[package]] -name = "jni" -version = "0.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "039022cdf4d7b1cf548d31f60ae783138e5fd42013f6271049d7df7afadef96c" -dependencies = [ - "cesu8", - "combine", - "jni-sys", - "log", - "thiserror", - "walkdir", + "system-deps", ] [[package]] @@ -1775,7 +2140,7 @@ dependencies = [ "combine", "jni-sys", "log", - "thiserror", + "thiserror 1.0.63", "walkdir", "windows-sys 0.45.0", ] @@ -1806,27 +2171,37 @@ dependencies = [ [[package]] name = "json-patch" -version = "2.0.0" +version = "3.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b1fb8864823fad91877e6caea0baca82e49e8db50f8e5c9f9a453e27d3330fc" +checksum = "863726d7afb6bc2590eeff7135d923545e5e964f004c2ccf8716c25e70a86f08" dependencies = [ "jsonptr", "serde", "serde_json", - "thiserror", + "thiserror 1.0.63", ] [[package]] name = "jsonptr" -version = "0.4.7" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c6e529149475ca0b2820835d3dce8fcc41c6b943ca608d32f35b449255e4627" +checksum = "5dea2b27dd239b2556ed7a25ba842fe47fd602e7fc7433c2a8d6106d4d9edd70" dependencies = [ - "fluent-uri", "serde", "serde_json", ] +[[package]] +name = "keyboard-types" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b750dcadc39a09dbadd74e118f6dd6598df77fa01df0cfcdc52c28dece74528a" +dependencies = [ + "bitflags 2.6.0", + "serde", + "unicode-segmentation", +] + [[package]] name = "kira" version = "0.9.5" @@ -1862,12 +2237,46 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +[[package]] +name = "libappindicator" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03589b9607c868cc7ae54c0b2a22c8dc03dd41692d48f2d7df73615c6a95dc0a" +dependencies = [ + "glib", + "gtk", + "gtk-sys", + "libappindicator-sys", + "log", +] + +[[package]] +name = "libappindicator-sys" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e9ec52138abedcc58dc17a7c6c0c00a2bdb4f3427c7f63fa97fd0d859155caf" +dependencies = [ + "gtk-sys", + "libloading 0.7.4", + "once_cell", +] + [[package]] name = "libc" version = "0.2.158" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" +[[package]] +name = "libloading" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" +dependencies = [ + "cfg-if", + "winapi", +] + [[package]] name = "libloading" version = "0.8.5" @@ -1886,7 +2295,6 @@ checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ "bitflags 2.6.0", "libc", - "redox_syscall", ] [[package]] @@ -1939,7 +2347,7 @@ checksum = "28bd4b9d8a5af74808932492521cdd272019b056f75fcc70056bd2c09fceb550" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.91", ] [[package]] @@ -1948,21 +2356,6 @@ version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" -[[package]] -name = "loom" -version = "0.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff50ecb28bb86013e935fb6683ab1f6d3a20016f123c76fd4c27470076ac30f5" -dependencies = [ - "cfg-if", - "generator", - "scoped-tls", - "serde", - "serde_json", - "tracing", - "tracing-subscriber", -] - [[package]] name = "lrc" version = "0.1.8" @@ -1998,7 +2391,11 @@ dependencies = [ "symphonia", "tauri", "tauri-build", - "thiserror", + "tauri-plugin-dialog", + "tauri-plugin-global-shortcut", + "tauri-plugin-os", + "tauri-plugin-shell", + "thiserror 1.0.63", "tokio", ] @@ -2040,15 +2437,6 @@ dependencies = [ "tendril", ] -[[package]] -name = "matchers" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" -dependencies = [ - "regex-automata 0.1.10", -] - [[package]] name = "matches" version = "0.1.10" @@ -2113,12 +2501,32 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" dependencies = [ - "hermit-abi", + "hermit-abi 0.3.9", "libc", "wasi 0.11.0+wasi-snapshot-preview1", "windows-sys 0.52.0", ] +[[package]] +name = "muda" +version = "0.15.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdae9c00e61cc0579bcac625e8ad22104c60548a025bfc972dc83868a28e1484" +dependencies = [ + "crossbeam-channel", + "dpi", + "gtk", + "keyboard-types", + "objc2", + "objc2-app-kit", + "objc2-foundation", + "once_cell", + "png", + "serde", + "thiserror 1.0.63", + "windows-sys 0.59.0", +] + [[package]] name = "native-tls" version = "0.2.12" @@ -2138,192 +2546,364 @@ dependencies = [ [[package]] name = "ndk" -version = "0.6.0" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2076a31b7010b17a38c01907c45b945e8f11495ee4dd588309718901b1f7a5b7" +dependencies = [ + "bitflags 2.6.0", + "jni-sys", + "log", + "ndk-sys 0.5.0+25.2.9519653", + "num_enum", + "thiserror 1.0.63", +] + +[[package]] +name = "ndk" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4" +dependencies = [ + "bitflags 2.6.0", + "jni-sys", + "log", + "ndk-sys 0.6.0+11769913", + "num_enum", + "raw-window-handle", + "thiserror 1.0.63", +] + +[[package]] +name = "ndk-context" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b" + +[[package]] +name = "ndk-sys" +version = "0.5.0+25.2.9519653" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c196769dd60fd4f363e11d948139556a344e79d451aeb2fa2fd040738ef7691" +dependencies = [ + "jni-sys", +] + +[[package]] +name = "ndk-sys" +version = "0.6.0+11769913" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee6cda3051665f1fb8d9e08fc35c96d5a244fb1be711a03b71118828afc9a873" +dependencies = [ + "jni-sys", +] + +[[package]] +name = "new_debug_unreachable" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" + +[[package]] +name = "nix" +version = "0.27.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053" +dependencies = [ + "bitflags 2.6.0", + "cfg-if", + "libc", + "memoffset", +] + +[[package]] +name = "nodrop" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + +[[package]] +name = "num-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.91", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_enum" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2032c77e030ddee34a6787a64166008da93f6a352b629261d0fee232b8742dd4" +checksum = "4e613fc340b2220f734a8595782c551f1250e969d87d3be1ae0579e8d4065179" dependencies = [ - "bitflags 1.3.2", - "jni-sys", - "ndk-sys 0.3.0", - "num_enum 0.5.11", - "thiserror", + "num_enum_derive", ] [[package]] -name = "ndk" -version = "0.8.0" +name = "num_enum_derive" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2076a31b7010b17a38c01907c45b945e8f11495ee4dd588309718901b1f7a5b7" +checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" dependencies = [ - "bitflags 2.6.0", - "jni-sys", - "log", - "ndk-sys 0.5.0+25.2.9519653", - "num_enum 0.7.3", - "thiserror", + "proc-macro-crate 2.0.2", + "proc-macro2", + "quote", + "syn 2.0.91", ] [[package]] -name = "ndk-context" -version = "0.1.1" +name = "objc" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b" +checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" +dependencies = [ + "malloc_buf", +] [[package]] -name = "ndk-sys" -version = "0.3.0" +name = "objc-sys" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e5a6ae77c8ee183dcbbba6150e2e6b9f3f4196a7666c02a715a95692ec1fa97" +checksum = "cdb91bdd390c7ce1a8607f35f3ca7151b65afc0ff5ff3b34fa350f7d7c7e4310" dependencies = [ - "jni-sys", + "cc", ] [[package]] -name = "ndk-sys" -version = "0.5.0+25.2.9519653" +name = "objc2" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c196769dd60fd4f363e11d948139556a344e79d451aeb2fa2fd040738ef7691" +checksum = "46a785d4eeff09c14c487497c162e92766fbb3e4059a71840cecc03d9a50b804" dependencies = [ - "jni-sys", + "objc-sys", + "objc2-encode", ] [[package]] -name = "new_debug_unreachable" -version = "1.0.6" +name = "objc2-app-kit" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" +checksum = "e4e89ad9e3d7d297152b17d39ed92cd50ca8063a89a9fa569046d41568891eff" +dependencies = [ + "bitflags 2.6.0", + "block2", + "libc", + "objc2", + "objc2-core-data", + "objc2-core-image", + "objc2-foundation", + "objc2-quartz-core", +] [[package]] -name = "nodrop" -version = "0.1.14" +name = "objc2-cloud-kit" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" +checksum = "74dd3b56391c7a0596a295029734d3c1c5e7e510a4cb30245f8221ccea96b009" +dependencies = [ + "bitflags 2.6.0", + "block2", + "objc2", + "objc2-core-location", + "objc2-foundation", +] [[package]] -name = "nom" -version = "7.1.3" +name = "objc2-contacts" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +checksum = "a5ff520e9c33812fd374d8deecef01d4a840e7b41862d849513de77e44aa4889" dependencies = [ - "memchr", - "minimal-lexical", + "block2", + "objc2", + "objc2-foundation", ] [[package]] -name = "nu-ansi-term" -version = "0.46.0" +name = "objc2-core-data" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +checksum = "617fbf49e071c178c0b24c080767db52958f716d9eabdf0890523aeae54773ef" dependencies = [ - "overload", - "winapi", + "bitflags 2.6.0", + "block2", + "objc2", + "objc2-foundation", ] [[package]] -name = "num-conv" -version = "0.1.0" +name = "objc2-core-image" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" +checksum = "55260963a527c99f1819c4f8e3b47fe04f9650694ef348ffd2227e8196d34c80" +dependencies = [ + "block2", + "objc2", + "objc2-foundation", + "objc2-metal", +] [[package]] -name = "num-derive" -version = "0.4.2" +name = "objc2-core-location" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" +checksum = "000cfee34e683244f284252ee206a27953279d370e309649dc3ee317b37e5781" dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.77", + "block2", + "objc2", + "objc2-contacts", + "objc2-foundation", ] [[package]] -name = "num-traits" -version = "0.2.19" +name = "objc2-encode" +version = "4.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" -dependencies = [ - "autocfg", -] +checksum = "7891e71393cd1f227313c9379a26a584ff3d7e6e7159e988851f0934c993f0f8" [[package]] -name = "num_enum" -version = "0.5.11" +name = "objc2-foundation" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f646caf906c20226733ed5b1374287eb97e3c2a5c227ce668c1f2ce20ae57c9" +checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8" dependencies = [ - "num_enum_derive 0.5.11", + "bitflags 2.6.0", + "block2", + "dispatch", + "libc", + "objc2", ] [[package]] -name = "num_enum" -version = "0.7.3" +name = "objc2-link-presentation" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e613fc340b2220f734a8595782c551f1250e969d87d3be1ae0579e8d4065179" +checksum = "a1a1ae721c5e35be65f01a03b6d2ac13a54cb4fa70d8a5da293d7b0020261398" dependencies = [ - "num_enum_derive 0.7.3", + "block2", + "objc2", + "objc2-app-kit", + "objc2-foundation", ] [[package]] -name = "num_enum_derive" -version = "0.5.11" +name = "objc2-metal" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcbff9bc912032c62bf65ef1d5aea88983b420f4f839db1e9b0c281a25c9c799" +checksum = "dd0cba1276f6023976a406a14ffa85e1fdd19df6b0f737b063b95f6c8c7aadd6" dependencies = [ - "proc-macro-crate 1.3.1", - "proc-macro2", - "quote", - "syn 1.0.109", + "bitflags 2.6.0", + "block2", + "objc2", + "objc2-foundation", ] [[package]] -name = "num_enum_derive" -version = "0.7.3" +name = "objc2-quartz-core" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" +checksum = "e42bee7bff906b14b167da2bac5efe6b6a07e6f7c0a21a7308d40c960242dc7a" dependencies = [ - "proc-macro-crate 3.2.0", - "proc-macro2", - "quote", - "syn 2.0.77", + "bitflags 2.6.0", + "block2", + "objc2", + "objc2-foundation", + "objc2-metal", ] [[package]] -name = "objc" -version = "0.2.7" +name = "objc2-symbols" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" +checksum = "0a684efe3dec1b305badae1a28f6555f6ddd3bb2c2267896782858d5a78404dc" dependencies = [ - "malloc_buf", - "objc_exception", + "objc2", + "objc2-foundation", ] [[package]] -name = "objc-foundation" -version = "0.1.1" +name = "objc2-ui-kit" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1add1b659e36c9607c7aab864a76c7a4c2760cd0cd2e120f3fb8b952c7e22bf9" +checksum = "b8bb46798b20cd6b91cbd113524c490f1686f4c4e8f49502431415f3512e2b6f" dependencies = [ - "block", - "objc", - "objc_id", + "bitflags 2.6.0", + "block2", + "objc2", + "objc2-cloud-kit", + "objc2-core-data", + "objc2-core-image", + "objc2-core-location", + "objc2-foundation", + "objc2-link-presentation", + "objc2-quartz-core", + "objc2-symbols", + "objc2-uniform-type-identifiers", + "objc2-user-notifications", +] + +[[package]] +name = "objc2-uniform-type-identifiers" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44fa5f9748dbfe1ca6c0b79ad20725a11eca7c2218bceb4b005cb1be26273bfe" +dependencies = [ + "block2", + "objc2", + "objc2-foundation", ] [[package]] -name = "objc_exception" -version = "0.1.2" +name = "objc2-user-notifications" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad970fb455818ad6cba4c122ad012fae53ae8b4795f86378bce65e4f6bab2ca4" +checksum = "76cfcbf642358e8689af64cee815d139339f3ed8ad05103ed5eaf73db8d84cb3" dependencies = [ - "cc", + "bitflags 2.6.0", + "block2", + "objc2", + "objc2-core-location", + "objc2-foundation", ] [[package]] -name = "objc_id" -version = "0.1.1" +name = "objc2-web-kit" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c92d4ddb4bd7b50d730c215ff871754d0da6b2178849f8a2a2ab69712d0c073b" +checksum = "68bc69301064cebefc6c4c90ce9cba69225239e4b8ff99d445a2b5563797da65" dependencies = [ - "objc", + "bitflags 2.6.0", + "block2", + "objc2", + "objc2-app-kit", + "objc2-foundation", ] [[package]] @@ -2341,7 +2921,7 @@ version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8b61bebd49e5d43f5f8cc7ee2891c16e0f41ec7954d36bcb6c14c5e0de867fb" dependencies = [ - "jni 0.21.1", + "jni", "ndk 0.8.0", "ndk-context", "num-derive", @@ -2375,12 +2955,13 @@ checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "open" -version = "3.2.0" +version = "5.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2078c0039e6a54a0c42c28faa984e115fb4c2d5bf2208f77d1961002df8576f8" +checksum = "3ecd52f0b8d15c40ce4820aa251ed5de032e5d91fab27f7db2f40d42a8bdf69c" dependencies = [ + "is-wsl", + "libc", "pathdiff", - "windows-sys 0.42.0", ] [[package]] @@ -2391,7 +2972,7 @@ checksum = "9529f4786b70a3e8c61e11179af17ab6188ad8d0ded78c5529441ed39d4bd9c1" dependencies = [ "bitflags 2.6.0", "cfg-if", - "foreign-types", + "foreign-types 0.3.2", "libc", "once_cell", "openssl-macros", @@ -2406,7 +2987,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.91", ] [[package]] @@ -2427,11 +3008,27 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "option-ext" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" + +[[package]] +name = "ordered-stream" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aa2b01e1d916879f73a53d01d1d6cee68adbb31d6d9177a8cfce093cced1d50" +dependencies = [ + "futures-core", + "pin-project-lite", +] + [[package]] name = "os_info" -version = "3.8.2" +version = "3.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae99c7fa6dd38c7cafe1ec085e804f8f555a2f8659b0dbe03f1f9963a9b51092" +checksum = "eb6651f4be5e39563c4fe5cc8326349eb99a25d805a3493f791d5bfd0269e430" dependencies = [ "log", "serde", @@ -2439,18 +3036,22 @@ dependencies = [ ] [[package]] -name = "overload" -version = "0.1.1" +name = "os_pipe" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" +checksum = "5ffd2b0a5634335b135d5728d84c5e0fd726954b87111f7506a61c502280d982" +dependencies = [ + "libc", + "windows-sys 0.59.0", +] [[package]] name = "pango" -version = "0.15.10" +version = "0.18.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22e4045548659aee5313bde6c582b0d83a627b7904dd20dc2d9ef0895d414e4f" +checksum = "7ca27ec1eb0457ab26f3036ea52229edbdb74dee1edd29063f5b9b010e7ebee4" dependencies = [ - "bitflags 1.3.2", + "gio", "glib", "libc", "once_cell", @@ -2459,16 +3060,22 @@ dependencies = [ [[package]] name = "pango-sys" -version = "0.15.10" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2a00081cde4661982ed91d80ef437c20eacaf6aa1a5962c0279ae194662c3aa" +checksum = "436737e391a843e5933d6d9aa102cb126d501e815b83601365a948a518555dc5" dependencies = [ "glib-sys", "gobject-sys", "libc", - "system-deps 6.2.2", + "system-deps", ] +[[package]] +name = "parking" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" + [[package]] name = "parking_lot" version = "0.12.3" @@ -2500,9 +3107,9 @@ checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" [[package]] name = "pathdiff" -version = "0.2.1" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd" +checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3" [[package]] name = "percent-encoding" @@ -2614,7 +3221,7 @@ dependencies = [ "phf_shared 0.11.2", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.91", ] [[package]] @@ -2661,7 +3268,7 @@ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.91", ] [[package]] @@ -2676,6 +3283,17 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "piper" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96c8c490f422ef9a4efd2cb5b42b76c8613d7e7dfc1caf667b8a3350a5acc066" +dependencies = [ + "atomic-waker", + "fastrand", + "futures-io", +] + [[package]] name = "pkg-config" version = "0.3.30" @@ -2690,7 +3308,7 @@ checksum = "42cf17e9a1800f5f396bc67d193dc9411b59012a5876445ef450d449881e1016" dependencies = [ "base64 0.22.1", "indexmap 2.5.0", - "quick-xml", + "quick-xml 0.32.0", "serde", "time", ] @@ -2708,6 +3326,21 @@ dependencies = [ "miniz_oxide 0.7.4", ] +[[package]] +name = "polling" +version = "3.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a604568c3202727d1507653cb121dbd627a58684eb09a820fd746bee38b4442f" +dependencies = [ + "cfg-if", + "concurrent-queue", + "hermit-abi 0.4.0", + "pin-project-lite", + "rustix", + "tracing", + "windows-sys 0.59.0", +] + [[package]] name = "powerfmt" version = "0.2.0" @@ -2741,11 +3374,12 @@ dependencies = [ [[package]] name = "proc-macro-crate" -version = "3.2.0" +version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b" +checksum = "b00f26d3400549137f92511a46ac1cd8ce37cb5598a96d382381458b992a5d24" dependencies = [ - "toml_edit 0.22.21", + "toml_datetime", + "toml_edit 0.20.2", ] [[package]] @@ -2780,9 +3414,9 @@ checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" [[package]] name = "proc-macro2" -version = "1.0.86" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" dependencies = [ "unicode-ident", ] @@ -2796,6 +3430,15 @@ dependencies = [ "memchr", ] +[[package]] +name = "quick-xml" +version = "0.36.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7649a7b4df05aed9ea7ec6f628c67c9953a43869b8bc50929569b2999d443fe" +dependencies = [ + "memchr", +] + [[package]] name = "quote" version = "1.0.37" @@ -2888,9 +3531,9 @@ dependencies = [ [[package]] name = "raw-window-handle" -version = "0.5.2" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2ff9a1f06a88b01621b7ae906ef0211290d1c8a168a15542486a8f61c0833b9" +checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539" [[package]] name = "rayon" @@ -2929,7 +3572,7 @@ checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" dependencies = [ "getrandom 0.2.15", "libredox", - "thiserror", + "thiserror 1.0.63", ] [[package]] @@ -2940,17 +3583,8 @@ checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.4.7", - "regex-syntax 0.8.4", -] - -[[package]] -name = "regex-automata" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" -dependencies = [ - "regex-syntax 0.6.29", + "regex-automata", + "regex-syntax", ] [[package]] @@ -2961,15 +3595,9 @@ checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.8.4", + "regex-syntax", ] -[[package]] -name = "regex-syntax" -version = "0.6.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" - [[package]] name = "regex-syntax" version = "0.8.4" @@ -2988,7 +3616,7 @@ dependencies = [ "futures-core", "futures-util", "h2", - "http 1.1.0", + "http", "http-body", "http-body-util", "hyper", @@ -3011,36 +3639,37 @@ dependencies = [ "system-configuration", "tokio", "tokio-native-tls", + "tokio-util", "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", + "wasm-streams", "web-sys", "windows-registry", ] [[package]] name = "rfd" -version = "0.10.0" +version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0149778bd99b6959285b0933288206090c50e2327f47a9c463bfdbf45c8823ea" +checksum = "8af382a047821a08aa6bfc09ab0d80ff48d45d8726f7cd8e44891f7cb4a4278e" dependencies = [ - "block", - "dispatch", + "ashpd", + "block2", "glib-sys", "gobject-sys", "gtk-sys", "js-sys", - "lazy_static", "log", - "objc", - "objc-foundation", - "objc_id", + "objc2", + "objc2-app-kit", + "objc2-foundation", "raw-window-handle", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "windows 0.37.0", + "windows-sys 0.48.0", ] [[package]] @@ -3155,12 +3784,6 @@ dependencies = [ "untrusted", ] -[[package]] -name = "rustversion" -version = "1.0.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" - [[package]] name = "ryu" version = "1.0.18" @@ -3185,6 +3808,33 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "schemars" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09c024468a378b7e36765cd36702b7a90cc3cba11654f6685c8f233408e89e92" +dependencies = [ + "dyn-clone", + "indexmap 1.9.3", + "schemars_derive", + "serde", + "serde_json", + "url", + "uuid", +] + +[[package]] +name = "schemars_derive" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1eee588578aff73f856ab961cd2f79e36bc45d7ded33a7562adba4667aecc0e" +dependencies = [ + "proc-macro2", + "quote", + "serde_derive_internals", + "syn 2.0.91", +] + [[package]] name = "scoped-tls" version = "1.0.1" @@ -3213,7 +3863,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" dependencies = [ "bitflags 2.6.0", - "core-foundation", + "core-foundation 0.9.4", "core-foundation-sys", "libc", "security-framework-sys", @@ -3273,6 +3923,17 @@ dependencies = [ "serde_derive", ] +[[package]] +name = "serde-untagged" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2676ba99bd82f75cae5cbd2c8eda6fa0b8760f18978ea840e980dd5567b5c5b6" +dependencies = [ + "erased-serde", + "serde", + "typeid", +] + [[package]] name = "serde_derive" version = "1.0.210" @@ -3281,7 +3942,18 @@ checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.91", +] + +[[package]] +name = "serde_derive_internals" +version = "0.29.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.91", ] [[package]] @@ -3290,7 +3962,6 @@ version = "1.0.128" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" dependencies = [ - "indexmap 2.5.0", "itoa 1.0.11", "memchr", "ryu", @@ -3305,7 +3976,7 @@ checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.91", ] [[package]] @@ -3356,14 +4027,14 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.91", ] [[package]] name = "serialize-to-javascript" -version = "0.1.2" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04f3666a07a197cdb77cdf306c32be9b7f598d7060d50cfd4d5aa04bfd92f6c5" +checksum = "c9823f2d3b6a81d98228151fdeaf848206a7855a7a042bbf9bf870449a66cafb" dependencies = [ "serde", "serde_json", @@ -3372,13 +4043,13 @@ dependencies = [ [[package]] name = "serialize-to-javascript-impl" -version = "0.1.2" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "772ee033c0916d670af7860b6e1ef7d658a4629a6d0b4c8c3e67f09b3765b75d" +checksum = "74064874e9f6a15f04c1f3cb627902d0e6b410abbf36668afa873c61889f1763" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 1.0.109", ] [[package]] @@ -3391,6 +4062,17 @@ dependencies = [ "stable_deref_trait", ] +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + [[package]] name = "sha2" version = "0.10.8" @@ -3403,12 +4085,13 @@ dependencies = [ ] [[package]] -name = "sharded-slab" -version = "0.1.7" +name = "shared_child" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +checksum = "09fa9338aed9a1df411814a5b2252f7cd206c55ae9bf2fa763f8de84603aa60c" dependencies = [ - "lazy_static", + "libc", + "windows-sys 0.59.0", ] [[package]] @@ -3464,31 +4147,51 @@ dependencies = [ ] [[package]] -name = "soup2" -version = "0.2.1" +name = "softbuffer" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18051cdd562e792cad055119e0cdb2cfc137e44e3987532e0f9659a77931bb08" +dependencies = [ + "bytemuck", + "cfg_aliases", + "core-graphics", + "foreign-types 0.5.0", + "js-sys", + "log", + "objc2", + "objc2-foundation", + "objc2-quartz-core", + "raw-window-handle", + "redox_syscall", + "wasm-bindgen", + "web-sys", + "windows-sys 0.59.0", +] + +[[package]] +name = "soup3" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2b4d76501d8ba387cf0fefbe055c3e0a59891d09f0f995ae4e4b16f6b60f3c0" +checksum = "471f924a40f31251afc77450e781cb26d55c0b650842efafc9c6cbd2f7cc4f9f" dependencies = [ - "bitflags 1.3.2", + "futures-channel", "gio", "glib", "libc", - "once_cell", - "soup2-sys", + "soup3-sys", ] [[package]] -name = "soup2-sys" -version = "0.2.0" +name = "soup3-sys" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "009ef427103fcb17f802871647a7fa6c60cbb654b4c4e4c0ac60a31c5f6dc9cf" +checksum = "7ebe8950a680a12f24f15ebe1bf70db7af98ad242d9db43596ad3108aab86c27" dependencies = [ - "bitflags 1.3.2", "gio-sys", "glib-sys", "gobject-sys", "libc", - "system-deps 5.0.0", + "system-deps", ] [[package]] @@ -3504,13 +4207,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" [[package]] -name = "state" -version = "0.5.3" +name = "static_assertions" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbe866e1e51e8260c9eed836a042a5e7f6726bb2b411dffeaa712e19c388f23b" -dependencies = [ - "loom", -] +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" [[package]] name = "string_cache" @@ -3550,6 +4250,17 @@ version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" +[[package]] +name = "swift-rs" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4057c98e2e852d51fdcfca832aac7b571f6b351ad159f9eda5db1655f8d0c4d7" +dependencies = [ + "base64 0.21.7", + "serde", + "serde_json", +] + [[package]] name = "symphonia" version = "0.5.4" @@ -3758,9 +4469,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.77" +version = "2.0.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed" +checksum = "d53cbcb5a243bd33b7858b1d7f4aca2153490815872d86d955d6ea29f743c035" dependencies = [ "proc-macro2", "quote", @@ -3778,9 +4489,9 @@ dependencies = [ [[package]] name = "sys-locale" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e801cf239ecd6ccd71f03d270d67dd53d13e90aab208bf4b8fe4ad957ea949b0" +checksum = "8eab9a99a024a169fe8a903cf9d4a3b3601109bcc13bd9e3c6fff259138626c4" dependencies = [ "libc", ] @@ -3792,7 +4503,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" dependencies = [ "bitflags 2.6.0", - "core-foundation", + "core-foundation 0.9.4", "system-configuration-sys", ] @@ -3806,76 +4517,55 @@ dependencies = [ "libc", ] -[[package]] -name = "system-deps" -version = "5.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18db855554db7bd0e73e06cf7ba3df39f97812cb11d3f75e71c39bf45171797e" -dependencies = [ - "cfg-expr 0.9.1", - "heck 0.3.3", - "pkg-config", - "toml 0.5.11", - "version-compare 0.0.11", -] - [[package]] name = "system-deps" version = "6.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a3e535eb8dded36d55ec13eddacd30dec501792ff23a0b1682c38601b8cf2349" dependencies = [ - "cfg-expr 0.15.8", + "cfg-expr", "heck 0.5.0", "pkg-config", - "toml 0.8.19", - "version-compare 0.2.0", + "toml 0.8.2", + "version-compare", ] [[package]] name = "tao" -version = "0.16.10" +version = "0.30.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48d298c441a1da46e28e8ad8ec205aab7fd8cd71b9d10e05454224eef422e1ae" +checksum = "6682a07cf5bab0b8a2bd20d0a542917ab928b5edb75ebd4eda6b05cbaab872da" dependencies = [ - "bitflags 1.3.2", - "cairo-rs", - "cc", + "bitflags 2.6.0", "cocoa", - "core-foundation", + "core-foundation 0.10.0", "core-graphics", "crossbeam-channel", "dispatch", - "gdk", - "gdk-pixbuf", - "gdk-sys", + "dlopen2", + "dpi", "gdkwayland-sys", "gdkx11-sys", - "gio", - "glib", - "glib-sys", "gtk", - "image", "instant", - "jni 0.20.0", + "jni", "lazy_static", "libc", "log", - "ndk 0.6.0", + "ndk 0.9.0", "ndk-context", - "ndk-sys 0.3.0", + "ndk-sys 0.6.0+11769913", "objc", "once_cell", "parking_lot", - "png", "raw-window-handle", "scopeguard", - "serde", "tao-macros", "unicode-segmentation", - "uuid", - "windows 0.39.0", - "windows-implement", + "url", + "windows 0.58.0", + "windows-core 0.58.0", + "windows-version", "x11-dl", ] @@ -3887,18 +4577,7 @@ checksum = "f4e16beb8b2ac17db28eab8bca40e62dbfbb34c0fcdc6d9826b11b7b5d047dfd" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", -] - -[[package]] -name = "tar" -version = "0.4.41" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb797dad5fb5b76fcf519e702f4a589483b5ef06567f160c392832c1f5e44909" -dependencies = [ - "filetime", - "libc", - "xattr", + "syn 2.0.91", ] [[package]] @@ -3909,84 +4588,84 @@ checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" [[package]] name = "tauri" -version = "1.8.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "570a20223602ad990a30a048f2fdb957ae3e38de3ca9582e04cc09d01e8ccfad" +checksum = "e545de0a2dfe296fa67db208266cd397c5a55ae782da77973ef4c4fac90e9f2c" dependencies = [ "anyhow", - "cocoa", - "dirs-next", + "bytes", + "dirs", "dunce", "embed_plist", - "encoding_rs", - "flate2", "futures-util", "getrandom 0.2.15", - "glib", "glob", "gtk", "heck 0.5.0", - "http 0.2.12", - "ignore", + "http", + "http-range", + "jni", + "libc", "log", - "objc", - "once_cell", - "open", - "os_info", + "mime", + "muda", + "objc2", + "objc2-app-kit", + "objc2-foundation", "percent-encoding", "plist", - "rand 0.8.5", "raw-window-handle", - "regex", - "rfd", - "semver", + "reqwest", "serde", "serde_json", "serde_repr", "serialize-to-javascript", - "state", - "sys-locale", - "tar", + "swift-rs", + "tauri-build", "tauri-macros", "tauri-runtime", "tauri-runtime-wry", "tauri-utils", - "tempfile", - "thiserror", + "thiserror 2.0.9", "tokio", + "tray-icon", "url", - "uuid", + "urlpattern", "webkit2gtk", "webview2-com", - "windows 0.39.0", + "window-vibrancy", + "windows 0.58.0", ] [[package]] name = "tauri-build" -version = "1.5.5" +version = "2.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "586f3e677f940c8bb4f70c52eda05dc59b79e61543f1182de83516810bb8e35d" +checksum = "7bd2a4bcfaf5fb9f4be72520eefcb61ae565038f8ccba2a497d8c28f463b8c01" dependencies = [ "anyhow", "cargo_toml", - "dirs-next", + "dirs", + "glob", "heck 0.5.0", "json-patch", + "schemars", "semver", "serde", "serde_json", "tauri-utils", "tauri-winres", + "toml 0.8.2", "walkdir", ] [[package]] name = "tauri-codegen" -version = "1.4.5" +version = "2.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93a9e3f5cebf779a63bf24903e714ec91196c307d8249a0008b882424328bcda" +checksum = "bf79faeecf301d3e969b1fae977039edb77a4c1f25cc0a961be298b54bff97cf" dependencies = [ - "base64 0.21.7", + "base64 0.22.1", "brotli", "ico", "json-patch", @@ -3994,85 +4673,203 @@ dependencies = [ "png", "proc-macro2", "quote", - "regex", "semver", "serde", "serde_json", "sha2", + "syn 2.0.91", "tauri-utils", - "thiserror", + "thiserror 2.0.9", "time", + "url", "uuid", "walkdir", ] [[package]] name = "tauri-macros" -version = "1.4.6" +version = "2.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1d0e989f54fe06c5ef0875c5e19cf96453d099a0a774d5192ab47e80471cdab" +checksum = "c52027c8c5afb83166dacddc092ee8fff50772f9646d461d8c33ee887e447a03" dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.91", "tauri-codegen", "tauri-utils", ] +[[package]] +name = "tauri-plugin" +version = "2.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e753f2a30933a9bbf0a202fa47d7cc4a3401f06e8d6dcc53b79aa62954828c79" +dependencies = [ + "anyhow", + "glob", + "plist", + "schemars", + "serde", + "serde_json", + "tauri-utils", + "toml 0.8.2", + "walkdir", +] + +[[package]] +name = "tauri-plugin-dialog" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b59fd750551b1066744ab956a1cd6b1ea3e1b3763b0b9153ac27a044d596426" +dependencies = [ + "log", + "raw-window-handle", + "rfd", + "serde", + "serde_json", + "tauri", + "tauri-plugin", + "tauri-plugin-fs", + "thiserror 2.0.9", + "url", +] + +[[package]] +name = "tauri-plugin-fs" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1a1edf18000f02903a7c2e5997fb89aca455ecbc0acc15c6535afbb883be223" +dependencies = [ + "anyhow", + "dunce", + "glob", + "percent-encoding", + "schemars", + "serde", + "serde_json", + "serde_repr", + "tauri", + "tauri-plugin", + "tauri-utils", + "thiserror 2.0.9", + "toml 0.8.2", + "url", + "uuid", +] + +[[package]] +name = "tauri-plugin-global-shortcut" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00f646a09511e8d283267dcdaa08c2ef27c4116bf271d9114849d9ca215606c3" +dependencies = [ + "global-hotkey", + "log", + "serde", + "serde_json", + "tauri", + "tauri-plugin", + "thiserror 2.0.9", +] + +[[package]] +name = "tauri-plugin-os" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dda2d571a9baf0664c1f2088db227e3072f9028602fafa885deade7547c3b738" +dependencies = [ + "gethostname", + "log", + "os_info", + "serde", + "serde_json", + "serialize-to-javascript", + "sys-locale", + "tauri", + "tauri-plugin", + "thiserror 2.0.9", +] + +[[package]] +name = "tauri-plugin-shell" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb2c50a63e60fb8925956cc5b7569f4b750ac197a4d39f13b8dd46ea8e2bad79" +dependencies = [ + "encoding_rs", + "log", + "open", + "os_pipe", + "regex", + "schemars", + "serde", + "serde_json", + "shared_child", + "tauri", + "tauri-plugin", + "thiserror 2.0.9", + "tokio", +] + [[package]] name = "tauri-runtime" -version = "0.14.5" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f33fda7d213e239077fad52e96c6b734cecedb30c2382118b64f94cb5103ff3a" +checksum = "cce18d43f80d4aba3aa8a0c953bbe835f3d0f2370aca75e8dbb14bd4bab27958" dependencies = [ + "dpi", "gtk", - "http 0.2.12", - "http-range", - "rand 0.8.5", + "http", + "jni", "raw-window-handle", "serde", "serde_json", "tauri-utils", - "thiserror", + "thiserror 2.0.9", "url", - "uuid", - "webview2-com", - "windows 0.39.0", + "windows 0.58.0", ] [[package]] name = "tauri-runtime-wry" -version = "0.14.10" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18c447dcd9b0f09c7dc4b752cc33e72788805bfd761fbda5692d30c48289efec" +checksum = "9f442a38863e10129ffe2cec7bd09c2dcf8a098a3a27801a476a304d5bb991d2" dependencies = [ - "cocoa", "gtk", + "http", + "jni", + "log", + "objc2", + "objc2-app-kit", + "objc2-foundation", "percent-encoding", - "rand 0.8.5", "raw-window-handle", + "softbuffer", + "tao", "tauri-runtime", "tauri-utils", - "uuid", + "url", "webkit2gtk", "webview2-com", - "windows 0.39.0", + "windows 0.58.0", "wry", ] [[package]] name = "tauri-utils" -version = "1.6.1" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83a0c939e88d82903a0a7dfb28388b12a3c03504d6bd6086550edaa3b6d8beaa" +checksum = "9271a88f99b4adea0dc71d0baca4505475a0bbd139fb135f62958721aaa8fe54" dependencies = [ "brotli", + "cargo_metadata", "ctor", "dunce", "glob", - "heck 0.5.0", "html5ever", + "http", "infer", "json-patch", "kuchikiki", @@ -4081,14 +4878,20 @@ dependencies = [ "phf 0.11.2", "proc-macro2", "quote", + "regex", + "schemars", "semver", "serde", + "serde-untagged", "serde_json", "serde_with", - "thiserror", + "swift-rs", + "thiserror 2.0.9", + "toml 0.8.2", "url", + "urlpattern", + "uuid", "walkdir", - "windows-version", ] [[package]] @@ -4137,7 +4940,16 @@ version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" dependencies = [ - "thiserror-impl", + "thiserror-impl 1.0.63", +] + +[[package]] +name = "thiserror" +version = "2.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f072643fd0190df67a8bab670c20ef5d8737177d6ac6b2e9a236cb096206b2cc" +dependencies = [ + "thiserror-impl 2.0.9", ] [[package]] @@ -4148,17 +4960,18 @@ checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.91", ] [[package]] -name = "thread_local" -version = "1.1.8" +name = "thiserror-impl" +version = "2.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" +checksum = "7b50fa271071aae2e6ee85f842e2e28ba8cd2c5fb67f11fcb1fd70b276f9e7d4" dependencies = [ - "cfg-if", - "once_cell", + "proc-macro2", + "quote", + "syn 2.0.91", ] [[package]] @@ -4222,6 +5035,7 @@ dependencies = [ "signal-hook-registry", "socket2", "tokio-macros", + "tracing", "windows-sys 0.52.0", ] @@ -4233,7 +5047,7 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.91", ] [[package]] @@ -4270,15 +5084,6 @@ dependencies = [ "tokio", ] -[[package]] -name = "toml" -version = "0.5.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" -dependencies = [ - "serde", -] - [[package]] name = "toml" version = "0.7.8" @@ -4293,21 +5098,21 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.19" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" +checksum = "185d8ab0dfbb35cf1399a6344d8484209c088f75f8f68230da55d48d95d43e3d" dependencies = [ "serde", "serde_spanned", "toml_datetime", - "toml_edit 0.22.21", + "toml_edit 0.20.2", ] [[package]] name = "toml_datetime" -version = "0.6.8" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" +checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" dependencies = [ "serde", ] @@ -4322,20 +5127,20 @@ dependencies = [ "serde", "serde_spanned", "toml_datetime", - "winnow 0.5.40", + "winnow", ] [[package]] name = "toml_edit" -version = "0.22.21" +version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b072cee73c449a636ffd6f32bd8de3a9f7119139aff882f44943ce2986dc5cf" +checksum = "396e4d48bbb2b7554c944bde63101b5ae446cff6ec4a24227428f15eb72ef338" dependencies = [ "indexmap 2.5.0", "serde", "serde_spanned", "toml_datetime", - "winnow 0.6.18", + "winnow", ] [[package]] @@ -4378,13 +5183,13 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.27" +version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.91", ] [[package]] @@ -4394,36 +5199,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" dependencies = [ "once_cell", - "valuable", -] - -[[package]] -name = "tracing-log" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" -dependencies = [ - "log", - "once_cell", - "tracing-core", ] [[package]] -name = "tracing-subscriber" -version = "0.3.18" +name = "tray-icon" +version = "0.19.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" +checksum = "d48a05076dd272615d03033bf04f480199f7d1b66a8ac64d75c625fc4a70c06b" dependencies = [ - "matchers", - "nu-ansi-term", + "core-graphics", + "crossbeam-channel", + "dirs", + "libappindicator", + "muda", + "objc2", + "objc2-app-kit", + "objc2-foundation", "once_cell", - "regex", - "sharded-slab", - "smallvec", - "thread_local", - "tracing", - "tracing-core", - "tracing-log", + "png", + "serde", + "thiserror 1.0.63", + "windows-sys 0.59.0", ] [[package]] @@ -4441,12 +5237,70 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" +[[package]] +name = "typeid" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e13db2e0ccd5e14a544e8a246ba2312cd25223f616442d7f2cb0e3db614236e" + [[package]] name = "typenum" version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" +[[package]] +name = "uds_windows" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89daebc3e6fd160ac4aa9fc8b3bf71e1f74fbf92367ae71fb83a037e8bf164b9" +dependencies = [ + "memoffset", + "tempfile", + "winapi", +] + +[[package]] +name = "unic-char-property" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8c57a407d9b6fa02b4795eb81c5b6652060a15a7903ea981f3d723e6c0be221" +dependencies = [ + "unic-char-range", +] + +[[package]] +name = "unic-char-range" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0398022d5f700414f6b899e10b8348231abf9173fa93144cbc1a43b9793c1fbc" + +[[package]] +name = "unic-common" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80d7ff825a6a654ee85a63e80f92f054f904f21e7d12da4e22f9834a4aaa35bc" + +[[package]] +name = "unic-ucd-ident" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e230a37c0381caa9219d67cf063aa3a375ffed5bf541a452db16e744bdab6987" +dependencies = [ + "unic-char-property", + "unic-char-range", + "unic-ucd-version", +] + +[[package]] +name = "unic-ucd-version" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96bd2f2237fe450fcd0a1d2f5f4e91711124f7857ba2e964247776ebeeb7b0c4" +dependencies = [ + "unic-common", +] + [[package]] name = "unicase" version = "2.7.0" @@ -4501,6 +5355,18 @@ dependencies = [ "serde", ] +[[package]] +name = "urlpattern" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70acd30e3aa1450bc2eece896ce2ad0d178e9c079493819301573dae3c37ba6d" +dependencies = [ + "regex", + "serde", + "unic-ucd-ident", + "url", +] + [[package]] name = "utf-8" version = "0.7.6" @@ -4514,26 +5380,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "81dfa00651efa65069b0b6b651f4aaa31ba9e3c3ce0137aaad053604ee7e0314" dependencies = [ "getrandom 0.2.15", + "serde", ] -[[package]] -name = "valuable" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" - [[package]] name = "vcpkg" version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" -[[package]] -name = "version-compare" -version = "0.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c18c859eead79d8b95d09e4678566e8d70105c4e7b251f707a03df32442661b" - [[package]] name = "version-compare" version = "0.2.0" @@ -4619,7 +5474,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.91", "wasm-bindgen-shared", ] @@ -4653,7 +5508,7 @@ checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.91", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -4664,6 +5519,79 @@ version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" +[[package]] +name = "wasm-streams" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e072d4e72f700fb3443d8fe94a39315df013eef1104903cdb0a2abd322bbecd" +dependencies = [ + "futures-util", + "js-sys", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "wayland-backend" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "056535ced7a150d45159d3a8dc30f91a2e2d588ca0b23f70e56033622b8016f6" +dependencies = [ + "cc", + "downcast-rs", + "rustix", + "scoped-tls", + "smallvec", + "wayland-sys", +] + +[[package]] +name = "wayland-client" +version = "0.31.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b66249d3fc69f76fd74c82cc319300faa554e9d865dab1f7cd66cc20db10b280" +dependencies = [ + "bitflags 2.6.0", + "rustix", + "wayland-backend", + "wayland-scanner", +] + +[[package]] +name = "wayland-protocols" +version = "0.32.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cd0ade57c4e6e9a8952741325c30bf82f4246885dca8bf561898b86d0c1f58e" +dependencies = [ + "bitflags 2.6.0", + "wayland-backend", + "wayland-client", + "wayland-scanner", +] + +[[package]] +name = "wayland-scanner" +version = "0.31.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597f2001b2e5fc1121e3d5b9791d3e78f05ba6bfa4641053846248e3a13661c3" +dependencies = [ + "proc-macro2", + "quick-xml 0.36.2", + "quote", +] + +[[package]] +name = "wayland-sys" +version = "0.31.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "efa8ac0d8e8ed3e3b5c9fc92c7881406a268e11555abe36493efabe649a29e09" +dependencies = [ + "dlib", + "log", + "pkg-config", +] + [[package]] name = "web-sys" version = "0.3.70" @@ -4676,9 +5604,9 @@ dependencies = [ [[package]] name = "webkit2gtk" -version = "0.18.2" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8f859735e4a452aeb28c6c56a852967a8a76c8eb1cc32dbf931ad28a13d6370" +checksum = "76b1bc1e54c581da1e9f179d0b38512ba358fb1af2d634a1affe42e37172361a" dependencies = [ "bitflags 1.3.2", "cairo-rs", @@ -4694,20 +5622,18 @@ dependencies = [ "javascriptcore-rs", "libc", "once_cell", - "soup2", + "soup3", "webkit2gtk-sys", ] [[package]] name = "webkit2gtk-sys" -version = "0.18.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d76ca6ecc47aeba01ec61e480139dda143796abcae6f83bcddf50d6b5b1dcf3" +checksum = "62daa38afc514d1f8f12b8693d30d5993ff77ced33ce30cd04deebc267a6d57c" dependencies = [ - "atk-sys", "bitflags 1.3.2", "cairo-sys-rs", - "gdk-pixbuf-sys", "gdk-sys", "gio-sys", "glib-sys", @@ -4715,48 +5641,45 @@ dependencies = [ "gtk-sys", "javascriptcore-rs-sys", "libc", - "pango-sys", "pkg-config", - "soup2-sys", - "system-deps 6.2.2", + "soup3-sys", + "system-deps", ] [[package]] name = "webview2-com" -version = "0.19.1" +version = "0.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4a769c9f1a64a8734bde70caafac2b96cada12cd4aefa49196b3a386b8b4178" +checksum = "6f61ff3d9d0ee4efcb461b14eb3acfda2702d10dc329f339303fc3e57215ae2c" dependencies = [ "webview2-com-macros", "webview2-com-sys", - "windows 0.39.0", + "windows 0.58.0", + "windows-core 0.58.0", "windows-implement", + "windows-interface", ] [[package]] name = "webview2-com-macros" -version = "0.6.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eaebe196c01691db62e9e4ca52c5ef1e4fd837dcae27dae3ada599b5a8fd05ac" +checksum = "1d228f15bba3b9d56dde8bddbee66fa24545bd17b48d5128ccf4a8742b18e431" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.91", ] [[package]] name = "webview2-com-sys" -version = "0.19.0" +version = "0.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aac48ef20ddf657755fdcda8dfed2a7b4fc7e4581acce6fe9b88c3d64f29dee7" +checksum = "a3a3e2eeb58f82361c93f9777014668eb3d07e7d174ee4c819575a9208011886" dependencies = [ - "regex", - "serde", - "serde_json", - "thiserror", - "windows 0.39.0", - "windows-bindgen", - "windows-metadata", + "thiserror 1.0.63", + "windows 0.58.0", + "windows-core 0.58.0", ] [[package]] @@ -4791,39 +5714,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] -name = "windows" -version = "0.37.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57b543186b344cc61c85b5aab0d2e3adf4e0f99bc076eff9aa5927bcc0b8a647" -dependencies = [ - "windows_aarch64_msvc 0.37.0", - "windows_i686_gnu 0.37.0", - "windows_i686_msvc 0.37.0", - "windows_x86_64_gnu 0.37.0", - "windows_x86_64_msvc 0.37.0", -] - -[[package]] -name = "windows" -version = "0.39.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1c4bd0a50ac6020f65184721f758dba47bb9fbc2133df715ec74a237b26794a" -dependencies = [ - "windows-implement", - "windows_aarch64_msvc 0.39.0", - "windows_i686_gnu 0.39.0", - "windows_i686_msvc 0.39.0", - "windows_x86_64_gnu 0.39.0", - "windows_x86_64_msvc 0.39.0", -] - -[[package]] -name = "windows" -version = "0.48.0" +name = "window-vibrancy" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" +checksum = "3ea403deff7b51fff19e261330f71608ff2cdef5721d72b64180bb95be7c4150" dependencies = [ - "windows-targets 0.48.5", + "objc2", + "objc2-app-kit", + "objc2-foundation", + "raw-window-handle", + "windows-sys 0.59.0", + "windows-version", ] [[package]] @@ -4837,13 +5738,13 @@ dependencies = [ ] [[package]] -name = "windows-bindgen" -version = "0.39.0" +name = "windows" +version = "0.58.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68003dbd0e38abc0fb85b939240f4bce37c43a5981d3df37ccbaaa981b47cb41" +checksum = "dd04d41d93c4992d421894c18c8b43496aa748dd4c081bac0dc93eb0489272b6" dependencies = [ - "windows-metadata", - "windows-tokens", + "windows-core 0.58.0", + "windows-targets 0.52.6", ] [[package]] @@ -4865,21 +5766,40 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-core" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-result 0.2.0", + "windows-strings", + "windows-targets 0.52.6", +] + [[package]] name = "windows-implement" -version = "0.39.0" +version = "0.58.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba01f98f509cb5dc05f4e5fc95e535f78260f15fea8fe1a8abdd08f774f1cee7" +checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b" dependencies = [ - "syn 1.0.109", - "windows-tokens", + "proc-macro2", + "quote", + "syn 2.0.91", ] [[package]] -name = "windows-metadata" -version = "0.39.0" +name = "windows-interface" +version = "0.58.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ee5e275231f07c6e240d14f34e1b635bf1faa1c76c57cfd59a5cdb9848e4278" +checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.91", +] [[package]] name = "windows-registry" @@ -4920,21 +5840,6 @@ dependencies = [ "windows-targets 0.52.6", ] -[[package]] -name = "windows-sys" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" -dependencies = [ - "windows_aarch64_gnullvm 0.42.2", - "windows_aarch64_msvc 0.42.2", - "windows_i686_gnu 0.42.2", - "windows_i686_msvc 0.42.2", - "windows_x86_64_gnu 0.42.2", - "windows_x86_64_gnullvm 0.42.2", - "windows_x86_64_msvc 0.42.2", -] - [[package]] name = "windows-sys" version = "0.45.0" @@ -5017,12 +5922,6 @@ dependencies = [ "windows_x86_64_msvc 0.52.6", ] -[[package]] -name = "windows-tokens" -version = "0.39.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f838de2fe15fe6bac988e74b798f26499a8b21a9d97edec321e79b28d1d7f597" - [[package]] name = "windows-version" version = "0.1.1" @@ -5050,18 +5949,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" -[[package]] -name = "windows_aarch64_msvc" -version = "0.37.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2623277cb2d1c216ba3b578c0f3cf9cdebeddb6e66b1b218bb33596ea7769c3a" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.39.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec7711666096bd4096ffa835238905bb33fb87267910e154b18b44eaabb340f2" - [[package]] name = "windows_aarch64_msvc" version = "0.42.2" @@ -5080,18 +5967,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" -[[package]] -name = "windows_i686_gnu" -version = "0.37.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3925fd0b0b804730d44d4b6278c50f9699703ec49bcd628020f46f4ba07d9e1" - -[[package]] -name = "windows_i686_gnu" -version = "0.39.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "763fc57100a5f7042e3057e7e8d9bdd7860d330070251a73d003563a3bb49e1b" - [[package]] name = "windows_i686_gnu" version = "0.42.2" @@ -5116,18 +5991,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" -[[package]] -name = "windows_i686_msvc" -version = "0.37.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce907ac74fe331b524c1298683efbf598bb031bc84d5e274db2083696d07c57c" - -[[package]] -name = "windows_i686_msvc" -version = "0.39.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bc7cbfe58828921e10a9f446fcaaf649204dcfe6c1ddd712c5eebae6bda1106" - [[package]] name = "windows_i686_msvc" version = "0.42.2" @@ -5146,18 +6009,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" -[[package]] -name = "windows_x86_64_gnu" -version = "0.37.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2babfba0828f2e6b32457d5341427dcbb577ceef556273229959ac23a10af33d" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.39.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6868c165637d653ae1e8dc4d82c25d4f97dd6605eaa8d784b5c6e0ab2a252b65" - [[package]] name = "windows_x86_64_gnu" version = "0.42.2" @@ -5194,18 +6045,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" -[[package]] -name = "windows_x86_64_msvc" -version = "0.37.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4dd6dc7df2d84cf7b33822ed5b86318fb1781948e9663bacd047fc9dd52259d" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.39.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e4d40883ae9cae962787ca76ba76390ffa29214667a111db9e0a1ad8377e809" - [[package]] name = "windows_x86_64_msvc" version = "0.42.2" @@ -5233,15 +6072,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "winnow" -version = "0.6.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68a9bda4691f099d435ad181000724da8e5899daa10713c2d432552b9ccd3a6f" -dependencies = [ - "memchr", -] - [[package]] name = "winreg" version = "0.52.0" @@ -5254,40 +6084,45 @@ dependencies = [ [[package]] name = "wry" -version = "0.24.11" +version = "0.47.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c55c80b12287eb1ff7c365fc2f7a5037cb6181bd44c9fce81c8d1cf7605ffad6" +checksum = "61ce51277d65170f6379d8cda935c80e3c2d1f0ff712a123c8bddb11b31a4b73" dependencies = [ - "base64 0.13.1", - "block", - "cocoa", - "core-graphics", + "base64 0.22.1", + "block2", + "cookie", "crossbeam-channel", + "dpi", "dunce", - "gdk", - "gio", - "glib", + "gdkx11", "gtk", "html5ever", - "http 0.2.12", + "http", + "javascriptcore-rs", + "jni", "kuchikiki", "libc", - "log", - "objc", - "objc_id", + "ndk 0.9.0", + "objc2", + "objc2-app-kit", + "objc2-foundation", + "objc2-ui-kit", + "objc2-web-kit", "once_cell", - "serde", - "serde_json", + "percent-encoding", + "raw-window-handle", "sha2", - "soup2", - "tao", - "thiserror", + "soup3", + "tao-macros", + "thiserror 1.0.63", "url", "webkit2gtk", "webkit2gtk-sys", "webview2-com", - "windows 0.39.0", - "windows-implement", + "windows 0.58.0", + "windows-core 0.58.0", + "windows-version", + "x11-dl", ] [[package]] @@ -5312,14 +6147,72 @@ dependencies = [ ] [[package]] -name = "xattr" -version = "1.3.1" +name = "xdg-home" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8da84f1a25939b27f6820d92aed108f83ff920fdf11a7b19366c27c4cda81d4f" +checksum = "ec1cdab258fb55c0da61328dc52c8764709b249011b2cad0454c72f0bf10a1f6" dependencies = [ "libc", - "linux-raw-sys", - "rustix", + "windows-sys 0.59.0", +] + +[[package]] +name = "zbus" +version = "4.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b8e3d6ae3342792a6cc2340e4394334c7402f3d793b390d2c5494a4032b3030" +dependencies = [ + "async-broadcast", + "async-process", + "async-recursion", + "async-trait", + "derivative", + "enumflags2", + "event-listener", + "futures-core", + "futures-sink", + "futures-util", + "hex", + "nix", + "ordered-stream", + "rand 0.8.5", + "serde", + "serde_repr", + "sha1", + "static_assertions", + "tokio", + "tracing", + "uds_windows", + "windows-sys 0.52.0", + "xdg-home", + "zbus_macros", + "zbus_names", + "zvariant", +] + +[[package]] +name = "zbus_macros" +version = "4.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7a3e850ff1e7217a3b7a07eba90d37fe9bb9e89a310f718afcde5885ca9b6d7" +dependencies = [ + "proc-macro-crate 1.3.1", + "proc-macro2", + "quote", + "regex", + "syn 1.0.109", + "zvariant_utils", +] + +[[package]] +name = "zbus_names" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b9b1fef7d021261cc16cba64c351d291b715febe0fa10dc3a443ac5a5022e6c" +dependencies = [ + "serde", + "static_assertions", + "zvariant", ] [[package]] @@ -5340,7 +6233,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.91", ] [[package]] @@ -5348,3 +6241,41 @@ name = "zeroize" version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" + +[[package]] +name = "zvariant" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e09e8be97d44eeab994d752f341e67b3b0d80512a8b315a0671d47232ef1b65" +dependencies = [ + "endi", + "enumflags2", + "serde", + "static_assertions", + "url", + "zvariant_derive", +] + +[[package]] +name = "zvariant_derive" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72a5857e2856435331636a9fbb415b09243df4521a267c5bedcd5289b4d5799e" +dependencies = [ + "proc-macro-crate 1.3.1", + "proc-macro2", + "quote", + "syn 1.0.109", + "zvariant_utils", +] + +[[package]] +name = "zvariant_utils" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00bedb16a193cc12451873fee2a1bc6550225acece0e36f333e68326c73c8172" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 5f2c2cc..cdac8f5 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -11,12 +11,12 @@ rust-version = "1.81" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [build-dependencies] -tauri-build = { version = "1.5.5", features = [] } +tauri-build = { version = "2", features = [] } [dependencies] serde_json = "1.0" serde = { version = "1.0", features = ["derive"] } -tauri = { version = "1.8.0", features = [ "shell-open", "devtools", "dialog-all", "global-shortcut-all", "os-all", "path-all", "protocol-all", "window-all"] } +tauri = { version = "2", features = [ "protocol-asset", "devtools"] } globwalk = "0.9.1" reqwest = { version = "0.12.7", features = ["json"] } lofty = "0.21.1" @@ -34,6 +34,9 @@ kira = "0.9.5" symphonia = { version = "0.5.4", features = ["all"] } regex = "1.10.4" lrc = "0.1.8" +tauri-plugin-os = "2" +tauri-plugin-shell = "2" +tauri-plugin-dialog = "2" [features] # by default Tauri runs in production mode @@ -66,3 +69,6 @@ opt-level = 3 [profile.dev.package.symphonia-codec-pcm] opt-level = 3 + +[target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dependencies] +tauri-plugin-global-shortcut = "2" diff --git a/src-tauri/build.rs b/src-tauri/build.rs index 795b9b7..d860e1e 100644 --- a/src-tauri/build.rs +++ b/src-tauri/build.rs @@ -1,3 +1,3 @@ fn main() { - tauri_build::build() + tauri_build::build() } diff --git a/src-tauri/capabilities/desktop.json b/src-tauri/capabilities/desktop.json new file mode 100644 index 0000000..cc0fa58 --- /dev/null +++ b/src-tauri/capabilities/desktop.json @@ -0,0 +1,16 @@ +{ + "identifier": "desktop-capability", + "platforms": [ + "macOS", + "windows", + "linux" + ], + "windows": [ + "main" + ], + "permissions": [ + "global-shortcut:default", + "shell:default", + "dialog:default" + ] +} \ No newline at end of file diff --git a/src-tauri/capabilities/migrated.json b/src-tauri/capabilities/migrated.json new file mode 100644 index 0000000..2b07528 --- /dev/null +++ b/src-tauri/capabilities/migrated.json @@ -0,0 +1,64 @@ +{ + "identifier": "migrated", + "description": "permissions that were migrated from v1", + "local": true, + "windows": [ + "main" + ], + "permissions": [ + "core:default", + "core:window:allow-create", + "core:window:allow-center", + "core:window:allow-request-user-attention", + "core:window:allow-set-resizable", + "core:window:allow-set-maximizable", + "core:window:allow-set-minimizable", + "core:window:allow-set-closable", + "core:window:allow-set-title", + "core:window:allow-maximize", + "core:window:allow-unmaximize", + "core:window:allow-minimize", + "core:window:allow-unminimize", + "core:window:allow-show", + "core:window:allow-hide", + "core:window:allow-close", + "core:window:allow-set-decorations", + "core:window:allow-set-always-on-top", + "core:window:allow-set-content-protected", + "core:window:allow-set-size", + "core:window:allow-set-min-size", + "core:window:allow-set-max-size", + "core:window:allow-set-position", + "core:window:allow-set-fullscreen", + "core:window:allow-set-focus", + "core:window:allow-set-icon", + "core:window:allow-set-skip-taskbar", + "core:window:allow-set-cursor-grab", + "core:window:allow-set-cursor-visible", + "core:window:allow-set-cursor-icon", + "core:window:allow-set-cursor-position", + "core:window:allow-set-ignore-cursor-events", + "core:window:allow-start-dragging", + "core:webview:allow-print", + "shell:allow-open", + "dialog:allow-open", + "dialog:allow-save", + "dialog:allow-message", + "dialog:allow-ask", + "dialog:allow-confirm", + "global-shortcut:allow-is-registered", + "global-shortcut:allow-register", + "global-shortcut:allow-register-all", + "global-shortcut:allow-unregister", + "global-shortcut:allow-unregister-all", + "os:allow-platform", + "os:allow-version", + "os:allow-os-type", + "os:allow-family", + "os:allow-arch", + "os:allow-exe-extension", + "os:allow-locale", + "os:allow-hostname", + "os:default" + ] +} \ No newline at end of file diff --git a/src-tauri/gen/schemas/acl-manifests.json b/src-tauri/gen/schemas/acl-manifests.json new file mode 100644 index 0000000..e76b3d2 --- /dev/null +++ b/src-tauri/gen/schemas/acl-manifests.json @@ -0,0 +1 @@ +{"core":{"default_permission":{"identifier":"default","description":"Default core plugins set which includes:\n- 'core:path:default'\n- 'core:event:default'\n- 'core:window:default'\n- 'core:webview:default'\n- 'core:app:default'\n- 'core:image:default'\n- 'core:resources:default'\n- 'core:menu:default'\n- 'core:tray:default'\n","permissions":["core:path:default","core:event:default","core:window:default","core:webview:default","core:app:default","core:image:default","core:resources:default","core:menu:default","core:tray:default"]},"permissions":{},"permission_sets":{},"global_scope_schema":null},"core:app":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin.","permissions":["allow-version","allow-name","allow-tauri-version"]},"permissions":{"allow-app-hide":{"identifier":"allow-app-hide","description":"Enables the app_hide command without any pre-configured scope.","commands":{"allow":["app_hide"],"deny":[]}},"allow-app-show":{"identifier":"allow-app-show","description":"Enables the app_show command without any pre-configured scope.","commands":{"allow":["app_show"],"deny":[]}},"allow-default-window-icon":{"identifier":"allow-default-window-icon","description":"Enables the default_window_icon command without any pre-configured scope.","commands":{"allow":["default_window_icon"],"deny":[]}},"allow-name":{"identifier":"allow-name","description":"Enables the name command without any pre-configured scope.","commands":{"allow":["name"],"deny":[]}},"allow-set-app-theme":{"identifier":"allow-set-app-theme","description":"Enables the set_app_theme command without any pre-configured scope.","commands":{"allow":["set_app_theme"],"deny":[]}},"allow-tauri-version":{"identifier":"allow-tauri-version","description":"Enables the tauri_version command without any pre-configured scope.","commands":{"allow":["tauri_version"],"deny":[]}},"allow-version":{"identifier":"allow-version","description":"Enables the version command without any pre-configured scope.","commands":{"allow":["version"],"deny":[]}},"deny-app-hide":{"identifier":"deny-app-hide","description":"Denies the app_hide command without any pre-configured scope.","commands":{"allow":[],"deny":["app_hide"]}},"deny-app-show":{"identifier":"deny-app-show","description":"Denies the app_show command without any pre-configured scope.","commands":{"allow":[],"deny":["app_show"]}},"deny-default-window-icon":{"identifier":"deny-default-window-icon","description":"Denies the default_window_icon command without any pre-configured scope.","commands":{"allow":[],"deny":["default_window_icon"]}},"deny-name":{"identifier":"deny-name","description":"Denies the name command without any pre-configured scope.","commands":{"allow":[],"deny":["name"]}},"deny-set-app-theme":{"identifier":"deny-set-app-theme","description":"Denies the set_app_theme command without any pre-configured scope.","commands":{"allow":[],"deny":["set_app_theme"]}},"deny-tauri-version":{"identifier":"deny-tauri-version","description":"Denies the tauri_version command without any pre-configured scope.","commands":{"allow":[],"deny":["tauri_version"]}},"deny-version":{"identifier":"deny-version","description":"Denies the version command without any pre-configured scope.","commands":{"allow":[],"deny":["version"]}}},"permission_sets":{},"global_scope_schema":null},"core:event":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin.","permissions":["allow-listen","allow-unlisten","allow-emit","allow-emit-to"]},"permissions":{"allow-emit":{"identifier":"allow-emit","description":"Enables the emit command without any pre-configured scope.","commands":{"allow":["emit"],"deny":[]}},"allow-emit-to":{"identifier":"allow-emit-to","description":"Enables the emit_to command without any pre-configured scope.","commands":{"allow":["emit_to"],"deny":[]}},"allow-listen":{"identifier":"allow-listen","description":"Enables the listen command without any pre-configured scope.","commands":{"allow":["listen"],"deny":[]}},"allow-unlisten":{"identifier":"allow-unlisten","description":"Enables the unlisten command without any pre-configured scope.","commands":{"allow":["unlisten"],"deny":[]}},"deny-emit":{"identifier":"deny-emit","description":"Denies the emit command without any pre-configured scope.","commands":{"allow":[],"deny":["emit"]}},"deny-emit-to":{"identifier":"deny-emit-to","description":"Denies the emit_to command without any pre-configured scope.","commands":{"allow":[],"deny":["emit_to"]}},"deny-listen":{"identifier":"deny-listen","description":"Denies the listen command without any pre-configured scope.","commands":{"allow":[],"deny":["listen"]}},"deny-unlisten":{"identifier":"deny-unlisten","description":"Denies the unlisten command without any pre-configured scope.","commands":{"allow":[],"deny":["unlisten"]}}},"permission_sets":{},"global_scope_schema":null},"core:image":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin.","permissions":["allow-new","allow-from-bytes","allow-from-path","allow-rgba","allow-size"]},"permissions":{"allow-from-bytes":{"identifier":"allow-from-bytes","description":"Enables the from_bytes command without any pre-configured scope.","commands":{"allow":["from_bytes"],"deny":[]}},"allow-from-path":{"identifier":"allow-from-path","description":"Enables the from_path command without any pre-configured scope.","commands":{"allow":["from_path"],"deny":[]}},"allow-new":{"identifier":"allow-new","description":"Enables the new command without any pre-configured scope.","commands":{"allow":["new"],"deny":[]}},"allow-rgba":{"identifier":"allow-rgba","description":"Enables the rgba command without any pre-configured scope.","commands":{"allow":["rgba"],"deny":[]}},"allow-size":{"identifier":"allow-size","description":"Enables the size command without any pre-configured scope.","commands":{"allow":["size"],"deny":[]}},"deny-from-bytes":{"identifier":"deny-from-bytes","description":"Denies the from_bytes command without any pre-configured scope.","commands":{"allow":[],"deny":["from_bytes"]}},"deny-from-path":{"identifier":"deny-from-path","description":"Denies the from_path command without any pre-configured scope.","commands":{"allow":[],"deny":["from_path"]}},"deny-new":{"identifier":"deny-new","description":"Denies the new command without any pre-configured scope.","commands":{"allow":[],"deny":["new"]}},"deny-rgba":{"identifier":"deny-rgba","description":"Denies the rgba command without any pre-configured scope.","commands":{"allow":[],"deny":["rgba"]}},"deny-size":{"identifier":"deny-size","description":"Denies the size command without any pre-configured scope.","commands":{"allow":[],"deny":["size"]}}},"permission_sets":{},"global_scope_schema":null},"core:menu":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin.","permissions":["allow-new","allow-append","allow-prepend","allow-insert","allow-remove","allow-remove-at","allow-items","allow-get","allow-popup","allow-create-default","allow-set-as-app-menu","allow-set-as-window-menu","allow-text","allow-set-text","allow-is-enabled","allow-set-enabled","allow-set-accelerator","allow-set-as-windows-menu-for-nsapp","allow-set-as-help-menu-for-nsapp","allow-is-checked","allow-set-checked","allow-set-icon"]},"permissions":{"allow-append":{"identifier":"allow-append","description":"Enables the append command without any pre-configured scope.","commands":{"allow":["append"],"deny":[]}},"allow-create-default":{"identifier":"allow-create-default","description":"Enables the create_default command without any pre-configured scope.","commands":{"allow":["create_default"],"deny":[]}},"allow-get":{"identifier":"allow-get","description":"Enables the get command without any pre-configured scope.","commands":{"allow":["get"],"deny":[]}},"allow-insert":{"identifier":"allow-insert","description":"Enables the insert command without any pre-configured scope.","commands":{"allow":["insert"],"deny":[]}},"allow-is-checked":{"identifier":"allow-is-checked","description":"Enables the is_checked command without any pre-configured scope.","commands":{"allow":["is_checked"],"deny":[]}},"allow-is-enabled":{"identifier":"allow-is-enabled","description":"Enables the is_enabled command without any pre-configured scope.","commands":{"allow":["is_enabled"],"deny":[]}},"allow-items":{"identifier":"allow-items","description":"Enables the items command without any pre-configured scope.","commands":{"allow":["items"],"deny":[]}},"allow-new":{"identifier":"allow-new","description":"Enables the new command without any pre-configured scope.","commands":{"allow":["new"],"deny":[]}},"allow-popup":{"identifier":"allow-popup","description":"Enables the popup command without any pre-configured scope.","commands":{"allow":["popup"],"deny":[]}},"allow-prepend":{"identifier":"allow-prepend","description":"Enables the prepend command without any pre-configured scope.","commands":{"allow":["prepend"],"deny":[]}},"allow-remove":{"identifier":"allow-remove","description":"Enables the remove command without any pre-configured scope.","commands":{"allow":["remove"],"deny":[]}},"allow-remove-at":{"identifier":"allow-remove-at","description":"Enables the remove_at command without any pre-configured scope.","commands":{"allow":["remove_at"],"deny":[]}},"allow-set-accelerator":{"identifier":"allow-set-accelerator","description":"Enables the set_accelerator command without any pre-configured scope.","commands":{"allow":["set_accelerator"],"deny":[]}},"allow-set-as-app-menu":{"identifier":"allow-set-as-app-menu","description":"Enables the set_as_app_menu command without any pre-configured scope.","commands":{"allow":["set_as_app_menu"],"deny":[]}},"allow-set-as-help-menu-for-nsapp":{"identifier":"allow-set-as-help-menu-for-nsapp","description":"Enables the set_as_help_menu_for_nsapp command without any pre-configured scope.","commands":{"allow":["set_as_help_menu_for_nsapp"],"deny":[]}},"allow-set-as-window-menu":{"identifier":"allow-set-as-window-menu","description":"Enables the set_as_window_menu command without any pre-configured scope.","commands":{"allow":["set_as_window_menu"],"deny":[]}},"allow-set-as-windows-menu-for-nsapp":{"identifier":"allow-set-as-windows-menu-for-nsapp","description":"Enables the set_as_windows_menu_for_nsapp command without any pre-configured scope.","commands":{"allow":["set_as_windows_menu_for_nsapp"],"deny":[]}},"allow-set-checked":{"identifier":"allow-set-checked","description":"Enables the set_checked command without any pre-configured scope.","commands":{"allow":["set_checked"],"deny":[]}},"allow-set-enabled":{"identifier":"allow-set-enabled","description":"Enables the set_enabled command without any pre-configured scope.","commands":{"allow":["set_enabled"],"deny":[]}},"allow-set-icon":{"identifier":"allow-set-icon","description":"Enables the set_icon command without any pre-configured scope.","commands":{"allow":["set_icon"],"deny":[]}},"allow-set-text":{"identifier":"allow-set-text","description":"Enables the set_text command without any pre-configured scope.","commands":{"allow":["set_text"],"deny":[]}},"allow-text":{"identifier":"allow-text","description":"Enables the text command without any pre-configured scope.","commands":{"allow":["text"],"deny":[]}},"deny-append":{"identifier":"deny-append","description":"Denies the append command without any pre-configured scope.","commands":{"allow":[],"deny":["append"]}},"deny-create-default":{"identifier":"deny-create-default","description":"Denies the create_default command without any pre-configured scope.","commands":{"allow":[],"deny":["create_default"]}},"deny-get":{"identifier":"deny-get","description":"Denies the get command without any pre-configured scope.","commands":{"allow":[],"deny":["get"]}},"deny-insert":{"identifier":"deny-insert","description":"Denies the insert command without any pre-configured scope.","commands":{"allow":[],"deny":["insert"]}},"deny-is-checked":{"identifier":"deny-is-checked","description":"Denies the is_checked command without any pre-configured scope.","commands":{"allow":[],"deny":["is_checked"]}},"deny-is-enabled":{"identifier":"deny-is-enabled","description":"Denies the is_enabled command without any pre-configured scope.","commands":{"allow":[],"deny":["is_enabled"]}},"deny-items":{"identifier":"deny-items","description":"Denies the items command without any pre-configured scope.","commands":{"allow":[],"deny":["items"]}},"deny-new":{"identifier":"deny-new","description":"Denies the new command without any pre-configured scope.","commands":{"allow":[],"deny":["new"]}},"deny-popup":{"identifier":"deny-popup","description":"Denies the popup command without any pre-configured scope.","commands":{"allow":[],"deny":["popup"]}},"deny-prepend":{"identifier":"deny-prepend","description":"Denies the prepend command without any pre-configured scope.","commands":{"allow":[],"deny":["prepend"]}},"deny-remove":{"identifier":"deny-remove","description":"Denies the remove command without any pre-configured scope.","commands":{"allow":[],"deny":["remove"]}},"deny-remove-at":{"identifier":"deny-remove-at","description":"Denies the remove_at command without any pre-configured scope.","commands":{"allow":[],"deny":["remove_at"]}},"deny-set-accelerator":{"identifier":"deny-set-accelerator","description":"Denies the set_accelerator command without any pre-configured scope.","commands":{"allow":[],"deny":["set_accelerator"]}},"deny-set-as-app-menu":{"identifier":"deny-set-as-app-menu","description":"Denies the set_as_app_menu command without any pre-configured scope.","commands":{"allow":[],"deny":["set_as_app_menu"]}},"deny-set-as-help-menu-for-nsapp":{"identifier":"deny-set-as-help-menu-for-nsapp","description":"Denies the set_as_help_menu_for_nsapp command without any pre-configured scope.","commands":{"allow":[],"deny":["set_as_help_menu_for_nsapp"]}},"deny-set-as-window-menu":{"identifier":"deny-set-as-window-menu","description":"Denies the set_as_window_menu command without any pre-configured scope.","commands":{"allow":[],"deny":["set_as_window_menu"]}},"deny-set-as-windows-menu-for-nsapp":{"identifier":"deny-set-as-windows-menu-for-nsapp","description":"Denies the set_as_windows_menu_for_nsapp command without any pre-configured scope.","commands":{"allow":[],"deny":["set_as_windows_menu_for_nsapp"]}},"deny-set-checked":{"identifier":"deny-set-checked","description":"Denies the set_checked command without any pre-configured scope.","commands":{"allow":[],"deny":["set_checked"]}},"deny-set-enabled":{"identifier":"deny-set-enabled","description":"Denies the set_enabled command without any pre-configured scope.","commands":{"allow":[],"deny":["set_enabled"]}},"deny-set-icon":{"identifier":"deny-set-icon","description":"Denies the set_icon command without any pre-configured scope.","commands":{"allow":[],"deny":["set_icon"]}},"deny-set-text":{"identifier":"deny-set-text","description":"Denies the set_text command without any pre-configured scope.","commands":{"allow":[],"deny":["set_text"]}},"deny-text":{"identifier":"deny-text","description":"Denies the text command without any pre-configured scope.","commands":{"allow":[],"deny":["text"]}}},"permission_sets":{},"global_scope_schema":null},"core:path":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin.","permissions":["allow-resolve-directory","allow-resolve","allow-normalize","allow-join","allow-dirname","allow-extname","allow-basename","allow-is-absolute"]},"permissions":{"allow-basename":{"identifier":"allow-basename","description":"Enables the basename command without any pre-configured scope.","commands":{"allow":["basename"],"deny":[]}},"allow-dirname":{"identifier":"allow-dirname","description":"Enables the dirname command without any pre-configured scope.","commands":{"allow":["dirname"],"deny":[]}},"allow-extname":{"identifier":"allow-extname","description":"Enables the extname command without any pre-configured scope.","commands":{"allow":["extname"],"deny":[]}},"allow-is-absolute":{"identifier":"allow-is-absolute","description":"Enables the is_absolute command without any pre-configured scope.","commands":{"allow":["is_absolute"],"deny":[]}},"allow-join":{"identifier":"allow-join","description":"Enables the join command without any pre-configured scope.","commands":{"allow":["join"],"deny":[]}},"allow-normalize":{"identifier":"allow-normalize","description":"Enables the normalize command without any pre-configured scope.","commands":{"allow":["normalize"],"deny":[]}},"allow-resolve":{"identifier":"allow-resolve","description":"Enables the resolve command without any pre-configured scope.","commands":{"allow":["resolve"],"deny":[]}},"allow-resolve-directory":{"identifier":"allow-resolve-directory","description":"Enables the resolve_directory command without any pre-configured scope.","commands":{"allow":["resolve_directory"],"deny":[]}},"deny-basename":{"identifier":"deny-basename","description":"Denies the basename command without any pre-configured scope.","commands":{"allow":[],"deny":["basename"]}},"deny-dirname":{"identifier":"deny-dirname","description":"Denies the dirname command without any pre-configured scope.","commands":{"allow":[],"deny":["dirname"]}},"deny-extname":{"identifier":"deny-extname","description":"Denies the extname command without any pre-configured scope.","commands":{"allow":[],"deny":["extname"]}},"deny-is-absolute":{"identifier":"deny-is-absolute","description":"Denies the is_absolute command without any pre-configured scope.","commands":{"allow":[],"deny":["is_absolute"]}},"deny-join":{"identifier":"deny-join","description":"Denies the join command without any pre-configured scope.","commands":{"allow":[],"deny":["join"]}},"deny-normalize":{"identifier":"deny-normalize","description":"Denies the normalize command without any pre-configured scope.","commands":{"allow":[],"deny":["normalize"]}},"deny-resolve":{"identifier":"deny-resolve","description":"Denies the resolve command without any pre-configured scope.","commands":{"allow":[],"deny":["resolve"]}},"deny-resolve-directory":{"identifier":"deny-resolve-directory","description":"Denies the resolve_directory command without any pre-configured scope.","commands":{"allow":[],"deny":["resolve_directory"]}}},"permission_sets":{},"global_scope_schema":null},"core:resources":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin.","permissions":["allow-close"]},"permissions":{"allow-close":{"identifier":"allow-close","description":"Enables the close command without any pre-configured scope.","commands":{"allow":["close"],"deny":[]}},"deny-close":{"identifier":"deny-close","description":"Denies the close command without any pre-configured scope.","commands":{"allow":[],"deny":["close"]}}},"permission_sets":{},"global_scope_schema":null},"core:tray":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin.","permissions":["allow-new","allow-get-by-id","allow-remove-by-id","allow-set-icon","allow-set-menu","allow-set-tooltip","allow-set-title","allow-set-visible","allow-set-temp-dir-path","allow-set-icon-as-template","allow-set-show-menu-on-left-click"]},"permissions":{"allow-get-by-id":{"identifier":"allow-get-by-id","description":"Enables the get_by_id command without any pre-configured scope.","commands":{"allow":["get_by_id"],"deny":[]}},"allow-new":{"identifier":"allow-new","description":"Enables the new command without any pre-configured scope.","commands":{"allow":["new"],"deny":[]}},"allow-remove-by-id":{"identifier":"allow-remove-by-id","description":"Enables the remove_by_id command without any pre-configured scope.","commands":{"allow":["remove_by_id"],"deny":[]}},"allow-set-icon":{"identifier":"allow-set-icon","description":"Enables the set_icon command without any pre-configured scope.","commands":{"allow":["set_icon"],"deny":[]}},"allow-set-icon-as-template":{"identifier":"allow-set-icon-as-template","description":"Enables the set_icon_as_template command without any pre-configured scope.","commands":{"allow":["set_icon_as_template"],"deny":[]}},"allow-set-menu":{"identifier":"allow-set-menu","description":"Enables the set_menu command without any pre-configured scope.","commands":{"allow":["set_menu"],"deny":[]}},"allow-set-show-menu-on-left-click":{"identifier":"allow-set-show-menu-on-left-click","description":"Enables the set_show_menu_on_left_click command without any pre-configured scope.","commands":{"allow":["set_show_menu_on_left_click"],"deny":[]}},"allow-set-temp-dir-path":{"identifier":"allow-set-temp-dir-path","description":"Enables the set_temp_dir_path command without any pre-configured scope.","commands":{"allow":["set_temp_dir_path"],"deny":[]}},"allow-set-title":{"identifier":"allow-set-title","description":"Enables the set_title command without any pre-configured scope.","commands":{"allow":["set_title"],"deny":[]}},"allow-set-tooltip":{"identifier":"allow-set-tooltip","description":"Enables the set_tooltip command without any pre-configured scope.","commands":{"allow":["set_tooltip"],"deny":[]}},"allow-set-visible":{"identifier":"allow-set-visible","description":"Enables the set_visible command without any pre-configured scope.","commands":{"allow":["set_visible"],"deny":[]}},"deny-get-by-id":{"identifier":"deny-get-by-id","description":"Denies the get_by_id command without any pre-configured scope.","commands":{"allow":[],"deny":["get_by_id"]}},"deny-new":{"identifier":"deny-new","description":"Denies the new command without any pre-configured scope.","commands":{"allow":[],"deny":["new"]}},"deny-remove-by-id":{"identifier":"deny-remove-by-id","description":"Denies the remove_by_id command without any pre-configured scope.","commands":{"allow":[],"deny":["remove_by_id"]}},"deny-set-icon":{"identifier":"deny-set-icon","description":"Denies the set_icon command without any pre-configured scope.","commands":{"allow":[],"deny":["set_icon"]}},"deny-set-icon-as-template":{"identifier":"deny-set-icon-as-template","description":"Denies the set_icon_as_template command without any pre-configured scope.","commands":{"allow":[],"deny":["set_icon_as_template"]}},"deny-set-menu":{"identifier":"deny-set-menu","description":"Denies the set_menu command without any pre-configured scope.","commands":{"allow":[],"deny":["set_menu"]}},"deny-set-show-menu-on-left-click":{"identifier":"deny-set-show-menu-on-left-click","description":"Denies the set_show_menu_on_left_click command without any pre-configured scope.","commands":{"allow":[],"deny":["set_show_menu_on_left_click"]}},"deny-set-temp-dir-path":{"identifier":"deny-set-temp-dir-path","description":"Denies the set_temp_dir_path command without any pre-configured scope.","commands":{"allow":[],"deny":["set_temp_dir_path"]}},"deny-set-title":{"identifier":"deny-set-title","description":"Denies the set_title command without any pre-configured scope.","commands":{"allow":[],"deny":["set_title"]}},"deny-set-tooltip":{"identifier":"deny-set-tooltip","description":"Denies the set_tooltip command without any pre-configured scope.","commands":{"allow":[],"deny":["set_tooltip"]}},"deny-set-visible":{"identifier":"deny-set-visible","description":"Denies the set_visible command without any pre-configured scope.","commands":{"allow":[],"deny":["set_visible"]}}},"permission_sets":{},"global_scope_schema":null},"core:webview":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin.","permissions":["allow-get-all-webviews","allow-webview-position","allow-webview-size","allow-internal-toggle-devtools"]},"permissions":{"allow-clear-all-browsing-data":{"identifier":"allow-clear-all-browsing-data","description":"Enables the clear_all_browsing_data command without any pre-configured scope.","commands":{"allow":["clear_all_browsing_data"],"deny":[]}},"allow-create-webview":{"identifier":"allow-create-webview","description":"Enables the create_webview command without any pre-configured scope.","commands":{"allow":["create_webview"],"deny":[]}},"allow-create-webview-window":{"identifier":"allow-create-webview-window","description":"Enables the create_webview_window command without any pre-configured scope.","commands":{"allow":["create_webview_window"],"deny":[]}},"allow-get-all-webviews":{"identifier":"allow-get-all-webviews","description":"Enables the get_all_webviews command without any pre-configured scope.","commands":{"allow":["get_all_webviews"],"deny":[]}},"allow-internal-toggle-devtools":{"identifier":"allow-internal-toggle-devtools","description":"Enables the internal_toggle_devtools command without any pre-configured scope.","commands":{"allow":["internal_toggle_devtools"],"deny":[]}},"allow-print":{"identifier":"allow-print","description":"Enables the print command without any pre-configured scope.","commands":{"allow":["print"],"deny":[]}},"allow-reparent":{"identifier":"allow-reparent","description":"Enables the reparent command without any pre-configured scope.","commands":{"allow":["reparent"],"deny":[]}},"allow-set-webview-focus":{"identifier":"allow-set-webview-focus","description":"Enables the set_webview_focus command without any pre-configured scope.","commands":{"allow":["set_webview_focus"],"deny":[]}},"allow-set-webview-position":{"identifier":"allow-set-webview-position","description":"Enables the set_webview_position command without any pre-configured scope.","commands":{"allow":["set_webview_position"],"deny":[]}},"allow-set-webview-size":{"identifier":"allow-set-webview-size","description":"Enables the set_webview_size command without any pre-configured scope.","commands":{"allow":["set_webview_size"],"deny":[]}},"allow-set-webview-zoom":{"identifier":"allow-set-webview-zoom","description":"Enables the set_webview_zoom command without any pre-configured scope.","commands":{"allow":["set_webview_zoom"],"deny":[]}},"allow-webview-close":{"identifier":"allow-webview-close","description":"Enables the webview_close command without any pre-configured scope.","commands":{"allow":["webview_close"],"deny":[]}},"allow-webview-hide":{"identifier":"allow-webview-hide","description":"Enables the webview_hide command without any pre-configured scope.","commands":{"allow":["webview_hide"],"deny":[]}},"allow-webview-position":{"identifier":"allow-webview-position","description":"Enables the webview_position command without any pre-configured scope.","commands":{"allow":["webview_position"],"deny":[]}},"allow-webview-show":{"identifier":"allow-webview-show","description":"Enables the webview_show command without any pre-configured scope.","commands":{"allow":["webview_show"],"deny":[]}},"allow-webview-size":{"identifier":"allow-webview-size","description":"Enables the webview_size command without any pre-configured scope.","commands":{"allow":["webview_size"],"deny":[]}},"deny-clear-all-browsing-data":{"identifier":"deny-clear-all-browsing-data","description":"Denies the clear_all_browsing_data command without any pre-configured scope.","commands":{"allow":[],"deny":["clear_all_browsing_data"]}},"deny-create-webview":{"identifier":"deny-create-webview","description":"Denies the create_webview command without any pre-configured scope.","commands":{"allow":[],"deny":["create_webview"]}},"deny-create-webview-window":{"identifier":"deny-create-webview-window","description":"Denies the create_webview_window command without any pre-configured scope.","commands":{"allow":[],"deny":["create_webview_window"]}},"deny-get-all-webviews":{"identifier":"deny-get-all-webviews","description":"Denies the get_all_webviews command without any pre-configured scope.","commands":{"allow":[],"deny":["get_all_webviews"]}},"deny-internal-toggle-devtools":{"identifier":"deny-internal-toggle-devtools","description":"Denies the internal_toggle_devtools command without any pre-configured scope.","commands":{"allow":[],"deny":["internal_toggle_devtools"]}},"deny-print":{"identifier":"deny-print","description":"Denies the print command without any pre-configured scope.","commands":{"allow":[],"deny":["print"]}},"deny-reparent":{"identifier":"deny-reparent","description":"Denies the reparent command without any pre-configured scope.","commands":{"allow":[],"deny":["reparent"]}},"deny-set-webview-focus":{"identifier":"deny-set-webview-focus","description":"Denies the set_webview_focus command without any pre-configured scope.","commands":{"allow":[],"deny":["set_webview_focus"]}},"deny-set-webview-position":{"identifier":"deny-set-webview-position","description":"Denies the set_webview_position command without any pre-configured scope.","commands":{"allow":[],"deny":["set_webview_position"]}},"deny-set-webview-size":{"identifier":"deny-set-webview-size","description":"Denies the set_webview_size command without any pre-configured scope.","commands":{"allow":[],"deny":["set_webview_size"]}},"deny-set-webview-zoom":{"identifier":"deny-set-webview-zoom","description":"Denies the set_webview_zoom command without any pre-configured scope.","commands":{"allow":[],"deny":["set_webview_zoom"]}},"deny-webview-close":{"identifier":"deny-webview-close","description":"Denies the webview_close command without any pre-configured scope.","commands":{"allow":[],"deny":["webview_close"]}},"deny-webview-hide":{"identifier":"deny-webview-hide","description":"Denies the webview_hide command without any pre-configured scope.","commands":{"allow":[],"deny":["webview_hide"]}},"deny-webview-position":{"identifier":"deny-webview-position","description":"Denies the webview_position command without any pre-configured scope.","commands":{"allow":[],"deny":["webview_position"]}},"deny-webview-show":{"identifier":"deny-webview-show","description":"Denies the webview_show command without any pre-configured scope.","commands":{"allow":[],"deny":["webview_show"]}},"deny-webview-size":{"identifier":"deny-webview-size","description":"Denies the webview_size command without any pre-configured scope.","commands":{"allow":[],"deny":["webview_size"]}}},"permission_sets":{},"global_scope_schema":null},"core:window":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin.","permissions":["allow-get-all-windows","allow-scale-factor","allow-inner-position","allow-outer-position","allow-inner-size","allow-outer-size","allow-is-fullscreen","allow-is-minimized","allow-is-maximized","allow-is-focused","allow-is-decorated","allow-is-resizable","allow-is-maximizable","allow-is-minimizable","allow-is-closable","allow-is-visible","allow-is-enabled","allow-title","allow-current-monitor","allow-primary-monitor","allow-monitor-from-point","allow-available-monitors","allow-cursor-position","allow-theme","allow-internal-toggle-maximize"]},"permissions":{"allow-available-monitors":{"identifier":"allow-available-monitors","description":"Enables the available_monitors command without any pre-configured scope.","commands":{"allow":["available_monitors"],"deny":[]}},"allow-center":{"identifier":"allow-center","description":"Enables the center command without any pre-configured scope.","commands":{"allow":["center"],"deny":[]}},"allow-close":{"identifier":"allow-close","description":"Enables the close command without any pre-configured scope.","commands":{"allow":["close"],"deny":[]}},"allow-create":{"identifier":"allow-create","description":"Enables the create command without any pre-configured scope.","commands":{"allow":["create"],"deny":[]}},"allow-current-monitor":{"identifier":"allow-current-monitor","description":"Enables the current_monitor command without any pre-configured scope.","commands":{"allow":["current_monitor"],"deny":[]}},"allow-cursor-position":{"identifier":"allow-cursor-position","description":"Enables the cursor_position command without any pre-configured scope.","commands":{"allow":["cursor_position"],"deny":[]}},"allow-destroy":{"identifier":"allow-destroy","description":"Enables the destroy command without any pre-configured scope.","commands":{"allow":["destroy"],"deny":[]}},"allow-get-all-windows":{"identifier":"allow-get-all-windows","description":"Enables the get_all_windows command without any pre-configured scope.","commands":{"allow":["get_all_windows"],"deny":[]}},"allow-hide":{"identifier":"allow-hide","description":"Enables the hide command without any pre-configured scope.","commands":{"allow":["hide"],"deny":[]}},"allow-inner-position":{"identifier":"allow-inner-position","description":"Enables the inner_position command without any pre-configured scope.","commands":{"allow":["inner_position"],"deny":[]}},"allow-inner-size":{"identifier":"allow-inner-size","description":"Enables the inner_size command without any pre-configured scope.","commands":{"allow":["inner_size"],"deny":[]}},"allow-internal-toggle-maximize":{"identifier":"allow-internal-toggle-maximize","description":"Enables the internal_toggle_maximize command without any pre-configured scope.","commands":{"allow":["internal_toggle_maximize"],"deny":[]}},"allow-is-closable":{"identifier":"allow-is-closable","description":"Enables the is_closable command without any pre-configured scope.","commands":{"allow":["is_closable"],"deny":[]}},"allow-is-decorated":{"identifier":"allow-is-decorated","description":"Enables the is_decorated command without any pre-configured scope.","commands":{"allow":["is_decorated"],"deny":[]}},"allow-is-enabled":{"identifier":"allow-is-enabled","description":"Enables the is_enabled command without any pre-configured scope.","commands":{"allow":["is_enabled"],"deny":[]}},"allow-is-focused":{"identifier":"allow-is-focused","description":"Enables the is_focused command without any pre-configured scope.","commands":{"allow":["is_focused"],"deny":[]}},"allow-is-fullscreen":{"identifier":"allow-is-fullscreen","description":"Enables the is_fullscreen command without any pre-configured scope.","commands":{"allow":["is_fullscreen"],"deny":[]}},"allow-is-maximizable":{"identifier":"allow-is-maximizable","description":"Enables the is_maximizable command without any pre-configured scope.","commands":{"allow":["is_maximizable"],"deny":[]}},"allow-is-maximized":{"identifier":"allow-is-maximized","description":"Enables the is_maximized command without any pre-configured scope.","commands":{"allow":["is_maximized"],"deny":[]}},"allow-is-minimizable":{"identifier":"allow-is-minimizable","description":"Enables the is_minimizable command without any pre-configured scope.","commands":{"allow":["is_minimizable"],"deny":[]}},"allow-is-minimized":{"identifier":"allow-is-minimized","description":"Enables the is_minimized command without any pre-configured scope.","commands":{"allow":["is_minimized"],"deny":[]}},"allow-is-resizable":{"identifier":"allow-is-resizable","description":"Enables the is_resizable command without any pre-configured scope.","commands":{"allow":["is_resizable"],"deny":[]}},"allow-is-visible":{"identifier":"allow-is-visible","description":"Enables the is_visible command without any pre-configured scope.","commands":{"allow":["is_visible"],"deny":[]}},"allow-maximize":{"identifier":"allow-maximize","description":"Enables the maximize command without any pre-configured scope.","commands":{"allow":["maximize"],"deny":[]}},"allow-minimize":{"identifier":"allow-minimize","description":"Enables the minimize command without any pre-configured scope.","commands":{"allow":["minimize"],"deny":[]}},"allow-monitor-from-point":{"identifier":"allow-monitor-from-point","description":"Enables the monitor_from_point command without any pre-configured scope.","commands":{"allow":["monitor_from_point"],"deny":[]}},"allow-outer-position":{"identifier":"allow-outer-position","description":"Enables the outer_position command without any pre-configured scope.","commands":{"allow":["outer_position"],"deny":[]}},"allow-outer-size":{"identifier":"allow-outer-size","description":"Enables the outer_size command without any pre-configured scope.","commands":{"allow":["outer_size"],"deny":[]}},"allow-primary-monitor":{"identifier":"allow-primary-monitor","description":"Enables the primary_monitor command without any pre-configured scope.","commands":{"allow":["primary_monitor"],"deny":[]}},"allow-request-user-attention":{"identifier":"allow-request-user-attention","description":"Enables the request_user_attention command without any pre-configured scope.","commands":{"allow":["request_user_attention"],"deny":[]}},"allow-scale-factor":{"identifier":"allow-scale-factor","description":"Enables the scale_factor command without any pre-configured scope.","commands":{"allow":["scale_factor"],"deny":[]}},"allow-set-always-on-bottom":{"identifier":"allow-set-always-on-bottom","description":"Enables the set_always_on_bottom command without any pre-configured scope.","commands":{"allow":["set_always_on_bottom"],"deny":[]}},"allow-set-always-on-top":{"identifier":"allow-set-always-on-top","description":"Enables the set_always_on_top command without any pre-configured scope.","commands":{"allow":["set_always_on_top"],"deny":[]}},"allow-set-closable":{"identifier":"allow-set-closable","description":"Enables the set_closable command without any pre-configured scope.","commands":{"allow":["set_closable"],"deny":[]}},"allow-set-content-protected":{"identifier":"allow-set-content-protected","description":"Enables the set_content_protected command without any pre-configured scope.","commands":{"allow":["set_content_protected"],"deny":[]}},"allow-set-cursor-grab":{"identifier":"allow-set-cursor-grab","description":"Enables the set_cursor_grab command without any pre-configured scope.","commands":{"allow":["set_cursor_grab"],"deny":[]}},"allow-set-cursor-icon":{"identifier":"allow-set-cursor-icon","description":"Enables the set_cursor_icon command without any pre-configured scope.","commands":{"allow":["set_cursor_icon"],"deny":[]}},"allow-set-cursor-position":{"identifier":"allow-set-cursor-position","description":"Enables the set_cursor_position command without any pre-configured scope.","commands":{"allow":["set_cursor_position"],"deny":[]}},"allow-set-cursor-visible":{"identifier":"allow-set-cursor-visible","description":"Enables the set_cursor_visible command without any pre-configured scope.","commands":{"allow":["set_cursor_visible"],"deny":[]}},"allow-set-decorations":{"identifier":"allow-set-decorations","description":"Enables the set_decorations command without any pre-configured scope.","commands":{"allow":["set_decorations"],"deny":[]}},"allow-set-effects":{"identifier":"allow-set-effects","description":"Enables the set_effects command without any pre-configured scope.","commands":{"allow":["set_effects"],"deny":[]}},"allow-set-enabled":{"identifier":"allow-set-enabled","description":"Enables the set_enabled command without any pre-configured scope.","commands":{"allow":["set_enabled"],"deny":[]}},"allow-set-focus":{"identifier":"allow-set-focus","description":"Enables the set_focus command without any pre-configured scope.","commands":{"allow":["set_focus"],"deny":[]}},"allow-set-fullscreen":{"identifier":"allow-set-fullscreen","description":"Enables the set_fullscreen command without any pre-configured scope.","commands":{"allow":["set_fullscreen"],"deny":[]}},"allow-set-icon":{"identifier":"allow-set-icon","description":"Enables the set_icon command without any pre-configured scope.","commands":{"allow":["set_icon"],"deny":[]}},"allow-set-ignore-cursor-events":{"identifier":"allow-set-ignore-cursor-events","description":"Enables the set_ignore_cursor_events command without any pre-configured scope.","commands":{"allow":["set_ignore_cursor_events"],"deny":[]}},"allow-set-max-size":{"identifier":"allow-set-max-size","description":"Enables the set_max_size command without any pre-configured scope.","commands":{"allow":["set_max_size"],"deny":[]}},"allow-set-maximizable":{"identifier":"allow-set-maximizable","description":"Enables the set_maximizable command without any pre-configured scope.","commands":{"allow":["set_maximizable"],"deny":[]}},"allow-set-min-size":{"identifier":"allow-set-min-size","description":"Enables the set_min_size command without any pre-configured scope.","commands":{"allow":["set_min_size"],"deny":[]}},"allow-set-minimizable":{"identifier":"allow-set-minimizable","description":"Enables the set_minimizable command without any pre-configured scope.","commands":{"allow":["set_minimizable"],"deny":[]}},"allow-set-position":{"identifier":"allow-set-position","description":"Enables the set_position command without any pre-configured scope.","commands":{"allow":["set_position"],"deny":[]}},"allow-set-progress-bar":{"identifier":"allow-set-progress-bar","description":"Enables the set_progress_bar command without any pre-configured scope.","commands":{"allow":["set_progress_bar"],"deny":[]}},"allow-set-resizable":{"identifier":"allow-set-resizable","description":"Enables the set_resizable command without any pre-configured scope.","commands":{"allow":["set_resizable"],"deny":[]}},"allow-set-shadow":{"identifier":"allow-set-shadow","description":"Enables the set_shadow command without any pre-configured scope.","commands":{"allow":["set_shadow"],"deny":[]}},"allow-set-size":{"identifier":"allow-set-size","description":"Enables the set_size command without any pre-configured scope.","commands":{"allow":["set_size"],"deny":[]}},"allow-set-size-constraints":{"identifier":"allow-set-size-constraints","description":"Enables the set_size_constraints command without any pre-configured scope.","commands":{"allow":["set_size_constraints"],"deny":[]}},"allow-set-skip-taskbar":{"identifier":"allow-set-skip-taskbar","description":"Enables the set_skip_taskbar command without any pre-configured scope.","commands":{"allow":["set_skip_taskbar"],"deny":[]}},"allow-set-theme":{"identifier":"allow-set-theme","description":"Enables the set_theme command without any pre-configured scope.","commands":{"allow":["set_theme"],"deny":[]}},"allow-set-title":{"identifier":"allow-set-title","description":"Enables the set_title command without any pre-configured scope.","commands":{"allow":["set_title"],"deny":[]}},"allow-set-title-bar-style":{"identifier":"allow-set-title-bar-style","description":"Enables the set_title_bar_style command without any pre-configured scope.","commands":{"allow":["set_title_bar_style"],"deny":[]}},"allow-set-visible-on-all-workspaces":{"identifier":"allow-set-visible-on-all-workspaces","description":"Enables the set_visible_on_all_workspaces command without any pre-configured scope.","commands":{"allow":["set_visible_on_all_workspaces"],"deny":[]}},"allow-show":{"identifier":"allow-show","description":"Enables the show command without any pre-configured scope.","commands":{"allow":["show"],"deny":[]}},"allow-start-dragging":{"identifier":"allow-start-dragging","description":"Enables the start_dragging command without any pre-configured scope.","commands":{"allow":["start_dragging"],"deny":[]}},"allow-start-resize-dragging":{"identifier":"allow-start-resize-dragging","description":"Enables the start_resize_dragging command without any pre-configured scope.","commands":{"allow":["start_resize_dragging"],"deny":[]}},"allow-theme":{"identifier":"allow-theme","description":"Enables the theme command without any pre-configured scope.","commands":{"allow":["theme"],"deny":[]}},"allow-title":{"identifier":"allow-title","description":"Enables the title command without any pre-configured scope.","commands":{"allow":["title"],"deny":[]}},"allow-toggle-maximize":{"identifier":"allow-toggle-maximize","description":"Enables the toggle_maximize command without any pre-configured scope.","commands":{"allow":["toggle_maximize"],"deny":[]}},"allow-unmaximize":{"identifier":"allow-unmaximize","description":"Enables the unmaximize command without any pre-configured scope.","commands":{"allow":["unmaximize"],"deny":[]}},"allow-unminimize":{"identifier":"allow-unminimize","description":"Enables the unminimize command without any pre-configured scope.","commands":{"allow":["unminimize"],"deny":[]}},"deny-available-monitors":{"identifier":"deny-available-monitors","description":"Denies the available_monitors command without any pre-configured scope.","commands":{"allow":[],"deny":["available_monitors"]}},"deny-center":{"identifier":"deny-center","description":"Denies the center command without any pre-configured scope.","commands":{"allow":[],"deny":["center"]}},"deny-close":{"identifier":"deny-close","description":"Denies the close command without any pre-configured scope.","commands":{"allow":[],"deny":["close"]}},"deny-create":{"identifier":"deny-create","description":"Denies the create command without any pre-configured scope.","commands":{"allow":[],"deny":["create"]}},"deny-current-monitor":{"identifier":"deny-current-monitor","description":"Denies the current_monitor command without any pre-configured scope.","commands":{"allow":[],"deny":["current_monitor"]}},"deny-cursor-position":{"identifier":"deny-cursor-position","description":"Denies the cursor_position command without any pre-configured scope.","commands":{"allow":[],"deny":["cursor_position"]}},"deny-destroy":{"identifier":"deny-destroy","description":"Denies the destroy command without any pre-configured scope.","commands":{"allow":[],"deny":["destroy"]}},"deny-get-all-windows":{"identifier":"deny-get-all-windows","description":"Denies the get_all_windows command without any pre-configured scope.","commands":{"allow":[],"deny":["get_all_windows"]}},"deny-hide":{"identifier":"deny-hide","description":"Denies the hide command without any pre-configured scope.","commands":{"allow":[],"deny":["hide"]}},"deny-inner-position":{"identifier":"deny-inner-position","description":"Denies the inner_position command without any pre-configured scope.","commands":{"allow":[],"deny":["inner_position"]}},"deny-inner-size":{"identifier":"deny-inner-size","description":"Denies the inner_size command without any pre-configured scope.","commands":{"allow":[],"deny":["inner_size"]}},"deny-internal-toggle-maximize":{"identifier":"deny-internal-toggle-maximize","description":"Denies the internal_toggle_maximize command without any pre-configured scope.","commands":{"allow":[],"deny":["internal_toggle_maximize"]}},"deny-is-closable":{"identifier":"deny-is-closable","description":"Denies the is_closable command without any pre-configured scope.","commands":{"allow":[],"deny":["is_closable"]}},"deny-is-decorated":{"identifier":"deny-is-decorated","description":"Denies the is_decorated command without any pre-configured scope.","commands":{"allow":[],"deny":["is_decorated"]}},"deny-is-enabled":{"identifier":"deny-is-enabled","description":"Denies the is_enabled command without any pre-configured scope.","commands":{"allow":[],"deny":["is_enabled"]}},"deny-is-focused":{"identifier":"deny-is-focused","description":"Denies the is_focused command without any pre-configured scope.","commands":{"allow":[],"deny":["is_focused"]}},"deny-is-fullscreen":{"identifier":"deny-is-fullscreen","description":"Denies the is_fullscreen command without any pre-configured scope.","commands":{"allow":[],"deny":["is_fullscreen"]}},"deny-is-maximizable":{"identifier":"deny-is-maximizable","description":"Denies the is_maximizable command without any pre-configured scope.","commands":{"allow":[],"deny":["is_maximizable"]}},"deny-is-maximized":{"identifier":"deny-is-maximized","description":"Denies the is_maximized command without any pre-configured scope.","commands":{"allow":[],"deny":["is_maximized"]}},"deny-is-minimizable":{"identifier":"deny-is-minimizable","description":"Denies the is_minimizable command without any pre-configured scope.","commands":{"allow":[],"deny":["is_minimizable"]}},"deny-is-minimized":{"identifier":"deny-is-minimized","description":"Denies the is_minimized command without any pre-configured scope.","commands":{"allow":[],"deny":["is_minimized"]}},"deny-is-resizable":{"identifier":"deny-is-resizable","description":"Denies the is_resizable command without any pre-configured scope.","commands":{"allow":[],"deny":["is_resizable"]}},"deny-is-visible":{"identifier":"deny-is-visible","description":"Denies the is_visible command without any pre-configured scope.","commands":{"allow":[],"deny":["is_visible"]}},"deny-maximize":{"identifier":"deny-maximize","description":"Denies the maximize command without any pre-configured scope.","commands":{"allow":[],"deny":["maximize"]}},"deny-minimize":{"identifier":"deny-minimize","description":"Denies the minimize command without any pre-configured scope.","commands":{"allow":[],"deny":["minimize"]}},"deny-monitor-from-point":{"identifier":"deny-monitor-from-point","description":"Denies the monitor_from_point command without any pre-configured scope.","commands":{"allow":[],"deny":["monitor_from_point"]}},"deny-outer-position":{"identifier":"deny-outer-position","description":"Denies the outer_position command without any pre-configured scope.","commands":{"allow":[],"deny":["outer_position"]}},"deny-outer-size":{"identifier":"deny-outer-size","description":"Denies the outer_size command without any pre-configured scope.","commands":{"allow":[],"deny":["outer_size"]}},"deny-primary-monitor":{"identifier":"deny-primary-monitor","description":"Denies the primary_monitor command without any pre-configured scope.","commands":{"allow":[],"deny":["primary_monitor"]}},"deny-request-user-attention":{"identifier":"deny-request-user-attention","description":"Denies the request_user_attention command without any pre-configured scope.","commands":{"allow":[],"deny":["request_user_attention"]}},"deny-scale-factor":{"identifier":"deny-scale-factor","description":"Denies the scale_factor command without any pre-configured scope.","commands":{"allow":[],"deny":["scale_factor"]}},"deny-set-always-on-bottom":{"identifier":"deny-set-always-on-bottom","description":"Denies the set_always_on_bottom command without any pre-configured scope.","commands":{"allow":[],"deny":["set_always_on_bottom"]}},"deny-set-always-on-top":{"identifier":"deny-set-always-on-top","description":"Denies the set_always_on_top command without any pre-configured scope.","commands":{"allow":[],"deny":["set_always_on_top"]}},"deny-set-closable":{"identifier":"deny-set-closable","description":"Denies the set_closable command without any pre-configured scope.","commands":{"allow":[],"deny":["set_closable"]}},"deny-set-content-protected":{"identifier":"deny-set-content-protected","description":"Denies the set_content_protected command without any pre-configured scope.","commands":{"allow":[],"deny":["set_content_protected"]}},"deny-set-cursor-grab":{"identifier":"deny-set-cursor-grab","description":"Denies the set_cursor_grab command without any pre-configured scope.","commands":{"allow":[],"deny":["set_cursor_grab"]}},"deny-set-cursor-icon":{"identifier":"deny-set-cursor-icon","description":"Denies the set_cursor_icon command without any pre-configured scope.","commands":{"allow":[],"deny":["set_cursor_icon"]}},"deny-set-cursor-position":{"identifier":"deny-set-cursor-position","description":"Denies the set_cursor_position command without any pre-configured scope.","commands":{"allow":[],"deny":["set_cursor_position"]}},"deny-set-cursor-visible":{"identifier":"deny-set-cursor-visible","description":"Denies the set_cursor_visible command without any pre-configured scope.","commands":{"allow":[],"deny":["set_cursor_visible"]}},"deny-set-decorations":{"identifier":"deny-set-decorations","description":"Denies the set_decorations command without any pre-configured scope.","commands":{"allow":[],"deny":["set_decorations"]}},"deny-set-effects":{"identifier":"deny-set-effects","description":"Denies the set_effects command without any pre-configured scope.","commands":{"allow":[],"deny":["set_effects"]}},"deny-set-enabled":{"identifier":"deny-set-enabled","description":"Denies the set_enabled command without any pre-configured scope.","commands":{"allow":[],"deny":["set_enabled"]}},"deny-set-focus":{"identifier":"deny-set-focus","description":"Denies the set_focus command without any pre-configured scope.","commands":{"allow":[],"deny":["set_focus"]}},"deny-set-fullscreen":{"identifier":"deny-set-fullscreen","description":"Denies the set_fullscreen command without any pre-configured scope.","commands":{"allow":[],"deny":["set_fullscreen"]}},"deny-set-icon":{"identifier":"deny-set-icon","description":"Denies the set_icon command without any pre-configured scope.","commands":{"allow":[],"deny":["set_icon"]}},"deny-set-ignore-cursor-events":{"identifier":"deny-set-ignore-cursor-events","description":"Denies the set_ignore_cursor_events command without any pre-configured scope.","commands":{"allow":[],"deny":["set_ignore_cursor_events"]}},"deny-set-max-size":{"identifier":"deny-set-max-size","description":"Denies the set_max_size command without any pre-configured scope.","commands":{"allow":[],"deny":["set_max_size"]}},"deny-set-maximizable":{"identifier":"deny-set-maximizable","description":"Denies the set_maximizable command without any pre-configured scope.","commands":{"allow":[],"deny":["set_maximizable"]}},"deny-set-min-size":{"identifier":"deny-set-min-size","description":"Denies the set_min_size command without any pre-configured scope.","commands":{"allow":[],"deny":["set_min_size"]}},"deny-set-minimizable":{"identifier":"deny-set-minimizable","description":"Denies the set_minimizable command without any pre-configured scope.","commands":{"allow":[],"deny":["set_minimizable"]}},"deny-set-position":{"identifier":"deny-set-position","description":"Denies the set_position command without any pre-configured scope.","commands":{"allow":[],"deny":["set_position"]}},"deny-set-progress-bar":{"identifier":"deny-set-progress-bar","description":"Denies the set_progress_bar command without any pre-configured scope.","commands":{"allow":[],"deny":["set_progress_bar"]}},"deny-set-resizable":{"identifier":"deny-set-resizable","description":"Denies the set_resizable command without any pre-configured scope.","commands":{"allow":[],"deny":["set_resizable"]}},"deny-set-shadow":{"identifier":"deny-set-shadow","description":"Denies the set_shadow command without any pre-configured scope.","commands":{"allow":[],"deny":["set_shadow"]}},"deny-set-size":{"identifier":"deny-set-size","description":"Denies the set_size command without any pre-configured scope.","commands":{"allow":[],"deny":["set_size"]}},"deny-set-size-constraints":{"identifier":"deny-set-size-constraints","description":"Denies the set_size_constraints command without any pre-configured scope.","commands":{"allow":[],"deny":["set_size_constraints"]}},"deny-set-skip-taskbar":{"identifier":"deny-set-skip-taskbar","description":"Denies the set_skip_taskbar command without any pre-configured scope.","commands":{"allow":[],"deny":["set_skip_taskbar"]}},"deny-set-theme":{"identifier":"deny-set-theme","description":"Denies the set_theme command without any pre-configured scope.","commands":{"allow":[],"deny":["set_theme"]}},"deny-set-title":{"identifier":"deny-set-title","description":"Denies the set_title command without any pre-configured scope.","commands":{"allow":[],"deny":["set_title"]}},"deny-set-title-bar-style":{"identifier":"deny-set-title-bar-style","description":"Denies the set_title_bar_style command without any pre-configured scope.","commands":{"allow":[],"deny":["set_title_bar_style"]}},"deny-set-visible-on-all-workspaces":{"identifier":"deny-set-visible-on-all-workspaces","description":"Denies the set_visible_on_all_workspaces command without any pre-configured scope.","commands":{"allow":[],"deny":["set_visible_on_all_workspaces"]}},"deny-show":{"identifier":"deny-show","description":"Denies the show command without any pre-configured scope.","commands":{"allow":[],"deny":["show"]}},"deny-start-dragging":{"identifier":"deny-start-dragging","description":"Denies the start_dragging command without any pre-configured scope.","commands":{"allow":[],"deny":["start_dragging"]}},"deny-start-resize-dragging":{"identifier":"deny-start-resize-dragging","description":"Denies the start_resize_dragging command without any pre-configured scope.","commands":{"allow":[],"deny":["start_resize_dragging"]}},"deny-theme":{"identifier":"deny-theme","description":"Denies the theme command without any pre-configured scope.","commands":{"allow":[],"deny":["theme"]}},"deny-title":{"identifier":"deny-title","description":"Denies the title command without any pre-configured scope.","commands":{"allow":[],"deny":["title"]}},"deny-toggle-maximize":{"identifier":"deny-toggle-maximize","description":"Denies the toggle_maximize command without any pre-configured scope.","commands":{"allow":[],"deny":["toggle_maximize"]}},"deny-unmaximize":{"identifier":"deny-unmaximize","description":"Denies the unmaximize command without any pre-configured scope.","commands":{"allow":[],"deny":["unmaximize"]}},"deny-unminimize":{"identifier":"deny-unminimize","description":"Denies the unminimize command without any pre-configured scope.","commands":{"allow":[],"deny":["unminimize"]}}},"permission_sets":{},"global_scope_schema":null},"dialog":{"default_permission":{"identifier":"default","description":"This permission set configures the types of dialogs\navailable from the dialog plugin.\n\n#### Granted Permissions\n\nAll dialog types are enabled.\n\n\n","permissions":["allow-ask","allow-confirm","allow-message","allow-save","allow-open"]},"permissions":{"allow-ask":{"identifier":"allow-ask","description":"Enables the ask command without any pre-configured scope.","commands":{"allow":["ask"],"deny":[]}},"allow-confirm":{"identifier":"allow-confirm","description":"Enables the confirm command without any pre-configured scope.","commands":{"allow":["confirm"],"deny":[]}},"allow-message":{"identifier":"allow-message","description":"Enables the message command without any pre-configured scope.","commands":{"allow":["message"],"deny":[]}},"allow-open":{"identifier":"allow-open","description":"Enables the open command without any pre-configured scope.","commands":{"allow":["open"],"deny":[]}},"allow-save":{"identifier":"allow-save","description":"Enables the save command without any pre-configured scope.","commands":{"allow":["save"],"deny":[]}},"deny-ask":{"identifier":"deny-ask","description":"Denies the ask command without any pre-configured scope.","commands":{"allow":[],"deny":["ask"]}},"deny-confirm":{"identifier":"deny-confirm","description":"Denies the confirm command without any pre-configured scope.","commands":{"allow":[],"deny":["confirm"]}},"deny-message":{"identifier":"deny-message","description":"Denies the message command without any pre-configured scope.","commands":{"allow":[],"deny":["message"]}},"deny-open":{"identifier":"deny-open","description":"Denies the open command without any pre-configured scope.","commands":{"allow":[],"deny":["open"]}},"deny-save":{"identifier":"deny-save","description":"Denies the save command without any pre-configured scope.","commands":{"allow":[],"deny":["save"]}}},"permission_sets":{},"global_scope_schema":null},"global-shortcut":{"default_permission":{"identifier":"default","description":"No features are enabled by default, as we believe\nthe shortcuts can be inherently dangerous and it is\napplication specific if specific shortcuts should be\nregistered or unregistered.\n","permissions":[]},"permissions":{"allow-is-registered":{"identifier":"allow-is-registered","description":"Enables the is_registered command without any pre-configured scope.","commands":{"allow":["is_registered"],"deny":[]}},"allow-register":{"identifier":"allow-register","description":"Enables the register command without any pre-configured scope.","commands":{"allow":["register"],"deny":[]}},"allow-register-all":{"identifier":"allow-register-all","description":"Enables the register_all command without any pre-configured scope.","commands":{"allow":["register_all"],"deny":[]}},"allow-unregister":{"identifier":"allow-unregister","description":"Enables the unregister command without any pre-configured scope.","commands":{"allow":["unregister"],"deny":[]}},"allow-unregister-all":{"identifier":"allow-unregister-all","description":"Enables the unregister_all command without any pre-configured scope.","commands":{"allow":["unregister_all"],"deny":[]}},"deny-is-registered":{"identifier":"deny-is-registered","description":"Denies the is_registered command without any pre-configured scope.","commands":{"allow":[],"deny":["is_registered"]}},"deny-register":{"identifier":"deny-register","description":"Denies the register command without any pre-configured scope.","commands":{"allow":[],"deny":["register"]}},"deny-register-all":{"identifier":"deny-register-all","description":"Denies the register_all command without any pre-configured scope.","commands":{"allow":[],"deny":["register_all"]}},"deny-unregister":{"identifier":"deny-unregister","description":"Denies the unregister command without any pre-configured scope.","commands":{"allow":[],"deny":["unregister"]}},"deny-unregister-all":{"identifier":"deny-unregister-all","description":"Denies the unregister_all command without any pre-configured scope.","commands":{"allow":[],"deny":["unregister_all"]}}},"permission_sets":{},"global_scope_schema":null},"os":{"default_permission":{"identifier":"default","description":"This permission set configures which\noperating system information are available\nto gather from the frontend.\n\n#### Granted Permissions\n\nAll information except the host name are available.\n\n","permissions":["allow-arch","allow-exe-extension","allow-family","allow-locale","allow-os-type","allow-platform","allow-version"]},"permissions":{"allow-arch":{"identifier":"allow-arch","description":"Enables the arch command without any pre-configured scope.","commands":{"allow":["arch"],"deny":[]}},"allow-exe-extension":{"identifier":"allow-exe-extension","description":"Enables the exe_extension command without any pre-configured scope.","commands":{"allow":["exe_extension"],"deny":[]}},"allow-family":{"identifier":"allow-family","description":"Enables the family command without any pre-configured scope.","commands":{"allow":["family"],"deny":[]}},"allow-hostname":{"identifier":"allow-hostname","description":"Enables the hostname command without any pre-configured scope.","commands":{"allow":["hostname"],"deny":[]}},"allow-locale":{"identifier":"allow-locale","description":"Enables the locale command without any pre-configured scope.","commands":{"allow":["locale"],"deny":[]}},"allow-os-type":{"identifier":"allow-os-type","description":"Enables the os_type command without any pre-configured scope.","commands":{"allow":["os_type"],"deny":[]}},"allow-platform":{"identifier":"allow-platform","description":"Enables the platform command without any pre-configured scope.","commands":{"allow":["platform"],"deny":[]}},"allow-version":{"identifier":"allow-version","description":"Enables the version command without any pre-configured scope.","commands":{"allow":["version"],"deny":[]}},"deny-arch":{"identifier":"deny-arch","description":"Denies the arch command without any pre-configured scope.","commands":{"allow":[],"deny":["arch"]}},"deny-exe-extension":{"identifier":"deny-exe-extension","description":"Denies the exe_extension command without any pre-configured scope.","commands":{"allow":[],"deny":["exe_extension"]}},"deny-family":{"identifier":"deny-family","description":"Denies the family command without any pre-configured scope.","commands":{"allow":[],"deny":["family"]}},"deny-hostname":{"identifier":"deny-hostname","description":"Denies the hostname command without any pre-configured scope.","commands":{"allow":[],"deny":["hostname"]}},"deny-locale":{"identifier":"deny-locale","description":"Denies the locale command without any pre-configured scope.","commands":{"allow":[],"deny":["locale"]}},"deny-os-type":{"identifier":"deny-os-type","description":"Denies the os_type command without any pre-configured scope.","commands":{"allow":[],"deny":["os_type"]}},"deny-platform":{"identifier":"deny-platform","description":"Denies the platform command without any pre-configured scope.","commands":{"allow":[],"deny":["platform"]}},"deny-version":{"identifier":"deny-version","description":"Denies the version command without any pre-configured scope.","commands":{"allow":[],"deny":["version"]}}},"permission_sets":{},"global_scope_schema":null},"shell":{"default_permission":{"identifier":"default","description":"This permission set configures which\nshell functionality is exposed by default.\n\n#### Granted Permissions\n\nIt allows to use the `open` functionality without any specific\nscope pre-configured. It will allow opening `http(s)://`,\n`tel:` and `mailto:` links.\n","permissions":["allow-open"]},"permissions":{"allow-execute":{"identifier":"allow-execute","description":"Enables the execute command without any pre-configured scope.","commands":{"allow":["execute"],"deny":[]}},"allow-kill":{"identifier":"allow-kill","description":"Enables the kill command without any pre-configured scope.","commands":{"allow":["kill"],"deny":[]}},"allow-open":{"identifier":"allow-open","description":"Enables the open command without any pre-configured scope.","commands":{"allow":["open"],"deny":[]}},"allow-spawn":{"identifier":"allow-spawn","description":"Enables the spawn command without any pre-configured scope.","commands":{"allow":["spawn"],"deny":[]}},"allow-stdin-write":{"identifier":"allow-stdin-write","description":"Enables the stdin_write command without any pre-configured scope.","commands":{"allow":["stdin_write"],"deny":[]}},"deny-execute":{"identifier":"deny-execute","description":"Denies the execute command without any pre-configured scope.","commands":{"allow":[],"deny":["execute"]}},"deny-kill":{"identifier":"deny-kill","description":"Denies the kill command without any pre-configured scope.","commands":{"allow":[],"deny":["kill"]}},"deny-open":{"identifier":"deny-open","description":"Denies the open command without any pre-configured scope.","commands":{"allow":[],"deny":["open"]}},"deny-spawn":{"identifier":"deny-spawn","description":"Denies the spawn command without any pre-configured scope.","commands":{"allow":[],"deny":["spawn"]}},"deny-stdin-write":{"identifier":"deny-stdin-write","description":"Denies the stdin_write command without any pre-configured scope.","commands":{"allow":[],"deny":["stdin_write"]}}},"permission_sets":{},"global_scope_schema":{"$schema":"http://json-schema.org/draft-07/schema#","anyOf":[{"additionalProperties":false,"properties":{"args":{"allOf":[{"$ref":"#/definitions/ShellScopeEntryAllowedArgs"}],"description":"The allowed arguments for the command execution."},"cmd":{"description":"The command name. It can start with a variable that resolves to a system base directory. The variables are: `$AUDIO`, `$CACHE`, `$CONFIG`, `$DATA`, `$LOCALDATA`, `$DESKTOP`, `$DOCUMENT`, `$DOWNLOAD`, `$EXE`, `$FONT`, `$HOME`, `$PICTURE`, `$PUBLIC`, `$RUNTIME`, `$TEMPLATE`, `$VIDEO`, `$RESOURCE`, `$LOG`, `$TEMP`, `$APPCONFIG`, `$APPDATA`, `$APPLOCALDATA`, `$APPCACHE`, `$APPLOG`.","type":"string"},"name":{"description":"The name for this allowed shell command configuration.\n\nThis name will be used inside of the webview API to call this command along with any specified arguments.","type":"string"}},"required":["cmd","name"],"type":"object"},{"additionalProperties":false,"properties":{"args":{"allOf":[{"$ref":"#/definitions/ShellScopeEntryAllowedArgs"}],"description":"The allowed arguments for the command execution."},"name":{"description":"The name for this allowed shell command configuration.\n\nThis name will be used inside of the webview API to call this command along with any specified arguments.","type":"string"},"sidecar":{"description":"If this command is a sidecar command.","type":"boolean"}},"required":["name","sidecar"],"type":"object"}],"definitions":{"ShellScopeEntryAllowedArg":{"anyOf":[{"description":"A non-configurable argument that is passed to the command in the order it was specified.","type":"string"},{"additionalProperties":false,"description":"A variable that is set while calling the command from the webview API.","properties":{"raw":{"default":false,"description":"Marks the validator as a raw regex, meaning the plugin should not make any modification at runtime.\n\nThis means the regex will not match on the entire string by default, which might be exploited if your regex allow unexpected input to be considered valid. When using this option, make sure your regex is correct.","type":"boolean"},"validator":{"description":"[regex] validator to require passed values to conform to an expected input.\n\nThis will require the argument value passed to this variable to match the `validator` regex before it will be executed.\n\nThe regex string is by default surrounded by `^...$` to match the full string. For example the `https?://\\w+` regex would be registered as `^https?://\\w+$`.\n\n[regex]: ","type":"string"}},"required":["validator"],"type":"object"}],"description":"A command argument allowed to be executed by the webview API."},"ShellScopeEntryAllowedArgs":{"anyOf":[{"description":"Use a simple boolean to allow all or disable all arguments to this command configuration.","type":"boolean"},{"description":"A specific set of [`ShellScopeEntryAllowedArg`] that are valid to call for the command configuration.","items":{"$ref":"#/definitions/ShellScopeEntryAllowedArg"},"type":"array"}],"description":"A set of command arguments allowed to be executed by the webview API.\n\nA value of `true` will allow any arguments to be passed to the command. `false` will disable all arguments. A list of [`ShellScopeEntryAllowedArg`] will set those arguments as the only valid arguments to be passed to the attached command configuration."}},"description":"Shell scope entry.","title":"ShellScopeEntry"}}} \ No newline at end of file diff --git a/src-tauri/gen/schemas/capabilities.json b/src-tauri/gen/schemas/capabilities.json new file mode 100644 index 0000000..3f3bdfb --- /dev/null +++ b/src-tauri/gen/schemas/capabilities.json @@ -0,0 +1 @@ +{"desktop-capability":{"identifier":"desktop-capability","description":"","local":true,"windows":["main"],"permissions":["global-shortcut:default","shell:default","dialog:default"],"platforms":["macOS","windows","linux"]},"migrated":{"identifier":"migrated","description":"permissions that were migrated from v1","local":true,"windows":["main"],"permissions":["core:default","core:window:allow-create","core:window:allow-center","core:window:allow-request-user-attention","core:window:allow-set-resizable","core:window:allow-set-maximizable","core:window:allow-set-minimizable","core:window:allow-set-closable","core:window:allow-set-title","core:window:allow-maximize","core:window:allow-unmaximize","core:window:allow-minimize","core:window:allow-unminimize","core:window:allow-show","core:window:allow-hide","core:window:allow-close","core:window:allow-set-decorations","core:window:allow-set-always-on-top","core:window:allow-set-content-protected","core:window:allow-set-size","core:window:allow-set-min-size","core:window:allow-set-max-size","core:window:allow-set-position","core:window:allow-set-fullscreen","core:window:allow-set-focus","core:window:allow-set-icon","core:window:allow-set-skip-taskbar","core:window:allow-set-cursor-grab","core:window:allow-set-cursor-visible","core:window:allow-set-cursor-icon","core:window:allow-set-cursor-position","core:window:allow-set-ignore-cursor-events","core:window:allow-start-dragging","core:webview:allow-print","shell:allow-open","dialog:allow-open","dialog:allow-save","dialog:allow-message","dialog:allow-ask","dialog:allow-confirm","global-shortcut:allow-is-registered","global-shortcut:allow-register","global-shortcut:allow-register-all","global-shortcut:allow-unregister","global-shortcut:allow-unregister-all","os:allow-platform","os:allow-version","os:allow-os-type","os:allow-family","os:allow-arch","os:allow-exe-extension","os:allow-locale","os:allow-hostname","os:default"]}} \ No newline at end of file diff --git a/src-tauri/gen/schemas/desktop-schema.json b/src-tauri/gen/schemas/desktop-schema.json new file mode 100644 index 0000000..869ffa4 --- /dev/null +++ b/src-tauri/gen/schemas/desktop-schema.json @@ -0,0 +1,2249 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "CapabilityFile", + "description": "Capability formats accepted in a capability file.", + "anyOf": [ + { + "description": "A single capability.", + "allOf": [ + { + "$ref": "#/definitions/Capability" + } + ] + }, + { + "description": "A list of capabilities.", + "type": "array", + "items": { + "$ref": "#/definitions/Capability" + } + }, + { + "description": "A list of capabilities.", + "type": "object", + "required": [ + "capabilities" + ], + "properties": { + "capabilities": { + "description": "The list of capabilities.", + "type": "array", + "items": { + "$ref": "#/definitions/Capability" + } + } + } + } + ], + "definitions": { + "Capability": { + "description": "A grouping and boundary mechanism developers can use to isolate access to the IPC layer.\n\nIt controls application windows fine grained access to the Tauri core, application, or plugin commands. If a window is not matching any capability then it has no access to the IPC layer at all.\n\nThis can be done to create groups of windows, based on their required system access, which can reduce impact of frontend vulnerabilities in less privileged windows. Windows can be added to a capability by exact name (e.g. `main-window`) or glob patterns like `*` or `admin-*`. A Window can have none, one, or multiple associated capabilities.\n\n## Example\n\n```json { \"identifier\": \"main-user-files-write\", \"description\": \"This capability allows the `main` window on macOS and Windows access to `filesystem` write related commands and `dialog` commands to enable programatic access to files selected by the user.\", \"windows\": [ \"main\" ], \"permissions\": [ \"core:default\", \"dialog:open\", { \"identifier\": \"fs:allow-write-text-file\", \"allow\": [{ \"path\": \"$HOME/test.txt\" }] }, ], \"platforms\": [\"macOS\",\"windows\"] } ```", + "type": "object", + "required": [ + "identifier", + "permissions" + ], + "properties": { + "identifier": { + "description": "Identifier of the capability.\n\n## Example\n\n`main-user-files-write`", + "type": "string" + }, + "description": { + "description": "Description of what the capability is intended to allow on associated windows.\n\nIt should contain a description of what the grouped permissions should allow.\n\n## Example\n\nThis capability allows the `main` window access to `filesystem` write related commands and `dialog` commands to enable programatic access to files selected by the user.", + "default": "", + "type": "string" + }, + "remote": { + "description": "Configure remote URLs that can use the capability permissions.\n\nThis setting is optional and defaults to not being set, as our default use case is that the content is served from our local application.\n\n:::caution Make sure you understand the security implications of providing remote sources with local system access. :::\n\n## Example\n\n```json { \"urls\": [\"https://*.mydomain.dev\"] } ```", + "anyOf": [ + { + "$ref": "#/definitions/CapabilityRemote" + }, + { + "type": "null" + } + ] + }, + "local": { + "description": "Whether this capability is enabled for local app URLs or not. Defaults to `true`.", + "default": true, + "type": "boolean" + }, + "windows": { + "description": "List of windows that are affected by this capability. Can be a glob pattern.\n\nOn multiwebview windows, prefer [`Self::webviews`] for a fine grained access control.\n\n## Example\n\n`[\"main\"]`", + "type": "array", + "items": { + "type": "string" + } + }, + "webviews": { + "description": "List of webviews that are affected by this capability. Can be a glob pattern.\n\nThis is only required when using on multiwebview contexts, by default all child webviews of a window that matches [`Self::windows`] are linked.\n\n## Example\n\n`[\"sub-webview-one\", \"sub-webview-two\"]`", + "type": "array", + "items": { + "type": "string" + } + }, + "permissions": { + "description": "List of permissions attached to this capability.\n\nMust include the plugin name as prefix in the form of `${plugin-name}:${permission-name}`. For commands directly implemented in the application itself only `${permission-name}` is required.\n\n## Example\n\n```json [ \"core:default\", \"shell:allow-open\", \"dialog:open\", { \"identifier\": \"fs:allow-write-text-file\", \"allow\": [{ \"path\": \"$HOME/test.txt\" }] } ] ```", + "type": "array", + "items": { + "$ref": "#/definitions/PermissionEntry" + }, + "uniqueItems": true + }, + "platforms": { + "description": "Limit which target platforms this capability applies to.\n\nBy default all platforms are targeted.\n\n## Example\n\n`[\"macOS\",\"windows\"]`", + "type": [ + "array", + "null" + ], + "items": { + "$ref": "#/definitions/Target" + } + } + } + }, + "CapabilityRemote": { + "description": "Configuration for remote URLs that are associated with the capability.", + "type": "object", + "required": [ + "urls" + ], + "properties": { + "urls": { + "description": "Remote domains this capability refers to using the [URLPattern standard](https://urlpattern.spec.whatwg.org/).\n\n## Examples\n\n- \"https://*.mydomain.dev\": allows subdomains of mydomain.dev - \"https://mydomain.dev/api/*\": allows any subpath of mydomain.dev/api", + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "PermissionEntry": { + "description": "An entry for a permission value in a [`Capability`] can be either a raw permission [`Identifier`] or an object that references a permission and extends its scope.", + "anyOf": [ + { + "description": "Reference a permission or permission set by identifier.", + "allOf": [ + { + "$ref": "#/definitions/Identifier" + } + ] + }, + { + "description": "Reference a permission or permission set by identifier and extends its scope.", + "type": "object", + "allOf": [ + { + "if": { + "properties": { + "identifier": { + "anyOf": [ + { + "description": "This permission set configures which\nshell functionality is exposed by default.\n\n#### Granted Permissions\n\nIt allows to use the `open` functionality without any specific\nscope pre-configured. It will allow opening `http(s)://`,\n`tel:` and `mailto:` links.\n", + "type": "string", + "const": "shell:default" + }, + { + "description": "Enables the execute command without any pre-configured scope.", + "type": "string", + "const": "shell:allow-execute" + }, + { + "description": "Enables the kill command without any pre-configured scope.", + "type": "string", + "const": "shell:allow-kill" + }, + { + "description": "Enables the open command without any pre-configured scope.", + "type": "string", + "const": "shell:allow-open" + }, + { + "description": "Enables the spawn command without any pre-configured scope.", + "type": "string", + "const": "shell:allow-spawn" + }, + { + "description": "Enables the stdin_write command without any pre-configured scope.", + "type": "string", + "const": "shell:allow-stdin-write" + }, + { + "description": "Denies the execute command without any pre-configured scope.", + "type": "string", + "const": "shell:deny-execute" + }, + { + "description": "Denies the kill command without any pre-configured scope.", + "type": "string", + "const": "shell:deny-kill" + }, + { + "description": "Denies the open command without any pre-configured scope.", + "type": "string", + "const": "shell:deny-open" + }, + { + "description": "Denies the spawn command without any pre-configured scope.", + "type": "string", + "const": "shell:deny-spawn" + }, + { + "description": "Denies the stdin_write command without any pre-configured scope.", + "type": "string", + "const": "shell:deny-stdin-write" + } + ] + } + } + }, + "then": { + "properties": { + "allow": { + "items": { + "title": "ShellScopeEntry", + "description": "Shell scope entry.", + "anyOf": [ + { + "type": "object", + "required": [ + "cmd", + "name" + ], + "properties": { + "args": { + "description": "The allowed arguments for the command execution.", + "allOf": [ + { + "$ref": "#/definitions/ShellScopeEntryAllowedArgs" + } + ] + }, + "cmd": { + "description": "The command name. It can start with a variable that resolves to a system base directory. The variables are: `$AUDIO`, `$CACHE`, `$CONFIG`, `$DATA`, `$LOCALDATA`, `$DESKTOP`, `$DOCUMENT`, `$DOWNLOAD`, `$EXE`, `$FONT`, `$HOME`, `$PICTURE`, `$PUBLIC`, `$RUNTIME`, `$TEMPLATE`, `$VIDEO`, `$RESOURCE`, `$LOG`, `$TEMP`, `$APPCONFIG`, `$APPDATA`, `$APPLOCALDATA`, `$APPCACHE`, `$APPLOG`.", + "type": "string" + }, + "name": { + "description": "The name for this allowed shell command configuration.\n\nThis name will be used inside of the webview API to call this command along with any specified arguments.", + "type": "string" + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "name", + "sidecar" + ], + "properties": { + "args": { + "description": "The allowed arguments for the command execution.", + "allOf": [ + { + "$ref": "#/definitions/ShellScopeEntryAllowedArgs" + } + ] + }, + "name": { + "description": "The name for this allowed shell command configuration.\n\nThis name will be used inside of the webview API to call this command along with any specified arguments.", + "type": "string" + }, + "sidecar": { + "description": "If this command is a sidecar command.", + "type": "boolean" + } + }, + "additionalProperties": false + } + ] + } + }, + "deny": { + "items": { + "title": "ShellScopeEntry", + "description": "Shell scope entry.", + "anyOf": [ + { + "type": "object", + "required": [ + "cmd", + "name" + ], + "properties": { + "args": { + "description": "The allowed arguments for the command execution.", + "allOf": [ + { + "$ref": "#/definitions/ShellScopeEntryAllowedArgs" + } + ] + }, + "cmd": { + "description": "The command name. It can start with a variable that resolves to a system base directory. The variables are: `$AUDIO`, `$CACHE`, `$CONFIG`, `$DATA`, `$LOCALDATA`, `$DESKTOP`, `$DOCUMENT`, `$DOWNLOAD`, `$EXE`, `$FONT`, `$HOME`, `$PICTURE`, `$PUBLIC`, `$RUNTIME`, `$TEMPLATE`, `$VIDEO`, `$RESOURCE`, `$LOG`, `$TEMP`, `$APPCONFIG`, `$APPDATA`, `$APPLOCALDATA`, `$APPCACHE`, `$APPLOG`.", + "type": "string" + }, + "name": { + "description": "The name for this allowed shell command configuration.\n\nThis name will be used inside of the webview API to call this command along with any specified arguments.", + "type": "string" + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "name", + "sidecar" + ], + "properties": { + "args": { + "description": "The allowed arguments for the command execution.", + "allOf": [ + { + "$ref": "#/definitions/ShellScopeEntryAllowedArgs" + } + ] + }, + "name": { + "description": "The name for this allowed shell command configuration.\n\nThis name will be used inside of the webview API to call this command along with any specified arguments.", + "type": "string" + }, + "sidecar": { + "description": "If this command is a sidecar command.", + "type": "boolean" + } + }, + "additionalProperties": false + } + ] + } + } + } + }, + "properties": { + "identifier": { + "description": "Identifier of the permission or permission set.", + "allOf": [ + { + "$ref": "#/definitions/Identifier" + } + ] + } + } + }, + { + "properties": { + "identifier": { + "description": "Identifier of the permission or permission set.", + "allOf": [ + { + "$ref": "#/definitions/Identifier" + } + ] + }, + "allow": { + "description": "Data that defines what is allowed by the scope.", + "type": [ + "array", + "null" + ], + "items": { + "$ref": "#/definitions/Value" + } + }, + "deny": { + "description": "Data that defines what is denied by the scope. This should be prioritized by validation logic.", + "type": [ + "array", + "null" + ], + "items": { + "$ref": "#/definitions/Value" + } + } + } + } + ], + "required": [ + "identifier" + ] + } + ] + }, + "Identifier": { + "description": "Permission identifier", + "oneOf": [ + { + "description": "Default core plugins set which includes:\n- 'core:path:default'\n- 'core:event:default'\n- 'core:window:default'\n- 'core:webview:default'\n- 'core:app:default'\n- 'core:image:default'\n- 'core:resources:default'\n- 'core:menu:default'\n- 'core:tray:default'\n", + "type": "string", + "const": "core:default" + }, + { + "description": "Default permissions for the plugin.", + "type": "string", + "const": "core:app:default" + }, + { + "description": "Enables the app_hide command without any pre-configured scope.", + "type": "string", + "const": "core:app:allow-app-hide" + }, + { + "description": "Enables the app_show command without any pre-configured scope.", + "type": "string", + "const": "core:app:allow-app-show" + }, + { + "description": "Enables the default_window_icon command without any pre-configured scope.", + "type": "string", + "const": "core:app:allow-default-window-icon" + }, + { + "description": "Enables the name command without any pre-configured scope.", + "type": "string", + "const": "core:app:allow-name" + }, + { + "description": "Enables the set_app_theme command without any pre-configured scope.", + "type": "string", + "const": "core:app:allow-set-app-theme" + }, + { + "description": "Enables the tauri_version command without any pre-configured scope.", + "type": "string", + "const": "core:app:allow-tauri-version" + }, + { + "description": "Enables the version command without any pre-configured scope.", + "type": "string", + "const": "core:app:allow-version" + }, + { + "description": "Denies the app_hide command without any pre-configured scope.", + "type": "string", + "const": "core:app:deny-app-hide" + }, + { + "description": "Denies the app_show command without any pre-configured scope.", + "type": "string", + "const": "core:app:deny-app-show" + }, + { + "description": "Denies the default_window_icon command without any pre-configured scope.", + "type": "string", + "const": "core:app:deny-default-window-icon" + }, + { + "description": "Denies the name command without any pre-configured scope.", + "type": "string", + "const": "core:app:deny-name" + }, + { + "description": "Denies the set_app_theme command without any pre-configured scope.", + "type": "string", + "const": "core:app:deny-set-app-theme" + }, + { + "description": "Denies the tauri_version command without any pre-configured scope.", + "type": "string", + "const": "core:app:deny-tauri-version" + }, + { + "description": "Denies the version command without any pre-configured scope.", + "type": "string", + "const": "core:app:deny-version" + }, + { + "description": "Default permissions for the plugin.", + "type": "string", + "const": "core:event:default" + }, + { + "description": "Enables the emit command without any pre-configured scope.", + "type": "string", + "const": "core:event:allow-emit" + }, + { + "description": "Enables the emit_to command without any pre-configured scope.", + "type": "string", + "const": "core:event:allow-emit-to" + }, + { + "description": "Enables the listen command without any pre-configured scope.", + "type": "string", + "const": "core:event:allow-listen" + }, + { + "description": "Enables the unlisten command without any pre-configured scope.", + "type": "string", + "const": "core:event:allow-unlisten" + }, + { + "description": "Denies the emit command without any pre-configured scope.", + "type": "string", + "const": "core:event:deny-emit" + }, + { + "description": "Denies the emit_to command without any pre-configured scope.", + "type": "string", + "const": "core:event:deny-emit-to" + }, + { + "description": "Denies the listen command without any pre-configured scope.", + "type": "string", + "const": "core:event:deny-listen" + }, + { + "description": "Denies the unlisten command without any pre-configured scope.", + "type": "string", + "const": "core:event:deny-unlisten" + }, + { + "description": "Default permissions for the plugin.", + "type": "string", + "const": "core:image:default" + }, + { + "description": "Enables the from_bytes command without any pre-configured scope.", + "type": "string", + "const": "core:image:allow-from-bytes" + }, + { + "description": "Enables the from_path command without any pre-configured scope.", + "type": "string", + "const": "core:image:allow-from-path" + }, + { + "description": "Enables the new command without any pre-configured scope.", + "type": "string", + "const": "core:image:allow-new" + }, + { + "description": "Enables the rgba command without any pre-configured scope.", + "type": "string", + "const": "core:image:allow-rgba" + }, + { + "description": "Enables the size command without any pre-configured scope.", + "type": "string", + "const": "core:image:allow-size" + }, + { + "description": "Denies the from_bytes command without any pre-configured scope.", + "type": "string", + "const": "core:image:deny-from-bytes" + }, + { + "description": "Denies the from_path command without any pre-configured scope.", + "type": "string", + "const": "core:image:deny-from-path" + }, + { + "description": "Denies the new command without any pre-configured scope.", + "type": "string", + "const": "core:image:deny-new" + }, + { + "description": "Denies the rgba command without any pre-configured scope.", + "type": "string", + "const": "core:image:deny-rgba" + }, + { + "description": "Denies the size command without any pre-configured scope.", + "type": "string", + "const": "core:image:deny-size" + }, + { + "description": "Default permissions for the plugin.", + "type": "string", + "const": "core:menu:default" + }, + { + "description": "Enables the append command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-append" + }, + { + "description": "Enables the create_default command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-create-default" + }, + { + "description": "Enables the get command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-get" + }, + { + "description": "Enables the insert command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-insert" + }, + { + "description": "Enables the is_checked command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-is-checked" + }, + { + "description": "Enables the is_enabled command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-is-enabled" + }, + { + "description": "Enables the items command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-items" + }, + { + "description": "Enables the new command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-new" + }, + { + "description": "Enables the popup command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-popup" + }, + { + "description": "Enables the prepend command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-prepend" + }, + { + "description": "Enables the remove command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-remove" + }, + { + "description": "Enables the remove_at command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-remove-at" + }, + { + "description": "Enables the set_accelerator command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-set-accelerator" + }, + { + "description": "Enables the set_as_app_menu command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-set-as-app-menu" + }, + { + "description": "Enables the set_as_help_menu_for_nsapp command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-set-as-help-menu-for-nsapp" + }, + { + "description": "Enables the set_as_window_menu command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-set-as-window-menu" + }, + { + "description": "Enables the set_as_windows_menu_for_nsapp command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-set-as-windows-menu-for-nsapp" + }, + { + "description": "Enables the set_checked command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-set-checked" + }, + { + "description": "Enables the set_enabled command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-set-enabled" + }, + { + "description": "Enables the set_icon command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-set-icon" + }, + { + "description": "Enables the set_text command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-set-text" + }, + { + "description": "Enables the text command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-text" + }, + { + "description": "Denies the append command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-append" + }, + { + "description": "Denies the create_default command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-create-default" + }, + { + "description": "Denies the get command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-get" + }, + { + "description": "Denies the insert command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-insert" + }, + { + "description": "Denies the is_checked command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-is-checked" + }, + { + "description": "Denies the is_enabled command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-is-enabled" + }, + { + "description": "Denies the items command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-items" + }, + { + "description": "Denies the new command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-new" + }, + { + "description": "Denies the popup command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-popup" + }, + { + "description": "Denies the prepend command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-prepend" + }, + { + "description": "Denies the remove command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-remove" + }, + { + "description": "Denies the remove_at command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-remove-at" + }, + { + "description": "Denies the set_accelerator command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-set-accelerator" + }, + { + "description": "Denies the set_as_app_menu command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-set-as-app-menu" + }, + { + "description": "Denies the set_as_help_menu_for_nsapp command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-set-as-help-menu-for-nsapp" + }, + { + "description": "Denies the set_as_window_menu command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-set-as-window-menu" + }, + { + "description": "Denies the set_as_windows_menu_for_nsapp command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-set-as-windows-menu-for-nsapp" + }, + { + "description": "Denies the set_checked command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-set-checked" + }, + { + "description": "Denies the set_enabled command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-set-enabled" + }, + { + "description": "Denies the set_icon command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-set-icon" + }, + { + "description": "Denies the set_text command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-set-text" + }, + { + "description": "Denies the text command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-text" + }, + { + "description": "Default permissions for the plugin.", + "type": "string", + "const": "core:path:default" + }, + { + "description": "Enables the basename command without any pre-configured scope.", + "type": "string", + "const": "core:path:allow-basename" + }, + { + "description": "Enables the dirname command without any pre-configured scope.", + "type": "string", + "const": "core:path:allow-dirname" + }, + { + "description": "Enables the extname command without any pre-configured scope.", + "type": "string", + "const": "core:path:allow-extname" + }, + { + "description": "Enables the is_absolute command without any pre-configured scope.", + "type": "string", + "const": "core:path:allow-is-absolute" + }, + { + "description": "Enables the join command without any pre-configured scope.", + "type": "string", + "const": "core:path:allow-join" + }, + { + "description": "Enables the normalize command without any pre-configured scope.", + "type": "string", + "const": "core:path:allow-normalize" + }, + { + "description": "Enables the resolve command without any pre-configured scope.", + "type": "string", + "const": "core:path:allow-resolve" + }, + { + "description": "Enables the resolve_directory command without any pre-configured scope.", + "type": "string", + "const": "core:path:allow-resolve-directory" + }, + { + "description": "Denies the basename command without any pre-configured scope.", + "type": "string", + "const": "core:path:deny-basename" + }, + { + "description": "Denies the dirname command without any pre-configured scope.", + "type": "string", + "const": "core:path:deny-dirname" + }, + { + "description": "Denies the extname command without any pre-configured scope.", + "type": "string", + "const": "core:path:deny-extname" + }, + { + "description": "Denies the is_absolute command without any pre-configured scope.", + "type": "string", + "const": "core:path:deny-is-absolute" + }, + { + "description": "Denies the join command without any pre-configured scope.", + "type": "string", + "const": "core:path:deny-join" + }, + { + "description": "Denies the normalize command without any pre-configured scope.", + "type": "string", + "const": "core:path:deny-normalize" + }, + { + "description": "Denies the resolve command without any pre-configured scope.", + "type": "string", + "const": "core:path:deny-resolve" + }, + { + "description": "Denies the resolve_directory command without any pre-configured scope.", + "type": "string", + "const": "core:path:deny-resolve-directory" + }, + { + "description": "Default permissions for the plugin.", + "type": "string", + "const": "core:resources:default" + }, + { + "description": "Enables the close command without any pre-configured scope.", + "type": "string", + "const": "core:resources:allow-close" + }, + { + "description": "Denies the close command without any pre-configured scope.", + "type": "string", + "const": "core:resources:deny-close" + }, + { + "description": "Default permissions for the plugin.", + "type": "string", + "const": "core:tray:default" + }, + { + "description": "Enables the get_by_id command without any pre-configured scope.", + "type": "string", + "const": "core:tray:allow-get-by-id" + }, + { + "description": "Enables the new command without any pre-configured scope.", + "type": "string", + "const": "core:tray:allow-new" + }, + { + "description": "Enables the remove_by_id command without any pre-configured scope.", + "type": "string", + "const": "core:tray:allow-remove-by-id" + }, + { + "description": "Enables the set_icon command without any pre-configured scope.", + "type": "string", + "const": "core:tray:allow-set-icon" + }, + { + "description": "Enables the set_icon_as_template command without any pre-configured scope.", + "type": "string", + "const": "core:tray:allow-set-icon-as-template" + }, + { + "description": "Enables the set_menu command without any pre-configured scope.", + "type": "string", + "const": "core:tray:allow-set-menu" + }, + { + "description": "Enables the set_show_menu_on_left_click command without any pre-configured scope.", + "type": "string", + "const": "core:tray:allow-set-show-menu-on-left-click" + }, + { + "description": "Enables the set_temp_dir_path command without any pre-configured scope.", + "type": "string", + "const": "core:tray:allow-set-temp-dir-path" + }, + { + "description": "Enables the set_title command without any pre-configured scope.", + "type": "string", + "const": "core:tray:allow-set-title" + }, + { + "description": "Enables the set_tooltip command without any pre-configured scope.", + "type": "string", + "const": "core:tray:allow-set-tooltip" + }, + { + "description": "Enables the set_visible command without any pre-configured scope.", + "type": "string", + "const": "core:tray:allow-set-visible" + }, + { + "description": "Denies the get_by_id command without any pre-configured scope.", + "type": "string", + "const": "core:tray:deny-get-by-id" + }, + { + "description": "Denies the new command without any pre-configured scope.", + "type": "string", + "const": "core:tray:deny-new" + }, + { + "description": "Denies the remove_by_id command without any pre-configured scope.", + "type": "string", + "const": "core:tray:deny-remove-by-id" + }, + { + "description": "Denies the set_icon command without any pre-configured scope.", + "type": "string", + "const": "core:tray:deny-set-icon" + }, + { + "description": "Denies the set_icon_as_template command without any pre-configured scope.", + "type": "string", + "const": "core:tray:deny-set-icon-as-template" + }, + { + "description": "Denies the set_menu command without any pre-configured scope.", + "type": "string", + "const": "core:tray:deny-set-menu" + }, + { + "description": "Denies the set_show_menu_on_left_click command without any pre-configured scope.", + "type": "string", + "const": "core:tray:deny-set-show-menu-on-left-click" + }, + { + "description": "Denies the set_temp_dir_path command without any pre-configured scope.", + "type": "string", + "const": "core:tray:deny-set-temp-dir-path" + }, + { + "description": "Denies the set_title command without any pre-configured scope.", + "type": "string", + "const": "core:tray:deny-set-title" + }, + { + "description": "Denies the set_tooltip command without any pre-configured scope.", + "type": "string", + "const": "core:tray:deny-set-tooltip" + }, + { + "description": "Denies the set_visible command without any pre-configured scope.", + "type": "string", + "const": "core:tray:deny-set-visible" + }, + { + "description": "Default permissions for the plugin.", + "type": "string", + "const": "core:webview:default" + }, + { + "description": "Enables the clear_all_browsing_data command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-clear-all-browsing-data" + }, + { + "description": "Enables the create_webview command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-create-webview" + }, + { + "description": "Enables the create_webview_window command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-create-webview-window" + }, + { + "description": "Enables the get_all_webviews command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-get-all-webviews" + }, + { + "description": "Enables the internal_toggle_devtools command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-internal-toggle-devtools" + }, + { + "description": "Enables the print command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-print" + }, + { + "description": "Enables the reparent command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-reparent" + }, + { + "description": "Enables the set_webview_focus command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-set-webview-focus" + }, + { + "description": "Enables the set_webview_position command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-set-webview-position" + }, + { + "description": "Enables the set_webview_size command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-set-webview-size" + }, + { + "description": "Enables the set_webview_zoom command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-set-webview-zoom" + }, + { + "description": "Enables the webview_close command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-webview-close" + }, + { + "description": "Enables the webview_hide command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-webview-hide" + }, + { + "description": "Enables the webview_position command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-webview-position" + }, + { + "description": "Enables the webview_show command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-webview-show" + }, + { + "description": "Enables the webview_size command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-webview-size" + }, + { + "description": "Denies the clear_all_browsing_data command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-clear-all-browsing-data" + }, + { + "description": "Denies the create_webview command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-create-webview" + }, + { + "description": "Denies the create_webview_window command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-create-webview-window" + }, + { + "description": "Denies the get_all_webviews command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-get-all-webviews" + }, + { + "description": "Denies the internal_toggle_devtools command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-internal-toggle-devtools" + }, + { + "description": "Denies the print command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-print" + }, + { + "description": "Denies the reparent command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-reparent" + }, + { + "description": "Denies the set_webview_focus command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-set-webview-focus" + }, + { + "description": "Denies the set_webview_position command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-set-webview-position" + }, + { + "description": "Denies the set_webview_size command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-set-webview-size" + }, + { + "description": "Denies the set_webview_zoom command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-set-webview-zoom" + }, + { + "description": "Denies the webview_close command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-webview-close" + }, + { + "description": "Denies the webview_hide command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-webview-hide" + }, + { + "description": "Denies the webview_position command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-webview-position" + }, + { + "description": "Denies the webview_show command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-webview-show" + }, + { + "description": "Denies the webview_size command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-webview-size" + }, + { + "description": "Default permissions for the plugin.", + "type": "string", + "const": "core:window:default" + }, + { + "description": "Enables the available_monitors command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-available-monitors" + }, + { + "description": "Enables the center command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-center" + }, + { + "description": "Enables the close command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-close" + }, + { + "description": "Enables the create command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-create" + }, + { + "description": "Enables the current_monitor command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-current-monitor" + }, + { + "description": "Enables the cursor_position command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-cursor-position" + }, + { + "description": "Enables the destroy command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-destroy" + }, + { + "description": "Enables the get_all_windows command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-get-all-windows" + }, + { + "description": "Enables the hide command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-hide" + }, + { + "description": "Enables the inner_position command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-inner-position" + }, + { + "description": "Enables the inner_size command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-inner-size" + }, + { + "description": "Enables the internal_toggle_maximize command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-internal-toggle-maximize" + }, + { + "description": "Enables the is_closable command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-is-closable" + }, + { + "description": "Enables the is_decorated command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-is-decorated" + }, + { + "description": "Enables the is_enabled command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-is-enabled" + }, + { + "description": "Enables the is_focused command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-is-focused" + }, + { + "description": "Enables the is_fullscreen command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-is-fullscreen" + }, + { + "description": "Enables the is_maximizable command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-is-maximizable" + }, + { + "description": "Enables the is_maximized command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-is-maximized" + }, + { + "description": "Enables the is_minimizable command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-is-minimizable" + }, + { + "description": "Enables the is_minimized command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-is-minimized" + }, + { + "description": "Enables the is_resizable command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-is-resizable" + }, + { + "description": "Enables the is_visible command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-is-visible" + }, + { + "description": "Enables the maximize command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-maximize" + }, + { + "description": "Enables the minimize command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-minimize" + }, + { + "description": "Enables the monitor_from_point command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-monitor-from-point" + }, + { + "description": "Enables the outer_position command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-outer-position" + }, + { + "description": "Enables the outer_size command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-outer-size" + }, + { + "description": "Enables the primary_monitor command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-primary-monitor" + }, + { + "description": "Enables the request_user_attention command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-request-user-attention" + }, + { + "description": "Enables the scale_factor command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-scale-factor" + }, + { + "description": "Enables the set_always_on_bottom command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-always-on-bottom" + }, + { + "description": "Enables the set_always_on_top command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-always-on-top" + }, + { + "description": "Enables the set_closable command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-closable" + }, + { + "description": "Enables the set_content_protected command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-content-protected" + }, + { + "description": "Enables the set_cursor_grab command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-cursor-grab" + }, + { + "description": "Enables the set_cursor_icon command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-cursor-icon" + }, + { + "description": "Enables the set_cursor_position command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-cursor-position" + }, + { + "description": "Enables the set_cursor_visible command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-cursor-visible" + }, + { + "description": "Enables the set_decorations command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-decorations" + }, + { + "description": "Enables the set_effects command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-effects" + }, + { + "description": "Enables the set_enabled command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-enabled" + }, + { + "description": "Enables the set_focus command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-focus" + }, + { + "description": "Enables the set_fullscreen command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-fullscreen" + }, + { + "description": "Enables the set_icon command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-icon" + }, + { + "description": "Enables the set_ignore_cursor_events command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-ignore-cursor-events" + }, + { + "description": "Enables the set_max_size command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-max-size" + }, + { + "description": "Enables the set_maximizable command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-maximizable" + }, + { + "description": "Enables the set_min_size command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-min-size" + }, + { + "description": "Enables the set_minimizable command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-minimizable" + }, + { + "description": "Enables the set_position command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-position" + }, + { + "description": "Enables the set_progress_bar command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-progress-bar" + }, + { + "description": "Enables the set_resizable command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-resizable" + }, + { + "description": "Enables the set_shadow command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-shadow" + }, + { + "description": "Enables the set_size command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-size" + }, + { + "description": "Enables the set_size_constraints command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-size-constraints" + }, + { + "description": "Enables the set_skip_taskbar command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-skip-taskbar" + }, + { + "description": "Enables the set_theme command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-theme" + }, + { + "description": "Enables the set_title command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-title" + }, + { + "description": "Enables the set_title_bar_style command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-title-bar-style" + }, + { + "description": "Enables the set_visible_on_all_workspaces command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-visible-on-all-workspaces" + }, + { + "description": "Enables the show command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-show" + }, + { + "description": "Enables the start_dragging command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-start-dragging" + }, + { + "description": "Enables the start_resize_dragging command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-start-resize-dragging" + }, + { + "description": "Enables the theme command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-theme" + }, + { + "description": "Enables the title command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-title" + }, + { + "description": "Enables the toggle_maximize command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-toggle-maximize" + }, + { + "description": "Enables the unmaximize command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-unmaximize" + }, + { + "description": "Enables the unminimize command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-unminimize" + }, + { + "description": "Denies the available_monitors command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-available-monitors" + }, + { + "description": "Denies the center command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-center" + }, + { + "description": "Denies the close command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-close" + }, + { + "description": "Denies the create command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-create" + }, + { + "description": "Denies the current_monitor command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-current-monitor" + }, + { + "description": "Denies the cursor_position command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-cursor-position" + }, + { + "description": "Denies the destroy command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-destroy" + }, + { + "description": "Denies the get_all_windows command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-get-all-windows" + }, + { + "description": "Denies the hide command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-hide" + }, + { + "description": "Denies the inner_position command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-inner-position" + }, + { + "description": "Denies the inner_size command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-inner-size" + }, + { + "description": "Denies the internal_toggle_maximize command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-internal-toggle-maximize" + }, + { + "description": "Denies the is_closable command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-is-closable" + }, + { + "description": "Denies the is_decorated command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-is-decorated" + }, + { + "description": "Denies the is_enabled command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-is-enabled" + }, + { + "description": "Denies the is_focused command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-is-focused" + }, + { + "description": "Denies the is_fullscreen command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-is-fullscreen" + }, + { + "description": "Denies the is_maximizable command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-is-maximizable" + }, + { + "description": "Denies the is_maximized command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-is-maximized" + }, + { + "description": "Denies the is_minimizable command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-is-minimizable" + }, + { + "description": "Denies the is_minimized command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-is-minimized" + }, + { + "description": "Denies the is_resizable command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-is-resizable" + }, + { + "description": "Denies the is_visible command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-is-visible" + }, + { + "description": "Denies the maximize command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-maximize" + }, + { + "description": "Denies the minimize command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-minimize" + }, + { + "description": "Denies the monitor_from_point command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-monitor-from-point" + }, + { + "description": "Denies the outer_position command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-outer-position" + }, + { + "description": "Denies the outer_size command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-outer-size" + }, + { + "description": "Denies the primary_monitor command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-primary-monitor" + }, + { + "description": "Denies the request_user_attention command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-request-user-attention" + }, + { + "description": "Denies the scale_factor command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-scale-factor" + }, + { + "description": "Denies the set_always_on_bottom command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-always-on-bottom" + }, + { + "description": "Denies the set_always_on_top command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-always-on-top" + }, + { + "description": "Denies the set_closable command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-closable" + }, + { + "description": "Denies the set_content_protected command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-content-protected" + }, + { + "description": "Denies the set_cursor_grab command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-cursor-grab" + }, + { + "description": "Denies the set_cursor_icon command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-cursor-icon" + }, + { + "description": "Denies the set_cursor_position command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-cursor-position" + }, + { + "description": "Denies the set_cursor_visible command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-cursor-visible" + }, + { + "description": "Denies the set_decorations command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-decorations" + }, + { + "description": "Denies the set_effects command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-effects" + }, + { + "description": "Denies the set_enabled command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-enabled" + }, + { + "description": "Denies the set_focus command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-focus" + }, + { + "description": "Denies the set_fullscreen command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-fullscreen" + }, + { + "description": "Denies the set_icon command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-icon" + }, + { + "description": "Denies the set_ignore_cursor_events command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-ignore-cursor-events" + }, + { + "description": "Denies the set_max_size command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-max-size" + }, + { + "description": "Denies the set_maximizable command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-maximizable" + }, + { + "description": "Denies the set_min_size command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-min-size" + }, + { + "description": "Denies the set_minimizable command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-minimizable" + }, + { + "description": "Denies the set_position command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-position" + }, + { + "description": "Denies the set_progress_bar command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-progress-bar" + }, + { + "description": "Denies the set_resizable command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-resizable" + }, + { + "description": "Denies the set_shadow command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-shadow" + }, + { + "description": "Denies the set_size command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-size" + }, + { + "description": "Denies the set_size_constraints command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-size-constraints" + }, + { + "description": "Denies the set_skip_taskbar command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-skip-taskbar" + }, + { + "description": "Denies the set_theme command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-theme" + }, + { + "description": "Denies the set_title command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-title" + }, + { + "description": "Denies the set_title_bar_style command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-title-bar-style" + }, + { + "description": "Denies the set_visible_on_all_workspaces command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-visible-on-all-workspaces" + }, + { + "description": "Denies the show command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-show" + }, + { + "description": "Denies the start_dragging command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-start-dragging" + }, + { + "description": "Denies the start_resize_dragging command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-start-resize-dragging" + }, + { + "description": "Denies the theme command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-theme" + }, + { + "description": "Denies the title command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-title" + }, + { + "description": "Denies the toggle_maximize command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-toggle-maximize" + }, + { + "description": "Denies the unmaximize command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-unmaximize" + }, + { + "description": "Denies the unminimize command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-unminimize" + }, + { + "description": "This permission set configures the types of dialogs\navailable from the dialog plugin.\n\n#### Granted Permissions\n\nAll dialog types are enabled.\n\n\n", + "type": "string", + "const": "dialog:default" + }, + { + "description": "Enables the ask command without any pre-configured scope.", + "type": "string", + "const": "dialog:allow-ask" + }, + { + "description": "Enables the confirm command without any pre-configured scope.", + "type": "string", + "const": "dialog:allow-confirm" + }, + { + "description": "Enables the message command without any pre-configured scope.", + "type": "string", + "const": "dialog:allow-message" + }, + { + "description": "Enables the open command without any pre-configured scope.", + "type": "string", + "const": "dialog:allow-open" + }, + { + "description": "Enables the save command without any pre-configured scope.", + "type": "string", + "const": "dialog:allow-save" + }, + { + "description": "Denies the ask command without any pre-configured scope.", + "type": "string", + "const": "dialog:deny-ask" + }, + { + "description": "Denies the confirm command without any pre-configured scope.", + "type": "string", + "const": "dialog:deny-confirm" + }, + { + "description": "Denies the message command without any pre-configured scope.", + "type": "string", + "const": "dialog:deny-message" + }, + { + "description": "Denies the open command without any pre-configured scope.", + "type": "string", + "const": "dialog:deny-open" + }, + { + "description": "Denies the save command without any pre-configured scope.", + "type": "string", + "const": "dialog:deny-save" + }, + { + "description": "No features are enabled by default, as we believe\nthe shortcuts can be inherently dangerous and it is\napplication specific if specific shortcuts should be\nregistered or unregistered.\n", + "type": "string", + "const": "global-shortcut:default" + }, + { + "description": "Enables the is_registered command without any pre-configured scope.", + "type": "string", + "const": "global-shortcut:allow-is-registered" + }, + { + "description": "Enables the register command without any pre-configured scope.", + "type": "string", + "const": "global-shortcut:allow-register" + }, + { + "description": "Enables the register_all command without any pre-configured scope.", + "type": "string", + "const": "global-shortcut:allow-register-all" + }, + { + "description": "Enables the unregister command without any pre-configured scope.", + "type": "string", + "const": "global-shortcut:allow-unregister" + }, + { + "description": "Enables the unregister_all command without any pre-configured scope.", + "type": "string", + "const": "global-shortcut:allow-unregister-all" + }, + { + "description": "Denies the is_registered command without any pre-configured scope.", + "type": "string", + "const": "global-shortcut:deny-is-registered" + }, + { + "description": "Denies the register command without any pre-configured scope.", + "type": "string", + "const": "global-shortcut:deny-register" + }, + { + "description": "Denies the register_all command without any pre-configured scope.", + "type": "string", + "const": "global-shortcut:deny-register-all" + }, + { + "description": "Denies the unregister command without any pre-configured scope.", + "type": "string", + "const": "global-shortcut:deny-unregister" + }, + { + "description": "Denies the unregister_all command without any pre-configured scope.", + "type": "string", + "const": "global-shortcut:deny-unregister-all" + }, + { + "description": "This permission set configures which\noperating system information are available\nto gather from the frontend.\n\n#### Granted Permissions\n\nAll information except the host name are available.\n\n", + "type": "string", + "const": "os:default" + }, + { + "description": "Enables the arch command without any pre-configured scope.", + "type": "string", + "const": "os:allow-arch" + }, + { + "description": "Enables the exe_extension command without any pre-configured scope.", + "type": "string", + "const": "os:allow-exe-extension" + }, + { + "description": "Enables the family command without any pre-configured scope.", + "type": "string", + "const": "os:allow-family" + }, + { + "description": "Enables the hostname command without any pre-configured scope.", + "type": "string", + "const": "os:allow-hostname" + }, + { + "description": "Enables the locale command without any pre-configured scope.", + "type": "string", + "const": "os:allow-locale" + }, + { + "description": "Enables the os_type command without any pre-configured scope.", + "type": "string", + "const": "os:allow-os-type" + }, + { + "description": "Enables the platform command without any pre-configured scope.", + "type": "string", + "const": "os:allow-platform" + }, + { + "description": "Enables the version command without any pre-configured scope.", + "type": "string", + "const": "os:allow-version" + }, + { + "description": "Denies the arch command without any pre-configured scope.", + "type": "string", + "const": "os:deny-arch" + }, + { + "description": "Denies the exe_extension command without any pre-configured scope.", + "type": "string", + "const": "os:deny-exe-extension" + }, + { + "description": "Denies the family command without any pre-configured scope.", + "type": "string", + "const": "os:deny-family" + }, + { + "description": "Denies the hostname command without any pre-configured scope.", + "type": "string", + "const": "os:deny-hostname" + }, + { + "description": "Denies the locale command without any pre-configured scope.", + "type": "string", + "const": "os:deny-locale" + }, + { + "description": "Denies the os_type command without any pre-configured scope.", + "type": "string", + "const": "os:deny-os-type" + }, + { + "description": "Denies the platform command without any pre-configured scope.", + "type": "string", + "const": "os:deny-platform" + }, + { + "description": "Denies the version command without any pre-configured scope.", + "type": "string", + "const": "os:deny-version" + }, + { + "description": "This permission set configures which\nshell functionality is exposed by default.\n\n#### Granted Permissions\n\nIt allows to use the `open` functionality without any specific\nscope pre-configured. It will allow opening `http(s)://`,\n`tel:` and `mailto:` links.\n", + "type": "string", + "const": "shell:default" + }, + { + "description": "Enables the execute command without any pre-configured scope.", + "type": "string", + "const": "shell:allow-execute" + }, + { + "description": "Enables the kill command without any pre-configured scope.", + "type": "string", + "const": "shell:allow-kill" + }, + { + "description": "Enables the open command without any pre-configured scope.", + "type": "string", + "const": "shell:allow-open" + }, + { + "description": "Enables the spawn command without any pre-configured scope.", + "type": "string", + "const": "shell:allow-spawn" + }, + { + "description": "Enables the stdin_write command without any pre-configured scope.", + "type": "string", + "const": "shell:allow-stdin-write" + }, + { + "description": "Denies the execute command without any pre-configured scope.", + "type": "string", + "const": "shell:deny-execute" + }, + { + "description": "Denies the kill command without any pre-configured scope.", + "type": "string", + "const": "shell:deny-kill" + }, + { + "description": "Denies the open command without any pre-configured scope.", + "type": "string", + "const": "shell:deny-open" + }, + { + "description": "Denies the spawn command without any pre-configured scope.", + "type": "string", + "const": "shell:deny-spawn" + }, + { + "description": "Denies the stdin_write command without any pre-configured scope.", + "type": "string", + "const": "shell:deny-stdin-write" + } + ] + }, + "Value": { + "description": "All supported ACL values.", + "anyOf": [ + { + "description": "Represents a null JSON value.", + "type": "null" + }, + { + "description": "Represents a [`bool`].", + "type": "boolean" + }, + { + "description": "Represents a valid ACL [`Number`].", + "allOf": [ + { + "$ref": "#/definitions/Number" + } + ] + }, + { + "description": "Represents a [`String`].", + "type": "string" + }, + { + "description": "Represents a list of other [`Value`]s.", + "type": "array", + "items": { + "$ref": "#/definitions/Value" + } + }, + { + "description": "Represents a map of [`String`] keys to [`Value`]s.", + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/Value" + } + } + ] + }, + "Number": { + "description": "A valid ACL number.", + "anyOf": [ + { + "description": "Represents an [`i64`].", + "type": "integer", + "format": "int64" + }, + { + "description": "Represents a [`f64`].", + "type": "number", + "format": "double" + } + ] + }, + "Target": { + "description": "Platform target.", + "oneOf": [ + { + "description": "MacOS.", + "type": "string", + "enum": [ + "macOS" + ] + }, + { + "description": "Windows.", + "type": "string", + "enum": [ + "windows" + ] + }, + { + "description": "Linux.", + "type": "string", + "enum": [ + "linux" + ] + }, + { + "description": "Android.", + "type": "string", + "enum": [ + "android" + ] + }, + { + "description": "iOS.", + "type": "string", + "enum": [ + "iOS" + ] + } + ] + }, + "ShellScopeEntryAllowedArg": { + "description": "A command argument allowed to be executed by the webview API.", + "anyOf": [ + { + "description": "A non-configurable argument that is passed to the command in the order it was specified.", + "type": "string" + }, + { + "description": "A variable that is set while calling the command from the webview API.", + "type": "object", + "required": [ + "validator" + ], + "properties": { + "raw": { + "description": "Marks the validator as a raw regex, meaning the plugin should not make any modification at runtime.\n\nThis means the regex will not match on the entire string by default, which might be exploited if your regex allow unexpected input to be considered valid. When using this option, make sure your regex is correct.", + "default": false, + "type": "boolean" + }, + "validator": { + "description": "[regex] validator to require passed values to conform to an expected input.\n\nThis will require the argument value passed to this variable to match the `validator` regex before it will be executed.\n\nThe regex string is by default surrounded by `^...$` to match the full string. For example the `https?://\\w+` regex would be registered as `^https?://\\w+$`.\n\n[regex]: ", + "type": "string" + } + }, + "additionalProperties": false + } + ] + }, + "ShellScopeEntryAllowedArgs": { + "description": "A set of command arguments allowed to be executed by the webview API.\n\nA value of `true` will allow any arguments to be passed to the command. `false` will disable all arguments. A list of [`ShellScopeEntryAllowedArg`] will set those arguments as the only valid arguments to be passed to the attached command configuration.", + "anyOf": [ + { + "description": "Use a simple boolean to allow all or disable all arguments to this command configuration.", + "type": "boolean" + }, + { + "description": "A specific set of [`ShellScopeEntryAllowedArg`] that are valid to call for the command configuration.", + "type": "array", + "items": { + "$ref": "#/definitions/ShellScopeEntryAllowedArg" + } + } + ] + } + } +} \ No newline at end of file diff --git a/src-tauri/gen/schemas/linux-schema.json b/src-tauri/gen/schemas/linux-schema.json new file mode 100644 index 0000000..869ffa4 --- /dev/null +++ b/src-tauri/gen/schemas/linux-schema.json @@ -0,0 +1,2249 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "CapabilityFile", + "description": "Capability formats accepted in a capability file.", + "anyOf": [ + { + "description": "A single capability.", + "allOf": [ + { + "$ref": "#/definitions/Capability" + } + ] + }, + { + "description": "A list of capabilities.", + "type": "array", + "items": { + "$ref": "#/definitions/Capability" + } + }, + { + "description": "A list of capabilities.", + "type": "object", + "required": [ + "capabilities" + ], + "properties": { + "capabilities": { + "description": "The list of capabilities.", + "type": "array", + "items": { + "$ref": "#/definitions/Capability" + } + } + } + } + ], + "definitions": { + "Capability": { + "description": "A grouping and boundary mechanism developers can use to isolate access to the IPC layer.\n\nIt controls application windows fine grained access to the Tauri core, application, or plugin commands. If a window is not matching any capability then it has no access to the IPC layer at all.\n\nThis can be done to create groups of windows, based on their required system access, which can reduce impact of frontend vulnerabilities in less privileged windows. Windows can be added to a capability by exact name (e.g. `main-window`) or glob patterns like `*` or `admin-*`. A Window can have none, one, or multiple associated capabilities.\n\n## Example\n\n```json { \"identifier\": \"main-user-files-write\", \"description\": \"This capability allows the `main` window on macOS and Windows access to `filesystem` write related commands and `dialog` commands to enable programatic access to files selected by the user.\", \"windows\": [ \"main\" ], \"permissions\": [ \"core:default\", \"dialog:open\", { \"identifier\": \"fs:allow-write-text-file\", \"allow\": [{ \"path\": \"$HOME/test.txt\" }] }, ], \"platforms\": [\"macOS\",\"windows\"] } ```", + "type": "object", + "required": [ + "identifier", + "permissions" + ], + "properties": { + "identifier": { + "description": "Identifier of the capability.\n\n## Example\n\n`main-user-files-write`", + "type": "string" + }, + "description": { + "description": "Description of what the capability is intended to allow on associated windows.\n\nIt should contain a description of what the grouped permissions should allow.\n\n## Example\n\nThis capability allows the `main` window access to `filesystem` write related commands and `dialog` commands to enable programatic access to files selected by the user.", + "default": "", + "type": "string" + }, + "remote": { + "description": "Configure remote URLs that can use the capability permissions.\n\nThis setting is optional and defaults to not being set, as our default use case is that the content is served from our local application.\n\n:::caution Make sure you understand the security implications of providing remote sources with local system access. :::\n\n## Example\n\n```json { \"urls\": [\"https://*.mydomain.dev\"] } ```", + "anyOf": [ + { + "$ref": "#/definitions/CapabilityRemote" + }, + { + "type": "null" + } + ] + }, + "local": { + "description": "Whether this capability is enabled for local app URLs or not. Defaults to `true`.", + "default": true, + "type": "boolean" + }, + "windows": { + "description": "List of windows that are affected by this capability. Can be a glob pattern.\n\nOn multiwebview windows, prefer [`Self::webviews`] for a fine grained access control.\n\n## Example\n\n`[\"main\"]`", + "type": "array", + "items": { + "type": "string" + } + }, + "webviews": { + "description": "List of webviews that are affected by this capability. Can be a glob pattern.\n\nThis is only required when using on multiwebview contexts, by default all child webviews of a window that matches [`Self::windows`] are linked.\n\n## Example\n\n`[\"sub-webview-one\", \"sub-webview-two\"]`", + "type": "array", + "items": { + "type": "string" + } + }, + "permissions": { + "description": "List of permissions attached to this capability.\n\nMust include the plugin name as prefix in the form of `${plugin-name}:${permission-name}`. For commands directly implemented in the application itself only `${permission-name}` is required.\n\n## Example\n\n```json [ \"core:default\", \"shell:allow-open\", \"dialog:open\", { \"identifier\": \"fs:allow-write-text-file\", \"allow\": [{ \"path\": \"$HOME/test.txt\" }] } ] ```", + "type": "array", + "items": { + "$ref": "#/definitions/PermissionEntry" + }, + "uniqueItems": true + }, + "platforms": { + "description": "Limit which target platforms this capability applies to.\n\nBy default all platforms are targeted.\n\n## Example\n\n`[\"macOS\",\"windows\"]`", + "type": [ + "array", + "null" + ], + "items": { + "$ref": "#/definitions/Target" + } + } + } + }, + "CapabilityRemote": { + "description": "Configuration for remote URLs that are associated with the capability.", + "type": "object", + "required": [ + "urls" + ], + "properties": { + "urls": { + "description": "Remote domains this capability refers to using the [URLPattern standard](https://urlpattern.spec.whatwg.org/).\n\n## Examples\n\n- \"https://*.mydomain.dev\": allows subdomains of mydomain.dev - \"https://mydomain.dev/api/*\": allows any subpath of mydomain.dev/api", + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "PermissionEntry": { + "description": "An entry for a permission value in a [`Capability`] can be either a raw permission [`Identifier`] or an object that references a permission and extends its scope.", + "anyOf": [ + { + "description": "Reference a permission or permission set by identifier.", + "allOf": [ + { + "$ref": "#/definitions/Identifier" + } + ] + }, + { + "description": "Reference a permission or permission set by identifier and extends its scope.", + "type": "object", + "allOf": [ + { + "if": { + "properties": { + "identifier": { + "anyOf": [ + { + "description": "This permission set configures which\nshell functionality is exposed by default.\n\n#### Granted Permissions\n\nIt allows to use the `open` functionality without any specific\nscope pre-configured. It will allow opening `http(s)://`,\n`tel:` and `mailto:` links.\n", + "type": "string", + "const": "shell:default" + }, + { + "description": "Enables the execute command without any pre-configured scope.", + "type": "string", + "const": "shell:allow-execute" + }, + { + "description": "Enables the kill command without any pre-configured scope.", + "type": "string", + "const": "shell:allow-kill" + }, + { + "description": "Enables the open command without any pre-configured scope.", + "type": "string", + "const": "shell:allow-open" + }, + { + "description": "Enables the spawn command without any pre-configured scope.", + "type": "string", + "const": "shell:allow-spawn" + }, + { + "description": "Enables the stdin_write command without any pre-configured scope.", + "type": "string", + "const": "shell:allow-stdin-write" + }, + { + "description": "Denies the execute command without any pre-configured scope.", + "type": "string", + "const": "shell:deny-execute" + }, + { + "description": "Denies the kill command without any pre-configured scope.", + "type": "string", + "const": "shell:deny-kill" + }, + { + "description": "Denies the open command without any pre-configured scope.", + "type": "string", + "const": "shell:deny-open" + }, + { + "description": "Denies the spawn command without any pre-configured scope.", + "type": "string", + "const": "shell:deny-spawn" + }, + { + "description": "Denies the stdin_write command without any pre-configured scope.", + "type": "string", + "const": "shell:deny-stdin-write" + } + ] + } + } + }, + "then": { + "properties": { + "allow": { + "items": { + "title": "ShellScopeEntry", + "description": "Shell scope entry.", + "anyOf": [ + { + "type": "object", + "required": [ + "cmd", + "name" + ], + "properties": { + "args": { + "description": "The allowed arguments for the command execution.", + "allOf": [ + { + "$ref": "#/definitions/ShellScopeEntryAllowedArgs" + } + ] + }, + "cmd": { + "description": "The command name. It can start with a variable that resolves to a system base directory. The variables are: `$AUDIO`, `$CACHE`, `$CONFIG`, `$DATA`, `$LOCALDATA`, `$DESKTOP`, `$DOCUMENT`, `$DOWNLOAD`, `$EXE`, `$FONT`, `$HOME`, `$PICTURE`, `$PUBLIC`, `$RUNTIME`, `$TEMPLATE`, `$VIDEO`, `$RESOURCE`, `$LOG`, `$TEMP`, `$APPCONFIG`, `$APPDATA`, `$APPLOCALDATA`, `$APPCACHE`, `$APPLOG`.", + "type": "string" + }, + "name": { + "description": "The name for this allowed shell command configuration.\n\nThis name will be used inside of the webview API to call this command along with any specified arguments.", + "type": "string" + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "name", + "sidecar" + ], + "properties": { + "args": { + "description": "The allowed arguments for the command execution.", + "allOf": [ + { + "$ref": "#/definitions/ShellScopeEntryAllowedArgs" + } + ] + }, + "name": { + "description": "The name for this allowed shell command configuration.\n\nThis name will be used inside of the webview API to call this command along with any specified arguments.", + "type": "string" + }, + "sidecar": { + "description": "If this command is a sidecar command.", + "type": "boolean" + } + }, + "additionalProperties": false + } + ] + } + }, + "deny": { + "items": { + "title": "ShellScopeEntry", + "description": "Shell scope entry.", + "anyOf": [ + { + "type": "object", + "required": [ + "cmd", + "name" + ], + "properties": { + "args": { + "description": "The allowed arguments for the command execution.", + "allOf": [ + { + "$ref": "#/definitions/ShellScopeEntryAllowedArgs" + } + ] + }, + "cmd": { + "description": "The command name. It can start with a variable that resolves to a system base directory. The variables are: `$AUDIO`, `$CACHE`, `$CONFIG`, `$DATA`, `$LOCALDATA`, `$DESKTOP`, `$DOCUMENT`, `$DOWNLOAD`, `$EXE`, `$FONT`, `$HOME`, `$PICTURE`, `$PUBLIC`, `$RUNTIME`, `$TEMPLATE`, `$VIDEO`, `$RESOURCE`, `$LOG`, `$TEMP`, `$APPCONFIG`, `$APPDATA`, `$APPLOCALDATA`, `$APPCACHE`, `$APPLOG`.", + "type": "string" + }, + "name": { + "description": "The name for this allowed shell command configuration.\n\nThis name will be used inside of the webview API to call this command along with any specified arguments.", + "type": "string" + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "name", + "sidecar" + ], + "properties": { + "args": { + "description": "The allowed arguments for the command execution.", + "allOf": [ + { + "$ref": "#/definitions/ShellScopeEntryAllowedArgs" + } + ] + }, + "name": { + "description": "The name for this allowed shell command configuration.\n\nThis name will be used inside of the webview API to call this command along with any specified arguments.", + "type": "string" + }, + "sidecar": { + "description": "If this command is a sidecar command.", + "type": "boolean" + } + }, + "additionalProperties": false + } + ] + } + } + } + }, + "properties": { + "identifier": { + "description": "Identifier of the permission or permission set.", + "allOf": [ + { + "$ref": "#/definitions/Identifier" + } + ] + } + } + }, + { + "properties": { + "identifier": { + "description": "Identifier of the permission or permission set.", + "allOf": [ + { + "$ref": "#/definitions/Identifier" + } + ] + }, + "allow": { + "description": "Data that defines what is allowed by the scope.", + "type": [ + "array", + "null" + ], + "items": { + "$ref": "#/definitions/Value" + } + }, + "deny": { + "description": "Data that defines what is denied by the scope. This should be prioritized by validation logic.", + "type": [ + "array", + "null" + ], + "items": { + "$ref": "#/definitions/Value" + } + } + } + } + ], + "required": [ + "identifier" + ] + } + ] + }, + "Identifier": { + "description": "Permission identifier", + "oneOf": [ + { + "description": "Default core plugins set which includes:\n- 'core:path:default'\n- 'core:event:default'\n- 'core:window:default'\n- 'core:webview:default'\n- 'core:app:default'\n- 'core:image:default'\n- 'core:resources:default'\n- 'core:menu:default'\n- 'core:tray:default'\n", + "type": "string", + "const": "core:default" + }, + { + "description": "Default permissions for the plugin.", + "type": "string", + "const": "core:app:default" + }, + { + "description": "Enables the app_hide command without any pre-configured scope.", + "type": "string", + "const": "core:app:allow-app-hide" + }, + { + "description": "Enables the app_show command without any pre-configured scope.", + "type": "string", + "const": "core:app:allow-app-show" + }, + { + "description": "Enables the default_window_icon command without any pre-configured scope.", + "type": "string", + "const": "core:app:allow-default-window-icon" + }, + { + "description": "Enables the name command without any pre-configured scope.", + "type": "string", + "const": "core:app:allow-name" + }, + { + "description": "Enables the set_app_theme command without any pre-configured scope.", + "type": "string", + "const": "core:app:allow-set-app-theme" + }, + { + "description": "Enables the tauri_version command without any pre-configured scope.", + "type": "string", + "const": "core:app:allow-tauri-version" + }, + { + "description": "Enables the version command without any pre-configured scope.", + "type": "string", + "const": "core:app:allow-version" + }, + { + "description": "Denies the app_hide command without any pre-configured scope.", + "type": "string", + "const": "core:app:deny-app-hide" + }, + { + "description": "Denies the app_show command without any pre-configured scope.", + "type": "string", + "const": "core:app:deny-app-show" + }, + { + "description": "Denies the default_window_icon command without any pre-configured scope.", + "type": "string", + "const": "core:app:deny-default-window-icon" + }, + { + "description": "Denies the name command without any pre-configured scope.", + "type": "string", + "const": "core:app:deny-name" + }, + { + "description": "Denies the set_app_theme command without any pre-configured scope.", + "type": "string", + "const": "core:app:deny-set-app-theme" + }, + { + "description": "Denies the tauri_version command without any pre-configured scope.", + "type": "string", + "const": "core:app:deny-tauri-version" + }, + { + "description": "Denies the version command without any pre-configured scope.", + "type": "string", + "const": "core:app:deny-version" + }, + { + "description": "Default permissions for the plugin.", + "type": "string", + "const": "core:event:default" + }, + { + "description": "Enables the emit command without any pre-configured scope.", + "type": "string", + "const": "core:event:allow-emit" + }, + { + "description": "Enables the emit_to command without any pre-configured scope.", + "type": "string", + "const": "core:event:allow-emit-to" + }, + { + "description": "Enables the listen command without any pre-configured scope.", + "type": "string", + "const": "core:event:allow-listen" + }, + { + "description": "Enables the unlisten command without any pre-configured scope.", + "type": "string", + "const": "core:event:allow-unlisten" + }, + { + "description": "Denies the emit command without any pre-configured scope.", + "type": "string", + "const": "core:event:deny-emit" + }, + { + "description": "Denies the emit_to command without any pre-configured scope.", + "type": "string", + "const": "core:event:deny-emit-to" + }, + { + "description": "Denies the listen command without any pre-configured scope.", + "type": "string", + "const": "core:event:deny-listen" + }, + { + "description": "Denies the unlisten command without any pre-configured scope.", + "type": "string", + "const": "core:event:deny-unlisten" + }, + { + "description": "Default permissions for the plugin.", + "type": "string", + "const": "core:image:default" + }, + { + "description": "Enables the from_bytes command without any pre-configured scope.", + "type": "string", + "const": "core:image:allow-from-bytes" + }, + { + "description": "Enables the from_path command without any pre-configured scope.", + "type": "string", + "const": "core:image:allow-from-path" + }, + { + "description": "Enables the new command without any pre-configured scope.", + "type": "string", + "const": "core:image:allow-new" + }, + { + "description": "Enables the rgba command without any pre-configured scope.", + "type": "string", + "const": "core:image:allow-rgba" + }, + { + "description": "Enables the size command without any pre-configured scope.", + "type": "string", + "const": "core:image:allow-size" + }, + { + "description": "Denies the from_bytes command without any pre-configured scope.", + "type": "string", + "const": "core:image:deny-from-bytes" + }, + { + "description": "Denies the from_path command without any pre-configured scope.", + "type": "string", + "const": "core:image:deny-from-path" + }, + { + "description": "Denies the new command without any pre-configured scope.", + "type": "string", + "const": "core:image:deny-new" + }, + { + "description": "Denies the rgba command without any pre-configured scope.", + "type": "string", + "const": "core:image:deny-rgba" + }, + { + "description": "Denies the size command without any pre-configured scope.", + "type": "string", + "const": "core:image:deny-size" + }, + { + "description": "Default permissions for the plugin.", + "type": "string", + "const": "core:menu:default" + }, + { + "description": "Enables the append command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-append" + }, + { + "description": "Enables the create_default command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-create-default" + }, + { + "description": "Enables the get command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-get" + }, + { + "description": "Enables the insert command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-insert" + }, + { + "description": "Enables the is_checked command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-is-checked" + }, + { + "description": "Enables the is_enabled command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-is-enabled" + }, + { + "description": "Enables the items command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-items" + }, + { + "description": "Enables the new command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-new" + }, + { + "description": "Enables the popup command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-popup" + }, + { + "description": "Enables the prepend command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-prepend" + }, + { + "description": "Enables the remove command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-remove" + }, + { + "description": "Enables the remove_at command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-remove-at" + }, + { + "description": "Enables the set_accelerator command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-set-accelerator" + }, + { + "description": "Enables the set_as_app_menu command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-set-as-app-menu" + }, + { + "description": "Enables the set_as_help_menu_for_nsapp command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-set-as-help-menu-for-nsapp" + }, + { + "description": "Enables the set_as_window_menu command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-set-as-window-menu" + }, + { + "description": "Enables the set_as_windows_menu_for_nsapp command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-set-as-windows-menu-for-nsapp" + }, + { + "description": "Enables the set_checked command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-set-checked" + }, + { + "description": "Enables the set_enabled command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-set-enabled" + }, + { + "description": "Enables the set_icon command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-set-icon" + }, + { + "description": "Enables the set_text command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-set-text" + }, + { + "description": "Enables the text command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-text" + }, + { + "description": "Denies the append command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-append" + }, + { + "description": "Denies the create_default command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-create-default" + }, + { + "description": "Denies the get command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-get" + }, + { + "description": "Denies the insert command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-insert" + }, + { + "description": "Denies the is_checked command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-is-checked" + }, + { + "description": "Denies the is_enabled command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-is-enabled" + }, + { + "description": "Denies the items command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-items" + }, + { + "description": "Denies the new command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-new" + }, + { + "description": "Denies the popup command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-popup" + }, + { + "description": "Denies the prepend command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-prepend" + }, + { + "description": "Denies the remove command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-remove" + }, + { + "description": "Denies the remove_at command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-remove-at" + }, + { + "description": "Denies the set_accelerator command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-set-accelerator" + }, + { + "description": "Denies the set_as_app_menu command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-set-as-app-menu" + }, + { + "description": "Denies the set_as_help_menu_for_nsapp command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-set-as-help-menu-for-nsapp" + }, + { + "description": "Denies the set_as_window_menu command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-set-as-window-menu" + }, + { + "description": "Denies the set_as_windows_menu_for_nsapp command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-set-as-windows-menu-for-nsapp" + }, + { + "description": "Denies the set_checked command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-set-checked" + }, + { + "description": "Denies the set_enabled command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-set-enabled" + }, + { + "description": "Denies the set_icon command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-set-icon" + }, + { + "description": "Denies the set_text command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-set-text" + }, + { + "description": "Denies the text command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-text" + }, + { + "description": "Default permissions for the plugin.", + "type": "string", + "const": "core:path:default" + }, + { + "description": "Enables the basename command without any pre-configured scope.", + "type": "string", + "const": "core:path:allow-basename" + }, + { + "description": "Enables the dirname command without any pre-configured scope.", + "type": "string", + "const": "core:path:allow-dirname" + }, + { + "description": "Enables the extname command without any pre-configured scope.", + "type": "string", + "const": "core:path:allow-extname" + }, + { + "description": "Enables the is_absolute command without any pre-configured scope.", + "type": "string", + "const": "core:path:allow-is-absolute" + }, + { + "description": "Enables the join command without any pre-configured scope.", + "type": "string", + "const": "core:path:allow-join" + }, + { + "description": "Enables the normalize command without any pre-configured scope.", + "type": "string", + "const": "core:path:allow-normalize" + }, + { + "description": "Enables the resolve command without any pre-configured scope.", + "type": "string", + "const": "core:path:allow-resolve" + }, + { + "description": "Enables the resolve_directory command without any pre-configured scope.", + "type": "string", + "const": "core:path:allow-resolve-directory" + }, + { + "description": "Denies the basename command without any pre-configured scope.", + "type": "string", + "const": "core:path:deny-basename" + }, + { + "description": "Denies the dirname command without any pre-configured scope.", + "type": "string", + "const": "core:path:deny-dirname" + }, + { + "description": "Denies the extname command without any pre-configured scope.", + "type": "string", + "const": "core:path:deny-extname" + }, + { + "description": "Denies the is_absolute command without any pre-configured scope.", + "type": "string", + "const": "core:path:deny-is-absolute" + }, + { + "description": "Denies the join command without any pre-configured scope.", + "type": "string", + "const": "core:path:deny-join" + }, + { + "description": "Denies the normalize command without any pre-configured scope.", + "type": "string", + "const": "core:path:deny-normalize" + }, + { + "description": "Denies the resolve command without any pre-configured scope.", + "type": "string", + "const": "core:path:deny-resolve" + }, + { + "description": "Denies the resolve_directory command without any pre-configured scope.", + "type": "string", + "const": "core:path:deny-resolve-directory" + }, + { + "description": "Default permissions for the plugin.", + "type": "string", + "const": "core:resources:default" + }, + { + "description": "Enables the close command without any pre-configured scope.", + "type": "string", + "const": "core:resources:allow-close" + }, + { + "description": "Denies the close command without any pre-configured scope.", + "type": "string", + "const": "core:resources:deny-close" + }, + { + "description": "Default permissions for the plugin.", + "type": "string", + "const": "core:tray:default" + }, + { + "description": "Enables the get_by_id command without any pre-configured scope.", + "type": "string", + "const": "core:tray:allow-get-by-id" + }, + { + "description": "Enables the new command without any pre-configured scope.", + "type": "string", + "const": "core:tray:allow-new" + }, + { + "description": "Enables the remove_by_id command without any pre-configured scope.", + "type": "string", + "const": "core:tray:allow-remove-by-id" + }, + { + "description": "Enables the set_icon command without any pre-configured scope.", + "type": "string", + "const": "core:tray:allow-set-icon" + }, + { + "description": "Enables the set_icon_as_template command without any pre-configured scope.", + "type": "string", + "const": "core:tray:allow-set-icon-as-template" + }, + { + "description": "Enables the set_menu command without any pre-configured scope.", + "type": "string", + "const": "core:tray:allow-set-menu" + }, + { + "description": "Enables the set_show_menu_on_left_click command without any pre-configured scope.", + "type": "string", + "const": "core:tray:allow-set-show-menu-on-left-click" + }, + { + "description": "Enables the set_temp_dir_path command without any pre-configured scope.", + "type": "string", + "const": "core:tray:allow-set-temp-dir-path" + }, + { + "description": "Enables the set_title command without any pre-configured scope.", + "type": "string", + "const": "core:tray:allow-set-title" + }, + { + "description": "Enables the set_tooltip command without any pre-configured scope.", + "type": "string", + "const": "core:tray:allow-set-tooltip" + }, + { + "description": "Enables the set_visible command without any pre-configured scope.", + "type": "string", + "const": "core:tray:allow-set-visible" + }, + { + "description": "Denies the get_by_id command without any pre-configured scope.", + "type": "string", + "const": "core:tray:deny-get-by-id" + }, + { + "description": "Denies the new command without any pre-configured scope.", + "type": "string", + "const": "core:tray:deny-new" + }, + { + "description": "Denies the remove_by_id command without any pre-configured scope.", + "type": "string", + "const": "core:tray:deny-remove-by-id" + }, + { + "description": "Denies the set_icon command without any pre-configured scope.", + "type": "string", + "const": "core:tray:deny-set-icon" + }, + { + "description": "Denies the set_icon_as_template command without any pre-configured scope.", + "type": "string", + "const": "core:tray:deny-set-icon-as-template" + }, + { + "description": "Denies the set_menu command without any pre-configured scope.", + "type": "string", + "const": "core:tray:deny-set-menu" + }, + { + "description": "Denies the set_show_menu_on_left_click command without any pre-configured scope.", + "type": "string", + "const": "core:tray:deny-set-show-menu-on-left-click" + }, + { + "description": "Denies the set_temp_dir_path command without any pre-configured scope.", + "type": "string", + "const": "core:tray:deny-set-temp-dir-path" + }, + { + "description": "Denies the set_title command without any pre-configured scope.", + "type": "string", + "const": "core:tray:deny-set-title" + }, + { + "description": "Denies the set_tooltip command without any pre-configured scope.", + "type": "string", + "const": "core:tray:deny-set-tooltip" + }, + { + "description": "Denies the set_visible command without any pre-configured scope.", + "type": "string", + "const": "core:tray:deny-set-visible" + }, + { + "description": "Default permissions for the plugin.", + "type": "string", + "const": "core:webview:default" + }, + { + "description": "Enables the clear_all_browsing_data command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-clear-all-browsing-data" + }, + { + "description": "Enables the create_webview command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-create-webview" + }, + { + "description": "Enables the create_webview_window command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-create-webview-window" + }, + { + "description": "Enables the get_all_webviews command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-get-all-webviews" + }, + { + "description": "Enables the internal_toggle_devtools command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-internal-toggle-devtools" + }, + { + "description": "Enables the print command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-print" + }, + { + "description": "Enables the reparent command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-reparent" + }, + { + "description": "Enables the set_webview_focus command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-set-webview-focus" + }, + { + "description": "Enables the set_webview_position command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-set-webview-position" + }, + { + "description": "Enables the set_webview_size command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-set-webview-size" + }, + { + "description": "Enables the set_webview_zoom command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-set-webview-zoom" + }, + { + "description": "Enables the webview_close command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-webview-close" + }, + { + "description": "Enables the webview_hide command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-webview-hide" + }, + { + "description": "Enables the webview_position command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-webview-position" + }, + { + "description": "Enables the webview_show command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-webview-show" + }, + { + "description": "Enables the webview_size command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-webview-size" + }, + { + "description": "Denies the clear_all_browsing_data command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-clear-all-browsing-data" + }, + { + "description": "Denies the create_webview command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-create-webview" + }, + { + "description": "Denies the create_webview_window command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-create-webview-window" + }, + { + "description": "Denies the get_all_webviews command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-get-all-webviews" + }, + { + "description": "Denies the internal_toggle_devtools command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-internal-toggle-devtools" + }, + { + "description": "Denies the print command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-print" + }, + { + "description": "Denies the reparent command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-reparent" + }, + { + "description": "Denies the set_webview_focus command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-set-webview-focus" + }, + { + "description": "Denies the set_webview_position command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-set-webview-position" + }, + { + "description": "Denies the set_webview_size command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-set-webview-size" + }, + { + "description": "Denies the set_webview_zoom command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-set-webview-zoom" + }, + { + "description": "Denies the webview_close command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-webview-close" + }, + { + "description": "Denies the webview_hide command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-webview-hide" + }, + { + "description": "Denies the webview_position command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-webview-position" + }, + { + "description": "Denies the webview_show command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-webview-show" + }, + { + "description": "Denies the webview_size command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-webview-size" + }, + { + "description": "Default permissions for the plugin.", + "type": "string", + "const": "core:window:default" + }, + { + "description": "Enables the available_monitors command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-available-monitors" + }, + { + "description": "Enables the center command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-center" + }, + { + "description": "Enables the close command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-close" + }, + { + "description": "Enables the create command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-create" + }, + { + "description": "Enables the current_monitor command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-current-monitor" + }, + { + "description": "Enables the cursor_position command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-cursor-position" + }, + { + "description": "Enables the destroy command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-destroy" + }, + { + "description": "Enables the get_all_windows command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-get-all-windows" + }, + { + "description": "Enables the hide command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-hide" + }, + { + "description": "Enables the inner_position command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-inner-position" + }, + { + "description": "Enables the inner_size command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-inner-size" + }, + { + "description": "Enables the internal_toggle_maximize command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-internal-toggle-maximize" + }, + { + "description": "Enables the is_closable command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-is-closable" + }, + { + "description": "Enables the is_decorated command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-is-decorated" + }, + { + "description": "Enables the is_enabled command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-is-enabled" + }, + { + "description": "Enables the is_focused command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-is-focused" + }, + { + "description": "Enables the is_fullscreen command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-is-fullscreen" + }, + { + "description": "Enables the is_maximizable command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-is-maximizable" + }, + { + "description": "Enables the is_maximized command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-is-maximized" + }, + { + "description": "Enables the is_minimizable command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-is-minimizable" + }, + { + "description": "Enables the is_minimized command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-is-minimized" + }, + { + "description": "Enables the is_resizable command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-is-resizable" + }, + { + "description": "Enables the is_visible command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-is-visible" + }, + { + "description": "Enables the maximize command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-maximize" + }, + { + "description": "Enables the minimize command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-minimize" + }, + { + "description": "Enables the monitor_from_point command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-monitor-from-point" + }, + { + "description": "Enables the outer_position command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-outer-position" + }, + { + "description": "Enables the outer_size command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-outer-size" + }, + { + "description": "Enables the primary_monitor command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-primary-monitor" + }, + { + "description": "Enables the request_user_attention command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-request-user-attention" + }, + { + "description": "Enables the scale_factor command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-scale-factor" + }, + { + "description": "Enables the set_always_on_bottom command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-always-on-bottom" + }, + { + "description": "Enables the set_always_on_top command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-always-on-top" + }, + { + "description": "Enables the set_closable command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-closable" + }, + { + "description": "Enables the set_content_protected command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-content-protected" + }, + { + "description": "Enables the set_cursor_grab command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-cursor-grab" + }, + { + "description": "Enables the set_cursor_icon command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-cursor-icon" + }, + { + "description": "Enables the set_cursor_position command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-cursor-position" + }, + { + "description": "Enables the set_cursor_visible command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-cursor-visible" + }, + { + "description": "Enables the set_decorations command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-decorations" + }, + { + "description": "Enables the set_effects command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-effects" + }, + { + "description": "Enables the set_enabled command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-enabled" + }, + { + "description": "Enables the set_focus command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-focus" + }, + { + "description": "Enables the set_fullscreen command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-fullscreen" + }, + { + "description": "Enables the set_icon command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-icon" + }, + { + "description": "Enables the set_ignore_cursor_events command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-ignore-cursor-events" + }, + { + "description": "Enables the set_max_size command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-max-size" + }, + { + "description": "Enables the set_maximizable command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-maximizable" + }, + { + "description": "Enables the set_min_size command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-min-size" + }, + { + "description": "Enables the set_minimizable command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-minimizable" + }, + { + "description": "Enables the set_position command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-position" + }, + { + "description": "Enables the set_progress_bar command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-progress-bar" + }, + { + "description": "Enables the set_resizable command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-resizable" + }, + { + "description": "Enables the set_shadow command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-shadow" + }, + { + "description": "Enables the set_size command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-size" + }, + { + "description": "Enables the set_size_constraints command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-size-constraints" + }, + { + "description": "Enables the set_skip_taskbar command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-skip-taskbar" + }, + { + "description": "Enables the set_theme command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-theme" + }, + { + "description": "Enables the set_title command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-title" + }, + { + "description": "Enables the set_title_bar_style command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-title-bar-style" + }, + { + "description": "Enables the set_visible_on_all_workspaces command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-visible-on-all-workspaces" + }, + { + "description": "Enables the show command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-show" + }, + { + "description": "Enables the start_dragging command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-start-dragging" + }, + { + "description": "Enables the start_resize_dragging command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-start-resize-dragging" + }, + { + "description": "Enables the theme command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-theme" + }, + { + "description": "Enables the title command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-title" + }, + { + "description": "Enables the toggle_maximize command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-toggle-maximize" + }, + { + "description": "Enables the unmaximize command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-unmaximize" + }, + { + "description": "Enables the unminimize command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-unminimize" + }, + { + "description": "Denies the available_monitors command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-available-monitors" + }, + { + "description": "Denies the center command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-center" + }, + { + "description": "Denies the close command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-close" + }, + { + "description": "Denies the create command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-create" + }, + { + "description": "Denies the current_monitor command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-current-monitor" + }, + { + "description": "Denies the cursor_position command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-cursor-position" + }, + { + "description": "Denies the destroy command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-destroy" + }, + { + "description": "Denies the get_all_windows command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-get-all-windows" + }, + { + "description": "Denies the hide command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-hide" + }, + { + "description": "Denies the inner_position command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-inner-position" + }, + { + "description": "Denies the inner_size command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-inner-size" + }, + { + "description": "Denies the internal_toggle_maximize command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-internal-toggle-maximize" + }, + { + "description": "Denies the is_closable command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-is-closable" + }, + { + "description": "Denies the is_decorated command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-is-decorated" + }, + { + "description": "Denies the is_enabled command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-is-enabled" + }, + { + "description": "Denies the is_focused command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-is-focused" + }, + { + "description": "Denies the is_fullscreen command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-is-fullscreen" + }, + { + "description": "Denies the is_maximizable command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-is-maximizable" + }, + { + "description": "Denies the is_maximized command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-is-maximized" + }, + { + "description": "Denies the is_minimizable command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-is-minimizable" + }, + { + "description": "Denies the is_minimized command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-is-minimized" + }, + { + "description": "Denies the is_resizable command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-is-resizable" + }, + { + "description": "Denies the is_visible command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-is-visible" + }, + { + "description": "Denies the maximize command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-maximize" + }, + { + "description": "Denies the minimize command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-minimize" + }, + { + "description": "Denies the monitor_from_point command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-monitor-from-point" + }, + { + "description": "Denies the outer_position command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-outer-position" + }, + { + "description": "Denies the outer_size command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-outer-size" + }, + { + "description": "Denies the primary_monitor command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-primary-monitor" + }, + { + "description": "Denies the request_user_attention command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-request-user-attention" + }, + { + "description": "Denies the scale_factor command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-scale-factor" + }, + { + "description": "Denies the set_always_on_bottom command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-always-on-bottom" + }, + { + "description": "Denies the set_always_on_top command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-always-on-top" + }, + { + "description": "Denies the set_closable command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-closable" + }, + { + "description": "Denies the set_content_protected command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-content-protected" + }, + { + "description": "Denies the set_cursor_grab command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-cursor-grab" + }, + { + "description": "Denies the set_cursor_icon command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-cursor-icon" + }, + { + "description": "Denies the set_cursor_position command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-cursor-position" + }, + { + "description": "Denies the set_cursor_visible command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-cursor-visible" + }, + { + "description": "Denies the set_decorations command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-decorations" + }, + { + "description": "Denies the set_effects command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-effects" + }, + { + "description": "Denies the set_enabled command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-enabled" + }, + { + "description": "Denies the set_focus command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-focus" + }, + { + "description": "Denies the set_fullscreen command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-fullscreen" + }, + { + "description": "Denies the set_icon command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-icon" + }, + { + "description": "Denies the set_ignore_cursor_events command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-ignore-cursor-events" + }, + { + "description": "Denies the set_max_size command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-max-size" + }, + { + "description": "Denies the set_maximizable command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-maximizable" + }, + { + "description": "Denies the set_min_size command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-min-size" + }, + { + "description": "Denies the set_minimizable command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-minimizable" + }, + { + "description": "Denies the set_position command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-position" + }, + { + "description": "Denies the set_progress_bar command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-progress-bar" + }, + { + "description": "Denies the set_resizable command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-resizable" + }, + { + "description": "Denies the set_shadow command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-shadow" + }, + { + "description": "Denies the set_size command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-size" + }, + { + "description": "Denies the set_size_constraints command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-size-constraints" + }, + { + "description": "Denies the set_skip_taskbar command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-skip-taskbar" + }, + { + "description": "Denies the set_theme command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-theme" + }, + { + "description": "Denies the set_title command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-title" + }, + { + "description": "Denies the set_title_bar_style command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-title-bar-style" + }, + { + "description": "Denies the set_visible_on_all_workspaces command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-visible-on-all-workspaces" + }, + { + "description": "Denies the show command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-show" + }, + { + "description": "Denies the start_dragging command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-start-dragging" + }, + { + "description": "Denies the start_resize_dragging command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-start-resize-dragging" + }, + { + "description": "Denies the theme command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-theme" + }, + { + "description": "Denies the title command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-title" + }, + { + "description": "Denies the toggle_maximize command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-toggle-maximize" + }, + { + "description": "Denies the unmaximize command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-unmaximize" + }, + { + "description": "Denies the unminimize command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-unminimize" + }, + { + "description": "This permission set configures the types of dialogs\navailable from the dialog plugin.\n\n#### Granted Permissions\n\nAll dialog types are enabled.\n\n\n", + "type": "string", + "const": "dialog:default" + }, + { + "description": "Enables the ask command without any pre-configured scope.", + "type": "string", + "const": "dialog:allow-ask" + }, + { + "description": "Enables the confirm command without any pre-configured scope.", + "type": "string", + "const": "dialog:allow-confirm" + }, + { + "description": "Enables the message command without any pre-configured scope.", + "type": "string", + "const": "dialog:allow-message" + }, + { + "description": "Enables the open command without any pre-configured scope.", + "type": "string", + "const": "dialog:allow-open" + }, + { + "description": "Enables the save command without any pre-configured scope.", + "type": "string", + "const": "dialog:allow-save" + }, + { + "description": "Denies the ask command without any pre-configured scope.", + "type": "string", + "const": "dialog:deny-ask" + }, + { + "description": "Denies the confirm command without any pre-configured scope.", + "type": "string", + "const": "dialog:deny-confirm" + }, + { + "description": "Denies the message command without any pre-configured scope.", + "type": "string", + "const": "dialog:deny-message" + }, + { + "description": "Denies the open command without any pre-configured scope.", + "type": "string", + "const": "dialog:deny-open" + }, + { + "description": "Denies the save command without any pre-configured scope.", + "type": "string", + "const": "dialog:deny-save" + }, + { + "description": "No features are enabled by default, as we believe\nthe shortcuts can be inherently dangerous and it is\napplication specific if specific shortcuts should be\nregistered or unregistered.\n", + "type": "string", + "const": "global-shortcut:default" + }, + { + "description": "Enables the is_registered command without any pre-configured scope.", + "type": "string", + "const": "global-shortcut:allow-is-registered" + }, + { + "description": "Enables the register command without any pre-configured scope.", + "type": "string", + "const": "global-shortcut:allow-register" + }, + { + "description": "Enables the register_all command without any pre-configured scope.", + "type": "string", + "const": "global-shortcut:allow-register-all" + }, + { + "description": "Enables the unregister command without any pre-configured scope.", + "type": "string", + "const": "global-shortcut:allow-unregister" + }, + { + "description": "Enables the unregister_all command without any pre-configured scope.", + "type": "string", + "const": "global-shortcut:allow-unregister-all" + }, + { + "description": "Denies the is_registered command without any pre-configured scope.", + "type": "string", + "const": "global-shortcut:deny-is-registered" + }, + { + "description": "Denies the register command without any pre-configured scope.", + "type": "string", + "const": "global-shortcut:deny-register" + }, + { + "description": "Denies the register_all command without any pre-configured scope.", + "type": "string", + "const": "global-shortcut:deny-register-all" + }, + { + "description": "Denies the unregister command without any pre-configured scope.", + "type": "string", + "const": "global-shortcut:deny-unregister" + }, + { + "description": "Denies the unregister_all command without any pre-configured scope.", + "type": "string", + "const": "global-shortcut:deny-unregister-all" + }, + { + "description": "This permission set configures which\noperating system information are available\nto gather from the frontend.\n\n#### Granted Permissions\n\nAll information except the host name are available.\n\n", + "type": "string", + "const": "os:default" + }, + { + "description": "Enables the arch command without any pre-configured scope.", + "type": "string", + "const": "os:allow-arch" + }, + { + "description": "Enables the exe_extension command without any pre-configured scope.", + "type": "string", + "const": "os:allow-exe-extension" + }, + { + "description": "Enables the family command without any pre-configured scope.", + "type": "string", + "const": "os:allow-family" + }, + { + "description": "Enables the hostname command without any pre-configured scope.", + "type": "string", + "const": "os:allow-hostname" + }, + { + "description": "Enables the locale command without any pre-configured scope.", + "type": "string", + "const": "os:allow-locale" + }, + { + "description": "Enables the os_type command without any pre-configured scope.", + "type": "string", + "const": "os:allow-os-type" + }, + { + "description": "Enables the platform command without any pre-configured scope.", + "type": "string", + "const": "os:allow-platform" + }, + { + "description": "Enables the version command without any pre-configured scope.", + "type": "string", + "const": "os:allow-version" + }, + { + "description": "Denies the arch command without any pre-configured scope.", + "type": "string", + "const": "os:deny-arch" + }, + { + "description": "Denies the exe_extension command without any pre-configured scope.", + "type": "string", + "const": "os:deny-exe-extension" + }, + { + "description": "Denies the family command without any pre-configured scope.", + "type": "string", + "const": "os:deny-family" + }, + { + "description": "Denies the hostname command without any pre-configured scope.", + "type": "string", + "const": "os:deny-hostname" + }, + { + "description": "Denies the locale command without any pre-configured scope.", + "type": "string", + "const": "os:deny-locale" + }, + { + "description": "Denies the os_type command without any pre-configured scope.", + "type": "string", + "const": "os:deny-os-type" + }, + { + "description": "Denies the platform command without any pre-configured scope.", + "type": "string", + "const": "os:deny-platform" + }, + { + "description": "Denies the version command without any pre-configured scope.", + "type": "string", + "const": "os:deny-version" + }, + { + "description": "This permission set configures which\nshell functionality is exposed by default.\n\n#### Granted Permissions\n\nIt allows to use the `open` functionality without any specific\nscope pre-configured. It will allow opening `http(s)://`,\n`tel:` and `mailto:` links.\n", + "type": "string", + "const": "shell:default" + }, + { + "description": "Enables the execute command without any pre-configured scope.", + "type": "string", + "const": "shell:allow-execute" + }, + { + "description": "Enables the kill command without any pre-configured scope.", + "type": "string", + "const": "shell:allow-kill" + }, + { + "description": "Enables the open command without any pre-configured scope.", + "type": "string", + "const": "shell:allow-open" + }, + { + "description": "Enables the spawn command without any pre-configured scope.", + "type": "string", + "const": "shell:allow-spawn" + }, + { + "description": "Enables the stdin_write command without any pre-configured scope.", + "type": "string", + "const": "shell:allow-stdin-write" + }, + { + "description": "Denies the execute command without any pre-configured scope.", + "type": "string", + "const": "shell:deny-execute" + }, + { + "description": "Denies the kill command without any pre-configured scope.", + "type": "string", + "const": "shell:deny-kill" + }, + { + "description": "Denies the open command without any pre-configured scope.", + "type": "string", + "const": "shell:deny-open" + }, + { + "description": "Denies the spawn command without any pre-configured scope.", + "type": "string", + "const": "shell:deny-spawn" + }, + { + "description": "Denies the stdin_write command without any pre-configured scope.", + "type": "string", + "const": "shell:deny-stdin-write" + } + ] + }, + "Value": { + "description": "All supported ACL values.", + "anyOf": [ + { + "description": "Represents a null JSON value.", + "type": "null" + }, + { + "description": "Represents a [`bool`].", + "type": "boolean" + }, + { + "description": "Represents a valid ACL [`Number`].", + "allOf": [ + { + "$ref": "#/definitions/Number" + } + ] + }, + { + "description": "Represents a [`String`].", + "type": "string" + }, + { + "description": "Represents a list of other [`Value`]s.", + "type": "array", + "items": { + "$ref": "#/definitions/Value" + } + }, + { + "description": "Represents a map of [`String`] keys to [`Value`]s.", + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/Value" + } + } + ] + }, + "Number": { + "description": "A valid ACL number.", + "anyOf": [ + { + "description": "Represents an [`i64`].", + "type": "integer", + "format": "int64" + }, + { + "description": "Represents a [`f64`].", + "type": "number", + "format": "double" + } + ] + }, + "Target": { + "description": "Platform target.", + "oneOf": [ + { + "description": "MacOS.", + "type": "string", + "enum": [ + "macOS" + ] + }, + { + "description": "Windows.", + "type": "string", + "enum": [ + "windows" + ] + }, + { + "description": "Linux.", + "type": "string", + "enum": [ + "linux" + ] + }, + { + "description": "Android.", + "type": "string", + "enum": [ + "android" + ] + }, + { + "description": "iOS.", + "type": "string", + "enum": [ + "iOS" + ] + } + ] + }, + "ShellScopeEntryAllowedArg": { + "description": "A command argument allowed to be executed by the webview API.", + "anyOf": [ + { + "description": "A non-configurable argument that is passed to the command in the order it was specified.", + "type": "string" + }, + { + "description": "A variable that is set while calling the command from the webview API.", + "type": "object", + "required": [ + "validator" + ], + "properties": { + "raw": { + "description": "Marks the validator as a raw regex, meaning the plugin should not make any modification at runtime.\n\nThis means the regex will not match on the entire string by default, which might be exploited if your regex allow unexpected input to be considered valid. When using this option, make sure your regex is correct.", + "default": false, + "type": "boolean" + }, + "validator": { + "description": "[regex] validator to require passed values to conform to an expected input.\n\nThis will require the argument value passed to this variable to match the `validator` regex before it will be executed.\n\nThe regex string is by default surrounded by `^...$` to match the full string. For example the `https?://\\w+` regex would be registered as `^https?://\\w+$`.\n\n[regex]: ", + "type": "string" + } + }, + "additionalProperties": false + } + ] + }, + "ShellScopeEntryAllowedArgs": { + "description": "A set of command arguments allowed to be executed by the webview API.\n\nA value of `true` will allow any arguments to be passed to the command. `false` will disable all arguments. A list of [`ShellScopeEntryAllowedArg`] will set those arguments as the only valid arguments to be passed to the attached command configuration.", + "anyOf": [ + { + "description": "Use a simple boolean to allow all or disable all arguments to this command configuration.", + "type": "boolean" + }, + { + "description": "A specific set of [`ShellScopeEntryAllowedArg`] that are valid to call for the command configuration.", + "type": "array", + "items": { + "$ref": "#/definitions/ShellScopeEntryAllowedArg" + } + } + ] + } + } +} \ No newline at end of file diff --git a/src-tauri/src/db.rs b/src-tauri/src/db.rs index 75cbc24..f737113 100644 --- a/src-tauri/src/db.rs +++ b/src-tauri/src/db.rs @@ -1,49 +1,57 @@ -use rusqlite::{Connection, named_params, params}; -use tauri::AppHandle; -use std::fs; -use anyhow::Result; -use indoc::indoc; -use crate::persistent_entities::{PersistentTrack, PersistentAlbum, PersistentArtist, PersistentConfig}; use crate::fs_track; +use crate::persistent_entities::{ + PersistentAlbum, PersistentArtist, PersistentConfig, PersistentTrack, +}; use crate::utils::prepare_input; +use anyhow::Result; +use indoc::indoc; use regex::Regex; +use rusqlite::{named_params, params, Connection}; +use std::fs; +use tauri::{AppHandle, Manager}; const CURRENT_DB_VERSION: u32 = 5; /// Initializes the database connection, creating the .sqlite file if needed, and upgrading the database /// if it's out of date. pub fn initialize_database(app_handle: &AppHandle) -> Result { - let app_dir = app_handle.path_resolver().app_data_dir().expect("The app data directory should exist."); - fs::create_dir_all(&app_dir).expect("The app data directory should be created."); - let sqlite_path = app_dir.join("db.sqlite3"); + let app_dir = app_handle + .path() + .app_data_dir() + .expect("The app data directory should exist."); + fs::create_dir_all(&app_dir).expect("The app data directory should be created."); + let sqlite_path = app_dir.join("db.sqlite3"); - println!("Database file path: {}", sqlite_path.display()); + println!("Database file path: {}", sqlite_path.display()); - let mut db = Connection::open(sqlite_path)?; + let mut db = Connection::open(sqlite_path)?; - let mut user_pragma = db.prepare("PRAGMA user_version")?; - let existing_user_version: u32 = user_pragma.query_row([], |row| { Ok(row.get(0)?) })?; - drop(user_pragma); + let mut user_pragma = db.prepare("PRAGMA user_version")?; + let existing_user_version: u32 = user_pragma.query_row([], |row| Ok(row.get(0)?))?; + drop(user_pragma); - upgrade_database_if_needed(&mut db, existing_user_version)?; + upgrade_database_if_needed(&mut db, existing_user_version)?; - Ok(db) + Ok(db) } /// Upgrades the database to the current version. -pub fn upgrade_database_if_needed(db: &mut Connection, existing_version: u32) -> Result<(), rusqlite::Error> { - println!("Existing database version: {}", existing_version); +pub fn upgrade_database_if_needed( + db: &mut Connection, + existing_version: u32, +) -> Result<(), rusqlite::Error> { + println!("Existing database version: {}", existing_version); - if existing_version < CURRENT_DB_VERSION { - if existing_version <= 0 { - println!("Mirgate database version 1..."); - db.pragma_update(None, "journal_mode", "WAL")?; + if existing_version < CURRENT_DB_VERSION { + if existing_version <= 0 { + println!("Mirgate database version 1..."); + db.pragma_update(None, "journal_mode", "WAL")?; - let tx = db.transaction()?; + let tx = db.transaction()?; - tx.pragma_update(None, "user_version", 1)?; + tx.pragma_update(None, "user_version", 1)?; - tx.execute_batch(indoc! {" + tx.execute_batch(indoc! {" CREATE TABLE directories ( id INTEGER PRIMARY KEY, path TEXT @@ -90,45 +98,45 @@ pub fn upgrade_database_if_needed(db: &mut Connection, existing_version: u32) -> INSERT INTO config_data (skip_not_needed_tracks, try_embed_lyrics) VALUES (1, 0); "})?; - tx.commit()?; - } + tx.commit()?; + } - if existing_version <= 1 { - println!("Mirgate database version 2..."); - db.pragma_update(None, "journal_mode", "WAL")?; + if existing_version <= 1 { + println!("Mirgate database version 2..."); + db.pragma_update(None, "journal_mode", "WAL")?; - let tx = db.transaction()?; + let tx = db.transaction()?; - tx.pragma_update(None, "user_version", 2)?; + tx.pragma_update(None, "user_version", 2)?; - tx.execute_batch(indoc! {" + tx.execute_batch(indoc! {" ALTER TABLE tracks ADD txt_lyrics TEXT; CREATE INDEX idx_tracks_title ON tracks(title); CREATE INDEX idx_albums_name ON albums(name); CREATE INDEX idx_artists_name ON artists(name); "})?; - tx.commit()?; - } + tx.commit()?; + } - if existing_version <= 2 { - println!("Mirgate database version 3..."); - let tx = db.transaction()?; + if existing_version <= 2 { + println!("Mirgate database version 3..."); + let tx = db.transaction()?; - tx.pragma_update(None, "user_version", 3)?; + tx.pragma_update(None, "user_version", 3)?; - tx.execute_batch(indoc! {" + tx.execute_batch(indoc! {" ALTER TABLE tracks ADD instrumental BOOLEAN; "})?; - tx.commit()?; - } + tx.commit()?; + } - if existing_version <= 3 { - println!("Mirgate database version 4..."); - let tx = db.transaction()?; + if existing_version <= 3 { + println!("Mirgate database version 4..."); + let tx = db.transaction()?; - tx.pragma_update(None, "user_version", 4)?; + tx.pragma_update(None, "user_version", 4)?; - tx.execute_batch(indoc! {" + tx.execute_batch(indoc! {" ALTER TABLE tracks ADD title_lower TEXT; ALTER TABLE albums ADD name_lower TEXT; ALTER TABLE artists ADD name_lower TEXT; @@ -137,16 +145,16 @@ pub fn upgrade_database_if_needed(db: &mut Connection, existing_version: u32) -> CREATE INDEX idx_artists_name_lower ON artists(name_lower); "})?; - tx.commit()?; - } + tx.commit()?; + } - if existing_version <= 4 { - println!("Mirgate database version 5..."); - let tx = db.transaction()?; + if existing_version <= 4 { + println!("Mirgate database version 5..."); + let tx = db.transaction()?; - tx.pragma_update(None, "user_version", 5)?; + tx.pragma_update(None, "user_version", 5)?; - tx.execute_batch(indoc! {" + tx.execute_batch(indoc! {" ALTER TABLE tracks ADD track_number INTEGER; ALTER TABLE albums ADD album_artist_name TEXT; ALTER TABLE albums ADD album_artist_name_lower TEXT; @@ -161,93 +169,110 @@ pub fn upgrade_database_if_needed(db: &mut Connection, existing_version: u32) -> UPDATE library_data SET init = 0 WHERE 1; "})?; - tx.commit()?; + tx.commit()?; + } } - } - Ok(()) + Ok(()) } pub fn get_directories(db: &Connection) -> Result> { - let mut statement = db.prepare("SELECT * FROM directories")?; - let mut rows = statement.query([])?; - let mut directories: Vec = Vec::new(); - while let Some(row) = rows.next()? { - let path: String = row.get("path")?; + let mut statement = db.prepare("SELECT * FROM directories")?; + let mut rows = statement.query([])?; + let mut directories: Vec = Vec::new(); + while let Some(row) = rows.next()? { + let path: String = row.get("path")?; - directories.push(path); - } + directories.push(path); + } - Ok(directories) + Ok(directories) } pub fn set_directories(directories: Vec, db: &Connection) -> Result<()> { - db.execute("DELETE FROM directories WHERE 1", ())?; - let mut statement = db.prepare("INSERT INTO directories (path) VALUES (@path)")?; - for directory in directories.iter() { - statement.execute(named_params! { "@path": directory })?; - } + db.execute("DELETE FROM directories WHERE 1", ())?; + let mut statement = db.prepare("INSERT INTO directories (path) VALUES (@path)")?; + for directory in directories.iter() { + statement.execute(named_params! { "@path": directory })?; + } - Ok(()) + Ok(()) } pub fn get_init(db: &Connection) -> Result { - let mut statement = db.prepare("SELECT init FROM library_data LIMIT 1")?; - let init: bool = statement.query_row([], |r| r.get(0))?; - Ok(init) + let mut statement = db.prepare("SELECT init FROM library_data LIMIT 1")?; + let init: bool = statement.query_row([], |r| r.get(0))?; + Ok(init) } pub fn set_init(init: bool, db: &Connection) -> Result<()> { - let mut statement = db.prepare("UPDATE library_data SET init = ? WHERE 1")?; - statement.execute([init])?; - Ok(()) + let mut statement = db.prepare("UPDATE library_data SET init = ? WHERE 1")?; + statement.execute([init])?; + Ok(()) } pub fn get_config(db: &Connection) -> Result { - let mut statement = db.prepare("SELECT skip_not_needed_tracks, try_embed_lyrics, theme_mode, lrclib_instance FROM config_data LIMIT 1")?; - let row = statement.query_row([], |r| { - Ok(PersistentConfig { - skip_not_needed_tracks: r.get("skip_not_needed_tracks")?, - try_embed_lyrics: r.get("try_embed_lyrics")?, - theme_mode: r.get("theme_mode")?, - lrclib_instance: r.get("lrclib_instance")? - }) - })?; - Ok(row) -} - -pub fn set_config(skip_not_needed_tracks: bool, try_embed_lyrics: bool, theme_mode: &str, lrclib_instance: &str, db: &Connection) -> Result<()> { - let mut statement = db.prepare("UPDATE config_data SET skip_not_needed_tracks = ?, try_embed_lyrics = ?, theme_mode = ?, lrclib_instance = ? WHERE 1")?; - statement.execute((skip_not_needed_tracks, try_embed_lyrics, theme_mode, lrclib_instance))?; - Ok(()) + let mut statement = db.prepare("SELECT skip_not_needed_tracks, try_embed_lyrics, theme_mode, lrclib_instance FROM config_data LIMIT 1")?; + let row = statement.query_row([], |r| { + Ok(PersistentConfig { + skip_not_needed_tracks: r.get("skip_not_needed_tracks")?, + try_embed_lyrics: r.get("try_embed_lyrics")?, + theme_mode: r.get("theme_mode")?, + lrclib_instance: r.get("lrclib_instance")?, + }) + })?; + Ok(row) +} + +pub fn set_config( + skip_not_needed_tracks: bool, + try_embed_lyrics: bool, + theme_mode: &str, + lrclib_instance: &str, + db: &Connection, +) -> Result<()> { + let mut statement = db.prepare("UPDATE config_data SET skip_not_needed_tracks = ?, try_embed_lyrics = ?, theme_mode = ?, lrclib_instance = ? WHERE 1")?; + statement.execute(( + skip_not_needed_tracks, + try_embed_lyrics, + theme_mode, + lrclib_instance, + ))?; + Ok(()) } pub fn find_artist(name: &str, db: &Connection) -> Result { - let mut statement = db.prepare("SELECT id FROM artists WHERE name = ?")?; - let id: i64 = statement.query_row([name], |r| r.get(0))?; - Ok(id) + let mut statement = db.prepare("SELECT id FROM artists WHERE name = ?")?; + let id: i64 = statement.query_row([name], |r| r.get(0))?; + Ok(id) } pub fn add_artist(name: &str, db: &Connection) -> Result { - let mut statement = db.prepare("INSERT INTO artists (name, name_lower) VALUES (?, ?)")?; - let row_id = statement.insert((name, prepare_input(name)))?; - Ok(row_id) + let mut statement = db.prepare("INSERT INTO artists (name, name_lower) VALUES (?, ?)")?; + let row_id = statement.insert((name, prepare_input(name)))?; + Ok(row_id) } pub fn find_album(name: &str, album_artist_name: &str, db: &Connection) -> Result { - let mut statement = db.prepare("SELECT id FROM albums WHERE name = ? AND album_artist_name = ?")?; - let id: i64 = statement.query_row((name, album_artist_name), |r| r.get(0))?; - Ok(id) + let mut statement = + db.prepare("SELECT id FROM albums WHERE name = ? AND album_artist_name = ?")?; + let id: i64 = statement.query_row((name, album_artist_name), |r| r.get(0))?; + Ok(id) } pub fn add_album(name: &str, album_artist_name: &str, db: &Connection) -> Result { - let mut statement = db.prepare("INSERT INTO albums (name, name_lower, album_artist_name, album_artist_name_lower) VALUES (?, ?, ?, ?)")?; - let row_id = statement.insert((name, prepare_input(name), album_artist_name, prepare_input(album_artist_name)))?; - Ok(row_id) + let mut statement = db.prepare("INSERT INTO albums (name, name_lower, album_artist_name, album_artist_name_lower) VALUES (?, ?, ?, ?)")?; + let row_id = statement.insert(( + name, + prepare_input(name), + album_artist_name, + prepare_input(album_artist_name), + ))?; + Ok(row_id) } pub fn get_track_by_id(id: i64, db: &Connection) -> Result { - let query = indoc! {" + let query = indoc! {" SELECT tracks.id, file_path, @@ -271,95 +296,109 @@ pub fn get_track_by_id(id: i64, db: &Connection) -> Result { LIMIT 1 "}; - let mut statement = db.prepare(query)?; - let row = statement.query_row( - [id], - |row| { - let is_instrumental: Option = row.get("instrumental")?; - - Ok(PersistentTrack { - id: row.get("id")?, - file_path: row.get("file_path")?, - file_name: row.get("file_name")?, - title: row.get("title")?, - artist_name: row.get("artist_name")?, - artist_id: row.get("artist_id")?, - album_name: row.get("album_name")?, - album_artist_name: row.get("album_artist_name")?, - album_id: row.get("album_id")?, - duration: row.get("duration")?, - track_number: row.get("track_number")?, - txt_lyrics: row.get("txt_lyrics")?, - lrc_lyrics: row.get("lrc_lyrics")?, - image_path: row.get("image_path")?, - instrumental: is_instrumental.unwrap_or(false) - }) + let mut statement = db.prepare(query)?; + let row = statement.query_row([id], |row| { + let is_instrumental: Option = row.get("instrumental")?; + + Ok(PersistentTrack { + id: row.get("id")?, + file_path: row.get("file_path")?, + file_name: row.get("file_name")?, + title: row.get("title")?, + artist_name: row.get("artist_name")?, + artist_id: row.get("artist_id")?, + album_name: row.get("album_name")?, + album_artist_name: row.get("album_artist_name")?, + album_id: row.get("album_id")?, + duration: row.get("duration")?, + track_number: row.get("track_number")?, + txt_lyrics: row.get("txt_lyrics")?, + lrc_lyrics: row.get("lrc_lyrics")?, + image_path: row.get("image_path")?, + instrumental: is_instrumental.unwrap_or(false), + }) })?; - Ok(row) + Ok(row) } -pub fn update_track_synced_lyrics(id: i64, synced_lyrics: &str, plain_lyrics: &str, db: &Connection) -> Result { - let mut statement = db.prepare("UPDATE tracks SET lrc_lyrics = ?, txt_lyrics = ?, instrumental = false WHERE id = ?")?; - statement.execute((synced_lyrics, plain_lyrics, id))?; +pub fn update_track_synced_lyrics( + id: i64, + synced_lyrics: &str, + plain_lyrics: &str, + db: &Connection, +) -> Result { + let mut statement = db.prepare( + "UPDATE tracks SET lrc_lyrics = ?, txt_lyrics = ?, instrumental = false WHERE id = ?", + )?; + statement.execute((synced_lyrics, plain_lyrics, id))?; - Ok(get_track_by_id(id, db)?) + Ok(get_track_by_id(id, db)?) } -pub fn update_track_plain_lyrics(id: i64, plain_lyrics: &str, db: &Connection) -> Result { - let mut statement = db.prepare("UPDATE tracks SET txt_lyrics = ?, lrc_lyrics = null, instrumental = false WHERE id = ?")?; - statement.execute((plain_lyrics, id))?; +pub fn update_track_plain_lyrics( + id: i64, + plain_lyrics: &str, + db: &Connection, +) -> Result { + let mut statement = db.prepare( + "UPDATE tracks SET txt_lyrics = ?, lrc_lyrics = null, instrumental = false WHERE id = ?", + )?; + statement.execute((plain_lyrics, id))?; - Ok(get_track_by_id(id, db)?) + Ok(get_track_by_id(id, db)?) } pub fn update_track_null_lyrics(id: i64, db: &Connection) -> Result { - let mut statement = db.prepare("UPDATE tracks SET txt_lyrics = null, lrc_lyrics = null, instrumental = false WHERE id = ?")?; - statement.execute([id])?; + let mut statement = db.prepare( + "UPDATE tracks SET txt_lyrics = null, lrc_lyrics = null, instrumental = false WHERE id = ?", + )?; + statement.execute([id])?; - Ok(get_track_by_id(id, db)?) + Ok(get_track_by_id(id, db)?) } pub fn update_track_instrumental(id: i64, db: &Connection) -> Result { - let mut statement = db.prepare("UPDATE tracks SET txt_lyrics = null, lrc_lyrics = ?, instrumental = true WHERE id = ?")?; - statement.execute(params!["[au: instrumental]", id])?; + let mut statement = db.prepare( + "UPDATE tracks SET txt_lyrics = null, lrc_lyrics = ?, instrumental = true WHERE id = ?", + )?; + statement.execute(params!["[au: instrumental]", id])?; - Ok(get_track_by_id(id, db)?) + Ok(get_track_by_id(id, db)?) } pub fn add_tracks(tracks: &Vec, db: &mut Connection) -> Result<()> { - let tx = db.transaction()?; + let tx = db.transaction()?; - for track in tracks.iter() { - add_track(track, &tx)?; - } + for track in tracks.iter() { + add_track(track, &tx)?; + } - tx.commit()?; + tx.commit()?; - Ok(()) + Ok(()) } pub fn add_track(track: &fs_track::FsTrack, db: &Connection) -> Result<()> { - let artist_result = find_artist(&track.artist(), db); - let artist_id = match artist_result { - Ok(artist_id) => artist_id, - Err(_) => { - add_artist(&track.artist(), db)? - } - }; + let artist_result = find_artist(&track.artist(), db); + let artist_id = match artist_result { + Ok(artist_id) => artist_id, + Err(_) => add_artist(&track.artist(), db)?, + }; - let album_result = find_album(&track.album(), &track.album_artist(), db); - let album_id = match album_result { - Ok(album_id) => album_id, - Err(_) => { - add_album(&track.album(), &track.album_artist(), db)? - } - }; + let album_result = find_album(&track.album(), &track.album_artist(), db); + let album_id = match album_result { + Ok(album_id) => album_id, + Err(_) => add_album(&track.album(), &track.album_artist(), db)?, + }; - // Create a regex to match "[au: instrumental]" or "[au:instrumental]" - let re = Regex::new(r"\[au:\s*instrumental\]").expect("Invalid regex"); - let is_instrumental = track.lrc_lyrics().as_ref().map_or(false, |lyrics| re.is_match(lyrics)); + // Create a regex to match "[au: instrumental]" or "[au:instrumental]" + let re = Regex::new(r"\[au:\s*instrumental\]").expect("Invalid regex"); + let is_instrumental = track + .lrc_lyrics() + .as_ref() + .map_or(false, |lyrics| re.is_match(lyrics)); - let query = indoc! {" + let query = indoc! {" INSERT INTO tracks ( file_path, file_name, @@ -374,26 +413,26 @@ pub fn add_track(track: &fs_track::FsTrack, db: &Connection) -> Result<()> { instrumental ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) "}; - let mut statement = db.prepare(query)?; - statement.execute(( - track.file_path(), - track.file_name(), - track.title(), - prepare_input(&track.title()), - album_id, - artist_id, - track.duration(), - track.track_number(), - track.txt_lyrics(), - track.lrc_lyrics(), - is_instrumental - ))?; - - Ok(()) + let mut statement = db.prepare(query)?; + statement.execute(( + track.file_path(), + track.file_name(), + track.title(), + prepare_input(&track.title()), + album_id, + artist_id, + track.duration(), + track.track_number(), + track.txt_lyrics(), + track.lrc_lyrics(), + is_instrumental, + ))?; + + Ok(()) } pub fn get_tracks(db: &Connection) -> Result> { - let query = indoc! {" + let query = indoc! {" SELECT tracks.id, file_path, file_name, title, artists.name AS artist_name, tracks.artist_id, @@ -404,47 +443,47 @@ pub fn get_tracks(db: &Connection) -> Result> { JOIN artists ON tracks.artist_id = artists.id ORDER BY title_lower ASC "}; - let mut statement = db.prepare(query)?; - let mut rows = statement.query([])?; - let mut tracks: Vec = Vec::new(); - - while let Some(row) = rows.next()? { - let is_instrumental: Option = row.get("instrumental")?; - - let track = PersistentTrack { - id: row.get("id")?, - file_path: row.get("file_path")?, - file_name: row.get("file_name")?, - title: row.get("title")?, - artist_name: row.get("artist_name")?, - artist_id: row.get("artist_id")?, - album_name: row.get("album_name")?, - album_artist_name: row.get("album_artist_name")?, - album_id: row.get("album_id")?, - duration: row.get("duration")?, - track_number: row.get("track_number")?, - txt_lyrics: row.get("txt_lyrics")?, - lrc_lyrics: row.get("lrc_lyrics")?, - image_path: row.get("image_path")?, - instrumental: is_instrumental.unwrap_or(false) - }; + let mut statement = db.prepare(query)?; + let mut rows = statement.query([])?; + let mut tracks: Vec = Vec::new(); - tracks.push(track); - } + while let Some(row) = rows.next()? { + let is_instrumental: Option = row.get("instrumental")?; + + let track = PersistentTrack { + id: row.get("id")?, + file_path: row.get("file_path")?, + file_name: row.get("file_name")?, + title: row.get("title")?, + artist_name: row.get("artist_name")?, + artist_id: row.get("artist_id")?, + album_name: row.get("album_name")?, + album_artist_name: row.get("album_artist_name")?, + album_id: row.get("album_id")?, + duration: row.get("duration")?, + track_number: row.get("track_number")?, + txt_lyrics: row.get("txt_lyrics")?, + lrc_lyrics: row.get("lrc_lyrics")?, + image_path: row.get("image_path")?, + instrumental: is_instrumental.unwrap_or(false), + }; + + tracks.push(track); + } - Ok(tracks) + Ok(tracks) } pub fn get_track_ids(db: &Connection) -> Result> { - let mut statement = db.prepare("SELECT id FROM tracks ORDER BY title_lower ASC")?; - let mut rows = statement.query([])?; - let mut track_ids: Vec = Vec::new(); + let mut statement = db.prepare("SELECT id FROM tracks ORDER BY title_lower ASC")?; + let mut rows = statement.query([])?; + let mut track_ids: Vec = Vec::new(); - while let Some(row) = rows.next()? { - track_ids.push(row.get("id")?); - } + while let Some(row) = rows.next()? { + track_ids.push(row.get("id")?); + } - Ok(track_ids) + Ok(track_ids) } pub fn get_search_track_ids(query_str: &String, db: &Connection) -> Result> { @@ -476,19 +515,19 @@ pub fn get_search_track_ids(query_str: &String, db: &Connection) -> Result Result> { - let mut statement = db.prepare("SELECT id FROM tracks WHERE lrc_lyrics IS NULL AND instrumental != true ORDER BY title_lower ASC")?; - let mut rows = statement.query([])?; - let mut track_ids: Vec = Vec::new(); + let mut statement = db.prepare("SELECT id FROM tracks WHERE lrc_lyrics IS NULL AND instrumental != true ORDER BY title_lower ASC")?; + let mut rows = statement.query([])?; + let mut track_ids: Vec = Vec::new(); - while let Some(row) = rows.next()? { - track_ids.push(row.get("id")?); - } + while let Some(row) = rows.next()? { + track_ids.push(row.get("id")?); + } - Ok(track_ids) + Ok(track_ids) } pub fn get_albums(db: &Connection) -> Result> { - let mut statement = db.prepare(indoc! {" + let mut statement = db.prepare(indoc! {" SELECT albums.id, albums.name, albums.album_artist_name AS album_artist_name, albums.album_artist_name, COUNT(tracks.id) AS tracks_count FROM albums @@ -496,27 +535,27 @@ pub fn get_albums(db: &Connection) -> Result> { GROUP BY albums.id, albums.name, albums.album_artist_name ORDER BY albums.name_lower ASC "})?; - let mut rows = statement.query([])?; - let mut albums: Vec = Vec::new(); - - while let Some(row) = rows.next()? { - let album = PersistentAlbum { - id: row.get("id")?, - name: row.get("name")?, - image_path: row.get("image_path")?, - artist_name: row.get("album_artist_name")?, - album_artist_name: row.get("album_artist_name")?, - tracks_count: row.get("tracks_count")?, - }; + let mut rows = statement.query([])?; + let mut albums: Vec = Vec::new(); - albums.push(album); - } + while let Some(row) = rows.next()? { + let album = PersistentAlbum { + id: row.get("id")?, + name: row.get("name")?, + image_path: row.get("image_path")?, + artist_name: row.get("album_artist_name")?, + album_artist_name: row.get("album_artist_name")?, + tracks_count: row.get("tracks_count")?, + }; + + albums.push(album); + } - Ok(albums) + Ok(albums) } pub fn get_album_by_id(id: i64, db: &Connection) -> Result { - let mut statement = db.prepare(indoc! {" + let mut statement = db.prepare(indoc! {" SELECT albums.id, albums.name, @@ -531,60 +570,58 @@ pub fn get_album_by_id(id: i64, db: &Connection) -> Result { albums.album_artist_name LIMIT 1 "})?; - let row = statement.query_row( - [id], - |row| - Ok(PersistentAlbum { - id: row.get("id")?, - name: row.get("name")?, - image_path: None, - artist_name: row.get("album_artist_name")?, - album_artist_name: row.get("album_artist_name")?, - tracks_count: row.get("tracks_count")?, - }) - )?; - Ok(row) + let row = statement.query_row([id], |row| { + Ok(PersistentAlbum { + id: row.get("id")?, + name: row.get("name")?, + image_path: None, + artist_name: row.get("album_artist_name")?, + album_artist_name: row.get("album_artist_name")?, + tracks_count: row.get("tracks_count")?, + }) + })?; + Ok(row) } pub fn get_album_ids(db: &Connection) -> Result> { - let mut statement = db.prepare("SELECT id FROM albums ORDER BY name_lower ASC")?; - let mut rows = statement.query([])?; - let mut album_ids: Vec = Vec::new(); + let mut statement = db.prepare("SELECT id FROM albums ORDER BY name_lower ASC")?; + let mut rows = statement.query([])?; + let mut album_ids: Vec = Vec::new(); - while let Some(row) = rows.next()? { - album_ids.push(row.get("id")?); - } + while let Some(row) = rows.next()? { + album_ids.push(row.get("id")?); + } - Ok(album_ids) + Ok(album_ids) } pub fn get_artists(db: &Connection) -> Result> { - let mut statement = db.prepare(indoc! {" + let mut statement = db.prepare(indoc! {" SELECT artists.id, artists.name AS name, COUNT(tracks.id) AS tracks_count FROM artists JOIN tracks ON tracks.artist_id = artists.id GROUP BY artists.id, artists.name ORDER BY artists.name_lower ASC "})?; - let mut rows = statement.query([])?; - let mut artists: Vec = Vec::new(); - - while let Some(row) = rows.next()? { - let artist = PersistentArtist { - id: row.get("id")?, - name: row.get("name")?, - // albums_count: row.get("albums_count")?, - tracks_count: row.get("tracks_count")?, - }; + let mut rows = statement.query([])?; + let mut artists: Vec = Vec::new(); - artists.push(artist); - } + while let Some(row) = rows.next()? { + let artist = PersistentArtist { + id: row.get("id")?, + name: row.get("name")?, + // albums_count: row.get("albums_count")?, + tracks_count: row.get("tracks_count")?, + }; + + artists.push(artist); + } - Ok(artists) + Ok(artists) } pub fn get_artist_by_id(id: i64, db: &Connection) -> Result { - let mut statement = db.prepare(indoc! {" + let mut statement = db.prepare(indoc! {" SELECT artists.id, artists.name AS name, COUNT(tracks.id) AS tracks_count @@ -594,33 +631,31 @@ pub fn get_artist_by_id(id: i64, db: &Connection) -> Result { GROUP BY artists.id, artists.name LIMIT 1 "})?; - let row = statement.query_row( - [id], - |row| - Ok(PersistentArtist { - id: row.get("id")?, - name: row.get("name")?, - // albums_count: row.get("albums_count")?, - tracks_count: row.get("tracks_count")?, - }) - )?; - Ok(row) + let row = statement.query_row([id], |row| { + Ok(PersistentArtist { + id: row.get("id")?, + name: row.get("name")?, + // albums_count: row.get("albums_count")?, + tracks_count: row.get("tracks_count")?, + }) + })?; + Ok(row) } pub fn get_artist_ids(db: &Connection) -> Result> { - let mut statement = db.prepare("SELECT id FROM artists ORDER BY name_lower ASC")?; - let mut rows = statement.query([])?; - let mut artist_ids: Vec = Vec::new(); + let mut statement = db.prepare("SELECT id FROM artists ORDER BY name_lower ASC")?; + let mut rows = statement.query([])?; + let mut artist_ids: Vec = Vec::new(); - while let Some(row) = rows.next()? { - artist_ids.push(row.get("id")?); - } + while let Some(row) = rows.next()? { + artist_ids.push(row.get("id")?); + } - Ok(artist_ids) + Ok(artist_ids) } pub fn get_album_tracks(album_id: i64, db: &Connection) -> Result> { - let mut statement = db.prepare(indoc! {" + let mut statement = db.prepare(indoc! {" SELECT tracks.id, file_path, @@ -643,56 +678,56 @@ pub fn get_album_tracks(album_id: i64, db: &Connection) -> Result = Vec::new(); - - while let Some(row) = rows.next()? { - let is_instrumental: Option = row.get("instrumental")?; - - let track = PersistentTrack { - id: row.get("id")?, - file_path: row.get("file_path")?, - file_name: row.get("file_name")?, - title: row.get("title")?, - artist_name: row.get("artist_name")?, - album_artist_name: row.get("album_artist_name")?, - album_name: row.get("album_name")?, - album_id: row.get("album_id")?, - artist_id: row.get("artist_id")?, - duration: row.get("duration")?, - track_number: row.get("track_number")?, - txt_lyrics: row.get("txt_lyrics")?, - lrc_lyrics: row.get("lrc_lyrics")?, - image_path: row.get("image_path")?, - instrumental: is_instrumental.unwrap_or(false) - }; + let mut rows = statement.query([album_id])?; + let mut tracks: Vec = Vec::new(); - tracks.push(track); - } + while let Some(row) = rows.next()? { + let is_instrumental: Option = row.get("instrumental")?; + + let track = PersistentTrack { + id: row.get("id")?, + file_path: row.get("file_path")?, + file_name: row.get("file_name")?, + title: row.get("title")?, + artist_name: row.get("artist_name")?, + album_artist_name: row.get("album_artist_name")?, + album_name: row.get("album_name")?, + album_id: row.get("album_id")?, + artist_id: row.get("artist_id")?, + duration: row.get("duration")?, + track_number: row.get("track_number")?, + txt_lyrics: row.get("txt_lyrics")?, + lrc_lyrics: row.get("lrc_lyrics")?, + image_path: row.get("image_path")?, + instrumental: is_instrumental.unwrap_or(false), + }; + + tracks.push(track); + } - Ok(tracks) + Ok(tracks) } pub fn get_album_track_ids(album_id: i64, db: &Connection) -> Result> { - let mut statement = db.prepare(indoc! {" + let mut statement = db.prepare(indoc! {" SELECT tracks.id FROM tracks JOIN albums ON tracks.album_id = albums.id WHERE tracks.album_id = ? ORDER BY track_number ASC "})?; - let mut rows = statement.query([album_id])?; - let mut tracks: Vec = Vec::new(); + let mut rows = statement.query([album_id])?; + let mut tracks: Vec = Vec::new(); - while let Some(row) = rows.next()? { - tracks.push(row.get("id")?); - } + while let Some(row) = rows.next()? { + tracks.push(row.get("id")?); + } - Ok(tracks) + Ok(tracks) } pub fn get_artist_tracks(artist_id: i64, db: &Connection) -> Result> { - let mut statement = db.prepare(indoc! {" + let mut statement = db.prepare(indoc! {" SELECT tracks.id, file_path, file_name, title, artists.name AS artist_name, tracks.artist_id, albums.name AS album_name, albums.album_artist_name, album_id, duration, track_number, albums.image_path, txt_lyrics, lrc_lyrics, instrumental @@ -702,38 +737,38 @@ pub fn get_artist_tracks(artist_id: i64, db: &Connection) -> Result = Vec::new(); - - while let Some(row) = rows.next()? { - let is_instrumental: Option = row.get("instrumental")?; - - let track = PersistentTrack { - id: row.get("id")?, - file_path: row.get("file_path")?, - file_name: row.get("file_name")?, - title: row.get("title")?, - artist_name: row.get("artist_name")?, - artist_id: row.get("artist_id")?, - album_name: row.get("album_name")?, - album_artist_name: row.get("album_artist_name")?, - album_id: row.get("album_id")?, - duration: row.get("duration")?, - track_number: row.get("track_number")?, - txt_lyrics: row.get("txt_lyrics")?, - lrc_lyrics: row.get("lrc_lyrics")?, - image_path: row.get("image_path")?, - instrumental: is_instrumental.unwrap_or(false) - }; + let mut rows = statement.query([artist_id])?; + let mut tracks: Vec = Vec::new(); - tracks.push(track); - } + while let Some(row) = rows.next()? { + let is_instrumental: Option = row.get("instrumental")?; + + let track = PersistentTrack { + id: row.get("id")?, + file_path: row.get("file_path")?, + file_name: row.get("file_name")?, + title: row.get("title")?, + artist_name: row.get("artist_name")?, + artist_id: row.get("artist_id")?, + album_name: row.get("album_name")?, + album_artist_name: row.get("album_artist_name")?, + album_id: row.get("album_id")?, + duration: row.get("duration")?, + track_number: row.get("track_number")?, + txt_lyrics: row.get("txt_lyrics")?, + lrc_lyrics: row.get("lrc_lyrics")?, + image_path: row.get("image_path")?, + instrumental: is_instrumental.unwrap_or(false), + }; + + tracks.push(track); + } - Ok(tracks) + Ok(tracks) } pub fn get_artist_track_ids(artist_id: i64, db: &Connection) -> Result> { - let mut statement = db.prepare(indoc! {" + let mut statement = db.prepare(indoc! {" SELECT tracks.id FROM tracks JOIN albums ON tracks.album_id = albums.id @@ -741,19 +776,19 @@ pub fn get_artist_track_ids(artist_id: i64, db: &Connection) -> Result> WHERE tracks.artist_id = ? ORDER BY albums.name_lower ASC, tracks.track_number ASC "})?; - let mut rows = statement.query([artist_id])?; - let mut tracks: Vec = Vec::new(); + let mut rows = statement.query([artist_id])?; + let mut tracks: Vec = Vec::new(); - while let Some(row) = rows.next()? { - tracks.push(row.get("id")?); - } + while let Some(row) = rows.next()? { + tracks.push(row.get("id")?); + } - Ok(tracks) + Ok(tracks) } pub fn clean_library(db: &Connection) -> Result<()> { - db.execute("DELETE FROM tracks WHERE 1", ())?; - db.execute("DELETE FROM albums WHERE 1", ())?; - db.execute("DELETE FROM artists WHERE 1", ())?; - Ok(()) + db.execute("DELETE FROM tracks WHERE 1", ())?; + db.execute("DELETE FROM albums WHERE 1", ())?; + db.execute("DELETE FROM artists WHERE 1", ())?; + Ok(()) } diff --git a/src-tauri/src/fs_track.rs b/src-tauri/src/fs_track.rs index 2037118..696618c 100644 --- a/src-tauri/src/fs_track.rs +++ b/src-tauri/src/fs_track.rs @@ -1,251 +1,313 @@ +use crate::db; +use anyhow::Result; use globwalk::{glob, DirEntry}; use lofty::error::LoftyError; use lofty::file::AudioFile; use lofty::file::TaggedFileExt; use lofty::read_from_path; use lofty::tag::Accessor; -use anyhow::Result; +use rayon::prelude::*; use rusqlite::Connection; -use tauri::AppHandle; +use serde::{Deserialize, Serialize}; use std::path::Path; use std::path::PathBuf; -use serde::{Deserialize, Serialize}; -use rayon::prelude::*; -use thiserror::Error; use std::time::Instant; -use crate::db; -use tauri::Manager; +use tauri::{AppHandle, Emitter}; +use thiserror::Error; #[derive(Serialize, Deserialize, Clone, Debug)] pub struct FsTrack { - file_path: String, - file_name: String, - title: String, - album: String, - artist: String, - album_artist: String, - duration: f64, - txt_lyrics: Option, - lrc_lyrics: Option, - track_number: Option, + file_path: String, + file_name: String, + title: String, + album: String, + artist: String, + album_artist: String, + duration: f64, + txt_lyrics: Option, + lrc_lyrics: Option, + track_number: Option, } #[derive(Error, Debug)] pub enum FsTrackError { - #[error("Cannot parse the tag info from track: `{0}`. Error: `{1}`")] - ParseFailed(String, LoftyError), - #[error("No title was found from track: `{0}`")] - TitleNotFound(String), - #[error("No album name was found from track: `{0}`")] - AlbumNotFound(String), - #[error("No artist name was found from track: `{0}`")] - ArtistNotFound(String), - #[error("No primary tag was found from track: `{0}`")] - PrimaryTagNotFound(String) + #[error("Cannot parse the tag info from track: `{0}`. Error: `{1}`")] + ParseFailed(String, LoftyError), + #[error("No title was found from track: `{0}`")] + TitleNotFound(String), + #[error("No album name was found from track: `{0}`")] + AlbumNotFound(String), + #[error("No artist name was found from track: `{0}`")] + ArtistNotFound(String), + #[error("No primary tag was found from track: `{0}`")] + PrimaryTagNotFound(String), } #[derive(Clone, Serialize)] #[serde(rename_all = "camelCase")] struct ScanProgress { - progress: Option, - files_scanned: usize, - files_count: Option + progress: Option, + files_scanned: usize, + files_count: Option, } impl FsTrack { - fn new(file_path: String, file_name: String, title: String, album: String, artist: String, album_artist: String, duration: f64, txt_lyrics: Option, lrc_lyrics: Option, track_number: Option) -> FsTrack { - FsTrack { - file_path, - file_name, - title, - album, - artist, - album_artist, - duration, - txt_lyrics, - lrc_lyrics, - track_number, - } - } - - fn new_from_path(path: &Path) -> Result { - let file_path = path.display().to_string(); - let file_name = path.file_name().unwrap().to_str().unwrap().to_owned(); - let tagged_file = read_from_path(&file_path).or_else(|err| Err(FsTrackError::ParseFailed(file_path.to_owned(), err)))?; - let tag = tagged_file.primary_tag().ok_or(FsTrackError::PrimaryTagNotFound(file_path.to_owned()))?.to_owned(); - let properties = tagged_file.properties(); - let title = tag.title().ok_or(FsTrackError::TitleNotFound(file_path.to_owned()))?.to_string(); - let album = tag.album().ok_or(FsTrackError::AlbumNotFound(file_path.to_owned()))?.to_string(); - let artist = tag.artist().ok_or(FsTrackError::ArtistNotFound(file_path.to_owned()))?.to_string(); - let album_artist = tag - .get_string(&lofty::tag::ItemKey::AlbumArtist) - .map(|s| s.to_string()) - .unwrap_or_else(|| artist.clone()); - let duration = properties.duration().as_secs_f64(); - let track_number = tag.track(); - - let mut track = FsTrack::new(file_path, file_name, title, album, artist, album_artist, duration, None, None, track_number); - track.txt_lyrics = track.get_txt_lyrics(); - track.lrc_lyrics = track.get_lrc_lyrics(); - - Ok(track) - } - - pub fn file_path(&self) -> String { - self.file_path.to_owned() - } - - pub fn file_name(&self) -> String { - self.file_name.to_owned() - } - - pub fn title(&self) -> String { - self.title.to_owned() - } - - pub fn album(&self) -> String { - self.album.to_owned() - } - - pub fn artist(&self) -> String { - self.artist.to_owned() - } - - pub fn album_artist(&self) -> String { - self.album_artist.to_owned() - } - - pub fn duration(&self) -> f64 { - self.duration - } - - pub fn txt_lyrics(&self) -> Option { - self.txt_lyrics.to_owned() - } - - pub fn lrc_lyrics(&self) -> Option { - self.lrc_lyrics.to_owned() - } - - pub fn track_number(&self) -> Option { - self.track_number - } - - fn get_txt_path(&self) -> String { - let path = PathBuf::from(self.file_path.to_owned()); - let file_name = path.file_name().unwrap().to_str().unwrap().to_owned(); - let parent_path = path.parent().unwrap(); - let file_name_without_extension = std::path::Path::new(&file_name) - .file_stem() - .unwrap() - .to_str() - .unwrap() - .to_owned(); - let mut txt_file_name = file_name_without_extension.to_owned(); - txt_file_name.push_str(".txt"); - - let txt_file_path = parent_path.join(txt_file_name).display().to_string(); - - txt_file_path - } - - fn get_txt_lyrics(&self) -> Option { - let txt_file_path = self.get_txt_path(); - let txt_content = std::fs::read_to_string(txt_file_path); - - match txt_content { - Ok(txt_content) => Some(txt_content), - Err(_) => None - } - } - - fn get_lrc_path(&self) -> String { - let path = PathBuf::from(self.file_path.to_owned()); - let file_name = path.file_name().unwrap().to_str().unwrap().to_owned(); - let parent_path = path.parent().unwrap(); - let file_name_without_extension = std::path::Path::new(&file_name) - .file_stem() - .unwrap() - .to_str() - .unwrap() - .to_owned(); - let mut lrc_file_name = file_name_without_extension.to_owned(); - lrc_file_name.push_str(".lrc"); - - let lrc_file_path = parent_path.join(lrc_file_name).display().to_string(); - - lrc_file_path - } - - fn get_lrc_lyrics(&self) -> Option { - let lrc_file_path = self.get_lrc_path(); - let lrc_content = std::fs::read_to_string(lrc_file_path); - - match lrc_content { - Ok(lrc_content) => Some(lrc_content), - Err(_) => None - } - } -} + fn new( + file_path: String, + file_name: String, + title: String, + album: String, + artist: String, + album_artist: String, + duration: f64, + txt_lyrics: Option, + lrc_lyrics: Option, + track_number: Option, + ) -> FsTrack { + FsTrack { + file_path, + file_name, + title, + album, + artist, + album_artist, + duration, + txt_lyrics, + lrc_lyrics, + track_number, + } + } -fn load_tracks_from_entry_batch(entry_batch: &Vec) -> Result> { - let track_results: Vec> = entry_batch - .par_iter() - .map(|file| FsTrack::new_from_path(file.path())) - .collect(); + fn new_from_path(path: &Path) -> Result { + let file_path = path.display().to_string(); + let file_name = path.file_name().unwrap().to_str().unwrap().to_owned(); + let tagged_file = read_from_path(&file_path) + .or_else(|err| Err(FsTrackError::ParseFailed(file_path.to_owned(), err)))?; + let tag = tagged_file + .primary_tag() + .ok_or(FsTrackError::PrimaryTagNotFound(file_path.to_owned()))? + .to_owned(); + let properties = tagged_file.properties(); + let title = tag + .title() + .ok_or(FsTrackError::TitleNotFound(file_path.to_owned()))? + .to_string(); + let album = tag + .album() + .ok_or(FsTrackError::AlbumNotFound(file_path.to_owned()))? + .to_string(); + let artist = tag + .artist() + .ok_or(FsTrackError::ArtistNotFound(file_path.to_owned()))? + .to_string(); + let album_artist = tag + .get_string(&lofty::tag::ItemKey::AlbumArtist) + .map(|s| s.to_string()) + .unwrap_or_else(|| artist.clone()); + let duration = properties.duration().as_secs_f64(); + let track_number = tag.track(); + + let mut track = FsTrack::new( + file_path, + file_name, + title, + album, + artist, + album_artist, + duration, + None, + None, + track_number, + ); + track.txt_lyrics = track.get_txt_lyrics(); + track.lrc_lyrics = track.get_lrc_lyrics(); + + Ok(track) + } + + pub fn file_path(&self) -> String { + self.file_path.to_owned() + } + + pub fn file_name(&self) -> String { + self.file_name.to_owned() + } + + pub fn title(&self) -> String { + self.title.to_owned() + } + + pub fn album(&self) -> String { + self.album.to_owned() + } - let mut tracks: Vec = vec![]; + pub fn artist(&self) -> String { + self.artist.to_owned() + } + + pub fn album_artist(&self) -> String { + self.album_artist.to_owned() + } - for track_result in track_results { - match track_result { - Ok(track) => { - tracks.push(track); - } - Err(error) => { - println!("{}", error); - } + pub fn duration(&self) -> f64 { + self.duration } - } - Ok(tracks) + pub fn txt_lyrics(&self) -> Option { + self.txt_lyrics.to_owned() + } + + pub fn lrc_lyrics(&self) -> Option { + self.lrc_lyrics.to_owned() + } + + pub fn track_number(&self) -> Option { + self.track_number + } + + fn get_txt_path(&self) -> String { + let path = PathBuf::from(self.file_path.to_owned()); + let file_name = path.file_name().unwrap().to_str().unwrap().to_owned(); + let parent_path = path.parent().unwrap(); + let file_name_without_extension = std::path::Path::new(&file_name) + .file_stem() + .unwrap() + .to_str() + .unwrap() + .to_owned(); + let mut txt_file_name = file_name_without_extension.to_owned(); + txt_file_name.push_str(".txt"); + + let txt_file_path = parent_path.join(txt_file_name).display().to_string(); + + txt_file_path + } + + fn get_txt_lyrics(&self) -> Option { + let txt_file_path = self.get_txt_path(); + let txt_content = std::fs::read_to_string(txt_file_path); + + match txt_content { + Ok(txt_content) => Some(txt_content), + Err(_) => None, + } + } + + fn get_lrc_path(&self) -> String { + let path = PathBuf::from(self.file_path.to_owned()); + let file_name = path.file_name().unwrap().to_str().unwrap().to_owned(); + let parent_path = path.parent().unwrap(); + let file_name_without_extension = std::path::Path::new(&file_name) + .file_stem() + .unwrap() + .to_str() + .unwrap() + .to_owned(); + let mut lrc_file_name = file_name_without_extension.to_owned(); + lrc_file_name.push_str(".lrc"); + + let lrc_file_path = parent_path.join(lrc_file_name).display().to_string(); + + lrc_file_path + } + + fn get_lrc_lyrics(&self) -> Option { + let lrc_file_path = self.get_lrc_path(); + let lrc_content = std::fs::read_to_string(lrc_file_path); + + match lrc_content { + Ok(lrc_content) => Some(lrc_content), + Err(_) => None, + } + } } -pub fn load_tracks_from_directories(directories: &Vec, conn: &mut Connection, app_handle: AppHandle) -> Result<()> { - let now = Instant::now(); - let files_count = count_files_from_directories(directories)?; - println!("Files count: {}", files_count); - let mut files_scanned: usize = 0; - for directory in directories.iter() { - let mut entry_batch: Vec = vec![]; - let globwalker = glob(format!("{}/**/*.{{mp3,m4a,flac,ogg,opus,wav,MP3,M4A,FLAC,OGG,OPUS,WAV}}", directory))?; - for item in globwalker { - let entry = item?; - entry_batch.push(entry); - if entry_batch.len() == 100 { - let tracks = load_tracks_from_entry_batch(&entry_batch)?; +fn load_tracks_from_entry_batch(entry_batch: &Vec) -> Result> { + let track_results: Vec> = entry_batch + .par_iter() + .map(|file| FsTrack::new_from_path(file.path())) + .collect(); + + let mut tracks: Vec = vec![]; + + for track_result in track_results { + match track_result { + Ok(track) => { + tracks.push(track); + } + Err(error) => { + println!("{}", error); + } + } + } + Ok(tracks) +} + +pub fn load_tracks_from_directories( + directories: &Vec, + conn: &mut Connection, + app_handle: AppHandle, +) -> Result<()> { + let now = Instant::now(); + let files_count = count_files_from_directories(directories)?; + println!("Files count: {}", files_count); + let mut files_scanned: usize = 0; + for directory in directories.iter() { + let mut entry_batch: Vec = vec![]; + let globwalker = glob(format!( + "{}/**/*.{{mp3,m4a,flac,ogg,opus,wav,MP3,M4A,FLAC,OGG,OPUS,WAV}}", + directory + ))?; + for item in globwalker { + let entry = item?; + entry_batch.push(entry); + if entry_batch.len() == 100 { + let tracks = load_tracks_from_entry_batch(&entry_batch)?; + + db::add_tracks(&tracks, conn)?; + files_scanned += entry_batch.len(); + app_handle + .emit( + "initialize-progress", + ScanProgress { + progress: None, + files_scanned, + files_count: Some(files_count), + }, + ) + .unwrap(); + entry_batch.clear(); + } + } + let tracks = load_tracks_from_entry_batch(&entry_batch)?; db::add_tracks(&tracks, conn)?; files_scanned += entry_batch.len(); - app_handle.emit_all("initialize-progress", ScanProgress { progress: None, files_scanned, files_count: Some(files_count) }).unwrap(); - entry_batch.clear(); - } - } - let tracks = load_tracks_from_entry_batch(&entry_batch)?; - db::add_tracks(&tracks, conn)?; - files_scanned += entry_batch.len(); - app_handle.emit_all("initialize-progress", ScanProgress { progress: None, files_scanned, files_count: Some(files_count) }).unwrap(); - } - println!("==> Scanning tracks take: {}ms", now.elapsed().as_millis()); - - Ok(()) + app_handle + .emit( + "initialize-progress", + ScanProgress { + progress: None, + files_scanned, + files_count: Some(files_count), + }, + ) + .unwrap(); + } + println!("==> Scanning tracks take: {}ms", now.elapsed().as_millis()); + + Ok(()) } pub fn count_files_from_directories(directories: &Vec) -> Result { - let mut files_count = 0; - for directory in directories.iter() { - let files_in_dir = glob(format!("{}/**/*.{{mp3,m4a,flac,ogg,opus,wav,MP3,M4A,FLAC,OGG,OPUS,WAV}}", directory))?; - files_count += files_in_dir.into_iter().count(); - } + let mut files_count = 0; + for directory in directories.iter() { + let files_in_dir = glob(format!( + "{}/**/*.{{mp3,m4a,flac,ogg,opus,wav,MP3,M4A,FLAC,OGG,OPUS,WAV}}", + directory + ))?; + files_count += files_in_dir.into_iter().count(); + } - Ok(files_count) + Ok(files_count) } diff --git a/src-tauri/src/library.rs b/src-tauri/src/library.rs index 4fbc3e2..ac2f8e9 100644 --- a/src-tauri/src/library.rs +++ b/src-tauri/src/library.rs @@ -1,111 +1,111 @@ +use crate::db; +use crate::fs_track::{self, FsTrack}; +use crate::persistent_entities::{PersistentAlbum, PersistentArtist, PersistentTrack}; use anyhow::Result; use rusqlite::Connection; use tauri::AppHandle; -use crate::persistent_entities::{PersistentTrack, PersistentAlbum, PersistentArtist}; -use crate::fs_track::{self, FsTrack}; -use crate::db; pub fn initialize_library(conn: &mut Connection, app_handle: AppHandle) -> Result<()> { - let init = db::get_init(conn)?; - if init { - return Ok(()) - } - - db::clean_library(conn)?; - - let directories = db::get_directories(conn)?; - let result = fs_track::load_tracks_from_directories(&directories, conn, app_handle); - - match result { - Ok(()) => { - db::set_init(true, conn)?; - Ok(()) - }, - Err(err) => { - let uninitialization = uninitialize_library(conn); - if let Err(uninit_error) = uninitialization { - println!("Uninitialization library errored. Message: {}", uninit_error.to_string()); - } - Err(err) + let init = db::get_init(conn)?; + if init { + return Ok(()); + } + + db::clean_library(conn)?; + + let directories = db::get_directories(conn)?; + let result = fs_track::load_tracks_from_directories(&directories, conn, app_handle); + + match result { + Ok(()) => { + db::set_init(true, conn)?; + Ok(()) + } + Err(err) => { + let uninitialization = uninitialize_library(conn); + if let Err(uninit_error) = uninitialization { + println!( + "Uninitialization library errored. Message: {}", + uninit_error.to_string() + ); + } + Err(err) + } } - } } pub fn uninitialize_library(conn: &Connection) -> Result<()> { - db::clean_library(conn)?; - db::set_init(false, conn)?; - Ok(()) + db::clean_library(conn)?; + db::set_init(false, conn)?; + Ok(()) } pub fn add_tracks(tracks: Vec, conn: &Connection) -> Result<()> { - for track in tracks.iter() { - db::add_track(&track, conn)?; - } - Ok(()) + for track in tracks.iter() { + db::add_track(&track, conn)?; + } + Ok(()) } pub fn get_tracks(conn: &Connection) -> Result> { - db::get_tracks(conn) + db::get_tracks(conn) } -pub fn get_track_ids( - search_query: Option, - conn: &Connection, -) -> Result> { - match search_query { - Some(search_query) => db::get_search_track_ids(&search_query, conn), - None => db::get_track_ids(conn) - } +pub fn get_track_ids(search_query: Option, conn: &Connection) -> Result> { + match search_query { + Some(search_query) => db::get_search_track_ids(&search_query, conn), + None => db::get_track_ids(conn), + } } pub fn get_no_lyrics_track_ids(conn: &Connection) -> Result> { - db::get_no_lyrics_track_ids(conn) + db::get_no_lyrics_track_ids(conn) } pub fn get_track(id: i64, conn: &Connection) -> Result { - db::get_track_by_id(id, conn) + db::get_track_by_id(id, conn) } pub fn get_albums(conn: &Connection) -> Result> { - db::get_albums(conn) + db::get_albums(conn) } pub fn get_album_ids(conn: &Connection) -> Result> { - db::get_album_ids(conn) + db::get_album_ids(conn) } pub fn get_album(id: i64, conn: &Connection) -> Result { - db::get_album_by_id(id, conn) + db::get_album_by_id(id, conn) } pub fn get_artists(conn: &Connection) -> Result> { - db::get_artists(conn) + db::get_artists(conn) } pub fn get_artist_ids(conn: &Connection) -> Result> { - db::get_artist_ids(conn) + db::get_artist_ids(conn) } pub fn get_artist(id: i64, conn: &Connection) -> Result { - db::get_artist_by_id(id, conn) + db::get_artist_by_id(id, conn) } pub fn get_album_tracks(album_id: i64, conn: &Connection) -> Result> { - db::get_album_tracks(album_id, conn) + db::get_album_tracks(album_id, conn) } pub fn get_artist_tracks(artist_id: i64, conn: &Connection) -> Result> { - db::get_artist_tracks(artist_id, conn) + db::get_artist_tracks(artist_id, conn) } pub fn get_album_track_ids(album_id: i64, conn: &Connection) -> Result> { - db::get_album_track_ids(album_id, conn) + db::get_album_track_ids(album_id, conn) } pub fn get_artist_track_ids(artist_id: i64, conn: &Connection) -> Result> { - db::get_artist_track_ids(artist_id, conn) + db::get_artist_track_ids(artist_id, conn) } pub fn get_init(conn: &Connection) -> Result { - db::get_init(conn) + db::get_init(conn) } diff --git a/src-tauri/src/lrclib.rs b/src-tauri/src/lrclib.rs index e2ac4fb..504cfc0 100644 --- a/src-tauri/src/lrclib.rs +++ b/src-tauri/src/lrclib.rs @@ -1,7 +1,7 @@ +pub mod challenge_solver; +pub mod flag; pub mod get; pub mod get_by_id; -pub mod search; pub mod publish; pub mod request_challenge; -pub mod challenge_solver; -pub mod flag; \ No newline at end of file +pub mod search; diff --git a/src-tauri/src/lrclib/challenge_solver.rs b/src-tauri/src/lrclib/challenge_solver.rs index 4375782..98c5aa2 100644 --- a/src-tauri/src/lrclib/challenge_solver.rs +++ b/src-tauri/src/lrclib/challenge_solver.rs @@ -1,40 +1,40 @@ -use ring::digest::{Context, SHA256}; use data_encoding::HEXUPPER; +use ring::digest::{Context, SHA256}; fn verify_nonce(result: &Vec, target: &Vec) -> bool { - if result.len() != target.len() { - return false - } + if result.len() != target.len() { + return false; + } - for i in 0..(result.len() - 1) { - if result[i] > target[i] { - return false - } else if result[i] < target[i] { - break; + for i in 0..(result.len() - 1) { + if result[i] > target[i] { + return false; + } else if result[i] < target[i] { + break; + } } - } - return true + return true; } pub fn solve_challenge(prefix: &str, target_hex: &str) -> String { - let mut nonce = 0; - let mut hashed; - let target = HEXUPPER.decode(target_hex.as_bytes()).unwrap(); + let mut nonce = 0; + let mut hashed; + let target = HEXUPPER.decode(target_hex.as_bytes()).unwrap(); - loop { - let mut context = Context::new(&SHA256); - let input = format!("{}{}", prefix, nonce); - context.update(input.as_bytes()); - hashed = context.finish().as_ref().to_vec(); + loop { + let mut context = Context::new(&SHA256); + let input = format!("{}{}", prefix, nonce); + context.update(input.as_bytes()); + hashed = context.finish().as_ref().to_vec(); - let result = verify_nonce(&hashed, &target); - if result { - break; - } else { - nonce += 1; + let result = verify_nonce(&hashed, &target); + if result { + break; + } else { + nonce += 1; + } } - } - nonce.to_string() + nonce.to_string() } diff --git a/src-tauri/src/lrclib/flag.rs b/src-tauri/src/lrclib/flag.rs index d385bd0..7c65782 100644 --- a/src-tauri/src/lrclib/flag.rs +++ b/src-tauri/src/lrclib/flag.rs @@ -1,58 +1,70 @@ use std::time::Duration; -use serde::{Deserialize,Serialize}; use anyhow::Result; use reqwest; +use serde::{Deserialize, Serialize}; use thiserror::Error; #[derive(Serialize)] #[serde(rename_all = "camelCase")] pub struct Request { - track_id: i64, - reason: String + track_id: i64, + reason: String, } #[derive(Error, Deserialize, Debug)] #[serde(rename_all = "camelCase")] #[error("{error}: {message}")] pub struct ResponseError { - status_code: Option, - error: String, - message: String + status_code: Option, + error: String, + message: String, } -pub async fn request(track_id: i64, reason: &str, publish_token: &str, lrclib_instance: &str) -> Result<()> { - let data = Request { - track_id, - reason: reason.to_owned() - }; - - let version = env!("CARGO_PKG_VERSION"); - let user_agent = format!("LRCGET v{} (https://github.com/tranxuanthang/lrcget)", version); - let client = reqwest::Client::builder() - .timeout(Duration::from_secs(10)) - .user_agent(user_agent) - .build()?; - let api_endpoint = format!("{}/api/flag", lrclib_instance.trim_end_matches('/')); - let url = reqwest::Url::parse(&api_endpoint)?; - let res = client.post(url).header("X-Publish-Token", publish_token).json(&data).send().await?; - - match res.status() { - reqwest::StatusCode::CREATED => { - Ok(()) - }, - - reqwest::StatusCode::BAD_REQUEST | reqwest::StatusCode::SERVICE_UNAVAILABLE | reqwest::StatusCode::INTERNAL_SERVER_ERROR => { - let error = res.json::().await?; - Err(error.into()) - }, - - _ => { - Err(ResponseError { - status_code: None, - error: "UnknownError".to_string(), - message: "Unknown error happened".to_string() - }.into()) +pub async fn request( + track_id: i64, + reason: &str, + publish_token: &str, + lrclib_instance: &str, +) -> Result<()> { + let data = Request { + track_id, + reason: reason.to_owned(), + }; + + let version = env!("CARGO_PKG_VERSION"); + let user_agent = format!( + "LRCGET v{} (https://github.com/tranxuanthang/lrcget)", + version + ); + let client = reqwest::Client::builder() + .timeout(Duration::from_secs(10)) + .user_agent(user_agent) + .build()?; + let api_endpoint = format!("{}/api/flag", lrclib_instance.trim_end_matches('/')); + let url = reqwest::Url::parse(&api_endpoint)?; + let res = client + .post(url) + .header("X-Publish-Token", publish_token) + .json(&data) + .send() + .await?; + + match res.status() { + reqwest::StatusCode::CREATED => Ok(()), + + reqwest::StatusCode::BAD_REQUEST + | reqwest::StatusCode::SERVICE_UNAVAILABLE + | reqwest::StatusCode::INTERNAL_SERVER_ERROR => { + let error = res.json::().await?; + Err(error.into()) + } + + _ => Err(ResponseError { + status_code: None, + error: "UnknownError".to_string(), + message: "Unknown error happened".to_string(), + } + .into()), } - } } diff --git a/src-tauri/src/lrclib/get.rs b/src-tauri/src/lrclib/get.rs index 49438d1..1a12d23 100644 --- a/src-tauri/src/lrclib/get.rs +++ b/src-tauri/src/lrclib/get.rs @@ -1,160 +1,175 @@ use std::time::Duration; -use serde::{Deserialize,Serialize}; +use crate::utils::strip_timestamp; use anyhow::Result; use reqwest; +use serde::{Deserialize, Serialize}; use thiserror::Error; -use crate::utils::strip_timestamp; #[derive(Deserialize, Serialize)] #[serde(rename_all = "camelCase")] pub struct RawResponse { - pub plain_lyrics: Option, - pub synced_lyrics: Option, - instrumental: bool, - lang: Option, - isrc: Option, - spotify_id: Option, - name: Option, - album_name: Option, - artist_name: Option, - release_date: Option, - duration: Option + pub plain_lyrics: Option, + pub synced_lyrics: Option, + instrumental: bool, + lang: Option, + isrc: Option, + spotify_id: Option, + name: Option, + album_name: Option, + artist_name: Option, + release_date: Option, + duration: Option, } #[derive(Serialize)] #[serde(tag = "type", content = "lyrics")] pub enum Response { - SyncedLyrics(String, String), - UnsyncedLyrics(String), - IsInstrumental, - None + SyncedLyrics(String, String), + UnsyncedLyrics(String), + IsInstrumental, + None, } impl Response { - pub fn from_raw_response(lrclib_response: RawResponse) -> Response { - match lrclib_response.synced_lyrics { - Some(synced_lyrics) => { - let plain_lyrics = match lrclib_response.plain_lyrics { - Some(plain_lyrics) => plain_lyrics, - None => { - strip_timestamp(&synced_lyrics) - } - }; - Response::SyncedLyrics(synced_lyrics, plain_lyrics) - }, - None => { - match lrclib_response.plain_lyrics { - Some(unsynced_lyrics) => { - Response::UnsyncedLyrics(unsynced_lyrics) - } - None => { - if lrclib_response.instrumental { - Response::IsInstrumental - } else { - Response::None + pub fn from_raw_response(lrclib_response: RawResponse) -> Response { + match lrclib_response.synced_lyrics { + Some(synced_lyrics) => { + let plain_lyrics = match lrclib_response.plain_lyrics { + Some(plain_lyrics) => plain_lyrics, + None => strip_timestamp(&synced_lyrics), + }; + Response::SyncedLyrics(synced_lyrics, plain_lyrics) } - } + None => match lrclib_response.plain_lyrics { + Some(unsynced_lyrics) => Response::UnsyncedLyrics(unsynced_lyrics), + None => { + if lrclib_response.instrumental { + Response::IsInstrumental + } else { + Response::None + } + } + }, } - } } - } } #[derive(Error, Deserialize, Debug)] #[serde(rename_all = "camelCase")] #[error("{error}: {message}")] pub struct ResponseError { - status_code: Option, - error: String, - message: String + status_code: Option, + error: String, + message: String, } -async fn make_request(title: &str, album_name: &str, artist_name: &str, duration: f64, lrclib_instance: &str) -> Result { - let params: Vec<(String, String)> = vec![ - ("artist_name".to_owned(), artist_name.to_owned()), - ("track_name".to_owned(), title.to_owned()), - ("album_name".to_owned(), album_name.to_owned()), - ("duration".to_owned(), duration.round().to_string()) - ]; - - let version = env!("CARGO_PKG_VERSION"); - let user_agent = format!("LRCGET v{} (https://github.com/tranxuanthang/lrcget)", version); - let client = reqwest::Client::builder() - .timeout(Duration::from_secs(10)) - .user_agent(user_agent) - .build()?; - let api_endpoint = format!("{}/api/get", lrclib_instance.trim_end_matches('/')); - let url = reqwest::Url::parse_with_params(&api_endpoint, ¶ms)?; - Ok(client.get(url).send().await?) +async fn make_request( + title: &str, + album_name: &str, + artist_name: &str, + duration: f64, + lrclib_instance: &str, +) -> Result { + let params: Vec<(String, String)> = vec![ + ("artist_name".to_owned(), artist_name.to_owned()), + ("track_name".to_owned(), title.to_owned()), + ("album_name".to_owned(), album_name.to_owned()), + ("duration".to_owned(), duration.round().to_string()), + ]; + + let version = env!("CARGO_PKG_VERSION"); + let user_agent = format!( + "LRCGET v{} (https://github.com/tranxuanthang/lrcget)", + version + ); + let client = reqwest::Client::builder() + .timeout(Duration::from_secs(10)) + .user_agent(user_agent) + .build()?; + let api_endpoint = format!("{}/api/get", lrclib_instance.trim_end_matches('/')); + let url = reqwest::Url::parse_with_params(&api_endpoint, ¶ms)?; + Ok(client.get(url).send().await?) } -pub async fn request_raw(title: &str, album_name: &str, artist_name: &str, duration: f64, lrclib_instance: &str) -> Result { - let res = make_request(title, album_name, artist_name, duration, lrclib_instance).await?; - - match res.status() { - reqwest::StatusCode::OK => { - let lrclib_response = res.json::().await?; - - if lrclib_response.synced_lyrics.is_some() || lrclib_response.plain_lyrics.is_some() { - Ok(lrclib_response) - } else { - Err(ResponseError { - status_code: Some(404), - error: "NotFound".to_string(), - message: "There is no lyrics for this track".to_string() - }.into()) - } - } +pub async fn request_raw( + title: &str, + album_name: &str, + artist_name: &str, + duration: f64, + lrclib_instance: &str, +) -> Result { + let res = make_request(title, album_name, artist_name, duration, lrclib_instance).await?; + + match res.status() { + reqwest::StatusCode::OK => { + let lrclib_response = res.json::().await?; + + if lrclib_response.synced_lyrics.is_some() || lrclib_response.plain_lyrics.is_some() { + Ok(lrclib_response) + } else { + Err(ResponseError { + status_code: Some(404), + error: "NotFound".to_string(), + message: "There is no lyrics for this track".to_string(), + } + .into()) + } + } - reqwest::StatusCode::NOT_FOUND => { - Err(ResponseError { - status_code: Some(404), - error: "NotFound".to_string(), - message: "There is no lyrics for this track".to_string() - }.into()) - } + reqwest::StatusCode::NOT_FOUND => Err(ResponseError { + status_code: Some(404), + error: "NotFound".to_string(), + message: "There is no lyrics for this track".to_string(), + } + .into()), - reqwest::StatusCode::BAD_REQUEST | reqwest::StatusCode::SERVICE_UNAVAILABLE | reqwest::StatusCode::INTERNAL_SERVER_ERROR => { - let error = res.json::().await?; - Err(error.into()) - }, - - _ => { - Err(ResponseError { - status_code: None, - error: "UnknownError".to_string(), - message: "Unknown error happened".to_string() - }.into()) + reqwest::StatusCode::BAD_REQUEST + | reqwest::StatusCode::SERVICE_UNAVAILABLE + | reqwest::StatusCode::INTERNAL_SERVER_ERROR => { + let error = res.json::().await?; + Err(error.into()) + } + + _ => Err(ResponseError { + status_code: None, + error: "UnknownError".to_string(), + message: "Unknown error happened".to_string(), + } + .into()), } - } } -pub async fn request(title: &str, album_name: &str, artist_name: &str, duration: f64, lrclib_instance: &str) -> Result { - let res = make_request(title, album_name, artist_name, duration, lrclib_instance).await?; +pub async fn request( + title: &str, + album_name: &str, + artist_name: &str, + duration: f64, + lrclib_instance: &str, +) -> Result { + let res = make_request(title, album_name, artist_name, duration, lrclib_instance).await?; + + match res.status() { + reqwest::StatusCode::OK => { + let lrclib_response = res.json::().await?; - match res.status() { - reqwest::StatusCode::OK => { - let lrclib_response = res.json::().await?; + Ok(Response::from_raw_response(lrclib_response)) + } - Ok(Response::from_raw_response(lrclib_response)) - }, + reqwest::StatusCode::NOT_FOUND => Ok(Response::None), - reqwest::StatusCode::NOT_FOUND => { - Ok(Response::None) - } + reqwest::StatusCode::BAD_REQUEST + | reqwest::StatusCode::SERVICE_UNAVAILABLE + | reqwest::StatusCode::INTERNAL_SERVER_ERROR => { + let error = res.json::().await?; + Err(error.into()) + } - reqwest::StatusCode::BAD_REQUEST | reqwest::StatusCode::SERVICE_UNAVAILABLE | reqwest::StatusCode::INTERNAL_SERVER_ERROR => { - let error = res.json::().await?; - Err(error.into()) - }, - - _ => { - Err(ResponseError { - status_code: None, - error: "UnknownError".to_string(), - message: "Unknown error happened".to_string() - }.into()) + _ => Err(ResponseError { + status_code: None, + error: "UnknownError".to_string(), + message: "Unknown error happened".to_string(), + } + .into()), } - } } diff --git a/src-tauri/src/lrclib/get_by_id.rs b/src-tauri/src/lrclib/get_by_id.rs index 0adeda3..80444a1 100644 --- a/src-tauri/src/lrclib/get_by_id.rs +++ b/src-tauri/src/lrclib/get_by_id.rs @@ -1,152 +1,152 @@ use std::time::Duration; -use serde::{Deserialize,Serialize}; +use crate::utils::strip_timestamp; use anyhow::Result; use reqwest; +use serde::{Deserialize, Serialize}; use thiserror::Error; -use crate::utils::strip_timestamp; #[derive(Deserialize, Serialize)] #[serde(rename_all = "camelCase")] pub struct RawResponse { - pub plain_lyrics: Option, - pub synced_lyrics: Option, - instrumental: bool, - lang: Option, - isrc: Option, - spotify_id: Option, - name: Option, - album_name: Option, - artist_name: Option, - release_date: Option, - duration: Option + pub plain_lyrics: Option, + pub synced_lyrics: Option, + instrumental: bool, + lang: Option, + isrc: Option, + spotify_id: Option, + name: Option, + album_name: Option, + artist_name: Option, + release_date: Option, + duration: Option, } #[derive(Serialize)] #[serde(tag = "type", content = "lyrics")] pub enum Response { - SyncedLyrics(String, String), - UnsyncedLyrics(String), - IsInstrumental, - None + SyncedLyrics(String, String), + UnsyncedLyrics(String), + IsInstrumental, + None, } impl Response { - pub fn from_raw_response(lrclib_response: RawResponse) -> Response { - match lrclib_response.synced_lyrics { - Some(synced_lyrics) => { - let plain_lyrics = match lrclib_response.plain_lyrics { - Some(plain_lyrics) => plain_lyrics, - None => { - strip_timestamp(&synced_lyrics) - } - }; - Response::SyncedLyrics(synced_lyrics, plain_lyrics) - }, - None => { - match lrclib_response.plain_lyrics { - Some(unsynced_lyrics) => { - Response::UnsyncedLyrics(unsynced_lyrics) - } - None => { - if lrclib_response.instrumental { - Response::IsInstrumental - } else { - Response::None + pub fn from_raw_response(lrclib_response: RawResponse) -> Response { + match lrclib_response.synced_lyrics { + Some(synced_lyrics) => { + let plain_lyrics = match lrclib_response.plain_lyrics { + Some(plain_lyrics) => plain_lyrics, + None => strip_timestamp(&synced_lyrics), + }; + Response::SyncedLyrics(synced_lyrics, plain_lyrics) } - } + None => match lrclib_response.plain_lyrics { + Some(unsynced_lyrics) => Response::UnsyncedLyrics(unsynced_lyrics), + None => { + if lrclib_response.instrumental { + Response::IsInstrumental + } else { + Response::None + } + } + }, } - } } - } } #[derive(Error, Deserialize, Debug)] #[serde(rename_all = "camelCase")] #[error("{error}: {message}")] pub struct ResponseError { - status_code: Option, - error: String, - message: String + status_code: Option, + error: String, + message: String, } async fn make_request(id: i64, lrclib_instance: &str) -> Result { - let version = env!("CARGO_PKG_VERSION"); - let user_agent = format!("LRCGET v{} (https://github.com/tranxuanthang/lrcget)", version); - let client = reqwest::Client::builder() - .timeout(Duration::from_secs(10)) - .user_agent(user_agent) - .build()?; - let api_endpoint = format!("{}/api/get/{}", lrclib_instance.trim_end_matches('/'), id); - Ok(client.get(&api_endpoint).send().await?) + let version = env!("CARGO_PKG_VERSION"); + let user_agent = format!( + "LRCGET v{} (https://github.com/tranxuanthang/lrcget)", + version + ); + let client = reqwest::Client::builder() + .timeout(Duration::from_secs(10)) + .user_agent(user_agent) + .build()?; + let api_endpoint = format!("{}/api/get/{}", lrclib_instance.trim_end_matches('/'), id); + Ok(client.get(&api_endpoint).send().await?) } pub async fn request_raw(id: i64, lrclib_instance: &str) -> Result { - let res = make_request(id, lrclib_instance).await?; - - match res.status() { - reqwest::StatusCode::OK => { - let lrclib_response = res.json::().await?; - - if lrclib_response.synced_lyrics.is_some() || lrclib_response.plain_lyrics.is_some() || lrclib_response.instrumental { - Ok(lrclib_response) - } else { - Err(ResponseError { - status_code: Some(404), - error: "NotFound".to_string(), - message: "There is no lyrics for this track".to_string() - }.into()) - } - } + let res = make_request(id, lrclib_instance).await?; - reqwest::StatusCode::NOT_FOUND => { - Err(ResponseError { - status_code: Some(404), - error: "NotFound".to_string(), - message: "There is no lyrics for this track".to_string() - }.into()) - } + match res.status() { + reqwest::StatusCode::OK => { + let lrclib_response = res.json::().await?; - reqwest::StatusCode::BAD_REQUEST | reqwest::StatusCode::SERVICE_UNAVAILABLE | reqwest::StatusCode::INTERNAL_SERVER_ERROR => { - let error = res.json::().await?; - Err(error.into()) - }, - - _ => { - Err(ResponseError { - status_code: None, - error: "UnknownError".to_string(), - message: "Unknown error happened".to_string() - }.into()) + if lrclib_response.synced_lyrics.is_some() + || lrclib_response.plain_lyrics.is_some() + || lrclib_response.instrumental + { + Ok(lrclib_response) + } else { + Err(ResponseError { + status_code: Some(404), + error: "NotFound".to_string(), + message: "There is no lyrics for this track".to_string(), + } + .into()) + } + } + + reqwest::StatusCode::NOT_FOUND => Err(ResponseError { + status_code: Some(404), + error: "NotFound".to_string(), + message: "There is no lyrics for this track".to_string(), + } + .into()), + + reqwest::StatusCode::BAD_REQUEST + | reqwest::StatusCode::SERVICE_UNAVAILABLE + | reqwest::StatusCode::INTERNAL_SERVER_ERROR => { + let error = res.json::().await?; + Err(error.into()) + } + + _ => Err(ResponseError { + status_code: None, + error: "UnknownError".to_string(), + message: "Unknown error happened".to_string(), + } + .into()), } - } } pub async fn request(id: i64, lrclib_instance: &str) -> Result { - let res = make_request(id, lrclib_instance).await?; + let res = make_request(id, lrclib_instance).await?; - match res.status() { - reqwest::StatusCode::OK => { - let lrclib_response = res.json::().await?; + match res.status() { + reqwest::StatusCode::OK => { + let lrclib_response = res.json::().await?; - Ok(Response::from_raw_response(lrclib_response)) - }, + Ok(Response::from_raw_response(lrclib_response)) + } - reqwest::StatusCode::NOT_FOUND => { - Ok(Response::None) - } + reqwest::StatusCode::NOT_FOUND => Ok(Response::None), + + reqwest::StatusCode::BAD_REQUEST + | reqwest::StatusCode::SERVICE_UNAVAILABLE + | reqwest::StatusCode::INTERNAL_SERVER_ERROR => { + let error = res.json::().await?; + Err(error.into()) + } - reqwest::StatusCode::BAD_REQUEST | reqwest::StatusCode::SERVICE_UNAVAILABLE | reqwest::StatusCode::INTERNAL_SERVER_ERROR => { - let error = res.json::().await?; - Err(error.into()) - }, - - _ => { - Err(ResponseError { - status_code: None, - error: "UnknownError".to_string(), - message: "Unknown error happened".to_string() - }.into()) + _ => Err(ResponseError { + status_code: None, + error: "UnknownError".to_string(), + message: "Unknown error happened".to_string(), + } + .into()), } - } } diff --git a/src-tauri/src/lrclib/publish.rs b/src-tauri/src/lrclib/publish.rs index ea6d3f9..fa5c37e 100644 --- a/src-tauri/src/lrclib/publish.rs +++ b/src-tauri/src/lrclib/publish.rs @@ -1,66 +1,82 @@ use std::time::Duration; -use serde::{Deserialize,Serialize}; use anyhow::Result; use reqwest; +use serde::{Deserialize, Serialize}; use thiserror::Error; #[derive(Serialize)] #[serde(rename_all = "camelCase")] pub struct Request { - track_name: String, - album_name: String, - artist_name: String, - duration: f64, - plain_lyrics: String, - synced_lyrics: String + track_name: String, + album_name: String, + artist_name: String, + duration: f64, + plain_lyrics: String, + synced_lyrics: String, } #[derive(Error, Deserialize, Debug)] #[serde(rename_all = "camelCase")] #[error("{error}: {message}")] pub struct ResponseError { - status_code: Option, - error: String, - message: String + status_code: Option, + error: String, + message: String, } -pub async fn request(title: &str, album_name: &str, artist_name: &str, duration: f64, plain_lyrics: &str, synced_lyrics: &str, publish_token: &str, lrclib_instance: &str) -> Result<()> { - let data = Request { - artist_name: artist_name.to_owned(), - track_name: title.to_owned(), - album_name: album_name.to_owned(), - duration: duration.round(), - plain_lyrics: plain_lyrics.to_owned(), - synced_lyrics: synced_lyrics.to_owned(), - }; +pub async fn request( + title: &str, + album_name: &str, + artist_name: &str, + duration: f64, + plain_lyrics: &str, + synced_lyrics: &str, + publish_token: &str, + lrclib_instance: &str, +) -> Result<()> { + let data = Request { + artist_name: artist_name.to_owned(), + track_name: title.to_owned(), + album_name: album_name.to_owned(), + duration: duration.round(), + plain_lyrics: plain_lyrics.to_owned(), + synced_lyrics: synced_lyrics.to_owned(), + }; - let version = env!("CARGO_PKG_VERSION"); - let user_agent = format!("LRCGET v{} (https://github.com/tranxuanthang/lrcget)", version); - let client = reqwest::Client::builder() - .timeout(Duration::from_secs(10)) - .user_agent(user_agent) - .build()?; - let api_endpoint = format!("{}/api/publish", lrclib_instance.trim_end_matches('/')); - let url = reqwest::Url::parse(&api_endpoint)?; - let res = client.post(url).header("X-Publish-Token", publish_token).json(&data).send().await?; + let version = env!("CARGO_PKG_VERSION"); + let user_agent = format!( + "LRCGET v{} (https://github.com/tranxuanthang/lrcget)", + version + ); + let client = reqwest::Client::builder() + .timeout(Duration::from_secs(10)) + .user_agent(user_agent) + .build()?; + let api_endpoint = format!("{}/api/publish", lrclib_instance.trim_end_matches('/')); + let url = reqwest::Url::parse(&api_endpoint)?; + let res = client + .post(url) + .header("X-Publish-Token", publish_token) + .json(&data) + .send() + .await?; - match res.status() { - reqwest::StatusCode::CREATED => { - Ok(()) - }, + match res.status() { + reqwest::StatusCode::CREATED => Ok(()), - reqwest::StatusCode::BAD_REQUEST | reqwest::StatusCode::SERVICE_UNAVAILABLE | reqwest::StatusCode::INTERNAL_SERVER_ERROR => { - let error = res.json::().await?; - Err(error.into()) - }, + reqwest::StatusCode::BAD_REQUEST + | reqwest::StatusCode::SERVICE_UNAVAILABLE + | reqwest::StatusCode::INTERNAL_SERVER_ERROR => { + let error = res.json::().await?; + Err(error.into()) + } - _ => { - Err(ResponseError { - status_code: None, - error: "UnknownError".to_string(), - message: "Unknown error happened".to_string() - }.into()) + _ => Err(ResponseError { + status_code: None, + error: "UnknownError".to_string(), + message: "Unknown error happened".to_string(), + } + .into()), } - } } diff --git a/src-tauri/src/lrclib/request_challenge.rs b/src-tauri/src/lrclib/request_challenge.rs index bd951e6..d5a9ed0 100644 --- a/src-tauri/src/lrclib/request_challenge.rs +++ b/src-tauri/src/lrclib/request_challenge.rs @@ -1,54 +1,61 @@ use std::time::Duration; -use serde::Deserialize; use anyhow::Result; use reqwest; +use serde::Deserialize; use thiserror::Error; #[derive(Deserialize)] #[serde(rename_all = "camelCase")] pub struct Response { - pub prefix: String, - pub target: String + pub prefix: String, + pub target: String, } #[derive(Error, Deserialize, Debug)] #[serde(rename_all = "camelCase")] #[error("{error}: {message}")] pub struct ResponseError { - status_code: Option, - error: String, - message: String + status_code: Option, + error: String, + message: String, } pub async fn request(lrclib_instance: &str) -> Result { - let version = env!("CARGO_PKG_VERSION"); - let user_agent = format!("LRCGET v{} (https://github.com/tranxuanthang/lrcget)", version); - let client = reqwest::Client::builder() - .timeout(Duration::from_secs(10)) - .user_agent(user_agent) - .build()?; - let api_endpoint = format!("{}/api/request-challenge", lrclib_instance.trim_end_matches('/')); - let url = reqwest::Url::parse(&api_endpoint)?; - let res = client.post(url).send().await?; + let version = env!("CARGO_PKG_VERSION"); + let user_agent = format!( + "LRCGET v{} (https://github.com/tranxuanthang/lrcget)", + version + ); + let client = reqwest::Client::builder() + .timeout(Duration::from_secs(10)) + .user_agent(user_agent) + .build()?; + let api_endpoint = format!( + "{}/api/request-challenge", + lrclib_instance.trim_end_matches('/') + ); + let url = reqwest::Url::parse(&api_endpoint)?; + let res = client.post(url).send().await?; - match res.status() { - reqwest::StatusCode::OK => { - let response = res.json::().await?; - Ok(response) - }, + match res.status() { + reqwest::StatusCode::OK => { + let response = res.json::().await?; + Ok(response) + } - reqwest::StatusCode::BAD_REQUEST | reqwest::StatusCode::SERVICE_UNAVAILABLE | reqwest::StatusCode::INTERNAL_SERVER_ERROR => { - let error = res.json::().await?; - Err(error.into()) - }, + reqwest::StatusCode::BAD_REQUEST + | reqwest::StatusCode::SERVICE_UNAVAILABLE + | reqwest::StatusCode::INTERNAL_SERVER_ERROR => { + let error = res.json::().await?; + Err(error.into()) + } - _ => { - Err(ResponseError { - status_code: None, - error: "UnknownError".to_string(), - message: "Unknown error happened".to_string() - }.into()) + _ => Err(ResponseError { + status_code: None, + error: "UnknownError".to_string(), + message: "Unknown error happened".to_string(), + } + .into()), } - } } diff --git a/src-tauri/src/lrclib/search.rs b/src-tauri/src/lrclib/search.rs index 09bcad4..94bdf12 100644 --- a/src-tauri/src/lrclib/search.rs +++ b/src-tauri/src/lrclib/search.rs @@ -1,21 +1,21 @@ use std::time::Duration; -use serde::{Deserialize,Serialize}; use anyhow::Result; use reqwest; +use serde::{Deserialize, Serialize}; use thiserror::Error; #[derive(Deserialize, Serialize)] #[serde(rename_all = "camelCase")] struct SearchItem { - id: i64, - name: Option, - artist_name: Option, - album_name: Option, - duration: Option, - instrumental: bool, - plain_lyrics: Option, - synced_lyrics: Option, + id: i64, + name: Option, + artist_name: Option, + album_name: Option, + duration: Option, + instrumental: bool, + plain_lyrics: Option, + synced_lyrics: Option, } #[derive(Deserialize, Serialize)] @@ -25,47 +25,56 @@ pub struct Response(Vec); #[serde(rename_all = "camelCase")] #[error("{error}: {message}")] pub struct ResponseError { - status_code: Option, - error: String, - message: String + status_code: Option, + error: String, + message: String, } -pub async fn request(title: &str, album_name: &str, artist_name: &str, q: &str, lrclib_instance: &str) -> Result { - let params: Vec<(String, String)> = vec![ - ("track_name".to_owned(), title.to_owned()), - ("artist_name".to_owned(), artist_name.to_owned()), - ("album_name".to_owned(), album_name.to_owned()), - ("q".to_owned(), q.to_owned()) - ]; +pub async fn request( + title: &str, + album_name: &str, + artist_name: &str, + q: &str, + lrclib_instance: &str, +) -> Result { + let params: Vec<(String, String)> = vec![ + ("track_name".to_owned(), title.to_owned()), + ("artist_name".to_owned(), artist_name.to_owned()), + ("album_name".to_owned(), album_name.to_owned()), + ("q".to_owned(), q.to_owned()), + ]; + let version = env!("CARGO_PKG_VERSION"); + let user_agent = format!( + "LRCGET v{} (https://github.com/tranxuanthang/lrcget)", + version + ); + let client = reqwest::Client::builder() + .timeout(Duration::from_secs(10)) + .user_agent(user_agent) + .build()?; + let api_endpoint = format!("{}/api/search", lrclib_instance.trim_end_matches('/')); + let url = reqwest::Url::parse_with_params(&api_endpoint, ¶ms)?; + let res = client.get(url).send().await?; - let version = env!("CARGO_PKG_VERSION"); - let user_agent = format!("LRCGET v{} (https://github.com/tranxuanthang/lrcget)", version); - let client = reqwest::Client::builder() - .timeout(Duration::from_secs(10)) - .user_agent(user_agent) - .build()?; - let api_endpoint = format!("{}/api/search", lrclib_instance.trim_end_matches('/')); - let url = reqwest::Url::parse_with_params(&api_endpoint, ¶ms)?; - let res = client.get(url).send().await?; + match res.status() { + reqwest::StatusCode::OK => { + let lrclib_response = res.json::().await?; + Ok(lrclib_response) + } - match res.status() { - reqwest::StatusCode::OK => { - let lrclib_response = res.json::().await?; - Ok(lrclib_response) - }, + reqwest::StatusCode::BAD_REQUEST + | reqwest::StatusCode::SERVICE_UNAVAILABLE + | reqwest::StatusCode::INTERNAL_SERVER_ERROR => { + let error = res.json::().await?; + Err(error.into()) + } - reqwest::StatusCode::BAD_REQUEST | reqwest::StatusCode::SERVICE_UNAVAILABLE | reqwest::StatusCode::INTERNAL_SERVER_ERROR => { - let error = res.json::().await?; - Err(error.into()) - }, - - _ => { - Err(ResponseError { - status_code: None, - error: "UnknownError".to_string(), - message: "Unknown error happened".to_string() - }.into()) + _ => Err(ResponseError { + status_code: None, + error: "UnknownError".to_string(), + message: "Unknown error happened".to_string(), + } + .into()), } - } } diff --git a/src-tauri/src/lyrics.rs b/src-tauri/src/lyrics.rs index df58896..0bc4da2 100644 --- a/src-tauri/src/lyrics.rs +++ b/src-tauri/src/lyrics.rs @@ -1,116 +1,135 @@ +use crate::lrclib::get::request; +use crate::lrclib::get::Response; +use crate::persistent_entities::PersistentTrack; use anyhow::Result; use lofty::{ - config::{ParseOptions, WriteOptions}, - file::AudioFile, - flac::FlacFile, - id3::v2::{ - BinaryFrame, Frame, FrameId, Id3v2Tag, SyncTextContentType, - SynchronizedTextFrame, TimestampFormat, UnsynchronizedTextFrame, - }, - mpeg::MpegFile, - TextEncoding, + config::{ParseOptions, WriteOptions}, + file::AudioFile, + flac::FlacFile, + id3::v2::{ + BinaryFrame, Frame, FrameId, Id3v2Tag, SyncTextContentType, SynchronizedTextFrame, + TimestampFormat, UnsynchronizedTextFrame, + }, + mpeg::MpegFile, + TextEncoding, }; +use lrc::Lyrics; use std::fs::{remove_file, write, OpenOptions}; -use std::path::PathBuf; use std::path::Path; -use crate::lrclib::get::request; -use crate::lrclib::get::Response; -use crate::persistent_entities::PersistentTrack; +use std::path::PathBuf; use thiserror::Error; -use lrc::Lyrics; #[derive(Error, Clone, Debug)] pub enum GetLyricsError { - #[error("This track does not exist in LRCLIB database")] - NotFound + #[error("This track does not exist in LRCLIB database")] + NotFound, } -pub async fn download_lyrics_for_track(track: PersistentTrack, is_try_embed_lyrics: bool, lrclib_instance: &str) -> Result { - let lyrics = request(&track.title, &track.album_name, &track.artist_name, track.duration, lrclib_instance).await?; - - apply_lyrics_for_track(track, lyrics, is_try_embed_lyrics).await +pub async fn download_lyrics_for_track( + track: PersistentTrack, + is_try_embed_lyrics: bool, + lrclib_instance: &str, +) -> Result { + let lyrics = request( + &track.title, + &track.album_name, + &track.artist_name, + track.duration, + lrclib_instance, + ) + .await?; + + apply_lyrics_for_track(track, lyrics, is_try_embed_lyrics).await } -pub async fn apply_string_lyrics_for_track(track: &PersistentTrack, plain_lyrics: &str, synced_lyrics: &str, is_try_embed_lyrics: bool) -> Result<()> { - save_plain_lyrics(&track.file_path, plain_lyrics)?; - save_synced_lyrics(&track.file_path, synced_lyrics)?; +pub async fn apply_string_lyrics_for_track( + track: &PersistentTrack, + plain_lyrics: &str, + synced_lyrics: &str, + is_try_embed_lyrics: bool, +) -> Result<()> { + save_plain_lyrics(&track.file_path, plain_lyrics)?; + save_synced_lyrics(&track.file_path, synced_lyrics)?; - if is_try_embed_lyrics { - embed_lyrics(&track.file_path, &plain_lyrics, &synced_lyrics); - } + if is_try_embed_lyrics { + embed_lyrics(&track.file_path, &plain_lyrics, &synced_lyrics); + } - Ok(()) + Ok(()) } -pub async fn apply_lyrics_for_track(track: PersistentTrack, lyrics: Response, is_try_embed_lyrics: bool) -> Result { - match &lyrics { - Response::SyncedLyrics(synced_lyrics, plain_lyrics) => { - save_synced_lyrics(&track.file_path, &synced_lyrics)?; - if is_try_embed_lyrics { - embed_lyrics(&track.file_path, &plain_lyrics, &synced_lyrics); - } - Ok(lyrics) - } - Response::UnsyncedLyrics(plain_lyrics) => { - save_plain_lyrics(&track.file_path, &plain_lyrics)?; - if is_try_embed_lyrics { - embed_lyrics(&track.file_path, &plain_lyrics, ""); - } - Ok(lyrics) - } - Response::IsInstrumental => { - save_instrumental(&track.file_path)?; - Ok(lyrics) - } - _ => { - Ok(lyrics) +pub async fn apply_lyrics_for_track( + track: PersistentTrack, + lyrics: Response, + is_try_embed_lyrics: bool, +) -> Result { + match &lyrics { + Response::SyncedLyrics(synced_lyrics, plain_lyrics) => { + save_synced_lyrics(&track.file_path, &synced_lyrics)?; + if is_try_embed_lyrics { + embed_lyrics(&track.file_path, &plain_lyrics, &synced_lyrics); + } + Ok(lyrics) + } + Response::UnsyncedLyrics(plain_lyrics) => { + save_plain_lyrics(&track.file_path, &plain_lyrics)?; + if is_try_embed_lyrics { + embed_lyrics(&track.file_path, &plain_lyrics, ""); + } + Ok(lyrics) + } + Response::IsInstrumental => { + save_instrumental(&track.file_path)?; + Ok(lyrics) + } + _ => Ok(lyrics), } - } } fn save_plain_lyrics(track_path: &str, lyrics: &str) -> Result<()> { - let txt_path = build_txt_path(track_path)?; - let lrc_path = build_lrc_path(track_path)?; + let txt_path = build_txt_path(track_path)?; + let lrc_path = build_lrc_path(track_path)?; - let _ = remove_file(lrc_path); + let _ = remove_file(lrc_path); - if lyrics.is_empty() { - let _ = remove_file(txt_path); - } else { - write(txt_path, lyrics)?; - } - Ok(()) + if lyrics.is_empty() { + let _ = remove_file(txt_path); + } else { + write(txt_path, lyrics)?; + } + Ok(()) } fn save_synced_lyrics(track_path: &str, lyrics: &str) -> Result<()> { - let txt_path = build_txt_path(track_path)?; - let lrc_path = build_lrc_path(track_path)?; - if lyrics.is_empty() { - let _ = remove_file(lrc_path); - } else { - let _ = remove_file(txt_path); - write(lrc_path, lyrics)?; - } - Ok(()) + let txt_path = build_txt_path(track_path)?; + let lrc_path = build_lrc_path(track_path)?; + if lyrics.is_empty() { + let _ = remove_file(lrc_path); + } else { + let _ = remove_file(txt_path); + write(lrc_path, lyrics)?; + } + Ok(()) } fn save_instrumental(track_path: &str) -> Result<()> { - let txt_path = build_txt_path(track_path)?; - let lrc_path = build_lrc_path(track_path)?; + let txt_path = build_txt_path(track_path)?; + let lrc_path = build_lrc_path(track_path)?; - let _ = remove_file(&lrc_path); - let _ = remove_file(txt_path); + let _ = remove_file(&lrc_path); + let _ = remove_file(txt_path); - write(lrc_path, "[au: instrumental]")?; + write(lrc_path, "[au: instrumental]")?; - Ok(()) + Ok(()) } fn build_txt_path(track_path: &str) -> Result { let path = Path::new(track_path); let parent_path = path.parent().unwrap(); let file_name_without_extension = path.file_stem().unwrap().to_str().unwrap(); - let txt_path = Path::new(parent_path).join(format!("{}.{}", file_name_without_extension, "txt")); + let txt_path = + Path::new(parent_path).join(format!("{}.{}", file_name_without_extension, "txt")); Ok(txt_path) } @@ -119,115 +138,113 @@ fn build_lrc_path(track_path: &str) -> Result { let path = Path::new(track_path); let parent_path = path.parent().unwrap(); let file_name_without_extension = path.file_stem().unwrap().to_str().unwrap(); - let lrc_path = Path::new(parent_path).join(format!("{}.{}", file_name_without_extension, "lrc")); + let lrc_path = + Path::new(parent_path).join(format!("{}.{}", file_name_without_extension, "lrc")); Ok(lrc_path) } fn embed_lyrics(track_path: &str, plain_lyrics: &str, synced_lyrics: &str) { - if track_path.to_lowercase().ends_with(".mp3") { - match embed_lyrics_mp3(track_path, plain_lyrics, synced_lyrics) { - Ok(_) => (), - Err(e) => println!("Error embedding lyrics in MP3: {}", e), - } - } else if track_path.to_lowercase().ends_with(".flac") { - match embed_lyrics_flac(track_path, plain_lyrics, synced_lyrics) { - Ok(_) => (), - Err(e) => println!("Error embedding lyrics in FLAC: {}", e), + if track_path.to_lowercase().ends_with(".mp3") { + match embed_lyrics_mp3(track_path, plain_lyrics, synced_lyrics) { + Ok(_) => (), + Err(e) => println!("Error embedding lyrics in MP3: {}", e), + } + } else if track_path.to_lowercase().ends_with(".flac") { + match embed_lyrics_flac(track_path, plain_lyrics, synced_lyrics) { + Ok(_) => (), + Err(e) => println!("Error embedding lyrics in FLAC: {}", e), + } } - } } fn embed_lyrics_flac(track_path: &str, plain_lyrics: &str, synced_lyrics: &str) -> Result<()> { - let mut file_content = OpenOptions::new() - .read(true) - .write(true) - .open(track_path)?; - let mut flac_file = FlacFile::read_from(&mut file_content, ParseOptions::new())?; - - if let Some(vorbis_comments) = flac_file.vorbis_comments_mut() { - if !plain_lyrics.is_empty() { - vorbis_comments.insert("UNSYNCEDLYRICS".to_string(), plain_lyrics.to_string()); - } else { - let _ = vorbis_comments.remove("UNSYNCEDLYRICS"); - } - - if !synced_lyrics.is_empty() { - vorbis_comments.insert("LYRICS".to_string(), synced_lyrics.to_string()); - } else { - let _ = vorbis_comments.remove("LYRICS"); + let mut file_content = OpenOptions::new().read(true).write(true).open(track_path)?; + let mut flac_file = FlacFile::read_from(&mut file_content, ParseOptions::new())?; + + if let Some(vorbis_comments) = flac_file.vorbis_comments_mut() { + if !plain_lyrics.is_empty() { + vorbis_comments.insert("UNSYNCEDLYRICS".to_string(), plain_lyrics.to_string()); + } else { + let _ = vorbis_comments.remove("UNSYNCEDLYRICS"); + } + + if !synced_lyrics.is_empty() { + vorbis_comments.insert("LYRICS".to_string(), synced_lyrics.to_string()); + } else { + let _ = vorbis_comments.remove("LYRICS"); + } + + flac_file.save_to_path(track_path, WriteOptions::default())?; } - flac_file.save_to_path(track_path, WriteOptions::default())?; - } - - Ok(()) + Ok(()) } fn embed_lyrics_mp3(track_path: &str, plain_lyrics: &str, synced_lyrics: &str) -> Result<()> { - let mut file_content = OpenOptions::new() - .read(true) - .write(true) - .open(track_path)?; - let mut mp3_file = MpegFile::read_from(&mut file_content, ParseOptions::new())?; + let mut file_content = OpenOptions::new().read(true).write(true).open(track_path)?; + let mut mp3_file = MpegFile::read_from(&mut file_content, ParseOptions::new())?; - if let Some(id3v2) = mp3_file.id3v2_mut() { - insert_id3v2_uslt_frame(id3v2, plain_lyrics)?; - insert_id3v2_sylt_frame(id3v2, synced_lyrics)?; + if let Some(id3v2) = mp3_file.id3v2_mut() { + insert_id3v2_uslt_frame(id3v2, plain_lyrics)?; + insert_id3v2_sylt_frame(id3v2, synced_lyrics)?; - mp3_file.save_to_path(track_path, WriteOptions::default())?; - } + mp3_file.save_to_path(track_path, WriteOptions::default())?; + } - Ok(()) + Ok(()) } fn insert_id3v2_uslt_frame(id3v2: &mut Id3v2Tag, plain_lyrics: &str) -> Result<()> { - if !plain_lyrics.is_empty() { - let uslt_frame = UnsynchronizedTextFrame::new( - TextEncoding::UTF8, - [b'X', b'X', b'X'], - "".to_string(), - plain_lyrics.to_string() - ); - id3v2.insert(Frame::UnsynchronizedText(uslt_frame)); - } else { - let _ = id3v2.remove(&FrameId::new("USLT")?); - } - - Ok(()) + if !plain_lyrics.is_empty() { + let uslt_frame = UnsynchronizedTextFrame::new( + TextEncoding::UTF8, + [b'X', b'X', b'X'], + "".to_string(), + plain_lyrics.to_string(), + ); + id3v2.insert(Frame::UnsynchronizedText(uslt_frame)); + } else { + let _ = id3v2.remove(&FrameId::new("USLT")?); + } + + Ok(()) } fn insert_id3v2_sylt_frame(id3v2: &mut Id3v2Tag, synced_lyrics: &str) -> Result<()> { - if !synced_lyrics.is_empty() { - let synced_lyrics_vec = synced_lyrics_to_sylt_vec(synced_lyrics)?; - - let sylt_frame = SynchronizedTextFrame::new( - TextEncoding::UTF8, - [b'X', b'X', b'X'], - TimestampFormat::MS, - SyncTextContentType::Lyrics, - None, - synced_lyrics_vec - ); - - let sylt_frame_byte = sylt_frame.as_bytes()?; - let sylt_frame_id = FrameId::new("SYLT")?; - id3v2.insert(Frame::Binary(BinaryFrame::new(sylt_frame_id, sylt_frame_byte))); - } else { - let _ = id3v2.remove(&FrameId::new("SYLT")?); - } - - Ok(()) + if !synced_lyrics.is_empty() { + let synced_lyrics_vec = synced_lyrics_to_sylt_vec(synced_lyrics)?; + + let sylt_frame = SynchronizedTextFrame::new( + TextEncoding::UTF8, + [b'X', b'X', b'X'], + TimestampFormat::MS, + SyncTextContentType::Lyrics, + None, + synced_lyrics_vec, + ); + + let sylt_frame_byte = sylt_frame.as_bytes()?; + let sylt_frame_id = FrameId::new("SYLT")?; + id3v2.insert(Frame::Binary(BinaryFrame::new( + sylt_frame_id, + sylt_frame_byte, + ))); + } else { + let _ = id3v2.remove(&FrameId::new("SYLT")?); + } + + Ok(()) } fn synced_lyrics_to_sylt_vec(synced_lyrics: &str) -> Result> { - let lyrics = Lyrics::from_str(synced_lyrics)?; - let lyrics_vec = lyrics.get_timed_lines(); + let lyrics = Lyrics::from_str(synced_lyrics)?; + let lyrics_vec = lyrics.get_timed_lines(); - let converted_lyrics: Vec<(u32, String)> = lyrics_vec - .iter() - .map(|(time_tag, text)| (time_tag.get_timestamp() as u32, text.to_string())) - .collect(); + let converted_lyrics: Vec<(u32, String)> = lyrics_vec + .iter() + .map(|(time_tag, text)| (time_tag.get_timestamp() as u32, text.to_string())) + .collect(); - Ok(converted_lyrics) + Ok(converted_lyrics) } diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index 2f71b8f..7035454 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -1,126 +1,151 @@ #![cfg_attr( - all(not(debug_assertions), target_os = "windows"), - windows_subsystem = "windows" + all(not(debug_assertions), target_os = "windows"), + windows_subsystem = "windows" )] pub mod db; pub mod fs_track; pub mod library; -pub mod persistent_entities; pub mod lrclib; pub mod lyrics; -pub mod state; +pub mod persistent_entities; pub mod player; +pub mod state; pub mod utils; -use persistent_entities::{PersistentTrack, PersistentAlbum, PersistentArtist, PersistentConfig}; +use persistent_entities::{PersistentAlbum, PersistentArtist, PersistentConfig, PersistentTrack}; use player::Player; -use tauri::{State, Manager, AppHandle}; +use regex::Regex; use rusqlite::Connection; -use state::{AppState, ServiceAccess}; use serde::Serialize; -use regex::Regex; +use state::{AppState, ServiceAccess}; +use tauri::{AppHandle, Manager, State, Emitter}; #[derive(Clone, Serialize)] #[serde(rename_all = "camelCase")] struct PublishLyricsProgress { - request_challenge: String, - solve_challenge: String, - publish_lyrics: String + request_challenge: String, + solve_challenge: String, + publish_lyrics: String, } #[derive(Clone, Serialize)] #[serde(rename_all = "camelCase")] struct FlagLyricsProgress { - request_challenge: String, - solve_challenge: String, - flag_lyrics: String + request_challenge: String, + solve_challenge: String, + flag_lyrics: String, } #[tauri::command] async fn get_directories(app_state: State<'_, AppState>) -> Result, String> { - let conn_guard = app_state.db.lock().unwrap(); - let conn = conn_guard.as_ref().unwrap(); - let directories = db::get_directories(conn); - match directories { - Ok(directories) => Ok(directories), - Err(error) => Err(format!("Cannot get existing directories from database. Error: {}", error)) - } + let conn_guard = app_state.db.lock().unwrap(); + let conn = conn_guard.as_ref().unwrap(); + let directories = db::get_directories(conn); + match directories { + Ok(directories) => Ok(directories), + Err(error) => Err(format!( + "Cannot get existing directories from database. Error: {}", + error + )), + } } #[tauri::command] -async fn set_directories(directories: Vec, app_state: State<'_, AppState>) -> Result<(), String> { - let conn_guard = app_state.db.lock().unwrap(); - let conn = conn_guard.as_ref().unwrap(); - db::set_directories(directories, conn).map_err(|err| err.to_string())?; +async fn set_directories( + directories: Vec, + app_state: State<'_, AppState>, +) -> Result<(), String> { + let conn_guard = app_state.db.lock().unwrap(); + let conn = conn_guard.as_ref().unwrap(); + db::set_directories(directories, conn).map_err(|err| err.to_string())?; - Ok(()) + Ok(()) } #[tauri::command] async fn get_init(app_state: State<'_, AppState>) -> Result { - let conn_guard = app_state.db.lock().unwrap(); - let conn = conn_guard.as_ref().unwrap(); - let init = library::get_init(conn).map_err(|err| err.to_string())?; + let conn_guard = app_state.db.lock().unwrap(); + let conn = conn_guard.as_ref().unwrap(); + let init = library::get_init(conn).map_err(|err| err.to_string())?; - Ok(init) + Ok(init) } #[tauri::command] async fn get_config(app_state: State<'_, AppState>) -> Result { - let conn_guard = app_state.db.lock().unwrap(); - let conn = conn_guard.as_ref().unwrap(); - let config = db::get_config(conn).map_err(|err| err.to_string())?; + let conn_guard = app_state.db.lock().unwrap(); + let conn = conn_guard.as_ref().unwrap(); + let config = db::get_config(conn).map_err(|err| err.to_string())?; - Ok(config) + Ok(config) } #[tauri::command] -async fn set_config(skip_not_needed_tracks: bool, try_embed_lyrics: bool, theme_mode: &str, lrclib_instance: &str, app_state: State<'_, AppState>) -> Result<(), String> { - let conn_guard = app_state.db.lock().unwrap(); - let conn = conn_guard.as_ref().unwrap(); - db::set_config(skip_not_needed_tracks, try_embed_lyrics, theme_mode, lrclib_instance, conn).map_err(|err| err.to_string())?; +async fn set_config( + skip_not_needed_tracks: bool, + try_embed_lyrics: bool, + theme_mode: &str, + lrclib_instance: &str, + app_state: State<'_, AppState>, +) -> Result<(), String> { + let conn_guard = app_state.db.lock().unwrap(); + let conn = conn_guard.as_ref().unwrap(); + db::set_config( + skip_not_needed_tracks, + try_embed_lyrics, + theme_mode, + lrclib_instance, + conn, + ) + .map_err(|err| err.to_string())?; - Ok(()) + Ok(()) } #[tauri::command] -async fn initialize_library(app_state: State<'_, AppState>, app_handle: AppHandle) -> Result<(), String> { - let mut conn_guard = app_state.db.lock().unwrap(); - let conn = conn_guard.as_mut().unwrap(); - library::initialize_library(conn, app_handle).map_err(|err| err.to_string())?; +async fn initialize_library( + app_state: State<'_, AppState>, + app_handle: AppHandle, +) -> Result<(), String> { + let mut conn_guard = app_state.db.lock().unwrap(); + let conn = conn_guard.as_mut().unwrap(); + library::initialize_library(conn, app_handle).map_err(|err| err.to_string())?; - Ok(()) + Ok(()) } #[tauri::command] async fn uninitialize_library(app_state: State<'_, AppState>) -> Result<(), String> { - let conn_guard = app_state.db.lock().unwrap(); - let conn = conn_guard.as_ref().unwrap(); + let conn_guard = app_state.db.lock().unwrap(); + let conn = conn_guard.as_ref().unwrap(); - library::uninitialize_library(conn).map_err(|err| err.to_string())?; + library::uninitialize_library(conn).map_err(|err| err.to_string())?; - Ok(()) + Ok(()) } #[tauri::command] -async fn refresh_library(app_state: State<'_, AppState>, app_handle: AppHandle) -> Result<(), String> { - let mut conn_guard = app_state.db.lock().unwrap(); - let conn = conn_guard.as_mut().unwrap(); +async fn refresh_library( + app_state: State<'_, AppState>, + app_handle: AppHandle, +) -> Result<(), String> { + let mut conn_guard = app_state.db.lock().unwrap(); + let conn = conn_guard.as_mut().unwrap(); - library::uninitialize_library(conn).map_err(|err| err.to_string())?; - library::initialize_library(conn, app_handle).map_err(|err| err.to_string())?; + library::uninitialize_library(conn).map_err(|err| err.to_string())?; + library::initialize_library(conn, app_handle).map_err(|err| err.to_string())?; - Ok(()) + Ok(()) } #[tauri::command] async fn get_tracks(app_state: State<'_, AppState>) -> Result, String> { - let conn_guard = app_state.db.lock().unwrap(); - let conn = conn_guard.as_ref().unwrap(); - let tracks = library::get_tracks(conn).map_err(|err| err.to_string())?; + let conn_guard = app_state.db.lock().unwrap(); + let conn = conn_guard.as_ref().unwrap(); + let tracks = library::get_tracks(conn).map_err(|err| err.to_string())?; - Ok(tracks) + Ok(tracks) } #[tauri::command] @@ -128,445 +153,633 @@ async fn get_track_ids( search_query: Option, app_state: State<'_, AppState>, ) -> Result, String> { - let conn_guard = app_state.db.lock().unwrap(); - let conn = conn_guard.as_ref().unwrap(); - let search_query = search_query.filter(|s| !s.is_empty()); - let track_ids = library::get_track_ids(search_query, conn) - .map_err(|err| err.to_string())?; + let conn_guard = app_state.db.lock().unwrap(); + let conn = conn_guard.as_ref().unwrap(); + let search_query = search_query.filter(|s| !s.is_empty()); + let track_ids = library::get_track_ids(search_query, conn).map_err(|err| err.to_string())?; - Ok(track_ids) + Ok(track_ids) } #[tauri::command] async fn get_no_lyrics_track_ids(app_state: State<'_, AppState>) -> Result, String> { - let conn_guard = app_state.db.lock().unwrap(); - let conn = conn_guard.as_ref().unwrap(); - let track_ids = library::get_no_lyrics_track_ids(conn).map_err(|err| err.to_string())?; + let conn_guard = app_state.db.lock().unwrap(); + let conn = conn_guard.as_ref().unwrap(); + let track_ids = library::get_no_lyrics_track_ids(conn).map_err(|err| err.to_string())?; - Ok(track_ids) + Ok(track_ids) } #[tauri::command] -async fn get_track(track_id: i64, app_state: State<'_, AppState>) -> Result { - let conn_guard = app_state.db.lock().unwrap(); - let conn = conn_guard.as_ref().unwrap(); - let track = library::get_track(track_id, conn).map_err(|err| err.to_string())?; +async fn get_track( + track_id: i64, + app_state: State<'_, AppState>, +) -> Result { + let conn_guard = app_state.db.lock().unwrap(); + let conn = conn_guard.as_ref().unwrap(); + let track = library::get_track(track_id, conn).map_err(|err| err.to_string())?; - Ok(track) + Ok(track) } - #[tauri::command] async fn get_albums(app_state: State<'_, AppState>) -> Result, String> { - let conn_guard = app_state.db.lock().unwrap(); - let conn = conn_guard.as_ref().unwrap(); - let albums = library::get_albums(conn).map_err(|err| err.to_string())?; + let conn_guard = app_state.db.lock().unwrap(); + let conn = conn_guard.as_ref().unwrap(); + let albums = library::get_albums(conn).map_err(|err| err.to_string())?; - Ok(albums) + Ok(albums) } #[tauri::command] async fn get_album_ids(app_state: State<'_, AppState>) -> Result, String> { - let conn_guard = app_state.db.lock().unwrap(); - let conn = conn_guard.as_ref().unwrap(); - let album_ids = library::get_album_ids(conn).map_err(|err| err.to_string())?; + let conn_guard = app_state.db.lock().unwrap(); + let conn = conn_guard.as_ref().unwrap(); + let album_ids = library::get_album_ids(conn).map_err(|err| err.to_string())?; - Ok(album_ids) + Ok(album_ids) } #[tauri::command] -async fn get_album(album_id: i64, app_state: State<'_, AppState>) -> Result { - let conn_guard = app_state.db.lock().unwrap(); - let conn = conn_guard.as_ref().unwrap(); - let album = library::get_album(album_id, conn).map_err(|err| err.to_string())?; +async fn get_album( + album_id: i64, + app_state: State<'_, AppState>, +) -> Result { + let conn_guard = app_state.db.lock().unwrap(); + let conn = conn_guard.as_ref().unwrap(); + let album = library::get_album(album_id, conn).map_err(|err| err.to_string())?; - Ok(album) + Ok(album) } #[tauri::command] async fn get_artists(app_state: State<'_, AppState>) -> Result, String> { - let conn_guard = app_state.db.lock().unwrap(); - let conn = conn_guard.as_ref().unwrap(); - let artists = library::get_artists(conn).map_err(|err| err.to_string())?; + let conn_guard = app_state.db.lock().unwrap(); + let conn = conn_guard.as_ref().unwrap(); + let artists = library::get_artists(conn).map_err(|err| err.to_string())?; - Ok(artists) + Ok(artists) } #[tauri::command] async fn get_artist_ids(app_state: State<'_, AppState>) -> Result, String> { - let conn_guard = app_state.db.lock().unwrap(); - let conn = conn_guard.as_ref().unwrap(); - let artist_ids = library::get_artist_ids(conn).map_err(|err| err.to_string())?; + let conn_guard = app_state.db.lock().unwrap(); + let conn = conn_guard.as_ref().unwrap(); + let artist_ids = library::get_artist_ids(conn).map_err(|err| err.to_string())?; - Ok(artist_ids) + Ok(artist_ids) } #[tauri::command] -async fn get_artist(artist_id: i64, app_state: State<'_, AppState>) -> Result { - let conn_guard = app_state.db.lock().unwrap(); - let conn = conn_guard.as_ref().unwrap(); - let artist = library::get_artist(artist_id, conn).map_err(|err| err.to_string())?; +async fn get_artist( + artist_id: i64, + app_state: State<'_, AppState>, +) -> Result { + let conn_guard = app_state.db.lock().unwrap(); + let conn = conn_guard.as_ref().unwrap(); + let artist = library::get_artist(artist_id, conn).map_err(|err| err.to_string())?; - Ok(artist) + Ok(artist) } #[tauri::command] -async fn get_album_tracks(album_id: i64, app_state: State<'_, AppState>) -> Result, String> { - let conn_guard = app_state.db.lock().unwrap(); - let conn = conn_guard.as_ref().unwrap(); - let tracks = library::get_album_tracks(album_id, conn).map_err(|err| err.to_string())?; +async fn get_album_tracks( + album_id: i64, + app_state: State<'_, AppState>, +) -> Result, String> { + let conn_guard = app_state.db.lock().unwrap(); + let conn = conn_guard.as_ref().unwrap(); + let tracks = library::get_album_tracks(album_id, conn).map_err(|err| err.to_string())?; - Ok(tracks) + Ok(tracks) } #[tauri::command] -async fn get_artist_tracks(artist_id: i64, app_state: State<'_, AppState>) -> Result, String> { - let conn_guard = app_state.db.lock().unwrap(); - let conn = conn_guard.as_ref().unwrap(); - let tracks = library::get_artist_tracks(artist_id, conn).map_err(|err| err.to_string())?; +async fn get_artist_tracks( + artist_id: i64, + app_state: State<'_, AppState>, +) -> Result, String> { + let conn_guard = app_state.db.lock().unwrap(); + let conn = conn_guard.as_ref().unwrap(); + let tracks = library::get_artist_tracks(artist_id, conn).map_err(|err| err.to_string())?; - Ok(tracks) + Ok(tracks) } #[tauri::command] -async fn get_album_track_ids(album_id: i64, app_state: State<'_, AppState>) -> Result, String> { - let conn_guard = app_state.db.lock().unwrap(); - let conn = conn_guard.as_ref().unwrap(); - let track_ids = library::get_album_track_ids(album_id, conn).map_err(|err| err.to_string())?; +async fn get_album_track_ids( + album_id: i64, + app_state: State<'_, AppState>, +) -> Result, String> { + let conn_guard = app_state.db.lock().unwrap(); + let conn = conn_guard.as_ref().unwrap(); + let track_ids = library::get_album_track_ids(album_id, conn).map_err(|err| err.to_string())?; - Ok(track_ids) + Ok(track_ids) } #[tauri::command] -async fn get_artist_track_ids(artist_id: i64, app_state: State<'_, AppState>) -> Result, String> { - let conn_guard = app_state.db.lock().unwrap(); - let conn = conn_guard.as_ref().unwrap(); - let track_ids = library::get_artist_track_ids(artist_id, conn).map_err(|err| err.to_string())?; +async fn get_artist_track_ids( + artist_id: i64, + app_state: State<'_, AppState>, +) -> Result, String> { + let conn_guard = app_state.db.lock().unwrap(); + let conn = conn_guard.as_ref().unwrap(); + let track_ids = + library::get_artist_track_ids(artist_id, conn).map_err(|err| err.to_string())?; - Ok(track_ids) + Ok(track_ids) } #[tauri::command] async fn download_lyrics(track_id: i64, app_handle: AppHandle) -> Result { - let track = app_handle.db(|db| db::get_track_by_id(track_id, db)).map_err(|err| err.to_string())?; - let config = app_handle.db(|db| db::get_config(db)).map_err(|err| err.to_string())?; - let lyrics = lyrics::download_lyrics_for_track(track, config.try_embed_lyrics, &config.lrclib_instance).await.map_err(|err| err.to_string())?; - match lyrics { - lrclib::get::Response::SyncedLyrics(synced_lyrics, plain_lyrics) => { - app_handle.db(|db: &Connection| db::update_track_synced_lyrics(track_id, &synced_lyrics, &plain_lyrics, db)).map_err(|err| err.to_string())?; - app_handle.emit_all("reload-track-id", track_id).unwrap(); - Ok("Synced lyrics downloaded".to_owned()) - } - lrclib::get::Response::UnsyncedLyrics(plain_lyrics) => { - app_handle.db(|db: &Connection| db::update_track_plain_lyrics(track_id, &plain_lyrics, db)).map_err(|err| err.to_string())?; - app_handle.emit_all("reload-track-id", track_id).unwrap(); - Ok("Plain lyrics downloaded".to_owned()) - } - lrclib::get::Response::IsInstrumental => { - app_handle.db(|db: &Connection| db::update_track_instrumental(track_id, db)).map_err(|err| err.to_string())?; - Ok("Marked track as instrumental".to_owned()) - } - lrclib::get::Response::None => { - Err(lyrics::GetLyricsError::NotFound.to_string()) + let track = app_handle + .db(|db| db::get_track_by_id(track_id, db)) + .map_err(|err| err.to_string())?; + let config = app_handle + .db(|db| db::get_config(db)) + .map_err(|err| err.to_string())?; + let lyrics = + lyrics::download_lyrics_for_track(track, config.try_embed_lyrics, &config.lrclib_instance) + .await + .map_err(|err| err.to_string())?; + match lyrics { + lrclib::get::Response::SyncedLyrics(synced_lyrics, plain_lyrics) => { + app_handle + .db(|db: &Connection| { + db::update_track_synced_lyrics(track_id, &synced_lyrics, &plain_lyrics, db) + }) + .map_err(|err| err.to_string())?; + app_handle.emit("reload-track-id", track_id).unwrap(); + Ok("Synced lyrics downloaded".to_owned()) + } + lrclib::get::Response::UnsyncedLyrics(plain_lyrics) => { + app_handle + .db(|db: &Connection| db::update_track_plain_lyrics(track_id, &plain_lyrics, db)) + .map_err(|err| err.to_string())?; + app_handle.emit("reload-track-id", track_id).unwrap(); + Ok("Plain lyrics downloaded".to_owned()) + } + lrclib::get::Response::IsInstrumental => { + app_handle + .db(|db: &Connection| db::update_track_instrumental(track_id, db)) + .map_err(|err| err.to_string())?; + Ok("Marked track as instrumental".to_owned()) + } + lrclib::get::Response::None => Err(lyrics::GetLyricsError::NotFound.to_string()), } - } } #[tauri::command] -async fn apply_lyrics(track_id: i64, lrclib_response: lrclib::get::RawResponse, app_handle: AppHandle) -> Result { - let track = app_handle.db(|db| db::get_track_by_id(track_id, db)).map_err(|err| err.to_string())?; - let is_try_embed_lyrics = app_handle.db(|db| db::get_config(db)).map_err(|err| err.to_string())?.try_embed_lyrics; - - let lyrics = lrclib::get::Response::from_raw_response(lrclib_response); - let lyrics = lyrics::apply_lyrics_for_track(track, lyrics, is_try_embed_lyrics).await.map_err(|err| err.to_string())?; - - match lyrics { - lrclib::get::Response::SyncedLyrics(synced_lyrics, plain_lyrics) => { - app_handle.db(|db: &Connection| db::update_track_synced_lyrics(track_id, &synced_lyrics, &plain_lyrics, db)).map_err(|err| err.to_string())?; - std::thread::spawn(move || { - app_handle.emit_all("reload-track-id", track_id).unwrap(); - }); - Ok("Synced lyrics downloaded".to_owned()) - } - lrclib::get::Response::UnsyncedLyrics(plain_lyrics) => { - app_handle.db(|db: &Connection| db::update_track_plain_lyrics(track_id, &plain_lyrics, db)).map_err(|err| err.to_string())?; - std::thread::spawn(move || { - app_handle.emit_all("reload-track-id", track_id).unwrap(); - }); - Ok("Plain lyrics downloaded".to_owned()) - } - lrclib::get::Response::IsInstrumental => { - app_handle.db(|db: &Connection| db::update_track_instrumental(track_id, db)).map_err(|err| err.to_string())?; - Ok("Marked track as instrumental".to_owned()) - } - lrclib::get::Response::None => { - Err(lyrics::GetLyricsError::NotFound.to_string()) +async fn apply_lyrics( + track_id: i64, + lrclib_response: lrclib::get::RawResponse, + app_handle: AppHandle, +) -> Result { + let track = app_handle + .db(|db| db::get_track_by_id(track_id, db)) + .map_err(|err| err.to_string())?; + let is_try_embed_lyrics = app_handle + .db(|db| db::get_config(db)) + .map_err(|err| err.to_string())? + .try_embed_lyrics; + + let lyrics = lrclib::get::Response::from_raw_response(lrclib_response); + let lyrics = lyrics::apply_lyrics_for_track(track, lyrics, is_try_embed_lyrics) + .await + .map_err(|err| err.to_string())?; + + match lyrics { + lrclib::get::Response::SyncedLyrics(synced_lyrics, plain_lyrics) => { + app_handle + .db(|db: &Connection| { + db::update_track_synced_lyrics(track_id, &synced_lyrics, &plain_lyrics, db) + }) + .map_err(|err| err.to_string())?; + std::thread::spawn(move || { + app_handle.emit("reload-track-id", track_id).unwrap(); + }); + Ok("Synced lyrics downloaded".to_owned()) + } + lrclib::get::Response::UnsyncedLyrics(plain_lyrics) => { + app_handle + .db(|db: &Connection| db::update_track_plain_lyrics(track_id, &plain_lyrics, db)) + .map_err(|err| err.to_string())?; + std::thread::spawn(move || { + app_handle.emit("reload-track-id", track_id).unwrap(); + }); + Ok("Plain lyrics downloaded".to_owned()) + } + lrclib::get::Response::IsInstrumental => { + app_handle + .db(|db: &Connection| db::update_track_instrumental(track_id, db)) + .map_err(|err| err.to_string())?; + Ok("Marked track as instrumental".to_owned()) + } + lrclib::get::Response::None => Err(lyrics::GetLyricsError::NotFound.to_string()), } - } } #[tauri::command] -async fn retrieve_lyrics(title: String, album_name: String, artist_name: String, duration: f64, app_handle: AppHandle) -> Result { - let config = app_handle.db(|db: &Connection| db::get_config(db)).map_err(|err| err.to_string())?; - - let response = lrclib::get::request_raw(&title, &album_name, &artist_name, duration, &config.lrclib_instance).await.map_err(|err| err.to_string())?; +async fn retrieve_lyrics( + title: String, + album_name: String, + artist_name: String, + duration: f64, + app_handle: AppHandle, +) -> Result { + let config = app_handle + .db(|db: &Connection| db::get_config(db)) + .map_err(|err| err.to_string())?; + + let response = lrclib::get::request_raw( + &title, + &album_name, + &artist_name, + duration, + &config.lrclib_instance, + ) + .await + .map_err(|err| err.to_string())?; - Ok(response) + Ok(response) } #[tauri::command] -async fn retrieve_lyrics_by_id(id: i64, app_handle: AppHandle) -> Result { - let config = app_handle.db(|db: &Connection| db::get_config(db)).map_err(|err| err.to_string())?; +async fn retrieve_lyrics_by_id( + id: i64, + app_handle: AppHandle, +) -> Result { + let config = app_handle + .db(|db: &Connection| db::get_config(db)) + .map_err(|err| err.to_string())?; - let response = lrclib::get_by_id::request_raw(id, &config.lrclib_instance).await.map_err(|err| err.to_string())?; + let response = lrclib::get_by_id::request_raw(id, &config.lrclib_instance) + .await + .map_err(|err| err.to_string())?; - Ok(response) + Ok(response) } #[tauri::command] -async fn search_lyrics(title: String, album_name: String, artist_name: String, q: String, app_handle: AppHandle) -> Result { - let config = app_handle.db(|db: &Connection| db::get_config(db)).map_err(|err| err.to_string())?; - let response = lrclib::search::request(&title, &album_name, &artist_name, &q, &config.lrclib_instance).await.map_err(|err| err.to_string())?; - - Ok(response) -} - -#[tauri::command] -async fn save_lyrics(track_id: i64, plain_lyrics: String, synced_lyrics: String, app_handle: AppHandle) -> Result { - let track = app_handle.db(|db| db::get_track_by_id(track_id, db)).map_err(|err| err.to_string())?; - let is_try_embed_lyrics = app_handle.db(|db| db::get_config(db)).map_err(|err| err.to_string())?.try_embed_lyrics; - - // Create a regex to match "[au: instrumental]" or "[au:instrumental]" - let re = Regex::new(r"\[au:\s*instrumental\]").expect("Invalid regex"); - let is_instrumental = re.is_match(&synced_lyrics); - - lyrics::apply_string_lyrics_for_track(&track, &plain_lyrics, &synced_lyrics, is_try_embed_lyrics).await.map_err(|err| err.to_string())?; - - if is_instrumental { - app_handle.db(|db: &Connection| db::update_track_instrumental(track.id, db)).map_err(|err| err.to_string())?; - } else if !synced_lyrics.is_empty() { - app_handle.db(|db: &Connection| db::update_track_synced_lyrics(track.id, &synced_lyrics, &plain_lyrics, db)).map_err(|err| err.to_string())?; - } else if !plain_lyrics.is_empty() { - app_handle.db(|db: &Connection| db::update_track_plain_lyrics(track.id, &plain_lyrics, db)).map_err(|err| err.to_string())?; - } else { - app_handle.db(|db: &Connection| db::update_track_null_lyrics(track.id, db)).map_err(|err| err.to_string())?; - } - - app_handle.emit_all("reload-track-id", track_id).unwrap(); - - Ok("Lyrics saved successfully".to_owned()) -} - -#[tauri::command] -async fn publish_lyrics(title: String, album_name: String, artist_name: String, duration: f64, plain_lyrics: String, synced_lyrics: String, app_handle: AppHandle) -> Result<(), String> { - let config = app_handle.db(|db: &Connection| db::get_config(db)).map_err(|err| err.to_string())?; +async fn search_lyrics( + title: String, + album_name: String, + artist_name: String, + q: String, + app_handle: AppHandle, +) -> Result { + let config = app_handle + .db(|db: &Connection| db::get_config(db)) + .map_err(|err| err.to_string())?; + let response = lrclib::search::request( + &title, + &album_name, + &artist_name, + &q, + &config.lrclib_instance, + ) + .await + .map_err(|err| err.to_string())?; - let mut progress = PublishLyricsProgress { - request_challenge: "Pending".to_owned(), - solve_challenge: "Pending".to_owned(), - publish_lyrics: "Pending".to_owned() - }; - progress.request_challenge = "In Progress".to_owned(); - app_handle.emit_all("publish-lyrics-progress", &progress).unwrap(); - let challenge_response = lrclib::request_challenge::request(&config.lrclib_instance).await.map_err(|err| err.to_string())?; - progress.request_challenge = "Done".to_owned(); - progress.solve_challenge = "In Progress".to_owned(); - app_handle.emit_all("publish-lyrics-progress", &progress).unwrap(); - let nonce = lrclib::challenge_solver::solve_challenge(&challenge_response.prefix, &challenge_response.target); - progress.solve_challenge = "Done".to_owned(); - progress.publish_lyrics = "In Progress".to_owned(); - app_handle.emit_all("publish-lyrics-progress", &progress).unwrap(); - let publish_token = format!("{}:{}", challenge_response.prefix, nonce); - lrclib::publish::request(&title, &album_name, &artist_name, duration, &plain_lyrics, &synced_lyrics, &publish_token, &config.lrclib_instance).await.map_err(|err| err.to_string())?; - progress.publish_lyrics = "Done".to_owned(); - app_handle.emit_all("publish-lyrics-progress", &progress).unwrap(); - Ok(()) -} + Ok(response) +} + +#[tauri::command] +async fn save_lyrics( + track_id: i64, + plain_lyrics: String, + synced_lyrics: String, + app_handle: AppHandle, +) -> Result { + let track = app_handle + .db(|db| db::get_track_by_id(track_id, db)) + .map_err(|err| err.to_string())?; + let is_try_embed_lyrics = app_handle + .db(|db| db::get_config(db)) + .map_err(|err| err.to_string())? + .try_embed_lyrics; + + // Create a regex to match "[au: instrumental]" or "[au:instrumental]" + let re = Regex::new(r"\[au:\s*instrumental\]").expect("Invalid regex"); + let is_instrumental = re.is_match(&synced_lyrics); + + lyrics::apply_string_lyrics_for_track( + &track, + &plain_lyrics, + &synced_lyrics, + is_try_embed_lyrics, + ) + .await + .map_err(|err| err.to_string())?; -#[tauri::command] -async fn flag_lyrics(track_id: i64, flag_reason: String, app_handle: AppHandle) -> Result<(), String> { - let config = app_handle.db(|db: &Connection| db::get_config(db)).map_err(|err| err.to_string())?; + if is_instrumental { + app_handle + .db(|db: &Connection| db::update_track_instrumental(track.id, db)) + .map_err(|err| err.to_string())?; + } else if !synced_lyrics.is_empty() { + app_handle + .db(|db: &Connection| { + db::update_track_synced_lyrics(track.id, &synced_lyrics, &plain_lyrics, db) + }) + .map_err(|err| err.to_string())?; + } else if !plain_lyrics.is_empty() { + app_handle + .db(|db: &Connection| db::update_track_plain_lyrics(track.id, &plain_lyrics, db)) + .map_err(|err| err.to_string())?; + } else { + app_handle + .db(|db: &Connection| db::update_track_null_lyrics(track.id, db)) + .map_err(|err| err.to_string())?; + } - let mut progress = FlagLyricsProgress { - request_challenge: "Pending".to_owned(), - solve_challenge: "Pending".to_owned(), - flag_lyrics: "Pending".to_owned() - }; - progress.request_challenge = "In Progress".to_owned(); - app_handle.emit_all("flag-lyrics-progress", &progress).unwrap(); - let challenge_response = lrclib::request_challenge::request(&config.lrclib_instance).await.map_err(|err| err.to_string())?; - progress.request_challenge = "Done".to_owned(); - progress.solve_challenge = "In Progress".to_owned(); - app_handle.emit_all("flag-lyrics-progress", &progress).unwrap(); - let nonce = lrclib::challenge_solver::solve_challenge(&challenge_response.prefix, &challenge_response.target); - progress.solve_challenge = "Done".to_owned(); - progress.flag_lyrics = "In Progress".to_owned(); - app_handle.emit_all("flag-lyrics-progress", &progress).unwrap(); - let publish_token = format!("{}:{}", challenge_response.prefix, nonce); - lrclib::flag::request(track_id, &flag_reason, &publish_token, &config.lrclib_instance).await.map_err(|err| err.to_string())?; - progress.flag_lyrics = "Done".to_owned(); - app_handle.emit_all("flag-lyrics-progress", &progress).unwrap(); - Ok(()) + app_handle.emit("reload-track-id", track_id).unwrap(); + + Ok("Lyrics saved successfully".to_owned()) +} + +#[tauri::command] +async fn publish_lyrics( + title: String, + album_name: String, + artist_name: String, + duration: f64, + plain_lyrics: String, + synced_lyrics: String, + app_handle: AppHandle, +) -> Result<(), String> { + let config = app_handle + .db(|db: &Connection| db::get_config(db)) + .map_err(|err| err.to_string())?; + + let mut progress = PublishLyricsProgress { + request_challenge: "Pending".to_owned(), + solve_challenge: "Pending".to_owned(), + publish_lyrics: "Pending".to_owned(), + }; + progress.request_challenge = "In Progress".to_owned(); + app_handle + .emit("publish-lyrics-progress", &progress) + .unwrap(); + let challenge_response = lrclib::request_challenge::request(&config.lrclib_instance) + .await + .map_err(|err| err.to_string())?; + progress.request_challenge = "Done".to_owned(); + progress.solve_challenge = "In Progress".to_owned(); + app_handle + .emit("publish-lyrics-progress", &progress) + .unwrap(); + let nonce = lrclib::challenge_solver::solve_challenge( + &challenge_response.prefix, + &challenge_response.target, + ); + progress.solve_challenge = "Done".to_owned(); + progress.publish_lyrics = "In Progress".to_owned(); + app_handle + .emit("publish-lyrics-progress", &progress) + .unwrap(); + let publish_token = format!("{}:{}", challenge_response.prefix, nonce); + lrclib::publish::request( + &title, + &album_name, + &artist_name, + duration, + &plain_lyrics, + &synced_lyrics, + &publish_token, + &config.lrclib_instance, + ) + .await + .map_err(|err| err.to_string())?; + progress.publish_lyrics = "Done".to_owned(); + app_handle + .emit("publish-lyrics-progress", &progress) + .unwrap(); + Ok(()) +} + +#[tauri::command] +async fn flag_lyrics( + track_id: i64, + flag_reason: String, + app_handle: AppHandle, +) -> Result<(), String> { + let config = app_handle + .db(|db: &Connection| db::get_config(db)) + .map_err(|err| err.to_string())?; + + let mut progress = FlagLyricsProgress { + request_challenge: "Pending".to_owned(), + solve_challenge: "Pending".to_owned(), + flag_lyrics: "Pending".to_owned(), + }; + progress.request_challenge = "In Progress".to_owned(); + app_handle + .emit("flag-lyrics-progress", &progress) + .unwrap(); + let challenge_response = lrclib::request_challenge::request(&config.lrclib_instance) + .await + .map_err(|err| err.to_string())?; + progress.request_challenge = "Done".to_owned(); + progress.solve_challenge = "In Progress".to_owned(); + app_handle + .emit("flag-lyrics-progress", &progress) + .unwrap(); + let nonce = lrclib::challenge_solver::solve_challenge( + &challenge_response.prefix, + &challenge_response.target, + ); + progress.solve_challenge = "Done".to_owned(); + progress.flag_lyrics = "In Progress".to_owned(); + app_handle + .emit("flag-lyrics-progress", &progress) + .unwrap(); + let publish_token = format!("{}:{}", challenge_response.prefix, nonce); + lrclib::flag::request( + track_id, + &flag_reason, + &publish_token, + &config.lrclib_instance, + ) + .await + .map_err(|err| err.to_string())?; + progress.flag_lyrics = "Done".to_owned(); + app_handle + .emit("flag-lyrics-progress", &progress) + .unwrap(); + Ok(()) } #[tauri::command] -fn play_track(track_id: i64, app_state: tauri::State, app_handle: AppHandle) -> Result<(), String> { - let track = app_handle.db(|db| db::get_track_by_id(track_id, db)).map_err(|err| err.to_string())?; +fn play_track( + track_id: i64, + app_state: tauri::State, + app_handle: AppHandle, +) -> Result<(), String> { + let track = app_handle + .db(|db| db::get_track_by_id(track_id, db)) + .map_err(|err| err.to_string())?; - let mut player_guard = app_state.player.lock().unwrap(); + let mut player_guard = app_state.player.lock().unwrap(); - if let Some(ref mut player) = *player_guard { - player.play(track).map_err(|err| err.to_string())?; - } + if let Some(ref mut player) = *player_guard { + player.play(track).map_err(|err| err.to_string())?; + } - Ok(()) + Ok(()) } #[tauri::command] fn pause_track(app_state: tauri::State) -> Result<(), String> { - let mut player_guard = app_state.player.lock().map_err(|e| e.to_string())?; + let mut player_guard = app_state.player.lock().map_err(|e| e.to_string())?; - if let Some(ref mut player) = *player_guard { - player.pause(); - } + if let Some(ref mut player) = *player_guard { + player.pause(); + } - Ok(()) + Ok(()) } #[tauri::command] fn resume_track(app_state: tauri::State) -> Result<(), String> { - let mut player_guard = app_state.player.lock().map_err(|e| e.to_string())?; + let mut player_guard = app_state.player.lock().map_err(|e| e.to_string())?; - if let Some(ref mut player) = *player_guard { - player.resume(); - } + if let Some(ref mut player) = *player_guard { + player.resume(); + } - Ok(()) + Ok(()) } #[tauri::command] fn seek_track(position: f64, app_state: tauri::State) -> Result<(), String> { - let mut player_guard = app_state.player.lock().map_err(|e| e.to_string())?; + let mut player_guard = app_state.player.lock().map_err(|e| e.to_string())?; - if let Some(ref mut player) = *player_guard { - player.seek(position); - } + if let Some(ref mut player) = *player_guard { + player.seek(position); + } - Ok(()) + Ok(()) } #[tauri::command] fn stop_track(app_state: tauri::State) -> Result<(), String> { - let mut player_guard = app_state.player.lock().map_err(|e| e.to_string())?; + let mut player_guard = app_state.player.lock().map_err(|e| e.to_string())?; - if let Some(ref mut player) = *player_guard { - player.stop(); - } + if let Some(ref mut player) = *player_guard { + player.stop(); + } - Ok(()) + Ok(()) } #[tauri::command] fn set_volume(volume: f64, app_state: tauri::State) -> Result<(), String> { - let mut player_guard = app_state.player.lock().map_err(|e| e.to_string())?; + let mut player_guard = app_state.player.lock().map_err(|e| e.to_string())?; - if let Some(ref mut player) = *player_guard { - player.set_volume(volume); - } + if let Some(ref mut player) = *player_guard { + player.set_volume(volume); + } - Ok(()) + Ok(()) } #[tauri::command] -fn open_devtools(window: tauri::Window) { - { - window.open_devtools(); - } +fn open_devtools(app_handle: AppHandle) { + app_handle.get_webview_window("main").unwrap().open_devtools(); } #[tokio::main] async fn main() { - tauri::Builder::default() - .manage(AppState { db: Default::default(), player: Default::default() }) - .setup(|app| { - let handle = app.handle(); - - let app_state: State = handle.state(); - let db = db::initialize_database(&handle).expect("Database initialize should succeed"); - *app_state.db.lock().unwrap() = Some(db); - - let player = Player::new().expect("Failed to initialize audio player"); - *app_state.player.lock().unwrap() = Some(player); - - let handle_clone = handle.clone(); - - tokio::spawn(async move { - let mut interval = tokio::time::interval(std::time::Duration::from_millis(40)); - loop { - interval.tick().await; - { - let app_state: State = handle_clone.state(); - let player_guard = app_state.player.lock(); - - match player_guard { - Ok(mut player_guard) => { - if let Some(ref mut player) = *player_guard { - player.renew_state(); - - let emit_player_state = handle_clone.emit_all("player-state", &player); - - if let Err(e) = emit_player_state { - eprintln!("Failed to emit player state: {}", e); - } + tauri::Builder::default() + .plugin(tauri_plugin_dialog::init()) + .plugin(tauri_plugin_shell::init()) + .plugin(tauri_plugin_global_shortcut::Builder::new().build()) + .plugin(tauri_plugin_os::init()) + .manage(AppState { + db: Default::default(), + player: Default::default(), + }) + .setup(|app| { + let handle = app.handle(); + + let app_state: State = handle.state(); + let db = db::initialize_database(&handle).expect("Database initialize should succeed"); + *app_state.db.lock().unwrap() = Some(db); + + let player = Player::new().expect("Failed to initialize audio player"); + *app_state.player.lock().unwrap() = Some(player); + + let handle_clone = handle.clone(); + + tokio::spawn(async move { + let mut interval = tokio::time::interval(std::time::Duration::from_millis(40)); + loop { + interval.tick().await; + { + let app_state: State = handle_clone.state(); + let player_guard = app_state.player.lock(); + + match player_guard { + Ok(mut player_guard) => { + if let Some(ref mut player) = *player_guard { + player.renew_state(); + + let emit_player_state = + handle_clone.emit("player-state", &player); + + if let Err(e) = emit_player_state { + eprintln!("Failed to emit player state: {}", e); + } + } + } + Err(e) => eprintln!("Failed to lock player: {}", e), + } + } } - } - Err(e) => eprintln!("Failed to lock player: {}", e), - } - } - } - }); - - Ok(()) - }) - .invoke_handler(tauri::generate_handler![ - get_directories, - set_directories, - get_init, - get_config, - set_config, - initialize_library, - uninitialize_library, - refresh_library, - get_tracks, - get_track_ids, - get_no_lyrics_track_ids, - get_track, - get_albums, - get_album_ids, - get_album, - get_artists, - get_artist_ids, - get_artist, - get_album_tracks, - get_artist_tracks, - get_album_track_ids, - get_artist_track_ids, - download_lyrics, - apply_lyrics, - retrieve_lyrics, - retrieve_lyrics_by_id, - search_lyrics, - save_lyrics, - publish_lyrics, - flag_lyrics, - play_track, - pause_track, - resume_track, - seek_track, - stop_track, - set_volume, - open_devtools - ]) - .run(tauri::generate_context!()) - .expect("error while running tauri application"); + }); + + Ok(()) + }) + .invoke_handler(tauri::generate_handler![ + get_directories, + set_directories, + get_init, + get_config, + set_config, + initialize_library, + uninitialize_library, + refresh_library, + get_tracks, + get_track_ids, + get_no_lyrics_track_ids, + get_track, + get_albums, + get_album_ids, + get_album, + get_artists, + get_artist_ids, + get_artist, + get_album_tracks, + get_artist_tracks, + get_album_track_ids, + get_artist_track_ids, + download_lyrics, + apply_lyrics, + retrieve_lyrics, + retrieve_lyrics_by_id, + search_lyrics, + save_lyrics, + publish_lyrics, + flag_lyrics, + play_track, + pause_track, + resume_track, + seek_track, + stop_track, + set_volume, + open_devtools + ]) + .run(tauri::generate_context!()) + .expect("error while running tauri application"); } diff --git a/src-tauri/src/persistent_entities.rs b/src-tauri/src/persistent_entities.rs index 5724f14..23a4f47 100644 --- a/src-tauri/src/persistent_entities.rs +++ b/src-tauri/src/persistent_entities.rs @@ -2,45 +2,45 @@ use serde::Serialize; #[derive(Serialize)] pub struct PersistentTrack { - pub id: i64, - pub file_path: String, - pub file_name: String, - pub title: String, - pub album_name: String, - pub album_artist_name: Option, - pub album_id: i64, - pub artist_name: String, - pub artist_id: i64, - pub image_path: Option, - pub track_number: Option, - pub txt_lyrics: Option, - pub lrc_lyrics: Option, - pub duration: f64, - pub instrumental: bool + pub id: i64, + pub file_path: String, + pub file_name: String, + pub title: String, + pub album_name: String, + pub album_artist_name: Option, + pub album_id: i64, + pub artist_name: String, + pub artist_id: i64, + pub image_path: Option, + pub track_number: Option, + pub txt_lyrics: Option, + pub lrc_lyrics: Option, + pub duration: f64, + pub instrumental: bool, } #[derive(Serialize)] pub struct PersistentAlbum { - pub id: i64, - pub name: String, - pub image_path: Option, - pub artist_name: String, - pub album_artist_name: Option, - pub tracks_count: i64 + pub id: i64, + pub name: String, + pub image_path: Option, + pub artist_name: String, + pub album_artist_name: Option, + pub tracks_count: i64, } #[derive(Serialize)] pub struct PersistentArtist { - pub id: i64, - pub name: String, - // pub albums_count: i64, - pub tracks_count: i64 + pub id: i64, + pub name: String, + // pub albums_count: i64, + pub tracks_count: i64, } #[derive(Serialize)] pub struct PersistentConfig { - pub skip_not_needed_tracks: bool, - pub try_embed_lyrics: bool, - pub theme_mode: String, - pub lrclib_instance: String + pub skip_not_needed_tracks: bool, + pub try_embed_lyrics: bool, + pub theme_mode: String, + pub lrclib_instance: String, } diff --git a/src-tauri/src/player.rs b/src-tauri/src/player.rs index 14afa11..dbb926a 100644 --- a/src-tauri/src/player.rs +++ b/src-tauri/src/player.rs @@ -1,130 +1,131 @@ use anyhow::Result; use kira::{ - manager::{ - AudioManager, AudioManagerSettings, - backend::DefaultBackend, - }, - sound::{streaming::{StreamingSoundData, StreamingSoundHandle}, FromFileError, PlaybackState}, - tween::Tween + manager::{backend::DefaultBackend, AudioManager, AudioManagerSettings}, + sound::{ + streaming::{StreamingSoundData, StreamingSoundHandle}, + FromFileError, PlaybackState, + }, + tween::Tween, }; -use serde::Serialize; use crate::persistent_entities::PersistentTrack; +use serde::Serialize; #[derive(Serialize)] #[serde(rename_all = "snake_case")] pub enum PlayerStatus { - Playing, - Paused, - Stopped + Playing, + Paused, + Stopped, } #[derive(Serialize)] pub struct Player { - #[serde(skip)] - manager: AudioManager, - #[serde(skip)] - sound_handle: Option>, - #[serde(skip)] - pub track: Option, - pub status: PlayerStatus, - pub progress: f64, - pub duration: f64, - pub volume: f64 + #[serde(skip)] + manager: AudioManager, + #[serde(skip)] + sound_handle: Option>, + #[serde(skip)] + pub track: Option, + pub status: PlayerStatus, + pub progress: f64, + pub duration: f64, + pub volume: f64, } impl Player { - pub fn new() -> Result { - let manager = AudioManager::::new(AudioManagerSettings::default())?; - - Ok(Player { - manager, - sound_handle: None, - track: None, - status: PlayerStatus::Stopped, - progress: 0.0, - duration: 0.0, - volume: 1.0 - }) - } - - pub fn renew_state(&mut self) { - if let Some(ref mut sound_handle) = self.sound_handle { - match sound_handle.state() { - PlaybackState::Playing => self.status = PlayerStatus::Playing, - PlaybackState::Pausing => self.status = PlayerStatus::Playing, - PlaybackState::Stopping => self.status = PlayerStatus::Playing, - PlaybackState::Paused => self.status = PlayerStatus::Paused, - PlaybackState::Stopped => self.status = PlayerStatus::Stopped, - } - } else { - self.status = PlayerStatus::Stopped + pub fn new() -> Result { + let manager = AudioManager::::new(AudioManagerSettings::default())?; + + Ok(Player { + manager, + sound_handle: None, + track: None, + status: PlayerStatus::Stopped, + progress: 0.0, + duration: 0.0, + volume: 1.0, + }) } - match self.sound_handle { - Some(ref mut sound_handle) => { - self.progress = sound_handle.position(); - } - None => {} + pub fn renew_state(&mut self) { + if let Some(ref mut sound_handle) = self.sound_handle { + match sound_handle.state() { + PlaybackState::Playing => self.status = PlayerStatus::Playing, + PlaybackState::Pausing => self.status = PlayerStatus::Playing, + PlaybackState::Stopping => self.status = PlayerStatus::Playing, + PlaybackState::Paused => self.status = PlayerStatus::Paused, + PlaybackState::Stopped => self.status = PlayerStatus::Stopped, + } + } else { + self.status = PlayerStatus::Stopped + } + + match self.sound_handle { + Some(ref mut sound_handle) => { + self.progress = sound_handle.position(); + } + None => {} + } } - } - pub fn play(&mut self, track: PersistentTrack) -> Result<()> { - let _ = self.stop(); - self.track = Some(track); + pub fn play(&mut self, track: PersistentTrack) -> Result<()> { + let _ = self.stop(); + self.track = Some(track); - if let Some(ref mut track) = self.track { - let sound_data = StreamingSoundData::from_file( - &track.file_path, - )?; + if let Some(ref mut track) = self.track { + let sound_data = StreamingSoundData::from_file(&track.file_path)?; - self.duration = sound_data.duration().as_secs_f64(); - self.sound_handle = Some(self.manager.play(sound_data)?); - self.sound_handle.as_mut().unwrap().set_volume(self.volume, Tween::default()); - } + self.duration = sound_data.duration().as_secs_f64(); + self.sound_handle = Some(self.manager.play(sound_data)?); + self.sound_handle + .as_mut() + .unwrap() + .set_volume(self.volume, Tween::default()); + } - Ok(()) - } + Ok(()) + } - pub fn resume(&mut self) { - if let Some(ref mut sound_handle) = self.sound_handle { - sound_handle.resume(Tween::default()); + pub fn resume(&mut self) { + if let Some(ref mut sound_handle) = self.sound_handle { + sound_handle.resume(Tween::default()); + } } - } - pub fn pause(&mut self) { - if let Some(ref mut sound_handle) = self.sound_handle { - sound_handle.pause(Tween::default()); + pub fn pause(&mut self) { + if let Some(ref mut sound_handle) = self.sound_handle { + sound_handle.pause(Tween::default()); + } } - } - - pub fn seek(&mut self, position: f64) { - if let Some(ref mut sound_handle) = self.sound_handle { - match sound_handle.state() { - PlaybackState::Playing => sound_handle.seek_to(position), - _ => { - sound_handle.seek_to(position); - sound_handle.resume(Tween::default()); + + pub fn seek(&mut self, position: f64) { + if let Some(ref mut sound_handle) = self.sound_handle { + match sound_handle.state() { + PlaybackState::Playing => sound_handle.seek_to(position), + _ => { + sound_handle.seek_to(position); + sound_handle.resume(Tween::default()); + } + } } - } } - } - - pub fn stop(&mut self) { - if let Some(ref mut sound_handle) = self.sound_handle { - sound_handle.stop(Tween::default()); - self.sound_handle = None; - self.track = None; - self.duration = 0.0; - self.progress = 0.0; - self.status = PlayerStatus::Stopped; + + pub fn stop(&mut self) { + if let Some(ref mut sound_handle) = self.sound_handle { + sound_handle.stop(Tween::default()); + self.sound_handle = None; + self.track = None; + self.duration = 0.0; + self.progress = 0.0; + self.status = PlayerStatus::Stopped; + } } - } - pub fn set_volume(&mut self, volume: f64) { - if let Some(ref mut sound_handle) = self.sound_handle { - sound_handle.set_volume(volume, Tween::default()); + pub fn set_volume(&mut self, volume: f64) { + if let Some(ref mut sound_handle) = self.sound_handle { + sound_handle.set_volume(volume, Tween::default()); + } + self.volume = volume; } - self.volume = volume; - } } diff --git a/src-tauri/src/state.rs b/src-tauri/src/state.rs index 40edba6..2d5f3fe 100644 --- a/src-tauri/src/state.rs +++ b/src-tauri/src/state.rs @@ -1,33 +1,43 @@ use rusqlite::Connection; -use tauri::{AppHandle, State, Manager}; +use tauri::{AppHandle, Manager, State}; use crate::player::Player; pub struct AppState { - pub db: std::sync::Mutex>, - pub player: std::sync::Mutex>, + pub db: std::sync::Mutex>, + pub player: std::sync::Mutex>, } pub trait ServiceAccess { - fn db(&self, operation: F) -> TResult where F: FnOnce(&Connection) -> TResult; + fn db(&self, operation: F) -> TResult + where + F: FnOnce(&Connection) -> TResult; - fn db_mut(&self, operation: F) -> TResult where F: FnOnce(&mut Connection) -> TResult; + fn db_mut(&self, operation: F) -> TResult + where + F: FnOnce(&mut Connection) -> TResult; } impl ServiceAccess for AppHandle { - fn db(&self, operation: F) -> TResult where F: FnOnce(&Connection) -> TResult { - let app_state: State = self.state(); - let db_connection_guard = app_state.db.lock().unwrap(); - let db = db_connection_guard.as_ref().unwrap(); - - operation(db) - } - - fn db_mut(&self, operation: F) -> TResult where F: FnOnce(&mut Connection) -> TResult { - let app_state: State = self.state(); - let mut db_connection_guard = app_state.db.lock().unwrap(); - let db = db_connection_guard.as_mut().unwrap(); - - operation(db) - } + fn db(&self, operation: F) -> TResult + where + F: FnOnce(&Connection) -> TResult, + { + let app_state: State = self.state(); + let db_connection_guard = app_state.db.lock().unwrap(); + let db = db_connection_guard.as_ref().unwrap(); + + operation(db) + } + + fn db_mut(&self, operation: F) -> TResult + where + F: FnOnce(&mut Connection) -> TResult, + { + let app_state: State = self.state(); + let mut db_connection_guard = app_state.db.lock().unwrap(); + let db = db_connection_guard.as_mut().unwrap(); + + operation(db) + } } diff --git a/src-tauri/src/utils.rs b/src-tauri/src/utils.rs index a1e014b..5cac830 100644 --- a/src-tauri/src/utils.rs +++ b/src-tauri/src/utils.rs @@ -1,24 +1,24 @@ -use secular::lower_lay_string; -use regex::Regex; use collapse::collapse; +use regex::Regex; +use secular::lower_lay_string; pub fn prepare_input(input: &str) -> String { - let mut prepared_input = lower_lay_string(&input); + let mut prepared_input = lower_lay_string(&input); - let re = Regex::new(r#"[`~!@#$%^&*()_|+\-=?;:",.<>\{\}\[\]\\\/]"#).unwrap(); - prepared_input = re.replace_all(&prepared_input, " ").to_string(); + let re = Regex::new(r#"[`~!@#$%^&*()_|+\-=?;:",.<>\{\}\[\]\\\/]"#).unwrap(); + prepared_input = re.replace_all(&prepared_input, " ").to_string(); - let re = Regex::new(r#"['’]"#).unwrap(); - prepared_input = re.replace_all(&prepared_input, "").to_string(); + let re = Regex::new(r#"['’]"#).unwrap(); + prepared_input = re.replace_all(&prepared_input, "").to_string(); - prepared_input = prepared_input.to_lowercase(); - prepared_input = collapse(&prepared_input); + prepared_input = prepared_input.to_lowercase(); + prepared_input = collapse(&prepared_input); - prepared_input + prepared_input } pub fn strip_timestamp(synced_lyrics: &str) -> String { - let re = Regex::new(r"^\[(.*)\] *").unwrap(); - let plain_lyrics = re.replace_all(synced_lyrics, ""); - plain_lyrics.to_string() + let re = Regex::new(r"^\[(.*)\] *").unwrap(); + let plain_lyrics = re.replace_all(synced_lyrics, ""); + plain_lyrics.to_string() } diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index 037ca45..c1687e6 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -2,81 +2,52 @@ "build": { "beforeDevCommand": "npm run dev", "beforeBuildCommand": "npm run build", - "devPath": "http://localhost:1420", - "distDir": "../dist", - "withGlobalTauri": false + "frontendDist": "../dist", + "devUrl": "http://localhost:1420" }, - "package": { - "productName": "LRCGET" - }, - "tauri": { - "allowlist": { - "os": { - "all": true - }, - "window": { - "all": true - }, - "dialog": { - "all": true - }, - "globalShortcut": { - "all": true - }, - "path": { - "all": true - }, - "protocol": { - "all": true, - "asset": true, - "assetScope": ["**"] - }, - "shell": { - "open": true - } + "bundle": { + "active": true, + "category": "Music", + "copyright": "", + "windows": { + "certificateThumbprint": null, + "digestAlgorithm": "sha256", + "timestampUrl": "" }, - "bundle": { - "active": true, - "category": "Music", - "copyright": "", + "externalBin": [], + "icon": [ + "icons/32x32.png", + "icons/128x128.png", + "icons/128x128@2x.png", + "icons/icon.icns", + "icons/icon.ico" + ], + "linux": { "deb": { "depends": [] }, - "externalBin": [], - "icon": [ - "icons/32x32.png", - "icons/128x128.png", - "icons/128x128@2x.png", - "icons/icon.icns", - "icons/icon.ico" - ], - "identifier": "net.lrclib.lrcget", - "longDescription": "", - "macOS": { - "entitlements": null, - "exceptionDomain": "", - "frameworks": [], - "providerShortName": null, - "signingIdentity": null - }, - "resources": [], - "shortDescription": "Utility for mass-downloading LRC synced lyrics for your offline music library.", - "targets": "all", - "windows": { - "certificateThumbprint": null, - "digestAlgorithm": "sha256", - "timestampUrl": "" - }, "appimage": { "bundleMediaFramework": false } }, - "security": { - "csp": "default-src 'self'; img-src 'self' asset: https://asset.localhost; media-src *; connect-src 'self' asset: *; style-src 'unsafe-inline' 'self'" - }, - "updater": { - "active": false + "longDescription": "", + "macOS": { + "entitlements": null, + "exceptionDomain": "", + "frameworks": [], + "providerShortName": null, + "signingIdentity": null }, + "resources": [], + "shortDescription": "Utility for mass-downloading LRC synced lyrics for your offline music library.", + "targets": "all" + }, + "productName": "LRCGET", + "mainBinaryName": "LRCGET", + "identifier": "net.lrclib.lrcget", + "plugins": {}, + "app": { + "withGlobalTauri": false, "windows": [ { "fullscreen": false, @@ -87,8 +58,18 @@ "resizable": true, "title": "LRCGET", "decorations": true, - "transparent": false + "transparent": false, + "useHttpsScheme": true } - ] + ], + "security": { + "assetProtocol": { + "scope": [ + "**" + ], + "enable": true + }, + "csp": "default-src 'self'; img-src 'self' asset: https://asset.localhost; media-src *; connect-src ipc: http://ipc.localhost 'self' asset: *; style-src 'unsafe-inline' 'self'" + } } -} +} \ No newline at end of file diff --git a/src/App.vue b/src/App.vue index 6af7a4b..20f2e05 100644 --- a/src/App.vue +++ b/src/App.vue @@ -19,11 +19,12 @@ import { Bug, WindowMinimize, WindowMaximize, WindowClose } from 'mdue' import ChooseDirectory from "./components/ChooseDirectory.vue"; import Library from "./components/Library.vue"; import { ref, onMounted, watch } from 'vue' -import { appWindow } from '@tauri-apps/api/window' -import { invoke } from '@tauri-apps/api/tauri' +import { getCurrentWebviewWindow } from '@tauri-apps/api/webviewWindow' +import { invoke } from '@tauri-apps/api/core' import { ModalsContainer } from 'vue-final-modal' import { useGlobalState } from './composables/global-state' import { useDownloader } from '@/composables/downloader.js' +const appWindow = getCurrentWebviewWindow() const { themeMode, setThemeMode, setLrclibInstance } = useGlobalState() const { downloadNext } = useDownloader() diff --git a/src/components/ChooseDirectory.vue b/src/components/ChooseDirectory.vue index b263aae..1ffa73d 100644 --- a/src/components/ChooseDirectory.vue +++ b/src/components/ChooseDirectory.vue @@ -42,9 +42,9 @@