Added manga-py source
This commit is contained in:
95
manga-py-stable_1.x/manga_py/cli/__init__.py
Normal file
95
manga-py-stable_1.x/manga_py/cli/__init__.py
Normal file
@@ -0,0 +1,95 @@
|
||||
import sys
|
||||
from argparse import ArgumentParser
|
||||
from getpass import getpass
|
||||
from os import name as os_name
|
||||
|
||||
from progressbar import ProgressBar
|
||||
|
||||
from manga_py.fs import check_free_space, get_temp_path
|
||||
from manga_py.parser import Parser
|
||||
|
||||
|
||||
class Cli: # pragma: no cover
|
||||
args = None
|
||||
parser = None
|
||||
_info = None
|
||||
__progress_bar = None
|
||||
|
||||
def __init__(self, args: ArgumentParser, info=None):
|
||||
self.args = args.parse_args()
|
||||
self.parser = Parser(args)
|
||||
self._info = info
|
||||
|
||||
space = self.args.min_free_space
|
||||
if not check_free_space(get_temp_path(), space) or not check_free_space(self.args.destination, space):
|
||||
raise OSError('No space left on device')
|
||||
|
||||
def start(self):
|
||||
try:
|
||||
self.parser.init_provider(
|
||||
progress=self.progress,
|
||||
log=self.print,
|
||||
quest=self.quest,
|
||||
quest_password=self.quest_password,
|
||||
info=self._info,
|
||||
)
|
||||
except AttributeError as e:
|
||||
print(e, file=sys.stderr)
|
||||
print('Please check if your inputed domain is supported by manga-py: ', file=sys.stderr)
|
||||
print('- https://manga-py.com/manga-py/#resources-list', file=sys.stderr)
|
||||
print('- https://manga-py.github.io/manga-py/#resources-list (alternative)', file=sys.stderr)
|
||||
print('- https://yuru-yuri.github.io/manga-py/ (deprecated)', file=sys.stderr)
|
||||
print('Make sure that your inputed URL is correct\n\nTrace:', file=sys.stderr)
|
||||
raise e
|
||||
self.parser.start()
|
||||
self.__progress_bar and self.__progress_bar.value > 0 and self.__progress_bar.finish()
|
||||
self.args.quiet or self.print(' ')
|
||||
|
||||
def __init_progress(self, items_count: int, re_init: bool):
|
||||
if re_init or not self.__progress_bar:
|
||||
if re_init:
|
||||
self.__progress_bar.finish()
|
||||
bar = ProgressBar()
|
||||
self.__progress_bar = bar(range(items_count))
|
||||
self.__progress_bar.init()
|
||||
|
||||
def progress(self, items_count: int, current_item: int, re_init: bool = False):
|
||||
if not items_count:
|
||||
return
|
||||
if not self.args.no_progress and not self.args.print_json:
|
||||
current_val = 0
|
||||
if self.__progress_bar:
|
||||
current_val = self.__progress_bar.value
|
||||
self.__init_progress(items_count, re_init and current_val > 0)
|
||||
self.__progress_bar.update(current_item)
|
||||
|
||||
def print(self, text, **kwargs):
|
||||
if os_name == 'nt':
|
||||
text = str(text).encode().decode(sys.stdout.encoding, 'ignore')
|
||||
self.args.quiet or print(text, **kwargs)
|
||||
|
||||
def _single_quest(self, variants, title):
|
||||
self.print(title)
|
||||
for v in variants:
|
||||
self.print(v)
|
||||
return input()
|
||||
|
||||
def _multiple_quest(self, variants, title):
|
||||
self.print('Accept - blank line + enter')
|
||||
self.print(title)
|
||||
for v in variants:
|
||||
self.print(v)
|
||||
result = []
|
||||
while True:
|
||||
_ = input().strip()
|
||||
if not len(_):
|
||||
return result
|
||||
result.append(_)
|
||||
|
||||
def quest(self, variants: enumerate, title: str, select_type=0): # 0 = single, 1 = multiple
|
||||
if select_type:
|
||||
return self._multiple_quest(variants, title)
|
||||
return self._single_quest(variants, title)
|
||||
|
||||
def quest_password(self, title):
|
||||
return getpass(title)
|
||||
338
manga-py-stable_1.x/manga_py/cli/args.py
Normal file
338
manga-py-stable_1.x/manga_py/cli/args.py
Normal file
@@ -0,0 +1,338 @@
|
||||
'''
|
||||
manga-py module for CLI and its options.
|
||||
'''
|
||||
|
||||
from argparse import ArgumentParser, ArgumentDefaultsHelpFormatter, RawDescriptionHelpFormatter
|
||||
|
||||
from manga_py.meta import __version__
|
||||
|
||||
|
||||
class DescriptionDefaultsHelpFormatter(ArgumentDefaultsHelpFormatter,
|
||||
RawDescriptionHelpFormatter):
|
||||
'''
|
||||
Class to format --help cli option with 2 features to output:
|
||||
programm's description in a raw mode,
|
||||
options default values.
|
||||
'''
|
||||
|
||||
|
||||
def _image_args(args_parser): # pragma: no cover
|
||||
args = args_parser.add_argument_group('Image options')
|
||||
|
||||
args.add_argument(
|
||||
'-E',
|
||||
'--not-change-files-extension',
|
||||
action='store_true',
|
||||
help=(
|
||||
'Save downloaded files to archive "as is".'
|
||||
)
|
||||
)
|
||||
|
||||
args.add_argument(
|
||||
'-W',
|
||||
'--no-webp',
|
||||
action='store_true',
|
||||
help=(
|
||||
'Convert `*.webp` images to `*.jpg` format.'
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def _debug_args(args_parser): # pragma: no cover
|
||||
args = args_parser.add_argument_group('Debug / Simulation options')
|
||||
|
||||
args.add_argument(
|
||||
'-h',
|
||||
'--help',
|
||||
action='help',
|
||||
help=(
|
||||
'Show this help and exit.'
|
||||
)
|
||||
)
|
||||
|
||||
args.add_argument(
|
||||
'-j',
|
||||
'--print-json',
|
||||
action='store_true',
|
||||
help=(
|
||||
'Print information about the results in the JSON format (after completion).'
|
||||
)
|
||||
)
|
||||
|
||||
args.add_argument(
|
||||
'-l',
|
||||
'--simulate',
|
||||
action='store_true',
|
||||
help=(
|
||||
'Simulate running %(prog)s, where: '
|
||||
'1) do not download files and, '
|
||||
'2) do not write anything on disk.'
|
||||
)
|
||||
)
|
||||
|
||||
args.add_argument(
|
||||
'-i',
|
||||
'--show-current-chapter-info',
|
||||
action='store_true',
|
||||
help=(
|
||||
'Show current processing chapter info.'
|
||||
)
|
||||
)
|
||||
|
||||
args.add_argument(
|
||||
'-b',
|
||||
'--debug',
|
||||
action='store_true',
|
||||
help=(
|
||||
'Debug %(prog)s.'
|
||||
)
|
||||
)
|
||||
|
||||
args.add_argument(
|
||||
'-q',
|
||||
'--quiet',
|
||||
action='store_true',
|
||||
help=(
|
||||
'Dont show any messages.'
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def _downloading_args(args_parser): # pragma: no cover
|
||||
args = args_parser.add_argument_group('Downloading options')
|
||||
|
||||
args.add_argument(
|
||||
'-s',
|
||||
'--skip-volumes',
|
||||
metavar='COUNT',
|
||||
type=int,
|
||||
help=(
|
||||
'Skip a total number, i.e. %(metavar)s, of volumes.'
|
||||
),
|
||||
default=0
|
||||
)
|
||||
|
||||
args.add_argument(
|
||||
'-m',
|
||||
'--max-volumes',
|
||||
metavar='COUNT',
|
||||
type=int,
|
||||
default=0,
|
||||
help=(
|
||||
'Download a maximum number, i.e. %(metavar)s, of volumes. '
|
||||
'E.g.: `--max-volumes 2` will download at most 2 volumes. '
|
||||
'If %(metavar)s is `0` (zero) then it will download all available volumes.'
|
||||
)
|
||||
)
|
||||
|
||||
args.add_argument(
|
||||
'-a',
|
||||
'--user-agent',
|
||||
type=str,
|
||||
help=(
|
||||
'Set an user-agent. '
|
||||
'Don\'t work from protected sites.'
|
||||
)
|
||||
)
|
||||
|
||||
args.add_argument(
|
||||
'-x',
|
||||
'--proxy',
|
||||
type=str,
|
||||
help=(
|
||||
'Set a http proxy.'
|
||||
)
|
||||
)
|
||||
|
||||
args.add_argument(
|
||||
'-e',
|
||||
'--reverse-downloading',
|
||||
action='store_true',
|
||||
help=(
|
||||
'Download manga volumes in a reverse order. '
|
||||
'By default, manga is downloaded in ascendent order '
|
||||
'(i.e. volume 00, volume 01, volume 02...). '
|
||||
'If `--reverse-downloading` is actived, then manga is downloaded in descendent order '
|
||||
'(i.e. volume 99, volume 98, volume 97...).'
|
||||
)
|
||||
)
|
||||
|
||||
args.add_argument(
|
||||
'-w',
|
||||
'--rewrite-exists-archives',
|
||||
action='store_true',
|
||||
help=(
|
||||
'(Re)Download manga volume if it already exists locally in the directory destination. '
|
||||
'Your manga files can be overwrited, so be careful.'
|
||||
)
|
||||
)
|
||||
|
||||
args.add_argument(
|
||||
'-t',
|
||||
'--max-threads',
|
||||
type=int,
|
||||
default=None,
|
||||
help=(
|
||||
'Set the maximum number of threads, i.e. MAX_THREADS, to be avaliable to manga-py. '
|
||||
'Threads run in pseudo-parallel when execute the process to download the manga images.'
|
||||
)
|
||||
)
|
||||
|
||||
args.add_argument(
|
||||
'-f',
|
||||
'--zero-fill',
|
||||
action='store_true',
|
||||
help=(
|
||||
'Pad a `-0` (dash-and-zero) at right for all downloaded manga volume filenames. '
|
||||
'E.g. from `vol_001.zip` to `vol_001-0.zip`. '
|
||||
'It is useful to standardize the filenames between: '
|
||||
'1) normal manga volumes (e.g. vol_006.zip) and, '
|
||||
'2) abnormal manga volumes (e.g. vol_006-5.zip). '
|
||||
'An abnormal manga volume is a released volume like: '
|
||||
'extra chapters, '
|
||||
'bonuses, '
|
||||
'updated, '
|
||||
'typos corrected, '
|
||||
'spelling errors corrected; '
|
||||
'and so on.'
|
||||
)
|
||||
)
|
||||
|
||||
args.add_argument(
|
||||
'-g',
|
||||
'--with-manga-name',
|
||||
action='store_true',
|
||||
help=(
|
||||
'Pad the manga name at left for all downloaded manga volumes filenames. '
|
||||
'E.g. from `vol_001.zip` to `manga_name-vol_001.zip`.'
|
||||
)
|
||||
)
|
||||
|
||||
args.add_argument(
|
||||
'-o',
|
||||
'--override-archive-name',
|
||||
metavar='ARCHIVE_NAME',
|
||||
type=str,
|
||||
default='',
|
||||
dest='override_archive_name',
|
||||
help=(
|
||||
'Pad %(metavar)s at left for all downloaded manga volumes filename. '
|
||||
'E.g from `vol_001.zip` to `%(metavar)s-vol_001.zip`.'
|
||||
)
|
||||
)
|
||||
|
||||
args.add_argument(
|
||||
'-c',
|
||||
'--min-free-space',
|
||||
metavar='MB',
|
||||
type=int,
|
||||
default=100,
|
||||
help=(
|
||||
'Alert when the minimum free disc space, i.e. MB, is reached. '
|
||||
'Insert it in order of megabytes (Mb).'
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def _reader_args(args_parser): # pragma: no cover
|
||||
args = args_parser.add_argument_group('Archive options')
|
||||
|
||||
args.add_argument(
|
||||
'-z',
|
||||
'--cbz',
|
||||
action='store_true',
|
||||
help=(
|
||||
'Make `*.cbz` archives (for reader).'
|
||||
)
|
||||
)
|
||||
|
||||
args.add_argument(
|
||||
'-r',
|
||||
'--rename-pages',
|
||||
action='store_true',
|
||||
help=(
|
||||
'Normalize image filenames. '
|
||||
'E.g. from `0_page_1.jpg` to `0001.jpg`.'
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def get_cli_arguments() -> ArgumentParser: # pragma: no cover
|
||||
'''
|
||||
Method to generate manga-py CLI with its options.
|
||||
'''
|
||||
args_parser = ArgumentParser(
|
||||
add_help=False,
|
||||
formatter_class=DescriptionDefaultsHelpFormatter,
|
||||
prog="manga-py",
|
||||
description=(
|
||||
'%(prog)s is the universal manga downloader (for your offline reading).\n '
|
||||
'Site: https://manga-py.com/manga-py/\n '
|
||||
'Source-code: https://github.com/manga-py/manga-py\n '
|
||||
'Version: ' + __version__
|
||||
),
|
||||
epilog=(
|
||||
'So, that is how %(prog)s can be executed to download yours favourite mangas.\n'
|
||||
'Enjoy! 😉'
|
||||
)
|
||||
)
|
||||
|
||||
args = args_parser.add_argument_group('General options')
|
||||
|
||||
args.add_argument(
|
||||
'url',
|
||||
metavar='URL',
|
||||
type=str,
|
||||
help=(
|
||||
'%(metavar)s, i.e. link from manga, to be downloaded.'
|
||||
)
|
||||
)
|
||||
|
||||
args.add_argument(
|
||||
'-v',
|
||||
'--version',
|
||||
action='version',
|
||||
version=__version__,
|
||||
help=(
|
||||
'Show %(prog)s\'s version number and exit.'
|
||||
)
|
||||
)
|
||||
|
||||
args.add_argument(
|
||||
'-n',
|
||||
'--name',
|
||||
metavar='NAME',
|
||||
type=str,
|
||||
default='',
|
||||
help=(
|
||||
'Rename manga, i.e. by %(metavar)s, and its folder to where it will be saved locally.'
|
||||
)
|
||||
)
|
||||
|
||||
args.add_argument(
|
||||
'-d',
|
||||
'--destination',
|
||||
metavar='PATH',
|
||||
type=str,
|
||||
default='Manga',
|
||||
help=(
|
||||
'Destination folder to where the manga will be saved locally. '
|
||||
'The path will be `./%(metavar)s/manga_name/`.'
|
||||
)
|
||||
)
|
||||
|
||||
args.add_argument(
|
||||
'-P',
|
||||
'--no-progress',
|
||||
action='store_true',
|
||||
help=(
|
||||
'Don\'t show progress bar.'
|
||||
)
|
||||
)
|
||||
|
||||
_image_args(args_parser)
|
||||
_reader_args(args_parser)
|
||||
_downloading_args(args_parser)
|
||||
_debug_args(args_parser)
|
||||
|
||||
return args_parser
|
||||
Reference in New Issue
Block a user