AppleScript用于将照片成功导入Aperture

时间:2013-07-19 13:26:00

标签: macos command-line applescript photos

我正在尝试制作一个苹果脚本,用于将大量照片导入Aperture,因为Aperture经常在这种情况下崩溃。出于这个原因,我想将每个文件单独导入到Library.My初始尝试在一张图片上工作:

on run argv
set file_name to item 1 of argv


tell application "Aperture"
activate
    tell library 1
      if not (exists project "OldPictures") then
          set theProject to make new project with properties {name:"OldPictures"}
      else
          set theProject to project "OldPictures"
      end if
end tell
with timeout of 600 seconds
      import file_name by moving into theProject
end timeout
end tell

end run

但是如果我按照以下方式运行它会崩溃

find /Volumes/Pictures/ -iname "*.jpg" -exec  osascript /Users/mac/apperture.scpt  {} \;

1 个答案:

答案 0 :(得分:0)

蛮力肌肉进口

您可能想尝试这个硬核脚本。这将需要AGES完成,但它应该工作,因为它做你所要求的...它将每个文件ONE BY ONE添加到指定的项目并检查以确保没有任何重复名称。我即将在13262张图片上测试这个脚本。它可能会整夜运行,但它有望击败一直失败的内置导入器。

我建议您在第一次运行时创建一个测试项目,以确保您不会导入重复项。或者,您可以将图像移动到Aperture中的相应项目中。我已经设置了这个。如果要忽略它并将它们直接导入原始项目,可以通过更改以下行来完成此操作:

  • my importToApertureAsReference(itemAlias, projectDst)

  • my importToApertureAsReference(itemAlias, projectName)

OS X 10.9.4

Aperture 3.5.1

免责声明:我把它扔到了一起。还有改进的余地,比如检查以确保列表中的文件都是图片。我没有做那样的检查。这可以在shell命令中完成,或者使用System Events来获取每个文件通过时的类型。此外,运行此计算机时,计算机将会翻转。我建议你不要在你的电脑上做任何其他事情。

AppleScript - 将丢失的文件逐个导入项目“

通过将图片名称与文件名称进行比较

2014年8月1日更新

我通过make bourne脚本完成大部分工作,大大提高了脚本的速度。 AppleScript在与程序交谈时陷入困境,但在迭代列表时速度相对较快。我刚刚使用了bourne脚本的find命令与basename结合使用来创建没有路径的所有文件的新列表。 AppleScript会迭代此列表并将其与指定项目中的名称列表进行比较。如果找到项目中不存在的项目projectName,则然后它会加入文件名的路径并将其作为参考添加到项目目标projectDst。如果要将文件复制到库中而不仅仅是作为参考,则需要调整处理程序importToApertureAsReference或创建一个名为importToApertureAsCopyingimportToApertureAsMoving的新处理程序。

set inputPath to "Volumes:Kielbasa:Camera:1970 - Fotos" as string
set inputPathHFS to inputPath as alias
log "inputPathHFS: " & inputPathHFS
set projectName to "1970 - Fotos" -- Check this project for duplicates
set projectDst to "AppleScript Import" -- This is where any missing files will be added
set importedList to {}

set inputPathPX to text 1 through -2 of POSIX path of inputPathHFS
log "inputPathPX: " & inputPathPX
set countItemsCommand to "find " & quoted form of inputPathPX & " -type f -maxdepth 1 \\! -name '.*' | wc -l"
set getItemsCommand to "find " & quoted form of inputPathPX & " -type f -maxdepth 1 ! -name '.*' -exec sh -c 'basename \"{}\"' \\;"

set itemCount to (do shell script countItemsCommand) as integer
set itemList to paragraphs of (do shell script getItemsCommand) as list
set missingItemsList to {}

set namesInProjectList to my getAllNamesInProject(projectName) as list

-- Check whether your project contains an object/item (image/video) with the same name
repeat with itemStep from 1 to count of itemList
    set thisItem to item itemStep of itemList
    log "This Item: " & thisItem
    set itemSplit to my splitExtension(thisItem)
    set itemName to item 1 of my splitExtension(thisItem)
    set itemExt to item 2 of my splitExtension(thisItem)
    log "Item Name: " & itemName & ", Item Ext: " & itemExt
    log "Checking if project " & projectName & " contains " & itemName
    set foundImages to my findAll(namesInProjectList, itemName)
    if foundImages is {} then -- if empty, then there is no match so image should be added to Aperture
        set end of missingItemsList to contents of thisItem -- this makes a new list of all missing images with extensions (no path), to import into Aperture you need to join this item with its full path

        set picAlias to (inputPathHFS as string) & thisItem as alias
        log "Importing: " & picAlias
        my importToApertureAsReference(picAlias, projectDst)
    else
        repeat with foundIndex in foundImages
            my deleteItem(namesInProjectList, foundIndex)
            log "Found Index: " & foundIndex
            log "Removed from namesInProjectList: " & thisItem
        end repeat
    end if
end repeat


return missingItemsList

