@@ -64,51 +64,137 @@ class CLI_Obj:
|
|||||||
|
|
||||||
|
|
||||||
CTX_SETTINGS = dict(help_option_names=["-h", "--help"])
|
CTX_SETTINGS = dict(help_option_names=["-h", "--help"])
|
||||||
|
DB_OPTION = click.option(
|
||||||
|
"--db",
|
||||||
|
required=False,
|
||||||
|
metavar="<Photos database path>",
|
||||||
|
default=None,
|
||||||
|
help=(
|
||||||
|
"Specify Photos database path. "
|
||||||
|
"Path to Photos library/database can be specified using either --db "
|
||||||
|
"or directly as PHOTOS_LIBRARY positional argument."
|
||||||
|
),
|
||||||
|
type=click.Path(exists=True),
|
||||||
|
)
|
||||||
|
|
||||||
|
DB_ARGUMENT = click.argument("photos_library", nargs=-1, type=click.Path(exists=True))
|
||||||
|
|
||||||
|
JSON_OPTION = click.option(
|
||||||
|
"--json", "json_",
|
||||||
|
required=False,
|
||||||
|
is_flag=True,
|
||||||
|
default=False,
|
||||||
|
help="Print output in JSON format.",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def query_options(f):
|
||||||
|
o = click.option
|
||||||
|
options = [
|
||||||
|
o("--keyword", default=None, multiple=True, help="Search for keyword(s)."),
|
||||||
|
o("--person", default=None, multiple=True, help="Search for person(s)."),
|
||||||
|
o("--album", default=None, multiple=True, help="Search for album(s)."),
|
||||||
|
o("--uuid", default=None, multiple=True, help="Search for UUID(s)."),
|
||||||
|
o(
|
||||||
|
"--title",
|
||||||
|
default=None,
|
||||||
|
multiple=True,
|
||||||
|
help="Search for TEXT in title of photo.",
|
||||||
|
),
|
||||||
|
o("--no-title", is_flag=True, help="Search for photos with no title."),
|
||||||
|
o(
|
||||||
|
"--description",
|
||||||
|
default=None,
|
||||||
|
multiple=True,
|
||||||
|
help="Search for TEXT in description of photo.",
|
||||||
|
),
|
||||||
|
o(
|
||||||
|
"--no-description",
|
||||||
|
is_flag=True,
|
||||||
|
help="Search for photos with no description.",
|
||||||
|
),
|
||||||
|
o(
|
||||||
|
"--uti",
|
||||||
|
default=None,
|
||||||
|
multiple=False,
|
||||||
|
help="Search for photos whose uniform type identifier (UTI) matches TEXT",
|
||||||
|
),
|
||||||
|
o(
|
||||||
|
"-i",
|
||||||
|
"--ignore-case",
|
||||||
|
is_flag=True,
|
||||||
|
help="Case insensitive search for title or description. Does not apply to keyword, person, or album.",
|
||||||
|
),
|
||||||
|
o("--edited", is_flag=True, help="Search for photos that have been edited."),
|
||||||
|
o(
|
||||||
|
"--external-edit",
|
||||||
|
is_flag=True,
|
||||||
|
help="Search for photos edited in external editor.",
|
||||||
|
),
|
||||||
|
o("--favorite", is_flag=True, help="Search for photos marked favorite."),
|
||||||
|
o(
|
||||||
|
"--not-favorite",
|
||||||
|
is_flag=True,
|
||||||
|
help="Search for photos not marked favorite.",
|
||||||
|
),
|
||||||
|
o("--hidden", is_flag=True, help="Search for photos marked hidden."),
|
||||||
|
o("--not-hidden", is_flag=True, help="Search for photos not marked hidden."),
|
||||||
|
o(
|
||||||
|
"--shared",
|
||||||
|
is_flag=True,
|
||||||
|
help="Search for photos in shared iCloud album (Photos 5 only).",
|
||||||
|
),
|
||||||
|
o(
|
||||||
|
"--not-shared",
|
||||||
|
is_flag=True,
|
||||||
|
help="Search for photos not in shared iCloud album (Photos 5 only).",
|
||||||
|
),
|
||||||
|
o(
|
||||||
|
"--burst",
|
||||||
|
is_flag=True,
|
||||||
|
help="Search for photos that were taken in a burst.",
|
||||||
|
),
|
||||||
|
o(
|
||||||
|
"--not-burst",
|
||||||
|
is_flag=True,
|
||||||
|
help="Search for photos that are not part of a burst.",
|
||||||
|
),
|
||||||
|
o("--live", is_flag=True, help="Search for Apple live photos"),
|
||||||
|
o(
|
||||||
|
"--not-live",
|
||||||
|
is_flag=True,
|
||||||
|
help="Search for photos that are not Apple live photos",
|
||||||
|
),
|
||||||
|
o(
|
||||||
|
"--only-movies",
|
||||||
|
is_flag=True,
|
||||||
|
help="Search only for movies (default searches both images and movies).",
|
||||||
|
),
|
||||||
|
o(
|
||||||
|
"--only-photos",
|
||||||
|
is_flag=True,
|
||||||
|
help="Search only for photos/images (default searches both images and movies).",
|
||||||
|
),
|
||||||
|
]
|
||||||
|
for o in options[::-1]:
|
||||||
|
f = o(f)
|
||||||
|
return f
|
||||||
|
|
||||||
|
|
||||||
@click.group(context_settings=CTX_SETTINGS)
|
@click.group(context_settings=CTX_SETTINGS)
|
||||||
@click.option(
|
@DB_OPTION
|
||||||
"--db",
|
@JSON_OPTION
|
||||||
required=False,
|
|
||||||
metavar="<Photos database path>",
|
|
||||||
default=None,
|
|
||||||
help="Specify Photos database path.",
|
|
||||||
type=click.Path(exists=True),
|
|
||||||
)
|
|
||||||
@click.option(
|
|
||||||
"--json",
|
|
||||||
required=False,
|
|
||||||
is_flag=True,
|
|
||||||
default=False,
|
|
||||||
help="Print output in JSON format.",
|
|
||||||
)
|
|
||||||
@click.option("--debug", required=False, is_flag=True, default=False, hidden=True)
|
@click.option("--debug", required=False, is_flag=True, default=False, hidden=True)
|
||||||
@click.version_option(__version__, "--version", "-v")
|
@click.version_option(__version__, "--version", "-v")
|
||||||
@click.pass_context
|
@click.pass_context
|
||||||
def cli(ctx, db, json, debug):
|
def cli(ctx, db, json_, debug):
|
||||||
ctx.obj = CLI_Obj(db=db, json=json, debug=debug)
|
ctx.obj = CLI_Obj(db=db, json=json_, debug=debug)
|
||||||
|
|
||||||
|
|
||||||
@cli.command()
|
@cli.command()
|
||||||
@click.option(
|
@DB_OPTION
|
||||||
"--db",
|
@JSON_OPTION
|
||||||
required=False,
|
@DB_ARGUMENT
|
||||||
metavar="<Photos database path>",
|
|
||||||
default=None,
|
|
||||||
help="Specify Photos database path. "
|
|
||||||
"Path to Photos library/database can be specified using either --db "
|
|
||||||
"or directly as PHOTOS_LIBRARY positional argument.",
|
|
||||||
type=click.Path(exists=True),
|
|
||||||
)
|
|
||||||
@click.option(
|
|
||||||
"--json",
|
|
||||||
"json_",
|
|
||||||
required=False,
|
|
||||||
is_flag=True,
|
|
||||||
default=False,
|
|
||||||
help="Print output in JSON format.",
|
|
||||||
)
|
|
||||||
@click.argument("photos_library", nargs=-1, type=click.Path(exists=True))
|
|
||||||
@click.pass_obj
|
@click.pass_obj
|
||||||
@click.pass_context
|
@click.pass_context
|
||||||
def keywords(ctx, cli_obj, db, json_, photos_library):
|
def keywords(ctx, cli_obj, db, json_, photos_library):
|
||||||
@@ -116,8 +202,8 @@ def keywords(ctx, cli_obj, db, json_, photos_library):
|
|||||||
|
|
||||||
db = get_photos_db(*photos_library, db, cli_obj.db)
|
db = get_photos_db(*photos_library, db, cli_obj.db)
|
||||||
if db is None:
|
if db is None:
|
||||||
click.echo(cli.commands["keywords"].get_help(ctx))
|
click.echo(cli.commands["keywords"].get_help(ctx), err=True)
|
||||||
click.echo("\n\nLocated the following Photos library databases: ")
|
click.echo("\n\nLocated the following Photos library databases: ", err=True)
|
||||||
_list_libraries()
|
_list_libraries()
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -130,25 +216,9 @@ def keywords(ctx, cli_obj, db, json_, photos_library):
|
|||||||
|
|
||||||
|
|
||||||
@cli.command()
|
@cli.command()
|
||||||
@click.option(
|
@DB_OPTION
|
||||||
"--db",
|
@JSON_OPTION
|
||||||
required=False,
|
@DB_ARGUMENT
|
||||||
metavar="<Photos database path>",
|
|
||||||
default=None,
|
|
||||||
help="Specify Photos database path. "
|
|
||||||
"Path to Photos library/database can be specified using either --db "
|
|
||||||
"or directly as PHOTOS_LIBRARY positional argument.",
|
|
||||||
type=click.Path(exists=True),
|
|
||||||
)
|
|
||||||
@click.option(
|
|
||||||
"--json",
|
|
||||||
"json_",
|
|
||||||
required=False,
|
|
||||||
is_flag=True,
|
|
||||||
default=False,
|
|
||||||
help="Print output in JSON format.",
|
|
||||||
)
|
|
||||||
@click.argument("photos_library", nargs=-1, type=click.Path(exists=True))
|
|
||||||
@click.pass_obj
|
@click.pass_obj
|
||||||
@click.pass_context
|
@click.pass_context
|
||||||
def albums(ctx, cli_obj, db, json_, photos_library):
|
def albums(ctx, cli_obj, db, json_, photos_library):
|
||||||
@@ -156,8 +226,8 @@ def albums(ctx, cli_obj, db, json_, photos_library):
|
|||||||
|
|
||||||
db = get_photos_db(*photos_library, db, cli_obj.db)
|
db = get_photos_db(*photos_library, db, cli_obj.db)
|
||||||
if db is None:
|
if db is None:
|
||||||
click.echo(cli.commands["albums"].get_help(ctx))
|
click.echo(cli.commands["albums"].get_help(ctx), err=True)
|
||||||
click.echo("\n\nLocated the following Photos library databases: ")
|
click.echo("\n\nLocated the following Photos library databases: ", err=True)
|
||||||
_list_libraries()
|
_list_libraries()
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -173,25 +243,9 @@ def albums(ctx, cli_obj, db, json_, photos_library):
|
|||||||
|
|
||||||
|
|
||||||
@cli.command()
|
@cli.command()
|
||||||
@click.option(
|
@DB_OPTION
|
||||||
"--db",
|
@JSON_OPTION
|
||||||
required=False,
|
@DB_ARGUMENT
|
||||||
metavar="<Photos database path>",
|
|
||||||
default=None,
|
|
||||||
help="Specify Photos database path. "
|
|
||||||
"Path to Photos library/database can be specified using either --db "
|
|
||||||
"or directly as PHOTOS_LIBRARY positional argument.",
|
|
||||||
type=click.Path(exists=True),
|
|
||||||
)
|
|
||||||
@click.option(
|
|
||||||
"--json",
|
|
||||||
"json_",
|
|
||||||
required=False,
|
|
||||||
is_flag=True,
|
|
||||||
default=False,
|
|
||||||
help="Print output in JSON format.",
|
|
||||||
)
|
|
||||||
@click.argument("photos_library", nargs=-1, type=click.Path(exists=True))
|
|
||||||
@click.pass_obj
|
@click.pass_obj
|
||||||
@click.pass_context
|
@click.pass_context
|
||||||
def persons(ctx, cli_obj, db, json_, photos_library):
|
def persons(ctx, cli_obj, db, json_, photos_library):
|
||||||
@@ -199,8 +253,8 @@ def persons(ctx, cli_obj, db, json_, photos_library):
|
|||||||
|
|
||||||
db = get_photos_db(*photos_library, db, cli_obj.db)
|
db = get_photos_db(*photos_library, db, cli_obj.db)
|
||||||
if db is None:
|
if db is None:
|
||||||
click.echo(cli.commands["persons"].get_help(ctx))
|
click.echo(cli.commands["persons"].get_help(ctx), err=True)
|
||||||
click.echo("\n\nLocated the following Photos library databases: ")
|
click.echo("\n\nLocated the following Photos library databases: ", err=True)
|
||||||
_list_libraries()
|
_list_libraries()
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -213,25 +267,9 @@ def persons(ctx, cli_obj, db, json_, photos_library):
|
|||||||
|
|
||||||
|
|
||||||
@cli.command()
|
@cli.command()
|
||||||
@click.option(
|
@DB_OPTION
|
||||||
"--db",
|
@JSON_OPTION
|
||||||
required=False,
|
@DB_ARGUMENT
|
||||||
metavar="<Photos database path>",
|
|
||||||
default=None,
|
|
||||||
help="Specify Photos database path. "
|
|
||||||
"Path to Photos library/database can be specified using either --db "
|
|
||||||
"or directly as PHOTOS_LIBRARY positional argument.",
|
|
||||||
type=click.Path(exists=True),
|
|
||||||
)
|
|
||||||
@click.option(
|
|
||||||
"--json",
|
|
||||||
"json_",
|
|
||||||
required=False,
|
|
||||||
is_flag=True,
|
|
||||||
default=False,
|
|
||||||
help="Print output in JSON format.",
|
|
||||||
)
|
|
||||||
@click.argument("photos_library", nargs=-1, type=click.Path(exists=True))
|
|
||||||
@click.pass_obj
|
@click.pass_obj
|
||||||
@click.pass_context
|
@click.pass_context
|
||||||
def info(ctx, cli_obj, db, json_, photos_library):
|
def info(ctx, cli_obj, db, json_, photos_library):
|
||||||
@@ -239,8 +277,8 @@ def info(ctx, cli_obj, db, json_, photos_library):
|
|||||||
|
|
||||||
db = get_photos_db(*photos_library, db, cli_obj.db)
|
db = get_photos_db(*photos_library, db, cli_obj.db)
|
||||||
if db is None:
|
if db is None:
|
||||||
click.echo(cli.commands["info"].get_help(ctx))
|
click.echo(cli.commands["info"].get_help(ctx), err=True)
|
||||||
click.echo("\n\nLocated the following Photos library databases: ")
|
click.echo("\n\nLocated the following Photos library databases: ", err=True)
|
||||||
_list_libraries()
|
_list_libraries()
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -302,25 +340,9 @@ def info(ctx, cli_obj, db, json_, photos_library):
|
|||||||
|
|
||||||
|
|
||||||
@cli.command()
|
@cli.command()
|
||||||
@click.option(
|
@DB_OPTION
|
||||||
"--db",
|
@JSON_OPTION
|
||||||
required=False,
|
@DB_ARGUMENT
|
||||||
metavar="<Photos database path>",
|
|
||||||
default=None,
|
|
||||||
help="Specify Photos database path. "
|
|
||||||
"Path to Photos library/database can be specified using either --db "
|
|
||||||
"or directly as PHOTOS_LIBRARY positional argument.",
|
|
||||||
type=click.Path(exists=True),
|
|
||||||
)
|
|
||||||
@click.option(
|
|
||||||
"--json",
|
|
||||||
"json_",
|
|
||||||
required=False,
|
|
||||||
is_flag=True,
|
|
||||||
default=False,
|
|
||||||
help="Print output in JSON format.",
|
|
||||||
)
|
|
||||||
@click.argument("photos_library", nargs=-1, type=click.Path(exists=True))
|
|
||||||
@click.pass_obj
|
@click.pass_obj
|
||||||
@click.pass_context
|
@click.pass_context
|
||||||
def dump(ctx, cli_obj, db, json_, photos_library):
|
def dump(ctx, cli_obj, db, json_, photos_library):
|
||||||
@@ -328,8 +350,8 @@ def dump(ctx, cli_obj, db, json_, photos_library):
|
|||||||
|
|
||||||
db = get_photos_db(*photos_library, db, cli_obj.db)
|
db = get_photos_db(*photos_library, db, cli_obj.db)
|
||||||
if db is None:
|
if db is None:
|
||||||
click.echo(cli.commands["dump"].get_help(ctx))
|
click.echo(cli.commands["dump"].get_help(ctx), err=True)
|
||||||
click.echo("\n\nLocated the following Photos library databases: ")
|
click.echo("\n\nLocated the following Photos library databases: ", err=True)
|
||||||
_list_libraries()
|
_list_libraries()
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -339,22 +361,15 @@ def dump(ctx, cli_obj, db, json_, photos_library):
|
|||||||
|
|
||||||
|
|
||||||
@cli.command(name="list")
|
@cli.command(name="list")
|
||||||
@click.option(
|
@JSON_OPTION
|
||||||
"--json",
|
|
||||||
"json_",
|
|
||||||
required=False,
|
|
||||||
is_flag=True,
|
|
||||||
default=False,
|
|
||||||
help="Print output in JSON format.",
|
|
||||||
)
|
|
||||||
@click.pass_obj
|
@click.pass_obj
|
||||||
@click.pass_context
|
@click.pass_context
|
||||||
def list_libraries(ctx, cli_obj, json_):
|
def list_libraries(ctx, cli_obj, json_):
|
||||||
""" Print list of Photos libraries found on the system. """
|
""" Print list of Photos libraries found on the system. """
|
||||||
_list_libraries(json_=json_ or cli_obj.json)
|
_list_libraries(json_=json_ or cli_obj.json, error=False)
|
||||||
|
|
||||||
|
|
||||||
def _list_libraries(json_=False):
|
def _list_libraries(json_=False, error=True):
|
||||||
""" Print list of Photos libraries found on the system.
|
""" Print list of Photos libraries found on the system.
|
||||||
If json_ == True, print output as JSON (default = False) """
|
If json_ == True, print output as JSON (default = False) """
|
||||||
|
|
||||||
@@ -374,106 +389,32 @@ def _list_libraries(json_=False):
|
|||||||
|
|
||||||
for lib in photo_libs:
|
for lib in photo_libs:
|
||||||
if lib == sys_lib:
|
if lib == sys_lib:
|
||||||
click.echo(f"(*)\t{lib}")
|
click.echo(f"(*)\t{lib}", err=error)
|
||||||
sys_lib_flag = True
|
sys_lib_flag = True
|
||||||
elif lib == last_lib:
|
elif lib == last_lib:
|
||||||
click.echo(f"(#)\t{lib}")
|
click.echo(f"(#)\t{lib}", err=error)
|
||||||
last_lib_flag = True
|
last_lib_flag = True
|
||||||
else:
|
else:
|
||||||
click.echo(f"\t{lib}")
|
click.echo(f"\t{lib}", err=error)
|
||||||
|
|
||||||
if sys_lib_flag or last_lib_flag:
|
if sys_lib_flag or last_lib_flag:
|
||||||
click.echo("\n")
|
click.echo("\n", err=error)
|
||||||
if sys_lib_flag:
|
if sys_lib_flag:
|
||||||
click.echo("(*)\tSystem Photos Library")
|
click.echo("(*)\tSystem Photos Library", err=error)
|
||||||
if last_lib_flag:
|
if last_lib_flag:
|
||||||
click.echo("(#)\tLast opened Photos Library")
|
click.echo("(#)\tLast opened Photos Library", err=error)
|
||||||
|
|
||||||
|
|
||||||
@cli.command()
|
@cli.command()
|
||||||
@click.option(
|
@DB_OPTION
|
||||||
"--db",
|
@JSON_OPTION
|
||||||
required=False,
|
@query_options
|
||||||
metavar="<Photos database path>",
|
|
||||||
default=None,
|
|
||||||
help="Specify Photos database path. "
|
|
||||||
"Path to Photos library/database can be specified using either --db "
|
|
||||||
"or directly as PHOTOS_LIBRARY positional argument.",
|
|
||||||
type=click.Path(exists=True),
|
|
||||||
)
|
|
||||||
@click.option(
|
|
||||||
"--json",
|
|
||||||
"json_",
|
|
||||||
required=False,
|
|
||||||
is_flag=True,
|
|
||||||
default=False,
|
|
||||||
help="Print output in JSON format.",
|
|
||||||
)
|
|
||||||
@click.option("--keyword", default=None, multiple=True, help="Search for keyword(s).")
|
|
||||||
@click.option("--person", default=None, multiple=True, help="Search for person(s).")
|
|
||||||
@click.option("--album", default=None, multiple=True, help="Search for album(s).")
|
|
||||||
@click.option("--uuid", default=None, multiple=True, help="Search for UUID(s).")
|
|
||||||
@click.option(
|
|
||||||
"--title", default=None, multiple=True, help="Search for TEXT in title of photo."
|
|
||||||
)
|
|
||||||
@click.option("--no-title", is_flag=True, help="Search for photos with no title.")
|
|
||||||
@click.option(
|
|
||||||
"--description",
|
|
||||||
default=None,
|
|
||||||
multiple=True,
|
|
||||||
help="Search for TEXT in description of photo.",
|
|
||||||
)
|
|
||||||
@click.option(
|
|
||||||
"--no-description", is_flag=True, help="Search for photos with no description."
|
|
||||||
)
|
|
||||||
@click.option(
|
|
||||||
"--uti",
|
|
||||||
default=None,
|
|
||||||
multiple=False,
|
|
||||||
help="Search for photos whose uniform type identifier (UTI) matches TEXT",
|
|
||||||
)
|
|
||||||
@click.option(
|
|
||||||
"-i",
|
|
||||||
"--ignore-case",
|
|
||||||
is_flag=True,
|
|
||||||
help="Case insensitive search for title or description. Does not apply to keyword, person, or album.",
|
|
||||||
)
|
|
||||||
@click.option("--edited", is_flag=True, help="Search for photos that have been edited.")
|
|
||||||
@click.option(
|
|
||||||
"--external-edit", is_flag=True, help="Search for photos edited in external editor."
|
|
||||||
)
|
|
||||||
@click.option("--favorite", is_flag=True, help="Search for photos marked favorite.")
|
|
||||||
@click.option(
|
|
||||||
"--not-favorite", is_flag=True, help="Search for photos not marked favorite."
|
|
||||||
)
|
|
||||||
@click.option("--hidden", is_flag=True, help="Search for photos marked hidden.")
|
|
||||||
@click.option("--not-hidden", is_flag=True, help="Search for photos not marked hidden.")
|
|
||||||
@click.option("--missing", is_flag=True, help="Search for photos missing from disk.")
|
@click.option("--missing", is_flag=True, help="Search for photos missing from disk.")
|
||||||
@click.option(
|
@click.option(
|
||||||
"--not-missing",
|
"--not-missing",
|
||||||
is_flag=True,
|
is_flag=True,
|
||||||
help="Search for photos present on disk (e.g. not missing).",
|
help="Search for photos present on disk (e.g. not missing).",
|
||||||
)
|
)
|
||||||
@click.option(
|
|
||||||
"--shared",
|
|
||||||
is_flag=True,
|
|
||||||
help="Search for photos in shared iCloud album (Photos 5 only).",
|
|
||||||
)
|
|
||||||
@click.option(
|
|
||||||
"--not-shared",
|
|
||||||
is_flag=True,
|
|
||||||
help="Search for photos not in shared iCloud album (Photos 5 only).",
|
|
||||||
)
|
|
||||||
@click.option(
|
|
||||||
"--burst", is_flag=True, help="Search for photos that were taken in a burst."
|
|
||||||
)
|
|
||||||
@click.option(
|
|
||||||
"--not-burst", is_flag=True, help="Search for photos that are not part of a burst."
|
|
||||||
)
|
|
||||||
@click.option("--live", is_flag=True, help="Search for Apple live photos")
|
|
||||||
@click.option(
|
|
||||||
"--not-live", is_flag=True, help="Search for photos that are not Apple live photos"
|
|
||||||
)
|
|
||||||
@click.option(
|
@click.option(
|
||||||
"--cloudasset",
|
"--cloudasset",
|
||||||
is_flag=True,
|
is_flag=True,
|
||||||
@@ -494,17 +435,7 @@ def _list_libraries(json_=False):
|
|||||||
is_flag=True,
|
is_flag=True,
|
||||||
help="Search for photos that are not in iCloud (have not been synched)",
|
help="Search for photos that are not in iCloud (have not been synched)",
|
||||||
)
|
)
|
||||||
@click.option(
|
@DB_ARGUMENT
|
||||||
"--only-movies",
|
|
||||||
is_flag=True,
|
|
||||||
help="Search only for movies (default searches both images and movies).",
|
|
||||||
)
|
|
||||||
@click.option(
|
|
||||||
"--only-photos",
|
|
||||||
is_flag=True,
|
|
||||||
help="Search only for photos/images (default searches both images and movies).",
|
|
||||||
)
|
|
||||||
@click.argument("photos_library", nargs=-1, type=click.Path(exists=True))
|
|
||||||
@click.pass_obj
|
@click.pass_obj
|
||||||
@click.pass_context
|
@click.pass_context
|
||||||
def query(
|
def query(
|
||||||
@@ -635,8 +566,8 @@ def query(
|
|||||||
|
|
||||||
db = get_photos_db(*photos_library, db, cli_obj.db)
|
db = get_photos_db(*photos_library, db, cli_obj.db)
|
||||||
if db is None:
|
if db is None:
|
||||||
click.echo(cli.commands["query"].get_help(ctx))
|
click.echo(cli.commands["query"].get_help(ctx), err=True)
|
||||||
click.echo("\n\nLocated the following Photos library databases: ")
|
click.echo("\n\nLocated the following Photos library databases: ", err=True)
|
||||||
_list_libraries()
|
_list_libraries()
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -677,75 +608,8 @@ def query(
|
|||||||
|
|
||||||
|
|
||||||
@cli.command()
|
@cli.command()
|
||||||
@click.option(
|
@DB_OPTION
|
||||||
"--db",
|
@query_options
|
||||||
required=False,
|
|
||||||
metavar="<Photos database path>",
|
|
||||||
default=None,
|
|
||||||
help="Specify Photos database path. "
|
|
||||||
"Path to Photos library/database can be specified using either --db "
|
|
||||||
"or directly as PHOTOS_LIBRARY positional argument.",
|
|
||||||
type=click.Path(exists=True),
|
|
||||||
)
|
|
||||||
@click.option("--keyword", default=None, multiple=True, help="Search for keyword(s).")
|
|
||||||
@click.option("--person", default=None, multiple=True, help="Search for person(s).")
|
|
||||||
@click.option("--album", default=None, multiple=True, help="Search for album(s).")
|
|
||||||
@click.option("--uuid", default=None, multiple=True, help="Search for UUID(s).")
|
|
||||||
@click.option(
|
|
||||||
"--title", default=None, multiple=True, help="Search for TEXT in title of photo."
|
|
||||||
)
|
|
||||||
@click.option("--no-title", is_flag=True, help="Search for photos with no title.")
|
|
||||||
@click.option(
|
|
||||||
"--description",
|
|
||||||
default=None,
|
|
||||||
multiple=True,
|
|
||||||
help="Search for TEXT in description of photo.",
|
|
||||||
)
|
|
||||||
@click.option(
|
|
||||||
"--no-description", is_flag=True, help="Search for photos with no description."
|
|
||||||
)
|
|
||||||
@click.option(
|
|
||||||
"--uti",
|
|
||||||
default=None,
|
|
||||||
multiple=False,
|
|
||||||
help="Search for photos whose uniform type identifier (UTI) matches TEXT",
|
|
||||||
)
|
|
||||||
@click.option(
|
|
||||||
"-i",
|
|
||||||
"--ignore-case",
|
|
||||||
is_flag=True,
|
|
||||||
help="Case insensitive search for title or description. Does not apply to keyword, person, or album.",
|
|
||||||
)
|
|
||||||
@click.option("--edited", is_flag=True, help="Search for photos that have been edited.")
|
|
||||||
@click.option(
|
|
||||||
"--external-edit", is_flag=True, help="Search for photos edited in external editor."
|
|
||||||
)
|
|
||||||
@click.option("--favorite", is_flag=True, help="Search for photos marked favorite.")
|
|
||||||
@click.option(
|
|
||||||
"--not-favorite", is_flag=True, help="Search for photos not marked favorite."
|
|
||||||
)
|
|
||||||
@click.option("--hidden", is_flag=True, help="Search for photos marked hidden.")
|
|
||||||
@click.option("--not-hidden", is_flag=True, help="Search for photos not marked hidden.")
|
|
||||||
@click.option(
|
|
||||||
"--burst", is_flag=True, help="Search for photos that were taken in a burst."
|
|
||||||
)
|
|
||||||
@click.option(
|
|
||||||
"--not-burst", is_flag=True, help="Search for photos that are not part of a burst."
|
|
||||||
)
|
|
||||||
@click.option("--live", is_flag=True, help="Search for Apple live photos")
|
|
||||||
@click.option(
|
|
||||||
"--not-live", is_flag=True, help="Search for photos that are not Apple live photos"
|
|
||||||
)
|
|
||||||
@click.option(
|
|
||||||
"--shared",
|
|
||||||
is_flag=True,
|
|
||||||
help="Search for photos in shared iCloud album (Photos 5 only).",
|
|
||||||
)
|
|
||||||
@click.option(
|
|
||||||
"--not-shared",
|
|
||||||
is_flag=True,
|
|
||||||
help="Search for photos not in shared iCloud album (Photos 5 only).",
|
|
||||||
)
|
|
||||||
@click.option("--verbose", "-V", is_flag=True, help="Print verbose output.")
|
@click.option("--verbose", "-V", is_flag=True, help="Print verbose output.")
|
||||||
@click.option(
|
@click.option(
|
||||||
"--overwrite",
|
"--overwrite",
|
||||||
@@ -793,16 +657,6 @@ def query(
|
|||||||
"The sidecar file is named in format photoname.ext.json where ext is extension of the photo (e.g. jpg). "
|
"The sidecar file is named in format photoname.ext.json where ext is extension of the photo (e.g. jpg). "
|
||||||
"Note: this does not create an XMP sidecar as used by Lightroom, etc.",
|
"Note: this does not create an XMP sidecar as used by Lightroom, etc.",
|
||||||
)
|
)
|
||||||
@click.option(
|
|
||||||
"--only-movies",
|
|
||||||
is_flag=True,
|
|
||||||
help="Search only for movies (default searches both images and movies).",
|
|
||||||
)
|
|
||||||
@click.option(
|
|
||||||
"--only-photos",
|
|
||||||
is_flag=True,
|
|
||||||
help="Search only for photos/images (default searches both images and movies).",
|
|
||||||
)
|
|
||||||
@click.option(
|
@click.option(
|
||||||
"--download-missing",
|
"--download-missing",
|
||||||
is_flag=True,
|
is_flag=True,
|
||||||
@@ -811,7 +665,7 @@ def query(
|
|||||||
"the photo does not exist on disk. This will be slow and will require internet connection. "
|
"the photo does not exist on disk. This will be slow and will require internet connection. "
|
||||||
"This obviously only works if the Photos library is synched to iCloud.",
|
"This obviously only works if the Photos library is synched to iCloud.",
|
||||||
)
|
)
|
||||||
@click.argument("photos_library", nargs=-1, type=click.Path(exists=True))
|
@DB_ARGUMENT
|
||||||
@click.argument("dest", nargs=1, type=click.Path(exists=True))
|
@click.argument("dest", nargs=1, type=click.Path(exists=True))
|
||||||
@click.pass_obj
|
@click.pass_obj
|
||||||
@click.pass_context
|
@click.pass_context
|
||||||
@@ -904,8 +758,8 @@ def export(
|
|||||||
|
|
||||||
db = get_photos_db(*photos_library, db, cli_obj.db)
|
db = get_photos_db(*photos_library, db, cli_obj.db)
|
||||||
if db is None:
|
if db is None:
|
||||||
click.echo(cli.commands["export"].get_help(ctx))
|
click.echo(cli.commands["export"].get_help(ctx), err=True)
|
||||||
click.echo("\n\nLocated the following Photos library databases: ")
|
click.echo("\n\nLocated the following Photos library databases: ", err=True)
|
||||||
_list_libraries()
|
_list_libraries()
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -1000,7 +854,7 @@ def help(ctx, topic, **kw):
|
|||||||
if topic is None:
|
if topic is None:
|
||||||
click.echo(ctx.parent.get_help())
|
click.echo(ctx.parent.get_help())
|
||||||
else:
|
else:
|
||||||
ctx.info_name = topic
|
ctx.info_name = topic
|
||||||
click.echo(cli.commands[topic].get_help(ctx))
|
click.echo(cli.commands[topic].get_help(ctx))
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user