MediaImporter / DEVELOPMENT.md
Newer Older
379 lines | 16.493kb
Bogdan Timofte authored 8 months ago
1
# Development Guide
2

            
3
## 1. Objectives
4

            
Bogdan Timofte authored 3 weeks ago
5
The Media Importer project aims to provide a robust, efficient solution for organizing media files by date with proper timezone handling and conflict resolution.
Bogdan Timofte authored 8 months ago
6

            
7
Key objectives:
Bogdan Timofte authored 3 weeks ago
8

            
Bogdan Timofte authored 8 months ago
9
- Reliable EXIF/metadata extraction and date parsing
10
- Proper UTC time conversion for QuickTime/Apple media files
11
- Flexible organization patterns (year/month/day/hour)
12
- Safe file operations with dry-run capabilities
13
- Cross-platform compatibility (macOS/Linux)
14

            
15
## 2. Guide
16

            
17
### Development Workflow
18

            
19
When making changes to the project, follow this structured approach:
20

            
21
### Changelog Entries Format
22

            
23
All changelog entries should follow this format:
24

            
Bogdan Timofte authored 3 weeks ago
25
```text
Bogdan Timofte authored 8 months ago
26
- Date time
27
- Bug/Feature description
28
- Changes made
29
```
30

            
31
Example:
Bogdan Timofte authored 3 weeks ago
32

            
33
```text
Bogdan Timofte authored 8 months ago
34
- 2025-09-07 10:30
35
- Fixed data loss issue when processing already-sorted folders
36
- Added exclusion patterns for sorted/organized/processed folders
37
- Added --include-sorted flag to override exclusions when needed
38
```
39

            
40
### File Move Confirmation
41

            
42
Every file move operation should be confirmed:
Bogdan Timofte authored 3 weeks ago
43

            
Bogdan Timofte authored 8 months ago
44
- After moving a file, the script must check that the file exists at the destination.
45
- If the file is not present at the destination after the move operation, the script should immediately stop and report an error.
46
- This ensures data integrity and prevents silent data loss.
47

            
Bogdan Timofte authored 3 weeks ago
48
Implementation note (2026-05):
49

            
50
- Move flow now uses `copy -> verify -> delete source`.
51
- Verification is controlled by `--verify-mode` with modes `size` (default), `strict`, and `none`.
52
- `size` validates destination existence, size match, and metadata/date consistency.
53
- `strict` adds byte-to-byte validation (`cmp`) on top of `size` checks.
54
- Source deletion is allowed only after successful verification.
55

            
Bogdan Timofte authored 8 months ago
56
### Destination Inside Source Handling
57

            
58
- Given the script's purpose, the destination folder may be inside the source folder.
59
- In this case, all files within the destination folder must be excluded from scanning and processing.
60
- For extra safety: before processing any file, if its path matches (or is inside) the destination path, the script must report an error and stop immediately.
61
- This prevents accidental re-processing or moving of files that have already been sorted, ensuring data integrity.
62

            
63
### Testing
64

            
65
Testing is essential to ensure the script's reliability and data safety. The following methodology should be used:
66

            
67
#### Test Environment Setup
Bogdan Timofte authored 3 weeks ago
68

            
Bogdan Timofte authored 8 months ago
69
- The `samples` directory contains a variety of media files for testing.
70
- Create a dedicated working directory named `test` for each test run.
71
- Copy selected files from `samples` into the `test` directory to simulate real-world scenarios.
72
- Perform import operations using the script, targeting the `test` directory as the source and a subdirectory (e.g., `test/sorted`) as the destination.
73

            
74
#### Test Execution and Documentation
Bogdan Timofte authored 3 weeks ago
75

            
Bogdan Timofte authored 8 months ago
76
- Before and after each import operation, run `find` on both the source and destination directories to capture the file structure:
77
  - Example: `find ./test > test/source_before.txt`
78
  - Example: `find ./test/sorted > test/dest_before.txt`
