Compare commits
28 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bead1b2291 | ||
| 36aeba08ec | |||
|
86e7d9fe57
|
|||
|
|
423277cc7a | ||
| 26b694999f | |||
|
c07d0ee919
|
|||
|
|
e16caa6473 | ||
|
382aac8d51
|
|||
| 1c9cf2065d | |||
|
bb3b922325
|
|||
|
674e9f9fd5
|
|||
|
|
f67ebededd | ||
| 79846dfed5 | |||
|
1f306cce53
|
|||
|
|
9b20484753 | ||
| e5ede589e7 | |||
| c7089edfdc | |||
|
1ed1403c43
|
|||
|
40d6e8824e
|
|||
|
|
d4ef36a54b | ||
| 8a0b73c60d | |||
|
c9d6d5de8f
|
|||
|
|
8d8e7549f6 | ||
| 5f09116071 | |||
|
26ef555765
|
|||
|
|
ea68370451 | ||
| 2343d66fe2 | |||
|
302599bb80
|
@@ -1,24 +0,0 @@
|
|||||||
[tool.bumpversion]
|
|
||||||
current_version = "0.1.7"
|
|
||||||
parse = "(?P<major>\\d+)\\.(?P<minor>\\d+)\\.(?P<patch>\\d+)"
|
|
||||||
serialize = ["{major}.{minor}.{patch}"]
|
|
||||||
search = "{current_version}"
|
|
||||||
replace = "{new_version}"
|
|
||||||
regex = false
|
|
||||||
ignore_missing_version = false
|
|
||||||
ignore_missing_files = false
|
|
||||||
tag = true
|
|
||||||
sign_tags = false
|
|
||||||
tag_name = "v{new_version}"
|
|
||||||
tag_message = "Bump version: {current_version} → {new_version}"
|
|
||||||
allow_dirty = false
|
|
||||||
commit = true
|
|
||||||
message = "Bump version: {current_version} → {new_version}"
|
|
||||||
moveable_tags = []
|
|
||||||
commit_args = ""
|
|
||||||
setup_hooks = []
|
|
||||||
pre_commit_hooks = []
|
|
||||||
post_commit_hooks = []
|
|
||||||
|
|
||||||
[[tool.bumpversion.files]]
|
|
||||||
filename = "pyproject.toml"
|
|
||||||
103
.gitea/changelog-config.json
Normal file
103
.gitea/changelog-config.json
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
{
|
||||||
|
"categories": [
|
||||||
|
{
|
||||||
|
"title": "## 🚀 Features",
|
||||||
|
"labels": [
|
||||||
|
"add",
|
||||||
|
"Add",
|
||||||
|
"Kind/Feature",
|
||||||
|
"feat",
|
||||||
|
"Feature",
|
||||||
|
"Feat"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "## 🧰 Enhancements",
|
||||||
|
"labels": [
|
||||||
|
"enhancement",
|
||||||
|
"Enhancement",
|
||||||
|
"Kind/Enhancement",
|
||||||
|
"improvement",
|
||||||
|
"Improvement",
|
||||||
|
"Kind/Improvement"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "## 🐛 Fixes",
|
||||||
|
"labels": [
|
||||||
|
"fix",
|
||||||
|
"Fix",
|
||||||
|
"Kind/Bug",
|
||||||
|
"Kind/Security"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "## 🧪 Upgrade",
|
||||||
|
"labels": ["upgrade","Upgrade","Clean"]
|
||||||
|
}
|
||||||
|
,
|
||||||
|
{
|
||||||
|
"title": "## 📝 Documentation",
|
||||||
|
"labels": ["docs","Docs", "Kind/Documentation"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "## 🛠️ Maintenance",
|
||||||
|
"labels": [
|
||||||
|
"maintenance",
|
||||||
|
"Maintenance",
|
||||||
|
"Kind/Maintenance",
|
||||||
|
"chore",
|
||||||
|
"Chore",
|
||||||
|
"Kind/Chore"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "## ⏪ Reverts",
|
||||||
|
"labels": [
|
||||||
|
"revert",
|
||||||
|
"Revert",
|
||||||
|
"Kind/Revert",
|
||||||
|
"Kind/Reverts",
|
||||||
|
"reverts",
|
||||||
|
"Reverts"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "## 🗑️ Deprecation",
|
||||||
|
"labels": ["deprecation","Deprecation", "Kind/Deprecation"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "## ⚡️ Performance Improvements",
|
||||||
|
"labels": [
|
||||||
|
"perf",
|
||||||
|
"Perf",
|
||||||
|
"Kind/Performance"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "## 🎨 Styling",
|
||||||
|
"labels": [
|
||||||
|
"style",
|
||||||
|
"Style",
|
||||||
|
"Kind/Style"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "## 🎯 Other Changes",
|
||||||
|
"labels": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"label_extractor": [
|
||||||
|
{
|
||||||
|
"pattern": "(\\w+) (.+)",
|
||||||
|
"target": "$1",
|
||||||
|
"on_property": "title"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"sort": "ASC",
|
||||||
|
"template": "${{CHANGELOG}}",
|
||||||
|
"pr_template": "- ${{TITLE}}\n - PR: #${{NUMBER}}",
|
||||||
|
"empty_template": "- no changes",
|
||||||
|
"max_pull_requests": 1000,
|
||||||
|
"max_back_track_time_days": 1000
|
||||||
|
}
|
||||||
@@ -1,10 +1,6 @@
|
|||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
inputs:
|
inputs:
|
||||||
release_notes:
|
|
||||||
description: Release notes (use \n for newlines)
|
|
||||||
type: string
|
|
||||||
required: false
|
|
||||||
github_release:
|
github_release:
|
||||||
description: 'Create Gitea Release'
|
description: 'Create Gitea Release'
|
||||||
default: true
|
default: true
|
||||||
@@ -29,6 +25,8 @@ jobs:
|
|||||||
uses: astral-sh/setup-uv@v5
|
uses: astral-sh/setup-uv@v5
|
||||||
- name: Set up Python
|
- name: Set up Python
|
||||||
run: uv python install
|
run: uv python install
|
||||||
|
with:
|
||||||
|
python-version-file: "pyproject.toml"
|
||||||
- name: Set Git identity
|
- name: Set Git identity
|
||||||
run: |
|
run: |
|
||||||
git config user.name "Gitea CI"
|
git config user.name "Gitea CI"
|
||||||
@@ -48,37 +46,31 @@ jobs:
|
|||||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
branch: ${{ github.ref }}
|
branch: ${{ github.ref }}
|
||||||
|
|
||||||
- name: Add release notes to environment
|
- name: Build Changelog
|
||||||
id: add_release_notes
|
id: build_changelog
|
||||||
run: |
|
uses: https://github.com/mikepenz/release-changelog-builder-action@v5
|
||||||
echo "RELEASE_NOTES<<EOF" >> $GITHUB_ENV
|
with:
|
||||||
echo "${{ github.event.inputs.release_notes }}" >> $GITHUB_ENV
|
platform: "gitea"
|
||||||
echo "EOF" >> $GITHUB_ENV
|
baseURL: "http://192.168.178.110:3000"
|
||||||
|
configuration: ".gitea/changelog-config.json"
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITEA_TOKEN }}
|
||||||
- name: Build package
|
- name: Build package
|
||||||
run: uv build
|
run: uv build
|
||||||
- name: Publish package
|
- name: Publish package
|
||||||
env:
|
env:
|
||||||
USERNAME: ${{ github.repository_owner }}
|
USERNAME: ${{ github.repository_owner }}
|
||||||
run: uv publish --publish-url https://git.theprivateserver.de/api/packages/$USERNAME/pypi/ -t ${{ secrets.TOKEN }}
|
run: uv publish --publish-url https://git.theprivateserver.de/api/packages/$USERNAME/pypi/ -t ${{ secrets.TOKEN }}
|
||||||
- name: Generate changelog
|
|
||||||
id: changelog
|
|
||||||
uses: metcalfc/changelog-generator@v4.6.2
|
|
||||||
with:
|
|
||||||
token: ${{ secrets.TOKEN }}
|
|
||||||
- name: Get the changelog
|
|
||||||
run: |
|
|
||||||
cat << "EOF"
|
|
||||||
${{ steps.changelog.outputs.changelog }}
|
|
||||||
EOF
|
|
||||||
|
|
||||||
- name: Create release
|
- name: Create release
|
||||||
id: create_release
|
id: create_release
|
||||||
if: ${{ github.event.inputs.github_release == 'true' }}
|
if: ${{ github.event.inputs.github_release == 'true' }}
|
||||||
uses: softprops/action-gh-release@master
|
uses: softprops/action-gh-release@master
|
||||||
with:
|
with:
|
||||||
tag_name: ${{ env.VERSION }}
|
tag_name: v${{ env.VERSION }}
|
||||||
release_name: Release ${{ env.VERSION }}
|
release_name: Release ${{ env.VERSION }}
|
||||||
body: ${{ steps.changelog.outputs.changelog }}
|
body: ${{steps.build_changelog.outputs.changelog}}
|
||||||
draft: false
|
draft: false
|
||||||
prerelease: false
|
prerelease: false
|
||||||
make_latest: true
|
make_latest: true
|
||||||
|
|||||||
7
.vscode/settings.json
vendored
Normal file
7
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"python.testing.pytestArgs": [
|
||||||
|
"tests"
|
||||||
|
],
|
||||||
|
"python.testing.unittestEnabled": false,
|
||||||
|
"python.testing.pytestEnabled": true
|
||||||
|
}
|
||||||
9
main.py
Normal file
9
main.py
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
from src.komconfig import KomConfig
|
||||||
|
|
||||||
|
|
||||||
|
def test_komconfig():
|
||||||
|
print(KomConfig().general.log_file)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
test_komconfig()
|
||||||
@@ -1,15 +1,46 @@
|
|||||||
[project]
|
[project]
|
||||||
name = "komconfig"
|
name = "komconfig"
|
||||||
version = "0.1.7"
|
version = "0.2.5"
|
||||||
description = "A small library providing a config class that provides settings data for the KomSuite"
|
description = "A small library providing a config class that provides settings data for the KomSuite"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
authors = [{ name = "WorldTeacher", email = "coding_contact@pm.me" }]
|
authors = [{ name = "WorldTeacher", email = "coding_contact@pm.me" }]
|
||||||
requires-python = ">=3.13"
|
requires-python = ">=3.13"
|
||||||
dependencies = ["omegaconf>=2.3.0"]
|
dependencies = [
|
||||||
|
"appdirs>=1.4.4",
|
||||||
|
"omegaconf>=2.3.0",
|
||||||
|
]
|
||||||
|
|
||||||
[build-system]
|
[build-system]
|
||||||
requires = ["hatchling"]
|
requires = ["hatchling"]
|
||||||
build-backend = "hatchling.build"
|
build-backend = "hatchling.build"
|
||||||
|
|
||||||
[dependency-groups]
|
[dependency-groups]
|
||||||
test = ["pytest>=8.3.4"]
|
dev = [
|
||||||
|
"pip>=25.1.1",
|
||||||
|
]
|
||||||
|
test = [
|
||||||
|
"pytest>=8.3.4",
|
||||||
|
"pytest-cov>=6.1.1",
|
||||||
|
]
|
||||||
|
|
||||||
|
[tool.bumpversion]
|
||||||
|
current_version = "0.2.5"
|
||||||
|
parse = "(?P<major>\\d+)\\.(?P<minor>\\d+)\\.(?P<patch>\\d+)"
|
||||||
|
serialize = ["{major}.{minor}.{patch}"]
|
||||||
|
search = "{current_version}"
|
||||||
|
replace = "{new_version}"
|
||||||
|
regex = false
|
||||||
|
ignore_missing_version = false
|
||||||
|
ignore_missing_files = false
|
||||||
|
tag = true
|
||||||
|
sign_tags = false
|
||||||
|
tag_name = "v{new_version}"
|
||||||
|
tag_message = "Bump version: {current_version} → {new_version}"
|
||||||
|
allow_dirty = true
|
||||||
|
commit = true
|
||||||
|
message = "Bump version: {current_version} → {new_version}"
|
||||||
|
moveable_tags = []
|
||||||
|
commit_args = ""
|
||||||
|
setup_hooks = []
|
||||||
|
pre_commit_hooks = []
|
||||||
|
post_commit_hooks = []
|
||||||
|
|||||||
@@ -1,2 +1,38 @@
|
|||||||
CONFIG_PATH = "~/.config/KomSuite/"
|
__all__ = ["KomConfig", "app"]
|
||||||
|
|
||||||
|
from appdirs import AppDirs
|
||||||
|
|
||||||
|
app = AppDirs("KomSuite", "KomConfig")
|
||||||
|
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
|
||||||
from .config import Settings as KomConfig
|
from .config import Settings as KomConfig
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
parser = argparse.ArgumentParser(description="Retrieve configuration values.")
|
||||||
|
parser.add_argument("key", type=str, help="The configuration key to retrieve.")
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
config = KomConfig()
|
||||||
|
|
||||||
|
try:
|
||||||
|
config_dict = config.dict()
|
||||||
|
if isinstance(config_dict, dict):
|
||||||
|
value = config_dict.get(args.key, None)
|
||||||
|
if value is None:
|
||||||
|
print(f"Key '{args.key}' not found in the configuration.")
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
print(str(value))
|
||||||
|
except Exception:
|
||||||
|
print(repr(value))
|
||||||
|
else:
|
||||||
|
print("Configuration data is not in dictionary format.")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error retrieving key '{args.key}': {e}")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
|
|||||||
30
src/komconfig/__main__.py
Normal file
30
src/komconfig/__main__.py
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
import argparse
|
||||||
|
from src.komconfig import KomConfig
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
parser = argparse.ArgumentParser(description="Retrieve configuration values.")
|
||||||
|
parser.add_argument("key", type=str, help="The configuration key to retrieve.")
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
config = KomConfig()
|
||||||
|
|
||||||
|
try:
|
||||||
|
config_dict = config.dict()
|
||||||
|
if isinstance(config_dict, dict):
|
||||||
|
value = config_dict.get(args.key, None)
|
||||||
|
if value is None:
|
||||||
|
print(f"Key '{args.key}' not found in the configuration.")
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
print(str(value))
|
||||||
|
except Exception:
|
||||||
|
print(repr(value))
|
||||||
|
else:
|
||||||
|
print("Configuration data is not in dictionary format.")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error retrieving key '{args.key}': {e}")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
@@ -1,11 +1,69 @@
|
|||||||
from dataclasses import dataclass
|
|
||||||
from typing import List, Optional
|
|
||||||
import os
|
import os
|
||||||
from omegaconf import OmegaConf, DictConfig
|
from dataclasses import dataclass
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from komconfig import CONFIG_PATH
|
from typing import List, Optional, Union
|
||||||
|
from urllib.parse import quote_plus
|
||||||
|
|
||||||
SETTINGS_PATH = os.path.join(CONFIG_PATH, "config.yaml")
|
from omegaconf import DictConfig, OmegaConf
|
||||||
|
|
||||||
|
from komconfig import app
|
||||||
|
|
||||||
|
SETTINGS_PATH = os.path.join(app.user_config_dir, "config.yaml")
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class RemoteSettings:
|
||||||
|
url: str
|
||||||
|
port: int
|
||||||
|
user: str
|
||||||
|
password: str
|
||||||
|
database_name: str = "komcache"
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Cache:
|
||||||
|
mode: str
|
||||||
|
remote: dict[str, Union[str, int]] | RemoteSettings
|
||||||
|
local_path: str | Path
|
||||||
|
|
||||||
|
def __post__init__(self):
|
||||||
|
if self.mode == "remote":
|
||||||
|
self.remote = RemoteSettings(**self.remote)
|
||||||
|
else:
|
||||||
|
self.remote = None
|
||||||
|
self.local_path = Path(self.local_path).expanduser()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def path(self):
|
||||||
|
if self.mode == "local":
|
||||||
|
return Path(self.local_path).expanduser()
|
||||||
|
else:
|
||||||
|
return f"{self.remote.url}:{self.remote.port}"
|
||||||
|
|
||||||
|
@property
|
||||||
|
def url(self):
|
||||||
|
password = quote_plus(self.remote.password) if self.remote else ""
|
||||||
|
return f"mysql+pymysql://{self.remote.user}:{password}@{self.remote.url}:{self.remote.port}/{self.remote.database_name}"
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Library:
|
||||||
|
"""Komga library settings."""
|
||||||
|
|
||||||
|
id: Optional[str] = None
|
||||||
|
name: Optional[str] = None
|
||||||
|
type: Optional[str] = None
|
||||||
|
media_path: Optional[str] = None
|
||||||
|
valid_extensions: Optional[List[str]] = None
|
||||||
|
|
||||||
|
def from_ddict(self, d: dict):
|
||||||
|
keys = d.keys()
|
||||||
|
for key in keys:
|
||||||
|
self.name = key
|
||||||
|
data = d[self.name]
|
||||||
|
for key, value in data.items():
|
||||||
|
setattr(self, key, value)
|
||||||
|
return self
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
@@ -15,9 +73,9 @@ class Komga:
|
|||||||
url: str
|
url: str
|
||||||
user: str
|
user: str
|
||||||
password: str
|
password: str
|
||||||
media_path: str
|
media_path: Path
|
||||||
api_key: str = None
|
api_key: str = None
|
||||||
libraries: dict[str, str] = None
|
libraries: List[Library] = None
|
||||||
|
|
||||||
def getattr(self, name):
|
def getattr(self, name):
|
||||||
return getattr(self, name)
|
return getattr(self, name)
|
||||||
@@ -27,7 +85,24 @@ class Komga:
|
|||||||
|
|
||||||
def __post_init__(self):
|
def __post_init__(self):
|
||||||
if "~" in self.media_path:
|
if "~" in self.media_path:
|
||||||
self.media_path = os.path.expanduser(self.media_path)
|
self.media_path = Path(os.path.expanduser(self.media_path))
|
||||||
|
if self.libraries:
|
||||||
|
self.libraries = [Library().from_ddict(lib) for lib in self.libraries]
|
||||||
|
|
||||||
|
def getLibraryByName(self, name: str) -> Optional[Library]:
|
||||||
|
"""Get a library by its name.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
name (str): The name of the library.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Optional[Library]: The library object if found, None otherwise.
|
||||||
|
"""
|
||||||
|
if self.libraries:
|
||||||
|
for lib in self.libraries:
|
||||||
|
if lib.name == name:
|
||||||
|
return lib
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
@@ -61,6 +136,23 @@ class Aria2:
|
|||||||
setattr(self, name, value)
|
setattr(self, name, value)
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class QbitTorrent:
|
||||||
|
"""QbitTorrent settings."""
|
||||||
|
|
||||||
|
host: str
|
||||||
|
port: int
|
||||||
|
username: str
|
||||||
|
password: str
|
||||||
|
category: str
|
||||||
|
|
||||||
|
def getattr(self, name):
|
||||||
|
return getattr(self, name)
|
||||||
|
|
||||||
|
def _setattr(self, name, value):
|
||||||
|
setattr(self, name, value)
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class EbookSettings:
|
class EbookSettings:
|
||||||
min_filesize: int
|
min_filesize: int
|
||||||
@@ -133,22 +225,35 @@ class KomGrabber:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
download_location: Path
|
download_location: Path
|
||||||
|
tag_location: Path
|
||||||
|
copy_location: Optional[Path]
|
||||||
|
copy_files: Optional[List[str]]
|
||||||
|
copy: bool
|
||||||
|
|
||||||
get_chapters: bool
|
get_chapters: bool
|
||||||
skip_parameters: List[str]
|
skip_parameters: List[str]
|
||||||
aria2: Aria2
|
|
||||||
tag_interactive: bool
|
tag_interactive: bool
|
||||||
ebook: EbookSettings
|
ebook: EbookSettings
|
||||||
manga: ComicSettings
|
manga: ComicSettings
|
||||||
check_interval: int
|
check_interval: int
|
||||||
use_cache: bool
|
use_cache: bool
|
||||||
cache_check_interval: int
|
cache_check_interval: int
|
||||||
|
downloader: str
|
||||||
|
downloader_settings: Union[Aria2, QbitTorrent]
|
||||||
|
|
||||||
def __post_init__(self):
|
def __post_init__(self):
|
||||||
self.skip_parameters = [param.lower() for param in self.skip_parameters]
|
self.skip_parameters = [param.lower() for param in self.skip_parameters]
|
||||||
if "~" in self.download_location:
|
# if "~" in self.download_location:
|
||||||
self.download_location = os.path.expanduser(self.download_location)
|
# self.download_location = os.path.expanduser(self.download_location)
|
||||||
if isinstance(self.download_location, str):
|
if isinstance(self.download_location, str):
|
||||||
self.download_location = Path(self.download_location)
|
self.download_location = Path(self.download_location).expanduser()
|
||||||
|
if isinstance(self.tag_location, str):
|
||||||
|
self.tag_location = Path(self.tag_location).expanduser()
|
||||||
|
if isinstance(self.downloader_settings, dict):
|
||||||
|
if self.downloader == "aria2":
|
||||||
|
self.downloader_settings = Aria2(**self.downloader_settings)
|
||||||
|
elif self.downloader == "qbit":
|
||||||
|
self.downloader_settings = QbitTorrent(**self.downloader_settings)
|
||||||
|
|
||||||
def getattr(self, name):
|
def getattr(self, name):
|
||||||
return getattr(self, name)
|
return getattr(self, name)
|
||||||
@@ -161,9 +266,9 @@ class KomGrabber:
|
|||||||
class KomTagger:
|
class KomTagger:
|
||||||
"""KomTagger settings."""
|
"""KomTagger settings."""
|
||||||
|
|
||||||
failed_location: str
|
|
||||||
success_location: str
|
|
||||||
sanitize_description: bool
|
sanitize_description: bool
|
||||||
|
check_cache: bool
|
||||||
|
check_interval: int
|
||||||
|
|
||||||
def getattr(self, name):
|
def getattr(self, name):
|
||||||
return getattr(self, name)
|
return getattr(self, name)
|
||||||
@@ -172,18 +277,15 @@ class KomTagger:
|
|||||||
setattr(self, name, value)
|
setattr(self, name, value)
|
||||||
|
|
||||||
def __post_init__(self):
|
def __post_init__(self):
|
||||||
if "~" in self.failed_location:
|
pass
|
||||||
self.failed_location = os.path.expanduser(self.failed_location)
|
|
||||||
if "~" in self.success_location:
|
|
||||||
self.success_location = os.path.expanduser(self.success_location)
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class ComicVine:
|
class ComicVine:
|
||||||
"""ComicVine settings."""
|
"""ComicVine settings."""
|
||||||
|
|
||||||
api_key: str
|
|
||||||
url: str
|
url: str
|
||||||
|
api_key: str
|
||||||
|
|
||||||
def getattr(self, name):
|
def getattr(self, name):
|
||||||
return getattr(self, name)
|
return getattr(self, name)
|
||||||
@@ -232,17 +334,11 @@ class API:
|
|||||||
mangadex: MangaDex
|
mangadex: MangaDex
|
||||||
comicsorg: ComicsOrg
|
comicsorg: ComicsOrg
|
||||||
|
|
||||||
@property
|
def __post_init__(self):
|
||||||
def comicvine(self):
|
# Convert dictionaries to their respective dataclass objects
|
||||||
return self.comicvine
|
self.comicvine = ComicVine(**self.comicvine)
|
||||||
|
self.mangadex = MangaDex(**self.mangadex)
|
||||||
@property
|
self.comicsorg = ComicsOrg(**self.comicsorg)
|
||||||
def mangadex(self):
|
|
||||||
return self.mangadex
|
|
||||||
|
|
||||||
@property
|
|
||||||
def comicsorg(self):
|
|
||||||
return self.comicsorg
|
|
||||||
|
|
||||||
def getattr(self, name):
|
def getattr(self, name):
|
||||||
return getattr(self, name)
|
return getattr(self, name)
|
||||||
@@ -329,6 +425,10 @@ class Settings:
|
|||||||
def komtagger(self):
|
def komtagger(self):
|
||||||
return KomTagger(**self._config.komtagger)
|
return KomTagger(**self._config.komtagger)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def cache(self):
|
||||||
|
return Cache(**self._config.cache)
|
||||||
|
|
||||||
def komtagger_attr(self, name):
|
def komtagger_attr(self, name):
|
||||||
return getattr(self.komtagger, name)
|
return getattr(self.komtagger, name)
|
||||||
|
|
||||||
|
|||||||
6
test.py
Normal file
6
test.py
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
from src.komconfig import KomConfig
|
||||||
|
|
||||||
|
cfg = KomConfig()
|
||||||
|
|
||||||
|
|
||||||
|
print(cfg.komga.libraries)
|
||||||
40
tests/test___init__.py
Normal file
40
tests/test___init__.py
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
import pytest
|
||||||
|
from unittest.mock import patch, MagicMock
|
||||||
|
from src.komconfig.__init__ import main
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
def test_valid_key():
|
||||||
|
mock_config = MagicMock()
|
||||||
|
mock_config.dict.return_value = {"valid_key": "value"}
|
||||||
|
|
||||||
|
with patch("src.komconfig.__init__.KomConfig", return_value=mock_config):
|
||||||
|
with patch("sys.argv", ["__init__.py", "valid_key"]):
|
||||||
|
main()
|
||||||
|
|
||||||
|
|
||||||
|
def test_key_not_found():
|
||||||
|
mock_config = MagicMock()
|
||||||
|
mock_config.dict.return_value = {"another_key": "value"}
|
||||||
|
|
||||||
|
with patch("src.komconfig.__init__.KomConfig", return_value=mock_config):
|
||||||
|
with patch("sys.argv", ["__init__.py", "missing_key"]):
|
||||||
|
main()
|
||||||
|
|
||||||
|
|
||||||
|
def test_non_dict_config():
|
||||||
|
mock_config = MagicMock()
|
||||||
|
mock_config.dict.return_value = None
|
||||||
|
|
||||||
|
with patch("src.komconfig.__init__.KomConfig", return_value=mock_config):
|
||||||
|
with patch("sys.argv", ["__init__.py", "any_key"]):
|
||||||
|
main()
|
||||||
|
|
||||||
|
|
||||||
|
def test_exception_handling():
|
||||||
|
mock_config = MagicMock()
|
||||||
|
mock_config.dict.side_effect = Exception("Test Exception")
|
||||||
|
|
||||||
|
with patch("src.komconfig.__init__.KomConfig", return_value=mock_config):
|
||||||
|
with patch("sys.argv", ["__init__.py", "any_key"]):
|
||||||
|
main()
|
||||||
18
tests/test_config.py
Normal file
18
tests/test_config.py
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
from komconfig import KomConfig
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def komconfig():
|
||||||
|
return KomConfig()
|
||||||
|
|
||||||
|
|
||||||
|
def test_komconfig(komconfig):
|
||||||
|
assert komconfig is not None
|
||||||
|
|
||||||
|
|
||||||
|
def test_general(komconfig):
|
||||||
|
assert KomConfig().general.log_file == "/var/log/komgrabber.log"
|
||||||
|
assert KomConfig().general.log_level == "INFO"
|
||||||
|
|
||||||
|
|
||||||
Reference in New Issue
Block a user