-
Alp Deniz Ogut authoreddff7133a
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)