Skip to content

Commit

Permalink
Added new features and functionality to main code. Also updated READM…
Browse files Browse the repository at this point in the history
…E and USER_GUIDE

Added new features and functionality to app. Also updated README and USER_GUIDE to reflect the changes.
These new added functions will allow for a more controlled and precise application of the name change operation.

- Added ability to choose top-level folders only, subfolders only, and files only or any combination to be renamed
- Added the ability to control the depth of subfolders you want to be effected by the name changing operation
- Added a cancel button to cancel the current operation
- The app now refreshes when the operation is completed or canceled
  • Loading branch information
midnightroachmedia committed Jul 13, 2024
1 parent 8db06de commit 5fd37e1
Show file tree
Hide file tree
Showing 3 changed files with 160 additions and 61 deletions.
20 changes: 5 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
# FATX360

FATX360 is a Python application with a graphical user interface (GUI) that allows users to easily rename files and folders to be compatible with the FATX file system. This tool is particularly useful for users working with Xbox systems or other platforms that use the FATX file system.
FATX360 is a Python application with a graphical user interface (GUI) that allows users to easily rename files and folders to be compatible with the FATX file system. This tool is particularly useful for users working with Xbox 360 systems or other platforms that use the FATX file system.

## Features

- Select a directory to rename files and folders
- Choose specific files or folders for renaming
- "Select All" functionality for easy batch selection
- Option to rename folders only without affecting their contents
- Rename items to be FATX compatible (42 character limit, restricted character set)
- Option to rename top-level folders only
- Option to rename subfolders with customizable depth
- Option to rename files
- Copy renamed items to a new directory, preserving the original files
- Progress bar to track the renaming process
- Cancel operation functionality
- Error handling for various scenarios

## Installation
Expand Down Expand Up @@ -39,14 +41,6 @@ FATX360 is a Python application with a graphical user interface (GUI) that allow

For detailed usage instructions, please refer to the [User Guide](USER_GUIDE.md).

## Quick Start

1. Click "Select Directory" to choose the folder containing files to rename.
2. Select files/folders in the list (use "Select All" for batch selection).
3. (Optional) Check "Rename folders only" to leave file names unchanged.
4. Click "Rename Selected" and choose a destination for the renamed items.
5. Monitor the progress bar and wait for the success message.

## Contributing

Contributions to FATX360 are welcome! Please feel free to submit a Pull Request.
Expand All @@ -60,10 +54,6 @@ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file
- Thanks to all contributors who have helped to improve this tool.
- Special thanks to the Python community for providing excellent documentation and libraries.

## Contact

If you have any questions, feel free to open an issue or contact the repository owner.

---

Happy renaming!
56 changes: 30 additions & 26 deletions USER_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,24 @@

