Merge branch 'logging'

This commit is contained in:
Joakim Holm 2023-05-18 22:55:39 +02:00
commit 4da73a73e1
10 changed files with 131 additions and 33 deletions

View File

@ -1,6 +1,6 @@
from .book import Book, Series from .book import Book, Series
from .config import load_config, Config, SourceConfig from .config import load_config, Config, SourceConfig
from .exceptions import SourceNotAuthenticated from .exceptions import SourceNotAuthenticated, GrawlixError
from .sources import load_source, Source from .sources import load_source, Source
from .output import download_book from .output import download_book
from . import arguments, logging from . import arguments, logging
@ -68,23 +68,27 @@ async def authenticate(source: Source, config: Config, options):
async def main() -> None: async def main() -> None:
args = arguments.parse_arguments() args = arguments.parse_arguments()
config = load_config() config = load_config()
logging.debug_mode = args.debug
urls = get_urls(args) urls = get_urls(args)
for url in urls: for url in urls:
source: Source = load_source(url) try:
if not source.authenticated and source.requires_authentication: source: Source = load_source(url)
await authenticate(source, config, args) if not source.authenticated and source.requires_authentication:
result = await source.download(url) await authenticate(source, config, args)
if isinstance(result, Book): result = await source.download(url)
with logging.progress(result.metadata.title, source.name) as progress: if isinstance(result, Book):
template: str = args.output or "{title}.{ext}" with logging.progress(result.metadata.title, source.name) as progress:
await download_with_progress(result, progress, template) template: str = args.output or "{title}.{ext}"
elif isinstance(result, Series): await download_with_progress(result, progress, template)
with logging.progress(result.title, source.name, len(result.book_ids)) as progress: elif isinstance(result, Series):
for book_id in result.book_ids: with logging.progress(result.title, source.name, len(result.book_ids)) as progress:
book: Book = await source.download_book_from_id(book_id) for book_id in result.book_ids:
template: str = args.output or "{series}/{title}.{ext}" book: Book = await source.download_book_from_id(book_id)
await download_with_progress(book, progress, template) template: str = args.output or "{series}/{title}.{ext}"
logging.info("") await download_with_progress(book, progress, template)
logging.info("")
except GrawlixError as error:
error.print_error()
async def download_with_progress(book: Book, progress: Progress, template: str): async def download_with_progress(book: Book, progress: Progress, template: str):

View File

@ -51,4 +51,10 @@ def parse_arguments() -> argparse.Namespace:
help = "Output destination", help = "Output destination",
dest = "output" dest = "output"
) )
# Logging
parser.add_argument(
'--debug',
help = "Enable debug messages",
dest = "debug"
)
return parser.parse_args() return parser.parse_args()

View File

@ -0,0 +1,9 @@
[red]ERROR: Missing data from source[/red]
grawlix is missing data from source. This can happen when you try to
download ebooks you don't have access too (not logged in or your profile
doesn't have the right permissions), the site has been updated and grawlix
hasn't implemented the new version, or it could be a bug in grawlix.
If you think it is a problem with grawlix please create an issue at
https://github.com/jo1gi/grawlix/issues

View File

@ -0,0 +1,6 @@
[red]ERROR: The given url does not match any sources[/red]
Please make sure the link goes to the ebook you want to download and the site is
supported by grawlix. Try the link to the reader page if available.
If nothing works please create an issue at {issue}

View File

@ -0,0 +1,8 @@
[red]ERROR: Source has not been authenticated[/red]
You need to login to use this site. You can either use
* [green]--username[/] and [green]--password[/]
* Write username and password in the config file
* Use a cookie file with [green]--cookies[/]
See the README for more information: {repo}

View File

@ -0,0 +1,4 @@
[red]ERROR: Your connection has been throttled[/]
The site you are downloading from has temporarily blocked you.
Please wait a bit before downloading again or try another site or account.

View File

@ -1,23 +1,30 @@
from grawlix.logging import print_error_file
ISSUE_URL = "https://github.com/jo1gi/grawlix/issues"
REPO_URL = "https://github.com/jo1gi/grawlix"
class GrawlixError(Exception): class GrawlixError(Exception):
pass error_file: str
def print_error(self) -> None:
print_error_file(
self.error_file,
repo = REPO_URL,
issue = ISSUE_URL,
)
class DataNotFound(GrawlixError): class DataNotFound(GrawlixError):
pass error_file = "data_not_found"
class InvalidUrl(GrawlixError): class InvalidUrl(GrawlixError):
pass error_file = "invalid_url"
class UnsupportedOutputFormat(GrawlixError): class UnsupportedOutputFormat(GrawlixError):
pass error_file = "unsupported_output_format"
class NoSourceFound(GrawlixError):
pass
class SourceNotAuthenticated(GrawlixError): class SourceNotAuthenticated(GrawlixError):
pass error_file = "source_not_authenticated"
class MissingArgument(GrawlixError):
pass
class ThrottleError(GrawlixError): class ThrottleError(GrawlixError):
pass error_file = "throttle"

