179 lines
4.9 KiB
Rust
179 lines
4.9 KiB
Rust
mod filters;
|
|
|
|
use std::{path::PathBuf, str::FromStr, sync::LazyLock};
|
|
|
|
use filters::*;
|
|
use tera::{Context, Tera};
|
|
use time::OffsetDateTime;
|
|
use tokio::time::Instant;
|
|
use tokio_stream::{wrappers::ReadDirStream, StreamExt};
|
|
|
|
use crate::{icon::extract_icon, AResult, FileInfo, BASE_DIR};
|
|
|
|
pub static TERA: LazyLock<Tera> = LazyLock::new(|| {
|
|
let mut tera = Tera::default();
|
|
tera.add_raw_template(
|
|
"index.html.jinja",
|
|
include_str!("../templates/index.html.jinja"),
|
|
)
|
|
.unwrap();
|
|
tera.add_raw_template(
|
|
"markdown.html.jinja",
|
|
include_str!("../templates/markdown.html.jinja"),
|
|
)
|
|
.unwrap();
|
|
tera.register_filter("iconize", iconize);
|
|
tera.register_filter("from_ico", from_ico);
|
|
tera.register_filter("size", size);
|
|
tera.register_filter("time", time);
|
|
tera.register_filter("md", md);
|
|
|
|
tera
|
|
});
|
|
|
|
pub async fn render_index(path: &PathBuf, time: Instant) -> AResult<String> {
|
|
let time2 = Instant::now();
|
|
let base = BASE_DIR.display().to_string();
|
|
let dirname = path
|
|
.display()
|
|
.to_string()
|
|
.replace(&base, "")
|
|
.replace('\\', "/");
|
|
|
|
let filename = path.file_name().unwrap().to_string_lossy().to_string();
|
|
let description = PathBuf::from_str(&format!(
|
|
"{}/.{}.info",
|
|
path.parent().unwrap().to_string_lossy(),
|
|
filename
|
|
))?;
|
|
let description = if description.exists() {
|
|
Some(std::fs::read_to_string(description)?)
|
|
} else {
|
|
None
|
|
};
|
|
|
|
let directories = get_directories(path).await?;
|
|
let files = get_files(path).await?;
|
|
|
|
let tera = &*TERA;
|
|
|
|
let mut context = Context::new();
|
|
context.insert("description", &description);
|
|
context.insert("dirname", &dirname);
|
|
context.insert("directories", &directories);
|
|
context.insert("files", &files);
|
|
|
|
let loading = time2.elapsed() + time.elapsed();
|
|
context.insert("loading", &loading.as_millis());
|
|
Ok(tera.render("index.html.jinja", &context)?)
|
|
}
|
|
|
|
pub fn render_markdown(filename: &str, content: &str) -> AResult<String> {
|
|
let tera = &*TERA;
|
|
|
|
let mut context = Context::new();
|
|
context.insert("filename", &filename);
|
|
context.insert("content", &content);
|
|
|
|
Ok(tera.render("markdown.html.jinja", &context)?)
|
|
}
|
|
|
|
async fn get_directories(path: &PathBuf) -> AResult<Vec<FileInfo>> {
|
|
let mut contents = ReadDirStream::new(tokio::fs::read_dir(&path).await?);
|
|
|
|
let mut files = vec![];
|
|
|
|
while let Some(file) = contents.next().await {
|
|
let file = file?;
|
|
let metadata = file.metadata().await?;
|
|
if !metadata.is_dir() {
|
|
continue;
|
|
}
|
|
let filename = file.file_name().to_string_lossy().to_string();
|
|
if filename.starts_with('.') {
|
|
continue;
|
|
}
|
|
|
|
// let created: OffsetDateTime = metadata.created()?.into();
|
|
let modified: OffsetDateTime = metadata.modified()?.into();
|
|
|
|
let description = PathBuf::from_str(&format!(
|
|
"{}/.{}.info",
|
|
file.path().parent().unwrap().to_string_lossy(),
|
|
filename
|
|
))?;
|
|
|
|
let description = if description.exists() {
|
|
Some(std::fs::read_to_string(description)?)
|
|
} else {
|
|
None
|
|
};
|
|
|
|
files.push(FileInfo {
|
|
filename,
|
|
format: "DIR".to_string(),
|
|
size: 0,
|
|
icon: None,
|
|
// created,
|
|
modified,
|
|
description,
|
|
});
|
|
}
|
|
|
|
Ok(files)
|
|
}
|
|
|
|
async fn get_files(path: &PathBuf) -> AResult<Vec<FileInfo>> {
|
|
let mut contents = ReadDirStream::new(tokio::fs::read_dir(&path).await?);
|
|
|
|
let mut files = vec![];
|
|
|
|
while let Some(file) = contents.next().await {
|
|
let file = file?;
|
|
let metadata = file.metadata().await?;
|
|
if metadata.is_dir() {
|
|
continue;
|
|
}
|
|
let filename = file.file_name().to_string_lossy().to_string();
|
|
if filename.starts_with('.') {
|
|
continue;
|
|
}
|
|
let format = file_format::FileFormat::from_file(file.path())?;
|
|
let format = format.media_type();
|
|
|
|
let icon = if format == "application/x-dosexec" {
|
|
// ..
|
|
extract_icon(&file.path()).ok().flatten()
|
|
} else {
|
|
None
|
|
};
|
|
|
|
// let created: OffsetDateTime = metadata.created()?.into();
|
|
let modified: OffsetDateTime = metadata.modified()?.into();
|
|
|
|
let description = PathBuf::from_str(&format!(
|
|
"{}/.{}.info",
|
|
file.path().parent().unwrap().to_string_lossy(),
|
|
filename
|
|
))?;
|
|
|
|
let description = if description.exists() {
|
|
Some(std::fs::read_to_string(description)?)
|
|
} else {
|
|
None
|
|
};
|
|
|
|
files.push(FileInfo {
|
|
filename,
|
|
format: format.to_string(),
|
|
size: metadata.len() as usize,
|
|
icon,
|
|
// created,
|
|
modified,
|
|
description,
|
|
});
|
|
}
|
|
|
|
Ok(files)
|
|
}
|