mirror of
https://github.com/DrizzleTime/Foxel.git
synced 2026-09-07 00:27:44 +08:00
feat: enhance list_virtual_dir to support sorting and improved entry annotation
This commit is contained in:
+52
-31
@@ -143,7 +143,7 @@ async def list_virtual_dir(path: str, page_num: int = 1, page_size: int = 50, so
|
|||||||
norm = (path if path.startswith('/') else '/' + path).rstrip('/') or '/'
|
norm = (path if path.startswith('/') else '/' + path).rstrip('/') or '/'
|
||||||
adapters = await StorageAdapter.filter(enabled=True)
|
adapters = await StorageAdapter.filter(enabled=True)
|
||||||
|
|
||||||
child_mount_entries = []
|
child_mount_entries: List[str] = []
|
||||||
norm_prefix = norm.rstrip('/')
|
norm_prefix = norm.rstrip('/')
|
||||||
for a in adapters:
|
for a in adapters:
|
||||||
if a.path == norm:
|
if a.path == norm:
|
||||||
@@ -154,6 +154,27 @@ async def list_virtual_dir(path: str, page_num: int = 1, page_size: int = 50, so
|
|||||||
child_mount_entries.append(tail)
|
child_mount_entries.append(tail)
|
||||||
child_mount_entries = sorted(set(child_mount_entries))
|
child_mount_entries = sorted(set(child_mount_entries))
|
||||||
|
|
||||||
|
sort_field = sort_by.lower()
|
||||||
|
reverse = sort_order.lower() == "desc"
|
||||||
|
|
||||||
|
def build_sort_key(item: Dict) -> Tuple:
|
||||||
|
key = (not bool(item.get("is_dir")),)
|
||||||
|
if sort_field == "name":
|
||||||
|
key += (str(item.get("name", "")).lower(),)
|
||||||
|
elif sort_field == "size":
|
||||||
|
key += (int(item.get("size", 0)),)
|
||||||
|
elif sort_field == "mtime":
|
||||||
|
key += (int(item.get("mtime", 0)),)
|
||||||
|
else:
|
||||||
|
key += (str(item.get("name", "")).lower(),)
|
||||||
|
return key
|
||||||
|
|
||||||
|
def annotate_entry(entry: Dict) -> None:
|
||||||
|
if not entry.get("is_dir"):
|
||||||
|
entry["is_image"] = is_image_filename(entry.get("name", ""))
|
||||||
|
else:
|
||||||
|
entry["is_image"] = False
|
||||||
|
|
||||||
try:
|
try:
|
||||||
adapter_model, rel = await resolve_adapter_by_path(norm)
|
adapter_model, rel = await resolve_adapter_by_path(norm)
|
||||||
adapter_instance = runtime_registry.get(adapter_model.id)
|
adapter_instance = runtime_registry.get(adapter_model.id)
|
||||||
@@ -173,18 +194,31 @@ async def list_virtual_dir(path: str, page_num: int = 1, page_size: int = 50, so
|
|||||||
effective_root = ''
|
effective_root = ''
|
||||||
rel = ''
|
rel = ''
|
||||||
|
|
||||||
adapter_entries = []
|
adapter_entries_page: List[Dict] = []
|
||||||
|
adapter_entries_for_merge: List[Dict] = []
|
||||||
adapter_total = 0
|
adapter_total = 0
|
||||||
covered = set()
|
covered = set()
|
||||||
|
|
||||||
if adapter_model and adapter_instance:
|
if adapter_model and adapter_instance:
|
||||||
list_dir = await _ensure_method(adapter_instance, "list_dir")
|
list_dir = await _ensure_method(adapter_instance, "list_dir")
|
||||||
try:
|
try:
|
||||||
adapter_entries, adapter_total = await list_dir(effective_root, rel, page_num, page_size, sort_by, sort_order)
|
adapter_entries_page, adapter_total = await list_dir(effective_root, rel, page_num, page_size, sort_by, sort_order)
|
||||||
except NotADirectoryError:
|
except NotADirectoryError:
|
||||||
raise HTTPException(400, detail="Not a directory")
|
raise HTTPException(400, detail="Not a directory")
|
||||||
|
|
||||||
for item in adapter_entries:
|
adapter_entries_for_merge = adapter_entries_page
|
||||||
|
|
||||||
|
# 存在挂载节点且适配器结果被分页时,补齐完整列表以便合并排序
|
||||||
|
if child_mount_entries and adapter_total > len(adapter_entries_page):
|
||||||
|
full_page_size = adapter_total
|
||||||
|
if full_page_size > 0:
|
||||||
|
adapter_entries_for_merge, adapter_total = await list_dir(
|
||||||
|
effective_root, rel, 1, full_page_size, sort_by, sort_order
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
adapter_entries_for_merge = adapter_entries_page
|
||||||
|
|
||||||
|
for item in adapter_entries_for_merge:
|
||||||
covered.add(item["name"])
|
covered.add(item["name"])
|
||||||
|
|
||||||
mount_entries = []
|
mount_entries = []
|
||||||
@@ -193,37 +227,24 @@ async def list_virtual_dir(path: str, page_num: int = 1, page_size: int = 50, so
|
|||||||
mount_entries.append({"name": name, "is_dir": True,
|
mount_entries.append({"name": name, "is_dir": True,
|
||||||
"size": 0, "mtime": 0, "type": "mount", "is_image": False})
|
"size": 0, "mtime": 0, "type": "mount", "is_image": False})
|
||||||
|
|
||||||
for ent in adapter_entries:
|
|
||||||
if not ent.get('is_dir'):
|
|
||||||
ent['is_image'] = is_image_filename(ent['name'])
|
|
||||||
else:
|
|
||||||
ent['is_image'] = False
|
|
||||||
|
|
||||||
all_entries = adapter_entries + mount_entries
|
|
||||||
|
|
||||||
if mount_entries:
|
if mount_entries:
|
||||||
reverse = sort_order.lower() == "desc"
|
for ent in adapter_entries_for_merge:
|
||||||
def get_sort_key(item):
|
annotate_entry(ent)
|
||||||
key = (not item.get("is_dir"),)
|
combined_entries = adapter_entries_for_merge + [
|
||||||
sort_field = sort_by.lower()
|
{**ent, "is_image": False} for ent in mount_entries
|
||||||
if sort_field == "name":
|
]
|
||||||
key += (item["name"].lower(),)
|
combined_entries.sort(key=build_sort_key, reverse=reverse)
|
||||||
elif sort_field == "size":
|
|
||||||
key += (item.get("size", 0),)
|
total_entries = len(combined_entries)
|
||||||
elif sort_field == "mtime":
|
|
||||||
key += (item.get("mtime", 0),)
|
|
||||||
else:
|
|
||||||
key += (item["name"].lower(),)
|
|
||||||
return key
|
|
||||||
all_entries.sort(key=get_sort_key, reverse=reverse)
|
|
||||||
|
|
||||||
total_entries = adapter_total + len(mount_entries)
|
|
||||||
start_idx = (page_num - 1) * page_size
|
start_idx = (page_num - 1) * page_size
|
||||||
end_idx = start_idx + page_size
|
end_idx = start_idx + page_size
|
||||||
page_entries = all_entries[start_idx:end_idx]
|
page_entries = combined_entries[start_idx:end_idx]
|
||||||
return page(page_entries, total_entries, page_num, page_size)
|
return page(page_entries, total_entries, page_num, page_size)
|
||||||
|
|
||||||
return page(adapter_entries, adapter_total, page_num, page_size)
|
annotate_entry_list = adapter_entries_page or []
|
||||||
|
for ent in annotate_entry_list:
|
||||||
|
annotate_entry(ent)
|
||||||
|
return page(adapter_entries_page, adapter_total, page_num, page_size)
|
||||||
|
|
||||||
|
|
||||||
async def read_file(path: str) -> Union[bytes, Any]:
|
async def read_file(path: str) -> Union[bytes, Any]:
|
||||||
|
|||||||
Reference in New Issue
Block a user