Command line application to export and backup your macOS Photos Library
Swift
169
8 commits
updated Oct 13, 2024
October 2024, Andreas Bentele
This is a headless program (with command line interface) to export all photos of the macOS Photos library to a filesystem folder. Like Apple's Time Machine, it backup's the data in folders containing full backups, while using hard links to minimize disk usage.
You may ask: why another backup solution in addition to Time Machine, which already backups my Photos library? The answer is: Time Machine is one of the best backup solutions I know. But the macOS Photos Library has it's very special database structure - it's in parts file system based, but not intended to open it with any other program than Apple's Photos. Time Machine does nothing else but backup this database to an external disk. Backups are not portable to another system other than a Mac with Photos.
Using Time Machine to backup my photos is what I've done for many years till I lost some of the most important photos in my Photos library (maybe by own mistake). Because of Time Machine automatically removes old backups to get new disk space, the photos were also deleted from my backups. Fortunately I found the photos in a backup of my old Aperture library. This opened my eyes, so I decided to implement a small program which implements the following requirements, partly inspired by how Time Machine works:
There are two possible general use cases:
You also can combine both: export to local disk using SnapshotPhotosExporter. Make a backup using Time Machine to an external disk. Then use the IncrementalPhotosExporter to export the photos to the same external disk while using hard links to the already exported photos in the Time Machine backup instead of copying all photos again (see parameter baseExportPath for more details).
I believe some other people who think backups are very important could make use of it as well, so I've decided to make the code open source. Any feedback is appreciated, especially pull requests with improvements.
This program was not my first try. I've tried out some other solutions before, that didn't work at all:
The next step was to re-implement everything using Apple's latest programming language Swift and the MediaLibrary Framework. The result was very robust, performant and maintainable compared to the previous solutions and worked with macOS Mojave.
Starting with macOS Catalina the MediaLibrary Framework had a bug which causes keywords cannot be requested from the Photos library any more. With macOS Big Sur, the MediaLibrary became deprecated. Therefore I've replaced the MediaLibrary Framework with the PhotoKit. This framework has also some drawbacks, e.g. the performance is not really optimal and some information cannot be requested from the Photos library, e.g. keywords. To compensate for this, keywords and other data are loaded directly from the Photos sqlite database.
Currently the program doesn't have any arguments and no user interface (I've started to work on it, but it's far from being usable).
To use it:
---
plans:
-
type: SnapshotFileSystemExport
enabled: false
name: My export
mediaObjectFilter:
keywordWhiteList:
- test
keywordBlackList:
targetFolder: /Users/<username>/Pictures/Fotos-Export/test
deleteFlatPath: false
exportOriginals: true
For settings attributes see the description below.
Normally, the exporter adds the timestamp of a photo to the exported photo's filename. Use the keyword "export-no-date" in Photos to omit the timestamp in the filename.
If you move the exported folder, be sure to recreate the Latest link, because it would be broken after moving the folders.
All settings can be applied both to the SnapshotPhotosExporter and to IncrementalPhotosExporter.
SnapshotFileSystemExport or IncrementalFileSystemExporttrue or false - can be used to disable export configurationThe program starts with reading all metadata of the System Photos Library. This is implemented in PhotosMetadataReader.swift using PhotoKit and SQL.
The rest is implemented in PhotosExporter.swift and inherited classes SnapshotPhotosExporter.swift and IncrementalPhotosExporter.swift.
The two implementations are different:
InProgress is created. This is a temporary folder where the program copies all exported folders and files to; . After the export of all files has been succeeded, the folder is renamed to the current date formatted with the date pattern yyyy-MM-dd HH-mm-ss. Also a symbolic link (alias) to this folder named Latest is created to know which files to link on the next export. If an error occurs during the backup, the InProgress folder will be left, until the next run of the program finally deletes it.InProgress folder, too. If the files of the Photos Library and the target folder are on the same file system, the files are not copied to the InProgress folder. Instead, hard links are created, to minimize disk usage. After the export of all files has been succeeded, the folder is renamed to Snapshot, while the old Snapshot folder is removed before.The main part - exporting the albums and photos - is done in two phases: the first phase is to export all original and modified photos to a folder named .flat. The second phase creates all sub-folders based on the folders and albums in the Photos Library.
This screenshot should give an idea about the generated folder structure:

