¿Hay alguna forma de obtener una lista de todas las fotos que faltan en la biblioteca de fotos?

Recibo el siguiente error en la aplicación Fotos en mi Mac.

Missing File
Photos with unavailable original files cannot be opened.
The original photo “IMG_3076.JPG” is either offline or cannot be found. Click “Find Original” to reconnect.

Quiero seguir las instrucciones de cómo evitar que se produzca un error de archivo faltante en las fotos , por lo que mi pregunta ahora es:
¿hay alguna forma de obtener todos los archivos faltantes de la biblioteca de Fotos? Será imposible hacer doble clic en cada foto para saber si falta. Solo necesito los directorios, puedo volver a colocarlos uno por uno y consolidar.

Tenía una idea, pero realmente no puedo probarla. Si copia todas las fotos potencialmente faltantes en un solo directorio, tal vez en un disco externo, luego intente consolidar... Me pregunto si buscará en ese directorio para todos, una vez que se haya descubierto uno allí manualmente. iTunes puede hacer algo similar, afaik.
Déjame probar esto, he copiado la biblioteca de fotos en la unidad de copia de seguridad que tiene la estructura de carpetas en su lugar, intentaré abrirla y ejecutar una consolidación en esa copia (la que está en el disco duro externo). ¿Eso funcionará?

Respuestas (5)

Respuesta corta: puede usar el script en este repositorio de GitHub .

Respuesta larga: tenía la misma pregunta, y resulta que la biblioteca de fotos está respaldada por una base de datos SQLite debajo de las sábanas. En su máquina, puede encontrar el archivo de la base de datos en <photo library root>/database/photos.db. Hay una tabla llamada RKMaster, con una fila para cada foto y una fileIsReferencecolumna que te dice si la foto es "externa" o no.

El script al que me vinculé simplemente vuelca la lista de todos los archivos externos y luego itera para verificar que cada uno existe en el disco.

Tenga en cuenta que la tabla también incluye una isMissingcolumna, pero esto no es suficiente por sí solo. Solo le informa sobre los archivos que Photos "sabe" que faltan, porque intentó hacer doble clic en ellos o usarlos de alguna manera. Si simplemente elimina un archivo del disco, pero no intenta acceder a él en Fotos, la isMissingcolumna será falsa.

Todavía no he podido confirmar que la lista generada sea precisa. Pero marcaré esto como respondido.
RKMaster ya no es la tabla con los datos clave [ ./find-missing-photo-references.sh | Error: no existe tal tabla: rkmaster]. Estoy tratando de rescatar fotos de un MBP que tiene tan poco espacio que Time Machine ni siquiera puede hacer una instantánea para hacer una copia de seguridad, por lo que todavía no tengo la capacidad de solucionar problemas.
Puede forzar la actualización del indicador "isMissing" mediante la operación "Reparar", que puede activar iniciando Photos.app con las teclas cmd y opción presionadas.

Si lo que desea es solo una lista de todos los archivos que faltan, puede obtenerla osxphotoscon el comando

osxphotos query --missing

Eso solo le dará el UUID de cada archivo, no la ruta. Sin embargo, una vez que RepairPhotosBookmarks está integrado OSXphotos( en breve ), no necesita la ruta del archivo porque esa poderosa aplicación podrá manejar esos archivos faltantes por usted.

El peligro de una solución que no sea de Applescript es que, si intenta actualizar la base de datos directamente, podría introducir errores si el programador no consideró todos los casos especiales o si Apple cambia el diseño de manera que el código no funcione correctamente. ya no. Es por eso que mi solución intenta acceder a la base de datos solo para encontrar los elementos que faltan, pero luego usa AppleScript para decirle a Fotos de manera segura que agregue las imágenes que faltan a un nuevo álbum. Por lo tanto, para estar seguro, le sugiero que haga una copia de seguridad completa de la biblioteca antes de probar esta solución.
Según tengo entendido, se OSXphotosbasa en [PhotoScript](github.com/RhetTbull/PhotoScript)lo que a su vez utiliza la interfaz de script de Apple Photo-Apps. Pero puedo estar equivocado. Sin embargo, me gusta su solución de script porque, si funcionara, sería mucho más fácil de implementar.

