fixed thumbnail gen

This commit is contained in:
Jamie 2021-12-27 21:49:43 -08:00
parent 1d09081f71
commit 25324fb1f9
7 changed files with 146 additions and 25 deletions

View file

@ -1,9 +1,12 @@
use std::time::Instant;
use anyhow::Result;
use sdcorelib::db::connection::db_instance;
use sdcorelib::file::{indexer, retrieve, retrieve::Directory};
use sdcorelib::native;
use sdcorelib::{AppConfig, CONFIG};
use sdcorelib::AppConfig;
use serde::Serialize;
use std::fs;
use swift_rs::types::SRObjectArray;
#[derive(Serialize)]
@ -46,7 +49,7 @@ pub async fn get_files(path: String) -> Result<Directory, String> {
}
#[tauri::command(async)]
pub async fn get_config() -> Result<&'static AppConfig, String> {
Ok(CONFIG.get().unwrap())
Ok(&sdcorelib::EXTERNAL_CLIENT.get().unwrap().config)
}
#[tauri::command]
pub fn get_mounts() -> Result<SRObjectArray<native::methods::Mount>, String> {
@ -77,3 +80,48 @@ pub async fn test_scan() -> Result<(), String> {
// // ....
// }
#[tauri::command(async)]
pub async fn get_thumbs_for_directory(window: tauri::Window, path: &str) -> Result<(), String> {
let config = &sdcorelib::EXTERNAL_CLIENT.get().unwrap().config;
let dir = retrieve::get_dir_with_contents(&path).await?;
// iterate over directory contents
for file in dir.contents.into_iter() {
let now = Instant::now();
let icon_name = format!(
"{}.png",
if file.is_dir {
"folder".to_owned()
} else {
file.extension
}
);
let icon_path = config.file_type_thumb_dir.join(icon_name);
// extract metadata from file
let existing = fs::metadata(&icon_path).is_ok();
// write thumbnail only if
if !existing {
// call swift to get thumbnail data
let thumbnail_b64 =
sdcorelib::native::methods::get_file_thumbnail_base64(&file.uri).to_string();
fs::write(
&icon_path,
base64::decode(thumbnail_b64).unwrap_or_default(),
)
.map_err(|_| "thumb_cache_failure")?;
}
println!("cached thumb {:?} in {:?}", file.id, now.elapsed());
if !existing {
reply(
&window,
GlobalEventKind::FileTypeThumb,
GenFileTypeIconsResponse {
icon_created: true,
file_id: file.id,
},
)
}
}
Ok(())
}

View file

@ -1,12 +1,11 @@
mod commands;
mod menu;
use futures::executor::block_on;
use sdcorelib;
use tauri::api::path;
fn main() {
let data_dir = path::data_dir().unwrap_or(std::path::PathBuf::from("./"));
block_on(sdcorelib::configure(data_dir));
sdcorelib::configure(data_dir);
tauri::Builder::default()
.setup(|_app| Ok(()))
@ -17,6 +16,7 @@ fn main() {
commands::get_config,
commands::get_mounts,
commands::test_scan,
commands::get_thumbs_for_directory,
])
.menu(menu::get_menu())
.run(tauri::generate_context!())

View file

@ -11,18 +11,18 @@ export const Shortcut: React.FC<ShortcutProps> = (props) => {
<span
className={clsx(
`
px-1
py-0.5
text-xs
font-bold
text-gray-400
bg-gray-200
border-gray-300
dark:text-gray-400
dark:bg-gray-600
dark:border-gray-500
border-t-2
rounded-lg
px-1
py-0.5
text-xs
font-bold
text-gray-400
bg-gray-200
border-gray-300
dark:text-gray-400
dark:bg-gray-600
dark:border-gray-500
border-t-2
rounded-lg
`,
props.className
)}

View file

@ -1,4 +1,5 @@
import React from 'react';
import { Button } from '../components/primitive';
import { Tag } from '../components/primitive/Tag';
interface StatItemProps {
@ -20,6 +21,7 @@ const StatItem: React.FC<StatItemProps> = (props) => {
};
export const OverviewScreen: React.FC<{}> = (props) => {
return (
<div className="flex flex-col w-full h-full p-5 bg-white dark:bg-gray-900">
<h1 className="text-xl font-bold ">Jamie's Library</h1>
@ -43,7 +45,6 @@ export const OverviewScreen: React.FC<{}> = (props) => {
</div>
<hr className="my-5 dark:border-gray-800" />
<div>
</div>
</div>
);

View file

@ -1,4 +1,4 @@
use crate::CONFIG;
use crate::EXTERNAL_CLIENT;
use anyhow::Result;
use once_cell::sync::OnceCell;
use rusqlite::Connection;
@ -8,7 +8,7 @@ use sea_orm::{Database, DatabaseConnection, DbErr};
// use std::str::FromStr;
pub async fn get_connection() -> Result<DatabaseConnection, DbErr> {
let config = CONFIG.get().unwrap();
let config = &EXTERNAL_CLIENT.get().unwrap().config;
let db_url = format!("{}{}", "sqlite://", config.primary_db.to_str().unwrap());
@ -29,7 +29,7 @@ pub async fn db_instance() -> Result<&'static DatabaseConnection, String> {
}
pub async fn create_primary_db() -> Result<(), sqlx::Error> {
let config = CONFIG.get().unwrap();
let config = &EXTERNAL_CLIENT.get().unwrap().config;
let db_url = config.primary_db.to_str().unwrap();
// establish connection, this is only used to create the db if missing

View file

@ -0,0 +1,45 @@
pub async fn get_thumbs_for_directory(window: tauri::Window, path: &str) -> Result<(), String> {
let config = config::get_config();
let dir = filesystem::retrieve::get_dir_with_contents(&path).await?;
// iterate over directory contents
for file in dir.contents.into_iter() {
let now = Instant::now();
let icon_name = format!(
"{}.png",
if file.is_dir {
"folder".to_owned()
} else {
file.extension
}
);
let icon_path = config.file_type_thumb_dir.join(icon_name);
// extract metadata from file
let existing = fs::metadata(&icon_path).is_ok();
// write thumbnail only if
if !existing {
// call swift to get thumbnail data
let thumbnail_b64 = get_file_thumbnail_base64(&file.uri).to_string();
fs::write(
&icon_path,
base64::decode(thumbnail_b64).unwrap_or_default(),
)
.map_err(|_| "thumb_cache_failure")?;
}
println!("cached thumb {:?} in {:?}", file.id, now.elapsed());
if !existing {
reply(
&window,
GlobalEventKind::FileTypeThumb,
GenFileTypeIconsResponse {
icon_created: true,
file_id: file.id,
},
)
}
}
Ok(())
}

View file

@ -17,9 +17,31 @@ pub struct AppConfig {
pub file_type_thumb_dir: std::path::PathBuf,
}
pub static CONFIG: OnceCell<AppConfig> = OnceCell::new();
// represents an event this library can emit
#[derive(Serialize, Deserialize, Debug)]
pub enum ClientEvent {
NewFileTypeThumb,
}
pub async fn configure(mut data_dir: std::path::PathBuf) {
// represents an application or client instance to communicate with
#[derive(Serialize, Deserialize, Debug)]
pub struct ExternalClient {
pub config: AppConfig,
}
trait Emitter {
fn emit(&self, event: ClientEvent, data: &str) -> Result<(), String>;
}
impl Emitter for ExternalClient {
fn emit(&self, event: ClientEvent, _: &str) -> Result<(), String> {
Ok(())
}
}
pub static EXTERNAL_CLIENT: OnceCell<ExternalClient> = OnceCell::new();
pub fn configure(mut data_dir: std::path::PathBuf) {
data_dir = data_dir.join("spacedrive");
let config = AppConfig {
@ -27,11 +49,16 @@ pub async fn configure(mut data_dir: std::path::PathBuf) {
primary_db: data_dir.clone().join("primary.db3"),
file_type_thumb_dir: data_dir.clone().join("file_icons"),
};
CONFIG.set(config).unwrap();
EXTERNAL_CLIENT.set(ExternalClient { config });
// EXTERNAL_CLIENT
// .unwrap()
// .emit(ClientEvent::NewFileTypeThumb, "...");
// create the data directories if not present
fs::create_dir_all(&CONFIG.get().unwrap().data_dir).unwrap();
fs::create_dir_all(&CONFIG.get().unwrap().file_type_thumb_dir).unwrap();
fs::create_dir_all(&EXTERNAL_CLIENT.get().unwrap().config.data_dir).unwrap();
fs::create_dir_all(&EXTERNAL_CLIENT.get().unwrap().config.file_type_thumb_dir).unwrap();
// create primary data base if not exists
block_on(db::connection::create_primary_db()).unwrap();