* 4.2.1-develop1

* Adds #747

* Fixes #764

* Replaced pre-commit hooks flake8, black, pyupgrade, etc. with ruff for linting and formatting.

* Bump ruff from 0.9.10 to 0.10.0 (#767)

Bumps [ruff](https://github.com/astral-sh/ruff) from 0.9.10 to 0.10.0.
- [Release notes](https://github.com/astral-sh/ruff/releases)
- [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md)
- [Commits](https://github.com/astral-sh/ruff/compare/0.9.10...0.10.0)

---
updated-dependencies:
- dependency-name: ruff
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* 4.2.1

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
This commit is contained in:
bobokun 2025-03-16 19:07:25 -04:00 committed by GitHub
parent fc24d1d934
commit 8478409027
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
23 changed files with 134 additions and 96 deletions

View file

@ -1,7 +0,0 @@
[flake8]
extend-ignore =
# E722 Do not use bare except, specify exception instead
E722,
# E402 module level import not at top of file
E402,
max-line-length = 130

View file

@ -28,3 +28,12 @@ jobs:
- name: Run pre-commit version check
run: |
pre-commit run increase-version --all-files
ruff:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: astral-sh/ruff-action@v3
with:
token: ${{ secrets.GITHUB_TOKEN }}
command: 'ruff check'

View file

@ -8,18 +8,11 @@ repos:
- id: check-merge-conflict
- id: check-json
- id: check-yaml
- id: debug-statements
- id: requirements-txt-fixer
- id: check-added-large-files
- id: fix-byte-order-marker
- id: fix-encoding-pragma
args: [--remove]
- id: pretty-format-json
args: [--autofix, --indent, '4', --no-sort-keys]
- repo: https://github.com/hhatto/autopep8
rev: v2.3.2
hooks:
- id: autopep8
- repo: https://github.com/adrienverge/yamllint.git
rev: v1.35.1 # or higher tag
hooks:
@ -31,28 +24,15 @@ repos:
hooks:
- id: yamlfix
exclude: ^.github/
- repo: https://github.com/pycqa/isort
rev: 6.0.0
- repo: https://github.com/astral-sh/ruff-pre-commit
# Ruff version.
rev: v0.9.10
hooks:
- id: isort
name: isort (python)
args: [--force-single-line-imports, --profile, black]
- repo: https://github.com/asottile/pyupgrade
rev: v3.19.1
hooks:
- id: pyupgrade
args: [--py3-plus]
- repo: https://github.com/psf/black
rev: 25.1.0
hooks:
- id: black
language_version: python3
args: [--line-length, '130']
- repo: https://github.com/PyCQA/flake8
rev: 7.1.2
hooks:
- id: flake8
args: [--config=.flake8]
# Run the linter.
- id: ruff
args: [--fix]
# Run the formatter.
- id: ruff-format
- repo: local
hooks:
- id: increase-version

View file

@ -1,9 +1,8 @@
# New Updates
- Removes deprecated cross-seed command/function (#758)
- Adds ability to tag stalled downloads (#757)
- Adds ability to customize a list of status to ignore during rem_unregistered command (#756)
- Adds new command to filter for completed torrents only for rem_unregistered (#747)
- Replace flake8/black with ruff for lint and formatting
# Bug Fixes
- Fixes bug in Windows during category updates (#755)
- Fixes bug in tagging `stalledDL` torrents when set to False (#764)
**Full Changelog**: https://github.com/StuffAnThings/qbit_manage/compare/v4.1.18...v4.2.0
**Full Changelog**: https://github.com/StuffAnThings/qbit_manage/compare/v4.2.0...v4.2.1

View file

@ -8,7 +8,7 @@
[![Ghcr packages](https://img.shields.io/badge/ghcr.io-packages?style=plastic&label=packages)](https://ghcr.io/StuffAnThings/qbit_manage)
[![Docker Pulls](https://img.shields.io/docker/pulls/bobokun/qbit_manage?style=plastic)](https://hub.docker.com/r/bobokun/qbit_manage)
[![Sponsor or Donate](https://img.shields.io/badge/-Sponsor_or_Donate-blueviolet?style=plastic)](https://github.com/sponsors/bobokun)
[![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)
This is a program used to manage your qBittorrent instance such as:
* Tag torrents based on tracker URLs

View file

@ -1 +1 @@
4.2.0
4.2.1

View file

@ -39,6 +39,7 @@ settings:
cat_filter_completed: True # Filters for completed torrents only when running cat_update command
share_limits_filter_completed: True # Filters for completed torrents only when running share_limits command
tag_nohardlinks_filter_completed: True # Filters for completed torrents only when running tag_nohardlinks command
rem_unregistered_filter_completed: False # Filters for completed torrents only when running rem_unregistered command
cat_update_all: True # Checks and updates all torrent categories if set to True when running cat_update command, otherwise only update torrents that are uncategorized
disable_qbt_default_share_limits: True # Allows QBM to handle share limits by disabling qBittorrents default Share limits. Only active when the share_limits command is set to True
tag_stalled_torrents: True # Tags any downloading torrents that are stalled with the `stalledDL` tag when running the tag_update command

View file

@ -223,6 +223,9 @@ class Config:
"tag_nohardlinks_filter_completed": self.util.check_for_attribute(
self.data, "tag_nohardlinks_filter_completed", parent="settings", var_type="bool", default=True
),
"rem_unregistered_filter_completed": self.util.check_for_attribute(
self.data, "rem_unregistered_filter_completed", parent="settings", var_type="bool", default=False
),
"cat_update_all": self.util.check_for_attribute(
self.data, "cat_update_all", parent="settings", var_type="bool", default=True
),
@ -847,7 +850,8 @@ class Config:
try:
fileStats = os.stat(file)
filename = os.path.basename(file)
last_modified = fileStats[stat.ST_MTIME] # in seconds (last modified time)
# in seconds (last modified time)
last_modified = fileStats[stat.ST_MTIME]
except FileNotFoundError:
ex = logger.print_line(
f"{location} Warning - FileNotFound: No such file or directory: {file} ", "WARNING"

View file

@ -84,7 +84,7 @@ class Category:
else:
title = "Updating Categories"
body += logger.print_line(logger.insert_space(f"New Category: {new_cat}", 3), self.config.loglevel)
body += logger.print_line(logger.insert_space(f'Tracker: {tracker["url"]}', 8), self.config.loglevel)
body += logger.print_line(logger.insert_space(f"Tracker: {tracker['url']}", 8), self.config.loglevel)
attr = {
"function": "cat_update",
"title": title,

View file

@ -14,7 +14,8 @@ class ReCheck:
self.stats_rechecked = 0
self.torrents_updated_recheck = [] # List of torrents updated
self.notify_attr_recheck = [] # List of single torrent attributes to send to notifiarr
# List of single torrent attributes to send to notifiarr
self.notify_attr_recheck = []
self.torrents_updated_resume = [] # List of torrents updated
self.notify_attr_resume = [] # List of single torrent attributes to send to notifiarr

View file

@ -22,6 +22,7 @@ class RemoveUnregistered:
self.cfg_rem_unregistered = self.config.commands["rem_unregistered"]
self.cfg_tag_error = self.config.commands["tag_tracker_error"]
self.rem_unregistered_ignore_list = self.config.settings["rem_unregistered_ignore_list"]
self.filter_completed = self.config.settings["rem_unregistered_filter_completed"]
tag_error_msg = "Tagging Torrents with Tracker Errors" if self.cfg_tag_error else ""
rem_unregistered_msg = "Removing Unregistered Torrents" if self.cfg_rem_unregistered else ""
@ -56,7 +57,7 @@ class RemoveUnregistered:
)
body += logger.print_line(logger.insert_space(f"Torrent Name: {t_name}", 3), self.config.loglevel)
body += logger.print_line(logger.insert_space(f"Removed Tag: {self.tag_error}", 4), self.config.loglevel)
body += logger.print_line(logger.insert_space(f'Tracker: {tracker["url"]}', 8), self.config.loglevel)
body += logger.print_line(logger.insert_space(f"Tracker: {tracker['url']}", 8), self.config.loglevel)
if not self.config.dry_run:
torrent.remove_tags(tags=self.tag_error)
attr = {
@ -108,6 +109,8 @@ class RemoveUnregistered:
self.t_status = self.qbt.torrentinfo[self.t_name]["status"]
check_tags = util.get_list(torrent.tags)
try:
if self.filter_completed and not torrent.state_enum.is_complete:
continue
tracker_working = False
for trk in torrent.trackers:
if (
@ -190,7 +193,7 @@ class RemoveUnregistered:
tor_error = ""
tor_error += logger.insert_space(f"Torrent Name: {self.t_name}", 3) + "\n"
tor_error += logger.insert_space(f"Status: {msg}", 9) + "\n"
tor_error += logger.insert_space(f'Tracker: {tracker["url"]}', 8) + "\n"
tor_error += logger.insert_space(f"Tracker: {tracker['url']}", 8) + "\n"
tor_error += logger.insert_space(f"Added Tag: {self.tag_error}", 6) + "\n"
self.tor_error_summary += tor_error
self.stats_tagged += 1
@ -215,7 +218,7 @@ class RemoveUnregistered:
body = []
body += logger.print_line(logger.insert_space(f"Torrent Name: {self.t_name}", 3), self.config.loglevel)
body += logger.print_line(logger.insert_space(f"Status: {msg}", 9), self.config.loglevel)
body += logger.print_line(logger.insert_space(f'Tracker: {tracker["url"]}', 8), self.config.loglevel)
body += logger.print_line(logger.insert_space(f"Tracker: {tracker['url']}", 8), self.config.loglevel)
attr = {
"function": "rem_unregistered",
"title": "Removing Unregistered Torrents",

View file

@ -21,17 +21,24 @@ class ShareLimits:
# meets the criteria for ratio limit/seed limit for deletion including contents \
self.status_filter = "completed" if self.config.settings["share_limits_filter_completed"] else "all"
self.tdel_dict = {} # dictionary to track the torrent names and content path that meet the deletion criteria
# dictionary to track the torrent names and content path that meet the deletion criteria
self.tdel_dict = {}
self.root_dir = qbit_manager.config.root_dir # root directory of torrents
self.remote_dir = qbit_manager.config.remote_dir # remote directory of torrents
self.share_limits_config = qbit_manager.config.share_limits # configuration of share limits
# configuration of share limits
self.share_limits_config = qbit_manager.config.share_limits
self.torrents_updated = [] # list of torrents that have been updated
self.torrent_hash_checked = [] # list of torrent hashes that have been checked for share limits
# list of torrent hashes that have been checked for share limits
self.torrent_hash_checked = []
self.share_limits_tag = qbit_manager.config.share_limits_tag # tag for share limits
self.share_limits_custom_tags = qbit_manager.config.share_limits_custom_tags # All possible custom share limits tags
self.min_seeding_time_tag = qbit_manager.config.share_limits_min_seeding_time_tag # tag for min seeding time
self.min_num_seeds_tag = qbit_manager.config.share_limits_min_num_seeds_tag # tag for min num seeds
self.last_active_tag = qbit_manager.config.share_limits_last_active_tag # tag for last active
# All possible custom share limits tags
self.share_limits_custom_tags = qbit_manager.config.share_limits_custom_tags
# tag for min seeding time
self.min_seeding_time_tag = qbit_manager.config.share_limits_min_seeding_time_tag
# tag for min num seeds
self.min_num_seeds_tag = qbit_manager.config.share_limits_min_num_seeds_tag
# tag for last active
self.last_active_tag = qbit_manager.config.share_limits_last_active_tag
self.group_tag = None # tag for the share limit group
self.update_share_limits()
@ -87,7 +94,7 @@ class ShareLimits:
tracker = self.qbt.get_tags(self.qbt.get_tracker_urls(torrent.trackers))
body = []
body += logger.print_line(logger.insert_space(f"Torrent Name: {t_name}", 3), self.config.loglevel)
body += logger.print_line(logger.insert_space(f'Tracker: {tracker["url"]}', 8), self.config.loglevel)
body += logger.print_line(logger.insert_space(f"Tracker: {tracker['url']}", 8), self.config.loglevel)
body += logger.print_line(torrent_dict["body"], self.config.loglevel)
body += logger.print_line(
logger.insert_space("Cleanup: True [Meets Share Limits]", 8),
@ -215,7 +222,8 @@ class ShareLimits:
else:
share_limits_not_yet_tagged = False
check_multiple_share_limits_tag = False # Default assume no multiple share limits tag
# Default assume no multiple share limits tag
check_multiple_share_limits_tag = False
# Check if any of the previous share limits custom tags are there
for custom_tag in self.share_limits_custom_tags:
@ -296,7 +304,7 @@ class ShareLimits:
or check_multiple_share_limits_tag
):
logger.print_line(logger.insert_space(f"Torrent Name: {t_name}", 3), self.config.loglevel)
logger.print_line(logger.insert_space(f'Tracker: {tracker["url"]}', 8), self.config.loglevel)
logger.print_line(logger.insert_space(f"Tracker: {tracker['url']}", 8), self.config.loglevel)
if self.group_tag:
logger.print_line(logger.insert_space(f"Added Tag: {self.group_tag}", 8), self.config.loglevel)
self.tag_and_update_share_limits_for_torrent(torrent, group_config)

View file

@ -9,7 +9,8 @@ class TagNoHardLinks:
self.config = qbit_manager.config
self.client = qbit_manager.client
self.stats_tagged = 0 # counter for the number of torrents that has no hardlinks
self.stats_untagged = 0 # counter for number of torrents that previously had no hardlinks but now have hardlinks
# counter for number of torrents that previously had no hardlinks but now have hardlinks
self.stats_untagged = 0
self.root_dir = qbit_manager.config.root_dir
self.remote_dir = qbit_manager.config.remote_dir
@ -20,7 +21,8 @@ class TagNoHardLinks:
self.notify_attr_tagged = [] # List of single torrent attributes to send to notifiarr
self.torrents_updated_untagged = [] # List of torrents updated
self.notify_attr_untagged = [] # List of single torrent attributes to send to notifiarr
# List of single torrent attributes to send to notifiarr
self.notify_attr_untagged = []
self.status_filter = "completed" if self.config.settings["tag_nohardlinks_filter_completed"] else "all"
@ -35,7 +37,7 @@ class TagNoHardLinks:
body.append(logger.insert_space(f"Torrent Name: {torrent.name}", 3))
body.append(logger.insert_space(f"Added Tag: {self.nohardlinks_tag}", 6))
title = "Tagging Torrents with No Hardlinks"
body.append(logger.insert_space(f'Tracker: {tracker["url"]}', 8))
body.append(logger.insert_space(f"Tracker: {tracker['url']}", 8))
if not self.config.dry_run:
torrent.add_tags(self.nohardlinks_tag)
self.stats_tagged += 1
@ -67,7 +69,7 @@ class TagNoHardLinks:
self.config.loglevel,
)
body += logger.print_line(logger.insert_space(f"Removed Tag: {self.nohardlinks_tag}", 6), self.config.loglevel)
body += logger.print_line(logger.insert_space(f'Tracker: {tracker["url"]}', 8), self.config.loglevel)
body += logger.print_line(logger.insert_space(f"Tracker: {tracker['url']}", 8), self.config.loglevel)
if not self.config.dry_run:
torrent.remove_tags(tags=self.nohardlinks_tag)
attr = {

View file

@ -9,10 +9,12 @@ class Tags:
self.config = qbit_manager.config
self.client = qbit_manager.client
self.stats = 0
self.share_limits_tag = qbit_manager.config.share_limits_tag # suffix tag for share limits
# suffix tag for share limits
self.share_limits_tag = qbit_manager.config.share_limits_tag
self.torrents_updated = [] # List of torrents updated
self.notify_attr = [] # List of single torrent attributes to send to notifiarr
self.stalled_tag = "stalledDL"
self.tag_stalled_torrents = self.config.settings["tag_stalled_torrents"]
self.tags()
self.config.webhooks_factory.notify(self.torrents_updated, self.notify_attr, group_by="tag")
@ -24,12 +26,16 @@ class Tags:
tracker = self.qbt.get_tags(self.qbt.get_tracker_urls(torrent.trackers))
# Remove stalled_tag if torrent is no longer stalled
if util.is_tag_in_torrent(self.stalled_tag, torrent.tags) and torrent.state != "stalledDL":
if (
self.tag_stalled_torrents
and util.is_tag_in_torrent(self.stalled_tag, torrent.tags)
and torrent.state != "stalledDL"
):
t_name = torrent.name
body = []
body += logger.print_line(logger.insert_space(f"Torrent Name: {t_name}", 3), self.config.loglevel)
body += logger.print_line(logger.insert_space(f"Removing Tag: {self.stalled_tag}", 3), self.config.loglevel)
body += logger.print_line(logger.insert_space(f'Tracker: {tracker["url"]}', 8), self.config.loglevel)
body += logger.print_line(logger.insert_space(f"Tracker: {tracker['url']}", 8), self.config.loglevel)
if not self.config.dry_run:
torrent.remove_tags(self.stalled_tag)
if (
@ -38,7 +44,7 @@ class Tags:
or (torrent.state == "stalledDL" and not util.is_tag_in_torrent(self.stalled_tag, torrent.tags))
):
stalled = False
if torrent.state == "stalledDL":
if self.tag_stalled_torrents and torrent.state == "stalledDL":
stalled = True
tracker["tag"].append(self.stalled_tag)
if tracker["tag"] or stalled:
@ -47,10 +53,10 @@ class Tags:
body = []
body += logger.print_line(logger.insert_space(f"Torrent Name: {t_name}", 3), self.config.loglevel)
body += logger.print_line(
logger.insert_space(f'New Tag{"s" if len(tracker["tag"]) > 1 else ""}: {", ".join(tracker["tag"])}', 8),
logger.insert_space(f"New Tag{'s' if len(tracker['tag']) > 1 else ''}: {', '.join(tracker['tag'])}", 8),
self.config.loglevel,
)
body += logger.print_line(logger.insert_space(f'Tracker: {tracker["url"]}', 8), self.config.loglevel)
body += logger.print_line(logger.insert_space(f"Tracker: {tracker['url']}", 8), self.config.loglevel)
if not self.config.dry_run:
torrent.add_tags(tracker["tag"])
category = self.qbt.get_category(torrent.save_path)[0] if torrent.category == "" else torrent.category

View file

@ -85,7 +85,7 @@ class MyLogger:
def _formatter(self, handler=None, border=True, log_only=False, space=False):
"""Format log message"""
console = f"| %(message)-{self.screen_width - 2}s |" if border else f"%(message)-{self.screen_width - 2}s"
file = f"{' '*65}" if space else "[%(asctime)s] %(filename)-27s %(levelname)-10s "
file = f"{' ' * 65}" if space else "[%(asctime)s] %(filename)-27s %(levelname)-10s "
handlers = [handler] if handler else self._logger.handlers
for h in handlers:
if not log_only or isinstance(h, RotatingFileHandler):

View file

@ -390,7 +390,7 @@ class Qbt:
self.config.data["tracker"][default_tag]["tag"] = [default_tag]
except Exception:
self.config.data["tracker"][default_tag] = {"tag": [default_tag]}
e = f'No tags matched for {tracker["url"]}. Please check your config.yml file. Setting tag to {default_tag}'
e = f"No tags matched for {tracker['url']}. Please check your config.yml file. Setting tag to {default_tag}"
self.config.notify(e, "Tag", False)
logger.warning(e)
return tracker
@ -448,8 +448,10 @@ class Qbt:
else:
recycle_path = self.config.recycle_dir
# Create recycle bin if not exists
torrent_path = os.path.join(recycle_path, "torrents") # Export torrent/fastresume from BT_backup
torrent_export_path = os.path.join(recycle_path, "torrents_export") # Exported torrent file (qbittorrent v4.5.0+)
# Export torrent/fastresume from BT_backup
torrent_path = os.path.join(recycle_path, "torrents")
# Exported torrent file (qbittorrent v4.5.0+)
torrent_export_path = os.path.join(recycle_path, "torrents_export")
torrents_json_path = os.path.join(recycle_path, "torrents_json")
torrent_name = info["torrents"][0]
torrent_exportable = self.current_version >= "v4.5.0"
@ -472,7 +474,8 @@ class Qbt:
dot_torrent_files = []
# Exporting torrent via Qbit API (v4.5.0+)
if torrent_exportable:
hash_suffix = f"{info_hash[-8:]}" # Get the last 8 hash characters of the torrent
# Get the last 8 hash characters of the torrent
hash_suffix = f"{info_hash[-8:]}"
torrent_export_file = os.path.join(torrent_export_path, f"{torrent_name} [{hash_suffix}].torrent")
truncated_torrent_export_file = util.truncate_filename(torrent_export_file, offset=11)
try:

View file

@ -1,5 +1,6 @@
#!/usr/bin/env python3
"""qBittorrent Manager."""
import argparse
import glob
import math
@ -27,8 +28,8 @@ current_version = sys.version_info
if current_version < (REQUIRED_VERSION):
print(
"Version Error: Version: %s.%s.%s incompatible with qbit_manage please use Python %s+"
% (current_version[0], current_version[1], current_version[2], REQUIRED_VERSION_STR)
f"Version Error: Version: {current_version[0]}.{current_version[1]}.{current_version[2]} incompatible with "
f"qbit_manage please use Python {REQUIRED_VERSION_STR}+"
)
sys.exit(1)
@ -450,7 +451,8 @@ def start():
end_time = datetime.now()
run_time = str(end_time - start_time).split(".", maxsplit=1)[0]
if run is False:
if is_valid_cron_syntax(sch): # Simple check to guess if it's a cron syntax
# Simple check to guess if it's a cron syntax
if is_valid_cron_syntax(sch):
next_run_time = schedule_from_cron(sch)
else:
delta = timedelta(minutes=sch)
@ -652,7 +654,8 @@ if __name__ == "__main__":
logger.info(run_mode_message)
start_loop(True)
else:
if is_valid_cron_syntax(sch): # Simple check to guess if it's a cron syntax
# Simple check to guess if it's a cron syntax
if is_valid_cron_syntax(sch):
run_mode_message = f" Scheduled Mode: Running cron '{sch}'"
next_run_time = schedule_from_cron(sch)
next_run = calc_next_run(next_run_time)

View file

@ -1,2 +1,3 @@
flake8==7.1.2
pre-commit==4.1.0
ruff==0.10.0

22
ruff.toml Normal file
View file

@ -0,0 +1,22 @@
line-length = 130
[lint]
select = [
"I", # isort - import order
"UP", # pyupgrade
"T10", # debugger
"E", # pycodestyle errors
"W", # pycodestyle warnings
"F", # pyflakes
]
ignore = [
"E722", # E722 Do not use bare except, specify exception instead
"E402", # E402 module level import not at top of file
]
[lint.isort]
force-single-line = true
[format]
line-ending = "auto"

View file

@ -14,16 +14,21 @@ import qbittorrentapi
"""===Config==="""
# qBittorrent WebUi Login
qbt_login = {"host": "localhost", "port": 8080, "username": "???", "password": "???"}
PATH = "M:" # Path of drive to monitor. Only torrents with paths that start with this may be deleted.
# Path of drive to monitor. Only torrents with paths that start with this may be deleted.
PATH = "M:"
MIN_FREE_SPACE = 10 # In GB. Min free space on drive.
MIN_FREE_USAGE = 0 # In decimal percentage, 0 to 1. Min % free space on drive.
MIN_TORRENT_SHARE_RATIO = 0 # In decimal percentage, 0 to inf. Min seeding ratio of torrent to delete.
MIN_TORRENT_AGE = 30 # In days, min age of torrent to delete. Uses seeding time.
# In decimal percentage, 0 to inf. Min seeding ratio of torrent to delete.
MIN_TORRENT_SHARE_RATIO = 0
# In days, min age of torrent to delete. Uses seeding time.
MIN_TORRENT_AGE = 30
ALLOW_INCOMPLETE_TORRENT_DELETIONS = (
False # Also delete torrents that haven't finished downloading. MIN_TORRENT_AGE now based on time active.
# Also delete torrents that haven't finished downloading. MIN_TORRENT_AGE now based on time active.
False
)
PREFER_PRIVATE_TORRENTS = (
True # Will delete public torrents before private ones regardless of seed difference. See is_torrent_public().
# Will delete public torrents before private ones regardless of seed difference. See is_torrent_public().
True
)
"""===End Config==="""
@ -171,7 +176,8 @@ def main():
qbt_client.torrents_delete(torrent_hashes=torrent_hash, delete_files=True)
deleted_torrents.append(torrent_name)
print(f"--- {torrent_name}")
time.sleep(1) # Sleep a bit after each deletion to make sure disk usage is updated.
# Sleep a bit after each deletion to make sure disk usage is updated.
time.sleep(1)
# Print results
print_free_space()

View file

@ -9,7 +9,8 @@ qbt_host = "qbittorrent:8080"
qbt_user = None
qbt_pass = None
OLD_TRACKER = "https://blutopia.xyz" # This is the tracker you want to replace
NEW_TRACKER = "https://blutopia.cc" # This is the tracker you want to replace it with
# This is the tracker you want to replace it with
NEW_TRACKER = "https://blutopia.cc"
# --DEFINE VARIABLES--#
# --START SCRIPT--#

View file

@ -10,6 +10,9 @@ fi
if git diff --cached --name-only | grep -q "VERSION"; then
echo "The VERSION file is already modified. Skipping version update."
exit 0
elif git diff --name-only | grep -q "VERSION"; then
echo "The VERSION file has unstaged changes. Please stage them before committing."
exit 0
fi
# Read the current version from the VERSION file

15
tox.ini
View file

@ -1,5 +1,5 @@
[tox]
envlist = py39,py310,py311,py312,pre-commit
envlist = py39,py310,py311,py312,py313,pre-commit
skip_missing_interpreters = true
tox_pip_extensions_ext_pip_custom_platform = true
tox_pip_extensions_ext_venv_update = true
@ -27,13 +27,6 @@ commands =
pre-commit install -f --install-hooks
pre-commit run --all-files
[flake8]
max-line-length = 130
[pep8]
extend-ignore = E722,E402
[tool.isort]
add_imports = ["from __future__ import annotations"]
force_single_line = true
profile = "black"
[testenv:ruff]
deps = ruff
commands = ruff check .