Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

module: Manhuaren #7

Closed
wants to merge 17 commits into from
42 changes: 42 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,47 @@
# Changelog

## Draft: 2.3.0

`2023-04-18`

### Deprecation

- [Dev] Import ComicDownloader from 'comic-downloader.ts' is deprecated, and will be removed in the next major version.
- This is only for module developers, the usage of the library and the CLI is unaffected.

```typescript
// Your module

// <= 2.2.0 and < 3.0.0
import ComicDownloader from '../../comic-downloader';

// >= 2.3.0
import ComicDownloader from '../../core';
```

### Feature

- [CLI] New `-S, --shorthand-url` flag is added, please refer to the documentation of each module.
- The `-m, --module` flag is required when using this flag.
- When using the `-h, --history` flag, the url registered will still be the completed url.
- A `static urlCompletion` method is added to modules for developers.
- The `-u, --url` flag has a higher priorty than this flag.
- [CLI] _Experimental_ New `-l, --list` flag is added, that can download a list of urls.
- This flag only applies to the `dl, download` command.
- Please note that due to the stability of each module, you may end up with multiple failures.
- You can use the `-h, --history` flag added in the `version 2.2.0` to register your download history, so that you can use this flag as a "sync" functionality.
- You can use the `-S, --shorthand-url` flag without value if the list your list is composed of shorthand urls.

### Fix

- [core] Fixed a bug that causes index 0 to display improperly.
- [core] To prevent unnecessary network requests, the check for chapter existence has been moved ahead of the network requests.

### Dev

- The `comic-downloader.ts` is moved to `core/index.ts`, causing the deprecation, but `comic-downloader.ts` will still exist for a while until the next major version.
- A `static urlCompletion` method is added to modules in order to parse the shorthand urls.

## 2.2.0

`2023-04-08`
Expand Down
12 changes: 10 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,14 @@ Please help me translate the documents, thanks.

## :star2: Features

- Very low memory usage
- CLI tools
- Supports multiple sites (More on the road).
- Supports multiple sites (More on the road)
- Supports shorthand URLs
- Download as ZIP/CBZ, or just a folder of pictures
- Downloading progress watch
- Detects downloaded chapters
- Sync / Update downloaded chapters
- Generates [ComicInfo.xml](https://anansi-project.github.io/docs/comicinfo/intro)

## :rainbow: [Site List](docs/user/sites.md)
Expand Down Expand Up @@ -88,17 +91,19 @@ Options:
-h, --history Optional: (Experimental) Add the serie url to a given text file when using the `download` command, its value is default to a `history.txt` file under the same path of `--output`.
-I, --indexed-chapters Optional: Add index to the folder / archive file name of chapters.
-i, --info Optional: Generate ComicInfo.xml.
-l, --list Optional: (Experimental) The path to a text file that contains a list of URLs.
-M, --max-title-length Optional: restrict the length of title as the folder name.
-m, --module Optional: Specify the module (site) name. Will attempt to detect module by url if not set.
-n, --name Optional: Proride the serie title and override the folder name.
-o, --output Optional: The path where downloaded files are saved (default to .), setting this flag when using list will save a ComicInfo.xml to the path.
-O, --override Optional: overrides downloaded chapters.
-p, --presets Optional: loading a JSON file of site presets.
-r, --retry Optional: Automatically re-download chapters with failed images.
-S, --shorthand-url Optional: The shorthand url, please refer to the module docs.
-s, --slience Optional: Silence the console output, including the confirm prompt.
-T, --timeout Optional: Override the default 10s request timeout.
-t, --to Optional: Ending chapter when downloading a serie, defaults to chapter.length - 1.
-u, --url The url to the serie or the chapter.
-u, --url Optional: The url to the serie or the chapter.
-v, --verbose Optional: Display detailed error message, overrides silence.
-V, --version Output the version number
-y, --yes Optional: Skipping confirmation prompt when downloading series.
Expand All @@ -120,6 +125,9 @@ Examples:
- List all chapters of the given serie.
$ npx comic-dl ls -u serie_url

- Using shorthand URLs.
$ npx comic-dl -m zerobyw -S 12345

- Download a chapter named Chapter1 to current path.
$ npx comic-dl ch -n Chapter1 -u chapter_url -c cookie.txt

Expand Down
4 changes: 4 additions & 0 deletions docs/dev/module.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,10 @@ This method is optional, but without which your module can't handle a url in CLI

Please note that this only serves as a template and is not taken as the default configs or options of this module.

### urlCompletion

`static urlCompletion` is used to complete a shorthand Url.

### constructor

`constructor` is the initialization function, where you can configurate your module with configs.
Expand Down
6 changes: 6 additions & 0 deletions docs/user/sites.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ Still zerobyw provides its contents with care, images are normally not compresse

As of today, you need to login to get access to most of contents, and some of the contents are behind the paywall (5 RMB per month).

Zerobyw accepts shorthand urls in the format of numbers, e.g. `--shorthand-url 12345`.

## [Copymanga](https://www.copymanga.site/)

`version 2.0.0`
Expand All @@ -36,6 +38,8 @@ Copymanga may provide series in groups:
- `other_group`: 其它系列
- `tankobon`: 单行本

Copymanga accepts shorthand urls in the format of mangaIds, e.g. `--shorthand-url doityourself`.

## [Ganma](https://ganma.jp/)

`version 2.1.0`
Expand All @@ -45,3 +49,5 @@ Ganma is a non-pirate site where contents are behind the paywall (680 JPY monthl
Ganma provides official Japanese manga series.

This module will be maintained for as long as my Ganma subscription lasts.

Ganma accepts shorthand urls in the format of mangaIds, e.g. `--shorthand-url otonanokoi`.
6 changes: 3 additions & 3 deletions package-lock.json

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

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "comic-dl",
"version": "2.2.0",
"version": "2.3.0",
"description": "Yet another batch downloader for manga/comic sites",
"main": "dist/index.js",
"bin": "dist/cli/index.js",
Expand Down
159 changes: 98 additions & 61 deletions src/cli/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,39 +55,42 @@ function buildDownloader(options: Partial<CliOptions> = {}) {
indexedChapters,
});

return downloader;
return { downloader, Downloader };
}

