Skip to content

Commit

Permalink
feat!: add M+ source (#34)
Browse files Browse the repository at this point in the history
Closes #30
  • Loading branch information
noaione authored May 17, 2024
1 parent 263a953 commit d019f42
Show file tree
Hide file tree
Showing 43 changed files with 5,252 additions and 167 deletions.
9 changes: 8 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,13 @@
"**/.qt_for_python": true,
"**/.pytest_cache": true,
"**/.mypy_cache": true,
"**/.ruff_cache": true
"**/.ruff_cache": true,
"**/target/release/deps": true,
"**/target/release/incremental": true,
"**/target/release/.fingerprint": true,
"**/target/debug/deps": true,
"**/target/debug/incremental": true,
"**/target/debug/.fingerprint": true,
"**/target/doc": true,
},
}
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ Starting from Rust port of the project, all changes will be put into this file.

## Unreleased (git master)
### New Features
- Add **`MPlus`** as a new source
- `MU`: Support downloading with subscriptions
- Add command to clear cache for all sources: `tosho tools clear-cache`

### Changes
- All source: Force use `rustls` and use `http2` adaptive window for reqwest client.
Expand All @@ -16,6 +18,7 @@ Starting from Rust port of the project, all changes will be put into this file.
- `AM`: Add title information when purchasing/downloading
- `SJ/M`: Early fetch chapters information
- Refactor some duplicate code
- Changes all `ToString` occurences to `std::fmt::Display`

### Build
- Bump `reqwest` to 0.12 (use hyper v1)
Expand Down
17 changes: 17 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ members = [
"tosho_amap",
"tosho_sjv",
"tosho_rbean",
"tosho_mplus",
"tosho_macros",
]

Expand Down
24 changes: 16 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,18 +28,16 @@ This is just a fun side project, and as a disclaimer, I'm not condoning anything

## Installation

**Requirements**:
- Rust 1.72+ (If manually building or using `cargo`)
- 64-bit devices (ARM64/aarch64 support might be experimental)
- Modern enough terminal (VT support)

