<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>Duplicates on Jingyuan</title>
        <link>https://jingyuan-zheng.github.io/tags/duplicates/</link>
        <description>Recent content in Duplicates on Jingyuan</description>
        <generator>Hugo -- gohugo.io</generator>
        <language>en-US</language>
        <copyright>Jingyuan Zheng</copyright>
        <lastBuildDate>Thu, 22 Oct 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://jingyuan-zheng.github.io/tags/duplicates/index.xml" rel="self" type="application/rss+xml" /><item>
            <title>Organize an Exported Photo Library on Mac: Live Photos, Duplicates, and Capture Dates</title>
            <link>https://jingyuan-zheng.github.io/p/gallery-organizer/</link>
            <pubDate>Fri, 02 Oct 2026 00:00:00 +0000</pubDate>
            <guid>https://jingyuan-zheng.github.io/p/gallery-organizer/</guid>
            <description>&lt;img src=&#34;https://jingyuan-zheng.github.io/img/gallery-organizer/web-ui-en.jpg&#34; alt=&#34;Featured image of post Organize an Exported Photo Library on Mac: Live Photos, Duplicates, and Capture Dates&#34; /&gt;&lt;p&gt;This guide shows how to organize a photo library already exported on a Mac with Gallery Organizer. You can preview the plan before moving files, file confirmed camera media by capture month, and review Live Photos, duplicates, and uncertain dates separately. Both the browser and CLI support the two main sorting passes.&lt;/p&gt;&#xA;&lt;h2 id=&#34;why-an-exported-library-gets-messy&#34;&gt;Why an exported library gets messy&#xA;&lt;/h2&gt;&lt;p&gt;Phones and cameras reuse names such as &lt;code&gt;IMG_0001&lt;/code&gt;. After overlapping exports, the same name may refer to different years or to another copy of the same picture. A Live Photo often arrives as a HEIC still plus a MOV clip, sometimes with &lt;code&gt;.aae&lt;/code&gt; or &lt;code&gt;.xmp&lt;/code&gt; editing information alongside it. Sorting by filename can split those relationships; sorting by modification date can mistake the day of copying for the day of capture.&lt;/p&gt;&#xA;&lt;p&gt;&lt;a class=&#34;link&#34; href=&#34;https://github.com/Jingyuan-Zheng/gallery-organizer&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;Gallery Organizer&lt;/a&gt; first files camera media it can identify, then checks the screenshots, recordings, saved images, and uncertain files left in the batch. It works on &lt;strong&gt;already exported folders&lt;/strong&gt; on macOS. Export from your phone or Apple Photos first, and do not point it at a Photos library package.&lt;/p&gt;&#xA;&lt;h2 id=&#34;prepare-a-batch-and-a-backup&#34;&gt;Prepare a batch and a backup&#xA;&lt;/h2&gt;&lt;p&gt;Keep a separate copy of the original export and start with a small batch you know well. Edit the project’s &lt;code&gt;config.ini&lt;/code&gt; to set the library root and destinations. The default layout is easier to understand as a journey through two stages:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;&#xA;&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt; 1&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 2&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 3&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 4&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 5&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 6&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 7&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 8&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 9&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;10&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;11&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#xA;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;~/Pictures/GalleryOrganizer/&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;├── Incoming/&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;│   ├── Stage0/Batch A/       ← exported batch before sorting&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;│   └── Stage1/Batch A/       ← batch after a successful first pass&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;└── Gallery/&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    ├── Main/                 ← confirmed camera media&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    ├── SortedFromUnsorted/   ← camera media found in pass two&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    ├── Screenshots/          ← screenshots and recordings&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    ├── OtherMedia/           ← saved images and other material&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    ├── NeedsRepair/          ← dates or sidecars to check&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    └── Duplicate/            ← confirmed redundant copies&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&lt;p&gt;These are possible outputs, not folders every run will create. Media with a known capture date normally goes under &lt;code&gt;2024/2024-06/&lt;/code&gt;. A same-name conflict can add a day-level folder rather than overwriting either file. Set &lt;code&gt;language = zh&lt;/code&gt; in &lt;code&gt;config.ini&lt;/code&gt; if you want Chinese reports and newly created category names; existing folders are not renamed.&lt;/p&gt;&#xA;&lt;h2 id=&#34;preview-the-first-pass-in-your-browser&#34;&gt;Preview the first pass in your browser&#xA;&lt;/h2&gt;&lt;p&gt;From the project directory, start its local web service:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;&#xA;&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;3&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;4&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#xA;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;python3 -m venv .venv&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;source&lt;/span&gt; .venv/bin/activate&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;python -m pip install -r requirements-api.txt&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;uvicorn api.app:app --host 127.0.0.1 --port &lt;span class=&#34;m&#34;&gt;8000&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&lt;p&gt;Open &lt;code&gt;http://127.0.0.1:8000/&lt;/code&gt; and keep Terminal open. Choose the main organizer, enter the full path to &lt;code&gt;Incoming/Stage0/Batch A&lt;/code&gt;, and select &lt;strong&gt;Scan / Dry Run&lt;/strong&gt;. Read the proposed destinations, filename collisions, Live Photo pairings, and items flagged for review. Only then select &lt;strong&gt;Apply changes&lt;/strong&gt;. The tool scans again before applying. After a successful pass, the whole batch moves to &lt;code&gt;Stage1&lt;/code&gt;; files still needing classification remain there.&lt;/p&gt;&#xA;&lt;div class=&#34;post-figure&#34;&gt;&#xA;&lt;img src=&#34;https://jingyuan-zheng.github.io/img/gallery-organizer/web-ui-en.jpg&#34; alt=&#34;Gallery Organizer local browser interface with tool and folder selection&#34;&gt;&#xA;&lt;div class=&#34;caption&#34;&gt;Figure 1: Scan and read the sorting plan before applying it. Screenshot from the repository.&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;p&gt;The browser can switch between English and Chinese, while detailed reports follow &lt;code&gt;config.ini&lt;/code&gt;. Job history helps you inspect a previous run, but an interrupted job does not resume itself and there is no whole-batch Undo. Check the report and real file locations before restarting.&lt;/p&gt;&#xA;&lt;h2 id=&#34;run-the-same-two-passes-from-terminal&#34;&gt;Run the same two passes from Terminal&#xA;&lt;/h2&gt;&lt;p&gt;The CLI is useful when you have a regular export folder and want to process batches one at a time. Replace the sample paths below. &lt;strong&gt;The first command in each pair previews; the command with &lt;code&gt;--apply&lt;/code&gt; moves files&lt;/strong&gt;:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;&#xA;&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;3&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;4&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;5&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#xA;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;python3 organize_gallery_media.py &lt;span class=&#34;s2&#34;&gt;&amp;#34;/your/photo/root/Incoming/Stage0/Batch A&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;python3 organize_gallery_media.py &lt;span class=&#34;s2&#34;&gt;&amp;#34;/your/photo/root/Incoming/Stage0/Batch A&amp;#34;&lt;/span&gt; --apply&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;python3 organize_leftover_media.py &lt;span class=&#34;s2&#34;&gt;&amp;#34;/your/photo/root/Incoming/Stage1/Batch A&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;python3 organize_leftover_media.py &lt;span class=&#34;s2&#34;&gt;&amp;#34;/your/photo/root/Incoming/Stage1/Batch A&amp;#34;&lt;/span&gt; --apply&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&lt;p&gt;Pass one puts confirmed photos and videos in &lt;code&gt;Gallery/Main/year/year-month/&lt;/code&gt; and tries to keep a Live Photo still, its movie, and identified companion files together. Pass two inspects what remains in &lt;code&gt;Stage1&lt;/code&gt;: screenshots and screen recordings go to &lt;code&gt;Screenshots&lt;/code&gt;, saved or downloaded images to &lt;code&gt;OtherMedia&lt;/code&gt;, and unresolved items to &lt;code&gt;NeedsRepair&lt;/code&gt;. Camera media confirmed only on pass two goes to &lt;code&gt;SortedFromUnsorted&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;p&gt;For example, &lt;code&gt;IMG_0100.HEIC&lt;/code&gt;, &lt;code&gt;IMG_0100.MOV&lt;/code&gt;, and &lt;code&gt;IMG_0100.HEIC.xmp&lt;/code&gt; may end up together under &lt;code&gt;Gallery/Main/2024/2024-06/&lt;/code&gt;. An &lt;code&gt;.xmp&lt;/code&gt; whose owner cannot be identified should stay available for review. Camera thumbnails such as &lt;code&gt;.thm&lt;/code&gt; and preview clips such as &lt;code&gt;.lrv&lt;/code&gt; can also be companion files, so keep unfamiliar sidecars until the relationship is clear.&lt;/p&gt;&#xA;&lt;h2 id=&#34;configure-a-root-you-can-recognize&#34;&gt;Configure a root you can recognize&#xA;&lt;/h2&gt;&lt;p&gt;For a library on an external disk, start by changing &lt;code&gt;backup_root&lt;/code&gt; to a dedicated folder on that disk and keep the child paths at their defaults. &lt;code&gt;gallery_root = Gallery&lt;/code&gt; is relative to that root; &lt;code&gt;main_library_root = Main&lt;/code&gt; is relative to Gallery. These settings form a hierarchy rather than three unrelated destinations.&lt;/p&gt;&#xA;&lt;p&gt;Put the test export in &lt;code&gt;Incoming/Stage0/Batch A&lt;/code&gt; and select that batch, not the entire Stage0 parent. The configured root also bounds allowed source and destination paths. In &lt;code&gt;config.ini&lt;/code&gt;, spaces do not need quotes; in Terminal, retain the quotes around folder arguments. Understand this structure before customizing category destinations.&lt;/p&gt;&#xA;&lt;p&gt;The Python packages in &lt;code&gt;requirements-api.txt&lt;/code&gt; support the local website. They do not necessarily supply every external media-reading executable. If a scan identifies a missing tool, inspect &lt;code&gt;[tools]&lt;/code&gt;: an empty setting searches the system, while an explicit setting should point to the executable itself. A directory containing a tool is not the executable path.&lt;/p&gt;&#xA;&lt;h2 id=&#34;review-a-representative-trial-batch&#34;&gt;Review a representative trial batch&#xA;&lt;/h2&gt;&lt;p&gt;Choose ordinary photos, one Live Photo pair, a few screenshots, and an overlapping export copy. After Dry Run, check capture months, photo/video pairings, remaining screenshots, and which duplicate copy will be retained. Investigate a clearly wrong date before applying the plan.&lt;/p&gt;&#xA;&lt;p&gt;After pass one, preview pass two on the same batch under Stage1. The scripts are separate operations, not an automatic end-to-end pipeline. After applying, open sample photos and play a video in their destinations. Read why unresolved items were left aside. A clear classification matters more than an empty incoming folder.&lt;/p&gt;&#xA;&lt;p&gt;Treat JPEG date repair as a separate investigation. A copied old photo may have a recent filesystem date, but that does not justify inventing its capture time from a plausible filename. Confirm the time zone, eligible range, and months reserved for manual review. Keep the repair backups and reports. &lt;code&gt;NeedsRepair&lt;/code&gt; is a place for further judgment, not a bin of disposable material.&lt;/p&gt;&#xA;&lt;h2 id=&#34;handle-duplicates-and-doubtful-dates-separately&#34;&gt;Handle duplicates and doubtful dates separately&#xA;&lt;/h2&gt;&lt;p&gt;The main pass sets confirmed duplicate copies aside. An optional tool checks duplicates already in the main library. &lt;strong&gt;Byte-identical copies&lt;/strong&gt; are different from similar-looking photos: bursts, edited versions, and exports in different formats can all be worth keeping. Browser image comparison is off by default; enable it when visual review helps. First-time HEIC previews can take longer.&lt;/p&gt;&#xA;&lt;div class=&#34;post-figure&#34;&gt;&#xA;&lt;img src=&#34;https://jingyuan-zheng.github.io/img/gallery-organizer/duplicate-preview.jpg&#34; alt=&#34;Gallery Organizer showing duplicate candidates side by side&#34;&gt;&#xA;&lt;div class=&#34;caption&#34;&gt;Figure 2: Compare the images, then check paths and the sorting report before deciding.&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;p&gt;JPEG date repair is another separate operation. Confirm its time-zone offset and eligible date range in &lt;code&gt;config.ini&lt;/code&gt; before allowing writes, and keep its backup and report. Only one browser or CLI job can apply changes at once. To check one photo’s capture fields first, use &lt;a class=&#34;link&#34; href=&#34;https://jingyuan-zheng.github.io/p/view-media-info/&#34; &gt;View Media Info&lt;/a&gt;. The &lt;a class=&#34;link&#34; href=&#34;https://github.com/Jingyuan-Zheng/gallery-organizer#readme&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;project README&lt;/a&gt; documents every path setting and optional tool.&lt;/p&gt;&#xA;</description>
        </item></channel>
</rss>
