Merge pull request #677 from StuffAnThings/develop

4.1.12
This commit is contained in:
bobokun 2024-10-19 09:48:02 -04:00 committed by GitHub
commit 00ce5c6c30
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 91 additions and 23 deletions

View file

@ -1,7 +1,7 @@
---
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.6.0
rev: v5.0.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
@ -38,12 +38,12 @@ repos:
name: isort (python)
args: [--force-single-line-imports, --profile, black]
- repo: https://github.com/asottile/pyupgrade
rev: v3.17.0
rev: v3.18.0
hooks:
- id: pyupgrade
args: [--py3-plus]
- repo: https://github.com/psf/black
rev: 24.8.0
rev: 24.10.0
hooks:
- id: black
language_version: python3
@ -60,4 +60,4 @@ repos:
entry: ./scripts/pre-commit/increase_version.sh
language: script
pass_filenames: false
stages: [commit]
stages: [pre-commit]

View file

@ -1,11 +1,11 @@
# Requirements Updated
humanize==4.11.0
# New Updates
- Adds new config option `disable_qbt_default_share_limits` to allow qbit_manage to handle share limits and disable qbittorrent's default share limits
- Adds new config option `max_orphaned_files_to_delete` to set default safeguards against mass deletion when running remove orphaned.
- Adds new environment variables `QBT_LOG_SIZE` and `QBT_LOG_COUNT` to customize log retention (Closes #656)
- Adds new script to remove cross-seed tag (`scripts/remove_cross-seed_tag.py`)
# Bug Fixes
- Truncates Recyclebin JSON filename when its too long. (Closes #604)
- Uses Qbittorrent's torrent export to save .torrent files for qbittorrent version > 4.5.0 (Closes #650)
- Include orphaned files and recycle bin in the list of folders to ignore when looking for noHL (Closes #660)
- List orphaned files when reaches max threshold. (Closes #672)
- Removing empty directories now ignores exclude patterns (Closes #624)
**Full Changelog**: https://github.com/StuffAnThings/qbit_manage/compare/v4.1.10...v4.1.11
**Full Changelog**: https://github.com/StuffAnThings/qbit_manage/compare/v4.1.11...v4.1.12

View file

@ -1,7 +1,7 @@
{
"master": {
"qbit": "v4.6.6",
"qbitapi": "2024.8.65"
"qbit": "v5.0.0",
"qbitapi": "2024.9.67"
},
"develop": {
"qbit": "v5.0.0",

View file

@ -1 +1 @@
4.1.11
4.1.12

View file

@ -29,7 +29,8 @@ class RemoveOrphaned:
logger.separator("Checking for Orphaned Files", space=False, border=False)
torrent_files = []
orphaned_files = []
excluded_orphan_files = []
excluded_orphan_files = set()
exclude_patterns = []
root_files = self.executor.submit(util.get_root_files, self.root_dir, self.remote_dir, self.orphaned_dir)
@ -54,11 +55,13 @@ class RemoveOrphaned:
exclude_pattern.replace(self.remote_dir, self.root_dir)
for exclude_pattern in self.config.orphaned["exclude_patterns"]
]
excluded_orphan_files = [
file for file in orphaned_files for exclude_pattern in exclude_patterns if fnmatch(file, exclude_pattern)
]
orphaned_files = set(orphaned_files) - set(excluded_orphan_files)
for file in orphaned_files:
for exclude_pattern in exclude_patterns:
if fnmatch(file, exclude_pattern):
excluded_orphan_files.add(file)
orphaned_files = orphaned_files - excluded_orphan_files
# Check the threshold before deleting orphaned files
max_orphaned_files_to_delete = self.config.orphaned.get("max_orphaned_files_to_delete")
@ -69,6 +72,7 @@ class RemoveOrphaned:
"Aborting deletion to avoid accidental data loss."
)
self.config.notify(e, "Remove Orphaned", False)
logger.debug(f"Orphaned files detected: {orphaned_files}")
logger.warning(e)
return
elif orphaned_files:
@ -104,7 +108,9 @@ class RemoveOrphaned:
orphaned_parent_path = set(self.executor.map(self.handle_orphaned_files, orphaned_files))
logger.print_line("Removing newly empty directories", self.config.loglevel)
self.executor.map(
lambda directory: util.remove_empty_directories(directory, self.qbt.get_category_save_paths()),
lambda directory: util.remove_empty_directories(
directory, self.qbt.get_category_save_paths(), exclude_patterns
),
orphaned_parent_path,
)

View file

@ -6,6 +6,7 @@ import os
import shutil
import signal
import time
from fnmatch import fnmatch
from pathlib import Path
import requests
@ -486,7 +487,7 @@ def copy_files(src, dest):
logger.error(ex)
def remove_empty_directories(pathlib_root_dir, excluded_paths=None):
def remove_empty_directories(pathlib_root_dir, excluded_paths=None, exclude_patterns=[]):
"""Remove empty directories recursively, optimized version."""
pathlib_root_dir = Path(pathlib_root_dir)
if excluded_paths is not None:
@ -499,6 +500,14 @@ def remove_empty_directories(pathlib_root_dir, excluded_paths=None):
if excluded_paths and root_path in excluded_paths:
continue
exclude_pattern_match = False
for exclude_pattern in exclude_patterns:
if fnmatch(os.path.join(root, ""), exclude_pattern):
exclude_pattern_match = True
break
if exclude_pattern_match:
continue
# Attempt to remove the directory if it's empty
try:
os.rmdir(root)

View file

@ -1,2 +1,2 @@
flake8==7.1.1
pre-commit==3.8.0
pre-commit==4.0.1

View file

@ -1,7 +1,7 @@
bencodepy==0.9.5
croniter==3.0.3
GitPython==3.1.43
humanize==4.10.0
humanize==4.11.0
pytimeparse2==1.7.1
qbittorrent-api==2024.9.67
requests==2.32.3

View file

@ -0,0 +1,53 @@
#!/usr/bin/env python3
import os
# USES ENVIRONMENTAL VARIABLES, IF NONE ARE PRESENT WILL FALLBACK TO THE SECOND STRING
QBIT_HOST = os.getenv("QBT_HOST", "http://localhost:8080")
QBIT_USERNAME = os.getenv("QBT_USERNAME", "admin")
QBIT_PASSWORD = os.getenv("QBT_PASSWORD", "YOURPASSWORD")
CRED = "\033[91m"
CGREEN = "\33[32m"
CEND = "\033[0m"
CROSS_SEED_TAG = "cross-seed"
def split(separator, data):
if data is None:
return None
else:
return [item.strip() for item in str(data).split(separator)]
try:
from qbittorrentapi import APIConnectionError
from qbittorrentapi import Client
from qbittorrentapi import LoginFailed
except ModuleNotFoundError:
print('Error: qbittorrent-api not installed. Please install using the command "pip install qbittorrent-api"')
exit(1)
try:
qbt_client = Client(host=QBIT_HOST, username=QBIT_USERNAME, password=QBIT_PASSWORD)
except LoginFailed:
raise "Qbittorrent Error: Failed to login. Invalid username/password."
except APIConnectionError:
raise "Qbittorrent Error: Unable to connect to the client."
except Exception:
raise "Qbittorrent Error: Unable to connect to the client."
print("qBittorrent:", qbt_client.app_version())
print("qBittorrent Web API:", qbt_client.app_web_api_version())
print()
torrents_list = qbt_client.torrents.info(sort="added_on", reverse=True)
print("Total torrents:", len(torrents_list))
print()
for torrent in torrents_list:
torrent_tags = split(",", torrent.tags)
if CROSS_SEED_TAG in torrent_tags:
print(CGREEN, "remove cross-seed tag:", torrent.name, CEND)
torrent.remove_tags(tags=CROSS_SEED_TAG)