MacOS: невозможно получить все фотографии в альбоме Apple Photos с помощью MLMediaLibrary - PullRequest
0 голосов
/ 11 октября 2018

Кажется, я не могу получить все фотографии в определенном пользователем альбоме "Фотографии" на Mac.Иногда я получаю большинство из них, но у меня также есть альбом в фотографиях, из которого я не получаю ни одного.Я считаю, что это вызвано iCloud;Я включил «Библиотеку фотографий iCloud» в настройках «Фотографии».

Я использую интерфейс MLMediaLibrary ( Media Library Framework ) в macOS 10.13, но я счастлив использовать любую другуюAPI, если он работает лучше.Обратите внимание, что я не спрашиваю о том, как использовать фреймворки на iOS.Я работаю на Mac.

Я уже искал в Интернете, я также посмотрел на отличный ответ на аналогичный вопрос здесь, на SO.Кроме того, я посмотрел на этот пример от Apple .

На самом деле, даже пример кода не показывает мне все фотографии.Я считаю, что это потому, что я включил «Библиотека фотографий iCloud» в настройках фотографий.Когда я щелкаю правой кнопкой мыши на альбоме и «Скачиваю оригиналы на этот Mac», через некоторое время я получаю все фотографии из этого альбома с моим кодом.

Итак, вопрос в том, как я могуубедитесь, что все оригиналы в определенном альбоме были загружены на Mac, или как я могу это сделать из своего кода?

Ниже вы можете найти код, который я придумал до сих пор.Это довольно полный отрывок из полного исходного кода (скринсейвер, который я пишу), поэтому он должен дать вам четкое представление о том, как он работает.Во время инициализации я получаю список пользовательских альбомов верхнего уровня.Затем, когда пользователь выбирает один из них, я нахожу соответствующий объект мультимедийной группы (альбом), а затем извлекаю из него все изображения.

Буду очень признателен за любую помощь, предложения или указатели.

С наилучшими пожеланиями, Габриэль

static char * MediaLibraryLoaded = "MediaLibraryLoaded";         // just IDs for the KVO
static char * RootMediaGroupLoaded = "RootMediaGroupLoaded";
static char * MediaObjects = "MediaObjects";

- (id) initWithFrame: (NSRect) frameRect isPreview: (BOOL) preview
{
[...]
    // start loading all Photos albums (has to be done asynchronously because MLMediaLibrary wants it that way)
    albums_ = [[NSMutableArray alloc] init];
    NSDictionary *options = @{
                              MLMediaLoadSourceTypesKey: @(MLMediaSourceTypeImage),
                              MLMediaLoadIncludeSourcesKey: @[MLMediaSourcePhotosIdentifier]
                              };
    mediaLibrary_ = [[MLMediaLibrary alloc] initWithOptions: options];
    [mediaLibrary_ addObserver: self
                        forKeyPath: @"mediaSources"
                           options: 0
                           context: (__bridge void *) &MediaLibraryLoaded];     // take the address, which will be always unique, even in case of string coalescing
    [mediaLibrary_.mediaSources objectForKey: MLMediaSourcePhotosIdentifier ];  // starts asynchronous loading
[...]
}


- (void) observeValueForKeyPath: (NSString *) keyPath   ofObject: (id) object
                         change: (NSDictionary *) change context: (void *) context
{
    MLMediaSource * mediaSource = [mediaLibrary_.mediaSources objectForKey: MLMediaSourcePhotosIdentifier];

    // this stuff was initiated from initWithFrame:
    if ( context == &MediaLibraryLoaded )
    {
        [mediaSource addObserver: self
                      forKeyPath: @"rootMediaGroup"
                         options: 0
                         context: (__bridge void *) &RootMediaGroupLoaded];
        [mediaSource rootMediaGroup];                                           // start next phase: load groups
    }
    else if ( context == &RootMediaGroupLoaded )
    {
        MLMediaGroup *albums = [mediaSource mediaGroupForIdentifier: @"TopLevelAlbums"];

        for ( MLMediaGroup * album in albums.childGroups )
        {
            NSString * type = [album.attributes objectForKey: @"typeIdentifier"];                   // only include user-defined albums
            if ( type && [type isEqualToString: @"com.apple.Photos.Album"] )                        // magic constant found by printf, couldn't find the proper pre-defined variable
            {
                NSString * albumName = [album.attributes objectForKey: @"name"];
                [albums_ addObject: album ];
            }
        }

        [mediaSource removeObserver: self forKeyPath: @"rootMediaGroup"];
        [mediaLibrary_ removeObserver: self forKeyPath: @"mediaSources"];
    }
    else if ( context == &MediaObjects )                // initiated by scanIPhotoPaths
    {
        NSArray * mediaObjects = album_.mediaObjects;                                             // album_ has been set by scanIPhotoPaths:
        for ( MLMediaObject * mediaObject in mediaObjects )
        {
            if ( mediaObject.mediaType != MLMediaTypeImage )                    // even if I remove this, I don't get all
                continue;                                   // media objects in the album (usually)
            NSURL * url  = mediaObject.URL;
            [photoPaths_ addObject: url.path];
        }

        [self scanIPhotoPathsFinish];
    }
}


- (void) scanIPhotoPaths: (NSString *) album_name
{
[...]
    // find album by name
    album_ = nil;
    for ( MLMediaGroup * album in albums_ )
    {
        if ( [album_name isEqualToString: [album.attributes objectForKey: @"name"] ] )
        {
            album_ = album;
            break;
        }
    }

    // if not found, return to default (can't happen)
    if ( ! album_ )
    {
        return;
    }

    photoPaths_ = [[NSMutableArray alloc] init];

    // we have to use the KVO, because right now, [album_.mediaObjects count] == 0
    [album_ addObserver: self
             forKeyPath: @"mediaObjects"
                options: 0
                context: (void *) &MediaObjects];

    [album_ mediaObjects];
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...