I found a Python script that does the job: https://github.com/im-PJs/GoPro-File-Organizer/tree/main:
# Author: https://github.com/im-PJs import os import shutil import sys from collections import defaultdict def organize_files(base_path): # Count occurrences of each file number for .MP4 files mp4_count = defaultdict(int) file_paths = defaultdict(list) # First pass to collect file information for filename in os.listdir(base_path): if filename.endswith(('.MP4', '.LRV', '.THM')): file_number = filename[4:8] file_paths[file_number].append(filename) if filename.endswith('.MP4'): mp4_count[file_number] += 1 # Save original paths before moving with open(os.path.join(base_path, 'original_paths.txt'), 'w') as f: # Second pass to move files if there are multiple MP4s with the same number for file_number, files in file_paths.items(): if mp4_count[file_number] > 1: # Create folder only if more than one MP4 file with the same number folder_name = f"Video_{file_number}" folder_path = os.path.join(base_path, folder_name) if not os.path.exists(folder_path): os.makedirs(folder_path) for filename in files: original_path = os.path.join(base_path, filename) new_path = os.path.join(folder_path, filename) shutil.move(original_path, new_path) print(f"Moved '{filename}' to '{new_path}'") f.write(f"{new_path}={original_path}\n") def undo_organization(base_path): paths_file = os.path.join(base_path, 'original_paths.txt') if not os.path.exists(paths_file): print("No organization to undo.") return # Read the original paths and move files back with open(paths_file, 'r') as file: for line in file: new_path, original_path = line.strip().split('=') shutil.move(new_path, original_path) print(f"Moved '{new_path}' back to '{original_path}'") # Remove empty folders for folder in os.listdir(base_path): folder_path = os.path.join(base_path, folder) if os.path.isdir(folder_path) and not os.listdir(folder_path): os.rmdir(folder_path) print(f"Removed empty folder: {folder_path}") os.remove(paths_file) print("Undo complete.") if __name__ == "__main__": # Use the current directory as the base directory base_directory = os.getcwd() if len(sys.argv) > 1 and sys.argv[1] == '-undoLast': undo_organization(base_directory) else: organize_files(base_directory)
Tested on Windows 10 21H2 Pro with Python 3.11.9, running python main.py.
Before:
(test) N:\GoPro\test>tree /F Folder PATH listing for volume 2024GoPro Volume serial number is 0746-89B1 N:. main.py GL010356.LRV GL020356.LRV GL030356.LRV GX010356.MP4 GX010356.THM GX020356.MP4 GX020356.THM GX030356.MP4 GX030356.THM GL010355.LRV GL020355.LRV GL030355.LRV GL040355.LRV GX010355.MP4 GX010355.THM GX020355.MP4 GX020355.THM GX030355.MP4 GX030355.THM GX040355.MP4 GX040355.THM GL010357.LRV GL020357.LRV GL030357.LRV GL040357.LRV GL050357.LRV GX010357.MP4 GX010357.THM GX020357.MP4 GX020357.THM GX030357.MP4 GX030357.THM GX040357.MP4 GX040357.THM GX050357.MP4 GX050357.THM No subfolders exist
After:
N:. │ main.py │ original_paths.txt │ ├───Video_0356 │ GL010356.LRV │ GL020356.LRV │ GL030356.LRV │ GX010356.MP4 │ GX010356.THM │ GX020356.MP4 │ GX020356.THM │ GX030356.MP4 │ GX030356.THM │ ├───Video_0355 │ GL010355.LRV │ GL020355.LRV │ GL030355.LRV │ GL040355.LRV │ GX010355.MP4 │ GX010355.THM │ GX020355.MP4 │ GX020355.THM │ GX030355.MP4 │ GX030355.THM │ GX040355.MP4 │ GX040355.THM │ └───Video_0357 GL010357.LRV GL020357.LRV GL030357.LRV GL040357.LRV GL050357.LRV GX010357.MP4 GX010357.THM GX020357.MP4 GX020357.THM GX030357.MP4 GX030357.THM GX040357.MP4 GX040357.THM GX050357.MP4 GX050357.THM
To undo the file move: python main.py -undoLast