From ff070beba42ef31e21e4ae4e380dd6420042d5c1 Mon Sep 17 00:00:00 2001 From: netquick Date: Wed, 26 Aug 2026 18:29:17 +0200 Subject: [PATCH] Add patterned rename and Move to, and keep settings, selection, and queue speed from resetting. Co-authored-by: Cursor --- Backlog.md | 26 +- docs/Documentation.md | 32 +- src/Explorer.App/BatchRenameWindow.xaml | 9 +- src/Explorer.App/MainWindow.xaml | 8 + src/Explorer.App/MainWindow.xaml.cs | 142 +++++++- src/Explorer.App/MoveToWindow.xaml | 66 ++++ src/Explorer.App/MoveToWindow.xaml.cs | 69 ++++ .../Settings/Pages/AdvancedSettingsPage.xaml | 3 +- .../Pages/AdvancedSettingsPage.xaml.cs | 2 +- .../Pages/AppearanceSettingsPage.xaml | 3 +- .../Pages/FileOperationsSettingsPage.xaml | 3 +- .../Pages/FileOperationsSettingsPage.xaml.cs | 4 +- .../Settings/Pages/GeneralSettingsPage.xaml | 3 +- .../Settings/Pages/IndexingSettingsPage.xaml | 21 +- .../Pages/NavigationSettingsPage.xaml | 3 +- .../Settings/SettingsPageContext.cs | 11 + src/Explorer.App/SettingsWindow.xaml | 4 +- src/Explorer.App/SettingsWindow.xaml.cs | 36 +- src/Explorer.App/TagRenameWindow.xaml | 50 +++ src/Explorer.App/TagRenameWindow.xaml.cs | 26 ++ .../DestinationPattern.cs | 193 +++++++++++ .../DestinationPatterns.cs | 88 +++++ src/Explorer.Application/FilenamePattern.cs | 314 +++++++++++++++++ src/Explorer.Application/FilenamePatterns.cs | 88 +++++ src/Explorer.Application/IMediaTagService.cs | 9 + src/Explorer.Application/MoveToPlanner.cs | 116 +++++++ src/Explorer.Application/RenamePlanner.cs | 49 ++- src/Explorer.Application/TagRenamePlanner.cs | 123 +++++++ .../UiPreferencesStore.cs | 38 +- src/Explorer.Contracts/IWorkbenchHost.cs | 4 + src/Explorer.Domain/Abstractions/Platform.cs | 1 + src/Explorer.Domain/Enums.cs | 3 +- src/Explorer.Domain/MediaTags.cs | 148 ++++++++ src/Explorer.Domain/OperationPlan.cs | 1 + src/Explorer.Domain/RenameRules.cs | 1 + src/Explorer.Domain/WindowsFileNames.cs | 21 ++ .../FileOperationService.cs | 16 + .../NativeFileOperationExecutor.cs | 68 +++- .../OperationAvailability.cs | 11 + .../RenameBatchService.cs | 7 +- src/Explorer.FileOperations/TransferQueue.cs | 82 ++++- .../ExplorerHostClientServices.cs | 1 + .../Ipc/WorkbenchPipeClient.cs | 4 + src/Explorer.Hosting/ExplorerHostServices.cs | 1 + .../Ipc/WorkbenchPipeServer.cs | 6 + .../ViewModels/BatchRenameViewModel.cs | 87 ++++- .../ViewModels/MainViewModel.cs | 50 ++- .../ViewModels/MoveToViewModel.cs | 141 ++++++++ .../ViewModels/TagRenameViewModel.cs | 324 ++++++++++++++++++ .../ViewModels/TransferQueueViewModel.cs | 23 +- src/Explorer.Windows/Explorer.Windows.csproj | 1 + src/Explorer.Windows/NativeMethods.cs | 31 ++ src/Explorer.Windows/TagLibMediaTagService.cs | 172 ++++++++++ src/Explorer.Windows/WindowsVolumeService.cs | 78 +++++ .../DestinationPatternTests.cs | 161 +++++++++ .../FilenamePatternTests.cs | 106 ++++++ .../FilenamePatternsTests.cs | 23 ++ .../RenamePlannerTests.cs | 54 ++- .../TagRenamePlannerTests.cs | 36 ++ .../UiPreferencesStoreTests.cs | 33 +- tests/Explorer.Domain.Tests/DomainTests.cs | 14 + .../TransferQueueTests.cs | 16 + 62 files changed, 3172 insertions(+), 92 deletions(-) create mode 100644 src/Explorer.App/MoveToWindow.xaml create mode 100644 src/Explorer.App/MoveToWindow.xaml.cs create mode 100644 src/Explorer.App/Settings/SettingsPageContext.cs create mode 100644 src/Explorer.App/TagRenameWindow.xaml create mode 100644 src/Explorer.App/TagRenameWindow.xaml.cs create mode 100644 src/Explorer.Application/DestinationPattern.cs create mode 100644 src/Explorer.Application/DestinationPatterns.cs create mode 100644 src/Explorer.Application/FilenamePattern.cs create mode 100644 src/Explorer.Application/FilenamePatterns.cs create mode 100644 src/Explorer.Application/IMediaTagService.cs create mode 100644 src/Explorer.Application/MoveToPlanner.cs create mode 100644 src/Explorer.Application/TagRenamePlanner.cs create mode 100644 src/Explorer.Domain/MediaTags.cs create mode 100644 src/Explorer.Presentation/ViewModels/MoveToViewModel.cs create mode 100644 src/Explorer.Presentation/ViewModels/TagRenameViewModel.cs create mode 100644 src/Explorer.Windows/TagLibMediaTagService.cs create mode 100644 tests/Explorer.Application.Tests/DestinationPatternTests.cs create mode 100644 tests/Explorer.Application.Tests/FilenamePatternTests.cs create mode 100644 tests/Explorer.Application.Tests/FilenamePatternsTests.cs create mode 100644 tests/Explorer.Application.Tests/TagRenamePlannerTests.cs diff --git a/Backlog.md b/Backlog.md index 66089f2..5670710 100644 --- a/Backlog.md +++ b/Backlog.md @@ -294,18 +294,19 @@ Goal: Replace FileRenamer workflows. - [x] Counter padding - [x] Case conversion - [x] Extension handling -- [ ] Metadata placeholders +- [x] Metadata placeholders Potential placeholders: - `{CreatedDate}` +- `{TakenDate}` - `{ModifiedDate}` - `{Counter}` - `{Width}` - `{Height}` - `{Artist}` - `{Title}` -- `{Project}` +- `{Project}` (Git repo folder, else parent) - `{Extension}` ## Workflow @@ -318,6 +319,25 @@ Potential placeholders: - [x] Add Rename operations to File Operations Queue - [x] Store `OldPath -> NewPath` - [x] Support Undo for completed rename batches +- [x] Tags from filename +- [x] Filename from tags +- [x] Tag editor (Artist, Title, Album, Track, Year, Genre) +- [x] Queue tag writes +- [x] Saved name patterns +- [x] EXIF Date Taken on photos +- [x] `{Project}` from Git repo / parent folder + +--- + +# Move to + +Patterned move with per-file destination folders (Plex-style movie folders, dated backups, and similar). + +- [x] Destination pattern popup +- [x] `%filename%` `%filename_noext%` `%ext%` `%year%` `%month%` `%parent%` `%source_drive%` +- [x] Create missing destination folders +- [x] History / saved patterns +- [x] Preview and queue through File Operations Queue --- @@ -440,7 +460,7 @@ Goal: Understand what files and folders represent rather than relying only on ex - [ ] MIME/content signature - [x] Folder structure - [x] Git metadata -- [ ] Media metadata +- [x] Media metadata - [x] Known application structures (`node_modules`, `bin`, `obj`, `.vs`) - [x] File age (old installers flagged in preview) - [ ] File relationships diff --git a/docs/Documentation.md b/docs/Documentation.md index 9f8ea79..70be125 100644 --- a/docs/Documentation.md +++ b/docs/Documentation.md @@ -44,7 +44,7 @@ Specialized tools still do specialized jobs. 7-Zip compresses. FFmpeg converts a | --- | --- | | `%LocalAppData%\ExplorerWorkbench\index.db` | Index, queue, profiles | | `%LocalAppData%\ExplorerWorkbench\logs\` | Rolling logs | -| `%LocalAppData%\ExplorerWorkbench\ui-preferences.txt` | Theme, layout, tool paths, organize destinations, favorite folders | +| `%LocalAppData%\ExplorerWorkbench\ui-preferences.txt` | Theme, layout, tool paths, organize destinations, favorite folders, saved name patterns, Move to history | --- @@ -226,9 +226,34 @@ Auto-clear when done is a setting. Failed items stay until you dismiss or retry Workflow: configure → preview → validate → queue. -Rules: search/replace, regex, prefix, suffix, counter (with padding), case, extension. Collisions and illegal Windows names are caught before enqueue. Completed batches can be undone (**Tools → File Operations → Undo last rename batch**). +Rules: search/replace, regex, prefix, suffix, counter (with padding), case, extension. An optional **name pattern** can replace the current name using placeholders: `{Artist}`, `{Title}`, `{Album}`, `{Track}`, `{Year}`, `{Genre}`, `{CreatedDate}`, `{TakenDate}`, `{ModifiedDate}`, `{Width}`, `{Height}`, `{Name}`, `{Extension}`, `{Parent}`, `{Project}`, `{Counter}`. Dates accept a format (`{TakenDate:yyyyMMdd}`). `{CreatedDate}` uses EXIF Date Taken when that was already read; `{TakenDate}` is the token that reads photo metadata. `{Project}` is the Git repository folder, or the parent folder if the file is not in a repo. **Save pattern** stores a custom pattern in `ui-preferences.txt` (built-in patterns stay in the list: `{Artist} - {Title}`, `{Track:00} - {Title}`, `{TakenDate}_{Name}`, `{CreatedDate}_{Name}`, `{Project}_{Name}`). Collisions and illegal Windows names are caught before enqueue. Completed batches can be undone (**Tools → File Operations → Undo last rename batch**). -Metadata placeholders such as `{CreatedDate}` or `{Width}` are not implemented yet. `{Counter}` and `{Extension}` work. +**Tags…** (select files first) is the Tag&Rename-style editor. **Filename → tags** fills Artist/Title/… from the current names using the same pattern. **Tags → filename** builds new names from tags. **Queue tags** writes ID3 on audio and EXIF (title, comment, creator, date taken) on photos through the File Operations Queue; **Queue rename** queues the new names. Online-only cloud files are skipped so they are not downloaded. + +--- + +## Move to + +**Tools → File Operations → Move to…** or **Move to…** on the item context menu (select items first). + +Not a plain “move into this folder”. The destination is a **pattern**. Placeholders expand per file, missing folders are created, then the move is queued. + +| Token | Meaning | +| --- | --- | +| `%filename%` | Name including extension | +| `%filename_noext%` | Name without extension | +| `%ext%` | Extension without the dot | +| `%year%` / `%month%` | Last-write time (`2024` / `08`) | +| `%parent%` | Parent folder name | +| `%source_drive%` | Drive (`D:`) or UNC share (`\\10.0.0.31\media`) | + +`{filename_noext}` and the other `{…}` forms work the same. + +Plex-style movies: `\\10.0.0.31\media\movies\%filename_noext%` creates `movies\Inception\` and places `Inception.mkv` inside it. If the last segment is `%filename%` or `%ext%`, the pattern is the full destination file path. + +Type the path in the text box (or **Browse…**), then click a token to insert it at the caret. **Recent** lists saved patterns; the `\\host\share\…` row is only an example and is rejected if you queue it. **Queue** and **Save** store real patterns in `ui-preferences.txt` (`move-to=`). + +If a UNC share or mapped drive is disconnected, Workbench tries to reconnect it (same credentials, no extra prompt). Jobs that still cannot reach the destination wait in the queue; **Retry** re-probes and reconnects. Online-only cloud files are skipped. --- @@ -387,7 +412,6 @@ Left open on purpose: - Scheduled profiles and folder-watcher triggers - MIME/EXIF classification - Duplicate “backup copy” auto-tagging -- Rename placeholders from EXIF or dates --- diff --git a/src/Explorer.App/BatchRenameWindow.xaml b/src/Explorer.App/BatchRenameWindow.xaml index cf97a24..3d453bd 100644 --- a/src/Explorer.App/BatchRenameWindow.xaml +++ b/src/Explorer.App/BatchRenameWindow.xaml @@ -68,7 +68,14 @@ + IsEnabled="{Binding ChangeExtension}" Margin="0,0,0,16"/> + + + +