diff --git a/CHANGELOG.md b/CHANGELOG.md index a6a2366..3a785e9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,70 @@ -## ✨ 新功能 -- **歌手相关**: 添加歌曲的艺术家入口, 歌曲的艺术家现可点击查看其他歌曲、专辑和介绍 -- **歌曲评论**: 添加歌曲的评论查看功能 +## v0.4.0 -## 🐛 修复 +### ✨ 新功能 +- 添加歌曲的艺术家入口,歌曲的艺术家现可点击查看其他歌曲、专辑和介绍 +- 添加歌曲的评论查看功能 + +### 🐛 修复 - 修复私人漫游自动播放下一首调用多次问题 -## ⚡ 优化 -- 优化播放逻辑,歌曲列表在点击时候不在单首累加, 而是直接获取当前列表所有的歌曲作为播放内容 \ No newline at end of file +### ⚡ 优化 +- 优化播放逻辑,歌曲列表在点击时候不再单首累加,而是直接获取当前列表所有的歌曲作为播放内容 + + +## v0.3.0 + +### ✨ 新功能 +- **本地音乐页面**:支持浏览、播放本地歌曲,横向菜单添加「从磁盘删除」功能 +- **下载系统**:支持下载歌曲到自定义路径,保存完整元数据(封面/专辑/时长) +- **封面补全**:本地音乐缺少封面时尝试从网易云 API 获取 +- **更新信息**:添加查看最新版更新日志按钮 +- **下载路径**:支持自定义下载路径 +- **本地音乐**:支持本地音乐播放 +- **下载提示**:下载进度与完成提示 +- **快捷键绑定**:支持自定义全局和本地快捷键(播放/暂停、上一首/下一首、音量调节) + +### 🐛 修复 +- 修复私人漫游播完一首歌后跳三首的问题 +- 修复全屏漫游抽屉和漫游页面无封面歌曲显示破损图片 +- 修复 PlayerBar 无封面歌曲显示破损图片 +- 修复播放网络歌曲时进度条先走但无声音 + +### ⚡ 优化 +- **流式播放**:边下载边播放,缓冲 64KB 后即刻开始,无需等待完整下载 + + +## v0.2.0 + +### 🎵 播放 +- 优化私人漫游(个人 FM)功能 +- 新增歌曲喜欢/取消喜欢红心 +- 新增播放历史本地记录(最近 200 首) + +### 📋 歌单 +- 修改逻辑 我的歌单 不再显示收藏按钮 +- 收藏歌单支持取消收藏 +- 实现我的音乐功能 +- 实现历史播放记录功能 + +### 🎨 外观 +- 全局复选框与选择框优化 +- 部分UI优化,统一风格 + +### 🖥️ 窗口 +- 关闭窗口弹出确认弹窗:最小化到托盘 / 退出程序 +- 支持"不再询问"选项,可在设置中修改 +- 修复退出时 WebView2 报错(Error 1410) +- 修复歌词抽屉全屏时候顶栏无法接收事件问题 + +### 💾 持久化 +- Cookie 存储迁移至 Tauri app_data_dir +- 播放历史持久化到 localStorage + +### ⚙️ 其他 +- 添加设置功能 +- 关于添加链接可直接访问仓库 + + +## v0.1.0 + +Nekosonic 是一款基于 Tauri 2 + Rust 的跨平台桌面音乐播放器,音源主要来自网易云音乐,开箱即用。 \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 48d0018..440c14d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -27,7 +27,7 @@ "@types/node": "^25.6.0", "@types/qrcode": "^1.5.6", "@vicons/ionicons5": "^0.13.0", - "@vitejs/plugin-vue": "^5.2.4", + "@vitejs/plugin-vue": "^5.2.1", "@vueuse/motion": "^3.0.3", "tailwindcss": "^4.2.4", "typescript": "~5.6.2", diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 5b5af21..6743579 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -4,7 +4,7 @@ version = 4 [[package]] name = "Nekosonic" -version = "0.3.0" +version = "0.4.0" dependencies = [ "base64 0.22.1", "cpal", @@ -23,6 +23,7 @@ dependencies = [ "tauri-plugin-opener", "tauri-plugin-process", "tauri-plugin-single-instance", + "tauri-plugin-updater", "tokio", ] @@ -104,6 +105,15 @@ version = "1.0.102" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" +[[package]] +name = "arbitrary" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1" +dependencies = [ + "derive_arbitrary", +] + [[package]] name = "arrayvec" version = "0.7.6" @@ -731,7 +741,7 @@ dependencies = [ "core-foundation-sys", "coreaudio-rs", "dasp_sample", - "jni", + "jni 0.21.1", "js-sys", "libc", "mach2", @@ -904,6 +914,17 @@ dependencies = [ "serde_core", ] +[[package]] +name = "derive_arbitrary" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e567bd82dcff979e4b03460c307b3cdc9e96fde3d73bed1496d2bc75d9dd62a" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + [[package]] name = "derive_more" version = "2.1.1" @@ -1243,6 +1264,16 @@ dependencies = [ "rustc_version", ] +[[package]] +name = "filetime" +version = "0.2.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c287a33c7f0a620c38e641e7f60827713987b3c0f26e8ddc9462cc69cf75759" +dependencies = [ + "cfg-if", + "libc", +] + [[package]] name = "find-msvc-tools" version = "0.1.9" @@ -2162,6 +2193,36 @@ dependencies = [ "windows-sys 0.45.0", ] +[[package]] +name = "jni" +version = "0.22.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5efd9a482cf3a427f00d6b35f14332adc7902ce91efb778580e180ff90fa3498" +dependencies = [ + "cfg-if", + "combine", + "jni-macros", + "jni-sys 0.4.1", + "log", + "simd_cesu8", + "thiserror 2.0.18", + "walkdir", + "windows-link 0.2.1", +] + +[[package]] +name = "jni-macros" +version = "0.22.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a00109accc170f0bdb141fed3e393c565b6f5e072365c3bd58f5b062591560a3" +dependencies = [ + "proc-macro2", + "quote", + "rustc_version", + "simd_cesu8", + "syn 2.0.117", +] + [[package]] name = "jni-sys" version = "0.3.1" @@ -2467,6 +2528,12 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" +[[package]] +name = "minisign-verify" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22f9645cb765ea72b8111f36c522475d2daa0d22c957a9826437e97534bc4e9e" + [[package]] name = "miniz_oxide" version = "0.8.9" @@ -2827,6 +2894,18 @@ dependencies = [ "objc2-core-foundation", ] +[[package]] +name = "objc2-osa-kit" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f112d1746737b0da274ef79a23aac283376f335f4095a083a267a082f21db0c0" +dependencies = [ + "bitflags 2.11.1", + "objc2", + "objc2-app-kit", + "objc2-foundation", +] + [[package]] name = "objc2-quartz-core" version = "0.3.2" @@ -2890,7 +2969,7 @@ version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8b61bebd49e5d43f5f8cc7ee2891c16e0f41ec7954d36bcb6c14c5e0de867fb" dependencies = [ - "jni", + "jni 0.21.1", "ndk 0.8.0", "ndk-context", "num-derive", @@ -2943,6 +3022,12 @@ dependencies = [ "pathdiff", ] +[[package]] +name = "openssl-probe" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" + [[package]] name = "option-ext" version = "0.2.0" @@ -2959,6 +3044,20 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "osakit" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "732c71caeaa72c065bb69d7ea08717bd3f4863a4f451402fc9513e29dbd5261b" +dependencies = [ + "objc2", + "objc2-foundation", + "objc2-osa-kit", + "serde", + "serde_json", + "thiserror 2.0.18", +] + [[package]] name = "pango" version = "0.18.3" @@ -3644,15 +3743,20 @@ dependencies = [ "http-body", "http-body-util", "hyper", + "hyper-rustls", "hyper-util", "js-sys", "log", "percent-encoding", "pin-project-lite", + "rustls", + "rustls-pki-types", + "rustls-platform-verifier", "serde", "serde_json", "sync_wrapper", "tokio", + "tokio-rustls", "tokio-util", "tower", "tower-http", @@ -3777,6 +3881,18 @@ dependencies = [ "zeroize", ] +[[package]] +name = "rustls-native-certs" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "612460d5f7bea540c490b2b6395d8e34a953e52b491accd6c86c8164c5932a63" +dependencies = [ + "openssl-probe", + "rustls-pki-types", + "schannel", + "security-framework", +] + [[package]] name = "rustls-pki-types" version = "1.14.1" @@ -3787,6 +3903,33 @@ dependencies = [ "zeroize", ] +[[package]] +name = "rustls-platform-verifier" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d1e2536ce4f35f4846aa13bff16bd0ff40157cdb14cc056c7b14ba41233ba0" +dependencies = [ + "core-foundation", + "core-foundation-sys", + "jni 0.22.4", + "log", + "once_cell", + "rustls", + "rustls-native-certs", + "rustls-platform-verifier-android", + "rustls-webpki", + "security-framework", + "security-framework-sys", + "webpki-root-certs", + "windows-sys 0.61.2", +] + +[[package]] +name = "rustls-platform-verifier-android" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f" + [[package]] name = "rustls-webpki" version = "0.103.13" @@ -3819,6 +3962,15 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "schannel" +version = "0.1.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91c1b7e4904c873ef0710c1f407dde2e6287de2bebc1bbbf7d430bb7cbffd939" +dependencies = [ + "windows-sys 0.61.2", +] + [[package]] name = "schemars" version = "0.8.22" @@ -3876,6 +4028,29 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "security-framework" +version = "3.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d" +dependencies = [ + "bitflags 2.11.1", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2691df843ecc5d231c0b14ece2acc3efb62c0a398c7e1d875f3983ce020e3" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "selectors" version = "0.36.1" @@ -4117,6 +4292,22 @@ version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "703d5c7ef118737c72f1af64ad2f6f8c5e1921f818cdcb97b8fe6fc69bf66214" +[[package]] +name = "simd_cesu8" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94f90157bb87cddf702797c5dadfa0be7d266cdf49e22da2fcaa32eff75b2c33" +dependencies = [ + "rustc_version", + "simdutf8", +] + +[[package]] +name = "simdutf8" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" + [[package]] name = "siphasher" version = "1.0.3" @@ -4383,7 +4574,7 @@ dependencies = [ "gdkwayland-sys", "gdkx11-sys", "gtk", - "jni", + "jni 0.21.1", "libc", "log", "ndk 0.9.0", @@ -4416,6 +4607,17 @@ dependencies = [ "syn 2.0.117", ] +[[package]] +name = "tar" +version = "0.4.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22692a6476a21fa75fdfc11d452fda482af402c008cdbaf3476414e122040973" +dependencies = [ + "filetime", + "libc", + "xattr", +] + [[package]] name = "target-lexicon" version = "0.12.16" @@ -4439,7 +4641,7 @@ dependencies = [ "gtk", "heck 0.5.0", "http", - "jni", + "jni 0.21.1", "libc", "log", "mime", @@ -4655,6 +4857,39 @@ dependencies = [ "zbus", ] +[[package]] +name = "tauri-plugin-updater" +version = "2.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "806d9dac662c2e4594ff03c647a552f2c9bd544e7d0f683ec58f872f952ce4af" +dependencies = [ + "base64 0.22.1", + "dirs 6.0.0", + "flate2", + "futures-util", + "http", + "infer", + "log", + "minisign-verify", + "osakit", + "percent-encoding", + "reqwest 0.13.3", + "rustls", + "semver", + "serde", + "serde_json", + "tar", + "tauri", + "tauri-plugin", + "tempfile", + "thiserror 2.0.18", + "time", + "tokio", + "url", + "windows-sys 0.60.2", + "zip", +] + [[package]] name = "tauri-runtime" version = "2.11.0" @@ -4665,7 +4900,7 @@ dependencies = [ "dpi", "gtk", "http", - "jni", + "jni 0.21.1", "objc2", "objc2-ui-kit", "objc2-web-kit", @@ -4688,7 +4923,7 @@ checksum = "2cadb13dad0c681e1e0a2c49ae488f0e2906ded3d57e7a0017f4aaf46e387117" dependencies = [ "gtk", "http", - "jni", + "jni 0.21.1", "log", "objc2", "objc2-app-kit", @@ -5558,6 +5793,15 @@ dependencies = [ "system-deps", ] +[[package]] +name = "webpki-root-certs" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31141ce3fc3e300ae89b78c0dd67f9708061d1d2eda54b8209346fd6be9a92c" +dependencies = [ + "rustls-pki-types", +] + [[package]] name = "webpki-roots" version = "1.0.7" @@ -6284,7 +6528,7 @@ dependencies = [ "gtk", "http", "javascriptcore-rs", - "jni", + "jni 0.21.1", "libc", "ndk 0.9.0", "objc2", @@ -6348,6 +6592,16 @@ version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ea6fc2961e4ef194dcbfe56bb845534d0dc8098940c7e5c012a258bfec6701bd" +[[package]] +name = "xattr" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32e45ad4206f6d2479085147f02bc2ef834ac85886624a23575ae137c8aa8156" +dependencies = [ + "libc", + "rustix", +] + [[package]] name = "xkeysym" version = "0.2.1" @@ -6518,6 +6772,18 @@ dependencies = [ "syn 2.0.117", ] +[[package]] +name = "zip" +version = "4.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "caa8cd6af31c3b31c6631b8f483848b91589021b28fffe50adada48d4f4d2ed1" +dependencies = [ + "arbitrary", + "crc32fast", + "indexmap 2.14.0", + "memchr", +] + [[package]] name = "zmij" version = "1.0.21" diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 41354ef..79c5e17 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "Nekosonic" -version = "0.3.0" +version = "0.4.0" description = "A Simple music app" authors = ["atdunbg"] edition = "2021" @@ -36,4 +36,5 @@ base64 = "0.22" ncm-api-rs = "0.1" tokio = { version = "1", features = ["rt", "sync"] } tauri-plugin-process = "2.3.1" +tauri-plugin-updater = "2" diff --git a/src-tauri/capabilities/default.json b/src-tauri/capabilities/default.json index 04a1157..d2fe68e 100644 --- a/src-tauri/capabilities/default.json +++ b/src-tauri/capabilities/default.json @@ -20,6 +20,7 @@ "global-shortcut:allow-register", "global-shortcut:allow-unregister", "dialog:allow-open", - "process:allow-restart" + "process:allow-restart", + "updater:default" ] } diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 29bdffd..9461ae4 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -163,6 +163,7 @@ pub fn run() { api::comment_like, ]) .plugin(tauri_plugin_process::init()) + .plugin(tauri_plugin_updater::Builder::new().build()) .plugin(tauri_plugin_opener::init()) .plugin(tauri_plugin_dialog::init()) .plugin(tauri_plugin_global_shortcut::Builder::new().build()) diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index 22c1c40..f828c90 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -1,7 +1,7 @@ { "$schema": "https://schema.tauri.app/config/2", "productName": "Nekosonic", - "version": "0.3.0", + "version": "0.4.0", "identifier": "com.atdunbg.Nekosonic", "build": { "beforeDevCommand": "npm run dev", @@ -40,5 +40,15 @@ "type": "downloadBootstrapper" } } + }, + "plugins": { + "updater": { + "active": true, + "endpoints": [ + "https://github.com/atdunbg/Nekosonic-Music/releases/latest/download/latest.json" + ], + "dialog": false, + "pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IDM1MDdCMTJCRTE3MUI4N0QKUldSOXVISGhLN0VITmM3ZkJlbjF3UGJrK3h6ellWZ2xSUG03b3d1RWlDeldSWk1nc0pic2J2MVkK" + } } -} +} \ No newline at end of file diff --git a/src/App.vue b/src/App.vue index b74c46e..42068df 100644 --- a/src/App.vue +++ b/src/App.vue @@ -213,6 +213,15 @@ + +
@@ -263,8 +272,10 @@ import { useSettingsStore, type CloseAction } from './stores/settings'; import PlayerBar from './components/PlayerBar.vue'; import ToastContainer from './components/ToastContainer.vue'; import CommentSection from './components/CommentSection.vue'; +import UpdateDialog from './components/UpdateDialog.vue'; import { usePlayerStore } from './stores/player'; import { useLyric } from './composables/UserLyric'; +import { useUpdater } from './composables/useUpdater'; import { getCurrentWindow } from '@tauri-apps/api/window'; import { listen } from '@tauri-apps/api/event'; import { register, unregister } from '@tauri-apps/plugin-global-shortcut'; @@ -274,6 +285,7 @@ const route = useRoute(); const userStore = useUserStore(); const player = usePlayerStore(); const settings = useSettingsStore(); +const updater = useUpdater(); const createdPlaylists = ref([]); const subPlaylists = ref([]); @@ -426,6 +438,8 @@ onMounted(async () => { }); } } catch {} + + updater.checkForUpdate(true); }); const currentWindow = getCurrentWindow(); diff --git a/src/components/UpdateDialog.vue b/src/components/UpdateDialog.vue new file mode 100644 index 0000000..adc8587 --- /dev/null +++ b/src/components/UpdateDialog.vue @@ -0,0 +1,87 @@ + + + diff --git a/src/composables/useUpdater.ts b/src/composables/useUpdater.ts new file mode 100644 index 0000000..a6a2cb0 --- /dev/null +++ b/src/composables/useUpdater.ts @@ -0,0 +1,143 @@ +import { ref } from 'vue' +import { check } from '@tauri-apps/plugin-updater' +import { relaunch } from '@tauri-apps/plugin-process' +import { getVersion } from '@tauri-apps/api/app' + +export interface UpdateInfo { + version: string + date: string | null + body: string | null +} + +const IGNORED_VERSION_KEY = 'updater_ignored_version' + +export function useUpdater() { + const checking = ref(false) + const downloading = ref(false) + const downloadProgress = ref(0) + const updateAvailable = ref(false) + const updateInfo = ref(null) + const currentVersion = ref('') + const error = ref('') + + async function getCurrentVersion() { + try { + currentVersion.value = await getVersion() + } catch { + currentVersion.value = '' + } + } + + function getIgnoredVersion(): string { + try { + return localStorage.getItem(IGNORED_VERSION_KEY) || '' + } catch { + return '' + } + } + + function setIgnoredVersion(version: string) { + try { + localStorage.setItem(IGNORED_VERSION_KEY, version) + } catch {} + } + + async function checkForUpdate(silent = false): Promise { + if (checking.value) return null + checking.value = true + error.value = '' + updateAvailable.value = false + updateInfo.value = null + + try { + await getCurrentVersion() + const result = await check() + + if (!result) { + if (!silent) error.value = '当前已是最新版本' + return null + } + + const info: UpdateInfo = { + version: result.version, + date: result.date ?? null, + body: result.body ?? null, + } + + const ignored = getIgnoredVersion() + if (info.version === ignored) { + if (!silent) error.value = '当前已是最新版本' + return null + } + + updateAvailable.value = true + updateInfo.value = info + return info + } catch (e: any) { + if (!silent) error.value = `检查更新失败: ${e}` + return null + } finally { + checking.value = false + } + } + + async function downloadAndInstall() { + if (downloading.value) return + downloading.value = true + downloadProgress.value = 0 + error.value = '' + + try { + const result = await check() + if (!result) { + error.value = '未找到可用更新' + return + } + + let downloaded = 0 + let contentLength = 0 + await result.downloadAndInstall((event) => { + switch (event.event) { + case 'Started': + contentLength = event.data.contentLength ?? 0 + break + case 'Progress': + downloaded += event.data.chunkLength + if (contentLength > 0) { + downloadProgress.value = Math.round((downloaded / contentLength) * 100) + } + break + case 'Finished': + downloadProgress.value = 100 + break + } + }) + + await relaunch() + } catch (e: any) { + error.value = `更新失败: ${e}` + } finally { + downloading.value = false + } + } + + function ignoreVersion(version: string) { + setIgnoredVersion(version) + updateAvailable.value = false + updateInfo.value = null + } + + return { + checking, + downloading, + downloadProgress, + updateAvailable, + updateInfo, + currentVersion, + error, + checkForUpdate, + downloadAndInstall, + ignoreVersion, + getCurrentVersion, + } +} diff --git a/src/views/Settings.vue b/src/views/Settings.vue index f10976e..aab862e 100644 --- a/src/views/Settings.vue +++ b/src/views/Settings.vue @@ -146,7 +146,7 @@

