use std::path::{Path, PathBuf};
use anyhow::Context;
use bookyard_core::{BookConfig, detect_book_source, insert_book, slugify_book_id};
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct RegisteredBook {
pub id: String,
pub title: String,
}
pub fn register_book(
source: PathBuf,
folder: String,
title: Option<String>,
id: Option<String>,
tags: Vec<String>,
) -> anyhow::Result<RegisteredBook> {
let path = crate::commands::config_path()?;
let root = crate::commands::root_dir()?;
let mut config = crate::commands::load_config()?;
let detected = detect_book_source(root.join(&source))
.with_context(|| format!("failed to detect book source at {}", source.display()))?;
let title = title
.or(detected.title)
.unwrap_or_else(|| title_from_path(&source));
let id = id.unwrap_or_else(|| slugify_book_id(&title));
let next_order = config
.books
.iter()
.map(|book| book.order)
.max()
.unwrap_or(0)
+ 10;
let mut book = BookConfig::new_mdbook(
id.clone(),
title.clone(),
path_to_config_source(&source),
vec![folder],
);
book.tags = tags;
book.order = next_order;
insert_book(&mut config, book)?;
config
.save_to(&path)
.with_context(|| format!("failed to write {}", path.display()))?;
Ok(RegisteredBook { id, title })
}
pub fn title_from_path(path: &Path) -> String {
path.file_name()
.and_then(|p| p.to_str())
.unwrap_or("Book")
.to_owned()
}
fn path_to_config_source(path: &Path) -> String {
path.to_string_lossy().replace('\\', "/")
}