Module mangdl.cli

Expand source code
import builtins
import inspect
import logging
from typing import Any, Callable, List

import click
from rich.logging import RichHandler
from tabulate import tabulate
from yachalk import chalk

from . import globals
from .providers import Provider
from .utils.settings import stg
from .utils.style import pprint
from .utils.utils import dd, de, dnrp

lvls = [
    "CRITICAL",
    "ERROR",
    "WARNING",
    "INFO",
    "DEBUG",
    "NOTSET",
]

def fn_log(lvl: int):
    if lvl == 1:
        l = "NOTSET"
    else:
        l = lvls[lvl - 2]

    logging.basicConfig(
        level=l,
        format="%(message)s",
        datefmt="[%H:%M:%S.%f]",
        handlers=[RichHandler(
            omit_repeated_times=False,
            markup=True,
            rich_tracebacks=True
        )]
    )

    op = logging.getLogger("rich")
    if lvl == 1:
        logging.disable()
    globals.log = op

pprint(r"""[#D2748D bold]
 _____   ___     _____    _____     __   _________   ______    __
/\    \/   \   / ____\ /\    \  /\ \ /\  ______\ /\  ___\ /\ \
\ \ \\   /\ \ /\ \__/\ \\ \ \\ \\ \ \\ \ \_____/_\ \ \_/\ \\ \ \
 \ \ \ \/\ \ \\ \  ____ \\ \ \ \ \ \ \\ \ \ /\__ \\ \ \\ \ \\ \ \
  \ \ \‾‾  \ \ \\ \ \__/\ \\ \ \  \ \\ \\ \ \\/__\ \\ \ \\_\ \\ \ \____
   \ \_\    \ \_\\ \_\ \ \_\\ \_\\ \____\\ \________\\ \_____/ \ \_____\
    \/_/     \/_/ \/_/  \/_/ \/_/  \/____/ \/________/ \/____/   \/_____/""")
pprint("[#D2748D bold]The most inefficient, non user-friendly and colorful manga downloader (and soon, also a reader)")
pprint("[#3279a1]Chat with whi~nyaan at https://discord.com/invite/JbAtUxGcJZ\n")

def cao(group: click.group, cmd: str) -> List[Callable[[Callable[[Any], Any]], Callable[[Any], Any]]]:
    """
    Retruns wrappers for a click command evaluated from the given arguments.

    Args:
        group (click.group): Command group of the command to be under.
        cmd (str): Name of the command.

    Returns:
        List[Callable[[Callable[[Any], Any]], Callable[[Any], Any]]]: The wrappers.
    """
    cmd = stg(f"cmd/{cmd}", f"{dnrp(__file__)}/utils/config.yaml")
    arguments = cmd["arguments"]

    def c(f: Callable[[Any], Any]) -> Callable[[Callable[[Any], Any]], Callable[[Any], Any]]:
        """
        The command wrapper.
        Args:
            f (Callable[[Any], Any]): The command function to be decorated.
        Returns:
            Callable[[Callable[[Any], Any]], Callable[[Any], Any]]
        """
        help = []
        if arguments:
            for k, v in arguments.items():
                arguments[k]["help"] = [*v["help"], *[None for _ in range(3 - len(v["help"]))]]
            for k, v in arguments.items():
                t, h, e = v["help"]
                e = '\nEx.: {e}' if e else ""
                help.append([f"<{k}>", t, f'{h}{e}'])
        s, h = cmd["help"]
        return group.command(*de(cmd["args"], []), **dd({"context_settings": {'help_option_names': ['-h', '--help']}, "short_help": s, "help": f"\b\n{h}\n{tabulate(help, tablefmt='plain')}"}, cmd["kwargs"]))(f)

    def a(f: Callable[[Any], Any]) -> Callable[[Callable[[Any], Any]], Callable[[Any], Any]]:
        """
        The arguments wrapper.
        Args:
            f (Callable[[Any], Any]): The command function to be decorated.
        Returns:
            Callable[[Callable[[Any], Any]], Callable[[Any], Any]]
        """
        args = {}
        kwargs = {}
        if arguments:
            for k, v in arguments.items():
                kw = {"metavar": f"<{k}>"}
                args[k] = [k, *de(v["args"], [])]
                kwargs[k] = dd(kw, v["kwargs"])
            for i in list(args.keys()):
                f = click.argument(*args[i], **kwargs[i])(f)
        return f

    def o(f: Callable[[Any], Any]) -> Callable[[Callable[[Any], Any]], Callable[[Any], Any]]:
        """
        The options wrapper.
        Args:
            f (Callable[[Any], Any]): The command function to be decorated.
        Returns:
            Callable[[Callable[[Any], Any]], Callable[[Any], Any]]
        """
        if opts:= cmd["options"]:
            n = 0
            args = {}
            kwargs = {}
            for k, v in opts.items():
                l = len(v["help"][0] or "")
                n = l if l > n else n
                opts[k]["help"] = [*v["help"], *[None for _ in range(3 - len(v["help"]))]]
            for k, v in opts.items():
                a = de(v["args"], [])
                kw = de(v["kwargs"], {})
                a[0] = f"--{a[0]}"
                a.insert(0, f"-{k}")
                kt = kw.get("type", None)
                t, h, e = v["help"]
                t = t or ""
                h = "\n".join(f'{" " * ((n + 3)-(0 if i else len(j)))}{j}' for i, j in enumerate(h.split("\n"))) if h else ""
                e = "\n" + "\n".join(f'{" " * (n + (11 if i else 5))}{"Ex.: " if not i else ""}{j}' for i, j in enumerate(e.split("\n"))) if e else ""
                kw["help"] = f'\b\n{t}{" "*((n + 3) - len(t))}{h}{e}'
                if isinstance(kt, dict):
                    ktk, ktv = list(kt.items())[0]
                    kta, ktkw = [i[1] for i in ktv.items()]
                    kw["type"] = getattr(click, ktk)(*kta, **ktkw if ktkw else {})
                elif kt:
                    kw["type"] = getattr(builtins, kt)
                args[k] = a
                kwargs[k] = kw
            for i in list(args.keys()):
                f = click.option(*args[i], **kwargs[i])(f)
        return f

    return c, a, o

