def scan_originals(self, folder, options): """Scan a folder of Original images, and delete obsolete ones.""" file_list = os.listdir(folder) if not file_list: return for f in file_list: # We won't touch some files. if imageutils.is_ignore(f): continue originalfile = unicodedata.normalize("NFC", os.path.join(folder, f)) if os.path.isdir(originalfile): delete_album_file(originalfile, self.albumdirectory, "Obsolete export Originals directory", options) continue base_name = unicodedata.normalize("NFC", su.getfilebasename(originalfile)) master_file = self.files.get(base_name) # everything else must have a master, or will have to go if (not master_file or originalfile != master_file.original_export_file or master_file.photo.rotation_is_only_edit): delete_album_file(originalfile, originalfile, "Obsolete Original", options)
def check_directories(self, directory, rel_path, album_directories, options): """Checks an export directory for obsolete files.""" if options.ignore: exclude_pattern = re.compile(su.fsdec(options.ignore)) if exclude_pattern.match(os.path.split(directory)[1]): return True if not os.path.exists(directory): return True contains_albums = False for f in su.os_listdir_unicode(directory): if self._check_abort(): return album_file = os.path.join(directory, f) if os.path.isdir(album_file): if f == "iPod Photo Cache": su.pout("Skipping " + album_file) continue rel_path_file = os.path.join(rel_path, f) if album_file in album_directories: contains_albums = True elif not self.check_directories(album_file, rel_path_file, album_directories, options): delete_album_file(album_file, directory, "Obsolete directory", options) else: # we won't touch some files if imageutils.is_ignore(f): continue delete_album_file(album_file, directory, "Obsolete", options) return contains_albums
def check_directories(self, directory, rel_path, album_directories, options): """Checks an export directory for obsolete files.""" if options.ignore: exclude_pattern = re.compile(su.fsdec(options.ignore)) if exclude_pattern.match(os.path.split(directory)[1]): return True if not os.path.exists(directory): return True contains_albums = False for f in su.os_listdir_unicode(directory): if self._check_abort(): return album_file = os.path.join(directory, f) if os.path.isdir(album_file): if f == "iPod Photo Cache": su.pout("Skipping " + album_file) continue rel_path_file = os.path.join(rel_path, f) if album_file in album_directories: contains_albums = True elif not self.check_directories(album_file, rel_path_file, album_directories, options): delete_album_file(album_file, directory, "Obsolete directory", options) else: contains_albums = True else: # we won't touch some files if imageutils.is_ignore(f): continue delete_album_file(album_file, directory, "Obsolete", options) return contains_albums
def load_album(self, options): """Loads an existing album (export folder).""" online_albums = {} for album in self.client.gd_client.GetUserFeed().entry: if online_albums.has_key(album.title.text): self.delete_online_album(album, "duplicate album", options) else: online_albums[su.unicode_string(album.title.text)] = album album_directories = {} for folder_name in sorted(self.named_folders): folder = self.named_folders.get(folder_name) if self._check_abort(): return album_directories[folder.name] = True folder.load_album(self.client, online_albums, options) ignore_pattern = None if options.ignore: ignore_pattern = re.compile(su.fsdec(options.ignore)) for album_name in online_albums: if self._check_abort(): return if album_name in album_directories: continue if ignore_pattern and ignore_pattern.match(album_name): continue # We won't touch some albums if imageutils.is_ignore(album_name): continue self.delete_online_album(online_albums[album_name], "obsolete album", options)
def scan_originals(self, folder, options): """Scan a folder of Original images, and delete obsolete ones.""" file_list = os.listdir(folder) if not file_list: return for f in file_list: # We won't touch some files. if imageutils.is_ignore(f): continue originalfile = unicodedata.normalize("NFC", os.path.join(folder, f)) if os.path.isdir(originalfile): delete_album_file(originalfile, self.albumdirectory, "Obsolete export Originals directory", options) continue base_name = unicodedata.normalize("NFC", su.getfilebasename(originalfile)) master_file = self.files.get(base_name.lower()) # everything else must have a master, or will have to go if (not master_file or originalfile != master_file.original_export_file or master_file.photo.rotation_is_only_edit): delete_album_file(originalfile, originalfile, "Obsolete Original", options)
def load_album(self, options): """walks the album directory tree, and scans it for existing files.""" if not os.path.exists(self.albumdirectory): su.pout("Creating folder " + self.albumdirectory) if not options.dryrun: os.makedirs(self.albumdirectory) else: return file_list = os.listdir(self.albumdirectory) if file_list is None: return for f in sorted(file_list): # we won't touch some files if imageutils.is_ignore(f): continue album_file = unicodedata.normalize("NFC", os.path.join(self.albumdirectory, f)) if os.path.isdir(album_file): if (options.originals and (f == "Originals" or (options.picasa and f == ".picasaoriginals"))): self.scan_originals(album_file, options) continue else: delete_album_file(album_file, self.albumdirectory, "Obsolete export directory", options) continue base_name = unicodedata.normalize("NFC", su.getfilebasename(album_file)) master_file = self.files.get(base_name.lower()) # everything else must have a master, or will have to go if master_file is None or not master_file.is_part_of(album_file): delete_album_file(album_file, self.albumdirectory, "Obsolete exported file", options)
class PicasaAlbum(object): """Tracks an album folder in the export location.""" def __init__(self, name, iphoto_container): self.name = name self.iphoto_container = iphoto_container self.files = {} # name -> PicasaFile self.online_album = None self.image_suffix = re.compile( r'\.(jpeg|jpg|mpg|mpeg|mov|png|tif|tiff)$', re.IGNORECASE) def add_iphoto_images(self, images, options): """Works through an image folder tree, and builds data for exporting.""" entries = 0 template = options.nametemplate if images is not None: entry_digits = len(str(len(images))) for image in images: if image.ismovie() and not options.movies: continue if _NOUPLOAD_KEYWORD in image.keywords: continue entries += 1 image_basename = self.make_album_basename( image, entries, str(entries).zfill(entry_digits), template) picture_file = PicasaFile(image, self.name, image_basename, options) self.files[image_basename] = picture_file return len(self.files) def make_album_basename(self, photo, index, padded_index, name_template): """creates unique file name.""" base_name = imageutils.format_photo_name(photo, self.iphoto_container.name, index, padded_index, name_template) index = 0 while True: album_basename = base_name if index > 0: album_basename += "_%d" % (index) if self.files.get(album_basename) is None: return album_basename index += 1 return base_name def load_album(self, client, online_albums, options): """Walks the album directory tree, and scans it for existing files.""" if options.verbose: print 'Reading online album ' + self.name comments = self.iphoto_container.getcommentwithouthints().strip() timestamp = get_picasaweb_date(self.iphoto_container.date) self.online_album = online_albums.get(self.name) if not self.online_album: print "Creating album: " + su.fsenc(self.name) if not options.dryrun: client.throttle() self.online_album = client.gd_client.InsertAlbum( title=self.name, summary=comments, access='private', timestamp=timestamp) online_albums[self.name] = self.online_album return # Check the properties of the online album changed = False online_album_summary_text = su.unicode_string( self.online_album.summary.text) if online_album_summary_text != comments: print 'Updating summary for online album %s (%s vs. %s)' % ( su.fsenc(self.name), su.fsenc(online_album_summary_text), su.fsenc(comments)) self.online_album.summary.text = comments changed = True if (timestamp and timestamp != self.online_album.timestamp.text): print 'Updating timestamp for online album %s (%s/%s)' % ( su.fsenc(self.name), self.online_album.timestamp.datetime(), self.iphoto_container.date) self.online_album.timestamp.text = timestamp changed = True if changed and not options.dryrun: client.throttle() try: self.online_album = client.gd_client.Put( self.online_album, self.online_album.GetEditLink().href, converter=gdata.photos.AlbumEntryFromString) except gdata.photos.service.GooglePhotosException, e: print 'Failed to update data for online album %s: %s' % ( self.name, str(e)) # Check the pictures in the online album try: photos = client.gd_client.GetFeed( '/data/feed/api/user/%s/albumid/%s?kind=photo' % ('default', self.online_album.gphoto_id.text)) for photo in photos.entry: # we won't touch some files if imageutils.is_ignore(photo.title.text): continue photo_name = su.unicode_string(photo.title.text) base_name = su.getfilebasename(photo_name) master_file = self.files.get(base_name) # everything else must have a master, or will have to go if master_file is None: delete_online_photo(client, photo, self.name, "Obsolete online photo", options) elif master_file.picasa_photo: delete_online_photo(client, photo, self.name, "Duplicate online photo", options) else: master_file.picasa_photo = photo except gdata.photos.service.GooglePhotosException, e: print 'Failed to load pictures for online album %s: %s' % ( self.name, str(e))