Compare commits

...

44 commits

Author SHA1 Message Date
cb70268966 Merge pull request 'Update sonarsource/sonarqube-scan-action action to v2.1.0' (#80) from renovate/sonarsource-sonarqube-scan-action-2.x into master
All checks were successful
check code / check-docs (push) Successful in 8s
check code / check-code-py38 (push) Successful in 20s
check code / check-code-py39 (push) Successful in 28s
check code / check-code-py310 (push) Successful in 26s
check code / check-code-py311 (push) Successful in 19s
check code / scan-code-py311 (push) Successful in 7m22s
run scheduled tests / check-code-py311 (push) Successful in 6m50s
Reviewed-on: #80
2024-06-01 09:39:09 +02:00
98b14838e8 Update sonarsource/sonarqube-scan-action action to v2.1.0
All checks were successful
build package and container / build-pypackage (pull_request) Successful in 15s
check code / check-docs (pull_request) Successful in 6s
create release / release-pypackage (pull_request) Successful in 19s
build package and container / build-container (pull_request) Successful in 4m11s
check code / check-code-py38 (pull_request) Successful in 6m56s
check code / scan-code-py311 (pull_request) Has been skipped
check code / check-code-py39 (pull_request) Successful in 6m52s
check code / check-code-py310 (pull_request) Successful in 6m58s
check code / check-code-py311 (pull_request) Successful in 7m7s
2024-05-23 20:17:07 +02:00
4911f02303 Merge pull request 'Update dependency shellcheck to v0.10.0' (#76) from renovate/shellcheck-0.x into master
All checks were successful
check code / check-docs (push) Successful in 6s
check code / check-code-py38 (push) Successful in 1m28s
check code / check-code-py39 (push) Successful in 2m55s
check code / check-code-py310 (push) Successful in 3m40s
check code / scan-code-py311 (push) Successful in 9m41s
check code / check-code-py311 (push) Successful in 21s
run scheduled tests / check-code-py311 (push) Successful in 6m53s
Reviewed-on: #76
2024-04-16 12:40:49 +02:00
5a04db3cd4 Merge pull request 'Update dependency just to v1.25.2' (#75) from renovate/just-1.x into master
Some checks failed
check code / check-code-py310 (push) Blocked by required conditions
check code / check-code-py311 (push) Blocked by required conditions
check code / check-docs (push) Successful in 6s
check code / check-code-py38 (push) Successful in 56s
check code / scan-code-py311 (push) Has been cancelled
check code / check-code-py39 (push) Has been cancelled
Reviewed-on: #75
2024-04-16 12:38:39 +02:00
fe8b36c705 Merge pull request 'Update sonarsource/sonarqube-scan-action action to v2.0.2' (#78) from renovate/sonarsource-sonarqube-scan-action-2.x into master
All checks were successful
check code / check-docs (push) Successful in 6s
check code / check-code-py38 (push) Successful in 33s
check code / check-code-py39 (push) Successful in 25s
check code / check-code-py310 (push) Successful in 25s
check code / check-code-py311 (push) Successful in 25s
check code / scan-code-py311 (push) Successful in 7m30s
run scheduled tests / check-code-py311 (push) Successful in 7m16s
Reviewed-on: #78
2024-04-08 12:19:20 +02:00
1ceaff2d67 Update sonarsource/sonarqube-scan-action action to v2.0.2
All checks were successful
check code / check-docs (pull_request) Successful in 7s
build package and container / build-pypackage (pull_request) Successful in 18s
create release / release-pypackage (pull_request) Successful in 30s
build package and container / build-container (pull_request) Successful in 3m2s
check code / check-code-py38 (pull_request) Successful in 6m59s
check code / scan-code-py311 (pull_request) Has been skipped
check code / check-code-py39 (pull_request) Successful in 7m14s
check code / check-code-py310 (pull_request) Successful in 7m14s
check code / check-code-py311 (pull_request) Successful in 7m15s
2024-04-04 20:14:07 +02:00
f8422f7670 Update dependency just to v1.25.2
All checks were successful
build package and container / build-pypackage (pull_request) Successful in 13s
check code / check-docs (pull_request) Successful in 12s
create release / release-pypackage (pull_request) Successful in 35s
build package and container / build-container (pull_request) Successful in 3m31s
check code / check-code-py38 (pull_request) Successful in 6m56s
check code / scan-code-py311 (pull_request) Has been skipped
check code / check-code-py39 (pull_request) Successful in 6m48s
check code / check-code-py310 (pull_request) Successful in 6m53s
check code / check-code-py311 (pull_request) Successful in 7m5s
2024-03-11 08:15:46 +01:00
f7fa583735 Update dependency shellcheck to v0.10.0
All checks were successful
build package and container / build-pypackage (pull_request) Successful in 14s
build package and container / build-container (pull_request) Successful in 3m4s
check code / check-docs (pull_request) Successful in 7s
create release / release-pypackage (pull_request) Successful in 29s
check code / check-code-py38 (pull_request) Successful in 6m58s
check code / scan-code-py311 (pull_request) Has been skipped
check code / check-code-py39 (pull_request) Successful in 6m47s
check code / check-code-py310 (pull_request) Successful in 7m3s
check code / check-code-py311 (pull_request) Successful in 6m49s
2024-03-08 08:18:50 +01:00
5afd538dcd fix pyproject coverage
All checks were successful
check code / check-docs (push) Successful in 6s
check code / check-code-py38 (push) Successful in 26s
check code / check-code-py39 (push) Successful in 22s
check code / check-code-py310 (push) Successful in 30s
check code / check-code-py311 (push) Successful in 22s
check code / scan-code-py311 (push) Successful in 7m11s
2024-02-21 13:38:37 +01:00
ee8a34b760 update release action
Some checks failed
check code / check-docs (push) Successful in 6s
check code / check-code-py38 (push) Successful in 26s
check code / check-code-py39 (push) Successful in 27s
check code / check-code-py310 (push) Successful in 22s
check code / check-code-py311 (push) Successful in 24s
check code / scan-code-py311 (push) Has been cancelled
2024-02-21 13:35:42 +01:00
0dc7e2f60d update ruff settings and fix lint violations 2024-02-21 13:35:42 +01:00
a1bd82778f Merge pull request 'Update dependency shfmt to v3.8.0' (#72) from renovate/shfmt-3.x into master
All checks were successful
check code / check-docs (push) Successful in 7s
check code / check-code-py38 (push) Successful in 22s
check code / check-code-py39 (push) Successful in 26s
check code / check-code-py310 (push) Successful in 30s
check code / check-code-py311 (push) Successful in 24s
check code / scan-code-py311 (push) Successful in 7m2s
Reviewed-on: #72
2024-02-13 08:18:17 +01:00
ae4b796469 Update dependency shfmt to v3.8.0
All checks were successful
build package and container / build-pypackage (pull_request) Successful in 13s
check code / check-docs (pull_request) Successful in 5s
create release / release-pypackage (pull_request) Successful in 22s
build package and container / build-container (pull_request) Successful in 4m0s
check code / check-code-py38 (pull_request) Successful in 6m49s
check code / scan-code-py311 (pull_request) Has been skipped
check code / check-code-py39 (pull_request) Successful in 7m6s
check code / check-code-py310 (pull_request) Successful in 6m51s
check code / check-code-py311 (pull_request) Successful in 6m53s
2024-02-12 20:14:36 +01:00
3950cd1927 Merge pull request 'Update dependency just to v1.24.0' (#73) from renovate/just-1.x into master
All checks were successful
check code / check-docs (push) Successful in 6s
check code / check-code-py38 (push) Successful in 20s
check code / check-code-py39 (push) Successful in 19s
check code / check-code-py310 (push) Successful in 19s
check code / check-code-py311 (push) Successful in 24s
check code / scan-code-py311 (push) Successful in 7m12s
Reviewed-on: #73
2024-02-12 14:43:02 +01:00
4a2e90ddda Update dependency just to v1.24.0
All checks were successful
build package and container / build-pypackage (pull_request) Successful in 13s
check code / check-docs (pull_request) Successful in 5s
create release / release-pypackage (pull_request) Successful in 30s
build package and container / build-container (pull_request) Successful in 2m51s
check code / check-code-py38 (pull_request) Successful in 6m48s
check code / scan-code-py311 (pull_request) Has been skipped
check code / check-code-py39 (pull_request) Successful in 7m1s
check code / check-code-py310 (pull_request) Successful in 6m47s
check code / check-code-py311 (pull_request) Successful in 7m10s
2024-02-12 08:16:05 +01:00
e1276b5be9 Fix pytz requirement
All checks were successful
check code / check-docs (push) Successful in 6s
check code / check-code-py38 (push) Successful in 26s
check code / check-code-py39 (push) Successful in 26s
check code / check-code-py310 (push) Successful in 25s
check code / check-code-py311 (push) Successful in 25s
check code / scan-code-py311 (push) Successful in 6m59s
2024-02-02 10:14:46 +01:00
8d652d6732
run ci tests only on PR
All checks were successful
check code / check-docs (push) Successful in 7s
check code / check-code-py38 (push) Successful in 23s
check code / check-code-py39 (push) Successful in 23s
check code / check-code-py310 (push) Successful in 22s
check code / check-code-py311 (push) Successful in 24s
check code / scan-code-py311 (push) Successful in 7m10s
2024-02-01 20:44:48 +01:00
0d0e45f800
run all tests only on PR
Some checks failed
check code / scan-code-py311 (push) Blocked by required conditions
check code / check-code-py39 (push) Blocked by required conditions
check code / check-code-py310 (push) Blocked by required conditions
check code / check-code-py311 (push) Blocked by required conditions
check code / check-docs (push) Successful in 7s
check code / check-code-py38 (push) Has been cancelled
2024-02-01 20:42:32 +01:00
01a56734f2 some ci fixes [skip ci]
All checks were successful
check code / check-docs (push) Successful in 7s
check code / check-code-py38 (push) Successful in 7m6s
check code / check-code-py39 (push) Successful in 7m7s
check code / check-code-py310 (push) Successful in 7m8s
check code / check-code-py311 (push) Successful in 6m52s
check code / scan-code-py311 (push) Successful in 7m2s
2024-02-01 16:02:22 +01:00
ed2dfd414c update badges in readme [skip ci] 2024-02-01 15:59:25 +01:00
85e57aec2e Bump version 2.4.0 → 2.4.1
Some checks failed
check code / check-docs (push) Successful in 7s
check code / scan-code-py311 (push) Successful in 6m55s
check code / check-code-py39 (push) Successful in 6m49s
check code / check-code-py38 (push) Successful in 6m59s
build package and container / build-pypackage (push) Successful in 19s
check code / check-code-py310 (push) Successful in 7m0s
create release / release-pypackage (push) Failing after 36s
build package and container / build-container (push) Successful in 4m38s
check code / check-code-py311 (push) Successful in 6m51s
2024-02-01 15:54:39 +01:00
b66cf11f95 update changelog 2024-02-01 15:54:33 +01:00
4eeaa4f603 add scheduled tests
Some checks failed
check code / check-code-py310 (push) Waiting to run
check code / check-code-py311 (push) Waiting to run
check code / check-docs (push) Successful in 6s
check code / scan-code-py311 (push) Has been cancelled
check code / check-code-py38 (push) Has been cancelled
check code / check-code-py39 (push) Has been cancelled
2024-02-01 15:52:39 +01:00
0e8f3768c2 update changelog 2024-02-01 15:52:39 +01:00
1f73c306bd fix release notes action 2024-02-01 15:52:39 +01:00
b20d442057 Merge pull request 'Release v2.4.0' (#55) from dev into master
Some checks failed
check code / check-code-py310 (push) Waiting to run
check code / check-code-py311 (push) Waiting to run
check code / check-docs (push) Successful in 7s
check code / scan-code-py311 (push) Has been cancelled
check code / check-code-py39 (push) Has been cancelled
check code / check-code-py38 (push) Has been cancelled
Reviewed-on: #55
2024-02-01 15:52:26 +01:00
9b83373450 fix coverage in sonarqube
All checks were successful
check code / scan-code-py311 (pull_request) Has been skipped
build package and container / build-pypackage (pull_request) Successful in 15s
check code / check-docs (pull_request) Successful in 7s
build package and container / build-container (pull_request) Successful in 4m54s
check code / check-code-py38 (pull_request) Successful in 6m51s
check code / check-code-py310 (pull_request) Successful in 6m46s
check code / check-code-py39 (pull_request) Successful in 6m58s
create release / release-pypackage (pull_request) Successful in 25s
check code / check-code-py311 (pull_request) Successful in 7m6s
2024-02-01 15:43:04 +01:00
7160e1b2a5 fix container build 2024-02-01 15:36:53 +01:00
9be6a07052 fix docker baseimage and CI errors
Some checks failed
build package and container / build-container (pull_request) Failing after 16s
check code / check-docs (pull_request) Successful in 6s
build package and container / build-pypackage (pull_request) Successful in 28s
check code / scan-code-py311 (pull_request) Successful in 17s
check code / check-code-py39 (pull_request) Successful in 6m40s
check code / check-code-py38 (pull_request) Successful in 7m2s
check code / check-code-py311 (pull_request) Successful in 6m40s
check code / check-code-py310 (pull_request) Successful in 6m56s
create release / release-pypackage (pull_request) Successful in 26s
2024-02-01 14:48:05 +01:00
9db6bb6f87 fix some CI errors
Some checks failed
build package and container / build-container (pull_request) Failing after 18s
check code / check-docs (pull_request) Successful in 6s
build package and container / build-pypackage (pull_request) Successful in 24s
check code / check-code-py311 (pull_request) Successful in 7m32s
check code / check-code-py39 (pull_request) Successful in 7m13s
check code / check-code-py310 (pull_request) Successful in 7m19s
check code / scan-code-py311 (pull_request) Successful in 18s
create release / release-pypackage (pull_request) Successful in 26s
check code / check-code-py38 (pull_request) Successful in 9m3s
2024-02-01 14:37:21 +01:00
89c7c1e386 Bump version 2.3.1 → 2.4.0
Some checks failed
create release / release-pypackage (push) Has been cancelled
build package and container / build-pypackage (push) Has been cancelled
build package and container / build-container (push) Has been cancelled
build package and container / build-container (pull_request) Failing after 18s
check code / check-docs (pull_request) Failing after 5s
check code / scan-code-py311 (pull_request) Failing after 4s
build package and container / build-pypackage (pull_request) Successful in 28s
check code / check-code-py311 (pull_request) Successful in 7m16s
create release / release-pypackage (pull_request) Successful in 28s
check code / check-code-py39 (pull_request) Successful in 7m39s
check code / check-code-py310 (pull_request) Successful in 7m41s
check code / check-code-py38 (pull_request) Successful in 8m24s
2024-02-01 14:23:23 +01:00
6fda875a48 fix tests and workflows 2024-02-01 14:22:25 +01:00
ea1eab403d update to ruff formatter and fix py3.8 compatibility 2024-02-01 13:59:45 +01:00
45dca15d39 Merge pull request 'Update dependency just to v1.23.0' (#53) from renovate/just-1.x into master
Reviewed-on: #53
2024-01-23 14:22:49 +01:00
9a709cc811 Update dependency just to v1.23.0 2024-01-13 08:10:57 +01:00
7166168850 update renovate path 2023-12-05 13:38:41 +01:00
236222b19b Merge pull request 'Update dependency just to v1.16.0' (#51) from renovate/just-1.x into master
Reviewed-on: #51
2023-11-09 09:27:46 +01:00
553a85b436 Update dependency just to v1.16.0 2023-11-09 08:08:31 +01:00
7a7ace9286
fix pytest fixtures
All checks were successful
ci/woodpecker/push/tests Pipeline was successful
Signed-off-by: Ivan Schaller <ivan@schaller.sh>
2023-07-02 16:45:33 +02:00
873e6ab0e2
update pyright and some type annotations. also increase line length to 100 chars
Some checks failed
ci/woodpecker/push/tests Pipeline failed
Signed-off-by: Ivan Schaller <ivan@schaller.sh>
2023-07-02 16:41:00 +02:00
d7c5bd7d17 Merge pull request 'Update dependency just to v1.14.0' (#44) from renovate/just-1.x into master
Some checks failed
ci/woodpecker/push/tests Pipeline failed
Reviewed-on: #44
2023-06-29 21:21:01 +02:00
d8947df817 Merge pull request 'Update dependency shfmt to v3.7.0' (#46) from renovate/shfmt-3.x into master
Some checks failed
ci/woodpecker/push/tests Pipeline failed
Reviewed-on: #46
2023-06-29 21:20:07 +02:00
2cbd204204 Update dependency shfmt to v3.7.0
Some checks failed
ci/woodpecker/push/tests Pipeline failed
ci/woodpecker/pr/tests Pipeline failed
ci/woodpecker/pr/test_tox_arm64 unknown status
ci/woodpecker/pr/test_docker_amd64 unknown status
ci/woodpecker/pr/test_docker_arm64 unknown status
ci/woodpecker/pr/test_release unknown status
ci/woodpecker/pr/test_tox_amd64 unknown status
2023-06-18 18:06:08 +00:00
ee72e8b6d9 Update dependency just to v1.14.0
Some checks failed
ci/woodpecker/push/tests Pipeline failed
ci/woodpecker/pr/tests Pipeline failed
ci/woodpecker/pr/test_tox_arm64 unknown status
ci/woodpecker/pr/test_docker_amd64 unknown status
ci/woodpecker/pr/test_release unknown status
ci/woodpecker/pr/test_docker_arm64 unknown status
ci/woodpecker/pr/test_tox_amd64 unknown status
2023-06-03 06:05:51 +00:00
58 changed files with 1125 additions and 1272 deletions

1
.envrc
View file

@ -1 +0,0 @@
use asdf

View file

@ -0,0 +1,99 @@
name: build package and container
on:
push:
tags:
- "v*.*.*"
pull_request:
branches: [main, master]
jobs:
build-pypackage:
runs-on: python311
env:
HATCH_INDEX_REPO: main
HATCH_INDEX_USER: __token__
HATCH_INDEX_AUTH: ${{ secrets.PYPI_TOKEN }}
steps:
- name: checkout code
uses: actions/checkout@v3
- name: install hatch
run: pip install -U hatch hatchling
- name: build package
run: hatch build --clean
- name: publish package
if: gitea.event_name != 'pull_request'
run: hatch publish --yes --no-prompt
build-container:
runs-on: ubuntu-latest
env:
REGISTRY: docker.io
AUTHOR: olofvndrhr
IMAGE: manga-dlp
steps:
- name: checkout code
uses: actions/checkout@v3
- name: setup qemu
uses: docker/setup-qemu-action@v2
- name: setup docker buildx
uses: docker/setup-buildx-action@v2
- name: get container metadata
uses: docker/metadata-action@v4
id: metadata
with:
images: ${{ env.REGISTRY }}/${{ env.AUTHOR }}/${{ env.IMAGE }}
flavor: |
latest=auto
prefix=
suffix=
tags: |
type=schedule
type=ref,event=branch
type=ref,event=pr
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=semver,pattern={{major}}
type=sha
- name: login to docker.io container registry
uses: docker/login-action@v2
with:
registry: ${{ env.REGISTRY }}
username: ${{ secrets.CR_USERNAME }}
password: ${{ secrets.CR_PASSWORD }}
- name: login to private container registry
uses: docker/login-action@v2
with:
registry: git.44net.ch
username: ${{ secrets.CR_PRIV_USERNAME }}
password: ${{ secrets.CR_PRIV_PASSWORD }}
- name: build and push docker image @amd64+arm64
uses: docker/build-push-action@v4
with:
push: ${{ gitea.event_name != 'pull_request' }}
platforms: linux/amd64,linux/arm64
context: .
file: docker/Dockerfile
provenance: false
tags: ${{ steps.metadata.outputs.tags }}
labels: ${{ steps.metadata.outputs.labels }}
- name: update dockerhub repo description
uses: peter-evans/dockerhub-description@v3
if: gitea.event_name != 'pull_request'
with:
repository: ${{ env.AUTHOR }}/${{ env.IMAGE }}
short-description: ${{ github.event.repository.description }}
enable-url-completion: true
username: ${{ secrets.CR_USERNAME }}
password: ${{ secrets.CR_PASSWORD }}

View file

@ -0,0 +1,122 @@
name: check code
on:
push:
branches: [main, master]
pull_request:
branches: [main, master]
jobs:
check-docs:
runs-on: python311
steps:
- name: checkout code
uses: actions/checkout@v3
- name: "build docs"
run: |
python3 -m pip install mkdocs
cd docs || exit 1
mkdocs build --strict
scan-code-py311:
runs-on: python311
if: gitea.event_name != 'pull_request'
needs: [check-code-py38]
steps:
- name: checkout code
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: install hatch
run: pip install -U hatch
- name: get coverage (hatch)
run: hatch run default:cov
- name: run sonar-scanner
uses: sonarsource/sonarqube-scan-action@v2.1.0
env:
SONAR_HOST_URL: ${{ secrets.SONARQUBE_HOST }}
SONAR_TOKEN: ${{ secrets.SONARQUBE_TOKEN }}
check-code-py38:
runs-on: python38
steps:
- name: checkout code
uses: actions/checkout@v3
- name: install hatch
run: pip install -U hatch
- name: test codestyle
run: hatch run +py=3.8 lint:style
- name: test typing
run: hatch run +py=3.8 lint:typing
- name: run tests
if: gitea.event_name == 'pull_request'
run: hatch run default:test
check-code-py39:
runs-on: python39
needs: [check-code-py38]
steps:
- name: checkout code
uses: actions/checkout@v3
- name: install hatch
run: pip install -U hatch
- name: test codestyle
run: hatch run +py=3.9 lint:style
- name: test typing
run: hatch run +py=3.9 lint:typing
- name: run tests
if: gitea.event_name == 'pull_request'
run: hatch run default:test
check-code-py310:
runs-on: python310
needs: [check-code-py39]
steps:
- name: checkout code
uses: actions/checkout@v3
- name: install hatch
run: pip install -U hatch
- name: test codestyle
run: hatch run +py=3.10 lint:style
- name: test typing
run: hatch run +py=3.10 lint:typing
- name: run tests
if: gitea.event_name == 'pull_request'
run: hatch run default:test
check-code-py311:
runs-on: python311
needs: [check-code-py310]
steps:
- name: checkout code
uses: actions/checkout@v3
- name: install hatch
run: pip install -U hatch
- name: test codestyle
run: hatch run +py=3.11 lint:style
- name: test typing
run: hatch run +py=3.11 lint:typing
- name: run tests
if: gitea.event_name == 'pull_request'
run: hatch run default:test

View file

@ -0,0 +1,56 @@
name: create release
on:
push:
tags:
- "v*.*.*"
pull_request:
branches: [main, master]
jobs:
release-pypackage:
runs-on: python311
env:
HATCH_INDEX_REPO: main
HATCH_INDEX_USER: __token__
HATCH_INDEX_AUTH: ${{ secrets.PYPI_TOKEN }}
steps:
- name: checkout code
uses: actions/checkout@v3
- name: setup go
uses: actions/setup-go@v4
with:
go-version: '>=1.20'
- name: install hatch
run: pip install -U hatch hatchling
- name: build package
run: hatch build --clean
- name: get release notes
id: release-notes
uses: olofvndrhr/releasenote-gen@v1
- name: create gitea release
uses: https://gitea.com/actions/release-action@main
if: gitea.event_name != 'pull_request'
with:
title: ${{ gitea.ref_name }}
body: ${{ steps.release-notes.outputs.releasenotes }}
files: |-
dist/**
- name: create github release
uses: ncipollo/release-action@v1
if: gitea.event_name != 'pull_request'
with:
token: ${{ secrets.GH_TOKEN }}
owner: olofvndrhr
repo: manga-dlp
name: ${{ gitea.ref_name }}
body: ${{ steps.release-notes.outputs.releasenotes }}
artifacts: |-
dist/**

View file

@ -0,0 +1,18 @@
name: run scheduled tests
on:
schedule:
- cron: "0 20 * * 6"
jobs:
check-code-py311:
runs-on: python311
steps:
- name: checkout code
uses: actions/checkout@v3
- name: install hatch
run: pip install -U hatch
- name: run tests
run: hatch run default:test

View file

@ -1,5 +1,4 @@
python 3.9.13 3.10.5 3.8.13
shellcheck 0.9.0
shfmt 3.6.0
direnv 2.32.2
just 1.13.0
shellcheck 0.10.0
shfmt 3.8.0
just 1.25.2
lefthook 1.4.6

View file

@ -1,36 +0,0 @@
#########################################
# build and publish docker images amd64 #
#########################################
# branch: master
# event: tag
platform: linux/amd64
depends_on:
- tests
clone:
git:
image: woodpeckerci/plugin-git:v1.6.0
when:
event: tag
pipeline:
# build and publish docker image for amd64 - x86
build-amd64:
image: plugins/docker
pull: true
when:
event: tag
settings:
repo: olofvndrhr/manga-dlp
platforms: linux/amd64
dockerfile: docker/Dockerfile.amd64
auto_tag: true
auto_tag_suffix: linux-amd64
build_args: BUILD_VERSION=${CI_COMMIT_TAG}
username:
from_secret: cr-dhub-username
password:
from_secret: cr-dhub-key

View file

@ -1,36 +0,0 @@
#########################################
# build and publish docker images arm64 #
#########################################
# branch: master
# event: tag
platform: linux/arm64
depends_on:
- tests
clone:
git:
image: woodpeckerci/plugin-git:v1.6.0
when:
event: tag
pipeline:
# build and publish docker image for arm64
build-arm64:
image: plugins/docker
pull: true
when:
event: tag
settings:
repo: olofvndrhr/manga-dlp
platforms: linux/arm64
dockerfile: docker/Dockerfile.arm64
auto_tag: true
auto_tag_suffix: linux-arm64
build_args: BUILD_VERSION=${CI_COMMIT_TAG}
username:
from_secret: cr-dhub-username
password:
from_secret: cr-dhub-key

View file

@ -1,36 +0,0 @@
###########################
# publish docker manifest #
###########################
# branch: master
# event: tag
platform: linux/amd64
depends_on:
- publish_docker_amd64
- publish_docker_arm64
clone:
git:
image: woodpeckerci/plugin-git:v1.6.0
when:
event: tag
tag: "*[!-dev]"
pipeline:
# publish docker manifest for automatic multi arch pulls
publish-manifest:
image: plugins/manifest
pull: true
when:
event: tag
tag: "*[!-dev]"
settings:
spec: docker/manifest.tmpl
auto_tag: true
ignore_missing: true
username:
from_secret: cr-dhub-username
password:
from_secret: cr-dhub-key

View file

@ -1,77 +0,0 @@
###################
# publish release #
###################
# branch: master
# event: tag
platform: linux/amd64
depends_on:
- tests
clone:
git:
image: woodpeckerci/plugin-git:v1.6.0
when:
event: tag
pipeline:
# build wheel and dist
build-pypi:
image: cr.44net.ch/ci-plugins/tests
pull: true
when:
event: tag
commands:
- python3 -m hatch build --clean
# create release-notes
create-release-notes:
image: cr.44net.ch/baseimages/debian-base
pull: true
when:
event: tag
commands:
- bash get_release_notes.sh ${CI_COMMIT_TAG%%-dev}
# publish release on github (github.com/olofvndrhr/manga-dlp)
publish-release-github:
image: woodpeckerci/plugin-github-release
pull: true
when:
event: tag
settings:
api_key:
from_secret: github-olofvndrhr-token
files: dist/*
title: ${CI_COMMIT_TAG}
note: RELEASENOTES.md
# publish release on gitea (git.44net.ch/olofvndrhr/manga-dlp)
publish-release-gitea:
image: woodpeckerci/plugin-gitea-release
pull: true
when:
event: tag
settings:
api_key:
from_secret: gitea-olofvndrhr-token
base_url: https://git.44net.ch
files: dist/*
title: ${CI_COMMIT_TAG}
note: RELEASENOTES.md
# release pypi
release-pypi:
image: cr.44net.ch/ci-plugins/tests
pull: true
when:
event: tag
secrets:
- source: pypi_username
target: HATCH_INDEX_USER
- source: pypi_token
target: HATCH_INDEX_AUTH
commands:
- python3 -m hatch publish --no-prompt --yes

View file

@ -1,35 +0,0 @@
##################################
# test build docker images amd64 #
##################################
# branch: master
# event: pull_request
platform: linux/amd64
depends_on:
- tests
clone:
git:
image: woodpeckerci/plugin-git:v1.6.0
when:
branch: master
event: pull_request
pipeline:
# build docker image for amd64 - x86
test-build-amd64:
image: plugins/docker
pull: true
when:
branch: master
event: pull_request
settings:
dry_run: true
repo: olofvndrhr/manga-dlp
platforms: linux/amd64
dockerfile: docker/Dockerfile.amd64
auto_tag: true
auto_tag_suffix: linux-amd64-test
build_args: BUILD_VERSION=test

View file

@ -1,35 +0,0 @@
##################################
# test build docker images arm64 #
##################################
# branch: master
# event: pull_request
platform: linux/arm64
depends_on:
- tests
clone:
git:
image: woodpeckerci/plugin-git:v1.6.0
when:
branch: master
event: pull_request
pipeline:
# build docker image for arm64
test-build-arm64:
image: plugins/docker
pull: true
when:
branch: master
event: pull_request
settings:
dry_run: true
repo: olofvndrhr/manga-dlp
platforms: linux/arm64
dockerfile: docker/Dockerfile.arm64
auto_tag: true
auto_tag_suffix: linux-arm64-test
build_args: BUILD_VERSION=test

View file

@ -1,40 +0,0 @@
################
# test release #
################
# branch: master
# event: pull_request
platform: linux/amd64
depends_on:
- tests
clone:
git:
image: woodpeckerci/plugin-git:v1.6.0
when:
branch: master
event: pull_request
pipeline:
# build wheel and dist
test-build-pypi:
image: cr.44net.ch/ci-plugins/tests
pull: true
when:
branch: master
event: pull_request
commands:
- just test_build
# create release-notes
test-create-release-notes:
image: cr.44net.ch/baseimages/debian-base
pull: true
when:
branch: master
event: pull_request
commands:
- bash get_release_notes.sh latest
- cat RELEASENOTES.md

View file

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

View file

@ -1,32 +0,0 @@
##################
# test tox arm64 #
##################
# branch: master
# event: pull_request
platform: linux/arm64
depends_on:
- tests
clone:
git:
image: woodpeckerci/plugin-git:v1.6.0
when:
branch: master
event: pull_request
pipeline:
# test code with different python versions - arm64
test-tox-arm64:
image: cr.44net.ch/ci-plugins/multipy
pull: true
when:
branch: master
event: pull_request
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
- just test_tox

View file

@ -1,83 +0,0 @@
##############################
# code testing and analysis #
#############################
# branch: all
# event: all
platform: linux/amd64
clone:
git:
image: woodpeckerci/plugin-git:v1.6.0
pipeline:
# check code style - shell
test-shfmt:
image: cr.44net.ch/ci-plugins/tests
pull: true
commands:
- just test_shfmt
# check code style - python
test-black:
image: cr.44net.ch/ci-plugins/tests
pull: true
commands:
- just test_black
# check static typing - python
test-pyright:
image: cr.44net.ch/ci-plugins/tests
pull: true
commands:
- just install_deps
- just test_pyright
# ruff test - python
test-ruff:
image: cr.44net.ch/ci-plugins/tests
pull: true
commands:
- just test_ruff
# test mkdocs generation
test-mkdocs:
image: cr.44net.ch/ci-plugins/tests
pull: true
commands:
- python3 -m pip install mkdocs
- cd docs || exit 1
- python3 -m mkdocs build --strict
# test code with pytest - python
test-tox-pytest:
when:
event: [ push ]
image: cr.44net.ch/ci-plugins/tests
pull: true
commands:
- just test_pytest
# generate coverage report - python
test-tox-coverage:
when:
branch: master
event: [ pull_request ]
image: cr.44net.ch/ci-plugins/tests
pull: true
commands:
- just test_coverage
# analyse code with sonarqube and upload it
sonarqube-analysis:
when:
branch: master
event: [ pull_request ]
image: cr.44net.ch/ci-plugins/sonar-scanner
pull: true
settings:
sonar_host: https://sonarqube.44net.ch
sonar_token:
from_secret: sq-44net-token
usingProperties: true

View file

@ -7,458 +7,476 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased]
- Add support for more sites
- Add support for more sites
## [2.4.1] - 2024-02-01
- same as 2.4.0
## [2.4.0] - 2024-02-01
### Fixed
- Some issues with Python3.8 compatibility
### Changed
- Moved build system from woodpecker-ci to gitea actions
- Updated some dependencies
- Updated the docker image
- Switched from formatter/linter `black` to `ruff`
- Switches typing from `pyright` to `mypy`
## [2.3.1] - 2023-03-12
### Added
- Added TypedDicts for type checkers and type annotation
- Added TypedDicts for type checkers and type annotation
### Fixed
- Fixed some typos in the README
- Fixed some typos in the README
### Changed
- Switched from pylint/pylama/isort/autoflake to ruff
- Switched from mypy to pyright and added strict type checking
- Updated the api template
- Switched from pylint/pylama/isort/autoflake to ruff
- Switched from mypy to pyright and added strict type checking
- Updated the api template
## [2.3.0] - 2023-02-15
### Added
- Metadata is now added to each chapter. Schema
standard: [https://anansi-project.github.io/docs/comicinfo/schemas/v2.0](https://anansi-project.github.io/docs/comicinfo/schemas/v2.0)
- Added `xmltodict` as a package requirement
- Cache now also saves the manga title
- New tests
- More typo annotations for function, compatible with python3.8
- File format checker if you use the MangaDLP class directly
- Metadata is now added to each chapter. Schema
standard: [https://anansi-project.github.io/docs/comicinfo/schemas/v2.0](https://anansi-project.github.io/docs/comicinfo/schemas/v2.0)
- Added `xmltodict` as a package requirement
- Cache now also saves the manga title
- New tests
- More typo annotations for function, compatible with python3.8
- File format checker if you use the MangaDLP class directly
### Fixed
- API template typos
- Some useless type annotations
- API template typos
- Some useless type annotations
### Changed
- Simplified the chapter info generation
- Updated the license year
- Updated the API template
- Updated the API detection and removed it from the MangaDLP class
- Simplified the chapter info generation
- Updated the license year
- Updated the API template
- Updated the API detection and removed it from the MangaDLP class
## [2.2.20] - 2023-02-12
### Fixed
- Script now doesn't exit if multiple mangas were requested and one had an error
- Script now doesn't exit if multiple mangas were requested and one had an error
## [2.2.19] - 2023-02-11
### Added
- First version of the chapter cache (very basic functionality)
- First version of the chapter cache (very basic functionality)
### Fixed
- Fixed all exception re-raises to include the original stack trace
- Fixed all exception re-raises to include the original stack trace
### Changed
- Simplified chapter download loop
- Simplified chapter download loop
## [2.2.18] - 2023-01-21
### Fixed
- Fixed manga titles on non english language
- Fixed title & filename fixing to not use `ascii` but `uft8`
- Fixed manga titles on non english language
- Fixed title & filename fixing to not use `ascii` but `uft8`
### Added
- Fallback title to english of none was found in requested language
- More debug logs
- More tests
- Fallback title to english of none was found in requested language
- More debug logs
- More tests
### Changed
- Now uses the first found alt-title. Before it was the last
- Removed `sys.exit` in the api
- Now uses the first found alt-title. Before it was the last
- Removed `sys.exit` in the api
## [2.2.17] - 2023-01-15
### Fixed
- Set a timeout of 10 seconds for the api requests
- Set a timeout of 10 seconds for the api requests
### Added
- `--name-format` and `--name-format-none` flags to add a custom naming scheme for the downloaded files. See
docs: https://manga-dlp.ivn.sh/download/
- More debug log messages
- More tests for the custom naming scheme
- More type hints
- `--name-format` and `--name-format-none` flags to add a custom naming scheme for the downloaded files. See
docs: https://manga-dlp.ivn.sh/download/
- More debug log messages
- More tests for the custom naming scheme
- More type hints
### Changed
- Make `--format` a `click.Choice` option
- In the `--format` option the leading dot is now invalid. `--format .cbz` -> `--format cbz`
- Changed empty values from the api from None to an empty string
- Minor code readability improvements
- Make `--format` a `click.Choice` option
- In the `--format` option the leading dot is now invalid. `--format .cbz` -> `--format cbz`
- Changed empty values from the api from None to an empty string
- Minor code readability improvements
## [2.2.16] - 2022-12-30
### Fixed
- Log level is now fixed and should not default to 0
- Docker schedule should now work again
- Log level is now fixed and should not default to 0
- Docker schedule should now work again
### Changed
- Integrate logging logs to loguru via custom sink
- Simplify docker shell scripts
- Integrate logging logs to loguru via custom sink
- Simplify docker shell scripts
## [2.2.15] - 2022-12-29
### Added
- `--warn` and `--loglevel` flags
- `--warn` and `--loglevel` flags
### Removed
- Remove `--lean` and `--verbose` flags and remove custom log levels
- Remove `--lean` and `--verbose` flags and remove custom log levels
### Changed
- Move from standard library logging to [loguru](https://loguru.readthedocs.io/en/stable/index.html)
- Move from standard library argparse to [click](https://click.palletsprojects.com/en/8.1.x/)
- Move from standard library logging to [loguru](https://loguru.readthedocs.io/en/stable/index.html)
- Move from standard library argparse to [click](https://click.palletsprojects.com/en/8.1.x/)
## [2.2.14] - 2022-10-06
### Changed
- Changed logging format to ISO 8601
- Small logging corrections
- Changed logging format to ISO 8601
- Small logging corrections
## [2.2.13] - 2022-08-15
### Added
- Option to run custom hooks before and after each chapter/manga download
- _Tests for the new hooks_
- _Docs for the new hooks_
- _Tests for mkdocs generation_
- Option to run custom hooks before and after each chapter/manga download
- _Tests for the new hooks_
- _Docs for the new hooks_
- _Tests for mkdocs generation_
### Changed
- Verbose and Debug logging now have a space as a seperator between log level-name and log-level
- APIs now have an attribute with their name (for the hooks) - `api.api_name`
- Docs moved to Cloudflare pages (generated with mkdocs)
- Verbose and Debug logging now have a space as a seperator between log level-name and log-level
- APIs now have an attribute with their name (for the hooks) - `api.api_name`
- Docs moved to Cloudflare pages (generated with mkdocs)
## [2.1.12] - 2022-07-25
### Fixed
- Image publishing with `hatch` on pypi should now work again
- The schedule fixer for the new `.sh` schedule should now work correctly
- Image publishing with `hatch` on pypi should now work again
- The schedule fixer for the new `.sh` schedule should now work correctly
### Added
- More CI tests: `pylint`, `pylama` and `autoflake`
- New function in `get_release_notes.sh` to get the latest version
- Docstrings for `MangaDLP` and the api module `Mangadex`
- More CI tests: `pylint`, `pylama` and `autoflake`
- New function in `get_release_notes.sh` to get the latest version
- Docstrings for `MangaDLP` and the api module `Mangadex`
### Changed
- CI workflow is now faster and runs natively on arm64 (before it was buildx/emulation)
- `Pylint`/`pylama` code improvements
- Version management is now done with `hatch` (in `__about__.py`)
- CI workflow is now faster and runs natively on arm64 (before it was buildx/emulation)
- `Pylint`/`pylama` code improvements
- Version management is now done with `hatch` (in `__about__.py`)
## [2.1.11] - 2022-07-18
### Fixed
- The `--read` option now filters empty lines, so it will not generate an error anymore
- An error which was caused by the interactive input method when you did not specify a chapter or to list them
- Some typos
- The `--read` option now filters empty lines, so it will not generate an error anymore
- An error which was caused by the interactive input method when you did not specify a chapter or to list them
- Some typos
### Added
- Options to configure the default schedule in the docker container via environment variables
- Section the the docker [README.md](docker/README.md) for the new environment variables
- `autoflake` test in `justfile`
- Some more things which get logged
- Options to configure the default schedule in the docker container via environment variables
- Section the the docker [README.md](docker/README.md) for the new environment variables
- `autoflake` test in `justfile`
- Some more things which get logged
### Changed
- **BREAKING**: renamed the default schedule from `daily` to `daily.sh`. Don't forget to fix your bind-mounts to
overwrite
the default schedule
- Added the `.sh` suffix to the s6 init scripts for better compatibility
- Adjusted the new logging implementation. It shows now more info about the module the log is from, and some other
improvements
- **BREAKING**: renamed the default schedule from `daily` to `daily.sh`. Don't forget to fix your bind-mounts to
overwrite
the default schedule
- Added the `.sh` suffix to the s6 init scripts for better compatibility
- Adjusted the new logging implementation. It shows now more info about the module the log is from, and some other
improvements
## [2.1.10] - 2022-07-14
### Fixed
- Removed some unused files
- Removed some unused files
### Added
- `logger.py` for all log related settings and functions
- `logger.py` for all log related settings and functions
### Changed
- Logging of output. The script now uses the `logging` library
- Logging of output. The script now uses the `logging` library
## [2.1.9] - 2022-06-26
### Fixed
- Timeouts in tests, due to api limitations. Now added a wait time between tests
- Pytest path
- 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)
- `--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)
- 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
### Fixed
- Interactive input
- Interactive input
## [2.1.7] - 2022-06-22
### Added
- tox version testing
- New pre-release tests
- Build info's with hatch
- [Pypi](https://pypi.org/project/manga-dlp/) build with hatch
- Pypi section in `README.md`
- [Snyk](https://app.snyk.io/org/olofvndrhr-t6h/project/aae9609d-a4e4-41f8-b1ac-f2561b2ad4e3) test results
in `README.md`
- tox version testing
- New pre-release tests
- Build info's with hatch
- [Pypi](https://pypi.org/project/manga-dlp/) build with hatch
- Pypi section in `README.md`
- [Snyk](https://app.snyk.io/org/olofvndrhr-t6h/project/aae9609d-a4e4-41f8-b1ac-f2561b2ad4e3) test results
in `README.md`
### Changed
- Moved code from `manga-dlp.py` to `input.py` for uniformity
- The default entrypoint is now `mangadlp.input:main`
- Moved code from `manga-dlp.py` to `input.py` for uniformity
- The default entrypoint is now `mangadlp.input:main`
## [2.1.6] - 2022-06-21
### Fixed
- Docker labels are now working
- Global variables are now fully uppercase
- Some errors with static types
- Docker labels are now working
- Global variables are now fully uppercase
- Some errors with static types
### Added
- bump2version config for releases
- More tests with: `mypy` and `isort`
- New issue templates
- bump2version config for releases
- More tests with: `mypy` and `isort`
- New issue templates
### Changed
- Release workflow now is based on configuration files
- Switched from `setup.py` to `pyproject.toml`
- `README.md` now has sorted badges
- Imports are now sorted with `isort`
- Static types are now checked with `mypy`
- Release note generation is now simplified
- Release workflow now is based on configuration files
- Switched from `setup.py` to `pyproject.toml`
- `README.md` now has sorted badges
- Imports are now sorted with `isort`
- Static types are now checked with `mypy`
- Release note generation is now simplified
## [2.1.5] - 2022-06-18
### Fixed
- Image names now have a suffix, as some comic readers have problems with no
suffix [fixes issue #2]
- Image names now have a suffix, as some comic readers have problems with no
suffix [fixes issue #2]
### Added
- `--format` section in the README
- `--format` section in the README
## [2.1.4] - 2022-05-29
### Fixed
- Docker container now works again
- Fixed cron in docker container
- Docker container now works again
- Fixed cron in docker container
### Changed
- Docker container scheduling is now more practical
- Docker container scheduling is now more practical
## [2.1.3] - 2022-05-29
### Fixed
- Error-chapters and skipped-chapters list are now shown again
- The Interactive input version now matches `--version`
- Error-chapters and skipped-chapters list are now shown again
- The Interactive input version now matches `--version`
### Added
- Ability to list chapters with interactive input
- Ability to list chapters with interactive input
### Changed
- Replace `exit()` with `sys.exit()`
- Renamed class methods to not look like dunder methods
- Script execution moved from `os.system()` to `subprocess.call()`
- Replace `exit()` with `sys.exit()`
- Renamed class methods to not look like dunder methods
- Script execution moved from `os.system()` to `subprocess.call()`
## [2.1.2] - 2022-05-20
### Fixed
- List chapters when none were specified
- Typos
- List chapters when none were specified
- Typos
### Added
- Ability to download whole volumes
- Ability to download whole volumes
### Changed
- Moved processing of list with links to input.py
- Updated README for volume and chapter selection
- Moved processing of list with links to input.py
- Updated README for volume and chapter selection
## [2.1.1] - 2022-05-18
### Fixed
- Progress bar on verbose output
- Sonarqube link for CI
- A few typos
- Removed unnecessary escapes from file rename regex
- Progress bar on verbose output
- Sonarqube link for CI
- A few typos
- Removed unnecessary escapes from file rename regex
### Added
- API template
- API template
### Changed
- Updated docker baseimage
- Rewrote app.py to a class
- Updated docker baseimage
- Rewrote app.py to a class
## [2.1.0] - 2022-05-16
### Fixed
- Detection of files. Now it will skip them again
- Detection of files. Now it will skip them again
### Added
- Ability to save the chapters as pdf (only on amd64/x86)
- New output formats: rar, zip
- Progress bar to show image download
- Interactive input if no command line flags are given
- Better KeyboardInterrupt handling
- Better error handling
- Removed duplicate code
- Ability to save the chapters as pdf (only on amd64/x86)
- New output formats: rar, zip
- Progress bar to show image download
- Interactive input if no command line flags are given
- Better KeyboardInterrupt handling
- Better error handling
- Removed duplicate code
### Changed
- How the variables are used inside the script
- Variables have now the same name as in other scripts (mostly)
- Better retrying when a task fails
- How the variables are used inside the script
- Variables have now the same name as in other scripts (mostly)
- Better retrying when a task fails
## [2.0.8] - 2022-05-13
### Changed
- Rewrote parts of script to be easier to maintain
- Moved the input script to the base folder
- Moved all arguments to a class
- Docker container creation
- Rewrote parts of script to be easier to maintain
- Moved the input script to the base folder
- Moved all arguments to a class
- Docker container creation
## [2.0.7] - 2022-05-13
### Changed
- Changed CI/CD Platform from Drone-CI to Woodpecker-CI
- Release title is now only the version
- Changed CI/CD Platform from Drone-CI to Woodpecker-CI
- Release title is now only the version
## [2.0.6] - 2022-05-11
### Fixed
- Filenames on windows (ntfs). Removed double quote from file and folder names
- Filenames on windows (ntfs). Removed double quote from file and folder names
## [2.0.5] - 2022-05-11
### Fixed
- Better error handling on "KeyboardInterrupt"
- Release notes now fixed
- Better error handling on "KeyboardInterrupt"
- Release notes now fixed
### Added
- New test cases
- New test cases
## [2.0.4] - 2022-05-10
### Added
- New test cases for more coverage
- Github release
- Updated docker baseimage
- New test cases for more coverage
- Github release
- Updated docker baseimage
## [2.0.3] - 2022-05-10
### Fixed
- Test cases now work again
- Sonarqube settings
- Test cases now work again
- Sonarqube settings
### Added
- Coverage report in sonarqube
- Gitea release
- Coverage report in sonarqube
- Gitea release
## [2.0.2] - 2022-05-09
### Fixed
- Restart failed api requests
- Added wait time for image gathering, as to stop api rate limiting from mangadex
- "--wait" options now works properly again
- Restart failed api requests
- Added wait time for image gathering, as to stop api rate limiting from mangadex
- "--wait" options now works properly again
## [2.0.1] - 2022-05-09
### Fixed
- Regex for removing illegal characters in the filenames now doesn't remove quotes
- Updated docker baseimage and fixed the mangadlp tag in it
- Update license for 2022
- Regex for removing illegal characters in the filenames now doesn't remove quotes
- Updated docker baseimage and fixed the mangadlp tag in it
- Update license for 2022
### Added
- Quick start section in README
- Preperation for pypi
- Quick start section in README
- Preperation for pypi
## [2.0.0] - 2022-05-09
### Fixed
- Support for new mangadex api
- Support for new mangadex api
### Changed
- Code is now formatted with [black](https://github.com/psf/black)
- Now also supports just the uuid for managex (not a full link)
- Code is now formatted with [black](https://github.com/psf/black)
- Now also supports just the uuid for managex (not a full link)

View file

@ -1,6 +1,6 @@
MIT License
Copyright (c) 2021-2023 Ivan Schaller
Copyright (c) 2021-present Ivan Schaller <ivan@schaller.sh>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View file

@ -1,13 +1 @@
include *.json
include *.md
include *.properties
include *.py
include *.txt
include *.yml
include *.xml
recursive-include contrib *.py
recursive-include mangadlp *.py
recursive-include mangadlp *.xml
recursive-include tests *.py
recursive-include tests *.xml
recursive-include tests *.txt
graft src

View file

@ -2,29 +2,23 @@
> Full docs: https://manga-dlp.ivn.sh
CI/CD
[![status-badge](https://img.shields.io/drone/build/olofvndrhr/manga-dlp?label=tests&server=https%3A%2F%2Fci.44net.ch)](https://ci.44net.ch/olofvndrhr/manga-dlp)
[![Last Release](https://img.shields.io/github/release-date/olofvndrhr/manga-DLP?label=last%20release)](https://github.com/olofvndrhr/manga-dlp/releases)
[![Version](https://img.shields.io/github/v/release/olofvndrhr/manga-dlp?label=git%20release)](https://github.com/olofvndrhr/manga-dlp/releases)
[![Version PyPi](https://img.shields.io/pypi/v/manga-dlp?label=pypi%20release)](https://pypi.org/project/manga-dlp/)
Code Analysis
[![Quality Gate Status](https://sonarqube.44net.ch/api/project_badges/measure?project=olofvndrhr%3Amanga-dlp&metric=alert_status&token=f9558470580eea5b4899cf33f190eee16011346d)](https://sonarqube.44net.ch/dashboard?id=olofvndrhr%3Amanga-dlp)
[![Coverage](https://sonarqube.44net.ch/api/project_badges/measure?project=olofvndrhr%3Amanga-dlp&metric=coverage&token=f9558470580eea5b4899cf33f190eee16011346d)](https://sonarqube.44net.ch/dashboard?id=olofvndrhr%3Amanga-dlp)
[![Bugs](https://sonarqube.44net.ch/api/project_badges/measure?project=olofvndrhr%3Amanga-dlp&metric=bugs&token=f9558470580eea5b4899cf33f190eee16011346d)](https://sonarqube.44net.ch/dashboard?id=olofvndrhr%3Amanga-dlp)
[![Security](https://img.shields.io/snyk/vulnerabilities/github/olofvndrhr/manga-dlp)](https://app.snyk.io/org/olofvndrhr-t6h/project/aae9609d-a4e4-41f8-b1ac-f2561b2ad4e3)
[![Maintainability Rating](https://sonarqube.44net.ch/api/project_badges/measure?project=olofvndrhr%3Amanga-dlp&metric=sqale_rating&token=f9558470580eea5b4899cf33f190eee16011346d)](https://sonarqube.44net.ch/dashboard?id=olofvndrhr%3Amanga-dlp)
[![Reliability Rating](https://sonarqube.44net.ch/api/project_badges/measure?project=olofvndrhr%3Amanga-dlp&metric=reliability_rating&token=f9558470580eea5b4899cf33f190eee16011346d)](https://sonarqube.44net.ch/dashboard?id=olofvndrhr%3Amanga-dlp)
[![Security Rating](https://sonarqube.44net.ch/api/project_badges/measure?project=olofvndrhr%3Amanga-dlp&metric=security_rating&token=f9558470580eea5b4899cf33f190eee16011346d)](https://sonarqube.44net.ch/dashboard?id=olofvndrhr%3Amanga-dlp)
Meta
[![Code style](https://img.shields.io/badge/code%20style-black-black)](https://github.com/psf/black)
[![Formatter](https://img.shields.io/badge/code%20style-ruff-black)](https://github.com/charliermarsh/ruff)
[![Linter](https://img.shields.io/badge/linter-ruff-red)](https://github.com/charliermarsh/ruff)
[![Types](https://img.shields.io/badge/types-pyright-blue)](https://github.com/microsoft/pyright)
[![Types](https://img.shields.io/badge/types-mypy-blue)](https://github.com/python/mypy)
[![Tests](https://img.shields.io/badge/tests-pytest%20%7C%20tox-yellow)](https://github.com/pytest-dev/pytest/)
[![Coverage](https://img.shields.io/badge/coverage-coveragepy-green)](https://github.com/nedbat/coveragepy)
[![License](https://img.shields.io/badge/license-MIT-9400d3.svg)](https://snyk.io/learn/what-is-mit-license/)
[![Compatibility](https://img.shields.io/pypi/pyversions/manga-dlp)](https://pypi.org/project/manga-dlp/)
[![Compatibility](https://img.shields.io/badge/python-3.11-blue)]()
---
@ -42,19 +36,19 @@ you just want the folder with all the pictures use the flag `--format ""`.
## _Currently_ Supported sites
- [Mangadex.org](https://mangadex.org/)
- [Mangadex.org](https://mangadex.org/)
## Features (not complete)
- Metadata support with [ComicInfo.xml](https://anansi-project.github.io/docs/comicinfo/intro)
- Json caching
- Custom hooks after/before each download
- Custom chapter name format
- Volume support
- Multiple archive formats supported (cbz,cbr,zip,none)
- Language selection
- Download all chapters directly
- And others...
- Metadata support with [ComicInfo.xml](https://anansi-project.github.io/docs/comicinfo/intro)
- Json caching
- Custom hooks after/before each download
- Custom chapter name format
- Volume support
- Multiple archive formats supported (cbz,cbr,zip,none)
- Language selection
- Download all chapters directly
- And others...
## Usage
@ -146,10 +140,10 @@ If you encounter any bugs, also just open an issue with a description of the pro
## TODO's
- <del>Make docker container for easy distribution</del>
--> [Dockerhub](https://hub.docker.com/r/olofvndrhr/manga-dlp)
- <del>Automate release</del>
--> Done with woodpecker-ci
- <del>Make pypi package</del>
--> Done with release [2.1.7](https://pypi.org/project/manga-dlp/)
- Add more supported sites
- <del>Make docker container for easy distribution</del>
--> [Dockerhub](https://hub.docker.com/r/olofvndrhr/manga-dlp)
- <del>Automate release</del>
--> Done with woodpecker-ci
- <del>Make pypi package</del>
--> Done with release [2.1.7](https://pypi.org/project/manga-dlp/)
- Add more supported sites

View file

@ -1,6 +1,7 @@
from typing import Dict, List, Union
from typing import Dict, List
from mangadlp.models import ChapterData, ComicInfo
from mangadlp.types import ChapterData,ComicInfo
# api template for manga-dlp
@ -45,7 +46,7 @@ class YourAPI:
"volume": "1",
"chapter": "1",
"name": "test",
"pages" 2,
"pages": 2,
},
"2": {
"uuid": "abc",

39
docker/Dockerfile Normal file
View file

@ -0,0 +1,39 @@
FROM git.44net.ch/44net/python311:11 AS builder
COPY pyproject.toml README.md /build/
COPY src /build/src
WORKDIR /build
RUN \
echo "**** building package ****" \
&& pip3 install hatch hatchling \
&& python3 -m hatch build --clean
FROM git.44net.ch/44net/debian-s6:11
LABEL maintainer="Ivan Schaller" \
description="A CLI manga downloader"
ENV PATH="/opt/python3/bin:${PATH}"
COPY --from=builder /opt/python3 /opt/python3
COPY --from=builder /build/dist/*.whl /build/dist/
COPY docker/rootfs /
RUN \
echo "**** creating folders ****" \
&& mkdir -p /app \
&& echo "**** updating pip ****" \
&& python3 -m pip install --upgrade pip setuptools wheel \
&& echo "**** install python packages ****" \
&& python3 -m pip install /build/dist/*.whl
RUN \
echo "**** cleanup ****" \
&& apt-get purge --auto-remove -y \
&& apt-get clean \
&& rm -rf \
/tmp/* \
/var/lib/apt/lists/* \
/var/tmp/*
WORKDIR /app

View file

@ -1,50 +0,0 @@
FROM cr.44net.ch/baseimages/debian-s6:11.6-linux-amd64
# set version label
ARG BUILD_VERSION
ENV IMAGE_VERSION=${BUILD_VERSION}
LABEL version="${BUILD_VERSION}"
LABEL maintainer="Ivan Schaller"
LABEL description="A CLI manga downloader"
# install packages
RUN \
echo "**** install base packages ****" \
&& apt-get update \
&& apt-get install -y --no-install-recommends \
python3 \
python3-pip
# prepare app
RUN \
echo "**** creating folders ****" \
&& mkdir -p /app \
&& echo "**** updating pip ****" \
&& python3 -m pip install --upgrade pip
# cleanup installation
RUN \
echo "**** cleanup ****" \
&& apt-get purge --auto-remove -y \
&& apt-get clean \
&& rm -rf \
/tmp/* \
/var/lib/apt/lists/* \
/var/tmp/*
# copy files to container
COPY docker/rootfs /
COPY mangadlp/ /app/mangadlp/
COPY \
manga-dlp.py \
requirements.txt \
LICENSE \
/app/
# install requirements
RUN pip install -r /app/requirements.txt
WORKDIR /app

View file

@ -1,52 +0,0 @@
FROM cr.44net.ch/baseimages/debian-s6:11.6-linux-arm64
# set version label
ARG BUILD_VERSION
ENV IMAGE_VERSION=${BUILD_VERSION}
LABEL version="${BUILD_VERSION}"
LABEL maintainer="Ivan Schaller"
LABEL description="A CLI manga downloader"
# install packages
RUN \
echo "**** install base packages ****" \
&& apt-get update \
&& apt-get install -y --no-install-recommends \
python3 \
python3-pip
# prepare app
RUN \
echo "**** creating folders ****" \
&& mkdir -p /app \
&& echo "**** updating pip ****" \
&& python3 -m pip install --upgrade pip
# cleanup installation
RUN \
echo "**** cleanup ****" \
&& apt-get purge --auto-remove -y \
&& apt-get clean \
&& rm -rf \
/tmp/* \
/var/lib/apt/lists/* \
/var/tmp/*
# copy files to container
COPY docker/rootfs /
COPY mangadlp/ /app/mangadlp/
COPY \
manga-dlp.py \
requirements.txt \
LICENSE \
/app/
# install requirements (without img2pdf)
RUN grep -v img2pdf /app/requirements.txt > /app/requirements-arm64.txt
RUN pip install -r /app/requirements-arm64.txt
WORKDIR /app

View file

@ -1,20 +0,0 @@
image: olofvndrhr/manga-dlp:{{#if build.tag}}{{trimPrefix "v" build.tag}}{{else}}dev{{/if}}
{{#if build.tags}}
tags:
{{#each build.tags}}
- {{this}}
{{/each}}
- "latest"
{{/if}}
manifests:
-
image: olofvndrhr/manga-dlp:{{#if build.tag}}{{trimPrefix "v" build.tag}}-{{else}}dev-{{/if}}linux-amd64
platform:
architecture: amd64
os: linux
-
image: olofvndrhr/manga-dlp:{{#if build.tag}}{{trimPrefix "v" build.tag}}-{{else}}dev-{{/if}}linux-arm64
platform:
architecture: arm64
os: linux
variant: v8

View file

@ -8,4 +8,3 @@ PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
# "s6-setuidgid abc" is used to set the permissions
0 12 * * * root s6-setuidgid abc /app/schedules/daily.sh > /proc/1/fd/1 2>&1

View file

@ -1,52 +0,0 @@
#!/bin/bash
# shellcheck disable=SC2016
# script to extract the release notes from the changelog
# show script help
function show_help() {
cat << EOF
Script to generate release-notes from a changelog (CHANGELOG.md)
Usage:
./get_release_notes.sh <new_version>
Example:
./get_release_notes.sh "2.0.5"
or
./get_release_notes.sh "latest"
EOF
exit 0
}
# create changelog for release
function get_release_notes() {
local l_version="${1}"
printf 'Creating release-notes\n'
# check for version
if [[ -z "${l_version}" ]]; then
printf 'You need to specify a version with $1\n'
exit 1
fi
if [[ ${l_version,,} == "latest" ]]; then
l_version="$(grep -o -E "^##\s\[[0-9]{1,2}.[0-9]{1,2}.[0-9]{1,2}\]" CHANGELOG.md | head -n 1 | grep -o -E "[0-9]{1,2}.[0-9]{1,2}.[0-9]{1,2}")"
fi
awk -v ver="[${l_version}]" \
'/^## / { if (p) { exit }; if ($2 == ver) { p=1 } } p && NF' \
'CHANGELOG.md' > 'RELEASENOTES.md'
printf 'Done\n'
}
# check options
case "${1}" in
'--help' | '-h' | 'help')
show_help
;;
*)
get_release_notes "${@}"
;;
esac

156
justfile
View file

@ -3,143 +3,73 @@
default: show_receipts
set shell := ["bash", "-uc"]
set dotenv-load := true
#set export
set dotenv-load
# 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
just --list
show_system_info:
@echo "=================================="
@echo "os : {{os()}}"
@echo "arch: {{arch()}}"
@echo "home: ${HOME}"
@echo "project dir: {{justfile_directory()}}"
@echo "justfile dir: {{justfile_directory()}}"
@echo "invocation dir: {{invocation_directory()}}"
@echo "running dir: `pwd -P`"
@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
setup:
asdf install
lefthook install
create_venv:
@echo "creating venv"
@python3 -m pip install --upgrade pip setuptools wheel
@python3 -m venv venv
python3 -m pip install --upgrade pip setuptools wheel
python3 -m venv venv
install_deps:
@echo "installing dependencies"
@pip3 install -r requirements.txt
python3 -m hatch dep show requirements --project-only > /tmp/requirements.txt
pip3 install -r /tmp/requirements.txt
install_deps_dev:
@echo "installing dependencies"
@pip3 install -r contrib/requirements_dev.txt
@echo "installing dev dependencies"
python3 -m hatch dep show requirements --project-only > /tmp/requirements.txt
python3 -m hatch dep show requirements --env-only >> /tmp/requirements.txt
pip3 install -r /tmp/requirements.txt
create_reqs:
@echo "creating requirements"
pipreqs --force --savepath requirements.txt src/mangadlp/
test_shfmt:
@find . -type f \( -name "**.sh" -and -not -path "./.**" -and -not -path "./venv**" \) -exec shfmt -d -i 4 -bn -ci -sr "{}" \+;
find . -type f \( -name "**.sh" -and -not -path "./.**" -and -not -path "./venv**" \) -exec shfmt -d -i 4 -bn -ci -sr "{}" \+;
test_black:
@python3 -m black --check --diff mangadlp/
test_pyright:
@python3 -m pyright mangadlp/
test_ruff:
@python3 -m ruff --diff mangadlp/
test_ci_conf:
@woodpecker-cli lint .woodpecker/
test_pytest:
@python3 -m tox -e basic
test_coverage:
@python3 -m tox -e coverage
test_tox:
@python3 -m tox
test_build:
@python3 -m hatch build --clean
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
format_shfmt:
find . -type f \( -name "**.sh" -and -not -path "./.**" -and -not -path "./venv**" \) -exec shfmt -w -i 4 -bn -ci -sr "{}" \+;
lint:
just show_system_info
-just test_ci_conf
just test_shfmt
just test_black
just test_pyright
just test_ruff
@echo -e "\n\033[0;32m=== ALL DONE ===\033[0m\n"
hatch run lint:style
hatch run lint:typing
tests:
format:
just show_system_info
-just test_ci_conf
just test_shfmt
just test_black
just test_pyright
just test_ruff
just test_pytest
@echo -e "\n\033[0;32m=== ALL DONE ===\033[0m\n"
just format_shfmt
hatch run lint:fmt
tests_full:
just show_system_info
-just test_ci_conf
just test_shfmt
just test_black
just test_pyright
just test_ruff
just test_build
just test_tox
just test_coverage
just test_docker_build
@echo -e "\n\033[0;32m=== ALL DONE ===\033[0m\n"
check:
just lint
just format
test:
hatch run default:test
coverage:
hatch run default:cov
build:
hatch build --clean
run loglevel *flags:
hatch run mangadlp --loglevel {{loglevel}} {{flags}}

View file

@ -1,6 +1,7 @@
import sys
import mangadlp.cli
import src.mangadlp.cli
if __name__ == "__main__":
sys.exit(mangadlp.cli.main()) # pylint: disable=no-value-for-parameter
sys.exit(src.mangadlp.cli.main())

View file

@ -1 +0,0 @@
__version__ = "2.3.1"

View file

View file

@ -1,6 +0,0 @@
import sys
import mangadlp.cli
if __name__ == "__main__":
sys.exit(mangadlp.cli.main()) # pylint: disable=no-value-for-parameter

View file

@ -1,14 +1,14 @@
[build-system]
requires = ["hatchling>=1.11.0"]
requires = ["hatchling>=1.18", "hatch-regex-commit>=0.0.3"]
build-backend = "hatchling.build"
[project]
dynamic = ["version"]
name = "manga-dlp"
description = "A cli manga downloader"
readme = "README.md"
license = "MIT"
requires-python = ">=3.8"
dynamic = ["version"]
authors = [{ name = "Ivan Schaller", email = "ivan@schaller.sh" }]
keywords = ["manga", "downloader", "mangadex"]
classifiers = [
@ -18,6 +18,7 @@ classifiers = [
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
]
dependencies = [
"requests>=2.28.0",
@ -25,125 +26,221 @@ dependencies = [
"click>=8.1.3",
"click-option-group>=0.5.5",
"xmltodict>=0.13.0",
"img2pdf>=0.4.4",
"pytz>=2022.1",
]
[project.urls]
Homepage = "https://github.com/olofvndrhr/manga-dlp"
History = "https://github.com/olofvndrhr/manga-dlp/commits/master"
Tracker = "https://github.com/olofvndrhr/manga-dlp/issues"
Source = "https://github.com/olofvndrhr/manga-dlp"
History = "https://github.com/olofvndrhr/manga-dlp/commits/master"
Tracker = "https://github.com/olofvndrhr/manga-dlp/issues"
Source = "https://github.com/olofvndrhr/manga-dlp"
[project.scripts]
mangadlp = "mangadlp.cli:main"
mangadlp = "mangadlp.cli:main"
manga-dlp = "mangadlp.cli:main"
[tool.hatch.version]
path = "mangadlp/__about__.py"
[tool.hatch.build]
ignore-vcs = true
source = "regex_commit"
path = "src/mangadlp/__about__.py"
tag_sign = false
[tool.hatch.build.targets.sdist]
packages = ["mangadlp"]
packages = ["src/mangadlp"]
[tool.hatch.build.targets.wheel]
packages = ["mangadlp"]
packages = ["src/mangadlp"]
###
### envs
###
[tool.hatch.envs.default]
python = "3.11"
dependencies = [
"requests>=2.28.0",
"loguru>=0.6.0",
"click>=8.1.3",
"click-option-group>=0.5.5",
"pytest==7.4.3",
"coverage==7.3.2",
"xmltodict>=0.13.0",
"xmlschema>=2.2.1",
"img2pdf>=0.4.4",
"hatch>=1.6.0",
"hatchling>=1.11.0",
"pytest>=7.0.0",
"coverage>=6.3.1",
"black>=22.1.0",
"mypy>=0.940",
"tox>=3.24.5",
"ruff>=0.0.247",
]
# pyright
[tool.hatch.envs.default.scripts]
test = "pytest {args:tests}"
test-cov = ["coverage erase", "coverage run -m pytest {args:tests}"]
cov-report = ["- coverage combine", "coverage report", "coverage xml"]
cov = ["test-cov", "cov-report"]
[tool.pyright]
typeCheckingMode = "strict"
pythonVersion = "3.9"
reportUnnecessaryTypeIgnoreComment = true
reportShadowedImports = true
reportUnusedExpression = true
reportMatchNotExhaustive = true
# venvPath = "."
# venv = "venv"
[[tool.hatch.envs.lint.matrix]]
python = ["3.8", "3.9", "3.10", "3.11"]
# ruff
[tool.hatch.envs.lint]
detached = true
dependencies = [
"mypy==1.8.0",
"ruff==0.2.2",
]
[tool.hatch.envs.lint.scripts]
typing = "mypy --non-interactive --install-types {args:src/mangadlp}"
style = [
"ruff check --diff {args:.}",
"ruff format --check --diff {args:.}"
]
fmt = [
"ruff check --fix {args:.}",
"ruff format {args:.}",
"style"
]
all = ["style", "typing"]
###
### ruff
###
[tool.ruff]
target-version = "py39"
select = [
"E", # pycodetyle err
"W", # pycodetyle warn
"D", # pydocstyle
"C90", # mccabe
"I", # isort
"PLE", # pylint err
"PLW", # pylint warn
"PLC", # pylint convention
"PLR", # pylint refactor
"F", # pyflakes
"RUF", # ruff specific
]
line-length = 88
target-version = "py38"
line-length = 100
indent-width = 4
fix = true
show-fixes = true
format = "grouped"
ignore-init-module-imports = true
respect-gitignore = true
ignore = ["E501", "D103", "D100", "D102", "PLR2004"]
src = ["src", "tests"]
exclude = [
".direnv",
".git",
".mypy_cache",
".ruff_cache",
".svn",
".tox",
".nox",
".venv",
"venv",
"__pypackages__",
"build",
"dist",
"node_modules",
"venv",
"contrib"
]
[tool.ruff.per-file-ignores]
[tool.ruff.lint]
select = [
"A",
"ARG",
"B",
"C",
"DTZ",
"E",
"EM",
"F",
"FBT",
"I",
"ICN",
"ISC",
"N",
"PLC",
"PLE",
"PLR",
"PLW",
"Q",
"RUF",
"S",
"T",
"TID",
"UP",
"W",
"YTT",
]
ignore-init-module-imports = true
ignore = ["E501", "D103", "D100", "D102", "PLR2004", "D403", "ISC001", "FBT001", "FBT002", "FBT003", "W505"]
unfixable = ["F401"]
[tool.ruff.format]
quote-style = "double"
indent-style = "space"
skip-magic-trailing-comma = false
line-ending = "lf"
docstring-code-format = true
[tool.ruff.lint.per-file-ignores]
"__init__.py" = ["D104"]
"__about__.py" = ["D104", "F841"]
"tests/**/*" = ["PLR2004", "S101", "TID252", "T201", "ARG001", "S603", "S605"]
[tool.ruff.pylint]
max-args = 10
[tool.ruff.lint.pyupgrade]
keep-runtime-typing = true
[tool.ruff.mccabe]
max-complexity = 10
[tool.ruff.lint.isort]
lines-after-imports = 2
known-first-party = ["mangadlp"]
[tool.ruff.pydocstyle]
[tool.ruff.lint.flake8-tidy-imports]
ban-relative-imports = "all"
[tool.ruff.lint.pylint]
max-branches = 24
max-returns = 12
max-statements = 100
max-args = 15
allow-magic-value-types = ["str", "bytes", "complex", "float", "int"]
[tool.ruff.lint.mccabe]
max-complexity = 15
[tool.ruff.lint.pydocstyle]
convention = "google"
[tool.ruff.pycodestyle]
max-doc-length = 88
[tool.ruff.lint.pycodestyle]
max-doc-length = 100
# pytest
###
### mypy
###
[tool.mypy]
#plugins = ["pydantic.mypy"]
follow_imports = "silent"
warn_redundant_casts = true
warn_unused_ignores = true
disallow_any_generics = true
check_untyped_defs = true
no_implicit_reexport = true
ignore_missing_imports = true
warn_return_any = true
pretty = true
show_column_numbers = true
show_error_codes = true
show_error_context = true
#[tool.pydantic-mypy]
#init_forbid_extra = true
#init_typed = true
#warn_required_dynamic_aliases = true
###
### pytest
###
[tool.pytest.ini_options]
pythonpath = ["."]
pythonpath = ["src"]
addopts = "--color=yes --exitfirst --verbose -ra"
filterwarnings = [
'ignore:Jupyter is migrating its paths to use standard platformdirs:DeprecationWarning',
]
# coverage
###
### coverage
###
[tool.coverage.run]
source = ["mangadlp"]
branch = true
command_line = "-m pytest --exitfirst"
source_pkgs = ["mangadlp", "tests"]
branch = true
parallel = true
omit = ["src/mangadlp/__about__.py"]
[tool.coverage.paths]
mangadlp = ["src/mangadlp", "*/manga-dlp/src/mangadlp"]
tests = ["tests", "*/manga-dlp/tests"]
[tool.coverage.report]
# Regexes for lines to exclude from consideration
@ -161,5 +258,7 @@ exclude_lines = [
"if __name__ == .__main__.:",
# Don't complain about abstract methods, they aren't run:
"@(abc.)?abstractmethod",
"no cov",
"if TYPE_CHECKING:",
]
ignore_errors = true
# ignore_errors = true

View file

@ -1,6 +1,4 @@
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": [
"local>44net-assets/docker-renovate-conf"
]
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": ["local>44net/renovate"]
}

View file

@ -5,8 +5,8 @@ sonar.links.scm=https://github.com/olofvndrhr/manga-dlp
sonar.links.issue=https://github.com/olofvndrhr/manga-dlp/issues
sonar.links.ci=https://ci.44net.ch/olofvndrhr/manga-dlp
#
sonar.sources=mangadlp
sonar.tests=tests
sonar.exclusions=docker/**,contrib/**
sonar.python.version=3.9
sonar.sources=src/mangadlp
sonar.tests=tests
#sonar.exclusions=
sonar.python.coverage.reportPaths=coverage.xml

View file

@ -0,0 +1 @@
__version__ = "2.4.1"

7
src/mangadlp/__main__.py Normal file
View file

@ -0,0 +1,7 @@
import sys
import mangadlp.cli
if __name__ == "__main__":
sys.exit(mangadlp.cli.main())

View file

@ -6,7 +6,7 @@ import requests
from loguru import logger as log
from mangadlp import utils
from mangadlp.types import ChapterData, ComicInfo
from mangadlp.models import ChapterData, ComicInfo
class Mangadex:
@ -22,7 +22,7 @@ class Mangadex:
Attributes:
api_name (str): Name of the API
manga_uuid (str): UUID of the manga, without the url part
manga_data (dict): Infos of the manga. Name, title etc
manga_data (dict): Infos of the manga. Name, title etc.
manga_title (str): The title of the manga, sanitized for all file systems
manga_chapter_data (dict): All chapter data of the manga. Volumes, chapters, chapter uuids and chapter names
chapter_list (list): A list of all available chapters for the language
@ -57,9 +57,7 @@ class Mangadex:
# get the uuid for the manga
def get_manga_uuid(self) -> str:
# isolate id from url
uuid_regex = re.compile(
"[a-z0-9]{8}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{12}"
)
uuid_regex = re.compile("[a-z0-9]{8}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{12}")
# try to get uuid in string
try:
uuid = uuid_regex.search(self.url_uuid)[0] # type: ignore
@ -67,7 +65,7 @@ class Mangadex:
log.error("No valid UUID found")
raise exc
return uuid # pyright:ignore
return uuid
# make initial request
def get_manga_data(self) -> Dict[str, Any]:
@ -75,9 +73,7 @@ class Mangadex:
counter = 1
while counter <= 3:
try:
response = requests.get(
f"{self.api_base_url}/manga/{self.manga_uuid}", timeout=10
)
response = requests.get(f"{self.api_base_url}/manga/{self.manga_uuid}", timeout=10)
except Exception as exc:
if counter >= 3:
log.error("Maybe the MangaDex API is down?")
@ -88,9 +84,9 @@ class Mangadex:
else:
break
response_body: Dict[str, Dict[str, Any]] = response.json() # pyright:ignore
response_body: Dict[str, Dict[str, Any]] = response.json()
# check if manga exists
if response_body["result"] != "ok": # type:ignore
if response_body["result"] != "ok":
log.error("Manga not found")
raise KeyError
@ -102,32 +98,35 @@ class Mangadex:
attributes = self.manga_data["attributes"]
# try to get the title in requested language
try:
title = attributes["title"][self.language]
found_title = attributes["title"][self.language]
title = utils.fix_name(found_title)
except KeyError:
log.info("Manga title not found in requested language. Trying alt titles")
else:
log.debug(f"Language={self.language}, Title='{title}'")
return utils.fix_name(title)
return title # type: ignore
# search in alt titles
try:
log.debug(f"Alt titles: {attributes['altTitles']}")
for item in attributes["altTitles"]:
if item.get(self.language):
alt_title = item
alt_title_item = item
break
title = alt_title[self.language] # pyright:ignore
found_title = alt_title_item[self.language]
except (KeyError, UnboundLocalError):
log.warning(
"Manga title also not found in alt titles. Falling back to english title"
)
log.warning("Manga title also not found in alt titles. Falling back to english title")
else:
log.debug(f"Language={self.language}, Alt-title='{title}'")
return utils.fix_name(title)
title = utils.fix_name(found_title)
log.debug(f"Language={self.language}, Alt-title='{found_title}'")
return title # type: ignore
found_title = attributes["title"]["en"]
title = utils.fix_name(found_title)
title = attributes["title"]["en"]
log.debug(f"Language=en, Fallback-title='{title}'")
return utils.fix_name(title)
return title # type: ignore
# check if chapters are available in requested language
def check_chapter_lang(self) -> int:
@ -139,9 +138,7 @@ class Mangadex:
try:
total_chapters: int = r.json()["total"]
except Exception as exc:
log.error(
"Error retrieving the chapters list. Did you specify a valid language code?"
)
log.error("Error retrieving the chapters list. Did you specify a valid language code?")
raise exc
if total_chapters == 0:
log.error("No chapters available to download in specified language")
@ -157,7 +154,7 @@ class Mangadex:
# check for chapters in specified lang
total_chapters = self.check_chapter_lang()
chapter_data: dict[str, ChapterData] = {}
chapter_data: Dict[str, ChapterData] = {}
last_volume, last_chapter = ("", "")
offset = 0
while offset < total_chapters: # if more than 500 chapters
@ -190,9 +187,7 @@ class Mangadex:
continue
# export chapter data as a dict
chapter_index = (
chapter_num if not self.forcevol else f"{chapter_vol}:{chapter_num}"
)
chapter_index = chapter_num if not self.forcevol else f"{chapter_vol}:{chapter_num}"
chapter_data[chapter_index] = {
"uuid": chapter_uuid,
"volume": chapter_vol,
@ -243,8 +238,8 @@ class Mangadex:
if api_error:
return []
chapter_hash = api_data["chapter"]["hash"] # pyright:ignore
chapter_img_data = api_data["chapter"]["data"] # pyright:ignore
chapter_hash = api_data["chapter"]["hash"]
chapter_img_data = api_data["chapter"]["data"]
# get list of image urls
image_urls: List[str] = []

View file

@ -10,7 +10,7 @@ from mangadlp.api.mangadex import Mangadex
from mangadlp.cache import CacheDB
from mangadlp.hooks import run_hook
from mangadlp.metadata import write_metadata
from mangadlp.types import ChapterData
from mangadlp.models import ChapterData
from mangadlp.utils import get_file_format
@ -73,7 +73,7 @@ class MangaDLP:
add_metadata: Flag to toggle creation & inclusion of metadata
"""
def __init__( # pylint: disable=too-many-locals
def __init__( # noqa
self,
url_uuid: str,
language: str = "en",
@ -139,9 +139,7 @@ class MangaDLP:
# prechecks userinput/options
# no url and no readin list given
if not self.url_uuid:
log.error(
'You need to specify a manga url/uuid with "-u" or a list with "--read"'
)
log.error('You need to specify a manga url/uuid with "-u" or a list with "--read"')
raise ValueError
# checks if --list is not used
if not self.list_chapters:
@ -161,7 +159,7 @@ class MangaDLP:
raise ValueError
# once called per manga
def get_manga(self) -> None:
def get_manga(self) -> None: # noqa
print_divider = "========================================="
# show infos
log.info(f"{print_divider}")
@ -179,9 +177,7 @@ class MangaDLP:
if self.chapters.lower() == "all":
chapters_to_download = self.manga_chapter_list
else:
chapters_to_download = utils.get_chapter_list(
self.chapters, self.manga_chapter_list
)
chapters_to_download = utils.get_chapter_list(self.chapters, self.manga_chapter_list)
# show chapters to download
log.info(f"Chapters selected: {', '.join(chapters_to_download)}")
@ -192,9 +188,7 @@ class MangaDLP:
# prepare cache if specified
if self.cache_path:
cache = CacheDB(
self.cache_path, self.manga_uuid, self.language, self.manga_title
)
cache = CacheDB(self.cache_path, self.manga_uuid, self.language, self.manga_title)
cached_chapters = cache.db_uuid_chapters
log.info(f"Cached chapters: {cached_chapters}")
@ -224,10 +218,10 @@ class MangaDLP:
)
# get chapters
skipped_chapters: list[Any] = []
error_chapters: list[Any] = []
skipped_chapters: List[Any] = []
error_chapters: List[Any] = []
for chapter in chapters_to_download:
if self.cache_path and chapter in cached_chapters: # pyright:ignore
if self.cache_path and chapter in cached_chapters:
log.info(f"Chapter '{chapter}' is in cache. Skipping download")
continue
@ -241,7 +235,7 @@ class MangaDLP:
skipped_chapters.append(chapter)
# update cache
if self.cache_path:
cache.add_chapter(chapter) # pyright:ignore
cache.add_chapter(chapter)
continue
except Exception:
# skip download/packing due to an error
@ -257,9 +251,7 @@ class MangaDLP:
{"Format": self.file_format[1:], **metadata},
)
except Exception as exc:
log.warning(
f"Can't write metadata for chapter '{chapter}'. Reason={exc}"
)
log.warning(f"Can't write metadata for chapter '{chapter}'. Reason={exc}")
# pack downloaded folder
if self.file_format:
@ -274,7 +266,7 @@ class MangaDLP:
# update cache
if self.cache_path:
cache.add_chapter(chapter) # pyright:ignore
cache.add_chapter(chapter)
# start chapter post hook
run_hook(
@ -316,9 +308,7 @@ class MangaDLP:
# get image urls for chapter
try:
chapter_image_urls = self.api.get_chapter_images(
chapter, self.download_wait
)
chapter_image_urls = self.api.get_chapter_images(chapter, self.download_wait)
except KeyboardInterrupt as exc:
log.critical("Keyboard interrupt. Stopping")
raise exc
@ -407,9 +397,7 @@ class MangaDLP:
# download images
try:
downloader.download_chapter(
chapter_image_urls, chapter_path, self.download_wait
)
downloader.download_chapter(chapter_image_urls, chapter_path, self.download_wait)
except KeyboardInterrupt as exc:
log.critical("Keyboard interrupt. Stopping")
raise exc
@ -441,7 +429,7 @@ class MangaDLP:
# check if image folder is existing
if not chapter_path.exists():
log.error(f"Image folder: {chapter_path} does not exist")
raise IOError
raise OSError
if self.file_format == ".pdf":
utils.make_pdf(chapter_path)
else:

View file

@ -1,9 +1,11 @@
import json
from pathlib import Path
from typing import Dict, List, Union
from typing import List, Union
from loguru import logger as log
from mangadlp.models import CacheData, CacheKeyData
class CacheDB:
def __init__(
@ -26,14 +28,12 @@ class CacheDB:
if not self.db_data.get(self.db_key):
self.db_data[self.db_key] = {}
self.db_uuid_data = self.db_data[self.db_key]
self.db_uuid_data: CacheKeyData = self.db_data[self.db_key]
if not self.db_uuid_data.get("name"):
self.db_uuid_data.update({"name": self.name})
self._write_db()
self.db_uuid_chapters: List[str] = (
self.db_uuid_data.get("chapters") or [] # type:ignore
)
self.db_uuid_chapters: List[str] = self.db_uuid_data.get("chapters") or []
def _prepare_db(self) -> None:
if self.db_path.exists():
@ -46,11 +46,11 @@ class CacheDB:
log.error("Can't create db-file")
raise exc
def _read_db(self) -> Dict[str, Dict[str, Union[str, List[str]]]]:
def _read_db(self) -> CacheData:
log.info(f"Reading cache-db: {self.db_path}")
try:
db_txt = self.db_path.read_text(encoding="utf8")
db_dict: Dict[str, Dict[str, Union[str, List[str]]]] = json.loads(db_txt)
db_dict: CacheData = json.loads(db_txt)
except Exception as exc:
log.error("Can't load cache-db")
raise exc

View file

@ -26,7 +26,8 @@ def readin_list(_ctx: click.Context, _param: str, value: str) -> List[str]:
url_str = list_file.read_text(encoding="utf-8")
url_list = url_str.splitlines()
except Exception as exc:
raise click.BadParameter("Can't get links from the file") from exc
msg = f"Reading in file '{list_file}'"
raise click.BadParameter(msg) from exc
# filter empty lines and remove them
filtered_list = list(filter(len, url_list))
@ -39,8 +40,8 @@ def readin_list(_ctx: click.Context, _param: str, value: str) -> List[str]:
@click.help_option()
@click.version_option(version=__version__, package_name="manga-dlp")
# manga selection
@optgroup.group("source", cls=RequiredMutuallyExclusiveOptionGroup) # type: ignore
@optgroup.option( # type: ignore
@optgroup.group("source", cls=RequiredMutuallyExclusiveOptionGroup)
@optgroup.option(
"-u",
"--url",
"--uuid",
@ -50,7 +51,7 @@ def readin_list(_ctx: click.Context, _param: str, value: str) -> List[str]:
show_default=True,
help="URL or UUID of the manga",
)
@optgroup.option( # type: ignore
@optgroup.option(
"--read",
"read_mangas",
is_eager=True,
@ -61,8 +62,8 @@ def readin_list(_ctx: click.Context, _param: str, value: str) -> List[str]:
help="Path of file with manga links to download. One per line",
)
# logging options
@optgroup.group("verbosity", cls=MutuallyExclusiveOptionGroup) # type: ignore
@optgroup.option( # type: ignore
@optgroup.group("verbosity", cls=MutuallyExclusiveOptionGroup)
@optgroup.option(
"--loglevel",
"verbosity",
type=int,
@ -70,7 +71,7 @@ def readin_list(_ctx: click.Context, _param: str, value: str) -> List[str]:
show_default=True,
help="Custom log level",
)
@optgroup.option( # type: ignore
@optgroup.option(
"--warn",
"verbosity",
flag_value=30,
@ -78,7 +79,7 @@ def readin_list(_ctx: click.Context, _param: str, value: str) -> List[str]:
show_default=True,
help="Only log warnings and higher",
)
@optgroup.option( # type: ignore
@optgroup.option(
"--debug",
"verbosity",
flag_value=10,
@ -231,7 +232,7 @@ def readin_list(_ctx: click.Context, _param: str, value: str) -> List[str]:
def main(ctx: click.Context, **kwargs: Any) -> None:
"""Script to download mangas from various sites."""
url_uuid: str = kwargs.pop("url_uuid")
read_mangas: list[str] = kwargs.pop("read_mangas")
read_mangas: List[str] = kwargs.pop("read_mangas")
verbosity: int = kwargs.pop("verbosity")
# set log level to INFO if not set

View file

@ -48,11 +48,10 @@ def download_chapter(
# write image
try:
with image_path.open("wb") as file:
r.raw.decode_content = True # pyright:ignore
shutil.copyfileobj(r.raw, file) # pyright:ignore
r.raw.decode_content = True
shutil.copyfileobj(r.raw, file)
except Exception as exc:
log.error("Can't write file")
raise exc
image_num += 1
sleep(download_wait)

View file

@ -31,7 +31,7 @@ def run_hook(command: str, hook_type: str, **kwargs: Any) -> int:
# running command
log.info(f"Hook '{hook_type}' - running command: '{command}'")
proc = subprocess.run(command_list, check=False, timeout=15, encoding="utf8")
proc = subprocess.run(command_list, check=False, timeout=15, encoding="utf8") # noqa
exit_code = proc.returncode
if exit_code == 0:

View file

@ -4,6 +4,7 @@ from typing import Any, Dict
from loguru import logger
LOGURU_FMT = "{time:%Y-%m-%dT%H:%M:%S%z} | <level>[{level: <7}]</level> [{name: <10}] [{function: <20}]: {message}"
@ -20,26 +21,20 @@ class InterceptHandler(logging.Handler):
# Find caller from where originated the logged message
frame, depth = logging.currentframe(), 2
while frame.f_code.co_filename == logging.__file__: # pyright:ignore
while frame.f_code.co_filename == logging.__file__:
frame = frame.f_back # type: ignore
depth += 1
logger.opt(depth=depth, exception=record.exc_info).log(
level, record.getMessage()
)
logger.opt(depth=depth, exception=record.exc_info).log(level, record.getMessage())
# init logger with format and log level
def prepare_logger(loglevel: int = 20) -> None:
config: Dict[str, Any] = {
"handlers": [
{
"sink": sys.stdout,
"level": loglevel,
"format": LOGURU_FMT,
}
],
stdout_handler: Dict[str, Any] = {
"sink": sys.stdout,
"level": loglevel,
"format": LOGURU_FMT,
}
logging.basicConfig(handlers=[InterceptHandler()], level=loglevel)
logger.configure(**config)
logger.configure(handlers=[stdout_handler])

View file

@ -4,15 +4,14 @@ from typing import Any, Dict, List, Tuple, Union
import xmltodict
from loguru import logger as log
from mangadlp.types import ComicInfo
from mangadlp.models import ComicInfo
METADATA_FILENAME = "ComicInfo.xml"
METADATA_TEMPLATE = Path("mangadlp/metadata/ComicInfo_v2.0.xml")
# define metadata types, defaults and valid values. an empty list means no value check
# {key: (type, default value, valid values)}
METADATA_TYPES: Dict[
str, Tuple[Any, Union[str, int, None], List[Union[str, int, None]]]
] = {
METADATA_TYPES: Dict[str, Tuple[Any, Union[str, int, None], List[Union[str, int, None]]]] = {
"Title": (str, None, []),
"Series": (str, None, []),
"Number": (str, None, []),
@ -66,15 +65,13 @@ METADATA_TYPES: Dict[
def validate_metadata(metadata_in: ComicInfo) -> Dict[str, ComicInfo]:
log.info("Validating metadata")
metadata_valid: dict[str, ComicInfo] = {"ComicInfo": {}}
metadata_valid: Dict[str, ComicInfo] = {"ComicInfo": {}}
for key, value in METADATA_TYPES.items():
metadata_type, metadata_default, metadata_validation = value
# add default value if present
if metadata_default:
log.debug(
f"Setting default value for Key:{key} -> value={metadata_default}"
)
log.debug(f"Setting default value for Key:{key} -> value={metadata_default}")
metadata_valid["ComicInfo"][key] = metadata_default
# check if metadata key is available
@ -89,17 +86,13 @@ def validate_metadata(metadata_in: ComicInfo) -> Dict[str, ComicInfo]:
# check if metadata type is correct
log.debug(f"Key:{key} -> value={type(md_to_check)} -> check={metadata_type}")
if not isinstance(md_to_check, metadata_type):
log.warning(
f"Metadata has wrong type: {key}:{metadata_type} -> {md_to_check}"
)
log.warning(f"Metadata has wrong type: {key}:{metadata_type} -> {md_to_check}")
continue
# check if metadata is valid
log.debug(f"Key:{key} -> value={md_to_check} -> valid={metadata_validation}")
if (len(metadata_validation) > 0) and (md_to_check not in metadata_validation):
log.warning(
f"Metadata is invalid: {key}:{metadata_validation} -> {md_to_check}"
)
log.warning(f"Metadata is invalid: {key}:{metadata_validation} -> {md_to_check}")
continue
log.debug(f"Updating metadata: '{key}' = '{md_to_check}'")
@ -109,7 +102,7 @@ def validate_metadata(metadata_in: ComicInfo) -> Dict[str, ComicInfo]:
def write_metadata(chapter_path: Path, metadata: ComicInfo) -> None:
if metadata["Format"] == "pdf": # pyright:ignore
if metadata["Format"] == "pdf":
log.warning("Can't add metadata for pdf format. Skipping")
return

View file

@ -1,4 +1,4 @@
from typing import Optional, TypedDict
from typing import List, Optional, TypedDict
class ComicInfo(TypedDict, total=False):
@ -48,3 +48,12 @@ class ChapterData(TypedDict):
chapter: str
name: str
pages: int
class CacheKeyData(TypedDict):
chapters: List[str]
name: str
class CacheData(TypedDict):
__root__: CacheKeyData

View file

@ -4,6 +4,7 @@ from pathlib import Path
from typing import Any, List
from zipfile import ZipFile
import pytz
from loguru import logger as log
@ -24,17 +25,17 @@ def make_archive(chapter_path: Path, file_format: str) -> None:
def make_pdf(chapter_path: Path) -> None:
try:
import img2pdf # pylint: disable=import-outside-toplevel # pyright:ignore
import img2pdf # pylint: disable=import-outside-toplevel
except Exception as exc:
log.error("Cant import img2pdf. Please install it first")
raise exc
pdf_path = Path(f"{chapter_path}.pdf")
images: list[str] = []
images: List[str] = []
for file in chapter_path.iterdir():
images.append(str(file))
try:
pdf_path.write_bytes(img2pdf.convert(images)) # pyright:ignore
pdf_path.write_bytes(img2pdf.convert(images))
except Exception as exc:
log.error("Can't create '.pdf' archive")
raise exc
@ -43,13 +44,13 @@ def make_pdf(chapter_path: Path) -> None:
# create a list of chapters
def get_chapter_list(chapters: str, available_chapters: List[str]) -> List[str]:
# check if there are available chapter
chapter_list: list[str] = []
chapter_list: List[str] = []
for chapter in chapters.split(","):
# check if chapter list is with volumes and ranges (forcevol)
if "-" in chapter and ":" in chapter:
# split chapters and volumes apart for list generation
lower_num_fv: list[str] = chapter.split("-")[0].split(":")
upper_num_fv: list[str] = chapter.split("-")[1].split(":")
lower_num_fv: List[str] = chapter.split("-")[0].split(":")
upper_num_fv: List[str] = chapter.split("-")[1].split(":")
vol_fv: str = lower_num_fv[0]
chap_beg_fv: int = int(lower_num_fv[1])
chap_end_fv: int = int(upper_num_fv[1])
@ -70,7 +71,7 @@ def get_chapter_list(chapters: str, available_chapters: List[str]) -> List[str]:
# select all chapters from the volume --> 1: == 1:1,1:2,1:3...
if vol_num and not chap_num:
regex: Any = re.compile(f"{vol_num}:[0-9]{{1,4}}")
vol_list: list[str] = [n for n in available_chapters if regex.match(n)]
vol_list: List[str] = [n for n in available_chapters if regex.match(n)]
chapter_list.extend(vol_list)
else:
chapter_list.append(chapter)
@ -160,7 +161,7 @@ def get_file_format(file_format: str) -> str:
def progress_bar(progress: float, total: float) -> None:
time = datetime.now().strftime("%Y-%m-%dT%H:%M:%S")
time = datetime.now(tz=pytz.timezone("Europe/Zurich")).strftime("%Y-%m-%dT%H:%M:%S")
percent = int(progress / (int(total) / 100))
bar_length = 50
bar_progress = int(progress / (int(total) / bar_length))
@ -168,9 +169,9 @@ def progress_bar(progress: float, total: float) -> None:
whitespace_texture = " " * (bar_length - bar_progress)
if progress == total:
full_bar = "" * bar_length
print(f"\r{time}{' '*6}| [BAR ] ❙{full_bar}❙ 100%", end="\n")
print(f"\r{time}{' '*6}| [BAR ] ❙{full_bar}❙ 100%", end="\n") # noqa
else:
print(
print( # noqa
f"\r{time}{' '*6}| [BAR ] ❙{bar_texture}{whitespace_texture}{percent}%",
end="\r",
)

View file

@ -5,7 +5,9 @@ from mangadlp.app import MangaDLP
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 = MangaDLP(url_uuid=url, list_chapters=True, download_wait=2)
assert test.api_used == Mangadex

View file

@ -1,8 +1,10 @@
import shutil
from pathlib import Path
from typing import List
import pytest
import requests
from pytest import MonkeyPatch
from mangadlp import downloader
@ -17,7 +19,7 @@ def test_downloader():
]
chapter_path = Path("tests/test_folder1")
chapter_path.mkdir(parents=True, exist_ok=True)
images = []
images: List[str] = []
downloader.download_chapter(urls, str(chapter_path), 2)
for file in chapter_path.iterdir():
images.append(file.name)
@ -28,7 +30,7 @@ def test_downloader():
shutil.rmtree(chapter_path, ignore_errors=True)
def test_downloader_fail(monkeypatch):
def test_downloader_fail(monkeypatch: MonkeyPatch):
images = [
"https://uploads.mangadex.org/data/f1117c5e7aff315bc3429a8791c89d63/A1-c111d78b798f1dda1879334a3478f7ae4503578e8adf1af0fcc4e14d2a396ad4.png",
"https://uploads.mangadex.org/data/f1117c5e7aff315bc3429a8791c89d63/A2-717ec3c83e8e05ed7b505941431a417ebfed6a005f78b89650efd3b088b951ec.png",

View file

@ -20,7 +20,9 @@ def test_no_read_and_url():
chapters = "1"
file_format = "cbz"
download_path = "tests"
command_args = f"-l {language} -c {chapters} --path {download_path} --format {file_format} --debug"
command_args = (
f"-l {language} -c {chapters} --path {download_path} --format {file_format} --debug"
)
script_path = "manga-dlp.py"
assert os.system(f"python3 {script_path} {command_args}") != 0
@ -30,7 +32,9 @@ def test_no_chaps():
language = "en"
file_format = "cbz"
download_path = "tests"
command_args = f"-u {url_uuid} -l {language} --path {download_path} --format {file_format} --debug"
command_args = (
f"-u {url_uuid} -l {language} --path {download_path} --format {file_format} --debug"
)
script_path = "manga-dlp.py"
assert os.system(f"python3 {script_path} {command_args}") != 0

View file

@ -4,6 +4,7 @@ import time
from pathlib import Path
import pytest
from pytest import MonkeyPatch
@pytest.fixture
@ -18,7 +19,7 @@ def wait_20s():
time.sleep(20)
def test_manga_pre_hook(wait_10s):
def test_manga_pre_hook(wait_10s: MonkeyPatch):
url_uuid = "https://mangadex.org/title/0aea9f43-d4a9-4bf7-bebc-550a512f9b95/shikimori-s-not-just-a-cutie"
manga_path = Path("tests/Shikimori's Not Just a Cutie")
language = "en"
@ -50,7 +51,7 @@ def test_manga_pre_hook(wait_10s):
hook_file.unlink()
def test_manga_post_hook(wait_10s):
def test_manga_post_hook(wait_10s: MonkeyPatch):
url_uuid = "https://mangadex.org/title/0aea9f43-d4a9-4bf7-bebc-550a512f9b95/shikimori-s-not-just-a-cutie"
manga_path = Path("tests/Shikimori's Not Just a Cutie")
language = "en"
@ -82,7 +83,7 @@ def test_manga_post_hook(wait_10s):
hook_file.unlink()
def test_chapter_pre_hook(wait_10s):
def test_chapter_pre_hook(wait_10s: MonkeyPatch):
url_uuid = "https://mangadex.org/title/0aea9f43-d4a9-4bf7-bebc-550a512f9b95/shikimori-s-not-just-a-cutie"
manga_path = Path("tests/Shikimori's Not Just a Cutie")
language = "en"
@ -114,7 +115,7 @@ def test_chapter_pre_hook(wait_10s):
hook_file.unlink()
def test_chapter_post_hook(wait_10s):
def test_chapter_post_hook(wait_10s: MonkeyPatch):
url_uuid = "https://mangadex.org/title/0aea9f43-d4a9-4bf7-bebc-550a512f9b95/shikimori-s-not-just-a-cutie"
manga_path = Path("tests/Shikimori's Not Just a Cutie")
language = "en"
@ -146,7 +147,7 @@ def test_chapter_post_hook(wait_10s):
hook_file.unlink()
def test_all_hooks(wait_10s):
def test_all_hooks(wait_10s: MonkeyPatch):
url_uuid = "https://mangadex.org/title/0aea9f43-d4a9-4bf7-bebc-550a512f9b95/shikimori-s-not-just-a-cutie"
manga_path = Path("tests/Shikimori's Not Just a Cutie")
language = "en"

View file

@ -5,6 +5,7 @@ from pathlib import Path
import pytest
import xmlschema
from pytest import MonkeyPatch
from mangadlp.metadata import validate_metadata, write_metadata
@ -110,8 +111,10 @@ def test_metadata_validation_values2():
}
def test_metadata_chapter_validity(wait_20s):
url_uuid = "https://mangadex.org/title/76ee7069-23b4-493c-bc44-34ccbf3051a8/tomo-chan-wa-onna-no-ko"
def test_metadata_chapter_validity(wait_20s: MonkeyPatch):
url_uuid = (
"https://mangadex.org/title/76ee7069-23b4-493c-bc44-34ccbf3051a8/tomo-chan-wa-onna-no-ko"
)
manga_path = Path("tests/Tomo-chan wa Onna no ko")
metadata_path = manga_path / "Ch. 1 - Once In A Life Time Misfire/ComicInfo.xml"
language = "en"
@ -130,7 +133,7 @@ def test_metadata_chapter_validity(wait_20s):
"",
"--debug",
]
schema = xmlschema.XMLSchema("mangadlp/metadata/ComicInfo_v2.0.xsd")
schema = xmlschema.XMLSchema("src/mangadlp/metadata/ComicInfo_v2.0.xsd")
script_path = "manga-dlp.py"
command = ["python3", script_path, *command_args]

View file

@ -1,11 +1,14 @@
import pytest
import requests
from pytest import MonkeyPatch
from mangadlp.api.mangadex import Mangadex
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"
forcevol = False
test = Mangadex(url_uuid, language, forcevol)
@ -33,7 +36,9 @@ def test_uuid_link_false():
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"
forcevol = False
test = Mangadex(url_uuid, language, forcevol)
@ -51,7 +56,9 @@ def test_alt_title():
def test_alt_title_fallback():
url_uuid = "https://mangadex.org/title/d7037b2a-874a-4360-8a7b-07f2899152fd/mairimashita-iruma-kun"
url_uuid = (
"https://mangadex.org/title/d7037b2a-874a-4360-8a7b-07f2899152fd/mairimashita-iruma-kun"
)
language = "fr"
forcevol = False
test = Mangadex(url_uuid, language, forcevol)
@ -60,7 +67,9 @@ def test_alt_title_fallback():
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"
forcevol = False
test = Mangadex(url_uuid, language, forcevol)
@ -79,7 +88,9 @@ def test_chapter_infos():
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"
forcevol = False
@ -88,12 +99,12 @@ def test_non_existing_manga():
assert e.type == KeyError
def test_api_failure(monkeypatch):
fail_url = (
"https://api.mangadex.nonexistant/manga/a96676e5-8ae2-425e-b549-7f15dd34a6d8"
)
def test_api_failure(monkeypatch: MonkeyPatch):
fail_url = "https://api.mangadex.nonexistant/manga/a96676e5-8ae2-425e-b549-7f15dd34a6d8"
monkeypatch.setattr(requests, "get", fail_url)
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"
forcevol = False
@ -103,7 +114,9 @@ def test_api_failure(monkeypatch):
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"
forcevol = False
test = Mangadex(url_uuid, language, forcevol)
@ -112,7 +125,9 @@ def test_chapter_lang_en():
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"
forcevol = False
@ -122,7 +137,9 @@ def test_empty_chapter_lang():
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"
forcevol = False
@ -132,9 +149,7 @@ def test_not_existing_lang():
def test_create_chapter_list():
url_uuid = (
"https://mangadex.org/title/6fef1f74-a0ad-4f0d-99db-d32a7cd24098/fire-punch"
)
url_uuid = "https://mangadex.org/title/6fef1f74-a0ad-4f0d-99db-d32a7cd24098/fire-punch"
language = "en"
forcevol = False
test = Mangadex(url_uuid, language, forcevol)
@ -160,15 +175,76 @@ def test_create_chapter_list():
"19",
"20",
"21",
"22",
"23",
"24",
"25",
"26",
"27",
"28",
"29",
"30",
"31",
"32",
"33",
"34",
"34.5",
"35",
"36",
"37",
"38",
"39",
"40",
"41",
"42",
"43",
"44",
"45",
"46",
"47",
"48",
"49",
"50",
"51",
"52",
"53",
"54",
"55",
"56",
"57",
"58",
"59",
"60",
"61",
"62",
"63",
"64",
"65",
"66",
"67",
"68",
"69",
"70",
"71",
"72",
"73",
"74",
"75",
"76",
"77",
"78",
"79",
"80",
"81",
"82",
"83",
]
assert test.create_chapter_list() == test_list
def test_create_chapter_list_forcevol():
url_uuid = (
"https://mangadex.org/title/6fef1f74-a0ad-4f0d-99db-d32a7cd24098/fire-punch"
)
url_uuid = "https://mangadex.org/title/6fef1f74-a0ad-4f0d-99db-d32a7cd24098/fire-punch"
language = "en"
forcevol = True
test = Mangadex(url_uuid, language, forcevol)
@ -194,13 +270,78 @@ def test_create_chapter_list_forcevol():
"3:19",
"3:20",
"3:21",
"3:22",
"3:23",
"3:24",
"3:25",
"3:26",
"3:27",
"3:28",
"4:29",
"4:30",
"4:31",
"4:32",
"4:33",
"4:34",
"4:34.5",
"4:35",
"4:36",
"4:37",
"4:38",
"4:39",
"5:40",
"5:41",
"5:42",
"5:43",
"5:44",
"5:45",
"5:46",
"5:47",
"5:48",
"5:49",
"6:50",
"6:51",
"6:52",
"6:53",
"6:54",
"6:55",
"6:56",
"6:57",
"6:58",
"6:59",
"6:60",
"7:61",
"7:62",
"7:63",
"7:64",
"7:65",
"7:66",
"7:67",
"7:68",
"7:69",
"7:70",
"8:71",
"8:72",
"8:73",
"8:74",
"8:75",
"8:76",
"8:77",
"8:78",
"8:79",
"8:80",
"8:81",
"8:82",
"8:83",
]
assert test.create_chapter_list() == test_list
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"
forcevol = False
test = Mangadex(url_uuid, language, forcevol)
@ -226,11 +367,11 @@ def test_get_chapter_images():
assert test.get_chapter_images(chapter_num, 2) == test_list
def test_get_chapter_images_error(monkeypatch):
fail_url = (
"https://api.mangadex.org/at-home/server/e86ec2c4-c5e4-4710-bfaa-999999999999"
def test_get_chapter_images_error(monkeypatch: MonkeyPatch):
fail_url = "https://api.mangadex.org/at-home/server/e86ec2c4-c5e4-4710-bfaa-999999999999"
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"
forcevol = False
test = Mangadex(url_uuid, language, forcevol)
@ -241,7 +382,9 @@ def test_get_chapter_images_error(monkeypatch):
def test_chapter_metadata():
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"
forcevol = False
test = Mangadex(url_uuid, language, forcevol)

View file

@ -3,8 +3,10 @@ import platform
import shutil
import time
from pathlib import Path
from typing import List
import pytest
from pytest import MonkeyPatch
from mangadlp import app
@ -21,11 +23,9 @@ def wait_20s():
time.sleep(20)
def test_full_api_mangadex(wait_20s):
def test_full_api_mangadex(wait_20s: MonkeyPatch):
manga_path = Path("tests/Tomo-chan wa Onna no ko")
chapter_path = Path(
"tests/Tomo-chan wa Onna no ko/Ch. 1 - Once In A Life Time Misfire.cbz"
)
chapter_path = Path("tests/Tomo-chan wa Onna no ko/Ch. 1 - Once In A Life Time Misfire.cbz")
mdlp = app.MangaDLP(
url_uuid="https://mangadex.org/title/76ee7069-23b4-493c-bc44-34ccbf3051a8/tomo-chan-wa-onna-no-ko",
language="en",
@ -44,16 +44,16 @@ def test_full_api_mangadex(wait_20s):
shutil.rmtree(manga_path, ignore_errors=True)
def test_full_with_input_cbz(wait_20s):
url_uuid = "https://mangadex.org/title/76ee7069-23b4-493c-bc44-34ccbf3051a8/tomo-chan-wa-onna-no-ko"
def test_full_with_input_cbz(wait_20s: MonkeyPatch):
url_uuid = (
"https://mangadex.org/title/76ee7069-23b4-493c-bc44-34ccbf3051a8/tomo-chan-wa-onna-no-ko"
)
language = "en"
chapters = "1"
file_format = "cbz"
download_path = "tests"
manga_path = Path("tests/Tomo-chan wa Onna no ko")
chapter_path = Path(
"tests/Tomo-chan wa Onna no ko/Ch. 1 - Once In A Life Time Misfire.cbz"
)
chapter_path = Path("tests/Tomo-chan wa Onna no ko/Ch. 1 - Once In A Life Time Misfire.cbz")
command_args = f"-u {url_uuid} -l {language} -c {chapters} --path {download_path} --format {file_format} --debug --wait 2"
script_path = "manga-dlp.py"
os.system(f"python3 {script_path} {command_args}")
@ -64,16 +64,16 @@ def test_full_with_input_cbz(wait_20s):
shutil.rmtree(manga_path, ignore_errors=True)
def test_full_with_input_cbz_info(wait_20s):
url_uuid = "https://mangadex.org/title/76ee7069-23b4-493c-bc44-34ccbf3051a8/tomo-chan-wa-onna-no-ko"
def test_full_with_input_cbz_info(wait_20s: MonkeyPatch):
url_uuid = (
"https://mangadex.org/title/76ee7069-23b4-493c-bc44-34ccbf3051a8/tomo-chan-wa-onna-no-ko"
)
language = "en"
chapters = "1"
file_format = "cbz"
download_path = "tests"
manga_path = Path("tests/Tomo-chan wa Onna no ko")
chapter_path = Path(
"tests/Tomo-chan wa Onna no ko/Ch. 1 - Once In A Life Time Misfire.cbz"
)
chapter_path = Path("tests/Tomo-chan wa Onna no ko/Ch. 1 - Once In A Life Time Misfire.cbz")
command_args = f"-u {url_uuid} -l {language} -c {chapters} --path {download_path} --format {file_format} --wait 2"
script_path = "manga-dlp.py"
os.system(f"python3 {script_path} {command_args}")
@ -84,19 +84,17 @@ def test_full_with_input_cbz_info(wait_20s):
shutil.rmtree(manga_path, ignore_errors=True)
@pytest.mark.skipif(
platform.machine() != "x86_64", reason="pdf only supported on amd64"
)
def test_full_with_input_pdf(wait_20s):
url_uuid = "https://mangadex.org/title/76ee7069-23b4-493c-bc44-34ccbf3051a8/tomo-chan-wa-onna-no-ko"
@pytest.mark.skipif(platform.machine() != "x86_64", reason="pdf only supported on amd64")
def test_full_with_input_pdf(wait_20s: MonkeyPatch):
url_uuid = (
"https://mangadex.org/title/76ee7069-23b4-493c-bc44-34ccbf3051a8/tomo-chan-wa-onna-no-ko"
)
language = "en"
chapters = "1"
file_format = "pdf"
download_path = "tests"
manga_path = Path("tests/Tomo-chan wa Onna no ko")
chapter_path = Path(
"tests/Tomo-chan wa Onna no ko/Ch. 1 - Once In A Life Time Misfire.pdf"
)
chapter_path = Path("tests/Tomo-chan wa Onna no ko/Ch. 1 - Once In A Life Time Misfire.pdf")
command_args = f"-u {url_uuid} -l {language} -c {chapters} --path {download_path} --format {file_format} --debug --wait 2"
script_path = "manga-dlp.py"
os.system(f"python3 {script_path} {command_args}")
@ -107,16 +105,16 @@ def test_full_with_input_pdf(wait_20s):
shutil.rmtree(manga_path, ignore_errors=True)
def test_full_with_input_folder(wait_20s):
url_uuid = "https://mangadex.org/title/76ee7069-23b4-493c-bc44-34ccbf3051a8/tomo-chan-wa-onna-no-ko"
def test_full_with_input_folder(wait_20s: MonkeyPatch):
url_uuid = (
"https://mangadex.org/title/76ee7069-23b4-493c-bc44-34ccbf3051a8/tomo-chan-wa-onna-no-ko"
)
language = "en"
chapters = "1"
file_format = ""
download_path = "tests"
manga_path = Path("tests/Tomo-chan wa Onna no ko")
chapter_path = Path(
"tests/Tomo-chan wa Onna no ko/Ch. 1 - Once In A Life Time Misfire"
)
chapter_path = Path("tests/Tomo-chan wa Onna no ko/Ch. 1 - Once In A Life Time Misfire")
metadata_path = Path(
"tests/Tomo-chan wa Onna no ko/Ch. 1 - Once In A Life Time Misfire/ComicInfo.xml"
)
@ -131,16 +129,16 @@ def test_full_with_input_folder(wait_20s):
shutil.rmtree(manga_path, ignore_errors=True)
def test_full_with_input_skip_cbz(wait_10s):
url_uuid = "https://mangadex.org/title/76ee7069-23b4-493c-bc44-34ccbf3051a8/tomo-chan-wa-onna-no-ko"
def test_full_with_input_skip_cbz(wait_10s: MonkeyPatch):
url_uuid = (
"https://mangadex.org/title/76ee7069-23b4-493c-bc44-34ccbf3051a8/tomo-chan-wa-onna-no-ko"
)
language = "en"
chapters = "1"
file_format = "cbz"
download_path = "tests"
manga_path = Path("tests/Tomo-chan wa Onna no ko")
chapter_path = Path(
"tests/Tomo-chan wa Onna no ko/Ch. 1 - Once In A Life Time Misfire.cbz"
)
chapter_path = Path("tests/Tomo-chan wa Onna no ko/Ch. 1 - Once In A Life Time Misfire.cbz")
command_args = f"-u {url_uuid} -l {language} -c {chapters} --path {download_path} --format {file_format} --debug --wait 2"
script_path = "manga-dlp.py"
manga_path.mkdir(parents=True, exist_ok=True)
@ -153,22 +151,22 @@ def test_full_with_input_skip_cbz(wait_10s):
shutil.rmtree(manga_path, ignore_errors=True)
def test_full_with_input_skip_folder(wait_10s):
url_uuid = "https://mangadex.org/title/76ee7069-23b4-493c-bc44-34ccbf3051a8/tomo-chan-wa-onna-no-ko"
def test_full_with_input_skip_folder(wait_10s: MonkeyPatch):
url_uuid = (
"https://mangadex.org/title/76ee7069-23b4-493c-bc44-34ccbf3051a8/tomo-chan-wa-onna-no-ko"
)
language = "en"
chapters = "1"
file_format = ""
download_path = "tests"
manga_path = Path("tests/Tomo-chan wa Onna no ko")
chapter_path = Path(
"tests/Tomo-chan wa Onna no ko/Ch. 1 - Once In A Life Time Misfire"
)
chapter_path = Path("tests/Tomo-chan wa Onna no ko/Ch. 1 - Once In A Life Time Misfire")
command_args = f"-u {url_uuid} -l {language} -c {chapters} --path {download_path} --format '{file_format}' --debug --wait 2"
script_path = "manga-dlp.py"
chapter_path.mkdir(parents=True, exist_ok=True)
os.system(f"python3 {script_path} {command_args}")
found_files = []
found_files: List[str] = []
for file in chapter_path.iterdir():
found_files.append(file.name)
@ -184,17 +182,15 @@ def test_full_with_input_skip_folder(wait_10s):
shutil.rmtree(manga_path, ignore_errors=True)
def test_full_with_read_cbz(wait_20s):
def test_full_with_read_cbz(wait_20s: MonkeyPatch):
url_list = Path("tests/test_list2.txt")
language = "en"
chapters = "1"
file_format = "cbz"
download_path = "tests"
manga_path = Path("tests/Tomo-chan wa Onna no ko")
chapter_path = Path(
"tests/Tomo-chan wa Onna no ko/Ch. 1 - Once In A Life Time Misfire.cbz"
)
command_args = f"--read {str(url_list)} -l {language} -c {chapters} --path {download_path} --format {file_format} --debug --wait 2"
chapter_path = Path("tests/Tomo-chan wa Onna no ko/Ch. 1 - Once In A Life Time Misfire.cbz")
command_args = f"--read {url_list!s} -l {language} -c {chapters} --path {download_path} --format {file_format} --debug --wait 2"
script_path = "manga-dlp.py"
url_list.write_text(
"https://mangadex.org/title/76ee7069-23b4-493c-bc44-34ccbf3051a8/tomo-chan-wa-onna-no-ko"
@ -208,17 +204,15 @@ def test_full_with_read_cbz(wait_20s):
shutil.rmtree(manga_path, ignore_errors=True)
def test_full_with_read_skip_cbz(wait_10s):
def test_full_with_read_skip_cbz(wait_10s: MonkeyPatch):
url_list = Path("tests/test_list2.txt")
language = "en"
chapters = "1"
file_format = "cbz"
download_path = "tests"
manga_path = Path("tests/Tomo-chan wa Onna no ko")
chapter_path = Path(
"tests/Tomo-chan wa Onna no ko/Ch. 1 - Once In A Life Time Misfire.cbz"
)
command_args = f"--read {str(url_list)} -l {language} -c {chapters} --path {download_path} --format {file_format} --debug --wait 2"
chapter_path = Path("tests/Tomo-chan wa Onna no ko/Ch. 1 - Once In A Life Time Misfire.cbz")
command_args = f"--read {url_list!s} -l {language} -c {chapters} --path {download_path} --format {file_format} --debug --wait 2"
script_path = "manga-dlp.py"
manga_path.mkdir(parents=True, exist_ok=True)
chapter_path.touch()

View file

@ -4,6 +4,7 @@ import time
from pathlib import Path
import pytest
from pytest import MonkeyPatch
@pytest.fixture
@ -18,7 +19,7 @@ def wait_20s():
time.sleep(20)
def test_full_with_all_flags(wait_20s):
def test_full_with_all_flags(wait_20s: MonkeyPatch):
manga_path = Path("tests/Tomo-chan wa Onna no ko")
chapter_path = manga_path / "Ch. 1 - Once In A Life Time Misfire.cbz"
cache_path = Path("tests/test_cache.json")

26
tox.ini
View file

@ -1,26 +0,0 @@
[tox]
envlist = py38, py39, py310
isolated_build = True
[testenv]
deps =
-rcontrib/requirements_dev.txt
commands =
pytest --verbose --exitfirst --basetemp="{envtmpdir}" {posargs}
[testenv:basic]
deps =
-rcontrib/requirements_dev.txt
commands =
pytest --verbose --exitfirst --basetemp="{envtmpdir}" {posargs}
[testenv:coverage]
deps =
-rcontrib/requirements_dev.txt
commands =
coverage erase
coverage run
coverage xml -i