From 7deb8e5bfc9eff514153ded2903d4c7b9542ee55 Mon Sep 17 00:00:00 2001 From: Sebastian Hugentobler Date: Wed, 26 Jun 2024 22:35:03 +0200 Subject: [PATCH] bring back full covers if needed --- Cargo.lock | 86 ++++++++++++------------- Cargo.toml | 4 +- Containerfile | 15 +++-- README.md | 13 ++-- little-hesinde/Cargo.toml | 16 ++--- little-hesinde/src/cache.rs | 10 +-- little-hesinde/src/handlers/cover.rs | 70 ++++++++++++++++---- little-hesinde/src/lib.rs | 10 ++- little-hesinde/templates/book_card.html | 2 +- 9 files changed, 142 insertions(+), 84 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 07db29f..4cf885a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -150,12 +150,6 @@ version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - [[package]] name = "bitflags" version = "2.5.0" @@ -251,9 +245,9 @@ dependencies = [ [[package]] name = "chrono-tz" -version = "0.8.6" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d59ae0466b83e838b81a54256c39d5d7c20b9d7daa10510a242d9b75abd5936e" +checksum = "93698b29de5e97ad0ae26447b344c482a7284c737d9ddc5f9e52b74a336671bb" dependencies = [ "chrono", "chrono-tz-build", @@ -262,9 +256,9 @@ dependencies = [ [[package]] name = "chrono-tz-build" -version = "0.2.1" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "433e39f13c9a060046954e0592a8d0a4bcb1040125cbf91cb8ee58964cfb350f" +checksum = "0c088aee841df9c3041febbb73934cfc39708749bf96dc827e3359cd39ef11b1" dependencies = [ "parse-zoneinfo", "phf", @@ -273,9 +267,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.4" +version = "4.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0" +checksum = "5db83dced34638ad474f39f250d7fea9598bdd239eaced1bdf45d597da0f433f" dependencies = [ "clap_builder", "clap_derive", @@ -283,9 +277,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.2" +version = "4.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4" +checksum = "f7e204572485eb3fbf28f871612191521df159bc3e15a9f5064c66dba3a8c05f" dependencies = [ "anstream", "anstyle", @@ -295,9 +289,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.4" +version = "4.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64" +checksum = "c780290ccf4fb26629baa7a1081e68ced113f1d3ec302fa5948f1c381ebf06c6" dependencies = [ "heck", "proc-macro2", @@ -619,11 +613,11 @@ dependencies = [ [[package]] name = "globwalk" -version = "0.8.1" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93e3af942408868f6934a7b85134a3230832b9977cf66125df2f9edcfce4ddcc" +checksum = "0bf760ebf69878d9fd8f110c89703d90ce35095324d1f1edcb595c63945ee757" dependencies = [ - "bitflags 1.3.2", + "bitflags", "ignore", "walkdir", ] @@ -944,7 +938,7 @@ checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" [[package]] name = "little-hesinde" -version = "0.2.3" +version = "0.3.0" dependencies = [ "calibre-db", "clap", @@ -1039,7 +1033,7 @@ version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab2156c4fce2f8df6c499cc1c763e4394b7482525bf2a9701c9d79d215f519e4" dependencies = [ - "bitflags 2.5.0", + "bitflags", "cfg-if", "cfg_aliases", "libc", @@ -1242,9 +1236,9 @@ checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" [[package]] name = "poem" -version = "3.0.0" +version = "3.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b735eaaaa6bc7ed2dcbcab1d5373afe1f6d03a37d8695ba3c42101f733a8455" +checksum = "e88b6912ed1e8833d7c22c9c986c517f4518d7d37e3c04566d917c789aaea591" dependencies = [ "bytes", "futures-util", @@ -1416,7 +1410,7 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "469052894dcb553421e483e4209ee581a45100d31b4018de03e5a7ad86374a7e" dependencies = [ - "bitflags 2.5.0", + "bitflags", ] [[package]] @@ -1463,7 +1457,7 @@ version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b838eba278d213a8beaf485bd313fd580ca4505a00d5871caeb1457c55322cae" dependencies = [ - "bitflags 2.5.0", + "bitflags", "fallible-iterator", "fallible-streaming-iterator", "hashlink", @@ -1474,9 +1468,9 @@ dependencies = [ [[package]] name = "rust-embed" -version = "8.3.0" +version = "8.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb78f46d0066053d16d4ca7b898e9343bc3530f71c61d5ad84cd404ada068745" +checksum = "19549741604902eb99a7ed0ee177a0663ee1eda51a29f71401f166e47e77806a" dependencies = [ "rust-embed-impl", "rust-embed-utils", @@ -1485,9 +1479,9 @@ dependencies = [ [[package]] name = "rust-embed-impl" -version = "8.3.0" +version = "8.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b91ac2a3c6c0520a3fb3dd89321177c3c692937c4eb21893378219da10c44fc8" +checksum = "cb9f96e283ec64401f30d3df8ee2aaeb2561f34c824381efa24a35f79bf40ee4" dependencies = [ "proc-macro2", "quote", @@ -1498,9 +1492,9 @@ dependencies = [ [[package]] name = "rust-embed-utils" -version = "8.3.0" +version = "8.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86f69089032567ffff4eada41c573fc43ff466c7db7c5688b2e7969584345581" +checksum = "38c74a686185620830701348de757fd36bef4aa9680fd23c49fc539ddcc1af32" dependencies = [ "sha2", "walkdir", @@ -1518,7 +1512,7 @@ version = "0.38.34" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" dependencies = [ - "bitflags 2.5.0", + "bitflags", "errno", "libc", "linux-raw-sys", @@ -1557,18 +1551,18 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "serde" -version = "1.0.200" +version = "1.0.203" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddc6f9cc94d67c0e21aaf7eda3a010fd3af78ebf6e096aa6e2e13c79749cce4f" +checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.200" +version = "1.0.203" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "856f046b9400cee3c8c94ed572ecdb752444c24528c035cd35882aad6f492bcb" +checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" dependencies = [ "proc-macro2", "quote", @@ -1577,9 +1571,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.116" +version = "1.0.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e17db7126d17feb94eb3fad46bf1a96b034e8aacbc2e775fe81505f8b0b2813" +checksum = "d947f6b3163d8857ea16c4fa0dd4840d52f3041039a85decd46867eb1abef2e4" dependencies = [ "itoa", "ryu", @@ -1761,9 +1755,9 @@ dependencies = [ [[package]] name = "tera" -version = "1.19.1" +version = "1.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "970dff17c11e884a4a09bc76e3a17ef71e01bb13447a11e85226e254fe6d10b8" +checksum = "ab9d851b45e865f178319da0abdbfe6acbc4328759ff18dafc3a41c16b4cd2ee" dependencies = [ "chrono", "chrono-tz", @@ -1844,9 +1838,9 @@ dependencies = [ [[package]] name = "tokio" -version = "1.37.0" +version = "1.38.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1adbebffeca75fcfd058afa480fb6c0b81e165a0323f9c9d39c9697e37c46787" +checksum = "ba4f4a02a7a80d6f274636f0aa95c7e383b912d41fe721a31f29e29698585a4a" dependencies = [ "backtrace", "bytes", @@ -1862,9 +1856,9 @@ dependencies = [ [[package]] name = "tokio-macros" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" +checksum = "5f5ae998a069d4b5aba8ee9dad856af7d520c3699e6159b185c2acd48155d39a" dependencies = [ "proc-macro2", "quote", @@ -2052,9 +2046,9 @@ checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" [[package]] name = "uuid" -version = "1.8.0" +version = "1.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a183cf7feeba97b4dd1c0d46788634f6221d87fa961b305bed08c851829efcc0" +checksum = "5de17fd2f7da591098415cff336e12965a28061ddace43b59cb3c430179c9439" dependencies = [ "getrandom", "rand", diff --git a/Cargo.toml b/Cargo.toml index dcf3448..44a1952 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,8 +5,8 @@ members = [ ] [workspace.dependencies] -serde = "1.0.200" -thiserror = "1.0.59" +serde = "1.0.203" +thiserror = "1.0.61" time = { version = "0.3.36", features = ["macros", "serde", "formatting", "parsing" ] } [workspace.package] diff --git a/Containerfile b/Containerfile index ae22d10..d82e1ec 100644 --- a/Containerfile +++ b/Containerfile @@ -1,5 +1,8 @@ FROM docker.io/rust:1-alpine3.20 AS builder +RUN mkdir /tmp/tmp +RUN echo "hesinde:x:2222:2222:Linux User,,,:/:/app" > /passwd + RUN apk --no-cache add \ musl-dev @@ -13,12 +16,16 @@ COPY . . RUN cargo build --release --target=$(arch)-unknown-linux-musl RUN cp "./target/$(arch)-unknown-linux-musl/release/little-hesinde" /app - FROM scratch +COPY --from=builder /passwd /etc/passwd COPY --from=builder /app /app -CMD ["/app", "--listen-address", "[::]:3000", "--", "/library"] +COPY --from=builder --chown=2222: /tmp/tmp /tmp -ENV TMPDIR=/ -VOLUME ["/library"] +USER hesinde + +CMD ["/app", "--listen-address", "[::]:3000", "--cache-path", "/tmp/cache", "--", "/library"] + +ENV TMPDIR=/tmp +VOLUME ["/library", "/tmp"] EXPOSE 3000 diff --git a/README.md b/README.md index 26ba9f5..92316fc 100644 --- a/README.md +++ b/README.md @@ -37,12 +37,17 @@ From there on `cargo run` and `cargo build` and so on can be used. Usage: little-hesinde [OPTIONS] -- Arguments: - Calibre library path + Calibre library path [env: LIBRARY_PATH=] Options: - -l, --listen-address Address to listen on [default: [::1]:3000] - -h, --help Print help - -V, --version Print version + -l, --listen-address + Address to listen on [env: LISTEN_ADDRESS=] [default: [::1]:3000] + -c, --cache-path + Cache path ($TMP cascades through $XDG_CACHE_HOME, $TMPDIR and /tmp) [env: CACHE_PATH=] [default: $TMP/little-hesinde] + -h, --help + Print help + -V, --version + Print version ``` Example: `little-hesinde -l [::]4000 -- ~/Documents/library/` diff --git a/little-hesinde/Cargo.toml b/little-hesinde/Cargo.toml index f1d622c..06a5985 100644 --- a/little-hesinde/Cargo.toml +++ b/little-hesinde/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "little-hesinde" -version = "0.2.3" +version = "0.3.0" edition = "2021" license = { workspace = true } authors = { workspace = true } @@ -9,23 +9,23 @@ description = "A very simple ebook server for a calibre library, providing a htm [dependencies] calibre-db = { path = "../calibre-db/", version = "0.1.0" } -clap = { version = "4.5.4", features = ["derive", "env"] } +clap = { version = "4.5.7", features = ["derive", "env"] } image = { version = "0.25.1", default-features = false, features = ["jpeg", "rayon"] } once_cell = "1.19.0" -poem = { version = "3.0.0", features = ["embed", "static-files"] } -rust-embed = "8.3.0" +poem = { version = "3.0.1", features = ["embed", "static-files"] } +rust-embed = "8.4.0" sha2 = "0.10.8" serde = { workspace = true } -serde_json = "1.0.116" +serde_json = "1.0.118" serde_with = "3.8.1" -tera = "1.19.1" +tera = "1.20.0" thiserror = { workspace = true } time = { workspace = true } -tokio = { version = "1.37.0", features = ["signal", "rt-multi-thread", "macros"] } +tokio = { version = "1.38.0", features = ["signal", "rt-multi-thread", "macros"] } tokio-util = "0.7.11" tracing = "0.1.40" tracing-subscriber = "0.3.18" -uuid = { version = "1.8.0", features = ["v4", "fast-rng"] } +uuid = { version = "1.9.1", features = ["v4", "fast-rng"] } quick-xml = { version = "0.34.0", features = ["serialize"] } [build-dependencies] diff --git a/little-hesinde/src/cache.rs b/little-hesinde/src/cache.rs index d9da937..ddf01e2 100644 --- a/little-hesinde/src/cache.rs +++ b/little-hesinde/src/cache.rs @@ -1,7 +1,7 @@ //! Handle caching of files, specifically book covers. use std::{ - fs, + fs::{self, File}, path::{Path, PathBuf}, }; @@ -11,7 +11,6 @@ use sha2::{ }; use std::fmt::Write; use thiserror::Error; -use tokio::fs::File; use tracing::debug; /// Errors from dealing with file caching. @@ -59,8 +58,9 @@ fn create_thumbnail(cover_path: &Path, thumbnail_path: &Path) -> Result<(), Cach .ok_or_else(|| CacheError::ThumbnailPathError(thumbnail_path.to_path_buf()))?; fs::create_dir_all(folders)?; + const THUMBNAIL_SIZE: u32 = 512; let img = image::open(cover_path)?; - let thumbnail = img.thumbnail(512, 512); + let thumbnail = img.thumbnail(THUMBNAIL_SIZE, THUMBNAIL_SIZE); thumbnail.save_with_format(thumbnail_path, image::ImageFormat::Jpeg)?; debug!("saved thumbnail to {}", thumbnail_path.to_string_lossy()); @@ -70,7 +70,7 @@ fn create_thumbnail(cover_path: &Path, thumbnail_path: &Path) -> Result<(), Cach /// Get the thumbnail for a book cover. /// /// If a thumbnail does not yet exist, create it. -pub async fn get_thumbnail(cover_path: &Path, cache_path: &Path) -> Result { +pub fn get_thumbnail(cover_path: &Path, cache_path: &Path) -> Result { let path_str = cover_path.to_string_lossy(); let mut hasher = Sha256::new(); hasher.update(path_str.as_bytes()); @@ -82,5 +82,5 @@ pub async fn get_thumbnail(cover_path: &Path, cache_path: &Path) -> Result, + state: Data<&Arc>, +) -> Result { + cover( + &state.calibre, + &state.config, + *id, + |cover_path, cache_path| Ok(cache::get_thumbnail(cover_path, cache_path)?), + ) + .await +} /// Handle a request for the cover image of book with id `id`. #[handler] -pub async fn handler(id: Path, state: Data<&Arc>) -> Result { - let book = state - .calibre - .scalar_book(*id) - .map_err(HandlerError::DataError)?; - let cover_path = state.config.library_path.join(book.path).join("cover.jpg"); +pub async fn handler_full( + id: Path, + state: Data<&Arc>, +) -> Result { + cover(&state.calibre, &state.config, *id, |cover_path, _| { + Ok(File::open(cover_path)?) + }) + .await +} - let mut cover = cache::get_thumbnail(&cover_path, &state.config.cache_path) - .await - .map_err(|_| NotFoundError)?; +async fn cover( + calibre: &Calibre, + config: &Config, + id: u64, + f: F, +) -> Result +where + F: Fn(&FilePath, &FilePath) -> Result, +{ + let book = calibre.scalar_book(id).map_err(HandlerError::DataError)?; + let cover_path = config.library_path.join(book.path).join("cover.jpg"); + + let cover = f(&cover_path, &config.cache_path).map_err(|_| NotFoundError)?; + let cover = AsyncFile::from_std(cover); crate::handlers::download::handler("cover.jpg", cover, &ContentType::jpeg().to_string()).await } diff --git a/little-hesinde/src/lib.rs b/little-hesinde/src/lib.rs index ade7dc5..3bdc615 100644 --- a/little-hesinde/src/lib.rs +++ b/little-hesinde/src/lib.rs @@ -77,7 +77,7 @@ pub mod opds { pub mod templates; pub const APP_NAME: &str = "little-hesinde"; -pub const VERSION: &str = "0.2.3"; +pub const VERSION: &str = "0.3.0"; /// Internal marker data in lieu of a proper `Accept` header. #[derive(Debug, Clone, Copy)] @@ -117,7 +117,11 @@ pub async fn run(config: Config) -> Result<(), std::io::Error> { "/authors/:cursor/:sort_order", get(handlers::authors::handler), ) - .at("/cover/:id", get(handlers::cover::handler)) + .at("/cover/:id", get(handlers::cover::handler_full)) + .at( + "/cover/:id/thumbnail", + get(handlers::cover::handler_thumbnail), + ) .at("/book/:id/:format", get(handlers::books::handler_download)) .at("/archive", get(handlers::source_archive::handler)) .at("/search", get(handlers::search::handler)) @@ -143,7 +147,7 @@ pub async fn run(config: Config) -> Result<(), std::io::Error> { .with(Tracing); let server = Server::new(TcpListener::bind(config.listen_address)) - .name("cops-web") + .name("little-hesinde") .run(app); tokio::select! { diff --git a/little-hesinde/templates/book_card.html b/little-hesinde/templates/book_card.html index db491eb..1549cb4 100644 --- a/little-hesinde/templates/book_card.html +++ b/little-hesinde/templates/book_card.html @@ -14,7 +14,7 @@ {% endif %} - book cover + book cover