79
- Log all results, including script output and directory listings, into a dedicated log file for each test.
80

            
81
#### Test Report Format
Bogdan Timofte authored 3 weeks ago
82

            
Bogdan Timofte authored 8 months ago
83
Each test must generate a comprehensive Markdown report in `test/test_report.md` with the following structure:
84

            
85
```markdown
86
# Test Report: [Test Name/Scenario]
87

            
88
## Test Information
89
- **Date**: $(date)
90
- **Scenario**: [Brief description of what is being tested]
91
- **Objective**: [What specific functionality/behavior is being verified]
92
- **Files Used**: [List of test files and their characteristics]
93

            
94
## Pre-Test State
95
### Source Directory Structure
96
\`\`\`
97
[Contents of source_before.txt]
98
\`\`\`
99

            
100
### Destination Directory Structure
101
\`\`\`
102
[Contents of dest_before.txt]
103
\`\`\`
104

            
105
## Test Execution
106
### Command Used
107
\`\`\`bash
108
[Exact command executed]
109
\`\`\`
110

            
111
### Script Output
112
\`\`\`
113
[Full script output from import_log.txt]
114
\`\`\`
115

            
116
## Post-Test State
117
### Source Directory Structure
118
\`\`\`
119
[Contents of source_after.txt]
120
\`\`\`
121

            
122
### Destination Directory Structure
123
\`\`\`
124
[Contents of dest_after.txt]
125
\`\`\`
126

            
127
## Analysis and Verification
128
### Expected Results
129
- [List what should happen]
130

            
131
### Actual Results
132
- [List what actually happened]
133

            
134
### Issues Found
135
- [Any problems, errors, or unexpected behavior]
136
- [Include error messages, incorrect file placements, etc.]
137

            
138
### Protections Verified
139
- [ ] Destination exclusion working
140
- [ ] Move confirmation functional
141
- [ ] No data loss detected
142
- [ ] UTC conversion correct (for QuickTime files)
143
- [ ] Unimportable files handling (if applicable)
144

            
145
## Corrective Actions
146
### Issues Identified
147
- [Detailed description of problems found]
148

            
149
### Fixes Applied
150
- [Code changes made]
151
- [Configuration adjustments]
152
- [Process improvements]
153

            
154
### Re-test Results
155
- [Results after applying fixes]
156

            
157
## Conclusion
158
### Test Result
159
- [ ] PASSED
160
- [ ] FAILED
161
- [ ] PARTIAL (with notes)
162

            
163
### Notes
164
[Any additional observations, recommendations, or follow-up actions needed]
165

            
166
### Files Generated
167
- `test/source_before.txt` - Pre-test source structure
168
- `test/dest_before.txt` - Pre-test destination structure
169
- `test/source_after.txt` - Post-test source structure
170
- `test/dest_after.txt` - Post-test destination structure
171
- `test/import_log.txt` - Full script execution log
172
- `test/test_report.md` - This report
173
```
174

            
175
#### Automated Test Runner
Bogdan Timofte authored 3 weeks ago
176

            
Bogdan Timofte authored 8 months ago
177
A comprehensive test runner script (`test_runner.sh`) is available to automate the testing process:
178

            
179
```bash
180
./test_runner.sh
181
```
182

            
183
The script provides:
Bogdan Timofte authored 3 weeks ago
184

            
Bogdan Timofte authored 8 months ago
185
- **Pre-configured test scenarios** for common use cases
186
- **Automatic report generation** in Markdown format
187
- **State capture** before and after test execution
188
- **Protection verification** with checkboxes
189
- **Custom test support** for specific scenarios
190

            
191
#### Test Categories
Bogdan Timofte authored 3 weeks ago
192

            
Bogdan Timofte authored 8 months ago
193
The test runner provides the following pre-configured test scenarios:
194

            
195
1. **Basic Functionality Test**: Tests processing of files with valid EXIF data to verify correct sorting and organization
196
2. **Unimportable Files Test**: Tests handling of files without EXIF data in both root and subfolders, without --collect-unimportable flag
197
3. **Mixed Content Test**: Tests processing of sortable and unimportable files in separate folders to verify cleanup behavior
198
4. **Safety Protections Test**: Tests destination exclusion and move confirmation mechanisms to prevent data loss
199
5. **UTC Conversion Test**: Tests UTC timestamp conversion for QuickTime/Apple EXIF data
200
6. **Subdirectory Processing Test**: Tests processing of files in nested subdirectories to ensure recursive file discovery
Bogdan Timofte authored 3 weeks ago
201
7. **Source Only Test**: Tests automatic `source/sorted` destination behavior
202
8. **Destination Inside Source Test**: Verifies destination exclusion and prevents `sorted/sorted` recursion
203
9. **Verify Mode Test**: Verifies default `size` verification and explicit `strict` mode
204
10. **Timestamp Collision No-Overwrite Test**: Reproduces GoPro-style chapters with identical `CreateDate` values and verifies unique destination filenames with no overwrite collapse
205
11. **GoPro Sidecar Metadata Sync Test**: Verifies GoPro MP4 imports use THM start times and automatically write the corrected timestamp into destination metadata
Bogdan Timofte authored 8 months ago
206

            
207
#### Test Result Persistence
Bogdan Timofte authored 3 weeks ago
208

            
Bogdan Timofte authored 8 months ago
209
The test runner includes automatic result persistence:
210

            
211
- **Archival Location**: Test results are saved as individual Markdown files in `test_reports/` directory
Bogdan Timofte authored 3 weeks ago
212
- **Naming Convention**: `{s/f}_{YYYYMMDD_HHMMSS}_{TestName}.md` format where:
213
  - `s` = success, `f` = failure