(*
tell application "System Events"
    repeat with itemStep from 1 to count of itemList
        set thisItem to item itemStep of itemList
        log "This Item: " & thisItem
        set itemSplit to my splitExtension(thisItem)
        set {itemName, itemExt} to {item 1 of itemSplit, item 2 of itemSplit}
        log "Item Name: " & itemName & ", Item Ext: " & itemExt
        log "Checking if project " & projectName & " contains " & itemName
        -- Compare Lists
        if namesInProjectList does not contain itemName then
            if otherList does not contain itemName then
                -- Generate Alias from filename by joining inputpath and filename
                set thisFileAlias to inputPath & ":" & thisItem as alias -- eg "Volumes:Kielbasa:Camera:1970 - Fotos000_0014.jpg"
                my importToApertureAsReference(thisFileAlias, projectDst)
                log "Imported: " & thisFileAlias
                set end of importedList to thisFileAlias
            end if
        end if

    end repeat
end tell
*)
return importedList

on importToApertureAsReference(picAlias, projectName)
    log "Importing: " & picAlias
    tell application "Aperture"
        tell library 1
            if not (exists project projectName) then
                set projectDst to make new project with properties {name:projectName}
            else
                set projectDst to project projectName
            end if
            import picAlias by referencing into projectDst
        end tell
    end tell
end importToApertureAsReference


on getAllNamesInProject(projectName)
    tell application "Aperture"
        tell library 1
            tell project projectName
                set nameList to name of image versions
            end tell
        end tell
    end tell
    return nameList
end getAllNamesInProject


on splitExtension(file_name)
    set dot to "."
    tell AppleScript
        set oT to text item delimiters
        set text item delimiters to dot
        if (count text items of file_name) > 1 then
            set out_name to (text items 1 through -2 of file_name) as string
            set ext to last text item of file_name
        else
            set out_name to file_name
            set ext to ""
        end if
        set text item delimiters to oT
        if ext is not "" then set ext to dot & ext
        return {out_name, ext}
    end tell
end splitExtension

on deleteItem(lst, idx)
    local lst, idx, len, ndx, l
    try
        if lst's class is not list then error "not a list." number -1704
        script k
            property l : lst
        end script
        set len to count of k's l
        set ndx to idx as integer
        if ndx is 0 then
            error "index 0 is out of range." number -1728
        else if ndx < 0 then
            set ndx to len + 1 + ndx
            if ndx < 1 then error "index " & idx & ¬
                " is out of range." number -1728
        else if ndx > len then
            error "index " & idx & " is out of range." number -1728
        end if
        if ndx is 1 then
            return rest of k's l
        else if ndx is len then
            return k's l's items 1 thru -2
        else
            return (k's l's items 1 thru (ndx - 1)) & ¬
                (k's l's items (ndx + 1) thru -1)
        end if
    on error eMsg number eNum
        error "Can't deleteItem: " & eMsg number eNum
    end try
end deleteItem

on findAll(lst, val)
    local lst, val, res
    try
        if lst's class is not list then error "not a list." number -1704
        if {val} is not in lst then return {}
        set res to {}
        script k
            property l : lst
        end script
        repeat with i from 1 to count of k's l
            if k's l's item i is val then set res's end to i
        end repeat
        return res
    on error eMsg number eNum
        error "Can't findAll: " & eMsg number eNum
    end try
end findAll

Python - 将丢失的文件逐个导入项目(使用AppleScript)

AppleScript对13262张图片的负载感到窒息。当AppleScript变大时,这些列表太多了,所以我决定编写一个Python脚本。使用Python,我可以相互减去两个集合(列表为集合),创建一个仅包含缺失项目的新列表。这样就无需再次检查列表中的每个项目。它显着加快了这个过程。

#!/usr/bin/env python
# -*- coding: utf-8 -*- 
# Imports
import subprocess
from subprocess import Popen, PIPE
import unicodedata
import codecs
import os


inputPath = "/Volumes/Kielbasa/Camera/1970 - Fotos" ## This is the source folder containing all images and videos you want to ensure are in your project (projectOriginal)
projectOriginal = "1970 - Fotos" ## This is where photos from original input are (if you just want to import everything from harddrive one by one, then create an empty project and use it here)
projectDst = "Python Import" ## This is where you will import all of the images and videos that are missing from you project. It is a debugging project (so that you don't screw anything up). You can then drag the images over to the projectOriginal project after ensuring that everything worked correctly.

importedList = []

getItemsCommand = """find '%s' -type f -maxdepth 1 ! -name '.*' -exec sh -c 'basename "{}"' \;""" % inputPath

#subprocess.check_output(*popenargs, **kwargs)
## itemsListEXT is a list of all files in your HD folder with extensions (Aperture projects import filenames without extensions, which I henceforth refer to as names). This list will be used to reconstruct the file paths later. It is important to have this if you have files with different extensions (e.g. images and movies, jpg, jpeg, png, raw)
itemsListEXT = subprocess.check_output(getItemsCommand, shell=True, executable="/bin/bash").splitlines()
itemCount = len(itemsListEXT)

