Last active
December 28, 2024 03:49
-
-
Save cmbuckley/2c4922f8fdd0725210841dd82bae4ac5 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
tell application "Photos" | |
activate | |
set folderList to name of every folder | |
set selectedFolders to choose from list folderList with prompt "Select folders:" with multiple selections allowed | |
set destination to POSIX path of (choose folder with prompt "Please select a backup location:") | |
repeat with f in folders | |
if selectedFolders contains name of f then | |
my exportFolder(f, destination) | |
end if | |
end repeat | |
end tell | |
-- export a folder to a given destination | |
on exportFolder(tFolder, tPath) | |
set folderName to tPath & "/" & my getFolderName(tFolder) | |
log folderName | |
using terms from application "Photos" | |
tell tFolder | |
repeat with childAlbum in albums | |
my exportAlbum(childAlbum, folderName) | |
end repeat | |
repeat with childFolder in folders | |
my exportFolder(childFolder, folderName) | |
end repeat | |
end tell | |
end using terms from | |
end exportFolder | |
-- work out the folder name | |
on getFolderName(tFolder) | |
set dateNames to {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"} | |
set folderName to name of tFolder | |
if dateNames contains folderName then | |
repeat with idx from 1 to the count of dateNames | |
if item idx of dateNames is folderName then return text -2 thru -1 of ("0" & idx) | |
end repeat | |
end if | |
return folderName | |
end getFolderName | |
-- export an album to a given destination | |
on exportAlbum(tAlbum, tPath) | |
set albumName to tPath & "/" & my getAlbumName(tAlbum, tPath) | |
my makeFolder(albumName) | |
log albumName | |
tell application "Photos" | |
try | |
with timeout of 30 * 60 seconds | |
export (get media items of tAlbum) to (albumName as POSIX file) with using originals | |
end timeout | |
on error | |
tell me to delay 5 | |
activate | |
with timeout of 30 * 60 seconds | |
export (get media items of tAlbum) to (albumName as POSIX file) with using originals | |
end timeout | |
end try | |
end tell | |
end exportAlbum | |
-- get an album name | |
-- some albums have no date prefix (if they are in Misc folder or are empty) | |
-- if all the dates are the same, use "YYYY-MM-DD Album" | |
-- if date is within a month, use "YYYY-MM-DD–EE Album" | |
-- otherwise use "YYYY-MM-DD–ZZZZ-NN-EE Album" | |
on getAlbumName(tAlbum, tPath) | |
using terms from application "Photos" | |
-- to avoid Photos naming clash there are some with "(2)" or "(1 Apr)", remove this | |
set albumName to do shell script "sed 's/ ([0-9].*)$//g' <<< " & quoted form of ((name of tAlbum) as text) | |
if tPath contains "/Misc/" then return albumName | |
set uniqueDates to {} | |
set photoDates to date of every media item of tAlbum | |
if (count of photoDates) = 0 then return albumName -- empty album | |
repeat with photoDate in photoDates | |
set [d, m, y] to [day, month, year] of photoDate | |
set m to m * 1 | |
set m to text -1 thru -2 of ("0" & m) | |
set d to text -1 thru -2 of ("0" & d) | |
set the text item delimiters to "-" | |
set newDate to {y, m, d} as string | |
if uniqueDates does not contain newDate then set end of uniqueDates to newDate | |
end repeat | |
-- single date | |
if length of uniqueDates = 1 then return first item of uniqueDates & " " & albumName | |
set sortedDates to my sortList(uniqueDates) | |
set minDate to first item of sortedDates | |
set maxDate to last item of sortedDates | |
-- same month | |
if text 1 thru 7 of minDate = text 1 thru 7 of maxDate then | |
return minDate & "–" & text 9 thru end of maxDate & " " & albumName | |
end if | |
-- different month/year | |
return minDate & "–" & maxDate & " " & albumName | |
end using terms from | |
end getAlbumName | |
on makeFolder(tPath) | |
do shell script "mkdir -p " & quoted form of tPath | |
end makeFolder | |
-- from: https://developer.apple.com/library/content/documentation/LanguagesUtilities/Conceptual/MacAutomationScriptingGuide/ManipulateListsofItems.html | |
on sortList(theList) | |
set theIndexList to {} | |
set theSortedList to {} | |
try | |
repeat (length of theList) times | |
set theLowItem to "" | |
repeat with a from 1 to (length of theList) | |
if a is not in theIndexList then | |
set theCurrentItem to item a of theList as text | |
if theLowItem is "" then | |
set theLowItem to theCurrentItem | |
set theLowItemIndex to a | |
else if theCurrentItem comes before theLowItem then | |
set theLowItem to theCurrentItem | |
set theLowItemIndex to a | |
end if | |
end if | |
end repeat | |
set end of theSortedList to theLowItem | |
set end of theIndexList to theLowItemIndex | |
end repeat | |
on error errMsg number errorNumber | |
return {"An unknown error occurred:"} & theSortedList | |
end try | |
return theSortedList | |
end sortList |
Excellent script, thank you
does it export the modified pictures of the original?
Is there a way to switch the export mode (original, modified, both)?
Sure, if you change “with using originals” to “without using originals” you’ll get the modified version.
If you wanted to output both, you’d need to loop over the media items add a suffix to the file name to identify the original/modified images (or output to a separate subfolder).
thank you very much
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Script to recursively export albums from Photos.
Starting with an album structure like:
and converting to a similar folder structure:
Where the date ranges depend on the creation dates of the media items within.