export const listCommand: Command = async (name, sub, _options = {}) => {
const options = mergeOptions(_options);
const { url, verbose, silence, output, name: rename } = options;
const { url, shorthandUrl, verbose, silence, output, name: rename } = options;

try {
if (url) {
const downloader = buildDownloader(options);
const serie = await downloader.getSerieInfo(url, options);
if (serie) {
if (!silence) {
console.log(`Title: ${serie.title}`);
if (!url && !shorthandUrl) {
console.warn('Please Provide URL.');
}

const { downloader, Downloader } = buildDownloader(options);
const completeUrl = shorthandUrl
? Downloader.urlCompletion(shorthandUrl as string)
: (url as string);
const serie = await downloader.getSerieInfo(completeUrl, options);
if (serie) {
if (!silence) {
console.log(`Title: ${serie.title}`);
console.log('----');
serie.chapters?.forEach(e => {
console.log(`${e.index} ${e.name}`);
console.log(`${e.uri}`);
console.log('----');
serie.chapters?.forEach(e => {
console.log(`${e.index} ${e.name}`);
console.log(`${e.uri}`);
console.log('----');
});
});

if (serie?.info) {
Object.keys(serie.info).forEach(e => {
console.log(`${e}: ${serie.info?.[e]}`);
});
}
if (serie?.info) {
Object.keys(serie.info).forEach(e => {
console.log(`${e}: ${serie.info?.[e]}`);
});
}
}

if (output) {
await downloader.writeComicInfo(serie, { output, rename });
}
} else {
console.log('Please Provide URL.');
if (output) {
await downloader.writeComicInfo(serie, { output, rename });
}
}
} catch (error) {
Expand All @@ -101,10 +104,11 @@ export const listCommand: Command = async (name, sub, _options = {}) => {
}
};

export const downloadCommand: Command = async (name, sub, _options = {}) => {
export const _downloadCommand: Command = async (name, sub, _options = {}) => {
const options = mergeOptions(_options);
const {
url,
shorthandUrl,
from,
to,
yes,
Expand All @@ -121,32 +125,35 @@ export const downloadCommand: Command = async (name, sub, _options = {}) => {
const current: Partial<DownloadProgress> = {};

try {
if (url) {
const downloader = buildDownloader(options);
if (history) {
const historyPath = isString(history)
? (history as string)
: path.resolve(output, 'history.txt');
writeHistory(historyPath, url);
}
if (!url && !shorthandUrl) {
console.warn('Please Provide URL.');
}

await downloader.downloadSerie(url, {
...options,
start: from,
end: to,
confirm: !yes,
rename,
retry,
info,
override,
chapters:
chapters !== undefined
? `${chapters}`.split(',').map(e => parseInt(e))
: undefined,
});
} else {
console.log('Please Provide URL.');
const { downloader, Downloader } = buildDownloader(options);
const completeUrl = shorthandUrl
? Downloader.urlCompletion(shorthandUrl as string)
: (url as string);
if (history) {
const historyPath = isString(history)
? (history as string)
: path.resolve(output, 'history.txt');
writeHistory(historyPath, completeUrl);
}

await downloader.downloadSerie(completeUrl, {
...options,
start: from,
end: to,
confirm: !yes,
rename,
retry,
info,
override,
chapters:
chapters !== undefined
? `${chapters}`.split(',').map(e => parseInt(e))
: undefined,
});
} catch (error) {
if (verbose) {
console.error(error);
Expand Down Expand Up @@ -174,24 +181,54 @@ export const downloadCommand: Command = async (name, sub, _options = {}) => {
}
};

export const downloadCommand: Command = async (name, sub, _options = {}) => {
const { list, shorthandUrl } = _options;
if (!list) {
await _downloadCommand(name, sub, _options);
} else {
const urlListReader = await fs.promises.readFile(path.resolve(list));
const urlList = urlListReader.toString().split('\n');
for (let u = 0; u < urlList.length; u++) {
const url = urlList[u];
const options = { ..._options };
if (shorthandUrl) {
options.shorthandUrl = url;
} else {
options.url = url;
}
await _downloadCommand(name, sub, options);
}
}
};

export const chapterCommand: Command = async (name, sub, _options = {}) => {
const options = mergeOptions(_options);
const { url, name: chapterName, verbose, output, override } = options;
const {
url,
shorthandUrl,
name: chapterName,
verbose,
output,
override,
} = options;

try {
if (url) {
const downloader = buildDownloader(options);
let serie: SerieInfo | undefined;
if (output) {
serie = await downloader.getSerieInfo(url, options);
}
await downloader.downloadChapter(chapterName ?? 'Untitled', url, {
info: serie?.info,
override,
});
} else {
console.log('Please Provide URL.');
if (!url && !shorthandUrl) {
console.warn('Please Provide URL.');
}

const { downloader, Downloader } = buildDownloader(options);
const completeUrl = shorthandUrl
? Downloader.urlCompletion(shorthandUrl as string)
: (url as string);
let serie: SerieInfo | undefined;
if (output) {
serie = await downloader.getSerieInfo(completeUrl, options);
}
await downloader.downloadChapter(chapterName ?? 'Untitled', url, {
info: serie?.info,
override,
});
} catch (error) {
if (verbose) {
console.error(error);
Expand Down
11 changes: 10 additions & 1 deletion src/cli/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ args
'module',
'Optional: Specify the module (site) name. Will attempt to detect module by url if not set.',
)
.option('url', 'The url to the serie or the chapter.')
.option('url', 'Optional: The url to the serie or the chapter.')
.option(
'name',
'Optional: Proride the serie title and override the folder name.',
Expand Down Expand Up @@ -108,6 +108,14 @@ args
'history',
'Optional: (Experimental) Add the serie url to a given text file when using the `download` command, its value is default to a `history.txt` file under the same path of `--output`.',
)
.option(
'shorthand-url',
'Optional: The shorthand url, please refer to the module docs.',
)
.option(
'list',
'Optional: (Experimental) The path to a text file that contains a list of URLs.',
)
.example(
'npx comic-dl dl -c cookie.txt -f 10 -t 20 -o ~/Download/manga -a zip -r -i -b 10 -u serie_url',
'Download a serie from its 10th chapter to 20th chapter to the given destination, 10 images at a time, output zip archives with ComicInfo.xml by chapter, retry if a chapter is not properly downloaded.',
Expand All @@ -128,6 +136,7 @@ args
'npx comic-dl ls -u serie_url',
'List all chapters of the given serie.',
)
.example('npx comic-dl -m zerobyw -S 12345', 'Using shorthand URLs.')
.example(
'npx comic-dl ch -n Chapter1 -u chapter_url -c cookie.txt',
'Download a chapter named Chapter1 to current path.',
Expand Down
Loading