Descubrí que el indicador isMissing no significa que la imagen se haya ido, solo que no está actualmente en el disco. Usando el script de Python aquí, estaba tratando de copiar todas mis imágenes de Fotos para hacer una copia de seguridad. Me di cuenta de que varias imágenes no se estaban copiando, y resultó que era porque tenían el indicador isMissing en ellas. Pero pude tomar el nombre de la imagen (por ejemplo, IMG_1234.JPG), buscarlo en Fotos y encontró la imagen. Y cuando abrí la imagen en Fotos para verla, se mostraba un círculo de progreso en la esquina inferior derecha (como si estuviera cargando el archivo desde algún lugar), y cuando revisé la carpeta dentro de la biblioteca de Fotos en el disco, efectivamente, el archivo que faltaba ahora estaba allí. Así que ahora el misterio es, ¿dónde están almacenados estos archivos "faltantes" y cómo accedo a ellos (sin tener que visitar todos y cada uno dentro de Fotos)? ¿Alguien ha realizado ingeniería inversa y ha documentado el esquema de Photos SQLLite DB, incluido el significado de los distintos campos? como "falta"? No he sido capaz de encontrarlo yo mismo.

(Nota: la solución parece funcionar solo si la biblioteca de Fotos se ha convertido de una biblioteca de iPhoto más antigua, y las imágenes ya faltaban en ese momento. Lo dejo aquí con fines educativos, pero he agregado otra respuesta con una detección más completa .)

Aquí hay un AppleScript que puede agregar todas las imágenes a Photos.appun nuevo álbum, desde donde puede seleccionarlas y eliminarlas (por ejemplo, con cmd-delete).

Solo funciona si Fotos ya ha detectado que falta el archivo. No sé qué causa esta detección, es solo que encontré una biblioteca de Fotos donde este era el caso, y luego funcionó este script. Pero cuando traté de reproducir esto con otra biblioteca, donde eliminé los archivos originales (y también me aseguré de que no se recrearan, lo que sucede cuando venían de iCloud), incluso reiniciar Fotos forzando una reparación de la biblioteca no actualizaría las propiedades de la imagen. a un estado en el que mi script los detectaría como perdidos. Tal vez esto solo funcione con bibliotecas que se convirtieron de antiguas bibliotecas de iPhoto (que sé que fue la primera).

Para usarlo, inicie Fotos, cambie para ver todas las fotos y seleccione todas las fotos que desea verificar, por ejemplo, con cmd-A. A continuación, ejecute el script y agregará todas las fotos para las que no haya un archivo de imagen conocido o accesible al álbum de "imágenes faltantes" creado automáticamente.

tell application "Photos"
    set media_items to selection
    set missing_items to {}
    repeat with media_item in media_items
        if width of media_item is 0 then
            set end of missing_items to media_item
        end if
    end repeat
    if missing_items is {} then
        display dialog "Found no missing files" buttons ¬
            "OK" default button "OK"
    else
        if not (exists album "missing images") then
            make new album named "missing images"
        end if
        set dest to album "missing images"
        add missing_items to dest
        display dialog "Found " & (count of missing_items) & ¬
            " missing files" buttons "OK" default button "OK"
    end if
