refactor remove_orphaned

This commit is contained in:
bobokun 2023-04-10 16:44:51 -04:00
parent 5cfb0cd4b3
commit 89d9188d9d
No known key found for this signature in database
GPG key ID: B73932169607D927
3 changed files with 107 additions and 93 deletions

View file

@ -0,0 +1,102 @@
import os
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
self.rem_orphaned()
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 = []
root_files = []
orphaned_files = []
excluded_orphan_files = []
orphaned_parent_path = set()
if self.remote_dir != self.root_dir:
root_files = [
os.path.join(path.replace(self.remote_dir, self.root_dir), name)
for path, subdirs, files in os.walk(self.remote_dir)
for name in files
if self.orphaned_dir.replace(self.remote_dir, self.root_dir) not in path
]
else:
root_files = [
os.path.join(path, name)
for path, subdirs, files in os.walk(self.root_dir)
for name in files
if self.orphaned_dir.replace(self.root_dir, self.remote_dir) not in path
]
# Get an updated list of torrents
torrent_list = self.qbt.get_torrents({"sort": "added_on"})
for torrent in torrent_list:
for file in torrent.files:
fullpath = os.path.join(torrent.save_path, file.name)
# Replace fullpath with \\ if qbm is running in docker (linux) but qbt is on windows
fullpath = fullpath.replace(r"/", "\\") if ":\\" in fullpath else fullpath
torrent_files.append(fullpath)
orphaned_files = set(root_files) - set(torrent_files)
orphaned_files = sorted(orphaned_files)
if self.config.orphaned["exclude_patterns"]:
exclude_patterns = 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.replace(self.remote_dir, self.root_dir))
]
orphaned_files = set(orphaned_files) - set(excluded_orphan_files)
if 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)
body += logger.print_line(
f"{'Did not move' if self.config.dry_run else 'Moved'} {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
logger.info("Cleaning up any empty directories...")
if not self.config.dry_run:
for file in orphaned_files:
src = file.replace(self.root_dir, self.remote_dir)
dest = os.path.join(self.orphaned_dir, file.replace(self.root_dir, ""))
util.move_files(src, dest, True)
orphaned_parent_path.add(os.path.dirname(file).replace(self.root_dir, self.remote_dir))
for parent_path in orphaned_parent_path:
util.remove_empty_directories(parent_path, "**/*")
else:
logger.print_line("No Orphaned Files found.", self.config.loglevel)

View file

@ -2,7 +2,6 @@
import os
import sys
from datetime import timedelta
from fnmatch import fnmatch
from qbittorrentapi import APIConnectionError
from qbittorrentapi import Client
@ -564,92 +563,6 @@ class Qbt:
logger.warning(e)
return category
def rem_orphaned(self):
"""Remove orphaned files from remote directory"""
orphaned = 0
if self.config.commands["rem_orphaned"]:
logger.separator("Checking for Orphaned Files", space=False, border=False)
torrent_files = []
root_files = []
orphaned_files = []
excluded_orphan_files = []
orphaned_parent_path = set()
remote_path = self.config.remote_dir
root_path = self.config.root_dir
orphaned_path = self.config.orphaned_dir
if remote_path != root_path:
root_files = [
os.path.join(path.replace(remote_path, root_path), name)
for path, subdirs, files in os.walk(remote_path)
for name in files
if orphaned_path.replace(remote_path, root_path) not in path
]
else:
root_files = [
os.path.join(path, name)
for path, subdirs, files in os.walk(root_path)
for name in files
if orphaned_path.replace(root_path, remote_path) not in path
]
# Get an updated list of torrents
torrent_list = self.get_torrents({"sort": "added_on"})
for torrent in torrent_list:
for file in torrent.files:
fullpath = os.path.join(torrent.save_path, file.name)
# Replace fullpath with \\ if qbm is running in docker (linux) but qbt is on windows
fullpath = fullpath.replace(r"/", "\\") if ":\\" in fullpath else fullpath
torrent_files.append(fullpath)
orphaned_files = set(root_files) - set(torrent_files)
orphaned_files = sorted(orphaned_files)
if self.config.orphaned["exclude_patterns"]:
exclude_patterns = 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.replace(remote_path, root_path))
]
orphaned_files = set(orphaned_files) - set(excluded_orphan_files)
if orphaned_files:
os.makedirs(orphaned_path, 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)
body += logger.print_line(
f"{'Did not move' if self.config.dry_run else 'Moved'} {num_orphaned} Orphaned files "
f"to {orphaned_path.replace(remote_path,root_path)}",
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": orphaned_path.replace(remote_path, root_path),
"total_orphaned_files": num_orphaned,
}
self.config.send_notifications(attr)
# Delete empty directories after moving orphan files
logger.info("Cleaning up any empty directories...")
if not self.config.dry_run:
for file in orphaned_files:
src = file.replace(root_path, remote_path)
dest = os.path.join(orphaned_path, file.replace(root_path, ""))
util.move_files(src, dest, True)
orphaned_parent_path.add(os.path.dirname(file).replace(root_path, remote_path))
for parent_path in orphaned_parent_path:
util.remove_empty_directories(parent_path, "**/*")
else:
logger.print_line("No Orphaned Files found.", self.config.loglevel)
return orphaned
def tor_delete_recycle(self, torrent, info):
"""Move torrent to recycle bin"""
if self.config.recyclebin["enabled"]:

View file

@ -293,6 +293,7 @@ from modules.core.remove_unregistered import RemoveUnregistered # noqa
from modules.core.cross_seed import CrossSeed # noqa
from modules.core.recheck import ReCheck # noqa
from modules.core.tag_nohardlinks import TagNoHardLinks # noqa
from modules.core.remove_orphaned import RemoveOrphaned # noqa
def my_except_hook(exctype, value, tbi):
@ -428,16 +429,14 @@ def start():
stats["deleted_contents"] += no_hardlinks.stats_deleted_contents
# Remove Orphaned Files
num_orphaned = cfg.qbt.rem_orphaned()
stats["orphaned"] += num_orphaned
if cfg.commands["rem_orphaned"]:
stats["orphaned"] += RemoveOrphaned(qbit_manager).stats
# Empty RecycleBin
recycle_emptied = cfg.cleanup_dirs("Recycle Bin")
stats["recycle_emptied"] += recycle_emptied
stats["recycle_emptied"] += cfg.cleanup_dirs("Recycle Bin")
# Empty Orphaned Directory
orphaned_emptied = cfg.cleanup_dirs("Orphaned Data")
stats["orphaned_emptied"] += orphaned_emptied
stats["orphaned_emptied"] += cfg.cleanup_dirs("Orphaned Data")
if stats["categorized"] > 0:
stats_summary.append(f"Total Torrents Categorized: {stats['categorized']}")