{"id":47612016,"url":"https://github.com/tiagotrindade/foliosort","last_synced_at":"2026-04-26T00:00:59.744Z","repository":{"id":344024203,"uuid":"1179957004","full_name":"tiagotrindade/FolioSort","owner":"tiagotrindade","description":"Native macOS app to organize and batch rename photos, videos, and files using EXIF metadata, GPS location, and Cloud/NAS import. Custom folder templates, reverse geocoding, regex rename, iCloud Drive \u0026 SMB/AFP NAS support, integrity verification, and full undo.","archived":false,"fork":false,"pushed_at":"2026-04-19T17:09:58.000Z","size":20247,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-19T19:33:41.457Z","etag":null,"topics":["exif","icloud","macos","media","nas","network-storage","photo-management","photo-organizer","swift","swiftui"],"latest_commit_sha":null,"homepage":null,"language":"Perl","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tiagotrindade.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-03-12T14:54:46.000Z","updated_at":"2026-04-19T17:10:01.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/tiagotrindade/FolioSort","commit_stats":null,"previous_names":["tiagotrindade/mediamover","tiagotrindade/foliosort"],"tags_count":40,"template":false,"template_full_name":null,"purl":"pkg:github/tiagotrindade/FolioSort","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tiagotrindade%2FFolioSort","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tiagotrindade%2FFolioSort/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tiagotrindade%2FFolioSort/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tiagotrindade%2FFolioSort/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tiagotrindade","download_url":"https://codeload.github.com/tiagotrindade/FolioSort/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tiagotrindade%2FFolioSort/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32280981,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-25T18:29:39.964Z","status":"ssl_error","status_checked_at":"2026-04-25T18:29:32.149Z","response_time":59,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["exif","icloud","macos","media","nas","network-storage","photo-management","photo-organizer","swift","swiftui"],"created_at":"2026-04-01T20:32:39.378Z","updated_at":"2026-04-26T00:00:59.701Z","avatar_url":"https://github.com/tiagotrindade.png","language":"Perl","funding_links":[],"categories":[],"sub_categories":[],"readme":"# FolioSort\n\n**Sort, rename, and organize your photos \u0026 videos — by date, location, or custom time ranges.**\n\nA native macOS app that reads EXIF metadata, GPS coordinates, and file dates to automatically organize large photo/video libraries into meaningful folder structures. Built for photographers, videographers, and anyone who deals with bulk media files.\n\n🌐 **[foliosort.app](https://foliosort.app)** · **[Download latest DMG](https://github.com/tiagotrindade/FolioSort/releases/latest)** — macOS 14+, Apple Silicon \u0026 Intel\n\n---\n\n## Screenshots\n\n| Mover | Rename |\n|:---:|:---:|\n| ![Mover](docs/screenshot-mover.png) | ![Rename](docs/screenshot-rename.png) |\n\n| Event Organizer |\n|:---:|\n| ![Events](docs/screenshot-events.png) |\n\n---\n\n## What's New\n\n### v2.13.0 — QA Stability Hardening\n- **ReDoS protection** — regex preview in the Rename tab now runs on a background thread with per-file cancellation; pathological patterns like `(a+)+b` can no longer freeze the UI\n- **Back-reference validation** — the Regex Rename preview now shows an error if the replacement references a capture group that doesn't exist (e.g. `$2` with only one group)\n- **255-byte path component limit** — the template engine now validates and truncates folder/file name components to stay within the macOS filesystem limit, with a clear warning in the template validator\n- **Invisible Unicode stripped** — characters like non-breaking space (U+00A0), zero-width joiner (U+200D), and BOM (U+FEFF) are now removed from folder and file names produced by the template engine, preventing visually-identical but byte-distinct filenames\n- **Null Island GPS rejected** — coordinates `(0.0, 0.0)` emitted by cameras before satellite fix are now ignored instead of being cached as a valid geocoding result\n- **Geocoding rate-limit safety margin** — request interval increased from 1.2 s to 1.5 s (~40 req/min) to absorb API latency variance and reduce rate-limit errors on large batches\n- **Memory leak fixed** — the geocoding background task in the Mover now captures `self` weakly, preventing the ViewModel from being kept alive indefinitely after the window closes\n- **Duplicate overwrite safety** — when \"Replace if larger\" is active, failure to read the size of an existing file now produces an explicit error instead of silently treating the size as 0 (which could overwrite the file)\n- **License grace period survives UserDefaults wipes** — `lastValidated` is now stored in the macOS Keychain alongside the license key; third-party cache cleaners can no longer accidentally reset the offline grace period\n- **Deactivation error surfaced** — if license deactivation fails (e.g. no internet), the Settings screen now shows the error instead of silently succeeding while the server slot remains occupied\n- Various force-unwrap eliminations: `TimeZone(identifier:\"UTC\")!`, `URL(string:)!`, `result.error!`\n\n### v2.12.0 — Automatic Updates (Sparkle)\n- **Over-the-air updates** — FolioSort now checks for updates automatically using [Sparkle](https://sparkle-project.org/); you'll be notified when a new version is available and can update in one click without visiting the website\n- **Manual check** — Settings › General › \"Check for Updates\" also available\n\n### v2.11.0 — UI Refinements\n- **Folder preview card** — the Mover grid now shows a folder preview card as the 8th cell, giving a visual summary of the target folder structure before starting\n- **Events layout cleanup** — sub-event configuration panels repositioned for a cleaner hierarchy; Photos and Videos rows merged into a single Thumbnails row\n\n### v2.10.2 — Google Photos Analytics \u0026 Pro Gating\n- **Usage analytics** — anonymous Aptabase events for Google Photos Takeout feature usage (opt-out in Settings)\n- **Flat mode is now the default** for all users in Google Photos Takeout — processes files directly into the destination without creating subfolders\n- **Date folder organisation is Pro-only** — the toggle to sort into date-based subfolders is now gated behind Pro (was previously available to all)\n\n### v2.10.1 — ExifTool Stability Fix\n- **Google Photos Takeout: fixed cascading slowdown** — when ExifTool timed out on a single problematic file, the daemon's pipe clogged and every subsequent file also timed out (30 s each). The daemon is now killed and restarted after any timeout, so bad files are skipped and the next file proceeds immediately\n- **Timeout reduced 30 s → 10 s** — problematic files fail 3× faster\n- **Console logs now show real file names** (were previously hidden as `\u003cprivate\u003e`)\n\n### v2.10.0 — Google Photos Takeout, Visual Redesign \u0026 Stability\n- **Google Photos Takeout organizer (Beta)** — import and sort your exported Google Takeout archives; EXIF dates + GPS + people tags written back to files; real camera name extracted from EXIF; Move mode and date-folder organisation gated behind Pro\n- **Visual redesign** — refreshed UI across all tabs, tighter layouts, improved colour use\n- **Geocoding prompt** — after scan, choose to resolve GPS locations now or in the background while you configure settings\n- **Settings fully wired** — System notifications on finish, Restore last session, Show wizard for new folders, Completion sound all now active\n- **Restore Purchase** — Settings › License now has a working Restore button (re-validates stored key with a result alert)\n- **9 QA stability fixes** — space-warning loop after \"Continue Anyway\", analytics firing before validation (Mover + Rename), EventProject persisted between sessions, Events Pro gate in navigation, redundant `generatePreview()` removed from Wizard, RenameView now respects Compact Rows setting\n\n### v2.8.0 — Events Layout Redesign \u0026 Wizard Flow Overhaul\n- **Events tab redesigned** — event creation on the left, source \u0026 destination setup in the middle, preview on the right; all panels are resizable by dragging the dividers\n- **Wizard Events flow reworked** — Step 1: define events \u0026 sub-events · Step 2: pick folders \u0026 settings · Step 3: full file preview before starting\n- **Wizard Review step** — Mover and Rename now show a file preview sample (before → after) after the integrity message\n\n### v2.7.0 — Wizard Tab \u0026 New App Icon\n- Guided step-by-step Wizard for Organize, Rename, and Events\n- New app icon\n- Various UX fixes and stability improvements\n\n### v2.6.0 — Analytics Integration\n- Aptabase privacy-first analytics to understand feature usage\n\n### v2.5.0 — Event Organizer\n- Sort photos and videos into folders based on custom time ranges\n- Two-level hierarchy: events → sub-events\n- UTC-aligned date pickers, overlap validation, live preview, full undo\n\n---\n\n## Features\n\n### Media Organization (Mover)\n- **Custom folder templates** — build folder structures with tokens like `{YYYY}/{MM}/{DD}`, `{Camera}`, `{City}`, `{Month}`, and more\n- **Preset profiles** — 4 built-in presets (Photography by date, Photography by camera, Video production, Archive flat) plus user-created profiles\n- **Simple \u0026 Advanced modes** — clean pattern dropdown for quick use, or toggle Advanced for full template builder with token palette\n- **EXIF-based sorting** — reads DateTaken from photo EXIF data\n- **Video metadata** — reads creation date from MOV, MP4, MKV and other formats\n- **Copy or Move mode** — choose whether to keep or move originals\n- **Rename with date prefix** — optionally prepend date-time to filenames during organization\n- **Videos subfolder** — separate videos into a dedicated `Videos` subfolder within each date folder\n- **Non-media files** — optionally include documents, archives, and any other file types\n- **Preview before organizing** — scan files and review the folder tree before committing\n- **Thumbnail previews** — toggle on/off for faster scanning on large libraries\n- **Drag \u0026 drop** — drop source and destination folders directly onto the app\n\n### GPS Reverse Geocoding\n- **Automatic location detection** — reads GPS coordinates from photo/video EXIF data\n- **Reverse geocoding** — resolves GPS to city, country, state using Apple's CLGeocoder\n- **Location tokens** — use `{City}`, `{Country}`, `{State}`, `{Locality}` in folder templates\n- **Smart caching** — in-memory + disk cache with coordinate rounding (~110m precision)\n- **Rate limiting** — respects Apple's geocoding limits with request coalescing\n\n### Date Handling\n- **EXIF date chain**: DateTimeOriginal → DateTimeDigitized → TIFFDateTime (supports scanned photos)\n- **Subsecond precision**: parses EXIF dates with milliseconds (e.g. Nikon, Sony cameras)\n- **File Creation Date** fallback (default) when no EXIF/metadata is found\n- **File Modification Date** fallback as alternative\n- **Skip** files with no metadata date available\n- **UTC-consistent** folder sorting — all dates interpreted in UTC to avoid timezone drift\n\n### Mass Rename\n- **Pattern-based rename** — 7 naming patterns (Date prefix, Date-Time, Sequential, Camera model, etc.)\n- **Regex rename** — find/replace with `NSRegularExpression`, capture groups (`$1`, `$2`), case-insensitive option\n- **Live preview** — see before/after filenames with regex match highlighting\n- **Common regex presets** — Remove prefix, Replace spaces, Extract date digits, Remove trailing numbers\n- **Rename in place or copy** — rename files where they are, or copy to a new folder\n\n### Google Photos Takeout Organizer (Beta)\n- **Import from Google Takeout** — point FolioSort at an exported Google Photos Takeout folder (any structure)\n- **EXIF injection** — writes original capture date, GPS coordinates, and people tags back into each file using ExifTool (bundled)\n- **Real metadata extraction** — reads original camera from EXIF even inside Takeout archives\n- **Flat mode (default, free)** — all processed files are placed directly in the destination folder, no subfolders\n- **Date-folder organisation (Pro)** — toggle on to sort into YYYY/MM/DD (or other patterns) subfolders; 7 patterns available\n- **Folder structure preview** — tree view mirroring the Mover preview, sorted newest-first\n- **Copy or Move** — Copy mode is free; Move mode requires Pro\n- **Progress tracking** — live scan progress with file count, speed, and ETA\n\n### Event Organizer (Pro)\n- **Time-range sorting** — define events and sub-events with start/end times; files are sorted into matching folders based on capture timestamp\n- **Two-level hierarchy** — top-level events (e.g. competition rounds) contain sub-events (e.g. heats)\n- **Overlap validation** — real-time warnings if event or sub-event time ranges overlap\n- **Between-slot fallback** — files captured between sub-events are placed in the parent event folder\n- **Unmatched file handling** — move unmatched files to an \"Unmatched\" folder or keep them in source\n- **UTC time alignment** — date pickers display in UTC to match EXIF metadata timestamps\n- **Live preview** — see matched/unmatched file counts and folder structure before committing\n- **Full undo support** — reverse event-based organization with one click\n\n### Integrity Verification\n- **Post-copy/move checksum** verification enabled by default\n- **XXHash64** — fast hashing for large batches (Free tier)\n- **SHA-256** — option for maximum security (Pro)\n\n### Cloud/NAS Import (Pro)\n- **Network volumes** — use SMB/AFP NAS shares (Synology, QNAP, etc.) as source or destination\n- **iCloud Drive** — full support, including auto-download of cloud-only files\n- **Resilient transfers** — retry logic with exponential backoff for network file operations\n- **Disconnect handling** — automatic pause/resume when network volumes disconnect and reconnect\n- **Transfer speed** — real-time MB/s display during network operations\n- **Space checking** — available disk space shown on destination, with low-space warning\n\n### Duplicate Detection\n- **Skip** — skip all duplicates (Free tier)\n- **Ask Each Time** — per-file dialog: rename, replace, replace if larger, or skip (Pro)\n- **Automatic** — configurable default action (Pro)\n\n### Automatic Updates\n- **Sparkle integration** — the app checks for updates on launch and notifies you when a new version is available\n- **One-click update** — download and install without leaving the app\n- **Manual check** — Settings › General › Check for Updates\n\n### Activity Log\n- Full operation log with timestamps and status indicators\n- Searchable and filterable (by status or text)\n- Export log file for external review\n\n### Undo\n- Reverse the last batch operation with one click\n- Copy undo: removes copied files · Move undo: moves files back\n- Persistent history across sessions (up to 50 batches)\n\n---\n\n## Free \u0026 Pro Tiers\n\nFolioSort works out of the box with a generous Free tier. Pro unlocks advanced features for power users.\n\n| Feature | Free | Pro |\n|---|:---:|:---:|\n| Files per operation | 100 | Unlimited |\n| Folder presets | 3 | All |\n| Custom templates | — | ✓ |\n| Custom profiles | — | ✓ |\n| Rename presets | 3 | All |\n| Regex rename | — | ✓ |\n| RAW photo formats | — | ✓ |\n| RAW video formats | — | ✓ |\n| Other (non-media) files | — | ✓ |\n| SHA-256 hashing | — | ✓ |\n| Advanced duplicate handling | — | ✓ |\n| Rename with date prefix | — | ✓ |\n| Videos subfolder | — | ✓ |\n| Reverse geocoding | — | ✓ |\n| Location tokens (City, Country) | — | ✓ |\n| Extended EXIF tokens (Lens, ISO) | — | ✓ |\n| Activity log search \u0026 export | — | ✓ |\n| Persistent undo history | — | ✓ |\n| Cloud/NAS Import (SMB/AFP/iCloud) | — | ✓ |\n| Event Organizer (time-range sorting) | — | ✓ |\n| Google Photos Takeout — Move mode | — | ✓ |\n| Google Photos Takeout — Date folder organisation | — | ✓ |\n\n---\n\n## Buy FolioSort Pro\n\n**€14.99 — One-time purchase, no subscription.**\n\n**[Buy FolioSort Pro](https://foliosort.lemonsqueezy.com/checkout/buy/5a21a602-f4fe-44a4-8415-bebfb86b5de9)**\n\n1. Click the link → complete checkout\n2. Receive your **license key** by email\n3. Open FolioSort → Settings → **Upgrade to Pro** → paste your key → **Activate**\n4. Done — Pro unlocked forever on that Mac\n\n- License key stored securely in macOS Keychain\n- Works offline (7-day grace period between validations)\n- Transfer your license to another Mac anytime (deactivate → reactivate)\n\n---\n\n## Supported Formats\n\n**Photos**: JPG, JPEG, PNG, HEIC, HEIF, TIFF, TIF, BMP, GIF, WebP\n\n**RAW Photos** (Pro): CR2, CR3, CRW (Canon), NEF, NRW (Nikon), ARW, SR2, SRF (Sony), DNG (Adobe), ORF (Olympus), RAF (Fujifilm), RW2 (Panasonic), PEF (Pentax), SRW (Samsung), X3F (Sigma), IIQ, 3FR, FFF (Medium Format), RWL, MRW, ERF, KDC, DCR\n\n**Videos**: MOV, MP4, AVI, MKV, M4V, 3GP, WMV, FLV, WebM, MTS, M2TS, TS, MPG, MPEG, VOB\n\n**RAW Video** (Pro): BRAW (Blackmagic), R3D (RED), ARI/ARR (ARRI), CRM (Canon Cinema)\n\n**Other** (Pro): Any file type via the \"Other Files\" toggle\n\n---\n\n## Requirements\n\n- macOS 14 (Sonoma) or later\n- Apple Silicon (M1/M2/M3/M4) or Intel Mac\n\n---\n\n## Build from Source\n\n```bash\n# Build and run\nswift build \u0026\u0026 swift run\n\n# Create release DMG\nmake dmg\n```\n\n---\n\n## Usage\n\n### Wizard\nThe quickest way to get started. Select an action (Organize, Rename, or Events), follow the guided steps, and hit Start.\n\n### Mover (Organize files into folders)\n1. Select a **source folder** — click **Scan** to enumerate files\n2. Select a **destination folder**\n3. Choose a **folder pattern** or toggle Advanced for the full template builder\n4. Configure options: Copy/Move, file types, duplicates, integrity verification\n5. Review the **Preview panel** then click **Start**\n\n### Event Organizer (Sort media by time ranges)\n1. **Left panel** — create events and sub-events with UTC time ranges\n2. **Middle panel** — select source \u0026 destination folders, choose Copy/Move, configure scan options, click **Scan**\n3. **Right panel** — review the live preview of matched and unmatched files\n4. Click **Start** to sort\n\n### Rename (Batch rename files)\n1. Select a **source folder** — click **Scan**\n2. Choose **Pattern** or **Regex** mode\n3. Preview before/after filenames in the right panel\n4. Click **Rename All** (or **Copy \u0026 Rename**) to apply\n\n### Google Photos Takeout (Beta)\n1. Export your Google Photos library via Google Takeout\n2. Select the **Google Photos** tab → point to the extracted Takeout folder\n3. Select a **destination folder**\n4. By default, all files are copied flat into the destination (no subfolders) — toggle **Organise into date folders** (Pro) to sort into date-based subfolders\n5. Choose **Copy or Move** (Move requires Pro)\n6. Review the folder tree preview, then click **Process**\n\n### Activity\nFull operation history with timestamps, status indicators, search, and export.\n\n### Settings\nManage Pro license, activate/deactivate, and configure preferences.\n\n---\n\n## License\n\nMIT License\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftiagotrindade%2Ffoliosort","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftiagotrindade%2Ffoliosort","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftiagotrindade%2Ffoliosort/lists"}