From cce3338dc9a84dd7da381602d4c2275b12c90368 Mon Sep 17 00:00:00 2001
From: Neshura <neshura@neshweb.net>
Date: Wed, 15 Nov 2023 23:53:16 +0100
Subject: [PATCH 1/4] Updated Tauri Config to accomodate needed APIs and change
 default size

---
 src-tauri/Cargo.toml      |  2 +-
 src-tauri/tauri.conf.json | 13 +++++++++++--
 2 files changed, 12 insertions(+), 3 deletions(-)

diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml
index 584ec19..3b65978 100644
--- a/src-tauri/Cargo.toml
+++ b/src-tauri/Cargo.toml
@@ -13,7 +13,7 @@ edition = "2021"
 tauri-build = { version = "1.4", features = [] }
 
 [dependencies]
-tauri = { version = "1.4", features = ["shell-open"] }
+tauri = { version = "1.4", features = [ "os-all", "path-all", "dialog-open", "shell-open"] }
 quick-xml = { version = "0.29.0", features = ["serde", "serialize"] }
 serde = { version = "1.0", features = ["derive"] }
 serde-xml-rs = "0.6.0"
diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json
index 686dc01..3a5e3fe 100644
--- a/src-tauri/tauri.conf.json
+++ b/src-tauri/tauri.conf.json
@@ -16,6 +16,15 @@
       "shell": {
         "all": false,
         "open": true
+      },
+      "dialog": {
+        "open": true
+      },
+      "path": {
+        "all": true
+      },
+      "os": {
+        "all": true
       }
     },
     "bundle": {
@@ -38,8 +47,8 @@
         "fullscreen": false,
         "resizable": true,
         "title": "comicinfo-editor-v2",
-        "width": 800,
-        "height": 600
+        "width": 1280,
+        "height": 720
       }
     ]
   }

From 87d703abe40cdac9c56c6e0709697aefa2b19e41 Mon Sep 17 00:00:00 2001
From: Neshura <neshura@neshweb.net>
Date: Wed, 15 Nov 2023 23:54:06 +0100
Subject: [PATCH 2/4] Auto-Focus New Elements in List Input (Tags)

---
 src/lib/ListTextInput/ListTextInputElement.svelte | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/lib/ListTextInput/ListTextInputElement.svelte b/src/lib/ListTextInput/ListTextInputElement.svelte
index 42f22e1..c4ff428 100644
--- a/src/lib/ListTextInput/ListTextInputElement.svelte
+++ b/src/lib/ListTextInput/ListTextInputElement.svelte
@@ -15,7 +15,7 @@
     }
 </script>
 
-<input id="tag-{id}" type="text" class="letterInput" style="--valuelen: {width}ch" bind:value={value}>
+<input id="tag-{id}" type="text" class="letterInput" style="--valuelen: {width}ch" bind:value={value} autofocus>
 <button on:click|preventDefault={handleClick}>X</button>
 
 <style>

From b5812fa32c129190e7a4eb522e42d237451800ce Mon Sep 17 00:00:00 2001
From: Neshura <neshura@neshweb.net>
Date: Wed, 15 Nov 2023 23:59:09 +0100
Subject: [PATCH 3/4] Added: Path Selection (ComicInfo + Bundle Source), Bundle
 Checkbox

---
 src-tauri/src/main.rs        | 16 ++++++++---
 src/App.svelte               |  8 ++++++
 src/lib/MetadataInput.svelte | 56 ++++++++++++++++++++++++++++++++++--
 src/lib/PathInput.svelte     | 35 ++++++++++++++++++++++
 4 files changed, 108 insertions(+), 7 deletions(-)
 create mode 100644 src/lib/PathInput.svelte

diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs
index 602d3c8..21dfc9d 100644
--- a/src-tauri/src/main.rs
+++ b/src-tauri/src/main.rs
@@ -2,6 +2,7 @@
 #![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
 
 use serde::{Deserialize, Serialize};
+use std::path::MAIN_SEPARATOR_STR;
 
 use crate::metadata::{*};
 mod metadata;
