[2.1.9] - 2022-06-26
All checks were successful
ci/woodpecker/tag/tests Pipeline was successful
ci/woodpecker/tag/publish_release Pipeline was successful
ci/woodpecker/tag/publish_docker Pipeline was successful

## [2.1.9] - 2022-06-26

### Fixed

- Timeouts in tests, due to api limitations. Now added a wait time between tests
- Pytest path

### Added

- `--lean` flag for less output
- [justfile](https://github.com/casey/just) for setting up a dev environment and testing the code
- [asdf](https://github.com/asdf-vm/asdf) for version management
- Dev requirements in [contrib/requirements_dev.txt](contrib/requirements_dev.txt)
- `README` in [contrib](contrib)

### Changed

- Handling of verbosity and logging. Now there are 4 types of verbosity: `normal`, `lean`, `verbose` and `debug`
- CI/CD pipeline for testing and releases
- Coverage testing now also done with `tox`
- Default verbosity of docker container is now `--lean`
- Reorganised [pyproject.toml](pyproject.toml)
This commit is contained in:
Ivan Schaller 2022-06-26 21:16:39 +02:00
commit b4d636a845
32 changed files with 512 additions and 251 deletions

View file

@ -1,5 +1,5 @@
[bumpversion] [bumpversion]
current_version = 2.1.8 current_version = 2.1.9
commit = True commit = True
tag = False tag = False
serialize = {major}.{minor}.{patch} serialize = {major}.{minor}.{patch}

1
.envrc Normal file
View file

@ -0,0 +1 @@
use asdf

5
.tool-versions Normal file
View file

@ -0,0 +1,5 @@
python 3.9.13 3.10.5 3.8.13 3.7.13 3.6.15
shfmt 3.5.1
shellcheck 0.8.0
just 1.2.0
direnv 2.32.1

View file

@ -1,42 +0,0 @@
#############
# build app #
#############
# branch: master
# event: tag
depends_on:
- tests
clone:
git:
when:
#branch: master
event: tag
image: woodpeckerci/plugin-git
pipeline:
# build wheel and dist
build-pypi:
when:
#branch: master
event: tag
image: cr.44net.ch/ci-plugins/tests
pull: true
commands:
- hatch build
# release pypi
release-pypi:
when:
#branch: master
event: tag
image: cr.44net.ch/ci-plugins/tests
pull: true
secrets:
- source: pypi_username
target: HATCH_PYPI_USER
- source: pypi_token
target: HATCH_PYPI_AUTH
commands:
- hatch publish

View file

@ -16,15 +16,15 @@ clone:
pipeline: pipeline:
# create release tar # build wheel and dist
create-release-tar: build-pypi:
when: when:
#branch: master #branch: master
event: tag event: tag
image: cr.44net.ch/baseimages/debian-base image: cr.44net.ch/ci-plugins/tests
pull: true pull: true
commands: commands:
- tar -czf manga-dlp-${CI_COMMIT_TAG}.tar.gz --files-from=release-files.txt - hatch build
# create release-notes # create release-notes
create-release-notes: create-release-notes:
@ -47,7 +47,7 @@ pipeline:
api_key: api_key:
from_secret: gitea-olofvndrhr-token from_secret: gitea-olofvndrhr-token
base_url: https://git.44net.ch base_url: https://git.44net.ch
files: manga-dlp-${CI_COMMIT_TAG}.tar.gz files: dist/*
title: ${CI_COMMIT_TAG} title: ${CI_COMMIT_TAG}
note: RELEASENOTES.md note: RELEASENOTES.md
@ -61,6 +61,21 @@ pipeline:
settings: settings:
api_key: api_key:
from_secret: github-olofvndrhr-token from_secret: github-olofvndrhr-token
files: manga-dlp-${CI_COMMIT_TAG}.tar.gz files: dist/*
title: ${CI_COMMIT_TAG} title: ${CI_COMMIT_TAG}
note: RELEASENOTES.md note: RELEASENOTES.md
# release pypi
release-pypi:
when:
#branch: master
event: tag
image: cr.44net.ch/ci-plugins/tests
pull: true
secrets:
- source: pypi_username
target: HATCH_PYPI_USER
- source: pypi_token
target: HATCH_PYPI_AUTH
commands:
- hatch publish

View file

@ -1,47 +0,0 @@
##################
# test build app #
##################
# branch: master
# event: pull_request
depends_on:
- tests
clone:
git:
when:
branch: master
event: pull_request
image: woodpeckerci/plugin-git
pipeline:
# build wheel and dist
test-build-pypi:
when:
branch: master
event: pull_request
image: cr.44net.ch/ci-plugins/tests
pull: true
commands:
- hatch build
# # test code with different python versions - amd64
# test-tox-amd64:
# when:
# branch: master
# event: pull_request
# image: cr.44net.ch/ci-plugins/tests:1-linux-amd64
# pull: true
# commands:
# - tox
#
# # test code with different python versions - arm64
# test-tox-arm64:
# when:
# branch: master
# event: pull_request
# image: cr.44net.ch/ci-plugins/tests:1-linux-arm64
# pull: true
# commands:
# - tox

View file

@ -30,7 +30,7 @@ pipeline:
dockerfile: docker/Dockerfile.amd64 dockerfile: docker/Dockerfile.amd64
auto_tag: true auto_tag: true
auto_tag_suffix: linux-amd64-test auto_tag_suffix: linux-amd64-test
build_args: BUILD_VERSION=2.1.8 build_args: BUILD_VERSION=2.1.9
# build docker image for arm64 # build docker image for arm64
test-build-arm64: test-build-arm64:
@ -46,4 +46,4 @@ pipeline:
dockerfile: docker/Dockerfile.arm64 dockerfile: docker/Dockerfile.arm64
auto_tag: true auto_tag: true
auto_tag_suffix: linux-arm64-test auto_tag_suffix: linux-arm64-test
build_args: BUILD_VERSION=2.1.8 build_args: BUILD_VERSION=2.1.9

View file

@ -1,6 +1,6 @@
######################## ################
# test publish release # # test release #
######################## ################
# branch: master # branch: master
# event: pull_request # event: pull_request
@ -16,18 +16,17 @@ clone:
pipeline: pipeline:
# create release tar # build wheel and dist
test-create-release-tar: test-build-pypi:
when: when:
branch: master branch: master
event: pull_request event: pull_request
image: cr.44net.ch/baseimages/debian-base image: cr.44net.ch/ci-plugins/tests
pull: true pull: true
commands: commands:
- tar -czf manga-dlp-2.1.8.tar.gz --files-from=release-files.txt - hatch build
- tar -tzf manga-dlp-2.1.8.tar.gz
# create release-notes # create release-notes
test-create-release-notes: test-create-release-notes:
when: when:
branch: master branch: master
@ -35,5 +34,5 @@ pipeline:
image: cr.44net.ch/baseimages/debian-base image: cr.44net.ch/baseimages/debian-base
pull: true pull: true
commands: commands:
- bash get_release_notes.sh 2.1.8 - bash get_release_notes.sh 2.1.9
- cat RELEASENOTES.md - cat RELEASENOTES.md

View file

@ -0,0 +1,27 @@
##################
# test tox amd64 #
##################
# branch: master
# event: pull_request
depends_on:
- tests
clone:
git:
when:
branch: master
event: pull_request
image: woodpeckerci/plugin-git
pipeline:
# test code with different python versions - amd64
test-tox-amd64:
when:
branch: master
event: pull_request
image: cr.44net.ch/ci-plugins/multipy:1-linux-amd64
pull: true
commands:
- tox

View file

@ -0,0 +1,30 @@
##################
# test tox arm64 #
##################
# branch: master
# event: pull_request
depends_on:
- tests
clone:
git:
when:
branch: master
event: pull_request
image: woodpeckerci/plugin-git
pipeline:
# test code with different python versions - arm64
test-tox-arm64:
when:
branch: master
event: pull_request
image: cr.44net.ch/ci-plugins/multipy:1-linux-arm64
pull: true
commands:
- grep -v img2pdf contrib/requirements_dev.txt > contrib/requirements_dev_arm64.txt
- rm -f contrib/requirements_dev.txt
- mv contrib/requirements_dev_arm64.txt contrib/requirements_dev.txt
- tox

View file

@ -38,20 +38,30 @@ pipeline:
commands: commands:
- mypy --install-types --non-interactive mangadlp/ - mypy --install-types --non-interactive mangadlp/
# test code and generate coverage report # test code with different python versions
test-coverage-pytest: test-tox-pytest:
image: cr.44net.ch/ci-plugins/tests when:
event: [ push ]
image: cr.44net.ch/ci-plugins/multipy:1-linux-amd64
pull: true pull: true
commands: commands:
- pip install -r requirements.txt - tox -e basic
- coverage erase
- coverage run # generate coverage report
- coverage xml -i test-tox-coverage:
when:
branch: master
event: [ pull_request ]
image: cr.44net.ch/ci-plugins/multipy:1-linux-amd64
pull: true
commands:
- tox -e coverage
# analyse code with sonarqube and upload it # analyse code with sonarqube and upload it
sonarqube-analysis: sonarqube-analysis:
when: when:
branch: master branch: master
event: [ pull_request ]
image: cr.44net.ch/ci-plugins/sonar-scanner image: cr.44net.ch/ci-plugins/sonar-scanner
pull: true pull: true
settings: settings:

View file

@ -9,6 +9,29 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
- Add support for more sites - Add support for more sites
## [2.1.9] - 2022-06-26
### Fixed
- Timeouts in tests, due to api limitations. Now added a wait time between tests
- Pytest path
### Added
- `--lean` flag for less output
- [justfile](https://github.com/casey/just) for setting up a dev environment and testing the code
- [asdf](https://github.com/asdf-vm/asdf) for version management
- Dev requirements in [contrib/requirements_dev.txt](contrib/requirements_dev.txt)
- `README` in [contrib](contrib)
### Changed
- Handling of verbosity and logging. Now there are 4 types of verbosity: `normal`, `lean`, `verbose` and `debug`
- CI/CD pipeline for testing and releases
- Coverage testing now also done with `tox`
- Default verbosity of docker container is now `--lean`
- Reorganised [pyproject.toml](pyproject.toml)
## [2.1.8] - 2022-06-22 ## [2.1.8] - 2022-06-22
### Fixed ### Fixed

View file

@ -224,10 +224,12 @@ This will download the chapter and save it as a zip archive.
For suggestions for improvement, just open a pull request. For suggestions for improvement, just open a pull request.
If you want to add support for a new site, there is an api [template file](./contrib/api_template.py) which you can use. If you want to add support for a new site, there is an api [template file](./contrib/api_template.py) which you can use.
And more infos and tools in the contrib [README.md](contrib/README.md)
Otherwise you can open a issue with the name of the site which you want support for. (not guaranteed to be implemented) Otherwise, you can open am issue with the name of the site which you want support for. (not guaranteed to be
implemented)
If you encounter any bugs, also just open a issue with a description of the problem. If you encounter any bugs, also just open an issue with a description of the problem.
## TODO's ## TODO's

16
contrib/README.md Normal file
View file

@ -0,0 +1,16 @@
# contribute
### install dev requirements
```sh
python3 -m pip install -r contrib/requirements_dev.txt
```
### setup asdf with all needed tools and versions
> you may need to install just first: [link](https://github.com/casey/just)
```sh
just prepare_workspace
```

View file

@ -0,0 +1,13 @@
# application requirements
requests>=2.24.0
img2pdf>=0.4.4
# dev and testing requirements
pytest>=7.0.0
coverage>=6.3.1
black>=22.1.0
isort>=5.10.0
pylint>=2.13.0
mypy>=0.940
tox>=3.24.5
hatch>=1.0.0

View file

@ -55,7 +55,8 @@ python3 /app/manga-dlp.py \
--path /app/downloads \ --path /app/downloads \
--read /app/mangas.txt \ --read /app/mangas.txt \
--chapters all \ --chapters all \
--wait 2 --wait 2 \
--lean
``` ```
To use your own schedule you need to mount (override) the default schedule or add new ones to the crontab. To use your own schedule you need to mount (override) the default schedule or add new ones to the crontab.

View file

@ -4,4 +4,5 @@ python3 /app/manga-dlp.py \
--path /app/downloads \ --path /app/downloads \
--read /app/mangas.txt \ --read /app/mangas.txt \
--chapters all \ --chapters all \
--wait 2 --wait 2 \
--lean

137
justfile Executable file
View file

@ -0,0 +1,137 @@
#!/usr/bin/env just --justfile
default: show_receipts
set shell := ["bash", "-uc"]
set dotenv-load := true
#set export
# aliases
alias s := show_receipts
alias i := show_system_info
alias p := prepare_workspace
alias l := lint
alias t := tests
alias f := tests_full
# variables
export asdf_version := "v0.10.2"
# default recipe to display help information
show_receipts:
@just --list
show_system_info:
@echo "=================================="
@echo "os : {{os()}}"
@echo "arch: {{arch()}}"
@echo "home: ${HOME}"
@echo "project dir: {{justfile_directory()}}"
@echo "=================================="
check_asdf:
@if ! asdf --version; then \
just install_asdf \
;else \
echo "asdf already installed" \
;fi
just install_asdf_bins
install_asdf:
@echo "installing asdf"
@echo "asdf version: ${asdf_version}"
@git clone https://github.com/asdf-vm/asdf.git ~/.asdf --branch "${asdf_version}"
@echo "adding asdf to .bashrc"
@if ! grep -q ".asdf/asdf.sh" "${HOME}/.bashrc"; then \
echo -e '\n# source asdf' >> "${HOME}/.bashrc" \
;echo 'source "${HOME}/.asdf/asdf.sh"' >> "${HOME}/.bashrc" \
;echo -e 'source "${HOME}/.asdf/completions/asdf.bash"\n' >> "${HOME}/.bashrc" \
;fi
@echo "to load asdf either restart your shell or do: 'source \${HOME}/.bashrc'"
setup_asdf:
@echo "installing asdf bins"
# add plugins
@if ! asdf plugin add python; then :; fi
@if ! asdf plugin add shfmt; then :; fi
@if ! asdf plugin add shellcheck; then :; fi
@if ! asdf plugin add just https://github.com/franklad/asdf-just; then :; fi
@if ! asdf plugin add direnv; then :; fi
# install bins
@if ! asdf install; then :; fi
# setup direnv
@if ! asdf direnv setup --shell bash --version latest; then :; fi
create_venv:
@echo "creating venv"
@python3 -m pip install --upgrade pip setuptools wheel
@python3 -m venv venv
test_shfmt:
@find . -type f \( -name "**.sh" -and -not -path "./venv/*" -and -not -path "./.tox/*" \) -exec shfmt -d -i 4 -bn -ci -sr "{}" \+;
test_black:
@python3 -m black --check --diff .
test_isort:
@python3 -m isort --check-only --diff .
test_mypy:
@python3 -m mypy --install-types --non-interactive mangadlp/
test_pytest:
@python3 -m tox -e basic
test_tox:
@python3 -m tox
test_tox_coverage:
@python3 -m tox -e coverage
test_build:
@python3 -m hatch build
test_ci_conf:
@woodpecker-cli lint .woodpecker/
test_docker_build:
@docker build . -f docker/Dockerfile.amd64 -t manga-dlp:test
# install dependecies and set everything up
prepare_workspace:
just show_system_info
just check_asdf
just setup_asdf
just create_venv
lint:
just show_system_info
-just test_ci_conf
just test_shfmt
just test_black
just test_isort
just test_mypy
@echo -e "\n\033[0;32m=== ALL DONE ===\033[0m\n"
tests:
just show_system_info
-just test_ci_conf
just test_shfmt
just test_black
just test_isort
just test_mypy
just test_pytest
@echo -e "\n\033[0;32m=== ALL DONE ===\033[0m\n"
tests_full:
just show_system_info
-just test_ci_conf
just test_shfmt
just test_black
just test_isort
just test_mypy
just test_build
just test_tox
just test_tox_coverage
just test_docker_build
@echo -e "\n\033[0;32m=== ALL DONE ===\033[0m\n"

View file

@ -1,6 +1,6 @@
from mangadlp.input import main from mangadlp.input import main
MDLP_VERSION = "2.1.8" MDLP_VERSION = "2.1.9"
if __name__ == "__main__": if __name__ == "__main__":
main() main()

View file

@ -15,12 +15,12 @@ class Mangadex:
img_base_url = "https://uploads.mangadex.org" img_base_url = "https://uploads.mangadex.org"
# get infos to initiate class # get infos to initiate class
def __init__(self, url_uuid: str, language: str, forcevol: bool, verbose: bool): def __init__(self, url_uuid: str, language: str, forcevol: bool, verbosity: int):
# static info # static info
self.url_uuid = url_uuid self.url_uuid = url_uuid
self.language = language self.language = language
self.forcevol = forcevol self.forcevol = forcevol
self.verbose = verbose self.verbosity = verbosity
# api stuff # api stuff
self.api_content_ratings = "contentRating[]=safe&contentRating[]=suggestive&contentRating[]=erotica&contentRating[]=pornographic" self.api_content_ratings = "contentRating[]=safe&contentRating[]=suggestive&contentRating[]=erotica&contentRating[]=pornographic"
@ -36,7 +36,7 @@ class Mangadex:
# make initial request # make initial request
def get_manga_data(self) -> requests.Response: def get_manga_data(self) -> requests.Response:
if self.verbose: if self.verbosity >= 2:
print(f"INFO: Getting manga data for: {self.manga_uuid}") print(f"INFO: Getting manga data for: {self.manga_uuid}")
counter = 1 counter = 1
while counter <= 3: while counter <= 3:
@ -76,7 +76,7 @@ class Mangadex:
# get the title of the manga (and fix the filename) # get the title of the manga (and fix the filename)
def get_manga_title(self) -> str: def get_manga_title(self) -> str:
if self.verbose: if self.verbosity >= 2:
print(f"INFO: Getting manga title for: {self.manga_uuid}") print(f"INFO: Getting manga title for: {self.manga_uuid}")
manga_data = self.manga_data.json() manga_data = self.manga_data.json()
try: try:
@ -95,7 +95,7 @@ class Mangadex:
# check if chapters are available in requested language # check if chapters are available in requested language
def check_chapter_lang(self) -> int: def check_chapter_lang(self) -> int:
if self.verbose: if self.verbosity >= 2:
print( print(
f"INFO: Checking for chapters in specified language for: {self.manga_uuid}" f"INFO: Checking for chapters in specified language for: {self.manga_uuid}"
) )
@ -118,7 +118,7 @@ class Mangadex:
# get chapter data like name, uuid etc # get chapter data like name, uuid etc
def get_chapter_data(self) -> dict: def get_chapter_data(self) -> dict:
if self.verbose: if self.verbosity >= 2:
print(f"INFO: Getting chapter data for: {self.manga_uuid}") print(f"INFO: Getting chapter data for: {self.manga_uuid}")
api_sorting = "order[chapter]=asc&order[volume]=asc" api_sorting = "order[chapter]=asc&order[volume]=asc"
# check for chapters in specified lang # check for chapters in specified lang
@ -177,7 +177,7 @@ class Mangadex:
# get images for the chapter (mangadex@home) # get images for the chapter (mangadex@home)
def get_chapter_images(self, chapter: str, wait_time: float) -> list: def get_chapter_images(self, chapter: str, wait_time: float) -> list:
if self.verbose: if self.verbosity >= 2:
print(f"INFO: Getting chapter images for: {self.manga_uuid}") print(f"INFO: Getting chapter images for: {self.manga_uuid}")
athome_url = f"{self.api_base_url}/at-home/server" athome_url = f"{self.api_base_url}/at-home/server"
chapter_uuid = self.manga_chapter_data[chapter][0] chapter_uuid = self.manga_chapter_data[chapter][0]
@ -224,7 +224,7 @@ class Mangadex:
# create list of chapters # create list of chapters
def create_chapter_list(self) -> list: def create_chapter_list(self) -> list:
if self.verbose: if self.verbosity >= 2:
print(f"INFO: Creating chapter list for: {self.manga_uuid}") print(f"INFO: Creating chapter list for: {self.manga_uuid}")
chapter_list = [] chapter_list = []
for chapter in self.manga_chapter_data.items(): for chapter in self.manga_chapter_data.items():
@ -240,7 +240,7 @@ class Mangadex:
# create easy to access chapter infos # create easy to access chapter infos
def get_chapter_infos(self, chapter: str) -> dict: def get_chapter_infos(self, chapter: str) -> dict:
if self.verbose: if self.verbosity >= 3:
print( print(
f"INFO: Getting chapter infos for: {self.manga_chapter_data[chapter][0]}" f"INFO: Getting chapter infos for: {self.manga_chapter_data[chapter][0]}"
) )

View file

@ -23,7 +23,7 @@ class MangaDLP:
:param forcevol: Force naming of volumes. Useful for mangas where chapters reset each volume :param forcevol: Force naming of volumes. Useful for mangas where chapters reset each volume
:param download_path: Download path. Defaults to '<script_dir>/downloads' :param download_path: Download path. Defaults to '<script_dir>/downloads'
:param download_wait: Time to wait for each picture to download in seconds :param download_wait: Time to wait for each picture to download in seconds
:param verbose: If verbose logging is enabled :param verbosity: Verbosity of the output
:return: Nothing. Just the files :return: Nothing. Just the files
""" """
@ -38,7 +38,7 @@ class MangaDLP:
forcevol: bool = False, forcevol: bool = False,
download_path: str = "downloads", download_path: str = "downloads",
download_wait: float = 0.5, download_wait: float = 0.5,
verbose: bool = False, verbosity: int = 0,
) -> None: ) -> None:
# init parameters # init parameters
self.url_uuid = url_uuid self.url_uuid = url_uuid
@ -49,7 +49,7 @@ class MangaDLP:
self.forcevol = forcevol self.forcevol = forcevol
self.download_path = download_path self.download_path = download_path
self.download_wait = download_wait self.download_wait = download_wait
self.verbose = verbose self.verbosity = verbosity
# prepare everything # prepare everything
self._prepare() self._prepare()
@ -63,7 +63,7 @@ class MangaDLP:
# init api # init api
self.api_used = self.check_api(self.url_uuid) self.api_used = self.check_api(self.url_uuid)
self.api = self.api_used( self.api = self.api_used(
self.url_uuid, self.language, self.forcevol, self.verbose self.url_uuid, self.language, self.forcevol, self.verbosity
) )
# get manga title and uuid # get manga title and uuid
self.manga_uuid = self.api.manga_uuid self.manga_uuid = self.api.manga_uuid
@ -125,12 +125,15 @@ class MangaDLP:
skipped_chapters: list[Any] = [] skipped_chapters: list[Any] = []
error_chapters: list[Any] = [] error_chapters: list[Any] = []
# show infos
print_divider = "=========================================" print_divider = "========================================="
print(f"\n{print_divider}") # show infos
print(f"INFO: Manga Name: {self.manga_title}") if self.verbosity == 1:
print(f"INFO: Manga UUID: {self.manga_uuid}") print(f"INFO: Manga Name: {self.manga_title}")
print(f"INFO: Total chapters: {len(self.manga_chapter_list)}") else:
print(f"{print_divider}")
print(f"INFO: Manga Name: {self.manga_title}")
print(f"INFO: Manga UUID: {self.manga_uuid}")
print(f"INFO: Total chapters: {len(self.manga_chapter_list)}")
# list chapters if list_chapters is true # list chapters if list_chapters is true
if self.list_chapters: if self.list_chapters:
@ -147,8 +150,11 @@ class MangaDLP:
) )
# show chapters to download # show chapters to download
print(f"INFO: Chapters selected:\n{', '.join(chapters_to_download)}") if self.verbosity == 1:
print(f"{print_divider}\n") print(f"INFO: Chapters selected: {', '.join(chapters_to_download)}")
else:
print(f"INFO: Chapters selected:\n{', '.join(chapters_to_download)}")
print(f"{print_divider}")
# create manga folder # create manga folder
self.manga_path.mkdir(parents=True, exist_ok=True) self.manga_path.mkdir(parents=True, exist_ok=True)
@ -171,17 +177,25 @@ class MangaDLP:
print("INFO: Done with chapter\n") print("INFO: Done with chapter\n")
# done with manga # done with manga
print(f"{print_divider}") if self.verbosity != 1:
print(f"{print_divider}")
print(f"INFO: Done with manga: {self.manga_title}") print(f"INFO: Done with manga: {self.manga_title}")
# filter skipped list # filter skipped list
skipped_chapters = list(filter(None, skipped_chapters)) skipped_chapters = list(filter(None, skipped_chapters))
if len(skipped_chapters) >= 1: if len(skipped_chapters) >= 1:
print(f"INFO: Skipped chapters:\n{', '.join(skipped_chapters)}") if self.verbosity == 1:
print(f"INFO: Skipped chapters: {', '.join(skipped_chapters)}")
else:
print(f"INFO: Skipped chapters:\n{', '.join(skipped_chapters)}")
# filter error list # filter error list
error_chapters = list(filter(None, error_chapters)) error_chapters = list(filter(None, error_chapters))
if len(error_chapters) >= 1: if len(error_chapters) >= 1:
print(f"INFO: Chapters with errors:\n{', '.join(error_chapters)}") if self.verbosity == 1:
print(f"{print_divider}\n") print(f"INFO: Chapters with errors: {', '.join(error_chapters)}")
else:
print(f"INFO: Chapters with errors:\n{', '.join(error_chapters)}")
if self.verbosity != 1:
print(f"{print_divider}\n")
# once called per chapter # once called per chapter
def get_chapter(self, chapter: str) -> dict: def get_chapter(self, chapter: str) -> dict:
@ -225,7 +239,8 @@ class MangaDLP:
# check if chapter already exists # check if chapter already exists
# check for folder, if file format is an empty string # check for folder, if file format is an empty string
if chapter_archive_path.exists(): if chapter_archive_path.exists():
print(f"INFO: '{chapter_archive_path}' already exists. Skipping") if self.verbosity != 1:
print(f"INFO: '{chapter_archive_path}' already exists. Skipping")
# add to skipped chapters list # add to skipped chapters list
return ( return (
{ {
@ -240,7 +255,7 @@ class MangaDLP:
chapter_path.mkdir(parents=True, exist_ok=True) chapter_path.mkdir(parents=True, exist_ok=True)
# verbose log # verbose log
if self.verbose: if self.verbosity >= 2:
print(f"INFO: Chapter UUID: {chapter_infos['uuid']}") print(f"INFO: Chapter UUID: {chapter_infos['uuid']}")
print(f"INFO: Filename: '{chapter_archive_path.name}'\n") print(f"INFO: Filename: '{chapter_archive_path.name}'\n")
print(f"INFO: File path: '{chapter_archive_path}'\n") print(f"INFO: File path: '{chapter_archive_path}'\n")
@ -252,7 +267,7 @@ class MangaDLP:
# download images # download images
try: try:
downloader.download_chapter( downloader.download_chapter(
chapter_image_urls, chapter_path, self.download_wait, self.verbose chapter_image_urls, chapter_path, self.download_wait, self.verbosity
) )
except KeyboardInterrupt: except KeyboardInterrupt:
print("ERR: Stopping") print("ERR: Stopping")

View file

@ -14,7 +14,7 @@ def download_chapter(
image_urls: list, image_urls: list,
chapter_path: Union[str, Path], chapter_path: Union[str, Path],
download_wait: float, download_wait: float,
verbose: bool, verbosity: int,
) -> None: ) -> None:
total_img = len(image_urls) total_img = len(image_urls)
for image_num, image in enumerate(image_urls, 1): for image_num, image in enumerate(image_urls, 1):
@ -22,11 +22,11 @@ def download_chapter(
image_suffix = str(Path(image).suffix) or ".png" image_suffix = str(Path(image).suffix) or ".png"
# set image path # set image path
image_path = Path(f"{chapter_path}/{image_num:03d}{image_suffix}") image_path = Path(f"{chapter_path}/{image_num:03d}{image_suffix}")
# show progress bar if verbose logging is not active # show progress bar or progress by image for verbose
if verbose: if verbosity == 0:
print(f"INFO: Downloading image {image_num}/{total_img}")
else:
utils.progress_bar(image_num, total_img) utils.progress_bar(image_num, total_img)
elif verbosity >= 2:
print(f"INFO: Downloading image {image_num}/{total_img}")
counter = 1 counter = 1
while counter <= 3: while counter <= 3:

View file

@ -5,7 +5,7 @@ from pathlib import Path
import mangadlp.app as app import mangadlp.app as app
MDLP_VERSION = "2.1.8" MDLP_VERSION = "2.1.9"
def check_args(args): def check_args(args):
@ -48,7 +48,7 @@ def call_app(args):
args.forcevol, args.forcevol,
args.path, args.path,
args.wait, args.wait,
args.verbose, args.verbosity,
) )
mdlp.get_manga() mdlp.get_manga()
@ -95,8 +95,10 @@ def get_args():
parser = argparse.ArgumentParser( parser = argparse.ArgumentParser(
description="Script to download mangas from various sites" description="Script to download mangas from various sites"
) )
group = parser.add_mutually_exclusive_group(required=True) action = parser.add_mutually_exclusive_group(required=True)
group.add_argument( verbosity = parser.add_mutually_exclusive_group(required=False)
action.add_argument(
"-u", "-u",
"--url", "--url",
"--uuid", "--uuid",
@ -105,14 +107,14 @@ def get_args():
help="URL or UUID of the manga", help="URL or UUID of the manga",
action="store", action="store",
) )
group.add_argument( action.add_argument(
"--read", "--read",
dest="read", dest="read",
required=False, required=False,
help="Path of file with manga links to download. One per line", help="Path of file with manga links to download. One per line",
action="store", action="store",
) )
group.add_argument( action.add_argument(
"-v", "-v",
"--version", "--version",
dest="version", dest="version",
@ -176,12 +178,32 @@ def get_args():
default=0.5, default=0.5,
help="Time to wait for each picture to download in seconds(float). Defaults 0.5", help="Time to wait for each picture to download in seconds(float). Defaults 0.5",
) )
parser.add_argument( verbosity.add_argument(
"--lean",
dest="verbosity",
required=False,
help="Lean logging. Defaults to false",
action="store_const",
const=1,
default=0,
)
verbosity.add_argument(
"--verbose", "--verbose",
dest="verbose", dest="verbosity",
required=False, required=False,
help="Verbose logging. Defaults to false", help="Verbose logging. Defaults to false",
action="store_true", action="store_const",
const=2,
default=0,
)
verbosity.add_argument(
"--debug",
dest="verbosity",
required=False,
help="Lean logging. Defaults to false",
action="store_const",
const=3,
default=0,
) )
# parser.print_help() # parser.print_help()

View file

@ -3,7 +3,7 @@ requires = ["hatchling"]
build-backend = "hatchling.build" build-backend = "hatchling.build"
[project] [project]
version = "2.1.8" version = "2.1.9"
name = "manga-dlp" name = "manga-dlp"
description = "A cli manga downloader" description = "A cli manga downloader"
readme = "README.md" readme = "README.md"
@ -39,7 +39,25 @@ Source = "https://github.com/olofvndrhr/manga-dlp"
mangadlp = "mangadlp.input:main" mangadlp = "mangadlp.input:main"
manga-dlp = "mangadlp.input:main" manga-dlp = "mangadlp.input:main"
# isort config [tool.hatch.build]
ignore-vcs = true
[tool.hatch.build.targets.sdist]
include = ["mangadlp"]
exclude = [
"docker",
".tox",
".mypy_cache"
]
[tool.hatch.build.targets.wheel]
include = ["mangadlp"]
exclude = [
"docker",
".tox",
".mypy_cache"
]
[tool.isort] [tool.isort]
py_version = 39 py_version = 39
skip_gitignore = true skip_gitignore = true
@ -49,7 +67,6 @@ multi_line_output = 3
include_trailing_comma = true include_trailing_comma = true
use_parentheses = true use_parentheses = true
# mypy config
[tool.mypy] [tool.mypy]
python_version = "3.9" python_version = "3.9"
disallow_untyped_defs = false disallow_untyped_defs = false
@ -62,11 +79,15 @@ show_column_numbers = true
show_error_codes = true show_error_codes = true
pretty = true pretty = true
# coverage.py config [tool.pytest.ini_options]
pythonpath = [
"."
]
[tool.coverage.run] [tool.coverage.run]
source = ["mangadlp"] source = ["mangadlp"]
branch = true branch = true
command_line = "-m pytest --verbose --exitfirst" command_line = "-m pytest --exitfirst"
[tool.coverage.report] [tool.coverage.report]
# Regexes for lines to exclude from consideration # Regexes for lines to exclude from consideration
@ -86,22 +107,3 @@ exclude_lines = [
"@(abc.)?abstractmethod", "@(abc.)?abstractmethod",
] ]
ignore_errors = true ignore_errors = true
[tool.hatch.build]
ignore-vcs = true
[tool.hatch.build.targets.sdist]
include = ["mangadlp"]
exclude = [
"docker",
".tox",
".mypy_cache"
]
[tool.hatch.build.targets.wheel]
include = ["mangadlp"]
exclude = [
"docker",
".tox",
".mypy_cache"
]

View file

@ -1,3 +1,3 @@
requests>=2.24.0 requests>=2.24.0
img2pdf>=0.4.4 img2pdf>=0.4.4

View file

@ -1,5 +1,3 @@
from pathlib import Path
import pytest import pytest
import mangadlp.app as app import mangadlp.app as app
@ -8,7 +6,7 @@ from mangadlp.api.mangadex import Mangadex
def test_check_api_mangadex(): def test_check_api_mangadex():
url = "https://mangadex.org/title/a96676e5-8ae2-425e-b549-7f15dd34a6d8/komi-san-wa-komyushou-desu" url = "https://mangadex.org/title/a96676e5-8ae2-425e-b549-7f15dd34a6d8/komi-san-wa-komyushou-desu"
test = app.MangaDLP(url_uuid=url, list_chapters=True) test = app.MangaDLP(url_uuid=url, list_chapters=True, download_wait=2)
assert test.api_used == Mangadex assert test.api_used == Mangadex
@ -16,5 +14,5 @@ def test_check_api_mangadex():
def test_check_api_none(): def test_check_api_none():
url = "https://abc.defghjk/title/abc/def" url = "https://abc.defghjk/title/abc/def"
with pytest.raises(ValueError) as e: with pytest.raises(ValueError) as e:
app.MangaDLP(url_uuid=url, list_chapters=True) app.MangaDLP(url_uuid=url, list_chapters=True, download_wait=2)
assert e.type == ValueError assert e.type == ValueError

View file

@ -56,8 +56,8 @@ def test_chapter_list_full():
file_format="cbz", file_format="cbz",
forcevol=True, forcevol=True,
download_path="tests", download_path="tests",
download_wait=0.5, download_wait=2,
verbose=True, verbosity=3,
) )
chap_list = utils.get_chapter_list("1:1,1:2,1:4-1:7,2:", mdlp.manga_chapter_list) chap_list = utils.get_chapter_list("1:1,1:2,1:4-1:7,2:", mdlp.manga_chapter_list)
assert chap_list == [ assert chap_list == [

View file

@ -18,11 +18,11 @@ def test_downloader():
chapter_path = Path("tests/test_folder1") chapter_path = Path("tests/test_folder1")
chapter_path.mkdir(parents=True, exist_ok=True) chapter_path.mkdir(parents=True, exist_ok=True)
images = [] images = []
downloader.download_chapter(urls, str(chapter_path), 0.5, True) downloader.download_chapter(urls, str(chapter_path), 2, True)
for file in chapter_path.iterdir(): for file in chapter_path.iterdir():
images.append(file.name) images.append(file.name)
print(images) images.sort()
assert images == ["001.png", "002.png", "003.png", "004.png", "005.png"] assert images == ["001.png", "002.png", "003.png", "004.png", "005.png"]
# cleanup # cleanup
shutil.rmtree(chapter_path, ignore_errors=True) shutil.rmtree(chapter_path, ignore_errors=True)
@ -43,7 +43,7 @@ def test_downloader_fail(monkeypatch):
chapter_path.mkdir(parents=True, exist_ok=True) chapter_path.mkdir(parents=True, exist_ok=True)
monkeypatch.setattr(requests, "get", fail_url) monkeypatch.setattr(requests, "get", fail_url)
with pytest.raises(ConnectionError) as e: with pytest.raises(ConnectionError) as e:
downloader.download_chapter(images, str(chapter_path), 0.5, True) downloader.download_chapter(images, str(chapter_path), 2, True)
assert e.type == ConnectionError assert e.type == ConnectionError
# cleanup # cleanup

View file

@ -13,7 +13,7 @@ def test_read_and_url():
chapters = "1" chapters = "1"
file_format = "cbz" file_format = "cbz"
download_path = "tests" download_path = "tests"
command_args = f"-u {url_uuid} --read {link_file} -l {language} -c {chapters} --path {download_path} --format {file_format} --verbose" command_args = f"-u {url_uuid} --read {link_file} -l {language} -c {chapters} --path {download_path} --format {file_format} --debug"
script_path = "manga-dlp.py" script_path = "manga-dlp.py"
assert os.system(f"python3 {script_path} {command_args}") != 0 assert os.system(f"python3 {script_path} {command_args}") != 0
@ -25,7 +25,7 @@ def test_no_read_and_url():
chapters = "1" chapters = "1"
file_format = "cbz" file_format = "cbz"
download_path = "tests" download_path = "tests"
command_args = f"-l {language} -c {chapters} --path {download_path} --format {file_format} --verbose" command_args = f"-l {language} -c {chapters} --path {download_path} --format {file_format} --debug"
script_path = "manga-dlp.py" script_path = "manga-dlp.py"
assert os.system(f"python3 {script_path} {command_args}") != 0 assert os.system(f"python3 {script_path} {command_args}") != 0
@ -36,7 +36,7 @@ def test_no_chaps():
chapters = "" chapters = ""
file_format = "cbz" file_format = "cbz"
download_path = "tests" download_path = "tests"
command_args = f"-u {url_uuid} -l {language} --path {download_path} --format {file_format} --verbose" command_args = f"-u {url_uuid} -l {language} --path {download_path} --format {file_format} --debug"
script_path = "manga-dlp.py" script_path = "manga-dlp.py"
assert os.system(f"python3 {script_path} {command_args}") != 0 assert os.system(f"python3 {script_path} {command_args}") != 0
@ -47,7 +47,7 @@ def test_no_volume():
chapters = "1" chapters = "1"
file_format = "cbz" file_format = "cbz"
download_path = "tests" download_path = "tests"
command_args = f"-u {url_uuid} -l {language} -c {chapters} --path {download_path} --format {file_format} --verbose --forcevol" command_args = f"-u {url_uuid} -l {language} -c {chapters} --path {download_path} --format {file_format} --debug --forcevol"
script_path = "manga-dlp.py" script_path = "manga-dlp.py"
assert os.system(f"python3 {script_path} {command_args}") != 0 assert os.system(f"python3 {script_path} {command_args}") != 0

View file

@ -8,8 +8,8 @@ def test_uuid_link():
url_uuid = "https://mangadex.org/title/a96676e5-8ae2-425e-b549-7f15dd34a6d8/komi-san-wa-komyushou-desu" url_uuid = "https://mangadex.org/title/a96676e5-8ae2-425e-b549-7f15dd34a6d8/komi-san-wa-komyushou-desu"
language = "en" language = "en"
forcevol = False forcevol = False
verbose = True verbosity = 3
test = Mangadex(url_uuid, language, forcevol, verbose) test = Mangadex(url_uuid, language, forcevol, verbosity)
assert test.manga_uuid == "a96676e5-8ae2-425e-b549-7f15dd34a6d8" assert test.manga_uuid == "a96676e5-8ae2-425e-b549-7f15dd34a6d8"
@ -18,8 +18,8 @@ def test_uuid_pure():
url_uuid = "a96676e5-8ae2-425e-b549-7f15dd34a6d8" url_uuid = "a96676e5-8ae2-425e-b549-7f15dd34a6d8"
language = "en" language = "en"
forcevol = False forcevol = False
verbose = True verbosity = 3
test = Mangadex(url_uuid, language, forcevol, verbose) test = Mangadex(url_uuid, language, forcevol, verbosity)
assert test.manga_uuid == "a96676e5-8ae2-425e-b549-7f15dd34a6d8" assert test.manga_uuid == "a96676e5-8ae2-425e-b549-7f15dd34a6d8"
@ -28,10 +28,10 @@ def test_uuid_link_false():
url_uuid = "https://mangadex.org/title/a966-76e-5-8a-e2-42-5e-b-549-7f15dd-34a6d8/komi-san-wa-komyushou-desu" url_uuid = "https://mangadex.org/title/a966-76e-5-8a-e2-42-5e-b-549-7f15dd-34a6d8/komi-san-wa-komyushou-desu"
language = "en" language = "en"
forcevol = False forcevol = False
verbose = True verbosity = 3
with pytest.raises(SystemExit) as e: with pytest.raises(SystemExit) as e:
Mangadex(url_uuid, language, forcevol, verbose) Mangadex(url_uuid, language, forcevol, verbosity)
assert e.type == SystemExit assert e.type == SystemExit
assert e.value.code == 1 assert e.value.code == 1
@ -40,8 +40,8 @@ def test_title():
url_uuid = "https://mangadex.org/title/a96676e5-8ae2-425e-b549-7f15dd34a6d8/komi-san-wa-komyushou-desu" url_uuid = "https://mangadex.org/title/a96676e5-8ae2-425e-b549-7f15dd34a6d8/komi-san-wa-komyushou-desu"
language = "en" language = "en"
forcevol = False forcevol = False
verbose = True verbosity = 3
test = Mangadex(url_uuid, language, forcevol, verbose) test = Mangadex(url_uuid, language, forcevol, verbosity)
assert test.manga_title == "Komi-san wa Komyushou Desu" assert test.manga_title == "Komi-san wa Komyushou Desu"
@ -50,8 +50,8 @@ def test_chapter_infos():
url_uuid = "https://mangadex.org/title/a96676e5-8ae2-425e-b549-7f15dd34a6d8/komi-san-wa-komyushou-desu" url_uuid = "https://mangadex.org/title/a96676e5-8ae2-425e-b549-7f15dd34a6d8/komi-san-wa-komyushou-desu"
language = "en" language = "en"
forcevol = False forcevol = False
verbose = True verbosity = 3
test = Mangadex(url_uuid, language, forcevol, verbose) test = Mangadex(url_uuid, language, forcevol, verbosity)
chapter_infos = test.get_chapter_infos("1") chapter_infos = test.get_chapter_infos("1")
chapter_uuid = chapter_infos["uuid"] chapter_uuid = chapter_infos["uuid"]
chapter_name = chapter_infos["name"] chapter_name = chapter_infos["name"]
@ -70,10 +70,10 @@ def test_non_existing_manga():
url_uuid = "https://mangadex.org/title/a96676e5-8ae2-425e-b549-999999999999/komi-san-wa-komyushou-desu" url_uuid = "https://mangadex.org/title/a96676e5-8ae2-425e-b549-999999999999/komi-san-wa-komyushou-desu"
language = "en" language = "en"
forcevol = False forcevol = False
verbose = True verbosity = 3
with pytest.raises(SystemExit) as e: with pytest.raises(SystemExit) as e:
Mangadex(url_uuid, language, forcevol, verbose) Mangadex(url_uuid, language, forcevol, verbosity)
assert e.type == SystemExit assert e.type == SystemExit
assert e.value.code == 1 assert e.value.code == 1
@ -86,10 +86,10 @@ def test_api_failure(monkeypatch):
url_uuid = "https://mangadex.org/title/a96676e5-8ae2-425e-b549-7f15dd34a6d8/komi-san-wa-komyushou-desu" url_uuid = "https://mangadex.org/title/a96676e5-8ae2-425e-b549-7f15dd34a6d8/komi-san-wa-komyushou-desu"
language = "en" language = "en"
forcevol = False forcevol = False
verbose = True verbosity = 3
with pytest.raises(SystemExit) as e: with pytest.raises(SystemExit) as e:
Mangadex(url_uuid, language, forcevol, verbose) Mangadex(url_uuid, language, forcevol, verbosity)
assert e.type == SystemExit assert e.type == SystemExit
assert e.value.code == 1 assert e.value.code == 1
@ -98,8 +98,8 @@ def test_chapter_lang_en():
url_uuid = "https://mangadex.org/title/a96676e5-8ae2-425e-b549-7f15dd34a6d8/komi-san-wa-komyushou-desu" url_uuid = "https://mangadex.org/title/a96676e5-8ae2-425e-b549-7f15dd34a6d8/komi-san-wa-komyushou-desu"
language = "en" language = "en"
forcevol = False forcevol = False
verbose = True verbosity = True
test = Mangadex(url_uuid, language, forcevol, verbose) test = Mangadex(url_uuid, language, forcevol, 3)
assert test.check_chapter_lang() > 0 assert test.check_chapter_lang() > 0
@ -108,11 +108,11 @@ def test_empty_chapter_lang():
url_uuid = "https://mangadex.org/title/a96676e5-8ae2-425e-b549-7f15dd34a6d8/komi-san-wa-komyushou-desu" url_uuid = "https://mangadex.org/title/a96676e5-8ae2-425e-b549-7f15dd34a6d8/komi-san-wa-komyushou-desu"
language = "ch" language = "ch"
forcevol = False forcevol = False
verbose = True verbosity = 3
with pytest.raises(SystemExit) as e: with pytest.raises(SystemExit) as e:
Mangadex(url_uuid, language, forcevol, verbose) Mangadex(url_uuid, language, forcevol, verbosity)
Mangadex(url_uuid, language, forcevol, verbose).check_chapter_lang() Mangadex(url_uuid, language, forcevol, verbosity).check_chapter_lang()
assert e.type == KeyError or e.type == SystemExit assert e.type == KeyError or e.type == SystemExit
assert e.value.code == 1 assert e.value.code == 1
@ -121,10 +121,10 @@ def test_not_existing_lang():
url_uuid = "https://mangadex.org/title/a96676e5-8ae2-425e-b549-7f15dd34a6d8/komi-san-wa-komyushou-desu" url_uuid = "https://mangadex.org/title/a96676e5-8ae2-425e-b549-7f15dd34a6d8/komi-san-wa-komyushou-desu"
language = "zz" language = "zz"
forcevol = False forcevol = False
verbose = True verbosity = 3
with pytest.raises(SystemExit) as e: with pytest.raises(SystemExit) as e:
Mangadex(url_uuid, language, forcevol, verbose) Mangadex(url_uuid, language, forcevol, verbosity)
assert e.type == SystemExit assert e.type == SystemExit
assert e.value.code == 1 assert e.value.code == 1
@ -135,8 +135,8 @@ def test_create_chapter_list():
) )
language = "en" language = "en"
forcevol = False forcevol = False
verbose = True verbosity = 3
test = Mangadex(url_uuid, language, forcevol, verbose) test = Mangadex(url_uuid, language, forcevol, verbosity)
test_list = [ test_list = [
"1", "1",
"2", "2",
@ -170,8 +170,8 @@ def test_create_chapter_list_forcevol():
) )
language = "en" language = "en"
forcevol = True forcevol = True
verbose = True verbosity = 3
test = Mangadex(url_uuid, language, forcevol, verbose) test = Mangadex(url_uuid, language, forcevol, verbosity)
test_list = [ test_list = [
"1:1", "1:1",
"1:2", "1:2",
@ -203,8 +203,8 @@ def test_get_chapter_images():
url_uuid = "https://mangadex.org/title/a96676e5-8ae2-425e-b549-7f15dd34a6d8/komi-san-wa-komyushou-desu" url_uuid = "https://mangadex.org/title/a96676e5-8ae2-425e-b549-7f15dd34a6d8/komi-san-wa-komyushou-desu"
language = "en" language = "en"
forcevol = False forcevol = False
verbose = True verbosity = 3
test = Mangadex(url_uuid, language, forcevol, verbose) test = Mangadex(url_uuid, language, forcevol, verbosity)
img_base_url = "https://uploads.mangadex.org" img_base_url = "https://uploads.mangadex.org"
chapter_hash = "0752bc5db298beff6b932b9151dd8437" chapter_hash = "0752bc5db298beff6b932b9151dd8437"
chapter_uuid = "e86ec2c4-c5e4-4710-bfaa-7604f00939c7" chapter_uuid = "e86ec2c4-c5e4-4710-bfaa-7604f00939c7"
@ -225,7 +225,7 @@ def test_get_chapter_images():
f"{img_base_url}/data/{chapter_hash}/x13-54d9718036b9d79e930e448b592c4a3df9045ed5b8c22ab411b09dadb864756f.jpg", f"{img_base_url}/data/{chapter_hash}/x13-54d9718036b9d79e930e448b592c4a3df9045ed5b8c22ab411b09dadb864756f.jpg",
f"{img_base_url}/data/{chapter_hash}/x14-f6ed71bbb9af2bceab51028b460813c57935c923e1872fb277beb21d54425434.jpg", f"{img_base_url}/data/{chapter_hash}/x14-f6ed71bbb9af2bceab51028b460813c57935c923e1872fb277beb21d54425434.jpg",
] ]
assert test.get_chapter_images(chapter_num, 0.5) == test_list assert test.get_chapter_images(chapter_num, 2) == test_list
def test_get_chapter_images_error(monkeypatch): def test_get_chapter_images_error(monkeypatch):
@ -235,9 +235,9 @@ def test_get_chapter_images_error(monkeypatch):
url_uuid = "https://mangadex.org/title/a96676e5-8ae2-425e-b549-7f15dd34a6d8/komi-san-wa-komyushou-desu" url_uuid = "https://mangadex.org/title/a96676e5-8ae2-425e-b549-7f15dd34a6d8/komi-san-wa-komyushou-desu"
language = "en" language = "en"
forcevol = False forcevol = False
verbose = True verbosity = 3
test = Mangadex(url_uuid, language, forcevol, verbose) test = Mangadex(url_uuid, language, forcevol, verbosity)
chapter_num = "1" chapter_num = "1"
monkeypatch.setattr(requests, "get", fail_url) monkeypatch.setattr(requests, "get", fail_url)
assert not test.get_chapter_images(chapter_num, 0.5) assert not test.get_chapter_images(chapter_num, 2)

View file

@ -1,11 +1,27 @@
import os import os
import platform
import shutil import shutil
import time
from pathlib import Path from pathlib import Path
import pytest
import mangadlp.app as app import mangadlp.app as app
def test_full_api_mangadex(): @pytest.fixture
def wait_10s():
print("sleeping 10 seconds because of api timeouts")
time.sleep(10)
@pytest.fixture
def wait_20s():
print("sleeping 20 seconds because of api timeouts")
time.sleep(20)
def test_full_api_mangadex(wait_20s):
manga_path = Path("tests/Shikimori's Not Just a Cutie") manga_path = Path("tests/Shikimori's Not Just a Cutie")
chapter_path = Path("tests/Shikimori's Not Just a Cutie/Ch. 1.cbz") chapter_path = Path("tests/Shikimori's Not Just a Cutie/Ch. 1.cbz")
mdlp = app.MangaDLP( mdlp = app.MangaDLP(
@ -16,8 +32,8 @@ def test_full_api_mangadex():
file_format="cbz", file_format="cbz",
forcevol=False, forcevol=False,
download_path="tests", download_path="tests",
download_wait=0.5, download_wait=2,
verbose=True, verbosity=3,
) )
mdlp.get_manga() mdlp.get_manga()
@ -27,7 +43,7 @@ def test_full_api_mangadex():
shutil.rmtree(manga_path, ignore_errors=True) shutil.rmtree(manga_path, ignore_errors=True)
def test_full_with_input_cbz(): def test_full_with_input_cbz(wait_20s):
url_uuid = "https://mangadex.org/title/0aea9f43-d4a9-4bf7-bebc-550a512f9b95/shikimori-s-not-just-a-cutie" url_uuid = "https://mangadex.org/title/0aea9f43-d4a9-4bf7-bebc-550a512f9b95/shikimori-s-not-just-a-cutie"
language = "en" language = "en"
chapters = "1" chapters = "1"
@ -35,7 +51,7 @@ def test_full_with_input_cbz():
download_path = "tests" download_path = "tests"
manga_path = Path("tests/Shikimori's Not Just a Cutie") manga_path = Path("tests/Shikimori's Not Just a Cutie")
chapter_path = Path("tests/Shikimori's Not Just a Cutie/Ch. 1.cbz") chapter_path = Path("tests/Shikimori's Not Just a Cutie/Ch. 1.cbz")
command_args = f"-u {url_uuid} -l {language} -c {chapters} --path {download_path} --format {file_format} --verbose" command_args = f"-u {url_uuid} -l {language} -c {chapters} --path {download_path} --format {file_format} --debug --wait 2"
script_path = "manga-dlp.py" script_path = "manga-dlp.py"
os.system(f"python3 {script_path} {command_args}") os.system(f"python3 {script_path} {command_args}")
@ -45,7 +61,11 @@ def test_full_with_input_cbz():
shutil.rmtree(manga_path, ignore_errors=True) shutil.rmtree(manga_path, ignore_errors=True)
def test_full_with_input_pdf(): def test_full_with_input_pdf(wait_20s):
# check if its arm64, if yes skip this step
if platform.machine() != "x86_64":
return True
url_uuid = "https://mangadex.org/title/0aea9f43-d4a9-4bf7-bebc-550a512f9b95/shikimori-s-not-just-a-cutie" url_uuid = "https://mangadex.org/title/0aea9f43-d4a9-4bf7-bebc-550a512f9b95/shikimori-s-not-just-a-cutie"
language = "en" language = "en"
chapters = "1" chapters = "1"
@ -53,7 +73,7 @@ def test_full_with_input_pdf():
download_path = "tests" download_path = "tests"
manga_path = Path("tests/Shikimori's Not Just a Cutie") manga_path = Path("tests/Shikimori's Not Just a Cutie")
chapter_path = Path("tests/Shikimori's Not Just a Cutie/Ch. 1.pdf") chapter_path = Path("tests/Shikimori's Not Just a Cutie/Ch. 1.pdf")
command_args = f"-u {url_uuid} -l {language} -c {chapters} --path {download_path} --format {file_format} --verbose" command_args = f"-u {url_uuid} -l {language} -c {chapters} --path {download_path} --format {file_format} --debug --wait 2"
script_path = "manga-dlp.py" script_path = "manga-dlp.py"
os.system(f"python3 {script_path} {command_args}") os.system(f"python3 {script_path} {command_args}")
@ -63,7 +83,7 @@ def test_full_with_input_pdf():
shutil.rmtree(manga_path, ignore_errors=True) shutil.rmtree(manga_path, ignore_errors=True)
def test_full_with_input_folder(): def test_full_with_input_folder(wait_20s):
url_uuid = "https://mangadex.org/title/0aea9f43-d4a9-4bf7-bebc-550a512f9b95/shikimori-s-not-just-a-cutie" url_uuid = "https://mangadex.org/title/0aea9f43-d4a9-4bf7-bebc-550a512f9b95/shikimori-s-not-just-a-cutie"
language = "en" language = "en"
chapters = "1" chapters = "1"
@ -71,7 +91,7 @@ def test_full_with_input_folder():
download_path = "tests" download_path = "tests"
manga_path = Path("tests/Shikimori's Not Just a Cutie") manga_path = Path("tests/Shikimori's Not Just a Cutie")
chapter_path = Path("tests/Shikimori's Not Just a Cutie/Ch. 1") chapter_path = Path("tests/Shikimori's Not Just a Cutie/Ch. 1")
command_args = f"-u {url_uuid} -l {language} -c {chapters} --path {download_path} --format '{file_format}' --verbose" command_args = f"-u {url_uuid} -l {language} -c {chapters} --path {download_path} --format '{file_format}' --debug --wait 2"
script_path = "manga-dlp.py" script_path = "manga-dlp.py"
os.system(f"python3 {script_path} {command_args}") os.system(f"python3 {script_path} {command_args}")
@ -81,7 +101,7 @@ def test_full_with_input_folder():
shutil.rmtree(manga_path, ignore_errors=True) shutil.rmtree(manga_path, ignore_errors=True)
def test_full_with_input_skip_cbz(): def test_full_with_input_skip_cbz(wait_10s):
url_uuid = "https://mangadex.org/title/0aea9f43-d4a9-4bf7-bebc-550a512f9b95/shikimori-s-not-just-a-cutie" url_uuid = "https://mangadex.org/title/0aea9f43-d4a9-4bf7-bebc-550a512f9b95/shikimori-s-not-just-a-cutie"
language = "en" language = "en"
chapters = "1" chapters = "1"
@ -89,7 +109,7 @@ def test_full_with_input_skip_cbz():
download_path = "tests" download_path = "tests"
manga_path = Path("tests/Shikimori's Not Just a Cutie") manga_path = Path("tests/Shikimori's Not Just a Cutie")
chapter_path = Path("tests/Shikimori's Not Just a Cutie/Ch. 1.cbz") chapter_path = Path("tests/Shikimori's Not Just a Cutie/Ch. 1.cbz")
command_args = f"-u {url_uuid} -l {language} -c {chapters} --path {download_path} --format {file_format} --verbose" command_args = f"-u {url_uuid} -l {language} -c {chapters} --path {download_path} --format {file_format} --debug --wait 2"
script_path = "manga-dlp.py" script_path = "manga-dlp.py"
manga_path.mkdir(parents=True, exist_ok=True) manga_path.mkdir(parents=True, exist_ok=True)
chapter_path.touch() chapter_path.touch()
@ -101,7 +121,7 @@ def test_full_with_input_skip_cbz():
shutil.rmtree(manga_path, ignore_errors=True) shutil.rmtree(manga_path, ignore_errors=True)
def test_full_with_input_skip_folder(): def test_full_with_input_skip_folder(wait_10s):
url_uuid = "https://mangadex.org/title/0aea9f43-d4a9-4bf7-bebc-550a512f9b95/shikimori-s-not-just-a-cutie" url_uuid = "https://mangadex.org/title/0aea9f43-d4a9-4bf7-bebc-550a512f9b95/shikimori-s-not-just-a-cutie"
language = "en" language = "en"
chapters = "1" chapters = "1"
@ -109,7 +129,7 @@ def test_full_with_input_skip_folder():
download_path = "tests" download_path = "tests"
manga_path = Path("tests/Shikimori's Not Just a Cutie") manga_path = Path("tests/Shikimori's Not Just a Cutie")
chapter_path = Path("tests/Shikimori's Not Just a Cutie/Ch. 1") chapter_path = Path("tests/Shikimori's Not Just a Cutie/Ch. 1")
command_args = f"-u {url_uuid} -l {language} -c {chapters} --path {download_path} --format '{file_format}' --verbose" command_args = f"-u {url_uuid} -l {language} -c {chapters} --path {download_path} --format '{file_format}' --debug --wait 2"
script_path = "manga-dlp.py" script_path = "manga-dlp.py"
chapter_path.mkdir(parents=True, exist_ok=True) chapter_path.mkdir(parents=True, exist_ok=True)
@ -126,7 +146,7 @@ def test_full_with_input_skip_folder():
shutil.rmtree(manga_path, ignore_errors=True) shutil.rmtree(manga_path, ignore_errors=True)
def test_full_with_read_cbz(): def test_full_with_read_cbz(wait_20s):
url_list = Path("tests/test_list2.txt") url_list = Path("tests/test_list2.txt")
language = "en" language = "en"
chapters = "1" chapters = "1"
@ -134,7 +154,7 @@ def test_full_with_read_cbz():
download_path = "tests" download_path = "tests"
manga_path = Path("tests/Shikimori's Not Just a Cutie") manga_path = Path("tests/Shikimori's Not Just a Cutie")
chapter_path = Path("tests/Shikimori's Not Just a Cutie/Ch. 1.cbz") chapter_path = Path("tests/Shikimori's Not Just a Cutie/Ch. 1.cbz")
command_args = f"--read {str(url_list)} -l {language} -c {chapters} --path {download_path} --format {file_format} --verbose" command_args = f"--read {str(url_list)} -l {language} -c {chapters} --path {download_path} --format {file_format} --debug --wait 2"
script_path = "manga-dlp.py" script_path = "manga-dlp.py"
url_list.write_text( url_list.write_text(
"https://mangadex.org/title/0aea9f43-d4a9-4bf7-bebc-550a512f9b95/shikimori-s-not-just-a-cutie" "https://mangadex.org/title/0aea9f43-d4a9-4bf7-bebc-550a512f9b95/shikimori-s-not-just-a-cutie"
@ -148,7 +168,7 @@ def test_full_with_read_cbz():
shutil.rmtree(manga_path, ignore_errors=True) shutil.rmtree(manga_path, ignore_errors=True)
def test_full_with_read_skip_cbz(): def test_full_with_read_skip_cbz(wait_10s):
url_list = Path("tests/test_list2.txt") url_list = Path("tests/test_list2.txt")
language = "en" language = "en"
chapters = "1" chapters = "1"
@ -156,7 +176,7 @@ def test_full_with_read_skip_cbz():
download_path = "tests" download_path = "tests"
manga_path = Path("tests/Shikimori's Not Just a Cutie") manga_path = Path("tests/Shikimori's Not Just a Cutie")
chapter_path = Path("tests/Shikimori's Not Just a Cutie/Ch. 1.cbz") chapter_path = Path("tests/Shikimori's Not Just a Cutie/Ch. 1.cbz")
command_args = f"--read {str(url_list)} -l {language} -c {chapters} --path {download_path} --format {file_format} --verbose" command_args = f"--read {str(url_list)} -l {language} -c {chapters} --path {download_path} --format {file_format} --debug --wait 2"
script_path = "manga-dlp.py" script_path = "manga-dlp.py"
manga_path.mkdir(parents=True, exist_ok=True) manga_path.mkdir(parents=True, exist_ok=True)
chapter_path.touch() chapter_path.touch()

21
tox.ini
View file

@ -4,10 +4,23 @@ isolated_build = True
[testenv] [testenv]
deps = deps =
pytest -rcontrib/requirements_dev.txt
coverage
-rrequirements.txt
commands = commands =
pytest -x --basetemp="{envtmpdir}" {posargs} pytest --exitfirst --basetemp="{envtmpdir}" {posargs}
[testenv:basic]
deps =
-rcontrib/requirements_dev.txt
commands =
pytest --exitfirst --basetemp="{envtmpdir}" {posargs}
[testenv:coverage]
deps =
-rcontrib/requirements_dev.txt
commands =
coverage erase
coverage run
coverage xml -i