diff --git a/README.md b/README.md index a5d2b1d..332e193 100644 --- a/README.md +++ b/README.md @@ -7,3 +7,24 @@ A handy helper, to help with Syntax's production. - Svelte(5) Kit - Tauri - FFMPEG + +## Features + +### Auto-Updater + +The application includes an automatic update system that allows users to check for and install updates seamlessly. + +**Usage:** +- Click the "Check for Updates" button in the main application interface +- If an update is available, you'll be prompted to install it +- The updater will download and install the update automatically +- Restart the application to complete the update process + +**Configuration:** +The updater is configured to check GitHub releases for updates. To set up releases for automatic updates: + +1. Create a GitHub release with the appropriate assets +2. Ensure the release includes a `latest.json` file with update metadata +3. The updater will automatically detect and offer to install new versions + +For production use, make sure to configure a proper signing key in `src-tauri/tauri.conf.json`. diff --git a/package.json b/package.json index 81359f5..67d251d 100644 --- a/package.json +++ b/package.json @@ -21,6 +21,7 @@ "@tauri-apps/plugin-http": "2.0.0-rc.1", "@tauri-apps/plugin-log": "2.0.0-rc.0", "@tauri-apps/plugin-shell": ">=2.0.0-rc.0", + "@tauri-apps/plugin-updater": "2.0.0-rc.0", "@types/markdown-it": "^14.1.2", "dexie": "^4.0.8", "ink-mde": "^0.33.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 482f859..9e341a9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -26,6 +26,9 @@ importers: '@tauri-apps/plugin-shell': specifier: '>=2.0.0-rc.0' version: 2.0.0-rc.0 + '@tauri-apps/plugin-updater': + specifier: 2.0.0-rc.0 + version: 2.0.0-rc.0 '@types/markdown-it': specifier: ^14.1.2 version: 14.1.2 @@ -691,6 +694,9 @@ packages: '@tauri-apps/plugin-shell@2.0.0-rc.0': resolution: {integrity: sha512-bhUcQcrqZoK8H1DFXapr5r1Z75oh6Kd5Tltz97XpZFLREEqp+KhN2Fvyh8r/fKAyenYsTYUIsDsyGdjdueuF9g==} + '@tauri-apps/plugin-updater@2.0.0-rc.0': + resolution: {integrity: sha512-EKajf/sBpFif0cwXhTo3BmNvTZ2t2DDLRyhA8FFKugZNoOeqU97bHhPT5DIqMUPRE1tyDk9o7sXm8dKf7oz+EA==} + '@types/cookie@0.6.0': resolution: {integrity: sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==} @@ -2430,6 +2436,10 @@ snapshots: dependencies: '@tauri-apps/api': 2.0.0-rc.2 + '@tauri-apps/plugin-updater@2.0.0-rc.0': + dependencies: + '@tauri-apps/api': 2.0.0-rc.2 + '@types/cookie@0.6.0': {} '@types/eslint@9.6.0': diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index cc4365c..27ec39b 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -28,5 +28,6 @@ tauri-plugin-decorum = "1.0.0" reqwest = { version = "0.11", features = ["json"] } tauri-plugin-devtools = "2.0.0-rc" tauri-plugin-log = "2.0.0-rc.1" +tauri-plugin-updater = "2.0.0-rc" log = "0.4" which = "6.0.3" diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 0466959..45e1701 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -388,6 +388,59 @@ async fn upload_to_youtube( Err("Upload failed".to_string()) } +#[tauri::command] +async fn check_for_updates(app: tauri::AppHandle) -> Result { + match tauri_plugin_updater::UpdaterExt::updater(&app) { + Some(updater) => { + match updater.check().await { + Ok(Some(update)) => { + Ok(format!("Update available: {} -> {}", env!("CARGO_PKG_VERSION"), update.version)) + }, + Ok(None) => { + Ok(format!("You're running the latest version: {}", env!("CARGO_PKG_VERSION"))) + }, + Err(e) => { + Err(format!("Failed to check for updates: {}", e)) + } + } + }, + None => { + Err("Updater not available".to_string()) + } + } +} + +#[tauri::command] +async fn install_update(app: tauri::AppHandle) -> Result { + match tauri_plugin_updater::UpdaterExt::updater(&app) { + Some(updater) => { + match updater.check().await { + Ok(Some(update)) => { + match update.download_and_install(|_chunk_length, _content_length| { + // You can use this to show progress + }).await { + Ok(_) => { + Ok("Update installed successfully. Please restart the application.".to_string()) + }, + Err(e) => { + Err(format!("Failed to install update: {}", e)) + } + } + }, + Ok(None) => { + Ok("No updates available to install".to_string()) + }, + Err(e) => { + Err(format!("Failed to check for updates: {}", e)) + } + } + }, + None => { + Err("Updater not available".to_string()) + } + } +} + #[cfg_attr(mobile, tauri::mobile_entry_point)] pub fn run() { let mut builder = tauri::Builder::default(); @@ -415,6 +468,7 @@ pub fn run() { builder .plugin(tauri_plugin_http::init()) .plugin(tauri_plugin_decorum::init()) // initialize the decorum plugin + .plugin(tauri_plugin_updater::Builder::new().build()) // initialize the updater plugin .setup(|app| { // Create a custom titlebar for main window // On macOS it needs hiddenTitle: true and titleBarStyle: overlay @@ -461,6 +515,8 @@ pub fn run() { hide_login_window, login_youtube, upload_to_youtube, + check_for_updates, + install_update, ]) .run(tauri::generate_context!()) .expect("error while running tauri application"); diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index 413ece0..c4569e8 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -78,6 +78,14 @@ "scope": [ "**" ] + }, + "updater": { + "active": true, + "endpoints": [ + "https://github.com/syntaxfm/production-assistant/releases/latest/download/latest.json" + ], + "dialog": true, + "pubkey": "" } }, "productName": "Syntax PA", diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index 76e99f4..e9bffac 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -5,6 +5,47 @@ import Avatar from '$lib/auth/Avatar.svelte'; import ProjectButton from '$/lib/components/ProjectButton.svelte'; app_data.sync(); + + let isCheckingUpdates = $state(false); + let updateMessage = $state(''); + + async function checkForUpdates() { + isCheckingUpdates = true; + updateMessage = ''; + try { + const result = await invoke('check_for_updates'); + updateMessage = result as string; + + // If update is available, offer to install + if ((result as string).includes('Update available')) { + const shouldInstall = confirm(`${result}\n\nWould you like to install the update now?`); + if (shouldInstall) { + await installUpdate(); + } + } else { + alert(result); + } + } catch (error) { + const errorMsg = `Error checking for updates: ${error}`; + updateMessage = errorMsg; + alert(errorMsg); + } finally { + isCheckingUpdates = false; + } + } + + async function installUpdate() { + try { + updateMessage = 'Installing update...'; + const result = await invoke('install_update'); + updateMessage = result as string; + alert(result); + } catch (error) { + const errorMsg = `Error installing update: ${error}`; + updateMessage = errorMsg; + alert(errorMsg); + } + }
@@ -27,6 +68,9 @@ /> +