plugin.py 8.07 KiB
from time import sleep
from google_photos.google_api.google_api import GoogleApi
from google_photos.data.schema import Edge, Person, Account, Service, Photo, Video, Document, OauthFlow, Camera
from pymemri.plugin.pluginbase import PluginBase
from .constants import SERVICE_NAME, CLIENT_ID, CLIENT_SECRET, PROJECT_ID
class GooglePhotos(PluginBase):
    user_account = None
    service = None
    existing_item_ids = {'Account': set(), 'Video': set(), 'Document': set(), 'Photo': set()}
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
    def auth(self):
        search_filter = {"type":"OauthFlow", 'service': SERVICE_NAME}
        oauth_items = self.client.search(search_filter)
        if len(oauth_items) == 0:
            self.google_api = GoogleApi()
            config = {"installed":{
                "client_id": CLIENT_ID,
                "client_secret": CLIENT_SECRET,
                "project_id": PROJECT_ID,
                "auth_uri":"https://accounts.google.com/o/oauth2/auth",
                "token_uri":"https://oauth2.googleapis.com/token",
                "auth_provider_x509_cert_url":"https://www.googleapis.com/oauth2/v1/certs",
                "redirect_uris":["http://localhost"]}}
            self.google_api.start_oauth(config)
            creds = self.google_api.get_credentials()
            auth_item = OauthFlow(accessToken=creds.token, refreshToken=creds.refresh_token, service=SERVICE_NAME, expiry=creds.expiry.strftime('%Y-%m-%dT%H:%M:%S'))
            self.client.create(auth_item)
        else:
            self.google_api = GoogleApi()
            self.google_api.use_oauth({
                "token": oauth_items[0].accessToken,
                "refresh_token": oauth_items[0].refreshToken,
                "client_id": CLIENT_ID,
                "client_secret": CLIENT_SECRET,
                "token_uri":"https://oauth2.googleapis.com/token",
                "expiry": oauth_items[0].expiry
    def import_userinfo(self, info):
        edges = []
        user_person = Person(displayName=info['name'], firstName=info['given_name'], lastName=info['family_name'], email=info['email'])
        user_account = Account(externalId=info['id'], displayName=info['name'], authEmail=info['email'])
        edges.append(Edge(user_account, user_person, 'owner'))
        print("GMAIL USER", user_person.displayName, user_account.authEmail)
        user_picture = self.google_api.get_media_data(info['picture'])
        user_picture = Photo.from_bytes(user_picture)
        user_picture.caption = "Profile picture"
        user_picture.name = info['name']
        edges.append(Edge(user_picture, user_picture.file[0], "file"))
        edges.append(Edge(user_account, user_picture, 'profilePicture'))
        self.client.upload_file(user_picture.data)
        self.client.bulk_action(create_items=[user_person, user_account, user_picture, user_picture.file[0]], create_edges=edges)
        return user_account
    def get_all_media_file(self):
        medias = self.client.search(
            fields_data={"type": "GooglePhotoItem"}
        return medias
    def parse_media(self, item):
        metadata = item["mediaMetadata"]
7172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
baseDict = { "id": item["id"], "width": metadata["width"], "height": metadata["width"], "creation_time": metadata["creationTime"], "base_url": item["baseUrl"], "file_name": item["filename"], "mime_type": item["mimeType"], } media_type = "photo" if metadata.get("video", None): media_type = "video" baseDict['fps'] = metadata[media_type].get("fps", None) baseDict['media_type'] = media_type baseDict['camera_make'] = metadata[media_type].get("cameraMake", None) baseDict['camera_model'] = metadata[media_type].get("cameraModel", None) baseDict['focal_length'] = metadata[media_type].get("focalLength", None) baseDict['exposure_time'] = metadata[media_type].get("exposureTime", None) baseDict['content'] = self.google_api.get_media_data(baseDict["base_url"]) return baseDict def import_media_file(self, item): externalId = item["id"] # State for check exist # Do not call DB for every item if externalId in self.existing_item_ids['Photo'] | self.existing_item_ids['Video']: print("This Item does exist") return media_dict = self.parse_media(item) media = None if media_dict['media_type'] == "photo": # may modify this method to accept kwargs to pass metadata # however, it already extracts exifData with PIL media = Photo.from_bytes(media_dict["content"]) else: # media_type = "video" media = Video.from_bytes( media_dict["content"], fps=media_dict["fps"], width=media_dict["width"], height=media_dict["height"], format=media_dict["mime_type"], filename=media_dict["file_name"], externalId=media_dict["id"], creationTime=media_dict["creation_time"]) media.externalId = media_dict["id"] edges = [] items = [media, media.file[0]] edges.append(Edge(media, media.file[0], "file")) edges.append(Edge(self.google_item, media, media_dict["media_type"])) if media_dict["camera_make"]: camera = self.get_or_create_item(media_dict["camera_model"], Camera, producer=media_dict["camera_make"], model=media_dict["camera_model"]) if not camera.id: items.append(camera) edges.append(Edge(media, camera, "camera")) self.client.bulk_action(create_items=items, create_edges=edges) self.client.upload_file(media.data, asyncFlag=False) def get_or_create_item(self, externalId, item_class, **kwargs): # Set datasource service item if it does not exist item = self.client.search({"type": item_class.__name__, "externalId": externalId})
141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
if item: item = item[0] else: item = item_class(externalId=externalId, **kwargs) return item def add_to_schema(self): self.client.add_to_schema(Photo, Video, Document, Account, Service, OauthFlow, Person, Camera) def get_external_ids(self, itemType: str): external_ids = [] search_filter = {'type': itemType} try: for batch in self.client.search_paginate(search_filter, 100): external_ids += [m.externalId for m in batch] finally: return external_ids # Plugin's entry point def run(self): self.auth() # google service as the data provider self.google_item = self.get_or_create_item(externalId=SERVICE_NAME, item_class=Service, name=SERVICE_NAME) if not self.google_item.id: self.client.create(self.google_item) # get existing items to prevent duplicates self.existing_item_ids["Photo"] = frozenset(self.get_external_ids(itemType="Photo")) self.existing_item_ids["Video"] = frozenset(self.get_external_ids(itemType="Video")) self.existing_item_ids["Camera"] = frozenset(self.get_external_ids(itemType="Camera")) self.existing_item_ids["Account"] = frozenset(self.get_external_ids(itemType="Account")) self.existing_item_ids["Document"] = frozenset(self.get_external_ids(itemType="Document")) # get user information and save Person, Account, Photo (profile picture) info = self.google_api.get_userinfo() if info['id'] not in self.existing_item_ids['Account']: self.user_account = self.import_userinfo(info) else: # get_by_externalId method may be needed self.user_account = self.client.search({'type': 'Account', 'externalId': info['id']})[0] # albums = self.google_api.get_albums() items = self.google_api.get_media() for item in items["mediaItems"]: print("Importing", item['filename']) self.import_media_file(item)