214
  - Followed by timestamp and test name (spaces converted to underscores)
Bogdan Timofte authored 8 months ago
215
- **Contents Preserved**: Single self-contained Markdown file with:
216
  - Complete test information and directory structures
217
  - Full script execution output embedded inline (ANSI codes stripped for readability)
218
  - Import log content included directly in the report
219
- **Excluded Files**: No separate files - everything is consolidated in the Markdown report
220
- **Historical Tracking**: Maintains complete test history for debugging and regression testing
221

            
222
#### Cleanup
Bogdan Timofte authored 3 weeks ago
223

            
Bogdan Timofte authored 8 months ago
224
- Review the test report and verify all aspects are documented
225
- Clean up the `test` directory after each test run to ensure a fresh environment for subsequent tests
226
- Archive important test reports in a `test_reports/` directory for future reference
227

            
228
## 3. Changelog
229

            
Bogdan Timofte authored 3 weeks ago
230
### 2026-05-16 00:10 - GoPro Chapter Overwrite Postmortem
231

            
232
- Documented the 2026-05-15 GoPro import data-loss incident in `INCIDENTS.md`.
233
- Root cause: multiple chaptered GoPro MP4 files shared the same timestamp-derived destination filename; the script warned but continued, allowing each copy to overwrite the previous destination before deleting the current source after verification.
234
- Clarified that QuickTime UTC-to-local conversion likely explains the visible `19:20` vs `22:20` timestamp difference, but was not the data-loss mechanism.
235
- Recorded surviving evidence: only the final full-resolution chapter remained in destination; `.THM` and `.LRV` sidecars remained on the card and preserved the chapter timeline.
236
- Added operational guidance for future GoPro imports: start with `--date-source filesystem --sync-metadata --dry-run -v` and verify that GoPro MP4 dates come from matching `.THM` sidecars.
237
- Added regression rule: future changes to date extraction, naming, conflict handling, copy/move, or GoPro/Garmin/Varia behavior must run `./test_runner.sh timestamp-collision`.
238

            
239
---
240

            
241
### 2026-05-17 08:35 - Automatic GoPro Metadata Timestamp Correction
242

            
243
- Changed GoPro import behavior so `GX/GH/GP*.MP4` files with matching `.THM` sidecars prefer the THM filesystem timestamp even in default `auto` date mode.
244
- GoPro imports that use THM/filesystem dates now automatically sync destination metadata to the corrected clip start time; `--sync-metadata` is no longer required for this GoPro path.
245
- Changed move flow for metadata-corrected imports to copy and verify first, write destination metadata, verify the metadata timestamp, and only then delete the source file.
246
- Added `GoPro_Sidecar_Metadata_Sync` regression coverage in `test_runner.sh`.
247
- Verified the real `/Volumes/GOPRO` dry-run maps the current files to `19:03:20`, `19:15:08`, `19:26:56`, and `19:38:44`, all from matching THM sidecars.
248

            
249
---
250

            
251
### 2026-05-17 09:20 - Explicit Destination Conflict Policy
252

            
253
- Added `--unattended`; unattended/non-interactive runs never prompt and resolve existing destinations with numeric suffixes (`_1`, `_2`, ...).
254
- Interactive runs now ask on destination conflicts and offer suffix once/all, skip once/all, or abort, so long imports do not require repeated decisions.
255
- Dry-run reserves planned destinations, so collisions within the same run are visible before writing.
256
- Updated `Timestamp_Collision_No_Overwrite` to assert numeric suffixes and reject the legacy `__GX...` suffix form.
257

            
258
---
259

            
260
### 2026-05-17 12:05 - Long Import UX Feedback
261

            
262
- Added per-file progress lines (`Processing [n/total]`) before long copy/move work starts.
263
- Replaced integer `files/sec` reporting with decimal throughput that shows `files/min` for large slow imports and keeps `MB/sec` precision.
264
- Added average time per processed file to the final report.
265

            
266
---
267

            
268
### 2026-05-17 12:20 - GoPro Filesystem Date Fallback
269

            
270
- GoPro auto date extraction now stays on filesystem timestamps even when THM is missing.
271
- Fallback order is matching `THM`, matching `LRV`, then the MP4 file's own filesystem mtime.
272
- Automatic metadata sync now applies to all GoPro filesystem date sources, including the MP4 fallback.
273
- Extended `GoPro_Sidecar_Metadata_Sync` to cover THM, LRV-only, and no-sidecar GoPro imports.
274
- Added `GoPro_No_Sidecar_Reimport` to verify no-sidecar MP4 fallback plus safe numeric suffixing when the same GoPro file is imported again.
275
- Excluded macOS AppleDouble `._*` files from source discovery so NAS metadata forks are not treated as importable media.
276

            
277
---
278

            
279
### 2026-05-13 21:10 - Critical Data Loss Incident + Hardening
280

            
281
- Observed incident: running with explicit source on a problematic/near-full card led to writes on source media and source content removal without strong post-write confirmation.
282
- Impact: major data loss risk on unstable storage media (including read-only/IO edge cases).
283
- Clarified behavior kept as valid: destination may be inside source (`source/sorted`) and must be excluded from scanning.
284
- Reworked move safety in `media-importer.sh`: direct `mv` path replaced by verified flow `copy -> verify -> delete source`.
285
- Added verification modes via `--verify-mode`:
286
  - `size` (default): destination exists + size match + metadata/date validation
