diff --git a/README.md b/README.md index 639171e..c2d73f4 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,25 @@ _A Library Genesis ebook uploader._ pip install libgen-uploader ``` -## Usage +## Usage from command-line + +```bash +python -m libgen_uploader (--scitech|--fiction) [args] book.epub +``` + +Optional arguments: +``` +--metadata-source {local,amazon_us,amazon_uk,amazon_de,amazon_fr,amazon_it,amazon_es,amazon_jp,bl,douban,goodreads,google_books,loc,rsl,worldcat} + Source to fetch book metadata from + +--metadata-query METADATA_QUERY + Metadata query for selected source (supports multiple, comma-separated) + +-d, --debug + Activate debug logging +``` + +## Usage as library This library uses [returns](https://github.com/dry-python/returns), and returns [Result containers](https://returns.readthedocs.io/en/latest/pages/result.html) which can either contain a success value or a failure/exception. Exception values are returned, not raised, so you can handle them as you wish and avoid wide `try/except` blocks or program crashes due to unforeseen exceptions. diff --git a/libgen_uploader/__init__.py b/libgen_uploader/__init__.py index 705e6fd..8ba9a78 100644 --- a/libgen_uploader/__init__.py +++ b/libgen_uploader/__init__.py @@ -1,2 +1 @@ from .libgen_uploader import LibgenMetadata, LibgenUploader -from . import helpers diff --git a/libgen_uploader/__main__.py b/libgen_uploader/__main__.py new file mode 100644 index 0000000..85c76e6 --- /dev/null +++ b/libgen_uploader/__main__.py @@ -0,0 +1,79 @@ +import logging + +from libgen_uploader import LibgenUploader +from returns.pipeline import is_successful + + +def main(args): + u = LibgenUploader(metadata_source=args.metadata_source) + + if args.scitech: + result = u.upload_scitech( + file_path=args.file, metadata_query=args.metadata_query + ) + else: + result = u.upload_fiction( + file_path=args.file, metadata_query=args.metadata_query + ) + + if is_successful(result): + logging.info(f"Upload successful! URL: {result.unwrap()}.") + else: + logging.error("Upload failed.") + raise result.failure() + + +if __name__ == "__main__": + import argparse + + # https://bugs.python.org/issue22240 + parser = argparse.ArgumentParser( + prog=None + if globals().get("__spec__") is None + else "python -m {}".format(__spec__.name.partition(".")[0]) # type: ignore + ) + upload_type = parser.add_mutually_exclusive_group(required=True) + upload_type.add_argument("--scitech", action="store_true") + upload_type.add_argument("--fiction", action="store_true") + parser.add_argument( + "--metadata-source", + type=str, + choices=[ + "local", + "amazon_us", + "amazon_uk", + "amazon_de", + "amazon_fr", + "amazon_it", + "amazon_es", + "amazon_jp", + "bl", + "douban", + "goodreads", + "google_books", + "loc", + "rsl", + "worldcat", + ], + help="Source to fetch book metadata from", + ) + parser.add_argument( + "--metadata-query", + type=str, + help="Metadata query for selected source (supports multiple, comma-separated)", + ) + parser.add_argument( + "-d", "--debug", action="store_true", help="Activate debug logging" + ) + parser.add_argument("file", type=str) + args = parser.parse_args() + + logging.basicConfig(level=logging.DEBUG if args.debug is True else logging.INFO) + + if args.metadata_source: + if args.metadata_query: + args.metadata_query = [q.strip() for q in args.metadata_query.split(",")] + else: + raise parser.error("--metadata-query requires --metadata-source") + + main(args) diff --git a/libgen_uploader/libgen_uploader.py b/libgen_uploader/libgen_uploader.py index e9f736c..c70e84a 100644 --- a/libgen_uploader/libgen_uploader.py +++ b/libgen_uploader/libgen_uploader.py @@ -4,7 +4,8 @@ import os from io import BytesIO -from typing import ByteString, List, Union +from ntpath import basename +from typing import List, Union # https://github.com/jmcarp/robobrowser/issues/93 import werkzeug @@ -107,16 +108,17 @@ def _submit_and_check_form(self, form: Form) -> Result[str, Exception]: @staticmethod @safe - def _validate_file(file: Union[str, bytes]): + def _validate_file(file: Union[str, bytes]) -> Union[str, bytes]: + if isinstance(file, bytes): + # TODO add file data validation? + return file + if isinstance(file, str): if not os.path.isfile(file): raise FileNotFoundError(f"Upload failed: {file} is not a file.") - elif isinstance(file, bytes): - # TODO add file data validation? - pass - - return file + logging.info(f"Selected file {basename(file)}") + return file @safe def _upload_file(self, file: Union[str, bytes]) -> BeautifulSoup: @@ -250,6 +252,13 @@ def _validate_metadata(form: Form) -> Form: # delete "fetch metadata" submit del form.fields["fetch_metadata"] + + logging.debug( + "Final book metadata: {}".format( + ", ".join(f"{k}: {v.value}" for k, v in form.fields.items() if v.value) + ) + ) + return form def _handle_save_failure(self, exception: Exception) -> Result[str, Exception]: @@ -311,7 +320,6 @@ def upload_fiction( metadata: LibgenMetadata = None, metadata_source: str = None, metadata_query: Union[str, List] = None, - ignore_empty_metadata_fetch: bool = False, ) -> Result[str, Exception]: self._init_browser() self._browser.open(FICTION_UPLOAD_URL)