From a61f7ee763fc05f14992e36489518bd123f1bdbf Mon Sep 17 00:00:00 2001 From: Ethanfel Date: Sat, 17 Jan 2026 15:49:59 +0100 Subject: [PATCH] Update tab_category_sorter.py --- tab_category_sorter.py | 66 +++++++++++++----------------------------- 1 file changed, 20 insertions(+), 46 deletions(-) diff --git a/tab_category_sorter.py b/tab_category_sorter.py index 45aae43..0829220 100644 --- a/tab_category_sorter.py +++ b/tab_category_sorter.py @@ -3,7 +3,6 @@ import os, shutil from engine import SorterEngine def render(path_s, path_o, quality, naming_mode): - # Validation of paths if not path_s or not os.path.exists(path_s): st.warning("Please provide a valid Source Folder path.") return @@ -11,19 +10,15 @@ def render(path_s, path_o, quality, naming_mode): st.warning("Please provide a Category Output folder.") return - # --- 1. Category Management Tools --- - with st.expander("🛠️ Category & Folder Management"): - # Bulk Sync Tool - st.write("### Sync Existing Folders") + # --- 1. Category Management Tools (Expander) --- + with st.expander("🛠️ Bulk Sync & Folder Renaming"): if st.button("🔄 Import Subfolders from Disk as Categories"): added = SorterEngine.sync_categories_from_disk(path_o) - st.success(f"Added {added} new category buttons based on your folders!") + st.success(f"Added {added} new categories!") st.rerun() st.divider() - # Physical Rename Tool - st.write("### Rename Category & Folder") categories = SorterEngine.get_categories() col_ren1, col_ren2 = st.columns(2) old_cat = col_ren1.selectbox("Folder to Rename", ["Select..."] + categories) @@ -32,22 +27,19 @@ def render(path_s, path_o, quality, naming_mode): if st.button("Apply Rename on Disk & Database"): if old_cat != "Select..." and new_cat_name: SorterEngine.rename_category(old_cat, new_cat_name, path_o) - st.success(f"Successfully moved folder and updated buttons: {old_cat} -> {new_cat_name}") st.rerun() st.divider() # --- 2. Image Discovery --- - # Toggle for Recursive Scanning recursive = st.toggle("🔍 Recursive Mode (Search all subfolders)", value=True) - images = SorterEngine.get_images(path_s, recursive=recursive) # + images = SorterEngine.get_images(path_s, recursive=recursive) categories = SorterEngine.get_categories() if st.session_state.idx_cat < len(images): - curr_p = images[st.session_state.idx_cat] # Full system path + curr_p = images[st.session_state.idx_cat] curr_file = os.path.basename(curr_p) - # 🎞️ Filmstrip Preview st.write("### 🎞️ Filmstrip") fs_cols = st.columns(7) for i, img_full_path in enumerate(images[st.session_state.idx_cat : st.session_state.idx_cat + 7]): @@ -55,64 +47,46 @@ def render(path_s, path_o, quality, naming_mode): st.divider() - # --- 3. Main Sorting UI --- col_img, col_btns = st.columns([2, 1]) with col_img: - st.image(SorterEngine.compress_for_web(curr_p, quality), caption=f"Processing: {curr_file}") - st.caption(f"Source Path: {curr_p}") + st.image(SorterEngine.compress_for_web(curr_p, quality), caption=f"File: {curr_file}") with col_btns: - # Generate ID based on the folder specifically containing this image - folder_of_image = os.path.dirname(curr_p) - fid = SorterEngine.get_folder_id(folder_of_image) # + # --- NEW CATEGORY ADDITION (Restored) --- + new_cat_input = st.text_input("➕ Quick Add Category", key="quick_add_cat") + if st.button("Add Category", use_container_width=True): + if new_cat_input: + SorterEngine.add_category(new_cat_input) + st.rerun() + + st.divider() + + fid = SorterEngine.get_folder_id(os.path.dirname(curr_p)) st.write(f"**Folder ID:** `{fid}`") - # Dynamic Category Buttons + # Dynamic Buttons for cat in categories: if st.button(cat, use_container_width=True, key=f"move_{cat}"): _, ext = os.path.splitext(curr_p) - - # Naming logic: Original vs ID name = curr_file if naming_mode == "original" else f"{fid}{ext}" - dst_dir = os.path.join(path_o, cat) os.makedirs(dst_dir, exist_ok=True) - # Collision protection - count = 2 final_dst = os.path.join(dst_dir, name) + count = 2 while os.path.exists(final_dst): root, ext = os.path.splitext(name) final_dst = os.path.join(dst_dir, f"{root}_{count}{ext}") count += 1 shutil.move(curr_p, final_dst) - - # Log history for the Undo button in app.py - st.session_state.history.append({ - 'type': 'cat_move', - 't_src': curr_p, - 't_dst': final_dst - }) - st.toast(f"Moved to {cat}") + st.session_state.history.append({'type': 'cat_move', 't_src': curr_p, 't_dst': final_dst}) st.rerun() st.divider() - if st.button("⏭️ SKIP IMAGE", use_container_width=True): st.session_state.idx_cat += 1 st.rerun() - - if st.button("🗑️ QUICK TRASH", type="primary", use_container_width=True): - # Uses the default _TRASH category from DB seed - dst_dir = os.path.join(path_o, "_TRASH") - os.makedirs(dst_dir, exist_ok=True) - final_dst = os.path.join(dst_dir, curr_file) - shutil.move(curr_p, final_dst) - st.rerun() else: - st.success("All images in this workspace have been categorized!") - if st.button("Restart from Beginning"): - st.session_state.idx_cat = 0 - st.rerun() \ No newline at end of file + st.success("Categorization complete.") \ No newline at end of file