mirror of
https://github.com/StuffAnThings/qbit_manage.git
synced 2025-10-11 06:16:35 +08:00
* 4.1.16-develop1 * Update SUPPORTED_VERSIONS.json for master (#724) * 4.1.15-develop1 * Update SUPPORTED_VERSIONS.json for master (#706) * 4.1.14-develop1 * Update SUPPORTED_VERSIONS.json for master (#692) * 4.1.13-develop * Bump croniter from 3.0.3 to 3.0.4 (#680) Bumps [croniter](https://github.com/kiorky/croniter) from 3.0.3 to 3.0.4. - [Changelog](https://github.com/kiorky/croniter/blob/master/CHANGELOG.rst) - [Commits](https://github.com/kiorky/croniter/compare/3.0.3...3.0.4) --- updated-dependencies: - dependency-name: croniter dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump qbittorrent-api from 2024.9.67 to 2024.10.68 (#684) Bumps [qbittorrent-api](https://github.com/rmartin16/qbittorrent-api) from 2024.9.67 to 2024.10.68. - [Release notes](https://github.com/rmartin16/qbittorrent-api/releases) - [Changelog](https://github.com/rmartin16/qbittorrent-api/blob/main/CHANGELOG.md) - [Commits](https://github.com/rmartin16/qbittorrent-api/compare/v2024.9.67...v2024.10.68) --- updated-dependencies: - dependency-name: qbittorrent-api dependency-type: direct:production 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> * Update SUPPORTED_VERSIONS.json * bump develop * (ci): add ci for version bump on develop (#688) * Fixes bug in torrent exporting for qbit versions under 4.5.0 * Bump actions/checkout from 3 to 4 (#690) * Bump actions/setup-python from 3 to 5 (#689) * Bump croniter from 3.0.4 to 5.0.1 (#685) * [pre-commit.ci] pre-commit autoupdate (#682) * 4.1.13 * Update SUPPORTED_VERSIONS.json --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: bobokun <jon.cy.lee98@gmail.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Co-authored-by: bobokun <12660469+bobokun@users.noreply.github.com> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> * chore(docs): Sync wiki to docs [skip-cd] * Bump qbittorrent-api from 2024.10.68 to 2024.11.69 (#693) * Bump qbittorrent-api from 2024.10.68 to 2024.11.69 Bumps [qbittorrent-api](https://github.com/rmartin16/qbittorrent-api) from 2024.10.68 to 2024.11.69. - [Release notes](https://github.com/rmartin16/qbittorrent-api/releases) - [Changelog](https://github.com/rmartin16/qbittorrent-api/blob/main/CHANGELOG.md) - [Commits](https://github.com/rmartin16/qbittorrent-api/compare/v2024.10.68...v2024.11.69) --- updated-dependencies: - dependency-name: qbittorrent-api dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> * bump develop (#694) * chore: bump qbittorrent-api (#697) * chore: bump qbittorrent-api * Update VERSION * Update SUPPORTED_VERSIONS.json * chore(docs): Sync wiki to docs [skip-cd] * 4.1.14 * Update SUPPORTED_VERSIONS.json * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: bobokun <jon.cy.lee98@gmail.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Co-authored-by: bobokun <12660469+bobokun@users.noreply.github.com> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Actionbot <actions@github.com> * (fix): BHD add additional unregistered messages for season packs (#707) * (fix): BHD add additional unregistered messages for season packs * Update VERSION * docs: update README.md (#708) * Update README.md Fixed small typo * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> * (bhd): handle additional season pack unregistered (#709) * (bhd): handle additional season pack unregistered "COMPLETE SEASON UPLOADED" did not match Complete Season Uploaded: https://beyond-hd.me/torrents/[link] * fixup! * Bump qbittorrent-api from 2024.11.70 to 2024.12.71 (#712) Bumps [qbittorrent-api](https://github.com/rmartin16/qbittorrent-api) from 2024.11.70 to 2024.12.71. - [Release notes](https://github.com/rmartin16/qbittorrent-api/releases) - [Changelog](https://github.com/rmartin16/qbittorrent-api/blob/main/CHANGELOG.md) - [Commits](https://github.com/rmartin16/qbittorrent-api/compare/v2024.11.70...v2024.12.71) --- updated-dependencies: - dependency-name: qbittorrent-api dependency-type: direct:production 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> * bump 4.1.15-develop4 * Update SUPPORTED_VERSIONS.json * Bump croniter from 5.0.1 to 6.0.0 (#711) * Fix help description for --rem-orphaned argument (#716) * Bump ruamel-yaml from 0.18.6 to 0.18.7 (#720) Bumps ruamel-yaml from 0.18.6 to 0.18.7. --- updated-dependencies: - dependency-name: ruamel-yaml dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump ruamel-yaml from 0.18.7 to 0.18.8 (#721) Bumps ruamel-yaml from 0.18.7 to 0.18.8. --- updated-dependencies: - dependency-name: ruamel-yaml dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump gitpython from 3.1.43 to 3.1.44 (#722) Bumps [gitpython](https://github.com/gitpython-developers/GitPython) from 3.1.43 to 3.1.44. - [Release notes](https://github.com/gitpython-developers/GitPython/releases) - [Changelog](https://github.com/gitpython-developers/GitPython/blob/main/CHANGES) - [Commits](https://github.com/gitpython-developers/GitPython/compare/3.1.43...3.1.44) --- updated-dependencies: - dependency-name: gitpython dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * [pre-commit.ci] pre-commit autoupdate (#715) * [pre-commit.ci] pre-commit autoupdate updates: - [github.com/asottile/pyupgrade: v3.19.0 → v3.19.1](https://github.com/asottile/pyupgrade/compare/v3.19.0...v3.19.1) * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: bobokun <12660469+bobokun@users.noreply.github.com> * Fixes #719 * 4.1.15 * Update SUPPORTED_VERSIONS.json * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: bobokun <jon.cy.lee98@gmail.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Co-authored-by: bobokun <12660469+bobokun@users.noreply.github.com> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Actionbot <actions@github.com> Co-authored-by: tanka8 <tanka8@gmail.com> Co-authored-by: Michael Brünen <34708235+OddMagnet@users.noreply.github.com> * Adds #695 * Bump ruamel-yaml from 0.18.8 to 0.18.9 (#725) Bumps ruamel-yaml from 0.18.8 to 0.18.9. --- updated-dependencies: - dependency-name: ruamel-yaml dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump ruamel-yaml from 0.18.9 to 0.18.10 (#727) Bumps ruamel-yaml from 0.18.9 to 0.18.10. --- updated-dependencies: - dependency-name: ruamel-yaml dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * log orphaned files detected in info instead of debug * Bump pre-commit from 4.0.1 to 4.1.0 (#735) Bumps [pre-commit](https://github.com/pre-commit/pre-commit) from 4.0.1 to 4.1.0. - [Release notes](https://github.com/pre-commit/pre-commit/releases) - [Changelog](https://github.com/pre-commit/pre-commit/blob/main/CHANGELOG.md) - [Commits](https://github.com/pre-commit/pre-commit/compare/v4.0.1...v4.1.0) --- updated-dependencies: - dependency-name: pre-commit 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> * Bump dependabot/fetch-metadata from 2.2.0 to 2.3.0 (#739) Bumps [dependabot/fetch-metadata](https://github.com/dependabot/fetch-metadata) from 2.2.0 to 2.3.0. - [Release notes](https://github.com/dependabot/fetch-metadata/releases) - [Commits](https://github.com/dependabot/fetch-metadata/compare/v2.2.0...v2.3.0) --- updated-dependencies: - dependency-name: dependabot/fetch-metadata dependency-type: direct:production 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> * [pre-commit.ci] pre-commit autoupdate (#734) updates: - [github.com/hhatto/autopep8: v2.3.1 → v2.3.2](https://github.com/hhatto/autopep8/compare/v2.3.1...v2.3.2) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> * 4.1.16 --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Actionbot <actions@github.com> Co-authored-by: tanka8 <tanka8@gmail.com> Co-authored-by: Michael Brünen <34708235+OddMagnet@users.noreply.github.com>
146 lines
6.3 KiB
Python
146 lines
6.3 KiB
Python
import os
|
|
from concurrent.futures import ThreadPoolExecutor
|
|
from fnmatch import fnmatch
|
|
|
|
from modules import util
|
|
|
|
logger = util.logger
|
|
|
|
|
|
class RemoveOrphaned:
|
|
def __init__(self, qbit_manager):
|
|
self.qbt = qbit_manager
|
|
self.config = qbit_manager.config
|
|
self.client = qbit_manager.client
|
|
self.stats = 0
|
|
|
|
self.remote_dir = qbit_manager.config.remote_dir
|
|
self.root_dir = qbit_manager.config.root_dir
|
|
self.orphaned_dir = qbit_manager.config.orphaned_dir
|
|
|
|
max_workers = max(os.cpu_count() - 1, 1)
|
|
self.executor = ThreadPoolExecutor(max_workers=max_workers)
|
|
self.rem_orphaned()
|
|
self.executor.shutdown()
|
|
|
|
def rem_orphaned(self):
|
|
"""Remove orphaned files from remote directory"""
|
|
self.stats = 0
|
|
logger.separator("Checking for Orphaned Files", space=False, border=False)
|
|
torrent_files = []
|
|
orphaned_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)
|
|
|
|
# Get an updated list of torrents
|
|
logger.print_line("Locating orphan files", self.config.loglevel)
|
|
torrent_list = self.qbt.get_torrents({"sort": "added_on"})
|
|
|
|
torrent_files.extend(
|
|
[
|
|
fullpath
|
|
for fullpathlist in self.executor.map(self.get_full_path_of_torrent_files, torrent_list)
|
|
for fullpath in fullpathlist
|
|
]
|
|
)
|
|
root_files_set = set(root_files.result())
|
|
torrent_files_set = set(torrent_files)
|
|
orphaned_files = root_files_set - torrent_files_set
|
|
|
|
if self.config.orphaned["exclude_patterns"]:
|
|
logger.print_line("Processing orphan exclude patterns")
|
|
exclude_patterns = [
|
|
exclude_pattern.replace(self.remote_dir, self.root_dir)
|
|
for exclude_pattern in self.config.orphaned["exclude_patterns"]
|
|
]
|
|
|
|
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")
|
|
if len(orphaned_files) and len(orphaned_files) > max_orphaned_files_to_delete and max_orphaned_files_to_delete != -1:
|
|
e = (
|
|
f"Too many orphaned files detected ({len(orphaned_files)}). "
|
|
f"Max Threshold for deletion is set to {max_orphaned_files_to_delete}. "
|
|
"Aborting deletion to avoid accidental data loss."
|
|
)
|
|
self.config.notify(e, "Remove Orphaned", False)
|
|
logger.info(f"Orphaned files detected: {orphaned_files}")
|
|
logger.warning(e)
|
|
return
|
|
elif orphaned_files:
|
|
orphaned_files = sorted(orphaned_files)
|
|
os.makedirs(self.orphaned_dir, exist_ok=True)
|
|
body = []
|
|
num_orphaned = len(orphaned_files)
|
|
logger.print_line(f"{num_orphaned} Orphaned files found", self.config.loglevel)
|
|
body += logger.print_line("\n".join(orphaned_files), self.config.loglevel)
|
|
if self.config.orphaned["empty_after_x_days"] == 0:
|
|
body += logger.print_line(
|
|
f"{'Not Deleting' if self.config.dry_run else 'Deleting'} {num_orphaned} Orphaned files",
|
|
self.config.loglevel,
|
|
)
|
|
else:
|
|
body += logger.print_line(
|
|
f"{'Not moving' if self.config.dry_run else 'Moving'} {num_orphaned} Orphaned files "
|
|
f"to {self.orphaned_dir.replace(self.remote_dir, self.root_dir)}",
|
|
self.config.loglevel,
|
|
)
|
|
|
|
attr = {
|
|
"function": "rem_orphaned",
|
|
"title": f"Removing {num_orphaned} Orphaned Files",
|
|
"body": "\n".join(body),
|
|
"orphaned_files": list(orphaned_files),
|
|
"orphaned_directory": self.orphaned_dir.replace(self.remote_dir, self.root_dir),
|
|
"total_orphaned_files": num_orphaned,
|
|
}
|
|
self.config.send_notifications(attr)
|
|
# Delete empty directories after moving orphan files
|
|
if not self.config.dry_run:
|
|
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(), exclude_patterns
|
|
),
|
|
orphaned_parent_path,
|
|
)
|
|
|
|
else:
|
|
logger.print_line("No Orphaned Files found.", self.config.loglevel)
|
|
|
|
def handle_orphaned_files(self, file):
|
|
src = file.replace(self.root_dir, self.remote_dir)
|
|
dest = os.path.join(self.orphaned_dir, file.replace(self.root_dir, ""))
|
|
orphaned_parent_path = os.path.dirname(file).replace(self.root_dir, self.remote_dir)
|
|
|
|
"""Delete orphaned files directly if empty_after_x_days is set to 0"""
|
|
if self.config.orphaned["empty_after_x_days"] == 0:
|
|
try:
|
|
util.delete_files(src)
|
|
except Exception:
|
|
logger.error(f"Error deleting orphaned file: {file}")
|
|
util.move_files(src, dest, True)
|
|
else: # Move orphaned files to orphaned directory
|
|
util.move_files(src, dest, True)
|
|
return orphaned_parent_path
|
|
|
|
def get_full_path_of_torrent_files(self, torrent):
|
|
torrent_files = map(lambda dict: dict.name, torrent.files)
|
|
save_path = torrent.save_path
|
|
|
|
fullpath_torrent_files = []
|
|
for file in torrent_files:
|
|
fullpath = os.path.join(save_path, file)
|
|
# Replace fullpath with \\ if qbm is running in docker (linux) but qbt is on windows
|
|
fullpath = fullpath.replace(r"/", "\\") if ":\\" in fullpath else fullpath
|
|
fullpath_torrent_files.append(fullpath)
|
|
return fullpath_torrent_files
|