关于

@@ -188,35 +188,6 @@
- -
-
-
-
-

最新版本日志

- v{{ latestRelease.tag_name?.replace('v', '') }} -
-

{{ formatDate(latestRelease.published_at) }}

-
-
-
{{ latestRelease.body }}
-
-
-

暂无更新日志

-
-
- - -
-
-
-
@@ -224,6 +195,7 @@ import { ref, computed, onMounted, onBeforeUnmount } from 'vue'; import { useSettingsStore, qualityLabels, closeActionLabels, defaultShortcuts, type CloseAction } from '../stores/settings'; import { useToast } from '../composables/useToast'; +import { useUpdater } from '../composables/useUpdater'; import { invoke } from '@tauri-apps/api/core'; import { getVersion } from '@tauri-apps/api/app'; import { openUrl } from '@tauri-apps/plugin-opener'; @@ -232,6 +204,7 @@ import CustomSelect from '../components/CustomSelect.vue'; const settings = useSettingsStore(); const { showToast } = useToast(); +const updater = useUpdater(); const appVersion = ref(''); const defaultDownloadPath = ref(''); @@ -264,45 +237,15 @@ function clearDownloadPath() { showToast('已重置为默认路径', 'success'); } -const checkingUpdate = ref(false); -const updateMessage = ref(''); -const updateMessageClass = ref('text-content-2'); -const latestRelease = ref(null); -const showUpdateModal = ref(false); - const themeOptions = [ { label: '深色', value: 'dark' as const }, { label: '浅色', value: 'light' as const }, ]; -async function checkUpdate() { - checkingUpdate.value = true; - updateMessage.value = ''; - try { - const resp = await fetch('https://gitea.atdunbg.xyz/api/v1/repos/atdunbg/Nekosonic-Music/releases?limit=1&draft=false'); - if (!resp.ok) throw new Error(`HTTP ${resp.status}`); - const releases = await resp.json(); - if (releases && releases.length > 0) { - latestRelease.value = releases[0]; - showUpdateModal.value = true; - } else { - updateMessage.value = '暂无发布版本'; - updateMessageClass.value = 'text-content-3'; - } - } catch (e: any) { - updateMessage.value = `获取失败: ${e}`; - updateMessageClass.value = 'text-danger'; - } finally { - checkingUpdate.value = false; - } -} - -function formatDate(dateStr: string) { - try { - const d = new Date(dateStr); - return d.toLocaleDateString('zh-CN', { year: 'numeric', month: 'long', day: 'numeric' }); - } catch { - return dateStr; +async function handleCheckUpdate() { + const result = await updater.checkForUpdate(false); + if (!result) { + showToast(updater.error.value || '当前已是最新版本', 'info'); } }