RhetTbull / osxphotos

Python app to work with pictures and associated metadata from Apple Photos on macOS. Also includes a package to provide programmatic access to the Photos library, pictures, and metadata.
MIT License
1.84k stars 94 forks source link

Handling for iCloud Shared Library #860

Open rizwank opened 1 year ago

rizwank commented 1 year ago

Is your feature request related to a problem? Please describe. macOS 13.0 added support for iCloud Shared Library; and there are two additional attributes that could be available from the database; whether an item is in the Personal Library or Shared Library; and who contributed the asset to the Shared Library. (The latter is not available as a Smart Album search, but is available via the inspector pane and the search bar)

Would it be possible for the inspect osxphotos function to show those details? (I imagine, once those details are available there; they might further be available to query, labels or keywords, etc.

RhetTbull commented 1 year ago

I'd definitely like to add support for this but will be some time before I have chance to look at this as I'm not yet using the shared library feature.

eecue commented 1 year ago

Glad I held off on setting this up, I'd like to use it soon. @RhetTbull you can test it easily by just making a very small shared library and adding just a few photos to it.

Also randomly, howdy @rizwank ... long time! https://eecue.com/tags/view/rizwan

rizwank commented 1 year ago

@RhetTbull anything I could provide from my system (a query against a sql db) that'd help conceptualizing?

@eecue HIIIIIIII . Almost two decades and multiple press interviews and commercials, and your pictures of me are still pretty highly rated for me on Google; so I think of you pretty often =)

RhetTbull commented 1 year ago

@rizwank yes, thanks! In the attached zip is a python file dump_photo_data.py. Copy it to your system and also install osxphotos if you've not already done so. Then in Photos, in the Library view (which shows all your photos in a grid) or in an Album view (which shows all photos inside an album), select a single photo that's in your shared iCloud library by clicking it with the mouse (but not double-clicking to open the photo in the full screen view) then from the terminal run:

osxphotos run dump_photo_data.py > computer1.txt

and send me the text file. If you have access to another user's Mac who's also using your shared library, do the same on their computer (osxphotos run dump_photo_data.py > computer2.txt ) after selecting the same photo.

Note that the dump script will dump a lot of data about the selected photo including location, filename, title, caption/description, etc. so pick a photo that doesn't contain sensitive information.

What I'm after information wise is how Photos is determining which photos are in the shared library. I believe I know enough enough now to match photos between the two libraries but I need to be able to filter for just photos in the shared library.

dump_photo_data.zip

kvisle commented 11 months ago

I took a random screenshot-file, and I ran the dump tool twice on it:

Once before I moved it to the shared library, and once after.

This is a diff:

--- shared  2023-08-01 23:07:22
+++ not_shared  2023-08-01 23:06:52
@@ -2,8 +2,8 @@
 ZASSET (2434906D-F55C-458A-A48D-399FFE9B4273):
     Z_PK: 42114
     Z_ENT: 3
-    Z_OPT: 7
-    ZACTIVELIBRARYSCOPEPARTICIPATIONSTATE: 1
+    Z_OPT: 6
+    ZACTIVELIBRARYSCOPEPARTICIPATIONSTATE: 0
     ZAVALANCHEPICKTYPE: 0
     ZBUNDLESCOPE: 0
     ZCAMERAPROCESSINGADJUSTMENTSTATE: 0
@@ -31,7 +31,7 @@
     ZISMAGICCARPET: 0
     ZKIND: 0
     ZKINDSUBTYPE: 10
-    ZLIBRARYSCOPESHARESTATE: 10485760
+    ZLIBRARYSCOPESHARESTATE: 0
     ZMONOSKITYPE: 0
     ZORIENTATION: 1
     ZPACKEDACCEPTABLECROPRECT: 0
@@ -69,7 +69,7 @@
     ZHIGHLIGHTBEINGKEYASSETSHARED: None
     ZHIGHLIGHTBEINGSUMMARYASSETS: None
     ZIMPORTSESSION: None
-    ZLIBRARYSCOPE: 1
+    ZLIBRARYSCOPE: None
     ZMASTER: 40518
     ZMEDIAANALYSISATTRIBUTES: None
     ZMOMENT: 6144
@@ -96,7 +96,7 @@
     ZLASTSHAREDDATE: 712604920
     ZLATITUDE: -180.0
     ZLONGITUDE: -180.0
-    ZMODIFICATIONDATE: 712616816.145502
+    ZMODIFICATIONDATE: 712604920.646597
     ZOVERALLAESTHETICSCORE: 0.5
     ZPROMOTIONSCORE: 0.0
     ZSORTTOKEN: 712604904.0