def command(group: click.group) -> Callable[[Callable[[Any], Any]], Callable[[Any], Any]]:
    """
    Wrapper for click commands.

    Args:
        group (click.group): Command group of the command to be under.

    Returns:
        Callable[[Callable[[Any], Any]], Callable[[Any], Any]]
    """
    def inner(f: Callable[[Any], Any]):
        m = inspect.getouterframes(inspect.currentframe())[1][4][0]
        for m in cao(group, m[4:m.index("(")]):
            f = m(f)
        return f
    return inner

@click.group(context_settings={'help_option_names': ['-h', '--help']})
def cli():
    """Main command group."""

@command(cli)
def dl(title: str, **kwargs: dict[str, Any]):
    """
    Download command.

    Args:
        title (str): The title of the manga to be search for and download.
    """
    fn_log(kwargs.pop("loglevel"))
    Provider(kwargs.pop("provider")).cli_dl(title, **kwargs)

@command(cli)
def credits():
    """Credits command. Display credits."""
    print(chalk.hex("D2748D").bold(r"""
 ______  ______  ______  _____   __  ______  ______
/\  ___\/\  == \/\  ___\/\  __-./\ \/\__  _\/\  ___\
\ \ \___\ \  __<\ \  __\\ \ \/\ \ \ \/_/\ \/\ \___  \
 \ \_____\ \_\ \_\ \_____\ \____-\ \_\ \ \_\ \/\_____\
  \/_____/\/_/ /_/\/_____/\/____/ \/_/  \/_/  \/_____/""") + chalk.hex("11b180").bold("\n\nThank you:") + chalk.hex("3279a1")("""\n
- To Arjix, who helped me in implementing majority of the features and de-minifying
  my code, making it more readable and more efficient at the same time
- To KR, who let me use the KR-naming scheme like "AnimDL" do
- To whi~nyaan, my alter ego, for just existing (and purring, ofc)
- And to everyone who supported me from the very beginning of this humble
  project to its release!\n"""))

Functions

def cao(group: , cmd: str) ‑> List[Callable[[Callable[[Any], Any]], Callable[[Any], Any]]]

Retruns wrappers for a click command evaluated from the given arguments.

Args

group : click.group
Command group of the command to be under.
cmd : str
Name of the command.

Returns

