qBitrr2 5.6.1__tar.gz → 5.6.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- qbitrr2-5.6.2/PKG-INFO +260 -0
- qbitrr2-5.6.2/README.md +156 -0
- {qbitrr2-5.6.1 → qbitrr2-5.6.2}/pyproject.toml +1 -1
- {qbitrr2-5.6.1 → qbitrr2-5.6.2}/qBitrr/arss.py +153 -1
- {qbitrr2-5.6.1 → qbitrr2-5.6.2}/qBitrr/bundled_data.py +2 -2
- {qbitrr2-5.6.1 → qbitrr2-5.6.2}/qBitrr/db_lock.py +24 -10
- qbitrr2-5.6.2/qBitrr/static/assets/app.css +1 -0
- {qbitrr2-5.6.1 → qbitrr2-5.6.2}/qBitrr/static/assets/app.js +5 -5
- qbitrr2-5.6.2/qBitrr/static/assets/app.js.map +1 -0
- qbitrr2-5.6.2/qBitrr2.egg-info/PKG-INFO +260 -0
- {qbitrr2-5.6.1 → qbitrr2-5.6.2}/setup.cfg +1 -1
- qbitrr2-5.6.1/PKG-INFO +0 -1210
- qbitrr2-5.6.1/README.md +0 -1106
- qbitrr2-5.6.1/qBitrr/static/assets/app.css +0 -1
- qbitrr2-5.6.1/qBitrr/static/assets/app.js.map +0 -1
- qbitrr2-5.6.1/qBitrr2.egg-info/PKG-INFO +0 -1210
- {qbitrr2-5.6.1 → qbitrr2-5.6.2}/LICENSE +0 -0
- {qbitrr2-5.6.1 → qbitrr2-5.6.2}/MANIFEST.in +0 -0
- {qbitrr2-5.6.1 → qbitrr2-5.6.2}/config.example.toml +0 -0
- {qbitrr2-5.6.1 → qbitrr2-5.6.2}/qBitrr/__init__.py +0 -0
- {qbitrr2-5.6.1 → qbitrr2-5.6.2}/qBitrr/auto_update.py +0 -0
- {qbitrr2-5.6.1 → qbitrr2-5.6.2}/qBitrr/config.py +0 -0
- {qbitrr2-5.6.1 → qbitrr2-5.6.2}/qBitrr/config_version.py +0 -0
- {qbitrr2-5.6.1 → qbitrr2-5.6.2}/qBitrr/db_recovery.py +0 -0
- {qbitrr2-5.6.1 → qbitrr2-5.6.2}/qBitrr/env_config.py +0 -0
- {qbitrr2-5.6.1 → qbitrr2-5.6.2}/qBitrr/errors.py +0 -0
- {qbitrr2-5.6.1 → qbitrr2-5.6.2}/qBitrr/ffprobe.py +0 -0
- {qbitrr2-5.6.1 → qbitrr2-5.6.2}/qBitrr/gen_config.py +0 -0
- {qbitrr2-5.6.1 → qbitrr2-5.6.2}/qBitrr/home_path.py +0 -0
- {qbitrr2-5.6.1 → qbitrr2-5.6.2}/qBitrr/logger.py +0 -0
- {qbitrr2-5.6.1 → qbitrr2-5.6.2}/qBitrr/main.py +0 -0
- {qbitrr2-5.6.1 → qbitrr2-5.6.2}/qBitrr/search_activity_store.py +0 -0
- {qbitrr2-5.6.1 → qbitrr2-5.6.2}/qBitrr/static/assets/ArrView.js +0 -0
- {qbitrr2-5.6.1 → qbitrr2-5.6.2}/qBitrr/static/assets/ArrView.js.map +0 -0
- {qbitrr2-5.6.1 → qbitrr2-5.6.2}/qBitrr/static/assets/ConfigView.js +0 -0
- {qbitrr2-5.6.1 → qbitrr2-5.6.2}/qBitrr/static/assets/ConfigView.js.map +0 -0
- {qbitrr2-5.6.1 → qbitrr2-5.6.2}/qBitrr/static/assets/LogsView.js +0 -0
- {qbitrr2-5.6.1 → qbitrr2-5.6.2}/qBitrr/static/assets/LogsView.js.map +0 -0
- {qbitrr2-5.6.1 → qbitrr2-5.6.2}/qBitrr/static/assets/ProcessesView.js +0 -0
- {qbitrr2-5.6.1 → qbitrr2-5.6.2}/qBitrr/static/assets/ProcessesView.js.map +0 -0
- {qbitrr2-5.6.1 → qbitrr2-5.6.2}/qBitrr/static/assets/build.svg +0 -0
- {qbitrr2-5.6.1 → qbitrr2-5.6.2}/qBitrr/static/assets/check-mark.svg +0 -0
- {qbitrr2-5.6.1 → qbitrr2-5.6.2}/qBitrr/static/assets/close.svg +0 -0
- {qbitrr2-5.6.1 → qbitrr2-5.6.2}/qBitrr/static/assets/download.svg +0 -0
- {qbitrr2-5.6.1 → qbitrr2-5.6.2}/qBitrr/static/assets/gear.svg +0 -0
- {qbitrr2-5.6.1 → qbitrr2-5.6.2}/qBitrr/static/assets/lidarr.svg +0 -0
- {qbitrr2-5.6.1 → qbitrr2-5.6.2}/qBitrr/static/assets/live-streaming.svg +0 -0
- {qbitrr2-5.6.1 → qbitrr2-5.6.2}/qBitrr/static/assets/log.svg +0 -0
- {qbitrr2-5.6.1 → qbitrr2-5.6.2}/qBitrr/static/assets/logo.svg +0 -0
- {qbitrr2-5.6.1 → qbitrr2-5.6.2}/qBitrr/static/assets/plus.svg +0 -0
- {qbitrr2-5.6.1 → qbitrr2-5.6.2}/qBitrr/static/assets/process.svg +0 -0
- {qbitrr2-5.6.1 → qbitrr2-5.6.2}/qBitrr/static/assets/react-select.esm.js +0 -0
- {qbitrr2-5.6.1 → qbitrr2-5.6.2}/qBitrr/static/assets/react-select.esm.js.map +0 -0
- {qbitrr2-5.6.1 → qbitrr2-5.6.2}/qBitrr/static/assets/refresh-arrow.svg +0 -0
- {qbitrr2-5.6.1 → qbitrr2-5.6.2}/qBitrr/static/assets/table.js +0 -0
- {qbitrr2-5.6.1 → qbitrr2-5.6.2}/qBitrr/static/assets/table.js.map +0 -0
- {qbitrr2-5.6.1 → qbitrr2-5.6.2}/qBitrr/static/assets/trash.svg +0 -0
- {qbitrr2-5.6.1 → qbitrr2-5.6.2}/qBitrr/static/assets/up-arrow.svg +0 -0
- {qbitrr2-5.6.1 → qbitrr2-5.6.2}/qBitrr/static/assets/useInterval.js +0 -0
- {qbitrr2-5.6.1 → qbitrr2-5.6.2}/qBitrr/static/assets/useInterval.js.map +0 -0
- {qbitrr2-5.6.1 → qbitrr2-5.6.2}/qBitrr/static/assets/vendor.js +0 -0
- {qbitrr2-5.6.1 → qbitrr2-5.6.2}/qBitrr/static/assets/vendor.js.map +0 -0
- {qbitrr2-5.6.1 → qbitrr2-5.6.2}/qBitrr/static/assets/visibility.svg +0 -0
- {qbitrr2-5.6.1 → qbitrr2-5.6.2}/qBitrr/static/favicon-16x16.png +0 -0
- {qbitrr2-5.6.1 → qbitrr2-5.6.2}/qBitrr/static/favicon-32x32.png +0 -0
- {qbitrr2-5.6.1 → qbitrr2-5.6.2}/qBitrr/static/favicon-48x48.png +0 -0
- {qbitrr2-5.6.1 → qbitrr2-5.6.2}/qBitrr/static/favicon.ico +0 -0
- {qbitrr2-5.6.1 → qbitrr2-5.6.2}/qBitrr/static/icon-192.png +0 -0
- {qbitrr2-5.6.1 → qbitrr2-5.6.2}/qBitrr/static/icon-512.png +0 -0
- {qbitrr2-5.6.1 → qbitrr2-5.6.2}/qBitrr/static/index.html +0 -0
- {qbitrr2-5.6.1 → qbitrr2-5.6.2}/qBitrr/static/logov2-clean.png +0 -0
- {qbitrr2-5.6.1 → qbitrr2-5.6.2}/qBitrr/static/logov2-clean.svg +0 -0
- {qbitrr2-5.6.1 → qbitrr2-5.6.2}/qBitrr/static/manifest.json +0 -0
- {qbitrr2-5.6.1 → qbitrr2-5.6.2}/qBitrr/static/sw.js +0 -0
- {qbitrr2-5.6.1 → qbitrr2-5.6.2}/qBitrr/static/vite.svg +0 -0
- {qbitrr2-5.6.1 → qbitrr2-5.6.2}/qBitrr/tables.py +0 -0
- {qbitrr2-5.6.1 → qbitrr2-5.6.2}/qBitrr/utils.py +0 -0
- {qbitrr2-5.6.1 → qbitrr2-5.6.2}/qBitrr/versioning.py +0 -0
- {qbitrr2-5.6.1 → qbitrr2-5.6.2}/qBitrr/webui.py +0 -0
- {qbitrr2-5.6.1 → qbitrr2-5.6.2}/qBitrr2.egg-info/SOURCES.txt +0 -0
- {qbitrr2-5.6.1 → qbitrr2-5.6.2}/qBitrr2.egg-info/dependency_links.txt +0 -0
- {qbitrr2-5.6.1 → qbitrr2-5.6.2}/qBitrr2.egg-info/entry_points.txt +0 -0
- {qbitrr2-5.6.1 → qbitrr2-5.6.2}/qBitrr2.egg-info/requires.txt +0 -0
- {qbitrr2-5.6.1 → qbitrr2-5.6.2}/qBitrr2.egg-info/top_level.txt +0 -0
- {qbitrr2-5.6.1 → qbitrr2-5.6.2}/setup.py +0 -0
qbitrr2-5.6.2/PKG-INFO
ADDED
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: qBitrr2
|
|
3
|
+
Version: 5.6.2
|
|
4
|
+
Summary: Intelligent automation for qBittorrent and *Arr apps (Radarr/Sonarr/Lidarr) - health monitoring, instant imports, quality upgrades, request integration
|
|
5
|
+
Home-page: https://github.com/Feramance/qBitrr
|
|
6
|
+
Author: Feramance
|
|
7
|
+
Author-email: fera@fera.wtf
|
|
8
|
+
License: MIT
|
|
9
|
+
Project-URL: Homepage, https://github.com/Feramance/qBitrr
|
|
10
|
+
Project-URL: Documentation, https://feramance.github.io/qBitrr/
|
|
11
|
+
Project-URL: Issue Tracker, https://github.com/Feramance/qBitrr/issues
|
|
12
|
+
Project-URL: Source Code, https://github.com/Feramance/qBitrr
|
|
13
|
+
Project-URL: Changelog, https://github.com/Feramance/qBitrr/blob/master/CHANGELOG.md
|
|
14
|
+
Project-URL: Docker Hub, https://hub.docker.com/r/feramance/qbitrr
|
|
15
|
+
Project-URL: PyPI, https://pypi.org/project/qBitrr2/
|
|
16
|
+
Project-URL: Systemd Guide, https://feramance.github.io/qBitrr/getting-started/installation/systemd/
|
|
17
|
+
Keywords: qbittorrent,radarr,sonarr,lidarr,arr,automation,torrent,media,plex,jellyfin,overseerr,ombi
|
|
18
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
19
|
+
Classifier: Intended Audience :: Developers
|
|
20
|
+
Classifier: Intended Audience :: End Users/Desktop
|
|
21
|
+
Classifier: Intended Audience :: System Administrators
|
|
22
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
23
|
+
Classifier: Natural Language :: English
|
|
24
|
+
Classifier: Operating System :: MacOS :: MacOS X
|
|
25
|
+
Classifier: Operating System :: Microsoft :: Windows
|
|
26
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
27
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
28
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
29
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
30
|
+
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
31
|
+
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
|
32
|
+
Classifier: Topic :: Communications
|
|
33
|
+
Classifier: Topic :: Internet
|
|
34
|
+
Classifier: Topic :: Multimedia :: Video
|
|
35
|
+
Classifier: Topic :: System :: Monitoring
|
|
36
|
+
Classifier: Topic :: Terminals
|
|
37
|
+
Classifier: Topic :: Utilities
|
|
38
|
+
Classifier: Typing :: Typed
|
|
39
|
+
Requires-Python: <4,>=3.11
|
|
40
|
+
Description-Content-Type: text/markdown
|
|
41
|
+
License-File: LICENSE
|
|
42
|
+
Requires-Dist: cachetools
|
|
43
|
+
Requires-Dist: colorama
|
|
44
|
+
Requires-Dist: coloredlogs
|
|
45
|
+
Requires-Dist: flask
|
|
46
|
+
Requires-Dist: environ-config
|
|
47
|
+
Requires-Dist: ffmpeg-python
|
|
48
|
+
Requires-Dist: jaraco.docker
|
|
49
|
+
Requires-Dist: packaging
|
|
50
|
+
Requires-Dist: pathos
|
|
51
|
+
Requires-Dist: peewee
|
|
52
|
+
Requires-Dist: ping3
|
|
53
|
+
Requires-Dist: pyarr
|
|
54
|
+
Requires-Dist: qbittorrent-api
|
|
55
|
+
Requires-Dist: requests
|
|
56
|
+
Requires-Dist: tomlkit
|
|
57
|
+
Requires-Dist: waitress
|
|
58
|
+
Requires-Dist: croniter
|
|
59
|
+
Provides-Extra: dev
|
|
60
|
+
Requires-Dist: black==24.3.0; extra == "dev"
|
|
61
|
+
Requires-Dist: bump2version==1.0.1; extra == "dev"
|
|
62
|
+
Requires-Dist: isort==5.10.1; extra == "dev"
|
|
63
|
+
Requires-Dist: pip-tools==7.3.0; extra == "dev"
|
|
64
|
+
Requires-Dist: pre-commit==3.3.3; extra == "dev"
|
|
65
|
+
Requires-Dist: pyinstaller==5.13.1; extra == "dev"
|
|
66
|
+
Requires-Dist: pyupgrade==2.31.0; extra == "dev"
|
|
67
|
+
Requires-Dist: twine==3.7.1; extra == "dev"
|
|
68
|
+
Requires-Dist: ujson==5.10.0; extra == "dev"
|
|
69
|
+
Requires-Dist: upgrade-pip==0.1.4; extra == "dev"
|
|
70
|
+
Provides-Extra: fast
|
|
71
|
+
Requires-Dist: ujson==5.10.0; extra == "fast"
|
|
72
|
+
Provides-Extra: docs
|
|
73
|
+
Requires-Dist: mkdocs>=1.5.3; extra == "docs"
|
|
74
|
+
Requires-Dist: mkdocs-material>=9.5.0; extra == "docs"
|
|
75
|
+
Requires-Dist: mkdocs-material-extensions>=1.3.0; extra == "docs"
|
|
76
|
+
Requires-Dist: mkdocs-git-revision-date-localized-plugin>=1.2.0; extra == "docs"
|
|
77
|
+
Requires-Dist: mkdocs-minify-plugin>=0.7.0; extra == "docs"
|
|
78
|
+
Requires-Dist: mkdocs-redirects>=1.2.0; extra == "docs"
|
|
79
|
+
Requires-Dist: mkdocs-include-markdown-plugin>=6.0.0; extra == "docs"
|
|
80
|
+
Requires-Dist: pymdown-extensions>=10.0.0; extra == "docs"
|
|
81
|
+
Requires-Dist: markdown-include>=0.8.0; extra == "docs"
|
|
82
|
+
Provides-Extra: all
|
|
83
|
+
Requires-Dist: black==24.3.0; extra == "all"
|
|
84
|
+
Requires-Dist: bump2version==1.0.1; extra == "all"
|
|
85
|
+
Requires-Dist: isort==5.10.1; extra == "all"
|
|
86
|
+
Requires-Dist: pip-tools==7.3.0; extra == "all"
|
|
87
|
+
Requires-Dist: pre-commit==3.3.3; extra == "all"
|
|
88
|
+
Requires-Dist: pyinstaller==5.13.1; extra == "all"
|
|
89
|
+
Requires-Dist: pyupgrade==2.31.0; extra == "all"
|
|
90
|
+
Requires-Dist: twine==3.7.1; extra == "all"
|
|
91
|
+
Requires-Dist: ujson==5.10.0; extra == "all"
|
|
92
|
+
Requires-Dist: upgrade-pip==0.1.4; extra == "all"
|
|
93
|
+
Requires-Dist: ujson==5.10.0; extra == "all"
|
|
94
|
+
Requires-Dist: mkdocs>=1.5.3; extra == "all"
|
|
95
|
+
Requires-Dist: mkdocs-material>=9.5.0; extra == "all"
|
|
96
|
+
Requires-Dist: mkdocs-material-extensions>=1.3.0; extra == "all"
|
|
97
|
+
Requires-Dist: mkdocs-git-revision-date-localized-plugin>=1.2.0; extra == "all"
|
|
98
|
+
Requires-Dist: mkdocs-minify-plugin>=0.7.0; extra == "all"
|
|
99
|
+
Requires-Dist: mkdocs-redirects>=1.2.0; extra == "all"
|
|
100
|
+
Requires-Dist: mkdocs-include-markdown-plugin>=6.0.0; extra == "all"
|
|
101
|
+
Requires-Dist: pymdown-extensions>=10.0.0; extra == "all"
|
|
102
|
+
Requires-Dist: markdown-include>=0.8.0; extra == "all"
|
|
103
|
+
Dynamic: license-file
|
|
104
|
+
|
|
105
|
+
# <img src="assets/logov2-clean.png" alt="qBitrr Logo" width="40" style="vertical-align: middle;"/> qBitrr
|
|
106
|
+
|
|
107
|
+
[](https://pypi.org/project/qBitrr2/)
|
|
108
|
+
[](https://pypi.org/project/qBitrr2/)
|
|
109
|
+
[](https://hub.docker.com/r/feramance/qbitrr)
|
|
110
|
+
[](https://github.com/Feramance/qBitrr/actions/workflows/codeql.yml)
|
|
111
|
+
[](https://github.com/Feramance/qBitrr/actions/workflows/nightly.yml)
|
|
112
|
+
[](https://results.pre-commit.ci/latest/github/Feramance/qBitrr/master)
|
|
113
|
+
[](LICENSE)
|
|
114
|
+
|
|
115
|
+
> 🧩 The intelligent glue between qBittorrent and the *Arr ecosystem (Radarr, Sonarr, Lidarr). Monitors torrent health, triggers instant imports, automates quality upgrades, manages disk space, integrates with request systems (Overseerr/Ombi), and provides a modern React dashboard for complete visibility and control.
|
|
116
|
+
|
|
117
|
+
## 📚 Documentation
|
|
118
|
+
|
|
119
|
+
**Full documentation is available at: https://feramance.github.io/qBitrr/**
|
|
120
|
+
|
|
121
|
+
- [Getting Started](https://feramance.github.io/qBitrr/getting-started/) – Installation guides for pip, Docker, and native setups
|
|
122
|
+
- [Configuration](https://feramance.github.io/qBitrr/configuration/) – qBittorrent, Arr instances, quality profiles, and more
|
|
123
|
+
- [Features](https://feramance.github.io/qBitrr/features/) – Health monitoring, automated search, quality management, disk space, auto-updates
|
|
124
|
+
- [WebUI](https://feramance.github.io/qBitrr/webui/) – Built-in React dashboard with live monitoring and config editor
|
|
125
|
+
- [Troubleshooting](https://feramance.github.io/qBitrr/troubleshooting/) – Common issues and debug logging
|
|
126
|
+
- [API Reference](https://feramance.github.io/qBitrr/reference/api/) – REST API documentation
|
|
127
|
+
|
|
128
|
+
## ⚡ Quick Start
|
|
129
|
+
|
|
130
|
+
### 🐍 Install with pip
|
|
131
|
+
```bash
|
|
132
|
+
python -m venv .venv
|
|
133
|
+
source .venv/bin/activate # Windows: .venv\Scripts\activate
|
|
134
|
+
pip install qBitrr2
|
|
135
|
+
|
|
136
|
+
# First run creates ~/config/config.toml
|
|
137
|
+
qbitrr
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### 🐳 Run with Docker
|
|
141
|
+
```bash
|
|
142
|
+
docker run -d \
|
|
143
|
+
--name qbitrr \
|
|
144
|
+
--tty \
|
|
145
|
+
-e TZ=Europe/London \
|
|
146
|
+
-p 6969:6969 \
|
|
147
|
+
-v /path/to/appdata/qbitrr:/config \
|
|
148
|
+
-v /path/to/completed/downloads:/completed_downloads:rw \
|
|
149
|
+
--restart unless-stopped \
|
|
150
|
+
feramance/qbitrr:latest
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
**Docker Compose:**
|
|
154
|
+
```yaml
|
|
155
|
+
services:
|
|
156
|
+
qbitrr:
|
|
157
|
+
image: feramance/qbitrr:latest
|
|
158
|
+
container_name: qbitrr
|
|
159
|
+
restart: unless-stopped
|
|
160
|
+
tty: true
|
|
161
|
+
environment:
|
|
162
|
+
TZ: Europe/London
|
|
163
|
+
ports:
|
|
164
|
+
- "6969:6969"
|
|
165
|
+
volumes:
|
|
166
|
+
- /path/to/appdata/qbitrr:/config
|
|
167
|
+
- /path/to/completed/downloads:/completed_downloads:rw
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
Access the WebUI at `http://<host>:6969/ui` after startup.
|
|
171
|
+
|
|
172
|
+
## ✨ Key Features
|
|
173
|
+
|
|
174
|
+
- **🚑 Torrent Health Monitoring** – Detect stalled/failed downloads, auto-blacklist, trigger re-searches
|
|
175
|
+
- **🔍 Automated Search** – Missing media, quality upgrades, custom format scoring
|
|
176
|
+
- **🎯 Request Integration** – Pull requests from Overseerr/Ombi, prioritize user-requested media
|
|
177
|
+
- **📊 Quality Management** – RSS sync, queue refresh, profile switching, custom format enforcement
|
|
178
|
+
- **🌱 Seeding Control** – Per-tracker settings, ratio/time limits, tracker injection
|
|
179
|
+
- **💾 Disk Space Management** – Auto-pause when low on space, configurable thresholds
|
|
180
|
+
- **🔄 Auto-Updates** – GitHub release-based updates with scheduled cron support
|
|
181
|
+
- **💻 Modern WebUI** – Live process monitoring, log viewer, Arr insights, config editor
|
|
182
|
+
|
|
183
|
+
## 🛠️ Essential Configuration
|
|
184
|
+
|
|
185
|
+
1. **Configure qBittorrent** in `~/config/config.toml`:
|
|
186
|
+
```toml
|
|
187
|
+
[qBit]
|
|
188
|
+
Host = "localhost"
|
|
189
|
+
Port = 8080
|
|
190
|
+
UserName = "admin"
|
|
191
|
+
Password = "adminpass"
|
|
192
|
+
Version5 = true # qBittorrent 5.x
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
2. **Add Arr instances**:
|
|
196
|
+
```toml
|
|
197
|
+
[Radarr-Movies]
|
|
198
|
+
URI = "http://localhost:7878"
|
|
199
|
+
APIKey = "your-radarr-api-key"
|
|
200
|
+
Category = "radarr-movies"
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
3. **Set completed folder**:
|
|
204
|
+
```toml
|
|
205
|
+
[Settings]
|
|
206
|
+
CompletedDownloadFolder = "/path/to/completed"
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
See [Configuration Guide](https://feramance.github.io/qBitrr/configuration/) and [config.example.toml](config.example.toml) for all available options.
|
|
210
|
+
|
|
211
|
+
## 📖 Resources
|
|
212
|
+
|
|
213
|
+
- **Documentation:** https://feramance.github.io/qBitrr/
|
|
214
|
+
- **PyPI Package:** https://pypi.org/project/qBitrr2/
|
|
215
|
+
- **Docker Hub:** https://hub.docker.com/r/feramance/qbitrr
|
|
216
|
+
- **Example Config:** [config.example.toml](config.example.toml)
|
|
217
|
+
- **API Documentation:** [API_DOCUMENTATION.md](API_DOCUMENTATION.md)
|
|
218
|
+
- **Systemd Setup:** [SYSTEMD_SERVICE.md](SYSTEMD_SERVICE.md)
|
|
219
|
+
|
|
220
|
+
## 🐛 Issues & Support
|
|
221
|
+
|
|
222
|
+
- **Report Bugs:** [Bug Report Template](.github/ISSUE_TEMPLATE/bug_report.yml)
|
|
223
|
+
- **Request Features:** [Feature Request Template](.github/ISSUE_TEMPLATE/feature_request.yml)
|
|
224
|
+
- **Discussions:** [GitHub Discussions](https://github.com/Feramance/qBitrr/discussions)
|
|
225
|
+
- **Troubleshooting:** [Common Issues](https://feramance.github.io/qBitrr/troubleshooting/)
|
|
226
|
+
|
|
227
|
+
## 🤝 Contributing
|
|
228
|
+
|
|
229
|
+
Contributions welcome! See [CONTRIBUTION.md](CONTRIBUTION.md) for coding guidelines and development setup.
|
|
230
|
+
|
|
231
|
+
**Development setup:**
|
|
232
|
+
```bash
|
|
233
|
+
# Python backend
|
|
234
|
+
make newenv && make syncenv
|
|
235
|
+
make reformat # Format and lint
|
|
236
|
+
|
|
237
|
+
# WebUI
|
|
238
|
+
cd webui && npm ci
|
|
239
|
+
npm run dev # Dev server at localhost:5173
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
## ❤️ Support
|
|
243
|
+
|
|
244
|
+
If qBitrr saves you time and headaches:
|
|
245
|
+
- ⭐ **Star the repo** – helps others discover qBitrr
|
|
246
|
+
- 💰 **Sponsor:** [Patreon](https://patreon.com/qBitrr) | [PayPal](https://www.paypal.me/feramance)
|
|
247
|
+
|
|
248
|
+
## 📄 License
|
|
249
|
+
|
|
250
|
+
Released under the [MIT License](LICENSE). Use it, modify it, share it—commercially or personally.
|
|
251
|
+
|
|
252
|
+
---
|
|
253
|
+
|
|
254
|
+
<div align="center">
|
|
255
|
+
|
|
256
|
+
**Made with ❤️ by the qBitrr community**
|
|
257
|
+
|
|
258
|
+
[Documentation](https://feramance.github.io/qBitrr/) • [PyPI](https://pypi.org/project/qBitrr2/) • [Docker](https://hub.docker.com/r/feramance/qbitrr) • [GitHub](https://github.com/Feramance/qBitrr)
|
|
259
|
+
|
|
260
|
+
</div>
|
qbitrr2-5.6.2/README.md
ADDED
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
# <img src="assets/logov2-clean.png" alt="qBitrr Logo" width="40" style="vertical-align: middle;"/> qBitrr
|
|
2
|
+
|
|
3
|
+
[](https://pypi.org/project/qBitrr2/)
|
|
4
|
+
[](https://pypi.org/project/qBitrr2/)
|
|
5
|
+
[](https://hub.docker.com/r/feramance/qbitrr)
|
|
6
|
+
[](https://github.com/Feramance/qBitrr/actions/workflows/codeql.yml)
|
|
7
|
+
[](https://github.com/Feramance/qBitrr/actions/workflows/nightly.yml)
|
|
8
|
+
[](https://results.pre-commit.ci/latest/github/Feramance/qBitrr/master)
|
|
9
|
+
[](LICENSE)
|
|
10
|
+
|
|
11
|
+
> 🧩 The intelligent glue between qBittorrent and the *Arr ecosystem (Radarr, Sonarr, Lidarr). Monitors torrent health, triggers instant imports, automates quality upgrades, manages disk space, integrates with request systems (Overseerr/Ombi), and provides a modern React dashboard for complete visibility and control.
|
|
12
|
+
|
|
13
|
+
## 📚 Documentation
|
|
14
|
+
|
|
15
|
+
**Full documentation is available at: https://feramance.github.io/qBitrr/**
|
|
16
|
+
|
|
17
|
+
- [Getting Started](https://feramance.github.io/qBitrr/getting-started/) – Installation guides for pip, Docker, and native setups
|
|
18
|
+
- [Configuration](https://feramance.github.io/qBitrr/configuration/) – qBittorrent, Arr instances, quality profiles, and more
|
|
19
|
+
- [Features](https://feramance.github.io/qBitrr/features/) – Health monitoring, automated search, quality management, disk space, auto-updates
|
|
20
|
+
- [WebUI](https://feramance.github.io/qBitrr/webui/) – Built-in React dashboard with live monitoring and config editor
|
|
21
|
+
- [Troubleshooting](https://feramance.github.io/qBitrr/troubleshooting/) – Common issues and debug logging
|
|
22
|
+
- [API Reference](https://feramance.github.io/qBitrr/reference/api/) – REST API documentation
|
|
23
|
+
|
|
24
|
+
## ⚡ Quick Start
|
|
25
|
+
|
|
26
|
+
### 🐍 Install with pip
|
|
27
|
+
```bash
|
|
28
|
+
python -m venv .venv
|
|
29
|
+
source .venv/bin/activate # Windows: .venv\Scripts\activate
|
|
30
|
+
pip install qBitrr2
|
|
31
|
+
|
|
32
|
+
# First run creates ~/config/config.toml
|
|
33
|
+
qbitrr
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### 🐳 Run with Docker
|
|
37
|
+
```bash
|
|
38
|
+
docker run -d \
|
|
39
|
+
--name qbitrr \
|
|
40
|
+
--tty \
|
|
41
|
+
-e TZ=Europe/London \
|
|
42
|
+
-p 6969:6969 \
|
|
43
|
+
-v /path/to/appdata/qbitrr:/config \
|
|
44
|
+
-v /path/to/completed/downloads:/completed_downloads:rw \
|
|
45
|
+
--restart unless-stopped \
|
|
46
|
+
feramance/qbitrr:latest
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
**Docker Compose:**
|
|
50
|
+
```yaml
|
|
51
|
+
services:
|
|
52
|
+
qbitrr:
|
|
53
|
+
image: feramance/qbitrr:latest
|
|
54
|
+
container_name: qbitrr
|
|
55
|
+
restart: unless-stopped
|
|
56
|
+
tty: true
|
|
57
|
+
environment:
|
|
58
|
+
TZ: Europe/London
|
|
59
|
+
ports:
|
|
60
|
+
- "6969:6969"
|
|
61
|
+
volumes:
|
|
62
|
+
- /path/to/appdata/qbitrr:/config
|
|
63
|
+
- /path/to/completed/downloads:/completed_downloads:rw
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Access the WebUI at `http://<host>:6969/ui` after startup.
|
|
67
|
+
|
|
68
|
+
## ✨ Key Features
|
|
69
|
+
|
|
70
|
+
- **🚑 Torrent Health Monitoring** – Detect stalled/failed downloads, auto-blacklist, trigger re-searches
|
|
71
|
+
- **🔍 Automated Search** – Missing media, quality upgrades, custom format scoring
|
|
72
|
+
- **🎯 Request Integration** – Pull requests from Overseerr/Ombi, prioritize user-requested media
|
|
73
|
+
- **📊 Quality Management** – RSS sync, queue refresh, profile switching, custom format enforcement
|
|
74
|
+
- **🌱 Seeding Control** – Per-tracker settings, ratio/time limits, tracker injection
|
|
75
|
+
- **💾 Disk Space Management** – Auto-pause when low on space, configurable thresholds
|
|
76
|
+
- **🔄 Auto-Updates** – GitHub release-based updates with scheduled cron support
|
|
77
|
+
- **💻 Modern WebUI** – Live process monitoring, log viewer, Arr insights, config editor
|
|
78
|
+
|
|
79
|
+
## 🛠️ Essential Configuration
|
|
80
|
+
|
|
81
|
+
1. **Configure qBittorrent** in `~/config/config.toml`:
|
|
82
|
+
```toml
|
|
83
|
+
[qBit]
|
|
84
|
+
Host = "localhost"
|
|
85
|
+
Port = 8080
|
|
86
|
+
UserName = "admin"
|
|
87
|
+
Password = "adminpass"
|
|
88
|
+
Version5 = true # qBittorrent 5.x
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
2. **Add Arr instances**:
|
|
92
|
+
```toml
|
|
93
|
+
[Radarr-Movies]
|
|
94
|
+
URI = "http://localhost:7878"
|
|
95
|
+
APIKey = "your-radarr-api-key"
|
|
96
|
+
Category = "radarr-movies"
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
3. **Set completed folder**:
|
|
100
|
+
```toml
|
|
101
|
+
[Settings]
|
|
102
|
+
CompletedDownloadFolder = "/path/to/completed"
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
See [Configuration Guide](https://feramance.github.io/qBitrr/configuration/) and [config.example.toml](config.example.toml) for all available options.
|
|
106
|
+
|
|
107
|
+
## 📖 Resources
|
|
108
|
+
|
|
109
|
+
- **Documentation:** https://feramance.github.io/qBitrr/
|
|
110
|
+
- **PyPI Package:** https://pypi.org/project/qBitrr2/
|
|
111
|
+
- **Docker Hub:** https://hub.docker.com/r/feramance/qbitrr
|
|
112
|
+
- **Example Config:** [config.example.toml](config.example.toml)
|
|
113
|
+
- **API Documentation:** [API_DOCUMENTATION.md](API_DOCUMENTATION.md)
|
|
114
|
+
- **Systemd Setup:** [SYSTEMD_SERVICE.md](SYSTEMD_SERVICE.md)
|
|
115
|
+
|
|
116
|
+
## 🐛 Issues & Support
|
|
117
|
+
|
|
118
|
+
- **Report Bugs:** [Bug Report Template](.github/ISSUE_TEMPLATE/bug_report.yml)
|
|
119
|
+
- **Request Features:** [Feature Request Template](.github/ISSUE_TEMPLATE/feature_request.yml)
|
|
120
|
+
- **Discussions:** [GitHub Discussions](https://github.com/Feramance/qBitrr/discussions)
|
|
121
|
+
- **Troubleshooting:** [Common Issues](https://feramance.github.io/qBitrr/troubleshooting/)
|
|
122
|
+
|
|
123
|
+
## 🤝 Contributing
|
|
124
|
+
|
|
125
|
+
Contributions welcome! See [CONTRIBUTION.md](CONTRIBUTION.md) for coding guidelines and development setup.
|
|
126
|
+
|
|
127
|
+
**Development setup:**
|
|
128
|
+
```bash
|
|
129
|
+
# Python backend
|
|
130
|
+
make newenv && make syncenv
|
|
131
|
+
make reformat # Format and lint
|
|
132
|
+
|
|
133
|
+
# WebUI
|
|
134
|
+
cd webui && npm ci
|
|
135
|
+
npm run dev # Dev server at localhost:5173
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
## ❤️ Support
|
|
139
|
+
|
|
140
|
+
If qBitrr saves you time and headaches:
|
|
141
|
+
- ⭐ **Star the repo** – helps others discover qBitrr
|
|
142
|
+
- 💰 **Sponsor:** [Patreon](https://patreon.com/qBitrr) | [PayPal](https://www.paypal.me/feramance)
|
|
143
|
+
|
|
144
|
+
## 📄 License
|
|
145
|
+
|
|
146
|
+
Released under the [MIT License](LICENSE). Use it, modify it, share it—commercially or personally.
|
|
147
|
+
|
|
148
|
+
---
|
|
149
|
+
|
|
150
|
+
<div align="center">
|
|
151
|
+
|
|
152
|
+
**Made with ❤️ by the qBitrr community**
|
|
153
|
+
|
|
154
|
+
[Documentation](https://feramance.github.io/qBitrr/) • [PyPI](https://pypi.org/project/qBitrr2/) • [Docker](https://hub.docker.com/r/feramance/qbitrr) • [GitHub](https://github.com/Feramance/qBitrr)
|
|
155
|
+
|
|
156
|
+
</div>
|
|
@@ -28,7 +28,7 @@ target-version = ['py311']
|
|
|
28
28
|
|
|
29
29
|
[tool.poetry]
|
|
30
30
|
name = "pypi-public"
|
|
31
|
-
version = "5.6.
|
|
31
|
+
version = "5.6.2"
|
|
32
32
|
description = "Intelligent automation for qBittorrent and *Arr apps (Radarr/Sonarr/Lidarr) - health monitoring, instant imports, quality upgrades, request integration"
|
|
33
33
|
authors = ["Drapersniper", "Feramance"]
|
|
34
34
|
readme = "README.md"
|
|
@@ -20,7 +20,7 @@ import qbittorrentapi
|
|
|
20
20
|
import qbittorrentapi.exceptions
|
|
21
21
|
import requests
|
|
22
22
|
from packaging import version as version_parser
|
|
23
|
-
from peewee import Model, SqliteDatabase
|
|
23
|
+
from peewee import DatabaseError, Model, OperationalError, SqliteDatabase
|
|
24
24
|
from pyarr import LidarrAPI, RadarrAPI, SonarrAPI
|
|
25
25
|
from pyarr.exceptions import PyarrResourceNotFound, PyarrServerError
|
|
26
26
|
from pyarr.types import JsonObject
|
|
@@ -4475,6 +4475,11 @@ class Arr:
|
|
|
4475
4475
|
if self.manager.qbit_manager.should_delay_torrent_scan:
|
|
4476
4476
|
raise DelayLoopException(length=NO_INTERNET_SLEEP_TIMER, type="delay")
|
|
4477
4477
|
|
|
4478
|
+
# Initialize database error tracking for exponential backoff
|
|
4479
|
+
if not hasattr(self, "_db_error_count"):
|
|
4480
|
+
self._db_error_count = 0
|
|
4481
|
+
self._db_last_error_time = 0
|
|
4482
|
+
|
|
4478
4483
|
# Periodic database health check (every 10th iteration)
|
|
4479
4484
|
if not hasattr(self, "_health_check_counter"):
|
|
4480
4485
|
self._health_check_counter = 0
|
|
@@ -4516,6 +4521,76 @@ class Arr:
|
|
|
4516
4521
|
self.logger.error("The qBittorrent API returned an unexpected error")
|
|
4517
4522
|
self.logger.debug("Unexpected APIError from qBitTorrent") # , exc_info=e)
|
|
4518
4523
|
raise DelayLoopException(length=300, type="qbit")
|
|
4524
|
+
except (OperationalError, DatabaseError) as e:
|
|
4525
|
+
# Database errors after retry exhaustion - implement automatic recovery with backoff
|
|
4526
|
+
error_msg = str(e).lower()
|
|
4527
|
+
current_time = time.time()
|
|
4528
|
+
|
|
4529
|
+
# Track consecutive database errors for exponential backoff
|
|
4530
|
+
if (
|
|
4531
|
+
current_time - self._db_last_error_time > 300
|
|
4532
|
+
): # Reset if >5min since last error
|
|
4533
|
+
self._db_error_count = 0
|
|
4534
|
+
self._db_error_count += 1
|
|
4535
|
+
self._db_last_error_time = current_time
|
|
4536
|
+
|
|
4537
|
+
# Calculate exponential backoff: 2min, 5min, 10min, 20min, 30min (max)
|
|
4538
|
+
delay_seconds = min(120 * (2 ** (self._db_error_count - 1)), 1800)
|
|
4539
|
+
|
|
4540
|
+
# Log detailed error information based on error type
|
|
4541
|
+
if "disk i/o error" in error_msg:
|
|
4542
|
+
self.logger.critical(
|
|
4543
|
+
"Persistent database I/O error detected (consecutive error #%d). "
|
|
4544
|
+
"This indicates disk issues, filesystem corruption, or resource exhaustion. "
|
|
4545
|
+
"Attempting automatic recovery and retrying in %d seconds...",
|
|
4546
|
+
self._db_error_count,
|
|
4547
|
+
delay_seconds,
|
|
4548
|
+
)
|
|
4549
|
+
elif "database is locked" in error_msg:
|
|
4550
|
+
self.logger.error(
|
|
4551
|
+
"Database locked error (consecutive error #%d). "
|
|
4552
|
+
"Retrying in %d seconds...",
|
|
4553
|
+
self._db_error_count,
|
|
4554
|
+
delay_seconds,
|
|
4555
|
+
)
|
|
4556
|
+
elif "disk image is malformed" in error_msg:
|
|
4557
|
+
self.logger.critical(
|
|
4558
|
+
"Database corruption detected (consecutive error #%d). "
|
|
4559
|
+
"Attempting automatic recovery and retrying in %d seconds...",
|
|
4560
|
+
self._db_error_count,
|
|
4561
|
+
delay_seconds,
|
|
4562
|
+
)
|
|
4563
|
+
else:
|
|
4564
|
+
self.logger.error(
|
|
4565
|
+
"Database error (consecutive error #%d): %s. " "Retrying in %d seconds...",
|
|
4566
|
+
self._db_error_count,
|
|
4567
|
+
error_msg,
|
|
4568
|
+
delay_seconds,
|
|
4569
|
+
)
|
|
4570
|
+
|
|
4571
|
+
# Attempt automatic recovery for critical errors
|
|
4572
|
+
if "disk i/o error" in error_msg or "disk image is malformed" in error_msg:
|
|
4573
|
+
try:
|
|
4574
|
+
self.logger.warning(
|
|
4575
|
+
"Attempting enhanced database recovery (WAL checkpoint, repair, and verification)..."
|
|
4576
|
+
)
|
|
4577
|
+
self._enhanced_database_recovery()
|
|
4578
|
+
self.logger.info(
|
|
4579
|
+
"Database recovery completed successfully - will retry operation after delay"
|
|
4580
|
+
)
|
|
4581
|
+
# Reduce error count on successful recovery (but don't reset completely)
|
|
4582
|
+
self._db_error_count = max(0, self._db_error_count - 1)
|
|
4583
|
+
except Exception as recovery_error:
|
|
4584
|
+
self.logger.critical(
|
|
4585
|
+
"Automatic database recovery failed: %s. "
|
|
4586
|
+
"MANUAL INTERVENTION REQUIRED: Check disk health (smartctl), "
|
|
4587
|
+
"filesystem integrity (fsck), available space (df -h), "
|
|
4588
|
+
"Docker volume mounts, permissions, and system logs (dmesg).",
|
|
4589
|
+
recovery_error,
|
|
4590
|
+
)
|
|
4591
|
+
|
|
4592
|
+
# Delay processing to avoid hammering failing database
|
|
4593
|
+
raise DelayLoopException(length=delay_seconds, type="database")
|
|
4519
4594
|
except DelayLoopException:
|
|
4520
4595
|
raise
|
|
4521
4596
|
except KeyboardInterrupt:
|
|
@@ -4566,6 +4641,83 @@ class Arr:
|
|
|
4566
4641
|
"Manual intervention may be required. Continuing with caution..."
|
|
4567
4642
|
)
|
|
4568
4643
|
|
|
4644
|
+
def _enhanced_database_recovery(self):
|
|
4645
|
+
"""
|
|
4646
|
+
Enhanced automatic database recovery with additional filesystem checks.
|
|
4647
|
+
|
|
4648
|
+
This method is called when disk I/O errors persist after retry logic has been exhausted.
|
|
4649
|
+
It implements a comprehensive recovery strategy:
|
|
4650
|
+
1. Try WAL checkpoint (least invasive)
|
|
4651
|
+
2. Try VACUUM to reclaim space and fix minor corruption
|
|
4652
|
+
3. Try full database repair (dump/restore) if needed
|
|
4653
|
+
4. Verify database integrity after recovery
|
|
4654
|
+
"""
|
|
4655
|
+
from qBitrr.db_recovery import (
|
|
4656
|
+
DatabaseRecoveryError,
|
|
4657
|
+
checkpoint_wal,
|
|
4658
|
+
repair_database,
|
|
4659
|
+
vacuum_database,
|
|
4660
|
+
)
|
|
4661
|
+
from qBitrr.home_path import APPDATA_FOLDER
|
|
4662
|
+
|
|
4663
|
+
db_path = APPDATA_FOLDER / "qbitrr.db"
|
|
4664
|
+
|
|
4665
|
+
self.logger.info("Starting enhanced database recovery procedure...")
|
|
4666
|
+
|
|
4667
|
+
# Step 1: Try WAL checkpoint
|
|
4668
|
+
self.logger.info("Step 1/3: Attempting WAL checkpoint...")
|
|
4669
|
+
if checkpoint_wal(db_path, self.logger):
|
|
4670
|
+
self.logger.info("WAL checkpoint successful")
|
|
4671
|
+
# Try a quick health check
|
|
4672
|
+
from qBitrr.db_lock import check_database_health
|
|
4673
|
+
|
|
4674
|
+
healthy, msg = check_database_health(db_path, self.logger)
|
|
4675
|
+
if healthy:
|
|
4676
|
+
self.logger.info("Database health verified - recovery complete")
|
|
4677
|
+
return
|
|
4678
|
+
else:
|
|
4679
|
+
self.logger.warning(
|
|
4680
|
+
"WAL checkpoint completed but database still unhealthy: %s", msg
|
|
4681
|
+
)
|
|
4682
|
+
|
|
4683
|
+
# Step 2: Try VACUUM (only if WAL didn't fully fix it)
|
|
4684
|
+
self.logger.info("Step 2/3: Attempting VACUUM to reclaim space and fix minor issues...")
|
|
4685
|
+
if vacuum_database(db_path, self.logger):
|
|
4686
|
+
self.logger.info("VACUUM completed successfully")
|
|
4687
|
+
from qBitrr.db_lock import check_database_health
|
|
4688
|
+
|
|
4689
|
+
healthy, msg = check_database_health(db_path, self.logger)
|
|
4690
|
+
if healthy:
|
|
4691
|
+
self.logger.info("Database health verified after VACUUM - recovery complete")
|
|
4692
|
+
return
|
|
4693
|
+
else:
|
|
4694
|
+
self.logger.warning("VACUUM completed but database still unhealthy: %s", msg)
|
|
4695
|
+
|
|
4696
|
+
# Step 3: Try full repair (most invasive)
|
|
4697
|
+
self.logger.warning("Step 3/3: Attempting full database repair (dump/restore)...")
|
|
4698
|
+
try:
|
|
4699
|
+
if repair_database(db_path, backup=True, logger_override=self.logger):
|
|
4700
|
+
self.logger.info("Database repair successful")
|
|
4701
|
+
# Final health check
|
|
4702
|
+
from qBitrr.db_lock import check_database_health
|
|
4703
|
+
|
|
4704
|
+
healthy, msg = check_database_health(db_path, self.logger)
|
|
4705
|
+
if healthy:
|
|
4706
|
+
self.logger.info("Database health verified after repair - recovery complete")
|
|
4707
|
+
return
|
|
4708
|
+
else:
|
|
4709
|
+
self.logger.error("Repair completed but database still unhealthy: %s", msg)
|
|
4710
|
+
raise DatabaseRecoveryError(f"Database unhealthy after repair: {msg}")
|
|
4711
|
+
except DatabaseRecoveryError as e:
|
|
4712
|
+
self.logger.error("Database repair failed: %s", e)
|
|
4713
|
+
raise
|
|
4714
|
+
except Exception as e:
|
|
4715
|
+
self.logger.error("Unexpected error during database repair: %s", e)
|
|
4716
|
+
raise
|
|
4717
|
+
|
|
4718
|
+
# If we reach here, all recovery methods failed
|
|
4719
|
+
raise DatabaseRecoveryError("All automatic recovery methods failed")
|
|
4720
|
+
|
|
4569
4721
|
def _process_single_torrent_failed_cat(self, torrent: qbittorrentapi.TorrentDictionary):
|
|
4570
4722
|
self.logger.notice(
|
|
4571
4723
|
"Deleting manually failed torrent: "
|