diff --git a/Cargo.lock b/Cargo.lock index fd7ac1f..7a1cb7b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -148,7 +148,7 @@ dependencies = [ [[package]] name = "pbdbfixer" -version = "0.2.0" +version = "0.1.0" dependencies = [ "rusqlite", "xml-rs", diff --git a/Cargo.toml b/Cargo.toml index 7fef784..2f59c6a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pbdbfixer" -version = "0.2.0" +version = "0.1.0" authors = ["Martin Brodbeck "] edition = "2018" diff --git a/README.md b/README.md index cc9d175..34c14c1 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ applications screen and tap on the PbDbFixer icon. 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`: +invoke. In my case, I hat to edit `~/.cargo/config`: ``` [target.arm-unknown-linux-gnueabi] linker = "arm-linux-gnueabi-gcc" diff --git a/src/main.rs b/src/main.rs index 8273e8d..7ac6f4b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,6 @@ mod pocketbook; -use rusqlite::{named_params, Connection, Result, Transaction, NO_PARAMS}; +use rusqlite::{named_params, Connection, Result, NO_PARAMS}; use std::error::Error; use std::fs::File; use std::io::BufReader; @@ -60,6 +60,7 @@ fn get_attribute_file_as(opf: ZipFile) -> Option { }) if name.local_name == "creator" => { for attr in attributes { if attr.name.local_name == "file-as" { + println!("File-as: {}", &attr.value); return Some(attr.value); } if is_epub3 && attr.name.local_name == "id" { @@ -111,72 +112,74 @@ struct BookEntry { filepath: String, } -fn fix_firstauthor(tx: &Transaction) -> i32 { +fn main() { let mut authors_fixed = 0; - // Get book ids from entries where we have something like "firstname lastname" in author - // but no "lastname, firstname" in fistauthor - // Get also book ids from the special case where we have multiple authors (separated by ", " in authors) - // but no ampersand ("&") in firstauthor - let mut stmt = tx.prepare(r" - SELECT files.book_id, folders.name, files.filename - FROM files INNER JOIN folders - ON files.folder_id = folders.id - WHERE files.book_id IN - ( - SELECT DISTINCT id FROM books_impl - WHERE (ext LIKE 'epub' AND author LIKE '% %' AND (firstauthor NOT LIKE '%\,%' ESCAPE '\' OR firstauthor LIKE '%&%')) - OR (ext LIKE 'epub' AND author LIKE '%\, %' ESCAPE '\' AND firstauthor NOT LIKE '%&%') - ) - AND files.storageid = 1 - ;").unwrap(); + let mut conn = Connection::open("/mnt/ext1/system/explorer-3/explorer-3.db").unwrap(); + let tx = conn.transaction().unwrap(); + { + // Get book ids from entries where we have something like "firstname lastname" in author + // but no "lastname, firstname" in fistauthor + let mut stmt = tx.prepare("SELECT id FROM books_impl WHERE ext LIKE 'epub' AND author LIKE '% %' AND (firstauthor NOT LIKE '%\\,%' ESCAPE '\\' OR firstauthor LIKE '%&%')").unwrap(); + let mut rows = stmt.query(NO_PARAMS).unwrap(); + let mut book_ids: Vec = Vec::new(); + while let Some(row) = rows.next().unwrap() { + book_ids.push(row.get(0).unwrap()); + } - let mut rows = stmt.query(NO_PARAMS).unwrap(); - let mut bookentries = Vec::new(); + // Get also book ids from the special case where we have multiple authors (separated by ", " in authors) + // but no ampersand ("&") in firstauthor + let mut stmt = tx.prepare("SELECT id FROM books_impl WHERE ext LIKE 'epub' AND author LIKE '%\\, %' ESCAPE '\\' AND firstauthor NOT LIKE '%&%'").unwrap(); + let mut rows = stmt.query(NO_PARAMS).unwrap(); + while let Some(row) = rows.next().unwrap() { + book_ids.push(row.get(0).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); - bookentries.push(BookEntry { - id: book_id, - filepath, - }); - } + book_ids.sort(); + book_ids.dedup(); - for entry in bookentries { - let file = File::open(entry.filepath.as_str()); - let file = match file { - Err(_) => continue, - Ok(file) => file, - }; + let mut bookentries = Vec::new(); - let mut archive = ZipArchive::new(BufReader::new(file)).unwrap(); + for book_id in book_ids { + let mut stmt = tx.prepare("SELECT folders.name,files.filename FROM files,folders WHERE files.book_id = :book_id AND files.storageid = 1 AND files.folder_id = folders.id").unwrap(); + let mut rows = stmt + .query_named(named_params! { ":book_id": book_id }) + .unwrap(); + while let Some(row) = rows.next().unwrap() { + let prefix: String = row.get(0).unwrap(); + let filename: String = row.get(1).unwrap(); + let filepath = format!("{}/{}", prefix, filename); + bookentries.push(BookEntry { + id: book_id, + filepath: filepath, + }); + } + } - let container = archive.by_name("META-INF/container.xml").unwrap(); + for entry in bookentries { + let file = File::open(entry.filepath.as_str()); + let file = match file { + Err(_) => continue, + Ok(file) => file, + }; - if let Some(opf_file) = get_root_file(container).unwrap() { - let opf = archive.by_name(opf_file.as_str()).unwrap(); - if let Some(file_as) = get_attribute_file_as(opf) { - 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(); - authors_fixed = authors_fixed + 1; + let mut archive = ZipArchive::new(BufReader::new(file)).unwrap(); + + 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(); + if let Some(file_as) = get_attribute_file_as(opf) { + 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(); + authors_fixed = authors_fixed + 1; + } } } } - - authors_fixed -} - -fn main() { - let mut conn = Connection::open("/mnt/ext1/system/explorer-3/explorer-3.db").unwrap(); - - let tx = conn.transaction().unwrap(); - let authors_fixed = fix_firstauthor(&tx); tx.commit().unwrap(); if cfg!(target_arch = "arm") {