novel_cli/renderer/
mod.rs

1mod mdbook;
2mod pandoc;
3
4use std::path::Path;
5use std::{fs, thread};
6
7use color_eyre::eyre::{self, Result};
8use image::DynamicImage;
9
10pub use self::mdbook::*;
11pub use self::pandoc::*;
12use crate::utils;
13use crate::utils::{Content, Novel};
14
15#[must_use]
16fn image_markdown_str<T>(path: T) -> String
17where
18    T: AsRef<str>,
19{
20    format!("![]({})", path.as_ref())
21}
22
23fn cover_image_name(cover_image: &DynamicImage) -> Result<String> {
24    let image_ext = utils::new_image_ext(cover_image);
25
26    match image_ext {
27        Ok(image_ext) => Ok(format!("cover.{image_ext}")),
28        Err(error) => eyre::bail!("{error}"),
29    }
30}
31
32fn new_image_name(image: &DynamicImage, image_index: u16) -> Result<String> {
33    Ok(format!(
34        "{}.{}",
35        utils::num_to_str(image_index),
36        utils::new_image_ext(image)?
37    ))
38}
39
40fn save_image<T>(novel: &Novel, image_dir_path: T) -> Result<()>
41where
42    T: AsRef<Path>,
43{
44    let image_dir_path = image_dir_path.as_ref();
45    if !image_dir_path.exists() {
46        fs::create_dir_all(image_dir_path)?;
47    }
48
49    if novel.cover_image.is_some() {
50        let cover_image = novel.cover_image.as_ref().unwrap();
51        let image_ext = utils::new_image_ext(cover_image);
52
53        if let Ok(image_ext) = image_ext {
54            let image_path = image_dir_path.join(format!("cover.{image_ext}"));
55
56            if image_ext == "webp" {
57                novel_api::save_as_webp(cover_image, 75.0, image_path).unwrap_or_else(|err| {
58                    tracing::error!("Failed to save cover image: {err}");
59                });
60            } else {
61                cover_image.save(image_path).unwrap_or_else(|err| {
62                    tracing::error!("Failed to save image: {err}");
63                });
64            }
65        }
66    }
67
68    let mut images = Vec::new();
69    for volume in &novel.volumes {
70        for chapter in &volume.chapters {
71            if chapter.contents.is_some() {
72                for content in chapter.contents.as_ref().unwrap() {
73                    if let Content::Image(image) = content {
74                        images.push(image);
75                    }
76                }
77            }
78        }
79    }
80
81    thread::scope(|s| {
82        let mut image_index = 1;
83
84        for image in images {
85            let image_ext = utils::new_image_ext(image);
86
87            if let Ok(image_ext) = image_ext {
88                let image_name = format!("{}.{}", utils::num_to_str(image_index), image_ext);
89                image_index += 1;
90
91                let image_path = image_dir_path.join(image_name);
92
93                if image_ext == "webp" {
94                    s.spawn(|| {
95                        novel_api::save_as_webp(image, 75.0, image_path).unwrap_or_else(|err| {
96                            tracing::error!("Failed to save cover image: {err}");
97                        });
98                    });
99                } else {
100                    s.spawn(|| {
101                        image.save(image_path).unwrap_or_else(|err| {
102                            tracing::error!("Failed to save image: {err}");
103                        });
104                    });
105                }
106            }
107        }
108    });
109
110    Ok(())
111}