Feature add import 754 (#762)
* Initial alpha version of import command * Refactored * Improved help, added --clear-metadata * Added --clear-metadata, --exiftool to import * Added --keyword, --title, --description * Added --location * Added test for --location * Changed --auto-folder to --split-folder, added docs * Added --walk, updated docs * Added --check-templates * Updated help text for import
This commit is contained in:
@@ -15,6 +15,7 @@ from .export import export
|
||||
from .exportdb import exportdb
|
||||
from .grep import grep
|
||||
from .help import help
|
||||
from .import_cli import import_cli
|
||||
from .info import info
|
||||
from .install_uninstall_run import install, run, uninstall
|
||||
from .keywords import keywords
|
||||
@@ -75,6 +76,7 @@ for command in [
|
||||
exportdb,
|
||||
grep,
|
||||
help,
|
||||
import_cli,
|
||||
info,
|
||||
install,
|
||||
keywords,
|
||||
|
||||
1072
osxphotos/cli/import_cli.py
Normal file
1072
osxphotos/cli/import_cli.py
Normal file
File diff suppressed because it is too large
Load Diff
@@ -4,7 +4,7 @@ from typing import List, Optional
|
||||
|
||||
import photoscript
|
||||
from more_itertools import chunked
|
||||
from photoscript import Photo, PhotosLibrary
|
||||
from photoscript import Album, Folder, Photo, PhotosLibrary
|
||||
|
||||
from .photoinfo import PhotoInfo
|
||||
from .utils import noop, pluralize
|
||||
@@ -51,19 +51,72 @@ class PhotosAlbum:
|
||||
return self.album.photos()
|
||||
|
||||
|
||||
def folder_by_path(folders: List[str], verbose: Optional[callable] = None) -> Folder:
|
||||
"""Get (and create if necessary) a Photos Folder by path (passed as list of folder names)"""
|
||||
library = PhotosLibrary()
|
||||
verbose = verbose or noop
|
||||
top_folder_name = folders.pop(0)
|
||||
top_folder = library.folder(top_folder_name, top_level=True)
|
||||
if not top_folder:
|
||||
verbose(f"Creating folder '{top_folder_name}'")
|
||||
top_folder = library.create_folder(top_folder_name)
|
||||
current_folder = top_folder
|
||||
for folder_name in folders:
|
||||
folder = current_folder.folder(folder_name)
|
||||
if not folder:
|
||||
verbose(f"Creating folder '{folder_name}'")
|
||||
folder = current_folder.create_folder(folder_name)
|
||||
current_folder = folder
|
||||
return current_folder
|
||||
|
||||
|
||||
def album_by_path(
|
||||
folders_album: List[str], verbose: Optional[callable] = None
|
||||
) -> Album:
|
||||
"""Get (and create if necessary) a Photos Album by path (pass as list of folders, album name)"""
|
||||
library = PhotosLibrary()
|
||||
verbose = verbose or noop
|
||||
if len(folders_album) > 1:
|
||||
# have folders
|
||||
album_name = folders_album.pop()
|
||||
folder = folder_by_path(folders_album, verbose)
|
||||
album = folder.album(album_name)
|
||||
if not album:
|
||||
verbose(f"Creating album '{album_name}'")
|
||||
album = folder.create_album(album_name)
|
||||
else:
|
||||
# only have album name
|
||||
album_name = folders_album[0]
|
||||
album = library.album(album_name, top_level=True)
|
||||
if not album:
|
||||
verbose(f"Creating album '{album_name}'")
|
||||
album = library.create_album(album_name)
|
||||
|
||||
return album
|
||||
|
||||
|
||||
class PhotosAlbumPhotoScript:
|
||||
"""Add photoscript.Photo objects to album"""
|
||||
|
||||
def __init__(self, name: str, verbose: Optional[callable] = None):
|
||||
self.name = name
|
||||
def __init__(
|
||||
self, name: str, verbose: Optional[callable] = None, split_folder: Optional[str] = None
|
||||
):
|
||||
"""Return a PhotosAlbumPhotoScript object, creating the album if necessary
|
||||
|
||||
Args:
|
||||
name: Name of album
|
||||
verbose: optional callable to print verbose output
|
||||
split_folder: if set, split album name on value of split_folder to create folders if necessary,
|
||||
e.g. if name = 'folder1/folder2/album' and split_folder='/',
|
||||
then folders 'folder1' and 'folder2' will be created and album 'album' will be created in 'folder2';
|
||||
if not set, album 'folder1/folder2/album' will be created
|
||||
"""
|
||||
self.verbose = verbose or noop
|
||||
self.library = PhotosLibrary()
|
||||
|
||||
album = self.library.album(name)
|
||||
if album is None:
|
||||
self.verbose(f"Creating Photos album '{self.name}'")
|
||||
album = self.library.create_album(name)
|
||||
self.album = album
|
||||
folders_album = name.split(split_folder) if split_folder else [name]
|
||||
self.album = album_by_path(folders_album, verbose=verbose)
|
||||
self.name = name
|
||||
|
||||
def add(self, photo: Photo):
|
||||
self.album.add([photo])
|
||||
|
||||
@@ -1629,20 +1629,18 @@ def _get_pathlib_value(field, value, quote):
|
||||
if len(parts) == 1:
|
||||
return shlex.quote(value) if quote else value
|
||||
|
||||
if len(parts) > 2:
|
||||
raise ValueError(f"Illegal value for path template: {field}")
|
||||
|
||||
path = parts[0]
|
||||
attribute = parts[1]
|
||||
path = pathlib.Path(value)
|
||||
try:
|
||||
val = getattr(path, attribute)
|
||||
val_str = str(val)
|
||||
if quote:
|
||||
val_str = shlex.quote(val_str)
|
||||
return val_str
|
||||
except AttributeError:
|
||||
raise ValueError("Illegal value for path template: {attribute}")
|
||||
for attribute in parts[1:]:
|
||||
try:
|
||||
val = getattr(path, attribute)
|
||||
path = pathlib.Path(val)
|
||||
except AttributeError as e:
|
||||
raise ValueError(f"Illegal value for filepath template: {attribute}") from e
|
||||
|
||||
val_str = str(val)
|
||||
if quote:
|
||||
val_str = shlex.quote(val_str)
|
||||
return val_str
|
||||
|
||||
|
||||
def format_str_value(value, format_str):
|
||||
|
||||
Reference in New Issue
Block a user