Skip to content

Instantly share code, notes, and snippets.

@MrCroxx
Created September 3, 2025 08:50
Show Gist options
  • Select an option

  • Save MrCroxx/ffc761ee7528ff123a916788b49b5420 to your computer and use it in GitHub Desktop.

Select an option

Save MrCroxx/ffc761ee7528ff123a916788b49b5420 to your computer and use it in GitHub Desktop.
#!/usr/bin/env ./venv/bin/python
import json
import os
import subprocess
import sys
from pathlib import Path
# Automatically generate the latest qbt_files.json each run
subprocess.run(["qbt", "torrent", "list", "--format", "json"], stdout=open("qbt_files.json", "w"))
# Read the file list output from qbt
with open('qbt_files.json') as f:
qbt_data = json.load(f)
# Collect all file paths managed by qbt
qbt_files = set()
for torrent in qbt_data:
content_path = torrent['content_path']
if os.path.isfile(content_path):
qbt_files.add(content_path)
elif os.path.isdir(content_path):
# If it's a directory, add all files under the directory
for root, _, files in os.walk(content_path):
for file in files:
qbt_files.add(os.path.join(root, file))
# Read target directories from command line arguments (supports multiple)
if len(sys.argv) < 2:
print("Usage: python main.py <target_dir1> [<target_dir2> ...]")
sys.exit(1)
target_dirs = sys.argv[1:]
for target_dir in target_dirs:
# Collect all files in the target directory
dir_files = set()
for root, _, files in os.walk(target_dir):
for file in files:
full_path = os.path.join(root, file)
if not file.endswith('.torrent'):
dir_files.add(full_path)
# Find files in the directory that are not managed by qbt
unmanaged_files = dir_files - qbt_files
# Output results
# print(f"\nFiles not managed by qBittorrent (directory: {target_dir}):")
def human_readable_size(size):
for unit in ['B', 'KB', 'MB', 'GB', 'TB', 'PB']:
if size < 1024:
return f"{size:.2f} {unit}"
size /= 1024
return f"{size:.2f} PB"
# Summarize top-level directories and files in target_dir not managed by qbt
print(f"Top-level directories and files in {target_dir} not managed by qbt, with total size:")
# Get all top-level entries in target_dir
level1_entries = {entry.name: entry for entry in os.scandir(target_dir)}
# Group unmanaged files by top-level directory
dir_unmanaged = {}
file_unmanaged = []
for file in unmanaged_files:
rel_path = os.path.relpath(file, target_dir)
parts = rel_path.split(os.sep)
if len(parts) == 1:
# Top-level file
file_unmanaged.append(file)
elif len(parts) > 1:
# Belongs to a top-level directory
dir_name = parts[0]
dir_unmanaged.setdefault(dir_name, []).append(file)
# Print unmanaged top-level files
for file in file_unmanaged:
try:
size = os.path.getsize(file)
print(f"{file} ({human_readable_size(size)})")
except Exception as e:
print(f"{file} (Unable to get size: {e})")
# Print unmanaged top-level directories and total size of unmanaged files within
for dir_name, files in dir_unmanaged.items():
total_size = 0
for file in files:
try:
total_size += os.path.getsize(file)
except Exception:
pass
print(f"{os.path.join(target_dir, dir_name)} ({human_readable_size(total_size)})")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment