Compare commits

..

8 commits
wip ... master

4 changed files with 51 additions and 55 deletions

6
Cargo.lock generated
View file

@ -330,9 +330,9 @@ dependencies = [
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.161" version = "0.2.162"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1" checksum = "18d287de67fe55fd7e1581fe933d965a5a9477b38e949cfa9f8574ef01506398"
[[package]] [[package]]
name = "libsqlite3-sys" name = "libsqlite3-sys"
@ -396,7 +396,7 @@ checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
[[package]] [[package]]
name = "pbdbfixer" name = "pbdbfixer"
version = "0.8.3" version = "0.9.0"
dependencies = [ dependencies = [
"quick-xml", "quick-xml",
"rusqlite", "rusqlite",

View file

@ -1,6 +1,6 @@
[package] [package]
name = "pbdbfixer" name = "pbdbfixer"
version = "0.8.3" version = "0.9.0"
authors = ["Martin Brodbeck <martin@brodbeck-online.de>"] authors = ["Martin Brodbeck <martin@brodbeck-online.de>"]
edition = "2021" edition = "2021"

View file

@ -1,13 +1,10 @@
# PbDbFixer # PbDbFixer
## Motivation ## Motivation
Since Pocketbook has some problems with extracting metadata correctly from 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.
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 ## 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 firstauthor entries (books_impl table)
- Correction of wrong first_author_letter entries (books_impl table) - Correction of wrong first_author_letter entries (books_impl table)
- Correction of wrong author 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**. The best results are achieved when metadata has been carefully maintained with **Calibre**.
## Compatibility ## Compatibility
This program is tested on a PocketBook This program has been tested on a PocketBook
- *Touch Lux 4* (software version 6.5) - *Touch Lux 4* (software version 6.5)
- *Touch HD 3* (software version 6.7) - *Touch HD 3* (software version 6.7)
- *Era* (software version 6.8) [^1] - *Era* (software version 6.8) [^1]
@ -28,8 +25,6 @@ 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!). 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!).
<span style="color: red">**Please note:**</span> 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 ## Installation and Usage
--- ---
**WARNING**: **WARNING**:
@ -44,17 +39,21 @@ 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.
## Feedback ## 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 ## 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] [target.armv7-unknown-linux-gnueabi]
linker = "arm-linux-gnueabi-gcc" linker = "SDKs/PB/SDK_6.3.0/SDK-B288/usr/bin/arm-obreey-linux-gnueabi-gcc"
```
Now you can easily compile the stuff by invoking
```
cargo build --release --target=arm-unknown-linux-gnueabi
``` ```
[^1]: User feedback 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

View file

@ -1,5 +1,4 @@
use std::{ use std::{
borrow::Borrow,
collections::HashMap, collections::HashMap,
fs::{self, File}, fs::{self, File},
io::Read, io::Read,
@ -61,18 +60,17 @@ fn get_rootfile(archive: &mut ZipArchive<File>) -> String {
loop { loop {
match reader.read_event_into(&mut buf) { match reader.read_event_into(&mut buf) {
Ok(Event::Start(ref e)) | Ok(Event::Empty(ref e)) 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( opf_filename = e
e.attributes() .attributes()
.filter(|attr| attr.as_ref().unwrap().key.into_inner() == b"full-path") .filter(|attr| attr.as_ref().unwrap().key.as_ref() == b"full-path")
.next() .next()
.unwrap() .unwrap()
.unwrap() .unwrap()
.value .unescape_value()
.to_vec(), .unwrap()
) .to_string();
.unwrap();
break; break;
} }
Ok(Event::Eof) => break, Ok(Event::Eof) => break,
@ -133,20 +131,20 @@ pub fn get_epub_metadata(filename: &str) -> Option<EpubMetadata> {
loop { loop {
match reader.read_event_into(&mut buf) { match reader.read_event_into(&mut buf) {
// See if we have EPUB3 or EPUB2 // 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| { 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") && attr.as_ref().unwrap().value.starts_with(b"3")
}) { }) {
is_epub3 = true; 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; creator_found = true;
if is_epub3 { if is_epub3 {
if let Some(idval) = e if let Some(idval) = e
.attributes() .attributes()
.filter(|attr| attr.as_ref().unwrap().key.into_inner() == b"id") .filter(|attr| attr.as_ref().unwrap().key.as_ref() == b"id")
.next() .next()
{ {
curr_id = "#".to_string() curr_id = "#".to_string()
@ -166,7 +164,7 @@ pub fn get_epub_metadata(filename: &str) -> Option<EpubMetadata> {
attr.as_ref() attr.as_ref()
.unwrap() .unwrap()
.key .key
.into_inner() .as_ref()
.ends_with(b"file-as") .ends_with(b"file-as")
}) })
.next() .next()
@ -175,13 +173,13 @@ pub fn get_epub_metadata(filename: &str) -> Option<EpubMetadata> {
let entry = xml_authors.entry(curr_id.clone()).or_insert(XmlAut::new()); let entry = xml_authors.entry(curr_id.clone()).or_insert(XmlAut::new());
entry.sort = file_as_val entry.sort = file_as_val
.unwrap() .unwrap()
.decode_and_unescape_value(*reader.decoder().borrow()) .unescape_value()
.unwrap_or_default() .unwrap_or_default()
.to_string(); .to_string();
entry.role = "aut".to_string(); entry.role = "aut".to_string();
} else if let Some(_role_val) = e } else if let Some(_role_val) = e
.attributes() .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() .next()
{ {
curr_id = "none".to_string() + xml_authors.len().to_string().as_str(); curr_id = "none".to_string() + xml_authors.len().to_string().as_str();
@ -200,33 +198,33 @@ pub fn get_epub_metadata(filename: &str) -> Option<EpubMetadata> {
creator_found = false; 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 if let Some(refines) = e
.attributes() .attributes()
.filter(|attr| attr.as_ref().unwrap().key.into_inner() == b"refines") .filter(|attr| attr.as_ref().unwrap().key.as_ref() == b"refines")
.next() .next()
{ {
if e.attributes().any(|attr| { 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") && attr.as_ref().unwrap().value.ends_with(b"file-as")
}) { }) {
curr_id = String::from_utf8(refines.unwrap().value.to_vec()).unwrap(); curr_id = String::from_utf8(refines.unwrap().value.to_vec()).unwrap();
file_as_found = true; file_as_found = true;
} else if e.attributes().any(|attr| { } 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") && attr.as_ref().unwrap().value.ends_with(b"role")
}) { }) {
curr_id = String::from_utf8(refines.unwrap().value.to_vec()).unwrap(); curr_id = String::from_utf8(refines.unwrap().value.to_vec()).unwrap();
role_found = true; role_found = true;
} else if e.attributes().any(|attr| { } 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") && attr.as_ref().unwrap().value.ends_with(b"group-position")
}) { }) {
series_index_found = true; series_index_found = true;
} }
} }
if e.attributes().any(|attr| { if e.attributes().any(|attr| {
attr.as_ref().unwrap().key.into_inner() == b"property" attr.as_ref().unwrap().key.as_ref() == b"property"
&& attr && attr
.as_ref() .as_ref()
.unwrap() .unwrap()
@ -236,9 +234,9 @@ pub fn get_epub_metadata(filename: &str) -> Option<EpubMetadata> {
series_found = true; 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| { if e.attributes().any(|attr| {
attr.as_ref().unwrap().key.into_inner() == b"name" attr.as_ref().unwrap().key.as_ref() == b"name"
&& attr && attr
.as_ref() .as_ref()
.unwrap() .unwrap()
@ -248,15 +246,15 @@ pub fn get_epub_metadata(filename: &str) -> Option<EpubMetadata> {
}) { }) {
epub_meta.series.name = e epub_meta.series.name = e
.attributes() .attributes()
.filter(|attr| attr.as_ref().unwrap().key.into_inner() == b"content") .filter(|attr| attr.as_ref().unwrap().key.as_ref() == b"content")
.next() .next()
.unwrap() .unwrap()
.unwrap() .unwrap()
.decode_and_unescape_value(*reader.decoder().borrow()) .unescape_value()
.unwrap_or_default() .unwrap_or_default()
.to_string(); .to_string();
} else if e.attributes().any(|attr| { } 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 && attr
.as_ref() .as_ref()
.unwrap() .unwrap()
@ -266,11 +264,11 @@ pub fn get_epub_metadata(filename: &str) -> Option<EpubMetadata> {
}) { }) {
let index_float = e let index_float = e
.attributes() .attributes()
.filter(|attr| attr.as_ref().unwrap().key.into_inner() == b"content") .filter(|attr| attr.as_ref().unwrap().key.as_ref() == b"content")
.next() .next()
.unwrap() .unwrap()
.unwrap() .unwrap()
.decode_and_unescape_value(*reader.decoder().borrow()) .unescape_value()
.unwrap_or_default() .unwrap_or_default()
.parse::<f32>() .parse::<f32>()
.unwrap_or_default(); .unwrap_or_default();
@ -302,11 +300,10 @@ pub fn get_epub_metadata(filename: &str) -> Option<EpubMetadata> {
series_index_found = false; 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; genre_found = true;
} }
Ok(Event::Text(ref e)) if genre_found => { 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(); epub_meta.genre = e.unescape().unwrap().to_string();
genre_found = false; genre_found = false;
} }