@@ -119,7 +119,7 @@
 ZADDITIONALASSETATTRIBUTES (2434906D-F55C-458A-A48D-399FFE9B4273):
     Z_PK: 42114
     Z_ENT: 1
-    Z_OPT: 3
+    Z_OPT: 2
     ZALLOWEDFORANALYSIS: 1
     ZCAMERACAPTUREDEVICE: 0
     ZCLOUDAVALANCHEPICKTYPE: 0
@@ -205,8 +205,8 @@
     ZSHIFTEDLOCATIONDATA: None
     Z_PK: 42114
     Z_ENT: 1
-    Z_OPT: 3
-    ZACTIVELIBRARYSCOPEPARTICIPATIONSTATE: 1
+    Z_OPT: 2
+    ZACTIVELIBRARYSCOPEPARTICIPATIONSTATE: 0
     ZAVALANCHEPICKTYPE: 0
     ZBUNDLESCOPE: 0
     ZCAMERAPROCESSINGADJUSTMENTSTATE: 0
@@ -234,7 +234,7 @@
     ZISMAGICCARPET: 0
     ZKIND: 0
     ZKINDSUBTYPE: 10
-    ZLIBRARYSCOPESHARESTATE: 10485760
+    ZLIBRARYSCOPESHARESTATE: 0
     ZMONOSKITYPE: 0
     ZORIENTATION: 1
     ZPACKEDACCEPTABLECROPRECT: 0
@@ -272,7 +272,7 @@
     ZHIGHLIGHTBEINGKEYASSETSHARED: None
     ZHIGHLIGHTBEINGSUMMARYASSETS: None
     ZIMPORTSESSION: None
-    ZLIBRARYSCOPE: 1
+    ZLIBRARYSCOPE: None
     ZMASTER: 40518
     ZMEDIAANALYSISATTRIBUTES: None
     ZMOMENT: 6144
@@ -299,7 +299,7 @@
     ZLASTSHAREDDATE: 712604920
     ZLATITUDE: -180.0
     ZLONGITUDE: -180.0
-    ZMODIFICATIONDATE: 712616816.145502
+    ZMODIFICATIONDATE: 712604920.646597
     ZOVERALLAESTHETICSCORE: 0.5
     ZPROMOTIONSCORE: 0.0
     ZSORTTOKEN: 712604904.0
RhetTbull commented 11 months ago

@kvisle Thank you! This is very helpful. Here's one more command to run from terminal.

osxphotos repl

At the >>> REPL prompt,

find('2434906D-F55C-458A-A48D-399FFE9B4273')

This will print out a list of all files associated with this UUID. Post the list here as it will help me figure out where the shared library files are being stored (my guess is photos moves them into the scopes subdirectory of the Photos library).

rizwank commented 11 months ago

Thanks! I totally forgot, and my wife’s laptop is in the shop.

On Tue, Aug 1 2023 at 3:25 PM, Rhet Turnbull @.***> wrote:

@kvisle https://github.com/kvisle Thank you! This is very helpful. Here's one more command to run from terminal.

osxphotos repl

At the >>> REPL prompt,

find('2434906D-F55C-458A-A48D-399FFE9B4273')

This will print out a list of all files associated with this UUID. Post the list here as it will help me figure out where the shared library files are being stored (my guess is photos moves them into the scopes subdirectory of the Photos library).

— Reply to this email directly, view it on GitHub https://github.com/RhetTbull/osxphotos/issues/860#issuecomment-1661180031, or unsubscribe https://github.com/notifications/unsubscribe-auth/AABWPZDDRRK7NEKZAITEBCLXTF65VANCNFSM6AAAAAAS2SWS5A . You are receiving this because you were mentioned.Message ID: @.***>

RhetTbull commented 11 months ago

Looks like the following columns will let us figure out if a photo is in a shared library:

ZACTIVELIBRARYSCOPEPARTICIPATIONSTATE ZLIBRARYSCOPESHARESTATE ZLIBRARYSCOPE

Any one of these may be sufficient for determining if photo is in a shared icloud library but there may be more to these so will require some more experimentation. This is enough though for now for osxphotos to recognize these photos. Now we just need to confirm where the photos are stored on disk. My guess is they'll have been moved from ~/Pictures/Photos Library.photoslibrary/originals to somewhere under ~/Pictures/Photos Library.photoslibrary/scopes.

RhetTbull commented 11 months ago

ZLIBRARYSCOPESHARESTATE: 10485760 may be a bit mask. 10485760 is '0b101000000000000000000000' in binary which is a 24-bit number with only 2 values set to 1.

