@@ -2,7 +2,6 @@ use std::collections::{HashMap, HashSet};
22use std:: path:: PathBuf ;
33use anyhow:: { Result , bail} ;
44use log:: { debug, info, warn} ;
5- use walkdir;
65
76use crate :: models:: Book ;
87use crate :: epub_parser:: EpubParser ;
@@ -11,22 +10,17 @@ use crate::utils::generate_book_id;
1110use crate :: partial_md5:: calculate_partial_md5;
1211
1312/// Configuration for where to find KOReader metadata
14- #[ derive( Clone , Debug ) ]
13+ #[ derive( Clone , Debug , Default ) ]
1514pub enum MetadataLocation {
1615 /// Default: metadata stored in .sdr folder next to each book
16+ #[ default]
1717 InBookFolder ,
1818 /// Metadata stored in docsettings folder with full path structure
1919 DocSettings ( PathBuf ) ,
2020 /// Metadata stored in hashdocsettings folder organized by partial MD5 hash
2121 HashDocSettings ( PathBuf ) ,
2222}
2323
24- impl Default for MetadataLocation {
25- fn default ( ) -> Self {
26- MetadataLocation :: InBookFolder
27- }
28- }
29-
3024/// Build an index of metadata files in a docsettings folder.
3125/// Maps the book filename (e.g., "MyBook.epub") to the metadata file path.
3226/// Returns an error if duplicate filenames are found.
@@ -48,24 +42,24 @@ fn build_docsettings_index(docsettings_path: &PathBuf) -> Result<HashMap<String,
4842 let path = entry. path ( ) ;
4943
5044 // Look for .sdr directories
51- if path. is_dir ( ) {
52- if let Some ( dir_name) = path. file_name ( ) . and_then ( |s| s. to_str ( ) ) {
53- if dir_name. ends_with ( ".sdr" ) {
54- // Extract the book filename from the sdr directory name
55- // e.g., "MyBook.sdr" -> "MyBook.epub"
56- let book_stem = & dir_name [ ..dir_name . len ( ) - 4 ] ; // Remove ".sdr"
57-
58- // Check for metadata.epub.lua inside the .sdr folder
59- let metadata_path = path . join ( "metadata.epub.lua" ) ;
60- if metadata_path . exists ( ) {
61- let book_filename = format ! ( "{}.epub" , book_stem ) ;
62-
63- if index . contains_key ( & book_filename ) {
64- duplicates. push ( book_filename. clone ( ) ) ;
65- } else {
66- debug ! ( "Found docsettings metadata for: {}" , book_filename ) ;
67- index . insert ( book_filename , metadata_path ) ;
68- }
45+ if path. is_dir ( )
46+ && let Some ( dir_name) = path. file_name ( ) . and_then ( |s| s. to_str ( ) )
47+ && let Some ( book_stem ) = dir_name. strip_suffix ( ".sdr" ) {
48+ // Extract the book filename from the sdr directory name
49+ // e.g., "MyBook.sdr" -> "MyBook.epub"
50+
51+ // Check for metadata.epub.lua inside the .sdr folder
52+ let metadata_path = path . join ( " metadata.epub.lua" ) ;
53+ if metadata_path. exists ( ) {
54+ let book_filename = format ! ( "{}.epub" , book_stem ) ;
55+
56+ match index . entry ( book_filename . clone ( ) ) {
57+ std :: collections :: hash_map :: Entry :: Occupied ( _ ) => {
58+ duplicates. push ( book_filename) ;
59+ }
60+ std :: collections :: hash_map :: Entry :: Vacant ( entry ) => {
61+ debug ! ( "Found docsettings metadata for: {}" , book_filename ) ;
62+ entry . insert ( metadata_path ) ;
6963 }
7064 }
7165 }
@@ -110,32 +104,28 @@ fn build_hashdocsettings_index(hashdocsettings_path: &PathBuf) -> Result<HashMap
110104 let path = entry. path ( ) ;
111105
112106 // Look for .sdr directories with hash names
113- if path. is_dir ( ) {
114- if let Some ( dir_name) = path. file_name ( ) . and_then ( |s| s. to_str ( ) ) {
115- if dir_name. ends_with ( ".sdr" ) {
116- // Extract the hash from the directory name
117- // e.g., "570615f811d504e628db1ef262bea270.sdr" -> "570615f811d504e628db1ef262bea270"
118- let hash = & dir_name[ ..dir_name. len ( ) - 4 ] ; // Remove ".sdr"
119-
120- // Validate it looks like an MD5 hash (32 hex characters)
121- if hash. len ( ) == 32 && hash. chars ( ) . all ( |c| c. is_ascii_hexdigit ( ) ) {
122- // Check for metadata file (could be .epub.lua or other extensions)
123- let epub_metadata_path = path. join ( "metadata.epub.lua" ) ;
124- if epub_metadata_path. exists ( ) {
125- debug ! ( "Found hashdocsettings metadata for hash: {}" , hash) ;
126- index. insert ( hash. to_lowercase ( ) , epub_metadata_path) ;
127- } else {
128- // Check for any metadata.*.lua file
129- if let Ok ( entries) = std:: fs:: read_dir ( path) {
130- for entry in entries. flatten ( ) {
131- if let Some ( name) = entry. file_name ( ) . to_str ( ) {
132- if name. starts_with ( "metadata." ) && name. ends_with ( ".lua" ) {
133- debug ! ( "Found hashdocsettings metadata for hash: {} ({})" , hash, name) ;
134- index. insert ( hash. to_lowercase ( ) , entry. path ( ) ) ;
135- break ;
136- }
137- }
138- }
107+ if path. is_dir ( )
108+ && let Some ( dir_name) = path. file_name ( ) . and_then ( |s| s. to_str ( ) )
109+ && let Some ( hash) = dir_name. strip_suffix ( ".sdr" ) {
110+ // Extract the hash from the directory name
111+ // e.g., "570615f811d504e628db1ef262bea270.sdr" -> "570615f811d504e628db1ef262bea270"
112+
113+ // Validate it looks like an MD5 hash (32 hex characters)
114+ if hash. len ( ) == 32 && hash. chars ( ) . all ( |c| c. is_ascii_hexdigit ( ) ) {
115+ // Check for metadata file (could be .epub.lua or other extensions)
116+ let epub_metadata_path = path. join ( "metadata.epub.lua" ) ;
117+ if epub_metadata_path. exists ( ) {
118+ debug ! ( "Found hashdocsettings metadata for hash: {}" , hash) ;
119+ index. insert ( hash. to_lowercase ( ) , epub_metadata_path) ;
120+ } else {
121+ // Check for any metadata.*.lua file
122+ if let Ok ( entries) = std:: fs:: read_dir ( path) {
123+ for entry in entries. flatten ( ) {
124+ if let Some ( name) = entry. file_name ( ) . to_str ( )
125+ && name. starts_with ( "metadata." ) && name. ends_with ( ".lua" ) {
126+ debug ! ( "Found hashdocsettings metadata for hash: {} ({})" , hash, name) ;
127+ index. insert ( hash. to_lowercase ( ) , entry. path ( ) ) ;
128+ break ;
139129 }
140130 }
141131 }
0 commit comments