A photo manager for VRChat.
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

more updates

+81 -42
+3 -1
changelog
··· 54 54 - Move away from localstorage and use the .config file 55 55 - Seems to be semi-stable on linux 56 56 - Update deeplink library 57 - - Fix bugs with multiple screens displaying on frontend 57 + - Fix bugs with multiple screens displaying on frontend 58 + - Fix caching issues with photo paths 59 + - Fix VRCPM using way to many resources while being minimised after starting in the background
+8 -4
src-tauri/src/frontend_calls/delete_photo.rs
··· 1 - use crate::util::get_photo_path::get_photo_path; 2 - use std::{fs, thread, time::Duration}; 1 + use tauri::State; 2 + 3 + use crate::util::cache::Cache; 4 + use std::{ fs, thread, time::Duration }; 3 5 4 6 // Delete a photo when the users confirms the prompt in the ui 5 7 #[tauri::command] 6 - pub fn delete_photo(path: String, token: String, is_syncing: bool) { 8 + pub fn delete_photo(path: String, token: String, is_syncing: bool, cache: State<Cache>) { 9 + let photo_path = cache.get("photo-path".into()); 10 + 7 11 thread::spawn(move || { 8 - let p = get_photo_path().join(&path); 12 + let p = photo_path.unwrap() + "/" + &path; 9 13 fs::remove_file(p).unwrap(); 10 14 11 15 let photo = path.split("/").last().unwrap();
+6 -4
src-tauri/src/frontend_calls/get_user_photos_path.rs
··· 1 - use crate::util::get_photo_path::get_photo_path; 2 - use std::path; 1 + use tauri::State; 2 + 3 + use crate::util::cache::Cache; 3 4 4 5 // Check if the photo config file exists 5 6 // if not just return the default vrchat path 6 7 #[tauri::command] 7 - pub fn get_user_photos_path() -> path::PathBuf { 8 - get_photo_path() 8 + pub fn get_user_photos_path( cache: State<Cache> ) -> String { 9 + let photo_path = cache.get("photo-path".into()); 10 + photo_path.unwrap() 9 11 }
+5 -4
src-tauri/src/frontend_calls/load_photo_meta.rs
··· 1 - use crate::util::get_photo_path::get_photo_path; 1 + use crate::util::cache::Cache; 2 2 use crate::PNGImage; 3 3 use std::{fs, io::Read, thread}; 4 - use tauri::Emitter; 4 + use tauri::{Emitter, State}; 5 5 6 6 // Reads the PNG file and loads the image metadata from it 7 7 // then sends the metadata to the frontend, returns width, height, colour depth and so on... more info "pngmeta.rs" 8 8 #[tauri::command] 9 - pub fn load_photo_meta(photo: &str, window: tauri::Window) { 9 + pub fn load_photo_meta(photo: &str, window: tauri::Window, cache: State<Cache> ) { 10 + let photo_path = cache.get("photo-path".into()); 10 11 let photo = photo.to_string(); 11 12 12 13 thread::spawn(move || { 13 - let base_dir = get_photo_path().join(&photo); 14 + let base_dir = photo_path.unwrap() + "/" + &photo; 14 15 15 16 let file = fs::File::open(base_dir.clone()); 16 17
+5 -4
src-tauri/src/frontend_calls/load_photos.rs
··· 1 - use crate::util::get_photo_path::get_photo_path; 1 + use crate::util::cache::Cache; 2 2 use regex::Regex; 3 3 use std::{fs, path, thread}; 4 - use tauri::Emitter; 4 + use tauri::{Emitter, State}; 5 5 6 6 // Scans all files under the "Pictures/VRChat" path 7 7 // then sends the list of photos to the frontend ··· 12 12 } 13 13 14 14 #[tauri::command] 15 - pub fn load_photos(window: tauri::Window) { 15 + pub fn load_photos(window: tauri::Window, cache: State<Cache> ) { 16 + let base_dir = cache.get("photo-path".into()).unwrap(); 17 + 16 18 thread::spawn(move || { 17 - let base_dir = get_photo_path(); 18 19 19 20 let mut photos: Vec<path::PathBuf> = Vec::new(); 20 21 let mut size: usize = 0;
+6
src-tauri/src/main.rs
··· 12 12 use notify::{EventKind, RecursiveMode, Watcher}; 13 13 use pngmeta::PNGImage; 14 14 use regex::Regex; 15 + use util::cache::Cache; 15 16 use std::{env, fs, thread}; 16 17 use tauri::{Emitter, Manager, WindowEvent}; 17 18 use tauri_plugin_deep_link::DeepLinkExt; ··· 19 20 // TODO: Linux support 20 21 21 22 fn main() { 23 + let cache = Cache::new(); 24 + 22 25 // Double check the app has an install directory 23 26 let container_folder = dirs::config_dir() 24 27 .unwrap() ··· 72 75 73 76 println!("Loading App..."); 74 77 let photos_path = util::get_photo_path::get_photo_path(); 78 + 79 + cache.insert("photo-path".into(), photos_path.to_str().unwrap().to_owned()); 75 80 76 81 match fs::metadata(&photos_path) { 77 82 Ok(_) => {} ··· 152 157 } 153 158 _ => {} 154 159 }) 160 + .manage(cache) 155 161 .setup(|app| { 156 162 let handle = app.handle(); 157 163
+28
src-tauri/src/util/cache.rs
··· 1 + use std::{collections::HashMap, sync::Mutex}; 2 + 3 + pub struct Cache{ 4 + store: Mutex<HashMap<String, String>>, 5 + } 6 + 7 + impl Cache{ 8 + pub fn new() -> Self{ 9 + Cache { 10 + store: Mutex::new(HashMap::new()) 11 + } 12 + } 13 + 14 + pub fn insert( &self, key: String, value: String ){ 15 + self.store.lock().unwrap().insert(key, value); 16 + } 17 + 18 + pub fn get( &self, key: String ) -> Option<String>{ 19 + let store = self.store.lock().unwrap(); 20 + let val = store.get(&key); 21 + 22 + if val.is_none(){ 23 + None 24 + } else{ 25 + Some(val.unwrap().clone()) 26 + } 27 + } 28 + }
+12 -24
src-tauri/src/util/get_photo_path.rs
··· 1 - use std::{fs, path, sync::RwLock}; 2 - 3 - static CACHED_PATH: RwLock<Option<path::PathBuf>> = RwLock::new(None); 1 + use std::{ fs, path }; 4 2 5 3 pub fn get_photo_path() -> path::PathBuf { 6 - let path = CACHED_PATH.read().unwrap(); 7 - if path.is_none(){ 8 - let config_path = dirs::config_dir() 9 - .unwrap() 10 - .join("PhazeDev/VRChatPhotoManager/.photos_path"); 11 - 12 - dbg!(&config_path); 13 - 14 - match fs::read_to_string(config_path) { 15 - Ok(path) => { 16 - let p = path::PathBuf::from(path); 4 + let config_path = dirs::config_dir() 5 + .unwrap() 6 + .join("PhazeDev/VRChatPhotoManager/.photos_path"); 17 7 18 - let mut wpath = CACHED_PATH.write().unwrap(); 19 - *wpath = Some(p.clone()); 8 + dbg!(&config_path); 20 9 21 - p 22 - }, 23 - Err(_) => { 24 - let p = dirs::picture_dir().unwrap().join("VRChat"); 10 + match fs::read_to_string(config_path) { 11 + Ok(path) => { 12 + path::PathBuf::from(path) 13 + }, 14 + Err(_) => { 15 + let p = dirs::picture_dir().unwrap().join("VRChat"); 25 16 26 - p 27 - } 17 + p 28 18 } 29 - } else{ 30 - path.clone().unwrap() 31 19 } 32 20 }
+1
src-tauri/src/util/mod.rs
··· 4 4 pub mod handle_uri_proto; 5 5 pub mod handle_deeplink; 6 6 pub mod setup_traymenu; 7 + pub mod cache;
+7 -1
src/Components/PhotoList.tsx
··· 56 56 let scroll: number = 0; 57 57 let targetScroll: number = 0; 58 58 59 - let quitRender: boolean = false; 59 + let quitRender: boolean = true; 60 60 let photoPath: string; 61 61 62 62 let currentPopup = ListPopup.NONE; ··· 206 206 }) 207 207 208 208 let render = () => { 209 + console.log('render', quitRender); 210 + 209 211 if(!quitRender) 210 212 requestAnimationFrame(render); 211 213 else ··· 368 370 } 369 371 370 372 listen('hide-window', () => { 373 + console.log('Hide Window'); 371 374 quitRender = true; 372 375 }) 373 376 374 377 listen('show-window', () => { 378 + console.log('Shown Window'); 379 + quitRender = false; 380 + 375 381 if(hasFirstLoaded) 376 382 requestAnimationFrame(render); 377 383 })