cobble_core/minecraft/screenshots/
mod.rs1mod screenshot;
2
3use crate::error::{CobbleError, CobbleResult};
4use futures::TryStreamExt;
5pub use screenshot::*;
6use std::path::{Path, PathBuf};
7use std::time::SystemTime;
8use tokio::fs::{metadata, read_dir};
9use tokio_stream::wrappers::ReadDirStream;
10
11#[cfg_attr(doc_cfg, doc(cfg(feature = "screenshots")))]
13#[instrument(
14 name = "load_screenshots",
15 level = "debug",
16 skip_all,
17 fields(minecraft_path)
18)]
19pub async fn load_screenshots(
20 minecraft_path: impl AsRef<Path> + Send,
21) -> CobbleResult<Vec<Screenshot>> {
22 let mut screenshots_path = PathBuf::from(minecraft_path.as_ref());
23 screenshots_path.push("screenshots");
24
25 if !screenshots_path.is_dir() {
26 trace!("Screenshots directory is empty");
27 return Ok(vec![]);
28 }
29
30 trace!("Loading screenshot files...");
31 let file_stream = ReadDirStream::new(read_dir(screenshots_path).await?);
32 let screenshots = file_stream
33 .map_err(CobbleError::from)
34 .try_filter_map(|e| parse_screenshot(e.path()))
35 .try_collect()
36 .await?;
37
38 Ok(screenshots)
39}
40
41#[instrument(name = "parse_screenshot", level = "trace", skip_all, fields(path,))]
42async fn parse_screenshot(path: impl AsRef<Path>) -> CobbleResult<Option<Screenshot>> {
43 if !path.as_ref().is_file() {
45 trace!("Entry is not a file.");
46 return Ok(None);
47 }
48
49 let mime = match mime_guess::from_path(&path).first() {
51 Some(mime) => mime,
52 None => {
53 trace!("Could not get MIME type for file.");
54 return Ok(None);
55 }
56 };
57 if mime.type_() != mime_guess::mime::IMAGE {
58 trace!("Entry is not an image");
59 return Ok(None);
60 }
61
62 let name = match path.as_ref().file_name() {
64 Some(name) => name.to_string_lossy().to_string(),
65 None => return Ok(None),
66 };
67
68 let created = metadata(path.as_ref())
69 .await
70 .and_then(|m| m.created())
71 .ok()
72 .and_then(|st| st.duration_since(SystemTime::UNIX_EPOCH).ok())
73 .and_then(|d| time::OffsetDateTime::from_unix_timestamp(d.as_secs() as i64).ok());
74
75 Ok(Some(Screenshot {
76 name,
77 path: PathBuf::from(path.as_ref()),
78 created,
79 }))
80}