kvisle commented 11 months ago

I did the osxphotos repl thing. The first output is in my personal library, and the second output is in the shared library.

They are identical:

['/Users/tv/Pictures/Photos Library.photoslibrary/resources/renders/2/2434906D-F55C-458A-A48D-399FFE9B4273_1_201_a.jpeg', '/Users/tv/Pictures/Photos Library.photoslibrary/resources/renders/2/2434906D-F55C-458A-A48D-399FFE9B4273.plist', '/Users/tv/Pictures/Photos Library.photoslibrary/resources/derivatives/masters/2/2434906D-F55C-458A-A48D-399FFE9B4273_4_5005_c.jpeg', '/Users/tv/Pictures/Photos Library.photoslibrary/resources/derivatives/2/2434906D-F55C-458A-A48D-399FFE9B4273_1_105_c.jpeg', '/Users/tv/Pictures/Photos Library.photoslibrary/originals/2/2434906D-F55C-458A-A48D-399FFE9B4273.png']

['/Users/tv/Pictures/Photos Library.photoslibrary/resources/renders/2/2434906D-F55C-458A-A48D-399FFE9B4273_1_201_a.jpeg', '/Users/tv/Pictures/Photos Library.photoslibrary/resources/renders/2/2434906D-F55C-458A-A48D-399FFE9B4273.plist', '/Users/tv/Pictures/Photos Library.photoslibrary/resources/derivatives/masters/2/2434906D-F55C-458A-A48D-399FFE9B4273_4_5005_c.jpeg', '/Users/tv/Pictures/Photos Library.photoslibrary/resources/derivatives/2/2434906D-F55C-458A-A48D-399FFE9B4273_1_105_c.jpeg', '/Users/tv/Pictures/Photos Library.photoslibrary/originals/2/2434906D-F55C-458A-A48D-399FFE9B4273.png']
RhetTbull commented 11 months ago

Great! The files are not moved from their default location as I thought they might be (other types of shared photos are moved). This means osxphotos should be able to export these now. All that is needed is a filter option to select or deselect photos from a shared library as desired.

RhetTbull commented 11 months ago

@kvisle I have one more request for data and I think I'll have enough to fully implement support for shared libraries. On one of the computers using the shared library do the following:

This will create a snapshot of the library then do a diff after the change is made. The diff.txt file will contain much more information than the previous dump including potentially identification info for the iCloud account so you may not want to post it here. You can post it (After sanitizing it) or email to me at rturnbull+git@gmail.com

kvisle commented 11 months ago

It didn't look too bad, but I dropped you an email.

RhetTbull commented 11 months ago

@kvisle I'm working on this now and want to confirm the location of photos which were shared by another user using the shared library. Can you select in Photos a single photo shared into the shared library by a different account then in the repl (osxphotos repl) run this command

find(selected[0].uuid)

kvisle commented 11 months ago

Here you go:

>>> find(selected[0].uuid)
['/Users/tv/Pictures/Photos Library.photoslibrary/resources/derivatives/masters/2/2D935AB6-D515-4307-9B2B-B86A957944C0_4_5005_c.jpeg', '/Users/tv/Pictures/Photos Library.photoslibrary/resources/derivatives/2/2D935AB6-D515-4307-9B2B-B86A957944C0_1_105_c.jpeg', '/Users/tv/Pictures/Photos Library.photoslibrary/originals/2/2D935AB6-D515-4307-9B2B-B86A957944C0.jpeg']
RhetTbull commented 11 months ago

@kvisle thanks. I think I've got enough data now to identify if an asset is in the shared library and get contact information for who shared it. I likely can't get a release out until this weekend but once I do, will need testing to confirm the code is working then I can add this to inspect, add query options to filter photos etc. I think I can also extract metadata about the shared library (who many assets are in it, etc.) but I've had to make some guesses so this will require more testing.

RhetTbull commented 10 months ago

@rizwank @kvisle I've added initial support for shared iCloud library to v0.62.0. I'm not 100% sure it's correct as I had to make some guesses. osxphotos inspect should now show shared iCloud library under the Flags: heading if the photo is a shared library. To add information on participants I need some more testing. If you could save the following script to shared_library.py then select a photo that is in your shared iCloud library in Photos then run the script with osxphotos run shared_library.py > shared.txt then send me the text file that would be helpful for testing. (send to rturnbull+git@gmail.com instead of posting here as it may contain names/email addresses of shared participants, etc.)

"""Dump info about shared library photos.
Select a photo that's in the shared library then run with `osxphotos run shared_library.py > shared.txt`
"""

import sys

import photoscript

import osxphotos
from osxphotos.cli import echo_error