List[Callable[[Callable[[Any], Any]], Callable[[Any], Any]]]
The wrappers.
Expand source code
def cao(group: click.group, cmd: str) -> List[Callable[[Callable[[Any], Any]], Callable[[Any], Any]]]:
    """
    Retruns wrappers for a click command evaluated from the given arguments.

    Args:
        group (click.group): Command group of the command to be under.
        cmd (str): Name of the command.

    Returns:
        List[Callable[[Callable[[Any], Any]], Callable[[Any], Any]]]: The wrappers.
    """
    cmd = stg(f"cmd/{cmd}", f"{dnrp(__file__)}/utils/config.yaml")
    arguments = cmd["arguments"]

    def c(f: Callable[[Any], Any]) -> Callable[[Callable[[Any], Any]], Callable[[Any], Any]]:
        """
        The command wrapper.
        Args:
            f (Callable[[Any], Any]): The command function to be decorated.
        Returns:
            Callable[[Callable[[Any], Any]], Callable[[Any], Any]]
        """
        help = []
        if arguments:
            for k, v in arguments.items():
                arguments[k]["help"] = [*v["help"], *[None for _ in range(3 - len(v["help"]))]]
            for k, v in arguments.items():
                t, h, e = v["help"]
                e = '\nEx.: {e}' if e else ""
                help.append([f"<{k}>", t, f'{h}{e}'])
        s, h = cmd["help"]
        return group.command(*de(cmd["args"], []), **dd({"context_settings": {'help_option_names': ['-h', '--help']}, "short_help": s, "help": f"\b\n{h}\n{tabulate(help, tablefmt='plain')}"}, cmd["kwargs"]))(f)

    def a(f: Callable[[Any], Any]) -> Callable[[Callable[[Any], Any]], Callable[[Any], Any]]:
        """
        The arguments wrapper.
        Args:
            f (Callable[[Any], Any]): The command function to be decorated.
        Returns:
            Callable[[Callable[[Any], Any]], Callable[[Any], Any]]
        """
        args = {}
        kwargs = {}
        if arguments:
            for k, v in arguments.items():
                kw = {"metavar": f"<{k}>"}
                args[k] = [k, *de(v["args"], [])]
                kwargs[k] = dd(kw, v["kwargs"])
            for i in list(args.keys()):
                f = click.argument(*args[i], **kwargs[i])(f)
        return f

    def o(f: Callable[[Any], Any]) -> Callable[[Callable[[Any], Any]], Callable[[Any], Any]]:
        """
        The options wrapper.
        Args:
            f (Callable[[Any], Any]): The command function to be decorated.
        Returns:
            Callable[[Callable[[Any], Any]], Callable[[Any], Any]]
        """
        if opts:= cmd["options"]:
            n = 0
            args = {}
            kwargs = {}
            for k, v in opts.items():
                l = len(v["help"][0] or "")
                n = l if l > n else n
                opts[k]["help"] = [*v["help"], *[None for _ in range(3 - len(v["help"]))]]
            for k, v in opts.items():
                a = de(v["args"], [])
                kw = de(v["kwargs"], {})
                a[0] = f"--{a[0]}"
                a.insert(0, f"-{k}")
                kt = kw.get("type", None)
                t, h, e = v["help"]
                t = t or ""
                h = "\n".join(f'{" " * ((n + 3)-(0 if i else len(j)))}{j}' for i, j in enumerate(h.split("\n"))) if h else ""
                e = "\n" + "\n".join(f'{" " * (n + (11 if i else 5))}{"Ex.: " if not i else ""}{j}' for i, j in enumerate(e.split("\n"))) if e else ""
                kw["help"] = f'\b\n{t}{" "*((n + 3) - len(t))}{h}{e}'
                if isinstance(kt, dict):
                    ktk, ktv = list(kt.items())[0]
                    kta, ktkw = [i[1] for i in ktv.items()]
                    kw["type"] = getattr(click, ktk)(*kta, **ktkw if ktkw else {})
                elif kt:
                    kw["type"] = getattr(builtins, kt)
                args[k] = a
                kwargs[k] = kw
            for i in list(args.keys()):
                f = click.option(*args[i], **kwargs[i])(f)
        return f

    return c, a, o
def command(group: ) ‑> Callable[[Callable[[Any], Any]], Callable[[Any], Any]]

Wrapper for click commands.

Args

group : click.group
Command group of the command to be under.

Returns

Callable[[Callable[[Any], Any]], Callable[[Any], Any]]

Expand source code
def command(group: click.group) -> Callable[[Callable[[Any], Any]], Callable[[Any], Any]]:
    """
    Wrapper for click commands.

    Args:
        group (click.group): Command group of the command to be under.

    Returns:
        Callable[[Callable[[Any], Any]], Callable[[Any], Any]]
    """
    def inner(f: Callable[[Any], Any]):
        m = inspect.getouterframes(inspect.currentframe())[1][4][0]
        for m in cao(group, m[4:m.index("(")]):
            f = m(f)
        return f
    return inner
def fn_log(lvl: int)
Expand source code
def fn_log(lvl: int):
    if lvl == 1:
        l = "NOTSET"
    else:
        l = lvls[lvl - 2]

    logging.basicConfig(
        level=l,
        format="%(message)s",
        datefmt="[%H:%M:%S.%f]",
        handlers=[RichHandler(
            omit_repeated_times=False,
            markup=True,
            rich_tracebacks=True
        )]
    )

    op = logging.getLogger("rich")
    if lvl == 1:
        logging.disable()
    globals.log = op