## Table of Contents
1. [Introduction](#introduction)
2. [Installation](#installation)
3. [Getting Started](#getting-started)
4. [Features](#features)
5. [Usage Guide](#usage-guide)
6. [Troubleshooting](#troubleshooting)
7. [FAQs](#faqs)
2. [Getting Started](#getting-started)
3. [Features](#features)
4. [Usage Guide](#usage-guide)
5. [Troubleshooting](#troubleshooting)
6. [FAQs](#faqs)

## Introduction

FATX360 is a Python application with a graphical user interface (GUI) that allows users to rename files and folders to be compatible with the FATX file system. This tool is particularly useful for users working with Xbox systems or other platforms that use the FATX file system.

## Installation

1. Ensure you have Python 3.x installed on your system. You can download it from [python.org](https://www.python.org/downloads/).
2. Save the `fatx360.py` script to your local machine.
3. No additional libraries are required as the application uses Python's standard libraries.
FATX360 is a Python application with a graphical user interface (GUI) that allows users to rename files and folders to be compatible with the FATX file system. This tool is particularly useful for users working with Xbox 360 systems or other platforms that use the FATX file system.

## Getting Started

To run the FATX360:
To run FATX360:

1. Open a command prompt or terminal.
2. Navigate to the directory containing `fatx360.py`.
3. Run the command: `python fatx360.py`
1. Ensure you have Python 3.x installed on your system.
2. Open a command prompt or terminal.
3. Navigate to the directory containing `fatx360.py`.
4. Run the command: `python fatx360.py`

The application window should appear, ready for use.

Expand All @@ -34,10 +28,12 @@ The application window should appear, ready for use.
- Select a directory to rename files and folders.
- Choose specific files or folders for renaming.
- "Select All" functionality to easily select or deselect all items.
- Option to rename folders only without affecting their contents.
- Rename items to be FATX compatible (42 character limit, restricted character set).
- Option to rename only top-level folders.
- Option to rename subfolders with customizable depth.
- Option to rename files.
- Copy renamed items to a new directory, preserving the original files.
- Progress bar to track the renaming process.
- Cancel button to stop the operation mid-process.
- Error handling for various scenarios (permission issues, file not found, etc.).

## Usage Guide
Expand All @@ -51,25 +47,33 @@ The application window should appear, ready for use.
- Click the "Select All" button to select or deselect all items at once.

3. **Set Options**:
- Check "Rename folders only" if you want to rename only folders without affecting their contents.
- Check "Rename top-level folders" to rename only the main folders.
- Check "Rename subfolders" to rename folders within the main folders.
- Use the depth slider to specify how many levels of subfolders to rename.
- Check "Rename files" to rename individual files.

4. **Start Renaming**:
- Click the "Rename Selected" button.
- Choose a destination folder for the renamed items when prompted.

5. **Monitor Progress**:
- The progress bar will show the status of the renaming process.
- The label next to the progress bar shows the number of processed items and total items.

6. **Cancel Operation** (if needed):
- Click the "Cancel" button to stop the renaming process.

6. **Review Results**:
7. **Review Results**:
- Once complete, a success message will appear.
- Check the "RENAMED" folder in your chosen destination directory for the renamed items.

## Troubleshooting

- **Permission Error**: Ensure you have the necessary permissions to access the selected directory and create new files/folders.
- **Files Not Appearing**: Make sure the selected directory contains files or folders.
- **Renaming Not Starting**: Verify that you've selected at least one item to rename.
- **Renaming Not Starting**: Verify that you've selected at least one item to rename and set at least one renaming option.
- **Application Not Starting**: Confirm that Python is correctly installed and the script is in the correct directory.
- **Operation Cancelled**: If you cancel the operation, the interface will reset. You can start a new operation as needed.

## FAQs

Expand All @@ -82,10 +86,10 @@ The application window should appear, ready for use.
3. **Q: Can I undo the renaming process?**
A: The renaming process creates copies, so your original files remain unchanged. To "undo", simply use the original files.

4. **Q: Why can't I select a file or folder?**
A: Ensure you have permission to access the file/folder. Also, check if the "Rename folders only" option is selected when trying to select files.
4. **Q: What happens if I don't select any renaming options?**
A: If no options are selected, all folders, subfolders, and files will be renamed to be FATX compatible.

5. **Q: The application is slow with many files. What can I do?**
A: For large directories, consider renaming in smaller batches by selecting fewer items at a time.
5. **Q: How does the subfolder depth slider work?**
A: The slider lets you choose how many levels of subfolders to rename. A value of 1 renames only immediate subfolders, while higher values rename deeper levels of subfolders.

For any additional questions or issues, please refer to the script comments or contact the developer.
145 changes: 125 additions & 20 deletions fatx360.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,15 @@ class Application(tk.Frame):
def __init__(self, master=None):
super().__init__(master)
self.master = master
self.master.title("FATX360 v1.2")
self.master.geometry("500x400")
self.master.title("FATX360 v1.3")
self.master.geometry("500x550")
self.pack(fill=tk.BOTH, expand=True)
self.create_widgets()
self.all_selected = False
self.total_items = 0
self.processed_items = 0
self.cancel_flag = False
self.max_depth = 10 # Maximum depth for the slider
self.create_widgets()

def create_widgets(self):
self.create_menu()
Expand All @@ -59,12 +61,39 @@ def create_widgets(self):
options_frame = ttk.Frame(self)
options_frame.pack(fill=tk.X, padx=10, pady=5)

self.folders_only_var = tk.BooleanVar()
self.folders_only_check = ttk.Checkbutton(options_frame, text="Rename folders only", variable=self.folders_only_var)
self.folders_only_check.pack(side=tk.LEFT)

self.rename_button = ttk.Button(options_frame, text="Rename Selected", command=self.rename_selected)
self.rename_button.pack(side=tk.RIGHT)
self.top_level_var = tk.BooleanVar()
self.top_level_check = ttk.Checkbutton(options_frame, text="Rename top-level folders",
variable=self.top_level_var)
self.top_level_check.pack(side=tk.TOP, anchor=tk.W)

self.subfolders_var = tk.BooleanVar()
self.subfolders_check = ttk.Checkbutton(options_frame, text="Rename subfolders",
variable=self.subfolders_var,
command=self.toggle_depth_slider)
self.subfolders_check.pack(side=tk.TOP, anchor=tk.W)

# Depth slider
self.depth_frame = ttk.Frame(options_frame)
self.depth_frame.pack(side=tk.TOP, fill=tk.X, padx=20, pady=5)
self.depth_label = ttk.Label(self.depth_frame, text="Subfolder depth:")
self.depth_label.pack(side=tk.LEFT)
self.depth_var = tk.IntVar(value=self.max_depth)
self.depth_slider = ttk.Scale(self.depth_frame, from_=1, to=self.max_depth,
orient=tk.HORIZONTAL, variable=self.depth_var,
length=200, command=self.update_depth_label)
self.depth_slider.pack(side=tk.LEFT, fill=tk.X, expand=True)
self.depth_value_label = ttk.Label(self.depth_frame, text=str(self.max_depth))
self.depth_value_label.pack(side=tk.LEFT)
self.depth_frame.pack_forget() # Initially hidden

self.files_var = tk.BooleanVar()
self.files_check = ttk.Checkbutton(options_frame, text="Rename files",
variable=self.files_var)
self.files_check.pack(side=tk.TOP, anchor=tk.W)

self.rename_button = ttk.Button(options_frame, text="Rename Selected",
command=self.rename_selected)
self.rename_button.pack(side=tk.TOP, pady=5)

progress_frame = ttk.Frame(self)
progress_frame.pack(fill=tk.X, padx=10, pady=5)
Expand All @@ -75,6 +104,9 @@ def create_widgets(self):
self.progress_label = ttk.Label(progress_frame, text="0 / 0")
self.progress_label.pack(side=tk.RIGHT)

self.cancel_button = ttk.Button(self, text="Cancel", command=self.cancel_operation, state=tk.DISABLED)
self.cancel_button.pack(pady=5)

def create_menu(self):
menubar = tk.Menu(self.master)
self.master.config(menu=menubar)
Expand Down Expand Up @@ -111,6 +143,15 @@ def toggle_select_all(self):
self.select_all_button.config(text="Deselect All")
self.all_selected = not self.all_selected

def toggle_depth_slider(self):
if self.subfolders_var.get():
self.depth_frame.pack(side=tk.TOP, fill=tk.X, padx=20, pady=5)
else:
self.depth_frame.pack_forget()

def update_depth_label(self, *args):
self.depth_value_label.config(text=str(self.depth_var.get()))

def rename_selected(self):
selected_indices = self.listbox.curselection()
selected_items = [self.listbox.get(i) for i in selected_indices]
Expand All @@ -124,6 +165,8 @@ def rename_selected(self):

self.progress['value'] = 0
self.rename_button['state'] = 'disabled'
self.cancel_button['state'] = 'normal'
self.cancel_flag = False

self.total_items = self.count_total_items(selected_items)
self.processed_items = 0
Expand All @@ -149,39 +192,62 @@ def rename_items_thread(self, items, dest_dir):
os.makedirs(renamed_dir, exist_ok=True)
except PermissionError:
self.show_error("Permission Error", "Cannot create the RENAMED directory.")
self.finish_operation()
return

for item in items:
if self.cancel_flag:
return # Exit the loop if cancelled
try:
full_path = os.path.join(self.directory, item)
if os.path.isdir(full_path):
self.process_directory(full_path, renamed_dir)
elif not self.folders_only_var.get():
self.process_file(full_path, renamed_dir)
self.process_directory(full_path, renamed_dir, self.top_level_var.get(), self.subfolders_var.get(), self.files_var.get())
else:
self.process_file(full_path, renamed_dir, self.files_var.get())
except PermissionError:
self.show_error("Permission Error", f"Cannot access {item}.")
except shutil.Error as e:
self.show_error("Copy Error", f"Error copying {item}: {str(e)}")
except OSError as e:
self.show_error("OS Error", f"Error processing {item}: {str(e)}")

self.show_success("Rename Complete", "Selected items have been renamed and copied to the RENAMED folder.")
if not self.cancel_flag:
self.show_success("Rename Complete", "Selected items have been renamed and copied to the RENAMED folder.")
self.finish_operation()

def process_directory(self, src_dir, dest_parent_dir):
new_dir_name = make_fatx_compatible(os.path.basename(src_dir))
def process_directory(self, src_dir, dest_parent_dir, rename_top_level, rename_subfolders, rename_files, current_depth=0):
new_dir_name = make_fatx_compatible(os.path.basename(src_dir)) if rename_top_level or (rename_subfolders and current_depth < self.depth_var.get()) else os.path.basename(src_dir)
new_dir_path = os.path.join(dest_parent_dir, new_dir_name)
os.makedirs(new_dir_path, exist_ok=True)

for root, dirs, files in os.walk(src_dir):
if self.cancel_flag:
return
rel_path = os.path.relpath(root, src_dir)
new_root = os.path.join(new_dir_path, rel_path)

# Rename subfolders if option is selected and within depth
if rename_subfolders and current_depth < self.depth_var.get() and root != src_dir:
new_root = os.path.join(os.path.dirname(new_root), make_fatx_compatible(os.path.basename(root)))

os.makedirs(new_root, exist_ok=True)

for file in files:
if self.cancel_flag:
return
src_file = os.path.join(root, file)
self.process_file(src_file, new_root)
self.process_file(src_file, new_root, rename_files)

# Process subdirectories
for dir_name in dirs:
full_dir_path = os.path.join(root, dir_name)
self.process_directory(full_dir_path, new_root, False, rename_subfolders, rename_files, current_depth + 1)

def process_file(self, src_file, dest_dir):
new_name = make_fatx_compatible(os.path.basename(src_file))
# We only want to process the top-level of this directory, so break the loop
break

def process_file(self, src_file, dest_dir, rename_file):
new_name = make_fatx_compatible(os.path.basename(src_file)) if rename_file else os.path.basename(src_file)
new_path = os.path.join(dest_dir, new_name)
shutil.copy2(src_file, new_path)
self.processed_items += 1
Expand All @@ -191,18 +257,57 @@ def update_progress(self):
progress_value = (self.processed_items / self.total_items) * 100
self.progress['value'] = progress_value
self.update_progress_label()
if progress_value >= 100:
self.rename_button['state'] = 'normal'

def update_progress_label(self):
self.progress_label.config(text=f"{self.processed_items} / {self.total_items}")

def cancel_operation(self):
self.cancel_flag = True
self.cancel_button['state'] = 'disabled'
self.show_info("Operation Cancelled", "The renaming operation was cancelled.")
self.reset_interface()

def finish_operation(self):
self.rename_button['state'] = 'normal'
self.cancel_button['state'] = 'disabled'
self.cancel_flag = False
self.reset_interface()

def reset_interface(self):
# Reset progress bar
self.progress['value'] = 0
self.progress_label.config(text="0 / 0")

# Reset selection
self.listbox.selection_clear(0, tk.END)
self.all_selected = False
self.select_all_button.config(text="Select All")

# Reset checkboxes
self.top_level_var.set(False)
self.subfolders_var.set(False)
self.files_var.set(False)

# Hide depth slider
self.depth_frame.pack_forget()

# Reset depth slider value
self.depth_var.set(self.max_depth)
self.update_depth_label()

# Reset counters
self.total_items = 0
self.processed_items = 0

def show_error(self, title, message):
self.master.after(0, lambda: messagebox.showerror(title, message))

def show_success(self, title, message):
self.master.after(0, lambda: messagebox.showinfo(title, message))

def show_info(self, title, message):
self.master.after(0, lambda: messagebox.showinfo(title, message))

root = tk.Tk()
app = Application(master=root)
app.mainloop()

0 comments on commit 5fd37e1

Please sign in to comment.