我打算将我的所有照片从 Mac 导出到任何其他环境,这个建议最终提供了使用 applescript 解决此问题的基础。这样照片总是会缩放(比原来的大),但至少它是有效的。
我知道这很长,但由于我在这个问题上挣扎了很长时间,所以我在下面发布了整个工作解决方案作为答案。也许有人有更好的建议。我拒绝对 Photos 正在使用的 sqlite 表中的内容进行逆向工程,因为这可能会随着下一个版本而改变。
问题多种多样
不幸的是,这是我能想到的最好的,这是我的第一个苹果脚本。这适用于带有 Sierra 的旧 Mac,也适用于带有 Catalina 的更新版本。我几乎可以肯定最新版本不会抱怨。我仍在寻找更好的解决方案。
几乎不支持从 Apple 的脚本编辑器内部运行它,只有命令行提供所有选项。
#!/usr/bin/osascript
global startAlbum, startPhoto, match, dummy, match, photoCnt, infoFd
global errorIndicator
on writePhotoAndData(thePath, mediaItem, mediaAlbum)
set ind to "X"
using terms from application "Photos"
set fName to filename of mediaItem
set fId to id of mediaItem
set photoCnt to photoCnt + 1
-- export each media to separate directory -> only chance to keep the order
if dummy then
if infoFd ≠ missing value then
set s to id of mediaAlbum & tab & id of mediaItem & tab & thePath & linefeed as text
write s to infoFd as «class utf8»
end if
else
makeEmptyPosixPath(thePath)
set exportPath to POSIX file thePath
set infoFile to POSIX file (thePath & "/" & "info.txt")
set infoText to "id" & tab & id of mediaItem & linefeed & "file" & tab & filename of mediaItem & linefeed & "album" & tab & name of mediaAlbum & linefeed
if exists name of mediaItem then set infoText to infoText & "name" & tab & name of mediaItem & linefeed
if exists description of mediaItem then set infoText to infoText & "desc" & tab & description of mediaItem & linefeed
if exists date of mediaItem then
set d to date of mediaItem
set infoText to infoText & "date" & tab & short date string of d & space & time string of d & linefeed
end if
if exists altitude of mediaItem then set infoText to infoText & "alt" & tab & altitude of mediaItem & linefeed
if exists location of mediaItem then set infoText to infoText & "location" & tab & location of mediaItem & linefeed
if exists keywords of mediaItem then
tell mediaItem to set myKeywords to keywords
repeat with keyword in myKeywords
set infoText to infoText & "keyword" & tab & keyword & linefeed
end repeat
end if
set fd to open for access infoFile with write permission
set eof fd to 0 -- of fd?
write infoText to fd starting at eof as «class utf8»
close access fd
try
tell mediaAlbum
--Not sure whether this does anything, so removed
--set settings to "JPEG - Original Size"
export {mediaItem} to (exportPath as alias)
end tell
set errorIndicator to 0
on error errStr number errNum
if errNum = -1712 then --timeout
set ind to "E"
set errorIndicator to errorIndicator + 1
if errorIndicator >= 3 then
error "3 errors in a row - exiting"
end if
else
error errStr number errNum
end if
end try
end if
log ind & tab & photoCnt & tab & id of mediaAlbum & tab & id of mediaItem & tab & name of mediaAlbum & tab & filename of mediaItem
end using terms from
end writePhotoAndData
on walkAlbum(theAlbum, thePath)
if match = 0 then
if id of theAlbum = startAlbum then
set match to 1
if startPhoto is missing value then
set match to 2
end if
else
return
end if
else if match = 1 then
if id of theAlbum is not equal to startAlbum then
set match to 3
end if
end if
set photoNum to 0
using terms from application "Photos"
set albumPath to thePath & name of theAlbum & "/"
repeat with mediaItem in media items of theAlbum
set photoNum to photoNum + 1
if match = 1 then
if id of mediaItem = startPhoto then
set match to 2
end if
else if match = 2 then
set match to 3 --photo after the photo chosen
end if
if match = 3 then
writePhotoAndData(albumPath & photoNum, mediaItem, theAlbum)
end if
end repeat
end using terms from
end walkAlbum
on walkFolder(theFolder, thePath)
using terms from application "Photos"
repeat with containedFolder in folders of theFolder
walkFolder(containedFolder, thePath & name of containedFolder & "/")
end repeat
repeat with containedAlbum in albums of theFolder
walkAlbum(containedAlbum, thePath)
end repeat
end using terms from
end walkFolder
on makePosixPath(tPath)
do shell script "mkdir -p " & quoted form of tPath
end makePosixPath
on makeEmptyPosixPath(tPath)
do shell script "rm -rf " & quoted form of tPath & " && mkdir -p " & quoted form of tPath
end makeEmptyPosixPath
on makeFolder(tPath)
do shell script "mkdir -p " & quoted form of POSIX path of tPath
end makeFolder
on walkFile(fileName, fileOffset as integer)
set thisOffset to 0
set saveDelim to text item delimiters of AppleScript
set walkFd to open for access POSIX file fileName
set rawLine to read walkFd before linefeed as «class utf8»
repeat
set thisOffset to thisOffset + 1
if fileOffset = 0 or thisOffset ≥ fileOffset then
set thisLine to rawLine as text
set text item delimiters of AppleScript to tab
set splitLine to text items of thisLine
set text item delimiters of AppleScript to saveDelim
set albumIdString to item 1 of splitLine
set photoIdString to item 2 of splitLine
set pathString to item 3 of splitLine
tell application "Photos"
set thisAlbum to album id albumIdString
set thisMedia to media item id photoIdString
end tell
writePhotoAndData(pathString, thisMedia, thisAlbum)
log "O" & tab & thisOffset
end if
try
set rawLine to read walkFd before linefeed as «class utf8»
on error errTxt number errNum
if errNum = -39 then --end of file
exit repeat
else
error "Error reading inputfile: " & errTxt
end if
end try
end repeat
end walkFile
on run (args)
set caller to class of args as string
set errorIndicator to 0
set destPath to POSIX path of (get path to home folder) & "export/photos/"
set photoCnt to 0
set startAlbum to missing value
set startPhoto to missing value
set match to 3
set dummy to false
set walkFileName to missing value
set walkFileOffset to 0
set infoFd to missing value
set infoFileName to missing value
set chooseDestinationFolder to "Select start folder (defaults to " & destPath & ")"
set chooseStart to "Give start album and photo"
set chooseDryRun to "dry-run"
if caller = "script" then
log "Running in ScriptEditor:" & name of me
set options to choose from list {chooseDestinationFolder, chooseStart, chooseDryRun} with title "Configure run" with prompt "Select options" with multiple selections allowed and empty selection allowed
if options contains chooseDryRun then set dummy to true
if options contains chooseDestinationFolder then
try
set destFolder to choose folder with prompt "Choose export directory or cancel for default location" default location (get path to home folder as alias)
set destPath to POSIX path of destFolder
end try
end if
if options contains chooseStart then
set res to display dialog "Enter Id of album to start" default answer "" buttons {"OK"} default button 1
if length of text returned of res > 0 then
set startAlbum to text returned of res
set match to 0
end if
if match = 0 then
set res to display dialog "Enter id of photo to resume after (leave empty to start with album)" default answer "" buttons {"OK"} default button 1
if length of text returned of res > 0 then
set startPhoto to text returned of res
end if
end if
end if
else if caller = "list" then
log "Running on the command line:" & name of me
set cnt to 1
repeat while cnt ≤ length of args
if item cnt of args = "-t" then
set cnt to (cnt + 1)
set destPath to item cnt of args
set cnt to (cnt + 1)
else if item cnt of args = "-a" then
set match to 0
set cnt to (cnt + 1)
set startAlbum to item cnt of args
else if item cnt of args = "-p" then
set cnt to (cnt + 1)
set startPhoto to item cnt of args
else if item cnt of args = "-h" then
return name of me & " [-t target path] [-a start album id] [-a start photo id] [-d] [-i info file path]" & linefeed ¬
& name of me & "[-t target path] -f info file [-o offset]" & linefeed ¬
& name of me & " -h .. this help"
else if item cnt of args = "-d" then
set dummy to true
else if item cnt of args = "-i" then
set cnt to (cnt + 1)
set infoFileName to item cnt of args
else if item cnt of args = "-f" then
set cnt to (cnt + 1)
set walkFileName to item cnt of args
else if item cnt of args = "-o" then
set cnt to cnt + 1
set walkFileOffset to item cnt of args
else
error "Invalid option:" & item cnt of args & " - use -h for help"
end if
set cnt to (cnt + 1)
end repeat
end if
set mySettings to "Destination directory:" & destPath
if startAlbum is not missing value then set mySettings to mySettings & linefeed & tab & "Start album id:" & tab & startAlbum
if startPhoto is not missing value then set mySettings to mySettings & linefeed & tab & "Start photo id:" & tab & startPhoto
if infoFileName ≠ missing value then
set mySettings to mySettings & linefeed & tab & "Write file '" & infoFileName & "'" & linefeed
set dummy to true
end if
if dummy then set mySettings to mySettings & linefeed & tab & "Dry run only"
if caller = "script" then
display dialog mySettings with title "Start exporting?" with icon note
else if caller = "list" then
log mySettings
else
error "Internal error - caller interface unknown"
end if
if infoFileName ≠ missing value then
set infoFd to open for access POSIX file infoFileName with write permission
set eof infoFd to 1
end if
if walkFileName ≠ missing value then
walkFile(walkFileName, walkFileOffset)
else
walkFolder(application "Photos", destPath)
end if
if infoFd ≠ missing value then close access infoFd
return "Done!"
end run
不知何故回复晚了...但这可能对其他人有帮助。
看看这个优秀的工具,它允许您从 Mac 照片中提取几乎所有内容,用于备份、导出或传输到其他工具等等:OSX Photos记录在这里其中:
OSXPhotos 提供了直接从 Python 代码与 macOS 上的 Apple Photos.app 库进行交互和查询的能力,以及用于导出照片的非常灵活的命令行界面 (CLI) 应用程序。您可以查询照片库数据库 - 例如文件名、文件路径和元数据(例如关键字/标签、人物/面孔、相册等)。您还可以轻松导出原始照片和编辑后的照片。