While exporting media files to the .flat folder, the program checks if a file has been changed since the last export, and uses a hard link in case the file hasn't been changed. This is done by comparing the media file in the Photos Library with the corresponding file in the Latest folder. While a comparison by something like a MD5 or SHA checksum would be the preferred way to check if the file content has been changed, I've decided to implement a simple comparison based on the file size for performance reasons.
As you can see, the SnapshotPhotosExporter is highly optimized to always keep the export directory on the same file system. If you backup your disk with Time Machine, no extra disk space is required because of the hard links. If photos are modified within the Photos app (or Photos recalculates the photos e.g. because of changed algorithms), the photos in the export directory may also be changed. For using the photos with other devices or programs, this behavior will be what you need. For backups on external drives it wouldn't be sufficient - therefore the IncrementalPhotosExporter was designed.
Swift
100.0%
Command line application to export and backup your macOS Photos Library
Swift
169
8 commits
updated Oct 13, 2024
October 2024, Andreas Bentele
This is a headless program (with command line interface) to export all photos of the macOS Photos library to a filesystem folder. Like Apple's Time Machine, it backup's the data in folders containing full backups, while using hard links to minimize disk usage.
You may ask: why another backup solution in addition to Time Machine, which already backups my Photos library? The answer is: Time Machine is one of the best backup solutions I know. But the macOS Photos Library has it's very special database structure - it's in parts file system based, but not intended to open it with any other program than Apple's Photos. Time Machine does nothing else but backup this database to an external disk. Backups are not portable to another system other than a Mac with Photos.
Using Time Machine to backup my photos is what I've done for many years till I lost some of the most important photos in my Photos library (maybe by own mistake). Because of Time Machine automatically removes old backups to get new disk space, the photos were also deleted from my backups. Fortunately I found the photos in a backup of my old Aperture library. This opened my eyes, so I decided to implement a small program which implements the following requirements, partly inspired by how Time Machine works:
There are two possible general use cases:
You also can combine both: export to local disk using SnapshotPhotosExporter. Make a backup using Time Machine to an external disk. Then use the IncrementalPhotosExporter to export the photos to the same external disk while using hard links to the already exported photos in the Time Machine backup instead of copying all photos again (see parameter baseExportPath for more details).
I believe some other people who think backups are very important could make use of it as well, so I've decided to make the code open source. Any feedback is appreciated, especially pull requests with improvements.
This program was not my first try. I've tried out some other solutions before, that didn't work at all:
The next step was to re-implement everything using Apple's latest programming language Swift and the MediaLibrary Framework. The result was very robust, performant and maintainable compared to the previous solutions and worked with macOS Mojave.
Starting with macOS Catalina the MediaLibrary Framework had a bug which causes keywords cannot be requested from the Photos library any more. With macOS Big Sur, the MediaLibrary became deprecated. Therefore I've replaced the MediaLibrary Framework with the PhotoKit. This framework has also some drawbacks, e.g. the performance is not really optimal and some information cannot be requested from the Photos library, e.g. keywords. To compensate for this, keywords and other data are loaded directly from the Photos sqlite database.
Currently the program doesn't have any arguments and no user interface (I've started to work on it, but it's far from being usable).
To use it:
---
plans:
-
type: SnapshotFileSystemExport
enabled: false
name: My export
mediaObjectFilter:
keywordWhiteList:
- test
keywordBlackList:
targetFolder: /Users/<username>/Pictures/Fotos-Export/test
deleteFlatPath: false
exportOriginals: true
For settings attributes see the description below.
Normally, the exporter adds the timestamp of a photo to the exported photo's filename. Use the keyword "export-no-date" in Photos to omit the timestamp in the filename.
If you move the exported folder, be sure to recreate the Latest link, because it would be broken after moving the folders.
All settings can be applied both to the SnapshotPhotosExporter and to IncrementalPhotosExporter.
SnapshotFileSystemExport or IncrementalFileSystemExporttrue or false - can be used to disable export configurationThe program starts with reading all metadata of the System Photos Library. This is implemented in PhotosMetadataReader.swift using PhotoKit and SQL.
The rest is implemented in PhotosExporter.swift and inherited classes SnapshotPhotosExporter.swift and IncrementalPhotosExporter.swift.
The two implementations are different:
InProgress is created. This is a temporary folder where the program copies all exported folders and files to; . After the export of all files has been succeeded, the folder is renamed to the current date formatted with the date pattern yyyy-MM-dd HH-mm-ss. Also a symbolic link (alias) to this folder named Latest is created to know which files to link on the next export. If an error occurs during the backup, the InProgress folder will be left, until the next run of the program finally deletes it.InProgress folder, too. If the files of the Photos Library and the target folder are on the same file system, the files are not copied to the InProgress folder. Instead, hard links are created, to minimize disk usage. After the export of all files has been succeeded, the folder is renamed to Snapshot, while the old Snapshot folder is removed before.The main part - exporting the albums and photos - is done in two phases: the first phase is to export all original and modified photos to a folder named .flat. The second phase creates all sub-folders based on the folders and albums in the Photos Library.
This screenshot should give an idea about the generated folder structure:

While exporting media files to the .flat folder, the program checks if a file has been changed since the last export, and uses a hard link in case the file hasn't been changed. This is done by comparing the media file in the Photos Library with the corresponding file in the Latest folder. While a comparison by something like a MD5 or SHA checksum would be the preferred way to check if the file content has been changed, I've decided to implement a simple comparison based on the file size for performance reasons.
As you can see, the SnapshotPhotosExporter is highly optimized to always keep the export directory on the same file system. If you backup your disk with Time Machine, no extra disk space is required because of the hard links. If photos are modified within the Photos app (or Photos recalculates the photos e.g. because of changed algorithms), the photos in the export directory may also be changed. For using the photos with other devices or programs, this behavior will be what you need. For backups on external drives it wouldn't be sufficient - therefore the IncrementalPhotosExporter was designed.
Swift
100.0%