Merge pull request 'Use rayon for memories endpoint' (#36) from feature/memories-parallel into master

Reviewed-on: #36
This commit was merged in pull request #36.
This commit is contained in:
2025-08-21 20:44:50 +00:00

View File

@@ -5,6 +5,7 @@ use chrono::{DateTime, Datelike, FixedOffset, Local, LocalResult, NaiveDate, Tim
use log::{debug, trace, warn};
use opentelemetry::trace::{Span, Status, Tracer};
use opentelemetry::KeyValue;
use rayon::prelude::*;
use serde::{Deserialize, Serialize};
use std::path::Path;
use walkdir::WalkDir;
@@ -133,8 +134,7 @@ fn extract_date_from_filename(filename: &str) -> Option<DateTime<FixedOffset>> {
};
// 1. Screenshot format: Screenshot_2014-06-01-20-44-50.png
if let Some(captures) =
regex::Regex::new(r"Screenshot_(\d{4})-(\d{2})-(\d{2})-(\d{2})-(\d{2})-(\d{2})")
if let Some(captures) = regex::Regex::new(r"Screenshot_(\d{4})-(\d{2})-(\d{2})-(\d{2})-(\d{2})-(\d{2})")
.ok()?
.captures(filename)
.and_then(|c| build_date_from_ymd_capture(&c))
@@ -169,19 +169,25 @@ fn extract_date_from_filename(filename: &str) -> Option<DateTime<FixedOffset>> {
// Millisecond timestamp (13 digits)
if timestamp_str.len() >= 13 {
if let Ok(ts_millis) = timestamp_str[0..13].parse::<i64>() {
if let Some(naive_dt) = DateTime::from_timestamp_millis(ts_millis) {
return Some(naive_dt.fixed_offset());
}
if let Some(date_time) = timestamp_str[0..13]
.parse::<i64>()
.ok()
.and_then(|timestamp_millis| DateTime::from_timestamp_millis(timestamp_millis))
.map(|naive_dt| naive_dt.fixed_offset())
{
return Some(date_time);
}
}
// Second timestamp (10 digits)
if timestamp_str.len() >= 10 {
if let Ok(ts_secs) = timestamp_str[0..10].parse::<i64>() {
if let Some(naive_dt) = DateTime::from_timestamp(ts_secs, 0) {
return Some(naive_dt.fixed_offset());
}
if let Some(date_time) = timestamp_str[0..10]
.parse::<i64>()
.ok()
.and_then(|timestamp_secs| DateTime::from_timestamp(timestamp_secs, 0))
.map(|naive_dt| naive_dt.fixed_offset())
{
return Some(date_time);
}
}
}
@@ -226,43 +232,46 @@ pub async fn list_memories(
let base = Path::new(&app_state.base_path);
let mut memories_with_dates: Vec<(MemoryItem, NaiveDate)> = Vec::new();
for entry in WalkDir::new(base)
let entries: Vec<_> = WalkDir::new(base)
.into_iter()
.filter_map(|e| e.ok())
.filter(|e| e.file_type().is_file())
{
let path = entry.path();
.filter(|e| is_image_or_video(e.path()))
.collect();
if !is_image_or_video(path) {
continue;
}
let mut memories_with_dates: Vec<(MemoryItem, NaiveDate)> = entries
.par_iter()
.filter_map(|entry| {
let path = entry.path();
// Get file date and timestamps in one operation
let (file_date, created, modified) = match get_file_date_info(path, &client_timezone) {
Some(info) => info,
None => {
warn!("No date info found for file: {:?}", path);
continue;
return None;
}
};
if is_memories_match(file_date, now, span_mode, years_back) {
if let Ok(rel) = path.strip_prefix(base) {
memories_with_dates.push((
return if let Ok(rel) = path.strip_prefix(base) {
Some((
MemoryItem {
path: rel.to_string_lossy().to_string(),
created,
modified,
},
file_date,
));
))
} else {
warn!("Failed to strip prefix from path: {:?}", path);
None
};
}
}
}
None
})
.collect();
match span_mode {
// Sort by absolute time for a more 'overview'