Files
opds-server/src/application/services/books.rs
2025-09-09 22:50:42 +03:00

101 lines
2.6 KiB
Rust

use crate::application::loaders::fs;
use crate::application::loaders::inotify;
use crate::domain::book::Book;
use crate::domain::feed::{BooksFeed, Entry};
use crate::domain::repository::{BookFilter, Repository};
use std::path::PathBuf;
use std::sync::{Arc, Mutex};
use std::{io, thread};
use url::Url;
const AUTHOR_URL_PREFIX: &str = "author";
pub struct Books {
pub repo: Arc<Mutex<Box<dyn Repository<Book, BookFilter> + 'static>>>,
root: PathBuf,
base_url: Url,
}
impl Books {
pub fn new(
repo: Arc<Mutex<Box<dyn Repository<Book, BookFilter> + 'static>>>,
root: PathBuf,
base_url: String,
) -> Self {
Books {
repo,
root,
base_url: Url::parse(&base_url).unwrap(),
}
}
fn book_entries(&self, filter: BookFilter) -> Vec<Entry> {
let mut res = self
.repo
.lock()
.unwrap()
.filter(filter)
.map(|book| Entry::from(&book))
.collect::<Vec<Entry>>();
for entry in &mut res {
for author in &mut entry.author {
author.url = self.build_author_url(author.url.as_str()).to_string();
}
}
res
}
fn build_author_url(&self, author_url: &str) -> Url {
let mut url = self.base_url.clone();
match url.join([AUTHOR_URL_PREFIX, author_url].join("/").as_str()) {
Ok(u) => url = u,
Err(err) => {
println!("{}", err);
}
}
url
}
pub fn books_feed(&self, filter: BookFilter) -> BooksFeed {
let mut feed: BooksFeed = Default::default();
feed.entry = self.book_entries(filter);
feed
}
pub fn add_books_from_path(&mut self) {
let books = fs::Loader::new(PathBuf::from(&self.root))
.into_iter()
.map(|mut book| {match book.source.strip_prefix(&self.root) {
Ok(path) => book.source = path.to_path_buf(),
Err(err) => eprintln!("strip source prefix: {}", err)
}; book})
.collect();
match self.repo.lock() {
Ok(mut repo) => {
repo.bulk_add(books);
}
Err(err) => eprintln!("{}", err),
}
}
pub fn watch_dir(&mut self) -> Result<(), io::Error> {
let root = self.root.clone();
let repo = Arc::clone(&self.repo);
let mut loader = inotify::Loader::new(root.clone())?;
thread::spawn(move || loop {
for book in loader.iter() {
repo.lock().unwrap().add(book);
}
});
Ok(())
}
}