View File

@ -1,22 +1,63 @@
from grawlix.book import Book from grawlix.book import Book
from rich.console import Console
from rich.progress import Progress, BarColumn, ProgressColumn, TaskID, SpinnerColumn
import rich import rich
from rich.console import Console
from rich.markup import render
from rich.progress import Progress, BarColumn, ProgressColumn, TaskID, SpinnerColumn
from rich.style import Style
from typing import Union from typing import Union
from dataclasses import dataclass from dataclasses import dataclass
import importlib.resources
console = Console(stderr=True) console = Console(stderr=True)
debug_mode = False
DEBUG_PREFIX = render("[yellow bold]DEBUG[/]")
def debug(msg: str, remove_styling=False) -> None:
"""
Print debug message in console
:param msg: Message to print
:param remove_styling: Remove automated styling from message
"""
if debug_mode:
if remove_styling:
rendered_msg = render(msg, style=Style(bold=False, color="white"))
console.print(DEBUG_PREFIX, rendered_msg)
else:
console.print(DEBUG_PREFIX, msg)
def info(msg: str) -> None: def info(msg: str) -> None:
""" """
Print message in log Print message in console
:param msg: Message to print :param msg: Message to print
""" """
console.print(msg) console.print(msg)
def error(msg: str) -> None:
console.print(msg)
def print_error_file(name: str, **kwargs) -> None:
"""
Print predefined error message
:param name: Name of error file
"""
message = importlib.resources.files("grawlix") \
.joinpath(f"assets/errors/{name}.txt") \
.read_text("utf8") \
.format(**kwargs) \
.strip()
error(message)
def progress(category_name: str, source_name: str, count=1) -> Progress: def progress(category_name: str, source_name: str, count=1) -> Progress:
if count > 1: if count > 1:
console.print(f"Downloading [yellow not bold]{count}[/] books in [blue]{category_name}[/] from [magenta]{source_name}[/]") console.print(f"Downloading [yellow not bold]{count}[/] books in [blue]{category_name}[/] from [magenta]{source_name}[/]")
@ -31,6 +72,7 @@ def progress(category_name: str, source_name: str, count=1) -> Progress:
) )
return progress return progress
def add_book(progress: Progress, book: Book) -> TaskID: def add_book(progress: Progress, book: Book) -> TaskID:
task = progress.add_task( task = progress.add_task(
f"[blue]{book.metadata.title}[/]", f"[blue]{book.metadata.title}[/]",

View File

@ -1,4 +1,4 @@
from grawlix.exceptions import NoSourceFound from grawlix.exceptions import InvalidUrl
from .source import Source from .source import Source
from .ereolen import Ereolen from .ereolen import Ereolen
@ -42,7 +42,7 @@ def find_source(url: str) -> type[Source]:
for num, match in enumerate(cls.match): for num, match in enumerate(cls.match):
if re.match(match, url): if re.match(match, url):
return cls return cls
raise NoSourceFound raise InvalidUrl
def get_source_classes() -> list[type[Source]]: def get_source_classes() -> list[type[Source]]:

View File

@ -2,6 +2,7 @@ from grawlix.exceptions import DataNotFound
from urllib.parse import urlparse, parse_qs from urllib.parse import urlparse, parse_qs
from functools import lru_cache from functools import lru_cache
import importlib.resources
def get_arg_from_url(url: str, key: str) -> str: def get_arg_from_url(url: str, key: str) -> str:
parsed_url = urlparse(url) parsed_url = urlparse(url)
@ -38,3 +39,14 @@ def nearest_string(input: str, list: list[str]) -> str:
Finds the nearest string in `list` to `input` based on levenstein distance Finds the nearest string in `list` to `input` based on levenstein distance
""" """
return sorted(list, key = lambda x: levenstein_distance(input, x))[0] return sorted(list, key = lambda x: levenstein_distance(input, x))[0]
def read_asset_file(path: str) -> str:
"""
Read asset file from the grawlix module
:param path: Path relative to root of grawlix module
"""
return importlib.resources.files("grawlix") \
.joinpath(path) \
.read_text(encoding="utf8")