From 226ce76c162a9ebca4a865c7507d23d370d132d8 Mon Sep 17 00:00:00 2001 From: Martin Brodbeck Date: Tue, 2 Feb 2021 19:44:31 +0100 Subject: [PATCH 01/57] Skipping Adobe drm encoded files since we can't read metadata. fixes #1 --- src/main.rs | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/src/main.rs b/src/main.rs index 153c9fb..6a23de2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -304,6 +304,7 @@ struct BookEntry { filepath: String, author: String, firstauthor: String, + has_drm: bool, } fn get_epubs_from_database(tx: &Transaction) -> Vec { @@ -331,12 +332,17 @@ fn get_epubs_from_database(tx: &Transaction) -> Vec { let filepath = format!("{}/{}", prefix, filename); let firstauthor: String = row.get(3).unwrap(); let author: String = row.get(4).unwrap(); + let has_drm = match prefix.as_str() { + "/mnt/ext1/Digital Editions" => true, + _ => false, + }; let entry = BookEntry { id: book_id, filepath, firstauthor, author, + has_drm, }; book_entries.push(entry); @@ -394,15 +400,22 @@ fn remove_ghost_books_from_db(tx: &Transaction) -> usize { struct Statistics { authors_fixed: i32, ghost_books_cleaned: usize, + drm_skipped: usize, } fn fix_db_entries(tx: &Transaction, book_entries: &Vec) -> Statistics { let mut stat = Statistics { authors_fixed: 0, ghost_books_cleaned: 0, + drm_skipped: 0, }; for entry in book_entries { + if entry.has_drm { + stat.drm_skipped = stat.drm_skipped + 1; + continue; + } + let file = File::open(entry.filepath.as_str()); let file = match file { Err(_) => continue, @@ -489,16 +502,20 @@ fn main() { pocketbook::dialog( pocketbook::Icon::Info, &format!( - "Authors fixed: {}\nBooks cleaned from DB: {}", - &stat.authors_fixed, &stat.ghost_books_cleaned + "Authors fixed: {}\n\ + Books skipped (DRM): {}\n\ + Books cleaned from DB: {}", + &stat.authors_fixed, &stat.drm_skipped, &stat.ghost_books_cleaned ), &["OK"], ); } } else { println!( - "Authors fixed: {}\nBooks cleaned from DB: {}", - &stat.authors_fixed, &stat.ghost_books_cleaned + "Authors fixed: {}\n\ + Books skipped (DRM): {}\n\ + Books cleaned from DB: {}", + &stat.authors_fixed, &stat.drm_skipped, &stat.ghost_books_cleaned ); } } From 846ee16f6bd266cae1c10b66e6661e5bbd57b55f Mon Sep 17 00:00:00 2001 From: Martin Brodbeck Date: Tue, 2 Feb 2021 20:11:13 +0100 Subject: [PATCH 02/57] summary message dialog improved --- src/main.rs | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/src/main.rs b/src/main.rs index 6a23de2..b3730ce 100644 --- a/src/main.rs +++ b/src/main.rs @@ -493,11 +493,25 @@ fn main() { if cfg!(target_arch = "arm") { if stat.authors_fixed == 0 { - pocketbook::dialog( - pocketbook::Icon::Info, - "The database seems to be ok.\nNothing had to be fixed.", - &["OK"], - ); + if stat.drm_skipped == 0 { + pocketbook::dialog( + pocketbook::Icon::Info, + "The database seems to be ok.\n\ + Nothing had to be fixed.", + &["OK"], + ); + } else { + pocketbook::dialog( + pocketbook::Icon::Info, + &format!( + "The database seems to be ok.\n\ + Nothing had to be fixed.\n\ + (Books skipped (DRM): {})", + &stat.drm_skipped + ), + &["OK"], + ); + } } else { pocketbook::dialog( pocketbook::Icon::Info, From a7c50df924fe1e0aeeaf95c533ebda6390e9d9b9 Mon Sep 17 00:00:00 2001 From: Martin Brodbeck Date: Tue, 2 Feb 2021 20:17:07 +0100 Subject: [PATCH 03/57] Push to version 0.3.1 --- Cargo.lock | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 269c889..2a3bfc4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -148,7 +148,7 @@ dependencies = [ [[package]] name = "pbdbfixer" -version = "0.3.0" +version = "0.3.1" dependencies = [ "rusqlite", "xml-rs", diff --git a/Cargo.toml b/Cargo.toml index cfad558..5733d89 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pbdbfixer" -version = "0.3.0" +version = "0.3.1" authors = ["Martin Brodbeck "] edition = "2018" From 0f642a61a441819c14c83b845e8a63710db75868 Mon Sep 17 00:00:00 2001 From: Martin Brodbeck Date: Wed, 3 Feb 2021 09:06:41 +0100 Subject: [PATCH 04/57] TL4 added --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index cc9d175..5d51516 100644 --- a/README.md +++ b/README.md @@ -7,10 +7,10 @@ wrong database entries and fix it by reading the corresponding epub metadata. ## Compatibility -This program is tested only on a PocketBook Touch HD 3 device (software -version 6.1.900). It might work with other PocketBook devices/software -versions. Please tell me, if it works for you (and do make a backup of the -explorer-3.db file before trying!). +This program is tested on a PocketBook +- *Touch HD 3* (software version 6.1.900) +- *Touch Lux 4* (software version 6.0.1118) +It might work with other PocketBook devices/software versions. Please tell me, if it works for you (and do make a backup of the explorer-3.db file before trying!). ## Installation and Usage Just copy the executable file into the PocketBook's application directory. From 77d87c751df5a1300f40756f786d2ece6f074c3e Mon Sep 17 00:00:00 2001 From: Martin Brodbeck Date: Wed, 3 Feb 2021 09:07:33 +0100 Subject: [PATCH 05/57] typo --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 5d51516..06cd8b5 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,7 @@ metadata. This program is tested on a PocketBook - *Touch HD 3* (software version 6.1.900) - *Touch Lux 4* (software version 6.0.1118) + It might work with other PocketBook devices/software versions. Please tell me, if it works for you (and do make a backup of the explorer-3.db file before trying!). ## Installation and Usage From e4f6efe12a71e54a028aeb374a5312799fc9b0bf Mon Sep 17 00:00:00 2001 From: Martin Brodbeck Date: Wed, 10 Feb 2021 10:31:44 +0100 Subject: [PATCH 06/57] fix genres --- Cargo.lock | 2 +- Cargo.toml | 2 +- src/main.rs | 86 +++++++++++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 82 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2a3bfc4..679cb60 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -148,7 +148,7 @@ dependencies = [ [[package]] name = "pbdbfixer" -version = "0.3.1" +version = "0.4.0" dependencies = [ "rusqlite", "xml-rs", diff --git a/Cargo.toml b/Cargo.toml index 5733d89..8700c1f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pbdbfixer" -version = "0.3.1" +version = "0.4.0" authors = ["Martin Brodbeck "] edition = "2018" diff --git a/src/main.rs b/src/main.rs index b3730ce..1bb944d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,9 +1,9 @@ mod pocketbook; use rusqlite::{named_params, Connection, Result, Transaction, NO_PARAMS}; -use std::io::BufReader; use std::{collections::HashMap, fs::File}; use std::{error::Error, io::Read}; +use std::{io::BufReader, usize}; use xml::reader::{EventReader, ParserConfig, XmlEvent}; use zip::{read::ZipFile, ZipArchive}; @@ -299,12 +299,48 @@ fn get_attribute_creator(opf: ZipFile) -> Option { None } +fn get_attribute_genre(opf: ZipFile) -> Option { + let parser = ParserConfig::new() + .trim_whitespace(true) + .ignore_comments(true) + .coalesce_characters(true) + .create_reader(opf); + + let mut genre_found = false; + + for e in parser { + match e { + Ok(XmlEvent::StartElement { name, .. }) if name.local_name == "subject" => { + genre_found = true; + } + Ok(XmlEvent::Characters(value)) => { + if genre_found { + return Some(value); + } + } + Ok(XmlEvent::StartElement { .. }) => { + if genre_found == true { + genre_found = false; + } + } + Err(e) => { + println!("{}", e); + break; + } + _ => {} + } + } + + None +} + struct BookEntry { id: i32, filepath: String, author: String, firstauthor: String, has_drm: bool, + genre: String, } fn get_epubs_from_database(tx: &Transaction) -> Vec { @@ -313,11 +349,15 @@ fn get_epubs_from_database(tx: &Transaction) -> Vec { let mut stmt = tx .prepare( r" - SELECT books.id, folders.name, files.filename, books.firstauthor, books.author + SELECT books.id, folders.name, files.filename, books.firstauthor, books.author, genres.name FROM books_impl books JOIN files ON books.id = files.book_id JOIN folders ON folders.id = files.folder_id + LEFT OUTER JOIN booktogenre btg + ON books.id = btg.bookid + LEFT OUTER JOIN genres + ON genres.id = btg.genreid WHERE files.storageid = 1 AND books.ext = 'epub' ORDER BY books.id", ) @@ -336,6 +376,7 @@ fn get_epubs_from_database(tx: &Transaction) -> Vec { "/mnt/ext1/Digital Editions" => true, _ => false, }; + let genre: String = row.get(5).unwrap_or_default(); let entry = BookEntry { id: book_id, @@ -343,6 +384,7 @@ fn get_epubs_from_database(tx: &Transaction) -> Vec { firstauthor, author, has_drm, + genre, }; book_entries.push(entry); @@ -401,6 +443,7 @@ struct Statistics { authors_fixed: i32, ghost_books_cleaned: usize, drm_skipped: usize, + genres_fixed: usize, } fn fix_db_entries(tx: &Transaction, book_entries: &Vec) -> Statistics { @@ -408,6 +451,7 @@ fn fix_db_entries(tx: &Transaction, book_entries: &Vec) -> Statistics authors_fixed: 0, ghost_books_cleaned: 0, drm_skipped: 0, + genres_fixed: 0, }; for entry in book_entries { @@ -453,6 +497,31 @@ fn fix_db_entries(tx: &Transaction, book_entries: &Vec) -> Statistics stat.authors_fixed = stat.authors_fixed + 1; } } + // genre… + if entry.genre.is_empty() { + let opf = archive.by_name(opf_file.as_str()).unwrap(); + if let Some(genre) = get_attribute_genre(opf) { + let mut stmt = tx + .prepare( + r#"INSERT INTO genres (name) SELECT :genre ON CONFLICT DO NOTHING"#, + ) + .unwrap(); + stmt.execute_named(named_params![":genre": &genre]).unwrap(); + let mut stmt = tx + .prepare( + r#" + INSERT INTO booktogenre (bookid, genreid) + VALUES (:bookid, + (SELECT id FROM genres WHERE name = :genre) + ) + ON CONFLICT DO NOTHING"#, + ) + .unwrap(); + stmt.execute_named(named_params![":bookid": &entry.id, ":genre": &genre]) + .unwrap(); + stat.genres_fixed = stat.genres_fixed + 1; + } + } } } @@ -517,9 +586,13 @@ fn main() { pocketbook::Icon::Info, &format!( "Authors fixed: {}\n\ - Books skipped (DRM): {}\n\ + Genres fixed: {}\n\ + Books skipped (DRM): {}\n\ Books cleaned from DB: {}", - &stat.authors_fixed, &stat.drm_skipped, &stat.ghost_books_cleaned + &stat.authors_fixed, + &stat.genres_fixed, + &stat.drm_skipped, + &stat.ghost_books_cleaned ), &["OK"], ); @@ -527,9 +600,10 @@ fn main() { } else { println!( "Authors fixed: {}\n\ - Books skipped (DRM): {}\n\ + Genres fixed: {}\n\ + Books skipped (DRM): {}\n\ Books cleaned from DB: {}", - &stat.authors_fixed, &stat.drm_skipped, &stat.ghost_books_cleaned + &stat.authors_fixed, &stat.genres_fixed, &stat.drm_skipped, &stat.ghost_books_cleaned ); } } From 1cf8b008d0ec2f8577c89185565c2818f5498f99 Mon Sep 17 00:00:00 2001 From: Martin Brodbeck Date: Wed, 10 Feb 2021 11:54:05 +0100 Subject: [PATCH 07/57] =?UTF-8?q?give=20more=20information=20(features,=20?= =?UTF-8?q?warning,=20=E2=80=A6)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 06cd8b5..758a355 100644 --- a/README.md +++ b/README.md @@ -6,23 +6,32 @@ EPUB files, this program tries fix these issues. It tries to identify wrong database entries and fix it by reading the corresponding epub metadata. +## Features +The app tries to fix the following issues in the database +- Correction of wrong firstauthor entries (books_impl table) +- Correction of wrong author entries (books_impl table) +- Removing deleted e-books from the database (various tables) +- Add missing genre if present in epub (genre and booktogenre tables) + ## Compatibility This program is tested on a PocketBook - *Touch HD 3* (software version 6.1.900) - *Touch Lux 4* (software version 6.0.1118) -It might work with other PocketBook devices/software versions. Please tell me, if it works for you (and do make a backup of the explorer-3.db file before trying!). +It might work with other PocketBook devices/software versions. Please tell me if it works for you (and do make a backup of the explorer-3.db file before trying!). ## Installation and Usage -Just copy the executable file into the PocketBook's application directory. -If you encounter duplicate authors in the PocketBook's library, open the -applications screen and tap on the PbDbFixer icon. +Just copy the executable file into the PocketBook's application directory. If you encounter duplicate authors or other issues (see "Features" above) in the PocketBook's library, open the applications screen and tap on the PbDbFixer icon. + +--- +**WARNING**: + +Use at your own risk. In case of doubt it is not a mistake to make a backup of the file `/system/explorer-3/explorer-3.db` beforehand. + +--- ## Build -To be able to build PbDbFixer, you have to have the cross compiler for -ARM CPUs installed. On Arch Linux, the AUR package `arm-linux-gnueabi-gcc75-linaro-bin` -does the job. Don't forget to tell `cargo` which compiler/linker it has to -invoke. In my case, I had to edit `~/.cargo/config`: +If you want to build PbDbFixer yourself, you have to have the cross compiler for ARM CPUs installed. On Arch Linux, the AUR package `arm-linux-gnueabi-gcc75-linaro-bin` does the job. Don't forget to tell `cargo` which compiler/linker it has to invoke. In my case, I had to edit `~/.cargo/config`: ``` [target.arm-unknown-linux-gnueabi] linker = "arm-linux-gnueabi-gcc" From 90c2d34c03f57625c0ffbbd205a4ec573b525772 Mon Sep 17 00:00:00 2001 From: Martin Brodbeck Date: Thu, 11 Feb 2021 21:58:10 +0100 Subject: [PATCH 08/57] xml parsing completely rewritten --- Cargo.lock | 19 ++- Cargo.toml | 4 +- src/epub.rs | 250 +++++++++++++++++++++++++++++ src/main.rs | 453 ++++++++-------------------------------------------- 4 files changed, 326 insertions(+), 400 deletions(-) create mode 100644 src/epub.rs diff --git a/Cargo.lock b/Cargo.lock index 679cb60..4d848cc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -148,10 +148,10 @@ dependencies = [ [[package]] name = "pbdbfixer" -version = "0.4.0" +version = "0.5.0" dependencies = [ + "quick-xml", "rusqlite", - "xml-rs", "zip", ] @@ -170,6 +170,15 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "quick-xml" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0452695941410a58c8ce4391707ba9bad26a247173bd9886a05a5e8a8babec75" +dependencies = [ + "memchr", +] + [[package]] name = "quote" version = "1.0.8" @@ -282,12 +291,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -[[package]] -name = "xml-rs" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b07db065a5cf61a7e4ba64f29e67db906fb1787316516c4e6e5ff0fea1efcd8a" - [[package]] name = "zip" version = "0.5.9" diff --git a/Cargo.toml b/Cargo.toml index 8700c1f..f7b9656 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pbdbfixer" -version = "0.4.0" +version = "0.5.0" authors = ["Martin Brodbeck "] edition = "2018" @@ -8,7 +8,7 @@ edition = "2018" [dependencies] zip = "0.5" -xml-rs = "0.8" +quick-xml = "0.21" [dependencies.rusqlite] version = "0.24" diff --git a/src/epub.rs b/src/epub.rs new file mode 100644 index 0000000..a640d47 --- /dev/null +++ b/src/epub.rs @@ -0,0 +1,250 @@ +use std::{ + collections::HashMap, + fs::{self, File}, + io::Read, +}; + +use quick_xml::{events::Event, Reader}; +use zip::ZipArchive; + +#[derive(Debug)] +pub struct Author { + pub name: String, + pub firstauthor: String, +} + +#[derive(Debug)] +pub struct EpubMetadata { + pub authors: Vec, + pub genre: String, +} + +impl EpubMetadata { + fn new() -> Self { + EpubMetadata { + authors: Vec::new(), + genre: String::new(), + } + } +} + +fn get_rootfile(archive: &mut ZipArchive) -> String { + let mut container = archive.by_name("META-INF/container.xml").unwrap(); + let mut xml_str_buffer = String::new(); + + container.read_to_string(&mut xml_str_buffer).unwrap(); + + let mut reader = Reader::from_str(&xml_str_buffer); + reader.trim_text(true); + + let mut buf = Vec::new(); + let mut opf_filename = String::new(); + + loop { + match reader.read_event(&mut buf) { + Ok(Event::Start(ref e)) | Ok(Event::Empty(ref e)) if e.local_name() == b"rootfile" => { + opf_filename = String::from_utf8( + e.attributes() + .filter(|attr| attr.as_ref().unwrap().key == b"full-path") + .next() + .unwrap() + .unwrap() + .value + .to_vec(), + ) + .unwrap(); + break; + } + Ok(Event::Eof) => break, + _ => (), + } + } + opf_filename +} + +pub fn get_epub_metadata(filename: &str) -> Option { + let mut epub_meta = EpubMetadata::new(); + let file = fs::File::open(&filename); + + let file = match file { + Err(_) => return None, + Ok(file) => file, + }; + + let mut archive = ZipArchive::new(file).unwrap(); + + let opf_filename = get_rootfile(&mut archive); + + let mut xml_str_buffer = String::new(); + let mut opf = archive.by_name(&opf_filename).unwrap(); + opf.read_to_string(&mut xml_str_buffer).unwrap(); + + let mut reader = Reader::from_str(&xml_str_buffer); + let mut buf = Vec::new(); + + let mut curr_id = String::new(); + let mut creator_found = false; + let mut file_as_found = false; + let mut role_found = false; + let mut genre_found = false; + let mut is_epub3 = false; + + #[derive(Debug)] + struct XmlAut { + name: String, + sort: String, + role: String, + } + + let mut xml_authors = HashMap::new(); + + loop { + match reader.read_event(&mut buf) { + // See if we have EPUB3 or EPUB2 + Ok(Event::Start(ref e)) if e.local_name() == b"package" => { + if e.attributes().any(|attr| { + attr.as_ref().unwrap().key == b"version" + && attr.as_ref().unwrap().value.starts_with(b"3") + }) { + is_epub3 = true; + } + } + Ok(Event::Start(ref e)) if e.local_name() == b"creator" => { + creator_found = true; + if is_epub3 { + if let Some(idval) = e + .attributes() + .filter(|attr| attr.as_ref().unwrap().key == b"id") + .next() + { + curr_id = "#".to_string() + + String::from_utf8(idval.unwrap().value.to_vec()) + .unwrap() + .as_str(); + xml_authors.insert( + curr_id.clone(), + XmlAut { + name: "".to_string(), + sort: "".to_string(), + role: "".to_string(), + }, + ); + } + } else { + if let Some(file_as_val) = e + .attributes() + .filter(|attr| attr.as_ref().unwrap().key.ends_with(b"file-as")) + .next() + { + let ns = + String::from_utf8(file_as_val.as_ref().unwrap().key.to_vec()).unwrap(); + curr_id = "none".to_string() + ns.split(':').collect::>()[0]; + let entry = xml_authors.entry(curr_id.clone()).or_insert(XmlAut { + name: "".to_string(), + sort: "".to_string(), + role: "".to_string(), + }); + entry.sort = file_as_val + .unwrap() + .unescape_and_decode_value(&reader) + .unwrap_or_default(); + entry.role = "aut".to_string(); + } + if let Some(role_val) = e + .attributes() + .filter(|attr| attr.as_ref().unwrap().key.ends_with(b"role")) + .next() + { + let ns = + String::from_utf8(role_val.as_ref().unwrap().key.to_vec()).unwrap(); + curr_id = "none".to_string() + ns.split(':').collect::>()[0]; + } + } + } + Ok(Event::Text(ref e)) if creator_found => { + if is_epub3 { + let entry = xml_authors.entry(curr_id.clone()).or_insert(XmlAut { + name: "".to_string(), + sort: "".to_string(), + role: "".to_string(), + }); + entry.name = String::from_utf8(e.to_vec()).unwrap(); + } else { + let entry = xml_authors.entry(curr_id.clone()).or_insert(XmlAut { + name: "".to_string(), + sort: "".to_string(), + role: "".to_string(), + }); + entry.name = String::from_utf8(e.to_vec()).unwrap(); + entry.role = "aut".to_string(); + } + + creator_found = false; + } + Ok(Event::Start(ref e)) if e.local_name() == b"meta" && is_epub3 => { + if let Some(refines) = e + .attributes() + .filter(|attr| attr.as_ref().unwrap().key == b"refines") + .next() + { + if e.attributes().any(|attr| { + attr.as_ref().unwrap().key == b"property" + && attr.as_ref().unwrap().value.ends_with(b"file-as") + }) { + curr_id = String::from_utf8(refines.unwrap().value.to_vec()).unwrap(); + file_as_found = true; + } else if e.attributes().any(|attr| { + attr.as_ref().unwrap().key == b"property" + && attr.as_ref().unwrap().value.ends_with(b"role") + }) { + curr_id = String::from_utf8(refines.unwrap().value.to_vec()).unwrap(); + role_found = true; + } + } + } + Ok(Event::Text(ref e)) if file_as_found && is_epub3 => { + let entry = xml_authors.entry(curr_id.clone()).or_insert(XmlAut { + name: "".to_string(), + sort: "".to_string(), + role: "".to_string(), + }); + entry.sort = String::from_utf8(e.to_vec()).unwrap(); + + file_as_found = false; + } + Ok(Event::Text(ref e)) if role_found && is_epub3 => { + let entry = xml_authors.entry(curr_id.clone()).or_insert(XmlAut { + name: "".to_string(), + sort: "".to_string(), + role: "".to_string(), + }); + entry.role = String::from_utf8(e.to_vec()).unwrap(); + + role_found = false; + } + Ok(Event::Start(ref e)) if e.local_name() == b"subject" => { + genre_found = true; + } + Ok(Event::Text(ref e)) if genre_found => { + //epub_meta.genre = String::from_utf8(e.to_vec()).unwrap(); + epub_meta.genre = e.unescape_and_decode(&reader).unwrap(); + genre_found = false; + } + Ok(Event::Eof) => break, + _ => (), + } + } + + //println!("{:?}", &xml_authors); + + epub_meta.authors = xml_authors + .into_iter() + .filter(|&(_, ref xml_author)| &xml_author.role == "aut" && &xml_author.name.len() > &0) + .map(|(_key, value)| Author { + name: value.name, + firstauthor: value.sort, + }) + .collect(); + + Some(epub_meta) +} diff --git a/src/main.rs b/src/main.rs index 1bb944d..06d25f3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,338 +1,8 @@ +mod epub; mod pocketbook; -use rusqlite::{named_params, Connection, Result, Transaction, NO_PARAMS}; -use std::{collections::HashMap, fs::File}; -use std::{error::Error, io::Read}; -use std::{io::BufReader, usize}; -use xml::reader::{EventReader, ParserConfig, XmlEvent}; -use zip::{read::ZipFile, ZipArchive}; - -fn get_root_file(mut container: ZipFile) -> Result, Box> { - let mut buf = String::new(); - container.read_to_string(&mut buf).unwrap(); - - // Get rid of the BOM mark, if any - if buf.starts_with("\u{feff}") { - buf = buf.strip_prefix("\u{feff}").unwrap().to_owned(); - } - - let parser = EventReader::new(BufReader::new(buf.as_bytes())); - - for e in parser { - match e { - Ok(XmlEvent::StartElement { - name, attributes, .. - }) if name.local_name == "rootfile" => { - for attr in attributes { - if attr.name.local_name == "full-path" { - return Ok(Some(attr.value)); - } - } - } - Err(e) => { - return Err(Box::new(e)); - } - _ => {} - } - } - Ok(None) -} - -struct Refine { - role: String, - file_as: String, -} - -fn get_attribute_file_as(opf: ZipFile) -> Option { - let parser = ParserConfig::new() - .trim_whitespace(true) - .ignore_comments(true) - .coalesce_characters(true) - .create_reader(opf); - - let mut is_epub3 = false; - let mut creator_ids = Vec::new(); - let mut refines_found = false; - let mut role_found = false; - let mut refine_entries = HashMap::new(); - let mut curr_id = String::new(); - - for e in parser { - match e { - Ok(XmlEvent::StartElement { - name, attributes, .. - }) if name.local_name == "package" => { - for attr in attributes { - if attr.name.local_name == "version" { - if attr.value.starts_with("3") == true { - is_epub3 = true; - } - } - } - } - Ok(XmlEvent::StartElement { - name, attributes, .. - }) if name.local_name == "creator" => { - for attr in attributes { - if attr.name.local_name == "file-as" { - return Some(attr.value); - } - if is_epub3 && attr.name.local_name == "id" { - creator_ids.push("#".to_owned() + attr.value.as_str()); - } - } - } - Ok(XmlEvent::StartElement { - name, attributes, .. - }) if name.local_name == "meta" => { - if attributes.iter().any(|attr| { - attr.name.local_name == "refines" && creator_ids.contains(&attr.value) - }) && attributes - .iter() - .any(|attr| attr.name.local_name == "property" && attr.value == "file-as") - { - refines_found = true; - curr_id = attributes - .iter() - .find(|a| a.name.local_name == "refines") - .unwrap() - .value - .clone(); - } else if attributes.iter().any(|attr| { - attr.name.local_name == "refines" && creator_ids.contains(&attr.value) - }) && attributes - .iter() - .any(|attr| attr.name.local_name == "property" && attr.value == "role") - { - role_found = true; - curr_id = attributes - .iter() - .find(|a| a.name.local_name == "refines") - .unwrap() - .value - .clone(); - } - } - Ok(XmlEvent::Characters(value)) => { - if role_found == true { - if value == "aut" { - let entry = refine_entries.entry(curr_id.clone()).or_insert(Refine { - role: "".to_string(), - file_as: "".to_string(), - }); - entry.role = value; - } - role_found = false; - } else if refines_found == true { - let entry = refine_entries.entry(curr_id.clone()).or_insert(Refine { - role: "".to_string(), - file_as: "".to_string(), - }); - entry.file_as = value; - refines_found = false; - } - } - Ok(XmlEvent::StartElement { .. }) => { - if refines_found == true { - refines_found = false; - } - } - Err(_e) => { - break; - } - _ => {} - } - } - - if refine_entries.len() == 1 { - return Some(refine_entries.values().next().unwrap().file_as.clone()); - } else if refine_entries.len() >= 2 { - return Some( - refine_entries - .values() - .into_iter() - .filter(|v| v.role == "aut") - .map(|v| v.file_as.clone()) - .collect::>() - .join(" & "), - ); - } - - None -} - -struct Creator { - role: String, - name: String, -} - -fn get_attribute_creator(opf: ZipFile) -> Option { - let parser = ParserConfig::new() - .trim_whitespace(true) - .ignore_comments(true) - .coalesce_characters(true) - .create_reader(opf); - - let mut is_epub3 = false; - let mut creator_found = true; - let mut creator_ids = Vec::new(); - let mut role_found = false; - let mut creator_entries = HashMap::new(); - let mut epub2_creator_entries = Vec::new(); - let mut curr_id = String::new(); - - for e in parser { - match e { - Ok(XmlEvent::StartElement { - name, attributes, .. - }) if name.local_name == "package" => { - for attr in attributes { - if attr.name.local_name == "version" { - if attr.value.starts_with("3") == true { - is_epub3 = true; - } - } - } - } - Ok(XmlEvent::StartElement { - name, attributes, .. - }) if name.local_name == "creator" => { - creator_found = true; - if !is_epub3 { - match attributes - .iter() - .find(|attr| attr.name.local_name == "role") - { - Some(attr) => { - epub2_creator_entries.push(Creator { - role: attr.value.clone(), - name: "".to_string(), - }); - } - None => { - epub2_creator_entries.push(Creator { - role: "aut".to_string(), - name: "".to_string(), - }); - } - } - } - for attr in attributes { - if is_epub3 && attr.name.local_name == "id" { - creator_ids.push("#".to_owned() + attr.value.as_str()); - //creator_entries.insert(attr.value.clone(), Creator{role: "".to_string(), name: "".to_string()}); - curr_id = "#".to_owned() + attr.value.as_str(); - } - } - } - Ok(XmlEvent::StartElement { - name, attributes, .. - }) if name.local_name == "meta" => { - if attributes.iter().any(|attr| { - attr.name.local_name == "refines" && creator_ids.contains(&attr.value) - }) && attributes - .iter() - .any(|attr| attr.name.local_name == "property" && attr.value == "role") - { - role_found = true; - curr_id = attributes - .iter() - .find(|a| a.name.local_name == "refines") - .unwrap() - .value - .clone(); - } - } - Ok(XmlEvent::Characters(value)) => { - if creator_found && is_epub3 == false { - epub2_creator_entries.last_mut().unwrap().name = value.clone(); - } else if creator_found && is_epub3 == true { - let entry = creator_entries.entry(curr_id.clone()).or_insert(Creator { - role: "".to_string(), - name: "".to_string(), - }); - entry.name = value; - creator_found = false; - } else if role_found == true { - let entry = creator_entries.entry(curr_id.clone()).or_insert(Creator { - role: "".to_string(), - name: "".to_string(), - }); - entry.role = value; - role_found = false; - } - } - Ok(XmlEvent::StartElement { .. }) => { - if creator_found == true { - creator_found = false; - } - } - Err(e) => { - println!("{}", e); - break; - } - _ => {} - } - } - - if !is_epub3 && epub2_creator_entries.len() >= 1 { - return Some( - epub2_creator_entries - .into_iter() - .filter(|v| v.role == "aut") - .map(|v| v.name.clone()) - .collect::>() - .join(", "), - ); - } else if creator_entries.len() >= 1 { - return Some( - creator_entries - .values() - .into_iter() - .filter(|v| v.role == "aut") - .map(|v| v.name.clone()) - .collect::>() - .join(", "), - ); - } - - None -} - -fn get_attribute_genre(opf: ZipFile) -> Option { - let parser = ParserConfig::new() - .trim_whitespace(true) - .ignore_comments(true) - .coalesce_characters(true) - .create_reader(opf); - - let mut genre_found = false; - - for e in parser { - match e { - Ok(XmlEvent::StartElement { name, .. }) if name.local_name == "subject" => { - genre_found = true; - } - Ok(XmlEvent::Characters(value)) => { - if genre_found { - return Some(value); - } - } - Ok(XmlEvent::StartElement { .. }) => { - if genre_found == true { - genre_found = false; - } - } - Err(e) => { - println!("{}", e); - break; - } - _ => {} - } - } - - None -} +use rusqlite::{named_params, Connection, Transaction, NO_PARAMS}; +use std::usize; struct BookEntry { id: i32, @@ -460,67 +130,70 @@ fn fix_db_entries(tx: &Transaction, book_entries: &Vec) -> Statistics continue; } - let file = File::open(entry.filepath.as_str()); - let file = match file { - Err(_) => continue, - Ok(file) => file, - }; + if let Some(epub_metadata) = epub::get_epub_metadata(&entry.filepath) { + let authors = epub_metadata + .authors + .iter() + .filter(|aut| aut.firstauthor.len() > 0) + .collect::>(); - let mut archive = ZipArchive::new(BufReader::new(file)).unwrap(); + // Fix firstauthor… + let firstauthors = authors + .iter() + .map(|aut| aut.firstauthor.clone()) + .collect::>(); + if !firstauthors.iter().all(|s| entry.firstauthor.contains(s)) { + let mut stmt = tx + .prepare("UPDATE books_impl SET firstauthor = :file_as WHERE id = :book_id") + .unwrap(); + stmt.execute_named( + named_params![":file_as": firstauthors.join(" & "), ":book_id": entry.id], + ) + .unwrap(); + stat.authors_fixed = stat.authors_fixed + 1; - let container = archive.by_name("META-INF/container.xml").unwrap(); - - if let Some(opf_file) = get_root_file(container).unwrap() { - let opf = archive.by_name(opf_file.as_str()).unwrap(); - // firstauthor… - if let Some(file_as) = get_attribute_file_as(opf) { - if !file_as.split(" & ").all(|s| entry.firstauthor.contains(s)) { - let mut stmt = tx - .prepare("UPDATE books_impl SET firstauthor = :file_as WHERE id = :book_id") - .unwrap(); - stmt.execute_named(named_params![":file_as": file_as, ":book_id": entry.id]) - .unwrap(); - stat.authors_fixed = stat.authors_fixed + 1; - } + println!("{}", firstauthors.join(" & ")); } - let opf = archive.by_name(opf_file.as_str()).unwrap(); - // author… - if let Some(creator) = get_attribute_creator(opf) { - if !creator.split(", ").all(|s| entry.author.contains(s)) - || creator.len() < entry.author.len() - { - let mut stmt = tx - .prepare("UPDATE books_impl SET author = :creator WHERE id = :book_id") - .unwrap(); - stmt.execute_named(named_params![":creator": creator, ":book_id": entry.id]) - .unwrap(); - stat.authors_fixed = stat.authors_fixed + 1; - } + + // Fix author names… + let authornames = authors + .iter() + .map(|aut| aut.name.clone()) + .collect::>(); + if !authornames.iter().all(|s| entry.author.contains(s)) { + let mut stmt = tx + .prepare("UPDATE books_impl SET author = :authors WHERE id = :book_id") + .unwrap(); + stmt.execute_named( + named_params![":authors": authornames.join(", "), ":book_id": entry.id], + ) + .unwrap(); + stat.authors_fixed = stat.authors_fixed + 1; + + println!("{}", authornames.join(" & ")); } - // genre… - if entry.genre.is_empty() { - let opf = archive.by_name(opf_file.as_str()).unwrap(); - if let Some(genre) = get_attribute_genre(opf) { - let mut stmt = tx - .prepare( - r#"INSERT INTO genres (name) SELECT :genre ON CONFLICT DO NOTHING"#, - ) - .unwrap(); - stmt.execute_named(named_params![":genre": &genre]).unwrap(); - let mut stmt = tx - .prepare( - r#" - INSERT INTO booktogenre (bookid, genreid) - VALUES (:bookid, - (SELECT id FROM genres WHERE name = :genre) - ) - ON CONFLICT DO NOTHING"#, - ) - .unwrap(); - stmt.execute_named(named_params![":bookid": &entry.id, ":genre": &genre]) - .unwrap(); - stat.genres_fixed = stat.genres_fixed + 1; - } + + if entry.genre.is_empty() && epub_metadata.genre.len() > 0 { + let mut stmt = tx + .prepare(r#"INSERT INTO genres (name) SELECT :genre ON CONFLICT DO NOTHING"#) + .unwrap(); + stmt.execute_named(named_params![":genre": &epub_metadata.genre]) + .unwrap(); + let mut stmt = tx + .prepare( + r#" + INSERT INTO booktogenre (bookid, genreid) + VALUES (:bookid, + (SELECT id FROM genres WHERE name = :genre) + ) + ON CONFLICT DO NOTHING"#, + ) + .unwrap(); + stmt.execute_named( + named_params![":bookid": &entry.id, ":genre": &epub_metadata.genre], + ) + .unwrap(); + stat.genres_fixed = stat.genres_fixed + 1; } } } From 247591707db8f1f0bf895231ca3ee66103687086 Mon Sep 17 00:00:00 2001 From: Martin Brodbeck Date: Thu, 11 Feb 2021 22:00:49 +0100 Subject: [PATCH 09/57] code cleanup --- src/epub.rs | 3 --- src/main.rs | 4 ---- 2 files changed, 7 deletions(-) diff --git a/src/epub.rs b/src/epub.rs index a640d47..1780f1b 100644 --- a/src/epub.rs +++ b/src/epub.rs @@ -226,7 +226,6 @@ pub fn get_epub_metadata(filename: &str) -> Option { genre_found = true; } Ok(Event::Text(ref e)) if genre_found => { - //epub_meta.genre = String::from_utf8(e.to_vec()).unwrap(); epub_meta.genre = e.unescape_and_decode(&reader).unwrap(); genre_found = false; } @@ -235,8 +234,6 @@ pub fn get_epub_metadata(filename: &str) -> Option { } } - //println!("{:?}", &xml_authors); - epub_meta.authors = xml_authors .into_iter() .filter(|&(_, ref xml_author)| &xml_author.role == "aut" && &xml_author.name.len() > &0) diff --git a/src/main.rs b/src/main.rs index 06d25f3..d997046 100644 --- a/src/main.rs +++ b/src/main.rs @@ -151,8 +151,6 @@ fn fix_db_entries(tx: &Transaction, book_entries: &Vec) -> Statistics ) .unwrap(); stat.authors_fixed = stat.authors_fixed + 1; - - println!("{}", firstauthors.join(" & ")); } // Fix author names… @@ -169,8 +167,6 @@ fn fix_db_entries(tx: &Transaction, book_entries: &Vec) -> Statistics ) .unwrap(); stat.authors_fixed = stat.authors_fixed + 1; - - println!("{}", authornames.join(" & ")); } if entry.genre.is_empty() && epub_metadata.genre.len() > 0 { From c6252464aae5efb09690d8d977ae40b9de84afa7 Mon Sep 17 00:00:00 2001 From: Martin Brodbeck Date: Fri, 12 Feb 2021 07:50:32 +0100 Subject: [PATCH 10/57] simplify creating XmlAut --- src/epub.rs | 49 ++++++++++++++++--------------------------------- 1 file changed, 16 insertions(+), 33 deletions(-) diff --git a/src/epub.rs b/src/epub.rs index 1780f1b..bc2ab90 100644 --- a/src/epub.rs +++ b/src/epub.rs @@ -96,6 +96,16 @@ pub fn get_epub_metadata(filename: &str) -> Option { role: String, } + impl XmlAut { + fn new() -> Self { + XmlAut { + name: String::new(), + sort: String::new(), + role: String::new(), + } + } + } + let mut xml_authors = HashMap::new(); loop { @@ -121,14 +131,7 @@ pub fn get_epub_metadata(filename: &str) -> Option { + String::from_utf8(idval.unwrap().value.to_vec()) .unwrap() .as_str(); - xml_authors.insert( - curr_id.clone(), - XmlAut { - name: "".to_string(), - sort: "".to_string(), - role: "".to_string(), - }, - ); + xml_authors.insert(curr_id.clone(), XmlAut::new()); } } else { if let Some(file_as_val) = e @@ -139,11 +142,7 @@ pub fn get_epub_metadata(filename: &str) -> Option { let ns = String::from_utf8(file_as_val.as_ref().unwrap().key.to_vec()).unwrap(); curr_id = "none".to_string() + ns.split(':').collect::>()[0]; - let entry = xml_authors.entry(curr_id.clone()).or_insert(XmlAut { - name: "".to_string(), - sort: "".to_string(), - role: "".to_string(), - }); + let entry = xml_authors.entry(curr_id.clone()).or_insert(XmlAut::new()); entry.sort = file_as_val .unwrap() .unescape_and_decode_value(&reader) @@ -163,18 +162,10 @@ pub fn get_epub_metadata(filename: &str) -> Option { } Ok(Event::Text(ref e)) if creator_found => { if is_epub3 { - let entry = xml_authors.entry(curr_id.clone()).or_insert(XmlAut { - name: "".to_string(), - sort: "".to_string(), - role: "".to_string(), - }); + let entry = xml_authors.entry(curr_id.clone()).or_insert(XmlAut::new()); entry.name = String::from_utf8(e.to_vec()).unwrap(); } else { - let entry = xml_authors.entry(curr_id.clone()).or_insert(XmlAut { - name: "".to_string(), - sort: "".to_string(), - role: "".to_string(), - }); + let entry = xml_authors.entry(curr_id.clone()).or_insert(XmlAut::new()); entry.name = String::from_utf8(e.to_vec()).unwrap(); entry.role = "aut".to_string(); } @@ -203,21 +194,13 @@ pub fn get_epub_metadata(filename: &str) -> Option { } } Ok(Event::Text(ref e)) if file_as_found && is_epub3 => { - let entry = xml_authors.entry(curr_id.clone()).or_insert(XmlAut { - name: "".to_string(), - sort: "".to_string(), - role: "".to_string(), - }); + let entry = xml_authors.entry(curr_id.clone()).or_insert(XmlAut::new()); entry.sort = String::from_utf8(e.to_vec()).unwrap(); file_as_found = false; } Ok(Event::Text(ref e)) if role_found && is_epub3 => { - let entry = xml_authors.entry(curr_id.clone()).or_insert(XmlAut { - name: "".to_string(), - sort: "".to_string(), - role: "".to_string(), - }); + let entry = xml_authors.entry(curr_id.clone()).or_insert(XmlAut::new()); entry.role = String::from_utf8(e.to_vec()).unwrap(); role_found = false; From a9620b3e347ffca930c78c52b248104f87588018 Mon Sep 17 00:00:00 2001 From: Martin Brodbeck Date: Fri, 12 Feb 2021 09:13:31 +0100 Subject: [PATCH 11/57] Fixes and improvements - Fix reading file-as from XML - Now fixing first_author_letter --- Cargo.lock | 2 +- Cargo.toml | 2 +- src/epub.rs | 15 ++++++------ src/main.rs | 67 +++++++++++++++++++++++++++++++++++++++-------------- 4 files changed, 58 insertions(+), 28 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4d848cc..1c65061 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -148,7 +148,7 @@ dependencies = [ [[package]] name = "pbdbfixer" -version = "0.5.0" +version = "0.6.0" dependencies = [ "quick-xml", "rusqlite", diff --git a/Cargo.toml b/Cargo.toml index f7b9656..05c3b23 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pbdbfixer" -version = "0.5.0" +version = "0.6.0" authors = ["Martin Brodbeck "] edition = "2018" diff --git a/src/epub.rs b/src/epub.rs index bc2ab90..ed63f75 100644 --- a/src/epub.rs +++ b/src/epub.rs @@ -139,24 +139,19 @@ pub fn get_epub_metadata(filename: &str) -> Option { .filter(|attr| attr.as_ref().unwrap().key.ends_with(b"file-as")) .next() { - let ns = - String::from_utf8(file_as_val.as_ref().unwrap().key.to_vec()).unwrap(); - curr_id = "none".to_string() + ns.split(':').collect::>()[0]; + curr_id = "none".to_string() + xml_authors.len().to_string().as_str(); let entry = xml_authors.entry(curr_id.clone()).or_insert(XmlAut::new()); entry.sort = file_as_val .unwrap() .unescape_and_decode_value(&reader) .unwrap_or_default(); entry.role = "aut".to_string(); - } - if let Some(role_val) = e + } else if let Some(_role_val) = e .attributes() .filter(|attr| attr.as_ref().unwrap().key.ends_with(b"role")) .next() { - let ns = - String::from_utf8(role_val.as_ref().unwrap().key.to_vec()).unwrap(); - curr_id = "none".to_string() + ns.split(':').collect::>()[0]; + curr_id = "none".to_string() + xml_authors.len().to_string().as_str(); } } } @@ -217,6 +212,8 @@ pub fn get_epub_metadata(filename: &str) -> Option { } } + //println!("Meta: {:?}", &xml_authors); + epub_meta.authors = xml_authors .into_iter() .filter(|&(_, ref xml_author)| &xml_author.role == "aut" && &xml_author.name.len() > &0) @@ -226,5 +223,7 @@ pub fn get_epub_metadata(filename: &str) -> Option { }) .collect(); + //println!("Meta: {:?}", &epub_meta); + Some(epub_meta) } diff --git a/src/main.rs b/src/main.rs index d997046..6bc4afd 100644 --- a/src/main.rs +++ b/src/main.rs @@ -11,6 +11,7 @@ struct BookEntry { firstauthor: String, has_drm: bool, genre: String, + first_author_letter: String, } fn get_epubs_from_database(tx: &Transaction) -> Vec { @@ -18,8 +19,9 @@ fn get_epubs_from_database(tx: &Transaction) -> Vec { let mut stmt = tx .prepare( - r" - SELECT books.id, folders.name, files.filename, books.firstauthor, books.author, genres.name + r#" + SELECT books.id, folders.name, files.filename, books.firstauthor, + books.author, genres.name, first_author_letter FROM books_impl books JOIN files ON books.id = files.book_id JOIN folders @@ -29,7 +31,7 @@ fn get_epubs_from_database(tx: &Transaction) -> Vec { LEFT OUTER JOIN genres ON genres.id = btg.genreid WHERE files.storageid = 1 AND books.ext = 'epub' - ORDER BY books.id", + ORDER BY books.id"#, ) .unwrap(); @@ -47,6 +49,7 @@ fn get_epubs_from_database(tx: &Transaction) -> Vec { _ => false, }; let genre: String = row.get(5).unwrap_or_default(); + let first_author_letter = row.get(6).unwrap_or_default(); let entry = BookEntry { id: book_id, @@ -55,6 +58,7 @@ fn get_epubs_from_database(tx: &Transaction) -> Vec { author, has_drm, genre, + first_author_letter, }; book_entries.push(entry); @@ -66,7 +70,7 @@ fn get_epubs_from_database(tx: &Transaction) -> Vec { fn remove_ghost_books_from_db(tx: &Transaction) -> usize { let mut stmt = tx .prepare( - r" + r#" DELETE FROM books_impl WHERE id IN ( SELECT books.id @@ -74,34 +78,34 @@ fn remove_ghost_books_from_db(tx: &Transaction) -> usize { LEFT OUTER JOIN files ON books.id = files.book_id WHERE files.filename is NULL - )", + )"#, ) .unwrap(); let num = stmt.execute(NO_PARAMS).unwrap(); tx.execute( - r"DELETE FROM books_settings WHERE bookid NOT IN ( SELECT id FROM books_impl )", + r#"DELETE FROM books_settings WHERE bookid NOT IN ( SELECT id FROM books_impl )"#, NO_PARAMS, ) .unwrap(); tx.execute( - r"DELETE FROM books_uids WHERE book_id NOT IN ( SELECT id FROM books_impl )", + r#"DELETE FROM books_uids WHERE book_id NOT IN ( SELECT id FROM books_impl )"#, NO_PARAMS, ) .unwrap(); tx.execute( - r"DELETE FROM bookshelfs_books WHERE bookid NOT IN ( SELECT id FROM books_impl )", + r#"DELETE FROM bookshelfs_books WHERE bookid NOT IN ( SELECT id FROM books_impl )"#, NO_PARAMS, ) .unwrap(); tx.execute( - r"DELETE FROM booktogenre WHERE bookid NOT IN ( SELECT id FROM books_impl )", + r#"DELETE FROM booktogenre WHERE bookid NOT IN ( SELECT id FROM books_impl )"#, NO_PARAMS, ) .unwrap(); tx.execute( - r"DELETE FROM social WHERE bookid NOT IN ( SELECT id FROM books_impl )", + r#"DELETE FROM social WHERE bookid NOT IN ( SELECT id FROM books_impl )"#, NO_PARAMS, ) .unwrap(); @@ -114,6 +118,7 @@ struct Statistics { ghost_books_cleaned: usize, drm_skipped: usize, genres_fixed: usize, + sorting_fixed: usize, } fn fix_db_entries(tx: &Transaction, book_entries: &Vec) -> Statistics { @@ -122,6 +127,7 @@ fn fix_db_entries(tx: &Transaction, book_entries: &Vec) -> Statistics ghost_books_cleaned: 0, drm_skipped: 0, genres_fixed: 0, + sorting_fixed: 0, }; for entry in book_entries { @@ -131,17 +137,14 @@ fn fix_db_entries(tx: &Transaction, book_entries: &Vec) -> Statistics } if let Some(epub_metadata) = epub::get_epub_metadata(&entry.filepath) { - let authors = epub_metadata + // Fix firstauthor… + let mut firstauthors = epub_metadata .authors .iter() .filter(|aut| aut.firstauthor.len() > 0) - .collect::>(); - - // Fix firstauthor… - let firstauthors = authors - .iter() .map(|aut| aut.firstauthor.clone()) .collect::>(); + firstauthors.sort(); if !firstauthors.iter().all(|s| entry.firstauthor.contains(s)) { let mut stmt = tx .prepare("UPDATE books_impl SET firstauthor = :file_as WHERE id = :book_id") @@ -153,8 +156,28 @@ fn fix_db_entries(tx: &Transaction, book_entries: &Vec) -> Statistics stat.authors_fixed = stat.authors_fixed + 1; } + // Fix first_author_letter + let first_author_letter = firstauthors + .join(" & ") + .chars() + .next() + .unwrap_or_default() + .to_string() + .to_uppercase(); + if entry.first_author_letter != first_author_letter { + let mut stmt = tx + .prepare("UPDATE books_impl SET first_author_letter = :first_letter WHERE id = :book_id") + .unwrap(); + stmt.execute_named( + named_params![":first_letter": first_author_letter,":book_id": entry.id], + ) + .unwrap(); + stat.sorting_fixed = stat.sorting_fixed + 1; + } + // Fix author names… - let authornames = authors + let authornames = epub_metadata + .authors .iter() .map(|aut| aut.name.clone()) .collect::>(); @@ -169,6 +192,7 @@ fn fix_db_entries(tx: &Transaction, book_entries: &Vec) -> Statistics stat.authors_fixed = stat.authors_fixed + 1; } + // Fix genre… if entry.genre.is_empty() && epub_metadata.genre.len() > 0 { let mut stmt = tx .prepare(r#"INSERT INTO genres (name) SELECT :genre ON CONFLICT DO NOTHING"#) @@ -255,10 +279,12 @@ fn main() { pocketbook::Icon::Info, &format!( "Authors fixed: {}\n\ + Sorting fixed: {}\n\ Genres fixed: {}\n\ Books skipped (DRM): {}\n\ Books cleaned from DB: {}", &stat.authors_fixed, + &stat.sorting_fixed, &stat.genres_fixed, &stat.drm_skipped, &stat.ghost_books_cleaned @@ -269,10 +295,15 @@ fn main() { } else { println!( "Authors fixed: {}\n\ + Sorting fixed: {}\n\ Genres fixed: {}\n\ Books skipped (DRM): {}\n\ Books cleaned from DB: {}", - &stat.authors_fixed, &stat.genres_fixed, &stat.drm_skipped, &stat.ghost_books_cleaned + &stat.authors_fixed, + &stat.sorting_fixed, + &stat.genres_fixed, + &stat.drm_skipped, + &stat.ghost_books_cleaned ); } } From 577ae2b889f803d47530881ef1127647f3a8887b Mon Sep 17 00:00:00 2001 From: Martin Brodbeck Date: Fri, 12 Feb 2021 09:34:58 +0100 Subject: [PATCH 12/57] Fix showing results screen --- src/main.rs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/main.rs b/src/main.rs index 6bc4afd..97056b7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -121,6 +121,15 @@ struct Statistics { sorting_fixed: usize, } +impl Statistics { + fn anything_fixed(&self) -> bool { + &self.authors_fixed > &0 + || &self.genres_fixed > &0 + || &self.ghost_books_cleaned > &0 + || &self.sorting_fixed > &0 + } +} + fn fix_db_entries(tx: &Transaction, book_entries: &Vec) -> Statistics { let mut stat = Statistics { authors_fixed: 0, @@ -254,7 +263,7 @@ fn main() { tx.commit().unwrap(); if cfg!(target_arch = "arm") { - if stat.authors_fixed == 0 { + if stat.anything_fixed() == false { if stat.drm_skipped == 0 { pocketbook::dialog( pocketbook::Icon::Info, From 7d8ab91d85af4bd7a11980fe896d5ddb25863fec Mon Sep 17 00:00:00 2001 From: Martin Brodbeck Date: Fri, 12 Feb 2021 10:10:10 +0100 Subject: [PATCH 13/57] readme updated --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 758a355..b348db3 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,7 @@ metadata. ## Features The app tries to fix the following issues in the database - Correction of wrong firstauthor entries (books_impl table) +- Correction of wrong first_author_letter entries (books_impl table) - Correction of wrong author entries (books_impl table) - Removing deleted e-books from the database (various tables) - Add missing genre if present in epub (genre and booktogenre tables) From a52b8a82883b9fcb136b8c5924a643c9561edef1 Mon Sep 17 00:00:00 2001 From: Martin Brodbeck Date: Mon, 15 Feb 2021 13:05:32 +0100 Subject: [PATCH 14/57] fix missing series information --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 2 ++ src/epub.rs | 91 ++++++++++++++++++++++++++++++++++++++++++++++++++--- src/main.rs | 24 +++++++++++++- 5 files changed, 114 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1c65061..fccaaa4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -148,7 +148,7 @@ dependencies = [ [[package]] name = "pbdbfixer" -version = "0.6.0" +version = "0.7.0" dependencies = [ "quick-xml", "rusqlite", diff --git a/Cargo.toml b/Cargo.toml index 05c3b23..1f36995 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pbdbfixer" -version = "0.6.0" +version = "0.7.0" authors = ["Martin Brodbeck "] edition = "2018" diff --git a/README.md b/README.md index b348db3..8839722 100644 --- a/README.md +++ b/README.md @@ -13,10 +13,12 @@ The app tries to fix the following issues in the database - Correction of wrong author entries (books_impl table) - Removing deleted e-books from the database (various tables) - Add missing genre if present in epub (genre and booktogenre tables) +- Add missing series information (books_impl table) ## Compatibility This program is tested on a PocketBook - *Touch HD 3* (software version 6.1.900) +- *Inkpad 3 Pro* (software version 6.0.1067) - *Touch Lux 4* (software version 6.0.1118) It might work with other PocketBook devices/software versions. Please tell me if it works for you (and do make a backup of the explorer-3.db file before trying!). diff --git a/src/epub.rs b/src/epub.rs index ed63f75..759c91f 100644 --- a/src/epub.rs +++ b/src/epub.rs @@ -13,10 +13,26 @@ pub struct Author { pub firstauthor: String, } +#[derive(Debug)] +pub struct Series { + pub name: String, + pub index: i32, +} + +impl Series { + fn new() -> Self { + Series { + name: String::new(), + index: 0, + } + } +} + #[derive(Debug)] pub struct EpubMetadata { pub authors: Vec, pub genre: String, + pub series: Series, } impl EpubMetadata { @@ -24,6 +40,7 @@ impl EpubMetadata { EpubMetadata { authors: Vec::new(), genre: String::new(), + series: Series::new(), } } } @@ -87,6 +104,8 @@ pub fn get_epub_metadata(filename: &str) -> Option { let mut file_as_found = false; let mut role_found = false; let mut genre_found = false; + let mut series_found = false; + let mut series_index_found = false; let mut is_epub3 = false; #[derive(Debug)] @@ -185,8 +204,63 @@ pub fn get_epub_metadata(filename: &str) -> Option { }) { curr_id = String::from_utf8(refines.unwrap().value.to_vec()).unwrap(); role_found = true; + } else if e.attributes().any(|attr| { + attr.as_ref().unwrap().key == b"property" + && attr.as_ref().unwrap().value.ends_with(b"group-position") + }) { + series_index_found = true; } } + if e.attributes().any(|attr| { + attr.as_ref().unwrap().key == b"property" + && attr + .as_ref() + .unwrap() + .value + .ends_with(b"belongs-to-collection") + }) { + series_found = true; + } + } + Ok(Event::Empty(ref e)) if e.local_name() == b"meta" && !is_epub3 => { + if e.attributes().any(|attr| { + attr.as_ref().unwrap().key == b"name" + && attr + .as_ref() + .unwrap() + .unescaped_value() + .unwrap() + .ends_with(b"series") + }) { + epub_meta.series.name = e + .attributes() + .filter(|attr| attr.as_ref().unwrap().key == b"content") + .next() + .unwrap() + .unwrap() + .unescape_and_decode_value(&reader) + .unwrap_or_default(); + } else if e.attributes().any(|attr| { + attr.as_ref().unwrap().key == b"name" + && attr + .as_ref() + .unwrap() + .unescaped_value() + .unwrap() + .ends_with(b"series_index") + }) { + let index_float = e + .attributes() + .filter(|attr| attr.as_ref().unwrap().key == b"content") + .next() + .unwrap() + .unwrap() + .unescape_and_decode_value(&reader) + .unwrap_or_default() + .parse::() + .unwrap_or_default(); + epub_meta.series.index = index_float as i32; + } } Ok(Event::Text(ref e)) if file_as_found && is_epub3 => { let entry = xml_authors.entry(curr_id.clone()).or_insert(XmlAut::new()); @@ -200,6 +274,19 @@ pub fn get_epub_metadata(filename: &str) -> Option { role_found = false; } + Ok(Event::Text(ref e)) if series_found && is_epub3 => { + epub_meta.series.name = String::from_utf8(e.to_vec()).unwrap(); + + series_found = false; + } + Ok(Event::Text(ref e)) if series_index_found && is_epub3 => { + epub_meta.series.index = String::from_utf8(e.to_vec()) + .unwrap() + .parse() + .unwrap_or_default(); + + series_index_found = false; + } Ok(Event::Start(ref e)) if e.local_name() == b"subject" => { genre_found = true; } @@ -212,8 +299,6 @@ pub fn get_epub_metadata(filename: &str) -> Option { } } - //println!("Meta: {:?}", &xml_authors); - epub_meta.authors = xml_authors .into_iter() .filter(|&(_, ref xml_author)| &xml_author.role == "aut" && &xml_author.name.len() > &0) @@ -223,7 +308,5 @@ pub fn get_epub_metadata(filename: &str) -> Option { }) .collect(); - //println!("Meta: {:?}", &epub_meta); - Some(epub_meta) } diff --git a/src/main.rs b/src/main.rs index 97056b7..b2cc8b6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -12,6 +12,7 @@ struct BookEntry { has_drm: bool, genre: String, first_author_letter: String, + series: String, } fn get_epubs_from_database(tx: &Transaction) -> Vec { @@ -21,7 +22,7 @@ fn get_epubs_from_database(tx: &Transaction) -> Vec { .prepare( r#" SELECT books.id, folders.name, files.filename, books.firstauthor, - books.author, genres.name, first_author_letter + books.author, genres.name, first_author_letter, series FROM books_impl books JOIN files ON books.id = files.book_id JOIN folders @@ -50,6 +51,7 @@ fn get_epubs_from_database(tx: &Transaction) -> Vec { }; let genre: String = row.get(5).unwrap_or_default(); let first_author_letter = row.get(6).unwrap_or_default(); + let series: String = row.get(7).unwrap_or_default(); let entry = BookEntry { id: book_id, @@ -59,6 +61,7 @@ fn get_epubs_from_database(tx: &Transaction) -> Vec { has_drm, genre, first_author_letter, + series, }; book_entries.push(entry); @@ -119,6 +122,7 @@ struct Statistics { drm_skipped: usize, genres_fixed: usize, sorting_fixed: usize, + series_fixed: usize, } impl Statistics { @@ -127,6 +131,7 @@ impl Statistics { || &self.genres_fixed > &0 || &self.ghost_books_cleaned > &0 || &self.sorting_fixed > &0 + || &self.series_fixed > &0 } } @@ -137,6 +142,7 @@ fn fix_db_entries(tx: &Transaction, book_entries: &Vec) -> Statistics drm_skipped: 0, genres_fixed: 0, sorting_fixed: 0, + series_fixed: 0, }; for entry in book_entries { @@ -224,6 +230,18 @@ fn fix_db_entries(tx: &Transaction, book_entries: &Vec) -> Statistics .unwrap(); stat.genres_fixed = stat.genres_fixed + 1; } + + // Fix series… + if !epub_metadata.series.name.is_empty() && entry.series.is_empty() { + let mut stmt = tx + .prepare("UPDATE books_impl SET series = :series, numinseries = :series_index WHERE id = :book_id") + .unwrap(); + stmt.execute_named( + named_params![":series": &epub_metadata.series.name, ":series_index": &epub_metadata.series.index, ":book_id": entry.id], + ) + .unwrap(); + stat.series_fixed = stat.series_fixed + 1; + } } } @@ -290,11 +308,13 @@ fn main() { "Authors fixed: {}\n\ Sorting fixed: {}\n\ Genres fixed: {}\n\ + Series fixed: {}\n\ Books skipped (DRM): {}\n\ Books cleaned from DB: {}", &stat.authors_fixed, &stat.sorting_fixed, &stat.genres_fixed, + &stat.series_fixed, &stat.drm_skipped, &stat.ghost_books_cleaned ), @@ -306,11 +326,13 @@ fn main() { "Authors fixed: {}\n\ Sorting fixed: {}\n\ Genres fixed: {}\n\ + Series fixed: {}\n\ Books skipped (DRM): {}\n\ Books cleaned from DB: {}", &stat.authors_fixed, &stat.sorting_fixed, &stat.genres_fixed, + &stat.series_fixed, &stat.drm_skipped, &stat.ghost_books_cleaned ); From 624987326deb0b580cb5a268123e21a3e4b949bc Mon Sep 17 00:00:00 2001 From: Martin Brodbeck Date: Mon, 15 Feb 2021 14:13:38 +0100 Subject: [PATCH 15/57] Also remove "false positive" authors If PB adds an author who doesn't have the "aut"-role, make sure to remove this false-positive entry --- Cargo.lock | 2 +- Cargo.toml | 2 +- src/main.rs | 4 +++- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fccaaa4..09beae3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -148,7 +148,7 @@ dependencies = [ [[package]] name = "pbdbfixer" -version = "0.7.0" +version = "0.7.1" dependencies = [ "quick-xml", "rusqlite", diff --git a/Cargo.toml b/Cargo.toml index 1f36995..03226d6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pbdbfixer" -version = "0.7.0" +version = "0.7.1" authors = ["Martin Brodbeck "] edition = "2018" diff --git a/src/main.rs b/src/main.rs index b2cc8b6..318f53d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -196,7 +196,9 @@ fn fix_db_entries(tx: &Transaction, book_entries: &Vec) -> Statistics .iter() .map(|aut| aut.name.clone()) .collect::>(); - if !authornames.iter().all(|s| entry.author.contains(s)) { + if !authornames.iter().all(|s| entry.author.contains(s)) + || authornames.join(", ").len() != entry.author.len() + { let mut stmt = tx .prepare("UPDATE books_impl SET author = :authors WHERE id = :book_id") .unwrap(); From 735335941e429bf13a3bd53690b17fda351c3ec3 Mon Sep 17 00:00:00 2001 From: Martin Brodbeck Date: Wed, 17 Feb 2021 16:20:57 +0100 Subject: [PATCH 16/57] db stuff moved to new database module --- src/database.rs | 266 ++++++++++++++++++++++++++++++++++++++++++++++++ src/main.rs | 263 +---------------------------------------------- 2 files changed, 268 insertions(+), 261 deletions(-) create mode 100644 src/database.rs diff --git a/src/database.rs b/src/database.rs new file mode 100644 index 0000000..67ee9a4 --- /dev/null +++ b/src/database.rs @@ -0,0 +1,266 @@ +use rusqlite::{named_params, Connection, Transaction, NO_PARAMS}; + +use crate::epub; + +const DATABASE_FILE: &str = "/mnt/ext1/system/explorer-3/explorer-3.db"; + +pub struct BookEntry { + id: i32, + filepath: String, + author: String, + firstauthor: String, + has_drm: bool, + genre: String, + first_author_letter: String, + series: String, +} + +fn get_epubs_from_database(tx: &Transaction) -> Vec { + let mut book_entries = Vec::new(); + + let mut stmt = tx + .prepare( + r#" + SELECT books.id, folders.name, files.filename, books.firstauthor, + books.author, genres.name, first_author_letter, series + FROM books_impl books JOIN files + ON books.id = files.book_id + JOIN folders + ON folders.id = files.folder_id + LEFT OUTER JOIN booktogenre btg + ON books.id = btg.bookid + LEFT OUTER JOIN genres + ON genres.id = btg.genreid + WHERE files.storageid = 1 AND books.ext = 'epub' + ORDER BY books.id"#, + ) + .unwrap(); + + let mut rows = stmt.query(NO_PARAMS).unwrap(); + + while let Some(row) = rows.next().unwrap() { + let book_id: i32 = row.get(0).unwrap(); + let prefix: String = row.get(1).unwrap(); + let filename: String = row.get(2).unwrap(); + let filepath = format!("{}/{}", prefix, filename); + let firstauthor: String = row.get(3).unwrap(); + let author: String = row.get(4).unwrap(); + let has_drm = match prefix.as_str() { + "/mnt/ext1/Digital Editions" => true, + _ => false, + }; + let genre: String = row.get(5).unwrap_or_default(); + let first_author_letter = row.get(6).unwrap_or_default(); + let series: String = row.get(7).unwrap_or_default(); + + let entry = BookEntry { + id: book_id, + filepath, + firstauthor, + author, + has_drm, + genre, + first_author_letter, + series, + }; + + book_entries.push(entry); + } + + book_entries +} + +fn remove_ghost_books_from_db(tx: &Transaction) -> usize { + tx.execute("PRAGMA foreign_keys = 0", NO_PARAMS).unwrap(); + + let mut stmt = tx + .prepare( + r#" + DELETE FROM books_impl + WHERE id IN ( + SELECT books.id + FROM books_impl books + LEFT OUTER JOIN files + ON books.id = files.book_id + WHERE files.filename is NULL + )"#, + ) + .unwrap(); + + let num = stmt.execute(NO_PARAMS).unwrap(); + + tx.execute( + r#"DELETE FROM books_settings WHERE bookid NOT IN ( SELECT id FROM books_impl )"#, + NO_PARAMS, + ) + .unwrap(); + tx.execute( + r#"DELETE FROM books_uids WHERE book_id NOT IN ( SELECT id FROM books_impl )"#, + NO_PARAMS, + ) + .unwrap(); + tx.execute( + r#"DELETE FROM bookshelfs_books WHERE bookid NOT IN ( SELECT id FROM books_impl )"#, + NO_PARAMS, + ) + .unwrap(); + tx.execute( + r#"DELETE FROM booktogenre WHERE bookid NOT IN ( SELECT id FROM books_impl )"#, + NO_PARAMS, + ) + .unwrap(); + tx.execute( + r#"DELETE FROM social WHERE bookid NOT IN ( SELECT id FROM books_impl )"#, + NO_PARAMS, + ) + .unwrap(); + + tx.execute("PRAGMA foreign_keys = 0", NO_PARAMS).unwrap(); + + num +} + +pub struct Statistics { + pub authors_fixed: i32, + pub ghost_books_cleaned: usize, + pub drm_skipped: usize, + pub genres_fixed: usize, + pub sorting_fixed: usize, + pub series_fixed: usize, +} + +impl Statistics { + pub fn anything_fixed(&self) -> bool { + &self.authors_fixed > &0 + || &self.genres_fixed > &0 + || &self.ghost_books_cleaned > &0 + || &self.sorting_fixed > &0 + || &self.series_fixed > &0 + } +} + +pub fn fix_db_entries() -> Statistics { + let mut stat = Statistics { + authors_fixed: 0, + ghost_books_cleaned: 0, + drm_skipped: 0, + genres_fixed: 0, + sorting_fixed: 0, + series_fixed: 0, + }; + + let mut conn = Connection::open(DATABASE_FILE).unwrap(); + let tx = conn.transaction().unwrap(); + + let book_entries = get_epubs_from_database(&tx); + + for entry in book_entries { + if entry.has_drm { + stat.drm_skipped = stat.drm_skipped + 1; + continue; + } + + if let Some(epub_metadata) = epub::get_epub_metadata(&entry.filepath) { + // Fix firstauthor… + let mut firstauthors = epub_metadata + .authors + .iter() + .filter(|aut| aut.firstauthor.len() > 0) + .map(|aut| aut.firstauthor.clone()) + .collect::>(); + firstauthors.sort(); + if !firstauthors.iter().all(|s| entry.firstauthor.contains(s)) { + let mut stmt = tx + .prepare("UPDATE books_impl SET firstauthor = :file_as WHERE id = :book_id") + .unwrap(); + stmt.execute_named( + named_params![":file_as": firstauthors.join(" & "), ":book_id": entry.id], + ) + .unwrap(); + stat.authors_fixed = stat.authors_fixed + 1; + } + + // Fix first_author_letter + let first_author_letter = firstauthors + .join(" & ") + .chars() + .next() + .unwrap_or_default() + .to_string() + .to_uppercase(); + if entry.first_author_letter != first_author_letter { + let mut stmt = tx + .prepare("UPDATE books_impl SET first_author_letter = :first_letter WHERE id = :book_id") + .unwrap(); + stmt.execute_named( + named_params![":first_letter": first_author_letter,":book_id": entry.id], + ) + .unwrap(); + stat.sorting_fixed = stat.sorting_fixed + 1; + } + + // Fix author names… + let authornames = epub_metadata + .authors + .iter() + .map(|aut| aut.name.clone()) + .collect::>(); + if !authornames.iter().all(|s| entry.author.contains(s)) + || authornames.join(", ").len() != entry.author.len() + { + let mut stmt = tx + .prepare("UPDATE books_impl SET author = :authors WHERE id = :book_id") + .unwrap(); + stmt.execute_named( + named_params![":authors": authornames.join(", "), ":book_id": entry.id], + ) + .unwrap(); + stat.authors_fixed = stat.authors_fixed + 1; + } + + // Fix genre… + if entry.genre.is_empty() && epub_metadata.genre.len() > 0 { + let mut stmt = tx + .prepare(r#"INSERT INTO genres (name) SELECT :genre ON CONFLICT DO NOTHING"#) + .unwrap(); + stmt.execute_named(named_params![":genre": &epub_metadata.genre]) + .unwrap(); + let mut stmt = tx + .prepare( + r#" + INSERT INTO booktogenre (bookid, genreid) + VALUES (:bookid, + (SELECT id FROM genres WHERE name = :genre) + ) + ON CONFLICT DO NOTHING"#, + ) + .unwrap(); + stmt.execute_named( + named_params![":bookid": &entry.id, ":genre": &epub_metadata.genre], + ) + .unwrap(); + stat.genres_fixed = stat.genres_fixed + 1; + } + + // Fix series… + if !epub_metadata.series.name.is_empty() && entry.series.is_empty() { + let mut stmt = tx + .prepare("UPDATE books_impl SET series = :series, numinseries = :series_index WHERE id = :book_id") + .unwrap(); + stmt.execute_named( + named_params![":series": &epub_metadata.series.name, ":series_index": &epub_metadata.series.index, ":book_id": entry.id], + ) + .unwrap(); + stat.series_fixed = stat.series_fixed + 1; + } + } + } + + // ghost books + let num = remove_ghost_books_from_db(&tx); + stat.ghost_books_cleaned = num; + + tx.commit().unwrap(); + + stat +} diff --git a/src/main.rs b/src/main.rs index 318f53d..79c1f8d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,259 +1,7 @@ +mod database; mod epub; mod pocketbook; -use rusqlite::{named_params, Connection, Transaction, NO_PARAMS}; -use std::usize; - -struct BookEntry { - id: i32, - filepath: String, - author: String, - firstauthor: String, - has_drm: bool, - genre: String, - first_author_letter: String, - series: String, -} - -fn get_epubs_from_database(tx: &Transaction) -> Vec { - let mut book_entries = Vec::new(); - - let mut stmt = tx - .prepare( - r#" - SELECT books.id, folders.name, files.filename, books.firstauthor, - books.author, genres.name, first_author_letter, series - FROM books_impl books JOIN files - ON books.id = files.book_id - JOIN folders - ON folders.id = files.folder_id - LEFT OUTER JOIN booktogenre btg - ON books.id = btg.bookid - LEFT OUTER JOIN genres - ON genres.id = btg.genreid - WHERE files.storageid = 1 AND books.ext = 'epub' - ORDER BY books.id"#, - ) - .unwrap(); - - let mut rows = stmt.query(NO_PARAMS).unwrap(); - - while let Some(row) = rows.next().unwrap() { - let book_id: i32 = row.get(0).unwrap(); - let prefix: String = row.get(1).unwrap(); - let filename: String = row.get(2).unwrap(); - let filepath = format!("{}/{}", prefix, filename); - let firstauthor: String = row.get(3).unwrap(); - let author: String = row.get(4).unwrap(); - let has_drm = match prefix.as_str() { - "/mnt/ext1/Digital Editions" => true, - _ => false, - }; - let genre: String = row.get(5).unwrap_or_default(); - let first_author_letter = row.get(6).unwrap_or_default(); - let series: String = row.get(7).unwrap_or_default(); - - let entry = BookEntry { - id: book_id, - filepath, - firstauthor, - author, - has_drm, - genre, - first_author_letter, - series, - }; - - book_entries.push(entry); - } - - book_entries -} - -fn remove_ghost_books_from_db(tx: &Transaction) -> usize { - let mut stmt = tx - .prepare( - r#" - DELETE FROM books_impl - WHERE id IN ( - SELECT books.id - FROM books_impl books - LEFT OUTER JOIN files - ON books.id = files.book_id - WHERE files.filename is NULL - )"#, - ) - .unwrap(); - - let num = stmt.execute(NO_PARAMS).unwrap(); - - tx.execute( - r#"DELETE FROM books_settings WHERE bookid NOT IN ( SELECT id FROM books_impl )"#, - NO_PARAMS, - ) - .unwrap(); - tx.execute( - r#"DELETE FROM books_uids WHERE book_id NOT IN ( SELECT id FROM books_impl )"#, - NO_PARAMS, - ) - .unwrap(); - tx.execute( - r#"DELETE FROM bookshelfs_books WHERE bookid NOT IN ( SELECT id FROM books_impl )"#, - NO_PARAMS, - ) - .unwrap(); - tx.execute( - r#"DELETE FROM booktogenre WHERE bookid NOT IN ( SELECT id FROM books_impl )"#, - NO_PARAMS, - ) - .unwrap(); - tx.execute( - r#"DELETE FROM social WHERE bookid NOT IN ( SELECT id FROM books_impl )"#, - NO_PARAMS, - ) - .unwrap(); - - num -} - -struct Statistics { - authors_fixed: i32, - ghost_books_cleaned: usize, - drm_skipped: usize, - genres_fixed: usize, - sorting_fixed: usize, - series_fixed: usize, -} - -impl Statistics { - fn anything_fixed(&self) -> bool { - &self.authors_fixed > &0 - || &self.genres_fixed > &0 - || &self.ghost_books_cleaned > &0 - || &self.sorting_fixed > &0 - || &self.series_fixed > &0 - } -} - -fn fix_db_entries(tx: &Transaction, book_entries: &Vec) -> Statistics { - let mut stat = Statistics { - authors_fixed: 0, - ghost_books_cleaned: 0, - drm_skipped: 0, - genres_fixed: 0, - sorting_fixed: 0, - series_fixed: 0, - }; - - for entry in book_entries { - if entry.has_drm { - stat.drm_skipped = stat.drm_skipped + 1; - continue; - } - - if let Some(epub_metadata) = epub::get_epub_metadata(&entry.filepath) { - // Fix firstauthor… - let mut firstauthors = epub_metadata - .authors - .iter() - .filter(|aut| aut.firstauthor.len() > 0) - .map(|aut| aut.firstauthor.clone()) - .collect::>(); - firstauthors.sort(); - if !firstauthors.iter().all(|s| entry.firstauthor.contains(s)) { - let mut stmt = tx - .prepare("UPDATE books_impl SET firstauthor = :file_as WHERE id = :book_id") - .unwrap(); - stmt.execute_named( - named_params![":file_as": firstauthors.join(" & "), ":book_id": entry.id], - ) - .unwrap(); - stat.authors_fixed = stat.authors_fixed + 1; - } - - // Fix first_author_letter - let first_author_letter = firstauthors - .join(" & ") - .chars() - .next() - .unwrap_or_default() - .to_string() - .to_uppercase(); - if entry.first_author_letter != first_author_letter { - let mut stmt = tx - .prepare("UPDATE books_impl SET first_author_letter = :first_letter WHERE id = :book_id") - .unwrap(); - stmt.execute_named( - named_params![":first_letter": first_author_letter,":book_id": entry.id], - ) - .unwrap(); - stat.sorting_fixed = stat.sorting_fixed + 1; - } - - // Fix author names… - let authornames = epub_metadata - .authors - .iter() - .map(|aut| aut.name.clone()) - .collect::>(); - if !authornames.iter().all(|s| entry.author.contains(s)) - || authornames.join(", ").len() != entry.author.len() - { - let mut stmt = tx - .prepare("UPDATE books_impl SET author = :authors WHERE id = :book_id") - .unwrap(); - stmt.execute_named( - named_params![":authors": authornames.join(", "), ":book_id": entry.id], - ) - .unwrap(); - stat.authors_fixed = stat.authors_fixed + 1; - } - - // Fix genre… - if entry.genre.is_empty() && epub_metadata.genre.len() > 0 { - let mut stmt = tx - .prepare(r#"INSERT INTO genres (name) SELECT :genre ON CONFLICT DO NOTHING"#) - .unwrap(); - stmt.execute_named(named_params![":genre": &epub_metadata.genre]) - .unwrap(); - let mut stmt = tx - .prepare( - r#" - INSERT INTO booktogenre (bookid, genreid) - VALUES (:bookid, - (SELECT id FROM genres WHERE name = :genre) - ) - ON CONFLICT DO NOTHING"#, - ) - .unwrap(); - stmt.execute_named( - named_params![":bookid": &entry.id, ":genre": &epub_metadata.genre], - ) - .unwrap(); - stat.genres_fixed = stat.genres_fixed + 1; - } - - // Fix series… - if !epub_metadata.series.name.is_empty() && entry.series.is_empty() { - let mut stmt = tx - .prepare("UPDATE books_impl SET series = :series, numinseries = :series_index WHERE id = :book_id") - .unwrap(); - stmt.execute_named( - named_params![":series": &epub_metadata.series.name, ":series_index": &epub_metadata.series.index, ":book_id": entry.id], - ) - .unwrap(); - stat.series_fixed = stat.series_fixed + 1; - } - } - } - - // ghost books - let num = remove_ghost_books_from_db(tx); - stat.ghost_books_cleaned = num; - - stat -} - fn main() { if cfg!(target_arch = "arm") { let res = pocketbook::dialog( @@ -273,14 +21,7 @@ fn main() { } } - let mut conn = Connection::open("/mnt/ext1/system/explorer-3/explorer-3.db").unwrap(); - - conn.execute("PRAGMA foreign_keys = 0", NO_PARAMS).unwrap(); - - let tx = conn.transaction().unwrap(); - let book_entries = get_epubs_from_database(&tx); - let stat = fix_db_entries(&tx, &book_entries); - tx.commit().unwrap(); + let stat = database::fix_db_entries(); if cfg!(target_arch = "arm") { if stat.anything_fixed() == false { From e2e246854305796a80df2d88b0b56748ba5321d4 Mon Sep 17 00:00:00 2001 From: Martin Brodbeck Date: Fri, 19 Feb 2021 13:12:28 +0100 Subject: [PATCH 17/57] more on usage and compatibility --- README.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 8839722..269ae27 100644 --- a/README.md +++ b/README.md @@ -19,13 +19,12 @@ The app tries to fix the following issues in the database This program is tested on a PocketBook - *Touch HD 3* (software version 6.1.900) - *Inkpad 3 Pro* (software version 6.0.1067) + - Known minor issue: dialog orientation is wrong - *Touch Lux 4* (software version 6.0.1118) It might work with other PocketBook devices/software versions. Please tell me if it works for you (and do make a backup of the explorer-3.db file before trying!). ## Installation and Usage -Just copy the executable file into the PocketBook's application directory. If you encounter duplicate authors or other issues (see "Features" above) in the PocketBook's library, open the applications screen and tap on the PbDbFixer icon. - --- **WARNING**: @@ -33,6 +32,11 @@ Use at your own risk. In case of doubt it is not a mistake to make a backup of t --- +Just copy the executable file into the PocketBook's application directory. If you encounter duplicate authors or other issues (see "Features" above) in the PocketBook's library, open the applications screen and tap on the PbDbFixer icon. + +If you don't see any changes: +There might be an explorer (which shows your library) process already running Then you should just stop/kill it with the task manager. Putting the device to sleep and then wake it up might also work. Afterwards, the changes should be visible to the explorer. + ## Build If you want to build PbDbFixer yourself, you have to have the cross compiler for ARM CPUs installed. On Arch Linux, the AUR package `arm-linux-gnueabi-gcc75-linaro-bin` does the job. Don't forget to tell `cargo` which compiler/linker it has to invoke. In my case, I had to edit `~/.cargo/config`: ``` From da405064d43a7f47e7fab5cb980431a7e853ced6 Mon Sep 17 00:00:00 2001 From: Martin Brodbeck Date: Fri, 19 Feb 2021 13:14:52 +0100 Subject: [PATCH 18/57] update dependencies --- Cargo.lock | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 09beae3..53e14ab 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -36,9 +36,9 @@ dependencies = [ [[package]] name = "bzip2-sys" -version = "0.1.9+1.0.8" +version = "0.1.10+1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad3b39a260062fca31f7b0b12f207e8f2590a67d32ec7d59c20484b07ea7285e" +checksum = "17fa3d1ac1ca21c5c4e36a97f3c3eb25084576f6fc47bf0139c1123434216c6c" dependencies = [ "cc", "libc", @@ -116,9 +116,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.83" +version = "0.2.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7eb0c4e9c72ee9d69b767adebc5f4788462a3b45624acd919475c92597bcaf4f" +checksum = "b7282d924be3275cec7f6756ff4121987bc6481325397dde6ba3e7802b1a8b1c" [[package]] name = "libsqlite3-sys" @@ -181,9 +181,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.8" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "991431c3519a3f36861882da93630ce66b52918dcf1b8e2fd66b397fc96f28df" +checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" dependencies = [ "proc-macro2", ] @@ -222,18 +222,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.23" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76cc616c6abf8c8928e2fdcc0dbfab37175edd8fb49a4641066ad1364fdab146" +checksum = "e0f4a65597094d4483ddaed134f409b2cb7c1beccf25201a9f73c719254fa98e" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.23" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9be73a2caec27583d0046ef3796c3794f868a5bc813db689eed00c7631275cd1" +checksum = "7765189610d8241a44529806d6fd1f2e0a08734313a35d5b3a556f92b381f3c0" dependencies = [ "proc-macro2", "quote", @@ -293,9 +293,9 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "zip" -version = "0.5.9" +version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc2896475a242c41366941faa27264df2cb935185a92e059a004d0048feb2ac5" +checksum = "5a8977234acab718eb2820494b2f96cbb16004c19dddf88b7445b27381450997" dependencies = [ "byteorder", "bzip2", From 94e1dedb1e484128a432bfa3dd27b37770be5f07 Mon Sep 17 00:00:00 2001 From: Martin Brodbeck Date: Wed, 24 Feb 2021 14:03:35 +0100 Subject: [PATCH 19/57] set foreign_key pragma correctly --- src/database.rs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/database.rs b/src/database.rs index 67ee9a4..0eb1214 100644 --- a/src/database.rs +++ b/src/database.rs @@ -43,8 +43,8 @@ fn get_epubs_from_database(tx: &Transaction) -> Vec { let prefix: String = row.get(1).unwrap(); let filename: String = row.get(2).unwrap(); let filepath = format!("{}/{}", prefix, filename); - let firstauthor: String = row.get(3).unwrap(); - let author: String = row.get(4).unwrap(); + let firstauthor: String = row.get(3).unwrap_or_default(); + let author: String = row.get(4).unwrap_or_default(); let has_drm = match prefix.as_str() { "/mnt/ext1/Digital Editions" => true, _ => false, @@ -71,8 +71,6 @@ fn get_epubs_from_database(tx: &Transaction) -> Vec { } fn remove_ghost_books_from_db(tx: &Transaction) -> usize { - tx.execute("PRAGMA foreign_keys = 0", NO_PARAMS).unwrap(); - let mut stmt = tx .prepare( r#" @@ -115,8 +113,6 @@ fn remove_ghost_books_from_db(tx: &Transaction) -> usize { ) .unwrap(); - tx.execute("PRAGMA foreign_keys = 0", NO_PARAMS).unwrap(); - num } @@ -150,6 +146,7 @@ pub fn fix_db_entries() -> Statistics { }; let mut conn = Connection::open(DATABASE_FILE).unwrap(); + conn.pragma_update(None, "foreign_keys", &0).unwrap(); let tx = conn.transaction().unwrap(); let book_entries = get_epubs_from_database(&tx); From 9baff090a8b80c3693ec661d14716670798512a6 Mon Sep 17 00:00:00 2001 From: Martin Brodbeck Date: Wed, 24 Feb 2021 14:05:03 +0100 Subject: [PATCH 20/57] push to new version --- Cargo.lock | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 53e14ab..c6c6c38 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -148,7 +148,7 @@ dependencies = [ [[package]] name = "pbdbfixer" -version = "0.7.1" +version = "0.7.2" dependencies = [ "quick-xml", "rusqlite", diff --git a/Cargo.toml b/Cargo.toml index 03226d6..ed4ea5a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pbdbfixer" -version = "0.7.1" +version = "0.7.2" authors = ["Martin Brodbeck "] edition = "2018" From a6594d4abccd01371325d8bcce5098f3680cfac4 Mon Sep 17 00:00:00 2001 From: Martin Brodbeck Date: Fri, 26 Feb 2021 13:28:29 +0100 Subject: [PATCH 21/57] Also fetch metadata from Adobe DRM encoded books --- src/database.rs | 16 ++-------------- src/epub.rs | 4 ++++ src/main.rs | 27 +++++---------------------- 3 files changed, 11 insertions(+), 36 deletions(-) diff --git a/src/database.rs b/src/database.rs index 0eb1214..4c50098 100644 --- a/src/database.rs +++ b/src/database.rs @@ -9,7 +9,6 @@ pub struct BookEntry { filepath: String, author: String, firstauthor: String, - has_drm: bool, genre: String, first_author_letter: String, series: String, @@ -45,10 +44,6 @@ fn get_epubs_from_database(tx: &Transaction) -> Vec { let filepath = format!("{}/{}", prefix, filename); let firstauthor: String = row.get(3).unwrap_or_default(); let author: String = row.get(4).unwrap_or_default(); - let has_drm = match prefix.as_str() { - "/mnt/ext1/Digital Editions" => true, - _ => false, - }; let genre: String = row.get(5).unwrap_or_default(); let first_author_letter = row.get(6).unwrap_or_default(); let series: String = row.get(7).unwrap_or_default(); @@ -58,7 +53,6 @@ fn get_epubs_from_database(tx: &Transaction) -> Vec { filepath, firstauthor, author, - has_drm, genre, first_author_letter, series, @@ -119,7 +113,6 @@ fn remove_ghost_books_from_db(tx: &Transaction) -> usize { pub struct Statistics { pub authors_fixed: i32, pub ghost_books_cleaned: usize, - pub drm_skipped: usize, pub genres_fixed: usize, pub sorting_fixed: usize, pub series_fixed: usize, @@ -139,7 +132,6 @@ pub fn fix_db_entries() -> Statistics { let mut stat = Statistics { authors_fixed: 0, ghost_books_cleaned: 0, - drm_skipped: 0, genres_fixed: 0, sorting_fixed: 0, series_fixed: 0, @@ -152,11 +144,6 @@ pub fn fix_db_entries() -> Statistics { let book_entries = get_epubs_from_database(&tx); for entry in book_entries { - if entry.has_drm { - stat.drm_skipped = stat.drm_skipped + 1; - continue; - } - if let Some(epub_metadata) = epub::get_epub_metadata(&entry.filepath) { // Fix firstauthor… let mut firstauthors = epub_metadata @@ -185,7 +172,8 @@ pub fn fix_db_entries() -> Statistics { .unwrap_or_default() .to_string() .to_uppercase(); - if entry.first_author_letter != first_author_letter { + + if first_author_letter != "\0" && (entry.first_author_letter != first_author_letter) { let mut stmt = tx .prepare("UPDATE books_impl SET first_author_letter = :first_letter WHERE id = :book_id") .unwrap(); diff --git a/src/epub.rs b/src/epub.rs index 759c91f..a5916d4 100644 --- a/src/epub.rs +++ b/src/epub.rs @@ -151,6 +151,10 @@ pub fn get_epub_metadata(filename: &str) -> Option { .unwrap() .as_str(); xml_authors.insert(curr_id.clone(), XmlAut::new()); + } else { + curr_id = "none".to_string() + xml_authors.len().to_string().as_str(); + let entry = xml_authors.entry(curr_id.clone()).or_insert(XmlAut::new()); + entry.role = "aut".to_string(); } } else { if let Some(file_as_val) = e diff --git a/src/main.rs b/src/main.rs index 79c1f8d..7374124 100644 --- a/src/main.rs +++ b/src/main.rs @@ -25,25 +25,12 @@ fn main() { if cfg!(target_arch = "arm") { if stat.anything_fixed() == false { - if stat.drm_skipped == 0 { - pocketbook::dialog( - pocketbook::Icon::Info, - "The database seems to be ok.\n\ + pocketbook::dialog( + pocketbook::Icon::Info, + "The database seems to be ok.\n\ Nothing had to be fixed.", - &["OK"], - ); - } else { - pocketbook::dialog( - pocketbook::Icon::Info, - &format!( - "The database seems to be ok.\n\ - Nothing had to be fixed.\n\ - (Books skipped (DRM): {})", - &stat.drm_skipped - ), - &["OK"], - ); - } + &["OK"], + ); } else { pocketbook::dialog( pocketbook::Icon::Info, @@ -52,13 +39,11 @@ fn main() { Sorting fixed: {}\n\ Genres fixed: {}\n\ Series fixed: {}\n\ - Books skipped (DRM): {}\n\ Books cleaned from DB: {}", &stat.authors_fixed, &stat.sorting_fixed, &stat.genres_fixed, &stat.series_fixed, - &stat.drm_skipped, &stat.ghost_books_cleaned ), &["OK"], @@ -70,13 +55,11 @@ fn main() { Sorting fixed: {}\n\ Genres fixed: {}\n\ Series fixed: {}\n\ - Books skipped (DRM): {}\n\ Books cleaned from DB: {}", &stat.authors_fixed, &stat.sorting_fixed, &stat.genres_fixed, &stat.series_fixed, - &stat.drm_skipped, &stat.ghost_books_cleaned ); } From 65007fdf50b2e0cf41cf83334e82a663649a7bb1 Mon Sep 17 00:00:00 2001 From: Martin Brodbeck Date: Fri, 26 Feb 2021 13:47:56 +0100 Subject: [PATCH 22/57] push to new version --- Cargo.lock | 6 +++--- Cargo.toml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c6c6c38..02b7a86 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -47,9 +47,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.66" +version = "1.0.67" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c0496836a84f8d0495758516b8621a622beb77c0fed418570e50764093ced48" +checksum = "e3c69b077ad434294d3ce9f1f6143a2a4b89a8a2d54ef813d85003a4fd1137fd" [[package]] name = "cfg-if" @@ -148,7 +148,7 @@ dependencies = [ [[package]] name = "pbdbfixer" -version = "0.7.2" +version = "0.8.0" dependencies = [ "quick-xml", "rusqlite", diff --git a/Cargo.toml b/Cargo.toml index ed4ea5a..465773a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pbdbfixer" -version = "0.7.2" +version = "0.8.0" authors = ["Martin Brodbeck "] edition = "2018" From ec11c16477821b79f97ef7c1d656a6eb4f8e5b39 Mon Sep 17 00:00:00 2001 From: Martin Brodbeck Date: Wed, 3 Mar 2021 13:29:35 +0100 Subject: [PATCH 23/57] build instructions improved --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 269ae27..d3e2597 100644 --- a/README.md +++ b/README.md @@ -35,10 +35,10 @@ Use at your own risk. In case of doubt it is not a mistake to make a backup of t Just copy the executable file into the PocketBook's application directory. If you encounter duplicate authors or other issues (see "Features" above) in the PocketBook's library, open the applications screen and tap on the PbDbFixer icon. If you don't see any changes: -There might be an explorer (which shows your library) process already running Then you should just stop/kill it with the task manager. Putting the device to sleep and then wake it up might also work. Afterwards, the changes should be visible to the explorer. +There might be an explorer (which shows your library) process already running. Then you should just stop/kill it with the task manager. Putting the device to sleep and then wake it up might also work. Afterwards, the changes should be visible to the explorer. ## Build -If you want to build PbDbFixer yourself, you have to have the cross compiler for ARM CPUs installed. On Arch Linux, the AUR package `arm-linux-gnueabi-gcc75-linaro-bin` does the job. Don't forget to tell `cargo` which compiler/linker it has to invoke. In my case, I had to edit `~/.cargo/config`: +If you want to build PbDbFixer yourself, make sure that you have Rust's toolchain target `arm-unknown-linux-gnueabi` as well as the GCC cross compiler for ARM CPUs installed. On Arch Linux, the AUR package `arm-linux-gnueabi-gcc75-linaro-bin` does the job. Don't forget to tell `cargo` which compiler/linker it has to invoke. In my case, I had to edit `~/.cargo/config`: ``` [target.arm-unknown-linux-gnueabi] linker = "arm-linux-gnueabi-gcc" From d6838046232331fedbefdd5c9e873eb6fcb56923 Mon Sep 17 00:00:00 2001 From: Martin Brodbeck Date: Wed, 3 Mar 2021 14:04:50 +0100 Subject: [PATCH 24/57] feedback part added --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index d3e2597..7dc68ac 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,8 @@ The app tries to fix the following issues in the database - Add missing genre if present in epub (genre and booktogenre tables) - Add missing series information (books_impl table) +The best results are achieved when metadata has been carefully maintained with Calibre. + ## Compatibility This program is tested on a PocketBook - *Touch HD 3* (software version 6.1.900) @@ -37,6 +39,9 @@ Just copy the executable file into the PocketBook's application directory. If yo If you don't see any changes: There might be an explorer (which shows your library) process already running. Then you should just stop/kill it with the task manager. Putting the device to sleep and then wake it up might also work. Afterwards, the changes should be visible to the explorer. +## Feedback +Feedback is highly appreciated. You can reach me via Matrix [@beedaddy:matrix.rustysoft.de](https://matrix.to/#/@beedaddy:matrix.rustysoft.de) or ask questions in the [PbDbFixer-Thread](https://www.e-reader-forum.de/t/pbdbfixer-noch-ein-tool-zum-korrigieren-von-metadaten.156702/) of the German *E-Reader Forum*. + ## Build If you want to build PbDbFixer yourself, make sure that you have Rust's toolchain target `arm-unknown-linux-gnueabi` as well as the GCC cross compiler for ARM CPUs installed. On Arch Linux, the AUR package `arm-linux-gnueabi-gcc75-linaro-bin` does the job. Don't forget to tell `cargo` which compiler/linker it has to invoke. In my case, I had to edit `~/.cargo/config`: ``` From ad179ac9e0dbe92639618f1b0e1170967ac6a63b Mon Sep 17 00:00:00 2001 From: Martin Brodbeck Date: Thu, 4 Mar 2021 12:57:23 +0100 Subject: [PATCH 25/57] push to new dependency versions --- Cargo.lock | 12 ++++++------ Cargo.toml | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 02b7a86..e8022d4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -116,9 +116,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.86" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7282d924be3275cec7f6756ff4121987bc6481325397dde6ba3e7802b1a8b1c" +checksum = "265d751d31d6780a3f956bb5b8022feba2d94eeee5a84ba64f4212eedca42213" [[package]] name = "libsqlite3-sys" @@ -172,9 +172,9 @@ dependencies = [ [[package]] name = "quick-xml" -version = "0.21.0" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0452695941410a58c8ce4391707ba9bad26a247173bd9886a05a5e8a8babec75" +checksum = "8533f14c8382aaad0d592c812ac3b826162128b65662331e1127b45c3d18536b" dependencies = [ "memchr", ] @@ -293,9 +293,9 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "zip" -version = "0.5.10" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a8977234acab718eb2820494b2f96cbb16004c19dddf88b7445b27381450997" +checksum = "8264fcea9b7a036a4a5103d7153e988dbc2ebbafb34f68a3c2d404b6b82d74b6" dependencies = [ "byteorder", "bzip2", diff --git a/Cargo.toml b/Cargo.toml index 465773a..57db8d2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,7 +8,7 @@ edition = "2018" [dependencies] zip = "0.5" -quick-xml = "0.21" +quick-xml = "0.22" [dependencies.rusqlite] version = "0.24" From 2fcb2ac3e702930b1f1e46b6e8bb1ab89c2569a8 Mon Sep 17 00:00:00 2001 From: Martin Brodbeck Date: Mon, 29 Mar 2021 15:19:03 +0200 Subject: [PATCH 26/57] Considering the altered database structure fixing #2 --- src/database.rs | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/src/database.rs b/src/database.rs index 4c50098..1ce6aea 100644 --- a/src/database.rs +++ b/src/database.rs @@ -86,11 +86,24 @@ fn remove_ghost_books_from_db(tx: &Transaction) -> usize { NO_PARAMS, ) .unwrap(); - tx.execute( - r#"DELETE FROM books_uids WHERE book_id NOT IN ( SELECT id FROM books_impl )"#, - NO_PARAMS, - ) - .unwrap(); + + let version: i32 = tx + .query_row(r#"SELECT id FROM version"#, NO_PARAMS, |r| r.get(0)) + .unwrap(); + if version >= 37 { + tx.execute( + r#"DELETE FROM books_fast_hashes WHERE book_id NOT IN ( SELECT id FROM books_impl )"#, + NO_PARAMS, + ) + .unwrap(); + } else { + tx.execute( + r#"DELETE FROM books_uids WHERE book_id NOT IN ( SELECT id FROM books_impl )"#, + NO_PARAMS, + ) + .unwrap(); + } + tx.execute( r#"DELETE FROM bookshelfs_books WHERE bookid NOT IN ( SELECT id FROM books_impl )"#, NO_PARAMS, From f50e5e09e6d0e809b7f6c01b3be5ea9c3735f7c4 Mon Sep 17 00:00:00 2001 From: Martin Brodbeck Date: Mon, 29 Mar 2021 15:24:28 +0200 Subject: [PATCH 27/57] firmware versions updated --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 7dc68ac..0f09fd8 100644 --- a/README.md +++ b/README.md @@ -19,10 +19,10 @@ The best results are achieved when metadata has been carefully maintained with C ## Compatibility This program is tested on a PocketBook -- *Touch HD 3* (software version 6.1.900) -- *Inkpad 3 Pro* (software version 6.0.1067) +- *Touch HD 3* (software version 6.1) +- *Inkpad 3 Pro* (software version 6.0 and 6.3 beta) - Known minor issue: dialog orientation is wrong -- *Touch Lux 4* (software version 6.0.1118) +- *Touch Lux 4* (software version 6.0) It might work with other PocketBook devices/software versions. Please tell me if it works for you (and do make a backup of the explorer-3.db file before trying!). From ef7710cca62906dd3d94803c49822b92f2793312 Mon Sep 17 00:00:00 2001 From: Martin Brodbeck Date: Mon, 29 Mar 2021 15:25:10 +0200 Subject: [PATCH 28/57] Calibre emphasized --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0f09fd8..c21e920 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ The app tries to fix the following issues in the database - Add missing genre if present in epub (genre and booktogenre tables) - Add missing series information (books_impl table) -The best results are achieved when metadata has been carefully maintained with Calibre. +The best results are achieved when metadata has been carefully maintained with **Calibre**. ## Compatibility This program is tested on a PocketBook From 3a794874dcd9dcd32fe8799a968b807ec7236393 Mon Sep 17 00:00:00 2001 From: Martin Brodbeck Date: Tue, 27 Apr 2021 07:51:12 +0200 Subject: [PATCH 29/57] software versions updated --- README.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index c21e920..7a511e0 100644 --- a/README.md +++ b/README.md @@ -20,9 +20,8 @@ The best results are achieved when metadata has been carefully maintained with * ## Compatibility This program is tested on a PocketBook - *Touch HD 3* (software version 6.1) -- *Inkpad 3 Pro* (software version 6.0 and 6.3 beta) - - Known minor issue: dialog orientation is wrong -- *Touch Lux 4* (software version 6.0) +- *Inkpad 3 Pro* (software version 6.3) +- *Touch Lux 4* (software version 6.3) It might work with other PocketBook devices/software versions. Please tell me if it works for you (and do make a backup of the explorer-3.db file before trying!). From 995bc5e3edc22602b382cdd94e7679023d9eeee5 Mon Sep 17 00:00:00 2001 From: Martin Brodbeck Date: Wed, 26 May 2021 13:29:43 +0200 Subject: [PATCH 30/57] updated to rusqlite 0.25 --- Cargo.lock | 50 ++++++++++++++++++++++++++++++++++++++----------- Cargo.toml | 2 +- src/database.rs | 32 +++++++++++++++---------------- 3 files changed, 56 insertions(+), 28 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e8022d4..ced2d54 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8,9 +8,14 @@ checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234" [[package]] name = "ahash" -version = "0.4.7" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "739f4a8db6605981345c5654f3a85b056ce52f37a39d34da03f25bf2151ea16e" +checksum = "43bb833f0bf979d8475d38fbf09ed3b8a55e1885fe93ad3f93239fc6a4f17b98" +dependencies = [ + "getrandom", + "once_cell", + "version_check", +] [[package]] name = "bitflags" @@ -97,19 +102,30 @@ dependencies = [ ] [[package]] -name = "hashbrown" -version = "0.9.1" +name = "getrandom" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04" +checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" +dependencies = [ + "cfg-if 1.0.0", + "libc", + "wasi", +] + +[[package]] +name = "hashbrown" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" dependencies = [ "ahash", ] [[package]] name = "hashlink" -version = "0.6.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d99cf782f0dc4372d26846bec3de7804ceb5df083c2d4462c0b8d2330e894fa8" +checksum = "7249a3129cbc1ffccd74857f81464a323a152173cdb134e0fd81bc803b29facf" dependencies = [ "hashbrown", ] @@ -122,9 +138,9 @@ checksum = "265d751d31d6780a3f956bb5b8022feba2d94eeee5a84ba64f4212eedca42213" [[package]] name = "libsqlite3-sys" -version = "0.20.1" +version = "0.22.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64d31059f22935e6c31830db5249ba2b7ecd54fd73a9909286f0a67aa55c2fbd" +checksum = "290b64917f8b0cb885d9de0f9959fe1f775d7fa12f1da2db9001c1c8ab60f89d" dependencies = [ "cc", "pkg-config", @@ -146,6 +162,12 @@ dependencies = [ "adler32", ] +[[package]] +name = "once_cell" +version = "1.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af8b08b04175473088b46763e51ee54da5f9a164bc162f615b91bc179dbf15a3" + [[package]] name = "pbdbfixer" version = "0.8.0" @@ -190,9 +212,9 @@ dependencies = [ [[package]] name = "rusqlite" -version = "0.24.2" +version = "0.25.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5f38ee71cbab2c827ec0ac24e76f82eca723cee92c509a65f67dee393c25112" +checksum = "57adcf67c8faaf96f3248c2a7b419a0dbc52ebe36ba83dd57fe83827c1ea4eb3" dependencies = [ "bitflags", "fallible-iterator", @@ -263,6 +285,12 @@ version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b00bca6106a5e23f3eee943593759b7fcddb00554332e856d990c893966879fb" +[[package]] +name = "version_check" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" + [[package]] name = "wasi" version = "0.10.0+wasi-snapshot-preview1" diff --git a/Cargo.toml b/Cargo.toml index 57db8d2..f6143dd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,5 +11,5 @@ zip = "0.5" quick-xml = "0.22" [dependencies.rusqlite] -version = "0.24" +version = "0.25" features = ["bundled"] diff --git a/src/database.rs b/src/database.rs index 1ce6aea..a4149ea 100644 --- a/src/database.rs +++ b/src/database.rs @@ -1,4 +1,4 @@ -use rusqlite::{named_params, Connection, Transaction, NO_PARAMS}; +use rusqlite::{named_params, Connection, Transaction}; use crate::epub; @@ -35,7 +35,7 @@ fn get_epubs_from_database(tx: &Transaction) -> Vec { ) .unwrap(); - let mut rows = stmt.query(NO_PARAMS).unwrap(); + let mut rows = stmt.query([]).unwrap(); while let Some(row) = rows.next().unwrap() { let book_id: i32 = row.get(0).unwrap(); @@ -79,44 +79,44 @@ fn remove_ghost_books_from_db(tx: &Transaction) -> usize { ) .unwrap(); - let num = stmt.execute(NO_PARAMS).unwrap(); + let num = stmt.execute([]).unwrap(); tx.execute( r#"DELETE FROM books_settings WHERE bookid NOT IN ( SELECT id FROM books_impl )"#, - NO_PARAMS, + [], ) .unwrap(); let version: i32 = tx - .query_row(r#"SELECT id FROM version"#, NO_PARAMS, |r| r.get(0)) + .query_row(r#"SELECT id FROM version"#, [], |r| r.get(0)) .unwrap(); if version >= 37 { tx.execute( r#"DELETE FROM books_fast_hashes WHERE book_id NOT IN ( SELECT id FROM books_impl )"#, - NO_PARAMS, + [], ) .unwrap(); } else { tx.execute( r#"DELETE FROM books_uids WHERE book_id NOT IN ( SELECT id FROM books_impl )"#, - NO_PARAMS, + [], ) .unwrap(); } tx.execute( r#"DELETE FROM bookshelfs_books WHERE bookid NOT IN ( SELECT id FROM books_impl )"#, - NO_PARAMS, + [], ) .unwrap(); tx.execute( r#"DELETE FROM booktogenre WHERE bookid NOT IN ( SELECT id FROM books_impl )"#, - NO_PARAMS, + [], ) .unwrap(); tx.execute( r#"DELETE FROM social WHERE bookid NOT IN ( SELECT id FROM books_impl )"#, - NO_PARAMS, + [], ) .unwrap(); @@ -170,7 +170,7 @@ pub fn fix_db_entries() -> Statistics { let mut stmt = tx .prepare("UPDATE books_impl SET firstauthor = :file_as WHERE id = :book_id") .unwrap(); - stmt.execute_named( + stmt.execute( named_params![":file_as": firstauthors.join(" & "), ":book_id": entry.id], ) .unwrap(); @@ -190,7 +190,7 @@ pub fn fix_db_entries() -> Statistics { let mut stmt = tx .prepare("UPDATE books_impl SET first_author_letter = :first_letter WHERE id = :book_id") .unwrap(); - stmt.execute_named( + stmt.execute( named_params![":first_letter": first_author_letter,":book_id": entry.id], ) .unwrap(); @@ -209,7 +209,7 @@ pub fn fix_db_entries() -> Statistics { let mut stmt = tx .prepare("UPDATE books_impl SET author = :authors WHERE id = :book_id") .unwrap(); - stmt.execute_named( + stmt.execute( named_params![":authors": authornames.join(", "), ":book_id": entry.id], ) .unwrap(); @@ -221,7 +221,7 @@ pub fn fix_db_entries() -> Statistics { let mut stmt = tx .prepare(r#"INSERT INTO genres (name) SELECT :genre ON CONFLICT DO NOTHING"#) .unwrap(); - stmt.execute_named(named_params![":genre": &epub_metadata.genre]) + stmt.execute(named_params![":genre": &epub_metadata.genre]) .unwrap(); let mut stmt = tx .prepare( @@ -233,7 +233,7 @@ pub fn fix_db_entries() -> Statistics { ON CONFLICT DO NOTHING"#, ) .unwrap(); - stmt.execute_named( + stmt.execute( named_params![":bookid": &entry.id, ":genre": &epub_metadata.genre], ) .unwrap(); @@ -245,7 +245,7 @@ pub fn fix_db_entries() -> Statistics { let mut stmt = tx .prepare("UPDATE books_impl SET series = :series, numinseries = :series_index WHERE id = :book_id") .unwrap(); - stmt.execute_named( + stmt.execute( named_params![":series": &epub_metadata.series.name, ":series_index": &epub_metadata.series.index, ":book_id": entry.id], ) .unwrap(); From 49853f9d2f31184e673d51f40f65de2850389f43 Mon Sep 17 00:00:00 2001 From: Martin Brodbeck Date: Fri, 6 Aug 2021 11:00:16 +0200 Subject: [PATCH 31/57] Do not rely on database column ext. Since firmware version 6.4 seems to ignore this column, we also look at the file name suffix. --- src/database.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/database.rs b/src/database.rs index a4149ea..596b397 100644 --- a/src/database.rs +++ b/src/database.rs @@ -30,7 +30,7 @@ fn get_epubs_from_database(tx: &Transaction) -> Vec { ON books.id = btg.bookid LEFT OUTER JOIN genres ON genres.id = btg.genreid - WHERE files.storageid = 1 AND books.ext = 'epub' + WHERE files.storageid = 1 AND (books.ext = 'epub' OR files.filename LIKE '%.epub') ORDER BY books.id"#, ) .unwrap(); From 8ef3238ac3fc90ac7c7cd4d4a0527e9bacdfa4ad Mon Sep 17 00:00:00 2001 From: Martin Brodbeck Date: Fri, 6 Aug 2021 11:03:10 +0200 Subject: [PATCH 32/57] Push to new version. --- Cargo.lock | 4 +++- Cargo.toml | 2 +- README.md | 4 ++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ced2d54..e25300f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,5 +1,7 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +version = 3 + [[package]] name = "adler32" version = "1.2.0" @@ -170,7 +172,7 @@ checksum = "af8b08b04175473088b46763e51ee54da5f9a164bc162f615b91bc179dbf15a3" [[package]] name = "pbdbfixer" -version = "0.8.0" +version = "0.8.2" dependencies = [ "quick-xml", "rusqlite", diff --git a/Cargo.toml b/Cargo.toml index f6143dd..a3db7aa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pbdbfixer" -version = "0.8.0" +version = "0.8.2" authors = ["Martin Brodbeck "] edition = "2018" diff --git a/README.md b/README.md index 7a511e0..5d2f018 100644 --- a/README.md +++ b/README.md @@ -19,8 +19,8 @@ The best results are achieved when metadata has been carefully maintained with * ## Compatibility This program is tested on a PocketBook -- *Touch HD 3* (software version 6.1) -- *Inkpad 3 Pro* (software version 6.3) +- *Touch HD 3* (software version 6.4) +- *Inkpad 3 Pro* (software version 6.4) - *Touch Lux 4* (software version 6.3) It might work with other PocketBook devices/software versions. Please tell me if it works for you (and do make a backup of the explorer-3.db file before trying!). From 56624427d55ca6e2456004e6f203600e42202a51 Mon Sep 17 00:00:00 2001 From: Martin Brodbeck Date: Fri, 6 Aug 2021 15:10:55 +0200 Subject: [PATCH 33/57] Adapted to the new database schema. --- src/database.rs | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/src/database.rs b/src/database.rs index 596b397..45d9771 100644 --- a/src/database.rs +++ b/src/database.rs @@ -17,9 +17,17 @@ pub struct BookEntry { fn get_epubs_from_database(tx: &Transaction) -> Vec { let mut book_entries = Vec::new(); - let mut stmt = tx - .prepare( - r#" + let version: i32 = tx + .query_row(r#"SELECT id FROM version"#, [], |r| r.get(0)) + .unwrap(); + + let books_or_files = match version { + x if x >= 38 => "files", + _ => "books", + }; + + let stmt_str = format!( + r#" SELECT books.id, folders.name, files.filename, books.firstauthor, books.author, genres.name, first_author_letter, series FROM books_impl books JOIN files @@ -30,10 +38,12 @@ fn get_epubs_from_database(tx: &Transaction) -> Vec { ON books.id = btg.bookid LEFT OUTER JOIN genres ON genres.id = btg.genreid - WHERE files.storageid = 1 AND (books.ext = 'epub' OR files.filename LIKE '%.epub') + WHERE files.storageid = 1 AND {}.ext = 'epub' ORDER BY books.id"#, - ) - .unwrap(); + &books_or_files + ); + + let mut stmt = tx.prepare(&stmt_str).unwrap(); let mut rows = stmt.query([]).unwrap(); @@ -233,10 +243,8 @@ pub fn fix_db_entries() -> Statistics { ON CONFLICT DO NOTHING"#, ) .unwrap(); - stmt.execute( - named_params![":bookid": &entry.id, ":genre": &epub_metadata.genre], - ) - .unwrap(); + stmt.execute(named_params![":bookid": &entry.id, ":genre": &epub_metadata.genre]) + .unwrap(); stat.genres_fixed = stat.genres_fixed + 1; } From 6db590f33342cc89ff91ca66e5e60868c995d14c Mon Sep 17 00:00:00 2001 From: Martin Brodbeck Date: Fri, 6 Aug 2021 15:14:50 +0200 Subject: [PATCH 34/57] Push to new version. --- Cargo.lock | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e25300f..d696a77 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -172,7 +172,7 @@ checksum = "af8b08b04175473088b46763e51ee54da5f9a164bc162f615b91bc179dbf15a3" [[package]] name = "pbdbfixer" -version = "0.8.2" +version = "0.8.3" dependencies = [ "quick-xml", "rusqlite", diff --git a/Cargo.toml b/Cargo.toml index a3db7aa..8908d78 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pbdbfixer" -version = "0.8.2" +version = "0.8.3" authors = ["Martin Brodbeck "] edition = "2018" From 5af608f45b8b1761e8f7d86ff28338589697d15f Mon Sep 17 00:00:00 2001 From: Martin Brodbeck Date: Mon, 25 Oct 2021 08:40:50 +0200 Subject: [PATCH 35/57] =?UTF-8?q?Rust=20edition=202018=20=E2=86=92=202021?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 8908d78..73c0dd5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,7 @@ name = "pbdbfixer" version = "0.8.3" authors = ["Martin Brodbeck "] -edition = "2018" +edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html From b30209c62f3c87bcd11fb380683f155cfebabfae Mon Sep 17 00:00:00 2001 From: Martin Brodbeck Date: Tue, 8 Feb 2022 12:36:31 +0100 Subject: [PATCH 36/57] Tested versions 6.4 -> 6.5 --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 5d2f018..31d3c8e 100644 --- a/README.md +++ b/README.md @@ -19,8 +19,8 @@ The best results are achieved when metadata has been carefully maintained with * ## Compatibility This program is tested on a PocketBook -- *Touch HD 3* (software version 6.4) -- *Inkpad 3 Pro* (software version 6.4) +- *Touch HD 3* (software version 6.5) +- *Inkpad 3 Pro* (software version 6.5) - *Touch Lux 4* (software version 6.3) It might work with other PocketBook devices/software versions. Please tell me if it works for you (and do make a backup of the explorer-3.db file before trying!). From acdeb3d19aed57a0088ee91f02eb7daa26c08471 Mon Sep 17 00:00:00 2001 From: Martin Brodbeck Date: Tue, 12 Jul 2022 13:21:59 +0200 Subject: [PATCH 37/57] dependencies updated --- Cargo.lock | 424 ++++++++++++++++++++++++++++++++++++----------------- Cargo.toml | 6 +- 2 files changed, 292 insertions(+), 138 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d696a77..6c4bf4c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3,16 +3,28 @@ version = 3 [[package]] -name = "adler32" -version = "1.2.0" +name = "adler" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "aes" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e8b47f52ea9bae42228d07ec09eb676433d7c4ed1ebdf0f1d1c29ed446f1ab8" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", + "opaque-debug", +] [[package]] name = "ahash" -version = "0.7.4" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43bb833f0bf979d8475d38fbf09ed3b8a55e1885fe93ad3f93239fc6a4f17b98" +checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" dependencies = [ "getrandom", "once_cell", @@ -20,22 +32,37 @@ dependencies = [ ] [[package]] -name = "bitflags" -version = "1.2.1" +name = "base64ct" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" +checksum = "8a32fd6af2b5827bce66c29053ba0e7c42b9dcab01835835058558c10851a46b" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "block-buffer" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf7fe51849ea569fd452f37822f606a5cabb684dc918707a0193fd4664ff324" +dependencies = [ + "generic-array", +] [[package]] name = "byteorder" -version = "1.4.2" +version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae44d1a3d5a19df61dd0c8beb138458ac2a53a7ac09eba97d55592540004306b" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "bzip2" -version = "0.3.3" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42b7c3cbf0fa9c1b82308d57191728ca0256cb821220f4e2fd410a72ade26e3b" +checksum = "6afcd980b5f3a45017c57e57a2fcccbb351cc43a356ce117ef760ef8052b89b0" dependencies = [ "bzip2-sys", "libc", @@ -43,9 +70,9 @@ dependencies = [ [[package]] name = "bzip2-sys" -version = "0.1.10+1.0.8" +version = "0.1.11+1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17fa3d1ac1ca21c5c4e36a97f3c3eb25084576f6fc47bf0139c1123434216c6c" +checksum = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc" dependencies = [ "cc", "libc", @@ -54,15 +81,12 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.67" +version = "1.0.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3c69b077ad434294d3ce9f1f6143a2a4b89a8a2d54ef813d85003a4fd1137fd" - -[[package]] -name = "cfg-if" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" +checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" +dependencies = [ + "jobserver", +] [[package]] name = "cfg-if" @@ -71,12 +95,67 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] -name = "crc32fast" -version = "1.2.1" +name = "cipher" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81156fece84ab6a9f2afdb109ce3ae577e42b1228441eded99bd77f627953b1a" +checksum = "7ee52072ec15386f770805afd189a01c8841be8696bed250fa2f13c4c0d6dfb7" dependencies = [ - "cfg-if 1.0.0", + "generic-array", +] + +[[package]] +name = "constant_time_eq" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" + +[[package]] +name = "cpufeatures" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59a6001667ab124aebae2a495118e11d30984c3a653e99d86d58971708cf5e4b" +dependencies = [ + "libc", +] + +[[package]] +name = "crc32fast" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d82ee10ce34d7bc12c2122495e7593a9c41347ecdd64185af4ecf72cb1a7f83" +dependencies = [ + "cfg-if", + "once_cell", +] + +[[package]] +name = "crypto-common" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ccfd8c0ee4cce11e45b3fd6f9d5e69e0cc62912aa6a0cb1bf4617b0eba5a12f" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "digest" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2fb860ca6fafa5552fb6d0e816a69c8e49f0908bf524e30a90d97c85892d506" +dependencies = [ + "block-buffer", + "crypto-common", + "subtle", ] [[package]] @@ -93,23 +172,31 @@ checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a" [[package]] name = "flate2" -version = "1.0.14" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cfff41391129e0a856d6d822600b8d71179d46879e310417eb9c762eb178b42" +checksum = "f82b0f4c27ad9f8bfd1f3208d882da2b09c301bc1c828fd3a00d0216d2fbbff6" dependencies = [ - "cfg-if 0.1.10", "crc32fast", - "libc", "miniz_oxide", ] [[package]] -name = "getrandom" -version = "0.2.3" +name = "generic-array" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" +checksum = "fd48d33ec7f05fbfa152300fdad764757cbded343c1aa1cff2fbaf4134851803" dependencies = [ - "cfg-if 1.0.0", + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6" +dependencies = [ + "cfg-if", "libc", "wasi", ] @@ -133,16 +220,40 @@ dependencies = [ ] [[package]] -name = "libc" -version = "0.2.87" +name = "hmac" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "265d751d31d6780a3f956bb5b8022feba2d94eeee5a84ba64f4212eedca42213" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + +[[package]] +name = "itoa" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d" + +[[package]] +name = "jobserver" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af25a77299a7f711a01975c35a6a424eb6862092cc2d6c72c4ed6cbc56dfc1fa" +dependencies = [ + "libc", +] + +[[package]] +name = "libc" +version = "0.2.126" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" [[package]] name = "libsqlite3-sys" -version = "0.22.2" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290b64917f8b0cb885d9de0f9959fe1f775d7fa12f1da2db9001c1c8ab60f89d" +checksum = "898745e570c7d0453cc1fbc4a701eb6c662ed54e8fec8b7d14be137ebeeb9d14" dependencies = [ "cc", "pkg-config", @@ -151,24 +262,50 @@ dependencies = [ [[package]] name = "memchr" -version = "2.3.4" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" [[package]] name = "miniz_oxide" -version = "0.3.7" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "791daaae1ed6889560f8c4359194f56648355540573244a5448a83ba1ecc7435" +checksum = "6f5c75688da582b8ffc1f1799e9db273f32133c49e048f614d22ec3256773ccc" dependencies = [ - "adler32", + "adler", +] + +[[package]] +name = "num_threads" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2819ce041d2ee131036f4fc9d6ae7ae125a3a40e97ba64d04fe799ad9dabbb44" +dependencies = [ + "libc", ] [[package]] name = "once_cell" -version = "1.7.2" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af8b08b04175473088b46763e51ee54da5f9a164bc162f615b91bc179dbf15a3" +checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1" + +[[package]] +name = "opaque-debug" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" + +[[package]] +name = "password-hash" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d791538a6dcc1e7cb7fe6f6b58aca40e7f79403c45b2bc274008b5e647af1d8" +dependencies = [ + "base64ct", + "rand_core", + "subtle", +] [[package]] name = "pbdbfixer" @@ -180,43 +317,43 @@ dependencies = [ ] [[package]] -name = "pkg-config" -version = "0.3.19" +name = "pbkdf2" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c" - -[[package]] -name = "proc-macro2" -version = "1.0.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" +checksum = "271779f35b581956db91a3e55737327a03aa051e90b1c47aeb189508533adfd7" dependencies = [ - "unicode-xid", + "digest", + "hmac", + "password-hash", + "sha2", ] [[package]] -name = "quick-xml" -version = "0.22.0" +name = "pkg-config" +version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8533f14c8382aaad0d592c812ac3b826162128b65662331e1127b45c3d18536b" +checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae" + +[[package]] +name = "quick-xml" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9279fbdacaad3baf559d8cabe0acc3d06e30ea14931af31af79578ac0946decc" dependencies = [ "memchr", ] [[package]] -name = "quote" -version = "1.0.9" +name = "rand_core" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" -dependencies = [ - "proc-macro2", -] +checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" [[package]] name = "rusqlite" -version = "0.25.3" +version = "0.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57adcf67c8faaf96f3248c2a7b419a0dbc52ebe36ba83dd57fe83827c1ea4eb3" +checksum = "85127183a999f7db96d1a976a309eebbfb6ea3b0b400ddd8340190129de6eb7a" dependencies = [ "bitflags", "fallible-iterator", @@ -227,110 +364,127 @@ dependencies = [ "smallvec", ] +[[package]] +name = "sha1" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c77f4e7f65455545c2153c1253d25056825e77ee2533f0e41deb65a93a34852f" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sha2" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55deaec60f81eefe3cce0dc50bda92d6d8e88f2a27df7c5033b42afeb1ed2676" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + [[package]] name = "smallvec" -version = "1.6.1" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e" +checksum = "2fd0db749597d91ff862fd1d55ea87f7855a744a8425a64695b6fca237d1dad1" [[package]] -name = "syn" -version = "1.0.60" +name = "subtle" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c700597eca8a5a762beb35753ef6b94df201c81cca676604f547495a0d7f0081" -dependencies = [ - "proc-macro2", - "quote", - "unicode-xid", -] - -[[package]] -name = "thiserror" -version = "1.0.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0f4a65597094d4483ddaed134f409b2cb7c1beccf25201a9f73c719254fa98e" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7765189610d8241a44529806d6fd1f2e0a08734313a35d5b3a556f92b381f3c0" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] +checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" [[package]] name = "time" -version = "0.1.44" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" +checksum = "72c91f41dcb2f096c05f0873d667dceec1087ce5bcf984ec8ffb19acddbb3217" dependencies = [ + "itoa", "libc", - "wasi", - "winapi", + "num_threads", + "time-macros", ] [[package]] -name = "unicode-xid" -version = "0.2.1" +name = "time-macros" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" +checksum = "42657b1a6f4d817cda8e7a0ace261fe0cc946cf3a80314390b22cc61ae080792" + +[[package]] +name = "typenum" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" [[package]] name = "vcpkg" -version = "0.2.11" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b00bca6106a5e23f3eee943593759b7fcddb00554332e856d990c893966879fb" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" [[package]] name = "version_check" -version = "0.9.3" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "wasi" -version = "0.10.0+wasi-snapshot-preview1" +version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "zip" -version = "0.5.11" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8264fcea9b7a036a4a5103d7153e988dbc2ebbafb34f68a3c2d404b6b82d74b6" +checksum = "bf225bcf73bb52cbb496e70475c7bd7a3f769df699c0020f6c7bd9a96dcf0b8d" dependencies = [ + "aes", "byteorder", "bzip2", + "constant_time_eq", "crc32fast", + "crossbeam-utils", "flate2", - "thiserror", + "hmac", + "pbkdf2", + "sha1", "time", + "zstd", +] + +[[package]] +name = "zstd" +version = "0.10.2+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f4a6bd64f22b5e3e94b4e238669ff9f10815c27a5180108b849d24174a83847" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "4.1.6+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94b61c51bb270702d6167b8ce67340d2754b088d0c091b06e593aa772c3ee9bb" +dependencies = [ + "libc", + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "1.6.3+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc49afa5c8d634e75761feda8c592051e7eeb4683ba827211eb0d731d3402ea8" +dependencies = [ + "cc", + "libc", ] diff --git a/Cargo.toml b/Cargo.toml index 73c0dd5..de4df26 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,9 +7,9 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -zip = "0.5" -quick-xml = "0.22" +zip = "0.6" +quick-xml = "0.23" [dependencies.rusqlite] -version = "0.25" +version = "0.27" features = ["bundled"] From aa0f1f6999a142ceeae8a91a5d9a756c3b5bf38a Mon Sep 17 00:00:00 2001 From: Martin Brodbeck Date: Wed, 14 Jun 2023 10:32:03 +0200 Subject: [PATCH 38/57] Tested firmware versions updated --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 31d3c8e..74717ef 100644 --- a/README.md +++ b/README.md @@ -19,9 +19,9 @@ The best results are achieved when metadata has been carefully maintained with * ## Compatibility This program is tested on a PocketBook -- *Touch HD 3* (software version 6.5) -- *Inkpad 3 Pro* (software version 6.5) -- *Touch Lux 4* (software version 6.3) +- *Touch Lux 4* (software version 6.5) +- *Touch HD 3* (software version 6.7) +- *InkPad 4* (software version 6.8) It might work with other PocketBook devices/software versions. Please tell me if it works for you (and do make a backup of the explorer-3.db file before trying!). From 9f0484f4a850e1bd8a6f5d4d59bc1658211abb8d Mon Sep 17 00:00:00 2001 From: Martin Brodbeck Date: Wed, 10 Jan 2024 10:53:40 +0100 Subject: [PATCH 39/57] User feedback added --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 74717ef..f023c87 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,8 @@ The best results are achieved when metadata has been carefully maintained with * This program is tested on a PocketBook - *Touch Lux 4* (software version 6.5) - *Touch HD 3* (software version 6.7) +- *Era* (software version 6.8) [^1] +- *InkPad 3 Pro* (software version 6.8) [^1] - *InkPad 4* (software version 6.8) It might work with other PocketBook devices/software versions. Please tell me if it works for you (and do make a backup of the explorer-3.db file before trying!). @@ -51,3 +53,5 @@ Now you can easily compile the stuff by invoking ``` cargo build --release --target=arm-unknown-linux-gnueabi ``` + +[^1]: User feedback \ No newline at end of file From e1d0ac3200e0bdf77169cafffa37a83bc14c4189 Mon Sep 17 00:00:00 2001 From: Martin Brodbeck Date: Mon, 15 Apr 2024 11:11:58 +0200 Subject: [PATCH 40/57] README.md aktualisiert --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index f023c87..31395b3 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,7 @@ This program is tested on a PocketBook - *Era* (software version 6.8) [^1] - *InkPad 3 Pro* (software version 6.8) [^1] - *InkPad 4* (software version 6.8) +- *Verse Pro* (software version 6.8) [^1] It might work with other PocketBook devices/software versions. Please tell me if it works for you (and do make a backup of the explorer-3.db file before trying!). From fb30301da80091c001127b96e0d5f83379491e2a Mon Sep 17 00:00:00 2001 From: Martin Brodbeck Date: Mon, 13 May 2024 07:44:34 +0200 Subject: [PATCH 41/57] note added --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 31395b3..7b88bb5 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,8 @@ This program is tested on a PocketBook It might work with other PocketBook devices/software versions. Please tell me if it works for you (and do make a backup of the explorer-3.db file before trying!). +**Please note:** As I do not currently own a PocketBook device, I am unfortunately unable to react to changes in the database structure. Perhaps you can send me your `explorer-3.db` so that I can take a look at the changes. Just get in touch with me. + ## Installation and Usage --- **WARNING**: From 339e8534ec6ba1130dba24e7b8ad5eca9770b47c Mon Sep 17 00:00:00 2001 From: martin Date: Fri, 17 May 2024 08:33:28 +0200 Subject: [PATCH 42/57] README.md aktualisiert --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 7b88bb5..97f8c9f 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ This program is tested on a PocketBook It might work with other PocketBook devices/software versions. Please tell me if it works for you (and do make a backup of the explorer-3.db file before trying!). -**Please note:** As I do not currently own a PocketBook device, I am unfortunately unable to react to changes in the database structure. Perhaps you can send me your `explorer-3.db` so that I can take a look at the changes. Just get in touch with me. +**Please note:** As I do not currently own a PocketBook device, I am unfortunately unable to react to changes in the database structure. Perhaps you can send me your `explorer-3.db` so that I can take a look at the changes. Just get in touch with me. ## Installation and Usage --- From 4c425dbddfe84d3b760420f41b30b7922d308a4b Mon Sep 17 00:00:00 2001 From: martin Date: Mon, 12 Aug 2024 12:07:13 +0200 Subject: [PATCH 43/57] Add Debian as an example. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 97f8c9f..61d483c 100644 --- a/README.md +++ b/README.md @@ -47,7 +47,7 @@ There might be an explorer (which shows your library) process already running. T Feedback is highly appreciated. You can reach me via Matrix [@beedaddy:matrix.rustysoft.de](https://matrix.to/#/@beedaddy:matrix.rustysoft.de) or ask questions in the [PbDbFixer-Thread](https://www.e-reader-forum.de/t/pbdbfixer-noch-ein-tool-zum-korrigieren-von-metadaten.156702/) of the German *E-Reader Forum*. ## Build -If you want to build PbDbFixer yourself, make sure that you have Rust's toolchain target `arm-unknown-linux-gnueabi` as well as the GCC cross compiler for ARM CPUs installed. On Arch Linux, the AUR package `arm-linux-gnueabi-gcc75-linaro-bin` does the job. Don't forget to tell `cargo` which compiler/linker it has to invoke. In my case, I had to edit `~/.cargo/config`: +If you want to build PbDbFixer yourself, make sure that you have Rust's toolchain target `arm-unknown-linux-gnueabi` as well as the GCC cross compiler for ARM CPUs installed. On **Arch** Linux, the AUR package `arm-linux-gnueabi-gcc75-linaro-bin` does the job. On **Debian**, you have to install the package `gcc-arm-linux-gnueabi`. Don't forget to tell `cargo` which compiler/linker it has to invoke. In my case, I had to edit `~/.cargo/config`: ``` [target.arm-unknown-linux-gnueabi] linker = "arm-linux-gnueabi-gcc" From d5c2b277dc2f84eba0488a802511e090375dc8c5 Mon Sep 17 00:00:00 2001 From: Martin Brodbeck Date: Tue, 5 Nov 2024 13:00:08 +0100 Subject: [PATCH 44/57] cargo update --- Cargo.lock | 293 +++++++++++++++++++++++++++++++++-------------------- 1 file changed, 181 insertions(+), 112 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6c4bf4c..d297240 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3,28 +3,27 @@ version = 3 [[package]] -name = "adler" -version = "1.0.2" +name = "adler2" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" [[package]] name = "aes" -version = "0.7.5" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e8b47f52ea9bae42228d07ec09eb676433d7c4ed1ebdf0f1d1c29ed446f1ab8" +checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" dependencies = [ "cfg-if", "cipher", "cpufeatures", - "opaque-debug", ] [[package]] name = "ahash" -version = "0.7.6" +version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" +checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" dependencies = [ "getrandom", "once_cell", @@ -33,9 +32,9 @@ dependencies = [ [[package]] name = "base64ct" -version = "1.0.1" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a32fd6af2b5827bce66c29053ba0e7c42b9dcab01835835058558c10851a46b" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" [[package]] name = "bitflags" @@ -45,24 +44,24 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "block-buffer" -version = "0.10.2" +version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bf7fe51849ea569fd452f37822f606a5cabb684dc918707a0193fd4664ff324" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" dependencies = [ "generic-array", ] [[package]] name = "byteorder" -version = "1.4.3" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bzip2" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6afcd980b5f3a45017c57e57a2fcccbb351cc43a356ce117ef760ef8052b89b0" +checksum = "bdb116a6ef3f6c3698828873ad02c3014b3c85cadb88496095628e3ef1e347f8" dependencies = [ "bzip2-sys", "libc", @@ -81,11 +80,13 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.73" +version = "1.1.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" +checksum = "67b9470d453346108f93a59222a9a1a5724db32d0a4727b7ab7ace4b4d822dc9" dependencies = [ "jobserver", + "libc", + "shlex", ] [[package]] @@ -96,11 +97,12 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "cipher" -version = "0.3.0" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ee52072ec15386f770805afd189a01c8841be8696bed250fa2f13c4c0d6dfb7" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" dependencies = [ - "generic-array", + "crypto-common", + "inout", ] [[package]] @@ -111,47 +113,52 @@ checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" [[package]] name = "cpufeatures" -version = "0.2.2" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59a6001667ab124aebae2a495118e11d30984c3a653e99d86d58971708cf5e4b" +checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0" dependencies = [ "libc", ] [[package]] name = "crc32fast" -version = "1.3.2" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" dependencies = [ "cfg-if", ] [[package]] name = "crossbeam-utils" -version = "0.8.10" +version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d82ee10ce34d7bc12c2122495e7593a9c41347ecdd64185af4ecf72cb1a7f83" -dependencies = [ - "cfg-if", - "once_cell", -] +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" [[package]] name = "crypto-common" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ccfd8c0ee4cce11e45b3fd6f9d5e69e0cc62912aa6a0cb1bf4617b0eba5a12f" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ "generic-array", "typenum", ] [[package]] -name = "digest" -version = "0.10.3" +name = "deranged" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2fb860ca6fafa5552fb6d0e816a69c8e49f0908bf524e30a90d97c85892d506" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +dependencies = [ + "powerfmt", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer", "crypto-common", @@ -172,9 +179,9 @@ checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a" [[package]] name = "flate2" -version = "1.0.24" +version = "1.0.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f82b0f4c27ad9f8bfd1f3208d882da2b09c301bc1c828fd3a00d0216d2fbbff6" +checksum = "a1b589b4dc103969ad3cf85c950899926ec64300a1a46d76c03a6072957036f0" dependencies = [ "crc32fast", "miniz_oxide", @@ -182,9 +189,9 @@ dependencies = [ [[package]] name = "generic-array" -version = "0.14.5" +version = "0.14.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd48d33ec7f05fbfa152300fdad764757cbded343c1aa1cff2fbaf4134851803" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ "typenum", "version_check", @@ -192,9 +199,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.7" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", "libc", @@ -229,25 +236,28 @@ dependencies = [ ] [[package]] -name = "itoa" -version = "1.0.2" +name = "inout" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d" +checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +dependencies = [ + "generic-array", +] [[package]] name = "jobserver" -version = "0.1.24" +version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af25a77299a7f711a01975c35a6a424eb6862092cc2d6c72c4ed6cbc56dfc1fa" +checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" dependencies = [ "libc", ] [[package]] name = "libc" -version = "0.2.126" +version = "0.2.161" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" +checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1" [[package]] name = "libsqlite3-sys" @@ -262,45 +272,36 @@ dependencies = [ [[package]] name = "memchr" -version = "2.5.0" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "miniz_oxide" -version = "0.5.3" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f5c75688da582b8ffc1f1799e9db273f32133c49e048f614d22ec3256773ccc" +checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" dependencies = [ - "adler", + "adler2", ] [[package]] -name = "num_threads" -version = "0.1.6" +name = "num-conv" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2819ce041d2ee131036f4fc9d6ae7ae125a3a40e97ba64d04fe799ad9dabbb44" -dependencies = [ - "libc", -] +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" [[package]] name = "once_cell" -version = "1.13.0" +version = "1.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1" - -[[package]] -name = "opaque-debug" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" [[package]] name = "password-hash" -version = "0.3.2" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d791538a6dcc1e7cb7fe6f6b58aca40e7f79403c45b2bc274008b5e647af1d8" +checksum = "7676374caaee8a325c9e7a2ae557f216c5563a171d6997b0ef8a65af35147700" dependencies = [ "base64ct", "rand_core", @@ -318,9 +319,9 @@ dependencies = [ [[package]] name = "pbkdf2" -version = "0.10.1" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "271779f35b581956db91a3e55737327a03aa051e90b1c47aeb189508533adfd7" +checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" dependencies = [ "digest", "hmac", @@ -330,24 +331,48 @@ dependencies = [ [[package]] name = "pkg-config" -version = "0.3.25" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae" +checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "proc-macro2" +version = "1.0.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e" +dependencies = [ + "unicode-ident", +] [[package]] name = "quick-xml" -version = "0.23.0" +version = "0.23.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9279fbdacaad3baf559d8cabe0acc3d06e30ea14931af31af79578ac0946decc" +checksum = "11bafc859c6815fbaffbbbf4229ecb767ac913fecb27f9ad4343662e9ef099ea" dependencies = [ "memchr", ] [[package]] -name = "rand_core" -version = "0.6.3" +name = "quote" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" [[package]] name = "rusqlite" @@ -365,10 +390,30 @@ dependencies = [ ] [[package]] -name = "sha1" -version = "0.10.1" +name = "serde" +version = "1.0.214" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c77f4e7f65455545c2153c1253d25056825e77ee2533f0e41deb65a93a34852f" +checksum = "f55c3193aca71c12ad7890f1785d2b73e1b9f63a0bbc353c08ef26fe03fc56b5" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.214" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de523f781f095e28fa605cdce0f8307e451cc0fd14e2eb4cd2e98a355b147766" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" dependencies = [ "cfg-if", "cpufeatures", @@ -377,9 +422,9 @@ dependencies = [ [[package]] name = "sha2" -version = "0.10.2" +version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55deaec60f81eefe3cce0dc50bda92d6d8e88f2a27df7c5033b42afeb1ed2676" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" dependencies = [ "cfg-if", "cpufeatures", @@ -387,40 +432,64 @@ dependencies = [ ] [[package]] -name = "smallvec" -version = "1.9.0" +name = "shlex" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fd0db749597d91ff862fd1d55ea87f7855a744a8425a64695b6fca237d1dad1" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "smallvec" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "subtle" -version = "2.4.1" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] -name = "time" -version = "0.3.11" +name = "syn" +version = "2.0.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72c91f41dcb2f096c05f0873d667dceec1087ce5bcf984ec8ffb19acddbb3217" +checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d" dependencies = [ - "itoa", - "libc", - "num_threads", - "time-macros", + "proc-macro2", + "quote", + "unicode-ident", ] [[package]] -name = "time-macros" -version = "0.2.4" +name = "time" +version = "0.3.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42657b1a6f4d817cda8e7a0ace261fe0cc946cf3a80314390b22cc61ae080792" +checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" +dependencies = [ + "deranged", + "num-conv", + "powerfmt", + "serde", + "time-core", +] + +[[package]] +name = "time-core" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" [[package]] name = "typenum" -version = "1.15.0" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "unicode-ident" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" [[package]] name = "vcpkg" @@ -430,9 +499,9 @@ checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" [[package]] name = "version_check" -version = "0.9.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "wasi" @@ -442,9 +511,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "zip" -version = "0.6.2" +version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf225bcf73bb52cbb496e70475c7bd7a3f769df699c0020f6c7bd9a96dcf0b8d" +checksum = "760394e246e4c28189f19d488c058bf16f564016aefac5d32bb1f3b51d5e9261" dependencies = [ "aes", "byteorder", @@ -462,18 +531,18 @@ dependencies = [ [[package]] name = "zstd" -version = "0.10.2+zstd.1.5.2" +version = "0.11.2+zstd.1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f4a6bd64f22b5e3e94b4e238669ff9f10815c27a5180108b849d24174a83847" +checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4" dependencies = [ "zstd-safe", ] [[package]] name = "zstd-safe" -version = "4.1.6+zstd.1.5.2" +version = "5.0.2+zstd.1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94b61c51bb270702d6167b8ce67340d2754b088d0c091b06e593aa772c3ee9bb" +checksum = "1d2a5585e04f9eea4b2a3d1eca508c4dee9592a89ef6f450c11719da0726f4db" dependencies = [ "libc", "zstd-sys", @@ -481,10 +550,10 @@ dependencies = [ [[package]] name = "zstd-sys" -version = "1.6.3+zstd.1.5.2" +version = "2.0.13+zstd.1.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc49afa5c8d634e75761feda8c592051e7eeb4683ba827211eb0d731d3402ea8" +checksum = "38ff0f21cfee8f97d94cef41359e0c89aa6113028ab0291aa8ca0038995a95aa" dependencies = [ "cc", - "libc", + "pkg-config", ] From 23c126ec9a98352b8c92b2e6ed3154c10fec081a Mon Sep 17 00:00:00 2001 From: Martin Brodbeck Date: Tue, 5 Nov 2024 14:01:48 +0100 Subject: [PATCH 45/57] deps updated particularly quick_xml which caused some code changes. Lots of testing should be done. --- Cargo.lock | 318 ++++++++++++++++++++++++++++++++++++++++++---------- Cargo.toml | 6 +- src/epub.rs | 78 +++++++------ 3 files changed, 304 insertions(+), 98 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d297240..8ae0154 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -21,26 +21,30 @@ dependencies = [ [[package]] name = "ahash" -version = "0.7.8" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" dependencies = [ - "getrandom", + "cfg-if", "once_cell", "version_check", + "zerocopy", ] [[package]] -name = "base64ct" -version = "1.6.0" +name = "arbitrary" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" +checksum = "775a8770d29db3dadcb858482cc240af7b2ffde4ac4de67d1d4955728103f0e2" +dependencies = [ + "derive_arbitrary", +] [[package]] name = "bitflags" -version = "1.3.2" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" [[package]] name = "block-buffer" @@ -51,6 +55,12 @@ dependencies = [ "generic-array", ] +[[package]] +name = "bumpalo" +version = "3.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" + [[package]] name = "byteorder" version = "1.5.0" @@ -107,9 +117,9 @@ dependencies = [ [[package]] name = "constant_time_eq" -version = "0.1.5" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" +checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6" [[package]] name = "cpufeatures" @@ -120,6 +130,21 @@ dependencies = [ "libc", ] +[[package]] +name = "crc" +version = "3.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69e6e4d7b33a94f0991c26729976b10ebde1d34c3ee82408fb536164fa10d636" +dependencies = [ + "crc-catalog", +] + +[[package]] +name = "crc-catalog" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" + [[package]] name = "crc32fast" version = "1.4.2" @@ -145,6 +170,12 @@ dependencies = [ "typenum", ] +[[package]] +name = "deflate64" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da692b8d1080ea3045efaab14434d40468c3d8657e42abddfffca87b428f4c1b" + [[package]] name = "deranged" version = "0.3.11" @@ -154,6 +185,17 @@ dependencies = [ "powerfmt", ] +[[package]] +name = "derive_arbitrary" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d475dfebcb4854d596b17b09f477616f80f17a550517f2b3615d8c205d5c802b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "digest" version = "0.10.7" @@ -166,10 +208,27 @@ dependencies = [ ] [[package]] -name = "fallible-iterator" -version = "0.2.0" +name = "displaydoc" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "fallible-iterator" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" [[package]] name = "fallible-streaming-iterator" @@ -210,20 +269,26 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.11.2" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" dependencies = [ "ahash", ] [[package]] -name = "hashlink" -version = "0.7.0" +name = "hashbrown" +version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7249a3129cbc1ffccd74857f81464a323a152173cdb134e0fd81bc803b29facf" +checksum = "3a9bfc1af68b1726ea47d3d5109de126281def866b33970e10fbab11b5dafab3" + +[[package]] +name = "hashlink" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ba4ff7128dee98c7dc9794b6a411377e1404dba1c97deb8d1a55297bd25d8af" dependencies = [ - "hashbrown", + "hashbrown 0.14.5", ] [[package]] @@ -235,6 +300,16 @@ dependencies = [ "digest", ] +[[package]] +name = "indexmap" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" +dependencies = [ + "equivalent", + "hashbrown 0.15.1", +] + [[package]] name = "inout" version = "0.1.3" @@ -261,15 +336,37 @@ checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1" [[package]] name = "libsqlite3-sys" -version = "0.24.2" +version = "0.30.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "898745e570c7d0453cc1fbc4a701eb6c662ed54e8fec8b7d14be137ebeeb9d14" +checksum = "2e99fb7a497b1e3339bc746195567ed8d3e24945ecd636e3619d20b9de9e9149" dependencies = [ "cc", "pkg-config", "vcpkg", ] +[[package]] +name = "lockfree-object-pool" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9374ef4228402d4b7e403e5838cb880d9ee663314b0a900d5a6aabf0c213552e" + +[[package]] +name = "log" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" + +[[package]] +name = "lzma-rs" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "297e814c836ae64db86b36cf2a557ba54368d03f6afcd7d947c266692f71115e" +dependencies = [ + "byteorder", + "crc", +] + [[package]] name = "memchr" version = "2.7.4" @@ -297,17 +394,6 @@ version = "1.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" -[[package]] -name = "password-hash" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7676374caaee8a325c9e7a2ae557f216c5563a171d6997b0ef8a65af35147700" -dependencies = [ - "base64ct", - "rand_core", - "subtle", -] - [[package]] name = "pbdbfixer" version = "0.8.3" @@ -319,14 +405,12 @@ dependencies = [ [[package]] name = "pbkdf2" -version = "0.11.0" +version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" +checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2" dependencies = [ "digest", "hmac", - "password-hash", - "sha2", ] [[package]] @@ -341,6 +425,15 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" +[[package]] +name = "ppv-lite86" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +dependencies = [ + "zerocopy", +] + [[package]] name = "proc-macro2" version = "1.0.89" @@ -352,9 +445,9 @@ dependencies = [ [[package]] name = "quick-xml" -version = "0.23.1" +version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11bafc859c6815fbaffbbbf4229ecb767ac913fecb27f9ad4343662e9ef099ea" +checksum = "ffbfb3ddf5364c9cfcd65549a1e7b801d0e8d1b14c1a1590a6408aa93cfbfa84" dependencies = [ "memchr", ] @@ -368,24 +461,47 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + [[package]] name = "rand_core" version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] [[package]] name = "rusqlite" -version = "0.27.0" +version = "0.32.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85127183a999f7db96d1a976a309eebbfb6ea3b0b400ddd8340190129de6eb7a" +checksum = "7753b721174eb8ff87a9a0e799e2d7bc3749323e773db92e0984debb00019d6e" dependencies = [ "bitflags", "fallible-iterator", "fallible-streaming-iterator", "hashlink", "libsqlite3-sys", - "memchr", "smallvec", ] @@ -420,23 +536,18 @@ dependencies = [ "digest", ] -[[package]] -name = "sha2" -version = "0.10.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - [[package]] name = "shlex" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +[[package]] +name = "simd-adler32" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" + [[package]] name = "smallvec" version = "1.13.2" @@ -460,6 +571,26 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "thiserror" +version = "1.0.68" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02dd99dc800bbb97186339685293e1cc5d9df1f8fae2d0aecd9ff1c77efea892" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.68" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7c61ec9a6f64d2793d8a45faba21efbe3ced62a886d44c36a009b2b519b4c7e" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "time" version = "0.3.36" @@ -510,41 +641,104 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] -name = "zip" -version = "0.6.6" +name = "zerocopy" +version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "760394e246e4c28189f19d488c058bf16f564016aefac5d32bb1f3b51d5e9261" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +dependencies = [ + "byteorder", + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "zeroize" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "zip" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc5e4288ea4057ae23afc69a4472434a87a2495cafce6632fd1c4ec9f5cf3494" dependencies = [ "aes", - "byteorder", + "arbitrary", "bzip2", "constant_time_eq", "crc32fast", "crossbeam-utils", + "deflate64", + "displaydoc", "flate2", "hmac", + "indexmap", + "lzma-rs", + "memchr", "pbkdf2", + "rand", "sha1", + "thiserror", "time", + "zeroize", + "zopfli", "zstd", ] [[package]] -name = "zstd" -version = "0.11.2+zstd.1.5.2" +name = "zopfli" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4" +checksum = "e5019f391bac5cf252e93bbcc53d039ffd62c7bfb7c150414d61369afe57e946" +dependencies = [ + "bumpalo", + "crc32fast", + "lockfree-object-pool", + "log", + "once_cell", + "simd-adler32", +] + +[[package]] +name = "zstd" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcf2b778a664581e31e389454a7072dab1647606d44f7feea22cd5abb9c9f3f9" dependencies = [ "zstd-safe", ] [[package]] name = "zstd-safe" -version = "5.0.2+zstd.1.5.2" +version = "7.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d2a5585e04f9eea4b2a3d1eca508c4dee9592a89ef6f450c11719da0726f4db" +checksum = "54a3ab4db68cea366acc5c897c7b4d4d1b8994a9cd6e6f841f8964566a419059" dependencies = [ - "libc", "zstd-sys", ] diff --git a/Cargo.toml b/Cargo.toml index de4df26..c94ace8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,9 +7,9 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -zip = "0.6" -quick-xml = "0.23" +zip = "2.2.0" +quick-xml = "0.37" [dependencies.rusqlite] -version = "0.27" +version = "0.32.1" features = ["bundled"] diff --git a/src/epub.rs b/src/epub.rs index a5916d4..3574377 100644 --- a/src/epub.rs +++ b/src/epub.rs @@ -1,4 +1,5 @@ use std::{ + borrow::Borrow, collections::HashMap, fs::{self, File}, io::Read, @@ -52,17 +53,19 @@ fn get_rootfile(archive: &mut ZipArchive) -> String { container.read_to_string(&mut xml_str_buffer).unwrap(); let mut reader = Reader::from_str(&xml_str_buffer); - reader.trim_text(true); + reader.config_mut().trim_text(true); let mut buf = Vec::new(); let mut opf_filename = String::new(); loop { - match reader.read_event(&mut buf) { - Ok(Event::Start(ref e)) | Ok(Event::Empty(ref e)) if e.local_name() == b"rootfile" => { + match reader.read_event_into(&mut buf) { + Ok(Event::Start(ref e)) | Ok(Event::Empty(ref e)) + if e.local_name().into_inner() == b"rootfile" => + { opf_filename = String::from_utf8( e.attributes() - .filter(|attr| attr.as_ref().unwrap().key == b"full-path") + .filter(|attr| attr.as_ref().unwrap().key.into_inner() == b"full-path") .next() .unwrap() .unwrap() @@ -128,22 +131,22 @@ pub fn get_epub_metadata(filename: &str) -> Option { let mut xml_authors = HashMap::new(); loop { - match reader.read_event(&mut buf) { + match reader.read_event_into(&mut buf) { // See if we have EPUB3 or EPUB2 - Ok(Event::Start(ref e)) if e.local_name() == b"package" => { + Ok(Event::Start(ref e)) if e.local_name().into_inner() == b"package" => { if e.attributes().any(|attr| { - attr.as_ref().unwrap().key == b"version" + attr.as_ref().unwrap().key.into_inner() == b"version" && attr.as_ref().unwrap().value.starts_with(b"3") }) { is_epub3 = true; } } - Ok(Event::Start(ref e)) if e.local_name() == b"creator" => { + Ok(Event::Start(ref e)) if e.local_name().into_inner() == b"creator" => { creator_found = true; if is_epub3 { if let Some(idval) = e .attributes() - .filter(|attr| attr.as_ref().unwrap().key == b"id") + .filter(|attr| attr.as_ref().unwrap().key.into_inner() == b"id") .next() { curr_id = "#".to_string() @@ -159,19 +162,26 @@ pub fn get_epub_metadata(filename: &str) -> Option { } else { if let Some(file_as_val) = e .attributes() - .filter(|attr| attr.as_ref().unwrap().key.ends_with(b"file-as")) + .filter(|attr| { + attr.as_ref() + .unwrap() + .key + .into_inner() + .ends_with(b"file-as") + }) .next() { curr_id = "none".to_string() + xml_authors.len().to_string().as_str(); let entry = xml_authors.entry(curr_id.clone()).or_insert(XmlAut::new()); entry.sort = file_as_val .unwrap() - .unescape_and_decode_value(&reader) - .unwrap_or_default(); + .decode_and_unescape_value(*reader.decoder().borrow()) + .unwrap_or_default() + .to_string(); entry.role = "aut".to_string(); } else if let Some(_role_val) = e .attributes() - .filter(|attr| attr.as_ref().unwrap().key.ends_with(b"role")) + .filter(|attr| attr.as_ref().unwrap().key.into_inner().ends_with(b"role")) .next() { curr_id = "none".to_string() + xml_authors.len().to_string().as_str(); @@ -190,33 +200,33 @@ pub fn get_epub_metadata(filename: &str) -> Option { creator_found = false; } - Ok(Event::Start(ref e)) if e.local_name() == b"meta" && is_epub3 => { + Ok(Event::Start(ref e)) if e.local_name().into_inner() == b"meta" && is_epub3 => { if let Some(refines) = e .attributes() - .filter(|attr| attr.as_ref().unwrap().key == b"refines") + .filter(|attr| attr.as_ref().unwrap().key.into_inner() == b"refines") .next() { if e.attributes().any(|attr| { - attr.as_ref().unwrap().key == b"property" + attr.as_ref().unwrap().key.into_inner() == b"property" && attr.as_ref().unwrap().value.ends_with(b"file-as") }) { curr_id = String::from_utf8(refines.unwrap().value.to_vec()).unwrap(); file_as_found = true; } else if e.attributes().any(|attr| { - attr.as_ref().unwrap().key == b"property" + attr.as_ref().unwrap().key.into_inner() == b"property" && attr.as_ref().unwrap().value.ends_with(b"role") }) { curr_id = String::from_utf8(refines.unwrap().value.to_vec()).unwrap(); role_found = true; } else if e.attributes().any(|attr| { - attr.as_ref().unwrap().key == b"property" + attr.as_ref().unwrap().key.into_inner() == b"property" && attr.as_ref().unwrap().value.ends_with(b"group-position") }) { series_index_found = true; } } if e.attributes().any(|attr| { - attr.as_ref().unwrap().key == b"property" + attr.as_ref().unwrap().key.into_inner() == b"property" && attr .as_ref() .unwrap() @@ -226,40 +236,41 @@ pub fn get_epub_metadata(filename: &str) -> Option { series_found = true; } } - Ok(Event::Empty(ref e)) if e.local_name() == b"meta" && !is_epub3 => { + Ok(Event::Empty(ref e)) if e.local_name().into_inner() == b"meta" && !is_epub3 => { if e.attributes().any(|attr| { - attr.as_ref().unwrap().key == b"name" + attr.as_ref().unwrap().key.into_inner() == b"name" && attr .as_ref() .unwrap() - .unescaped_value() + .unescape_value() .unwrap() - .ends_with(b"series") + .ends_with("series") }) { epub_meta.series.name = e .attributes() - .filter(|attr| attr.as_ref().unwrap().key == b"content") + .filter(|attr| attr.as_ref().unwrap().key.into_inner() == b"content") .next() .unwrap() .unwrap() - .unescape_and_decode_value(&reader) - .unwrap_or_default(); + .decode_and_unescape_value(*reader.decoder().borrow()) + .unwrap_or_default() + .to_string(); } else if e.attributes().any(|attr| { - attr.as_ref().unwrap().key == b"name" + attr.as_ref().unwrap().key.into_inner() == b"name" && attr .as_ref() .unwrap() - .unescaped_value() + .unescape_value() .unwrap() - .ends_with(b"series_index") + .ends_with("series_index") }) { let index_float = e .attributes() - .filter(|attr| attr.as_ref().unwrap().key == b"content") + .filter(|attr| attr.as_ref().unwrap().key.into_inner() == b"content") .next() .unwrap() .unwrap() - .unescape_and_decode_value(&reader) + .decode_and_unescape_value(*reader.decoder().borrow()) .unwrap_or_default() .parse::() .unwrap_or_default(); @@ -291,11 +302,12 @@ pub fn get_epub_metadata(filename: &str) -> Option { series_index_found = false; } - Ok(Event::Start(ref e)) if e.local_name() == b"subject" => { + Ok(Event::Start(ref e)) if e.local_name().into_inner() == b"subject" => { genre_found = true; } Ok(Event::Text(ref e)) if genre_found => { - epub_meta.genre = e.unescape_and_decode(&reader).unwrap(); + //epub_meta.genre = e.unescape_and_decode(&reader).unwrap(); + epub_meta.genre = e.unescape().unwrap().to_string(); genre_found = false; } Ok(Event::Eof) => break, From 660ff77dfc25194acf53cd3194f2ab1034b6707d Mon Sep 17 00:00:00 2001 From: martin Date: Tue, 5 Nov 2024 14:19:59 +0100 Subject: [PATCH 46/57] some tweaks, email added --- README.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 61d483c..9ece53f 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,10 @@ # PbDbFixer ## Motivation -Since Pocketbook has some problems with extracting metadata correctly from -EPUB files, this program tries fix these issues. It tries to identify -wrong database entries and fix it by reading the corresponding epub -metadata. +Since Pocketbook has some problems with extracting metadata correctly from EPUB files, this program tries fix these issues. It tries to identify wrong database entries and fix it by reading the corresponding epub metadata. ## Features -The app tries to fix the following issues in the database +PbDbFixer tries to fix the following issues in the database - Correction of wrong firstauthor entries (books_impl table) - Correction of wrong first_author_letter entries (books_impl table) - Correction of wrong author entries (books_impl table) @@ -18,7 +15,7 @@ The app tries to fix the following issues in the database The best results are achieved when metadata has been carefully maintained with **Calibre**. ## Compatibility -This program is tested on a PocketBook +This program has been tested on a PocketBook - *Touch Lux 4* (software version 6.5) - *Touch HD 3* (software version 6.7) - *Era* (software version 6.8) [^1] @@ -28,7 +25,7 @@ This program is tested on a PocketBook It might work with other PocketBook devices/software versions. Please tell me if it works for you (and do make a backup of the explorer-3.db file before trying!). -**Please note:** As I do not currently own a PocketBook device, I am unfortunately unable to react to changes in the database structure. Perhaps you can send me your `explorer-3.db` so that I can take a look at the changes. Just get in touch with me. +**Please note:** As I do not currently own a PocketBook device, I am unfortunately unable to react to changes in the database structure. Perhaps you can send me your `explorer-3.db` so that I can take a look at the changes. Just get in touch with me. ## Installation and Usage --- @@ -44,7 +41,10 @@ If you don't see any changes: There might be an explorer (which shows your library) process already running. Then you should just stop/kill it with the task manager. Putting the device to sleep and then wake it up might also work. Afterwards, the changes should be visible to the explorer. ## Feedback -Feedback is highly appreciated. You can reach me via Matrix [@beedaddy:matrix.rustysoft.de](https://matrix.to/#/@beedaddy:matrix.rustysoft.de) or ask questions in the [PbDbFixer-Thread](https://www.e-reader-forum.de/t/pbdbfixer-noch-ein-tool-zum-korrigieren-von-metadaten.156702/) of the German *E-Reader Forum*. +Feedback is highly appreciated. You can reach me via +- Matrix Chat [@beedaddy:matrix.rustysoft.de](https://matrix.to/#/@beedaddy:matrix.rustysoft.de) +- [PbDbFixer-Thread](https://www.e-reader-forum.de/t/pbdbfixer-noch-ein-tool-zum-korrigieren-von-metadaten.156702/) of the German *E-Reader Forum*. +- E-Mail: info@rustysoft.de ## Build If you want to build PbDbFixer yourself, make sure that you have Rust's toolchain target `arm-unknown-linux-gnueabi` as well as the GCC cross compiler for ARM CPUs installed. On **Arch** Linux, the AUR package `arm-linux-gnueabi-gcc75-linaro-bin` does the job. On **Debian**, you have to install the package `gcc-arm-linux-gnueabi`. Don't forget to tell `cargo` which compiler/linker it has to invoke. In my case, I had to edit `~/.cargo/config`: From 445662727ea4b34af25333914e54b06401765c70 Mon Sep 17 00:00:00 2001 From: Martin Brodbeck Date: Thu, 7 Nov 2024 14:26:52 +0100 Subject: [PATCH 47/57] strip release builds --- Cargo.toml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index c94ace8..49e3b07 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,3 +13,6 @@ quick-xml = "0.37" [dependencies.rusqlite] version = "0.32.1" features = ["bundled"] + +[profile.release] +strip = true From 2cf198e52b664234c837b0548f8102d77b3b4277 Mon Sep 17 00:00:00 2001 From: Martin Brodbeck Date: Fri, 8 Nov 2024 14:03:41 +0100 Subject: [PATCH 48/57] Cargo.lock updated --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8ae0154..a1e7a0f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -330,9 +330,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.161" +version = "0.2.162" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1" +checksum = "18d287de67fe55fd7e1581fe933d965a5a9477b38e949cfa9f8574ef01506398" [[package]] name = "libsqlite3-sys" From 18873c4b3e7fa8f03e8fc19ba0f852f6ca1e9188 Mon Sep 17 00:00:00 2001 From: Martin Brodbeck Date: Fri, 8 Nov 2024 14:10:51 +0100 Subject: [PATCH 49/57] Update description for compiling the stuff --- README.md | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 9ece53f..1b3d891 100644 --- a/README.md +++ b/README.md @@ -47,14 +47,15 @@ Feedback is highly appreciated. You can reach me via - E-Mail: info@rustysoft.de ## Build -If you want to build PbDbFixer yourself, make sure that you have Rust's toolchain target `arm-unknown-linux-gnueabi` as well as the GCC cross compiler for ARM CPUs installed. On **Arch** Linux, the AUR package `arm-linux-gnueabi-gcc75-linaro-bin` does the job. On **Debian**, you have to install the package `gcc-arm-linux-gnueabi`. Don't forget to tell `cargo` which compiler/linker it has to invoke. In my case, I had to edit `~/.cargo/config`: +If you want to build PbDbFixer yourself, make sure that you have Rust's toolchain target `armv7-unknown-linux-gnueabi` installed. Additionaly, you should use [PocketBook's SDK](https://github.com/pocketbook/SDK_6.3.0/tree/6.5) for being able to cross-compile specific for these devices. Don't forget to tell `cargo` which compiler/linker it has to invoke. In my case, I had to edit `~/.cargo/config.toml`: ``` -[target.arm-unknown-linux-gnueabi] -linker = "arm-linux-gnueabi-gcc" -``` -Now you can easily compile the stuff by invoking -``` -cargo build --release --target=arm-unknown-linux-gnueabi +[target.armv7-unknown-linux-gnueabi] +linker = "SDKs/PB/SDK_6.3.0/SDK-B288/usr/bin/arm-obreey-linux-gnueabi-gcc" ``` -[^1]: User feedback \ No newline at end of file +Now you can easily compile the stuff. Note that you have to tell where the libraries are located (`LD_LIBRARY_PATH`): +``` +LD_LIBRARY_PATH="$HOME/SDKs/PB/SDK_6.3.0/SDK-B288/usr/lib" cargo build --release --target=armv7-unknown-linux-gnueabi +``` + +[^1]: User feedback From e9fa11b70067438ef2c2906cf5518bdd856b4236 Mon Sep 17 00:00:00 2001 From: Martin Brodbeck Date: Fri, 8 Nov 2024 14:29:28 +0100 Subject: [PATCH 50/57] push to new version --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 49e3b07..08f848d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pbdbfixer" -version = "0.8.3" +version = "0.9.0" authors = ["Martin Brodbeck "] edition = "2021" From 8b38cee7b888dace02d2248c6f6019c7fddc17b7 Mon Sep 17 00:00:00 2001 From: martin Date: Mon, 11 Nov 2024 10:15:03 +0100 Subject: [PATCH 51/57] README updated --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index 1b3d891..564b3dc 100644 --- a/README.md +++ b/README.md @@ -25,8 +25,6 @@ This program has been tested on a PocketBook It might work with other PocketBook devices/software versions. Please tell me if it works for you (and do make a backup of the explorer-3.db file before trying!). -**Please note:** As I do not currently own a PocketBook device, I am unfortunately unable to react to changes in the database structure. Perhaps you can send me your `explorer-3.db` so that I can take a look at the changes. Just get in touch with me. - ## Installation and Usage --- **WARNING**: From da77983228cfae45cfd4f8fc66b75919f67014ae Mon Sep 17 00:00:00 2001 From: Martin Brodbeck Date: Tue, 12 Nov 2024 10:37:01 +0100 Subject: [PATCH 52/57] get_rootfile() simplified --- Cargo.lock | 2 +- src/epub.rs | 21 ++++++++++----------- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a1e7a0f..dd0508f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -396,7 +396,7 @@ checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" [[package]] name = "pbdbfixer" -version = "0.8.3" +version = "0.9.0" dependencies = [ "quick-xml", "rusqlite", diff --git a/src/epub.rs b/src/epub.rs index 3574377..82d67bc 100644 --- a/src/epub.rs +++ b/src/epub.rs @@ -61,18 +61,17 @@ fn get_rootfile(archive: &mut ZipArchive) -> String { loop { match reader.read_event_into(&mut buf) { Ok(Event::Start(ref e)) | Ok(Event::Empty(ref e)) - if e.local_name().into_inner() == b"rootfile" => + if e.name().as_ref() == b"rootfile" => { - opf_filename = String::from_utf8( - e.attributes() - .filter(|attr| attr.as_ref().unwrap().key.into_inner() == b"full-path") - .next() - .unwrap() - .unwrap() - .value - .to_vec(), - ) - .unwrap(); + opf_filename = e + .attributes() + .filter(|attr| attr.as_ref().unwrap().key.as_ref() == b"full-path") + .next() + .unwrap() + .unwrap() + .unescape_value() + .unwrap() + .to_string(); break; } Ok(Event::Eof) => break, From b02ede51820d9293cc6152f2a821f4687ff5ecb8 Mon Sep 17 00:00:00 2001 From: Martin Brodbeck Date: Tue, 12 Nov 2024 10:57:03 +0100 Subject: [PATCH 53/57] get_epub_metadata() simplified. --- src/epub.rs | 44 +++++++++++++++++++++----------------------- 1 file changed, 21 insertions(+), 23 deletions(-) diff --git a/src/epub.rs b/src/epub.rs index 82d67bc..3ee7e28 100644 --- a/src/epub.rs +++ b/src/epub.rs @@ -1,5 +1,4 @@ use std::{ - borrow::Borrow, collections::HashMap, fs::{self, File}, io::Read, @@ -132,20 +131,20 @@ pub fn get_epub_metadata(filename: &str) -> Option { loop { match reader.read_event_into(&mut buf) { // See if we have EPUB3 or EPUB2 - Ok(Event::Start(ref e)) if e.local_name().into_inner() == b"package" => { + Ok(Event::Start(ref e)) if e.name().as_ref() == b"package" => { if e.attributes().any(|attr| { - attr.as_ref().unwrap().key.into_inner() == b"version" + attr.as_ref().unwrap().key.as_ref() == b"version" && attr.as_ref().unwrap().value.starts_with(b"3") }) { is_epub3 = true; } } - Ok(Event::Start(ref e)) if e.local_name().into_inner() == b"creator" => { + Ok(Event::Start(ref e)) if e.local_name().as_ref() == b"creator" => { creator_found = true; if is_epub3 { if let Some(idval) = e .attributes() - .filter(|attr| attr.as_ref().unwrap().key.into_inner() == b"id") + .filter(|attr| attr.as_ref().unwrap().key.as_ref() == b"id") .next() { curr_id = "#".to_string() @@ -165,7 +164,7 @@ pub fn get_epub_metadata(filename: &str) -> Option { attr.as_ref() .unwrap() .key - .into_inner() + .as_ref() .ends_with(b"file-as") }) .next() @@ -174,13 +173,13 @@ pub fn get_epub_metadata(filename: &str) -> Option { let entry = xml_authors.entry(curr_id.clone()).or_insert(XmlAut::new()); entry.sort = file_as_val .unwrap() - .decode_and_unescape_value(*reader.decoder().borrow()) + .unescape_value() .unwrap_or_default() .to_string(); entry.role = "aut".to_string(); } else if let Some(_role_val) = e .attributes() - .filter(|attr| attr.as_ref().unwrap().key.into_inner().ends_with(b"role")) + .filter(|attr| attr.as_ref().unwrap().key.as_ref().ends_with(b"role")) .next() { curr_id = "none".to_string() + xml_authors.len().to_string().as_str(); @@ -199,33 +198,33 @@ pub fn get_epub_metadata(filename: &str) -> Option { creator_found = false; } - Ok(Event::Start(ref e)) if e.local_name().into_inner() == b"meta" && is_epub3 => { + Ok(Event::Start(ref e)) if e.local_name().as_ref() == b"meta" && is_epub3 => { if let Some(refines) = e .attributes() - .filter(|attr| attr.as_ref().unwrap().key.into_inner() == b"refines") + .filter(|attr| attr.as_ref().unwrap().key.as_ref() == b"refines") .next() { if e.attributes().any(|attr| { - attr.as_ref().unwrap().key.into_inner() == b"property" + attr.as_ref().unwrap().key.as_ref() == b"property" && attr.as_ref().unwrap().value.ends_with(b"file-as") }) { curr_id = String::from_utf8(refines.unwrap().value.to_vec()).unwrap(); file_as_found = true; } else if e.attributes().any(|attr| { - attr.as_ref().unwrap().key.into_inner() == b"property" + attr.as_ref().unwrap().key.as_ref() == b"property" && attr.as_ref().unwrap().value.ends_with(b"role") }) { curr_id = String::from_utf8(refines.unwrap().value.to_vec()).unwrap(); role_found = true; } else if e.attributes().any(|attr| { - attr.as_ref().unwrap().key.into_inner() == b"property" + attr.as_ref().unwrap().key.as_ref() == b"property" && attr.as_ref().unwrap().value.ends_with(b"group-position") }) { series_index_found = true; } } if e.attributes().any(|attr| { - attr.as_ref().unwrap().key.into_inner() == b"property" + attr.as_ref().unwrap().key.as_ref() == b"property" && attr .as_ref() .unwrap() @@ -235,9 +234,9 @@ pub fn get_epub_metadata(filename: &str) -> Option { series_found = true; } } - Ok(Event::Empty(ref e)) if e.local_name().into_inner() == b"meta" && !is_epub3 => { + Ok(Event::Empty(ref e)) if e.local_name().as_ref() == b"meta" && !is_epub3 => { if e.attributes().any(|attr| { - attr.as_ref().unwrap().key.into_inner() == b"name" + attr.as_ref().unwrap().key.as_ref() == b"name" && attr .as_ref() .unwrap() @@ -247,15 +246,15 @@ pub fn get_epub_metadata(filename: &str) -> Option { }) { epub_meta.series.name = e .attributes() - .filter(|attr| attr.as_ref().unwrap().key.into_inner() == b"content") + .filter(|attr| attr.as_ref().unwrap().key.as_ref() == b"content") .next() .unwrap() .unwrap() - .decode_and_unescape_value(*reader.decoder().borrow()) + .unescape_value() .unwrap_or_default() .to_string(); } else if e.attributes().any(|attr| { - attr.as_ref().unwrap().key.into_inner() == b"name" + attr.as_ref().unwrap().key.as_ref() == b"name" && attr .as_ref() .unwrap() @@ -265,11 +264,11 @@ pub fn get_epub_metadata(filename: &str) -> Option { }) { let index_float = e .attributes() - .filter(|attr| attr.as_ref().unwrap().key.into_inner() == b"content") + .filter(|attr| attr.as_ref().unwrap().key.as_ref() == b"content") .next() .unwrap() .unwrap() - .decode_and_unescape_value(*reader.decoder().borrow()) + .unescape_value() .unwrap_or_default() .parse::() .unwrap_or_default(); @@ -301,11 +300,10 @@ pub fn get_epub_metadata(filename: &str) -> Option { series_index_found = false; } - Ok(Event::Start(ref e)) if e.local_name().into_inner() == b"subject" => { + Ok(Event::Start(ref e)) if e.local_name().as_ref() == b"subject" => { genre_found = true; } Ok(Event::Text(ref e)) if genre_found => { - //epub_meta.genre = e.unescape_and_decode(&reader).unwrap(); epub_meta.genre = e.unescape().unwrap().to_string(); genre_found = false; } From 35a0c1559ba51f6be7aacc7ffb4f4974f808de3a Mon Sep 17 00:00:00 2001 From: Martin Brodbeck Date: Tue, 14 Jan 2025 10:02:30 +0100 Subject: [PATCH 54/57] Attempt to support books on sdcard --- src/database.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/database.rs b/src/database.rs index 45d9771..e640771 100644 --- a/src/database.rs +++ b/src/database.rs @@ -30,7 +30,7 @@ fn get_epubs_from_database(tx: &Transaction) -> Vec { r#" SELECT books.id, folders.name, files.filename, books.firstauthor, books.author, genres.name, first_author_letter, series - FROM books_impl books JOIN files + FROM books_impl books JOIN files, storages ON books.id = files.book_id JOIN folders ON folders.id = files.folder_id @@ -38,7 +38,7 @@ fn get_epubs_from_database(tx: &Transaction) -> Vec { ON books.id = btg.bookid LEFT OUTER JOIN genres ON genres.id = btg.genreid - WHERE files.storageid = 1 AND {}.ext = 'epub' + WHERE files.storageid IN (SELECT storages.id WHERE storages.type = 1) AND {}.ext = 'epub' ORDER BY books.id"#, &books_or_files ); From d40637f5358d259d0a63a92b30660db350c78e9e Mon Sep 17 00:00:00 2001 From: Martin Brodbeck Date: Fri, 21 Feb 2025 08:52:49 +0100 Subject: [PATCH 55/57] edition 2024 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 08f848d..79d147d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,7 @@ name = "pbdbfixer" version = "0.9.0" authors = ["Martin Brodbeck "] -edition = "2021" +edition = "2024" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html From a26225b3a29248b06923e7e9f48801e9777e6426 Mon Sep 17 00:00:00 2001 From: Martin Brodbeck Date: Thu, 8 May 2025 10:18:19 +0200 Subject: [PATCH 56/57] New version --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 79d147d..7ec5c0b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pbdbfixer" -version = "0.9.0" +version = "1.0.0" authors = ["Martin Brodbeck "] edition = "2024" From 35a689dbeb1a4ac1d78b14ac5d25b46a51704014 Mon Sep 17 00:00:00 2001 From: Martin Brodbeck Date: Thu, 8 May 2025 10:41:21 +0200 Subject: [PATCH 57/57] =?UTF-8?q?=E2=80=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index dd0508f..81ed7a6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "adler2" @@ -396,7 +396,7 @@ checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" [[package]] name = "pbdbfixer" -version = "0.9.0" +version = "1.0.0" dependencies = [ "quick-xml", "rusqlite",