`tosho` comes with a pre-compiled binary that you can choose:
- The **Stable** release in the **[Releases](https://github.com/noaione/tosho-mango/releases)** tab.
- The **Nightly** release from any latest successful commits: [Master CI](https://github.com/noaione/tosho-mango/actions/workflows/ci.yml?query=branch%3Amaster) / [nightly.link](https://nightly.link/noaione/tosho-mango/workflows/ci/master?preview).

Or, if you have Rust you can do the following:

**Requirements:**
- Rust 1.72+
- 64-bit devices (ARM64/aarch64 support might be experimental)
- Modern enough terminal (VT support)

Installing with `cargo`:
You can also utilize `cargo`:
```bash
cargo install --locked tosho
```
Expand All @@ -61,6 +59,16 @@ For a list of available commands, use the `--help` argument.

[![asciicast](https://asciinema.org/a/636303.svg)](https://asciinema.org/a/636303)

## Supported Platform

We support the following platform:
- [MU! by SQ](https://github.com/noaione/tosho-mango/tree/master/tosho_musq) (Android, Apple)
- [KM by KC](https://github.com/noaione/tosho-mango/tree/master/tosho_kmkc) (Android, Apple, Web)
- [AM by AP](https://github.com/noaione/tosho-mango/tree/master/tosho_amap) (Android)
- [SJ/M by V](https://github.com/noaione/tosho-mango/tree/master/tosho_sjv) (Android, Apple, Web)
- [小豆 (Red Bean) by KRKR](https://github.com/noaione/tosho-mango/tree/master/tosho_rbean) (Android)
- [M+ by S](https://github.com/noaione/tosho-mango/tree/master/tosho_mplus) (Android)

## License

[MIT License](LICENSE)
Expand Down
1 change: 1 addition & 0 deletions tosho/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ tosho-kmkc = { path = "../tosho_kmkc", version = "=0.3.4" }
tosho-amap = { path = "../tosho_amap", version = "=0.3.3" }
tosho-sjv = { path = "../tosho_sjv", version = "=0.3.5" }
tosho-rbean = { path = "../tosho_rbean", version = "=0.1.3" }
tosho-mplus = { path = "../tosho_mplus", version = "=0.1.0" }
tosho-macros = { path = "../tosho_macros", version = "0.3" }

# External deps
Expand Down
7 changes: 6 additions & 1 deletion tosho/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ Currently we support the following source:
- [AM by AP](https://crates.io/crates/tosho-amap)
- [SJ/M by V](https://crates.io/crates/tosho-sjv)
- [小豆 (Red Bean) by KRKR](https://crates.io/crates/tosho-rbean)
- [M+ by S](https://crates.io/crates/tosho-mplus)

## Installation

Expand All @@ -27,6 +28,10 @@ Or, if you have [cargo-binstall](https://github.com/cargo-bins/cargo-binstall)..
cargo binstall --locked tosho
```

We also provide a pre-built binary in two flavours:
- **Stable** release in the **[GitHub Releases](https://github.com/noaione/tosho-mango/releases)** tab.
- **Nightly** release from any latest successful commits: [Master CI](https://github.com/noaione/tosho-mango/actions/workflows/ci.yml?query=branch%3Amaster) / [nightly.link](https://nightly.link/noaione/tosho-mango/workflows/ci/master?preview).

## Usage

Refer to the [repo](tosho) on how to authenticate with each source.<br />
Expand All @@ -44,4 +49,4 @@ We're not responsible if your account got deactivated.

This project is licensed with MIT License ([LICENSE](https://github.com/noaione/tosho-mango/blob/master/LICENSE) or http://opensource.org/licenses/MIT)

[tosho]: https://github.com/noaione/tosho-mango
[tosho]: https://github.com/noaione/tosho-mango
14 changes: 14 additions & 0 deletions tosho/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,20 @@ pub(crate) enum ToshoCommands {
#[command(subcommand)]
subcommand: crate::r#impl::rbean::RBeanCommands,
},
/// Download manga from M+
#[command(name = "mp")]
Mplus {
/// Account ID to use
#[arg(short = 'a', long = "account", default_value = None)]
account_id: Option<String>,

/// Language to use
#[arg(short = 'l', long = "language", value_enum, default_value = "en")]
language: Option<crate::r#impl::mplus::MPlusLanguage>,

#[command(subcommand)]
subcommand: crate::r#impl::mplus::MPlusCommands,
},
/// Additional tools to manage your downloaded manga
Tools {
#[command(subcommand)]
Expand Down
24 changes: 24 additions & 0 deletions tosho/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ pub enum ConfigImpl {
Amap(crate::r#impl::amap::config::Config),
Sjv(crate::r#impl::sjv::config::Config),
Rbean(crate::r#impl::rbean::config::Config),
Mplus(crate::r#impl::mplus::config::Config),
}

// Adapt web/mobile
Expand All @@ -87,6 +88,7 @@ impl_from_config!(crate::r#impl::musq::config::Config, Musq);
impl_from_config!(crate::r#impl::amap::config::Config, Amap);
impl_from_config!(crate::r#impl::sjv::config::Config, Sjv);
impl_from_config!(crate::r#impl::rbean::config::Config, Rbean);
impl_from_config!(crate::r#impl::mplus::config::Config, Mplus);

pub(crate) fn get_user_path() -> std::path::PathBuf {
#[cfg(windows)]
Expand Down Expand Up @@ -173,6 +175,13 @@ config_reader!(
crate::r#impl::rbean::config::PREFIX
);

config_reader!(
read_mplus_config,
get_config_mplus,
crate::r#impl::mplus::config::Config,
crate::r#impl::mplus::config::PREFIX
);

pub fn get_config(
id: &str,
r#impl: &Implementations,
Expand Down Expand Up @@ -201,6 +210,10 @@ pub fn get_config(
let conf = get_config_rbean(id, user_path);
conf.map(ConfigImpl::Rbean)
}
Implementations::Mplus => {
let conf = get_config_mplus(id, user_path);
conf.map(ConfigImpl::Mplus)
}
}
}

Expand All @@ -219,6 +232,7 @@ pub fn get_all_config(r#impl: &Implementations, user_path: Option<PathBuf>) -> V
Implementations::Amap => crate::r#impl::amap::config::PREFIX,
Implementations::Sjv => crate::r#impl::sjv::config::PREFIX,
Implementations::Rbean => crate::r#impl::rbean::config::PREFIX,
Implementations::Mplus => crate::r#impl::mplus::config::PREFIX,
};
glob_path.push(format!("{}.*.tmconf", prefix));

Expand Down Expand Up @@ -258,6 +272,12 @@ pub fn get_all_config(r#impl: &Implementations, user_path: Option<PathBuf>) -> V
matched_entries.push(ConfigImpl::Rbean(conf));
}
}
Implementations::Mplus => {
let conf = read_mplus_config(entry);
if let Some(conf) = conf {
matched_entries.push(ConfigImpl::Mplus(conf));
}
}
}
}
matched_entries
Expand Down Expand Up @@ -309,6 +329,9 @@ pub fn save_config(config: ConfigImpl, user_path: Option<PathBuf>) {
ConfigImpl::Rbean(config) => {
save_config_impl!(crate::r#impl::rbean::config::PREFIX, user_path, config)
}
ConfigImpl::Mplus(config) => {
save_config_impl!(crate::r#impl::mplus::config::PREFIX, user_path, config)
}
}
}

Expand All @@ -326,6 +349,7 @@ pub fn try_remove_config(
Implementations::Amap => crate::r#impl::amap::config::PREFIX,
Implementations::Sjv => crate::r#impl::sjv::config::PREFIX,
Implementations::Rbean => crate::r#impl::rbean::config::PREFIX,
Implementations::Mplus => crate::r#impl::mplus::config::PREFIX,
};
user_conf.push(format!("{}.{}.tmconf", prefix, id));

Expand Down
31 changes: 5 additions & 26 deletions tosho/src/impl/amap/download.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@ use tosho_amap::{

use crate::{
cli::ExitCode,
r#impl::models::{ChapterDetailDump, MangaDetailDump},
r#impl::{
common::check_downloaded_image_count,
models::{ChapterDetailDump, MangaDetailDump},
},
};

use super::{common::common_purchase_select, config::Config};
Expand All @@ -36,30 +39,6 @@ pub(crate) struct AMDownloadCliConfig {
pub(crate) no_purchased: bool,
}

fn check_downloaded_image_count(image_dir: &PathBuf) -> Option<usize> {
// check if dir exist
if !image_dir.exists() {
return None;
}

// check if dir is dir
if !image_dir.is_dir() {
return None;
}

// check how many .jpg files in the dir
let mut count = 0;
for entry in std::fs::read_dir(image_dir).unwrap() {
let entry = entry.unwrap();
let path = entry.path();
if path.is_file() && path.extension().unwrap() == "jpg" {
count += 1;
}
}

Some(count)
}

fn create_chapters_info(manga_detail: ComicInfo) -> MangaDetailDump {
let mut chapters: Vec<ChapterDetailDump> = vec![];
for chapter in manga_detail.episodes {
Expand Down Expand Up @@ -291,7 +270,7 @@ pub(crate) async fn amap_download(
let ch_pages = ch_view.info.pages;
let ch_dir =
get_output_directory(&output_dir, title_id, Some(chapter.info.id), false);
if let Some(count) = check_downloaded_image_count(&ch_dir) {
if let Some(count) = check_downloaded_image_count(&ch_dir, "jpg") {
if count >= ch_pages.len() {
console.warn(&cformat!(
" Chapter <m,s>{}</> (<s>{}</>) has been downloaded, skipping",
Expand Down
23 changes: 23 additions & 0 deletions tosho/src/impl/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,19 @@ pub(crate) fn select_single_account(
name: c.id.clone(),
value: format!("{} [{} - {}]", c.id, c.email, c.platform().to_name()),
},
crate::config::ConfigImpl::Mplus(c) => ConsoleChoice {
name: c.id.clone(),
value: if c.username.is_some() {
format!(
"{} [{} - {}]",
c.id,
c.username.as_ref().unwrap(),
c.r#type().to_name()
)
} else {
format!("{} [{}]", c.id, c.r#type().to_name())
},
},
})
.collect();

Expand Down Expand Up @@ -85,6 +98,7 @@ pub(crate) fn select_single_account(
crate::config::ConfigImpl::Musq(c) => c.id == selected.name,
crate::config::ConfigImpl::Sjv(c) => c.id == selected.name,
crate::config::ConfigImpl::Rbean(c) => c.id == selected.name,
crate::config::ConfigImpl::Mplus(c) => c.id == selected.name,
})
.unwrap();

Expand Down Expand Up @@ -119,3 +133,12 @@ pub(crate) fn make_sjv_client(config: &super::sjv::config::Config) -> tosho_sjv:
pub(crate) fn make_rbean_client(config: &super::rbean::config::Config) -> tosho_rbean::RBClient {
tosho_rbean::RBClient::new(config.clone().into())
}

pub(crate) fn make_mplus_client(
config: &super::mplus::config::Config,
language: tosho_mplus::proto::Language,
) -> tosho_mplus::MPClient {
let constants = tosho_mplus::constants::get_constants(config.r#type() as u8);

tosho_mplus::MPClient::new(&config.session, language, constants)
}
48 changes: 48 additions & 0 deletions tosho/src/impl/common.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::{path::PathBuf, sync::Arc};

use chrono::TimeZone;

pub(super) fn unix_timestamp_to_string(timestamp: i64) -> Option<String> {
Expand All @@ -13,3 +15,49 @@ pub(super) fn unix_timestamp_to_string(timestamp: i64) -> Option<String> {
None => None,
}
}

pub(super) fn check_downloaded_image_count(image_dir: &PathBuf, extension: &str) -> Option<usize> {
// check if dir exist
if !image_dir.exists() {
return None;
}

// check if dir is dir
if !image_dir.is_dir() {
return None;
}

// check how many .[extension] files in the dir
let mut count = 0;
for entry in std::fs::read_dir(image_dir).unwrap() {
let entry = entry.unwrap();
let path = entry.path();
if path.is_file() && path.extension().unwrap_or_default() == extension {
count += 1;
}
}

Some(count)
}

/// Create an Atomic Reference Counted progress bar
///
/// This wrap [`indicatif::ProgressBar`] with [`std::sync::Arc`] to allow it to be shared between threads
///
/// # Arguments
/// * `total` - The total number of items to be processed
pub(super) fn create_progress_bar(total: u64) -> Arc<indicatif::ProgressBar> {
let progress = Arc::new(indicatif::ProgressBar::new(total));
progress.enable_steady_tick(std::time::Duration::from_millis(120));
progress.set_style(
indicatif::ProgressStyle::with_template(
"{spinner:.blue} {msg} [{elapsed_precise}] [{wide_bar:.cyan/blue}] {pos}/{len}",
)
.unwrap()
.progress_chars("#>-")
.tick_strings(&["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏", " "]),
);
progress.set_message("Downloading");

progress
}
Loading

0 comments on commit d019f42

Please sign in to comment.