def getItemsInProject(projectOriginal):
    cmd = """osascript<<END
    tell application "Aperture"
            tell library 1
                tell project "%s"
                    return name of image versions
                end tell
            end tell
        end tell
    END""" % projectOriginal
    itemsListEXT = subprocess.check_output(cmd,shell=True,executable="/bin/bash").split(', ')
    return itemsListEXT

## namesInProjectList is a list containing all names of images inside your projectOriginal project.
namesInProjectList = getItemsInProject(projectOriginal)

## namesOnHDList is a list that will be populated with all of the items in itemsListEXT, but without the extensions. The indexes must be the same between these two lists for reconstructing the file paths later.
namesOnHDList = []

for itemStep,thisItem in enumerate(itemsListEXT):
    #print itemStep, thisItem.decode('UTF-8')
    name,ext = os.path.splitext(thisItem)
    namesOnHDList.append(name)

missingItemsList = []
for itemStep,thisItem in enumerate(namesOnHDList):
    if thisItem in namesInProjectList:
        ## Just a place holder
        continue
    else:
        ## This reconstructs full paths out of all the missing item names by getting name + extension from itemsListEXT (the indexes in these two lists MUST be the same)
        missingItemsList.append(os.path.join(inputPath,itemsListEXT[itemStep]))

## This is for debugging only. You can compare the total number of missing items to the difference between your project and HD items. If that number is the same as the sum of items in missingItemsList, then it is likely working.
print len(missingItemsList)
print missingItemsList


def importToApertureAsReference(objectPath,projectDestination):
    scpt = '''
    on run {objectPath,projectDestination}
        set objectAlias to POSIX file objectPath as alias
        set projectName to projectDestination
        tell application "Aperture"
            tell library 1
                if not (exists project projectName) then
                    set projectDst to make new project with properties {name:projectName}
                else
                    set projectDst to project projectName
                end if
                import objectAlias by referencing into projectDst
            end tell
        end tell
    end run
    '''
    args = [objectPath, projectDestination]
    p = Popen(['osascript', '-'] + args, stdin=PIPE, stdout=PIPE, stderr=PIPE)
    stdout, stderr = p.communicate(scpt)
    print (p.returncode, stdout, stderr)
    print "--> Imported: " + objectPath +  " to Project: " +  projectDestination

## Add all items from the missingItemsList to your Aperture project destination (projectDst)
countItems = len(missingItemsList)
for itemStep,thisItem in enumerate(missingItemsList):
    importToApertureAsReference(thisItem,projectDst)
    print "Item: " + str(itemStep) + " of " + str(countItems)

最初发布的AppleScript

set inputPath to "Volumes:Kielbasa:Camera:1970 - Fotos" as alias
log "inputPath: " & inputPath
set projectName to "1970 - Fotos" -- Check this project for duplicates
set projectDst to "AppleScript Import" -- This is where any missing files will be added
set importedList to {}

set inputPathPX to text 1 through -2 of POSIX path of inputPath
log "inputPathPX: " & inputPathPX
set countItemsCommand to "find " & quoted form of inputPathPX & " -type f \\! -name '.*' | wc -l"
set getItemsCommand to "find " & quoted form of inputPathPX & " -type f ! -name '.*'"

set itemCount to (do shell script countItemsCommand) as integer
set itemList to paragraphs of (do shell script getItemsCommand) as list


set namesList to my getAllNamesInProject(projectName) as list
set otherList to my getAllNamesInProject("Test Project") as list


tell application "System Events"
    repeat with itemStep from 1 to count of itemList
        tell me to set itemAlias to POSIX file (item itemStep of itemList) as alias
        log itemAlias
        set itemName to name of itemAlias
        set fileNameNOEXT to item 1 of my splitExtension(itemName)
        log "Checking if project " & projectName & " contains " & fileNameNOEXT
        if namesList does not contain fileNameNOEXT then
            if otherList does not contain fileNameNOEXT then
                my importToApertureAsReference(itemAlias, projectDst)
                set end of importedList to itemAlias
            end if
        end if
    end repeat
end tell

return importedList

on importToApertureAsReference(picAlias, projectName)
    log "Importing: " & picAlias
    tell application "Aperture"
        tell library 1
            if not (exists project projectName) then
                set projectDst to make new project with properties {name:projectName}
            else
                set projectDst to project projectName
            end if
            import picAlias by referencing into projectDst
        end tell
    end tell
end importToApertureAsReference


on getAllNamesInProject(projectName)
    tell application "Aperture"
        tell library 1
            tell project projectName
                set nameList to name of image versions
            end tell
        end tell
    end tell
    return nameList
end getAllNamesInProject


on splitExtension(file_name)
    set dot to "."
    tell AppleScript
        set oT to text item delimiters
        set text item delimiters to dot
        if (count text items of file_name) > 1 then
            set out_name to (text items 1 through -2 of file_name) as string
            set ext to last text item of file_name
        else
            set out_name to file_name
            set ext to ""
        end if
        set text item delimiters to oT
        if ext is not "" then set ext to dot & ext
        return {out_name, ext}
    end tell
end splitExtension

提示:如果单击AppleScript编辑器底部的事件或响应选项,您可以观察正在发生的事情(最好在运行脚本之前执行此操作)