end tell
Cuando ejecuto ese script en un par de fotos, obtengo: error "Photos got an error: Can't add the provided media items to the album." number 6Esto sucede independientemente de si a esas fotos les faltan archivos o no.
Actualización: el error parece deberse a que no se seleccionaron elementos (el error desaparece con if missing_items is not {} then add missing_items to dest end if). Por lo tanto, el problema parece estar relacionado con la condición de selección si el ancho de media_item es 0. Aparentemente, la consulta no devuelve 0 cuando el artículo no existe...
Si tiene sugerencias para mejorar la secuencia de comandos para que esto funcione de manera más confiable, no dude en editar mi respuesta si puede. ¿Funcionó para usted una vez que realmente le faltaron archivos, o no funciona en absoluto para usted?
Me senté durante bastante tiempo tratando de hacer que funcionara, pero no tuve éxito. No funciona con archivos faltantes. Incluso cuando el archivo se pierde, Fotos aún conoce el ancho (y otra información sobre la imagen. No tengo idea de cómo comprobar si falta la imagen.
Para que esto funcione, sería necesario determinar la ubicación del archivo de imagen maestra y luego verificar si ese archivo realmente existe. Lamentablemente, la API de AppleScript no proporciona una forma de determinar la ubicación real del archivo: uno podría obtener su ubicación si está almacenado dentro de la carpeta Masters, pero eso no funcionará para los archivos con referencia externa (y no hay manera a través de AppleScript para determinar si son internos o externos). Apple proporcionó una interfaz AppleScript mal diseñada para Fotos, y no están haciendo nada al respecto.

Nota: La siguiente solución, si bien funciona bien en mi propio caso de prueba, probablemente no sea adecuada para imágenes grandes (100 000) en la biblioteca, ni con fotos descargadas en iCloud. Tome esto como una respuesta educativa, pero no espere que funcione en su caso. Doy la bienvenida a otros a mejorar este script y publicarlo en sus propias respuestas.

El siguiente AppleScript analiza la sqlitebase de datos para identificar las rutas a los archivos y luego verifica si esos archivos están presentes. Si encuentra archivos faltantes, inicia Photos.app e intenta identificar las imágenes (o películas) relacionadas y las agrega a un álbum llamado "imágenes faltantes".

Funciona con las versiones 2 y 3 de la biblioteca de Fotos, probada con Photos.app v3.0 (en macOS 10.13 "High Sierra") y v7.0 (en macOS 12.6 "Montery").

Para usar este script, copie el código a continuación y péguelo en un nuevo documento "Script Editor.app". Si solo desea verificar imágenes específicas en busca de archivos faltantes, abra Fotos y luego seleccione los elementos que desea verificar. De lo contrario, para verificar todos los elementos (fotos, películas), salga de Fotos. Luego ejecute el script. Una vez que el script haya verificado todos los archivos, iniciará Fotos y agregará los elementos faltantes al álbum "imágenes faltantes". Cuando termine, mostrará un mensaje al respecto. Luego puede ver el álbum en Fotos, seleccionar todos los elementos y eliminarlos con cmd-delete si desea deshacerse de ellos.

Sin embargo, tenga en cuenta que si tiene algunas imágenes en medios externos y esos discos no están montados, este script también considerará que faltan; sin embargo, ¡entonces probablemente no desee eliminar esos elementos!

use scripting additions

set path_to_photos_library to POSIX path of (choose file of type ¬
    "com.apple.photos.library" with prompt ¬
    "Choose the photos library that Photos.app currently uses" default location path to pictures folder)

--
-- Get the current selection from Photos
--
set selectedIDs to {}
if application "Photos" is running then
    tell application "Photos"
        local media_items
        set media_items to selection
        repeat with media_item in media_items
            set end of selectedIDs to id of media_item
        end repeat
        quit -- need to quit Photos so that we can access its database
        delay 0.5
    end tell
end if

--
-- Make sure the database is accessible and determine which DB version to use
--
repeat
    try
        local files_dir
        do shell script "sqlite3 " & quoted form of path_to_photos_library ¬
            & "database/photos.db 'SELECT value FROM LiGlobals WHERE keyPath=\"metaSchemaVersion\"'"
        ignoring white space
            if result = "2" then
                set db_version to 2
                set files_dir to "Masters"
                set db_name to "photos.db"
            else if result = "3" then
                set db_version to 3
                set files_dir to "originals"
                set db_name to "Photos.sqlite"
            else
                my showMessage("Sorry, the database appears to be in an unsupported format.")
                quit
            end if
        end ignoring
        set db_path to quoted form of path_to_photos_library & "database/" & db_name
        set files_path to path_to_photos_library & files_dir & "/"
        delay 0.1
        exit repeat
    on error
        with timeout of 86400 seconds
            display dialog "Can't access database - make sure Photos.app is quit, then click OK"
        end timeout
    end try
end repeat

--
-- Determine the file paths by querying the photos database
--
if selectedIDs is {} then
    set where_clause to ""
else
    if db_version = 2 then
        set where_clause to ¬
            " JOIN RKVersion v ON (m.uuid=v.masterUuid)" & ¬
            " WHERE v.uuid IN (\"" & joinText(selectedIDs, "\",\"") & "\")"
    else
        -- need to remove the "/L0/001" suffix from the IDs first
        set uuids to {}
        repeat with anID in selectedIDs
            set end of uuids to first item of splitText(anID, "/")
        end repeat
        set where_clause to " WHERE ZUUID IN (\"" & joinText(uuids, "\",\"") & "\")"
    end if
end if
if db_version = 2 then
    set sql to " 'SELECT m.imagePath FROM RKMaster m" & where_clause & "'"
else
    set sql to " 'SELECT printf(\"%s/%s\",ZDIRECTORY,ZFILENAME) FROM ZASSET" & where_clause & "'"
end if
do shell script "sqlite3 " & db_path & sql
set check_paths to my splitText(result, return)
delay 0.1

--
-- Check the availability of every file
--
set missing_paths to {}
repeat with relPath in check_paths
    set fullPath to (files_path & relPath)
    set theFile to POSIX file fullPath
    try
        (theFile as alias)
    on error
        set end of missing_paths to relPath as string
    end try
end repeat

if missing_paths is {} then
    my showMessage("Found no missing files")
    quit
end if

--
-- Query the database again to get the ids of the images that reference the missing files
--
with timeout of 86400 seconds
    if db_version = 2 then
        do shell script "sqlite3 " & db_path & ¬
            " 'SELECT v.uuid FROM RKMaster m JOIN RKVersion v ON (m.uuid=v.masterUuid)" & ¬
            " WHERE m.imagePath IN (\"" & joinText(missing_paths, "\",\"") & "\")'"
        set missing_ids to my splitText(result, return)
    else
        do shell script "sqlite3 " & db_path & ¬
            " 'SELECT ZUUID FROM ZASSET" & ¬
            " WHERE printf(\"%s/%s\",ZDIRECTORY,ZFILENAME) IN (\"" & joinText(missing_paths, "\",\"") & "\")'"
        set missing_ids to my splitText(result, return)
    end if
end timeout
delay 0.1

--
-- Launch Photos, locate the images by their ids and add them to the "missing images" album
--
tell application "Photos"
    set unlocated to {}
    set missing_items to {}
    set all_items to media items
    repeat with anID in missing_ids
        try
            if db_version = 2 then
                set anItem to media item id anID
            else
                set anItem to media item id (anID & "L0/001")
            end if
            set end of missing_items to anItem
        on error
            set end of unlocated to anID
        end try
    end repeat
    if missing_items is {} then
        my showMessage("Can't locate the images for the missing files." & return & return & ¬
            "Make sure you choose the same library that Photos.app currently uses!")
    else
        if unlocated is not {} then
            with timeout of 86400 seconds
                display dialog "" & (count of unlocated) & " missing items could not be found in Photos.app" & ¬
                    return & return & "This means that the script needs to be updated to handle this."
            end timeout
        end if
        if not (exists album "missing images") then
            make new album named "missing images"
        end if
        set dest to album "missing images"
        add missing_items to dest
        my showMessage("Found " & (count of missing_items) & " missing files")
    end if
end tell

--
-- Finished
--

on showMessage(theText)
    with timeout of 86400 seconds
        display dialog theText buttons "OK" default button "OK"
    end timeout
end showMessage

on splitText(theText, theDelimiter)
    set old_delimts to AppleScript's text item delimiters
    set AppleScript's text item delimiters to theDelimiter
    set theTextItems to every text item of theText
    set AppleScript's text item delimiters to old_delimts
    return theTextItems
end splitText

on joinText(theList, theDelimiter)
    set old_delimts to AppleScript's text item delimiters
    set AppleScript's text item delimiters to theDelimiter
    set theText to theList as string
    set AppleScript's text item delimiters to old_delimts
    return theText
end joinText
Parece prometedor. Pero me da un "error de tipo 100002" (después de correr por un tiempo). Siguiendo lo que resalta el editor de secuencias de comandos cuando falla, el error ocurre en la parte "Consultar la base de datos nuevamente". Más específicamente, es el elsescript de shell el que está resaltado.
Interactuar con la aplicación Fotos a través de scripts parece ser un proceso bastante complejo y propenso a errores. Los intentos más avanzados de hacerlo de todos modos parecen ser los de RhetTbull con la osxphotosaplicación y la interfaz de Python PhotoScript (consulte github.com/RhetTbull/osxphotos y github.com/RhetTbull/PhotoScript , así como mi respuesta a continuación).
@Christoph ¿Tiene fotos en el modo en que mantiene todos los originales en la Mac o almacena solo versiones comprimidas en la Mac? –– Sin embargo, no tengo idea de por qué obtendrías el error 100002. Esa parte del script es solo una llamada al comando sqlite3, que no debería fallar. A menos que sea simplemente un tiempo de espera del script. ¿Puedes envolver eso en "con tiempo de espera de 86400 segundos... fin" e intentarlo de nuevo, por favor?
No estoy usando iCloud para fotos en absoluto, si eso responde a tu pregunta. Probé su envoltorio en la parte "hacer script de shell ...", así como en eso más "establecer ids faltantes ..." pero no tuve suerte. Falla con el mismo error 100002. En lugar de tiempo de espera, ¿podría ser algún tipo de desbordamiento? La cantidad de archivos que faltan en mi biblioteca es enorme (varios miles)...
@Christoph Otro probador se encontró con otro problema (no se encontraron ID en las fotos), y hay poco que pueda depurar sin poder reproducirlos yo mismo. Entonces, abandonemos esto. Agregaré una nota en la parte superior de que este es un ejemplo educativo que probablemente fallará. Demasiado. Todo es culpa de Apple por no proporcionar la ruta completa y alguna otra metainformación a través de AppleScript.
Sí, eso es lo que quise decir con mi comentario acerca de que este es un proceso propenso a errores: hay una razón por la cual esto aún no se ha resuelto de manera concluyente, por lo que invertir tiempo en tratar de arreglar este script es una inversión arriesgada. Por mucho que me gustaría ver que el guión funcione, entiendo perfectamente por qué no quieres seguir adelante.