chore: move download and extracting themes to tauri backend
This commit is contained in:
1 parent
e5e09505a0
commit
3768ab1064
6 files changed
+228
-102
No files matched your search
Generated
+4
-2
@@ -1191,6 +1191,7 @@ dependencies = [
|
|||||||
"byteorder",
|
"byteorder",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"hardware-id",
|
"hardware-id",
|
||||||
|
"hex",
|
||||||
"md5",
|
"md5",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"open",
|
"open",
|
||||||
@@ -1199,6 +1200,7 @@ dependencies = [
|
|||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"serde_repr",
|
"serde_repr",
|
||||||
|
"sha1",
|
||||||
"sysinfo",
|
"sysinfo",
|
||||||
"tauri",
|
"tauri",
|
||||||
"tauri-build",
|
"tauri-build",
|
||||||
@@ -3710,9 +3712,9 @@ checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "reqwest"
|
name = "reqwest"
|
||||||
version = "0.13.3"
|
version = "0.13.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "62e0021ea2c22aed41653bc7e1419abb2c97e038ff2c33d0e1309e49a97deec0"
|
checksum = "219c5811de6525e5416c7d5d53bb656d3afdbc6c5af816e0802bcfa42dbdc1c3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64 0.22.1",
|
"base64 0.22.1",
|
||||||
"bytes",
|
"bytes",
|
||||||
|
|||||||
@@ -38,9 +38,9 @@ tauri-plugin-fs = "2.5.1"
|
|||||||
hardware-id = "0.3.0"
|
hardware-id = "0.3.0"
|
||||||
tauri-plugin-cors-fetch = "5.0.0"
|
tauri-plugin-cors-fetch = "5.0.0"
|
||||||
sysinfo = "0.39.2"
|
sysinfo = "0.39.2"
|
||||||
reqwest = { version = "0.13.3", features = ["json", "stream", "query"] }
|
reqwest = { version = "0.13.4", features = ["json", "stream", "query"] }
|
||||||
md5 = "0.8.0"
|
md5 = "0.8.0"
|
||||||
tokio = { version = "1.52.2", features = ["full"] }
|
tokio = { version = "1.52.3", features = ["full"] }
|
||||||
open = "5.3.5"
|
open = "5.3.5"
|
||||||
presenceforge = { version = "0.2.1", features = ["tokio-runtime"] }
|
presenceforge = { version = "0.2.1", features = ["tokio-runtime"] }
|
||||||
once_cell = "1.21.4"
|
once_cell = "1.21.4"
|
||||||
@@ -49,10 +49,12 @@ byteorder = "1.5.0"
|
|||||||
anyhow = "1.0.102"
|
anyhow = "1.0.102"
|
||||||
url = "2.5.8"
|
url = "2.5.8"
|
||||||
zip = "8.6.0"
|
zip = "8.6.0"
|
||||||
|
sha1 = "0.11.0"
|
||||||
|
hex = "0.4.3"
|
||||||
|
|
||||||
[target.'cfg(windows)'.dependencies]
|
[target.'cfg(windows)'.dependencies]
|
||||||
winreg = "0.56.0"
|
winreg = "0.56.0"
|
||||||
winapi = { version = "0.3", features = ["winuser", "wincrypt", "memoryapi", "winbase", "dpapi"] }
|
winapi = { version = "0.3.9", features = ["winuser", "wincrypt", "memoryapi", "winbase", "dpapi"] }
|
||||||
base64 = "0.22.1"
|
base64 = "0.22.1"
|
||||||
widestring = "1.2.1"
|
widestring = "1.2.1"
|
||||||
windows-sys = "0.61.2"
|
windows-sys = "0.61.2"
|
||||||
|
|||||||
+141
-1
@@ -8,6 +8,7 @@ use sysinfo::System;
|
|||||||
use tauri::AppHandle;
|
use tauri::AppHandle;
|
||||||
use tauri::Emitter;
|
use tauri::Emitter;
|
||||||
use tauri::Manager;
|
use tauri::Manager;
|
||||||
|
use tauri_plugin_fs::FsExt;
|
||||||
use tokio::fs;
|
use tokio::fs;
|
||||||
use tokio::io::AsyncWriteExt;
|
use tokio::io::AsyncWriteExt;
|
||||||
use tokio::process::Command;
|
use tokio::process::Command;
|
||||||
@@ -1049,6 +1050,143 @@ pub struct ExtractProgress {
|
|||||||
pub current_file: String,
|
pub current_file: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Clone)]
|
||||||
|
pub struct DownloadProgress {
|
||||||
|
pub theme_name: String,
|
||||||
|
pub received: u64,
|
||||||
|
pub total: u64,
|
||||||
|
pub progress: f64,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tauri::command]
|
||||||
|
pub async fn download_and_extract_theme(
|
||||||
|
app: AppHandle,
|
||||||
|
download_url: String,
|
||||||
|
expected_sha: String,
|
||||||
|
theme_folder: String,
|
||||||
|
theme_name: String,
|
||||||
|
) -> Result<(), String> {
|
||||||
|
let client = reqwest::Client::new();
|
||||||
|
let response = client
|
||||||
|
.get(&download_url)
|
||||||
|
.header(
|
||||||
|
"User-Agent",
|
||||||
|
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36",
|
||||||
|
)
|
||||||
|
.send()
|
||||||
|
.await
|
||||||
|
.map_err(|e| format!("Failed to download theme: {}", e))?;
|
||||||
|
|
||||||
|
let total = response.content_length().unwrap_or(0);
|
||||||
|
let mut received: u64 = 0;
|
||||||
|
let mut chunks: Vec<u8> = Vec::new();
|
||||||
|
|
||||||
|
let mut stream = response.bytes_stream();
|
||||||
|
while let Some(chunk) = futures_util::StreamExt::next(&mut stream).await {
|
||||||
|
let chunk = chunk.map_err(|e| format!("Failed to read chunk: {}", e))?;
|
||||||
|
received += chunk.len() as u64;
|
||||||
|
chunks.extend_from_slice(&chunk);
|
||||||
|
let _ = app.emit(
|
||||||
|
"download_progress",
|
||||||
|
DownloadProgress {
|
||||||
|
theme_name: theme_name.clone(),
|
||||||
|
received,
|
||||||
|
total,
|
||||||
|
progress: if total > 0 {
|
||||||
|
received as f64 / total as f64
|
||||||
|
} else {
|
||||||
|
0.0
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let sha = tokio::task::spawn_blocking({
|
||||||
|
let chunks = chunks.clone();
|
||||||
|
move || {
|
||||||
|
use sha1::{Digest, Sha1};
|
||||||
|
let header = format!("blob {}\0", chunks.len());
|
||||||
|
let mut hasher = Sha1::new();
|
||||||
|
hasher.update(header.as_bytes());
|
||||||
|
hasher.update(&chunks);
|
||||||
|
hex::encode(hasher.finalize())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
.map_err(|e| format!("Thread error: {}", e))?;
|
||||||
|
|
||||||
|
if sha != expected_sha {
|
||||||
|
return Err("Failed to verify downloaded theme file hash.".to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse zip on blocking thread
|
||||||
|
let entries: Vec<(String, Vec<u8>, bool)> = tokio::task::spawn_blocking(move || {
|
||||||
|
let cursor = std::io::Cursor::new(chunks);
|
||||||
|
let mut archive = zip::ZipArchive::new(cursor)
|
||||||
|
.map_err(|e| format!("Failed to read zip archive: {}", e))?;
|
||||||
|
|
||||||
|
let mut entries = Vec::new();
|
||||||
|
for i in 0..archive.len() {
|
||||||
|
let mut zip_entry = archive
|
||||||
|
.by_index(i)
|
||||||
|
.map_err(|e| format!("Failed to read zip entry: {}", e))?;
|
||||||
|
|
||||||
|
let name = match zip_entry.enclosed_name() {
|
||||||
|
Some(p) => p.to_string_lossy().to_string(),
|
||||||
|
None => continue,
|
||||||
|
};
|
||||||
|
|
||||||
|
let is_dir = zip_entry.is_dir();
|
||||||
|
let mut buf = Vec::new();
|
||||||
|
if !is_dir {
|
||||||
|
std::io::copy(&mut zip_entry, &mut buf)
|
||||||
|
.map_err(|e| format!("Failed to read zip entry data: {}", e))?;
|
||||||
|
}
|
||||||
|
entries.push((name, buf, is_dir));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok::<_, String>(entries)
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
.map_err(|e| format!("Thread error: {}", e))??;
|
||||||
|
|
||||||
|
let total_files = entries.len();
|
||||||
|
let mut extracted = 0;
|
||||||
|
|
||||||
|
for (name, buf, is_dir) in entries {
|
||||||
|
let entry_path = std::path::Path::new(&theme_folder).join(&name);
|
||||||
|
|
||||||
|
if is_dir {
|
||||||
|
tokio::fs::create_dir_all(&entry_path)
|
||||||
|
.await
|
||||||
|
.map_err(|e| format!("Failed to create directory: {}", e))?;
|
||||||
|
} else {
|
||||||
|
if let Some(parent) = entry_path.parent() {
|
||||||
|
tokio::fs::create_dir_all(parent)
|
||||||
|
.await
|
||||||
|
.map_err(|e| format!("Failed to create parent directory: {}", e))?;
|
||||||
|
}
|
||||||
|
tokio::fs::write(&entry_path, &buf)
|
||||||
|
.await
|
||||||
|
.map_err(|e| format!("Failed to write file: {}", e))?;
|
||||||
|
}
|
||||||
|
|
||||||
|
extracted += 1;
|
||||||
|
let _ = app.emit(
|
||||||
|
"extract_progress",
|
||||||
|
ExtractProgress {
|
||||||
|
theme_name: theme_name.clone(),
|
||||||
|
total: total_files,
|
||||||
|
extracted,
|
||||||
|
progress: extracted as f64 / total_files as f64,
|
||||||
|
current_file: name,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub async fn extract_theme(
|
pub async fn extract_theme(
|
||||||
app: AppHandle,
|
app: AppHandle,
|
||||||
@@ -1056,6 +1194,7 @@ pub async fn extract_theme(
|
|||||||
theme_folder: String,
|
theme_folder: String,
|
||||||
theme_name: String,
|
theme_name: String,
|
||||||
) -> Result<(), String> {
|
) -> Result<(), String> {
|
||||||
|
app.fs_scope().allow_file(&file_path).ok();
|
||||||
let entries: Vec<(String, Vec<u8>, bool)> = tokio::task::spawn_blocking(move || {
|
let entries: Vec<(String, Vec<u8>, bool)> = tokio::task::spawn_blocking(move || {
|
||||||
let file = std::fs::File::open(&file_path)
|
let file = std::fs::File::open(&file_path)
|
||||||
.map_err(|e| format!("Failed to open theme file: {}", e))?;
|
.map_err(|e| format!("Failed to open theme file: {}", e))?;
|
||||||
@@ -1133,7 +1272,8 @@ pub struct ThemeInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub async fn read_theme_info(file_path: String) -> Result<ThemeInfo, String> {
|
pub async fn read_theme_info(app: AppHandle, file_path: String) -> Result<ThemeInfo, String> {
|
||||||
|
app.fs_scope().allow_file(&file_path).ok();
|
||||||
tokio::task::spawn_blocking(move || {
|
tokio::task::spawn_blocking(move || {
|
||||||
let file = std::fs::File::open(&file_path)
|
let file = std::fs::File::open(&file_path)
|
||||||
.map_err(|e| format!("Failed to open theme file: {}", e))?;
|
.map_err(|e| format!("Failed to open theme file: {}", e))?;
|
||||||
|
|||||||
+11
-10
@@ -9,15 +9,15 @@ pub mod osudb;
|
|||||||
pub mod presence;
|
pub mod presence;
|
||||||
pub mod utils;
|
pub mod utils;
|
||||||
use crate::commands::{
|
use crate::commands::{
|
||||||
check_for_corruption, download_ezpp_launcher_update, download_ezpp_launcher_update_files,
|
check_for_corruption, download_and_extract_theme, download_ezpp_launcher_update,
|
||||||
encrypt_string, exit, extract_theme, find_osu_installation, get_beatmapsets_count,
|
download_ezpp_launcher_update_files, encrypt_string, exit, extract_theme,
|
||||||
get_ezpp_launcher_update_files, get_hwid, get_launcher_version, get_osu_release_stream,
|
find_osu_installation, get_beatmapsets_count, get_ezpp_launcher_update_files, get_hwid,
|
||||||
get_osu_skin, get_osu_version, get_platform, get_skins, get_skins_count, has_net8,
|
get_launcher_version, get_osu_release_stream, get_osu_skin, get_osu_version, get_platform,
|
||||||
has_osuwinello, has_wmctrl, install_ezpp_launcher_update, is_osu_running, open_url_in_browser,
|
get_skins, get_skins_count, has_net8, has_osuwinello, has_wmctrl, install_ezpp_launcher_update,
|
||||||
opened_urls, presence_connect, presence_disconnect, presence_is_connected,
|
is_osu_running, open_url_in_browser, opened_urls, presence_connect, presence_disconnect,
|
||||||
presence_update_button, presence_update_status, presence_update_user, read_theme_info,
|
presence_is_connected, presence_update_button, presence_update_status, presence_update_user,
|
||||||
replace_ui_files, run_osu, run_osu_updater, set_osu_config_values, set_osu_user_config_values,
|
read_theme_info, replace_ui_files, run_osu, run_osu_updater, set_osu_config_values,
|
||||||
valid_osu_folder,
|
set_osu_user_config_values, valid_osu_folder,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct OpenedUrls(Mutex<Vec<PathBuf>>);
|
struct OpenedUrls(Mutex<Vec<PathBuf>>);
|
||||||
@@ -118,7 +118,8 @@ pub fn run() {
|
|||||||
download_ezpp_launcher_update,
|
download_ezpp_launcher_update,
|
||||||
install_ezpp_launcher_update,
|
install_ezpp_launcher_update,
|
||||||
read_theme_info,
|
read_theme_info,
|
||||||
extract_theme
|
extract_theme,
|
||||||
|
download_and_extract_theme
|
||||||
])
|
])
|
||||||
.plugin(tauri_plugin_fs::init())
|
.plugin(tauri_plugin_fs::init())
|
||||||
.plugin(tauri_plugin_dialog::init())
|
.plugin(tauri_plugin_dialog::init())
|
||||||
|
|||||||
+56
-85
@@ -1,5 +1,5 @@
|
|||||||
import { active_custom_theme, custom_themes } from './global';
|
import { active_custom_theme, custom_themes } from './global';
|
||||||
import { calculateGitBlobSha, setGlobalVolume } from './utils';
|
import { setGlobalVolume } from './utils';
|
||||||
import { betterFetch } from '@better-fetch/fetch';
|
import { betterFetch } from '@better-fetch/fetch';
|
||||||
import { convertFileSrc } from '@tauri-apps/api/core';
|
import { convertFileSrc } from '@tauri-apps/api/core';
|
||||||
import { invoke } from '@tauri-apps/api/core';
|
import { invoke } from '@tauri-apps/api/core';
|
||||||
@@ -31,6 +31,13 @@ export type ThemeInfo = {
|
|||||||
preview: string;
|
preview: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type DownloadProgress = {
|
||||||
|
theme_name: string;
|
||||||
|
received: number;
|
||||||
|
total: number;
|
||||||
|
progress: number;
|
||||||
|
};
|
||||||
|
|
||||||
type ExtractProgress = {
|
type ExtractProgress = {
|
||||||
theme_name: string;
|
theme_name: string;
|
||||||
total: number;
|
total: number;
|
||||||
@@ -125,18 +132,6 @@ export const getThemes = async (): Promise<Theme[]> => {
|
|||||||
return themes;
|
return themes;
|
||||||
};
|
};
|
||||||
|
|
||||||
function combineChunks(chunks: Uint8Array[], totalLength: number): Uint8Array {
|
|
||||||
const result = new Uint8Array(totalLength);
|
|
||||||
|
|
||||||
let offset = 0;
|
|
||||||
for (const chunk of chunks) {
|
|
||||||
result.set(chunk, offset);
|
|
||||||
offset += chunk.length;
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const downloadTheme = async (
|
export const downloadTheme = async (
|
||||||
theme: Theme,
|
theme: Theme,
|
||||||
force = false
|
force = false
|
||||||
@@ -168,100 +163,65 @@ export const downloadTheme = async (
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const downloadUrl = `https://git.ez-pp.farm/EZPPFarm/EZPPLauncher-Themes/raw/branch/main/themes/${themeFileName}`;
|
|
||||||
const downloadReq = await fetch(downloadUrl, {
|
|
||||||
method: 'GET',
|
|
||||||
headers: {
|
|
||||||
'User-Agent':
|
|
||||||
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!downloadReq.ok || downloadReq.body === null) {
|
|
||||||
custom_themes.update((themes) => {
|
|
||||||
const matchedTheme = themes.find((t) => t.name === theme.name);
|
|
||||||
if (matchedTheme) matchedTheme.status = 'not-installed';
|
|
||||||
return themes;
|
|
||||||
});
|
|
||||||
return { success: false, error: 'Failed to download theme file.' };
|
|
||||||
}
|
|
||||||
|
|
||||||
custom_themes.update((themes) => {
|
|
||||||
const matchedTheme = themes.find((t) => t.name === theme.name);
|
|
||||||
if (matchedTheme) matchedTheme.progress = 0;
|
|
||||||
return themes;
|
|
||||||
});
|
|
||||||
|
|
||||||
const total = Number(downloadReq.headers.get('content-length')) || 0;
|
|
||||||
const reader = downloadReq.body.getReader();
|
|
||||||
let received = 0;
|
|
||||||
const chunks: Uint8Array[] = [];
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
const { done, value } = await reader.read();
|
|
||||||
if (done) break;
|
|
||||||
chunks.push(value);
|
|
||||||
received += value.length;
|
|
||||||
custom_themes.update((themes) => {
|
|
||||||
const matchedTheme = themes.find((t) => t.name === theme.name);
|
|
||||||
if (matchedTheme) matchedTheme.progress = received / total;
|
|
||||||
return themes;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const fileBuffer = combineChunks(chunks, total);
|
|
||||||
const sha = calculateGitBlobSha(Buffer.from(fileBuffer));
|
|
||||||
|
|
||||||
if (sha !== themeContents.data.file_contents.sha) {
|
|
||||||
custom_themes.update((themes) => {
|
|
||||||
const matchedTheme = themes.find((t) => t.name === theme.name);
|
|
||||||
if (matchedTheme) matchedTheme.status = 'not-installed';
|
|
||||||
return themes;
|
|
||||||
});
|
|
||||||
return { success: false, error: 'Failed to verify downloaded theme file hash.' };
|
|
||||||
}
|
|
||||||
|
|
||||||
custom_themes.update((themes) => {
|
|
||||||
const matchedTheme = themes.find((t) => t.name === theme.name);
|
|
||||||
if (matchedTheme) matchedTheme.status = 'extracting';
|
|
||||||
return themes;
|
|
||||||
});
|
|
||||||
|
|
||||||
const baseThemeFolder = await path.join(await path.homeDir(), '.ezpplauncher', 'themes');
|
const baseThemeFolder = await path.join(await path.homeDir(), '.ezpplauncher', 'themes');
|
||||||
const themeFolder = await path.join(baseThemeFolder, toSafeName(theme.name));
|
const themeFolder = await path.join(baseThemeFolder, toSafeName(theme.name));
|
||||||
if (!(await fs.exists(baseThemeFolder))) await fs.mkdir(baseThemeFolder, { recursive: true });
|
if (!(await fs.exists(baseThemeFolder))) await fs.mkdir(baseThemeFolder, { recursive: true });
|
||||||
if (!(await fs.exists(themeFolder))) await fs.mkdir(themeFolder, { recursive: true });
|
if (!(await fs.exists(themeFolder))) await fs.mkdir(themeFolder, { recursive: true });
|
||||||
|
|
||||||
// Write buffer to temp file for Tauri invoke
|
const downloadUrl = `https://git.ez-pp.farm/EZPPFarm/EZPPLauncher-Themes/raw/branch/main/themes/${themeFileName}`;
|
||||||
const tempPath = await path.join(await path.tempDir(), themeFileName);
|
|
||||||
await fs.writeFile(tempPath, fileBuffer);
|
|
||||||
|
|
||||||
const unlisten = await listen<ExtractProgress>('extract_progress', (event) => {
|
custom_themes.update((themes) => {
|
||||||
|
const matchedTheme = themes.find((t) => t.name === theme.name);
|
||||||
|
if (matchedTheme) {
|
||||||
|
matchedTheme.status = 'downloading';
|
||||||
|
matchedTheme.progress = 0;
|
||||||
|
}
|
||||||
|
return themes;
|
||||||
|
});
|
||||||
|
|
||||||
|
const unlistenDownload = await listen<DownloadProgress>('download_progress', (event) => {
|
||||||
if (event.payload.theme_name !== theme.name) return;
|
if (event.payload.theme_name !== theme.name) return;
|
||||||
custom_themes.update((themes) => {
|
custom_themes.update((themes) => {
|
||||||
const matchedTheme = themes.find((t) => t.name === theme.name);
|
const matchedTheme = themes.find((t) => t.name === theme.name);
|
||||||
if (matchedTheme) matchedTheme.progress = event.payload.progress;
|
if (matchedTheme) {
|
||||||
|
matchedTheme.status = 'downloading';
|
||||||
|
matchedTheme.progress = event.payload.progress;
|
||||||
|
}
|
||||||
|
return themes;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const unlistenExtract = await listen<ExtractProgress>('extract_progress', (event) => {
|
||||||
|
if (event.payload.theme_name !== theme.name) return;
|
||||||
|
custom_themes.update((themes) => {
|
||||||
|
const matchedTheme = themes.find((t) => t.name === theme.name);
|
||||||
|
if (matchedTheme) {
|
||||||
|
matchedTheme.status = 'extracting';
|
||||||
|
matchedTheme.progress = event.payload.progress;
|
||||||
|
}
|
||||||
return themes;
|
return themes;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await invoke('extract_theme', {
|
await invoke('download_and_extract_theme', {
|
||||||
filePath: tempPath,
|
downloadUrl,
|
||||||
|
expectedSha: themeContents.data.file_contents.sha,
|
||||||
themeFolder,
|
themeFolder,
|
||||||
themeName: theme.name,
|
themeName: theme.name,
|
||||||
});
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
|
const erro = err as Error;
|
||||||
custom_themes.update((themes) => {
|
custom_themes.update((themes) => {
|
||||||
const matchedTheme = themes.find((t) => t.name === theme.name);
|
const matchedTheme = themes.find((t) => t.name === theme.name);
|
||||||
if (matchedTheme) matchedTheme.status = 'not-installed';
|
if (matchedTheme) matchedTheme.status = 'not-installed';
|
||||||
return themes;
|
return themes;
|
||||||
});
|
});
|
||||||
return { success: false, error: 'Failed to extract theme file.' };
|
return { success: false, error: erro.message || 'Failed to download or extract theme.' };
|
||||||
} finally {
|
} finally {
|
||||||
unlisten();
|
unlistenDownload();
|
||||||
await fs.remove(tempPath).catch(() => {});
|
unlistenExtract();
|
||||||
}
|
}
|
||||||
|
|
||||||
const themeInfo = await fs.readTextFile(await path.join(themeFolder, 'theme.json'));
|
const themeInfo = await fs.readTextFile(await path.join(themeFolder, 'theme.json'));
|
||||||
@@ -282,6 +242,7 @@ export const downloadTheme = async (
|
|||||||
matchedTheme.preview = themePreview;
|
matchedTheme.preview = themePreview;
|
||||||
matchedTheme.status = 'installed';
|
matchedTheme.status = 'installed';
|
||||||
matchedTheme.progress = 1;
|
matchedTheme.progress = 1;
|
||||||
|
matchedTheme.folder_name = toSafeName(theme.name);
|
||||||
}
|
}
|
||||||
return themes;
|
return themes;
|
||||||
});
|
});
|
||||||
@@ -301,11 +262,21 @@ export const loadTheme = async (theme: Theme, themeContainer: HTMLElement, volum
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const deleteTheme = async (themeToUninstall: Theme) => {
|
export const deleteTheme = async (themeToUninstall: Theme) => {
|
||||||
if (themeToUninstall.status !== 'installed') return false;
|
console.log('Uninstall', themeToUninstall);
|
||||||
|
if (themeToUninstall.status !== 'installed') {
|
||||||
|
console.log('Theme is not installed', themeToUninstall.status);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
const baseThemeFolder = await path.join(await path.homeDir(), '.ezpplauncher', 'themes');
|
const baseThemeFolder = await path.join(await path.homeDir(), '.ezpplauncher', 'themes');
|
||||||
if (!(await fs.exists(baseThemeFolder))) return false;
|
if (!(await fs.exists(baseThemeFolder))) {
|
||||||
|
console.log('Theme base folder does not exist');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
const themeFolder = await path.join(baseThemeFolder, themeToUninstall.folder_name);
|
const themeFolder = await path.join(baseThemeFolder, themeToUninstall.folder_name);
|
||||||
if (!(await fs.exists(themeFolder))) return false;
|
if (!(await fs.exists(themeFolder))) {
|
||||||
|
console.log('Theme folder does not exist', themeFolder);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
custom_themes.update((themes) => {
|
custom_themes.update((themes) => {
|
||||||
const matchedTheme = themes.find((t) => t.name === themeToUninstall.name);
|
const matchedTheme = themes.find((t) => t.name === themeToUninstall.name);
|
||||||
if (matchedTheme) {
|
if (matchedTheme) {
|
||||||
|
|||||||
@@ -1910,7 +1910,17 @@
|
|||||||
size="icon"
|
size="icon"
|
||||||
variant="destructive"
|
variant="destructive"
|
||||||
disabled={theme.status !== 'installed'}
|
disabled={theme.status !== 'installed'}
|
||||||
onclick={() => deleteTheme(theme)}
|
onclick={async () => {
|
||||||
|
try {
|
||||||
|
await deleteTheme(theme);
|
||||||
|
} catch (err) {
|
||||||
|
console.log(err);
|
||||||
|
sileo.error({
|
||||||
|
title: 'Uhhm..',
|
||||||
|
description: 'Failed to uninstall theme.',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
{#if theme.status === 'deleting'}
|
{#if theme.status === 'deleting'}
|
||||||
<LoaderCircle class="animate-spin" />
|
<LoaderCircle class="animate-spin" />
|
||||||
|
|||||||
Reference in new issue
Block a user