@@ -14,13 +15,20 @@ fn greet(name: &str) -> String {
 
 fn main() {
     tauri::Builder::default()
-        .invoke_handler(tauri::generate_handler![greet, test])
+        .invoke_handler(tauri::generate_handler![greet, save])
         .run(tauri::generate_context!())
         .expect("error while running tauri application");
 }
 
 #[tauri::command]
-fn test(message: metadata::Metadata) -> String {
-    message.save_to_xml("/home/neshura/Repositories/comicinfo-editor-v2/ComicInfo.xml");
-    format!("Series: '{}' | Title: '{}'", message.series_title, message.title)
+fn save(metadata: Metadata, path: String) -> String {
+    let file_path: String;
+    if path.ends_with(MAIN_SEPARATOR_STR) {
+        file_path = path + "ComicInfo.xml";
+    }
+    else {
+        file_path = path + MAIN_SEPARATOR_STR + "ComicInfo.xml";
+    }
+    metadata.save_to_xml(&file_path);
+    file_path
 }
diff --git a/src/App.svelte b/src/App.svelte
index d97f7cd..a79addc 100644
--- a/src/App.svelte
+++ b/src/App.svelte
@@ -21,6 +21,14 @@
       <p>
         Settings go here
       </p>
+
+      <p>
+        Default ComicInfo.xml save location
+      </p>
+
+      <p>
+        Default Metadata Settings (genre, age rating)
+      </p>
     {/if}
   
   </div>
diff --git a/src/lib/MetadataInput.svelte b/src/lib/MetadataInput.svelte
index 08c75b9..310420e 100644
--- a/src/lib/MetadataInput.svelte
+++ b/src/lib/MetadataInput.svelte
@@ -6,6 +6,13 @@
   import {invoke} from "@tauri-apps/api/tauri";
   import {AgeRating, LanguageISO, type Metadata} from "./metadata";
   import Dropdown from "./Dropdown/Dropdown.svelte";
+  import PathInput from "./PathInput.svelte";
+  import {tempdir} from "@tauri-apps/api/os";
+  import {downloadDir} from "@tauri-apps/api/path";
+  let tauriInitDone = false;
+
+  let downloadDirPath: string;
+  let tempDirPath: string;
 
   let returnMessage = "";
 
@@ -47,6 +54,11 @@
     age_rating: AgeRating.Unknown
   };
 
+  let saveDirectory = "";
+
+  let bundleDirectory = "";
+  let doBundle = false;
+
   $: {
     if (metadata.release_date.year < 0) {
       metadata.release_date.month = -1;
@@ -56,15 +68,43 @@
     }
   }
 
+  $: {
+    if (tauriInitDone) {
+      if (saveDirectory == "") {
+        saveDirectory = downloadDirPath;
+      }
+
+      if (bundleDirectory == "") {
+        bundleDirectory = downloadDirPath;
+      }
+    }
+  }
+
+  async function init() {
+    downloadDirPath = await downloadDir();
+    tempDirPath = await tempdir();
+    tauriInitDone = true;
+  }
+
   function deleteTag(event: any) {
     metadata.tags.splice(event.detail.tagId, 1);
     metadata.tags = metadata.tags;
   }
   
   async function saveMetadata() {
+    while (!tauriInitDone) {
+      await new Promise( resolve => setTimeout(resolve, 100) );
+    }
     console.log(metadata);
-    returnMessage = await invoke("test", { message: metadata })
+    if (bundleDirectory != "") {
+    }
+    else {
+      let comicInfoPath = await invoke("save", { message: metadata, path: saveDirectory })
+      returnMessage = "Saved '" + metadata.title + "' to '" + comicInfoPath + "'";
+    }
   }
+
+  init();
 </script>
 
 <div class="metadataInputContainer">
@@ -131,14 +171,24 @@
       <TextInput id="genre" bind:value={metadata.genre} placeholder="Genre" />
 
       <label for="language-select">Language:</label>
-      <Dropdown id="language-select" bind:activeElement={metadata.language} list={Object.values(LanguageISO)}></Dropdown>
+      <Dropdown id="language-select" bind:activeElement={metadata.language} list={Object.values(LanguageISO)} />
     </div>
 
     <div class="row-left">
       <label for="age-rating">Age Rating:</label>
-      <Dropdown id="" bind:activeElement={metadata.age_rating} list={Object.values(AgeRating)}></Dropdown>
+      <Dropdown id="" bind:activeElement={metadata.age_rating} list={Object.values(AgeRating)} />
     </div>
 
+    <hr>
+
+    <PathInput bind:path={saveDirectory}/>
+    <div class="row-left">
+      <label for="bundle-check">Bundle:</label>
+      <input id="bundle-check" type="checkbox" bind:checked={doBundle}>
+    </div>
+    {#if doBundle}
+      <PathInput bind:path={bundleDirectory}/>
+    {/if}
     <input type="submit" value="Save"/>
     <p>{returnMessage}</p>
   </form>
diff --git a/src/lib/PathInput.svelte b/src/lib/PathInput.svelte
new file mode 100644
index 0000000..ed38668
--- /dev/null
+++ b/src/lib/PathInput.svelte
@@ -0,0 +1,35 @@
+<script lang="ts">
+    import { open } from '@tauri-apps/api/dialog';
+
+    export let path: string;
+
+    let buttonPrompt = "Select";
+
+    async function handleClick() {
+        const dirHandle = await open({
+            multiple: false,
+            directory: true,
+            defaultPath: path
+        });
+        if (Array.isArray(dirHandle)) {
+            path = dirHandle[0];
+        }
+        else if (dirHandle !== null) {
+            path = dirHandle;
+        }
+    }
+
+</script>
+
+<div>
+    <button on:click|preventDefault={handleClick}>{buttonPrompt}</button>
+    {#if path != ""}
+        <p>{path}</p>
+    {:else}
+        <p>Select Save Location...</p>
+    {/if}
+</div>
+
+<style>
+
+</style>
\ No newline at end of file

From 25ef82cf2d4bd4c04c3be271b83c29fbe9c6cd66 Mon Sep 17 00:00:00 2001
From: Neshura <neshura@neshweb.net>
Date: Wed, 15 Nov 2023 23:59:50 +0100
Subject: [PATCH 4/4] Add functional bundling of ComicInfo File with static
 test name

---
 src-tauri/Cargo.lock         | 332 ++++++++++++++++++++++++++++++++++-
 src-tauri/Cargo.toml         |   1 +
 src-tauri/src/main.rs        |  29 ++-
 src/lib/MetadataInput.svelte |  11 ++
 4 files changed, 368 insertions(+), 5 deletions(-)

diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock
index ff33e0b..5e7e179 100644
--- a/src-tauri/Cargo.lock
+++ b/src-tauri/Cargo.lock
@@ -17,6 +17,17 @@ version = "1.0.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
 
+[[package]]
+name = "aes"
+version = "0.8.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac1f845298e95f983ff1944b728ae08b8cebab80d684f0a832ed0fc74dfa27e2"
+dependencies = [
+ "cfg-if",
+ "cipher",
+ "cpufeatures",
+]
+
 [[package]]
 name = "aho-corasick"
 version = "1.1.2"
@@ -119,6 +130,12 @@ version = "0.21.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "9ba43ea6f343b788c8764558649e08df62f86c6ef251fdaeb1ffd010a9ae50a2"
 
+[[package]]
+name = "base64ct"
+version = "1.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b"
+
 [[package]]
 name = "bitflags"
 version = "1.3.2"
@@ -201,6 +218,27 @@ version = "1.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223"
 
+[[package]]
+name = "bzip2"
+version = "0.4.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bdb116a6ef3f6c3698828873ad02c3014b3c85cadb88496095628e3ef1e347f8"
+dependencies = [
+ "bzip2-sys",
+ "libc",
+]
+
+[[package]]
+name = "bzip2-sys"
+version = "0.1.11+1.0.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc"
+dependencies = [
+ "cc",
+ "libc",
+ "pkg-config",
+]
+
 [[package]]
 name = "cairo-rs"
 version = "0.15.12"
@@ -241,6 +279,7 @@ version = "1.0.83"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0"
 dependencies = [
+ "jobserver",
  "libc",
 ]
 
@@ -296,7 +335,17 @@ dependencies = [
  "iana-time-zone",
  "num-traits",
  "serde",
- "windows-targets",
+ "windows-targets 0.48.5",
+]
+
+[[package]]
+name = "cipher"
+version = "0.4.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad"
+dependencies = [
+ "crypto-common",
+ "inout",
 ]
 
 [[package]]
@@ -357,8 +406,15 @@ dependencies = [
  "strum_macros",
  "tauri",
  "tauri-build",
+ "zip",
 ]
 
+[[package]]
+name = "constant_time_eq"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc"
+
 [[package]]
 name = "convert_case"
 version = "0.4.0"
@@ -554,6 +610,7 @@ checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
 dependencies = [
  "block-buffer",
  "crypto-common",
+ "subtle",
 ]
 
 [[package]]
@@ -1143,6 +1200,15 @@ version = "0.4.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
 
+[[package]]
+name = "hmac"
+version = "0.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e"
+dependencies = [
+ "digest",
+]
+
 [[package]]
 name = "html5ever"
 version = "0.25.2"
@@ -1298,6 +1364,15 @@ dependencies = [
  "cfb",
 ]
 
+[[package]]
+name = "inout"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5"
+dependencies = [
+ "generic-array",
+]
+
 [[package]]
 name = "instant"
 version = "0.1.12"
@@ -1362,6 +1437,15 @@ version = "0.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130"
 
+[[package]]
+name = "jobserver"
+version = "0.1.27"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8c37f63953c4c63420ed5fd3d6d398c719489b9f872b9fa683262f8edd363c7d"
+dependencies = [
+ "libc",
+]
+
 [[package]]
 name = "js-sys"
 version = "0.3.64"
@@ -1670,6 +1754,17 @@ dependencies = [
  "objc_exception",
 ]
 
+[[package]]
+name = "objc-foundation"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1add1b659e36c9607c7aab864a76c7a4c2760cd0cd2e120f3fb8b952c7e22bf9"
+dependencies = [
+ "block",
+ "objc",
+ "objc_id",
+]
+
 [[package]]
 name = "objc_exception"
 version = "0.1.2"
@@ -1713,6 +1808,17 @@ dependencies = [
  "windows-sys 0.42.0",
 ]
 
+[[package]]
+name = "os_info"
+version = "3.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "006e42d5b888366f1880eda20371fedde764ed2213dc8496f49622fa0c99cd5e"
+dependencies = [
+ "log",
+ "serde",
+ "winapi",
+]
+
 [[package]]
 name = "overload"
 version = "0.1.1"
@@ -1764,7 +1870,18 @@ dependencies = [
  "libc",
  "redox_syscall 0.3.5",
  "smallvec",
- "windows-targets",
+ "windows-targets 0.48.5",
+]
+
+[[package]]
+name = "password-hash"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7676374caaee8a325c9e7a2ae557f216c5563a171d6997b0ef8a65af35147700"
+dependencies = [
+ "base64ct",
+ "rand_core 0.6.4",
+ "subtle",
 ]
 
 [[package]]
@@ -1773,6 +1890,18 @@ version = "0.2.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd"
 
+[[package]]
+name = "pbkdf2"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917"
+dependencies = [
+ "digest",
+ "hmac",
+ "password-hash",
+ "sha2",
+]
+
 [[package]]
 name = "percent-encoding"
 version = "2.3.0"
@@ -2172,6 +2301,30 @@ version = "0.8.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "c3cbb081b9784b07cceb8824c8583f86db4814d172ab043f3c23f7dc600bf83d"
 
+[[package]]
+name = "rfd"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0149778bd99b6959285b0933288206090c50e2327f47a9c463bfdbf45c8823ea"
+dependencies = [
+ "block",
+ "dispatch",
+ "glib-sys",
+ "gobject-sys",
+ "gtk-sys",
+ "js-sys",
+ "lazy_static",
+ "log",
+ "objc",
+ "objc-foundation",
+ "objc_id",
+ "raw-window-handle",
+ "wasm-bindgen",
+ "wasm-bindgen-futures",
+ "web-sys",
+ "windows 0.37.0",
+]
+
 [[package]]
 name = "rustc-demangle"
 version = "0.1.23"
@@ -2392,6 +2545,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"
@@ -2533,6 +2697,12 @@ dependencies = [
  "syn 2.0.38",
 ]
 
+[[package]]
+name = "subtle"
+version = "2.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc"
+
 [[package]]
 name = "syn"
 version = "1.0.109"
@@ -2555,6 +2725,19 @@ dependencies = [
  "unicode-ident",
 ]
 
+[[package]]
+name = "sys-locale"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f8a11bd9c338fdba09f7881ab41551932ad42e405f61d01e8406baea71c07aee"
+dependencies = [
+ "js-sys",
+ "libc",
+ "wasm-bindgen",
+ "web-sys",
+ "windows-sys 0.45.0",
+]
+
 [[package]]
 name = "system-deps"
 version = "5.0.0"
@@ -2678,16 +2861,19 @@ dependencies = [
  "objc",
  "once_cell",
  "open",
+ "os_info",
  "percent-encoding",
  "rand 0.8.5",
  "raw-window-handle",
  "regex",
+ "rfd",
  "semver",
  "serde",
  "serde_json",
  "serde_repr",
  "serialize-to-javascript",
  "state",
+ "sys-locale",
  "tar",
  "tauri-macros",
  "tauri-runtime",
@@ -3248,6 +3434,18 @@ dependencies = [
  "wasm-bindgen-shared",
 ]
 
+[[package]]
+name = "wasm-bindgen-futures"
+version = "0.4.37"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c02dbc21516f9f1f04f187958890d7e6026df8d16540b7ad9492bc34a67cea03"
+dependencies = [
+ "cfg-if",
+ "js-sys",
+ "wasm-bindgen",
+ "web-sys",
+]
+
 [[package]]
 name = "wasm-bindgen-macro"
 version = "0.2.87"
@@ -3277,6 +3475,16 @@ version = "0.2.87"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1"
 
+[[package]]
+name = "web-sys"
+version = "0.3.64"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b"
+dependencies = [
+ "js-sys",
+ "wasm-bindgen",
+]
+
 [[package]]
 name = "webkit2gtk"
 version = "0.18.2"
@@ -3393,6 +3601,19 @@ version = "0.4.0"
 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"
@@ -3413,7 +3634,7 @@ version = "0.48.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f"
 dependencies = [
- "windows-targets",
+ "windows-targets 0.48.5",
 ]
 
 [[package]]
@@ -3457,13 +3678,37 @@ dependencies = [
  "windows_x86_64_msvc 0.42.2",
 ]
 
+[[package]]
+name = "windows-sys"
+version = "0.45.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
+dependencies = [
+ "windows-targets 0.42.2",
+]
+
 [[package]]
 name = "windows-sys"
 version = "0.48.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
 dependencies = [
- "windows-targets",
+ "windows-targets 0.48.5",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.42.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071"
+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]]
@@ -3499,6 +3744,12 @@ version = "0.48.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
 
+[[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"
@@ -3517,6 +3768,12 @@ version = "0.48.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
 
+[[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"
@@ -3535,6 +3792,12 @@ version = "0.48.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
 
+[[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"
@@ -3553,6 +3816,12 @@ version = "0.48.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
 
+[[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"
@@ -3583,6 +3852,12 @@ version = "0.48.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
 
+[[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"
@@ -3693,3 +3968,52 @@ name = "xml-rs"
 version = "0.8.19"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "0fcb9cbac069e033553e8bb871be2fbdffcab578eb25bd0f7c508cedc6dcd75a"
+
+[[package]]
+name = "zip"
+version = "0.6.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "760394e246e4c28189f19d488c058bf16f564016aefac5d32bb1f3b51d5e9261"
+dependencies = [
+ "aes",
+ "byteorder",
+ "bzip2",
+ "constant_time_eq",
+ "crc32fast",
+ "crossbeam-utils",
+ "flate2",
+ "hmac",
+ "pbkdf2",
+ "sha1",
+ "time",
+ "zstd",
+]
+
+[[package]]
+name = "zstd"
+version = "0.11.2+zstd.1.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4"
+dependencies = [
+ "zstd-safe",
+]
+
+[[package]]
+name = "zstd-safe"
+version = "5.0.2+zstd.1.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1d2a5585e04f9eea4b2a3d1eca508c4dee9592a89ef6f450c11719da0726f4db"
+dependencies = [
+ "libc",
+ "zstd-sys",
+]
+
+[[package]]
+name = "zstd-sys"
+version = "2.0.9+zstd.1.5.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9e16efa8a874a0481a574084d34cc26fdb3b99627480f785888deb6386506656"
+dependencies = [
+ "cc",
+ "pkg-config",
+]
diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml
index 3b65978..e493a08 100644
--- a/src-tauri/Cargo.toml
+++ b/src-tauri/Cargo.toml
@@ -20,6 +20,7 @@ serde-xml-rs = "0.6.0"
 serde_json = "1.0"
 strum = "0.25.0"
 strum_macros = "0.25.0"
+zip = { version = "0.6.6", features = [] }
 
 [features]
 # this feature is used for production builds or when `devPath` points to the filesystem
diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs
index 21dfc9d..c2b736a 100644
--- a/src-tauri/src/main.rs
+++ b/src-tauri/src/main.rs
@@ -1,6 +1,8 @@
 // Prevents additional console window on Windows in release, DO NOT REMOVE!!
 #![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
 
+use std::fs::File;
+use std::io::{Read, Write};
 use serde::{Deserialize, Serialize};
 use std::path::MAIN_SEPARATOR_STR;
 
@@ -15,7 +17,7 @@ fn greet(name: &str) -> String {
 
 fn main() {
     tauri::Builder::default()
-        .invoke_handler(tauri::generate_handler![greet, save])
+        .invoke_handler(tauri::generate_handler![greet, save, save_bundle])
         .run(tauri::generate_context!())
         .expect("error while running tauri application");
 }
@@ -32,3 +34,28 @@ fn save(metadata: Metadata, path: String) -> String {
     metadata.save_to_xml(&file_path);
     file_path
 }
+
+#[tauri::command]
+fn save_bundle(bundle_dir: String, metadata_file_path: String, save_path: String) -> String {
+    let comic_book_zip = File::create(&save_path).unwrap();
+    let mut zip = zip::ZipWriter::new(comic_book_zip);
+
+    let options = zip::write::FileOptions::default().compression_method(zip::CompressionMethod::Stored);
+
+    let mut file_list: Vec<String> = Vec::new();
+
+    file_list.push(metadata_file_path);
+
+    for file in file_list {
+        zip.start_file(file.clone().split(MAIN_SEPARATOR_STR).last().unwrap(), options).unwrap();
+        let mut file = File::open(file).unwrap();
+        let mut buffer = Vec::new();
+
+        file.read_to_end(&mut buffer).unwrap();
+
+        zip.write(&*buffer).unwrap();
+    }
+
+    zip.finish().unwrap();
+    return bundle_dir
+}
diff --git a/src/lib/MetadataInput.svelte b/src/lib/MetadataInput.svelte
index 310420e..96e4e85 100644
--- a/src/lib/MetadataInput.svelte
+++ b/src/lib/MetadataInput.svelte
@@ -97,6 +97,17 @@
     }
     console.log(metadata);
     if (bundleDirectory != "") {
+      let savePath = saveDirectory;
+      if (saveDirectory.endsWith("/")) {
+        savePath += "test.cbz";
+      }
+      else {
+        savePath += "/test.cbz";
+      }
+
+      let comicInfoPath = await invoke("save", { metadata: metadata, path: tempDirPath});
+      let bundlePath = await invoke("save_bundle", { bundleDir: bundleDirectory, metadataFilePath: comicInfoPath, savePath: savePath })
+      returnMessage = "Saved '" + metadata.title + "' bundled to '" + bundlePath + "'";
     }
     else {
       let comicInfoPath = await invoke("save", { message: metadata, path: saveDirectory })