diff --git a/README.md b/README.md index 93e1e4c..f9d7acf 100644 --- a/README.md +++ b/README.md @@ -4,40 +4,39 @@

- +

- - - - - + + +

- pip-install-bitches was made by + pip-install-traps was made with -Love ❌ code βœ… +Cum ❌ code βœ…

--- -### πŸŽˆγƒ»Code example - -Example of how you can use [traps](https://pypi.org/project/traps/) +### Installation +``` +pip install -U traps +``` +### Usage ```python import traps -traps.get() - -# or - -traps.get( - "yes", # directory name (default: "traps") - 5 # amount of traps (default: randint(5, 10)) -) +traps.get() # Download to `traps` directory. +traps.get("my_homework") # Or to another directory. ``` + +### Command-line interface +* `$ traps` to download 10 traps to `traps` directory +* `$ traps -n 20 my_homework` to download 20 traps to `my_homework` directory +* `$ traps --help` for more help diff --git a/images/trap.jpg b/images/trap.jpg new file mode 100644 index 0000000..942eab7 Binary files /dev/null and b/images/trap.jpg differ diff --git a/poetry.lock b/poetry.lock index 990c8c2..2d8273f 100644 --- a/poetry.lock +++ b/poetry.lock @@ -62,6 +62,21 @@ docs = ["sphinx", "jaraco.packaging (>=9)", "rst.linker (>=1.9)"] perf = ["ipython"] testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "packaging", "pyfakefs", "flufl.flake8", "pytest-perf (>=0.9.2)", "pytest-black (>=0.3.7)", "pytest-mypy (>=0.9.1)", "importlib-resources (>=1.3)"] +[[package]] +name = "loguru" +version = "0.6.0" +description = "Python logging made (stupidly) simple" +category = "main" +optional = false +python-versions = ">=3.5" + +[package.dependencies] +colorama = {version = ">=0.3.4", markers = "sys_platform == \"win32\""} +win32-setctime = {version = ">=1.0.0", markers = "sys_platform == \"win32\""} + +[package.extras] +dev = ["colorama (>=0.3.4)", "docutils (==0.16)", "flake8 (>=3.7.7)", "tox (>=3.9.0)", "pytest (>=4.6.2)", "pytest-cov (>=2.7.1)", "black (>=19.10b0)", "isort (>=5.1.1)", "Sphinx (>=4.1.1)", "sphinx-autobuild (>=0.7.1)", "sphinx-rtd-theme (>=0.4.3)"] + [[package]] name = "requests" version = "2.28.0" @@ -101,6 +116,17 @@ brotli = ["brotlicffi (>=0.8.0)", "brotli (>=1.0.9)", "brotlipy (>=0.6.0)"] secure = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "certifi", "ipaddress"] socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] +[[package]] +name = "win32-setctime" +version = "1.1.0" +description = "A small Python utility to set file creation time on Windows" +category = "main" +optional = false +python-versions = ">=3.5" + +[package.extras] +dev = ["pytest (>=4.6.2)", "black (>=19.3b0)"] + [[package]] name = "zipp" version = "3.8.0" @@ -116,7 +142,7 @@ testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest- [metadata] lock-version = "1.1" python-versions = "^3.7" -content-hash = "1d7efb30a6917067ee323aff51674a885542ec0ab42d54f1b3a07ea5e0aac6e2" +content-hash = "b10cf466f2fef3f183da66173a0f64e6aea107f54a3ab9c476c62548f3f798d0" [metadata.files] certifi = [ @@ -143,6 +169,10 @@ importlib-metadata = [ {file = "importlib_metadata-4.11.4-py3-none-any.whl", hash = "sha256:c58c8eb8a762858f49e18436ff552e83914778e50e9d2f1660535ffb364552ec"}, {file = "importlib_metadata-4.11.4.tar.gz", hash = "sha256:5d26852efe48c0a32b0509ffbc583fda1a2266545a78d104a6f4aff3db17d700"}, ] +loguru = [ + {file = "loguru-0.6.0-py3-none-any.whl", hash = "sha256:4e2414d534a2ab57573365b3e6d0234dfb1d84b68b7f3b948e6fb743860a77c3"}, + {file = "loguru-0.6.0.tar.gz", hash = "sha256:066bd06758d0a513e9836fd9c6b5a75bfb3fd36841f4b996bc60b547a309d41c"}, +] requests = [ {file = "requests-2.28.0-py3-none-any.whl", hash = "sha256:bc7861137fbce630f17b03d3ad02ad0bf978c844f3536d0edda6499dafce2b6f"}, {file = "requests-2.28.0.tar.gz", hash = "sha256:d568723a7ebd25875d8d1eaf5dfa068cd2fc8194b2e483d7b1f7c81918dbec6b"}, @@ -155,6 +185,10 @@ urllib3 = [ {file = "urllib3-1.26.9-py2.py3-none-any.whl", hash = "sha256:44ece4d53fb1706f667c9bd1c648f5469a2ec925fcf3a776667042d645472c14"}, {file = "urllib3-1.26.9.tar.gz", hash = "sha256:aabaf16477806a5e1dd19aa41f8c2b7950dd3c746362d7e3223dbe6de6ac448e"}, ] +win32-setctime = [ + {file = "win32_setctime-1.1.0-py3-none-any.whl", hash = "sha256:231db239e959c2fe7eb1d7dc129f11172354f98361c4fa2d6d2d7e278baa8aad"}, + {file = "win32_setctime-1.1.0.tar.gz", hash = "sha256:15cf5750465118d6929ae4de4eb46e8edae9a5634350c01ba582df868e932cb2"}, +] zipp = [ {file = "zipp-3.8.0-py3-none-any.whl", hash = "sha256:c4f6e5bbf48e74f7a38e7cc5b0480ff42b0ae5178957d564d18932525d5cf099"}, {file = "zipp-3.8.0.tar.gz", hash = "sha256:56bf8aadb83c24db6c4b577e13de374ccfb67da2078beba1d037c17980bf43ad"}, diff --git a/pyproject.toml b/pyproject.toml index b26d7df..3cecc38 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -24,6 +24,7 @@ classifiers = [ python = "^3.7" requests = "^2.28.0" click = "^8.1.3" +loguru = "^0.6.0" [tool.poetry.dev-dependencies] diff --git a/traps/__init__.py b/traps/__init__.py index 38ddcf5..1c77c67 100644 --- a/traps/__init__.py +++ b/traps/__init__.py @@ -1,31 +1,50 @@ -import pathlib +import os import secrets +import sys +from typing import Union import urllib.parse -from multiprocessing import Pool +from concurrent.futures import ThreadPoolExecutor +from pathlib import Path from threading import Thread import click import requests +from loguru import logger __version__ = "1.0.0" API_URL = "https://api.waifu.pics/nsfw/trap" +try: + logger.remove(0) +except ValueError: + pass -def get_traps(params): - directory, url = params - filename = urllib.parse.urlparse(url) - filename = directory.joinpath(secrets.token_hex(8) + pathlib.Path(filename.path).suffix) + +def fetch_url(urls_list: list = None) -> str: + url = requests.get(API_URL).json()["url"] + if urls_list is not None: + urls_list.append(url) + return url + + +def get(directory: Union[str, os.PathLike] = "traps", url: str = None, + create_dir: bool = True): + if url is None: + url = fetch_url() + directory = Path(directory) + if not directory.exists() and create_dir: + directory.mkdir() + filename = urllib.parse.urlparse(url).path + filename = directory.joinpath(secrets.token_hex(8) + Path(filename).suffix) with open(filename, "wb") as f: + logger.debug(f"downloading {url}") response = requests.get(url, stream=True) for block in response.iter_content(1024): if not block: break f.write(block) - - -def fetch_url(urls_list: list): - url = requests.get(API_URL).json()["url"] - urls_list.append(url) + else: + logger.success(f"downloaded {url}") @click.command(help="how about you pip install some traps") @@ -38,33 +57,50 @@ def fetch_url(urls_list: list): show_default=True, help="number of traps to get" ) +@click.option( + "-v", + "--verbose", + is_flag=True, + help="verbose output") @click.argument( "directory", default="traps", type=click.Path( dir_okay=True, file_okay=False, - path_type=pathlib.Path + path_type=Path ) ) -def main(traps: int, directory: pathlib.Path): +def main(traps: int, directory: Path, verbose: bool): + if verbose: + loglevel = "DEBUG" + else: + loglevel = "INFO" + logger.add( + sys.stderr, + level=loglevel, + format="{time:YYYY-MM-DD HH:mm:ss} | " + "{level: <8} | {message}" + ) if not directory.exists(): + logger.debug(f"creating directory {directory}") directory.mkdir() + logger.debug("done") urls = [] threads = [ Thread(target=fetch_url, args=(urls,)) for _ in range(traps) ] + logger.debug("fetching URLs") for thread in threads: thread.start() for thread in threads: thread.join() - params = [ - (directory, url) - for url in urls - ] - with Pool(8) as p: - p.map(get_traps, params) + logger.debug("done") + logger.info("downloading traps") + with ThreadPoolExecutor(max_workers=8) as p: + p.map(lambda url: get(directory, url, False), urls) + logger.info(f"downloaded {traps} traps") if __name__ == '__main__':