use cliclack::{confirm, input, intro, log, note, outro, password, spinner};
use ik_mini::types::StoryResponse;
use ik_mini::InkittClient;
use ik_mini_epub::download_story_to_folder;
use reqwest::Client;
use std::path::PathBuf;
use tracing_subscriber::EnvFilter;
#[tokio::main]
async fn main() -> anyhow::Result<(), anyhow::Error> {
intro("KittDownload")?;
let filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("warn"));
tracing_subscriber::fmt().with_env_filter(filter).init();
let http_client = Client::builder()
.cookie_store(true)
.user_agent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36")
.build()?;
let inkitt_client = InkittClient::new();
let story_id: u64;
loop {
let story_id_input: u64 = input("Enter Story ID")
.placeholder("e.g. 123456789")
.interact()?;
let StoryResponse {
title: story_title,
teaser: story_teaser,
age_rating: story_age_rating,
..
} = inkitt_client.story.get_story_info(story_id_input).await?;
let mut story_teaser = story_teaser;
const MAX_CAPTION_LENGTH: usize = 100;
if 0 < MAX_CAPTION_LENGTH {
let ellipsis = "...";
if story_teaser.chars().count() > MAX_CAPTION_LENGTH {
if MAX_CAPTION_LENGTH > ellipsis.len() {
let trim_to = MAX_CAPTION_LENGTH - ellipsis.len();
story_teaser = story_teaser.chars().take(trim_to).collect();
story_teaser.push_str(ellipsis);
} else {
story_teaser.clear();
}
}
} else {
story_teaser.clear();
}
note(
"Story Details",
format!(
"Title: {}\nDescription: {}\nAge Rating: {}",
story_title, story_teaser, story_age_rating
),
)?;
let is_correct = confirm("Is this the story you want to proceed?").interact()?;
if is_correct {
story_id = story_id_input;
break;
} else {
log::info("Don't worry, let's start over")?;
}
}
let include_images = confirm("Do you want to include images?").interact()?;
let semaphore_count: u64 = input(
"Please enter no of concurrent chapters to be processed concurrently. (Default is 20)",
)
.placeholder("e.g. 20")
.default_input("20")
.interact()?;
let output_dir: PathBuf =
input("Please enter output directory path (relative or absolute) (Default is current dir)")
.placeholder("Ex: C:/book_downloads")
.default_input("./")
.interact()?;
loop {
let email: String = input("Please enter your Inkitt email").interact()?;
let pass: String = password("Please enter your Inkitt password")
.mask('▪')
.interact()?;
let spin = spinner();
spin.start("Checking authentication status...");
if ik_mini_epub::login(&inkitt_client, &email, &pass)
.await
.is_ok()
{
spin.stop("Authentication successful!");
break;
} else {
spin.error("Authentication failed");
log::error("Failed to authenticate, retry.")?;
}
}
let spin = spinner();
spin.start("Processing download...");
download_story_to_folder(
&inkitt_client,
&http_client,
story_id,
include_images,
semaphore_count as usize,
&output_dir,
)
.await?;
spin.stop("Download complete!");
outro("Job's done!!!")?;
Ok(())
}