MooseCP/tools/list_directory.py
2026-07-21 23:48:58 -07:00

100 lines
3.3 KiB
Python

import os
import logging
import datetime
from typing import Any, Dict
from tools.utils import format_relative_time
logger = logging.getLogger("MattCP")
async def handle(args: Dict[str, Any]):
"""
Lists the contents of a directory in a file browser format.
Directories are listed first, then files.
Supports pagination and sorting.
"""
path = args.get("path")
page = int(args.get("page", 1))
page_size = int(args.get("page_size", 64))
sort_by = args.get("sort_by", "mtime")
if not path:
return {"text": "Error: Missing path argument"}
if not os.path.isdir(path):
return {"text": f"Error: {path} is not a directory."}
try:
entries = os.listdir(path)
except Exception as e:
return {"text": f"Error reading directory: {e}"}
all_items = []
for entry in entries:
full_path = os.path.join(path, entry)
try:
stats = os.stat(full_path)
mtime_rel = format_relative_time(stats.st_mtime)
if os.path.isdir(full_path):
try:
count = len(os.listdir(full_path))
except:
count = 0
all_items.append({
"type": "dir",
"name": entry,
"info": f"{count} items",
"mtime": mtime_rel,
"mtime_raw": stats.st_mtime,
"size": stats.st_size
})
else:
size_kb = stats.st_size / 1024
all_items.append({
"type": "file",
"name": entry,
"info": f"{size_kb:.1f}KB",
"mtime": mtime_rel,
"mtime_raw": stats.st_mtime,
"size": stats.st_size
})
except Exception as e:
logger.error(f"Could not stat {entry}: {e}")
# Sort Logic: Directories always come first, then apply secondary sort
if sort_by == "mtime":
all_items.sort(key=lambda x: (x["type"] == "file", -x["mtime_raw"]))
elif sort_by == "size":
all_items.sort(key=lambda x: (x["type"] == "file", -x["size"]))
else:
all_items.sort(key=lambda x: (x["type"] == "file", x["name"].lower()))
total_items = len(all_items)
# Custom Pagination: show all if <= 100, otherwise paginate by 64
if total_items <= 100:
start_idx = 0
end_idx = total_items
effective_page = 1
total_pages = 1
else:
start_idx = (page - 1) * page_size
end_idx = start_idx + page_size
total_pages = (total_items + page_size - 1) // page_size
effective_page = page
paged_items = all_items[start_idx:end_idx]
if not paged_items:
return {"text": f"No items found on page {page}."}
output = []
for item in paged_items:
if item["type"] == "dir":
output.append(f"[DIR] {item['name']} | {item['info']} | {item['mtime']}")
else:
output.append(f" {item['name']} | {item['info']} | {item['mtime']}")
header = f"Listing of {path}\nPage {effective_page} of {total_pages} ({total_items} total items). Showing {start_idx+1}-{min(end_idx, total_items)}."
return {"text": f"{header}\n\n" + "\n".join(output)}