feat(settings): add button to open app data folder

This commit is contained in:
2025-10-05 00:17:33 -04:00
parent 8fb27b1acd
commit ca5f79b23a
9 changed files with 122 additions and 24 deletions

50
src-tauri/Cargo.lock generated
View File

@@ -21,6 +21,7 @@ dependencies = [
"tauri-plugin-fs",
"tauri-plugin-http",
"tauri-plugin-opener",
"tauri-plugin-os",
"tauri-plugin-process",
"tauri-plugin-sql",
"tauri-plugin-store",
@@ -1471,6 +1472,16 @@ dependencies = [
"version_check",
]
[[package]]
name = "gethostname"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc257fdb4038301ce4b9cd1b3b51704509692bb3ff716a410cbd07925d9dae55"
dependencies = [
"rustix",
"windows-targets 0.52.6",
]
[[package]]
name = "getrandom"
version = "0.1.16"
@@ -2969,6 +2980,18 @@ dependencies = [
"pin-project-lite",
]
[[package]]
name = "os_info"
version = "3.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d0e1ac5fde8d43c34139135df8ea9ee9465394b2d8d20f032d38998f64afffc3"
dependencies = [
"log",
"plist",
"serde",
"windows-sys 0.52.0",
]
[[package]]
name = "pango"
version = "0.18.3"
@@ -4609,6 +4632,15 @@ dependencies = [
"syn 2.0.106",
]
[[package]]
name = "sys-locale"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8eab9a99a024a169fe8a903cf9d4a3b3601109bcc13bd9e3c6fff259138626c4"
dependencies = [
"libc",
]
[[package]]
name = "system-configuration"
version = "0.6.1"
@@ -4919,6 +4951,24 @@ dependencies = [
"zbus",
]
[[package]]
name = "tauri-plugin-os"
version = "2.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77a1c77ebf6f20417ab2a74e8c310820ba52151406d0c80fbcea7df232e3f6ba"
dependencies = [
"gethostname",
"log",
"os_info",
"serde",
"serde_json",
"serialize-to-javascript",
"sys-locale",
"tauri",
"tauri-plugin",
"thiserror 2.0.17",
]
[[package]]
name = "tauri-plugin-process"
version = "2.3.0"

View File

@@ -36,4 +36,5 @@ byteorder = "1.5.0"
reqwest = { version = "0.12.23", features = ["stream", "rustls-tls"] }
tokio = { version = "1.47.1", features = ["fs", "io-util"] }
futures-util = "0.3.31"
tauri-plugin-os = "2"

View File

@@ -8,6 +8,20 @@
"permissions": [
"core:default",
"opener:default",
{
"identifier": "opener:allow-open-path",
"allow": [
{
"path": "$APPDATA"
},
{
"path": "$APPCONFIG"
},
{
"path": "$APPLOCALDATA"
}
]
},
"core:window:default",
"core:window:allow-start-dragging",
"core:window:allow-minimize",
@@ -63,6 +77,7 @@
},
"sql:default",
"sql:allow-execute",
"process:default"
"process:default",
"os:default"
]
}

View File

@@ -23,8 +23,7 @@ pub fn generate_blowfish_key(track_id: &str) -> Vec<u8> {
/// Decrypt a single 2048-byte chunk using Blowfish CBC
pub fn decrypt_chunk(chunk: &[u8], blowfish_key: &[u8]) -> Vec<u8> {
let cipher = Blowfish::<BigEndian>::new_from_slice(blowfish_key)
.expect("Invalid key length");
let cipher = Blowfish::<BigEndian>::new_from_slice(blowfish_key).expect("Invalid key length");
let mut result = chunk.to_vec();
let iv = [0u8, 1, 2, 3, 4, 5, 6, 7];

View File

@@ -1,8 +1,8 @@
use tauri_plugin_sql::{Migration, MigrationKind};
mod tagger;
mod metadata;
mod deezer_crypto;
mod metadata;
mod tagger;
// Learn more about Tauri commands at https://tauri.app/develop/calling-rust/
#[tauri::command]
@@ -58,10 +58,10 @@ async fn download_and_decrypt_track(
is_encrypted: bool,
window: tauri::Window,
) -> Result<(), String> {
use tokio::io::AsyncWriteExt;
use tokio::fs::File;
use deezer_crypto::StreamingDecryptor;
use tauri::Emitter;
use tokio::fs::File;
use tokio::io::AsyncWriteExt;
// Build HTTP client
let client = reqwest::Client::builder()
@@ -117,11 +117,14 @@ async fn download_and_decrypt_track(
if rounded_percentage > last_reported_percentage || percentage == 100 {
last_reported_percentage = rounded_percentage;
let _ = window.emit("download-progress", serde_json::json!({
"downloaded": downloaded_bytes,
"total": total_size as u64,
"percentage": percentage
}));
let _ = window.emit(
"download-progress",
serde_json::json!({
"downloaded": downloaded_bytes,
"total": total_size as u64,
"percentage": percentage
}),
);
}
}
}
@@ -154,11 +157,14 @@ async fn download_and_decrypt_track(
if rounded_percentage > last_reported_percentage || percentage == 100 {
last_reported_percentage = rounded_percentage;
let _ = window.emit("download-progress", serde_json::json!({
"downloaded": downloaded_bytes,
"total": total_size as u64,
"percentage": percentage
}));
let _ = window.emit(
"download-progress",
serde_json::json!({
"downloaded": downloaded_bytes,
"total": total_size as u64,
"percentage": percentage
}),
);
}
}
}
@@ -293,6 +299,7 @@ pub fn run() {
}];
tauri::Builder::default()
.plugin(tauri_plugin_os::init())
.plugin(tauri_plugin_process::init())
.plugin(
tauri_plugin_sql::Builder::new()

View File

@@ -1,5 +1,5 @@
use metaflac::Tag as FlacTag;
use id3::{Tag as ID3Tag, TagLike};
use metaflac::Tag as FlacTag;
use serde::{Deserialize, Serialize};
use std::path::Path;
@@ -40,8 +40,8 @@ pub fn read_audio_metadata(path: &str) -> Result<AudioMetadata, String> {
/// Read metadata from MP3 file
fn read_mp3_metadata(path: &str) -> Result<AudioMetadata, String> {
let tag = ID3Tag::read_from_path(path)
.map_err(|e| format!("Failed to read MP3 tags: {}", e))?;
let tag =
ID3Tag::read_from_path(path).map_err(|e| format!("Failed to read MP3 tags: {}", e))?;
Ok(AudioMetadata {
title: tag.title().map(|s| s.to_string()),
@@ -55,8 +55,8 @@ fn read_mp3_metadata(path: &str) -> Result<AudioMetadata, String> {
/// Read metadata from FLAC file
fn read_flac_metadata(path: &str) -> Result<AudioMetadata, String> {
let tag = FlacTag::read_from_path(path)
.map_err(|e| format!("Failed to read FLAC tags: {}", e))?;
let tag =
FlacTag::read_from_path(path).map_err(|e| format!("Failed to read FLAC tags: {}", e))?;
// Helper to get first value from vorbis comment
let get_first = |key: &str| -> Option<String> {
@@ -66,8 +66,7 @@ fn read_flac_metadata(path: &str) -> Result<AudioMetadata, String> {
};
// Parse track number
let track_number = get_first("TRACKNUMBER")
.and_then(|s| s.parse::<u32>().ok());
let track_number = get_first("TRACKNUMBER").and_then(|s| s.parse::<u32>().ok());
// Get duration from streaminfo block (in samples)
let duration = tag.get_streaminfo().map(|info| {