Added places command to CLI
This commit is contained in:
10
README.md
10
README.md
@@ -57,7 +57,14 @@ Then you should be able to run `osxphotos` on the command line:
|
|||||||
Usage: osxphotos [OPTIONS] COMMAND [ARGS]...
|
Usage: osxphotos [OPTIONS] COMMAND [ARGS]...
|
||||||
|
|
||||||
Options:
|
Options:
|
||||||
--db <Photos database path> Specify database file.
|
--db <Photos database path> Specify Photos database path. Path to Photos
|
||||||
|
library/database can be specified using either
|
||||||
|
--db or directly as PHOTOS_LIBRARY positional
|
||||||
|
argument. If neither --db or PHOTOS_LIBRARY
|
||||||
|
provided, will attempt to find the library to
|
||||||
|
use in the following order: 1. last opened
|
||||||
|
library, 2. system library, 3.
|
||||||
|
~/Pictures/Photos Library.photoslibrary
|
||||||
--json Print output in JSON format.
|
--json Print output in JSON format.
|
||||||
-v, --version Show the version and exit.
|
-v, --version Show the version and exit.
|
||||||
-h, --help Show this message and exit.
|
-h, --help Show this message and exit.
|
||||||
@@ -71,6 +78,7 @@ Commands:
|
|||||||
keywords Print out keywords found in the Photos library.
|
keywords Print out keywords found in the Photos library.
|
||||||
list Print list of Photos libraries found on the system.
|
list Print list of Photos libraries found on the system.
|
||||||
persons Print out persons (faces) found in the Photos library.
|
persons Print out persons (faces) found in the Photos library.
|
||||||
|
places Print out places found in the Photos library.
|
||||||
query Query the Photos database using 1 or more search options; if...
|
query Query the Photos database using 1 or more search options; if...
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ from pathvalidate import (
|
|||||||
|
|
||||||
import osxphotos
|
import osxphotos
|
||||||
|
|
||||||
from ._constants import _EXIF_TOOL_URL, _PHOTOS_5_VERSION
|
from ._constants import _EXIF_TOOL_URL, _PHOTOS_5_VERSION, _UNKNOWN_PLACE
|
||||||
from ._version import __version__
|
from ._version import __version__
|
||||||
from .exiftool import get_exiftool_path
|
from .exiftool import get_exiftool_path
|
||||||
from .template import render_filepath_template, TEMPLATE_SUBSTITUTIONS
|
from .template import render_filepath_template, TEMPLATE_SUBSTITUTIONS
|
||||||
@@ -479,6 +479,56 @@ def info(ctx, cli_obj, db, json_, photos_library):
|
|||||||
click.echo(yaml.dump(info, sort_keys=False))
|
click.echo(yaml.dump(info, sort_keys=False))
|
||||||
|
|
||||||
|
|
||||||
|
@cli.command()
|
||||||
|
@DB_OPTION
|
||||||
|
@JSON_OPTION
|
||||||
|
@DB_ARGUMENT
|
||||||
|
@click.pass_obj
|
||||||
|
@click.pass_context
|
||||||
|
def places(ctx, cli_obj, db, json_, photos_library):
|
||||||
|
""" Print out places found in the Photos library. """
|
||||||
|
|
||||||
|
# below needed for to make CliRunner work for testing
|
||||||
|
cli_db = cli_obj.db if cli_obj is not None else None
|
||||||
|
db = get_photos_db(*photos_library, db, cli_db)
|
||||||
|
if db is None:
|
||||||
|
click.echo(cli.commands["places"].get_help(ctx), err=True)
|
||||||
|
click.echo("\n\nLocated the following Photos library databases: ", err=True)
|
||||||
|
_list_libraries()
|
||||||
|
return
|
||||||
|
|
||||||
|
photosdb = osxphotos.PhotosDB(dbfile=db)
|
||||||
|
place_names = {}
|
||||||
|
for photo in photosdb.photos(movies=True):
|
||||||
|
if photo.place:
|
||||||
|
try:
|
||||||
|
place_names[photo.place.name] += 1
|
||||||
|
except:
|
||||||
|
place_names[photo.place.name] = 1
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
place_names[_UNKNOWN_PLACE] += 1
|
||||||
|
except:
|
||||||
|
place_names[_UNKNOWN_PLACE] = 1
|
||||||
|
|
||||||
|
# sort by place count
|
||||||
|
places = {
|
||||||
|
"places": {
|
||||||
|
name: place_names[name]
|
||||||
|
for name in sorted(
|
||||||
|
place_names.keys(), key=lambda key: place_names[key], reverse=True
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# below needed for to make CliRunner work for testing
|
||||||
|
cli_json = cli_obj.json if cli_obj is not None else None
|
||||||
|
if json_ or cli_json:
|
||||||
|
click.echo(json.dumps(places))
|
||||||
|
else:
|
||||||
|
click.echo(yaml.dump(places, sort_keys=False))
|
||||||
|
|
||||||
|
|
||||||
@cli.command()
|
@cli.command()
|
||||||
@DB_OPTION
|
@DB_OPTION
|
||||||
@JSON_OPTION
|
@JSON_OPTION
|
||||||
|
|||||||
@@ -25,6 +25,9 @@ _TESTED_OS_VERSIONS = ["12", "13", "14", "15"]
|
|||||||
# Photos 5 has persons who are empty string if unidentified face
|
# Photos 5 has persons who are empty string if unidentified face
|
||||||
_UNKNOWN_PERSON = "_UNKNOWN_"
|
_UNKNOWN_PERSON = "_UNKNOWN_"
|
||||||
|
|
||||||
|
# photos with no reverse geolocation info (place)
|
||||||
|
_UNKNOWN_PLACE = "_UNKNOWN_"
|
||||||
|
|
||||||
_EXIF_TOOL_URL = "https://exiftool.org/"
|
_EXIF_TOOL_URL = "https://exiftool.org/"
|
||||||
|
|
||||||
# Where are shared iCloud photos located?
|
# Where are shared iCloud photos located?
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
""" version info """
|
""" version info """
|
||||||
|
|
||||||
__version__ = "0.24.2"
|
__version__ = "0.24.3"
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ from click.testing import CliRunner
|
|||||||
CLI_PHOTOS_DB = "tests/Test-10.15.1.photoslibrary"
|
CLI_PHOTOS_DB = "tests/Test-10.15.1.photoslibrary"
|
||||||
LIVE_PHOTOS_DB = "tests/Test-Cloud-10.15.1.photoslibrary/database/photos.db"
|
LIVE_PHOTOS_DB = "tests/Test-Cloud-10.15.1.photoslibrary/database/photos.db"
|
||||||
RAW_PHOTOS_DB = "tests/Test-RAW-10.15.1.photoslibrary"
|
RAW_PHOTOS_DB = "tests/Test-RAW-10.15.1.photoslibrary"
|
||||||
|
PLACES_PHOTOS_DB = "tests/Test-Places-Catalina-10_15_1.photoslibrary"
|
||||||
|
|
||||||
CLI_OUTPUT_NO_SUBCOMMAND = [
|
CLI_OUTPUT_NO_SUBCOMMAND = [
|
||||||
"Options:",
|
"Options:",
|
||||||
@@ -85,6 +86,8 @@ CLI_EXPORT_RAW_EDITED = [
|
|||||||
]
|
]
|
||||||
CLI_EXPORT_RAW_EDITED_ORIGINAL = ["IMG_0476_2.CR2", "IMG_0476_2_edited.jpeg"]
|
CLI_EXPORT_RAW_EDITED_ORIGINAL = ["IMG_0476_2.CR2", "IMG_0476_2_edited.jpeg"]
|
||||||
|
|
||||||
|
CLI_PLACES_JSON = """{"places": {"_UNKNOWN_": 1, "Maui, Wailea, Hawai'i, United States": 1, "Washington, District of Columbia, United States": 1}}"""
|
||||||
|
|
||||||
|
|
||||||
def test_osxphotos():
|
def test_osxphotos():
|
||||||
import osxphotos
|
import osxphotos
|
||||||
@@ -408,3 +411,20 @@ def test_export_directory_template_3():
|
|||||||
workdir = os.getcwd()
|
workdir = os.getcwd()
|
||||||
for filepath in CLI_EXPORTED_DIRECTORY_TEMPLATE_FILENAMES3:
|
for filepath in CLI_EXPORTED_DIRECTORY_TEMPLATE_FILENAMES3:
|
||||||
assert os.path.isfile(os.path.join(workdir, filepath))
|
assert os.path.isfile(os.path.join(workdir, filepath))
|
||||||
|
|
||||||
|
|
||||||
|
def test_places():
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import os.path
|
||||||
|
import osxphotos
|
||||||
|
from osxphotos.__main__ import places
|
||||||
|
|
||||||
|
runner = CliRunner()
|
||||||
|
cwd = os.getcwd()
|
||||||
|
# pylint: disable=not-context-manager
|
||||||
|
with runner.isolated_filesystem():
|
||||||
|
result = runner.invoke(places, [os.path.join(cwd, PLACES_PHOTOS_DB), "--json"])
|
||||||
|
assert result.exit_code == 0
|
||||||
|
json_got = json.loads(result.output)
|
||||||
|
assert json_got == json.loads(CLI_PLACES_JSON)
|
||||||
|
|||||||
Reference in New Issue
Block a user