287
  - `strict`: adds byte-to-byte content validation (`cmp`)
288
  - `none`: disables verification (explicit opt-out)
289
- Applied the same verified move logic for unsortable collection path.
290
- Added regression coverage in `test_runner.sh`:
291
  - Destination-inside-source test (`-s source -d source/sorted`) to verify destination exclusion and no `sorted/sorted` recursion.
292
  - Verify-mode test to confirm default `size` and explicit `strict` behavior.
293
- Updated ignore/staging hygiene to avoid committing generated test artifacts and `.DS_Store`.
294

            
295
---
296

            
Bogdan Timofte authored 8 months ago
297
### 2025-09-07 21:15 - Test 2 and 3 Enhancements
Bogdan Timofte authored 3 weeks ago
298

            
Bogdan Timofte authored 8 months ago
299
- Updated Test 2 (Unimportable Files Test) to include files in both root and subfolder
300
- Removed --collect-unimportable flag from Test 2 to test default behavior
301
- Updated Test 3 (Mixed Content Test) to use separate folders for sortable vs unimportable files
302
- Test 3 now verifies that folders with only sortable files are cleaned up while folders with unimportable files are preserved
303
- Updated menu descriptions to reflect the changes
304
- Tests now verify proper handling of unimportable files without collection flag
305

            
306
---
307

            
308
### 2025-09-07 21:25 - Documentation Enhancement
Bogdan Timofte authored 3 weeks ago
309

            
Bogdan Timofte authored 8 months ago
310
- Added comprehensive documentation for --collect-unimportable flag in README.md
311
- Added Example 4 showing how to use --collect-unimportable flag
312
- Updated Features section to mention unimportable files handling
313
- Updated Configuration section to explain default behavior for unimportable files
314
- Added usage example for --collect-unimportable in Basic Usage section
315

            
316
---
317

            
318
### 2025-09-07 21:30 - Git Ignore Enhancement
Bogdan Timofte authored 3 weeks ago
319

            
Bogdan Timofte authored 8 months ago
320
- Added test_reports/ to .gitignore to exclude generated test reports from version control
321
- Test reports are generated files that don't need to be tracked in Git
322
- Prevents large numbers of timestamped report files from cluttering the repository
323
- Added sample/ to .gitignore to exclude test media files from version control
324

            
325
---
326

            
327
### 2025-09-07 20:40 - Source Only Test Addition
Bogdan Timofte authored 3 weeks ago
328

            
Bogdan Timofte authored 8 months ago
329
- Added Test 8: Source Only Test to test runner
330
- Tests processing with only source parameter (creates sorted subdirectory automatically)
331
- Verifies that when no destination is specified, files are sorted into source/sorted/
332
- Updated menu and command line options for new test
333

            
334
---
335

            
336
### 2025-09-07 20:45 - Test 7 Refinement
Bogdan Timofte authored 3 weeks ago
337

            
Bogdan Timofte authored 8 months ago
338
- Updated Test 7 to test --keep-empty-dirs functionality instead of cleanup
339
- Since cleanup is now default behavior, Test 7 now verifies empty directory preservation
340
- Renamed from "Cleanup Empty Directories Test" to "Keep Empty Directories Test"
341
- Updated test scenario to validate --keep-empty-dirs flag behavior
342
- Added command line option "keep-empty-dirs" for test 7
343

            
344
---
345

            
346
### 2025-09-07 19:30 - Test Runner Directory Separation
Bogdan Timofte authored 3 weeks ago
347

            
Bogdan Timofte authored 8 months ago
348
- Adapted test runner to use separate source and destination directories
349
- Changed from test/ as source to test/source/ and test/destination/
350
- Updated all test functions to use proper directory separation
351
- Improved test isolation and clarity
352

            
353
---
354

            
355
### 2025-09-07 19:00 - Default Cleanup Behavior
Bogdan Timofte authored 3 weeks ago
356

            
Bogdan Timofte authored 8 months ago
357
- Made --cleanup-empty-dirs the default behavior (implicit option)
358
- Added --keep-empty-dirs flag to disable cleanup if needed
359
- Updated help text and configuration display to reflect new default
360
- Cleanup now runs automatically unless explicitly disabled
361

            
362
---
363

            
364
### 2025-09-07 18:56 - Cleanup Empty Directories Feature
Bogdan Timofte authored 3 weeks ago
365

            
Bogdan Timofte authored 8 months ago
366
- Added --cleanup-empty-dirs option to remove empty directories from source after processing
367
- Added cleanup_empty_directories() function with safe empty directory detection
368
- Updated final report to show cleanup status
369
- Maintains safety by not removing source root directories
370
- Works correctly with dry-run mode
371

            
372
## 4. Todo
373

            
374
Key areas for future development:
Bogdan Timofte authored 3 weeks ago
375

            
Bogdan Timofte authored 8 months ago
376
- GPS metadata integration for timezone detection
377
- Enhanced duplicate detection
378
- Performance optimizations for large file sets
379
- Additional organization patterns