def main():
    selected = photoscript.PhotosLibrary().selection
    if not selected:
        echo_error("No photo selected")
        sys.exit(1)

    uuid = selected[0].uuid
    library = osxphotos.PhotosDB()
    photo = library.get_photo(uuid)
    if not photo:
        echo_error(f"Could not find photo with UUID {uuid}")
        sys.exit(1)

    print(f"Photo info (uuid={uuid}):")
    print(f"{photo.path=}")
    print(f"{photo.shared_library=}")
    print(f"{photo.share_info=}")
    if participants := photo.share_participants:
        print("Shared participants:")
        for participant in participants:
            print(participant.asdict())
    print()
    print(photo.asdict())

if __name__ == "__main__":
    main()
kvisle commented 10 months ago

Ran tool and sent you output.

RhetTbull commented 10 months ago

@kvisle Got it -- thanks! I've been able to decode the name data of the person who shared the photo thanks to the data you provided. Working on an update to osxphotos to incorporate this.

RhetTbull commented 10 months ago

@all-contributors please add @kvisle for user testing

allcontributors[bot] commented 10 months ago

@RhetTbull

I've put up a pull request to add @kvisle! :tada:

RhetTbull commented 10 months ago

@kvisle I've pushed a new release at v0.62.2. If you don't mind, please update to this version then run osxphotos inspect and select a photo in your shared iCloud library. Try selecting one that you added and one added by another contributor to the library. The inspect window should show the name of the contributor.

Also, with one of these photos selected, run osxphotos repl then at the prompt, try:

get_selected()[0].share_participants

and

get_selected()[0].share_participant_info

Both of these should show additional information about the shared photo (and hopefully not throw an error). I've not been able to test this part of the code.

kvisle commented 10 months ago

This works as expected on objects I shared a while ago

When I do it on objects I shared today (although the objects themselves are years old) - both of these return a blank array.

The returned values look to me to be information about the person who shared the object.

rizwank commented 10 months ago

Noticed in the most recent under inspect that

Tried to run the script you sent to get you more info, but threw an Exception

│ /Users/rizwank/shared_library.py:33 in main │ │ │ │ 30 │ if participants := photo.share_participants: │ │ 31 │ │ print("Shared participants:") │ │ 32 │ │ for participant in participants: │ │ ❱ 33 │ │ │ print(participant.asdict()) │ │ 34 │ print() │ │ 35 │ print(photo.asdict()) │ │ 36 │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────╯ AttributeError: 'str' object has no attribute 'asdict'

RhetTbull commented 10 months ago

Does this mean you might have more access to the underlying Persons database?

Yes. But it varies by what you mean by person. For people in a shared library I can access full name, email, and phone. For persons labeled in photos osxphotos doesn't currently provide much other than name but it is possible in some cases to get the associated Contacts record. I've not yet done the engineering to implement that though.

RhetTbull commented 10 months ago

Search info lists categories 2401 (appears to be which library personal or shared) and 1900 (says Photos for me, not sure what it says on others.)

Thanks. For categories which I've not yet decoded I just print the category number and the value. Apple sadly doesn't provide a key to the category numbers as this is extracted from an undocumented database.

rizwank commented 10 months ago

2401 seems to just say Personal or Shared, for what it’s worth.

In the database, is there a persons table that shows the underlying face matching score? When I get home, I’m happy to check the database myself as well. Thanks!

On Tue, Aug 29 2023 at 1:03 AM, Rhet Turnbull @.***> wrote:

Search info lists categories 2401 (appears to be which library personal or shared) and 1900 (says Photos for me, not sure what it says on others.)

Thanks. For categories which I've not yet decoded I just print the category number and the value. Apple sadly doesn't provide a key to the category numbers as this is extracted from an undocumented database.

— Reply to this email directly, view it on GitHub https://github.com/RhetTbull/osxphotos/issues/860#issuecomment-1696541024, or unsubscribe https://github.com/notifications/unsubscribe-auth/AABWPZA5URUDLGI2D7DIS43XXUPSJANCNFSM6AAAAAAS2SWS5A . You are receiving this because you were mentioned.Message ID: @.***>

RhetTbull commented 10 months ago

The ZPERSON table has information about persons associated with faces (ZDETECTEDFACE table). The column ZPERSON.ZMERGECANDIDATECONFIDENCE might be what you're looking for. I've not explored faces/persons beyond just ensuring that what osxphotos reports matches what is shown in Photos.

RhetTbull commented 10 months ago

By the way, the full schema is in the wiki if you want to look at the tables (ZPERSON and ZDETECTEDFACE would be good places to start).