From f0ad4d0d353844a5f159a0d657122076c7169ee2 Mon Sep 17 00:00:00 2001 From: moosecrap Date: Tue, 21 Jul 2026 03:44:42 -0700 Subject: [PATCH] sorting --- tools.py | 80 ++++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 60 insertions(+), 20 deletions(-) diff --git a/tools.py b/tools.py index 3a31593..97f8800 100644 --- a/tools.py +++ b/tools.py @@ -61,6 +61,7 @@ async def list_thumbnails_handler(args: Dict[str, Any]): dir_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 dir_path: return {"text": "Error: Missing path argument"} @@ -68,24 +69,47 @@ async def list_thumbnails_handler(args: Dict[str, Any]): return {"text": f"Error: {dir_path} is not a directory."} exts = ('.png', '.jpg', '.jpeg', '.webp', '.bmp') - all_files = sorted([f for f in os.listdir(dir_path) if f.lower().endswith(exts)]) - if not all_files: + # Collect file info for sorting + file_info_list = [] + for f in os.listdir(dir_path): + if f.lower().endswith(exts): + full_path = os.path.join(dir_path, f) + try: + stats = os.stat(full_path) + file_info_list.append({ + "name": f, + "path": full_path, + "mtime": stats.st_mtime, + "size": stats.st_size + }) + except Exception as e: + logger.error(f"Could not stat {f}: {e}") + + if not file_info_list: return {"text": "No supported images found in the directory."} - total_files = len(all_files) + # Sorting logic + if sort_by == "mtime": + file_info_list.sort(key=lambda x: x["mtime"], reverse=True) + elif sort_by == "size": + file_info_list.sort(key=lambda x: x["size"], reverse=True) + else: # Default to name + file_info_list.sort(key=lambda x: x["name"].lower()) + + total_files = len(file_info_list) start_idx = (page - 1) * page_size end_idx = start_idx + page_size - files = all_files[start_idx:end_idx] + paged_files = file_info_list[start_idx:end_idx] - if not files: + if not paged_files: return {"text": f"No images found on page {page}."} thumb_size = 160 padding = 15 - label_height = 30 + label_height = 35 # Increased for larger font - num_files = len(files) + num_files = len(paged_files) cols = int(num_files**0.5) if num_files > 0 else 1 if cols == 0: cols = 1 rows = (num_files + cols - 1) // cols @@ -96,38 +120,53 @@ async def list_thumbnails_handler(args: Dict[str, Any]): canvas = Image.new('RGB', (canvas_w, canvas_h), (30, 30, 30)) draw = ImageDraw.Draw(canvas) - try: + # Attempt to load a larger font + font = None + font_paths = [ + "/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf", + "/usr/share/fonts/truetype/liberation/LiberationSans-Bold.ttf", + "/usr/share/fonts/truetype/freefont/FreeSansBold.ttf", + ] + for path in font_paths: + if os.path.exists(path): + try: + font = ImageFont.truetype(path, 20) + break + except Exception: + continue + if font is None: font = ImageFont.load_default() - except Exception: - font = None file_details = [] - for i, filename in enumerate(files): - full_path = os.path.join(dir_path, filename) + for i, info in enumerate(paged_files): + filename = info["name"] + full_path = info["path"] row = i // cols col = i % cols x = padding + col * (thumb_size + padding) y = padding + row * (thumb_size + label_height + padding) - # Gather metadata for the text list try: - stats = os.stat(full_path) with Image.open(full_path) as img: width, height = img.size - # Process thumbnail img.thumbnail((thumb_size, thumb_size)) off_x = (thumb_size - img.width) // 2 off_y = (thumb_size - img.height) // 2 canvas.paste(img, (x + off_x, y + off_y)) - mod_time = datetime.datetime.fromtimestamp(stats.st_mtime).strftime('%Y-%m-%d %H:%M') - size_kb = stats.st_size / 1024 + mod_time = datetime.datetime.fromtimestamp(info["mtime"]).strftime('%Y-%m-%d %H:%M') + size_kb = info["size"] / 1024 file_details.append(f"{i+1}. {filename} | {width}x{height} | {size_kb:.1f}KB | {mod_time}") - # Label the thumbnail with just the index number - draw.text((x, y + thumb_size + 2), str(i + 1), fill=(220, 220, 220), font=font) + # Draw index number - add a small background rectangle for contrast + text = str(i + 1) + # Simple text bounding box calculation (approximate) + text_w = len(text) * 10 + draw.rectangle([x, y + thumb_size + 2, x + text_w + 4, y + thumb_size + 24], fill=(60, 60, 60)) + draw.text((x + 2, y + thumb_size + 2), text, fill=(255, 255, 255), font=font) + except Exception as e: logger.error(f"Failed to process {filename}: {e}") draw.text((x, y + thumb_size // 2), "Error", fill=(255, 0, 0), font=font) @@ -170,13 +209,14 @@ TOOL_REGISTRY = [ ), Tool( name="list_thumbnails", - description="Generates a thumbnail grid of images in a directory. Returns a numbered grid and a detailed file list.", + description="Generates a thumbnail grid of images in a directory. Supports pagination and sorting.", schema={ "type": "object", "properties": { "path": {"type": "string", "description": "Path to the directory containing images"}, "page": {"type": "integer", "description": "The page number to retrieve (1-indexed)", "default": 1}, "page_size": {"type": "integer", "description": "Number of images per page", "default": 64}, + "sort_by": {"type": "string", "description": "Sort order: 'mtime' (newest first, default), 'name' (alphabetical), or 'size' (largest first)", "default": "mtime"}, }, "required": ["path"], },