mirror of
https://github.com/spacedriveapp/spacedrive.git
synced 2026-10-11 03:52:06 -04:00
Object Kind (#397)
* add temp custom icons and tweak styles * tweaks * - added Object type structs - added extension enums with variant macros - improved explorer rendering - added database migration hotfix * - added dev only data folder - improved explorer image loading * macros do rule ! * remove baselining Co-authored-by: Brendan Allan <brendonovich@outlook.com>
This commit is contained in:
1 parent
9bf071e5d9
commit
d27ff3cd80
24 files changed
+848
-253
No files matched your search
@@ -51,8 +51,8 @@ pub(crate) fn mount() -> RouterBuilder {
|
||||
.spawn_job(Job::new(
|
||||
ThumbnailJobInit {
|
||||
location_id: args.id,
|
||||
path: args.path,
|
||||
background: false, // fix
|
||||
path: PathBuf::new(),
|
||||
background: true,
|
||||
},
|
||||
Box::new(ThumbnailJob {}),
|
||||
))
|
||||
|
||||
@@ -46,6 +46,9 @@ const CONSOLE_LOG_FILTER: LevelFilter = LevelFilter::INFO;
|
||||
impl Node {
|
||||
pub async fn new(data_dir: impl AsRef<Path>) -> Result<(Arc<Node>, Arc<Router>), NodeError> {
|
||||
let data_dir = data_dir.as_ref();
|
||||
#[cfg(debug_assertions)]
|
||||
let data_dir = data_dir.join("dev");
|
||||
|
||||
fs::create_dir_all(&data_dir).await?;
|
||||
|
||||
tracing_subscriber::registry()
|
||||
|
||||
@@ -0,0 +1,267 @@
|
||||
use std::{
|
||||
fmt::{Display, Formatter},
|
||||
str::FromStr,
|
||||
};
|
||||
|
||||
use int_enum::IntEnum;
|
||||
use rspc::Type;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::Value;
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone, Copy, Type, IntEnum)]
|
||||
#[repr(u8)]
|
||||
pub enum ObjectKind {
|
||||
// A file that can not be identified by the indexer
|
||||
Unknown = 0,
|
||||
// A known filetype, but without specific support
|
||||
Document = 1,
|
||||
// A virtual filesystem directory
|
||||
Folder = 2,
|
||||
// A file that contains human-readable text
|
||||
Text = 3,
|
||||
// A virtual directory int
|
||||
Package = 4,
|
||||
// An image file
|
||||
Image = 5,
|
||||
// An audio file
|
||||
Audio = 6,
|
||||
// A video file
|
||||
Video = 7,
|
||||
// A compressed archive of data
|
||||
Archive = 8,
|
||||
// An executable, program or application
|
||||
Executable = 9,
|
||||
// A link to another object
|
||||
Alias = 10,
|
||||
// Raw bytes encrypted by Spacedrive with self contained metadata
|
||||
Encrypted = 11,
|
||||
// A link can open web pages, apps or Spaces
|
||||
Key = 12,
|
||||
// A link can open web pages, apps or Spaces
|
||||
Link = 13,
|
||||
// A special filetype that represents a preserved webpage
|
||||
WebPageArchive = 14,
|
||||
// A widget is a mini app that can be placed in a Space at various sizes, associated Widget struct required
|
||||
Widget = 15,
|
||||
// Albums can only have one level of children, and are associated with the Album struct
|
||||
Album = 16,
|
||||
// Its like a folder, but appears like a stack of files, designed for burst photos / associated groups of files
|
||||
Collection = 17,
|
||||
}
|
||||
|
||||
macro_rules! extension_enum {
|
||||
(
|
||||
Extension {
|
||||
$( $variant:ident($type:ident), )*
|
||||
}
|
||||
) => {
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub enum Extension {
|
||||
$( $variant($type), )*
|
||||
}
|
||||
// convert extension to object kind
|
||||
impl From<Extension> for ObjectKind {
|
||||
fn from(ext: Extension) -> Self {
|
||||
match ext {
|
||||
$( Extension::$variant(_) => ObjectKind::$variant, )*
|
||||
}
|
||||
}
|
||||
}
|
||||
impl Display for Extension {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
$( Extension::$variant(x) => write!(f, "{}", x), )*
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
extension_enum! {
|
||||
Extension {
|
||||
Unknown(String),
|
||||
Video(VideoExtension),
|
||||
Image(ImageExtension),
|
||||
Audio(AudioExtension),
|
||||
Archive(ArchiveExtension),
|
||||
Executable(ExecutableExtension),
|
||||
Text(TextExtension),
|
||||
Encrypted(EncryptedExtension),
|
||||
Key(KeyExtension),
|
||||
}
|
||||
}
|
||||
|
||||
/// Define a public enum with static array of all possible variants
|
||||
/// including implementations to convert to/from string
|
||||
macro_rules! enum_with_variants {
|
||||
(
|
||||
$(#[$enum_attr:meta])*
|
||||
$enum_name:ident $static_array_name:ident {
|
||||
$($(#[$variant_attr:meta])* $variant:ident, )*
|
||||
}
|
||||
) => {
|
||||
#[derive(Debug, Serialize, Deserialize, Clone, Copy)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
$(#[$enum_attr])*
|
||||
// construct enum
|
||||
pub enum $enum_name {
|
||||
$( $(#[$variant_attr])* $variant, )*
|
||||
}
|
||||
// a static array of all variants
|
||||
pub static $static_array_name: &[$enum_name] = &[
|
||||
$( $enum_name::$variant, )*
|
||||
];
|
||||
// convert from string
|
||||
impl FromStr for $enum_name {
|
||||
type Err = serde_json::Error;
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
serde_json::from_value(Value::String(s.to_string()))
|
||||
}
|
||||
}
|
||||
// convert to string
|
||||
impl std::fmt::Display for $enum_name {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", serde_json::to_string(self).unwrap()) // SAFETY: This is safe
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// video extensions
|
||||
enum_with_variants! {
|
||||
VideoExtension ALL_VIDEO_EXTENSIONS {
|
||||
Avi,
|
||||
Asf,
|
||||
Mpeg,
|
||||
Mts,
|
||||
Mpg,
|
||||
Mpe,
|
||||
Qt,
|
||||
Mov,
|
||||
Swf,
|
||||
Mjpeg,
|
||||
Ts,
|
||||
Mxf,
|
||||
M2v,
|
||||
M2ts,
|
||||
Flv,
|
||||
Wm,
|
||||
#[serde(rename = "3gp")]
|
||||
_3gp,
|
||||
M4v,
|
||||
Wmv,
|
||||
Mp4,
|
||||
Webm,
|
||||
}
|
||||
}
|
||||
|
||||
// image extensions
|
||||
enum_with_variants! {
|
||||
ImageExtension _ALL_IMAGE_EXTENSIONS {
|
||||
Jpg,
|
||||
Jpeg,
|
||||
Png,
|
||||
Gif,
|
||||
Bmp,
|
||||
Tiff,
|
||||
Webp,
|
||||
Svg,
|
||||
Ico,
|
||||
Heic,
|
||||
}
|
||||
}
|
||||
|
||||
// audio extensions
|
||||
enum_with_variants! {
|
||||
AudioExtension _ALL_AUDIO_EXTENSIONS {
|
||||
Mp3,
|
||||
M4a,
|
||||
Wav,
|
||||
Aiff,
|
||||
Aif,
|
||||
Flac,
|
||||
Ogg,
|
||||
Opus,
|
||||
}
|
||||
}
|
||||
|
||||
// archive extensions
|
||||
enum_with_variants! {
|
||||
ArchiveExtension _ALL_ARCHIVE_EXTENSIONS {
|
||||
Zip,
|
||||
Rar,
|
||||
Tar,
|
||||
Gz,
|
||||
Bz2,
|
||||
SevenZip,
|
||||
}
|
||||
}
|
||||
|
||||
// executable extensions
|
||||
enum_with_variants! {
|
||||
ExecutableExtension _ALL_EXECUTABLE_EXTENSIONS {
|
||||
Exe,
|
||||
App,
|
||||
Apk,
|
||||
Deb,
|
||||
Dmg,
|
||||
Pkg,
|
||||
Rpm,
|
||||
Msi,
|
||||
}
|
||||
}
|
||||
|
||||
// document extensions
|
||||
enum_with_variants! {
|
||||
DocumentExtension _ALL_DOCUMENT_EXTENSIONS {
|
||||
Pdf,
|
||||
Key,
|
||||
Pages,
|
||||
Numbers,
|
||||
Doc,
|
||||
Docx,
|
||||
Xls,
|
||||
Xlsx,
|
||||
Ppt,
|
||||
Pptx,
|
||||
Odt,
|
||||
Ods,
|
||||
Odp,
|
||||
Ics,
|
||||
}
|
||||
}
|
||||
|
||||
// text file extensions
|
||||
enum_with_variants! {
|
||||
TextExtension _ALL_TEXT_EXTENSIONS {
|
||||
Txt,
|
||||
Rtf,
|
||||
Csv,
|
||||
Html,
|
||||
Css,
|
||||
Json,
|
||||
Yaml,
|
||||
Xml,
|
||||
Md,
|
||||
}
|
||||
}
|
||||
// encrypted file extensions
|
||||
enum_with_variants! {
|
||||
EncryptedExtension _ALL_ENCRYPTED_EXTENSIONS {
|
||||
Bit, // Spacedrive encrypted file
|
||||
Box, // Spacedrive container
|
||||
Block,// Spacedrive block storage,
|
||||
}
|
||||
}
|
||||
|
||||
// key extensions
|
||||
enum_with_variants! {
|
||||
KeyExtension _ALL_KEY_EXTENSIONS {
|
||||
Pgp,
|
||||
Pub,
|
||||
Pem,
|
||||
P12,
|
||||
P8,
|
||||
Keychain,
|
||||
}
|
||||
}
|
||||
+1
-38
@@ -1,5 +1,6 @@
|
||||
pub mod cas;
|
||||
pub mod identifier_job;
|
||||
pub mod kind;
|
||||
pub mod preview;
|
||||
|
||||
// Objects are primarily created by the identifier from Paths
|
||||
@@ -31,41 +32,3 @@ pub enum ObjectData {
|
||||
Object(Box<prisma::object::Data>),
|
||||
Path(Box<prisma::file_path::Data>),
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Type)]
|
||||
pub enum ObjectKind {
|
||||
// A file that can not be identified by the indexer
|
||||
Unknown,
|
||||
// A known filetype, but without specific support
|
||||
Document,
|
||||
// A virtual filesystem directory
|
||||
Folder,
|
||||
// A file that contains human-readable text
|
||||
TextFile,
|
||||
// A virtual directory int
|
||||
Package,
|
||||
// An image file
|
||||
Image,
|
||||
// An audio file
|
||||
Audio,
|
||||
// A video file
|
||||
Video,
|
||||
// A compressed archive of data
|
||||
Archive,
|
||||
// An executable, program or application
|
||||
Executable,
|
||||
// A link to another object
|
||||
Alias,
|
||||
// Raw bytes encrypted by Spacedrive with self contained metadata
|
||||
EncryptedBytes,
|
||||
// A link can open web pages, apps or Spaces
|
||||
Link,
|
||||
// A special filetype that represents a preserved webpage
|
||||
WebPageArchive,
|
||||
// A widget is a mini app that can be placed in a Space at various sizes, associated Widget struct required
|
||||
Widget,
|
||||
// Albums can only have one level of children, and are associated with the Album struct
|
||||
Album,
|
||||
// Its like a folder, but appears like a stack of files, designed for burst photos / associated groups of files
|
||||
Collection,
|
||||
}
|
||||
@@ -3,6 +3,7 @@ use crate::{
|
||||
invalidate_query,
|
||||
job::{JobError, JobReportUpdate, JobResult, JobState, StatefulJob, WorkerContext},
|
||||
library::LibraryContext,
|
||||
object::kind::{Extension, ImageExtension, VideoExtension, ALL_VIDEO_EXTENSIONS},
|
||||
prisma::{file_path, location},
|
||||
};
|
||||
|
||||
@@ -93,17 +94,20 @@ impl StatefulJob for ThumbnailJob {
|
||||
let root_path = location.local_path.map(PathBuf::from).unwrap();
|
||||
|
||||
// query database for all image files in this location that need thumbnails
|
||||
let image_files = get_files_by_extension(
|
||||
let image_files = get_files_by_extensions(
|
||||
&library_ctx,
|
||||
state.init.location_id,
|
||||
&state.init.path,
|
||||
vec![
|
||||
"png".to_string(),
|
||||
"jpeg".to_string(),
|
||||
"jpg".to_string(),
|
||||
"gif".to_string(),
|
||||
"webp".to_string(),
|
||||
],
|
||||
[
|
||||
ImageExtension::Png,
|
||||
ImageExtension::Jpeg,
|
||||
ImageExtension::Jpg,
|
||||
ImageExtension::Gif,
|
||||
ImageExtension::Webp,
|
||||
]
|
||||
.into_iter()
|
||||
.map(Extension::Image)
|
||||
.collect(),
|
||||
ThumbnailJobStepKind::Image,
|
||||
)
|
||||
.await?;
|
||||
@@ -112,38 +116,16 @@ impl StatefulJob for ThumbnailJob {
|
||||
#[cfg(feature = "ffmpeg")]
|
||||
let all_files = {
|
||||
// query database for all video files in this location that need thumbnails
|
||||
let video_files = get_files_by_extension(
|
||||
let video_files = get_files_by_extensions(
|
||||
&library_ctx,
|
||||
state.init.location_id,
|
||||
&state.init.path,
|
||||
// Some formats extracted from https://ffmpeg.org/ffmpeg-formats.html
|
||||
vec![
|
||||
"avi".to_string(),
|
||||
"asf".to_string(),
|
||||
"mpeg".to_string(),
|
||||
// "mpg".to_string(),
|
||||
"mts".to_string(),
|
||||
"mpe".to_string(),
|
||||
"vob".to_string(),
|
||||
"qt".to_string(),
|
||||
"mov".to_string(),
|
||||
"asf".to_string(),
|
||||
"asx".to_string(),
|
||||
// "swf".to_string(),
|
||||
"mjpeg".to_string(),
|
||||
"ts".to_string(),
|
||||
"mxf".to_string(),
|
||||
// "m2v".to_string(),
|
||||
"m2ts".to_string(),
|
||||
"f4v".to_string(),
|
||||
"wm".to_string(),
|
||||
"3gp".to_string(),
|
||||
"m4v".to_string(),
|
||||
"wmv".to_string(),
|
||||
"mp4".to_string(),
|
||||
"webm".to_string(),
|
||||
"flv".to_string(),
|
||||
],
|
||||
ALL_VIDEO_EXTENSIONS
|
||||
.into_iter()
|
||||
.map(Clone::clone)
|
||||
.filter(can_generate_thumbnail_for_video)
|
||||
.map(Extension::Video)
|
||||
.collect(),
|
||||
ThumbnailJobStepKind::Video,
|
||||
)
|
||||
.await?;
|
||||
@@ -305,16 +287,16 @@ async fn generate_video_thumbnail<P: AsRef<Path>>(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn get_files_by_extension(
|
||||
async fn get_files_by_extensions(
|
||||
ctx: &LibraryContext,
|
||||
location_id: i32,
|
||||
path: impl AsRef<Path>,
|
||||
extensions: Vec<String>,
|
||||
extensions: Vec<Extension>,
|
||||
kind: ThumbnailJobStepKind,
|
||||
) -> Result<Vec<ThumbnailJobStep>, JobError> {
|
||||
let mut params = vec![
|
||||
file_path::location_id::equals(location_id),
|
||||
file_path::extension::in_vec(extensions),
|
||||
file_path::extension::in_vec(extensions.iter().map(|e| e.to_string()).collect()),
|
||||
];
|
||||
|
||||
let path_str = path.as_ref().to_string_lossy().to_string();
|
||||
@@ -334,3 +316,11 @@ async fn get_files_by_extension(
|
||||
.map(|file_path| ThumbnailJobStep { file_path, kind })
|
||||
.collect())
|
||||
}
|
||||
|
||||
pub fn can_generate_thumbnail_for_video(video_extension: &VideoExtension) -> bool {
|
||||
use VideoExtension::*;
|
||||
match video_extension {
|
||||
Mpg | Swf | M2v => false,
|
||||
_ => true,
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user