Skip to content

Commit

Permalink
Improve the speed of natural sort algorithm
Browse files Browse the repository at this point in the history
Avoid creating regex object for each iteration
Set image formats as static
Remove pdf from supported image formats
  • Loading branch information
dormant-user committed Mar 1, 2024
1 parent bd7a4a3 commit 6d900ff
Show file tree
Hide file tree
Showing 4 changed files with 24 additions and 27 deletions.
1 change: 0 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ serde_json = "1.0.113"
chrono = { version = "0.4.33", features = ["serde"] }
env_logger = "0.11.1"
log = "0.4.20"
lazy_static = "1.4.0"
base64 = "0.21.7"
sha2 = "0.10.8"
rand = "0.8.5"
Expand Down
2 changes: 2 additions & 0 deletions src/constant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ use std::env;
use std::sync::{Arc, Mutex};
use fernet::Fernet;

pub static IMAGE_FORMATS: [&str; 7] = ["jpeg", "jpg", "png", "gif", "bmp", "svg", "webp"];

/// Struct to store the cargo information gathered at compile time using the `env!` macro.
#[derive(Debug)]
pub struct Cargo {
Expand Down
6 changes: 3 additions & 3 deletions src/routes/media.rs
Original file line number Diff line number Diff line change
Expand Up @@ -173,9 +173,9 @@ pub async fn stream(request: HttpRequest, media_path: web::Path<String>,
("previous", &prev),
("next", &next)
].into_iter().collect::<HashMap<_, _>>();
if vec!["jpeg", "jpg", "png", "gif", "tiff", "tif", "bmp",
"svg", "ico", "raw", "psd", "ai", "eps", "pdf", "webp"]
.contains(&render_path.split('.').last()
if constant::IMAGE_FORMATS
.contains(&render_path.split('.')
.last()
.unwrap() // file extension WILL be present at this point
.to_lowercase().as_str()) {
context_builder.insert("render_image", &render_path);
Expand Down
42 changes: 19 additions & 23 deletions src/squire/content.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ use regex::Regex;
use serde::{Deserialize, Serialize};
use walkdir::WalkDir;

use crate::squire::settings::Config;
use crate::squire::settings;
use crate::constant;

/// Represents the payload structure for content, including files and directories.
///
Expand Down Expand Up @@ -36,15 +37,15 @@ pub fn default_structure() -> Vec<HashMap<String, String>> {
///
/// # Arguments
///
/// * `regex` - Pre-compiled regex object.
/// * `filename` - A string representing the filename.
///
/// # Returns
///
/// A vector of `Result<i32, String>` where each element is either an integer representing a numeric part
/// or a string representing a non-numeric part converted to lowercase.
fn natural_sort_key(filename: &str) -> Vec<Result<i32, String>> {
let re = Regex::new(r"(\D+|\d+)").unwrap();
re.find_iter(filename)
fn natural_sort_key(regex: &Regex, filename: &str) -> Vec<Result<i32, String>> {
regex.find_iter(filename)
.map(|part| {
if let Ok(num) = part.as_str().parse::<i32>() {
Ok(num)
Expand All @@ -58,29 +59,21 @@ fn natural_sort_key(filename: &str) -> Vec<Result<i32, String>> {

/// Generate font awesome icon's value for a given file extension.
///
/// Creates custom icons for `pdf` and `image` files, defaults to `video` icon.
/// Creates custom icons for `image` files, defaults to `video` icon.
///
/// # Arguments
///
/// * `extn` - File extension.
///
/// # Returns
///
/// A string with the `fa` value based on match statement.
/// A string with the `fa` value based on the file extension.
fn get_font_icon(extn: &str) -> String {
let font;
match extn {
"pdf" => {
font = "fa-regular fa-file-pdf";
}
_ => {
if ["jpeg", "jpg", "png", "gif", "tiff", "tif", "bmp", "svg", "ico",
"raw", "psd", "ai", "eps", "webp"].contains(&extn) {
font = "fa-regular fa-file-image";
} else {
font = "fa-regular fa-file-video";
}
}
if constant::IMAGE_FORMATS.contains(&extn) {
font = "fa-regular fa-file-image";
} else {
font = "fa-regular fa-file-video";
}
font.to_string()
}
Expand All @@ -94,7 +87,7 @@ fn get_font_icon(extn: &str) -> String {
/// # Returns
///
/// A `ContentPayload` struct representing the content of all streams.
pub fn get_all_stream_content(config: &Config) -> ContentPayload {
pub fn get_all_stream_content(config: &settings::Config) -> ContentPayload {
let mut payload = ContentPayload::default();

for entry in WalkDir::new(&config.media_source).into_iter().filter_map(|e| e.ok()) {
Expand Down Expand Up @@ -138,8 +131,9 @@ pub fn get_all_stream_content(config: &Config) -> ContentPayload {
}
}

payload.files.sort_by(|a, b| natural_sort_key(&a["name"]).cmp(&natural_sort_key(&b["name"])));
payload.directories.sort_by(|a, b| natural_sort_key(&a["name"]).cmp(&natural_sort_key(&b["name"])));
let re = Regex::new(r"(\D+|\d+)").unwrap();
payload.files.sort_by(|a, b| natural_sort_key(&re, &a["name"]).cmp(&natural_sort_key(&re, &b["name"])));
payload.directories.sort_by(|a, b| natural_sort_key(&re, &a["name"]).cmp(&natural_sort_key(&re, &b["name"])));

payload
}
Expand Down Expand Up @@ -174,7 +168,8 @@ pub fn get_dir_stream_content(parent: &str, child: &str, file_formats: &[String]
files.push(map);
}
}
files.sort_by_key(|a| natural_sort_key(a.get("name").unwrap()));
let re = Regex::new(r"(\D+|\d+)").unwrap();
files.sort_by_key(|a| natural_sort_key(&re, a.get("name").unwrap()));
ContentPayload { files, ..Default::default() }
}

Expand Down Expand Up @@ -212,7 +207,8 @@ pub fn get_iter(filepath: &Path, file_formats: &[String]) -> Iter {
}
})
.collect();
dir_content.sort_by_key(|a| natural_sort_key(a));
let re = Regex::new(r"(\D+|\d+)").unwrap();
dir_content.sort_by_key(|a| natural_sort_key(&re, a));

let idx = dir_content.iter().position(|file| file == filepath.file_name().unwrap().to_str().unwrap()).unwrap();

Expand Down

0 comments on commit 6d900ff

Please sign in to comment.