class SaveThumbnails(object): def __init__(self, path, photos_path, tmp_db): self.path = os.path.abspath(path) self.photos_path = photos_path db_path = os.path.join(photos_path, "database") self.library = Library(db_path, tmp_db) self.photos = dict() def build(self): logger.debug("Fetch photos") self.photos = dict((p.id, p) for p in self.library.fetch_photos()) logger.debug("Save folders and albums") self.save_folder(self.library.top_folder, None) def save_folder(self, folder, parent_path): logger.debug("Save %s with parent %s", folder, parent_path) path = os.path.join(parent_path, folder.name) if folder != self.library.top_folder else "." logger.debug("Create directory %s", path) if not os.path.exists(os.path.join(self.path, path)): os.makedirs(os.path.join(self.path, path)) for sub_folder in self.library.fetch_subfolders(folder): self.save_folder(sub_folder, path) for album in self.library.fetch_albums(folder): self.save_album(album, path) def save_album(self, album, parent_path): logger.debug("Save %s with parent %s", album, parent_path) path = os.path.join(parent_path, album.name) logger.debug("Create directory %s", path) if not os.path.exists(os.path.join(self.path, path)): os.makedirs(os.path.join(self.path, path)) photos = set(self.photos[i] for i in self.library.fetch_album_photo_id_list(album)) for photo in sorted(photos, key=lambda p: p.date): self.save_photo(photo, path) def save_photo(self, photo, parent_path): caption = photo.name or "Photo_%d" % photo.id file_name = photo.thumbnails["hd"] or photo.thumbnails["mini"] or photo.original src = os.path.join(self.photos_path, file_name) ext = os.path.splitext(src)[1] dst = os.path.join(self.path, parent_path, caption + ext) logger.debug("Copy %s to %s", src, dst) shutil.copy(src, dst)
class AlbumData(object): def __init__(self, path, disable_rolls=None, disable_rating=None, tmp_db=None, gen_caption=None): self.path = os.path.abspath(path) db_path = os.path.join(path, "database") self.library = Library(db_path, tmp_db) self.data = copy.deepcopy(BASE) self.data[ARCHIVE_PATH] = self.path self.data[ALBUMS] = [] self.photos = dict() self.disable_rolls = disable_rolls self.disable_rating = disable_rating self.all_roll_id = 5 self.generate_caption = gen_caption def build(self): logger.debug("Fetch photos") self.photos = dict((p.id, p) for p in self.library.fetch_photos()) logger.debug("Save folders and albums") self.data[ALBUMS] += [self._all_photos_album, self._flagged_album] self.save_folder(self.library.top_folder, None) logger.debug("Save rolls") if not self.disable_rolls: self.data["List of Rolls"] = [self._all_roll] logger.debug("Save images") self.data[IMAGES] = dict((str(p.id), self._photo(p)) for p in self.photos.values()) def save_folder(self, folder, parent): logger.debug("Save %s with parent %s", folder, parent) photo_ids = set() if folder != self.library.top_folder: data = self._album_base(folder, [], parent=parent) self.data[ALBUMS].append(data) parent = folder if folder != self.library.top_folder else None for sub_folder in self.library.fetch_subfolders(folder): photo_ids |= self.save_folder(sub_folder, parent) for album in self.library.fetch_albums(folder): photo_ids |= self.save_album(album, parent) if folder != self.library.top_folder: self._append_photos(data, photo_ids) logger.debug("Got %s photos for %s", len(photo_ids), folder) return photo_ids def save_album(self, album, parent): logger.debug("Save %s with parent %s", album, parent) photo_ids = set(self.library.fetch_album_photo_id_list(album)) self.data[ALBUMS].append(self._album_base(album, photo_ids, parent=parent)) return photo_ids def walk_through_tree(self, folder): logger.info("Process %s", folder) for album in self.library.fetch_albums(folder): logger.info("Write %s", album) for folder in self.library.fetch_subfolders(folder): self.walk_through_tree(folder) @property def _all_photos_album(self): album = self.library.all_photos_album photo_ids = self.photos.keys() data = self._album_base(album, photo_ids, album_type="99", name="Photos") data["Master"] = True return data @property def _flagged_album(self): album = self.library.favorites photo_ids = list(str(p.id) for p in self.photos.values() if p.is_favorite) return self._album_base(album, photo_ids, album_type="Flagged", name="Flagged", sort_order="1") @property def _last_imported_album(self): album = self.library.last_import_album photo_ids = set(self.library.fetch_album_photo_id_list(album)) return self._album_base(album, photo_ids) def _album_base(self, album, photo_ids, name=None, album_type=None, sort_order=None, parent=None): if album_type is None: if isinstance(album, Album): album_type = "Regular" elif isinstance(album, Folder): album_type = "Folder" data = { "AlbumId": _iphoto_id(album), "AlbumName": name or album.name, "GUID": album.uuid, "Album Type": album_type, } if album.poster_id: data["KeyPhotoKey"] = str(album.poster_id) if sort_order: data["Sort Order"] = sort_order if parent: data["Parent"] = _iphoto_id(parent) if photo_ids: self._append_photos(data, photo_ids) return data def _append_photos(self, data, photo_ids): data["KeyList"] = list(str(k) for k in sorted(photo_ids)) data["PhotoCount"] = len(photo_ids) return data def _photo(self, photo): empty_caption = "" if self.generate_caption: empty_caption = "photo_%d" % photo.id data = { "Caption": photo.name or empty_caption, "Comment": photo.description or " ", "GUID": photo.uuid, "Roll": self.all_roll_id, "Rating": 5 if photo.is_favorite and not self.disable_rating else 0, "ImagePath": os.path.join(self.path, photo.path), "MediaType": "Image", # "MediaType": "photo", "ModDateAsTimerInterval": photo.export_image_change_date_ts, "MetaModDateAsTimerInterval": photo.export_metadata_change_date_ts, "DateAsTimerInterval": photo.image_date_ts, "DateAsTimerIntervalGMT": photo.image_data_gmt_ts, "OriginalPath": os.path.join(self.path, photo.original), "ThumbPath": os.path.join(self.path, photo.thumbnails["mini"]), } if photo.is_favorite: data["Flagged"] = True return data @property def _all_roll(self): """One fake event""" return { "RollID": self.all_roll_id, "ProjectUuid": "RBoLkXF0QxGHAqJTrs9p0Q", "RollName": "Photos", "RollDateAsTimerInterval": min(p.image_date_ts for p in self.photos.values()), "KeyPhotoKey": str(min(p.id for p in self.photos.values())), "PhotoCount": len(self.photos), "KeyList": list(str(p.id) for p in self.photos.values()), }