@@ -6,7 +6,7 @@ use std::time::{Duration, Instant};
66use rayon:: prelude:: * ;
77
88use super :: media_library:: { MediaLibrary , MediaLibraryError } ;
9- use super :: website_info:: { SITE_TOML , WebsiteInfo , WebsiteInfoError } ;
9+ use super :: website_info:: { WebsiteInfo , WebsiteInfoError , SITE_TOML } ;
1010use super :: website_media:: { GenerationResult , WebsiteMedia } ;
1111
1212const DEFAULT_BUILD_DIR : & str = "build" ;
@@ -23,18 +23,24 @@ const TEMPLATE_RSS: &str = include_str!("../../template/rss.xml");
2323
2424pub struct BuildReport {
2525 pub items_processed : usize ,
26+ pub items_skipped : usize ,
2627 pub total_media_size : u64 ,
2728 pub total_thumbs_size : u64 ,
2829 pub processing_time : Duration ,
2930}
3031
3132impl BuildReport {
32- fn from_results ( results : Vec < GenerationResult > , processing_time : Duration ) -> Self {
33+ fn from_results (
34+ results : Vec < GenerationResult > ,
35+ items_skipped : usize ,
36+ processing_time : Duration ,
37+ ) -> Self {
3338 let items_processed = results. len ( ) ;
3439 let total_media_size = results. iter ( ) . map ( |r| r. media_size ) . sum ( ) ;
3540 let total_thumbs_size = results. iter ( ) . map ( |r| r. thumb_size ) . sum ( ) ;
3641 Self {
3742 items_processed,
43+ items_skipped,
3844 total_media_size,
3945 total_thumbs_size,
4046 processing_time,
@@ -46,6 +52,7 @@ impl std::fmt::Display for BuildReport {
4652 fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
4753 writeln ! ( f, "Build report:" ) ?;
4854 writeln ! ( f, " Items processed: {}" , self . items_processed) ?;
55+ writeln ! ( f, " Items skipped (up to date): {}" , self . items_skipped) ?;
4956 writeln ! (
5057 f,
5158 " Total media size: {}" ,
@@ -174,7 +181,7 @@ impl Website {
174181 library. update_metadata ( & source_media_path) ?;
175182
176183 // Scan source media directory, copy files, generate thumbnails, and collect data entries
177- let ( clutterlog_data, rss_items, generation_results) =
184+ let ( clutterlog_data, rss_items, generation_results, items_skipped ) =
178185 self . scan_and_copy_media ( & source_media_path, & build_media_path, & library) ?;
179186
180187 // Render index.html from template
@@ -213,6 +220,7 @@ impl Website {
213220
214221 Ok ( BuildReport :: from_results (
215222 generation_results,
223+ items_skipped,
216224 start. elapsed ( ) ,
217225 ) )
218226 }
@@ -222,11 +230,11 @@ impl Website {
222230 source_path : & Path ,
223231 dest_path : & Path ,
224232 library : & MediaLibrary ,
225- ) -> Result < ( String , Vec < String > , Vec < GenerationResult > ) , WebsiteError > {
233+ ) -> Result < ( String , Vec < String > , Vec < GenerationResult > , usize ) , WebsiteError > {
226234 let base_url = self . info . url . trim_end_matches ( '/' ) ;
227235
228236 if !source_path. exists ( ) {
229- return Ok ( ( "[]" . to_string ( ) , Vec :: new ( ) , Vec :: new ( ) ) ) ;
237+ return Ok ( ( "[]" . to_string ( ) , Vec :: new ( ) , Vec :: new ( ) , 0 ) ) ;
230238 }
231239
232240 let dir_entries = fs:: read_dir ( source_path)
@@ -243,18 +251,25 @@ impl Website {
243251 } )
244252 . collect ( ) ;
245253
246- // Process items in parallel: copy files and generate thumbnails
247- let processed: Vec < Result < ( GenerationResult , String , String ) , WebsiteError > > = items
254+ // Process items in parallel: copy files and generate thumbnails (skipping up-to-date items)
255+ // Each result includes a bool indicating whether the item was skipped.
256+ let processed: Vec < Result < ( GenerationResult , String , String , bool ) , WebsiteError > > = items
248257 . par_iter ( )
249258 . filter_map ( |( path, datetime) | {
250259 let item = WebsiteMedia :: from_path ( path, datetime. as_deref ( ) ) ?;
251- let result = item. copy_and_generate_thumb ( dest_path) ;
260+
261+ let ( result, skipped) = if item. is_up_to_date ( dest_path) {
262+ ( item. read_existing_sizes ( dest_path) , true )
263+ } else {
264+ ( item. copy_and_generate_thumb ( dest_path) , false )
265+ } ;
266+
252267 let entry = item. to_json_entry ( base_url, DEFAULT_MEDIA_DIR ) ;
253268 let rss_item = item. to_rss_item ( base_url, DEFAULT_MEDIA_DIR ) ;
254269 let image_url = item. image_url ( base_url, DEFAULT_MEDIA_DIR ) ;
255270 Some ( result. map ( |mut r| {
256271 r. image_url = image_url;
257- ( r, entry, rss_item)
272+ ( r, entry, rss_item, skipped )
258273 } ) )
259274 } )
260275 . collect ( ) ;
@@ -263,8 +278,12 @@ impl Website {
263278 let mut results: Vec < GenerationResult > = Vec :: new ( ) ;
264279 let mut entries: Vec < String > = Vec :: new ( ) ;
265280 let mut rss_items: Vec < String > = Vec :: new ( ) ;
281+ let mut items_skipped: usize = 0 ;
266282 for item_result in processed {
267- let ( gen_result, entry, rss_item) = item_result?;
283+ let ( gen_result, entry, rss_item, skipped) = item_result?;
284+ if skipped {
285+ items_skipped += 1 ;
286+ }
268287 results. push ( gen_result) ;
269288 entries. push ( entry) ;
270289 rss_items. push ( rss_item) ;
@@ -276,7 +295,7 @@ impl Website {
276295 format ! ( "[\n {}\n ]" , entries. join( ",\n " ) )
277296 } ;
278297
279- Ok ( ( json, rss_items, results) )
298+ Ok ( ( json, rss_items, results, items_skipped ) )
280299 }
281300}
282301
0 commit comments